Merge branch 'beta' into evcndrf2

This commit is contained in:
NightKev 2025-06-12 21:34:13 -07:00
commit 2215aa0972
23 changed files with 90 additions and 123 deletions

View File

@ -1635,6 +1635,9 @@ export default class BattleScene extends SceneBase {
case SpeciesId.TATSUGIRI: case SpeciesId.TATSUGIRI:
case SpeciesId.PALDEA_TAUROS: case SpeciesId.PALDEA_TAUROS:
return randSeedInt(species.forms.length); return randSeedInt(species.forms.length);
case SpeciesId.MAUSHOLD:
case SpeciesId.DUDUNSPARCE:
return !randSeedInt(4) ? 1 : 0;
case SpeciesId.PIKACHU: case SpeciesId.PIKACHU:
if (this.currentBattle?.battleType === BattleType.TRAINER && this.currentBattle?.waveIndex < 30) { if (this.currentBattle?.battleType === BattleType.TRAINER && this.currentBattle?.waveIndex < 30) {
return 0; // Ban Cosplay and Partner Pika from Trainers before wave 30 return 0; // Ban Cosplay and Partner Pika from Trainers before wave 30

View File

@ -9,6 +9,7 @@ import {
randSeedInt, randSeedInt,
type Constructor, type Constructor,
randSeedFloat, randSeedFloat,
coerceArray,
} from "#app/utils/common"; } from "#app/utils/common";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import { GroundedTag } from "#app/data/battler-tags"; import { GroundedTag } from "#app/data/battler-tags";
@ -4689,7 +4690,7 @@ export class PreApplyBattlerTagImmunityAbAttr extends PreApplyBattlerTagAbAttr {
constructor(immuneTagTypes: BattlerTagType | BattlerTagType[]) { constructor(immuneTagTypes: BattlerTagType | BattlerTagType[]) {
super(true); super(true);
this.immuneTagTypes = Array.isArray(immuneTagTypes) ? immuneTagTypes : [immuneTagTypes]; this.immuneTagTypes = coerceArray(immuneTagTypes);
} }
override canApplyPreApplyBattlerTag( override canApplyPreApplyBattlerTag(
@ -6694,7 +6695,7 @@ export class FlinchStatStageChangeAbAttr extends FlinchEffectAbAttr {
constructor(stats: BattleStat[], stages: number) { constructor(stats: BattleStat[], stages: number) {
super(); super();
this.stats = Array.isArray(stats) ? stats : [stats]; this.stats = stats;
this.stages = stages; this.stages = stages;
} }

View File

@ -2,7 +2,7 @@ import { globalScene } from "#app/global-scene";
import { allMoves } from "./data-lists"; import { allMoves } from "./data-lists";
import { MoveFlags } from "#enums/MoveFlags"; import { MoveFlags } from "#enums/MoveFlags";
import type Pokemon from "../field/pokemon"; import type Pokemon from "../field/pokemon";
import { type nil, getFrameMs, getEnumKeys, getEnumValues, animationFileName } from "../utils/common"; import { type nil, getFrameMs, getEnumKeys, getEnumValues, animationFileName, coerceArray } from "../utils/common";
import type { BattlerIndex } from "#enums/battler-index"; import type { BattlerIndex } from "#enums/battler-index";
import { MoveId } from "#enums/move-id"; import { MoveId } from "#enums/move-id";
import { SubstituteTag } from "./battler-tags"; import { SubstituteTag } from "./battler-tags";
@ -520,7 +520,7 @@ function logMissingMoveAnim(move: MoveId, ...optionalParams: any[]) {
* @param encounterAnim one or more animations to fetch * @param encounterAnim one or more animations to fetch
*/ */
export async function initEncounterAnims(encounterAnim: EncounterAnim | EncounterAnim[]): Promise<void> { export async function initEncounterAnims(encounterAnim: EncounterAnim | EncounterAnim[]): Promise<void> {
const anims = Array.isArray(encounterAnim) ? encounterAnim : [encounterAnim]; const anims = coerceArray(encounterAnim);
const encounterAnimNames = getEnumKeys(EncounterAnim); const encounterAnimNames = getEnumKeys(EncounterAnim);
const encounterAnimFetches: Promise<Map<EncounterAnim, AnimConfig>>[] = []; const encounterAnimFetches: Promise<Map<EncounterAnim, AnimConfig>>[] = [];
for (const anim of anims) { for (const anim of anims) {

View File

@ -21,7 +21,7 @@ import type { MoveEffectPhase } from "#app/phases/move-effect-phase";
import type { MovePhase } from "#app/phases/move-phase"; import type { MovePhase } from "#app/phases/move-phase";
import type { StatStageChangeCallback } from "#app/phases/stat-stage-change-phase"; import type { StatStageChangeCallback } from "#app/phases/stat-stage-change-phase";
import i18next from "#app/plugins/i18n"; import i18next from "#app/plugins/i18n";
import { BooleanHolder, getFrameMs, NumberHolder, toDmgValue } from "#app/utils/common"; import { BooleanHolder, coerceArray, getFrameMs, NumberHolder, toDmgValue } from "#app/utils/common";
import { AbilityId } from "#enums/ability-id"; import { AbilityId } from "#enums/ability-id";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { MoveId } from "#enums/move-id"; import { MoveId } from "#enums/move-id";
@ -50,7 +50,7 @@ export class BattlerTag {
isBatonPassable = false, isBatonPassable = false,
) { ) {
this.tagType = tagType; this.tagType = tagType;
this.lapseTypes = Array.isArray(lapseType) ? lapseType : [lapseType]; this.lapseTypes = coerceArray(lapseType);
this.turnCount = turnCount; this.turnCount = turnCount;
this.sourceMove = sourceMove!; // TODO: is this bang correct? this.sourceMove = sourceMove!; // TODO: is this bang correct?
this.sourceId = sourceId; this.sourceId = sourceId;

View File

@ -10,7 +10,7 @@ import { WeatherType } from "#enums/weather-type";
import type { PlayerPokemon } from "#app/field/pokemon"; import type { PlayerPokemon } from "#app/field/pokemon";
import { AttackTypeBoosterModifier } from "#app/modifier/modifier"; import { AttackTypeBoosterModifier } from "#app/modifier/modifier";
import type { AttackTypeBoosterModifierType } from "#app/modifier/modifier-type"; import type { AttackTypeBoosterModifierType } from "#app/modifier/modifier-type";
import { isNullOrUndefined } from "#app/utils/common"; import { coerceArray, isNullOrUndefined } from "#app/utils/common";
import type { AbilityId } from "#enums/ability-id"; import type { AbilityId } from "#enums/ability-id";
import { MoveId } from "#enums/move-id"; import { MoveId } from "#enums/move-id";
import type { MysteryEncounterType } from "#enums/mystery-encounter-type"; import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
@ -270,7 +270,7 @@ export class TimeOfDayRequirement extends EncounterSceneRequirement {
constructor(timeOfDay: TimeOfDay | TimeOfDay[]) { constructor(timeOfDay: TimeOfDay | TimeOfDay[]) {
super(); super();
this.requiredTimeOfDay = Array.isArray(timeOfDay) ? timeOfDay : [timeOfDay]; this.requiredTimeOfDay = coerceArray(timeOfDay);
} }
override meetsRequirement(): boolean { override meetsRequirement(): boolean {
@ -292,7 +292,7 @@ export class WeatherRequirement extends EncounterSceneRequirement {
constructor(weather: WeatherType | WeatherType[]) { constructor(weather: WeatherType | WeatherType[]) {
super(); super();
this.requiredWeather = Array.isArray(weather) ? weather : [weather]; this.requiredWeather = coerceArray(weather);
} }
override meetsRequirement(): boolean { override meetsRequirement(): boolean {
@ -358,7 +358,7 @@ export class PersistentModifierRequirement extends EncounterSceneRequirement {
constructor(heldItem: string | string[], minNumberOfItems = 1) { constructor(heldItem: string | string[], minNumberOfItems = 1) {
super(); super();
this.minNumberOfItems = minNumberOfItems; this.minNumberOfItems = minNumberOfItems;
this.requiredHeldItemModifiers = Array.isArray(heldItem) ? heldItem : [heldItem]; this.requiredHeldItemModifiers = coerceArray(heldItem);
} }
override meetsRequirement(): boolean { override meetsRequirement(): boolean {
@ -424,7 +424,7 @@ export class SpeciesRequirement extends EncounterPokemonRequirement {
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredSpecies = Array.isArray(species) ? species : [species]; this.requiredSpecies = coerceArray(species);
} }
override meetsRequirement(): boolean { override meetsRequirement(): boolean {
@ -464,7 +464,7 @@ export class NatureRequirement extends EncounterPokemonRequirement {
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredNature = Array.isArray(nature) ? nature : [nature]; this.requiredNature = coerceArray(nature);
} }
override meetsRequirement(): boolean { override meetsRequirement(): boolean {
@ -502,7 +502,7 @@ export class TypeRequirement extends EncounterPokemonRequirement {
this.excludeFainted = excludeFainted; this.excludeFainted = excludeFainted;
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredType = Array.isArray(type) ? type : [type]; this.requiredType = coerceArray(type);
} }
override meetsRequirement(): boolean { override meetsRequirement(): boolean {
@ -556,7 +556,7 @@ export class MoveRequirement extends EncounterPokemonRequirement {
this.excludeDisallowedPokemon = excludeDisallowedPokemon; this.excludeDisallowedPokemon = excludeDisallowedPokemon;
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredMoves = Array.isArray(moves) ? moves : [moves]; this.requiredMoves = coerceArray(moves);
} }
override meetsRequirement(): boolean { override meetsRequirement(): boolean {
@ -607,7 +607,7 @@ export class CompatibleMoveRequirement extends EncounterPokemonRequirement {
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredMoves = Array.isArray(learnableMove) ? learnableMove : [learnableMove]; this.requiredMoves = coerceArray(learnableMove);
} }
override meetsRequirement(): boolean { override meetsRequirement(): boolean {
@ -663,7 +663,7 @@ export class AbilityRequirement extends EncounterPokemonRequirement {
this.excludeDisallowedPokemon = excludeDisallowedPokemon; this.excludeDisallowedPokemon = excludeDisallowedPokemon;
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredAbilities = Array.isArray(abilities) ? abilities : [abilities]; this.requiredAbilities = coerceArray(abilities);
} }
override meetsRequirement(): boolean { override meetsRequirement(): boolean {
@ -708,7 +708,7 @@ export class StatusEffectRequirement extends EncounterPokemonRequirement {
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredStatusEffect = Array.isArray(statusEffect) ? statusEffect : [statusEffect]; this.requiredStatusEffect = coerceArray(statusEffect);
} }
override meetsRequirement(): boolean { override meetsRequirement(): boolean {
@ -783,7 +783,7 @@ export class CanFormChangeWithItemRequirement extends EncounterPokemonRequiremen
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredFormChangeItem = Array.isArray(formChangeItem) ? formChangeItem : [formChangeItem]; this.requiredFormChangeItem = coerceArray(formChangeItem);
} }
override meetsRequirement(): boolean { override meetsRequirement(): boolean {
@ -842,7 +842,7 @@ export class HeldItemRequirement extends EncounterPokemonRequirement {
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredHeldItemModifiers = Array.isArray(heldItem) ? heldItem : [heldItem]; this.requiredHeldItemModifiers = coerceArray(heldItem);
this.requireTransferable = requireTransferable; this.requireTransferable = requireTransferable;
} }
@ -906,7 +906,7 @@ export class AttackTypeBoosterHeldItemTypeRequirement extends EncounterPokemonRe
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredHeldItemTypes = Array.isArray(heldItemTypes) ? heldItemTypes : [heldItemTypes]; this.requiredHeldItemTypes = coerceArray(heldItemTypes);
this.requireTransferable = requireTransferable; this.requireTransferable = requireTransferable;
} }

View File

@ -2,7 +2,7 @@ import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encoun
import type { PlayerPokemon } from "#app/field/pokemon"; import type { PlayerPokemon } from "#app/field/pokemon";
import type { PokemonMove } from "../moves/pokemon-move"; import type { PokemonMove } from "../moves/pokemon-move";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { capitalizeFirstLetter, isNullOrUndefined } from "#app/utils/common"; import { capitalizeFirstLetter, coerceArray, isNullOrUndefined } from "#app/utils/common";
import type { MysteryEncounterType } from "#enums/mystery-encounter-type"; import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
import type { MysteryEncounterSpriteConfig } from "#app/field/mystery-encounter-intro"; import type { MysteryEncounterSpriteConfig } from "#app/field/mystery-encounter-intro";
import MysteryEncounterIntroVisuals from "#app/field/mystery-encounter-intro"; import MysteryEncounterIntroVisuals from "#app/field/mystery-encounter-intro";
@ -717,7 +717,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
withAnimations( withAnimations(
...encounterAnimations: EncounterAnim[] ...encounterAnimations: EncounterAnim[]
): this & Required<Pick<IMysteryEncounter, "encounterAnimations">> { ): this & Required<Pick<IMysteryEncounter, "encounterAnimations">> {
const animations = Array.isArray(encounterAnimations) ? encounterAnimations : [encounterAnimations]; const animations = coerceArray(encounterAnimations);
return Object.assign(this, { encounterAnimations: animations }); return Object.assign(this, { encounterAnimations: animations });
} }
@ -729,7 +729,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
withDisallowedGameModes( withDisallowedGameModes(
...disallowedGameModes: GameModes[] ...disallowedGameModes: GameModes[]
): this & Required<Pick<IMysteryEncounter, "disallowedGameModes">> { ): this & Required<Pick<IMysteryEncounter, "disallowedGameModes">> {
const gameModes = Array.isArray(disallowedGameModes) ? disallowedGameModes : [disallowedGameModes]; const gameModes = coerceArray(disallowedGameModes);
return Object.assign(this, { disallowedGameModes: gameModes }); return Object.assign(this, { disallowedGameModes: gameModes });
} }
@ -741,7 +741,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
withDisallowedChallenges( withDisallowedChallenges(
...disallowedChallenges: Challenges[] ...disallowedChallenges: Challenges[]
): this & Required<Pick<IMysteryEncounter, "disallowedChallenges">> { ): this & Required<Pick<IMysteryEncounter, "disallowedChallenges">> {
const challenges = Array.isArray(disallowedChallenges) ? disallowedChallenges : [disallowedChallenges]; const challenges = coerceArray(disallowedChallenges);
return Object.assign(this, { disallowedChallenges: challenges }); return Object.assign(this, { disallowedChallenges: challenges });
} }

View File

@ -1,7 +1,7 @@
import type { MoveId } from "#enums/move-id"; import type { MoveId } from "#enums/move-id";
import type { PlayerPokemon } from "#app/field/pokemon"; import type { PlayerPokemon } from "#app/field/pokemon";
import { PokemonMove } from "#app/data/moves/pokemon-move"; import { PokemonMove } from "#app/data/moves/pokemon-move";
import { isNullOrUndefined } from "#app/utils/common"; import { coerceArray, isNullOrUndefined } from "#app/utils/common";
import { EncounterPokemonRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements"; import { EncounterPokemonRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
@ -29,7 +29,7 @@ export class CanLearnMoveRequirement extends EncounterPokemonRequirement {
constructor(requiredMoves: MoveId | MoveId[], options: CanLearnMoveRequirementOptions = {}) { constructor(requiredMoves: MoveId | MoveId[], options: CanLearnMoveRequirementOptions = {}) {
super(); super();
this.requiredMoves = Array.isArray(requiredMoves) ? requiredMoves : [requiredMoves]; this.requiredMoves = coerceArray(requiredMoves);
this.excludeLevelMoves = options.excludeLevelMoves ?? false; this.excludeLevelMoves = options.excludeLevelMoves ?? false;
this.excludeTmMoves = options.excludeTmMoves ?? false; this.excludeTmMoves = options.excludeTmMoves ?? false;

View File

@ -25,7 +25,7 @@ import type { OptionSelectConfig, OptionSelectItem } from "#app/ui/abstact-optio
import type { PartyOption, PokemonSelectFilter } from "#app/ui/party-ui-handler"; import type { PartyOption, PokemonSelectFilter } from "#app/ui/party-ui-handler";
import { PartyUiMode } from "#app/ui/party-ui-handler"; import { PartyUiMode } from "#app/ui/party-ui-handler";
import { UiMode } from "#enums/ui-mode"; import { UiMode } from "#enums/ui-mode";
import { isNullOrUndefined, randSeedInt, randomString, randSeedItem } from "#app/utils/common"; import { isNullOrUndefined, randSeedInt, randomString, randSeedItem, coerceArray } from "#app/utils/common";
import type { BattlerTagType } from "#enums/battler-tag-type"; import type { BattlerTagType } from "#enums/battler-tag-type";
import { BiomeId } from "#enums/biome-id"; import { BiomeId } from "#enums/biome-id";
import type { TrainerType } from "#enums/trainer-type"; import type { TrainerType } from "#enums/trainer-type";
@ -449,7 +449,7 @@ export async function initBattleWithEnemyConfig(partyConfig: EnemyPartyConfig):
* @param moves * @param moves
*/ */
export function loadCustomMovesForEncounter(moves: MoveId | MoveId[]) { export function loadCustomMovesForEncounter(moves: MoveId | MoveId[]) {
moves = Array.isArray(moves) ? moves : [moves]; moves = coerceArray(moves);
return Promise.all(moves.map(move => initMoveAnim(move))).then(() => loadMoveAnimAssets(moves)); return Promise.all(moves.map(move => initMoveAnim(move))).then(() => loadMoveAnimAssets(moves));
} }
@ -792,7 +792,7 @@ export function setEncounterRewards(
* @param useWaveIndex - set to false when directly passing the the full exp value instead of baseExpValue * @param useWaveIndex - set to false when directly passing the the full exp value instead of baseExpValue
*/ */
export function setEncounterExp(participantId: number | number[], baseExpValue: number, useWaveIndex = true) { export function setEncounterExp(participantId: number | number[], baseExpValue: number, useWaveIndex = true) {
const participantIds = Array.isArray(participantId) ? participantId : [participantId]; const participantIds = coerceArray(participantId);
globalScene.currentBattle.mysteryEncounter!.doEncounterExp = () => { globalScene.currentBattle.mysteryEncounter!.doEncounterExp = () => {
globalScene.phaseManager.unshiftNew("PartyExpPhase", baseExpValue, useWaveIndex, new Set(participantIds)); globalScene.phaseManager.unshiftNew("PartyExpPhase", baseExpValue, useWaveIndex, new Set(participantIds));

View File

@ -1,5 +1,5 @@
import i18next from "i18next"; import i18next from "i18next";
import type { Constructor } from "#app/utils/common"; import { coerceArray, type Constructor } from "#app/utils/common";
import type { TimeOfDay } from "#enums/time-of-day"; import type { TimeOfDay } from "#enums/time-of-day";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import type { SpeciesFormChange } from "#app/data/pokemon-forms"; import type { SpeciesFormChange } from "#app/data/pokemon-forms";
@ -125,10 +125,7 @@ export class SpeciesFormChangeStatusEffectTrigger extends SpeciesFormChangeTrigg
constructor(statusEffects: StatusEffect | StatusEffect[], invert = false) { constructor(statusEffects: StatusEffect | StatusEffect[], invert = false) {
super(); super();
if (!Array.isArray(statusEffects)) { this.statusEffects = coerceArray(statusEffects);
statusEffects = [statusEffects];
}
this.statusEffects = statusEffects;
this.invert = invert; this.invert = invert;
// this.description = i18next.t("pokemonEvolutions:Forms.statusEffect"); // this.description = i18next.t("pokemonEvolutions:Forms.statusEffect");
} }

View File

@ -1,7 +1,14 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { modifierTypes } from "../data-lists"; import { modifierTypes } from "../data-lists";
import { PokemonMove } from "../moves/pokemon-move"; import { PokemonMove } from "../moves/pokemon-move";
import { toReadableString, isNullOrUndefined, randSeedItem, randSeedInt, randSeedIntRange } from "#app/utils/common"; import {
toReadableString,
isNullOrUndefined,
randSeedItem,
randSeedInt,
coerceArray,
randSeedIntRange,
} from "#app/utils/common";
import { pokemonEvolutions, pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions"; import { pokemonEvolutions, pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions";
import { getPokemonSpecies } from "#app/data/pokemon-species"; import { getPokemonSpecies } from "#app/data/pokemon-species";
import { tmSpecies } from "#app/data/balance/tms"; import { tmSpecies } from "#app/data/balance/tms";
@ -554,10 +561,7 @@ export class TrainerConfig {
this.speciesPools = evilAdminTrainerPools[poolName]; this.speciesPools = evilAdminTrainerPools[poolName];
signatureSpecies.forEach((speciesPool, s) => { signatureSpecies.forEach((speciesPool, s) => {
if (!Array.isArray(speciesPool)) { this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(coerceArray(speciesPool)));
speciesPool = [speciesPool];
}
this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool));
}); });
const nameForCall = this.name.toLowerCase().replace(/\s/g, "_"); const nameForCall = this.name.toLowerCase().replace(/\s/g, "_");
@ -620,10 +624,7 @@ export class TrainerConfig {
this.setPartyTemplates(trainerPartyTemplates.RIVAL_5); this.setPartyTemplates(trainerPartyTemplates.RIVAL_5);
} }
signatureSpecies.forEach((speciesPool, s) => { signatureSpecies.forEach((speciesPool, s) => {
if (!Array.isArray(speciesPool)) { this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(coerceArray(speciesPool)));
speciesPool = [speciesPool];
}
this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool));
}); });
if (!isNullOrUndefined(specialtyType)) { if (!isNullOrUndefined(specialtyType)) {
this.setSpeciesFilter(p => p.isOfType(specialtyType)); this.setSpeciesFilter(p => p.isOfType(specialtyType));
@ -668,12 +669,8 @@ export class TrainerConfig {
// Set up party members with their corresponding species. // Set up party members with their corresponding species.
signatureSpecies.forEach((speciesPool, s) => { signatureSpecies.forEach((speciesPool, s) => {
// Ensure speciesPool is an array.
if (!Array.isArray(speciesPool)) {
speciesPool = [speciesPool];
}
// Set a function to get a random party member from the species pool. // Set a function to get a random party member from the species pool.
this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool)); this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(coerceArray(speciesPool)));
}); });
// If specialty type is provided, set species filter and specialty type. // If specialty type is provided, set species filter and specialty type.
@ -729,12 +726,8 @@ export class TrainerConfig {
// Set up party members with their corresponding species. // Set up party members with their corresponding species.
signatureSpecies.forEach((speciesPool, s) => { signatureSpecies.forEach((speciesPool, s) => {
// Ensure speciesPool is an array.
if (!Array.isArray(speciesPool)) {
speciesPool = [speciesPool];
}
// Set a function to get a random party member from the species pool. // Set a function to get a random party member from the species pool.
this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool)); this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(coerceArray(speciesPool)));
}); });
// Set species filter and specialty type if provided, otherwise filter by base total. // Set species filter and specialty type if provided, otherwise filter by base total.

View File

@ -1,6 +1,6 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import Pokemon from "./pokemon"; import Pokemon from "./pokemon";
import { fixedInt, randInt } from "#app/utils/common"; import { fixedInt, coerceArray, randInt } from "#app/utils/common";
export default class PokemonSpriteSparkleHandler { export default class PokemonSpriteSparkleHandler {
private sprites: Set<Phaser.GameObjects.Sprite>; private sprites: Set<Phaser.GameObjects.Sprite>;
@ -57,9 +57,7 @@ export default class PokemonSpriteSparkleHandler {
} }
add(sprites: Phaser.GameObjects.Sprite | Phaser.GameObjects.Sprite[]): void { add(sprites: Phaser.GameObjects.Sprite | Phaser.GameObjects.Sprite[]): void {
if (!Array.isArray(sprites)) { sprites = coerceArray(sprites);
sprites = [sprites];
}
for (const s of sprites) { for (const s of sprites) {
if (this.sprites.has(s)) { if (this.sprites.has(s)) {
continue; continue;
@ -69,9 +67,7 @@ export default class PokemonSpriteSparkleHandler {
} }
remove(sprites: Phaser.GameObjects.Sprite | Phaser.GameObjects.Sprite[]): void { remove(sprites: Phaser.GameObjects.Sprite | Phaser.GameObjects.Sprite[]): void {
if (!Array.isArray(sprites)) { sprites = coerceArray(sprites);
sprites = [sprites];
}
for (const s of sprites) { for (const s of sprites) {
this.sprites.delete(s); this.sprites.delete(s);
} }

View File

@ -41,6 +41,7 @@ import {
type nil, type nil,
type Constructor, type Constructor,
randSeedIntRange, randSeedIntRange,
coerceArray,
} from "#app/utils/common"; } from "#app/utils/common";
import type { TypeDamageMultiplier } from "#app/data/type"; import type { TypeDamageMultiplier } from "#app/data/type";
import { getTypeDamageMultiplier, getTypeRgb } from "#app/data/type"; import { getTypeDamageMultiplier, getTypeRgb } from "#app/data/type";
@ -1774,9 +1775,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
let overrideArray: MoveId | Array<MoveId> = this.isPlayer() let overrideArray: MoveId | Array<MoveId> = this.isPlayer()
? Overrides.MOVESET_OVERRIDE ? Overrides.MOVESET_OVERRIDE
: Overrides.OPP_MOVESET_OVERRIDE; : Overrides.OPP_MOVESET_OVERRIDE;
if (!Array.isArray(overrideArray)) { overrideArray = coerceArray(overrideArray);
overrideArray = [overrideArray];
}
if (overrideArray.length > 0) { if (overrideArray.length > 0) {
if (!this.isPlayer()) { if (!this.isPlayer()) {
this.moveset = []; this.moveset = [];

View File

@ -12,7 +12,7 @@ import { CheckStatusEffectPhase } from "#app/phases/check-status-effect-phase";
import { CheckSwitchPhase } from "#app/phases/check-switch-phase"; import { CheckSwitchPhase } from "#app/phases/check-switch-phase";
import { CommandPhase } from "#app/phases/command-phase"; import { CommandPhase } from "#app/phases/command-phase";
import { CommonAnimPhase } from "#app/phases/common-anim-phase"; import { CommonAnimPhase } from "#app/phases/common-anim-phase";
import type { Constructor } from "#app/utils/common"; import { coerceArray, type Constructor } from "#app/utils/common";
import { DamageAnimPhase } from "#app/phases/damage-anim-phase"; import { DamageAnimPhase } from "#app/phases/damage-anim-phase";
import type { DynamicPhaseType } from "#enums/dynamic-phase-type"; import type { DynamicPhaseType } from "#enums/dynamic-phase-type";
import { EggHatchPhase } from "#app/phases/egg-hatch-phase"; import { EggHatchPhase } from "#app/phases/egg-hatch-phase";
@ -438,9 +438,7 @@ export class PhaseManager {
* @returns boolean if a targetPhase was found and added * @returns boolean if a targetPhase was found and added
*/ */
prependToPhase(phase: Phase | Phase[], targetPhase: PhaseString): boolean { prependToPhase(phase: Phase | Phase[], targetPhase: PhaseString): boolean {
if (!Array.isArray(phase)) { phase = coerceArray(phase);
phase = [phase];
}
const target = PHASES[targetPhase]; const target = PHASES[targetPhase];
const targetIndex = this.phaseQueue.findIndex(ph => ph instanceof target); const targetIndex = this.phaseQueue.findIndex(ph => ph instanceof target);
@ -460,9 +458,7 @@ export class PhaseManager {
* @returns `true` if a `targetPhase` was found to append to * @returns `true` if a `targetPhase` was found to append to
*/ */
appendToPhase(phase: Phase | Phase[], targetPhase: PhaseString, condition?: (p: Phase) => boolean): boolean { appendToPhase(phase: Phase | Phase[], targetPhase: PhaseString, condition?: (p: Phase) => boolean): boolean {
if (!Array.isArray(phase)) { phase = coerceArray(phase);
phase = [phase];
}
const target = PHASES[targetPhase]; const target = PHASES[targetPhase];
const targetIndex = this.phaseQueue.findIndex(ph => ph instanceof target && (!condition || condition(ph))); const targetIndex = this.phaseQueue.findIndex(ph => ph instanceof target && (!condition || condition(ph)));

View File

@ -1,10 +1,8 @@
import { coerceArray } from "#app/utils/common";
let manifest: object; let manifest: object;
export default class CacheBustedLoaderPlugin extends Phaser.Loader.LoaderPlugin { export default class CacheBustedLoaderPlugin extends Phaser.Loader.LoaderPlugin {
constructor(scene: Phaser.Scene) {
super(scene);
}
get manifest() { get manifest() {
return manifest; return manifest;
} }
@ -14,9 +12,7 @@ export default class CacheBustedLoaderPlugin extends Phaser.Loader.LoaderPlugin
} }
addFile(file): void { addFile(file): void {
if (!Array.isArray(file)) { file = coerceArray(file);
file = [file];
}
file.forEach(item => { file.forEach(item => {
if (manifest) { if (manifest) {

View File

@ -41,9 +41,9 @@ export function minifyJsonPlugin(basePath: string | string[], recursive?: boolea
}, },
async closeBundle() { async closeBundle() {
console.log("Minifying JSON files..."); console.log("Minifying JSON files...");
const basePathes = Array.isArray(basePath) ? basePath : [basePath]; const basePaths = Array.isArray(basePath) ? basePath : [basePath];
basePathes.forEach(basePath => { basePaths.forEach(basePath => {
const baseDir = path.resolve(buildDir, basePath); const baseDir = path.resolve(buildDir, basePath);
if (fs.existsSync(baseDir)) { if (fs.existsSync(baseDir)) {
applyToDir(baseDir, recursive); applyToDir(baseDir, recursive);

View File

@ -1,3 +1,5 @@
import { coerceArray } from "#app/utils/common";
export const legacyCompatibleImages: string[] = []; export const legacyCompatibleImages: string[] = [];
export class SceneBase extends Phaser.Scene { export class SceneBase extends Phaser.Scene {
@ -88,9 +90,7 @@ export class SceneBase extends Phaser.Scene {
} else { } else {
folder += "/"; folder += "/";
} }
if (!Array.isArray(filenames)) { filenames = coerceArray(filenames);
filenames = [filenames];
}
for (const f of filenames as string[]) { for (const f of filenames as string[]) {
this.load.audio(folder + key, this.getCachedUrl(`audio/${folder}${f}`)); this.load.audio(folder + key, this.getCachedUrl(`audio/${folder}${f}`));
} }

View File

@ -1,5 +1,5 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { fixedInt } from "#app/utils/common"; import { fixedInt, coerceArray } from "#app/utils/common";
export enum PokemonIconAnimMode { export enum PokemonIconAnimMode {
NONE, NONE,
@ -49,9 +49,7 @@ export default class PokemonIconAnimHandler {
} }
addOrUpdate(icons: PokemonIcon | PokemonIcon[], mode: PokemonIconAnimMode): void { addOrUpdate(icons: PokemonIcon | PokemonIcon[], mode: PokemonIconAnimMode): void {
if (!Array.isArray(icons)) { icons = coerceArray(icons);
icons = [icons];
}
for (const i of icons) { for (const i of icons) {
if (this.icons.has(i) && this.icons.get(i) === mode) { if (this.icons.has(i) && this.icons.get(i) === mode) {
continue; continue;
@ -66,9 +64,7 @@ export default class PokemonIconAnimHandler {
} }
remove(icons: PokemonIcon | PokemonIcon[]): void { remove(icons: PokemonIcon | PokemonIcon[]): void {
if (!Array.isArray(icons)) { icons = coerceArray(icons);
icons = [icons];
}
for (const i of icons) { for (const i of icons) {
if (this.toggled) { if (this.toggled) {
const icon = this.icons.get(i); const icon = this.icons.get(i);

View File

@ -611,3 +611,12 @@ export function getShinyDescriptor(variant: Variant): string {
return i18next.t("common:commonShiny"); return i18next.t("common:commonShiny");
} }
} }
/**
* If the input isn't already an array, turns it into one.
* @returns An array with the same type as the type of the input
*/
export function coerceArray<T>(input: T): T extends any[] ? T : [T];
export function coerceArray<T>(input: T): T | [T] {
return Array.isArray(input) ? input : [input];
}

View File

@ -12,6 +12,7 @@ import { UiMode } from "#enums/ui-mode";
import { getMovePosition } from "#test/testUtils/gameManagerUtils"; import { getMovePosition } from "#test/testUtils/gameManagerUtils";
import { GameManagerHelper } from "#test/testUtils/helpers/gameManagerHelper"; import { GameManagerHelper } from "#test/testUtils/helpers/gameManagerHelper";
import { vi } from "vitest"; import { vi } from "vitest";
import { coerceArray } from "#app/utils/common";
/** /**
* Helper to handle a Pokemon's move * Helper to handle a Pokemon's move
@ -157,9 +158,7 @@ export class MoveHelper extends GameManagerHelper {
* @param moveset - The {@linkcode MoveId} (single or array) to change the Pokemon's moveset to. * @param moveset - The {@linkcode MoveId} (single or array) to change the Pokemon's moveset to.
*/ */
public changeMoveset(pokemon: Pokemon, moveset: MoveId | MoveId[]): void { public changeMoveset(pokemon: Pokemon, moveset: MoveId | MoveId[]): void {
if (!Array.isArray(moveset)) { moveset = coerceArray(moveset);
moveset = [moveset];
}
pokemon.moveset = []; pokemon.moveset = [];
moveset.forEach(move => { moveset.forEach(move => {
pokemon.moveset.push(new PokemonMove(move)); pokemon.moveset.push(new PokemonMove(move));

View File

@ -14,7 +14,7 @@ import { StatusEffect } from "#enums/status-effect";
import type { WeatherType } from "#enums/weather-type"; import type { WeatherType } from "#enums/weather-type";
import { expect, vi } from "vitest"; import { expect, vi } from "vitest";
import { GameManagerHelper } from "./gameManagerHelper"; import { GameManagerHelper } from "./gameManagerHelper";
import { shiftCharCodes } from "#app/utils/common"; import { coerceArray, shiftCharCodes } from "#app/utils/common";
import type { RandomTrainerOverride } from "#app/overrides"; import type { RandomTrainerOverride } from "#app/overrides";
import type { BattleType } from "#enums/battle-type"; import type { BattleType } from "#enums/battle-type";
@ -202,9 +202,7 @@ export class OverridesHelper extends GameManagerHelper {
*/ */
public moveset(moveset: MoveId | MoveId[]): this { public moveset(moveset: MoveId | MoveId[]): this {
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue(moveset); vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue(moveset);
if (!Array.isArray(moveset)) { moveset = coerceArray(moveset);
moveset = [moveset];
}
const movesetStr = moveset.map(moveId => MoveId[moveId]).join(", "); const movesetStr = moveset.map(moveId => MoveId[moveId]).join(", ");
this.log(`Player Pokemon moveset set to ${movesetStr} (=[${moveset.join(", ")}])!`); this.log(`Player Pokemon moveset set to ${movesetStr} (=[${moveset.join(", ")}])!`);
return this; return this;
@ -382,9 +380,7 @@ export class OverridesHelper extends GameManagerHelper {
*/ */
public enemyMoveset(moveset: MoveId | MoveId[]): this { public enemyMoveset(moveset: MoveId | MoveId[]): this {
vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue(moveset); vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue(moveset);
if (!Array.isArray(moveset)) { moveset = coerceArray(moveset);
moveset = [moveset];
}
const movesetStr = moveset.map(moveId => MoveId[moveId]).join(", "); const movesetStr = moveset.map(moveId => MoveId[moveId]).join(", ");
this.log(`Enemy Pokemon moveset set to ${movesetStr} (=[${moveset.join(", ")}])!`); this.log(`Enemy Pokemon moveset set to ${movesetStr} (=[${moveset.join(", ")}])!`);
return this; return this;

View File

@ -1,3 +1,4 @@
import { coerceArray } from "#app/utils/common";
import type MockTextureManager from "#test/testUtils/mocks/mockTextureManager"; import type MockTextureManager from "#test/testUtils/mocks/mockTextureManager";
import type { MockGameObject } from "../mockGameObject"; import type { MockGameObject } from "../mockGameObject";
@ -216,11 +217,7 @@ export default class MockContainer implements MockGameObject {
} }
add(obj: MockGameObject | MockGameObject[]): this { add(obj: MockGameObject | MockGameObject[]): this {
if (Array.isArray(obj)) { this.list.push(...coerceArray(obj));
this.list.push(...obj);
} else {
this.list.push(obj);
}
return this; return this;
} }
@ -232,18 +229,12 @@ export default class MockContainer implements MockGameObject {
addAt(obj: MockGameObject | MockGameObject[], index = 0): this { addAt(obj: MockGameObject | MockGameObject[], index = 0): this {
// Adds a Game Object to this Container at the given index. // Adds a Game Object to this Container at the given index.
if (!Array.isArray(obj)) { this.list.splice(index, 0, ...coerceArray(obj));
obj = [obj];
}
this.list.splice(index, 0, ...obj);
return this; return this;
} }
remove(obj: MockGameObject | MockGameObject[], destroyChild = false): this { remove(obj: MockGameObject | MockGameObject[], destroyChild = false): this {
if (!Array.isArray(obj)) { for (const item of coerceArray(obj)) {
obj = [obj];
}
for (const item of obj) {
const index = this.list.indexOf(item); const index = this.list.indexOf(item);
if (index !== -1) { if (index !== -1) {
this.list.splice(index, 1); this.list.splice(index, 1);

View File

@ -1,3 +1,4 @@
import { coerceArray } from "#app/utils/common";
import type { MockGameObject } from "../mockGameObject"; import type { MockGameObject } from "../mockGameObject";
export default class MockRectangle implements MockGameObject { export default class MockRectangle implements MockGameObject {
@ -50,11 +51,7 @@ export default class MockRectangle implements MockGameObject {
add(obj: MockGameObject | MockGameObject[]): this { add(obj: MockGameObject | MockGameObject[]): this {
// Adds a child to this Game Object. // Adds a child to this Game Object.
if (Array.isArray(obj)) { this.list.push(...coerceArray(obj));
this.list.push(...obj);
} else {
this.list.push(obj);
}
return this; return this;
} }

View File

@ -1,6 +1,8 @@
import { coerceArray } from "#app/utils/common";
import Phaser from "phaser"; import Phaser from "phaser";
import type { MockGameObject } from "../mockGameObject"; import type { MockGameObject } from "../mockGameObject";
import Frame = Phaser.Textures.Frame;
type Frame = Phaser.Textures.Frame;
export default class MockSprite implements MockGameObject { export default class MockSprite implements MockGameObject {
private phaserSprite; private phaserSprite;
@ -204,11 +206,7 @@ export default class MockSprite implements MockGameObject {
add(obj: MockGameObject | MockGameObject[]): this { add(obj: MockGameObject | MockGameObject[]): this {
// Adds a child to this Game Object. // Adds a child to this Game Object.
if (Array.isArray(obj)) { this.list.push(...coerceArray(obj));
this.list.push(...obj);
} else {
this.list.push(obj);
}
return this; return this;
} }