From ac2f09ad339d95c1481e79b068f0695dd6c0c42d Mon Sep 17 00:00:00 2001 From: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com> Date: Mon, 22 Sep 2025 18:42:50 -0500 Subject: [PATCH] Even more array improvements --- src/@types/trainer-funcs.ts | 4 +- src/battle.ts | 17 +- src/constants.ts | 2 +- src/data/balance/biomes.ts | 49 ++--- src/data/battler-tags.ts | 8 +- src/data/egg.ts | 6 +- src/data/pokemon-forms.ts | 5 +- .../pokemon-forms/form-change-triggers.ts | 15 +- src/field/pokemon.ts | 3 +- src/field/trainer.ts | 4 +- src/modifier/modifier-type.ts | 12 +- src/phases/battle-phase.ts | 2 +- src/timed-event-manager.ts | 203 +++++++++--------- src/ui/handlers/pokedex-page-ui-handler.ts | 6 +- src/utils/speed-order.ts | 11 +- 15 files changed, 178 insertions(+), 169 deletions(-) diff --git a/src/@types/trainer-funcs.ts b/src/@types/trainer-funcs.ts index aa839cbd158..cc4ba91aff3 100644 --- a/src/@types/trainer-funcs.ts +++ b/src/@types/trainer-funcs.ts @@ -7,8 +7,8 @@ import type { TrainerPartyTemplate } from "#trainers/trainer-party-template"; export type PartyTemplateFunc = () => TrainerPartyTemplate; export type PartyMemberFunc = (level: number, strength: PartyMemberStrength) => EnemyPokemon; -export type GenModifiersFunc = (party: EnemyPokemon[]) => PersistentModifier[]; -export type GenAIFunc = (party: EnemyPokemon[]) => void; +export type GenModifiersFunc = (party: readonly EnemyPokemon[]) => PersistentModifier[]; +export type GenAIFunc = (party: readonly EnemyPokemon[]) => void; export interface TrainerTierPools { [key: number]: SpeciesId[]; diff --git a/src/battle.ts b/src/battle.ts index 1b789707806..27a2498ffdb 100644 --- a/src/battle.ts +++ b/src/battle.ts @@ -526,24 +526,25 @@ export class FixedBattleConfig { /** * Helper function to generate a random trainer for evil team trainers and the elite 4/champion - * @param trainerPool The TrainerType or list of TrainerTypes that can possibly be generated - * @param randomGender whether or not to randomly (50%) generate a female trainer (for use with evil team grunts) - * @param seedOffset the seed offset to use for the random generation of the trainer - * @returns the generated trainer + * @param trainerPool - An array of trainer types to choose from. If an entry is an array, a random trainer type will be chosen from that array + * @param randomGender - Whether or not to randomly (50%) generate a female trainer (for use with evil team grunts) + * @param seedOffset - The seed offset to use for the random generation of the trainer + * @returns A function to get a random trainer */ export function getRandomTrainerFunc( - trainerPool: (TrainerType | TrainerType[])[], + trainerPool: readonly (TrainerType | readonly TrainerType[])[], randomGender = false, seedOffset = 0, ): GetTrainerFunc { return () => { const rand = randSeedInt(trainerPool.length); - const trainerTypes: TrainerType[] = []; + const trainerTypes: TrainerType[] = new Array(trainerPool.length); globalScene.executeWithSeedOffset(() => { - for (const trainerPoolEntry of trainerPool) { + for (let i = 0; i < trainerPool.length; i++) { + const trainerPoolEntry = trainerPool[i]; const trainerType = Array.isArray(trainerPoolEntry) ? randSeedItem(trainerPoolEntry) : trainerPoolEntry; - trainerTypes.push(trainerType); + trainerTypes[i] = trainerType; } }, seedOffset); diff --git a/src/constants.ts b/src/constants.ts index 17cf08aa7e2..8cc2cb550cb 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -23,7 +23,7 @@ export const TYPE_BOOST_ITEM_BOOST_PERCENT = 20; /** * The default species that a new player can choose from */ -export const defaultStarterSpecies: SpeciesId[] = [ +export const defaultStarterSpecies: readonly SpeciesId[] = [ SpeciesId.BULBASAUR, SpeciesId.CHARMANDER, SpeciesId.SQUIRTLE, diff --git a/src/data/balance/biomes.ts b/src/data/balance/biomes.ts index 9af2dbe221c..b7d74634589 100644 --- a/src/data/balance/biomes.ts +++ b/src/data/balance/biomes.ts @@ -5,6 +5,7 @@ import { PokemonType } from "#enums/pokemon-type"; import { SpeciesId } from "#enums/species-id"; import { TimeOfDay } from "#enums/time-of-day"; import { TrainerType } from "#enums/trainer-type"; +import type { Mutable } from "#types/type-helpers"; import { randSeedInt } from "#utils/common"; import { getEnumValues } from "#utils/enums"; import { toCamelCase } from "#utils/strings"; @@ -88,19 +89,19 @@ export enum BiomePoolTier { export const uncatchableSpecies: SpeciesId[] = []; interface SpeciesTree { - [key: number]: SpeciesId[] + readonly [key: number]: SpeciesId[] } export interface PokemonPools { - [key: number]: (SpeciesId | SpeciesTree)[] + readonly [key: number]: (SpeciesId | SpeciesTree)[] } interface BiomeTierPokemonPools { - [key: number]: PokemonPools + readonly [key: number]: PokemonPools } interface BiomePokemonPools { - [key: number]: BiomeTierPokemonPools + readonly [key: number]: BiomeTierPokemonPools } export interface BiomeTierTod { @@ -110,17 +111,17 @@ export interface BiomeTierTod { } export interface CatchableSpecies{ - [key: number]: BiomeTierTod[] + readonly [key: number]: readonly BiomeTierTod[] } export const catchableSpecies: CatchableSpecies = {}; export interface BiomeTierTrainerPools { - [key: number]: TrainerType[] + readonly [key: number]: readonly TrainerType[] } export interface BiomeTrainerPools { - [key: number]: BiomeTierTrainerPools + readonly [key: number]: BiomeTierTrainerPools } export const biomePokemonPools: BiomePokemonPools = { @@ -7621,12 +7622,10 @@ export function initBiomes() { ? biomeLinks[biome] as (BiomeId | [ BiomeId, number ])[] : [ biomeLinks[biome] as BiomeId ]; for (const linkedBiomeEntry of linkedBiomes) { - const linkedBiome = !Array.isArray(linkedBiomeEntry) - ? linkedBiomeEntry as BiomeId - : linkedBiomeEntry[0]; - const biomeChance = !Array.isArray(linkedBiomeEntry) - ? 1 - : linkedBiomeEntry[1]; + const linkedBiome = Array.isArray(linkedBiomeEntry) + ? linkedBiomeEntry[0] : linkedBiomeEntry as BiomeId; + const biomeChance = Array.isArray(linkedBiomeEntry) + ? linkedBiomeEntry[1] : 1; if (!biomeDepths.hasOwnProperty(linkedBiome) || biomeChance < biomeDepths[linkedBiome][1] || (depth < biomeDepths[linkedBiome][0] && biomeChance === biomeDepths[linkedBiome][1])) { biomeDepths[linkedBiome] = [ depth + 1, biomeChance ]; traverseBiome(linkedBiome, depth + 1); @@ -7638,15 +7637,15 @@ export function initBiomes() { biomeDepths[BiomeId.END] = [ Object.values(biomeDepths).map(d => d[0]).reduce((max: number, value: number) => Math.max(max, value), 0) + 1, 1 ]; for (const biome of getEnumValues(BiomeId)) { - biomePokemonPools[biome] = {}; - biomeTrainerPools[biome] = {}; + (biomePokemonPools[biome] as Mutable) = {}; + (biomeTrainerPools[biome] as Mutable) = {}; for (const tier of getEnumValues(BiomePoolTier)) { - biomePokemonPools[biome][tier] = {}; - biomeTrainerPools[biome][tier] = []; + (biomePokemonPools[biome][tier] as Mutable) = {}; + (biomeTrainerPools[biome][tier] as Mutable) = []; for (const tod of getEnumValues(TimeOfDay)) { - biomePokemonPools[biome][tier][tod] = []; + (biomePokemonPools[biome][tier][tod] as Mutable) = []; } } } @@ -7663,8 +7662,9 @@ export function initBiomes() { uncatchableSpecies.push(speciesId); } + type mutableSpecies = Mutable; // array of biome options for the current species - catchableSpecies[speciesId] = []; + (catchableSpecies[speciesId] as mutableSpecies) = []; for (const b of biomeEntries) { const biome = b[0]; @@ -7675,7 +7675,7 @@ export function initBiomes() { : [ b[2] ] : [ TimeOfDay.ALL ]; - catchableSpecies[speciesId].push({ + (catchableSpecies[speciesId] as mutableSpecies).push({ biome: biome as BiomeId, tier: tier as BiomePoolTier, tod: timesOfDay as TimeOfDay[] @@ -7735,12 +7735,13 @@ export function initBiomes() { }; for (let s = 1; s < entry.length; s++) { const speciesId = entry[s]; + // biome-ignore lint/nursery/noShadow: one-off const prevolution = entry.flatMap((s: string | number) => pokemonEvolutions[s]).find(e => e && e.speciesId === speciesId); const level = prevolution.level - (prevolution.level === 1 ? 1 : 0) + (prevolution.wildDelay * 10) - (tier >= BiomePoolTier.BOSS ? 10 : 0); - if (!newEntry.hasOwnProperty(level)) { - newEntry[level] = [ speciesId ]; - } else { + if (newEntry.hasOwnProperty(level)) { newEntry[level].push(speciesId); + } else { + newEntry[level] = [ speciesId ]; } } biomeTierTimePool[e] = newEntry; @@ -7763,7 +7764,7 @@ export function initBiomes() { } const biomeTierPool = biomeTrainerPools[biome][tier]; - biomeTierPool.push(trainerType); + (biomeTierPool as Mutable).push(trainerType); } //outputPools(); } diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index f9bd31beb17..ae5a3882ccc 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -2154,8 +2154,8 @@ export class HighestStatBoostTag extends AbilityBattlerTag { } export class WeatherHighestStatBoostTag extends HighestStatBoostTag { - #weatherTypes: WeatherType[]; - public get weatherTypes(): WeatherType[] { + readonly #weatherTypes: readonly WeatherType[]; + public get weatherTypes(): readonly WeatherType[] { return this.#weatherTypes; } @@ -2166,8 +2166,8 @@ export class WeatherHighestStatBoostTag extends HighestStatBoostTag { } export class TerrainHighestStatBoostTag extends HighestStatBoostTag { - #terrainTypes: TerrainType[]; - public get terrainTypes(): TerrainType[] { + readonly #terrainTypes: readonly TerrainType[]; + public get terrainTypes(): readonly TerrainType[] { return this.#terrainTypes; } diff --git a/src/data/egg.ts b/src/data/egg.ts index d4d37071d11..1e8dcc1665c 100644 --- a/src/data/egg.ts +++ b/src/data/egg.ts @@ -485,14 +485,14 @@ export class Egg { * and being the same each time */ let totalWeight = 0; - const speciesWeights: number[] = []; - for (const speciesId of speciesPool) { + const speciesWeights = new Array(speciesPool.length); + for (const [idx, speciesId] of speciesPool.entries()) { // Accounts for species that have starter costs outside of the normal range for their EggTier const speciesCostClamped = Phaser.Math.Clamp(speciesStarterCosts[speciesId], minStarterValue, maxStarterValue); const weight = Math.floor( (((maxStarterValue - speciesCostClamped) / (maxStarterValue - minStarterValue + 1)) * 1.5 + 1) * 100, ); - speciesWeights.push(totalWeight + weight); + speciesWeights[idx] = totalWeight + weight; totalWeight += weight; } diff --git a/src/data/pokemon-forms.ts b/src/data/pokemon-forms.ts index 909967b84fa..f223347c60f 100644 --- a/src/data/pokemon-forms.ts +++ b/src/data/pokemon-forms.ts @@ -25,6 +25,7 @@ import { SpeciesId } from "#enums/species-id"; import { WeatherType } from "#enums/weather-type"; import type { Pokemon } from "#field/pokemon"; import type { Constructor, nil } from "#types/common"; +import type { Mutable } from "#types/type-helpers"; export type SpeciesFormChangeConditionPredicate = (p: Pokemon) => boolean; export type SpeciesFormChangeConditionEnforceFunc = (p: Pokemon) => void; @@ -116,7 +117,7 @@ function getSpeciesDependentFormChangeCondition(species: SpeciesId): SpeciesForm } interface PokemonFormChanges { - [key: string]: SpeciesFormChange[]; + [key: string]: readonly SpeciesFormChange[]; } // biome-ignore format: manually formatted @@ -608,6 +609,6 @@ export function initPokemonForms() { ); } } - formChanges.push(...newFormChanges); + (formChanges as Mutable).push(...newFormChanges); } } diff --git a/src/data/pokemon-forms/form-change-triggers.ts b/src/data/pokemon-forms/form-change-triggers.ts index de0deb412a1..149c44bd978 100644 --- a/src/data/pokemon-forms/form-change-triggers.ts +++ b/src/data/pokemon-forms/form-change-triggers.ts @@ -240,9 +240,9 @@ export class SpeciesFormChangeWeatherTrigger extends SpeciesFormChangeTrigger { /** The ability that triggers the form change */ public ability: AbilityId; /** The list of weathers that trigger the form change */ - public weathers: WeatherType[]; + public readonly weathers: readonly WeatherType[]; - constructor(ability: AbilityId, weathers: WeatherType[]) { + constructor(ability: AbilityId, weathers: readonly WeatherType[]) { super(); this.ability = ability; this.weathers = weathers; @@ -278,9 +278,9 @@ export class SpeciesFormChangeRevertWeatherFormTrigger extends SpeciesFormChange /** The ability that triggers the form change*/ public ability: AbilityId; /** The list of weathers that will also trigger a form change to original form */ - public weathers: WeatherType[]; + public readonly weathers: readonly WeatherType[]; - constructor(ability: AbilityId, weathers: WeatherType[]) { + constructor(ability: AbilityId, weathers: readonly WeatherType[]) { super(); this.ability = ability; this.weathers = weathers; @@ -310,9 +310,10 @@ export class SpeciesFormChangeRevertWeatherFormTrigger extends SpeciesFormChange } export function getSpeciesFormChangeMessage(pokemon: Pokemon, formChange: SpeciesFormChange, preName: string): string { - const isMega = formChange.formKey.indexOf(SpeciesFormKey.MEGA) > -1; - const isGmax = formChange.formKey.indexOf(SpeciesFormKey.GIGANTAMAX) > -1; - const isEmax = formChange.formKey.indexOf(SpeciesFormKey.ETERNAMAX) > -1; + const formKey = formChange.formKey; + const isMega = formKey.indexOf(SpeciesFormKey.MEGA) > -1; + const isGmax = formKey.indexOf(SpeciesFormKey.GIGANTAMAX) > -1; + const isEmax = formKey.indexOf(SpeciesFormKey.ETERNAMAX) > -1; const isRevert = !isMega && formChange.formKey === pokemon.species.forms[0].formKey; if (isMega) { return i18next.t("battlePokemonForm:megaChange", { diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 9f5656aae12..40fdb35a6e1 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -2140,7 +2140,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container { * Suppresses an ability and calls its onlose attributes */ public suppressAbility() { - [true, false].forEach(passive => applyOnLoseAbAttrs({ pokemon: this, passive })); + applyOnLoseAbAttrs({ pokemon: this, passive: true }); + applyOnLoseAbAttrs({ pokemon: this, passive: false }); this.summonData.abilitySuppressed = true; } diff --git a/src/field/trainer.ts b/src/field/trainer.ts index f5b2e5dad99..d3fe36259dc 100644 --- a/src/field/trainer.ts +++ b/src/field/trainer.ts @@ -642,14 +642,14 @@ export class Trainer extends Phaser.GameObjects.Container { } } - genModifiers(party: EnemyPokemon[]): PersistentModifier[] { + genModifiers(party: readonly EnemyPokemon[]): PersistentModifier[] { if (this.config.genModifiersFunc) { return this.config.genModifiersFunc(party); } return []; } - genAI(party: EnemyPokemon[]) { + genAI(party: readonly EnemyPokemon[]) { if (this.config.genAIFuncs) { this.config.genAIFuncs.forEach(f => f(party)); } diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index d67011bc145..0b1656e5464 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -277,7 +277,7 @@ export class ModifierType { } } -type ModifierTypeGeneratorFunc = (party: Pokemon[], pregenArgs?: any[]) => ModifierType | null; +type ModifierTypeGeneratorFunc = (party: readonly Pokemon[], pregenArgs?: any[]) => ModifierType | null; export class ModifierTypeGenerator extends ModifierType { private genTypeFunc: ModifierTypeGeneratorFunc; @@ -287,7 +287,7 @@ export class ModifierTypeGenerator extends ModifierType { this.genTypeFunc = genTypeFunc; } - generateType(party: Pokemon[], pregenArgs?: any[]) { + generateType(party: readonly Pokemon[], pregenArgs?: any[]) { const ret = this.genTypeFunc(party, pregenArgs); if (ret) { ret.id = this.id; @@ -2360,7 +2360,11 @@ const tierWeights = [768 / 1024, 195 / 1024, 48 / 1024, 12 / 1024, 1 / 1024]; */ export const itemPoolChecks: Map = new Map(); -export function regenerateModifierPoolThresholds(party: Pokemon[], poolType: ModifierPoolType, rerollCount = 0) { +export function regenerateModifierPoolThresholds( + party: readonly Pokemon[], + poolType: ModifierPoolType, + rerollCount = 0, +) { const pool = getModifierPoolForType(poolType); itemPoolChecks.forEach((_v, k) => { itemPoolChecks.set(k, false); @@ -2906,7 +2910,7 @@ export class ModifierTypeOption { * @param party The player's party. * @returns A number between 0 and 14 based on the party's total luck value, or a random number between 0 and 14 if the player is in Daily Run mode. */ -export function getPartyLuckValue(party: Pokemon[]): number { +export function getPartyLuckValue(party: readonly Pokemon[]): number { if (globalScene.gameMode.isDaily) { const DailyLuck = new NumberHolder(0); globalScene.executeWithSeedOffset( diff --git a/src/phases/battle-phase.ts b/src/phases/battle-phase.ts index 26794ed9bc5..eb87aca9ca4 100644 --- a/src/phases/battle-phase.ts +++ b/src/phases/battle-phase.ts @@ -12,7 +12,7 @@ export abstract class BattlePhase extends Phase { const tintSprites = globalScene.currentBattle.trainer.getTintSprites(); for (let i = 0; i < sprites.length; i++) { const visible = !trainerSlot || !i === (trainerSlot === TrainerSlot.TRAINER) || sprites.length < 2; - [sprites[i], tintSprites[i]].map(sprite => { + [sprites[i], tintSprites[i]].forEach(sprite => { if (visible) { sprite.x = trainerSlot || sprites.length < 2 ? 0 : i ? 16 : -16; } diff --git a/src/timed-event-manager.ts b/src/timed-event-manager.ts index d0ebb5607bb..f225bf8db61 100644 --- a/src/timed-event-manager.ts +++ b/src/timed-event-manager.ts @@ -18,59 +18,59 @@ export enum EventType { } interface EventBanner { - bannerKey?: string; - xOffset?: number; - yOffset?: number; - scale?: number; - availableLangs?: string[]; + readonly bannerKey?: string; + readonly xOffset?: number; + readonly yOffset?: number; + readonly scale?: number; + readonly availableLangs?: readonly string[]; } interface EventEncounter { - species: SpeciesId; - blockEvolution?: boolean; - formIndex?: number; + readonly species: SpeciesId; + readonly blockEvolution?: boolean; + readonly formIndex?: number; } interface EventMysteryEncounterTier { - mysteryEncounter: MysteryEncounterType; - tier?: MysteryEncounterTier; - disable?: boolean; + readonly mysteryEncounter: MysteryEncounterType; + readonly tier?: MysteryEncounterTier; + readonly disable?: boolean; } interface EventWaveReward { - wave: number; - type: string; + readonly wave: number; + readonly type: string; } -type EventMusicReplacement = [string, string]; +type EventMusicReplacement = readonly [string, string]; interface EventChallenge { - challenge: Challenges; - value: number; + readonly challenge: Challenges; + readonly value: number; } interface TimedEvent extends EventBanner { - name: string; - eventType: EventType; - shinyMultiplier?: number; - classicFriendshipMultiplier?: number; - luckBoost?: number; - upgradeUnlockedVouchers?: boolean; - startDate: Date; - endDate: Date; - eventEncounters?: EventEncounter[]; - delibirdyBuff?: string[]; - weather?: WeatherPoolEntry[]; - mysteryEncounterTierChanges?: EventMysteryEncounterTier[]; - luckBoostedSpecies?: SpeciesId[]; - boostFusions?: boolean; //MODIFIER REWORK PLEASE - classicWaveRewards?: EventWaveReward[]; // Rival battle rewards - trainerShinyChance?: number; // Odds over 65536 of trainer mon generating as shiny - music?: EventMusicReplacement[]; - dailyRunChallenges?: EventChallenge[]; + readonly name: string; + readonly eventType: EventType; + readonly shinyMultiplier?: number; + readonly classicFriendshipMultiplier?: number; + readonly luckBoost?: number; + readonly upgradeUnlockedVouchers?: boolean; + readonly startDate: Date; + readonly endDate: Date; + readonly eventEncounters?: readonly EventEncounter[]; + readonly delibirdyBuff?: readonly string[]; + readonly weather?: readonly WeatherPoolEntry[]; + readonly mysteryEncounterTierChanges?: readonly EventMysteryEncounterTier[]; + readonly luckBoostedSpecies?: readonly SpeciesId[]; + readonly boostFusions?: boolean; //MODIFIER REWORK PLEASE + readonly classicWaveRewards?: readonly EventWaveReward[]; // Rival battle rewards + readonly trainerShinyChance?: number; // Odds over 65536 of trainer mon generating as shiny + readonly music?: readonly EventMusicReplacement[]; + readonly dailyRunChallenges?: readonly EventChallenge[]; } -const timedEvents: TimedEvent[] = [ +const timedEvents: readonly TimedEvent[] = [ { name: "Winter Holiday Update", eventType: EventType.SHINY, @@ -385,7 +385,8 @@ const timedEvents: TimedEvent[] = [ export class TimedEventManager { isActive(event: TimedEvent) { - return event.startDate < new Date() && new Date() < event.endDate; + const now = new Date(); + return event.startDate < now && now < event.endDate; } activeEvent(): TimedEvent | undefined { @@ -427,19 +428,17 @@ export class TimedEventManager { getEventBannerLangs(): string[] { const ret: string[] = []; - ret.push(...timedEvents.find(te => this.isActive(te) && te.availableLangs != null)?.availableLangs!); + ret.push(...(timedEvents.find(te => this.isActive(te) && te.availableLangs != null)?.availableLangs ?? [])); return ret; } getEventEncounters(): EventEncounter[] { const ret: EventEncounter[] = []; - timedEvents - .filter(te => this.isActive(te)) - .map(te => { - if (te.eventEncounters != null) { - ret.push(...te.eventEncounters); - } - }); + for (const te of timedEvents) { + if (this.isActive(te) && te.eventEncounters != null) { + ret.push(...te.eventEncounters); + } + } return ret; } @@ -472,13 +471,11 @@ export class TimedEventManager { */ getDelibirdyBuff(): string[] { const ret: string[] = []; - timedEvents - .filter(te => this.isActive(te)) - .map(te => { - if (te.delibirdyBuff != null) { - ret.push(...te.delibirdyBuff); - } - }); + for (const te of timedEvents) { + if (this.isActive(te) && te.delibirdyBuff != null) { + ret.push(...te.delibirdyBuff); + } + } return ret; } @@ -488,39 +485,35 @@ export class TimedEventManager { */ getWeather(): WeatherPoolEntry[] { const ret: WeatherPoolEntry[] = []; - timedEvents - .filter(te => this.isActive(te)) - .map(te => { - if (te.weather != null) { - ret.push(...te.weather); - } - }); + for (const te of timedEvents) { + if (this.isActive(te) && te.weather != null) { + ret.push(...te.weather); + } + } return ret; } getAllMysteryEncounterChanges(): EventMysteryEncounterTier[] { const ret: EventMysteryEncounterTier[] = []; - timedEvents - .filter(te => this.isActive(te)) - .map(te => { - if (te.mysteryEncounterTierChanges != null) { - ret.push(...te.mysteryEncounterTierChanges); - } - }); + for (const te of timedEvents) { + if (this.isActive(te) && te.mysteryEncounterTierChanges != null) { + ret.push(...te.mysteryEncounterTierChanges); + } + } return ret; } getEventMysteryEncountersDisabled(): MysteryEncounterType[] { const ret: MysteryEncounterType[] = []; - timedEvents - .filter(te => this.isActive(te) && te.mysteryEncounterTierChanges != null) - .map(te => { - te.mysteryEncounterTierChanges?.map(metc => { + for (const te of timedEvents) { + if (this.isActive(te) && te.mysteryEncounterTierChanges != null) { + for (const metc of te.mysteryEncounterTierChanges) { if (metc.disable) { ret.push(metc.mysteryEncounter); } - }); - }); + } + } + } return ret; } @@ -529,15 +522,15 @@ export class TimedEventManager { normal: MysteryEncounterTier, ): MysteryEncounterTier { let ret = normal; - timedEvents - .filter(te => this.isActive(te) && te.mysteryEncounterTierChanges != null) - .map(te => { - te.mysteryEncounterTierChanges?.map(metc => { + for (const te of timedEvents) { + if (this.isActive(te) && te.mysteryEncounterTierChanges != null) { + for (const metc of te.mysteryEncounterTierChanges) { if (metc.mysteryEncounter === encounterType) { ret = metc.tier ?? normal; } - }); - }); + } + } + } return ret; } @@ -551,15 +544,16 @@ export class TimedEventManager { } getEventLuckBoostedSpecies(): SpeciesId[] { - const ret: SpeciesId[] = []; - timedEvents - .filter(te => this.isActive(te)) - .map(te => { - if (te.luckBoostedSpecies != null) { - ret.push(...te.luckBoostedSpecies.filter(s => !ret.includes(s))); + const ret = new Set(); + + for (const te of timedEvents) { + if (this.isActive(te) && te.luckBoostedSpecies != null) { + for (const s of te.luckBoostedSpecies) { + ret.add(s); } - }); - return ret; + } + } + return Array.from(ret); } areFusionsBoosted(): boolean { @@ -574,45 +568,50 @@ export class TimedEventManager { */ getFixedBattleEventRewards(wave: number): string[] { const ret: string[] = []; - timedEvents - .filter(te => this.isActive(te) && te.classicWaveRewards != null) - .map(te => { - ret.push(...te.classicWaveRewards!.filter(cwr => cwr.wave === wave).map(cwr => cwr.type)); - }); + for (const te of timedEvents) { + if (this.isActive(te) && te.classicWaveRewards != null) { + ret.push(...te.classicWaveRewards.filter(cwr => cwr.wave === wave).map(cwr => cwr.type)); + } + } return ret; } - // Gets the extra shiny chance for trainers due to event (odds/65536) + /** + * Get the extra shiny chance for trainers due to event + */ getClassicTrainerShinyChance(): number { let ret = 0; - const tsEvents = timedEvents.filter(te => this.isActive(te) && te.trainerShinyChance != null); - tsEvents.map(t => (ret += t.trainerShinyChance!)); + for (const te of timedEvents) { + const shinyChance = te.trainerShinyChance; + if (shinyChance && this.isActive(te)) { + ret += shinyChance; + } + } return ret; } getEventBgmReplacement(bgm: string): string { let ret = bgm; - timedEvents.map(te => { + for (const te of timedEvents) { if (this.isActive(te) && te.music != null) { - te.music.map(mr => { + for (const mr of te.music) { if (mr[0] === bgm) { console.log(`it is ${te.name} so instead of ${mr[0]} we play ${mr[1]}`); ret = mr[1]; } - }); + } } - }); + } return ret; } /** - * Activates any challenges on {@linkcode globalScene.gameMode} for the currently active event + * Activate any challenges on {@linkcode globalScene.gameMode} for the currently active event */ startEventChallenges(): void { - const challenges = this.activeEvent()?.dailyRunChallenges; - challenges?.forEach((eventChal: EventChallenge) => - globalScene.gameMode.setChallengeValue(eventChal.challenge, eventChal.value), - ); + for (const eventChal of this.activeEvent()?.dailyRunChallenges ?? []) { + globalScene.gameMode.setChallengeValue(eventChal.challenge, eventChal.value); + } } } diff --git a/src/ui/handlers/pokedex-page-ui-handler.ts b/src/ui/handlers/pokedex-page-ui-handler.ts index 684ead7d45a..393e0b713b4 100644 --- a/src/ui/handlers/pokedex-page-ui-handler.ts +++ b/src/ui/handlers/pokedex-page-ui-handler.ts @@ -240,8 +240,8 @@ export class PokedexPageUiHandler extends MessageUiHandler { private passive: AbilityId; private hasPassive: boolean; private hasAbilities: number[]; - private biomes: BiomeTierTod[]; - private preBiomes: BiomeTierTod[]; + private biomes: readonly BiomeTierTod[]; + private preBiomes: readonly BiomeTierTod[]; private baseStats: number[]; private baseTotal: number; private evolutions: SpeciesFormEvolution[]; @@ -893,7 +893,7 @@ export class PokedexPageUiHandler extends MessageUiHandler { } // Function to ensure that forms appear in the appropriate biome and tod - sanitizeBiomes(biomes: BiomeTierTod[], speciesId: number): BiomeTierTod[] { + sanitizeBiomes(biomes: readonly BiomeTierTod[], speciesId: number): readonly BiomeTierTod[] { if (speciesId === SpeciesId.BURMY || speciesId === SpeciesId.WORMADAM) { return biomes.filter(b => { const formIndex = (() => { diff --git a/src/utils/speed-order.ts b/src/utils/speed-order.ts index 1d894369bb3..de1e978510d 100644 --- a/src/utils/speed-order.ts +++ b/src/utils/speed-order.ts @@ -16,22 +16,23 @@ interface hasPokemon { * @returns The sorted array of {@linkcode Pokemon} */ export function sortInSpeedOrder(pokemonList: T[], shuffleFirst = true): T[] { - pokemonList = shuffleFirst ? shufflePokemonList(pokemonList) : pokemonList; + if (shuffleFirst) { + shufflePokemonList(pokemonList); + } sortBySpeed(pokemonList); return pokemonList; } /** + * Shuffle the list of pokemon *in place* * @param pokemonList - The array of Pokemon or objects containing Pokemon - * @returns The shuffled array + * @returns The same array instance that was passed in, shuffled. */ function shufflePokemonList(pokemonList: T[]): T[] { // This is seeded with the current turn to prevent an inconsistency where it // was varying based on how long since you last reloaded globalScene.executeWithSeedOffset( - () => { - pokemonList = randSeedShuffle(pokemonList); - }, + () => randSeedShuffle(pokemonList), globalScene.currentBattle.turn * 1000 + pokemonList.length, globalScene.waveSeed, );