diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 6cde5929308b..e20a507a7fbb 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -69,7 +69,7 @@ import { TimedEventManager } from "#app/timed-event-manager.js"; import i18next from "i18next"; import IMysteryEncounter, { MysteryEncounterTier, MysteryEncounterVariant } from "./data/mystery-encounters/mystery-encounter"; import { mysteryEncountersByBiome, allMysteryEncounters, BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT, AVERAGE_ENCOUNTERS_PER_RUN_TARGET, WIGHT_INCREMENT_ON_SPAWN_MISS } from "./data/mystery-encounters/mystery-encounters"; -import { MysteryEncounterData } from "#app/data/mystery-encounters/mystery-encounter-data"; +import { MysteryEncounterData, MysteryEncounterAuras, AuraType } from "#app/data/mystery-encounters/mystery-encounter-data"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1"; @@ -216,6 +216,7 @@ export default class BattleScene extends SceneBase { public pokemonInfoContainer: PokemonInfoContainer; private party: PlayerPokemon[]; public mysteryEncounterData: MysteryEncounterData = new MysteryEncounterData(null); + public mysteryEncounterAuras: MysteryEncounterAuras = new MysteryEncounterAuras(); public lastMysteryEncounter: IMysteryEncounter; /** Combined Biome and Wave count text */ private biomeWaveText: Phaser.GameObjects.Text; @@ -2151,12 +2152,23 @@ export default class BattleScene extends SceneBase { } addMoney(amount: integer): void { - this.money = Math.min(this.money + amount, Number.MAX_SAFE_INTEGER); + const mysteryIncomeAura = this.mysteryEncounterAuras.FindAura(AuraType.INCOME); + const mysteryIncomeMult = 1 + (mysteryIncomeAura.length > 0 ? this.mysteryEncounterAuras.FindAuraTotals(AuraType.INCOME) : 0); + this.money = Math.min(this.money + Math.floor(amount * mysteryIncomeMult), Number.MAX_SAFE_INTEGER); this.updateMoneyText(); this.animateMoneyChanged(true); this.validateAchvs(MoneyAchv); } + getFormattedMoneyString(moneyAmount: number): string { + const userLocale = navigator.language || "en-US"; + const mysteryIncomeAura = this.mysteryEncounterAuras.FindAura(AuraType.INCOME); + const mysteryIncomeMult = 1 + (mysteryIncomeAura.length > 0 ? this.mysteryEncounterAuras.FindAuraTotals(AuraType.INCOME) : 0); + const formattedMoneyAmount = (moneyAmount * mysteryIncomeMult).toLocaleString(userLocale); + const message = i18next.t("battle:moneyWon", { moneyAmount: formattedMoneyAmount }); + return message; + } + getWaveMoneyAmount(moneyMultiplier: number): integer { const waveIndex = this.currentBattle.waveIndex; const waveSetIndex = Math.ceil(waveIndex / 10) - 1; diff --git a/src/battle.ts b/src/battle.ts index ab47eac7993a..d0879db08c45 100644 --- a/src/battle.ts +++ b/src/battle.ts @@ -13,7 +13,7 @@ import { Moves } from "#enums/moves"; import { PlayerGender } from "#enums/player-gender"; import { Species } from "#enums/species"; import { TrainerType } from "#enums/trainer-type"; -import i18next from "#app/plugins/i18n"; +//import i18next from "#app/plugins/i18n"; import IMysteryEncounter, { MysteryEncounterVariant } from "./data/mystery-encounters/mystery-encounter"; export enum BattleType { @@ -177,9 +177,10 @@ export default class Battle { scene.addMoney(moneyAmount.value); - const userLocale = navigator.language || "en-US"; - const formattedMoneyAmount = moneyAmount.value.toLocaleString(userLocale); - const message = i18next.t("battle:moneyPickedUp", { moneyAmount: formattedMoneyAmount }); + //const userLocale = navigator.language || "en-US"; + //const formattedMoneyAmount = moneyAmount.value.toLocaleString(userLocale); + //const message = i18next.t("battle:moneyPickedUp", { moneyAmount: formattedMoneyAmount }); + const message = this.scene.getFormattedMoneyString(moneyAmount.value); scene.queueMessage(message, null, true); scene.currentBattle.moneyScattered = 0; diff --git a/src/data/mystery-encounters/encounters/choice-of-balance-encounter.ts b/src/data/mystery-encounters/encounters/choice-of-balance-encounter.ts new file mode 100644 index 000000000000..146cb1fb14d3 --- /dev/null +++ b/src/data/mystery-encounters/encounters/choice-of-balance-encounter.ts @@ -0,0 +1,391 @@ +//import { +// getHighestLevelPlayerPokemon, +// koPlayerPokemon, +// leaveEncounterWithoutBattle, +// queueEncounterMessage, +// setEncounterRewards, +// showEncounterText, +//} from "#app/data/mystery-encounters/mystery-encounter-utils"; +import { leaveEncounterWithoutBattle } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; +//import { mysteryEncounter } from "#app/locales/en/mystery-encounter"; +//import { ModifierTier } from "#app/modifier/modifier-tier"; +//import { GameOverPhase } from "#app/phases"; +import { randSeedInt } from "#app/utils"; +import { MysteryEncounterType } from "#enums/mystery-encounter-type"; +import i18next from "i18next"; +import BattleScene from "../../../battle-scene"; +import IMysteryEncounter, { + MysteryEncounterBuilder, + MysteryEncounterTier, +} from "../mystery-encounter"; +import { EncounterOptionMode, MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; +import { Aura, AuraType, getAuraName, auraStatMap } from "#app/data/mystery-encounters/mystery-encounter-data"; + +const namespace = "mysteryEncounter:choice_of_balance"; + +function generateRewards(numOptions: number): RewardOption[] { + const negativeRewards = getNegativeRewards(numOptions); + const positiveRewards = getPositiveRewards(numOptions); + const rewardArray = []; + for (let i = 0; i < negativeRewards.length; i++) { + rewardArray.push(new RewardOption(negativeRewards[i], positiveRewards[i])); + } + + return rewardArray; +} + +export const ChoiceOfBalanceEncounter: IMysteryEncounter = MysteryEncounterBuilder + .withEncounterType(MysteryEncounterType.CHOICE_OF_BALANCE) + .withEncounterTier(MysteryEncounterTier.GREAT) + .withIntroSpriteConfigs([ + { + spriteKey: "200", + fileRoot: "pokemon", + hasShadow: true, + x: 4, + y: -16, + scale: 1, + disableAnimation: true // Re-enabled after option select + }, + { + spriteKey: "amulet_coin", + fileRoot: "items", + hasShadow: true, + x: 35, + y: -3, + scale: 0.75, + isItem: true, + }, + { + spriteKey: "cracked_pot", + fileRoot: "items", + hasShadow: true, + x: 20, + y: -14, + scale: 0.75, + isItem: true, + }, + { + spriteKey: "griseous_core", + fileRoot: "items", + hasShadow: true, + x: -6, + y: -1, + scale: 0.75, + isItem: true, + } + ]) + .withHideIntroVisuals(false) + .withSceneWaveRangeRequirement(10, 180) // waves 10 to 180 + .withIntroDialogue([ + { + text: `${namespace}_intro_message`, + } + ]) + .withOnInit((scene: BattleScene) => { + const encounter = scene.currentBattle.mysteryEncounter; + encounter.misc = []; + console.log(encounter); + + const options = 3; + + const rewardsArray = generateRewards(options); + + for (let i = 0; i < rewardsArray.length; i++) { + rewardsArray[i].generateStats(); + rewardsArray[i].generateAuras(); + if (rewardsArray[i].negativeStat > 0) { + if (rewardsArray[i].negativeOption === NegativeRewards.ENEMY_STATS) { + encounter.setDialogueToken("negativeEnemySTAT", getAuraName(rewardsArray[i].negativeStat)); + } else if (rewardsArray[i].negativeOption === NegativeRewards.PLAYER_STATS) { + encounter.setDialogueToken("negativePlayerSTAT", getAuraName(rewardsArray[i].negativeStat)); + } + } + if (rewardsArray[i].positiveStat > 0) { + if (rewardsArray[i].positiveOption === PositiveRewards.ENEMY_STATS) { + encounter.setDialogueToken("positiveEnemySTAT", getAuraName(rewardsArray[i].positiveStat)); + } else if (rewardsArray[i].positiveOption === PositiveRewards.PLAYER_STATS) { + encounter.setDialogueToken("positivePlayerSTAT", getAuraName(rewardsArray[i].positiveStat)); + } + } + encounter.misc.push(rewardsArray[i]); + } + + encounter.setDialogueToken("dynamic1", rewardsArray[0].generateMessage()); + encounter.setDialogueToken("dynamic2", rewardsArray[1].generateMessage()); + encounter.setDialogueToken("dynamic3", rewardsArray[2].generateMessage()); + + return true; + }) + .withTitle(`${namespace}_title`) + .withDescription(`${ namespace }_description`) + .withQuery(`${namespace}_query`) + .withOption( + new MysteryEncounterOptionBuilder() + .withOptionMode(EncounterOptionMode.DEFAULT) + .withDialogue({ + buttonLabel: `${namespace}_option_1_label`, + buttonTooltip: `${ namespace }_dynamic_tooltip_1`, + selected: [ + { + text: `${namespace}_option_selected_message`, + }, + ], + }) + .withOptionPhase(async (scene: BattleScene) => { + // Leave encounter with no rewards or exp + //[const negativeAura, const positiveAura] + scene.mysteryEncounterAuras.AddAura(scene.currentBattle.mysteryEncounter.misc[0].negativeAura); + scene.mysteryEncounterAuras.AddAura(scene.currentBattle.mysteryEncounter.misc[0].positiveAura); + leaveEncounterWithoutBattle(scene, true); + return true; + }) + .build() + ) + .withSimpleOption( + { + buttonLabel: `${namespace}_option_2_label`, + buttonTooltip: `${namespace}_dynamic_tooltip_2`, + selected: [ + { + text: `${namespace}_option_selected_message`, + }, + ], + }, + async (scene: BattleScene) => { + // Leave encounter with no rewards or exp + scene.mysteryEncounterAuras.AddAura(scene.currentBattle.mysteryEncounter.misc[1].negativeAura); + scene.mysteryEncounterAuras.AddAura(scene.currentBattle.mysteryEncounter.misc[1].positiveAura); + leaveEncounterWithoutBattle(scene, true); + return true; + }) + .withSimpleOption( + { + buttonLabel: `${namespace}_option_3_label`, + buttonTooltip: `${namespace}_dynamic_tooltip_3`, + selected: [ + { + text: `${namespace}_option_selected_message`, + }, + ], + }, + async (scene: BattleScene) => { + // Leave encounter with no rewards or exp + scene.mysteryEncounterAuras.AddAura(scene.currentBattle.mysteryEncounter.misc[2].negativeAura); + scene.mysteryEncounterAuras.AddAura(scene.currentBattle.mysteryEncounter.misc[2].positiveAura); + leaveEncounterWithoutBattle(scene, true); + return true; + }) + .withSimpleOption( + { + buttonLabel: `${namespace}_option_4_label`, + buttonTooltip: `${namespace}_option_4_description`, + selected: [ + { + text: `${namespace}_option_leave_selected_message`, + }, + ], + }, + async (scene: BattleScene) => { + // Leave encounter with no rewards or exp + leaveEncounterWithoutBattle(scene, true); + return true; + }) + .build(); + +export enum NegativeRewards { + INCOME, + LUCK, + PLAYER_STATS, + ENEMY_STATS, + PP, + NO_REROLL +} + +export enum PositiveRewards { + INCOME = 1000, // starting at 1000 for positive so we can tell them apart between the negatives later + LUCK, + PLAYER_STATS, + ENEMY_STATS, + PP, + INSTANT_MONEY, + INSTANT_CANDY +} + +export function getNegativeRewards(totalOptions: number): number[] { + const negativeOptions = []; + const numNegatives = Object.keys(NegativeRewards).filter(nr => !isNaN(Number(nr))); + while (negativeOptions.length < totalOptions) { + const roll = randSeedInt(numNegatives.length); + if (!negativeOptions.includes(roll)) { + negativeOptions.push(roll); + } + } + return negativeOptions; +} + +export function getPositiveRewards(totalOptions: number): number[] { + const positiveOptions = []; + const numPositives = Object.values(PositiveRewards).filter(pr => !isNaN(Number(pr))); + while (positiveOptions.length < totalOptions) { + const roll = randSeedInt(numPositives.length); + if (!positiveOptions.includes(numPositives[roll])) { + positiveOptions.push(numPositives[roll]); + } + } + return positiveOptions; +} + +export class RewardOption { + public negativeOption: number; + public positiveOption: number; + public negativeStat = -1; + public positiveStat = -1; + public negativeAura: Aura; + public positiveAura: Aura; + + constructor(negativeOption: number, positiveOption: number) { + this.negativeOption = negativeOption; + this.positiveOption = positiveOption; + } + + generateMessage(): string { + const [negativeType, negativeText, negativeStrength, negativeDuration] = this.getRewardInfo(this.negativeOption); + const [positiveType, positiveText, positiveStrength, positiveDuration] = this.getRewardInfo(this.positiveOption); + let outputMessage: string; + + const formattedNegativeStrength = this.formattedStrengths(negativeType, negativeStrength); + const formattedPositiveStrength = this.formattedStrengths(positiveType, positiveStrength); + if (negativeDuration > 0) { + // this is a normal reward; the output message uses {{description}}, {{strength}} and {{duration}} to describe a reward + outputMessage = i18next.t("mysteryEncounter:choice_of_balance_text_template_normal", { descriptor: this.getDescriptorText(negativeText), strength: formattedNegativeStrength !== "" ? " " + formattedNegativeStrength : "", duration: negativeDuration }); + } else if (negativeDuration === 0) { + // this is an instant reward; the output message uses {{description}} and {{strength}} to describe a reward + outputMessage = i18next.t("mysteryEncounter:choice_of_balance_text_template_instant", { descriptor: this.getDescriptorText(negativeText), strength: formattedNegativeStrength !== "" ? " " + formattedNegativeStrength : "" }); + } else if (negativeDuration < 0) { + // this is a reward that lasts the rest of the run; the output message uses {{description}} and {{strength}} to describe a reward + outputMessage = i18next.t("mysteryEncounter:choice_of_balance_text_template_permanent", { descriptor: this.getDescriptorText(negativeText), strength: formattedNegativeStrength !== "" ? " " + formattedNegativeStrength : "" }); + } + outputMessage += " " + i18next.t(this.getDescriptorText("then")) + " "; + + if (positiveDuration > 0) { + // this is a normal reward; the output message uses {{description}}, {{strength}} and {{duration}} to describe a reward + outputMessage += i18next.t("mysteryEncounter:choice_of_balance_text_template_normal", { descriptor: this.getDescriptorText(positiveText), strength: formattedPositiveStrength !== "" ? " " + formattedPositiveStrength : "", duration: positiveDuration }); + } else if (positiveDuration === 0) { + // this is an instant reward; the output message uses {{description}} and {{strength}} to describe a reward + outputMessage += i18next.t("mysteryEncounter:choice_of_balance_text_template_instant", { descriptor: this.getDescriptorText(positiveText), strength: formattedPositiveStrength !== "" ? " " + formattedPositiveStrength : "" }); + } else if (positiveDuration < 0) { + // this is a reward that lasts the rest of the run; the output message uses {{description}} and {{strength}} to describe a reward + outputMessage += i18next.t("mysteryEncounter:choice_of_balance_text_template_permanent", { descriptor: this.getDescriptorText(positiveText), strength: formattedPositiveStrength !== "" ? " " + formattedPositiveStrength : "" }); + } + return outputMessage;//.join(" "); + } + + getRewardInfo(reward: number): [index: number, dialogueName: string, auraStrength: number, auraDuration: number] { + //if (Object.values(PositiveRewards).includes(reward) || Object.values(NegativeRewards).includes(reward)) { + return statMessageIndex.find(r => r[0] === reward); + //return statMessageIndex.filter(r => r[0] === reward)[1]; + //} + } + + private formattedStrengths(type: number, strength: number): string { + let newStrength: string; + switch (type) { + // These are for percentages + case NegativeRewards.INCOME: + case NegativeRewards.PP: + case PositiveRewards.INCOME: + case PositiveRewards.PP: + newStrength = i18next.t("{{percentageValue, percent}}", { percentageValue: strength }); + break; + // These are for single numbers (i.e. stat stage increase/decrease, luck increase/decrease etc) + case NegativeRewards.LUCK: + case NegativeRewards.PLAYER_STATS: + case NegativeRewards.ENEMY_STATS: + case PositiveRewards.LUCK: + case PositiveRewards.PLAYER_STATS: + case PositiveRewards.ENEMY_STATS: + newStrength = String(Math.abs(strength)); + break; + // These are for exceptions that don't have a strength + case NegativeRewards.NO_REROLL: + case PositiveRewards.INSTANT_CANDY: + newStrength = ""; + break; + // These are for money rewards + case PositiveRewards.INSTANT_MONEY: + newStrength = i18next.t("{{moneyValue, money}}", { moneyValue: strength }); + break; + default: + console.log("Missing formattedStrengths!!!"); + newStrength = "Missing formattedStrengths"; + break; + } + return newStrength; + } + + private getDescriptorText(text: string) { + return i18next.t(namespace + "_" + text); + } + + generateStats() { + const statArray = [AuraType.ATK, AuraType.SPATK, AuraType.DEF, AuraType.SPDEF, AuraType.SPD, AuraType.EVA, AuraType.ACC]; + if (this.negativeStat < 0 && (this.negativeOption === NegativeRewards.ENEMY_STATS || this.negativeOption === NegativeRewards.PLAYER_STATS)) { + this.negativeStat = statArray[randSeedInt(statArray.length)]; + } + if (this.positiveStat < 0 && (this.positiveOption === PositiveRewards.PLAYER_STATS || this.positiveOption === PositiveRewards.ENEMY_STATS)) { + this.positiveStat = statArray[randSeedInt(statArray.length)]; + } + } + + generateAuras() { + const [negativeType, negativeText, negativeStrength, negativeDuration] = this.getRewardInfo(this.negativeOption); + const [positiveType, positiveText, positiveStrength, positiveDuration] = this.getRewardInfo(this.positiveOption); + console.log(negativeText + ", " + positiveText); + this.negativeAura = new Aura([-1], negativeStrength, negativeDuration, this.convertRewardsToAura(negativeType), 0, 0); + this.positiveAura = new Aura([-1], positiveStrength, positiveDuration, this.convertRewardsToAura(positiveType), 0, negativeDuration); + } + + convertRewardsToAura(reward: number): number { + switch (reward) { + case NegativeRewards.INCOME: + return AuraType.INCOME; + case NegativeRewards.LUCK: + return AuraType.LUCK; + case NegativeRewards.PLAYER_STATS: + case NegativeRewards.ENEMY_STATS: + return auraStatMap[this.negativeStat]; + case NegativeRewards.NO_REROLL: + return -1; + case PositiveRewards.INCOME: + return AuraType.INCOME; + case PositiveRewards.LUCK: + return AuraType.LUCK; + case PositiveRewards.PLAYER_STATS: + case PositiveRewards.ENEMY_STATS: + return auraStatMap[this.positiveStat]; + case PositiveRewards.PP: + return AuraType.PP; + case PositiveRewards.INSTANT_MONEY: + return AuraType.MONEY; + case PositiveRewards.INSTANT_CANDY: + return AuraType.CANDY; + } + } +} + +const statMessageIndex: [index: number, dialogueName: string, auraStrength: number, auraDuration: number][] = [ + [NegativeRewards.INCOME, "negative_income", -0.4, 5], + [NegativeRewards.LUCK, "negative_luck", 0, 15], + [NegativeRewards.PLAYER_STATS, "negative_player_stats", -1, 10], + [NegativeRewards.ENEMY_STATS, "negative_enemy_stats", 1, 8], + [NegativeRewards.NO_REROLL, "negative_no_reroll", 0, 7], + [NegativeRewards.PP, "negative_pp_chance", -0.1, 10], + [PositiveRewards.INCOME, "positive_income", 0.7, -1], + [PositiveRewards.LUCK, "positive_luck", 5, -1], + [PositiveRewards.PLAYER_STATS, "positive_player_stats", 1, 13], + [PositiveRewards.ENEMY_STATS, "positive_enemy_stats", -1, 12], + [PositiveRewards.PP, "positive_pp_chance", 0.2, 40], + [PositiveRewards.INSTANT_MONEY, "positive_instant_money", 5000, 0], + [PositiveRewards.INSTANT_CANDY, "positive_instant_candy", 0, 0], +]; diff --git a/src/data/mystery-encounters/mystery-encounter-data.ts b/src/data/mystery-encounters/mystery-encounter-data.ts index 7162450bfc59..da635e00caaa 100644 --- a/src/data/mystery-encounters/mystery-encounter-data.ts +++ b/src/data/mystery-encounters/mystery-encounter-data.ts @@ -2,6 +2,9 @@ import { MysteryEncounterTier } from "#app/data/mystery-encounters/mystery-encou import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT } from "#app/data/mystery-encounters/mystery-encounters"; import { isNullOrUndefined } from "#app/utils"; +import { EnemyPokemon, PlayerPokemon } from "field/pokemon"; +import BattleScene from "../../battle-scene"; +import { TempBattleStat } from "#app/data/temp-battle-stat"; export class MysteryEncounterData { encounteredEvents: [MysteryEncounterType, MysteryEncounterTier][] = []; @@ -14,3 +17,212 @@ export class MysteryEncounterData { } } } + +export class MysteryEncounterAuras { + public auraList: Aura[]; + + constructor() { + this.auraList = []; + } + + + //AddAura(targetOrAura: number[] | Aura, auraStrength: number, duration: number, auraType: number, team: number, timeUntilActive: number = 0) { + // this.auraList.push(new Aura(targetOrAura, auraStrength, duration, auraType, team, timeUntilActive)); + //} + + AddAura(aura: Aura) { + this.auraList.push(aura); + } + + UpdateAurasDurations(scene: BattleScene) { + for (let i = 0; i < this.auraList.length; i++) { + if (this.auraList[i].timeUntilActive !== 0) { + this.auraList[i].timeUntilActive -= 1; // removes a turn from the timeUntilActive + } else { + if (this.auraList[i].duration > 0) { + this.auraList[i].duration -= 1; // removes a counter from the duration + if (this.auraList[i].isInstant() && this.auraList[i].duration === 0 && this.auraList[i].timeUntilActive === 0) { // this checks if the aura is an instant effect + this.TriggerInstantAura(this.auraList[i], scene); + } + } + } + } + this.auraList = this.auraList.filter(aura => aura.duration !== 0 && aura.timeUntilActive !== 0); // this updates our list to make sure to only have things that are peristent or still counting down + } + + /* this method will find all auras of a certain type and add up their total strengths. + * For example, if you wanted to find the total strength of all luck related auras + * or all income related auras. Note that this make the percentage additive. + * This does not filter by pokemon or team + */ + FindAuraTotals(auraType: number): number { + let total = 0; + const filteredAuras = this.FindAura(auraType); + if (filteredAuras.length > 0) { + for (let i = 0; i < filteredAuras.length; i++) { + const auraValue = filteredAuras[i].auraStrength; + if (auraType === AuraType.LUCK && auraValue === 0) { // this is used to check if luck has "Set to 0" + total = 0.5; + break; + } + total += filteredAuras[i].timeUntilActive > 0 ? 0 : auraValue; // this checks to make sure the aura is active before adding it to our totals + } + } + return total; + } + + FindAura(auraType: number): Aura[] { // this method will find all auras of a certain type (for example, all income related auras) + return this.auraList.filter(auras => auras.auraType === auraType); + } + + FindAurasByPokemon(pokemon: PlayerPokemon | EnemyPokemon, auraType?: number): Aura[] { // this method finds an aura by pokemon, with optional filtering for type + const allAuras: Aura[] = []; + const pokemonId = pokemon.id; + const isPlayer = pokemon.isPlayer(); + auraType = auraType || 0; + for (let i = 0; i < this.auraList.length; i++) { + const auraTeam = this.auraList[i].team; + if (this.auraList[i].auraType === auraType || auraType === 0) { + if (this.auraList[i].target.includes(pokemonId) || this.auraList[i].target[0] === 0) { // the target[0] being 0 is our way of saying it's for all valid pokemon + if ((auraTeam === TeamTarget.ALL || auraTeam === TeamTarget.PLAYER) && isPlayer) { + allAuras.push(this.auraList[i]); + continue; + } + if ((auraTeam === TeamTarget.ALL || auraTeam === TeamTarget.ENEMY) && !isPlayer) { + allAuras.push(this.auraList[i]); + continue; + } + } + } + } + return allAuras; + } + + UpdateStats(pokemon: PlayerPokemon | EnemyPokemon) { + const pokemonAuras = this.FindAurasByPokemon(pokemon); + const pokemonSummonData = pokemon.summonData ? pokemon.summonData : pokemon.getPrimeSummonData(); + if (pokemonAuras.length > 0) { + for (let i = 0; i < pokemonSummonData.battleStats.length; i++) { + const mysteryStatAura = pokemonAuras.filter(aura => aura.auraType === auraStatMap[i]); + const totalStatChange = mysteryStatAura.reduce((accumulator, current) => accumulator + current.auraStrength, 0); + pokemonSummonData.battleStats[i] += mysteryStatAura.length > 0 ? totalStatChange : 0; + } + } + pokemon.updateInfo(); + } + + TriggerInstantAura(aura: Aura, scene: BattleScene) { + if (aura.auraType === AuraType.MONEY) { + scene.addMoney(aura.auraStrength); + } + } +} + +export class Aura { + public target: number[]; // this can be used to target specific pokemon (using an array of pokemon ID) or all pokemon (using [-1]) + public auraStrength: number; // this is the amount boosted/reduced - can be positive or negative + public duration: number; // this is how many waves the aura lasts for; use a number > 0 for timed auras, or -1 for auras for the rest of the game + public auraType: number; // this is the aura type - for now, for example, what stat will be changed + public team: number; // this is the team using the team enum of Team.PLAYER, Team.ENEMY, Team.ALL to target the player, enemy or everyone respectively. + public timeUntilActive: number; // this will be the amount of waves until an aura is active; for example, a positive aura being activated when a negative one runs out. + + constructor(target: number[], auraStrength: number, duration: number, auraType: number, team: number, timeUntilActive: number) { + this.target = target; + this.auraStrength = auraStrength; + this.duration = duration; + this.auraType = auraType; + this.team = team; + this.timeUntilActive = timeUntilActive; + } + + isInstant() { + return this.auraType === AuraType.MONEY || this.auraType === AuraType.CANDY; + } +} + +export enum TeamTarget { + ENEMY = -1, + ALL, + PLAYER +} + +export enum AuraType { + INCOME, + MONEY, + ATK, + DEF, + SPATK, + SPDEF, + ACC, + EVA, + SPD, + LUCK, + XP, + CANDY, + PP, + PASSIVE, + CRIT +} + +export function getAuraName(aura: AuraType) { + switch (aura) { + case AuraType.INCOME: + return "INCOME"; + case AuraType.MONEY: + return "MONEY"; + case AuraType.ATK: + return "ATK"; + case AuraType.SPATK: + return "SP. ATK"; + case AuraType.DEF: + return "DEF"; + case AuraType.SPDEF: + return "SP. DEF"; + case AuraType.SPD: + return "SPEED"; + case AuraType.ACC: + return "ACC"; + case AuraType.EVA: + return "EVA"; + case AuraType.LUCK: + return "LUCK"; + case AuraType.XP: + return "EXP"; + case AuraType.CANDY: + return "CANDY"; + case AuraType.PP: + return "PP"; + case AuraType.PASSIVE: + return "PASSIVE"; + case AuraType.CRIT: + return "CRIT"; + default: + return "???"; + } +} + +export function ConvertAuraToBattleStat(auraType: AuraType): Number { + switch (auraType) { + case AuraType.ATK: + return TempBattleStat.ATK; + case AuraType.DEF: + return TempBattleStat.DEF; + case AuraType.SPATK: + return TempBattleStat.SPATK; + case AuraType.SPDEF: + return TempBattleStat.SPDEF; + case AuraType.ACC: + return TempBattleStat.ACC; + case AuraType.EVA: + return -1; + case AuraType.SPD: + return TempBattleStat.SPD; + case AuraType.CRIT: + return TempBattleStat.CRIT; + default: + return -1; + } +} + +export const auraStatMap = [AuraType.ATK, AuraType.DEF, AuraType.SPATK, AuraType.SPDEF, AuraType.ACC, AuraType.EVA, AuraType.SPD]; + diff --git a/src/data/mystery-encounters/mystery-encounter.ts b/src/data/mystery-encounters/mystery-encounter.ts index c6fc8c1ca66e..dbc261790038 100644 --- a/src/data/mystery-encounters/mystery-encounter.ts +++ b/src/data/mystery-encounters/mystery-encounter.ts @@ -153,6 +153,7 @@ export default class IMysteryEncounter implements IMysteryEncounter { this.hideIntroVisuals = !isNullOrUndefined(this.hideIntroVisuals) ? this.hideIntroVisuals : true; // Reset any dirty flags or encounter data + this.options = [...this.options]; this.lockEncounterRewardTiers = true; this.dialogueTokens = {}; this.enemyPartyConfigs = []; diff --git a/src/data/mystery-encounters/mystery-encounters.ts b/src/data/mystery-encounters/mystery-encounters.ts index e70c00d90c85..2727fbd9f265 100644 --- a/src/data/mystery-encounters/mystery-encounters.ts +++ b/src/data/mystery-encounters/mystery-encounters.ts @@ -12,6 +12,7 @@ import { SleepingSnorlaxEncounter } from "./encounters/sleeping-snorlax-encounte import { TrainingSessionEncounter } from "./encounters/training-session-encounter"; import IMysteryEncounter from "./mystery-encounter"; import { SafariZoneEncounter } from "#app/data/mystery-encounters/encounters/safari-zone-encounter"; +import { ChoiceOfBalanceEncounter } from "./encounters/choice-of-balance-encounter"; // Spawn chance: (BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT + WIGHT_INCREMENT_ON_SPAWN_MISS * ) / 256 export const BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT = 1; @@ -217,6 +218,7 @@ export function initMysteryEncounters() { allMysteryEncounters[MysteryEncounterType.SLEEPING_SNORLAX] = SleepingSnorlaxEncounter; allMysteryEncounters[MysteryEncounterType.DEPARTMENT_STORE_SALE] = DepartmentStoreSaleEncounter; allMysteryEncounters[MysteryEncounterType.SHADY_VITAMIN_DEALER] = ShadyVitaminDealerEncounter; + allMysteryEncounters[MysteryEncounterType.CHOICE_OF_BALANCE] = ChoiceOfBalanceEncounter; allMysteryEncounters[MysteryEncounterType.FIELD_TRIP] = FieldTripEncounter; allMysteryEncounters[MysteryEncounterType.SAFARI_ZONE] = SafariZoneEncounter; allMysteryEncounters[MysteryEncounterType.LOST_AT_SEA] = LostAtSeaEncounter; diff --git a/src/enums/mystery-encounter-type.ts b/src/enums/mystery-encounter-type.ts index 1f2711cd674e..1e8a882d5dc7 100644 --- a/src/enums/mystery-encounter-type.ts +++ b/src/enums/mystery-encounter-type.ts @@ -7,6 +7,7 @@ export enum MysteryEncounterType { TRAINING_SESSION, DEPARTMENT_STORE_SALE, SHADY_VITAMIN_DEALER, + CHOICE_OF_BALANCE, FIELD_TRIP, SAFARI_ZONE, LOST_AT_SEA //might be generalized later on diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index ebae5fe81227..46d0ca33226c 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -2650,6 +2650,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.summonDataPrimer = summonDataPrimer; } + getPrimeSummonData(): PokemonSummonData { + return this.summonDataPrimer; + } + resetSummonData(): void { if (this.summonData?.speciesForm) { this.summonData.speciesForm = null; diff --git a/src/locales/en/mystery-encounter.ts b/src/locales/en/mystery-encounter.ts index 47c601cc9db2..70019c3ebb29 100644 --- a/src/locales/en/mystery-encounter.ts +++ b/src/locales/en/mystery-encounter.ts @@ -40,6 +40,44 @@ export const mysteryEncounter = { "mysterious_chest_option_1_bad_result": `Oh no!@d{32}\nThe chest was trapped! $Your {{pokeName}} jumps in front of you\nbut is KOed in the process.`, + "choice_of_balance_intro_message": `You feel a strange pull in a certain direction. + $Heading towards it, you hear some weird sounds in the distance. + $It's a...@d{64} Misdreavus?! It locks eyes with you and seems to smirk at you. + $It moves aside, and you see some items nearby - Misdreavus wants you to take one!`, + "choice_of_balance_title": "The Choice of Balance", + "choice_of_balance_description": "Misdreavus wants you to take one of their items. You can feel from here that while they hold great power, they're slighly cursed. You can tell the curse will wear off shortly", + "choice_of_balance_query": "What will you choose?", + "choice_of_balance_option_1_label": "Option A", + "choice_of_balance_dynamic_tooltip_1": "$t({{dynamic1}})", + "choice_of_balance_option_2_label": "Option B", + "choice_of_balance_option_2_tooltip": "(-) No Rewards", + "choice_of_balance_dynamic_tooltip_2": "$t({{dynamic2}})", + "choice_of_balance_option_3_label": "Option C", + "choice_of_balance_dynamic_tooltip_3": "$t({{dynamic3}})", + "choice_of_balance_option_4_label": "Leave", + "choice_of_balance_option_4_description": "No rewards", + "choice_of_balance_option_selected_message": "You hope you've made the right decision...", + "choice_of_balance_option_leave_selected_message": "You decide to leave - you don't want to risk taking something too cursed", + "choice_of_balance_text_template_normal": "{{descriptor}}{{strength}} for {{duration}} waves.", + "choice_of_balance_text_template_instant": "{{descriptor}}{{strength}} instantly", + "choice_of_balance_text_template_permanent": "{{descriptor}}{{strength}} for the rest of this run", + "choice_of_balance_negative_income": "Reduce income by", + "choice_of_balance_negative_luck": "Set luck to", + "choice_of_balance_negative_player_stats": "Reduce {{negativePlayerSTAT}} by", + "choice_of_balance_negative_enemy_stats": "Increase enemy {{negativeEnemySTAT}} by", + "choice_of_balance_negative_pp_chance": "Increase PP usage chance by", + "choice_of_balance_negative_add_pokemon": "Unable to add pokemon", + "choice_of_balance_negative_damage_to_player": "Increase DMG taken by", + "choice_of_balance_negative_no_reroll": "No shop rerolls", + "choice_of_balance_positive_income": "Increase income by", + "choice_of_balance_positive_luck": "Increase luck by", + "choice_of_balance_positive_player_stats": "Increase {{positivePlayerSTAT}} by", + "choice_of_balance_positive_enemy_stats": "Reduce enemy {{positiveEnemySTAT}} by", + "choice_of_balance_positive_pp_chance": "Reduce PP usage chance by", + "choice_of_balance_positive_instant_money": "Gain", + "choice_of_balance_positive_instant_candy": "Gain a rarer candy", + "choice_of_balance_then": "After this effect:", + "fight_or_flight_intro_message": "Something shiny is sparkling\non the ground near that Pokémon!", "fight_or_flight_title": "Fight or Flight", "fight_or_flight_description": "It looks like there's a strong Pokémon guarding an item. Battling is the straightforward approach, but this Pokémon looks strong. You could also try to sneak around, though the Pokémon might catch you.", diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 250b2953fdf2..a3f8f7516916 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -27,6 +27,7 @@ import { BattlerTagType } from "#enums/battler-tag-type"; import { BerryType } from "#enums/berry-type"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { Aura, AuraType } from "#app/data/mystery-encounters/mystery-encounter-data"; const outputModifierData = false; const useMaxWeightForOutput = false; @@ -412,6 +413,33 @@ export class RememberMoveModifierType extends PokemonModifierType { } } +export class LapsingAuraModifierType extends ModifierType { + private myAuraData: Aura; + + constructor(localeKey: string, iconImage: string, myAuraData?: Aura) { + super(localeKey, iconImage, () => new Modifiers.LapsingAuraModifier(this, myAuraData)); + this.myAuraData = myAuraData; + } + + getDescription(scene: BattleScene): string { + return i18next.t("modifierType:ModifierType.AugmentModifierType.description", { myAuraData: this.myAuraData }); + } +} + +export class PersistentAuraModifierType extends ModifierType { + private myAuraData: Aura; + + constructor(localeKey: string, iconImage: string, myAuraData?: Aura) { + super(localeKey, iconImage, () => new Modifiers.PersistentAuraModifier(this, myAuraData)); + + this.myAuraData = myAuraData; + } + + getDescription(scene: BattleScene): string { + return i18next.t("modifierType:ModifierType.AugmentModifierType.description", { myAuraData: this.myAuraData }); + } +} + export class DoubleBattleChanceBoosterModifierType extends ModifierType { public battleCount: integer; @@ -1202,6 +1230,8 @@ export const modifierTypes = { SUPER_REPEL: () => new DoubleBattleChanceBoosterModifierType('Super Repel', 10), MAX_REPEL: () => new DoubleBattleChanceBoosterModifierType('Max Repel', 25),*/ + AURA_STAT: () => new LapsingAuraModifierType("aura_stat_EVA", "lucarionite"), + LURE: () => new DoubleBattleChanceBoosterModifierType("modifierType:ModifierType.LURE", "lure", 5), SUPER_LURE: () => new DoubleBattleChanceBoosterModifierType("modifierType:ModifierType.SUPER_LURE", "super_lure", 10), MAX_LURE: () => new DoubleBattleChanceBoosterModifierType("modifierType:ModifierType.MAX_LURE", "max_lure", 25), @@ -2088,8 +2118,17 @@ export class ModifierTypeOption { } export function getPartyLuckValue(party: Pokemon[]): integer { + const mysteryLuckAura = party[0].scene.mysteryEncounterAuras.FindAura(AuraType.LUCK); + let auraLuck = 0; + if (mysteryLuckAura.length > 0) { + const auraTotalLuck = party[0].scene.mysteryEncounterAuras.FindAuraTotals(AuraType.LUCK); + if (auraTotalLuck === 0.5) { /// this means that there are luck related auras, but the luck is forcibly being set to 0, so we need to return 0 here + return 0; + } + auraLuck += auraTotalLuck; + } const luck = Phaser.Math.Clamp(party.map(p => p.isFainted() ? 0 : p.getLuck()) - .reduce((total: integer, value: integer) => total += value, 0), 0, 14); + .reduce((total: integer, value: integer) => total += value, 0) + auraLuck, 0, 14); return luck || 0; } diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 6f098ade124b..ba2ee70ab1f9 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -28,6 +28,7 @@ import i18next from "i18next"; import { allMoves } from "#app/data/move.js"; import { Abilities } from "#app/enums/abilities.js"; +import { Aura, AuraType, ConvertAuraToBattleStat } from "#app/data/mystery-encounters/mystery-encounter-data"; export type ModifierPredicate = (modifier: Modifier) => boolean; @@ -323,6 +324,109 @@ export abstract class LapsingPersistentModifier extends PersistentModifier { } } +export class LapsingAuraModifier extends LapsingPersistentModifier { + private aura: Aura; + + constructor(type: ModifierTypes.LapsingAuraModifierType, aura: Aura) { + super(type, aura.duration); + this.aura = aura; + } + + clone(): LapsingAuraModifier { + return new LapsingAuraModifier(this.type as ModifierTypes.LapsingAuraModifierType, this.aura); + } + + getArgs(): any[] { + return [this.aura]; + } + + lapse(): boolean { + + return true; + } + + shouldApply(args: any[]): boolean { + return true; + } + + apply(args: any[]): boolean { // args[0] will be an aura + const aura = args[0] as Aura; + //if (pokemon) { // this is for pokemon specific auras + switch (aura.auraType) { + case AuraType.ATK: + case AuraType.DEF: + case AuraType.SPATK: + case AuraType.SPDEF: + case AuraType.ACC: + case AuraType.EVA: // need to deal with EVA since there's no temp version of it + case AuraType.SPD: + case AuraType.CRIT: + const tempBattleStat = args[0] as TempBattleStat; + const auraType = ConvertAuraToBattleStat(this.aura.auraType); + if (auraType >= 0) { + if (tempBattleStat === auraType as TempBattleStat) { + const currentStatLevel = args[1] as Utils.IntegerHolder; + currentStatLevel.value = Math.min(currentStatLevel.value + aura.auraStrength, 6); + return true; + } + + return false; + } + break; + case AuraType.XP: + // do XP stuff + break; + case AuraType.PP: + // do PP stuff + break; + case AuraType.PASSIVE: + //do passive stuff + break; + } + //} + //else { // this is for player/team specific auras + switch (aura.auraType) { + case AuraType.INCOME: + // do income stuff + break; + case AuraType.MONEY: + // do instant money stuff + break; + case AuraType.LUCK: + // do luck stuff + break; + case AuraType.XP: + // do XP stuff + break; + case AuraType.CANDY: + // do instant candy stuff + break; + } + //} + + return true; + + } +} + +export class PersistentAuraModifier extends PersistentModifier { + constructor(type: ModifierType, stackCount?: number) { + super(type, stackCount); + } + + clone(): PersistentAuraModifier { + return new PersistentAuraModifier(this.type, this.stackCount); + } + + apply(args: any[]): boolean { + return true; + } + + getMaxStackCount(): number { // auras don't stack + return 1; + } +} + export class DoubleBattleChanceBoosterModifier extends LapsingPersistentModifier { constructor(type: ModifierTypes.DoubleBattleChanceBoosterModifierType, battlesLeft: integer, stackCount?: integer) { super(type, battlesLeft, stackCount); diff --git a/src/overrides.ts b/src/overrides.ts index e19a5bf20ddd..dca1d47937ce 100644 --- a/src/overrides.ts +++ b/src/overrides.ts @@ -34,22 +34,22 @@ export const SEED_OVERRIDE: string = ""; export const WEATHER_OVERRIDE: WeatherType = WeatherType.NONE; export const DOUBLE_BATTLE_OVERRIDE: boolean = false; export const SINGLE_BATTLE_OVERRIDE: boolean = false; -export const STARTING_WAVE_OVERRIDE: integer = 0; +export const STARTING_WAVE_OVERRIDE: integer = 11; export const STARTING_BIOME_OVERRIDE: Biome = Biome.TOWN; export const ARENA_TINT_OVERRIDE: TimeOfDay = null; // Multiplies XP gained by this value including 0. Set to null to ignore the override -export const XP_MULTIPLIER_OVERRIDE: number = null; +export const XP_MULTIPLIER_OVERRIDE: number = 10; // default 1000 export const STARTING_MONEY_OVERRIDE: integer = 0; export const FREE_CANDY_UPGRADE_OVERRIDE: boolean = false; export const POKEBALL_OVERRIDE: { active: boolean, pokeballs: PokeballCounts } = { - active: false, + active: true, pokeballs: { [PokeballType.POKEBALL]: 5, [PokeballType.GREAT_BALL]: 0, [PokeballType.ULTRA_BALL]: 0, [PokeballType.ROGUE_BALL]: 0, - [PokeballType.MASTER_BALL]: 0, + [PokeballType.MASTER_BALL]: 99, } }; @@ -70,7 +70,7 @@ export const POKEBALL_OVERRIDE: { active: boolean, pokeballs: PokeballCounts } = export const STARTER_FORM_OVERRIDES: Partial> = {}; // default 5 or 20 for Daily -export const STARTING_LEVEL_OVERRIDE: integer = 0; +export const STARTING_LEVEL_OVERRIDE: integer = 100; /** * SPECIES OVERRIDE * will only apply to the first starter in your party or each enemy pokemon @@ -117,9 +117,9 @@ export const EGG_GACHA_PULL_COUNT_OVERRIDE: number = 0; */ // 1 to 256, set to null to ignore -export const MYSTERY_ENCOUNTER_RATE_OVERRIDE: number = null; +export const MYSTERY_ENCOUNTER_RATE_OVERRIDE: number = 0; export const MYSTERY_ENCOUNTER_TIER_OVERRIDE: MysteryEncounterTier = null; -export const MYSTERY_ENCOUNTER_OVERRIDE: MysteryEncounterType = null; +export const MYSTERY_ENCOUNTER_OVERRIDE: MysteryEncounterType = MysteryEncounterType.CHOICE_OF_BALANCE; /** * MODIFIER / ITEM OVERRIDES @@ -142,7 +142,7 @@ interface ModifierOverride { count?: integer type?: TempBattleStat|Stat|Nature|Type|BerryType|SpeciesStatBoosterItem } -export const STARTING_MODIFIER_OVERRIDE: Array = []; +export const STARTING_MODIFIER_OVERRIDE: Array = [{name: "EXP_SHARE", count: 5}]; export const OPP_MODIFIER_OVERRIDE: Array = []; export const STARTING_HELD_ITEMS_OVERRIDE: Array = []; diff --git a/src/phases.ts b/src/phases.ts index f98c914e3207..312cfac165d4 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -976,6 +976,13 @@ export class EncounterPhase extends BattlePhase { } const enemyField = this.scene.getEnemyField(); + const playerField = this.scene.getPlayerField(); + for (let i = 0; i < enemyField.length; i++) { + this.scene.mysteryEncounterAuras.UpdateStats(enemyField[i]); + } + for (let i = 0; i < playerField.length; i++) { + this.scene.mysteryEncounterAuras.UpdateStats(playerField[i]); + } this.scene.tweens.add({ targets: [this.scene.arenaEnemy, this.scene.currentBattle.trainer, enemyField, this.scene.currentBattle?.mysteryEncounter?.introVisuals, this.scene.arenaPlayer, this.scene.trainer].flat(), x: (_target, _key, value, fieldIndex: integer) => fieldIndex < 3 + (enemyField.length) ? value + 300 : value - 300, @@ -2677,6 +2684,8 @@ export class BattleEndPhase extends BattlePhase { } } + this.scene.mysteryEncounterAuras.UpdateAurasDurations(this.scene); + this.scene.updateModifiers().then(() => this.end()); } } @@ -4235,9 +4244,10 @@ export class MoneyRewardPhase extends BattlePhase { this.scene.addMoney(moneyAmount.value); - const userLocale = navigator.language || "en-US"; - const formattedMoneyAmount = moneyAmount.value.toLocaleString(userLocale); - const message = i18next.t("battle:moneyWon", { moneyAmount: formattedMoneyAmount }); + //const userLocale = navigator.language || "en-US"; + //const formattedMoneyAmount = moneyAmount.value.toLocaleString(userLocale); + //const message = i18next.t("battle:moneyWon", { moneyAmount: formattedMoneyAmount }); + const message = this.scene.getFormattedMoneyString(moneyAmount.value); this.scene.ui.showText(message, null, () => this.end(), null, true); } diff --git a/src/plugins/i18n.ts b/src/plugins/i18n.ts index 1b4bfdbb16a5..08010e44c397 100644 --- a/src/plugins/i18n.ts +++ b/src/plugins/i18n.ts @@ -144,6 +144,13 @@ export async function initI18n(): Promise { return `@[MONEY]{₽${numberFormattedString}}`; }); + // Input: {{percentageValue, percent}} - this will be a percentage as a decimal - i.e. 0.2 + // Output: {20%} + i18next.services.formatter.add("percent", (value, lng, options) => { + const percentFormattedString = Intl.NumberFormat(lng, options).format(Math.abs(value) * 100); + return `${percentFormattedString}%`; + }); + await initFonts(); } diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 606d63d70fe8..87be929b0029 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -40,7 +40,7 @@ import { GameDataType } from "#enums/game-data-type"; import { Moves } from "#enums/moves"; import { PlayerGender } from "#enums/player-gender"; import { Species } from "#enums/species"; -import { MysteryEncounterData } from "../data/mystery-encounters/mystery-encounter-data"; +import { MysteryEncounterData, MysteryEncounterAuras /*, AuraType, getAuraName*/ } from "../data/mystery-encounters/mystery-encounter-data"; import IMysteryEncounter from "../data/mystery-encounters/mystery-encounter"; export const defaultStarterSpecies: Species[] = [ @@ -126,6 +126,7 @@ export interface SessionSaveData { challenges: ChallengeData[]; mysteryEncounter: IMysteryEncounter; mysteryEncounterData: MysteryEncounterData; + mysteryEncounterAuras: MysteryEncounterAuras } interface Unlocks { @@ -842,7 +843,8 @@ export class GameData { timestamp: new Date().getTime(), challenges: scene.gameMode.challenges.map(c => new ChallengeData(c)), mysteryEncounter: scene.currentBattle.mysteryEncounter, - mysteryEncounterData: scene.mysteryEncounterData + mysteryEncounterData: scene.mysteryEncounterData, + mysteryEncounterAuras: scene.mysteryEncounterAuras } as SessionSaveData; } @@ -935,6 +937,8 @@ export class GameData { scene.mysteryEncounterData = sessionData?.mysteryEncounterData ? sessionData?.mysteryEncounterData : new MysteryEncounterData(null); + scene.mysteryEncounterAuras = sessionData?.mysteryEncounterAuras ? sessionData?.mysteryEncounterAuras : new MysteryEncounterAuras(); + scene.newArena(sessionData.arena.biome); const battleType = sessionData.battleType || 0; @@ -1162,6 +1166,10 @@ export class GameData { return new MysteryEncounterData(v); } + if (k === "mysteryEncounterAuras") { + return new MysteryEncounterAuras(); + } + return v; }) as SessionSaveData; }