pokerogue/src/data/mystery-encounters/requirements/can-learn-move-requirement.ts
NightKev 7c6189e812
[Refactor] Create utility function coerceArray (#5723)
* [Refactor] Create utility function `makeArray`

This replaces the `if(!Array.isArray(var)) { var = [var] }` pattern

* Replace `if` with ternary, rename to `coerceArray`

* Add TSDocs

* Improve type inferencing

* Replace missed `Array.isArray` checks

* Apply Biome

* Re-apply changes to phase manager

* Re-apply to `SpeciesFormChangeStatusEffectTrigger` constructor

Apply to new instances in test mocks
2025-06-12 21:30:01 -07:00

94 lines
3.2 KiB
TypeScript

import type { MoveId } from "#enums/move-id";
import type { PlayerPokemon } from "#app/field/pokemon";
import { PokemonMove } from "#app/data/moves/pokemon-move";
import { coerceArray, isNullOrUndefined } from "#app/utils/common";
import { EncounterPokemonRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
import { globalScene } from "#app/global-scene";
/**
* {@linkcode CanLearnMoveRequirement} options
*/
export interface CanLearnMoveRequirementOptions {
excludeLevelMoves?: boolean;
excludeTmMoves?: boolean;
excludeEggMoves?: boolean;
includeFainted?: boolean;
minNumberOfPokemon?: number;
invertQuery?: boolean;
}
/**
* Requires that a pokemon can learn a specific move/moveset.
*/
export class CanLearnMoveRequirement extends EncounterPokemonRequirement {
private readonly requiredMoves: MoveId[];
private readonly excludeLevelMoves?: boolean;
private readonly excludeTmMoves?: boolean;
private readonly excludeEggMoves?: boolean;
private readonly includeFainted?: boolean;
constructor(requiredMoves: MoveId | MoveId[], options: CanLearnMoveRequirementOptions = {}) {
super();
this.requiredMoves = coerceArray(requiredMoves);
this.excludeLevelMoves = options.excludeLevelMoves ?? false;
this.excludeTmMoves = options.excludeTmMoves ?? false;
this.excludeEggMoves = options.excludeEggMoves ?? false;
this.includeFainted = options.includeFainted ?? false;
this.minNumberOfPokemon = options.minNumberOfPokemon ?? 1;
this.invertQuery = options.invertQuery ?? false;
}
override meetsRequirement(): boolean {
const partyPokemon = globalScene
.getPlayerParty()
.filter(pkm => (this.includeFainted ? pkm.isAllowedInChallenge() : pkm.isAllowedInBattle()));
if (isNullOrUndefined(partyPokemon) || this.requiredMoves?.length < 0) {
return false;
}
return this.queryParty(partyPokemon).length >= this.minNumberOfPokemon;
}
override queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {
if (!this.invertQuery) {
return partyPokemon.filter(pokemon =>
// every required move should be included
this.requiredMoves.every(requiredMove => this.getAllPokemonMoves(pokemon).includes(requiredMove)),
);
}
return partyPokemon.filter(
pokemon =>
// none of the "required" moves should be included
!this.requiredMoves.some(requiredMove => this.getAllPokemonMoves(pokemon).includes(requiredMove)),
);
}
override getDialogueToken(__pokemon?: PlayerPokemon): [string, string] {
return ["requiredMoves", this.requiredMoves.map(m => new PokemonMove(m).getName()).join(", ")];
}
private getPokemonLevelMoves(pkm: PlayerPokemon): MoveId[] {
return pkm.getLevelMoves().map(([_level, move]) => move);
}
private getAllPokemonMoves(pkm: PlayerPokemon): MoveId[] {
const allPokemonMoves: MoveId[] = [];
if (!this.excludeLevelMoves) {
allPokemonMoves.push(...(this.getPokemonLevelMoves(pkm) ?? []));
}
if (!this.excludeTmMoves) {
allPokemonMoves.push(...(pkm.compatibleTms ?? []));
}
if (!this.excludeEggMoves) {
allPokemonMoves.push(...(pkm.getEggMoves() ?? []));
}
return allPokemonMoves;
}
}