Even more array improvements

This commit is contained in:
Sirz Benjie 2025-09-22 18:42:50 -05:00
parent 8003215c39
commit ac2f09ad33
No known key found for this signature in database
GPG Key ID: 4A524B4D196C759E
15 changed files with 178 additions and 169 deletions

View File

@ -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[];

View File

@ -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);

View File

@ -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,

View File

@ -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<typeof biomePokemonPools[number]>) = {};
(biomeTrainerPools[biome] as Mutable<typeof biomeTrainerPools[number]>) = {};
for (const tier of getEnumValues(BiomePoolTier)) {
biomePokemonPools[biome][tier] = {};
biomeTrainerPools[biome][tier] = [];
(biomePokemonPools[biome][tier] as Mutable<typeof biomePokemonPools[number][number]>) = {};
(biomeTrainerPools[biome][tier] as Mutable<typeof biomeTrainerPools[number][number]>) = [];
for (const tod of getEnumValues(TimeOfDay)) {
biomePokemonPools[biome][tier][tod] = [];
(biomePokemonPools[biome][tier][tod] as Mutable<typeof biomePokemonPools[number][number][number]>) = [];
}
}
}
@ -7663,8 +7662,9 @@ export function initBiomes() {
uncatchableSpecies.push(speciesId);
}
type mutableSpecies = Mutable<typeof catchableSpecies[SpeciesId]>;
// 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<typeof biomeTierPool>).push(trainerType);
}
//outputPools();
}

View File

@ -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;
}

View File

@ -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<number>(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;
}

View File

@ -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<typeof formChanges>).push(...newFormChanges);
}
}

View File

@ -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", {

View File

@ -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;
}

View File

@ -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));
}

View File

@ -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<ModifierTypeKeys, boolean | undefined> = 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(

View File

@ -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;
}

View File

@ -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<SpeciesId>();
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);
}
}
}

View File

@ -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 = (() => {

View File

@ -16,22 +16,23 @@ interface hasPokemon {
* @returns The sorted array of {@linkcode Pokemon}
*/
export function sortInSpeedOrder<T extends Pokemon | hasPokemon>(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<T extends Pokemon | hasPokemon>(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,
);