diff --git a/src/data/mystery-encounters/encounters/lost-at-sea-encounter.ts b/src/data/mystery-encounters/encounters/lost-at-sea-encounter.ts index b4525176cf1..f3af2e79c0e 100644 --- a/src/data/mystery-encounters/encounters/lost-at-sea-encounter.ts +++ b/src/data/mystery-encounters/encounters/lost-at-sea-encounter.ts @@ -1,21 +1,12 @@ import { Type } from "#app/data/type.js"; +import { Moves } from "#app/enums/moves.js"; import { Species } from "#app/enums/species.js"; import { PlayerPokemon } from "#app/field/pokemon.js"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import BattleScene from "../../../battle-scene"; -import MysteryEncounter, { - MysteryEncounterBuilder, - MysteryEncounterTier, -} from "../mystery-encounter"; -import { - EncounterOptionMode, - MysteryEncounterOptionBuilder, -} from "../mystery-encounter-option"; -import { - applyDamageToPokemon, - leaveEncounterWithoutBattle, - setEncounterExp, -} from "../mystery-encounter-utils"; +import MysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier } from "../mystery-encounter"; +import { EncounterOptionMode, MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; +import { applyDamageToPokemon, leaveEncounterWithoutBattle, setEncounterExp } from "../mystery-encounter-utils"; /** * Damage percentage taken when wandering aimlessly. @@ -26,7 +17,7 @@ const DAMAGE_PERCENTAGE: number = 30; // 0 - 100 /** The i18n namespace for the encounter */ const namepsace = "mysteryEncounter:lostAtSea"; -let waterPkm: PlayerPokemon; +let surfablePkm: PlayerPokemon; let flyingPkm: PlayerPokemon; /** @@ -34,137 +25,108 @@ let flyingPkm: PlayerPokemon; * @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/9 | GitHub Issue #9} * @see For biome requirements check [mysteryEncountersByBiome](../mystery-encounters.ts) */ -export const LostAtSeaEncounter: MysteryEncounter = - MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.LOST_AT_SEA) - .withEncounterTier(MysteryEncounterTier.COMMON) - .withSceneWaveRangeRequirement(11, 179) - .withIntroSpriteConfigs([ - { - fileRoot: "pokemon", - spriteKey: `${Species.GYARADOS}`, - hasShadow: false, - scale: 4, - y: 100, - x: 130, - tint: 0.75, - alpha: 0.25, - }, - ]) - .withIntroDialogue([ - { - text: `${namepsace}:intro`, - }, - ]) - .withOnInit((scene: BattleScene) => { - const allowedPokemon = scene - .getParty() - .filter((p) => p.isAllowedInBattle()); - const { mysteryEncounter } = scene.currentBattle; +export const LostAtSeaEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.LOST_AT_SEA) + .withEncounterTier(MysteryEncounterTier.COMMON) + .withSceneWaveRangeRequirement(11, 179) + .withIntroSpriteConfigs([ + { + fileRoot: "pokemon", + spriteKey: `${Species.GYARADOS}`, + hasShadow: false, + scale: 4, + y: 100, + x: 130, + tint: 0.75, + alpha: 0.25, + }, + ]) + .withIntroDialogue([{ text: `${namepsace}:intro` }]) + .withOnInit((scene: BattleScene) => { + // const allowedPokemon = scene.getParty().filter((p) => p.isAllowedInBattle()); + const { mysteryEncounter } = scene.currentBattle; - mysteryEncounter.setDialogueToken( - "damagePercentage", - String(DAMAGE_PERCENTAGE) - ); + mysteryEncounter.setDialogueToken("damagePercentage", String(DAMAGE_PERCENTAGE)); - // check for water pokemon - waterPkm = findPokemonByType(allowedPokemon, Type.WATER); - mysteryEncounter.setDialogueToken("waterPkm", waterPkm?.name ?? ""); + // check for water pokemon + // surfablePkm = findPokemonThatCanLearnMove(allowedPokemon, Type.WATER); + // mysteryEncounter.setDialogueToken("waterPkm", surfablePkm?.name ?? ""); - // check for flying pokemon - flyingPkm = findPokemonByType(allowedPokemon, Type.FLYING); - mysteryEncounter.setDialogueToken( - "flyingPkm", - flyingPkm?.name ?? "" - ); + // check for flying pokemon + // flyingPkm = findPokemonThatCanLearnMove(allowedPokemon, Type.FLYING); + // mysteryEncounter.setDialogueToken("flyingPkm", flyingPkm?.name ?? ""); - return true; - }) - .withTitle(`${namepsace}:title`) - .withDescription(`${namepsace}:description`) - .withQuery(`${namepsace}:query`) - .withOption( - /** - * Option 1: Use a (non fainted) water pokemon to guide you back. - * Receives EXP similar to defeating a Lapras - */ - new MysteryEncounterOptionBuilder() - .withPokemonTypeRequirement(Type.WATER, true, 1) - .withOptionMode(EncounterOptionMode.DISABLED_OR_DEFAULT) - .withDialogue({ - buttonLabel: `${namepsace}:option:1:label`, - buttonTooltip: `${namepsace}:option:1:tooltip`, - selected: [ - { - text: `${namepsace}:option:1:selected`, - }, - ], - }) - .withOptionPhase(async (scene: BattleScene) => - handleGuidingOptionPhase(scene, waterPkm) - ) - .build() - ) - .withOption( - /** - * Option 2: Use a (non fainted) flying pokemon to guide you back. - * Receives EXP similar to defeating a Lapras - */ - new MysteryEncounterOptionBuilder() - .withPokemonTypeRequirement(Type.FLYING, true, 1) - .withOptionMode(EncounterOptionMode.DISABLED_OR_DEFAULT) - .withDialogue({ - buttonLabel: `${namepsace}:option:2:label`, - buttonTooltip: `${namepsace}:option:2:tooltip`, - selected: [ - { - text: `${namepsace}:option:2:selected`, - }, - ], - }) - .withOptionPhase(async (scene: BattleScene) => - handleGuidingOptionPhase(scene, flyingPkm) - ) - .build() - ) - .withSimpleOption( - /** - * Option 3: Wander aimlessly. All pokemons lose {@linkcode DAMAGE_PERCENTAGE}}% of their HP (or KO on 0 HP). - */ - { - buttonLabel: `${namepsace}:option:3:label`, - buttonTooltip: `${namepsace}:option:3:tooltip`, + return true; + }) + .withTitle(`${namepsace}:title`) + .withDescription(`${namepsace}:description`) + .withQuery(`${namepsace}:query`) + .withOption( + /** + * Option 1: Use a (non fainted) water pokemon to guide you back. + * Receives EXP similar to defeating a Lapras + */ + new MysteryEncounterOptionBuilder() + .withPokemonCanLearnMoveRequirement(Moves.SURF) + .withOptionMode(EncounterOptionMode.DISABLED_OR_DEFAULT) + .withDialogue({ + buttonLabel: `${namepsace}:option:1:label`, + buttonTooltip: `${namepsace}:option:1:tooltip`, selected: [ { - text: `${namepsace}:option:3:selected`, + text: `${namepsace}:option:1:selected`, }, ], - }, - async (scene: BattleScene) => { - const allowedPokemon = scene - .getParty() - .filter((p) => p.isAllowedInBattle()); + }) + .withOptionPhase(async (scene: BattleScene) => handleGuidingOptionPhase(scene, surfablePkm)) + .build() + ) + .withOption( + /** + * Option 2: Use a (non fainted) flying pokemon to guide you back. + * Receives EXP similar to defeating a Lapras + */ + new MysteryEncounterOptionBuilder() + .withPokemonTypeRequirement(Type.FLYING, true, 1) + .withOptionMode(EncounterOptionMode.DISABLED_OR_DEFAULT) + .withDialogue({ + buttonLabel: `${namepsace}:option:2:label`, + buttonTooltip: `${namepsace}:option:2:tooltip`, + selected: [ + { + text: `${namepsace}:option:2:selected`, + }, + ], + }) + .withOptionPhase(async (scene: BattleScene) => handleGuidingOptionPhase(scene, flyingPkm)) + .build() + ) + .withSimpleOption( + /** + * Option 3: Wander aimlessly. All pokemons lose {@linkcode DAMAGE_PERCENTAGE}}% of their HP (or KO on 0 HP). + */ + { + buttonLabel: `${namepsace}:option:3:label`, + buttonTooltip: `${namepsace}:option:3:tooltip`, + selected: [ + { + text: `${namepsace}:option:3:selected`, + }, + ], + }, + async (scene: BattleScene) => { + const allowedPokemon = scene.getParty().filter((p) => p.isAllowedInBattle()); - allowedPokemon.forEach((pkm) => { - const percentage = DAMAGE_PERCENTAGE / 100; - const damage = Math.floor(pkm.getMaxHp() * percentage); - return applyDamageToPokemon(pkm, damage); - }); - leaveEncounterWithoutBattle(scene); - return true; - } - ) - .build(); + allowedPokemon.forEach((pkm) => { + const percentage = DAMAGE_PERCENTAGE / 100; + const damage = Math.floor(pkm.getMaxHp() * percentage); + return applyDamageToPokemon(pkm, damage); + }); + leaveEncounterWithoutBattle(scene); -/** - * Find a pokemon inside the given party by a given type - * - * @param party player pokemon party - * @param type type to search for - * @returns - */ -function findPokemonByType(party: PlayerPokemon[], type: Type) { - return party.find((p) => p.getTypes(true).includes(type)); -} + return true; + } + ) + .build(); /** * Generic handler for using a guiding pokemon to guide you back. @@ -172,19 +134,14 @@ function findPokemonByType(party: PlayerPokemon[], type: Type) { * @param scene Battle scene * @param guidePokemon pokemon choosen as a guide */ -function handleGuidingOptionPhase( - scene: BattleScene, - guidePokemon: PlayerPokemon -) { +function handleGuidingOptionPhase(scene: BattleScene, guidePokemon: PlayerPokemon) { /** Base EXP value for guiding pokemon. Currently Lapras base-value */ const baseExpValue: number = 187; if (guidePokemon) { setEncounterExp(scene, guidePokemon.id, baseExpValue, true); } else { - console.warn( - "Lost at sea: No guide pokemon found but pokemon guides player. huh!?" - ); + console.warn("Lost at sea: No guide pokemon found but pokemon guides player. huh!?"); } leaveEncounterWithoutBattle(scene); diff --git a/src/data/mystery-encounters/mystery-encounter-option.ts b/src/data/mystery-encounters/mystery-encounter-option.ts index 1dc62a5d2e5..7bbde3f3830 100644 --- a/src/data/mystery-encounters/mystery-encounter-option.ts +++ b/src/data/mystery-encounters/mystery-encounter-option.ts @@ -1,9 +1,11 @@ import { OptionTextDisplay } from "#app/data/mystery-encounters/mystery-encounter-dialogue"; +import { Moves } from "#app/enums/moves.js"; import { PlayerPokemon } from "#app/field/pokemon"; import BattleScene from "../../battle-scene"; import * as Utils from "../../utils"; import { Type } from "../type"; import { EncounterPokemonRequirement, EncounterSceneRequirement, MoneyRequirement, TypeRequirement } from "./mystery-encounter-requirements"; +import { CanLearnMoveRequirement, CanlearnMoveRequirementOptions } from "./requirements/can-learn-move-requirement"; export enum EncounterOptionMode { /** Default style */ @@ -194,8 +196,18 @@ export class MysteryEncounterOptionBuilder implements Partial> { diff --git a/src/data/mystery-encounters/mystery-encounters.ts b/src/data/mystery-encounters/mystery-encounters.ts index 67c95917a33..d489c51e178 100644 --- a/src/data/mystery-encounters/mystery-encounters.ts +++ b/src/data/mystery-encounters/mystery-encounters.ts @@ -1,15 +1,16 @@ -import IMysteryEncounter from "./mystery-encounter"; +import { Biome } from "#enums/biome"; +import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { DarkDealEncounter } from "./encounters/dark-deal-encounter"; +import { DepartmentStoreSaleEncounter } from "./encounters/department-store-sale-encounter"; +import { FieldTripEncounter } from "./encounters/field-trip-encounter"; +import { FightOrFlightEncounter } from "./encounters/fight-or-flight-encounter"; +import { LostAtSeaEncounter } from "./encounters/lost-at-sea-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-encounter"; -import { MysteryEncounterType } from "#enums/mystery-encounter-type"; -import { DepartmentStoreSaleEncounter } from "./encounters/department-store-sale-encounter"; import { ShadyVitaminDealerEncounter } from "./encounters/shady-vitamin-dealer-encounter"; -import { LostAtSeaEncounter } from "./encounters/lost-at-sea-encounter"; +import { SleepingSnorlaxEncounter } from "./encounters/sleeping-snorlax-encounter"; +import { TrainingSessionEncounter } from "./encounters/training-session-encounter"; +import IMysteryEncounter from "./mystery-encounter"; // Spawn chance: (BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT + WIGHT_INCREMENT_ON_SPAWN_MISS * ) / 256 export const BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT = 1; diff --git a/src/data/mystery-encounters/requirements/can-learn-move-requirement.ts b/src/data/mystery-encounters/requirements/can-learn-move-requirement.ts index c881602b4f8..ffdd1324177 100644 --- a/src/data/mystery-encounters/requirements/can-learn-move-requirement.ts +++ b/src/data/mystery-encounters/requirements/can-learn-move-requirement.ts @@ -7,7 +7,7 @@ import { EncounterPokemonRequirement } from "../mystery-encounter-requirements"; /** * {@linkcode CanLearnMoveRequirement} options */ -interface Options { +export interface CanlearnMoveRequirementOptions { excludeLevelMoves?: boolean; excludeTmMoves?: boolean; excludeEggMoves?: boolean; @@ -26,20 +26,11 @@ export class CanLearnMoveRequirement extends EncounterPokemonRequirement { private readonly excludeEggMoves?: boolean; private readonly includeFainted?: boolean; - constructor(requiredMoves: Moves | Moves[], options: Options = {}) { + constructor(requiredMoves: Moves | Moves[], options: CanlearnMoveRequirementOptions = {}) { super(); - this.requiredMoves = Array.isArray(requiredMoves) - ? requiredMoves - : [requiredMoves]; + this.requiredMoves = Array.isArray(requiredMoves) ? requiredMoves : [requiredMoves]; - const { - excludeLevelMoves, - excludeTmMoves, - excludeEggMoves, - includeFainted, - minNumberOfPokemon, - invertQuery, - } = options; + const { excludeLevelMoves, excludeTmMoves, excludeEggMoves, includeFainted, minNumberOfPokemon, invertQuery } = options; this.excludeLevelMoves = excludeLevelMoves ?? false; this.excludeTmMoves = excludeTmMoves ?? false; @@ -50,11 +41,7 @@ export class CanLearnMoveRequirement extends EncounterPokemonRequirement { } override meetsRequirement(scene: BattleScene): boolean { - const partyPokemon = scene - .getParty() - .filter((pkm) => - this.includeFainted ? pkm.isAllowed() : pkm.isAllowedInBattle() - ); + const partyPokemon = scene.getParty().filter((pkm) => (this.includeFainted ? pkm.isAllowed() : pkm.isAllowedInBattle())); if (isNullOrUndefined(partyPokemon) || this?.requiredMoves?.length < 0) { return false; @@ -67,26 +54,19 @@ export class CanLearnMoveRequirement extends EncounterPokemonRequirement { if (!this.invertQuery) { return partyPokemon.filter((pokemon) => // every required move should be included - this.requiredMoves.every((requiredMove) => - this.getAllPokemonMoves(pokemon).includes(requiredMove) - ) + this.requiredMoves.every((requiredMove) => this.getAllPokemonMoves(pokemon).includes(requiredMove)) ); } else { return partyPokemon.filter( (pokemon) => // none of the "required" moves should be included - !this.requiredMoves.some((requiredMove) => - this.getAllPokemonMoves(pokemon).includes(requiredMove) - ) + !this.requiredMoves.some((requiredMove) => this.getAllPokemonMoves(pokemon).includes(requiredMove)) ); } } - override getDialogueToken( - _scene: BattleScene, - _pokemon?: PlayerPokemon - ): [string, string] { - return ["requiredMoves", this.requiredMoves.join(", ")]; + override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { + return pokemon ? ["pokemonCanLearnMove", pokemon.name] : null; } private getPokemonLevelMoves(pkm: PlayerPokemon): Moves[] { diff --git a/src/locales/en/mystery-encounters/lost-at-sea.ts b/src/locales/en/mystery-encounters/lost-at-sea.ts index e4ea07c77ad..6c4664b8a4a 100644 --- a/src/locales/en/mystery-encounters/lost-at-sea.ts +++ b/src/locales/en/mystery-encounters/lost-at-sea.ts @@ -6,10 +6,10 @@ export const lostAtSea = { query: "What will you do?", option: { 1: { - label: "Use @ec{waterPkm}", // pkm has to be of type water + label: "Use @ec{pokemonCanLearnMove}", // pkm has to be of type water tooltip: - "Use @ec{waterPkm} to guide you back. @ec{waterPkm} earns EXP as if having defeated a Lapras.", - selected: "@ec{waterPkm} guides you back and earns EXP.", + "Use @ec{pokemonCanLearnMove} to guide you back. @ec{pokemonCanLearnMove} earns EXP as if having defeated a Lapras.", + selected: "@ec{pokemonCanLearnMove} guides you back and earns EXP.", }, 2: { label: "Use @ec{flyingPkm}", // pkm has to be of type flying