From 74125ef1cfd0db811a2d3e35c0b8cc90f5dffbad Mon Sep 17 00:00:00 2001 From: Felix Staud Date: Thu, 11 Jul 2024 12:56:15 -0700 Subject: [PATCH 01/19] WIP: add option to use dialogues in builder --- .../dialogue/dark-deal-dialogue.ts | 68 +++--- .../encounters/dark-deal.ts | 197 ++++++++++++------ .../mystery-encounter-dialogue.ts | 2 +- .../mystery-encounter-option.ts | 6 + .../mystery-encounters/mystery-encounter.ts | 19 +- src/overrides.ts | 6 +- src/phases.ts | 2 +- src/ui/mystery-encounter-ui-handler.ts | 6 +- 8 files changed, 195 insertions(+), 111 deletions(-) diff --git a/src/data/mystery-encounters/dialogue/dark-deal-dialogue.ts b/src/data/mystery-encounters/dialogue/dark-deal-dialogue.ts index 25b31f79a50..9ee7ce5472b 100644 --- a/src/data/mystery-encounters/dialogue/dark-deal-dialogue.ts +++ b/src/data/mystery-encounters/dialogue/dark-deal-dialogue.ts @@ -1,44 +1,44 @@ import MysteryEncounterDialogue from "#app/data/mystery-encounters/mystery-encounter-dialogue"; export const DarkDealDialogue: MysteryEncounterDialogue = { - intro: [ - { - text: "mysteryEncounter:dark_deal_intro_message" - }, - { - speaker: "mysteryEncounter:dark_deal_speaker", - text: "mysteryEncounter:dark_deal_intro_dialogue" - } - ], + // intro: [ + // { + // text: "mysteryEncounter:dark_deal_intro_message" + // }, + // { + // speaker: "mysteryEncounter:dark_deal_speaker", + // text: "mysteryEncounter:dark_deal_intro_dialogue" + // } + // ], encounterOptionsDialogue: { title: "mysteryEncounter:dark_deal_title", description: "mysteryEncounter:dark_deal_description", query: "mysteryEncounter:dark_deal_query", - options: [ - { - buttonLabel: "mysteryEncounter:dark_deal_option_1_label", - buttonTooltip: "mysteryEncounter:dark_deal_option_1_tooltip", - selected: [ - { - speaker: "mysteryEncounter:dark_deal_speaker", - text: "mysteryEncounter:dark_deal_option_1_selected" - }, - { - text: "mysteryEncounter:dark_deal_option_1_selected_message" - } - ] - }, - { - buttonLabel: "mysteryEncounter:dark_deal_option_2_label", - buttonTooltip: "mysteryEncounter:dark_deal_option_2_tooltip", - selected: [ - { - speaker: "mysteryEncounter:dark_deal_speaker", - text: "mysteryEncounter:dark_deal_option_2_selected" - } - ] - } - ] + // options: [ + // { + // buttonLabel: "mysteryEncounter:dark_deal_option_1_label", + // buttonTooltip: "mysteryEncounter:dark_deal_option_1_tooltip", + // selected: [ + // { + // speaker: "mysteryEncounter:dark_deal_speaker", + // text: "mysteryEncounter:dark_deal_option_1_selected" + // }, + // { + // text: "mysteryEncounter:dark_deal_option_1_selected_message" + // } + // ] + // }, + // { + // buttonLabel: "mysteryEncounter:dark_deal_option_2_label", + // buttonTooltip: "mysteryEncounter:dark_deal_option_2_tooltip", + // selected: [ + // { + // speaker: "mysteryEncounter:dark_deal_speaker", + // text: "mysteryEncounter:dark_deal_option_2_selected" + // } + // ] + // } + // ] }, outro: [ { diff --git a/src/data/mystery-encounters/encounters/dark-deal.ts b/src/data/mystery-encounters/encounters/dark-deal.ts index 1985ffcf8dd..c1651aa8dec 100644 --- a/src/data/mystery-encounters/encounters/dark-deal.ts +++ b/src/data/mystery-encounters/encounters/dark-deal.ts @@ -7,14 +7,18 @@ import BattleScene from "../../../battle-scene"; import { AddPokeballModifierType } from "../../../modifier/modifier-type"; import { PokeballType } from "../../pokeball"; import { getPokemonSpecies } from "../../pokemon-species"; -import MysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier } from "../mystery-encounter"; +import MysteryEncounter, { + MysteryEncounterBuilder, + MysteryEncounterTier, +} from "../mystery-encounter"; import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; import { - EnemyPartyConfig, EnemyPokemonConfig, + EnemyPartyConfig, + EnemyPokemonConfig, getRandomPlayerPokemon, getRandomSpeciesByStarterTier, initBattleWithEnemyConfig, - leaveEncounterWithoutBattle + leaveEncounterWithoutBattle, } from "../mystery-encounter-utils"; // Exclude Ultra Beasts, Paradox, Necrozma, Eternatus, and egg-locked mythicals @@ -63,71 +67,132 @@ const excludedBosses = [ Species.ARCEUS, Species.VICTINI, Species.MELTAN, - Species.PECHARUNT + Species.PECHARUNT, ]; -export const DarkDealEncounter: MysteryEncounter = MysteryEncounterBuilder - .withEncounterType(MysteryEncounterType.DARK_DEAL) - .withEncounterTier(MysteryEncounterTier.ROGUE) - .withIntroSpriteConfigs([ - { - spriteKey: "mad_scientist_m", - fileRoot: "mystery-encounters", - hasShadow: true - }, - { - spriteKey: "dark_deal_porygon", - fileRoot: "mystery-encounters", - hasShadow: true, - repeat: true - } - ]) - .withSceneWaveRangeRequirement(30, 180) // waves 30 to 180 - .withScenePartySizeRequirement(2, 6) // Must have at least 2 pokemon in party - .withCatchAllowed(true) - .withOption(new MysteryEncounterOptionBuilder() - .withPreOptionPhase(async (scene: BattleScene) => { - // Removes random pokemon (including fainted) from party and adds name to dialogue data tokens - // Will never return last battle able mon and instead pick fainted/unable to battle - const removedPokemon = getRandomPlayerPokemon(scene, false, true); - scene.removePokemonFromPlayerParty(removedPokemon); +export const DarkDealEncounter: MysteryEncounter = + MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.DARK_DEAL) + .withEncounterTier(MysteryEncounterTier.ROGUE) + .withIntroSpriteConfigs([ + { + spriteKey: "mad_scientist_m", + fileRoot: "mystery-encounters", + hasShadow: true, + }, + { + spriteKey: "dark_deal_porygon", + fileRoot: "mystery-encounters", + hasShadow: true, + repeat: true, + }, + ]) + .withIntroDialogue([ + { + text: "mysteryEncounter:dark_deal_intro_message", + }, + { + speaker: "mysteryEncounter:dark_deal_speaker", + text: "mysteryEncounter:dark_deal_intro_dialogue", + }, + ]) + .withSceneWaveRangeRequirement(30, 180) // waves 30 to 180 + .withScenePartySizeRequirement(2, 6) // Must have at least 2 pokemon in party + .withCatchAllowed(true) + .withOption( + new MysteryEncounterOptionBuilder() + .withDialogue({ + buttonLabel: "mysteryEncounter:dark_deal_option_1_label", + buttonTooltip: "mysteryEncounter:dark_deal_option_1_tooltip", + selected: [ + { + speaker: "mysteryEncounter:dark_deal_speaker", + text: "mysteryEncounter:dark_deal_option_1_selected", + }, + { + text: "mysteryEncounter:dark_deal_option_1_selected_message", + }, + ], + }) + .withPreOptionPhase(async (scene: BattleScene) => { + // Removes random pokemon (including fainted) from party and adds name to dialogue data tokens + // Will never return last battle able mon and instead pick fainted/unable to battle + const removedPokemon = getRandomPlayerPokemon(scene, false, true); + scene.removePokemonFromPlayerParty(removedPokemon); - scene.currentBattle.mysteryEncounter.setDialogueToken("pokeName", removedPokemon.name); + scene.currentBattle.mysteryEncounter.setDialogueToken( + "pokeName", + removedPokemon.name + ); - // Store removed pokemon types - scene.currentBattle.mysteryEncounter.misc = [removedPokemon.species.type1]; - if (removedPokemon.species.type2) { - scene.currentBattle.mysteryEncounter.misc.push(removedPokemon.species.type2); - } - }) - .withOptionPhase(async (scene: BattleScene) => { - // Give the player 5 Rogue Balls - scene.unshiftPhase(new ModifierRewardPhase(scene, () => new AddPokeballModifierType("rb", PokeballType.ROGUE_BALL, 5))); + // Store removed pokemon types + scene.currentBattle.mysteryEncounter.misc = [ + removedPokemon.species.type1, + ]; + if (removedPokemon.species.type2) { + scene.currentBattle.mysteryEncounter.misc.push( + removedPokemon.species.type2 + ); + } + }) + .withOptionPhase(async (scene: BattleScene) => { + // Give the player 5 Rogue Balls + scene.unshiftPhase( + new ModifierRewardPhase( + scene, + () => + new AddPokeballModifierType("rb", PokeballType.ROGUE_BALL, 5) + ) + ); - // Start encounter with random legendary (7-10 starter strength) that has level additive - const bossTypes = scene.currentBattle.mysteryEncounter.misc as Type[]; - // Starter egg tier, 35/50/10/5 %odds for tiers 6/7/8/9+ - const roll = randSeedInt(100); - const starterTier: number | [number, number] = roll > 65 ? 6 : roll > 15 ? 7 : roll > 5 ? 8 : [9, 10]; - const bossSpecies = getPokemonSpecies(getRandomSpeciesByStarterTier(starterTier, excludedBosses, bossTypes)); - const pokemonConfig: EnemyPokemonConfig = { - species: bossSpecies, - isBoss: true - }; - if (!isNullOrUndefined(bossSpecies.forms) && bossSpecies.forms.length > 0) { - pokemonConfig.formIndex = 0; - } - const config: EnemyPartyConfig = { - levelAdditiveMultiplier: 0.75, - pokemonConfigs: [pokemonConfig] - }; - return initBattleWithEnemyConfig(scene, config); - }) - .build() - ) - .withOptionPhase(async (scene: BattleScene) => { - // Leave encounter with no rewards or exp - leaveEncounterWithoutBattle(scene, true); - return true; - }) - .build(); + // Start encounter with random legendary (7-10 starter strength) that has level additive + const bossTypes = scene.currentBattle.mysteryEncounter.misc as Type[]; + // Starter egg tier, 35/50/10/5 %odds for tiers 6/7/8/9+ + const roll = randSeedInt(100); + const starterTier: number | [number, number] = + roll > 65 ? 6 : roll > 15 ? 7 : roll > 5 ? 8 : [9, 10]; + const bossSpecies = getPokemonSpecies( + getRandomSpeciesByStarterTier( + starterTier, + excludedBosses, + bossTypes + ) + ); + const pokemonConfig: EnemyPokemonConfig = { + species: bossSpecies, + isBoss: true, + }; + if ( + !isNullOrUndefined(bossSpecies.forms) && + bossSpecies.forms.length > 0 + ) { + pokemonConfig.formIndex = 0; + } + const config: EnemyPartyConfig = { + levelAdditiveMultiplier: 0.75, + pokemonConfigs: [pokemonConfig], + }; + return initBattleWithEnemyConfig(scene, config); + }) + .build() + ) + .withOption( + new MysteryEncounterOptionBuilder() + .withDialogue({ + buttonLabel: "mysteryEncounter:dark_deal_option_2_label", + buttonTooltip: "mysteryEncounter:dark_deal_option_2_tooltip", + selected: [ + { + speaker: "mysteryEncounter:dark_deal_speaker", + text: "mysteryEncounter:dark_deal_option_2_selected", + }, + ], + }) + .withOptionPhase(async (scene: BattleScene) => { + // Leave encounter with no rewards or exp + + leaveEncounterWithoutBattle(scene, true); + return true; + }) + .build() + ) + .build(); diff --git a/src/data/mystery-encounters/mystery-encounter-dialogue.ts b/src/data/mystery-encounters/mystery-encounter-dialogue.ts index 1e2dfe85045..7a9427a5d4a 100644 --- a/src/data/mystery-encounters/mystery-encounter-dialogue.ts +++ b/src/data/mystery-encounters/mystery-encounter-dialogue.ts @@ -28,7 +28,7 @@ export class EncounterOptionsDialogue { title: TemplateStringsArray | `mysteryEncounter:${string}`; description: TemplateStringsArray | `mysteryEncounter:${string}`; query?: TemplateStringsArray | `mysteryEncounter:${string}`; - options: [OptionTextDisplay, OptionTextDisplay, ...OptionTextDisplay[]]; // Options array with minimum 2 options + options?: [...OptionTextDisplay[]]; // Options array with minimum 2 options } export default class MysteryEncounterDialogue { diff --git a/src/data/mystery-encounters/mystery-encounter-option.ts b/src/data/mystery-encounters/mystery-encounter-option.ts index f1316ff64f1..2d1b4e5cfb9 100644 --- a/src/data/mystery-encounters/mystery-encounter-option.ts +++ b/src/data/mystery-encounters/mystery-encounter-option.ts @@ -127,6 +127,7 @@ export class MysteryEncounterOptionBuilder implements Partial> { this.requirements.push(requirement); @@ -163,4 +164,9 @@ export class MysteryEncounterOptionBuilder implements Partial o.dialogue = this.dialogue.encounterOptionsDialogue.options[i]); + if (this.dialogue?.encounterOptionsDialogue) { + // this.options.forEach((o, i) => o.dialogue = this.dialogue.encounterOptionsDialogue.options[i]); } // Reset any dirty flags or encounter data @@ -408,9 +410,20 @@ export class MysteryEncounterBuilder implements Partial { * @returns */ withIntroSpriteConfigs(spriteConfigs: MysteryEncounterSpriteConfig[]): this & Pick { + console.debug("with intro sprite configs: ", spriteConfigs); return Object.assign(this, { spriteConfigs: spriteConfigs }); } + withIntroDialogue(dialogue: MysteryEncounterDialogue["intro"] = []): this { + console.debug("with intro dialogue: ", dialogue); + this.dialogue = {...this.dialogue, intro: dialogue }; + return this; + } + + withIntro({spriteConfigs, dialogue} : {spriteConfigs: MysteryEncounterSpriteConfig[], dialogue?: MysteryEncounterDialogue["intro"]}) { + return this.withIntroSpriteConfigs(spriteConfigs).withIntroDialogue(dialogue); + } + /** * OPTIONAL */ diff --git a/src/overrides.ts b/src/overrides.ts index ce706173691..f6a3778c4da 100644 --- a/src/overrides.ts +++ b/src/overrides.ts @@ -35,7 +35,7 @@ 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 = 33; 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 @@ -118,9 +118,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 = 10000; export const MYSTERY_ENCOUNTER_TIER_OVERRIDE: MysteryEncounterTier = null; -export const MYSTERY_ENCOUNTER_OVERRIDE: MysteryEncounterType = null; +export const MYSTERY_ENCOUNTER_OVERRIDE: MysteryEncounterType = MysteryEncounterType.DARK_DEAL; /** * MODIFIER / ITEM OVERRIDES diff --git a/src/phases.ts b/src/phases.ts index 091629b31d5..2233763dc7f 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -828,7 +828,7 @@ export class EncounterPhase extends BattlePhase { if (mysteryEncounter.onInit) { mysteryEncounter.onInit(this.scene); } - mysteryEncounter.populateDialogueTokensFromRequirements(this.scene); + // mysteryEncounter.populateDialogueTokensFromRequirements(this.scene); }, this.scene.currentBattle.waveIndex); // Add intro visuals for mystery encounter diff --git a/src/ui/mystery-encounter-ui-handler.ts b/src/ui/mystery-encounter-ui-handler.ts index 163d79784f8..7be7f16e8bc 100644 --- a/src/ui/mystery-encounter-ui-handler.ts +++ b/src/ui/mystery-encounter-ui-handler.ts @@ -319,13 +319,13 @@ export default class MysteryEncounterUiHandler extends UiHandler { optionText = addBBCodeTextObject(this.scene, i % 2 === 0 ? 0 : 100, i < 2 ? 0 : 16, "-", TextStyle.WINDOW, { wordWrap: { width: 558 }, fontSize: "80px", lineSpacing: -8 }); break; } - const option = mysteryEncounter.dialogue.encounterOptionsDialogue.options[i]; - const text = getEncounterText(this.scene, option.buttonLabel, option.style ? option.style : TextStyle.WINDOW); + const option = this.filteredEncounterOptions[i]; + const text = getEncounterText(this.scene, option.dialogue?.buttonLabel, option.dialogue?.style ? option.dialogue?.style : TextStyle.WINDOW); if (text) { optionText.setText(text); } - this.optionsMeetsReqs.push(this.filteredEncounterOptions[i].meetsRequirements(this.scene)); + this.optionsMeetsReqs.push(option.meetsRequirements(this.scene)); if (!this.optionsMeetsReqs[i]) { optionText.setAlpha(0.5); From c589689a6c067189f22b918e91a82f1914ac2045 Mon Sep 17 00:00:00 2001 From: Felix Staud Date: Thu, 11 Jul 2024 13:26:21 -0700 Subject: [PATCH 02/19] migrate dark-deal encounter to new dialogue setup --- .../dialogue/dark-deal-dialogue.ts | 48 ------------- .../encounters/dark-deal.ts | 42 +++++++----- .../encounters/department-store-sale.ts | 8 +-- .../encounters/fight-or-flight.ts | 4 +- .../encounters/mysterious-challengers.ts | 6 +- .../encounters/mysterious-chest.ts | 2 +- .../encounters/shady-vitamin-dealer.ts | 2 +- .../encounters/sleeping-snorlax.ts | 4 +- .../mystery-encounter-dialogue.ts | 8 +-- .../mystery-encounters/mystery-encounter.ts | 68 ++++++++++++++++--- src/ui/mystery-encounter-ui-handler.ts | 11 +-- 11 files changed, 104 insertions(+), 99 deletions(-) delete mode 100644 src/data/mystery-encounters/dialogue/dark-deal-dialogue.ts diff --git a/src/data/mystery-encounters/dialogue/dark-deal-dialogue.ts b/src/data/mystery-encounters/dialogue/dark-deal-dialogue.ts deleted file mode 100644 index 9ee7ce5472b..00000000000 --- a/src/data/mystery-encounters/dialogue/dark-deal-dialogue.ts +++ /dev/null @@ -1,48 +0,0 @@ -import MysteryEncounterDialogue from "#app/data/mystery-encounters/mystery-encounter-dialogue"; - -export const DarkDealDialogue: MysteryEncounterDialogue = { - // intro: [ - // { - // text: "mysteryEncounter:dark_deal_intro_message" - // }, - // { - // speaker: "mysteryEncounter:dark_deal_speaker", - // text: "mysteryEncounter:dark_deal_intro_dialogue" - // } - // ], - encounterOptionsDialogue: { - title: "mysteryEncounter:dark_deal_title", - description: "mysteryEncounter:dark_deal_description", - query: "mysteryEncounter:dark_deal_query", - // options: [ - // { - // buttonLabel: "mysteryEncounter:dark_deal_option_1_label", - // buttonTooltip: "mysteryEncounter:dark_deal_option_1_tooltip", - // selected: [ - // { - // speaker: "mysteryEncounter:dark_deal_speaker", - // text: "mysteryEncounter:dark_deal_option_1_selected" - // }, - // { - // text: "mysteryEncounter:dark_deal_option_1_selected_message" - // } - // ] - // }, - // { - // buttonLabel: "mysteryEncounter:dark_deal_option_2_label", - // buttonTooltip: "mysteryEncounter:dark_deal_option_2_tooltip", - // selected: [ - // { - // speaker: "mysteryEncounter:dark_deal_speaker", - // text: "mysteryEncounter:dark_deal_option_2_selected" - // } - // ] - // } - // ] - }, - outro: [ - { - text: "mysteryEncounter:dark_deal_outro" - } - ] -}; diff --git a/src/data/mystery-encounters/encounters/dark-deal.ts b/src/data/mystery-encounters/encounters/dark-deal.ts index c1651aa8dec..740c4e86c28 100644 --- a/src/data/mystery-encounters/encounters/dark-deal.ts +++ b/src/data/mystery-encounters/encounters/dark-deal.ts @@ -98,6 +98,9 @@ export const DarkDealEncounter: MysteryEncounter = .withSceneWaveRangeRequirement(30, 180) // waves 30 to 180 .withScenePartySizeRequirement(2, 6) // Must have at least 2 pokemon in party .withCatchAllowed(true) + .withTitle("mysteryEncounter:dark_deal_title") + .withDescription("mysteryEncounter:dark_deal_description") + .withQuery("mysteryEncounter:dark_deal_query") .withOption( new MysteryEncounterOptionBuilder() .withDialogue({ @@ -175,24 +178,27 @@ export const DarkDealEncounter: MysteryEncounter = }) .build() ) - .withOption( - new MysteryEncounterOptionBuilder() - .withDialogue({ - buttonLabel: "mysteryEncounter:dark_deal_option_2_label", - buttonTooltip: "mysteryEncounter:dark_deal_option_2_tooltip", - selected: [ - { - speaker: "mysteryEncounter:dark_deal_speaker", - text: "mysteryEncounter:dark_deal_option_2_selected", - }, - ], - }) - .withOptionPhase(async (scene: BattleScene) => { - // Leave encounter with no rewards or exp + .withSimpleOption( + { + buttonLabel: "mysteryEncounter:dark_deal_option_2_label", + buttonTooltip: "mysteryEncounter:dark_deal_option_2_tooltip", + selected: [ + { + speaker: "mysteryEncounter:dark_deal_speaker", + text: "mysteryEncounter:dark_deal_option_2_selected", + }, + ], + }, + async (scene: BattleScene) => { + // Leave encounter with no rewards or exp - leaveEncounterWithoutBattle(scene, true); - return true; - }) - .build() + leaveEncounterWithoutBattle(scene, true); + return true; + } ) + .withOutroDialogue([ + { + text: "mysteryEncounter:dark_deal_outro" + } + ]) .build(); diff --git a/src/data/mystery-encounters/encounters/department-store-sale.ts b/src/data/mystery-encounters/encounters/department-store-sale.ts index 19269a774f3..4323fc15434 100644 --- a/src/data/mystery-encounters/encounters/department-store-sale.ts +++ b/src/data/mystery-encounters/encounters/department-store-sale.ts @@ -29,7 +29,7 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter = MysteryEncounterBu ]) // .withHideIntroVisuals(false) .withSceneWaveRangeRequirement(10, 100) - .withOptionPhase(async (scene: BattleScene) => { + .withSimpleOption(async (scene: BattleScene) => { // Choose TMs const modifiers = []; let i = 0; @@ -49,7 +49,7 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter = MysteryEncounterBu setEncounterRewards(scene, { guaranteedModifierTypeFuncs: modifiers, fillRemaining: false }); leaveEncounterWithoutBattle(scene); }) - .withOptionPhase(async (scene: BattleScene) => { + .withSimpleOption(async (scene: BattleScene) => { // Choose Vitamins const modifiers = []; let i = 0; @@ -67,7 +67,7 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter = MysteryEncounterBu setEncounterRewards(scene, { guaranteedModifierTypeFuncs: modifiers, fillRemaining: false }); leaveEncounterWithoutBattle(scene); }) - .withOptionPhase(async (scene: BattleScene) => { + .withSimpleOption(async (scene: BattleScene) => { // Choose X Items const modifiers = []; let i = 0; @@ -85,7 +85,7 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter = MysteryEncounterBu setEncounterRewards(scene, { guaranteedModifierTypeFuncs: modifiers, fillRemaining: false }); leaveEncounterWithoutBattle(scene); }) - .withOptionPhase(async (scene: BattleScene) => { + .withSimpleOption(async (scene: BattleScene) => { // Choose Pokeballs const modifiers = []; let i = 0; diff --git a/src/data/mystery-encounters/encounters/fight-or-flight.ts b/src/data/mystery-encounters/encounters/fight-or-flight.ts index 8a82439772c..2a362eaed37 100644 --- a/src/data/mystery-encounters/encounters/fight-or-flight.ts +++ b/src/data/mystery-encounters/encounters/fight-or-flight.ts @@ -83,7 +83,7 @@ export const FightOrFlightEncounter: MysteryEncounter = MysteryEncounterBuilder return true; }) - .withOptionPhase(async (scene: BattleScene) => { + .withSimpleOption(async (scene: BattleScene) => { // Pick battle const item = scene.currentBattle.mysteryEncounter.misc as ModifierTypeOption; setEncounterRewards(scene, { guaranteedModifierTypeOptions: [item], fillRemaining: false }); @@ -127,7 +127,7 @@ export const FightOrFlightEncounter: MysteryEncounter = MysteryEncounterBuilder } }) .build()) - .withOptionPhase(async (scene: BattleScene) => { + .withSimpleOption(async (scene: BattleScene) => { // Leave encounter with no rewards or exp leaveEncounterWithoutBattle(scene, true); return true; diff --git a/src/data/mystery-encounters/encounters/mysterious-challengers.ts b/src/data/mystery-encounters/encounters/mysterious-challengers.ts index 880c7be4ca2..db794c58e9f 100644 --- a/src/data/mystery-encounters/encounters/mysterious-challengers.ts +++ b/src/data/mystery-encounters/encounters/mysterious-challengers.ts @@ -95,7 +95,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = MysteryEncounter return true; }) - .withOptionPhase(async (scene: BattleScene) => { + .withSimpleOption(async (scene: BattleScene) => { const encounter = scene.currentBattle.mysteryEncounter; // Spawn standard trainer battle with memory mushroom reward const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0]; @@ -109,7 +109,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = MysteryEncounter }, scene.currentBattle.waveIndex * 10); return ret; }) - .withOptionPhase(async (scene: BattleScene) => { + .withSimpleOption(async (scene: BattleScene) => { const encounter = scene.currentBattle.mysteryEncounter; // Spawn hard fight with ULTRA/GREAT reward (can improve with luck) const config: EnemyPartyConfig = encounter.enemyPartyConfigs[1]; @@ -123,7 +123,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = MysteryEncounter }, scene.currentBattle.waveIndex * 100); return ret; }) - .withOptionPhase(async (scene: BattleScene) => { + .withSimpleOption(async (scene: BattleScene) => { const encounter = scene.currentBattle.mysteryEncounter; // Spawn brutal fight with ROGUE/ULTRA/GREAT reward (can improve with luck) const config: EnemyPartyConfig = encounter.enemyPartyConfigs[2]; diff --git a/src/data/mystery-encounters/encounters/mysterious-chest.ts b/src/data/mystery-encounters/encounters/mysterious-chest.ts index 5e572131562..69ae93f312f 100644 --- a/src/data/mystery-encounters/encounters/mysterious-chest.ts +++ b/src/data/mystery-encounters/encounters/mysterious-chest.ts @@ -85,7 +85,7 @@ export const MysteriousChestEncounter: MysteryEncounter = MysteryEncounterBuilde }) .build() ) - .withOptionPhase(async (scene: BattleScene) => { + .withSimpleOption(async (scene: BattleScene) => { // Leave encounter with no rewards or exp leaveEncounterWithoutBattle(scene, true); return true; diff --git a/src/data/mystery-encounters/encounters/shady-vitamin-dealer.ts b/src/data/mystery-encounters/encounters/shady-vitamin-dealer.ts index 21e1b199e04..6ab668d73a6 100644 --- a/src/data/mystery-encounters/encounters/shady-vitamin-dealer.ts +++ b/src/data/mystery-encounters/encounters/shady-vitamin-dealer.ts @@ -186,7 +186,7 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter = MysteryEncounterBui chosenPokemon.updateInfo(); }) .build()) - .withOptionPhase(async (scene: BattleScene) => { + .withSimpleOption(async (scene: BattleScene) => { // Leave encounter with no rewards or exp leaveEncounterWithoutBattle(scene, true); return true; diff --git a/src/data/mystery-encounters/encounters/sleeping-snorlax.ts b/src/data/mystery-encounters/encounters/sleeping-snorlax.ts index 444ce5a6581..6a820812ae1 100644 --- a/src/data/mystery-encounters/encounters/sleeping-snorlax.ts +++ b/src/data/mystery-encounters/encounters/sleeping-snorlax.ts @@ -55,13 +55,13 @@ export const SleepingSnorlaxEncounter: MysteryEncounter = MysteryEncounterBuilde encounter.enemyPartyConfigs = [config]; return true; }) - .withOptionPhase(async (scene: BattleScene) => { + .withSimpleOption(async (scene: BattleScene) => { // Pick battle // TODO: do we want special rewards for this? // setCustomEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.LEFTOVERS], fillRemaining: true}); await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0]); }) - .withOptionPhase(async (scene: BattleScene) => { + .withSimpleOption(async (scene: BattleScene) => { const instance = scene.currentBattle.mysteryEncounter; let roll: integer; scene.executeWithSeedOffset(() => { diff --git a/src/data/mystery-encounters/mystery-encounter-dialogue.ts b/src/data/mystery-encounters/mystery-encounter-dialogue.ts index c0eb3fdfec7..11135a58085 100644 --- a/src/data/mystery-encounters/mystery-encounter-dialogue.ts +++ b/src/data/mystery-encounters/mystery-encounter-dialogue.ts @@ -1,7 +1,6 @@ import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteriousChallengersDialogue } from "#app/data/mystery-encounters/dialogue/mysterious-challengers-dialogue"; import { MysteriousChestDialogue } from "#app/data/mystery-encounters/dialogue/mysterious-chest-dialogue"; -import { DarkDealDialogue } from "#app/data/mystery-encounters/dialogue/dark-deal-dialogue"; import { FightOrFlightDialogue } from "#app/data/mystery-encounters/dialogue/fight-or-flight-dialogue"; import { TrainingSessionDialogue } from "#app/data/mystery-encounters/dialogue/training-session-dialogue"; import { SleepingSnorlaxDialogue } from "./dialogue/sleeping-snorlax-dialogue"; @@ -26,15 +25,15 @@ export class OptionTextDisplay { } export class EncounterOptionsDialogue { - title: TemplateStringsArray | `mysteryEncounter:${string}`; - description: TemplateStringsArray | `mysteryEncounter:${string}`; + title?: TemplateStringsArray | `mysteryEncounter:${string}`; + description?: TemplateStringsArray | `mysteryEncounter:${string}`; query?: TemplateStringsArray | `mysteryEncounter:${string}`; options?: [...OptionTextDisplay[]]; // Options array with minimum 2 options } export default class MysteryEncounterDialogue { intro?: TextDisplay[]; - encounterOptionsDialogue: EncounterOptionsDialogue; + encounterOptionsDialogue?: EncounterOptionsDialogue; outro?: TextDisplay[]; } @@ -87,7 +86,6 @@ export const allMysteryEncounterDialogue: { [encounterType: number]: MysteryEnco export function initMysteryEncounterDialogue() { allMysteryEncounterDialogue[MysteryEncounterType.MYSTERIOUS_CHALLENGERS] = MysteriousChallengersDialogue; allMysteryEncounterDialogue[MysteryEncounterType.MYSTERIOUS_CHEST] = MysteriousChestDialogue; - allMysteryEncounterDialogue[MysteryEncounterType.DARK_DEAL] = DarkDealDialogue; allMysteryEncounterDialogue[MysteryEncounterType.FIGHT_OR_FLIGHT] = FightOrFlightDialogue; allMysteryEncounterDialogue[MysteryEncounterType.TRAINING_SESSION] = TrainingSessionDialogue; allMysteryEncounterDialogue[MysteryEncounterType.SLEEPING_SNORLAX] = SleepingSnorlaxDialogue; diff --git a/src/data/mystery-encounters/mystery-encounter.ts b/src/data/mystery-encounters/mystery-encounter.ts index 6c8c0b4381d..0780aa33ae4 100644 --- a/src/data/mystery-encounters/mystery-encounter.ts +++ b/src/data/mystery-encounters/mystery-encounter.ts @@ -7,7 +7,8 @@ import MysteryEncounterIntroVisuals, { MysteryEncounterSpriteConfig } from "../. import * as Utils from "../../utils"; import { StatusEffect } from "../status-effect"; import MysteryEncounterDialogue, { - allMysteryEncounterDialogue + allMysteryEncounterDialogue, + OptionTextDisplay } from "./mystery-encounter-dialogue"; import MysteryEncounterOption, { MysteryEncounterOptionBuilder, OptionPhaseCallback } from "./mystery-encounter-option"; import { @@ -136,9 +137,7 @@ export default class MysteryEncounter implements MysteryEncounter { Object.assign(this, encounter); } this.encounterTier = this.encounterTier ? this.encounterTier : MysteryEncounterTier.COMMON; - this.dialogue = Object.assign((this.dialogue ?? {}), allMysteryEncounterDialogue[this.encounterType]); - // this.dialogue = allMysteryEncounterDialogue[this.encounterType]; - console.log(`${MysteryEncounterType[encounter.encounterType]} Encounter Dialogue:`, this.dialogue); + this.dialogue = Object.assign((this.dialogue ?? {}), allMysteryEncounterDialogue[this.encounterType] ?? {}); this.encounterVariant = MysteryEncounterVariant.DEFAULT; this.requirements = this.requirements ? this.requirements : []; this.hideBattleIntroMessage = !isNullOrUndefined(this.hideBattleIntroMessage) ? this.hideBattleIntroMessage : false; @@ -399,11 +398,12 @@ export class MysteryEncounterBuilder implements Partial { * Adds a streamlined option phase. * Only use if no pre-/post-options or condtions necessary. * - * @param callback - OptionPhaseCallback + * @param dialogue - {@linkcode OptionTextDisplay} + * @param callback - {@linkcode OptionPhaseCallback} * @returns */ - withOptionPhase(callback: OptionPhaseCallback) { - return this.withOption(new MysteryEncounterOptionBuilder().withOptionPhase(callback).build()); + withSimpleOption(dialogue: OptionTextDisplay, callback: OptionPhaseCallback) { + return this.withOption(new MysteryEncounterOptionBuilder().withDialogue(dialogue).withOptionPhase(callback).build()); } /** @@ -413,12 +413,10 @@ export class MysteryEncounterBuilder implements Partial { * @returns */ withIntroSpriteConfigs(spriteConfigs: MysteryEncounterSpriteConfig[]): this & Pick { - console.debug("with intro sprite configs: ", spriteConfigs); return Object.assign(this, { spriteConfigs: spriteConfigs }); } - withIntroDialogue(dialogue: MysteryEncounterDialogue["intro"] = []): this { - console.debug("with intro dialogue: ", dialogue); + withIntroDialogue(dialogue: MysteryEncounterDialogue["intro"] = []) { this.dialogue = {...this.dialogue, intro: dialogue }; return this; } @@ -581,6 +579,56 @@ export class MysteryEncounterBuilder implements Partial { return Object.assign(this, { hideIntroVisuals: hideIntroVisuals }); } + withTitle(title: TemplateStringsArray | `mysteryEncounter:${string}`) { + const dialogue = this.dialogue ?? {}; + const encounterOptionsDialogue = this.dialogue?.encounterOptionsDialogue ?? {}; + + this.dialogue = { + ...dialogue, + encounterOptionsDialogue: { + ...encounterOptionsDialogue, + title, + } + }; + + return this; + } + + withDescription(description: TemplateStringsArray | `mysteryEncounter:${string}`) { + const dialogue = this.dialogue ?? {}; + const encounterOptionsDialogue = this.dialogue?.encounterOptionsDialogue ?? {}; + + this.dialogue = { + ...dialogue, + encounterOptionsDialogue: { + ...encounterOptionsDialogue, + description, + } + }; + + return this; + } + + withQuery(query: TemplateStringsArray | `mysteryEncounter:${string}`) { + const dialogue = this.dialogue ?? {}; + const encounterOptionsDialogue = this.dialogue?.encounterOptionsDialogue ?? {}; + + this.dialogue = { + ...dialogue, + encounterOptionsDialogue: { + ...encounterOptionsDialogue, + query, + } + }; + + return this; + } + + withOutroDialogue(dialogue: MysteryEncounterDialogue["outro"] = []) { + this.dialogue = {...this.dialogue, outro: dialogue }; + return this; + } + build(this: MysteryEncounter) { return new MysteryEncounter(this); } diff --git a/src/ui/mystery-encounter-ui-handler.ts b/src/ui/mystery-encounter-ui-handler.ts index 5c0ceac4964..c446481b744 100644 --- a/src/ui/mystery-encounter-ui-handler.ts +++ b/src/ui/mystery-encounter-ui-handler.ts @@ -424,12 +424,13 @@ export default class MysteryEncounterUiHandler extends UiHandler { } const mysteryEncounter = this.scene.currentBattle.mysteryEncounter; - let text; - const option = mysteryEncounter.dialogue.encounterOptionsDialogue.options[cursor]; - if (!this.optionsMeetsReqs[cursor] && this.filteredEncounterOptions[cursor].isDisabledOnRequirementsNotMet && option.disabledTooltip) { - text = getEncounterText(this.scene, option.disabledTooltip, TextStyle.TOOLTIP_CONTENT); + let text: string; + const option = this.filteredEncounterOptions[cursor]; + const optionDialogue = option.dialogue ?? mysteryEncounter.dialogue.encounterOptionsDialogue.options[cursor]; + if (!this.optionsMeetsReqs[cursor] && this.filteredEncounterOptions[cursor].isDisabledOnRequirementsNotMet && optionDialogue.disabledTooltip) { + text = getEncounterText(this.scene, optionDialogue.disabledTooltip, TextStyle.TOOLTIP_CONTENT); } else { - text = getEncounterText(this.scene, option.buttonTooltip, TextStyle.TOOLTIP_CONTENT); + text = getEncounterText(this.scene, optionDialogue.buttonTooltip, TextStyle.TOOLTIP_CONTENT); } // Auto-color options green/blue for good/bad by looking for (+)/(-) From d9e0957d409828895abe2f52a09dd992440b4519 Mon Sep 17 00:00:00 2001 From: Felix Staud Date: Thu, 11 Jul 2024 13:35:46 -0700 Subject: [PATCH 03/19] migrate department-store-sale encounter --- .../department-store-sale-dialogue.ts | 36 --- .../encounters/dark-deal.ts | 35 +-- .../encounters/department-store-sale.ts | 242 +++++++++++------- .../mystery-encounter-dialogue.ts | 2 - 4 files changed, 168 insertions(+), 147 deletions(-) delete mode 100644 src/data/mystery-encounters/dialogue/department-store-sale-dialogue.ts diff --git a/src/data/mystery-encounters/dialogue/department-store-sale-dialogue.ts b/src/data/mystery-encounters/dialogue/department-store-sale-dialogue.ts deleted file mode 100644 index 87cd8dbda55..00000000000 --- a/src/data/mystery-encounters/dialogue/department-store-sale-dialogue.ts +++ /dev/null @@ -1,36 +0,0 @@ -import MysteryEncounterDialogue from "#app/data/mystery-encounters/mystery-encounter-dialogue"; - -export const DepartmentStoreSaleDialogue: MysteryEncounterDialogue = { - intro: [ - { - text: "mysteryEncounter:department_store_sale_intro_message" - }, - { - text: "mysteryEncounter:department_store_sale_intro_dialogue", - speaker: "mysteryEncounter:department_store_sale_speaker" - } - ], - encounterOptionsDialogue: { - title: "mysteryEncounter:department_store_sale_title", - description: "mysteryEncounter:department_store_sale_description", - query: "mysteryEncounter:department_store_sale_query", - options: [ - { - buttonLabel: "mysteryEncounter:department_store_sale_option_1_label", - buttonTooltip: "mysteryEncounter:department_store_sale_option_1_tooltip" - }, - { - buttonLabel: "mysteryEncounter:department_store_sale_option_2_label", - buttonTooltip: "mysteryEncounter:department_store_sale_option_2_tooltip" - }, - { - buttonLabel: "mysteryEncounter:department_store_sale_option_3_label", - buttonTooltip: "mysteryEncounter:department_store_sale_option_3_tooltip" - }, - { - buttonLabel: "mysteryEncounter:department_store_sale_option_4_label", - buttonTooltip: "mysteryEncounter:department_store_sale_option_4_tooltip" - } - ] - } -}; diff --git a/src/data/mystery-encounters/encounters/dark-deal.ts b/src/data/mystery-encounters/encounters/dark-deal.ts index 740c4e86c28..8f13e373e9a 100644 --- a/src/data/mystery-encounters/encounters/dark-deal.ts +++ b/src/data/mystery-encounters/encounters/dark-deal.ts @@ -21,6 +21,9 @@ import { leaveEncounterWithoutBattle, } from "../mystery-encounter-utils"; +/** i18n namespace for encounter */ +const namespace = "mysteryEncounter:dark_deal"; + // Exclude Ultra Beasts, Paradox, Necrozma, Eternatus, and egg-locked mythicals const excludedBosses = [ Species.NECROZMA, @@ -88,31 +91,31 @@ export const DarkDealEncounter: MysteryEncounter = ]) .withIntroDialogue([ { - text: "mysteryEncounter:dark_deal_intro_message", + text: `${namespace}_intro_message`, }, { - speaker: "mysteryEncounter:dark_deal_speaker", - text: "mysteryEncounter:dark_deal_intro_dialogue", + speaker: `${namespace}_speaker`, + text: `${namespace}_intro_dialogue`, }, ]) .withSceneWaveRangeRequirement(30, 180) // waves 30 to 180 .withScenePartySizeRequirement(2, 6) // Must have at least 2 pokemon in party .withCatchAllowed(true) - .withTitle("mysteryEncounter:dark_deal_title") - .withDescription("mysteryEncounter:dark_deal_description") - .withQuery("mysteryEncounter:dark_deal_query") + .withTitle(`${namespace}_title`) + .withDescription(`${namespace}_description`) + .withQuery(`${namespace}_query`) .withOption( new MysteryEncounterOptionBuilder() .withDialogue({ - buttonLabel: "mysteryEncounter:dark_deal_option_1_label", - buttonTooltip: "mysteryEncounter:dark_deal_option_1_tooltip", + buttonLabel: `${namespace}_option_1_label`, + buttonTooltip: `${namespace}_option_1_tooltip`, selected: [ { - speaker: "mysteryEncounter:dark_deal_speaker", - text: "mysteryEncounter:dark_deal_option_1_selected", + speaker: `${namespace}_speaker`, + text: `${namespace}_option_1_selected`, }, { - text: "mysteryEncounter:dark_deal_option_1_selected_message", + text: `${namespace}_option_1_selected_message`, }, ], }) @@ -180,12 +183,12 @@ export const DarkDealEncounter: MysteryEncounter = ) .withSimpleOption( { - buttonLabel: "mysteryEncounter:dark_deal_option_2_label", - buttonTooltip: "mysteryEncounter:dark_deal_option_2_tooltip", + buttonLabel: `${namespace}_option_2_label`, + buttonTooltip: `${namespace}_option_2_tooltip`, selected: [ { - speaker: "mysteryEncounter:dark_deal_speaker", - text: "mysteryEncounter:dark_deal_option_2_selected", + speaker: `${namespace}_speaker`, + text: `${namespace}_option_2_selected`, }, ], }, @@ -198,7 +201,7 @@ export const DarkDealEncounter: MysteryEncounter = ) .withOutroDialogue([ { - text: "mysteryEncounter:dark_deal_outro" + text: `${namespace}_outro` } ]) .build(); diff --git a/src/data/mystery-encounters/encounters/department-store-sale.ts b/src/data/mystery-encounters/encounters/department-store-sale.ts index 4323fc15434..2dcee4455df 100644 --- a/src/data/mystery-encounters/encounters/department-store-sale.ts +++ b/src/data/mystery-encounters/encounters/department-store-sale.ts @@ -7,104 +7,160 @@ import { randSeedInt } from "#app/utils"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { Species } from "#enums/species"; import BattleScene from "../../../battle-scene"; -import MysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier } from "../mystery-encounter"; +import MysteryEncounter, { + MysteryEncounterBuilder, + MysteryEncounterTier, +} from "../mystery-encounter"; -export const DepartmentStoreSaleEncounter: MysteryEncounter = MysteryEncounterBuilder - .withEncounterType(MysteryEncounterType.DEPARTMENT_STORE_SALE) - .withEncounterTier(MysteryEncounterTier.COMMON) - .withIntroSpriteConfigs([ - { - spriteKey: "b2w2_lady", - fileRoot: "mystery-encounters", - hasShadow: true, - x: -20 - }, - { - spriteKey: Species.FURFROU.toString(), - fileRoot: "pokemon", - hasShadow: true, - repeat: true, - x: 30 - } - ]) - // .withHideIntroVisuals(false) - .withSceneWaveRangeRequirement(10, 100) - .withSimpleOption(async (scene: BattleScene) => { - // Choose TMs - const modifiers = []; - let i = 0; - while (i < 4) { - // 2/2/1 weight on TM rarity - const roll = randSeedInt(5); - if (roll < 2) { - modifiers.push(modifierTypes.TM_COMMON); - } else if (roll < 4) { - modifiers.push(modifierTypes.TM_GREAT); - } else { - modifiers.push(modifierTypes.TM_ULTRA); +/** i18n namespace for encounter */ +const namespace = "mysteryEncounter:department_store_sale"; + +export const DepartmentStoreSaleEncounter: MysteryEncounter = + MysteryEncounterBuilder.withEncounterType( + MysteryEncounterType.DEPARTMENT_STORE_SALE + ) + .withEncounterTier(MysteryEncounterTier.COMMON) + .withSceneWaveRangeRequirement(10, 100) + .withIntroSpriteConfigs([ + { + spriteKey: "b2w2_lady", + fileRoot: "mystery-encounters", + hasShadow: true, + x: -20, + }, + { + spriteKey: Species.FURFROU.toString(), + fileRoot: "pokemon", + hasShadow: true, + repeat: true, + x: 30, + }, + ]) + .withIntroDialogue([ + { + text: `${namespace}_intro_message`, + }, + { + text: `${namespace}_intro_dialogue`, + speaker: `${namespace}_speaker`, + }, + ]) + // .withHideIntroVisuals(false) + .withTitle(`${namespace}_title`) + .withDescription(`${namespace}_description`) + .withQuery(`${namespace}_query`) + .withSimpleOption( + { + buttonLabel: `${namespace}_option_1_label`, + buttonTooltip: `${namespace}_option_1_tooltip`, + }, + async (scene: BattleScene) => { + // Choose TMs + const modifiers = []; + let i = 0; + while (i < 4) { + // 2/2/1 weight on TM rarity + const roll = randSeedInt(5); + if (roll < 2) { + modifiers.push(modifierTypes.TM_COMMON); + } else if (roll < 4) { + modifiers.push(modifierTypes.TM_GREAT); + } else { + modifiers.push(modifierTypes.TM_ULTRA); + } + i++; + } + + setEncounterRewards(scene, { + guaranteedModifierTypeFuncs: modifiers, + fillRemaining: false, + }); + leaveEncounterWithoutBattle(scene); } - i++; - } + ) + .withSimpleOption( + { + buttonLabel: `${namespace}_option_2_label`, + buttonTooltip: `${namespace}_option_2_tooltip`, + }, + async (scene: BattleScene) => { + // Choose Vitamins + const modifiers = []; + let i = 0; + while (i < 3) { + // 2/1 weight on base stat booster vs PP Up + const roll = randSeedInt(3); + if (roll === 0) { + modifiers.push(modifierTypes.PP_UP); + } else { + modifiers.push(modifierTypes.BASE_STAT_BOOSTER); + } + i++; + } - setEncounterRewards(scene, { guaranteedModifierTypeFuncs: modifiers, fillRemaining: false }); - leaveEncounterWithoutBattle(scene); - }) - .withSimpleOption(async (scene: BattleScene) => { - // Choose Vitamins - const modifiers = []; - let i = 0; - while (i < 3) { - // 2/1 weight on base stat booster vs PP Up - const roll = randSeedInt(3); - if (roll === 0) { - modifiers.push(modifierTypes.PP_UP); - } else { - modifiers.push(modifierTypes.BASE_STAT_BOOSTER); + setEncounterRewards(scene, { + guaranteedModifierTypeFuncs: modifiers, + fillRemaining: false, + }); + leaveEncounterWithoutBattle(scene); } - i++; - } + ) + .withSimpleOption( + { + buttonLabel: `${namespace}_option_3_label`, + buttonTooltip: `${namespace}_option_3_tooltip`, + }, + async (scene: BattleScene) => { + // Choose X Items + const modifiers = []; + let i = 0; + while (i < 5) { + // 4/1 weight on base stat booster vs Dire Hit + const roll = randSeedInt(5); + if (roll === 0) { + modifiers.push(modifierTypes.DIRE_HIT); + } else { + modifiers.push(modifierTypes.TEMP_STAT_BOOSTER); + } + i++; + } - setEncounterRewards(scene, { guaranteedModifierTypeFuncs: modifiers, fillRemaining: false }); - leaveEncounterWithoutBattle(scene); - }) - .withSimpleOption(async (scene: BattleScene) => { - // Choose X Items - const modifiers = []; - let i = 0; - while (i < 5) { - // 4/1 weight on base stat booster vs Dire Hit - const roll = randSeedInt(5); - if (roll === 0) { - modifiers.push(modifierTypes.DIRE_HIT); - } else { - modifiers.push(modifierTypes.TEMP_STAT_BOOSTER); + setEncounterRewards(scene, { + guaranteedModifierTypeFuncs: modifiers, + fillRemaining: false, + }); + leaveEncounterWithoutBattle(scene); } - i++; - } + ) + .withSimpleOption( + { + buttonLabel: `${namespace}_option_4_label`, + buttonTooltip: `${namespace}_option_4_tooltip`, + }, + async (scene: BattleScene) => { + // Choose Pokeballs + const modifiers = []; + let i = 0; + while (i < 4) { + // 10/30/20/5 weight on pokeballs + const roll = randSeedInt(65); + if (roll < 10) { + modifiers.push(modifierTypes.POKEBALL); + } else if (roll < 40) { + modifiers.push(modifierTypes.GREAT_BALL); + } else if (roll < 60) { + modifiers.push(modifierTypes.ULTRA_BALL); + } else { + modifiers.push(modifierTypes.ROGUE_BALL); + } + i++; + } - setEncounterRewards(scene, { guaranteedModifierTypeFuncs: modifiers, fillRemaining: false }); - leaveEncounterWithoutBattle(scene); - }) - .withSimpleOption(async (scene: BattleScene) => { - // Choose Pokeballs - const modifiers = []; - let i = 0; - while (i < 4) { - // 10/30/20/5 weight on pokeballs - const roll = randSeedInt(65); - if (roll < 10) { - modifiers.push(modifierTypes.POKEBALL); - } else if (roll < 40) { - modifiers.push(modifierTypes.GREAT_BALL); - } else if (roll < 60) { - modifiers.push(modifierTypes.ULTRA_BALL); - } else { - modifiers.push(modifierTypes.ROGUE_BALL); + setEncounterRewards(scene, { + guaranteedModifierTypeFuncs: modifiers, + fillRemaining: false, + }); + leaveEncounterWithoutBattle(scene); } - i++; - } - - setEncounterRewards(scene, { guaranteedModifierTypeFuncs: modifiers, fillRemaining: false }); - leaveEncounterWithoutBattle(scene); - }) - .build(); + ) + .build(); diff --git a/src/data/mystery-encounters/mystery-encounter-dialogue.ts b/src/data/mystery-encounters/mystery-encounter-dialogue.ts index 11135a58085..d6938f49607 100644 --- a/src/data/mystery-encounters/mystery-encounter-dialogue.ts +++ b/src/data/mystery-encounters/mystery-encounter-dialogue.ts @@ -4,7 +4,6 @@ import { MysteriousChestDialogue } from "#app/data/mystery-encounters/dialogue/m import { FightOrFlightDialogue } from "#app/data/mystery-encounters/dialogue/fight-or-flight-dialogue"; import { TrainingSessionDialogue } from "#app/data/mystery-encounters/dialogue/training-session-dialogue"; import { SleepingSnorlaxDialogue } from "./dialogue/sleeping-snorlax-dialogue"; -import { DepartmentStoreSaleDialogue } from "#app/data/mystery-encounters/dialogue/department-store-sale-dialogue"; import { ShadyVitaminDealerDialogue } from "#app/data/mystery-encounters/dialogue/shady-vitamin-dealer"; import { TextStyle } from "#app/ui/text"; import { FieldTripDialogue } from "#app/data/mystery-encounters/dialogue/field-trip-dialogue"; @@ -89,7 +88,6 @@ export function initMysteryEncounterDialogue() { allMysteryEncounterDialogue[MysteryEncounterType.FIGHT_OR_FLIGHT] = FightOrFlightDialogue; allMysteryEncounterDialogue[MysteryEncounterType.TRAINING_SESSION] = TrainingSessionDialogue; allMysteryEncounterDialogue[MysteryEncounterType.SLEEPING_SNORLAX] = SleepingSnorlaxDialogue; - allMysteryEncounterDialogue[MysteryEncounterType.DEPARTMENT_STORE_SALE] = DepartmentStoreSaleDialogue; allMysteryEncounterDialogue[MysteryEncounterType.SHADY_VITAMIN_DEALER] = ShadyVitaminDealerDialogue; allMysteryEncounterDialogue[MysteryEncounterType.FIELD_TRIP] = FieldTripDialogue; } From ce73c38e330694108e856d05bf9d8c7cb5ad77eb Mon Sep 17 00:00:00 2001 From: Felix Staud Date: Thu, 11 Jul 2024 13:47:10 -0700 Subject: [PATCH 04/19] migrate field-trip encounter --- .../dialogue/field-trip-dialogue.ts | 50 -- .../encounters/field-trip-encounter.ts | 509 +++++++++++------- .../mystery-encounter-dialogue.ts | 2 - 3 files changed, 311 insertions(+), 250 deletions(-) delete mode 100644 src/data/mystery-encounters/dialogue/field-trip-dialogue.ts diff --git a/src/data/mystery-encounters/dialogue/field-trip-dialogue.ts b/src/data/mystery-encounters/dialogue/field-trip-dialogue.ts deleted file mode 100644 index dca3f48f5bf..00000000000 --- a/src/data/mystery-encounters/dialogue/field-trip-dialogue.ts +++ /dev/null @@ -1,50 +0,0 @@ -import MysteryEncounterDialogue from "#app/data/mystery-encounters/mystery-encounter-dialogue"; - -export const FieldTripDialogue: MysteryEncounterDialogue = { - intro: [ - { - text: "mysteryEncounter:field_trip_intro_message" - }, - { - text: "mysteryEncounter:field_trip_intro_dialogue", - speaker: "mysteryEncounter:field_trip_speaker" - } - ], - encounterOptionsDialogue: { - title: "mysteryEncounter:field_trip_title", - description: "mysteryEncounter:field_trip_description", - query: "mysteryEncounter:field_trip_query", - options: [ - { - buttonLabel: "mysteryEncounter:field_trip_option_1_label", - buttonTooltip: "mysteryEncounter:field_trip_option_1_tooltip", - secondOptionPrompt: "mysteryEncounter:field_trip_second_option_prompt", - selected: [ - { - text: "mysteryEncounter:field_trip_option_selected" - } - ] - }, - { - buttonLabel: "mysteryEncounter:field_trip_option_2_label", - buttonTooltip: "mysteryEncounter:field_trip_option_2_tooltip", - secondOptionPrompt: "mysteryEncounter:field_trip_second_option_prompt", - selected: [ - { - text: "mysteryEncounter:field_trip_option_selected" - } - ] - }, - { - buttonLabel: "mysteryEncounter:field_trip_option_3_label", - buttonTooltip: "mysteryEncounter:field_trip_option_3_tooltip", - secondOptionPrompt: "mysteryEncounter:field_trip_second_option_prompt", - selected: [ - { - text: "mysteryEncounter:field_trip_option_selected" - } - ] - } - ] - } -}; diff --git a/src/data/mystery-encounters/encounters/field-trip-encounter.ts b/src/data/mystery-encounters/encounters/field-trip-encounter.ts index 410df127b6e..8cb6fe65048 100644 --- a/src/data/mystery-encounters/encounters/field-trip-encounter.ts +++ b/src/data/mystery-encounters/encounters/field-trip-encounter.ts @@ -1,220 +1,333 @@ -import { generateModifierTypeOption, leaveEncounterWithoutBattle, selectPokemonForOption, setEncounterExp, setEncounterRewards, } from "#app/data/mystery-encounters/mystery-encounter-utils"; +import { MoveCategory } from "#app/data/move"; +import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option"; +import { + generateModifierTypeOption, + leaveEncounterWithoutBattle, + selectPokemonForOption, + setEncounterExp, + setEncounterRewards, +} from "#app/data/mystery-encounters/mystery-encounter-utils"; +import { TempBattleStat } from "#app/data/temp-battle-stat"; +import { PlayerPokemon, PokemonMove } from "#app/field/pokemon"; import { modifierTypes } from "#app/modifier/modifier-type"; +import { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import BattleScene from "../../../battle-scene"; -import MysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier } from "../mystery-encounter"; -import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option"; -import { PlayerPokemon, PokemonMove } from "#app/field/pokemon"; -import { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler"; -import { MoveCategory } from "#app/data/move"; -import { TempBattleStat } from "#app/data/temp-battle-stat"; +import MysteryEncounter, { + MysteryEncounterBuilder, + MysteryEncounterTier, +} from "../mystery-encounter"; -export const FieldTripEncounter: MysteryEncounter = MysteryEncounterBuilder - .withEncounterType(MysteryEncounterType.FIELD_TRIP) - .withEncounterTier(MysteryEncounterTier.COMMON) - .withIntroSpriteConfigs([ - { - spriteKey: "preschooler_m", - fileRoot: "trainer", - hasShadow: true - }, - { - spriteKey: "teacher", - fileRoot: "mystery-encounters", - hasShadow: true - }, - { - spriteKey: "preschooler_f", - fileRoot: "trainer", - hasShadow: true - }, - ]) - .withHideIntroVisuals(false) - .withSceneWaveRangeRequirement(10, 180) - .withOption(new MysteryEncounterOptionBuilder() - .withPreOptionPhase(async (scene: BattleScene): Promise => { - const encounter = scene.currentBattle.mysteryEncounter; - const onPokemonSelected = (pokemon: PlayerPokemon) => { - // Return the options for Pokemon move valid for this option - return pokemon.moveset.map((move: PokemonMove) => { - const option: OptionSelectItem = { - label: move.getName(), - handler: () => { - // Pokemon and move selected - const correctMove = move.getMove().category === MoveCategory.PHYSICAL; - encounter.setDialogueToken("moveCategory", "Physical"); - if (!correctMove) { - encounter.dialogue.encounterOptionsDialogue.options[0].selected = [ - { - text: "mysteryEncounter:field_trip_option_incorrect", - speaker: "mysteryEncounter:field_trip_speaker" - }, - { - text: "mysteryEncounter:field_trip_lesson_learned", +/** i18n namespace for the encounter */ +const namespace = "mysteryEncounter:field_trip"; + +export const FieldTripEncounter: MysteryEncounter = + MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.FIELD_TRIP) + .withEncounterTier(MysteryEncounterTier.COMMON) + .withSceneWaveRangeRequirement(10, 180) + .withIntroSpriteConfigs([ + { + spriteKey: "preschooler_m", + fileRoot: "trainer", + hasShadow: true, + }, + { + spriteKey: "teacher", + fileRoot: "mystery-encounters", + hasShadow: true, + }, + { + spriteKey: "preschooler_f", + fileRoot: "trainer", + hasShadow: true, + }, + ]) + .withIntroDialogue([ + { + text: `${namespace}_intro_message`, + }, + { + text: `${namespace}_intro_dialogue`, + speaker: `${namespace}_speaker`, + }, + ]) + .withHideIntroVisuals(false) + .withTitle(`${namespace}_title`) + .withDescription(`${namespace}_description`) + .withQuery(`${namespace}_query`) + .withOption( + new MysteryEncounterOptionBuilder() + .withDialogue({ + buttonLabel: `${namespace}_option_1_label`, + buttonTooltip: `${namespace}_option_1_tooltip`, + secondOptionPrompt: `${namespace}_second_option_prompt`, + selected: [ + { + text: `${namespace}_option_selected`, + }, + ], + }) + .withPreOptionPhase(async (scene: BattleScene): Promise => { + const encounter = scene.currentBattle.mysteryEncounter; + const onPokemonSelected = (pokemon: PlayerPokemon) => { + // Return the options for Pokemon move valid for this option + return pokemon.moveset.map((move: PokemonMove) => { + const option: OptionSelectItem = { + label: move.getName(), + handler: () => { + // Pokemon and move selected + const correctMove = + move.getMove().category === MoveCategory.PHYSICAL; + encounter.setDialogueToken("moveCategory", "Physical"); + if (!correctMove) { + encounter.options[0].dialogue.selected = [ + { + text: `${namespace}_option_incorrect`, + speaker: `${namespace}_speaker`, + }, + { + text: `${namespace}_lesson_learned`, + }, + ]; + setEncounterExp( + scene, + scene.getParty().map((p) => p.id), + 50 + ); + } else { + encounter.setDialogueToken("pokeName", pokemon.name); + encounter.setDialogueToken("move", move.getName()); + encounter.options[0].dialogue.selected = [ + { + text: `${namespace}_option_selected`, + }, + ]; + setEncounterExp(scene, [pokemon.id], 100); } - ]; - setEncounterExp(scene, scene.getParty().map(p => p.id), 50); - } else { - encounter.setDialogueToken("pokeName", pokemon.name); - encounter.setDialogueToken("move", move.getName()); - encounter.dialogue.encounterOptionsDialogue.options[0].selected = [ - { - text: "mysteryEncounter:field_trip_option_selected" - } - ]; - setEncounterExp(scene, [pokemon.id], 100); - } - encounter.misc = { - correctMove: correctMove + encounter.misc = { + correctMove: correctMove, + }; + return true; + }, }; - return true; - } + return option; + }); }; - return option; - }); - }; - return selectPokemonForOption(scene, onPokemonSelected); - }) - .withOptionPhase(async (scene: BattleScene) => { - const encounter = scene.currentBattle.mysteryEncounter; - if (encounter.misc.correctMove) { - const modifiers = [ - generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.ATK]), - generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.DEF]), - generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.SPD]), - generateModifierTypeOption(scene, modifierTypes.DIRE_HIT) - ]; + return selectPokemonForOption(scene, onPokemonSelected); + }) + .withOptionPhase(async (scene: BattleScene) => { + const encounter = scene.currentBattle.mysteryEncounter; + if (encounter.misc.correctMove) { + const modifiers = [ + generateModifierTypeOption( + scene, + modifierTypes.TEMP_STAT_BOOSTER, + [TempBattleStat.ATK] + ), + generateModifierTypeOption( + scene, + modifierTypes.TEMP_STAT_BOOSTER, + [TempBattleStat.DEF] + ), + generateModifierTypeOption( + scene, + modifierTypes.TEMP_STAT_BOOSTER, + [TempBattleStat.SPD] + ), + generateModifierTypeOption(scene, modifierTypes.DIRE_HIT), + ]; - setEncounterRewards(scene, { guaranteedModifierTypeOptions: modifiers, fillRemaining: false }); - } + setEncounterRewards(scene, { + guaranteedModifierTypeOptions: modifiers, + fillRemaining: false, + }); + } - leaveEncounterWithoutBattle(scene, !encounter.misc.correctMove); - }) - .build() - ) - .withOption(new MysteryEncounterOptionBuilder() - .withPreOptionPhase(async (scene: BattleScene): Promise => { - const encounter = scene.currentBattle.mysteryEncounter; - const onPokemonSelected = (pokemon: PlayerPokemon) => { - // Return the options for Pokemon move valid for this option - return pokemon.moveset.map((move: PokemonMove) => { - const option: OptionSelectItem = { - label: move.getName(), - handler: () => { - // Pokemon and move selected - const correctMove = move.getMove().category === MoveCategory.SPECIAL; - encounter.setDialogueToken("moveCategory", "Special"); - if (!correctMove) { - encounter.dialogue.encounterOptionsDialogue.options[1].selected = [ - { - text: "mysteryEncounter:field_trip_option_incorrect", - speaker: "mysteryEncounter:field_trip_speaker" - }, - { - text: "mysteryEncounter:field_trip_lesson_learned", + leaveEncounterWithoutBattle(scene, !encounter.misc.correctMove); + }) + .build() + ) + .withOption( + new MysteryEncounterOptionBuilder() + .withDialogue({ + buttonLabel: `${namespace}_option_2_label`, + buttonTooltip: `${namespace}_option_2_tooltip`, + secondOptionPrompt: `${namespace}_second_option_prompt`, + selected: [ + { + text: `${namespace}_option_selected`, + }, + ], + }) + .withPreOptionPhase(async (scene: BattleScene): Promise => { + const encounter = scene.currentBattle.mysteryEncounter; + const onPokemonSelected = (pokemon: PlayerPokemon) => { + // Return the options for Pokemon move valid for this option + return pokemon.moveset.map((move: PokemonMove) => { + const option: OptionSelectItem = { + label: move.getName(), + handler: () => { + // Pokemon and move selected + const correctMove = + move.getMove().category === MoveCategory.SPECIAL; + encounter.setDialogueToken("moveCategory", "Special"); + if (!correctMove) { + encounter.options[1].dialogue.selected = [ + { + text: `${namespace}_option_incorrect`, + speaker: `${namespace}_speaker`, + }, + { + text: `${namespace}_lesson_learned`, + }, + ]; + setEncounterExp( + scene, + scene.getParty().map((p) => p.id), + 50 + ); + } else { + encounter.setDialogueToken("pokeName", pokemon.name); + encounter.setDialogueToken("move", move.getName()); + encounter.options[1].dialogue.selected = [ + { + text: `${namespace}_option_selected`, + }, + ]; + setEncounterExp(scene, [pokemon.id], 100); } - ]; - setEncounterExp(scene, scene.getParty().map(p => p.id), 50); - } else { - encounter.setDialogueToken("pokeName", pokemon.name); - encounter.setDialogueToken("move", move.getName()); - encounter.dialogue.encounterOptionsDialogue.options[1].selected = [ - { - text: "mysteryEncounter:field_trip_option_selected" - } - ]; - setEncounterExp(scene, [pokemon.id], 100); - } - encounter.misc = { - correctMove: correctMove + encounter.misc = { + correctMove: correctMove, + }; + return true; + }, }; - return true; - } + return option; + }); }; - return option; - }); - }; - return selectPokemonForOption(scene, onPokemonSelected); - }) - .withOptionPhase(async (scene: BattleScene) => { - const encounter = scene.currentBattle.mysteryEncounter; - if (encounter.misc.correctMove) { - const modifiers = [ - generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.SPATK]), - generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.SPDEF]), - generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.SPD]), - generateModifierTypeOption(scene, modifierTypes.DIRE_HIT) - ]; + return selectPokemonForOption(scene, onPokemonSelected); + }) + .withOptionPhase(async (scene: BattleScene) => { + const encounter = scene.currentBattle.mysteryEncounter; + if (encounter.misc.correctMove) { + const modifiers = [ + generateModifierTypeOption( + scene, + modifierTypes.TEMP_STAT_BOOSTER, + [TempBattleStat.SPATK] + ), + generateModifierTypeOption( + scene, + modifierTypes.TEMP_STAT_BOOSTER, + [TempBattleStat.SPDEF] + ), + generateModifierTypeOption( + scene, + modifierTypes.TEMP_STAT_BOOSTER, + [TempBattleStat.SPD] + ), + generateModifierTypeOption(scene, modifierTypes.DIRE_HIT), + ]; - setEncounterRewards(scene, { guaranteedModifierTypeOptions: modifiers, fillRemaining: false }); - } + setEncounterRewards(scene, { + guaranteedModifierTypeOptions: modifiers, + fillRemaining: false, + }); + } - leaveEncounterWithoutBattle(scene, !encounter.misc.correctMove); - }) - .build() - ) - .withOption(new MysteryEncounterOptionBuilder() - .withPreOptionPhase(async (scene: BattleScene): Promise => { - const encounter = scene.currentBattle.mysteryEncounter; - const onPokemonSelected = (pokemon: PlayerPokemon) => { - // Return the options for Pokemon move valid for this option - return pokemon.moveset.map((move: PokemonMove) => { - const option: OptionSelectItem = { - label: move.getName(), - handler: () => { - // Pokemon and move selected - const correctMove = move.getMove().category === MoveCategory.STATUS; - encounter.setDialogueToken("moveCategory", "Status"); - if (!correctMove) { - encounter.dialogue.encounterOptionsDialogue.options[2].selected = [ - { - text: "mysteryEncounter:field_trip_option_incorrect", - speaker: "mysteryEncounter:field_trip_speaker" - }, - { - text: "mysteryEncounter:field_trip_lesson_learned", + leaveEncounterWithoutBattle(scene, !encounter.misc.correctMove); + }) + .build() + ) + .withOption( + new MysteryEncounterOptionBuilder() + .withDialogue({ + buttonLabel: `${namespace}_option_3_label`, + buttonTooltip: `${namespace}_option_3_tooltip`, + secondOptionPrompt: `${namespace}_second_option_prompt`, + selected: [ + { + text: `${namespace}_option_selected`, + }, + ], + }) + .withPreOptionPhase(async (scene: BattleScene): Promise => { + const encounter = scene.currentBattle.mysteryEncounter; + const onPokemonSelected = (pokemon: PlayerPokemon) => { + // Return the options for Pokemon move valid for this option + return pokemon.moveset.map((move: PokemonMove) => { + const option: OptionSelectItem = { + label: move.getName(), + handler: () => { + // Pokemon and move selected + const correctMove = + move.getMove().category === MoveCategory.STATUS; + encounter.setDialogueToken("moveCategory", "Status"); + if (!correctMove) { + encounter.options[2].dialogue.selected = [ + { + text: `${namespace}_option_incorrect`, + speaker: `${namespace}_speaker`, + }, + { + text: `${namespace}_lesson_learned`, + }, + ]; + setEncounterExp( + scene, + scene.getParty().map((p) => p.id), + 50 + ); + } else { + encounter.setDialogueToken("pokeName", pokemon.name); + encounter.setDialogueToken("move", move.getName()); + encounter.options[2].dialogue.selected = [ + { + text: `${namespace}_option_selected`, + }, + ]; + setEncounterExp(scene, [pokemon.id], 100); } - ]; - setEncounterExp(scene, scene.getParty().map(p => p.id), 50); - } else { - encounter.setDialogueToken("pokeName", pokemon.name); - encounter.setDialogueToken("move", move.getName()); - encounter.dialogue.encounterOptionsDialogue.options[2].selected = [ - { - text: "mysteryEncounter:field_trip_option_selected" - } - ]; - setEncounterExp(scene, [pokemon.id], 100); - } - encounter.misc = { - correctMove: correctMove + encounter.misc = { + correctMove: correctMove, + }; + return true; + }, }; - return true; - } + return option; + }); }; - return option; - }); - }; - return selectPokemonForOption(scene, onPokemonSelected); - }) - .withOptionPhase(async (scene: BattleScene) => { - const encounter = scene.currentBattle.mysteryEncounter; - if (encounter.misc.correctMove) { - const modifiers = [ - generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.ACC]), - generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.SPD]), - generateModifierTypeOption(scene, modifierTypes.GREAT_BALL), - generateModifierTypeOption(scene, modifierTypes.IV_SCANNER) - ]; + return selectPokemonForOption(scene, onPokemonSelected); + }) + .withOptionPhase(async (scene: BattleScene) => { + const encounter = scene.currentBattle.mysteryEncounter; + if (encounter.misc.correctMove) { + const modifiers = [ + generateModifierTypeOption( + scene, + modifierTypes.TEMP_STAT_BOOSTER, + [TempBattleStat.ACC] + ), + generateModifierTypeOption( + scene, + modifierTypes.TEMP_STAT_BOOSTER, + [TempBattleStat.SPD] + ), + generateModifierTypeOption(scene, modifierTypes.GREAT_BALL), + generateModifierTypeOption(scene, modifierTypes.IV_SCANNER), + ]; - setEncounterRewards(scene, { guaranteedModifierTypeOptions: modifiers, fillRemaining: false }); - } + setEncounterRewards(scene, { + guaranteedModifierTypeOptions: modifiers, + fillRemaining: false, + }); + } - leaveEncounterWithoutBattle(scene, !encounter.misc.correctMove); - }) - .build() - ) - .build(); + leaveEncounterWithoutBattle(scene, !encounter.misc.correctMove); + }) + .build() + ) + .build(); diff --git a/src/data/mystery-encounters/mystery-encounter-dialogue.ts b/src/data/mystery-encounters/mystery-encounter-dialogue.ts index d6938f49607..bfeb094c9a5 100644 --- a/src/data/mystery-encounters/mystery-encounter-dialogue.ts +++ b/src/data/mystery-encounters/mystery-encounter-dialogue.ts @@ -6,7 +6,6 @@ import { TrainingSessionDialogue } from "#app/data/mystery-encounters/dialogue/t import { SleepingSnorlaxDialogue } from "./dialogue/sleeping-snorlax-dialogue"; import { ShadyVitaminDealerDialogue } from "#app/data/mystery-encounters/dialogue/shady-vitamin-dealer"; import { TextStyle } from "#app/ui/text"; -import { FieldTripDialogue } from "#app/data/mystery-encounters/dialogue/field-trip-dialogue"; export class TextDisplay { speaker?: TemplateStringsArray | `mysteryEncounter:${string}`; @@ -89,5 +88,4 @@ export function initMysteryEncounterDialogue() { allMysteryEncounterDialogue[MysteryEncounterType.TRAINING_SESSION] = TrainingSessionDialogue; allMysteryEncounterDialogue[MysteryEncounterType.SLEEPING_SNORLAX] = SleepingSnorlaxDialogue; allMysteryEncounterDialogue[MysteryEncounterType.SHADY_VITAMIN_DEALER] = ShadyVitaminDealerDialogue; - allMysteryEncounterDialogue[MysteryEncounterType.FIELD_TRIP] = FieldTripDialogue; } From 171339509170803b1bd6a0036f337620822316d9 Mon Sep 17 00:00:00 2001 From: Felix Staud Date: Thu, 11 Jul 2024 13:54:44 -0700 Subject: [PATCH 05/19] migrate fight-or-flight encounter --- .../dialogue/fight-or-flight-dialogue.ts | 38 --- .../encounters/fight-or-flight.ts | 304 ++++++++++++------ .../mystery-encounter-dialogue.ts | 2 - 3 files changed, 202 insertions(+), 142 deletions(-) delete mode 100644 src/data/mystery-encounters/dialogue/fight-or-flight-dialogue.ts diff --git a/src/data/mystery-encounters/dialogue/fight-or-flight-dialogue.ts b/src/data/mystery-encounters/dialogue/fight-or-flight-dialogue.ts deleted file mode 100644 index 93d46548d7f..00000000000 --- a/src/data/mystery-encounters/dialogue/fight-or-flight-dialogue.ts +++ /dev/null @@ -1,38 +0,0 @@ -import MysteryEncounterDialogue from "#app/data/mystery-encounters/mystery-encounter-dialogue"; - -export const FightOrFlightDialogue: MysteryEncounterDialogue = { - intro: [ - { - text: "mysteryEncounter:fight_or_flight_intro_message" - } - ], - encounterOptionsDialogue: { - title: "mysteryEncounter:fight_or_flight_title", - description: "mysteryEncounter:fight_or_flight_description", - query: "mysteryEncounter:fight_or_flight_query", - options: [ - { - buttonLabel: "mysteryEncounter:fight_or_flight_option_1_label", - buttonTooltip: "mysteryEncounter:fight_or_flight_option_1_tooltip", - selected: [ - { - text: "mysteryEncounter:fight_or_flight_option_1_selected_message" - } - ] - }, - { - buttonLabel: "mysteryEncounter:fight_or_flight_option_2_label", - buttonTooltip: "mysteryEncounter:fight_or_flight_option_2_tooltip" - }, - { - buttonLabel: "mysteryEncounter:fight_or_flight_option_3_label", - buttonTooltip: "mysteryEncounter:fight_or_flight_option_3_tooltip", - selected: [ - { - text: "mysteryEncounter:fight_or_flight_option_3_selected" - } - ] - } - ] - } -}; diff --git a/src/data/mystery-encounters/encounters/fight-or-flight.ts b/src/data/mystery-encounters/encounters/fight-or-flight.ts index 2a362eaed37..3080ab76810 100644 --- a/src/data/mystery-encounters/encounters/fight-or-flight.ts +++ b/src/data/mystery-encounters/encounters/fight-or-flight.ts @@ -1,11 +1,14 @@ import { BattleStat } from "#app/data/battle-stat"; +import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option"; import { EnemyPartyConfig, initBattleWithEnemyConfig, - leaveEncounterWithoutBattle, queueEncounterMessage, + leaveEncounterWithoutBattle, + queueEncounterMessage, setEncounterRewards, - showEncounterText + showEncounterText, } from "#app/data/mystery-encounters/mystery-encounter-utils"; +import { STEALING_MOVES } from "#app/data/mystery-encounters/requirements/requirement-groups"; import Pokemon from "#app/field/pokemon"; import { ModifierTier } from "#app/modifier/modifier-tier"; import { @@ -13,123 +16,220 @@ import { getPlayerModifierTypeOptions, ModifierPoolType, ModifierTypeOption, - regenerateModifierPoolThresholds + regenerateModifierPoolThresholds, } from "#app/modifier/modifier-type"; import { StatChangePhase } from "#app/phases"; import { randSeedInt } from "#app/utils"; import { BattlerTagType } from "#enums/battler-tag-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import BattleScene from "../../../battle-scene"; -import MysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier } from "../mystery-encounter"; +import MysteryEncounter, { + MysteryEncounterBuilder, + MysteryEncounterTier, +} from "../mystery-encounter"; import { MoveRequirement } from "../mystery-encounter-requirements"; -import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option"; -import { STEALING_MOVES } from "#app/data/mystery-encounters/requirements/requirement-groups"; -export const FightOrFlightEncounter: MysteryEncounter = MysteryEncounterBuilder - .withEncounterType(MysteryEncounterType.FIGHT_OR_FLIGHT) - .withEncounterTier(MysteryEncounterTier.COMMON) - .withIntroSpriteConfigs([]) // Set in onInit() - .withSceneWaveRangeRequirement(10, 180) // waves 10 to 180 - .withCatchAllowed(true) - .withHideWildIntroMessage(true) - .withOnInit((scene: BattleScene) => { - const encounter = scene.currentBattle.mysteryEncounter; +/** the i18n namespace for the encounter */ +const namespace = "mysteryEncounter:fight_or_flight"; - // Calculate boss mon - const bossSpecies = scene.arena.randomSpecies(scene.currentBattle.waveIndex, scene.currentBattle.waveIndex, 0, getPartyLuckValue(scene.getParty()), true); - const config: EnemyPartyConfig = { - levelAdditiveMultiplier: 1, - pokemonConfigs: [{ species: bossSpecies, isBoss: true }] - }; - encounter.enemyPartyConfigs = [config]; - - // Calculate item - // 10-60 GREAT, 60-110 ULTRA, 110-160 ROGUE, 160-180 MASTER - const tier = scene.currentBattle.waveIndex > 160 ? ModifierTier.MASTER : scene.currentBattle.waveIndex > 110 ? ModifierTier.ROGUE : scene.currentBattle.waveIndex > 60 ? ModifierTier.ULTRA : ModifierTier.GREAT; - regenerateModifierPoolThresholds(scene.getParty(), ModifierPoolType.PLAYER, 0); // refresh player item pool - const item = getPlayerModifierTypeOptions(1, scene.getParty(), [], { guaranteedModifierTiers: [tier] })[0]; - encounter.setDialogueToken("itemName", item.type.name); - encounter.misc = item; - - encounter.spriteConfigs = [ +export const FightOrFlightEncounter: MysteryEncounter = + MysteryEncounterBuilder.withEncounterType( + MysteryEncounterType.FIGHT_OR_FLIGHT + ) + .withEncounterTier(MysteryEncounterTier.COMMON) + .withSceneWaveRangeRequirement(10, 180) // waves 10 to 180 + .withCatchAllowed(true) + .withHideWildIntroMessage(true) + .withIntroSpriteConfigs([]) // Set in onInit() + .withIntroDialogue([ { - spriteKey: item.type.iconImage, - fileRoot: "items", - hasShadow: false, - x: 35, - y: -5, - scale: 0.75, - isItem: true + text: `${namespace}_intro_message`, }, - { - spriteKey: bossSpecies.speciesId.toString(), - fileRoot: "pokemon", - hasShadow: true, - tint: 0.25, - x: -5, - repeat: true - } - ]; - - // If player has a stealing move, they succeed automatically - encounter.options[1].meetsRequirements(scene); - const primaryPokemon = encounter.options[1].primaryPokemon; - if (primaryPokemon) { - // Use primaryPokemon to execute the thievery - encounter.dialogue.encounterOptionsDialogue.options[1].buttonTooltip = "mysteryEncounter:fight_or_flight_option_2_steal_tooltip"; - } else { - encounter.dialogue.encounterOptionsDialogue.options[1].buttonTooltip = "mysteryEncounter:fight_or_flight_option_2_tooltip"; - } - - return true; - }) - .withSimpleOption(async (scene: BattleScene) => { - // Pick battle - const item = scene.currentBattle.mysteryEncounter.misc as ModifierTypeOption; - setEncounterRewards(scene, { guaranteedModifierTypeOptions: [item], fillRemaining: false }); - await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0]); - }) - .withOption(new MysteryEncounterOptionBuilder() - .withPrimaryPokemonRequirement(new MoveRequirement(STEALING_MOVES)) // Will set option2PrimaryName and option2PrimaryMove dialogue tokens automatically - .withDisabledOnRequirementsNotMet(false) - .withOptionPhase(async (scene: BattleScene) => { - // Pick steal + ]) + .withOnInit((scene: BattleScene) => { const encounter = scene.currentBattle.mysteryEncounter; - const item = scene.currentBattle.mysteryEncounter.misc as ModifierTypeOption; - setEncounterRewards(scene, { guaranteedModifierTypeOptions: [item], fillRemaining: false }); + + // Calculate boss mon + const bossSpecies = scene.arena.randomSpecies( + scene.currentBattle.waveIndex, + scene.currentBattle.waveIndex, + 0, + getPartyLuckValue(scene.getParty()), + true + ); + const config: EnemyPartyConfig = { + levelAdditiveMultiplier: 1, + pokemonConfigs: [{ species: bossSpecies, isBoss: true }], + }; + encounter.enemyPartyConfigs = [config]; + + // Calculate item + // 10-60 GREAT, 60-110 ULTRA, 110-160 ROGUE, 160-180 MASTER + const tier = + scene.currentBattle.waveIndex > 160 + ? ModifierTier.MASTER + : scene.currentBattle.waveIndex > 110 + ? ModifierTier.ROGUE + : scene.currentBattle.waveIndex > 60 + ? ModifierTier.ULTRA + : ModifierTier.GREAT; + regenerateModifierPoolThresholds( + scene.getParty(), + ModifierPoolType.PLAYER, + 0 + ); // refresh player item pool + const item = getPlayerModifierTypeOptions(1, scene.getParty(), [], { + guaranteedModifierTiers: [tier], + })[0]; + encounter.setDialogueToken("itemName", item.type.name); + encounter.misc = item; + + encounter.spriteConfigs = [ + { + spriteKey: item.type.iconImage, + fileRoot: "items", + hasShadow: false, + x: 35, + y: -5, + scale: 0.75, + isItem: true, + }, + { + spriteKey: bossSpecies.speciesId.toString(), + fileRoot: "pokemon", + hasShadow: true, + tint: 0.25, + x: -5, + repeat: true, + }, + ]; // If player has a stealing move, they succeed automatically + encounter.options[1].meetsRequirements(scene); const primaryPokemon = encounter.options[1].primaryPokemon; if (primaryPokemon) { // Use primaryPokemon to execute the thievery - await showEncounterText(scene, "mysteryEncounter:fight_or_flight_option_2_steal_result"); - leaveEncounterWithoutBattle(scene); - return; + encounter.options[1].dialogue.buttonTooltip = `${namespace}_option_2_steal_tooltip`; + } else { + encounter.options[1].dialogue.buttonTooltip = `${namespace}_option_2_tooltip`; } - const roll = randSeedInt(16); - if (roll > 6) { - // Noticed and attacked by boss, gets +1 to all stats at start of fight (62.5%) - const config = scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0]; - config.pokemonConfigs[0].tags = [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON]; - config.pokemonConfigs[0].mysteryEncounterBattleEffects = (pokemon: Pokemon) => { - pokemon.scene.currentBattle.mysteryEncounter.setDialogueToken("enemyPokemon", pokemon.name); - queueEncounterMessage(pokemon.scene, "mysteryEncounter:fight_or_flight_boss_enraged"); - pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD], 1)); - }; - await showEncounterText(scene, "mysteryEncounter:fight_or_flight_option_2_bad_result"); - await initBattleWithEnemyConfig(scene, config); - } else { - // Steal item (37.5%) - // Display result message then proceed to rewards - await showEncounterText(scene, "mysteryEncounter:fight_or_flight_option_2_good_result"); - leaveEncounterWithoutBattle(scene); - } + return true; }) - .build()) - .withSimpleOption(async (scene: BattleScene) => { - // Leave encounter with no rewards or exp - leaveEncounterWithoutBattle(scene, true); - return true; - }) - .build(); + .withTitle(`${namespace}_title`) + .withDescription(`${namespace}_description`) + .withQuery(`${namespace}_query`) + .withSimpleOption( + { + buttonLabel: `${namespace}_option_1_label`, + buttonTooltip: `${namespace}_option_1_tooltip`, + selected: [ + { + text: `${namespace}_option_1_selected_message`, + }, + ], + }, + async (scene: BattleScene) => { + // Pick battle + const item = scene.currentBattle.mysteryEncounter + .misc as ModifierTypeOption; + setEncounterRewards(scene, { + guaranteedModifierTypeOptions: [item], + fillRemaining: false, + }); + await initBattleWithEnemyConfig( + scene, + scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0] + ); + } + ) + .withOption( + new MysteryEncounterOptionBuilder() + .withPrimaryPokemonRequirement(new MoveRequirement(STEALING_MOVES)) // Will set option2PrimaryName and option2PrimaryMove dialogue tokens automatically + .withDisabledOnRequirementsNotMet(false) + .withDialogue({ + buttonLabel: `${namespace}_option_2_label`, + buttonTooltip: `${namespace}_option_2_tooltip`, + }) + .withOptionPhase(async (scene: BattleScene) => { + // Pick steal + const encounter = scene.currentBattle.mysteryEncounter; + const item = scene.currentBattle.mysteryEncounter + .misc as ModifierTypeOption; + setEncounterRewards(scene, { + guaranteedModifierTypeOptions: [item], + fillRemaining: false, + }); + + // If player has a stealing move, they succeed automatically + const primaryPokemon = encounter.options[1].primaryPokemon; + if (primaryPokemon) { + // Use primaryPokemon to execute the thievery + await showEncounterText( + scene, + `${namespace}_option_2_steal_result` + ); + leaveEncounterWithoutBattle(scene); + return; + } + + const roll = randSeedInt(16); + if (roll > 6) { + // Noticed and attacked by boss, gets +1 to all stats at start of fight (62.5%) + const config = + scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0]; + config.pokemonConfigs[0].tags = [ + BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON, + ]; + config.pokemonConfigs[0].mysteryEncounterBattleEffects = ( + pokemon: Pokemon + ) => { + pokemon.scene.currentBattle.mysteryEncounter.setDialogueToken( + "enemyPokemon", + pokemon.name + ); + queueEncounterMessage(pokemon.scene, `${namespace}_boss_enraged`); + pokemon.scene.unshiftPhase( + new StatChangePhase( + pokemon.scene, + pokemon.getBattlerIndex(), + true, + [ + BattleStat.ATK, + BattleStat.DEF, + BattleStat.SPATK, + BattleStat.SPDEF, + BattleStat.SPD, + ], + 1 + ) + ); + }; + await showEncounterText(scene, `${namespace}_option_2_bad_result`); + await initBattleWithEnemyConfig(scene, config); + } else { + // Steal item (37.5%) + // Display result message then proceed to rewards + await showEncounterText(scene, `${namespace}_option_2_good_result`); + leaveEncounterWithoutBattle(scene); + } + }) + .build() + ) + .withSimpleOption( + { + buttonLabel: `${namespace}_option_3_label`, + buttonTooltip: `${namespace}_option_3_tooltip`, + selected: [ + { + text: `${namespace}_option_3_selected`, + }, + ], + }, + async (scene: BattleScene) => { + // Leave encounter with no rewards or exp + leaveEncounterWithoutBattle(scene, true); + return true; + } + ) + .build(); diff --git a/src/data/mystery-encounters/mystery-encounter-dialogue.ts b/src/data/mystery-encounters/mystery-encounter-dialogue.ts index bfeb094c9a5..d9532ee4984 100644 --- a/src/data/mystery-encounters/mystery-encounter-dialogue.ts +++ b/src/data/mystery-encounters/mystery-encounter-dialogue.ts @@ -1,7 +1,6 @@ import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteriousChallengersDialogue } from "#app/data/mystery-encounters/dialogue/mysterious-challengers-dialogue"; import { MysteriousChestDialogue } from "#app/data/mystery-encounters/dialogue/mysterious-chest-dialogue"; -import { FightOrFlightDialogue } from "#app/data/mystery-encounters/dialogue/fight-or-flight-dialogue"; import { TrainingSessionDialogue } from "#app/data/mystery-encounters/dialogue/training-session-dialogue"; import { SleepingSnorlaxDialogue } from "./dialogue/sleeping-snorlax-dialogue"; import { ShadyVitaminDealerDialogue } from "#app/data/mystery-encounters/dialogue/shady-vitamin-dealer"; @@ -84,7 +83,6 @@ export const allMysteryEncounterDialogue: { [encounterType: number]: MysteryEnco export function initMysteryEncounterDialogue() { allMysteryEncounterDialogue[MysteryEncounterType.MYSTERIOUS_CHALLENGERS] = MysteriousChallengersDialogue; allMysteryEncounterDialogue[MysteryEncounterType.MYSTERIOUS_CHEST] = MysteriousChestDialogue; - allMysteryEncounterDialogue[MysteryEncounterType.FIGHT_OR_FLIGHT] = FightOrFlightDialogue; allMysteryEncounterDialogue[MysteryEncounterType.TRAINING_SESSION] = TrainingSessionDialogue; allMysteryEncounterDialogue[MysteryEncounterType.SLEEPING_SNORLAX] = SleepingSnorlaxDialogue; allMysteryEncounterDialogue[MysteryEncounterType.SHADY_VITAMIN_DEALER] = ShadyVitaminDealerDialogue; From e6bf12ab8c1e0918cf938b006f0a3a6942df8474 Mon Sep 17 00:00:00 2001 From: Felix Staud Date: Thu, 11 Jul 2024 14:02:26 -0700 Subject: [PATCH 06/19] migrate mysterious-challengers --- .../mysterious-challengers-dialogue.ts | 57 --- .../encounters/mysterious-challengers.ts | 339 ++++++++++++------ .../mystery-encounter-dialogue.ts | 2 - 3 files changed, 220 insertions(+), 178 deletions(-) delete mode 100644 src/data/mystery-encounters/dialogue/mysterious-challengers-dialogue.ts diff --git a/src/data/mystery-encounters/dialogue/mysterious-challengers-dialogue.ts b/src/data/mystery-encounters/dialogue/mysterious-challengers-dialogue.ts deleted file mode 100644 index 065cfceb1b7..00000000000 --- a/src/data/mystery-encounters/dialogue/mysterious-challengers-dialogue.ts +++ /dev/null @@ -1,57 +0,0 @@ -import MysteryEncounterDialogue from "#app/data/mystery-encounters/mystery-encounter-dialogue"; - -export const MysteriousChallengersDialogue: MysteryEncounterDialogue = { - intro: [ - { - text: "mysteryEncounter:mysterious_challengers_intro_message" - } - ], - encounterOptionsDialogue: { - title: "mysteryEncounter:mysterious_challengers_title", - description: "mysteryEncounter:mysterious_challengers_description", - query: "mysteryEncounter:mysterious_challengers_query", - options: [ - { - buttonLabel: "mysteryEncounter:mysterious_challengers_option_1_label", - buttonTooltip: "mysteryEncounter:mysterious_challengers_option_1_tooltip", - selected: [ - { - text: "mysteryEncounter:mysterious_challengers_option_selected_message" - } - ] - }, - { - buttonLabel: "mysteryEncounter:mysterious_challengers_option_2_label", - buttonTooltip: "mysteryEncounter:mysterious_challengers_option_2_tooltip", - selected: [ - { - text: "mysteryEncounter:mysterious_challengers_option_selected_message" - } - ] - }, - { - buttonLabel: "mysteryEncounter:mysterious_challengers_option_3_label", - buttonTooltip: "mysteryEncounter:mysterious_challengers_option_3_tooltip", - selected: [ - { - text: "mysteryEncounter:mysterious_challengers_option_selected_message" - } - ] - }, - { - buttonLabel: "mysteryEncounter:mysterious_challengers_option_4_label", - buttonTooltip: "mysteryEncounter:mysterious_challengers_option_4_tooltip", - selected: [ - { - text: "mysteryEncounter:mysterious_challengers_option_4_selected_message" - } - ] - } - ] - }, - outro: [ - { - text: "mysteryEncounter:mysterious_challengers_outro_win" - } - ] -}; diff --git a/src/data/mystery-encounters/encounters/mysterious-challengers.ts b/src/data/mystery-encounters/encounters/mysterious-challengers.ts index db794c58e9f..e8efc3470ed 100644 --- a/src/data/mystery-encounters/encounters/mysterious-challengers.ts +++ b/src/data/mystery-encounters/encounters/mysterious-challengers.ts @@ -1,9 +1,13 @@ -import { EnemyPartyConfig, initBattleWithEnemyConfig, setEncounterRewards } from "#app/data/mystery-encounters/mystery-encounter-utils"; +import { + EnemyPartyConfig, + initBattleWithEnemyConfig, + setEncounterRewards, +} from "#app/data/mystery-encounters/mystery-encounter-utils"; import { trainerConfigs, TrainerPartyCompoundTemplate, TrainerPartyTemplate, - trainerPartyTemplates + trainerPartyTemplates, } from "#app/data/trainer-config"; import { ModifierTier } from "#app/modifier/modifier-tier"; import { modifierTypes } from "#app/modifier/modifier-type"; @@ -11,133 +15,230 @@ import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { PartyMemberStrength } from "#enums/party-member-strength"; import BattleScene from "../../../battle-scene"; import * as Utils from "../../../utils"; -import MysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier } from "../mystery-encounter"; +import MysteryEncounter, { + MysteryEncounterBuilder, + MysteryEncounterTier, +} from "../mystery-encounter"; -export const MysteriousChallengersEncounter: MysteryEncounter = MysteryEncounterBuilder - .withEncounterType(MysteryEncounterType.MYSTERIOUS_CHALLENGERS) - .withEncounterTier(MysteryEncounterTier.GREAT) - .withIntroSpriteConfigs([]) // These are set in onInit() - .withSceneWaveRangeRequirement(10, 180) // waves 10 to 180 - .withOnInit((scene: BattleScene) => { - const encounter = scene.currentBattle.mysteryEncounter; - // Calculates what trainers are available for battle in the encounter +/** the i18n namespace for the encounter */ +const namespace = "mysteryEncounter:mysterious_challengers"; - // Normal difficulty trainer is randomly pulled from biome - const normalTrainerType = scene.arena.randomTrainerType(scene.currentBattle.waveIndex); - const normalConfig = trainerConfigs[normalTrainerType].copy(); - let female = false; - if (normalConfig.hasGenders) { - female = !!(Utils.randSeedInt(2)); - } - const normalSpriteKey = normalConfig.getSpriteKey(female, normalConfig.doubleOnly); - encounter.enemyPartyConfigs.push({ - trainerConfig: normalConfig, - female: female - }); - - // Hard difficulty trainer is another random trainer, but with AVERAGE_BALANCED config - // Number of mons is based off wave: 1-20 is 2, 20-40 is 3, etc. capping at 6 after wave 100 - const hardTrainerType = scene.arena.randomTrainerType(scene.currentBattle.waveIndex); - const hardTemplate = new TrainerPartyCompoundTemplate( - new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER, false, true), - new TrainerPartyTemplate(Math.min(Math.ceil(scene.currentBattle.waveIndex / 20), 5), PartyMemberStrength.AVERAGE, false, true)); - const hardConfig = trainerConfigs[hardTrainerType].copy(); - hardConfig.setPartyTemplates(hardTemplate); - female = false; - if (hardConfig.hasGenders) { - female = !!(Utils.randSeedInt(2)); - } - const hardSpriteKey = hardConfig.getSpriteKey(female, hardConfig.doubleOnly); - encounter.enemyPartyConfigs.push({ - trainerConfig: hardConfig, - levelAdditiveMultiplier: 0.5, - female: female, - }); - - // Brutal trainer is pulled from pool of boss trainers (gym leaders) for the biome - // They are given an E4 template team, so will be stronger than usual boss encounter and always have 6 mons - const brutalTrainerType = scene.arena.randomTrainerType(scene.currentBattle.waveIndex, true); - const e4Template = trainerPartyTemplates.ELITE_FOUR; - const brutalConfig = trainerConfigs[brutalTrainerType].copy(); - brutalConfig.setPartyTemplates(e4Template); - brutalConfig.partyTemplateFunc = null; // Overrides gym leader party template func - female = false; - if (brutalConfig.hasGenders) { - female = !!(Utils.randSeedInt(2)); - } - const brutalSpriteKey = brutalConfig.getSpriteKey(female, brutalConfig.doubleOnly); - encounter.enemyPartyConfigs.push({ - trainerConfig: brutalConfig, - levelAdditiveMultiplier: 1.1, - female: female - }); - - encounter.spriteConfigs = [ +export const MysteriousChallengersEncounter: MysteryEncounter = + MysteryEncounterBuilder.withEncounterType( + MysteryEncounterType.MYSTERIOUS_CHALLENGERS + ) + .withEncounterTier(MysteryEncounterTier.GREAT) + .withSceneWaveRangeRequirement(10, 180) // waves 10 to 180 + .withIntroSpriteConfigs([]) // These are set in onInit() + .withIntroDialogue([ { - spriteKey: normalSpriteKey, - fileRoot: "trainer", - hasShadow: true, - tint: 1 + text: `${namespace}_intro_message`, }, - { - spriteKey: hardSpriteKey, - fileRoot: "trainer", - hasShadow: true, - tint: 1 - }, - { - spriteKey: brutalSpriteKey, - fileRoot: "trainer", - hasShadow: true, - tint: 1 + ]) + .withOnInit((scene: BattleScene) => { + const encounter = scene.currentBattle.mysteryEncounter; + // Calculates what trainers are available for battle in the encounter + + // Normal difficulty trainer is randomly pulled from biome + const normalTrainerType = scene.arena.randomTrainerType( + scene.currentBattle.waveIndex + ); + const normalConfig = trainerConfigs[normalTrainerType].copy(); + let female = false; + if (normalConfig.hasGenders) { + female = !!Utils.randSeedInt(2); } - ]; + const normalSpriteKey = normalConfig.getSpriteKey( + female, + normalConfig.doubleOnly + ); + encounter.enemyPartyConfigs.push({ + trainerConfig: normalConfig, + female: female, + }); - return true; - }) - .withSimpleOption(async (scene: BattleScene) => { - const encounter = scene.currentBattle.mysteryEncounter; - // Spawn standard trainer battle with memory mushroom reward - const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0]; + // Hard difficulty trainer is another random trainer, but with AVERAGE_BALANCED config + // Number of mons is based off wave: 1-20 is 2, 20-40 is 3, etc. capping at 6 after wave 100 + const hardTrainerType = scene.arena.randomTrainerType( + scene.currentBattle.waveIndex + ); + const hardTemplate = new TrainerPartyCompoundTemplate( + new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER, false, true), + new TrainerPartyTemplate( + Math.min(Math.ceil(scene.currentBattle.waveIndex / 20), 5), + PartyMemberStrength.AVERAGE, + false, + true + ) + ); + const hardConfig = trainerConfigs[hardTrainerType].copy(); + hardConfig.setPartyTemplates(hardTemplate); + female = false; + if (hardConfig.hasGenders) { + female = !!Utils.randSeedInt(2); + } + const hardSpriteKey = hardConfig.getSpriteKey( + female, + hardConfig.doubleOnly + ); + encounter.enemyPartyConfigs.push({ + trainerConfig: hardConfig, + levelAdditiveMultiplier: 0.5, + female: female, + }); - setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.TM_COMMON, modifierTypes.TM_GREAT, modifierTypes.MEMORY_MUSHROOM], fillRemaining: true }); + // Brutal trainer is pulled from pool of boss trainers (gym leaders) for the biome + // They are given an E4 template team, so will be stronger than usual boss encounter and always have 6 mons + const brutalTrainerType = scene.arena.randomTrainerType( + scene.currentBattle.waveIndex, + true + ); + const e4Template = trainerPartyTemplates.ELITE_FOUR; + const brutalConfig = trainerConfigs[brutalTrainerType].copy(); + brutalConfig.setPartyTemplates(e4Template); + brutalConfig.partyTemplateFunc = null; // Overrides gym leader party template func + female = false; + if (brutalConfig.hasGenders) { + female = !!Utils.randSeedInt(2); + } + const brutalSpriteKey = brutalConfig.getSpriteKey( + female, + brutalConfig.doubleOnly + ); + encounter.enemyPartyConfigs.push({ + trainerConfig: brutalConfig, + levelAdditiveMultiplier: 1.1, + female: female, + }); - // Seed offsets to remove possibility of different trainers having exact same teams - let ret; - scene.executeWithSeedOffset(() => { - ret = initBattleWithEnemyConfig(scene, config); - }, scene.currentBattle.waveIndex * 10); - return ret; - }) - .withSimpleOption(async (scene: BattleScene) => { - const encounter = scene.currentBattle.mysteryEncounter; - // Spawn hard fight with ULTRA/GREAT reward (can improve with luck) - const config: EnemyPartyConfig = encounter.enemyPartyConfigs[1]; + encounter.spriteConfigs = [ + { + spriteKey: normalSpriteKey, + fileRoot: "trainer", + hasShadow: true, + tint: 1, + }, + { + spriteKey: hardSpriteKey, + fileRoot: "trainer", + hasShadow: true, + tint: 1, + }, + { + spriteKey: brutalSpriteKey, + fileRoot: "trainer", + hasShadow: true, + tint: 1, + }, + ]; - setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT], fillRemaining: true }); + return true; + }) + .withTitle(`${namespace}_title`) + .withDescription(`${namespace}_description`) + .withQuery(`${namespace}_query`) + .withSimpleOption( + { + buttonLabel: `${namespace}_option_1_label`, + buttonTooltip: `${namespace}_option_1_tooltip`, + selected: [ + { + text: `${namespace}_option_selected_message`, + }, + ], + }, + async (scene: BattleScene) => { + const encounter = scene.currentBattle.mysteryEncounter; + // Spawn standard trainer battle with memory mushroom reward + const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0]; - // Seed offsets to remove possibility of different trainers having exact same teams - let ret; - scene.executeWithSeedOffset(() => { - ret = initBattleWithEnemyConfig(scene, config); - }, scene.currentBattle.waveIndex * 100); - return ret; - }) - .withSimpleOption(async (scene: BattleScene) => { - const encounter = scene.currentBattle.mysteryEncounter; - // Spawn brutal fight with ROGUE/ULTRA/GREAT reward (can improve with luck) - const config: EnemyPartyConfig = encounter.enemyPartyConfigs[2]; + setEncounterRewards(scene, { + guaranteedModifierTypeFuncs: [ + modifierTypes.TM_COMMON, + modifierTypes.TM_GREAT, + modifierTypes.MEMORY_MUSHROOM, + ], + fillRemaining: true, + }); - // To avoid player level snowballing from picking this option - encounter.expMultiplier = 0.9; + // Seed offsets to remove possibility of different trainers having exact same teams + let ret; + scene.executeWithSeedOffset(() => { + ret = initBattleWithEnemyConfig(scene, config); + }, scene.currentBattle.waveIndex * 10); + return ret; + } + ) + .withSimpleOption( + { + buttonLabel: `${namespace}_option_2_label`, + buttonTooltip: `${namespace}_option_2_tooltip`, + selected: [ + { + text: `${namespace}_option_selected_message`, + }, + ], + }, + async (scene: BattleScene) => { + const encounter = scene.currentBattle.mysteryEncounter; + // Spawn hard fight with ULTRA/GREAT reward (can improve with luck) + const config: EnemyPartyConfig = encounter.enemyPartyConfigs[1]; - setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.GREAT], fillRemaining: true }); + setEncounterRewards(scene, { + guaranteedModifierTiers: [ + ModifierTier.ULTRA, + ModifierTier.GREAT, + ModifierTier.GREAT, + ], + fillRemaining: true, + }); - // Seed offsets to remove possibility of different trainers having exact same teams - let ret; - scene.executeWithSeedOffset(() => { - ret = initBattleWithEnemyConfig(scene, config); - }, scene.currentBattle.waveIndex * 1000); - return ret; - }) - .build(); + // Seed offsets to remove possibility of different trainers having exact same teams + let ret; + scene.executeWithSeedOffset(() => { + ret = initBattleWithEnemyConfig(scene, config); + }, scene.currentBattle.waveIndex * 100); + return ret; + } + ) + .withSimpleOption( + { + buttonLabel: `${namespace}_option_3_label`, + buttonTooltip: `${namespace}_option_3_tooltip`, + selected: [ + { + text: `${namespace}_option_selected_message`, + }, + ], + }, + async (scene: BattleScene) => { + const encounter = scene.currentBattle.mysteryEncounter; + // Spawn brutal fight with ROGUE/ULTRA/GREAT reward (can improve with luck) + const config: EnemyPartyConfig = encounter.enemyPartyConfigs[2]; + + // To avoid player level snowballing from picking this option + encounter.expMultiplier = 0.9; + + setEncounterRewards(scene, { + guaranteedModifierTiers: [ + ModifierTier.ROGUE, + ModifierTier.ULTRA, + ModifierTier.GREAT, + ], + fillRemaining: true, + }); + + // Seed offsets to remove possibility of different trainers having exact same teams + let ret; + scene.executeWithSeedOffset(() => { + ret = initBattleWithEnemyConfig(scene, config); + }, scene.currentBattle.waveIndex * 1000); + return ret; + } + ) + .withOutroDialogue([ + { + text: `${namespace}_outro_win`, + }, + ]) + .build(); diff --git a/src/data/mystery-encounters/mystery-encounter-dialogue.ts b/src/data/mystery-encounters/mystery-encounter-dialogue.ts index d9532ee4984..f1051c698d5 100644 --- a/src/data/mystery-encounters/mystery-encounter-dialogue.ts +++ b/src/data/mystery-encounters/mystery-encounter-dialogue.ts @@ -1,5 +1,4 @@ import { MysteryEncounterType } from "#enums/mystery-encounter-type"; -import { MysteriousChallengersDialogue } from "#app/data/mystery-encounters/dialogue/mysterious-challengers-dialogue"; import { MysteriousChestDialogue } from "#app/data/mystery-encounters/dialogue/mysterious-chest-dialogue"; import { TrainingSessionDialogue } from "#app/data/mystery-encounters/dialogue/training-session-dialogue"; import { SleepingSnorlaxDialogue } from "./dialogue/sleeping-snorlax-dialogue"; @@ -81,7 +80,6 @@ export default class MysteryEncounterDialogue { export const allMysteryEncounterDialogue: { [encounterType: number]: MysteryEncounterDialogue } = {}; export function initMysteryEncounterDialogue() { - allMysteryEncounterDialogue[MysteryEncounterType.MYSTERIOUS_CHALLENGERS] = MysteriousChallengersDialogue; allMysteryEncounterDialogue[MysteryEncounterType.MYSTERIOUS_CHEST] = MysteriousChestDialogue; allMysteryEncounterDialogue[MysteryEncounterType.TRAINING_SESSION] = TrainingSessionDialogue; allMysteryEncounterDialogue[MysteryEncounterType.SLEEPING_SNORLAX] = SleepingSnorlaxDialogue; From 71a047a1f66f4e78551bda6e577a9e363f9d7fa9 Mon Sep 17 00:00:00 2001 From: Felix Staud Date: Thu, 11 Jul 2024 14:10:21 -0700 Subject: [PATCH 07/19] migrate mysterious-chest encounter --- .../dialogue/mysterious-chest-dialogue.ts | 34 --- .../encounters/mysterious-chest.ts | 231 ++++++++++++------ .../mystery-encounter-dialogue.ts | 2 - 3 files changed, 153 insertions(+), 114 deletions(-) delete mode 100644 src/data/mystery-encounters/dialogue/mysterious-chest-dialogue.ts diff --git a/src/data/mystery-encounters/dialogue/mysterious-chest-dialogue.ts b/src/data/mystery-encounters/dialogue/mysterious-chest-dialogue.ts deleted file mode 100644 index ba8dafc6826..00000000000 --- a/src/data/mystery-encounters/dialogue/mysterious-chest-dialogue.ts +++ /dev/null @@ -1,34 +0,0 @@ -import MysteryEncounterDialogue from "#app/data/mystery-encounters/mystery-encounter-dialogue"; - -export const MysteriousChestDialogue: MysteryEncounterDialogue = { - intro: [ - { - text: "mysteryEncounter:mysterious_chest_intro_message" - } - ], - encounterOptionsDialogue: { - title: "mysteryEncounter:mysterious_chest_title", - description: "mysteryEncounter:mysterious_chest_description", - query: "mysteryEncounter:mysterious_chest_query", - options: [ - { - buttonLabel: "mysteryEncounter:mysterious_chest_option_1_label", - buttonTooltip: "mysteryEncounter:mysterious_chest_option_1_tooltip", - selected: [ - { - text: "mysteryEncounter:mysterious_chest_option_1_selected_message" - } - ] - }, - { - buttonLabel: "mysteryEncounter:mysterious_chest_option_2_label", - buttonTooltip: "mysteryEncounter:mysterious_chest_option_2_tooltip", - selected: [ - { - text: "mysteryEncounter:mysterious_chest_option_2_selected_message" - } - ] - } - ] - } -}; diff --git a/src/data/mystery-encounters/encounters/mysterious-chest.ts b/src/data/mystery-encounters/encounters/mysterious-chest.ts index 69ae93f312f..9dd4f56f623 100644 --- a/src/data/mystery-encounters/encounters/mysterious-chest.ts +++ b/src/data/mystery-encounters/encounters/mysterious-chest.ts @@ -4,90 +4,165 @@ import { leaveEncounterWithoutBattle, queueEncounterMessage, setEncounterRewards, - showEncounterText + showEncounterText, } from "#app/data/mystery-encounters/mystery-encounter-utils"; 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 BattleScene from "../../../battle-scene"; -import MysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier } from "../mystery-encounter"; +import MysteryEncounter, { + MysteryEncounterBuilder, + MysteryEncounterTier, +} from "../mystery-encounter"; import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; -export const MysteriousChestEncounter: MysteryEncounter = MysteryEncounterBuilder - .withEncounterType(MysteryEncounterType.MYSTERIOUS_CHEST) - .withEncounterTier(MysteryEncounterTier.COMMON) - .withIntroSpriteConfigs([ - { - spriteKey: "chest_blue", - fileRoot: "mystery-encounters", - hasShadow: true, - x: 4, - y: 8, - disableAnimation: true // Re-enabled after option select - } - ]) - .withHideIntroVisuals(false) - .withSceneWaveRangeRequirement(10, 180) // waves 2 to 180 - .withOption(new MysteryEncounterOptionBuilder() - .withPreOptionPhase(async (scene: BattleScene) => { - // Play animation - const introVisuals = scene.currentBattle.mysteryEncounter.introVisuals; - introVisuals.spriteConfigs[0].disableAnimation = false; - introVisuals.playAnim(); - }) - .withOptionPhase(async (scene: BattleScene) => { - // Open the chest - const roll = randSeedInt(100); - if (roll > 60) { - // Choose between 2 COMMON / 2 GREAT tier items (40%) - setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.COMMON, ModifierTier.COMMON, ModifierTier.GREAT, ModifierTier.GREAT] }); - // Display result message then proceed to rewards - queueEncounterMessage(scene, "mysteryEncounter:mysterious_chest_option_1_normal_result"); - leaveEncounterWithoutBattle(scene); - } else if (roll > 40) { - // Choose between 3 ULTRA tier items (20%) - setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA] }); - // Display result message then proceed to rewards - queueEncounterMessage(scene, "mysteryEncounter:mysterious_chest_option_1_good_result"); - leaveEncounterWithoutBattle(scene); - } else if (roll > 36) { - // Choose between 2 ROGUE tier items (4%) - setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ROGUE] }); - // Display result message then proceed to rewards - queueEncounterMessage(scene, "mysteryEncounter:mysterious_chest_option_1_great_result"); - leaveEncounterWithoutBattle(scene); - } else if (roll > 35) { - // Choose 1 MASTER tier item (1%) - setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.MASTER] }); - // Display result message then proceed to rewards - queueEncounterMessage(scene, "mysteryEncounter:mysterious_chest_option_1_amazing_result"); - leaveEncounterWithoutBattle(scene); - } else { - // Your highest level unfainted Pok�mon gets OHKO. Progress with no rewards (35%) - const highestLevelPokemon = getHighestLevelPlayerPokemon(scene, true); - koPlayerPokemon(highestLevelPokemon); - - scene.currentBattle.mysteryEncounter.setDialogueToken("pokeName", highestLevelPokemon.name); - // Show which Pokemon was KOed, then leave encounter with no rewards - // Does this synchronously so that game over doesn't happen over result message - await showEncounterText(scene, "mysteryEncounter:mysterious_chest_option_1_bad_result") - .then(() => { - if (scene.getParty().filter(p => p.isAllowedInBattle()).length === 0) { - // All pokemon fainted, game over - scene.clearPhaseQueue(); - scene.unshiftPhase(new GameOverPhase(scene)); - } else { - leaveEncounterWithoutBattle(scene); - } - }); - } - }) - .build() +export const MysteriousChestEncounter: MysteryEncounter = + MysteryEncounterBuilder.withEncounterType( + MysteryEncounterType.MYSTERIOUS_CHEST ) - .withSimpleOption(async (scene: BattleScene) => { - // Leave encounter with no rewards or exp - leaveEncounterWithoutBattle(scene, true); - return true; - }) - .build(); + .withEncounterTier(MysteryEncounterTier.COMMON) + .withSceneWaveRangeRequirement(10, 180) // waves 2 to 180 + .withHideIntroVisuals(false) + .withIntroSpriteConfigs([ + { + spriteKey: "chest_blue", + fileRoot: "mystery-encounters", + hasShadow: true, + x: 4, + y: 8, + disableAnimation: true, // Re-enabled after option select + }, + ]) + .withIntroDialogue([ + { + text: "mysteryEncounter:mysterious_chest_intro_message", + }, + ]) + .withTitle("mysteryEncounter:mysterious_chest_title") + .withDescription("mysteryEncounter:mysterious_chest_description") + .withQuery("mysteryEncounter:mysterious_chest_query") + .withOption( + new MysteryEncounterOptionBuilder() + .withDialogue({ + buttonLabel: "mysteryEncounter:mysterious_chest_option_1_label", + buttonTooltip: "mysteryEncounter:mysterious_chest_option_1_tooltip", + selected: [ + { + text: "mysteryEncounter:mysterious_chest_option_1_selected_message", + }, + ], + }) + .withPreOptionPhase(async (scene: BattleScene) => { + // Play animation + const introVisuals = + scene.currentBattle.mysteryEncounter.introVisuals; + introVisuals.spriteConfigs[0].disableAnimation = false; + introVisuals.playAnim(); + }) + .withOptionPhase(async (scene: BattleScene) => { + // Open the chest + const roll = randSeedInt(100); + if (roll > 60) { + // Choose between 2 COMMON / 2 GREAT tier items (40%) + setEncounterRewards(scene, { + guaranteedModifierTiers: [ + ModifierTier.COMMON, + ModifierTier.COMMON, + ModifierTier.GREAT, + ModifierTier.GREAT, + ], + }); + // Display result message then proceed to rewards + queueEncounterMessage( + scene, + "mysteryEncounter:mysterious_chest_option_1_normal_result" + ); + leaveEncounterWithoutBattle(scene); + } else if (roll > 40) { + // Choose between 3 ULTRA tier items (20%) + setEncounterRewards(scene, { + guaranteedModifierTiers: [ + ModifierTier.ULTRA, + ModifierTier.ULTRA, + ModifierTier.ULTRA, + ], + }); + // Display result message then proceed to rewards + queueEncounterMessage( + scene, + "mysteryEncounter:mysterious_chest_option_1_good_result" + ); + leaveEncounterWithoutBattle(scene); + } else if (roll > 36) { + // Choose between 2 ROGUE tier items (4%) + setEncounterRewards(scene, { + guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ROGUE], + }); + // Display result message then proceed to rewards + queueEncounterMessage( + scene, + "mysteryEncounter:mysterious_chest_option_1_great_result" + ); + leaveEncounterWithoutBattle(scene); + } else if (roll > 35) { + // Choose 1 MASTER tier item (1%) + setEncounterRewards(scene, { + guaranteedModifierTiers: [ModifierTier.MASTER], + }); + // Display result message then proceed to rewards + queueEncounterMessage( + scene, + "mysteryEncounter:mysterious_chest_option_1_amazing_result" + ); + leaveEncounterWithoutBattle(scene); + } else { + // Your highest level unfainted Pok�mon gets OHKO. Progress with no rewards (35%) + const highestLevelPokemon = getHighestLevelPlayerPokemon( + scene, + true + ); + koPlayerPokemon(highestLevelPokemon); + + scene.currentBattle.mysteryEncounter.setDialogueToken( + "pokeName", + highestLevelPokemon.name + ); + // Show which Pokemon was KOed, then leave encounter with no rewards + // Does this synchronously so that game over doesn't happen over result message + await showEncounterText( + scene, + "mysteryEncounter:mysterious_chest_option_1_bad_result" + ).then(() => { + if ( + scene.getParty().filter((p) => p.isAllowedInBattle()).length === + 0 + ) { + // All pokemon fainted, game over + scene.clearPhaseQueue(); + scene.unshiftPhase(new GameOverPhase(scene)); + } else { + leaveEncounterWithoutBattle(scene); + } + }); + } + }) + .build() + ) + .withSimpleOption( + { + buttonLabel: "mysteryEncounter:mysterious_chest_option_2_label", + buttonTooltip: "mysteryEncounter:mysterious_chest_option_2_tooltip", + selected: [ + { + text: "mysteryEncounter:mysterious_chest_option_2_selected_message", + }, + ], + }, + async (scene: BattleScene) => { + // Leave encounter with no rewards or exp + leaveEncounterWithoutBattle(scene, true); + return true; + } + ) + .build(); diff --git a/src/data/mystery-encounters/mystery-encounter-dialogue.ts b/src/data/mystery-encounters/mystery-encounter-dialogue.ts index f1051c698d5..c5663eef6ba 100644 --- a/src/data/mystery-encounters/mystery-encounter-dialogue.ts +++ b/src/data/mystery-encounters/mystery-encounter-dialogue.ts @@ -1,5 +1,4 @@ import { MysteryEncounterType } from "#enums/mystery-encounter-type"; -import { MysteriousChestDialogue } from "#app/data/mystery-encounters/dialogue/mysterious-chest-dialogue"; import { TrainingSessionDialogue } from "#app/data/mystery-encounters/dialogue/training-session-dialogue"; import { SleepingSnorlaxDialogue } from "./dialogue/sleeping-snorlax-dialogue"; import { ShadyVitaminDealerDialogue } from "#app/data/mystery-encounters/dialogue/shady-vitamin-dealer"; @@ -80,7 +79,6 @@ export default class MysteryEncounterDialogue { export const allMysteryEncounterDialogue: { [encounterType: number]: MysteryEncounterDialogue } = {}; export function initMysteryEncounterDialogue() { - allMysteryEncounterDialogue[MysteryEncounterType.MYSTERIOUS_CHEST] = MysteriousChestDialogue; allMysteryEncounterDialogue[MysteryEncounterType.TRAINING_SESSION] = TrainingSessionDialogue; allMysteryEncounterDialogue[MysteryEncounterType.SLEEPING_SNORLAX] = SleepingSnorlaxDialogue; allMysteryEncounterDialogue[MysteryEncounterType.SHADY_VITAMIN_DEALER] = ShadyVitaminDealerDialogue; From 19d96ed381b2aea7bbb17f2d52bf2cc843491730 Mon Sep 17 00:00:00 2001 From: Felix Staud Date: Thu, 11 Jul 2024 14:39:18 -0700 Subject: [PATCH 08/19] migrate shady-vitamin-dealer encounter --- src/battle-scene.ts | 4 +- .../dialogue/shady-vitamin-dealer.ts | 42 -- .../encounters/shady-vitamin-dealer.ts | 446 +++++++++++------- .../mystery-encounter-dialogue.ts | 2 - 4 files changed, 273 insertions(+), 221 deletions(-) delete mode 100644 src/data/mystery-encounters/dialogue/shady-vitamin-dealer.ts diff --git a/src/battle-scene.ts b/src/battle-scene.ts index d3eac7fc973..be0e83b7976 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -2646,7 +2646,7 @@ export default class BattleScene extends SceneBase { if (encounter) { encounter = new MysteryEncounter(encounter); - encounter.meetsRequirements(this); + encounter.populateDialogueTokensFromRequirements(this); return encounter; } @@ -2674,7 +2674,7 @@ export default class BattleScene extends SceneBase { tier = Overrides.MYSTERY_ENCOUNTER_TIER_OVERRIDE; } - let availableEncounters = []; + let availableEncounters: MysteryEncounter[] = []; // New encounter will never be the same as the most recent encounter const previousEncounter = this.mysteryEncounterData.encounteredEvents?.length > 0 ? this.mysteryEncounterData.encounteredEvents[this.mysteryEncounterData.encounteredEvents.length - 1][0] : null; const biomeMysteryEncounters = mysteryEncountersByBiome.get(this.arena.biomeType); diff --git a/src/data/mystery-encounters/dialogue/shady-vitamin-dealer.ts b/src/data/mystery-encounters/dialogue/shady-vitamin-dealer.ts deleted file mode 100644 index 52b9741caf8..00000000000 --- a/src/data/mystery-encounters/dialogue/shady-vitamin-dealer.ts +++ /dev/null @@ -1,42 +0,0 @@ -import MysteryEncounterDialogue from "#app/data/mystery-encounters/mystery-encounter-dialogue"; - -export const ShadyVitaminDealerDialogue: MysteryEncounterDialogue = { - intro: [ - { - text: "mysteryEncounter:shady_vitamin_dealer_intro_message" - }, - { - text: "mysteryEncounter:shady_vitamin_dealer_intro_dialogue", - speaker: "mysteryEncounter:shady_vitamin_dealer_speaker" - } - ], - encounterOptionsDialogue: { - title: "mysteryEncounter:shady_vitamin_dealer_title", - description: "mysteryEncounter:shady_vitamin_dealer_description", - query: "mysteryEncounter:shady_vitamin_dealer_query", - options: [ - { - buttonLabel: "mysteryEncounter:shady_vitamin_dealer_option_1_label", - buttonTooltip: "mysteryEncounter:shady_vitamin_dealer_option_1_tooltip", - selected: [ - { - text: "mysteryEncounter:shady_vitamin_dealer_option_selected" - } - ] - }, - { - buttonLabel: "mysteryEncounter:shady_vitamin_dealer_option_2_label", - buttonTooltip: "mysteryEncounter:shady_vitamin_dealer_option_2_tooltip", - selected: [ - { - text: "mysteryEncounter:shady_vitamin_dealer_option_selected" - } - ] - }, - { - buttonLabel: "mysteryEncounter:shady_vitamin_dealer_option_3_label", - buttonTooltip: "mysteryEncounter:shady_vitamin_dealer_option_3_tooltip" - } - ] - } -}; diff --git a/src/data/mystery-encounters/encounters/shady-vitamin-dealer.ts b/src/data/mystery-encounters/encounters/shady-vitamin-dealer.ts index 6ab668d73a6..773c4b97b0e 100644 --- a/src/data/mystery-encounters/encounters/shady-vitamin-dealer.ts +++ b/src/data/mystery-encounters/encounters/shady-vitamin-dealer.ts @@ -2,7 +2,8 @@ import { generateModifierTypeOption, leaveEncounterWithoutBattle, queueEncounterMessage, - selectPokemonForOption, setEncounterExp, + selectPokemonForOption, + setEncounterExp, updatePlayerMoney, } from "#app/data/mystery-encounters/mystery-encounter-utils"; import { StatusEffect } from "#app/data/status-effect"; @@ -11,184 +12,279 @@ import { modifierTypes } from "#app/modifier/modifier-type"; import { randSeedInt } from "#app/utils"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { Species } from "#enums/species"; -import BattleScene from "../../../battle-scene"; -import MysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier } from "../mystery-encounter"; -import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; -import { - MoneyRequirement -} from "../mystery-encounter-requirements"; import i18next from "i18next"; +import BattleScene from "../../../battle-scene"; +import MysteryEncounter, { + MysteryEncounterBuilder, + MysteryEncounterTier, +} from "../mystery-encounter"; +import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; +import { MoneyRequirement } from "../mystery-encounter-requirements"; -export const ShadyVitaminDealerEncounter: MysteryEncounter = MysteryEncounterBuilder - .withEncounterType(MysteryEncounterType.SHADY_VITAMIN_DEALER) - .withEncounterTier(MysteryEncounterTier.COMMON) - .withIntroSpriteConfigs([ - { - spriteKey: Species.KROOKODILE.toString(), - fileRoot: "pokemon", - hasShadow: true, - repeat: true, - x: 10, - y: -1 - }, - { - spriteKey: "b2w2_veteran_m", - fileRoot: "mystery-encounters", - hasShadow: true, - x: -10, - y: 2 - } - ]) - .withSceneWaveRangeRequirement(10, 180) - .withPrimaryPokemonStatusEffectRequirement([StatusEffect.NONE]) // Pokemon must not have status - .withPrimaryPokemonHealthRatioRequirement([0.34, 1]) // Pokemon must have above 1/3rd HP - .withOption(new MysteryEncounterOptionBuilder() - .withSceneMoneyRequirement(0, 2) // Wave scaling money multiplier of 2 - .withPreOptionPhase(async (scene: BattleScene): Promise => { - const encounter = scene.currentBattle.mysteryEncounter; - const onPokemonSelected = (pokemon: PlayerPokemon) => { - // Update money - updatePlayerMoney(scene, -(encounter.options[0].requirements[0] as MoneyRequirement).requiredMoney); - // Calculate modifiers and dialogue tokens - const modifiers = [ - generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER).type, - generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER).type - ]; - encounter.setDialogueToken("boost1", modifiers[0].name); - encounter.setDialogueToken("boost2", modifiers[1].name); - encounter.misc = { - chosenPokemon: pokemon, - modifiers: modifiers - }; - }; +export const ShadyVitaminDealerEncounter: MysteryEncounter = + MysteryEncounterBuilder.withEncounterType( + MysteryEncounterType.SHADY_VITAMIN_DEALER + ) + .withEncounterTier(MysteryEncounterTier.COMMON) + .withSceneWaveRangeRequirement(10, 180) + .withPrimaryPokemonStatusEffectRequirement([StatusEffect.NONE]) // Pokemon must not have status + .withPrimaryPokemonHealthRatioRequirement([0.34, 1]) // Pokemon must have above 1/3rd HP + .withIntroSpriteConfigs([ + { + spriteKey: Species.KROOKODILE.toString(), + fileRoot: "pokemon", + hasShadow: true, + repeat: true, + x: 10, + y: -1, + }, + { + spriteKey: "b2w2_veteran_m", + fileRoot: "mystery-encounters", + hasShadow: true, + x: -10, + y: 2, + }, + ]) + .withIntroDialogue([ + { + text: "mysteryEncounter:shady_vitamin_dealer_intro_message", + }, + { + text: "mysteryEncounter:shady_vitamin_dealer_intro_dialogue", + speaker: "mysteryEncounter:shady_vitamin_dealer_speaker", + }, + ]) + .withTitle("mysteryEncounter:shady_vitamin_dealer_title") + .withDescription("mysteryEncounter:shady_vitamin_dealer_description") + .withQuery("mysteryEncounter:shady_vitamin_dealer_query") + .withOption( + new MysteryEncounterOptionBuilder() + .withSceneMoneyRequirement(0, 2) // Wave scaling money multiplier of 2 + .withDialogue({ + buttonLabel: "mysteryEncounter:shady_vitamin_dealer_option_1_label", + buttonTooltip: + "mysteryEncounter:shady_vitamin_dealer_option_1_tooltip", + selected: [ + { + text: "mysteryEncounter:shady_vitamin_dealer_option_selected", + }, + ], + }) + .withPreOptionPhase(async (scene: BattleScene): Promise => { + const encounter = scene.currentBattle.mysteryEncounter; + const onPokemonSelected = (pokemon: PlayerPokemon) => { + // Update money + updatePlayerMoney( + scene, + -(encounter.options[0].requirements[0] as MoneyRequirement) + .requiredMoney + ); + // Calculate modifiers and dialogue tokens + const modifiers = [ + generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER) + .type, + generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER) + .type, + ]; + encounter.setDialogueToken("boost1", modifiers[0].name); + encounter.setDialogueToken("boost2", modifiers[1].name); + encounter.misc = { + chosenPokemon: pokemon, + modifiers: modifiers, + }; + }; - // Only Pokemon that can gain benefits are above 1/3rd HP with no status - const selectableFilter = (pokemon: Pokemon) => { - // If pokemon meets primary pokemon reqs, it can be selected - const meetsReqs = encounter.pokemonMeetsPrimaryRequirements(scene, pokemon); - if (!meetsReqs) { - return i18next.t("mysteryEncounter:shady_vitamin_dealer_invalid_selection"); - } + // Only Pokemon that can gain benefits are above 1/3rd HP with no status + const selectableFilter = (pokemon: Pokemon) => { + // If pokemon meets primary pokemon reqs, it can be selected + const meetsReqs = encounter.pokemonMeetsPrimaryRequirements( + scene, + pokemon + ); + if (!meetsReqs) { + return i18next.t( + "mysteryEncounter:shady_vitamin_dealer_invalid_selection" + ); + } - return null; - }; + return null; + }; - return selectPokemonForOption(scene, onPokemonSelected, null, selectableFilter); - }) - .withOptionPhase(async (scene: BattleScene) => { - // Choose Cheap Option - const encounter = scene.currentBattle.mysteryEncounter; - const chosenPokemon = encounter.misc.chosenPokemon; - const modifiers = encounter.misc.modifiers; + return selectPokemonForOption( + scene, + onPokemonSelected, + null, + selectableFilter + ); + }) + .withOptionPhase(async (scene: BattleScene) => { + // Choose Cheap Option + const encounter = scene.currentBattle.mysteryEncounter; + const chosenPokemon = encounter.misc.chosenPokemon; + const modifiers = encounter.misc.modifiers; - for (const modType of modifiers) { - const modifier = modType.newModifier(chosenPokemon); - await scene.addModifier(modifier, true, false, false, true); + for (const modType of modifiers) { + const modifier = modType.newModifier(chosenPokemon); + await scene.addModifier(modifier, true, false, false, true); + } + scene.updateModifiers(true); + + leaveEncounterWithoutBattle(scene); + }) + .withPostOptionPhase(async (scene: BattleScene) => { + // Damage and status applied after dealer leaves (to make thematic sense) + const encounter = scene.currentBattle.mysteryEncounter; + const chosenPokemon = encounter.misc.chosenPokemon; + + // Pokemon takes 1/3 max HP damage + const damage = Math.round(chosenPokemon.getMaxHp() / 3); + chosenPokemon.hp = Math.max(chosenPokemon.hp - damage, 0); + + // Roll for poison (80%) + if (randSeedInt(10) < 8) { + if (chosenPokemon.trySetStatus(StatusEffect.TOXIC)) { + // Toxic applied + queueEncounterMessage( + scene, + "mysteryEncounter:shady_vitamin_dealer_bad_poison" + ); + } else { + // Pokemon immune or something else prevents status + queueEncounterMessage( + scene, + "mysteryEncounter:shady_vitamin_dealer_damage_only" + ); + } + } else { + queueEncounterMessage( + scene, + "mysteryEncounter:shady_vitamin_dealer_damage_only" + ); + } + + setEncounterExp(scene, [chosenPokemon.id], 100); + + chosenPokemon.updateInfo(); + }) + .build() + ) + .withOption( + new MysteryEncounterOptionBuilder() + .withDialogue({ + buttonLabel: "mysteryEncounter:shady_vitamin_dealer_option_2_label", + buttonTooltip: + "mysteryEncounter:shady_vitamin_dealer_option_2_tooltip", + selected: [ + { + text: "mysteryEncounter:shady_vitamin_dealer_option_selected", + }, + ], + }) + .withSceneMoneyRequirement(0, 5) // Wave scaling money multiplier of 5 + .withPreOptionPhase(async (scene: BattleScene): Promise => { + const encounter = scene.currentBattle.mysteryEncounter; + const onPokemonSelected = (pokemon: PlayerPokemon) => { + // Update money + updatePlayerMoney( + scene, + -(encounter.options[1].requirements[0] as MoneyRequirement) + .requiredMoney + ); + // Calculate modifiers and dialogue tokens + const modifiers = [ + generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER) + .type, + generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER) + .type, + ]; + encounter.setDialogueToken("boost1", modifiers[0].name); + encounter.setDialogueToken("boost2", modifiers[1].name); + encounter.misc = { + chosenPokemon: pokemon, + modifiers: modifiers, + }; + }; + + // Only Pokemon that can gain benefits are above 1/3rd HP with no status + const selectableFilter = (pokemon: Pokemon) => { + // If pokemon meets primary pokemon reqs, it can be selected + const meetsReqs = encounter.pokemonMeetsPrimaryRequirements( + scene, + pokemon + ); + if (!meetsReqs) { + return i18next.t( + "mysteryEncounter:shady_vitamin_dealer_invalid_selection" + ); + } + + return null; + }; + + return selectPokemonForOption( + scene, + onPokemonSelected, + null, + selectableFilter + ); + }) + .withOptionPhase(async (scene: BattleScene) => { + // Choose Expensive Option + const encounter = scene.currentBattle.mysteryEncounter; + const chosenPokemon = encounter.misc.chosenPokemon; + const modifiers = encounter.misc.modifiers; + + for (const modType of modifiers) { + const modifier = modType.newModifier(chosenPokemon); + await scene.addModifier(modifier, true, false, false, true); + } + scene.updateModifiers(true); + + leaveEncounterWithoutBattle(scene); + }) + .withPostOptionPhase(async (scene: BattleScene) => { + // Status applied after dealer leaves (to make thematic sense) + const encounter = scene.currentBattle.mysteryEncounter; + const chosenPokemon = encounter.misc.chosenPokemon; + + // Roll for poison (20%) + if (randSeedInt(10) < 2) { + if (chosenPokemon.trySetStatus(StatusEffect.POISON)) { + // Poison applied + queueEncounterMessage( + scene, + "mysteryEncounter:shady_vitamin_dealer_poison" + ); + } else { + // Pokemon immune or something else prevents status + queueEncounterMessage( + scene, + "mysteryEncounter:shady_vitamin_dealer_no_bad_effects" + ); + } + } else { + queueEncounterMessage( + scene, + "mysteryEncounter:shady_vitamin_dealer_no_bad_effects" + ); + } + + setEncounterExp(scene, [chosenPokemon.id], 100); + + chosenPokemon.updateInfo(); + }) + .build() + ) + .withSimpleOption( + { + buttonLabel: "mysteryEncounter:shady_vitamin_dealer_option_3_label", + buttonTooltip: "mysteryEncounter:shady_vitamin_dealer_option_3_tooltip", + }, + async (scene: BattleScene) => { + // Leave encounter with no rewards or exp + leaveEncounterWithoutBattle(scene, true); + return true; } - scene.updateModifiers(true); - - leaveEncounterWithoutBattle(scene); - }) - .withPostOptionPhase(async (scene: BattleScene) => { - // Damage and status applied after dealer leaves (to make thematic sense) - const encounter = scene.currentBattle.mysteryEncounter; - const chosenPokemon = encounter.misc.chosenPokemon; - - // Pokemon takes 1/3 max HP damage - const damage = Math.round(chosenPokemon.getMaxHp() / 3); - chosenPokemon.hp = Math.max(chosenPokemon.hp - damage, 0); - - // Roll for poison (80%) - if (randSeedInt(10) < 8) { - if (chosenPokemon.trySetStatus(StatusEffect.TOXIC)) { - // Toxic applied - queueEncounterMessage(scene, "mysteryEncounter:shady_vitamin_dealer_bad_poison"); - } else { - // Pokemon immune or something else prevents status - queueEncounterMessage(scene, "mysteryEncounter:shady_vitamin_dealer_damage_only"); - } - } else { - queueEncounterMessage(scene, "mysteryEncounter:shady_vitamin_dealer_damage_only"); - } - - setEncounterExp(scene, [chosenPokemon.id], 100); - - chosenPokemon.updateInfo(); - }) - .build()) - .withOption(new MysteryEncounterOptionBuilder() - .withSceneMoneyRequirement(0, 5) // Wave scaling money multiplier of 5 - .withPreOptionPhase(async (scene: BattleScene): Promise => { - const encounter = scene.currentBattle.mysteryEncounter; - const onPokemonSelected = (pokemon: PlayerPokemon) => { - // Update money - updatePlayerMoney(scene, -(encounter.options[1].requirements[0] as MoneyRequirement).requiredMoney); - // Calculate modifiers and dialogue tokens - const modifiers = [ - generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER).type, - generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER).type - ]; - encounter.setDialogueToken("boost1", modifiers[0].name); - encounter.setDialogueToken("boost2", modifiers[1].name); - encounter.misc = { - chosenPokemon: pokemon, - modifiers: modifiers - }; - }; - - // Only Pokemon that can gain benefits are above 1/3rd HP with no status - const selectableFilter = (pokemon: Pokemon) => { - // If pokemon meets primary pokemon reqs, it can be selected - const meetsReqs = encounter.pokemonMeetsPrimaryRequirements(scene, pokemon); - if (!meetsReqs) { - return i18next.t("mysteryEncounter:shady_vitamin_dealer_invalid_selection"); - } - - return null; - }; - - return selectPokemonForOption(scene, onPokemonSelected, null, selectableFilter); - }) - .withOptionPhase(async (scene: BattleScene) => { - // Choose Expensive Option - const encounter = scene.currentBattle.mysteryEncounter; - const chosenPokemon = encounter.misc.chosenPokemon; - const modifiers = encounter.misc.modifiers; - - for (const modType of modifiers) { - const modifier = modType.newModifier(chosenPokemon); - await scene.addModifier(modifier, true, false, false, true); - } - scene.updateModifiers(true); - - leaveEncounterWithoutBattle(scene); - }) - .withPostOptionPhase(async (scene: BattleScene) => { - // Status applied after dealer leaves (to make thematic sense) - const encounter = scene.currentBattle.mysteryEncounter; - const chosenPokemon = encounter.misc.chosenPokemon; - - // Roll for poison (20%) - if (randSeedInt(10) < 2) { - if (chosenPokemon.trySetStatus(StatusEffect.POISON)) { - // Poison applied - queueEncounterMessage(scene, "mysteryEncounter:shady_vitamin_dealer_poison"); - } else { - // Pokemon immune or something else prevents status - queueEncounterMessage(scene, "mysteryEncounter:shady_vitamin_dealer_no_bad_effects"); - } - } else { - queueEncounterMessage(scene, "mysteryEncounter:shady_vitamin_dealer_no_bad_effects"); - } - - setEncounterExp(scene, [chosenPokemon.id], 100); - - chosenPokemon.updateInfo(); - }) - .build()) - .withSimpleOption(async (scene: BattleScene) => { - // Leave encounter with no rewards or exp - leaveEncounterWithoutBattle(scene, true); - return true; - }) - .build(); + ) + .build(); diff --git a/src/data/mystery-encounters/mystery-encounter-dialogue.ts b/src/data/mystery-encounters/mystery-encounter-dialogue.ts index c5663eef6ba..f44921ba677 100644 --- a/src/data/mystery-encounters/mystery-encounter-dialogue.ts +++ b/src/data/mystery-encounters/mystery-encounter-dialogue.ts @@ -1,7 +1,6 @@ import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { TrainingSessionDialogue } from "#app/data/mystery-encounters/dialogue/training-session-dialogue"; import { SleepingSnorlaxDialogue } from "./dialogue/sleeping-snorlax-dialogue"; -import { ShadyVitaminDealerDialogue } from "#app/data/mystery-encounters/dialogue/shady-vitamin-dealer"; import { TextStyle } from "#app/ui/text"; export class TextDisplay { @@ -81,5 +80,4 @@ export const allMysteryEncounterDialogue: { [encounterType: number]: MysteryEnco export function initMysteryEncounterDialogue() { allMysteryEncounterDialogue[MysteryEncounterType.TRAINING_SESSION] = TrainingSessionDialogue; allMysteryEncounterDialogue[MysteryEncounterType.SLEEPING_SNORLAX] = SleepingSnorlaxDialogue; - allMysteryEncounterDialogue[MysteryEncounterType.SHADY_VITAMIN_DEALER] = ShadyVitaminDealerDialogue; } From 2d4269732103eac8c6dadc93211c06ed1808188a Mon Sep 17 00:00:00 2001 From: Felix Staud Date: Thu, 11 Jul 2024 14:44:31 -0700 Subject: [PATCH 09/19] migrate sleeping snorlax encounter --- .../dialogue/sleeping-snorlax-dialogue.ts | 39 --- .../encounters/sleeping-snorlax.ts | 256 +++++++++++------- .../mystery-encounter-dialogue.ts | 2 - 3 files changed, 159 insertions(+), 138 deletions(-) delete mode 100644 src/data/mystery-encounters/dialogue/sleeping-snorlax-dialogue.ts diff --git a/src/data/mystery-encounters/dialogue/sleeping-snorlax-dialogue.ts b/src/data/mystery-encounters/dialogue/sleeping-snorlax-dialogue.ts deleted file mode 100644 index c10835f728e..00000000000 --- a/src/data/mystery-encounters/dialogue/sleeping-snorlax-dialogue.ts +++ /dev/null @@ -1,39 +0,0 @@ -import MysteryEncounterDialogue from "#app/data/mystery-encounters/mystery-encounter-dialogue"; - -export const SleepingSnorlaxDialogue: MysteryEncounterDialogue = { - intro: [ - { - text: "mysteryEncounter:sleeping_snorlax_intro_message" - } - ], - encounterOptionsDialogue: { - title: "mysteryEncounter:sleeping_snorlax_title", - description: "mysteryEncounter:sleeping_snorlax_description", - query: "mysteryEncounter:sleeping_snorlax_query", - options: [ - { - buttonLabel: "mysteryEncounter:sleeping_snorlax_option_1_label", - buttonTooltip: "mysteryEncounter:sleeping_snorlax_option_1_tooltip", - selected: [ - { - text: "mysteryEncounter:sleeping_snorlax_option_1_selected_message" - } - ] - }, - { - buttonLabel: "mysteryEncounter:sleeping_snorlax_option_2_label", - buttonTooltip: "mysteryEncounter:sleeping_snorlax_option_2_tooltip", - selected: [ - { - text: "mysteryEncounter:sleeping_snorlax_option_2_selected_message" - } - ] - }, - { - buttonLabel: "mysteryEncounter:sleeping_snorlax_option_3_label", - buttonTooltip: "mysteryEncounter:sleeping_snorlax_option_3_tooltip", - disabledTooltip: "mysteryEncounter:sleeping_snorlax_option_3_disabled_tooltip" - } - ] - } -}; diff --git a/src/data/mystery-encounters/encounters/sleeping-snorlax.ts b/src/data/mystery-encounters/encounters/sleeping-snorlax.ts index 6a820812ae1..324beb35e99 100644 --- a/src/data/mystery-encounters/encounters/sleeping-snorlax.ts +++ b/src/data/mystery-encounters/encounters/sleeping-snorlax.ts @@ -1,6 +1,5 @@ -import { - modifierTypes -} from "#app/modifier/modifier-type"; +import { STEALING_MOVES } from "#app/data/mystery-encounters/requirements/requirement-groups"; +import { modifierTypes } from "#app/modifier/modifier-type"; import { BerryType } from "#enums/berry-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { Species } from "#enums/species"; @@ -8,106 +7,169 @@ import BattleScene from "../../../battle-scene"; import * as Utils from "../../../utils"; import { getPokemonSpecies } from "../../pokemon-species"; import { Status, StatusEffect } from "../../status-effect"; -import MysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier } from "../mystery-encounter"; +import MysteryEncounter, { + MysteryEncounterBuilder, + MysteryEncounterTier, +} from "../mystery-encounter"; import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; import { MoveRequirement } from "../mystery-encounter-requirements"; import { EnemyPartyConfig, - EnemyPokemonConfig, generateModifierTypeOption, + EnemyPokemonConfig, + generateModifierTypeOption, initBattleWithEnemyConfig, - leaveEncounterWithoutBattle, queueEncounterMessage, setEncounterExp, - setEncounterRewards + leaveEncounterWithoutBattle, + queueEncounterMessage, + setEncounterExp, + setEncounterRewards, } from "../mystery-encounter-utils"; -import { STEALING_MOVES } from "#app/data/mystery-encounters/requirements/requirement-groups"; -export const SleepingSnorlaxEncounter: MysteryEncounter = MysteryEncounterBuilder - .withEncounterType(MysteryEncounterType.SLEEPING_SNORLAX) - .withEncounterTier(MysteryEncounterTier.ULTRA) - .withIntroSpriteConfigs([ - { - spriteKey: Species.SNORLAX.toString(), - fileRoot: "pokemon", - hasShadow: true, - tint: 0.25, - scale: 1.5, - repeat: true, - y: 5 - } - ]) - .withSceneWaveRangeRequirement(10, 180) // waves 10 to 180 - .withCatchAllowed(true) - .withHideWildIntroMessage(true) - .withOnInit((scene: BattleScene) => { - const encounter = scene.currentBattle.mysteryEncounter; - console.log(encounter); +/** i18n namespace for the encounter */ +const namespace = "mysteryEncounter:sleeping_snorlax"; - // Calculate boss mon - const bossSpecies = getPokemonSpecies(Species.SNORLAX); - const pokemonConfig: EnemyPokemonConfig = { - species: bossSpecies, - isBoss: true, - status: StatusEffect.SLEEP - }; - const config: EnemyPartyConfig = { - levelAdditiveMultiplier: 2, - pokemonConfigs: [pokemonConfig] - }; - encounter.enemyPartyConfigs = [config]; - return true; - }) - .withSimpleOption(async (scene: BattleScene) => { - // Pick battle - // TODO: do we want special rewards for this? - // setCustomEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.LEFTOVERS], fillRemaining: true}); - await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0]); - }) - .withSimpleOption(async (scene: BattleScene) => { - const instance = scene.currentBattle.mysteryEncounter; - let roll: integer; - scene.executeWithSeedOffset(() => { - roll = Utils.randSeedInt(16, 0); - }, scene.currentBattle.waveIndex); - - // Half Snorlax exp to entire party - setEncounterExp(scene, scene.getParty().map(p => p.id), 98); - - if (roll > 4) { - // Fall asleep and get a sitrus berry (75%) - const p = instance.primaryPokemon; - p.status = new Status(StatusEffect.SLEEP, 0, 3); - p.updateInfo(true); - // const sitrus = (modifierTypes.BERRY?.() as ModifierTypeGenerator).generateType(scene.getParty(), [BerryType.SITRUS]); - const sitrus = generateModifierTypeOption(scene, modifierTypes.BERRY, [BerryType.SITRUS]); - - setEncounterRewards(scene, { guaranteedModifierTypeOptions: [sitrus], fillRemaining: false }); - queueEncounterMessage(scene, "mysteryEncounter:sleeping_snorlax_option_2_bad_result"); - leaveEncounterWithoutBattle(scene); - } else { - // Heal to full (25%) - for (const pokemon of scene.getParty()) { - pokemon.hp = pokemon.getMaxHp(); - pokemon.resetStatus(); - for (const move of pokemon.moveset) { - move.ppUsed = 0; - } - pokemon.updateInfo(true); - } - - queueEncounterMessage(scene, "mysteryEncounter:sleeping_snorlax_option_2_good_result"); - leaveEncounterWithoutBattle(scene); - } - }) - .withOption(new MysteryEncounterOptionBuilder() - .withPrimaryPokemonRequirement(new MoveRequirement(STEALING_MOVES)) - .withOptionPhase(async (scene: BattleScene) => { - // Steal the Snorlax's Leftovers - const instance = scene.currentBattle.mysteryEncounter; - setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.LEFTOVERS], fillRemaining: false }); - queueEncounterMessage(scene, "mysteryEncounter:sleeping_snorlax_option_3_good_result"); - // Snorlax exp to Pokemon that did the stealing - setEncounterExp(scene, [instance.primaryPokemon.id], 189); - leaveEncounterWithoutBattle(scene); - }) - .build() +export const SleepingSnorlaxEncounter: MysteryEncounter = + MysteryEncounterBuilder.withEncounterType( + MysteryEncounterType.SLEEPING_SNORLAX ) - .build(); + .withEncounterTier(MysteryEncounterTier.ULTRA) + .withSceneWaveRangeRequirement(10, 180) // waves 10 to 180 + .withCatchAllowed(true) + .withHideWildIntroMessage(true) + .withIntroSpriteConfigs([ + { + spriteKey: Species.SNORLAX.toString(), + fileRoot: "pokemon", + hasShadow: true, + tint: 0.25, + scale: 1.5, + repeat: true, + y: 5, + }, + ]) + .withIntroDialogue([ + { + text: `${namespace}_intro_message`, + }, + ]) + .withOnInit((scene: BattleScene) => { + const encounter = scene.currentBattle.mysteryEncounter; + console.log(encounter); + + // Calculate boss mon + const bossSpecies = getPokemonSpecies(Species.SNORLAX); + const pokemonConfig: EnemyPokemonConfig = { + species: bossSpecies, + isBoss: true, + status: StatusEffect.SLEEP, + }; + const config: EnemyPartyConfig = { + levelAdditiveMultiplier: 2, + pokemonConfigs: [pokemonConfig], + }; + encounter.enemyPartyConfigs = [config]; + return true; + }) + .withTitle(`${namespace}_title`) + .withDescription(`${namespace}_description`) + .withQuery(`${namespace}_query`) + .withSimpleOption( + { + buttonLabel: `${namespace}_option_1_label`, + buttonTooltip: `${namespace}_option_1_tooltip`, + selected: [ + { + text: `${namespace}_option_1_selected_message`, + }, + ], + }, + async (scene: BattleScene) => { + // Pick battle + // TODO: do we want special rewards for this? + // setCustomEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.LEFTOVERS], fillRemaining: true}); + await initBattleWithEnemyConfig( + scene, + scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0] + ); + } + ) + .withSimpleOption( + { + buttonLabel: `${namespace}_option_2_label`, + buttonTooltip: `${namespace}_option_2_tooltip`, + selected: [ + { + text: `${namespace}_option_2_selected_message`, + }, + ], + }, + async (scene: BattleScene) => { + const instance = scene.currentBattle.mysteryEncounter; + let roll: integer; + scene.executeWithSeedOffset(() => { + roll = Utils.randSeedInt(16, 0); + }, scene.currentBattle.waveIndex); + + // Half Snorlax exp to entire party + setEncounterExp( + scene, + scene.getParty().map((p) => p.id), + 98 + ); + + if (roll > 4) { + // Fall asleep and get a sitrus berry (75%) + const p = instance.primaryPokemon; + p.status = new Status(StatusEffect.SLEEP, 0, 3); + p.updateInfo(true); + // const sitrus = (modifierTypes.BERRY?.() as ModifierTypeGenerator).generateType(scene.getParty(), [BerryType.SITRUS]); + const sitrus = generateModifierTypeOption( + scene, + modifierTypes.BERRY, + [BerryType.SITRUS] + ); + + setEncounterRewards(scene, { + guaranteedModifierTypeOptions: [sitrus], + fillRemaining: false, + }); + queueEncounterMessage(scene, `${namespace}_option_2_bad_result`); + leaveEncounterWithoutBattle(scene); + } else { + // Heal to full (25%) + for (const pokemon of scene.getParty()) { + pokemon.hp = pokemon.getMaxHp(); + pokemon.resetStatus(); + for (const move of pokemon.moveset) { + move.ppUsed = 0; + } + pokemon.updateInfo(true); + } + + queueEncounterMessage(scene, `${namespace}_option_2_good_result`); + leaveEncounterWithoutBattle(scene); + } + } + ) + .withOption( + new MysteryEncounterOptionBuilder() + .withPrimaryPokemonRequirement(new MoveRequirement(STEALING_MOVES)) + .withDialogue({ + buttonLabel: `${namespace}_option_3_label`, + buttonTooltip: `${namespace}_option_3_tooltip`, + disabledTooltip: `${namespace}_option_3_disabled_tooltip`, + }) + .withOptionPhase(async (scene: BattleScene) => { + // Steal the Snorlax's Leftovers + const instance = scene.currentBattle.mysteryEncounter; + setEncounterRewards(scene, { + guaranteedModifierTypeFuncs: [modifierTypes.LEFTOVERS], + fillRemaining: false, + }); + queueEncounterMessage(scene, `${namespace}_option_3_good_result`); + // Snorlax exp to Pokemon that did the stealing + setEncounterExp(scene, [instance.primaryPokemon.id], 189); + leaveEncounterWithoutBattle(scene); + }) + .build() + ) + .build(); diff --git a/src/data/mystery-encounters/mystery-encounter-dialogue.ts b/src/data/mystery-encounters/mystery-encounter-dialogue.ts index f44921ba677..fcd2db8cc52 100644 --- a/src/data/mystery-encounters/mystery-encounter-dialogue.ts +++ b/src/data/mystery-encounters/mystery-encounter-dialogue.ts @@ -1,6 +1,5 @@ import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { TrainingSessionDialogue } from "#app/data/mystery-encounters/dialogue/training-session-dialogue"; -import { SleepingSnorlaxDialogue } from "./dialogue/sleeping-snorlax-dialogue"; import { TextStyle } from "#app/ui/text"; export class TextDisplay { @@ -79,5 +78,4 @@ export const allMysteryEncounterDialogue: { [encounterType: number]: MysteryEnco export function initMysteryEncounterDialogue() { allMysteryEncounterDialogue[MysteryEncounterType.TRAINING_SESSION] = TrainingSessionDialogue; - allMysteryEncounterDialogue[MysteryEncounterType.SLEEPING_SNORLAX] = SleepingSnorlaxDialogue; } From 39f98222a6a0a8a82b362f67b1f7b97ff9bcc327 Mon Sep 17 00:00:00 2001 From: Felix Staud Date: Thu, 11 Jul 2024 14:50:19 -0700 Subject: [PATCH 10/19] migrate training session encounter --- .../dialogue/training-session-dialogue.ts | 50 -- .../encounters/training-session.ts | 649 +++++++++++------- .../mystery-encounter-dialogue.ts | 3 - 3 files changed, 396 insertions(+), 306 deletions(-) delete mode 100644 src/data/mystery-encounters/dialogue/training-session-dialogue.ts diff --git a/src/data/mystery-encounters/dialogue/training-session-dialogue.ts b/src/data/mystery-encounters/dialogue/training-session-dialogue.ts deleted file mode 100644 index 87f30ca14c2..00000000000 --- a/src/data/mystery-encounters/dialogue/training-session-dialogue.ts +++ /dev/null @@ -1,50 +0,0 @@ -import MysteryEncounterDialogue from "#app/data/mystery-encounters/mystery-encounter-dialogue"; - -export const TrainingSessionDialogue: MysteryEncounterDialogue = { - intro: [ - { - text: "mysteryEncounter:training_session_intro_message" - } - ], - encounterOptionsDialogue: { - title: "mysteryEncounter:training_session_title", - description: "mysteryEncounter:training_session_description", - query: "mysteryEncounter:training_session_query", - options: [ - { - buttonLabel: "mysteryEncounter:training_session_option_1_label", - buttonTooltip: "mysteryEncounter:training_session_option_1_tooltip", - selected: [ - { - text: "mysteryEncounter:training_session_option_selected_message" - } - ] - }, - { - buttonLabel: "mysteryEncounter:training_session_option_2_label", - buttonTooltip: "mysteryEncounter:training_session_option_2_tooltip", - secondOptionPrompt: "mysteryEncounter:training_session_option_2_select_prompt", - selected: [ - { - text: "mysteryEncounter:training_session_option_selected_message" - } - ] - }, - { - buttonLabel: "mysteryEncounter:training_session_option_3_label", - buttonTooltip: "mysteryEncounter:training_session_option_3_tooltip", - secondOptionPrompt: "mysteryEncounter:training_session_option_3_select_prompt", - selected: [ - { - text: "mysteryEncounter:training_session_option_selected_message" - } - ] - } - ] - }, - outro: [ - { - text: "mysteryEncounter:training_session_outro_win" - } - ] -}; diff --git a/src/data/mystery-encounters/encounters/training-session.ts b/src/data/mystery-encounters/encounters/training-session.ts index 8030cbaf850..e9b0461857d 100644 --- a/src/data/mystery-encounters/encounters/training-session.ts +++ b/src/data/mystery-encounters/encounters/training-session.ts @@ -4,7 +4,7 @@ import { getEncounterText, initBattleWithEnemyConfig, selectPokemonForOption, - setEncounterRewards + setEncounterRewards, } from "#app/data/mystery-encounters/mystery-encounter-utils"; import { getNatureName, Nature } from "#app/data/nature"; import { speciesStarters } from "#app/data/pokemon-species"; @@ -20,270 +20,414 @@ import { randSeedShuffle } from "#app/utils"; import { BattlerTagType } from "#enums/battler-tag-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import BattleScene from "../../../battle-scene"; -import MysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier } from "../mystery-encounter"; +import MysteryEncounter, { + MysteryEncounterBuilder, + MysteryEncounterTier, +} from "../mystery-encounter"; import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; -export const TrainingSessionEncounter: MysteryEncounter = MysteryEncounterBuilder - .withEncounterType(MysteryEncounterType.TRAINING_SESSION) - .withEncounterTier(MysteryEncounterTier.ULTRA) - .withIntroSpriteConfigs([ - { - spriteKey: "training_gear", - fileRoot: "mystery-encounters", - hasShadow: true, - y: 3 - } - ]) - .withSceneWaveRangeRequirement(10, 180) // waves 10 to 180 - .withHideWildIntroMessage(true) - .withOption(new MysteryEncounterOptionBuilder() - .withPreOptionPhase(async (scene: BattleScene): Promise => { - const encounter = scene.currentBattle.mysteryEncounter; - const onPokemonSelected = (pokemon: PlayerPokemon) => { - encounter.misc = { - playerPokemon: pokemon - }; - }; - - return selectPokemonForOption(scene, onPokemonSelected); - }) - .withOptionPhase(async (scene: BattleScene) => { - const encounter = scene.currentBattle.mysteryEncounter; - const playerPokemon: PlayerPokemon = encounter.misc.playerPokemon; - - // Spawn light training session with chosen pokemon - // Every 50 waves, add +1 boss segment, capping at 5 - const segments = Math.min(2 + Math.floor(scene.currentBattle.waveIndex / 50), 5); - const modifiers = new ModifiersHolder(); - const config = getEnemyConfig(scene, playerPokemon, segments, modifiers); - scene.removePokemonFromPlayerParty(playerPokemon, false); - - const getIvName = (index: number) => { - switch (index) { - case Stat.HP: - return pokemonInfo.Stat["HPshortened"]; - case Stat.ATK: - return pokemonInfo.Stat["ATKshortened"]; - case Stat.DEF: - return pokemonInfo.Stat["DEFshortened"]; - case Stat.SPATK: - return pokemonInfo.Stat["SPATKshortened"]; - case Stat.SPDEF: - return pokemonInfo.Stat["SPDEFshortened"]; - case Stat.SPD: - return pokemonInfo.Stat["SPDshortened"]; - } - }; - - const onBeforeRewardsPhase = () => { - encounter.setDialogueToken("stat1", "-"); - encounter.setDialogueToken("stat2", "-"); - // Add the pokemon back to party with IV boost - const ivIndexes = []; - playerPokemon.ivs.forEach((iv, index) => { - if (iv < 31) { - ivIndexes.push({ iv: iv, index: index }); - } - }); - - // Improves 2 random non-maxed IVs - // +10 if IV is < 10, +5 if between 10-20, and +3 if > 20 - // A 0-4 starting IV will cap in 6 encounters (assuming you always rolled that IV) - // 5-14 starting IV caps in 5 encounters - // 15-19 starting IV caps in 4 encounters - // 20-24 starting IV caps in 3 encounters - // 25-27 starting IV caps in 2 encounters - let improvedCount = 0; - while (ivIndexes.length > 0 && improvedCount < 2) { - randSeedShuffle(ivIndexes); - const ivToChange = ivIndexes.pop(); - let newVal = ivToChange.iv; - if (improvedCount === 0) { - encounter.setDialogueToken("stat1", getIvName(ivToChange.index)); - } else { - encounter.setDialogueToken("stat2", getIvName(ivToChange.index)); - } - - // Corrects required encounter breakpoints to be continuous for all IV values - if (ivToChange.iv <= 21 && ivToChange.iv - 1 % 5 === 0) { - newVal += 1; - } - - newVal += ivToChange.iv <= 10 ? 10 : ivToChange.iv <= 20 ? 5 : 3; - newVal = Math.min(newVal, 31); - playerPokemon.ivs[ivToChange.index] = newVal; - improvedCount++; - } - - if (improvedCount > 0) { - playerPokemon.calculateStats(); - scene.gameData.updateSpeciesDexIvs(playerPokemon.species.getRootSpeciesId(true), playerPokemon.ivs); - scene.gameData.setPokemonCaught(playerPokemon, false); - } - - // Add pokemon and mods back - scene.getParty().push(playerPokemon); - for (const mod of modifiers.value) { - scene.addModifier(mod, true, false, false, true); - } - scene.updateModifiers(true); - scene.queueMessage(getEncounterText(scene, "mysteryEncounter:training_session_battle_finished_1"), null, true); - }; - - setEncounterRewards(scene, { fillRemaining: true }, null, onBeforeRewardsPhase); - - return initBattleWithEnemyConfig(scene, config); - }) - .build() +export const TrainingSessionEncounter: MysteryEncounter = + MysteryEncounterBuilder.withEncounterType( + MysteryEncounterType.TRAINING_SESSION ) - .withOption(new MysteryEncounterOptionBuilder() - .withPreOptionPhase(async (scene: BattleScene): Promise => { - // Open menu for selecting pokemon and Nature - const encounter = scene.currentBattle.mysteryEncounter; - const natures = new Array(25).fill(null).map((val, i) => i as Nature); - const onPokemonSelected = (pokemon: PlayerPokemon) => { - // Return the options for nature selection - return natures.map((nature: Nature) => { - const option: OptionSelectItem = { - label: getNatureName(nature, true, true, true, scene.uiTheme), - handler: () => { - // Pokemon and second option selected - encounter.setDialogueToken("nature", getNatureName(nature)); - encounter.misc = { - playerPokemon: pokemon, - chosenNature: nature - }; - return true; - } - }; - return option; - }); - }; - - return selectPokemonForOption(scene, onPokemonSelected); - }) - .withOptionPhase(async (scene: BattleScene) => { - const encounter = scene.currentBattle.mysteryEncounter; - const playerPokemon: PlayerPokemon = encounter.misc.playerPokemon; - - // Spawn medium training session with chosen pokemon - // Every 40 waves, add +1 boss segment, capping at 6 - const segments = Math.min(2 + Math.floor(scene.currentBattle.waveIndex / 40), 6); - const modifiers = new ModifiersHolder(); - const config = getEnemyConfig(scene, playerPokemon, segments, modifiers); - scene.removePokemonFromPlayerParty(playerPokemon, false); - - const onBeforeRewardsPhase = () => { - scene.queueMessage(getEncounterText(scene, "mysteryEncounter:training_session_battle_finished_2"), null, true); - // Add the pokemon back to party with Nature change - playerPokemon.setNature(encounter.misc.chosenNature); - scene.gameData.setPokemonCaught(playerPokemon, false); - - // Add pokemon and mods back - scene.getParty().push(playerPokemon); - for (const mod of modifiers.value) { - scene.addModifier(mod, true, false, false, true); - } - scene.updateModifiers(true); - }; - - setEncounterRewards(scene, { fillRemaining: true }, null, onBeforeRewardsPhase); - - return initBattleWithEnemyConfig(scene, config); - }) - .build() - ) - .withOption(new MysteryEncounterOptionBuilder() - .withPreOptionPhase(async (scene: BattleScene): Promise => { - // Open menu for selecting pokemon and ability to learn - const encounter = scene.currentBattle.mysteryEncounter; - const onPokemonSelected = (pokemon: PlayerPokemon) => { - // Return the options for ability selection - const speciesForm = !!pokemon.getFusionSpeciesForm() ? pokemon.getFusionSpeciesForm() : pokemon.getSpeciesForm(); - const abilityCount = speciesForm.getAbilityCount(); - const abilities = new Array(abilityCount).fill(null).map((val, i) => allAbilities[speciesForm.getAbility(i)]); - return abilities.map((ability: Ability, index) => { - const option: OptionSelectItem = { - label: ability.name, - handler: () => { - // Pokemon and ability selected - encounter.setDialogueToken("ability", ability.name); - encounter.misc = { - playerPokemon: pokemon, - abilityIndex: index - }; - return true; + .withEncounterTier(MysteryEncounterTier.ULTRA) + .withSceneWaveRangeRequirement(10, 180) // waves 10 to 180 + .withHideWildIntroMessage(true) + .withIntroSpriteConfigs([ + { + spriteKey: "training_gear", + fileRoot: "mystery-encounters", + hasShadow: true, + y: 3, + }, + ]) + .withIntroDialogue([ + { + text: "mysteryEncounter:training_session_intro_message", + }, + ]) + .withTitle("mysteryEncounter:training_session_title") + .withDescription("mysteryEncounter:training_session_description") + .withQuery("mysteryEncounter:training_session_query") + .withOption( + new MysteryEncounterOptionBuilder() + .withDialogue({ + buttonLabel: "mysteryEncounter:training_session_option_1_label", + buttonTooltip: "mysteryEncounter:training_session_option_1_tooltip", + selected: [ + { + text: "mysteryEncounter:training_session_option_selected_message", }, - onHover: () => { - scene.ui.showText(ability.description); + ], + }) + .withPreOptionPhase(async (scene: BattleScene): Promise => { + const encounter = scene.currentBattle.mysteryEncounter; + const onPokemonSelected = (pokemon: PlayerPokemon) => { + encounter.misc = { + playerPokemon: pokemon, + }; + }; + + return selectPokemonForOption(scene, onPokemonSelected); + }) + .withOptionPhase(async (scene: BattleScene) => { + const encounter = scene.currentBattle.mysteryEncounter; + const playerPokemon: PlayerPokemon = encounter.misc.playerPokemon; + + // Spawn light training session with chosen pokemon + // Every 50 waves, add +1 boss segment, capping at 5 + const segments = Math.min( + 2 + Math.floor(scene.currentBattle.waveIndex / 50), + 5 + ); + const modifiers = new ModifiersHolder(); + const config = getEnemyConfig( + scene, + playerPokemon, + segments, + modifiers + ); + scene.removePokemonFromPlayerParty(playerPokemon, false); + + const getIvName = (index: number) => { + switch (index) { + case Stat.HP: + return pokemonInfo.Stat["HPshortened"]; + case Stat.ATK: + return pokemonInfo.Stat["ATKshortened"]; + case Stat.DEF: + return pokemonInfo.Stat["DEFshortened"]; + case Stat.SPATK: + return pokemonInfo.Stat["SPATKshortened"]; + case Stat.SPDEF: + return pokemonInfo.Stat["SPDEFshortened"]; + case Stat.SPD: + return pokemonInfo.Stat["SPDshortened"]; } }; - return option; - }); - }; - return selectPokemonForOption(scene, onPokemonSelected); - }) - .withOptionPhase(async (scene: BattleScene) => { - const encounter = scene.currentBattle.mysteryEncounter; - const playerPokemon: PlayerPokemon = encounter.misc.playerPokemon; + const onBeforeRewardsPhase = () => { + encounter.setDialogueToken("stat1", "-"); + encounter.setDialogueToken("stat2", "-"); + // Add the pokemon back to party with IV boost + const ivIndexes = []; + playerPokemon.ivs.forEach((iv, index) => { + if (iv < 31) { + ivIndexes.push({ iv: iv, index: index }); + } + }); - // Spawn hard training session with chosen pokemon - // Every 30 waves, add +1 boss segment, capping at 6 - // Also starts with +1 to all stats - const segments = Math.min(2 + Math.floor(scene.currentBattle.waveIndex / 30), 6); - const modifiers = new ModifiersHolder(); - const config = getEnemyConfig(scene, playerPokemon, segments, modifiers); - config.pokemonConfigs[0].tags = [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON]; - scene.removePokemonFromPlayerParty(playerPokemon, false); + // Improves 2 random non-maxed IVs + // +10 if IV is < 10, +5 if between 10-20, and +3 if > 20 + // A 0-4 starting IV will cap in 6 encounters (assuming you always rolled that IV) + // 5-14 starting IV caps in 5 encounters + // 15-19 starting IV caps in 4 encounters + // 20-24 starting IV caps in 3 encounters + // 25-27 starting IV caps in 2 encounters + let improvedCount = 0; + while (ivIndexes.length > 0 && improvedCount < 2) { + randSeedShuffle(ivIndexes); + const ivToChange = ivIndexes.pop(); + let newVal = ivToChange.iv; + if (improvedCount === 0) { + encounter.setDialogueToken( + "stat1", + getIvName(ivToChange.index) + ); + } else { + encounter.setDialogueToken( + "stat2", + getIvName(ivToChange.index) + ); + } - const onBeforeRewardsPhase = () => { - scene.queueMessage(getEncounterText(scene, "mysteryEncounter:training_session_battle_finished_3"), null, true); - // Add the pokemon back to party with ability change - const abilityIndex = encounter.misc.abilityIndex; - if (!!playerPokemon.getFusionSpeciesForm()) { - playerPokemon.fusionAbilityIndex = abilityIndex; - if (speciesStarters.hasOwnProperty(playerPokemon.fusionSpecies.speciesId)) { - scene.gameData.starterData[playerPokemon.fusionSpecies.speciesId].abilityAttr |= abilityIndex !== 1 || playerPokemon.fusionSpecies.ability2 - ? Math.pow(2, playerPokemon.fusionAbilityIndex) - : AbilityAttr.ABILITY_HIDDEN; - } - } else { - playerPokemon.abilityIndex = abilityIndex; - if (speciesStarters.hasOwnProperty(playerPokemon.species.speciesId)) { - scene.gameData.starterData[playerPokemon.species.speciesId].abilityAttr |= abilityIndex !== 1 || playerPokemon.species.ability2 - ? Math.pow(2, playerPokemon.abilityIndex) - : AbilityAttr.ABILITY_HIDDEN; - } - } + // Corrects required encounter breakpoints to be continuous for all IV values + if (ivToChange.iv <= 21 && ivToChange.iv - (1 % 5) === 0) { + newVal += 1; + } - playerPokemon.getAbility(); - playerPokemon.calculateStats(); - scene.gameData.setPokemonCaught(playerPokemon, false); + newVal += ivToChange.iv <= 10 ? 10 : ivToChange.iv <= 20 ? 5 : 3; + newVal = Math.min(newVal, 31); + playerPokemon.ivs[ivToChange.index] = newVal; + improvedCount++; + } - // Add pokemon and mods back - scene.getParty().push(playerPokemon); - for (const mod of modifiers.value) { - scene.addModifier(mod, true, false, false, true); - } - scene.updateModifiers(true); - }; + if (improvedCount > 0) { + playerPokemon.calculateStats(); + scene.gameData.updateSpeciesDexIvs( + playerPokemon.species.getRootSpeciesId(true), + playerPokemon.ivs + ); + scene.gameData.setPokemonCaught(playerPokemon, false); + } - setEncounterRewards(scene, { fillRemaining: true }, null, onBeforeRewardsPhase); + // Add pokemon and mods back + scene.getParty().push(playerPokemon); + for (const mod of modifiers.value) { + scene.addModifier(mod, true, false, false, true); + } + scene.updateModifiers(true); + scene.queueMessage( + getEncounterText( + scene, + "mysteryEncounter:training_session_battle_finished_1" + ), + null, + true + ); + }; - return initBattleWithEnemyConfig(scene, config); - }) - .build() - ) - .build(); + setEncounterRewards( + scene, + { fillRemaining: true }, + null, + onBeforeRewardsPhase + ); -function getEnemyConfig(scene: BattleScene, playerPokemon: PlayerPokemon, segments: number, modifiers: ModifiersHolder): EnemyPartyConfig { + return initBattleWithEnemyConfig(scene, config); + }) + .build() + ) + .withOption( + new MysteryEncounterOptionBuilder() + .withDialogue({ + buttonLabel: "mysteryEncounter:training_session_option_2_label", + buttonTooltip: "mysteryEncounter:training_session_option_2_tooltip", + secondOptionPrompt: + "mysteryEncounter:training_session_option_2_select_prompt", + selected: [ + { + text: "mysteryEncounter:training_session_option_selected_message", + }, + ], + }) + .withPreOptionPhase(async (scene: BattleScene): Promise => { + // Open menu for selecting pokemon and Nature + const encounter = scene.currentBattle.mysteryEncounter; + const natures = new Array(25).fill(null).map((val, i) => i as Nature); + const onPokemonSelected = (pokemon: PlayerPokemon) => { + // Return the options for nature selection + return natures.map((nature: Nature) => { + const option: OptionSelectItem = { + label: getNatureName(nature, true, true, true, scene.uiTheme), + handler: () => { + // Pokemon and second option selected + encounter.setDialogueToken("nature", getNatureName(nature)); + encounter.misc = { + playerPokemon: pokemon, + chosenNature: nature, + }; + return true; + }, + }; + return option; + }); + }; + + return selectPokemonForOption(scene, onPokemonSelected); + }) + .withOptionPhase(async (scene: BattleScene) => { + const encounter = scene.currentBattle.mysteryEncounter; + const playerPokemon: PlayerPokemon = encounter.misc.playerPokemon; + + // Spawn medium training session with chosen pokemon + // Every 40 waves, add +1 boss segment, capping at 6 + const segments = Math.min( + 2 + Math.floor(scene.currentBattle.waveIndex / 40), + 6 + ); + const modifiers = new ModifiersHolder(); + const config = getEnemyConfig( + scene, + playerPokemon, + segments, + modifiers + ); + scene.removePokemonFromPlayerParty(playerPokemon, false); + + const onBeforeRewardsPhase = () => { + scene.queueMessage( + getEncounterText( + scene, + "mysteryEncounter:training_session_battle_finished_2" + ), + null, + true + ); + // Add the pokemon back to party with Nature change + playerPokemon.setNature(encounter.misc.chosenNature); + scene.gameData.setPokemonCaught(playerPokemon, false); + + // Add pokemon and mods back + scene.getParty().push(playerPokemon); + for (const mod of modifiers.value) { + scene.addModifier(mod, true, false, false, true); + } + scene.updateModifiers(true); + }; + + setEncounterRewards( + scene, + { fillRemaining: true }, + null, + onBeforeRewardsPhase + ); + + return initBattleWithEnemyConfig(scene, config); + }) + .build() + ) + .withOption( + new MysteryEncounterOptionBuilder() + .withDialogue({ + buttonLabel: "mysteryEncounter:training_session_option_3_label", + buttonTooltip: "mysteryEncounter:training_session_option_3_tooltip", + secondOptionPrompt: + "mysteryEncounter:training_session_option_3_select_prompt", + selected: [ + { + text: "mysteryEncounter:training_session_option_selected_message", + }, + ], + }) + .withPreOptionPhase(async (scene: BattleScene): Promise => { + // Open menu for selecting pokemon and ability to learn + const encounter = scene.currentBattle.mysteryEncounter; + const onPokemonSelected = (pokemon: PlayerPokemon) => { + // Return the options for ability selection + const speciesForm = !!pokemon.getFusionSpeciesForm() + ? pokemon.getFusionSpeciesForm() + : pokemon.getSpeciesForm(); + const abilityCount = speciesForm.getAbilityCount(); + const abilities = new Array(abilityCount) + .fill(null) + .map((val, i) => allAbilities[speciesForm.getAbility(i)]); + return abilities.map((ability: Ability, index) => { + const option: OptionSelectItem = { + label: ability.name, + handler: () => { + // Pokemon and ability selected + encounter.setDialogueToken("ability", ability.name); + encounter.misc = { + playerPokemon: pokemon, + abilityIndex: index, + }; + return true; + }, + onHover: () => { + scene.ui.showText(ability.description); + }, + }; + return option; + }); + }; + + return selectPokemonForOption(scene, onPokemonSelected); + }) + .withOptionPhase(async (scene: BattleScene) => { + const encounter = scene.currentBattle.mysteryEncounter; + const playerPokemon: PlayerPokemon = encounter.misc.playerPokemon; + + // Spawn hard training session with chosen pokemon + // Every 30 waves, add +1 boss segment, capping at 6 + // Also starts with +1 to all stats + const segments = Math.min( + 2 + Math.floor(scene.currentBattle.waveIndex / 30), + 6 + ); + const modifiers = new ModifiersHolder(); + const config = getEnemyConfig( + scene, + playerPokemon, + segments, + modifiers + ); + config.pokemonConfigs[0].tags = [ + BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON, + ]; + scene.removePokemonFromPlayerParty(playerPokemon, false); + + const onBeforeRewardsPhase = () => { + scene.queueMessage( + getEncounterText( + scene, + "mysteryEncounter:training_session_battle_finished_3" + ), + null, + true + ); + // Add the pokemon back to party with ability change + const abilityIndex = encounter.misc.abilityIndex; + if (!!playerPokemon.getFusionSpeciesForm()) { + playerPokemon.fusionAbilityIndex = abilityIndex; + if ( + speciesStarters.hasOwnProperty( + playerPokemon.fusionSpecies.speciesId + ) + ) { + scene.gameData.starterData[ + playerPokemon.fusionSpecies.speciesId + ].abilityAttr |= + abilityIndex !== 1 || playerPokemon.fusionSpecies.ability2 + ? Math.pow(2, playerPokemon.fusionAbilityIndex) + : AbilityAttr.ABILITY_HIDDEN; + } + } else { + playerPokemon.abilityIndex = abilityIndex; + if ( + speciesStarters.hasOwnProperty(playerPokemon.species.speciesId) + ) { + scene.gameData.starterData[ + playerPokemon.species.speciesId + ].abilityAttr |= + abilityIndex !== 1 || playerPokemon.species.ability2 + ? Math.pow(2, playerPokemon.abilityIndex) + : AbilityAttr.ABILITY_HIDDEN; + } + } + + playerPokemon.getAbility(); + playerPokemon.calculateStats(); + scene.gameData.setPokemonCaught(playerPokemon, false); + + // Add pokemon and mods back + scene.getParty().push(playerPokemon); + for (const mod of modifiers.value) { + scene.addModifier(mod, true, false, false, true); + } + scene.updateModifiers(true); + }; + + setEncounterRewards( + scene, + { fillRemaining: true }, + null, + onBeforeRewardsPhase + ); + + return initBattleWithEnemyConfig(scene, config); + }) + .build() + ) + .build(); + +function getEnemyConfig( + scene: BattleScene, + playerPokemon: PlayerPokemon, + segments: number, + modifiers: ModifiersHolder +): EnemyPartyConfig { playerPokemon.resetSummonData(); // Passes modifiers by reference - modifiers.value = scene.findModifiers(m => m instanceof PokemonHeldItemModifier - && (m as PokemonHeldItemModifier).pokemonId === playerPokemon.id) as PokemonHeldItemModifier[]; - const modifierTypes = modifiers.value.map(mod => mod.type) as PokemonHeldItemModifierType[]; + modifiers.value = scene.findModifiers( + (m) => + m instanceof PokemonHeldItemModifier && + (m as PokemonHeldItemModifier).pokemonId === playerPokemon.id + ) as PokemonHeldItemModifier[]; + const modifierTypes = modifiers.value.map( + (mod) => mod.type + ) as PokemonHeldItemModifierType[]; const data = new PokemonData(playerPokemon); return { @@ -295,15 +439,14 @@ function getEnemyConfig(scene: BattleScene, playerPokemon: PlayerPokemon, segmen formIndex: playerPokemon.formIndex, level: playerPokemon.level, dataSource: data, - modifierTypes: modifierTypes - } - ] + modifierTypes: modifierTypes, + }, + ], }; } class ModifiersHolder { public value: PokemonHeldItemModifier[] = []; - constructor() { - } + constructor() {} } diff --git a/src/data/mystery-encounters/mystery-encounter-dialogue.ts b/src/data/mystery-encounters/mystery-encounter-dialogue.ts index fcd2db8cc52..9e4943f37a2 100644 --- a/src/data/mystery-encounters/mystery-encounter-dialogue.ts +++ b/src/data/mystery-encounters/mystery-encounter-dialogue.ts @@ -1,5 +1,3 @@ -import { MysteryEncounterType } from "#enums/mystery-encounter-type"; -import { TrainingSessionDialogue } from "#app/data/mystery-encounters/dialogue/training-session-dialogue"; import { TextStyle } from "#app/ui/text"; export class TextDisplay { @@ -77,5 +75,4 @@ export default class MysteryEncounterDialogue { export const allMysteryEncounterDialogue: { [encounterType: number]: MysteryEncounterDialogue } = {}; export function initMysteryEncounterDialogue() { - allMysteryEncounterDialogue[MysteryEncounterType.TRAINING_SESSION] = TrainingSessionDialogue; } From 941a8e71d66848bc02ca06c1377146be1240380d Mon Sep 17 00:00:00 2001 From: Felix Staud Date: Thu, 11 Jul 2024 14:58:52 -0700 Subject: [PATCH 11/19] finishing touches --- .../mystery-encounter-dialogue.ts | 5 -- .../mystery-encounters/mystery-encounter.ts | 75 +++++++++++++++---- src/loading-scene.ts | 2 - src/overrides.ts | 4 +- src/test/vitest.setup.ts | 2 - 5 files changed, 61 insertions(+), 27 deletions(-) diff --git a/src/data/mystery-encounters/mystery-encounter-dialogue.ts b/src/data/mystery-encounters/mystery-encounter-dialogue.ts index 9e4943f37a2..d96aeb87ba6 100644 --- a/src/data/mystery-encounters/mystery-encounter-dialogue.ts +++ b/src/data/mystery-encounters/mystery-encounter-dialogue.ts @@ -71,8 +71,3 @@ export default class MysteryEncounterDialogue { } * */ - -export const allMysteryEncounterDialogue: { [encounterType: number]: MysteryEncounterDialogue } = {}; - -export function initMysteryEncounterDialogue() { -} diff --git a/src/data/mystery-encounters/mystery-encounter.ts b/src/data/mystery-encounters/mystery-encounter.ts index 0780aa33ae4..c367f2377b2 100644 --- a/src/data/mystery-encounters/mystery-encounter.ts +++ b/src/data/mystery-encounters/mystery-encounter.ts @@ -7,7 +7,6 @@ import MysteryEncounterIntroVisuals, { MysteryEncounterSpriteConfig } from "../. import * as Utils from "../../utils"; import { StatusEffect } from "../status-effect"; import MysteryEncounterDialogue, { - allMysteryEncounterDialogue, OptionTextDisplay } from "./mystery-encounter-dialogue"; import MysteryEncounterOption, { MysteryEncounterOptionBuilder, OptionPhaseCallback } from "./mystery-encounter-option"; @@ -137,17 +136,12 @@ export default class MysteryEncounter implements MysteryEncounter { Object.assign(this, encounter); } this.encounterTier = this.encounterTier ? this.encounterTier : MysteryEncounterTier.COMMON; - this.dialogue = Object.assign((this.dialogue ?? {}), allMysteryEncounterDialogue[this.encounterType] ?? {}); + this.dialogue = {}; this.encounterVariant = MysteryEncounterVariant.DEFAULT; this.requirements = this.requirements ? this.requirements : []; this.hideBattleIntroMessage = !isNullOrUndefined(this.hideBattleIntroMessage) ? this.hideBattleIntroMessage : false; this.hideIntroVisuals = !isNullOrUndefined(this.hideIntroVisuals) ? this.hideIntroVisuals : true; - // Populate options with respective dialogue - if (this.dialogue?.encounterOptionsDialogue) { - // this.options.forEach((o, i) => o.dialogue = this.dialogue.encounterOptionsDialogue.options[i]); - } - // Reset any dirty flags or encounter data this.lockEncounterRewardTiers = true; this.dialogueTokens = new Map; @@ -482,15 +476,37 @@ export class MysteryEncounterBuilder implements Partial { return this.withSceneRequirement(new PartySizeRequirement([min, max ?? min])); } + /** + * Add a primary pokemon requirement + * + * @param requirement {@linkcode EncounterPokemonRequirement} + * @returns + */ withPrimaryPokemonRequirement(requirement: EncounterPokemonRequirement): this & Required> { this.primaryPokemonRequirements.push(requirement); return Object.assign(this, { primaryPokemonRequirements: this.primaryPokemonRequirements }); } + /** + * Add a primary pokemon status effect requirement + * + * @param statusEffect the status effect/s to check + * @param minNumberOfPokemon minimum number of pokemon to have the effect + * @param invertQuery if true will invert the query + * @returns + */ withPrimaryPokemonStatusEffectRequirement(statusEffect: StatusEffect | StatusEffect[], minNumberOfPokemon: number = 1, invertQuery: boolean = false): this & Required> { return this.withPrimaryPokemonRequirement(new StatusEffectRequirement(statusEffect, minNumberOfPokemon, invertQuery)); } + /** + * Add a primary pokemon health ratio requirement + * + * @param requiredHealthRange the health range to check + * @param minNumberOfPokemon minimum number of pokemon to have the health range + * @param invertQuery if true will invert the query + * @returns + */ withPrimaryPokemonHealthRatioRequirement(requiredHealthRange: [number, number], minNumberOfPokemon: number = 1, invertQuery: boolean = false): this & Required> { return this.withPrimaryPokemonRequirement(new HealthRatioRequirement(requiredHealthRange, minNumberOfPokemon, invertQuery)); } @@ -579,12 +595,17 @@ export class MysteryEncounterBuilder implements Partial { return Object.assign(this, { hideIntroVisuals: hideIntroVisuals }); } + /** + * Add a title for the encounter + * + * @param title - title of the encounter + * @returns + */ withTitle(title: TemplateStringsArray | `mysteryEncounter:${string}`) { - const dialogue = this.dialogue ?? {}; - const encounterOptionsDialogue = this.dialogue?.encounterOptionsDialogue ?? {}; + const encounterOptionsDialogue = this.dialogue.encounterOptionsDialogue ?? {}; this.dialogue = { - ...dialogue, + ...this.dialogue, encounterOptionsDialogue: { ...encounterOptionsDialogue, title, @@ -594,12 +615,17 @@ export class MysteryEncounterBuilder implements Partial { return this; } + /** + * Add a description of the encounter + * + * @param description - description of the encounter + * @returns + */ withDescription(description: TemplateStringsArray | `mysteryEncounter:${string}`) { - const dialogue = this.dialogue ?? {}; - const encounterOptionsDialogue = this.dialogue?.encounterOptionsDialogue ?? {}; + const encounterOptionsDialogue = this.dialogue.encounterOptionsDialogue ?? {}; this.dialogue = { - ...dialogue, + ...this.dialogue, encounterOptionsDialogue: { ...encounterOptionsDialogue, description, @@ -609,12 +635,17 @@ export class MysteryEncounterBuilder implements Partial { return this; } + /** + * Add a query for the encounter + * + * @param query - query to use for the encounter + * @returns + */ withQuery(query: TemplateStringsArray | `mysteryEncounter:${string}`) { - const dialogue = this.dialogue ?? {}; - const encounterOptionsDialogue = this.dialogue?.encounterOptionsDialogue ?? {}; + const encounterOptionsDialogue = this.dialogue.encounterOptionsDialogue ?? {}; this.dialogue = { - ...dialogue, + ...this.dialogue, encounterOptionsDialogue: { ...encounterOptionsDialogue, query, @@ -624,11 +655,23 @@ export class MysteryEncounterBuilder implements Partial { return this; } + /** + * Add outro dialogue/s for the encounter + * + * @param dialogue - outro dialogue/s + * @returns + */ withOutroDialogue(dialogue: MysteryEncounterDialogue["outro"] = []) { this.dialogue = {...this.dialogue, outro: dialogue }; return this; } + /** + * Builds the mystery encounter + * + * @param this - MysteryEncounter + * @returns + */ build(this: MysteryEncounter) { return new MysteryEncounter(this); } diff --git a/src/loading-scene.ts b/src/loading-scene.ts index 096986ebcc8..1ce8ed87156 100644 --- a/src/loading-scene.ts +++ b/src/loading-scene.ts @@ -22,7 +22,6 @@ import { initStatsKeys } from "./ui/game-stats-ui-handler"; import { initVouchers } from "./system/voucher"; import { Biome } from "#enums/biome"; import { TrainerType } from "#enums/trainer-type"; -import {initMysteryEncounterDialogue} from "#app/data/mystery-encounters/mystery-encounter-dialogue"; import {initMysteryEncounters} from "#app/data/mystery-encounters/mystery-encounters"; export class LoadingScene extends SceneBase { @@ -346,7 +345,6 @@ export class LoadingScene extends SceneBase { initMoves(); initAbilities(); initChallenges(); - initMysteryEncounterDialogue(); initMysteryEncounters(); } diff --git a/src/overrides.ts b/src/overrides.ts index c2a6edf9868..1e428c6dd2d 100644 --- a/src/overrides.ts +++ b/src/overrides.ts @@ -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 = 10000; +export const MYSTERY_ENCOUNTER_RATE_OVERRIDE: number = null; export const MYSTERY_ENCOUNTER_TIER_OVERRIDE: MysteryEncounterTier = null; -export const MYSTERY_ENCOUNTER_OVERRIDE: MysteryEncounterType = MysteryEncounterType.DARK_DEAL; +export const MYSTERY_ENCOUNTER_OVERRIDE: MysteryEncounterType = null; /** * MODIFIER / ITEM OVERRIDES diff --git a/src/test/vitest.setup.ts b/src/test/vitest.setup.ts index b8b655e3e96..37c533a33db 100644 --- a/src/test/vitest.setup.ts +++ b/src/test/vitest.setup.ts @@ -13,7 +13,6 @@ import { initVouchers } from "#app/system/voucher"; import { initAchievements } from "#app/system/achv"; import { initStatsKeys } from "#app/ui/game-stats-ui-handler"; import { initMysteryEncounters } from "#app/data/mystery-encounters/mystery-encounters"; -import { initMysteryEncounterDialogue } from "#app/data/mystery-encounters/mystery-encounter-dialogue"; import { beforeAll, beforeEach, vi } from "vitest"; import * as overrides from "#app/overrides"; @@ -28,7 +27,6 @@ initSpecies(); initMoves(); initAbilities(); initLoggedInUser(); -initMysteryEncounterDialogue(); initMysteryEncounters(); global.testFailed = false; From e8670c4f00d2dfe9ee020a2fb70bedcdf796ada1 Mon Sep 17 00:00:00 2001 From: Felix Staud Date: Thu, 11 Jul 2024 15:01:30 -0700 Subject: [PATCH 12/19] rename MysteryEncounter interface to IMysteryEncounter --- src/battle-scene.ts | 16 +++---- src/battle.ts | 4 +- .../encounters/dark-deal.ts | 4 +- .../encounters/department-store-sale.ts | 4 +- .../encounters/field-trip-encounter.ts | 4 +- .../encounters/fight-or-flight.ts | 4 +- .../encounters/mysterious-challengers.ts | 4 +- .../encounters/mysterious-chest.ts | 4 +- .../encounters/shady-vitamin-dealer.ts | 4 +- .../encounters/sleeping-snorlax.ts | 4 +- .../encounters/training-session.ts | 4 +- .../mystery-encounters/mystery-encounter.ts | 44 +++++++++---------- .../mystery-encounters/mystery-encounters.ts | 4 +- src/field/mystery-encounter-intro.ts | 6 +-- src/system/game-data.ts | 6 +-- .../mystery-encounter-utils.test.ts | 12 ++--- 16 files changed, 64 insertions(+), 64 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index be0e83b7976..729cc826886 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -67,7 +67,7 @@ import { Species } from "#enums/species"; import { UiTheme } from "#enums/ui-theme"; import { TimedEventManager } from "#app/timed-event-manager.js"; import i18next from "i18next"; -import MysteryEncounter, { MysteryEncounterTier, MysteryEncounterVariant } from "./data/mystery-encounters/mystery-encounter"; +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 { MysteryEncounterType } from "#enums/mystery-encounter-type"; @@ -216,7 +216,7 @@ export default class BattleScene extends SceneBase { public pokemonInfoContainer: PokemonInfoContainer; private party: PlayerPokemon[]; public mysteryEncounterData: MysteryEncounterData = new MysteryEncounterData(null); - public lastMysteryEncounter: MysteryEncounter; + public lastMysteryEncounter: IMysteryEncounter; /** Combined Biome and Wave count text */ private biomeWaveText: Phaser.GameObjects.Text; private moneyText: Phaser.GameObjects.Text; @@ -1026,7 +1026,7 @@ export default class BattleScene extends SceneBase { } } - newBattle(waveIndex?: integer, battleType?: BattleType, trainerData?: TrainerData, double?: boolean, mysteryEncounter?: MysteryEncounter): Battle { + newBattle(waveIndex?: integer, battleType?: BattleType, trainerData?: TrainerData, double?: boolean, mysteryEncounter?: IMysteryEncounter): Battle { const _startingWave = Overrides.STARTING_WAVE_OVERRIDE || startingWave; const newWaveIndex = waveIndex || ((this.currentBattle?.waveIndex || (_startingWave - 1)) + 1); let newDouble: boolean; @@ -2621,9 +2621,9 @@ export default class BattleScene extends SceneBase { * @param override - used to load session encounter when restarting game, etc. * @returns */ - getMysteryEncounter(override: MysteryEncounter): MysteryEncounter { + getMysteryEncounter(override: IMysteryEncounter): IMysteryEncounter { // Loading override or session encounter - let encounter: MysteryEncounter; + let encounter: IMysteryEncounter; if (!isNullOrUndefined(Overrides.MYSTERY_ENCOUNTER_OVERRIDE) && allMysteryEncounters.hasOwnProperty(Overrides.MYSTERY_ENCOUNTER_OVERRIDE)) { encounter = allMysteryEncounters[Overrides.MYSTERY_ENCOUNTER_OVERRIDE]; } else { @@ -2645,7 +2645,7 @@ export default class BattleScene extends SceneBase { } if (encounter) { - encounter = new MysteryEncounter(encounter); + encounter = new IMysteryEncounter(encounter); encounter.populateDialogueTokensFromRequirements(this); return encounter; } @@ -2674,7 +2674,7 @@ export default class BattleScene extends SceneBase { tier = Overrides.MYSTERY_ENCOUNTER_TIER_OVERRIDE; } - let availableEncounters: MysteryEncounter[] = []; + let availableEncounters: IMysteryEncounter[] = []; // New encounter will never be the same as the most recent encounter const previousEncounter = this.mysteryEncounterData.encounteredEvents?.length > 0 ? this.mysteryEncounterData.encounteredEvents[this.mysteryEncounterData.encounteredEvents.length - 1][0] : null; const biomeMysteryEncounters = mysteryEncountersByBiome.get(this.arena.biomeType); @@ -2695,7 +2695,7 @@ export default class BattleScene extends SceneBase { } encounter = availableEncounters[Utils.randSeedInt(availableEncounters.length)]; // New encounter object to not dirty flags - encounter = new MysteryEncounter(encounter); + encounter = new IMysteryEncounter(encounter); encounter.populateDialogueTokensFromRequirements(this); return encounter; } diff --git a/src/battle.ts b/src/battle.ts index 30543933f49..ab47eac7993 100644 --- a/src/battle.ts +++ b/src/battle.ts @@ -14,7 +14,7 @@ import { PlayerGender } from "#enums/player-gender"; import { Species } from "#enums/species"; import { TrainerType } from "#enums/trainer-type"; import i18next from "#app/plugins/i18n"; -import MysteryEncounter, { MysteryEncounterVariant } from "./data/mystery-encounters/mystery-encounter"; +import IMysteryEncounter, { MysteryEncounterVariant } from "./data/mystery-encounters/mystery-encounter"; export enum BattleType { WILD, @@ -69,7 +69,7 @@ export default class Battle { public lastUsedPokeball: PokeballType; public playerFaints: number; // The amount of times pokemon on the players side have fainted public enemyFaints: number; // The amount of times pokemon on the enemies side have fainted - public mysteryEncounter: MysteryEncounter; + public mysteryEncounter: IMysteryEncounter; private rngCounter: integer = 0; diff --git a/src/data/mystery-encounters/encounters/dark-deal.ts b/src/data/mystery-encounters/encounters/dark-deal.ts index 8f13e373e9a..9d755ad9493 100644 --- a/src/data/mystery-encounters/encounters/dark-deal.ts +++ b/src/data/mystery-encounters/encounters/dark-deal.ts @@ -7,7 +7,7 @@ import BattleScene from "../../../battle-scene"; import { AddPokeballModifierType } from "../../../modifier/modifier-type"; import { PokeballType } from "../../pokeball"; import { getPokemonSpecies } from "../../pokemon-species"; -import MysteryEncounter, { +import IMysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier, } from "../mystery-encounter"; @@ -73,7 +73,7 @@ const excludedBosses = [ Species.PECHARUNT, ]; -export const DarkDealEncounter: MysteryEncounter = +export const DarkDealEncounter: IMysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.DARK_DEAL) .withEncounterTier(MysteryEncounterTier.ROGUE) .withIntroSpriteConfigs([ diff --git a/src/data/mystery-encounters/encounters/department-store-sale.ts b/src/data/mystery-encounters/encounters/department-store-sale.ts index 2dcee4455df..d821a952864 100644 --- a/src/data/mystery-encounters/encounters/department-store-sale.ts +++ b/src/data/mystery-encounters/encounters/department-store-sale.ts @@ -7,7 +7,7 @@ import { randSeedInt } from "#app/utils"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { Species } from "#enums/species"; import BattleScene from "../../../battle-scene"; -import MysteryEncounter, { +import IMysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier, } from "../mystery-encounter"; @@ -15,7 +15,7 @@ import MysteryEncounter, { /** i18n namespace for encounter */ const namespace = "mysteryEncounter:department_store_sale"; -export const DepartmentStoreSaleEncounter: MysteryEncounter = +export const DepartmentStoreSaleEncounter: IMysteryEncounter = MysteryEncounterBuilder.withEncounterType( MysteryEncounterType.DEPARTMENT_STORE_SALE ) diff --git a/src/data/mystery-encounters/encounters/field-trip-encounter.ts b/src/data/mystery-encounters/encounters/field-trip-encounter.ts index 8cb6fe65048..9235504e332 100644 --- a/src/data/mystery-encounters/encounters/field-trip-encounter.ts +++ b/src/data/mystery-encounters/encounters/field-trip-encounter.ts @@ -13,7 +13,7 @@ import { modifierTypes } from "#app/modifier/modifier-type"; import { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import BattleScene from "../../../battle-scene"; -import MysteryEncounter, { +import IMysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier, } from "../mystery-encounter"; @@ -21,7 +21,7 @@ import MysteryEncounter, { /** i18n namespace for the encounter */ const namespace = "mysteryEncounter:field_trip"; -export const FieldTripEncounter: MysteryEncounter = +export const FieldTripEncounter: IMysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.FIELD_TRIP) .withEncounterTier(MysteryEncounterTier.COMMON) .withSceneWaveRangeRequirement(10, 180) diff --git a/src/data/mystery-encounters/encounters/fight-or-flight.ts b/src/data/mystery-encounters/encounters/fight-or-flight.ts index 3080ab76810..c98d7cd485f 100644 --- a/src/data/mystery-encounters/encounters/fight-or-flight.ts +++ b/src/data/mystery-encounters/encounters/fight-or-flight.ts @@ -23,7 +23,7 @@ import { randSeedInt } from "#app/utils"; import { BattlerTagType } from "#enums/battler-tag-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import BattleScene from "../../../battle-scene"; -import MysteryEncounter, { +import IMysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier, } from "../mystery-encounter"; @@ -32,7 +32,7 @@ import { MoveRequirement } from "../mystery-encounter-requirements"; /** the i18n namespace for the encounter */ const namespace = "mysteryEncounter:fight_or_flight"; -export const FightOrFlightEncounter: MysteryEncounter = +export const FightOrFlightEncounter: IMysteryEncounter = MysteryEncounterBuilder.withEncounterType( MysteryEncounterType.FIGHT_OR_FLIGHT ) diff --git a/src/data/mystery-encounters/encounters/mysterious-challengers.ts b/src/data/mystery-encounters/encounters/mysterious-challengers.ts index e8efc3470ed..1276d6e2226 100644 --- a/src/data/mystery-encounters/encounters/mysterious-challengers.ts +++ b/src/data/mystery-encounters/encounters/mysterious-challengers.ts @@ -15,7 +15,7 @@ import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { PartyMemberStrength } from "#enums/party-member-strength"; import BattleScene from "../../../battle-scene"; import * as Utils from "../../../utils"; -import MysteryEncounter, { +import IMysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier, } from "../mystery-encounter"; @@ -23,7 +23,7 @@ import MysteryEncounter, { /** the i18n namespace for the encounter */ const namespace = "mysteryEncounter:mysterious_challengers"; -export const MysteriousChallengersEncounter: MysteryEncounter = +export const MysteriousChallengersEncounter: IMysteryEncounter = MysteryEncounterBuilder.withEncounterType( MysteryEncounterType.MYSTERIOUS_CHALLENGERS ) diff --git a/src/data/mystery-encounters/encounters/mysterious-chest.ts b/src/data/mystery-encounters/encounters/mysterious-chest.ts index 9dd4f56f623..8d1f1c2eeb1 100644 --- a/src/data/mystery-encounters/encounters/mysterious-chest.ts +++ b/src/data/mystery-encounters/encounters/mysterious-chest.ts @@ -11,13 +11,13 @@ import { GameOverPhase } from "#app/phases"; import { randSeedInt } from "#app/utils"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import BattleScene from "../../../battle-scene"; -import MysteryEncounter, { +import IMysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier, } from "../mystery-encounter"; import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; -export const MysteriousChestEncounter: MysteryEncounter = +export const MysteriousChestEncounter: IMysteryEncounter = MysteryEncounterBuilder.withEncounterType( MysteryEncounterType.MYSTERIOUS_CHEST ) diff --git a/src/data/mystery-encounters/encounters/shady-vitamin-dealer.ts b/src/data/mystery-encounters/encounters/shady-vitamin-dealer.ts index 773c4b97b0e..f26890cefbc 100644 --- a/src/data/mystery-encounters/encounters/shady-vitamin-dealer.ts +++ b/src/data/mystery-encounters/encounters/shady-vitamin-dealer.ts @@ -14,14 +14,14 @@ import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { Species } from "#enums/species"; import i18next from "i18next"; import BattleScene from "../../../battle-scene"; -import MysteryEncounter, { +import IMysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier, } from "../mystery-encounter"; import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; import { MoneyRequirement } from "../mystery-encounter-requirements"; -export const ShadyVitaminDealerEncounter: MysteryEncounter = +export const ShadyVitaminDealerEncounter: IMysteryEncounter = MysteryEncounterBuilder.withEncounterType( MysteryEncounterType.SHADY_VITAMIN_DEALER ) diff --git a/src/data/mystery-encounters/encounters/sleeping-snorlax.ts b/src/data/mystery-encounters/encounters/sleeping-snorlax.ts index 324beb35e99..b0130c34419 100644 --- a/src/data/mystery-encounters/encounters/sleeping-snorlax.ts +++ b/src/data/mystery-encounters/encounters/sleeping-snorlax.ts @@ -7,7 +7,7 @@ import BattleScene from "../../../battle-scene"; import * as Utils from "../../../utils"; import { getPokemonSpecies } from "../../pokemon-species"; import { Status, StatusEffect } from "../../status-effect"; -import MysteryEncounter, { +import IMysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier, } from "../mystery-encounter"; @@ -27,7 +27,7 @@ import { /** i18n namespace for the encounter */ const namespace = "mysteryEncounter:sleeping_snorlax"; -export const SleepingSnorlaxEncounter: MysteryEncounter = +export const SleepingSnorlaxEncounter: IMysteryEncounter = MysteryEncounterBuilder.withEncounterType( MysteryEncounterType.SLEEPING_SNORLAX ) diff --git a/src/data/mystery-encounters/encounters/training-session.ts b/src/data/mystery-encounters/encounters/training-session.ts index e9b0461857d..4338f587583 100644 --- a/src/data/mystery-encounters/encounters/training-session.ts +++ b/src/data/mystery-encounters/encounters/training-session.ts @@ -20,13 +20,13 @@ import { randSeedShuffle } from "#app/utils"; import { BattlerTagType } from "#enums/battler-tag-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import BattleScene from "../../../battle-scene"; -import MysteryEncounter, { +import IMysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier, } from "../mystery-encounter"; import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; -export const TrainingSessionEncounter: MysteryEncounter = +export const TrainingSessionEncounter: IMysteryEncounter = MysteryEncounterBuilder.withEncounterType( MysteryEncounterType.TRAINING_SESSION ) diff --git a/src/data/mystery-encounters/mystery-encounter.ts b/src/data/mystery-encounters/mystery-encounter.ts index c367f2377b2..30e2e6682a6 100644 --- a/src/data/mystery-encounters/mystery-encounter.ts +++ b/src/data/mystery-encounters/mystery-encounter.ts @@ -35,7 +35,7 @@ export enum MysteryEncounterTier { MASTER // Not currently used } -export default interface MysteryEncounter { +export default interface IMysteryEncounter { /** * Required params */ @@ -130,8 +130,8 @@ export default interface MysteryEncounter { * These objects will be saved as part of session data any time the player is on a floor with an encounter * Unless you know what you're doing, you should use MysteryEncounterBuilder to create an instance for this class */ -export default class MysteryEncounter implements MysteryEncounter { - constructor(encounter: MysteryEncounter) { +export default class IMysteryEncounter implements IMysteryEncounter { + constructor(encounter: IMysteryEncounter) { if (!isNullOrUndefined(encounter)) { Object.assign(this, encounter); } @@ -339,7 +339,7 @@ export default class MysteryEncounter implements MysteryEncounter { } } -export class MysteryEncounterBuilder implements Partial { +export class MysteryEncounterBuilder implements Partial { encounterType?: MysteryEncounterType; options?: [MysteryEncounterOption, MysteryEncounterOption, ...MysteryEncounterOption[]] = [null, null]; spriteConfigs?: MysteryEncounterSpriteConfig[]; @@ -367,7 +367,7 @@ export class MysteryEncounterBuilder implements Partial { * @param encounterType * @returns this */ - static withEncounterType(encounterType: MysteryEncounterType): MysteryEncounterBuilder & Pick { + static withEncounterType(encounterType: MysteryEncounterType): MysteryEncounterBuilder & Pick { return Object.assign(new MysteryEncounterBuilder(), { encounterType: encounterType }); } @@ -377,7 +377,7 @@ export class MysteryEncounterBuilder implements Partial { * @param option - MysteryEncounterOption to add, can use MysteryEncounterOptionBuilder to create instance * @returns */ - withOption(option: MysteryEncounterOption): this & Pick { + withOption(option: MysteryEncounterOption): this & Pick { if (this.options[0] === null) { return Object.assign(this, { options: [option, this.options[0]] }); } else if (this.options[1] === null) { @@ -406,7 +406,7 @@ export class MysteryEncounterBuilder implements Partial { * @param spriteConfigs * @returns */ - withIntroSpriteConfigs(spriteConfigs: MysteryEncounterSpriteConfig[]): this & Pick { + withIntroSpriteConfigs(spriteConfigs: MysteryEncounterSpriteConfig[]): this & Pick { return Object.assign(this, { spriteConfigs: spriteConfigs }); } @@ -435,7 +435,7 @@ export class MysteryEncounterBuilder implements Partial { * @param encounterTier * @returns */ - withEncounterTier(encounterTier: MysteryEncounterTier): this & Required> { + withEncounterTier(encounterTier: MysteryEncounterTier): this & Required> { return Object.assign(this, { encounterTier: encounterTier }); } @@ -446,7 +446,7 @@ export class MysteryEncounterBuilder implements Partial { * @param requirement * @returns */ - withSceneRequirement(requirement: EncounterSceneRequirement): this & Required> { + withSceneRequirement(requirement: EncounterSceneRequirement): this & Required> { if (requirement instanceof EncounterPokemonRequirement) { Error("Incorrectly added pokemon requirement as scene requirement."); } @@ -482,7 +482,7 @@ export class MysteryEncounterBuilder implements Partial { * @param requirement {@linkcode EncounterPokemonRequirement} * @returns */ - withPrimaryPokemonRequirement(requirement: EncounterPokemonRequirement): this & Required> { + withPrimaryPokemonRequirement(requirement: EncounterPokemonRequirement): this & Required> { this.primaryPokemonRequirements.push(requirement); return Object.assign(this, { primaryPokemonRequirements: this.primaryPokemonRequirements }); } @@ -495,7 +495,7 @@ export class MysteryEncounterBuilder implements Partial { * @param invertQuery if true will invert the query * @returns */ - withPrimaryPokemonStatusEffectRequirement(statusEffect: StatusEffect | StatusEffect[], minNumberOfPokemon: number = 1, invertQuery: boolean = false): this & Required> { + withPrimaryPokemonStatusEffectRequirement(statusEffect: StatusEffect | StatusEffect[], minNumberOfPokemon: number = 1, invertQuery: boolean = false): this & Required> { return this.withPrimaryPokemonRequirement(new StatusEffectRequirement(statusEffect, minNumberOfPokemon, invertQuery)); } @@ -507,14 +507,14 @@ export class MysteryEncounterBuilder implements Partial { * @param invertQuery if true will invert the query * @returns */ - withPrimaryPokemonHealthRatioRequirement(requiredHealthRange: [number, number], minNumberOfPokemon: number = 1, invertQuery: boolean = false): this & Required> { + withPrimaryPokemonHealthRatioRequirement(requiredHealthRange: [number, number], minNumberOfPokemon: number = 1, invertQuery: boolean = false): this & Required> { return this.withPrimaryPokemonRequirement(new HealthRatioRequirement(requiredHealthRange, minNumberOfPokemon, invertQuery)); } // TODO: Maybe add an optional parameter for excluding primary pokemon from the support cast? // ex. if your only grass type pokemon, a snivy, is chosen as primary, if the support pokemon requires a grass type, the event won't trigger because // it's already been - withSecondaryPokemonRequirement(requirement: EncounterPokemonRequirement, excludePrimaryFromSecondaryRequirements: boolean = false): this & Required> { + withSecondaryPokemonRequirement(requirement: EncounterPokemonRequirement, excludePrimaryFromSecondaryRequirements: boolean = false): this & Required> { this.secondaryPokemonRequirements.push(requirement); this.excludePrimaryFromSupportRequirements = excludePrimaryFromSecondaryRequirements; return Object.assign(this, { excludePrimaryFromSecondaryRequirements: this.excludePrimaryFromSupportRequirements, secondaryPokemonRequirements: this.secondaryPokemonRequirements }); @@ -530,7 +530,7 @@ export class MysteryEncounterBuilder implements Partial { * @param doEncounterRewards - synchronous callback function to perform during rewards phase of the encounter * @returns */ - withRewards(doEncounterRewards: (scene: BattleScene) => boolean): this & Required> { + withRewards(doEncounterRewards: (scene: BattleScene) => boolean): this & Required> { return Object.assign(this, { doEncounterRewards: doEncounterRewards }); } @@ -544,7 +544,7 @@ export class MysteryEncounterBuilder implements Partial { * @param doEncounterExp - synchronous callback function to perform during rewards phase of the encounter * @returns */ - withExp(doEncounterExp: (scene: BattleScene) => boolean): this & Required> { + withExp(doEncounterExp: (scene: BattleScene) => boolean): this & Required> { return Object.assign(this, { doEncounterExp: doEncounterExp }); } @@ -555,7 +555,7 @@ export class MysteryEncounterBuilder implements Partial { * @param onInit - synchronous callback function to perform as soon as the encounter is selected for the next phase * @returns */ - withOnInit(onInit: (scene: BattleScene) => boolean): this & Required> { + withOnInit(onInit: (scene: BattleScene) => boolean): this & Required> { return Object.assign(this, { onInit: onInit }); } @@ -564,7 +564,7 @@ export class MysteryEncounterBuilder implements Partial { * @param enemyPartyConfig * @returns */ - withEnemyPartyConfig(enemyPartyConfig: EnemyPartyConfig): this & Required> { + withEnemyPartyConfig(enemyPartyConfig: EnemyPartyConfig): this & Required> { this.enemyPartyConfigs.push(enemyPartyConfig); return Object.assign(this, { enemyPartyConfigs: this.enemyPartyConfigs }); } @@ -575,7 +575,7 @@ export class MysteryEncounterBuilder implements Partial { * @param catchAllowed - if true, allows enemy pokemon to be caught during the encounter * @returns */ - withCatchAllowed(catchAllowed: boolean): this & Required> { + withCatchAllowed(catchAllowed: boolean): this & Required> { return Object.assign(this, { catchAllowed: catchAllowed }); } @@ -583,7 +583,7 @@ export class MysteryEncounterBuilder implements Partial { * @param hideBattleIntroMessage - if true, will not show the trainerAppeared/wildAppeared/bossAppeared message for an encounter * @returns */ - withHideWildIntroMessage(hideBattleIntroMessage: boolean): this & Required> { + withHideWildIntroMessage(hideBattleIntroMessage: boolean): this & Required> { return Object.assign(this, { hideBattleIntroMessage: hideBattleIntroMessage }); } @@ -591,7 +591,7 @@ export class MysteryEncounterBuilder implements Partial { * @param hideIntroVisuals - if false, will not hide the intro visuals that are displayed at the beginning of encounter * @returns */ - withHideIntroVisuals(hideIntroVisuals: boolean): this & Required> { + withHideIntroVisuals(hideIntroVisuals: boolean): this & Required> { return Object.assign(this, { hideIntroVisuals: hideIntroVisuals }); } @@ -672,7 +672,7 @@ export class MysteryEncounterBuilder implements Partial { * @param this - MysteryEncounter * @returns */ - build(this: MysteryEncounter) { - return new MysteryEncounter(this); + build(this: IMysteryEncounter) { + return new IMysteryEncounter(this); } } diff --git a/src/data/mystery-encounters/mystery-encounters.ts b/src/data/mystery-encounters/mystery-encounters.ts index 1651430e59d..602a01627c6 100644 --- a/src/data/mystery-encounters/mystery-encounters.ts +++ b/src/data/mystery-encounters/mystery-encounters.ts @@ -1,4 +1,4 @@ -import MysteryEncounter from "./mystery-encounter"; +import IMysteryEncounter from "./mystery-encounter"; import { DarkDealEncounter } from "./encounters/dark-deal"; import { MysteriousChallengersEncounter } from "./encounters/mysterious-challengers"; import { MysteriousChestEncounter } from "./encounters/mysterious-chest"; @@ -117,7 +117,7 @@ export const CIVILIZATION_ENCOUNTER_BIOMES = [ Biome.ISLAND ]; -export const allMysteryEncounters: { [encounterType: number]: MysteryEncounter } = {}; +export const allMysteryEncounters: { [encounterType: number]: IMysteryEncounter } = {}; const extremeBiomeEncounters: MysteryEncounterType[] = []; diff --git a/src/field/mystery-encounter-intro.ts b/src/field/mystery-encounter-intro.ts index adb700b4854..1b0fb3bca01 100644 --- a/src/field/mystery-encounter-intro.ts +++ b/src/field/mystery-encounter-intro.ts @@ -1,6 +1,6 @@ import { GameObjects } from "phaser"; import BattleScene from "../battle-scene"; -import MysteryEncounter from "../data/mystery-encounters/mystery-encounter"; +import IMysteryEncounter from "../data/mystery-encounters/mystery-encounter"; export class MysteryEncounterSpriteConfig { spriteKey: string; // e.g. "ace_trainer_f" @@ -21,10 +21,10 @@ export class MysteryEncounterSpriteConfig { * Note: intro visuals are not "Trainers" or any other specific game object, though they may contain trainer sprites */ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Container { - public encounter: MysteryEncounter; + public encounter: IMysteryEncounter; public spriteConfigs: MysteryEncounterSpriteConfig[]; - constructor(scene: BattleScene, encounter: MysteryEncounter) { + constructor(scene: BattleScene, encounter: IMysteryEncounter) { super(scene, -72, 76); this.encounter = encounter; // Shallow copy configs to allow visual config updates at runtime without dirtying master copy of Encounter diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 871e2458bbd..606d63d70fe 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -41,7 +41,7 @@ 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 MysteryEncounter from "../data/mystery-encounters/mystery-encounter"; +import IMysteryEncounter from "../data/mystery-encounters/mystery-encounter"; export const defaultStarterSpecies: Species[] = [ Species.BULBASAUR, Species.CHARMANDER, Species.SQUIRTLE, @@ -124,7 +124,7 @@ export interface SessionSaveData { gameVersion: string; timestamp: integer; challenges: ChallengeData[]; - mysteryEncounter: MysteryEncounter; + mysteryEncounter: IMysteryEncounter; mysteryEncounterData: MysteryEncounterData; } @@ -1155,7 +1155,7 @@ export class GameData { } if (k === "mysteryEncounter") { - return new MysteryEncounter(v); + return new IMysteryEncounter(v); } if (k === "mysteryEncounterData") { diff --git a/src/test/mystery-encounter/mystery-encounter-utils.test.ts b/src/test/mystery-encounter/mystery-encounter-utils.test.ts index e558fe7a95c..50853c05a2e 100644 --- a/src/test/mystery-encounter/mystery-encounter-utils.test.ts +++ b/src/test/mystery-encounter/mystery-encounter-utils.test.ts @@ -10,7 +10,7 @@ import { initSceneWithoutEncounterPhase } from "#test/utils/gameManagerUtils"; import { Species } from "#enums/species"; import BattleScene from "#app/battle-scene"; import { StatusEffect } from "#app/data/status-effect"; -import MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; +import IMysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; import { MessagePhase } from "#app/phases"; import { getPokemonSpecies, speciesStarters } from "#app/data/pokemon-species"; import { Type } from "#app/data/type"; @@ -273,7 +273,7 @@ describe("Mystery Encounter Utils", () => { describe("getTextWithEncounterDialogueTokens", () => { it("injects dialogue tokens and color styling", () => { - scene.currentBattle.mysteryEncounter = new MysteryEncounter(null); + scene.currentBattle.mysteryEncounter = new IMysteryEncounter(null); scene.currentBattle.mysteryEncounter.setDialogueToken("test", "value"); const result = getEncounterText(scene, "mysteryEncounter:unit_test_dialogue"); @@ -281,7 +281,7 @@ describe("Mystery Encounter Utils", () => { }); it("can perform nested dialogue token injection", () => { - scene.currentBattle.mysteryEncounter = new MysteryEncounter(null); + scene.currentBattle.mysteryEncounter = new IMysteryEncounter(null); scene.currentBattle.mysteryEncounter.setDialogueToken("test", "value"); scene.currentBattle.mysteryEncounter.setDialogueToken("testvalue", "new"); @@ -292,7 +292,7 @@ describe("Mystery Encounter Utils", () => { describe("queueEncounterMessage", () => { it("queues a message with encounter dialogue tokens", async () => { - scene.currentBattle.mysteryEncounter = new MysteryEncounter(null); + scene.currentBattle.mysteryEncounter = new IMysteryEncounter(null); scene.currentBattle.mysteryEncounter.setDialogueToken("test", "value"); const spy = vi.spyOn(game.scene, "queueMessage"); const phaseSpy = vi.spyOn(game.scene, "unshiftPhase"); @@ -305,7 +305,7 @@ describe("Mystery Encounter Utils", () => { describe("showEncounterText", () => { it("showText with dialogue tokens", async () => { - scene.currentBattle.mysteryEncounter = new MysteryEncounter(null); + scene.currentBattle.mysteryEncounter = new IMysteryEncounter(null); scene.currentBattle.mysteryEncounter.setDialogueToken("test", "value"); const spy = vi.spyOn(game.scene.ui, "showText"); @@ -316,7 +316,7 @@ describe("Mystery Encounter Utils", () => { describe("showEncounterDialogue", () => { it("showText with dialogue tokens", async () => { - scene.currentBattle.mysteryEncounter = new MysteryEncounter(null); + scene.currentBattle.mysteryEncounter = new IMysteryEncounter(null); scene.currentBattle.mysteryEncounter.setDialogueToken("test", "value"); const spy = vi.spyOn(game.scene.ui, "showDialogue"); From 55805d180470f757118c5f6097665f466caef6ca Mon Sep 17 00:00:00 2001 From: Felix Staud Date: Thu, 11 Jul 2024 15:13:01 -0700 Subject: [PATCH 13/19] apply `namespace` for shady vitamin dealer encounter --- .../encounters/shady-vitamin-dealer.ts | 71 +++++++------------ 1 file changed, 25 insertions(+), 46 deletions(-) diff --git a/src/data/mystery-encounters/encounters/shady-vitamin-dealer.ts b/src/data/mystery-encounters/encounters/shady-vitamin-dealer.ts index f26890cefbc..14dddf91189 100644 --- a/src/data/mystery-encounters/encounters/shady-vitamin-dealer.ts +++ b/src/data/mystery-encounters/encounters/shady-vitamin-dealer.ts @@ -21,6 +21,9 @@ import IMysteryEncounter, { import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; import { MoneyRequirement } from "../mystery-encounter-requirements"; +/** the i18n namespace for this encounter */ +const namespace = "mysteryEncounter:shady_vitamin_dealer"; + export const ShadyVitaminDealerEncounter: IMysteryEncounter = MysteryEncounterBuilder.withEncounterType( MysteryEncounterType.SHADY_VITAMIN_DEALER @@ -48,26 +51,25 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter = ]) .withIntroDialogue([ { - text: "mysteryEncounter:shady_vitamin_dealer_intro_message", + text: `${namespace}_intro_message`, }, { - text: "mysteryEncounter:shady_vitamin_dealer_intro_dialogue", - speaker: "mysteryEncounter:shady_vitamin_dealer_speaker", + text: `${namespace}_intro_dialogue`, + speaker: `${namespace}_speaker`, }, ]) - .withTitle("mysteryEncounter:shady_vitamin_dealer_title") - .withDescription("mysteryEncounter:shady_vitamin_dealer_description") - .withQuery("mysteryEncounter:shady_vitamin_dealer_query") + .withTitle(`${namespace}_title`) + .withDescription(`${namespace}_description`) + .withQuery(`${namespace}_query`) .withOption( new MysteryEncounterOptionBuilder() .withSceneMoneyRequirement(0, 2) // Wave scaling money multiplier of 2 .withDialogue({ - buttonLabel: "mysteryEncounter:shady_vitamin_dealer_option_1_label", - buttonTooltip: - "mysteryEncounter:shady_vitamin_dealer_option_1_tooltip", + buttonLabel: `${namespace}_option_1_label`, + buttonTooltip: `${namespace}_option_1_tooltip`, selected: [ { - text: "mysteryEncounter:shady_vitamin_dealer_option_selected", + text: `${namespace}_option_selected`, }, ], }) @@ -103,9 +105,7 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter = pokemon ); if (!meetsReqs) { - return i18next.t( - "mysteryEncounter:shady_vitamin_dealer_invalid_selection" - ); + return i18next.t(`${namespace}_invalid_selection`); } return null; @@ -145,22 +145,13 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter = if (randSeedInt(10) < 8) { if (chosenPokemon.trySetStatus(StatusEffect.TOXIC)) { // Toxic applied - queueEncounterMessage( - scene, - "mysteryEncounter:shady_vitamin_dealer_bad_poison" - ); + queueEncounterMessage(scene, `${namespace}_bad_poison`); } else { // Pokemon immune or something else prevents status - queueEncounterMessage( - scene, - "mysteryEncounter:shady_vitamin_dealer_damage_only" - ); + queueEncounterMessage(scene, `${namespace}_damage_only`); } } else { - queueEncounterMessage( - scene, - "mysteryEncounter:shady_vitamin_dealer_damage_only" - ); + queueEncounterMessage(scene, `${namespace}_damage_only`); } setEncounterExp(scene, [chosenPokemon.id], 100); @@ -172,12 +163,11 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter = .withOption( new MysteryEncounterOptionBuilder() .withDialogue({ - buttonLabel: "mysteryEncounter:shady_vitamin_dealer_option_2_label", - buttonTooltip: - "mysteryEncounter:shady_vitamin_dealer_option_2_tooltip", + buttonLabel: `${namespace}_option_2_label`, + buttonTooltip: `${namespace}_option_2_tooltip`, selected: [ { - text: "mysteryEncounter:shady_vitamin_dealer_option_selected", + text: `${namespace}_option_selected`, }, ], }) @@ -214,9 +204,7 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter = pokemon ); if (!meetsReqs) { - return i18next.t( - "mysteryEncounter:shady_vitamin_dealer_invalid_selection" - ); + return i18next.t(`${namespace}_invalid_selection`); } return null; @@ -252,22 +240,13 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter = if (randSeedInt(10) < 2) { if (chosenPokemon.trySetStatus(StatusEffect.POISON)) { // Poison applied - queueEncounterMessage( - scene, - "mysteryEncounter:shady_vitamin_dealer_poison" - ); + queueEncounterMessage(scene, `${namespace}_poison`); } else { // Pokemon immune or something else prevents status - queueEncounterMessage( - scene, - "mysteryEncounter:shady_vitamin_dealer_no_bad_effects" - ); + queueEncounterMessage(scene, `${namespace}_no_bad_effects`); } } else { - queueEncounterMessage( - scene, - "mysteryEncounter:shady_vitamin_dealer_no_bad_effects" - ); + queueEncounterMessage(scene, `${namespace}_no_bad_effects`); } setEncounterExp(scene, [chosenPokemon.id], 100); @@ -278,8 +257,8 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter = ) .withSimpleOption( { - buttonLabel: "mysteryEncounter:shady_vitamin_dealer_option_3_label", - buttonTooltip: "mysteryEncounter:shady_vitamin_dealer_option_3_tooltip", + buttonLabel: `${namespace}_option_3_label`, + buttonTooltip: `${namespace}_option_3_tooltip`, }, async (scene: BattleScene) => { // Leave encounter with no rewards or exp From 4da5e0fb107011affe5772bb3b8ecbdba70d55d3 Mon Sep 17 00:00:00 2001 From: Felix Staud Date: Thu, 11 Jul 2024 15:14:03 -0700 Subject: [PATCH 14/19] apply `namespace` for training session encounter --- .../encounters/training-session.ts | 52 ++++++++----------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/src/data/mystery-encounters/encounters/training-session.ts b/src/data/mystery-encounters/encounters/training-session.ts index 4338f587583..c5f0ee2e46f 100644 --- a/src/data/mystery-encounters/encounters/training-session.ts +++ b/src/data/mystery-encounters/encounters/training-session.ts @@ -6,7 +6,7 @@ import { selectPokemonForOption, setEncounterRewards, } from "#app/data/mystery-encounters/mystery-encounter-utils"; -import { getNatureName, Nature } from "#app/data/nature"; +import { Nature, getNatureName } from "#app/data/nature"; import { speciesStarters } from "#app/data/pokemon-species"; import { Stat } from "#app/data/pokemon-stat"; import { PlayerPokemon } from "#app/field/pokemon"; @@ -26,6 +26,9 @@ import IMysteryEncounter, { } from "../mystery-encounter"; import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; +/** The i18n namespace for the encounter */ +const namespace = "mysteryEncounter:training_session"; + export const TrainingSessionEncounter: IMysteryEncounter = MysteryEncounterBuilder.withEncounterType( MysteryEncounterType.TRAINING_SESSION @@ -43,20 +46,20 @@ export const TrainingSessionEncounter: IMysteryEncounter = ]) .withIntroDialogue([ { - text: "mysteryEncounter:training_session_intro_message", + text: `${namespace}_intro_message`, }, ]) - .withTitle("mysteryEncounter:training_session_title") - .withDescription("mysteryEncounter:training_session_description") - .withQuery("mysteryEncounter:training_session_query") + .withTitle(`${namespace}_title`) + .withDescription(`${namespace}_description`) + .withQuery(`${namespace}_query`) .withOption( new MysteryEncounterOptionBuilder() .withDialogue({ - buttonLabel: "mysteryEncounter:training_session_option_1_label", - buttonTooltip: "mysteryEncounter:training_session_option_1_tooltip", + buttonLabel: `${namespace}_option_1_label`, + buttonTooltip: `${namespace}_option_1_tooltip`, selected: [ { - text: "mysteryEncounter:training_session_option_selected_message", + text: `${namespace}_option_selected_message`, }, ], }) @@ -168,10 +171,7 @@ export const TrainingSessionEncounter: IMysteryEncounter = } scene.updateModifiers(true); scene.queueMessage( - getEncounterText( - scene, - "mysteryEncounter:training_session_battle_finished_1" - ), + getEncounterText(scene, `${namespace}_battle_finished_1`), null, true ); @@ -191,13 +191,12 @@ export const TrainingSessionEncounter: IMysteryEncounter = .withOption( new MysteryEncounterOptionBuilder() .withDialogue({ - buttonLabel: "mysteryEncounter:training_session_option_2_label", - buttonTooltip: "mysteryEncounter:training_session_option_2_tooltip", - secondOptionPrompt: - "mysteryEncounter:training_session_option_2_select_prompt", + buttonLabel: `${namespace}_option_2_label`, + buttonTooltip: `${namespace}_option_2_tooltip`, + secondOptionPrompt: `${namespace}_option_2_select_prompt`, selected: [ { - text: "mysteryEncounter:training_session_option_selected_message", + text: `${namespace}_option_selected_message`, }, ], }) @@ -247,10 +246,7 @@ export const TrainingSessionEncounter: IMysteryEncounter = const onBeforeRewardsPhase = () => { scene.queueMessage( - getEncounterText( - scene, - "mysteryEncounter:training_session_battle_finished_2" - ), + getEncounterText(scene, `${namespace}_battle_finished_2`), null, true ); @@ -280,13 +276,12 @@ export const TrainingSessionEncounter: IMysteryEncounter = .withOption( new MysteryEncounterOptionBuilder() .withDialogue({ - buttonLabel: "mysteryEncounter:training_session_option_3_label", - buttonTooltip: "mysteryEncounter:training_session_option_3_tooltip", - secondOptionPrompt: - "mysteryEncounter:training_session_option_3_select_prompt", + buttonLabel: `${namespace}_option_3_label`, + buttonTooltip: `${namespace}_option_3_tooltip`, + secondOptionPrompt: `${namespace}_option_3_select_prompt`, selected: [ { - text: "mysteryEncounter:training_session_option_selected_message", + text: `${namespace}_option_selected_message`, }, ], }) @@ -349,10 +344,7 @@ export const TrainingSessionEncounter: IMysteryEncounter = const onBeforeRewardsPhase = () => { scene.queueMessage( - getEncounterText( - scene, - "mysteryEncounter:training_session_battle_finished_3" - ), + getEncounterText(scene, `${namespace}_battle_finished_3`), null, true ); From 14289d27362bd75356af346fdfad628500117c69 Mon Sep 17 00:00:00 2001 From: Felix Staud Date: Thu, 11 Jul 2024 15:17:37 -0700 Subject: [PATCH 15/19] add `-encounter` as suffix for encounter files --- .../{dark-deal.ts => dark-deal-encounter.ts} | 0 ...e.ts => department-store-sale-encounter.ts} | 0 ...-flight.ts => fight-or-flight-encounter.ts} | 0 ....ts => mysterious-challengers-encounter.ts} | 0 ...-chest.ts => mysterious-chest-encounter.ts} | 0 ...er.ts => shady-vitamin-dealer-encounter.ts} | 0 ...norlax.ts => sleeping-snorlax-encounter.ts} | 0 ...ession.ts => training-session-encounter.ts} | 0 .../mystery-encounters/mystery-encounters.ts | 18 +++++++++--------- 9 files changed, 9 insertions(+), 9 deletions(-) rename src/data/mystery-encounters/encounters/{dark-deal.ts => dark-deal-encounter.ts} (100%) rename src/data/mystery-encounters/encounters/{department-store-sale.ts => department-store-sale-encounter.ts} (100%) rename src/data/mystery-encounters/encounters/{fight-or-flight.ts => fight-or-flight-encounter.ts} (100%) rename src/data/mystery-encounters/encounters/{mysterious-challengers.ts => mysterious-challengers-encounter.ts} (100%) rename src/data/mystery-encounters/encounters/{mysterious-chest.ts => mysterious-chest-encounter.ts} (100%) rename src/data/mystery-encounters/encounters/{shady-vitamin-dealer.ts => shady-vitamin-dealer-encounter.ts} (100%) rename src/data/mystery-encounters/encounters/{sleeping-snorlax.ts => sleeping-snorlax-encounter.ts} (100%) rename src/data/mystery-encounters/encounters/{training-session.ts => training-session-encounter.ts} (100%) diff --git a/src/data/mystery-encounters/encounters/dark-deal.ts b/src/data/mystery-encounters/encounters/dark-deal-encounter.ts similarity index 100% rename from src/data/mystery-encounters/encounters/dark-deal.ts rename to src/data/mystery-encounters/encounters/dark-deal-encounter.ts diff --git a/src/data/mystery-encounters/encounters/department-store-sale.ts b/src/data/mystery-encounters/encounters/department-store-sale-encounter.ts similarity index 100% rename from src/data/mystery-encounters/encounters/department-store-sale.ts rename to src/data/mystery-encounters/encounters/department-store-sale-encounter.ts diff --git a/src/data/mystery-encounters/encounters/fight-or-flight.ts b/src/data/mystery-encounters/encounters/fight-or-flight-encounter.ts similarity index 100% rename from src/data/mystery-encounters/encounters/fight-or-flight.ts rename to src/data/mystery-encounters/encounters/fight-or-flight-encounter.ts diff --git a/src/data/mystery-encounters/encounters/mysterious-challengers.ts b/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts similarity index 100% rename from src/data/mystery-encounters/encounters/mysterious-challengers.ts rename to src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts diff --git a/src/data/mystery-encounters/encounters/mysterious-chest.ts b/src/data/mystery-encounters/encounters/mysterious-chest-encounter.ts similarity index 100% rename from src/data/mystery-encounters/encounters/mysterious-chest.ts rename to src/data/mystery-encounters/encounters/mysterious-chest-encounter.ts diff --git a/src/data/mystery-encounters/encounters/shady-vitamin-dealer.ts b/src/data/mystery-encounters/encounters/shady-vitamin-dealer-encounter.ts similarity index 100% rename from src/data/mystery-encounters/encounters/shady-vitamin-dealer.ts rename to src/data/mystery-encounters/encounters/shady-vitamin-dealer-encounter.ts diff --git a/src/data/mystery-encounters/encounters/sleeping-snorlax.ts b/src/data/mystery-encounters/encounters/sleeping-snorlax-encounter.ts similarity index 100% rename from src/data/mystery-encounters/encounters/sleeping-snorlax.ts rename to src/data/mystery-encounters/encounters/sleeping-snorlax-encounter.ts diff --git a/src/data/mystery-encounters/encounters/training-session.ts b/src/data/mystery-encounters/encounters/training-session-encounter.ts similarity index 100% rename from src/data/mystery-encounters/encounters/training-session.ts rename to src/data/mystery-encounters/encounters/training-session-encounter.ts diff --git a/src/data/mystery-encounters/mystery-encounters.ts b/src/data/mystery-encounters/mystery-encounters.ts index 602a01627c6..7a78c6edb4c 100644 --- a/src/data/mystery-encounters/mystery-encounters.ts +++ b/src/data/mystery-encounters/mystery-encounters.ts @@ -1,15 +1,15 @@ import IMysteryEncounter from "./mystery-encounter"; -import { DarkDealEncounter } from "./encounters/dark-deal"; -import { MysteriousChallengersEncounter } from "./encounters/mysterious-challengers"; -import { MysteriousChestEncounter } from "./encounters/mysterious-chest"; -import { FightOrFlightEncounter } from "#app/data/mystery-encounters/encounters/fight-or-flight"; -import { TrainingSessionEncounter } from "#app/data/mystery-encounters/encounters/training-session"; +import { DarkDealEncounter } from "./encounters/dark-deal-encounter"; +import { MysteriousChallengersEncounter } from "./encounters/mysterious-challengers-encounter"; +import { MysteriousChestEncounter } from "./encounters/mysterious-chest-encounter"; +import { FightOrFlightEncounter } from "./encounters/fight-or-flight-encounter"; +import { TrainingSessionEncounter } from "./encounters/training-session-encounter"; import { Biome } from "#enums/biome"; -import { SleepingSnorlaxEncounter } from "./encounters/sleeping-snorlax"; +import { SleepingSnorlaxEncounter } from "./encounters/sleeping-snorlax-encounter"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; -import { DepartmentStoreSaleEncounter } from "#app/data/mystery-encounters/encounters/department-store-sale"; -import { ShadyVitaminDealerEncounter } from "#app/data/mystery-encounters/encounters/shady-vitamin-dealer"; -import { FieldTripEncounter } from "#app/data/mystery-encounters/encounters/field-trip-encounter"; +import { DepartmentStoreSaleEncounter } from "./encounters/department-store-sale-encounter"; +import { ShadyVitaminDealerEncounter } from "./encounters/shady-vitamin-dealer-encounter"; +import { FieldTripEncounter } from "./encounters/field-trip-encounter"; // Spawn chance: (BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT + WIGHT_INCREMENT_ON_SPAWN_MISS * ) / 256 export const BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT = 1; From 92565691810f29354489c5efa988396431faa632 Mon Sep 17 00:00:00 2001 From: Felix Staud Date: Thu, 11 Jul 2024 15:18:27 -0700 Subject: [PATCH 16/19] minor fix in phases.ts for myst.-enc. --- src/phases.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/phases.ts b/src/phases.ts index eeee9640427..6c64cc9454f 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -828,7 +828,7 @@ export class EncounterPhase extends BattlePhase { if (mysteryEncounter.onInit) { mysteryEncounter.onInit(this.scene); } - // mysteryEncounter.populateDialogueTokensFromRequirements(this.scene); + mysteryEncounter.populateDialogueTokensFromRequirements(this.scene); }, this.scene.currentBattle.waveIndex); // Add intro visuals for mystery encounter From 0326cb25383e0f4dc0fab834cbc6b4fad0b41b60 Mon Sep 17 00:00:00 2001 From: Felix Staud Date: Thu, 11 Jul 2024 15:18:59 -0700 Subject: [PATCH 17/19] reset overrides.ts --- src/overrides.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/overrides.ts b/src/overrides.ts index 1e428c6dd2d..e19a5bf20dd 100644 --- a/src/overrides.ts +++ b/src/overrides.ts @@ -34,7 +34,7 @@ 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 = 33; +export const STARTING_WAVE_OVERRIDE: integer = 0; 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 From 4d4d0e55cc9fdc6f7a4ff38df8759a8450b6c07a Mon Sep 17 00:00:00 2001 From: Felix Staud Date: Thu, 11 Jul 2024 15:24:40 -0700 Subject: [PATCH 18/19] fix myster-encounter-ui-handler duplicate req. check --- src/ui/mystery-encounter-ui-handler.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/ui/mystery-encounter-ui-handler.ts b/src/ui/mystery-encounter-ui-handler.ts index c446481b744..7eb93f9b4ab 100644 --- a/src/ui/mystery-encounter-ui-handler.ts +++ b/src/ui/mystery-encounter-ui-handler.ts @@ -307,6 +307,8 @@ export default class MysteryEncounterUiHandler extends UiHandler { // Options Window for (let i = 0; i < this.filteredEncounterOptions.length; i++) { + const option = this.filteredEncounterOptions[i]; + let optionText; switch (this.filteredEncounterOptions.length) { case 2: @@ -319,10 +321,9 @@ export default class MysteryEncounterUiHandler extends UiHandler { optionText = addBBCodeTextObject(this.scene, i % 2 === 0 ? 0 : 100, i < 2 ? 0 : 16, "-", TextStyle.WINDOW, { wordWrap: { width: 558 }, fontSize: "80px", lineSpacing: -8 }); break; } - const option = this.filteredEncounterOptions[i]; - this.optionsMeetsReqs.push(this.filteredEncounterOptions[i].meetsRequirements(this.scene)); - const optionDialogue = option.dialogue ?? mysteryEncounter.dialogue.encounterOptionsDialogue.options[i]; + this.optionsMeetsReqs.push(option.meetsRequirements(this.scene)); + const optionDialogue = option.dialogue; let text: string; if (option.hasRequirements() && this.optionsMeetsReqs[i]) { // Options with special requirements that are met are automatically colored green @@ -336,8 +337,6 @@ export default class MysteryEncounterUiHandler extends UiHandler { optionText.setText(text); } - this.optionsMeetsReqs.push(option.meetsRequirements(this.scene)); - if (!this.optionsMeetsReqs[i]) { optionText.setAlpha(0.5); } From 96554427b586ed3acdac3c3e825d16958c037fd2 Mon Sep 17 00:00:00 2001 From: Felix Staud Date: Thu, 11 Jul 2024 15:27:33 -0700 Subject: [PATCH 19/19] fix myster-encounter-ui-handler duplicate --- src/ui/mystery-encounter-ui-handler.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/ui/mystery-encounter-ui-handler.ts b/src/ui/mystery-encounter-ui-handler.ts index 7eb93f9b4ab..9eccfd5d0e8 100644 --- a/src/ui/mystery-encounter-ui-handler.ts +++ b/src/ui/mystery-encounter-ui-handler.ts @@ -337,7 +337,7 @@ export default class MysteryEncounterUiHandler extends UiHandler { optionText.setText(text); } - if (!this.optionsMeetsReqs[i]) { + if (!this.optionsMeetsReqs[i] && option.isDisabledOnRequirementsNotMet) { optionText.setAlpha(0.5); } if (this.blockInput) { @@ -422,11 +422,10 @@ export default class MysteryEncounterUiHandler extends UiHandler { return; } - const mysteryEncounter = this.scene.currentBattle.mysteryEncounter; let text: string; - const option = this.filteredEncounterOptions[cursor]; - const optionDialogue = option.dialogue ?? mysteryEncounter.dialogue.encounterOptionsDialogue.options[cursor]; - if (!this.optionsMeetsReqs[cursor] && this.filteredEncounterOptions[cursor].isDisabledOnRequirementsNotMet && optionDialogue.disabledTooltip) { + const cursorOption = this.filteredEncounterOptions[cursor]; + const optionDialogue = cursorOption.dialogue; + if (!this.optionsMeetsReqs[cursor] && cursorOption.isDisabledOnRequirementsNotMet && optionDialogue.disabledTooltip) { text = getEncounterText(this.scene, optionDialogue.disabledTooltip, TextStyle.TOOLTIP_CONTENT); } else { text = getEncounterText(this.scene, optionDialogue.buttonTooltip, TextStyle.TOOLTIP_CONTENT);