[Biome] Add and apply lint/style/noNamespaceImport (#5650)

* Add `lint/style/noNamespaceImport` Biome rule

* Apply Biome rule, add exception for `*.test.ts` files
This commit is contained in:
NightKev 2025-04-11 22:31:56 -07:00 committed by GitHub
parent 81f424dc71
commit 6f56dce771
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
86 changed files with 1112 additions and 1103 deletions

View File

@ -65,7 +65,8 @@
"useDefaultParameterLast": "off", // TODO: Fix spots in the codebase where this flag would be triggered, and then enable "useDefaultParameterLast": "off", // TODO: Fix spots in the codebase where this flag would be triggered, and then enable
"useSingleVarDeclarator": "off", "useSingleVarDeclarator": "off",
"useNodejsImportProtocol": "off", "useNodejsImportProtocol": "off",
"useTemplate": "off" // string concatenation is faster: https://stackoverflow.com/questions/29055518/are-es6-template-literals-faster-than-string-concatenation "useTemplate": "off", // string concatenation is faster: https://stackoverflow.com/questions/29055518/are-es6-template-literals-faster-than-string-concatenation
"noNamespaceImport": "error"
}, },
"suspicious": { "suspicious": {
"noDoubleEquals": "error", "noDoubleEquals": "error",
@ -99,6 +100,9 @@
"rules": { "rules": {
"performance": { "performance": {
"noDelete": "off" "noDelete": "off"
},
"style": {
"noNamespaceImport": "off"
} }
} }
} }

View File

@ -1,11 +1,11 @@
import { pokerogueApi } from "#app/plugins/api/pokerogue-api"; import { pokerogueApi } from "#app/plugins/api/pokerogue-api";
import type { UserInfo } from "#app/@types/UserInfo"; import type { UserInfo } from "#app/@types/UserInfo";
import { bypassLogin } from "./battle-scene"; import { bypassLogin } from "#app/battle-scene";
import * as Utils from "./utils"; import { randomString } from "#app/utils";
export let loggedInUser: UserInfo | null = null; export let loggedInUser: UserInfo | null = null;
// This is a random string that is used to identify the client session - unique per session (tab or window) so that the game will only save on the one that the server is expecting // This is a random string that is used to identify the client session - unique per session (tab or window) so that the game will only save on the one that the server is expecting
export const clientSessionId = Utils.randomString(32); export const clientSessionId = randomString(32);
export function initLoggedInUser(): void { export function initLoggedInUser(): void {
loggedInUser = { loggedInUser = {

View File

@ -5,9 +5,20 @@ import { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon";
import type { PokemonSpeciesFilter } from "#app/data/pokemon-species"; import type { PokemonSpeciesFilter } from "#app/data/pokemon-species";
import type PokemonSpecies from "#app/data/pokemon-species"; import type PokemonSpecies from "#app/data/pokemon-species";
import { allSpecies, getPokemonSpecies } from "#app/data/pokemon-species"; import { allSpecies, getPokemonSpecies } from "#app/data/pokemon-species";
import type { Constructor } from "#app/utils"; import {
import { isNullOrUndefined, randSeedInt } from "#app/utils"; fixedInt,
import * as Utils from "#app/utils"; deepMergeObjects,
getIvsFromId,
randSeedInt,
getEnumValues,
randomString,
NumberHolder,
shiftCharCodes,
formatMoney,
isNullOrUndefined,
BooleanHolder,
type Constructor,
} from "#app/utils";
import type { Modifier, ModifierPredicate, TurnHeldItemTransferModifier } from "./modifier/modifier"; import type { Modifier, ModifierPredicate, TurnHeldItemTransferModifier } from "./modifier/modifier";
import { import {
ConsumableModifier, ConsumableModifier,
@ -733,7 +744,7 @@ export default class BattleScene extends SceneBase {
} }
this.playTimeTimer = this.time.addEvent({ this.playTimeTimer = this.time.addEvent({
delay: Utils.fixedInt(1000), delay: fixedInt(1000),
repeat: -1, repeat: -1,
callback: () => { callback: () => {
if (this.gameData) { if (this.gameData) {
@ -783,7 +794,7 @@ export default class BattleScene extends SceneBase {
return; return;
} }
const expVariantData = await this.cachedFetch("./images/pokemon/variant/_exp_masterlist.json").then(r => r.json()); const expVariantData = await this.cachedFetch("./images/pokemon/variant/_exp_masterlist.json").then(r => r.json());
Utils.deepMergeObjects(variantData, expVariantData); deepMergeObjects(variantData, expVariantData);
} }
cachedFetch(url: string, init?: RequestInit): Promise<Response> { cachedFetch(url: string, init?: RequestInit): Promise<Response> {
@ -988,7 +999,7 @@ export default class BattleScene extends SceneBase {
} }
if (boss && !dataSource) { if (boss && !dataSource) {
const secondaryIvs = Utils.getIvsFromId(Utils.randSeedInt(4294967296)); const secondaryIvs = getIvsFromId(randSeedInt(4294967296));
for (let s = 0; s < pokemon.ivs.length; s++) { for (let s = 0; s < pokemon.ivs.length; s++) {
pokemon.ivs[s] = Math.round( pokemon.ivs[s] = Math.round(
@ -1147,7 +1158,7 @@ export default class BattleScene extends SceneBase {
* Generates a random number using the current battle's seed * Generates a random number using the current battle's seed
* *
* This calls {@linkcode Battle.randSeedInt}({@linkcode range}, {@linkcode min}) in `src/battle.ts` * This calls {@linkcode Battle.randSeedInt}({@linkcode range}, {@linkcode min}) in `src/battle.ts`
* which calls {@linkcode Utils.randSeedInt randSeedInt}({@linkcode range}, {@linkcode min}) in `src/utils.ts` * which calls {@linkcode randSeedInt randSeedInt}({@linkcode range}, {@linkcode min}) in `src/utils.ts`
* *
* @param range How large of a range of random numbers to choose from. If {@linkcode range} <= 1, returns {@linkcode min} * @param range How large of a range of random numbers to choose from. If {@linkcode range} <= 1, returns {@linkcode min}
* @param min The minimum integer to pick, default `0` * @param min The minimum integer to pick, default `0`
@ -1172,7 +1183,7 @@ export default class BattleScene extends SceneBase {
this.lockModifierTiers = false; this.lockModifierTiers = false;
this.pokeballCounts = Object.fromEntries( this.pokeballCounts = Object.fromEntries(
Utils.getEnumValues(PokeballType) getEnumValues(PokeballType)
.filter(p => p <= PokeballType.MASTER_BALL) .filter(p => p <= PokeballType.MASTER_BALL)
.map(t => [t, 0]), .map(t => [t, 0]),
); );
@ -1204,7 +1215,7 @@ export default class BattleScene extends SceneBase {
// Reset RNG after end of game or save & quit. // Reset RNG after end of game or save & quit.
// This needs to happen after clearing this.currentBattle or the seed will be affected by the last wave played // This needs to happen after clearing this.currentBattle or the seed will be affected by the last wave played
this.setSeed(Overrides.SEED_OVERRIDE || Utils.randomString(24)); this.setSeed(Overrides.SEED_OVERRIDE || randomString(24));
console.log("Seed:", this.seed); console.log("Seed:", this.seed);
this.resetSeed(); this.resetSeed();
@ -1245,7 +1256,7 @@ export default class BattleScene extends SceneBase {
...allSpecies, ...allSpecies,
...allMoves, ...allMoves,
...allAbilities, ...allAbilities,
...Utils.getEnumValues(ModifierPoolType) ...getEnumValues(ModifierPoolType)
.map(mpt => getModifierPoolForType(mpt)) .map(mpt => getModifierPoolForType(mpt))
.flatMap(mp => .flatMap(mp =>
Object.values(mp) Object.values(mp)
@ -1285,7 +1296,7 @@ export default class BattleScene extends SceneBase {
} }
getDoubleBattleChance(newWaveIndex: number, playerField: PlayerPokemon[]) { getDoubleBattleChance(newWaveIndex: number, playerField: PlayerPokemon[]) {
const doubleChance = new Utils.NumberHolder(newWaveIndex % 10 === 0 ? 32 : 8); const doubleChance = new NumberHolder(newWaveIndex % 10 === 0 ? 32 : 8);
this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance); this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance);
for (const p of playerField) { for (const p of playerField) {
applyAbAttrs(DoubleBattleChanceAbAttr, p, null, false, doubleChance); applyAbAttrs(DoubleBattleChanceAbAttr, p, null, false, doubleChance);
@ -1342,7 +1353,7 @@ export default class BattleScene extends SceneBase {
if (trainerConfigs[trainerType].doubleOnly) { if (trainerConfigs[trainerType].doubleOnly) {
doubleTrainer = true; doubleTrainer = true;
} else if (trainerConfigs[trainerType].hasDouble) { } else if (trainerConfigs[trainerType].hasDouble) {
doubleTrainer = !Utils.randSeedInt(this.getDoubleBattleChance(newWaveIndex, playerField)); doubleTrainer = !randSeedInt(this.getDoubleBattleChance(newWaveIndex, playerField));
// Add a check that special trainers can't be double except for tate and liza - they should use the normal double chance // Add a check that special trainers can't be double except for tate and liza - they should use the normal double chance
if ( if (
trainerConfigs[trainerType].trainerTypeDouble && trainerConfigs[trainerType].trainerTypeDouble &&
@ -1353,7 +1364,7 @@ export default class BattleScene extends SceneBase {
} }
const variant = doubleTrainer const variant = doubleTrainer
? TrainerVariant.DOUBLE ? TrainerVariant.DOUBLE
: Utils.randSeedInt(2) : randSeedInt(2)
? TrainerVariant.FEMALE ? TrainerVariant.FEMALE
: TrainerVariant.DEFAULT; : TrainerVariant.DEFAULT;
newTrainer = trainerData !== undefined ? trainerData.toTrainer() : new Trainer(trainerType, variant); newTrainer = trainerData !== undefined ? trainerData.toTrainer() : new Trainer(trainerType, variant);
@ -1371,7 +1382,7 @@ export default class BattleScene extends SceneBase {
if (double === undefined && newWaveIndex > 1) { if (double === undefined && newWaveIndex > 1) {
if (newBattleType === BattleType.WILD && !this.gameMode.isWaveFinal(newWaveIndex)) { if (newBattleType === BattleType.WILD && !this.gameMode.isWaveFinal(newWaveIndex)) {
newDouble = !Utils.randSeedInt(this.getDoubleBattleChance(newWaveIndex, playerField)); newDouble = !randSeedInt(this.getDoubleBattleChance(newWaveIndex, playerField));
} else if (newBattleType === BattleType.TRAINER) { } else if (newBattleType === BattleType.TRAINER) {
newDouble = newTrainer?.variant === TrainerVariant.DOUBLE; newDouble = newTrainer?.variant === TrainerVariant.DOUBLE;
} }
@ -1559,7 +1570,7 @@ export default class BattleScene extends SceneBase {
scale: scale, scale: scale,
x: (defaultWidth - scaledWidth) / 2, x: (defaultWidth - scaledWidth) / 2,
y: defaultHeight - scaledHeight, y: defaultHeight - scaledHeight,
duration: !instant ? Utils.fixedInt(Math.abs(this.field.scale - scale) * 200) : 0, duration: !instant ? fixedInt(Math.abs(this.field.scale - scale) * 200) : 0,
ease: "Sine.easeInOut", ease: "Sine.easeInOut",
onComplete: () => resolve(), onComplete: () => resolve(),
}); });
@ -1656,12 +1667,12 @@ export default class BattleScene extends SceneBase {
case Species.SQUAWKABILLY: case Species.SQUAWKABILLY:
case Species.TATSUGIRI: case Species.TATSUGIRI:
case Species.PALDEA_TAUROS: case Species.PALDEA_TAUROS:
return Utils.randSeedInt(species.forms.length); return randSeedInt(species.forms.length);
case Species.PIKACHU: case Species.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
} }
return Utils.randSeedInt(8); return randSeedInt(8);
case Species.EEVEE: case Species.EEVEE:
if ( if (
this.currentBattle?.battleType === BattleType.TRAINER && this.currentBattle?.battleType === BattleType.TRAINER &&
@ -1670,22 +1681,22 @@ export default class BattleScene extends SceneBase {
) { ) {
return 0; // No Partner Eevee for Wave 12 Preschoolers return 0; // No Partner Eevee for Wave 12 Preschoolers
} }
return Utils.randSeedInt(2); return randSeedInt(2);
case Species.FROAKIE: case Species.FROAKIE:
case Species.FROGADIER: case Species.FROGADIER:
case Species.GRENINJA: case Species.GRENINJA:
if (this.currentBattle?.battleType === BattleType.TRAINER && !isEggPhase) { if (this.currentBattle?.battleType === BattleType.TRAINER && !isEggPhase) {
return 0; // Don't give trainers Battle Bond Greninja, Froakie or Frogadier return 0; // Don't give trainers Battle Bond Greninja, Froakie or Frogadier
} }
return Utils.randSeedInt(2); return randSeedInt(2);
case Species.URSHIFU: case Species.URSHIFU:
return Utils.randSeedInt(2); return randSeedInt(2);
case Species.ZYGARDE: case Species.ZYGARDE:
return Utils.randSeedInt(4); return randSeedInt(4);
case Species.MINIOR: case Species.MINIOR:
return Utils.randSeedInt(7); return randSeedInt(7);
case Species.ALCREMIE: case Species.ALCREMIE:
return Utils.randSeedInt(9); return randSeedInt(9);
case Species.MEOWSTIC: case Species.MEOWSTIC:
case Species.INDEEDEE: case Species.INDEEDEE:
case Species.BASCULEGION: case Species.BASCULEGION:
@ -1716,7 +1727,7 @@ export default class BattleScene extends SceneBase {
if (this.gameMode.hasMysteryEncounters && !isEggPhase) { if (this.gameMode.hasMysteryEncounters && !isEggPhase) {
return 1; // Wandering form return 1; // Wandering form
} }
return Utils.randSeedInt(species.forms.length); return randSeedInt(species.forms.length);
} }
if (ignoreArena) { if (ignoreArena) {
@ -1725,7 +1736,7 @@ export default class BattleScene extends SceneBase {
case Species.WORMADAM: case Species.WORMADAM:
case Species.ROTOM: case Species.ROTOM:
case Species.LYCANROC: case Species.LYCANROC:
return Utils.randSeedInt(species.forms.length); return randSeedInt(species.forms.length);
} }
return 0; return 0;
} }
@ -1737,7 +1748,7 @@ export default class BattleScene extends SceneBase {
let ret = false; let ret = false;
this.executeWithSeedOffset( this.executeWithSeedOffset(
() => { () => {
ret = !Utils.randSeedInt(2); ret = !randSeedInt(2);
}, },
0, 0,
this.seed.toString(), this.seed.toString(),
@ -1749,7 +1760,7 @@ export default class BattleScene extends SceneBase {
let ret = 0; let ret = 0;
this.executeWithSeedOffset( this.executeWithSeedOffset(
() => { () => {
ret = Utils.randSeedInt(8) * 5; ret = randSeedInt(8) * 5;
}, },
0, 0,
this.seed.toString(), this.seed.toString(),
@ -1778,7 +1789,7 @@ export default class BattleScene extends SceneBase {
isBoss = isBoss =
waveIndex % 10 === 0 || waveIndex % 10 === 0 ||
(this.gameMode.hasRandomBosses && (this.gameMode.hasRandomBosses &&
Utils.randSeedInt(100) < Math.min(Math.max(Math.ceil((waveIndex - 250) / 50), 0) * 2, 30)); randSeedInt(100) < Math.min(Math.max(Math.ceil((waveIndex - 250) / 50), 0) * 2, 30));
}, waveIndex << 2); }, waveIndex << 2);
} }
if (!isBoss) { if (!isBoss) {
@ -1805,7 +1816,7 @@ export default class BattleScene extends SceneBase {
const infectedIndexes: number[] = []; const infectedIndexes: number[] = [];
const spread = (index: number, spreadTo: number) => { const spread = (index: number, spreadTo: number) => {
const partyMember = party[index + spreadTo]; const partyMember = party[index + spreadTo];
if (!partyMember.pokerus && !Utils.randSeedInt(10)) { if (!partyMember.pokerus && !randSeedInt(10)) {
partyMember.pokerus = true; partyMember.pokerus = true;
infectedIndexes.push(index + spreadTo); infectedIndexes.push(index + spreadTo);
} }
@ -1831,7 +1842,7 @@ export default class BattleScene extends SceneBase {
resetSeed(waveIndex?: number): void { resetSeed(waveIndex?: number): void {
const wave = waveIndex || this.currentBattle?.waveIndex || 0; const wave = waveIndex || this.currentBattle?.waveIndex || 0;
this.waveSeed = Utils.shiftCharCodes(this.seed, wave); this.waveSeed = shiftCharCodes(this.seed, wave);
Phaser.Math.RND.sow([this.waveSeed]); Phaser.Math.RND.sow([this.waveSeed]);
console.log("Wave Seed:", this.waveSeed, wave); console.log("Wave Seed:", this.waveSeed, wave);
this.rngCounter = 0; this.rngCounter = 0;
@ -1850,7 +1861,7 @@ export default class BattleScene extends SceneBase {
const tempRngOffset = this.rngOffset; const tempRngOffset = this.rngOffset;
const tempRngSeedOverride = this.rngSeedOverride; const tempRngSeedOverride = this.rngSeedOverride;
const state = Phaser.Math.RND.state(); const state = Phaser.Math.RND.state();
Phaser.Math.RND.sow([Utils.shiftCharCodes(seedOverride || this.seed, offset)]); Phaser.Math.RND.sow([shiftCharCodes(seedOverride || this.seed, offset)]);
this.rngCounter = 0; this.rngCounter = 0;
this.rngOffset = offset; this.rngOffset = offset;
this.rngSeedOverride = seedOverride || ""; this.rngSeedOverride = seedOverride || "";
@ -1995,7 +2006,7 @@ export default class BattleScene extends SceneBase {
if (this.money === undefined) { if (this.money === undefined) {
return; return;
} }
const formattedMoney = Utils.formatMoney(this.moneyFormat, this.money); const formattedMoney = formatMoney(this.moneyFormat, this.money);
this.moneyText.setText(i18next.t("battleScene:moneyOwned", { formattedMoney })); this.moneyText.setText(i18next.t("battleScene:moneyOwned", { formattedMoney }));
this.fieldUI.moveAbove(this.moneyText, this.luckText); this.fieldUI.moveAbove(this.moneyText, this.luckText);
if (forceVisible) { if (forceVisible) {
@ -2152,12 +2163,12 @@ export default class BattleScene extends SceneBase {
), ),
] ]
: allSpecies.filter(s => s.isCatchable()); : allSpecies.filter(s => s.isCatchable());
return filteredSpecies[Utils.randSeedInt(filteredSpecies.length)]; return filteredSpecies[randSeedInt(filteredSpecies.length)];
} }
generateRandomBiome(waveIndex: number): Biome { generateRandomBiome(waveIndex: number): Biome {
const relWave = waveIndex % 250; const relWave = waveIndex % 250;
const biomes = Utils.getEnumValues(Biome).filter(b => b !== Biome.TOWN && b !== Biome.END); const biomes = getEnumValues(Biome).filter(b => b !== Biome.TOWN && b !== Biome.END);
const maxDepth = biomeDepths[Biome.END][0] - 2; const maxDepth = biomeDepths[Biome.END][0] - 2;
const depthWeights = new Array(maxDepth + 1) const depthWeights = new Array(maxDepth + 1)
.fill(null) .fill(null)
@ -2169,7 +2180,7 @@ export default class BattleScene extends SceneBase {
biomeThresholds.push(totalWeight); biomeThresholds.push(totalWeight);
} }
const randInt = Utils.randSeedInt(totalWeight); const randInt = randSeedInt(totalWeight);
for (let i = 0; i < biomes.length; i++) { for (let i = 0; i < biomes.length; i++) {
if (randInt < biomeThresholds[i]) { if (randInt < biomeThresholds[i]) {
@ -2177,7 +2188,7 @@ export default class BattleScene extends SceneBase {
} }
} }
return biomes[Utils.randSeedInt(biomes.length)]; return biomes[randSeedInt(biomes.length)];
} }
isBgmPlaying(): boolean { isBgmPlaying(): boolean {
@ -2362,7 +2373,7 @@ export default class BattleScene extends SceneBase {
this.bgmResumeTimer.destroy(); this.bgmResumeTimer.destroy();
} }
if (resumeBgm) { if (resumeBgm) {
this.bgmResumeTimer = this.time.delayedCall(pauseDuration || Utils.fixedInt(sound.totalDuration * 1000), () => { this.bgmResumeTimer = this.time.delayedCall(pauseDuration || fixedInt(sound.totalDuration * 1000), () => {
this.resumeBgm(); this.resumeBgm();
this.bgmResumeTimer = null; this.bgmResumeTimer = null;
}); });
@ -2955,7 +2966,7 @@ export default class BattleScene extends SceneBase {
const args: unknown[] = []; const args: unknown[] = [];
if (modifier instanceof PokemonHpRestoreModifier) { if (modifier instanceof PokemonHpRestoreModifier) {
if (!(modifier as PokemonHpRestoreModifier).fainted) { if (!(modifier as PokemonHpRestoreModifier).fainted) {
const hpRestoreMultiplier = new Utils.NumberHolder(1); const hpRestoreMultiplier = new NumberHolder(1);
this.applyModifiers(HealingBoosterModifier, true, hpRestoreMultiplier); this.applyModifiers(HealingBoosterModifier, true, hpRestoreMultiplier);
args.push(hpRestoreMultiplier.value); args.push(hpRestoreMultiplier.value);
} else { } else {
@ -2963,7 +2974,7 @@ export default class BattleScene extends SceneBase {
} }
} else if (modifier instanceof FusePokemonModifier) { } else if (modifier instanceof FusePokemonModifier) {
args.push(this.getPokemonById(modifier.fusePokemonId) as PlayerPokemon); args.push(this.getPokemonById(modifier.fusePokemonId) as PlayerPokemon);
} else if (modifier instanceof RememberMoveModifier && !Utils.isNullOrUndefined(cost)) { } else if (modifier instanceof RememberMoveModifier && !isNullOrUndefined(cost)) {
args.push(cost); args.push(cost);
} }
@ -3032,7 +3043,7 @@ export default class BattleScene extends SceneBase {
itemLost = true, itemLost = true,
): boolean { ): boolean {
const source = itemModifier.pokemonId ? itemModifier.getPokemon() : null; const source = itemModifier.pokemonId ? itemModifier.getPokemon() : null;
const cancelled = new Utils.BooleanHolder(false); const cancelled = new BooleanHolder(false);
if (source && source.isPlayer() !== target.isPlayer()) { if (source && source.isPlayer() !== target.isPlayer()) {
applyAbAttrs(BlockItemTheftAbAttr, source, cancelled); applyAbAttrs(BlockItemTheftAbAttr, source, cancelled);
@ -3101,7 +3112,7 @@ export default class BattleScene extends SceneBase {
canTransferHeldItemModifier(itemModifier: PokemonHeldItemModifier, target: Pokemon, transferQuantity = 1): boolean { canTransferHeldItemModifier(itemModifier: PokemonHeldItemModifier, target: Pokemon, transferQuantity = 1): boolean {
const mod = itemModifier.clone() as PokemonHeldItemModifier; const mod = itemModifier.clone() as PokemonHeldItemModifier;
const source = mod.pokemonId ? mod.getPokemon() : null; const source = mod.pokemonId ? mod.getPokemon() : null;
const cancelled = new Utils.BooleanHolder(false); const cancelled = new BooleanHolder(false);
if (source && source.isPlayer() !== target.isPlayer()) { if (source && source.isPlayer() !== target.isPlayer()) {
applyAbAttrs(BlockItemTheftAbAttr, source, cancelled); applyAbAttrs(BlockItemTheftAbAttr, source, cancelled);
@ -3195,7 +3206,7 @@ export default class BattleScene extends SceneBase {
} }
let count = 0; let count = 0;
for (let c = 0; c < chances; c++) { for (let c = 0; c < chances; c++) {
if (!Utils.randSeedInt(this.gameMode.getEnemyModifierChance(isBoss))) { if (!randSeedInt(this.gameMode.getEnemyModifierChance(isBoss))) {
count++; count++;
} }
} }
@ -3371,7 +3382,7 @@ export default class BattleScene extends SceneBase {
if (mods.length < 1) { if (mods.length < 1) {
return mods; return mods;
} }
const rand = Utils.randSeedInt(mods.length); const rand = randSeedInt(mods.length);
return [mods[rand], ...shuffleModifiers(mods.filter((_, i) => i !== rand))]; return [mods[rand], ...shuffleModifiers(mods.filter((_, i) => i !== rand))];
}; };
modifiers = shuffleModifiers(modifiers); modifiers = shuffleModifiers(modifiers);
@ -3597,7 +3608,7 @@ export default class BattleScene extends SceneBase {
*/ */
initFinalBossPhaseTwo(pokemon: Pokemon): void { initFinalBossPhaseTwo(pokemon: Pokemon): void {
if (pokemon instanceof EnemyPokemon && pokemon.isBoss() && !pokemon.formIndex && pokemon.bossSegmentIndex < 1) { if (pokemon instanceof EnemyPokemon && pokemon.isBoss() && !pokemon.formIndex && pokemon.bossSegmentIndex < 1) {
this.fadeOutBgm(Utils.fixedInt(2000), false); this.fadeOutBgm(fixedInt(2000), false);
this.ui.showDialogue( this.ui.showDialogue(
battleSpecDialogue[BattleSpec.FINAL_BOSS].firstStageWin, battleSpecDialogue[BattleSpec.FINAL_BOSS].firstStageWin,
pokemon.species.name, pokemon.species.name,
@ -3700,7 +3711,7 @@ export default class BattleScene extends SceneBase {
if (Overrides.XP_MULTIPLIER_OVERRIDE !== null) { if (Overrides.XP_MULTIPLIER_OVERRIDE !== null) {
expMultiplier = Overrides.XP_MULTIPLIER_OVERRIDE; expMultiplier = Overrides.XP_MULTIPLIER_OVERRIDE;
} }
const pokemonExp = new Utils.NumberHolder(expValue * expMultiplier); const pokemonExp = new NumberHolder(expValue * expMultiplier);
this.applyModifiers(PokemonExpBoosterModifier, true, partyMember, pokemonExp); this.applyModifiers(PokemonExpBoosterModifier, true, partyMember, pokemonExp);
partyMemberExp.push(Math.floor(pokemonExp.value)); partyMemberExp.push(Math.floor(pokemonExp.value));
} }
@ -3849,7 +3860,7 @@ export default class BattleScene extends SceneBase {
while (i < this.mysteryEncounterSaveData.queuedEncounters.length && !!encounter) { while (i < this.mysteryEncounterSaveData.queuedEncounters.length && !!encounter) {
const candidate = this.mysteryEncounterSaveData.queuedEncounters[i]; const candidate = this.mysteryEncounterSaveData.queuedEncounters[i];
const forcedChance = candidate.spawnPercent; const forcedChance = candidate.spawnPercent;
if (Utils.randSeedInt(100) < forcedChance) { if (randSeedInt(100) < forcedChance) {
encounter = allMysteryEncounters[candidate.type]; encounter = allMysteryEncounters[candidate.type];
} }
@ -3882,7 +3893,7 @@ export default class BattleScene extends SceneBase {
} }
const totalWeight = tierWeights.reduce((a, b) => a + b); const totalWeight = tierWeights.reduce((a, b) => a + b);
const tierValue = Utils.randSeedInt(totalWeight); const tierValue = randSeedInt(totalWeight);
const commonThreshold = totalWeight - tierWeights[0]; const commonThreshold = totalWeight - tierWeights[0];
const greatThreshold = totalWeight - tierWeights[0] - tierWeights[1]; const greatThreshold = totalWeight - tierWeights[0] - tierWeights[1];
const ultraThreshold = totalWeight - tierWeights[0] - tierWeights[1] - tierWeights[2]; const ultraThreshold = totalWeight - tierWeights[0] - tierWeights[1] - tierWeights[2];
@ -3974,7 +3985,7 @@ export default class BattleScene extends SceneBase {
console.log("No Mystery Encounters found, falling back to Mysterious Challengers."); console.log("No Mystery Encounters found, falling back to Mysterious Challengers.");
return allMysteryEncounters[MysteryEncounterType.MYSTERIOUS_CHALLENGERS]; return allMysteryEncounters[MysteryEncounterType.MYSTERIOUS_CHALLENGERS];
} }
encounter = availableEncounters[Utils.randSeedInt(availableEncounters.length)]; encounter = availableEncounters[randSeedInt(availableEncounters.length)];
// New encounter object to not dirty flags // New encounter object to not dirty flags
encounter = new MysteryEncounter(encounter); encounter = new MysteryEncounter(encounter);
encounter.populateDialogueTokensFromRequirements(); encounter.populateDialogueTokensFromRequirements();

View File

@ -1,6 +1,14 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import type { Command } from "./ui/command-ui-handler"; import type { Command } from "./ui/command-ui-handler";
import * as Utils from "./utils"; import {
randomString,
getEnumValues,
NumberHolder,
randSeedInt,
shiftCharCodes,
randSeedItem,
randInt,
} from "#app/utils";
import Trainer, { TrainerVariant } from "./field/trainer"; import Trainer, { TrainerVariant } from "./field/trainer";
import type { GameMode } from "./game-mode"; import type { GameMode } from "./game-mode";
import { MoneyMultiplierModifier, PokemonHeldItemModifier } from "./modifier/modifier"; import { MoneyMultiplierModifier, PokemonHeldItemModifier } from "./modifier/modifier";
@ -99,7 +107,7 @@ export default class Battle {
public postBattleLoot: PokemonHeldItemModifier[] = []; public postBattleLoot: PokemonHeldItemModifier[] = [];
public escapeAttempts = 0; public escapeAttempts = 0;
public lastMove: Moves; public lastMove: Moves;
public battleSeed: string = Utils.randomString(16, true); public battleSeed: string = randomString(16, true);
private battleSeedState: string | null = null; private battleSeedState: string | null = null;
public moneyScattered = 0; public moneyScattered = 0;
/** Primarily for double battles, keeps track of last enemy and player pokemon that triggered its ability or used a move */ /** Primarily for double battles, keeps track of last enemy and player pokemon that triggered its ability or used a move */
@ -181,8 +189,8 @@ export default class Battle {
incrementTurn(): void { incrementTurn(): void {
this.turn++; this.turn++;
this.turnCommands = Object.fromEntries(Utils.getEnumValues(BattlerIndex).map(bt => [bt, null])); this.turnCommands = Object.fromEntries(getEnumValues(BattlerIndex).map(bt => [bt, null]));
this.preTurnCommands = Object.fromEntries(Utils.getEnumValues(BattlerIndex).map(bt => [bt, null])); this.preTurnCommands = Object.fromEntries(getEnumValues(BattlerIndex).map(bt => [bt, null]));
this.battleSeedState = null; this.battleSeedState = null;
} }
@ -211,7 +219,7 @@ export default class Battle {
} }
pickUpScatteredMoney(): void { pickUpScatteredMoney(): void {
const moneyAmount = new Utils.NumberHolder(globalScene.currentBattle.moneyScattered); const moneyAmount = new NumberHolder(globalScene.currentBattle.moneyScattered);
globalScene.applyModifiers(MoneyMultiplierModifier, true, moneyAmount); globalScene.applyModifiers(MoneyMultiplierModifier, true, moneyAmount);
if (globalScene.arena.getTag(ArenaTagType.HAPPY_HOUR)) { if (globalScene.arena.getTag(ArenaTagType.HAPPY_HOUR)) {
@ -448,7 +456,7 @@ export default class Battle {
} }
/** /**
* Generates a random number using the current battle's seed. Calls {@linkcode Utils.randSeedInt} * Generates a random number using the current battle's seed. Calls {@linkcode randSeedInt}
* @param range How large of a range of random numbers to choose from. If {@linkcode range} <= 1, returns {@linkcode min} * @param range How large of a range of random numbers to choose from. If {@linkcode range} <= 1, returns {@linkcode min}
* @param min The minimum integer to pick, default `0` * @param min The minimum integer to pick, default `0`
* @returns A random integer between {@linkcode min} and ({@linkcode min} + {@linkcode range} - 1) * @returns A random integer between {@linkcode min} and ({@linkcode min} + {@linkcode range} - 1)
@ -463,12 +471,12 @@ export default class Battle {
if (this.battleSeedState) { if (this.battleSeedState) {
Phaser.Math.RND.state(this.battleSeedState); Phaser.Math.RND.state(this.battleSeedState);
} else { } else {
Phaser.Math.RND.sow([Utils.shiftCharCodes(this.battleSeed, this.turn << 6)]); Phaser.Math.RND.sow([shiftCharCodes(this.battleSeed, this.turn << 6)]);
console.log("Battle Seed:", this.battleSeed); console.log("Battle Seed:", this.battleSeed);
} }
globalScene.rngCounter = this.rngCounter++; globalScene.rngCounter = this.rngCounter++;
globalScene.rngSeedOverride = this.battleSeed; globalScene.rngSeedOverride = this.battleSeed;
const ret = Utils.randSeedInt(range, min); const ret = randSeedInt(range, min);
this.battleSeedState = Phaser.Math.RND.state(); this.battleSeedState = Phaser.Math.RND.state();
Phaser.Math.RND.state(state); Phaser.Math.RND.state(state);
globalScene.rngCounter = tempRngCounter; globalScene.rngCounter = tempRngCounter;
@ -554,19 +562,19 @@ export function getRandomTrainerFunc(
seedOffset = 0, seedOffset = 0,
): GetTrainerFunc { ): GetTrainerFunc {
return () => { return () => {
const rand = Utils.randSeedInt(trainerPool.length); const rand = randSeedInt(trainerPool.length);
const trainerTypes: TrainerType[] = []; const trainerTypes: TrainerType[] = [];
globalScene.executeWithSeedOffset(() => { globalScene.executeWithSeedOffset(() => {
for (const trainerPoolEntry of trainerPool) { for (const trainerPoolEntry of trainerPool) {
const trainerType = Array.isArray(trainerPoolEntry) ? Utils.randSeedItem(trainerPoolEntry) : trainerPoolEntry; const trainerType = Array.isArray(trainerPoolEntry) ? randSeedItem(trainerPoolEntry) : trainerPoolEntry;
trainerTypes.push(trainerType); trainerTypes.push(trainerType);
} }
}, seedOffset); }, seedOffset);
let trainerGender = TrainerVariant.DEFAULT; let trainerGender = TrainerVariant.DEFAULT;
if (randomGender) { if (randomGender) {
trainerGender = Utils.randInt(2) === 0 ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT; trainerGender = randInt(2) === 0 ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT;
} }
/* 1/3 chance for evil team grunts to be double battles */ /* 1/3 chance for evil team grunts to be double battles */
@ -585,7 +593,7 @@ export function getRandomTrainerFunc(
const isEvilTeamGrunt = evilTeamGrunts.includes(trainerTypes[rand]); const isEvilTeamGrunt = evilTeamGrunts.includes(trainerTypes[rand]);
if (trainerConfigs[trainerTypes[rand]].hasDouble && isEvilTeamGrunt) { if (trainerConfigs[trainerTypes[rand]].hasDouble && isEvilTeamGrunt) {
return new Trainer(trainerTypes[rand], Utils.randInt(3) === 0 ? TrainerVariant.DOUBLE : trainerGender); return new Trainer(trainerTypes[rand], randInt(3) === 0 ? TrainerVariant.DOUBLE : trainerGender);
} }
return new Trainer(trainerTypes[rand], trainerGender); return new Trainer(trainerTypes[rand], trainerGender);
@ -608,7 +616,7 @@ export const classicFixedBattles: FixedBattleConfigs = {
[ClassicFixedBossWaves.TOWN_YOUNGSTER]: new FixedBattleConfig() [ClassicFixedBossWaves.TOWN_YOUNGSTER]: new FixedBattleConfig()
.setBattleType(BattleType.TRAINER) .setBattleType(BattleType.TRAINER)
.setGetTrainerFunc( .setGetTrainerFunc(
() => new Trainer(TrainerType.YOUNGSTER, Utils.randSeedInt(2) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT), () => new Trainer(TrainerType.YOUNGSTER, randSeedInt(2) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT),
), ),
[ClassicFixedBossWaves.RIVAL_1]: new FixedBattleConfig() [ClassicFixedBossWaves.RIVAL_1]: new FixedBattleConfig()
.setBattleType(BattleType.TRAINER) .setBattleType(BattleType.TRAINER)

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
import { PokemonType } from "#enums/pokemon-type"; import { PokemonType } from "#enums/pokemon-type";
import * as Utils from "#app/utils"; import { randSeedInt, getEnumValues } from "#app/utils";
import type { SpeciesFormEvolution } from "#app/data/balance/pokemon-evolutions"; import type { SpeciesFormEvolution } from "#app/data/balance/pokemon-evolutions";
import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions"; import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions";
import i18next from "i18next"; import i18next from "i18next";
@ -7710,7 +7710,7 @@ export function initBiomes() {
if (biome === Biome.END) { if (biome === Biome.END) {
const biomeList = Object.keys(Biome).filter(key => !Number.isNaN(Number(key))); const biomeList = Object.keys(Biome).filter(key => !Number.isNaN(Number(key)));
biomeList.pop(); // Removes Biome.END from the list biomeList.pop(); // Removes Biome.END from the list
const randIndex = Utils.randSeedInt(biomeList.length, 1); // Will never be Biome.TOWN const randIndex = randSeedInt(biomeList.length, 1); // Will never be Biome.TOWN
biome = Biome[biomeList[randIndex]]; biome = Biome[biomeList[randIndex]];
} }
const linkedBiomes: (Biome | [ Biome, number ])[] = Array.isArray(biomeLinks[biome]) const linkedBiomes: (Biome | [ Biome, number ])[] = Array.isArray(biomeLinks[biome])
@ -7733,15 +7733,15 @@ export function initBiomes() {
traverseBiome(Biome.TOWN, 0); traverseBiome(Biome.TOWN, 0);
biomeDepths[Biome.END] = [ Object.values(biomeDepths).map(d => d[0]).reduce((max: number, value: number) => Math.max(max, value), 0) + 1, 1 ]; biomeDepths[Biome.END] = [ Object.values(biomeDepths).map(d => d[0]).reduce((max: number, value: number) => Math.max(max, value), 0) + 1, 1 ];
for (const biome of Utils.getEnumValues(Biome)) { for (const biome of getEnumValues(Biome)) {
biomePokemonPools[biome] = {}; biomePokemonPools[biome] = {};
biomeTrainerPools[biome] = {}; biomeTrainerPools[biome] = {};
for (const tier of Utils.getEnumValues(BiomePoolTier)) { for (const tier of getEnumValues(BiomePoolTier)) {
biomePokemonPools[biome][tier] = {}; biomePokemonPools[biome][tier] = {};
biomeTrainerPools[biome][tier] = []; biomeTrainerPools[biome][tier] = [];
for (const tod of Utils.getEnumValues(TimeOfDay)) { for (const tod of getEnumValues(TimeOfDay)) {
biomePokemonPools[biome][tier][tod] = []; biomePokemonPools[biome][tier][tod] = [];
} }
} }

View File

@ -1,5 +1,5 @@
import { allMoves } from "#app/data/moves/move"; import { allMoves } from "#app/data/moves/move";
import * as Utils from "#app/utils"; import { getEnumKeys, getEnumValues } from "#app/utils";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
@ -587,8 +587,8 @@ export const speciesEggMoves = {
function parseEggMoves(content: string): void { function parseEggMoves(content: string): void {
let output = ""; let output = "";
const speciesNames = Utils.getEnumKeys(Species); const speciesNames = getEnumKeys(Species);
const speciesValues = Utils.getEnumValues(Species); const speciesValues = getEnumValues(Species);
const lines = content.split(/\n/g); const lines = content.split(/\n/g);
for (const line of lines) { for (const line of lines) {

View File

@ -3,7 +3,7 @@ import { Gender } from "#app/data/gender";
import { PokeballType } from "#enums/pokeball"; import { PokeballType } from "#enums/pokeball";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { PokemonType } from "#enums/pokemon-type"; import { PokemonType } from "#enums/pokemon-type";
import * as Utils from "#app/utils"; import { randSeedInt } from "#app/utils";
import { WeatherType } from "#enums/weather-type"; import { WeatherType } from "#enums/weather-type";
import { Nature } from "#enums/nature"; import { Nature } from "#enums/nature";
import { Biome } from "#enums/biome"; import { Biome } from "#enums/biome";
@ -333,7 +333,7 @@ class DunsparceEvolutionCondition extends SpeciesEvolutionCondition {
super(p => { super(p => {
let ret = false; let ret = false;
if (p.moveset.filter(m => m.moveId === Moves.HYPER_DRILL).length > 0) { if (p.moveset.filter(m => m.moveId === Moves.HYPER_DRILL).length > 0) {
globalScene.executeWithSeedOffset(() => ret = !Utils.randSeedInt(4), p.id); globalScene.executeWithSeedOffset(() => ret = !randSeedInt(4), p.id);
} }
return ret; return ret;
}); });
@ -346,7 +346,7 @@ class TandemausEvolutionCondition extends SpeciesEvolutionCondition {
constructor() { constructor() {
super(p => { super(p => {
let ret = false; let ret = false;
globalScene.executeWithSeedOffset(() => ret = !Utils.randSeedInt(4), p.id); globalScene.executeWithSeedOffset(() => ret = !randSeedInt(4), p.id);
return ret; return ret;
}); });
} }

View File

@ -42,7 +42,7 @@ import { Species } from "#enums/species";
import { EFFECTIVE_STATS, getStatKey, Stat, type BattleStat, type EffectiveStat } from "#enums/stat"; import { EFFECTIVE_STATS, getStatKey, Stat, type BattleStat, type EffectiveStat } from "#enums/stat";
import { StatusEffect } from "#enums/status-effect"; import { StatusEffect } from "#enums/status-effect";
import { WeatherType } from "#enums/weather-type"; import { WeatherType } from "#enums/weather-type";
import * as Utils from "../utils"; import { isNullOrUndefined } from "#app/utils";
export enum BattlerTagLapseType { export enum BattlerTagLapseType {
FAINT, FAINT,
@ -302,7 +302,7 @@ export class DisabledTag extends MoveRestrictionBattlerTag {
super.onAdd(pokemon); super.onAdd(pokemon);
const move = pokemon.getLastXMoves(-1).find(m => !m.virtual); const move = pokemon.getLastXMoves(-1).find(m => !m.virtual);
if (Utils.isNullOrUndefined(move) || move.move === Moves.STRUGGLE || move.move === Moves.NONE) { if (isNullOrUndefined(move) || move.move === Moves.STRUGGLE || move.move === Moves.NONE) {
return; return;
} }

View File

@ -2,7 +2,7 @@ import { getPokemonNameWithAffix } from "../messages";
import type Pokemon from "../field/pokemon"; import type Pokemon from "../field/pokemon";
import { HitResult } from "../field/pokemon"; import { HitResult } from "../field/pokemon";
import { getStatusEffectHealText } from "./status-effect"; import { getStatusEffectHealText } from "./status-effect";
import * as Utils from "../utils"; import { NumberHolder, toDmgValue, randSeedInt } from "#app/utils";
import { import {
DoubleBerryEffectAbAttr, DoubleBerryEffectAbAttr,
PostItemLostAbAttr, PostItemLostAbAttr,
@ -43,7 +43,7 @@ export function getBerryPredicate(berryType: BerryType): BerryPredicate {
case BerryType.APICOT: case BerryType.APICOT:
case BerryType.SALAC: case BerryType.SALAC:
return (pokemon: Pokemon) => { return (pokemon: Pokemon) => {
const threshold = new Utils.NumberHolder(0.25); const threshold = new NumberHolder(0.25);
// Offset BerryType such that LIECHI -> Stat.ATK = 1, GANLON -> Stat.DEF = 2, so on and so forth // Offset BerryType such that LIECHI -> Stat.ATK = 1, GANLON -> Stat.DEF = 2, so on and so forth
const stat: BattleStat = berryType - BerryType.ENIGMA; const stat: BattleStat = berryType - BerryType.ENIGMA;
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold); applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold);
@ -51,19 +51,19 @@ export function getBerryPredicate(berryType: BerryType): BerryPredicate {
}; };
case BerryType.LANSAT: case BerryType.LANSAT:
return (pokemon: Pokemon) => { return (pokemon: Pokemon) => {
const threshold = new Utils.NumberHolder(0.25); const threshold = new NumberHolder(0.25);
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold); applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold);
return pokemon.getHpRatio() < 0.25 && !pokemon.getTag(BattlerTagType.CRIT_BOOST); return pokemon.getHpRatio() < 0.25 && !pokemon.getTag(BattlerTagType.CRIT_BOOST);
}; };
case BerryType.STARF: case BerryType.STARF:
return (pokemon: Pokemon) => { return (pokemon: Pokemon) => {
const threshold = new Utils.NumberHolder(0.25); const threshold = new NumberHolder(0.25);
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold); applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold);
return pokemon.getHpRatio() < 0.25; return pokemon.getHpRatio() < 0.25;
}; };
case BerryType.LEPPA: case BerryType.LEPPA:
return (pokemon: Pokemon) => { return (pokemon: Pokemon) => {
const threshold = new Utils.NumberHolder(0.25); const threshold = new NumberHolder(0.25);
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold); applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold);
return !!pokemon.getMoveset().find(m => !m.getPpRatio()); return !!pokemon.getMoveset().find(m => !m.getPpRatio());
}; };
@ -80,7 +80,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
if (pokemon.battleData) { if (pokemon.battleData) {
pokemon.battleData.berriesEaten.push(berryType); pokemon.battleData.berriesEaten.push(berryType);
} }
const hpHealed = new Utils.NumberHolder(Utils.toDmgValue(pokemon.getMaxHp() / 4)); const hpHealed = new NumberHolder(toDmgValue(pokemon.getMaxHp() / 4));
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, hpHealed); applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, hpHealed);
globalScene.unshiftPhase( globalScene.unshiftPhase(
new PokemonHealPhase( new PokemonHealPhase(
@ -118,7 +118,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
} }
// Offset BerryType such that LIECHI -> Stat.ATK = 1, GANLON -> Stat.DEF = 2, so on and so forth // Offset BerryType such that LIECHI -> Stat.ATK = 1, GANLON -> Stat.DEF = 2, so on and so forth
const stat: BattleStat = berryType - BerryType.ENIGMA; const stat: BattleStat = berryType - BerryType.ENIGMA;
const statStages = new Utils.NumberHolder(1); const statStages = new NumberHolder(1);
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, statStages); applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, statStages);
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [stat], statStages.value)); globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [stat], statStages.value));
applyPostItemLostAbAttrs(PostItemLostAbAttr, berryOwner ?? pokemon, false); applyPostItemLostAbAttrs(PostItemLostAbAttr, berryOwner ?? pokemon, false);
@ -136,8 +136,8 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
if (pokemon.battleData) { if (pokemon.battleData) {
pokemon.battleData.berriesEaten.push(berryType); pokemon.battleData.berriesEaten.push(berryType);
} }
const randStat = Utils.randSeedInt(Stat.SPD, Stat.ATK); const randStat = randSeedInt(Stat.SPD, Stat.ATK);
const stages = new Utils.NumberHolder(2); const stages = new NumberHolder(2);
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, stages); applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, stages);
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [randStat], stages.value)); globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [randStat], stages.value));
applyPostItemLostAbAttrs(PostItemLostAbAttr, berryOwner ?? pokemon, false); applyPostItemLostAbAttrs(PostItemLostAbAttr, berryOwner ?? pokemon, false);

View File

@ -1,4 +1,4 @@
import * as Utils from "#app/utils"; import { BooleanHolder, type NumberHolder, randSeedItem, deepCopy } from "#app/utils";
import i18next from "i18next"; import i18next from "i18next";
import type { DexAttrProps, GameData } from "#app/system/game-data"; import type { DexAttrProps, GameData } from "#app/system/game-data";
import { defaultStarterSpecies } from "#app/system/game-data"; import { defaultStarterSpecies } from "#app/system/game-data";
@ -283,30 +283,30 @@ export abstract class Challenge {
/** /**
* An apply function for STARTER_CHOICE challenges. Derived classes should alter this. * An apply function for STARTER_CHOICE challenges. Derived classes should alter this.
* @param _pokemon {@link PokemonSpecies} The pokemon to check the validity of. * @param _pokemon {@link PokemonSpecies} The pokemon to check the validity of.
* @param _valid {@link Utils.BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed. * @param _valid {@link BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed.
* @param _dexAttr {@link DexAttrProps} The dex attributes of the pokemon. * @param _dexAttr {@link DexAttrProps} The dex attributes of the pokemon.
* @returns {@link boolean} Whether this function did anything. * @returns {@link boolean} Whether this function did anything.
*/ */
applyStarterChoice(_pokemon: PokemonSpecies, _valid: Utils.BooleanHolder, _dexAttr: DexAttrProps): boolean { applyStarterChoice(_pokemon: PokemonSpecies, _valid: BooleanHolder, _dexAttr: DexAttrProps): boolean {
return false; return false;
} }
/** /**
* An apply function for STARTER_POINTS challenges. Derived classes should alter this. * An apply function for STARTER_POINTS challenges. Derived classes should alter this.
* @param _points {@link Utils.NumberHolder} The amount of points you have available. * @param _points {@link NumberHolder} The amount of points you have available.
* @returns {@link boolean} Whether this function did anything. * @returns {@link boolean} Whether this function did anything.
*/ */
applyStarterPoints(_points: Utils.NumberHolder): boolean { applyStarterPoints(_points: NumberHolder): boolean {
return false; return false;
} }
/** /**
* An apply function for STARTER_COST challenges. Derived classes should alter this. * An apply function for STARTER_COST challenges. Derived classes should alter this.
* @param _species {@link Species} The pokemon to change the cost of. * @param _species {@link Species} The pokemon to change the cost of.
* @param _cost {@link Utils.NumberHolder} The cost of the starter. * @param _cost {@link NumberHolder} The cost of the starter.
* @returns {@link boolean} Whether this function did anything. * @returns {@link boolean} Whether this function did anything.
*/ */
applyStarterCost(_species: Species, _cost: Utils.NumberHolder): boolean { applyStarterCost(_species: Species, _cost: NumberHolder): boolean {
return false; return false;
} }
@ -322,10 +322,10 @@ export abstract class Challenge {
/** /**
* An apply function for POKEMON_IN_BATTLE challenges. Derived classes should alter this. * An apply function for POKEMON_IN_BATTLE challenges. Derived classes should alter this.
* @param _pokemon {@link Pokemon} The pokemon to check the validity of. * @param _pokemon {@link Pokemon} The pokemon to check the validity of.
* @param _valid {@link Utils.BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed. * @param _valid {@link BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed.
* @returns {@link boolean} Whether this function did anything. * @returns {@link boolean} Whether this function did anything.
*/ */
applyPokemonInBattle(_pokemon: Pokemon, _valid: Utils.BooleanHolder): boolean { applyPokemonInBattle(_pokemon: Pokemon, _valid: BooleanHolder): boolean {
return false; return false;
} }
@ -341,42 +341,42 @@ export abstract class Challenge {
/** /**
* An apply function for TYPE_EFFECTIVENESS challenges. Derived classes should alter this. * An apply function for TYPE_EFFECTIVENESS challenges. Derived classes should alter this.
* @param _effectiveness {@linkcode Utils.NumberHolder} The current effectiveness of the move. * @param _effectiveness {@linkcode NumberHolder} The current effectiveness of the move.
* @returns Whether this function did anything. * @returns Whether this function did anything.
*/ */
applyTypeEffectiveness(_effectiveness: Utils.NumberHolder): boolean { applyTypeEffectiveness(_effectiveness: NumberHolder): boolean {
return false; return false;
} }
/** /**
* An apply function for AI_LEVEL challenges. Derived classes should alter this. * An apply function for AI_LEVEL challenges. Derived classes should alter this.
* @param _level {@link Utils.NumberHolder} The generated level. * @param _level {@link NumberHolder} The generated level.
* @param _levelCap {@link Number} The current level cap. * @param _levelCap {@link Number} The current level cap.
* @param _isTrainer {@link Boolean} Whether this is a trainer pokemon. * @param _isTrainer {@link Boolean} Whether this is a trainer pokemon.
* @param _isBoss {@link Boolean} Whether this is a non-trainer boss pokemon. * @param _isBoss {@link Boolean} Whether this is a non-trainer boss pokemon.
* @returns {@link boolean} Whether this function did anything. * @returns {@link boolean} Whether this function did anything.
*/ */
applyLevelChange(_level: Utils.NumberHolder, _levelCap: number, _isTrainer: boolean, _isBoss: boolean): boolean { applyLevelChange(_level: NumberHolder, _levelCap: number, _isTrainer: boolean, _isBoss: boolean): boolean {
return false; return false;
} }
/** /**
* An apply function for AI_MOVE_SLOTS challenges. Derived classes should alter this. * An apply function for AI_MOVE_SLOTS challenges. Derived classes should alter this.
* @param pokemon {@link Pokemon} The pokemon that is being considered. * @param pokemon {@link Pokemon} The pokemon that is being considered.
* @param moveSlots {@link Utils.NumberHolder} The amount of move slots. * @param moveSlots {@link NumberHolder} The amount of move slots.
* @returns {@link boolean} Whether this function did anything. * @returns {@link boolean} Whether this function did anything.
*/ */
applyMoveSlot(_pokemon: Pokemon, _moveSlots: Utils.NumberHolder): boolean { applyMoveSlot(_pokemon: Pokemon, _moveSlots: NumberHolder): boolean {
return false; return false;
} }
/** /**
* An apply function for PASSIVE_ACCESS challenges. Derived classes should alter this. * An apply function for PASSIVE_ACCESS challenges. Derived classes should alter this.
* @param pokemon {@link Pokemon} The pokemon to change. * @param pokemon {@link Pokemon} The pokemon to change.
* @param hasPassive {@link Utils.BooleanHolder} Whether it should have its passive. * @param hasPassive {@link BooleanHolder} Whether it should have its passive.
* @returns {@link boolean} Whether this function did anything. * @returns {@link boolean} Whether this function did anything.
*/ */
applyPassiveAccess(_pokemon: Pokemon, _hasPassive: Utils.BooleanHolder): boolean { applyPassiveAccess(_pokemon: Pokemon, _hasPassive: BooleanHolder): boolean {
return false; return false;
} }
@ -393,15 +393,10 @@ export abstract class Challenge {
* @param _pokemon {@link Pokemon} What pokemon would learn the move. * @param _pokemon {@link Pokemon} What pokemon would learn the move.
* @param _moveSource {@link MoveSourceType} What source the pokemon would get the move from. * @param _moveSource {@link MoveSourceType} What source the pokemon would get the move from.
* @param _move {@link Moves} The move in question. * @param _move {@link Moves} The move in question.
* @param _level {@link Utils.NumberHolder} The level threshold for access. * @param _level {@link NumberHolder} The level threshold for access.
* @returns {@link boolean} Whether this function did anything. * @returns {@link boolean} Whether this function did anything.
*/ */
applyMoveAccessLevel( applyMoveAccessLevel(_pokemon: Pokemon, _moveSource: MoveSourceType, _move: Moves, _level: NumberHolder): boolean {
_pokemon: Pokemon,
_moveSource: MoveSourceType,
_move: Moves,
_level: Utils.NumberHolder,
): boolean {
return false; return false;
} }
@ -410,10 +405,10 @@ export abstract class Challenge {
* @param _pokemon {@link Pokemon} What pokemon would learn the move. * @param _pokemon {@link Pokemon} What pokemon would learn the move.
* @param _moveSource {@link MoveSourceType} What source the pokemon would get the move from. * @param _moveSource {@link MoveSourceType} What source the pokemon would get the move from.
* @param _move {@link Moves} The move in question. * @param _move {@link Moves} The move in question.
* @param _weight {@link Utils.NumberHolder} The base weight of the move * @param _weight {@link NumberHolder} The base weight of the move
* @returns {@link boolean} Whether this function did anything. * @returns {@link boolean} Whether this function did anything.
*/ */
applyMoveWeight(_pokemon: Pokemon, _moveSource: MoveSourceType, _move: Moves, _level: Utils.NumberHolder): boolean { applyMoveWeight(_pokemon: Pokemon, _moveSource: MoveSourceType, _move: Moves, _level: NumberHolder): boolean {
return false; return false;
} }
@ -438,7 +433,7 @@ export class SingleGenerationChallenge extends Challenge {
super(Challenges.SINGLE_GENERATION, 9); super(Challenges.SINGLE_GENERATION, 9);
} }
applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder): boolean { applyStarterChoice(pokemon: PokemonSpecies, valid: BooleanHolder): boolean {
if (pokemon.generation !== this.value) { if (pokemon.generation !== this.value) {
valid.value = false; valid.value = false;
return true; return true;
@ -446,7 +441,7 @@ export class SingleGenerationChallenge extends Challenge {
return false; return false;
} }
applyPokemonInBattle(pokemon: Pokemon, valid: Utils.BooleanHolder): boolean { applyPokemonInBattle(pokemon: Pokemon, valid: BooleanHolder): boolean {
const baseGeneration = getPokemonSpecies(pokemon.species.speciesId).generation; const baseGeneration = getPokemonSpecies(pokemon.species.speciesId).generation;
const fusionGeneration = pokemon.isFusion() ? getPokemonSpecies(pokemon.fusionSpecies!.speciesId).generation : 0; const fusionGeneration = pokemon.isFusion() ? getPokemonSpecies(pokemon.fusionSpecies!.speciesId).generation : 0;
if ( if (
@ -575,7 +570,7 @@ export class SingleGenerationChallenge extends Challenge {
TrainerType.AARON, TrainerType.AARON,
TrainerType.SHAUNTAL, TrainerType.SHAUNTAL,
TrainerType.MALVA, TrainerType.MALVA,
Utils.randSeedItem([TrainerType.HALA, TrainerType.MOLAYNE]), randSeedItem([TrainerType.HALA, TrainerType.MOLAYNE]),
TrainerType.MARNIE_ELITE, TrainerType.MARNIE_ELITE,
TrainerType.RIKA, TrainerType.RIKA,
]; ];
@ -602,7 +597,7 @@ export class SingleGenerationChallenge extends Challenge {
TrainerType.GRIMSLEY, TrainerType.GRIMSLEY,
TrainerType.WIKSTROM, TrainerType.WIKSTROM,
TrainerType.ACEROLA, TrainerType.ACEROLA,
Utils.randSeedItem([TrainerType.BEA_ELITE, TrainerType.ALLISTER_ELITE]), randSeedItem([TrainerType.BEA_ELITE, TrainerType.ALLISTER_ELITE]),
TrainerType.LARRY_ELITE, TrainerType.LARRY_ELITE,
]; ];
break; break;
@ -622,14 +617,14 @@ export class SingleGenerationChallenge extends Challenge {
case ClassicFixedBossWaves.CHAMPION: case ClassicFixedBossWaves.CHAMPION:
trainerTypes = [ trainerTypes = [
TrainerType.BLUE, TrainerType.BLUE,
Utils.randSeedItem([TrainerType.RED, TrainerType.LANCE_CHAMPION]), randSeedItem([TrainerType.RED, TrainerType.LANCE_CHAMPION]),
Utils.randSeedItem([TrainerType.STEVEN, TrainerType.WALLACE]), randSeedItem([TrainerType.STEVEN, TrainerType.WALLACE]),
TrainerType.CYNTHIA, TrainerType.CYNTHIA,
Utils.randSeedItem([TrainerType.ALDER, TrainerType.IRIS]), randSeedItem([TrainerType.ALDER, TrainerType.IRIS]),
TrainerType.DIANTHA, TrainerType.DIANTHA,
Utils.randSeedItem([TrainerType.KUKUI, TrainerType.HAU]), randSeedItem([TrainerType.KUKUI, TrainerType.HAU]),
Utils.randSeedItem([TrainerType.LEON, TrainerType.MUSTARD]), randSeedItem([TrainerType.LEON, TrainerType.MUSTARD]),
Utils.randSeedItem([TrainerType.GEETA, TrainerType.NEMONA]), randSeedItem([TrainerType.GEETA, TrainerType.NEMONA]),
]; ];
break; break;
} }
@ -718,7 +713,7 @@ export class SingleTypeChallenge extends Challenge {
super(Challenges.SINGLE_TYPE, 18); super(Challenges.SINGLE_TYPE, 18);
} }
override applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps): boolean { override applyStarterChoice(pokemon: PokemonSpecies, valid: BooleanHolder, dexAttr: DexAttrProps): boolean {
const speciesForm = getPokemonSpeciesForm(pokemon.speciesId, dexAttr.formIndex); const speciesForm = getPokemonSpeciesForm(pokemon.speciesId, dexAttr.formIndex);
const types = [speciesForm.type1, speciesForm.type2]; const types = [speciesForm.type1, speciesForm.type2];
if (!types.includes(this.value - 1)) { if (!types.includes(this.value - 1)) {
@ -728,7 +723,7 @@ export class SingleTypeChallenge extends Challenge {
return false; return false;
} }
applyPokemonInBattle(pokemon: Pokemon, valid: Utils.BooleanHolder): boolean { applyPokemonInBattle(pokemon: Pokemon, valid: BooleanHolder): boolean {
if ( if (
pokemon.isPlayer() && pokemon.isPlayer() &&
!pokemon.isOfType(this.value - 1, false, false, true) && !pokemon.isOfType(this.value - 1, false, false, true) &&
@ -798,7 +793,7 @@ export class FreshStartChallenge extends Challenge {
super(Challenges.FRESH_START, 1); super(Challenges.FRESH_START, 1);
} }
applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder): boolean { applyStarterChoice(pokemon: PokemonSpecies, valid: BooleanHolder): boolean {
if (!defaultStarterSpecies.includes(pokemon.speciesId)) { if (!defaultStarterSpecies.includes(pokemon.speciesId)) {
valid.value = false; valid.value = false;
return true; return true;
@ -806,7 +801,7 @@ export class FreshStartChallenge extends Challenge {
return false; return false;
} }
applyStarterCost(species: Species, cost: Utils.NumberHolder): boolean { applyStarterCost(species: Species, cost: NumberHolder): boolean {
if (defaultStarterSpecies.includes(species)) { if (defaultStarterSpecies.includes(species)) {
cost.value = speciesStarterCosts[species]; cost.value = speciesStarterCosts[species];
return true; return true;
@ -864,7 +859,7 @@ export class InverseBattleChallenge extends Challenge {
return 0; return 0;
} }
applyTypeEffectiveness(effectiveness: Utils.NumberHolder): boolean { applyTypeEffectiveness(effectiveness: NumberHolder): boolean {
if (effectiveness.value < 1) { if (effectiveness.value < 1) {
effectiveness.value = 2; effectiveness.value = 2;
return true; return true;
@ -887,7 +882,7 @@ export class FlipStatChallenge extends Challenge {
} }
override applyFlipStat(_pokemon: Pokemon, baseStats: number[]) { override applyFlipStat(_pokemon: Pokemon, baseStats: number[]) {
const origStats = Utils.deepCopy(baseStats); const origStats = deepCopy(baseStats);
baseStats[0] = origStats[5]; baseStats[0] = origStats[5];
baseStats[1] = origStats[4]; baseStats[1] = origStats[4];
baseStats[2] = origStats[3]; baseStats[2] = origStats[3];
@ -923,7 +918,7 @@ export class LowerStarterMaxCostChallenge extends Challenge {
return (DEFAULT_PARTY_MAX_COST - overrideValue).toString(); return (DEFAULT_PARTY_MAX_COST - overrideValue).toString();
} }
applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder): boolean { applyStarterChoice(pokemon: PokemonSpecies, valid: BooleanHolder): boolean {
if (speciesStarterCosts[pokemon.speciesId] > DEFAULT_PARTY_MAX_COST - this.value) { if (speciesStarterCosts[pokemon.speciesId] > DEFAULT_PARTY_MAX_COST - this.value) {
valid.value = false; valid.value = false;
return true; return true;
@ -957,7 +952,7 @@ export class LowerStarterPointsChallenge extends Challenge {
return (DEFAULT_PARTY_MAX_COST - overrideValue).toString(); return (DEFAULT_PARTY_MAX_COST - overrideValue).toString();
} }
applyStarterPoints(points: Utils.NumberHolder): boolean { applyStarterPoints(points: NumberHolder): boolean {
points.value -= this.value; points.value -= this.value;
return true; return true;
} }
@ -974,34 +969,34 @@ export class LowerStarterPointsChallenge extends Challenge {
* Apply all challenges that modify starter choice. * Apply all challenges that modify starter choice.
* @param challengeType {@link ChallengeType} ChallengeType.STARTER_CHOICE * @param challengeType {@link ChallengeType} ChallengeType.STARTER_CHOICE
* @param pokemon {@link PokemonSpecies} The pokemon to check the validity of. * @param pokemon {@link PokemonSpecies} The pokemon to check the validity of.
* @param valid {@link Utils.BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed. * @param valid {@link BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed.
* @param dexAttr {@link DexAttrProps} The dex attributes of the pokemon. * @param dexAttr {@link DexAttrProps} The dex attributes of the pokemon.
* @returns True if any challenge was successfully applied. * @returns True if any challenge was successfully applied.
*/ */
export function applyChallenges( export function applyChallenges(
challengeType: ChallengeType.STARTER_CHOICE, challengeType: ChallengeType.STARTER_CHOICE,
pokemon: PokemonSpecies, pokemon: PokemonSpecies,
valid: Utils.BooleanHolder, valid: BooleanHolder,
dexAttr: DexAttrProps, dexAttr: DexAttrProps,
): boolean; ): boolean;
/** /**
* Apply all challenges that modify available total starter points. * Apply all challenges that modify available total starter points.
* @param challengeType {@link ChallengeType} ChallengeType.STARTER_POINTS * @param challengeType {@link ChallengeType} ChallengeType.STARTER_POINTS
* @param points {@link Utils.NumberHolder} The amount of points you have available. * @param points {@link NumberHolder} The amount of points you have available.
* @returns True if any challenge was successfully applied. * @returns True if any challenge was successfully applied.
*/ */
export function applyChallenges(challengeType: ChallengeType.STARTER_POINTS, points: Utils.NumberHolder): boolean; export function applyChallenges(challengeType: ChallengeType.STARTER_POINTS, points: NumberHolder): boolean;
/** /**
* Apply all challenges that modify the cost of a starter. * Apply all challenges that modify the cost of a starter.
* @param challengeType {@link ChallengeType} ChallengeType.STARTER_COST * @param challengeType {@link ChallengeType} ChallengeType.STARTER_COST
* @param species {@link Species} The pokemon to change the cost of. * @param species {@link Species} The pokemon to change the cost of.
* @param points {@link Utils.NumberHolder} The cost of the pokemon. * @param points {@link NumberHolder} The cost of the pokemon.
* @returns True if any challenge was successfully applied. * @returns True if any challenge was successfully applied.
*/ */
export function applyChallenges( export function applyChallenges(
challengeType: ChallengeType.STARTER_COST, challengeType: ChallengeType.STARTER_COST,
species: Species, species: Species,
cost: Utils.NumberHolder, cost: NumberHolder,
): boolean; ): boolean;
/** /**
* Apply all challenges that modify a starter after selection. * Apply all challenges that modify a starter after selection.
@ -1014,13 +1009,13 @@ export function applyChallenges(challengeType: ChallengeType.STARTER_MODIFY, pok
* Apply all challenges that what pokemon you can have in battle. * Apply all challenges that what pokemon you can have in battle.
* @param challengeType {@link ChallengeType} ChallengeType.POKEMON_IN_BATTLE * @param challengeType {@link ChallengeType} ChallengeType.POKEMON_IN_BATTLE
* @param pokemon {@link Pokemon} The pokemon to check the validity of. * @param pokemon {@link Pokemon} The pokemon to check the validity of.
* @param valid {@link Utils.BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed. * @param valid {@link BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed.
* @returns True if any challenge was successfully applied. * @returns True if any challenge was successfully applied.
*/ */
export function applyChallenges( export function applyChallenges(
challengeType: ChallengeType.POKEMON_IN_BATTLE, challengeType: ChallengeType.POKEMON_IN_BATTLE,
pokemon: Pokemon, pokemon: Pokemon,
valid: Utils.BooleanHolder, valid: BooleanHolder,
): boolean; ): boolean;
/** /**
* Apply all challenges that modify what fixed battles there are. * Apply all challenges that modify what fixed battles there are.
@ -1037,17 +1032,14 @@ export function applyChallenges(
/** /**
* Apply all challenges that modify type effectiveness. * Apply all challenges that modify type effectiveness.
* @param challengeType {@linkcode ChallengeType} ChallengeType.TYPE_EFFECTIVENESS * @param challengeType {@linkcode ChallengeType} ChallengeType.TYPE_EFFECTIVENESS
* @param effectiveness {@linkcode Utils.NumberHolder} The current effectiveness of the move. * @param effectiveness {@linkcode NumberHolder} The current effectiveness of the move.
* @returns True if any challenge was successfully applied. * @returns True if any challenge was successfully applied.
*/ */
export function applyChallenges( export function applyChallenges(challengeType: ChallengeType.TYPE_EFFECTIVENESS, effectiveness: NumberHolder): boolean;
challengeType: ChallengeType.TYPE_EFFECTIVENESS,
effectiveness: Utils.NumberHolder,
): boolean;
/** /**
* Apply all challenges that modify what level AI are. * Apply all challenges that modify what level AI are.
* @param challengeType {@link ChallengeType} ChallengeType.AI_LEVEL * @param challengeType {@link ChallengeType} ChallengeType.AI_LEVEL
* @param level {@link Utils.NumberHolder} The generated level of the pokemon. * @param level {@link NumberHolder} The generated level of the pokemon.
* @param levelCap {@link Number} The maximum level cap for the current wave. * @param levelCap {@link Number} The maximum level cap for the current wave.
* @param isTrainer {@link Boolean} Whether this is a trainer pokemon. * @param isTrainer {@link Boolean} Whether this is a trainer pokemon.
* @param isBoss {@link Boolean} Whether this is a non-trainer boss pokemon. * @param isBoss {@link Boolean} Whether this is a non-trainer boss pokemon.
@ -1055,7 +1047,7 @@ export function applyChallenges(
*/ */
export function applyChallenges( export function applyChallenges(
challengeType: ChallengeType.AI_LEVEL, challengeType: ChallengeType.AI_LEVEL,
level: Utils.NumberHolder, level: NumberHolder,
levelCap: number, levelCap: number,
isTrainer: boolean, isTrainer: boolean,
isBoss: boolean, isBoss: boolean,
@ -1064,25 +1056,25 @@ export function applyChallenges(
* Apply all challenges that modify how many move slots the AI has. * Apply all challenges that modify how many move slots the AI has.
* @param challengeType {@link ChallengeType} ChallengeType.AI_MOVE_SLOTS * @param challengeType {@link ChallengeType} ChallengeType.AI_MOVE_SLOTS
* @param pokemon {@link Pokemon} The pokemon being considered. * @param pokemon {@link Pokemon} The pokemon being considered.
* @param moveSlots {@link Utils.NumberHolder} The amount of move slots. * @param moveSlots {@link NumberHolder} The amount of move slots.
* @returns True if any challenge was successfully applied. * @returns True if any challenge was successfully applied.
*/ */
export function applyChallenges( export function applyChallenges(
challengeType: ChallengeType.AI_MOVE_SLOTS, challengeType: ChallengeType.AI_MOVE_SLOTS,
pokemon: Pokemon, pokemon: Pokemon,
moveSlots: Utils.NumberHolder, moveSlots: NumberHolder,
): boolean; ): boolean;
/** /**
* Apply all challenges that modify whether a pokemon has its passive. * Apply all challenges that modify whether a pokemon has its passive.
* @param challengeType {@link ChallengeType} ChallengeType.PASSIVE_ACCESS * @param challengeType {@link ChallengeType} ChallengeType.PASSIVE_ACCESS
* @param pokemon {@link Pokemon} The pokemon to modify. * @param pokemon {@link Pokemon} The pokemon to modify.
* @param hasPassive {@link Utils.BooleanHolder} Whether it has its passive. * @param hasPassive {@link BooleanHolder} Whether it has its passive.
* @returns True if any challenge was successfully applied. * @returns True if any challenge was successfully applied.
*/ */
export function applyChallenges( export function applyChallenges(
challengeType: ChallengeType.PASSIVE_ACCESS, challengeType: ChallengeType.PASSIVE_ACCESS,
pokemon: Pokemon, pokemon: Pokemon,
hasPassive: Utils.BooleanHolder, hasPassive: BooleanHolder,
): boolean; ): boolean;
/** /**
* Apply all challenges that modify the game modes settings. * Apply all challenges that modify the game modes settings.
@ -1096,7 +1088,7 @@ export function applyChallenges(challengeType: ChallengeType.GAME_MODE_MODIFY):
* @param pokemon {@link Pokemon} What pokemon would learn the move. * @param pokemon {@link Pokemon} What pokemon would learn the move.
* @param moveSource {@link MoveSourceType} What source the pokemon would get the move from. * @param moveSource {@link MoveSourceType} What source the pokemon would get the move from.
* @param move {@link Moves} The move in question. * @param move {@link Moves} The move in question.
* @param level {@link Utils.NumberHolder} The level threshold for access. * @param level {@link NumberHolder} The level threshold for access.
* @returns True if any challenge was successfully applied. * @returns True if any challenge was successfully applied.
*/ */
export function applyChallenges( export function applyChallenges(
@ -1104,7 +1096,7 @@ export function applyChallenges(
pokemon: Pokemon, pokemon: Pokemon,
moveSource: MoveSourceType, moveSource: MoveSourceType,
move: Moves, move: Moves,
level: Utils.NumberHolder, level: NumberHolder,
): boolean; ): boolean;
/** /**
* Apply all challenges that modify what weight a pokemon gives to move generation * Apply all challenges that modify what weight a pokemon gives to move generation
@ -1112,7 +1104,7 @@ export function applyChallenges(
* @param pokemon {@link Pokemon} What pokemon would learn the move. * @param pokemon {@link Pokemon} What pokemon would learn the move.
* @param moveSource {@link MoveSourceType} What source the pokemon would get the move from. * @param moveSource {@link MoveSourceType} What source the pokemon would get the move from.
* @param move {@link Moves} The move in question. * @param move {@link Moves} The move in question.
* @param weight {@link Utils.NumberHolder} The weight of the move. * @param weight {@link NumberHolder} The weight of the move.
* @returns True if any challenge was successfully applied. * @returns True if any challenge was successfully applied.
*/ */
export function applyChallenges( export function applyChallenges(
@ -1120,7 +1112,7 @@ export function applyChallenges(
pokemon: Pokemon, pokemon: Pokemon,
moveSource: MoveSourceType, moveSource: MoveSourceType,
move: Moves, move: Moves,
weight: Utils.NumberHolder, weight: NumberHolder,
): boolean; ): boolean;
export function applyChallenges(challengeType: ChallengeType.FLIP_STAT, pokemon: Pokemon, baseStats: number[]): boolean; export function applyChallenges(challengeType: ChallengeType.FLIP_STAT, pokemon: Pokemon, baseStats: number[]): boolean;
@ -1225,7 +1217,7 @@ export function initChallenges() {
*/ */
export function checkStarterValidForChallenge(species: PokemonSpecies, props: DexAttrProps, soft: boolean) { export function checkStarterValidForChallenge(species: PokemonSpecies, props: DexAttrProps, soft: boolean) {
if (!soft) { if (!soft) {
const isValidForChallenge = new Utils.BooleanHolder(true); const isValidForChallenge = new BooleanHolder(true);
applyChallenges(ChallengeType.STARTER_CHOICE, species, isValidForChallenge, props); applyChallenges(ChallengeType.STARTER_CHOICE, species, isValidForChallenge, props);
return isValidForChallenge.value; return isValidForChallenge.value;
} }
@ -1263,7 +1255,7 @@ export function checkStarterValidForChallenge(species: PokemonSpecies, props: De
* @returns `true` if the species is considered valid. * @returns `true` if the species is considered valid.
*/ */
function checkSpeciesValidForChallenge(species: PokemonSpecies, props: DexAttrProps, soft: boolean) { function checkSpeciesValidForChallenge(species: PokemonSpecies, props: DexAttrProps, soft: boolean) {
const isValidForChallenge = new Utils.BooleanHolder(true); const isValidForChallenge = new BooleanHolder(true);
applyChallenges(ChallengeType.STARTER_CHOICE, species, isValidForChallenge, props); applyChallenges(ChallengeType.STARTER_CHOICE, species, isValidForChallenge, props);
if (!soft || !pokemonFormChanges.hasOwnProperty(species.speciesId)) { if (!soft || !pokemonFormChanges.hasOwnProperty(species.speciesId)) {
return isValidForChallenge.value; return isValidForChallenge.value;
@ -1282,7 +1274,7 @@ function checkSpeciesValidForChallenge(species: PokemonSpecies, props: DexAttrPr
return species.forms.some((f2, formIndex) => { return species.forms.some((f2, formIndex) => {
if (f1.formKey === f2.formKey) { if (f1.formKey === f2.formKey) {
const formProps = { ...props, formIndex }; const formProps = { ...props, formIndex };
const isFormValidForChallenge = new Utils.BooleanHolder(true); const isFormValidForChallenge = new BooleanHolder(true);
applyChallenges(ChallengeType.STARTER_CHOICE, species, isFormValidForChallenge, formProps); applyChallenges(ChallengeType.STARTER_CHOICE, species, isFormValidForChallenge, formProps);
return isFormValidForChallenge.value; return isFormValidForChallenge.value;
} }

View File

@ -3,7 +3,7 @@ import type { Species } from "#enums/species";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { PlayerPokemon } from "#app/field/pokemon"; import { PlayerPokemon } from "#app/field/pokemon";
import type { Starter } from "#app/ui/starter-select-ui-handler"; import type { Starter } from "#app/ui/starter-select-ui-handler";
import * as Utils from "#app/utils"; import { randSeedGauss, randSeedInt, randSeedItem, getEnumValues } from "#app/utils";
import type { PokemonSpeciesForm } from "#app/data/pokemon-species"; import type { PokemonSpeciesForm } from "#app/data/pokemon-species";
import PokemonSpecies, { getPokemonSpecies, getPokemonSpeciesForm } from "#app/data/pokemon-species"; import PokemonSpecies, { getPokemonSpecies, getPokemonSpeciesForm } from "#app/data/pokemon-species";
import { speciesStarterCosts } from "#app/data/balance/starters"; import { speciesStarterCosts } from "#app/data/balance/starters";
@ -43,8 +43,8 @@ export function getDailyRunStarters(seed: string): Starter[] {
} }
const starterCosts: number[] = []; const starterCosts: number[] = [];
starterCosts.push(Math.min(Math.round(3.5 + Math.abs(Utils.randSeedGauss(1))), 8)); starterCosts.push(Math.min(Math.round(3.5 + Math.abs(randSeedGauss(1))), 8));
starterCosts.push(Utils.randSeedInt(9 - starterCosts[0], 1)); starterCosts.push(randSeedInt(9 - starterCosts[0], 1));
starterCosts.push(10 - (starterCosts[0] + starterCosts[1])); starterCosts.push(10 - (starterCosts[0] + starterCosts[1]));
for (let c = 0; c < starterCosts.length; c++) { for (let c = 0; c < starterCosts.length; c++) {
@ -52,7 +52,7 @@ export function getDailyRunStarters(seed: string): Starter[] {
const costSpecies = Object.keys(speciesStarterCosts) const costSpecies = Object.keys(speciesStarterCosts)
.map(s => Number.parseInt(s) as Species) .map(s => Number.parseInt(s) as Species)
.filter(s => speciesStarterCosts[s] === cost); .filter(s => speciesStarterCosts[s] === cost);
const randPkmSpecies = getPokemonSpecies(Utils.randSeedItem(costSpecies)); const randPkmSpecies = getPokemonSpecies(randSeedItem(costSpecies));
const starterSpecies = getPokemonSpecies( const starterSpecies = getPokemonSpecies(
randPkmSpecies.getTrainerSpeciesForLevel(startingLevel, true, PartyMemberStrength.STRONGER), randPkmSpecies.getTrainerSpeciesForLevel(startingLevel, true, PartyMemberStrength.STRONGER),
); );
@ -143,7 +143,7 @@ const dailyBiomeWeights: BiomeWeights = {
}; };
export function getDailyStartingBiome(): Biome { export function getDailyStartingBiome(): Biome {
const biomes = Utils.getEnumValues(Biome).filter(b => b !== Biome.TOWN && b !== Biome.END); const biomes = getEnumValues(Biome).filter(b => b !== Biome.TOWN && b !== Biome.END);
let totalWeight = 0; let totalWeight = 0;
const biomeThresholds: number[] = []; const biomeThresholds: number[] = [];
@ -155,7 +155,7 @@ export function getDailyStartingBiome(): Biome {
biomeThresholds.push(totalWeight); biomeThresholds.push(totalWeight);
} }
const randInt = Utils.randSeedInt(totalWeight); const randInt = randSeedInt(totalWeight);
for (let i = 0; i < biomes.length; i++) { for (let i = 0; i < biomes.length; i++) {
if (randInt < biomeThresholds[i]) { if (randInt < biomeThresholds[i]) {
@ -164,5 +164,5 @@ export function getDailyStartingBiome(): Biome {
} }
// Fallback in case something went wrong // Fallback in case something went wrong
return biomes[Utils.randSeedInt(biomes.length)]; return biomes[randSeedInt(biomes.length)];
} }

View File

@ -4,7 +4,7 @@ import type PokemonSpecies from "#app/data/pokemon-species";
import { getPokemonSpecies } from "#app/data/pokemon-species"; import { getPokemonSpecies } from "#app/data/pokemon-species";
import { speciesStarterCosts } from "#app/data/balance/starters"; import { speciesStarterCosts } from "#app/data/balance/starters";
import { VariantTier } from "#enums/variant-tier"; import { VariantTier } from "#enums/variant-tier";
import * as Utils from "#app/utils"; import { randInt, randomString, randSeedInt, getIvsFromId } from "#app/utils";
import Overrides from "#app/overrides"; import Overrides from "#app/overrides";
import { pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions"; import { pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions";
import type { PlayerPokemon } from "#app/field/pokemon"; import type { PlayerPokemon } from "#app/field/pokemon";
@ -171,7 +171,7 @@ export class Egg {
this.checkForPityTierOverrides(); this.checkForPityTierOverrides();
} }
this._id = eggOptions?.id ?? Utils.randInt(EGG_SEED, EGG_SEED * this._tier); this._id = eggOptions?.id ?? randInt(EGG_SEED, EGG_SEED * this._tier);
this._sourceType = eggOptions?.sourceType ?? undefined; this._sourceType = eggOptions?.sourceType ?? undefined;
this._hatchWaves = eggOptions?.hatchWaves ?? this.getEggTierDefaultHatchWaves(); this._hatchWaves = eggOptions?.hatchWaves ?? this.getEggTierDefaultHatchWaves();
@ -203,7 +203,7 @@ export class Egg {
} }
}; };
const seedOverride = Utils.randomString(24); const seedOverride = randomString(24);
globalScene.executeWithSeedOffset( globalScene.executeWithSeedOffset(
() => { () => {
generateEggProperties(eggOptions); generateEggProperties(eggOptions);
@ -248,18 +248,15 @@ export class Egg {
let pokemonSpecies = getPokemonSpecies(this._species); let pokemonSpecies = getPokemonSpecies(this._species);
// Special condition to have Phione eggs also have a chance of generating Manaphy // Special condition to have Phione eggs also have a chance of generating Manaphy
if (this._species === Species.PHIONE && this._sourceType === EggSourceType.SAME_SPECIES_EGG) { if (this._species === Species.PHIONE && this._sourceType === EggSourceType.SAME_SPECIES_EGG) {
pokemonSpecies = getPokemonSpecies( pokemonSpecies = getPokemonSpecies(randSeedInt(MANAPHY_EGG_MANAPHY_RATE) ? Species.PHIONE : Species.MANAPHY);
Utils.randSeedInt(MANAPHY_EGG_MANAPHY_RATE) ? Species.PHIONE : Species.MANAPHY,
);
} }
// Sets the hidden ability if a hidden ability exists and // Sets the hidden ability if a hidden ability exists and
// the override is set or the egg hits the chance // the override is set or the egg hits the chance
let abilityIndex: number | undefined = undefined; let abilityIndex: number | undefined = undefined;
const sameSpeciesEggHACheck = const sameSpeciesEggHACheck =
this._sourceType === EggSourceType.SAME_SPECIES_EGG && !Utils.randSeedInt(SAME_SPECIES_EGG_HA_RATE); this._sourceType === EggSourceType.SAME_SPECIES_EGG && !randSeedInt(SAME_SPECIES_EGG_HA_RATE);
const gachaEggHACheck = const gachaEggHACheck = !(this._sourceType === EggSourceType.SAME_SPECIES_EGG) && !randSeedInt(GACHA_EGG_HA_RATE);
!(this._sourceType === EggSourceType.SAME_SPECIES_EGG) && !Utils.randSeedInt(GACHA_EGG_HA_RATE);
if (pokemonSpecies.abilityHidden && (this._overrideHiddenAbility || sameSpeciesEggHACheck || gachaEggHACheck)) { if (pokemonSpecies.abilityHidden && (this._overrideHiddenAbility || sameSpeciesEggHACheck || gachaEggHACheck)) {
abilityIndex = 2; abilityIndex = 2;
} }
@ -269,7 +266,7 @@ export class Egg {
ret.shiny = this._isShiny; ret.shiny = this._isShiny;
ret.variant = this._variantTier; ret.variant = this._variantTier;
const secondaryIvs = Utils.getIvsFromId(Utils.randSeedInt(4294967295)); const secondaryIvs = getIvsFromId(randSeedInt(4294967295));
for (let s = 0; s < ret.ivs.length; s++) { for (let s = 0; s < ret.ivs.length; s++) {
ret.ivs[s] = Math.max(ret.ivs[s], secondaryIvs[s]); ret.ivs[s] = Math.max(ret.ivs[s], secondaryIvs[s]);
@ -370,7 +367,7 @@ export class Egg {
} }
const tierMultiplier = this.isManaphyEgg() ? 2 : Math.pow(2, 3 - this.tier); const tierMultiplier = this.isManaphyEgg() ? 2 : Math.pow(2, 3 - this.tier);
return Utils.randSeedInt(baseChance * tierMultiplier) ? Utils.randSeedInt(3) : 3; return randSeedInt(baseChance * tierMultiplier) ? randSeedInt(3) : 3;
} }
private getEggTierDefaultHatchWaves(eggTier?: EggTier): number { private getEggTierDefaultHatchWaves(eggTier?: EggTier): number {
@ -392,7 +389,7 @@ export class Egg {
private rollEggTier(): EggTier { private rollEggTier(): EggTier {
const tierValueOffset = const tierValueOffset =
this._sourceType === EggSourceType.GACHA_LEGENDARY ? GACHA_LEGENDARY_UP_THRESHOLD_OFFSET : 0; this._sourceType === EggSourceType.GACHA_LEGENDARY ? GACHA_LEGENDARY_UP_THRESHOLD_OFFSET : 0;
const tierValue = Utils.randInt(256); const tierValue = randInt(256);
return tierValue >= GACHA_DEFAULT_COMMON_EGG_THRESHOLD + tierValueOffset return tierValue >= GACHA_DEFAULT_COMMON_EGG_THRESHOLD + tierValueOffset
? EggTier.COMMON ? EggTier.COMMON
: tierValue >= GACHA_DEFAULT_RARE_EGG_THRESHOLD + tierValueOffset : tierValue >= GACHA_DEFAULT_RARE_EGG_THRESHOLD + tierValueOffset
@ -417,11 +414,11 @@ export class Egg {
* when Utils.randSeedInt(8) = 1, and by making the generatePlayerPokemon() species * when Utils.randSeedInt(8) = 1, and by making the generatePlayerPokemon() species
* check pass when Utils.randSeedInt(8) = 0, we can tell them apart during tests. * check pass when Utils.randSeedInt(8) = 0, we can tell them apart during tests.
*/ */
const rand = Utils.randSeedInt(MANAPHY_EGG_MANAPHY_RATE) !== 1; const rand = randSeedInt(MANAPHY_EGG_MANAPHY_RATE) !== 1;
return rand ? Species.PHIONE : Species.MANAPHY; return rand ? Species.PHIONE : Species.MANAPHY;
} }
if (this.tier === EggTier.LEGENDARY && this._sourceType === EggSourceType.GACHA_LEGENDARY) { if (this.tier === EggTier.LEGENDARY && this._sourceType === EggSourceType.GACHA_LEGENDARY) {
if (!Utils.randSeedInt(2)) { if (!randSeedInt(2)) {
return getLegendaryGachaSpeciesForTimestamp(this.timestamp); return getLegendaryGachaSpeciesForTimestamp(this.timestamp);
} }
} }
@ -501,7 +498,7 @@ export class Egg {
let species: Species; let species: Species;
const rand = Utils.randSeedInt(totalWeight); const rand = randSeedInt(totalWeight);
for (let s = 0; s < speciesWeights.length; s++) { for (let s = 0; s < speciesWeights.length; s++) {
if (rand < speciesWeights[s]) { if (rand < speciesWeights[s]) {
species = speciesPool[s]; species = speciesPool[s];
@ -539,7 +536,7 @@ export class Egg {
break; break;
} }
return !Utils.randSeedInt(shinyChance); return !randSeedInt(shinyChance);
} }
// Uses the same logic as pokemon.generateVariant(). I would like to only have this logic in one // Uses the same logic as pokemon.generateVariant(). I would like to only have this logic in one
@ -550,7 +547,7 @@ export class Egg {
return VariantTier.STANDARD; return VariantTier.STANDARD;
} }
const rand = Utils.randSeedInt(10); const rand = randSeedInt(10);
if (rand >= SHINY_VARIANT_CHANCE) { if (rand >= SHINY_VARIANT_CHANCE) {
return VariantTier.STANDARD; // 6/10 return VariantTier.STANDARD; // 6/10
} }

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,7 @@ import { modifierTypes } from "#app/modifier/modifier-type";
import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { PartyMemberStrength } from "#enums/party-member-strength"; import { PartyMemberStrength } from "#enums/party-member-strength";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import * as Utils from "#app/utils"; import { randSeedInt } from "#app/utils";
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter"; import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
@ -46,7 +46,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = MysteryEncounter
const normalConfig = trainerConfigs[normalTrainerType].clone(); const normalConfig = trainerConfigs[normalTrainerType].clone();
let female = false; let female = false;
if (normalConfig.hasGenders) { if (normalConfig.hasGenders) {
female = !!Utils.randSeedInt(2); female = !!randSeedInt(2);
} }
const normalSpriteKey = normalConfig.getSpriteKey(female, normalConfig.doubleOnly); const normalSpriteKey = normalConfig.getSpriteKey(female, normalConfig.doubleOnly);
encounter.enemyPartyConfigs.push({ encounter.enemyPartyConfigs.push({
@ -76,7 +76,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = MysteryEncounter
hardConfig.setPartyTemplates(hardTemplate); hardConfig.setPartyTemplates(hardTemplate);
female = false; female = false;
if (hardConfig.hasGenders) { if (hardConfig.hasGenders) {
female = !!Utils.randSeedInt(2); female = !!randSeedInt(2);
} }
const hardSpriteKey = hardConfig.getSpriteKey(female, hardConfig.doubleOnly); const hardSpriteKey = hardConfig.getSpriteKey(female, hardConfig.doubleOnly);
encounter.enemyPartyConfigs.push({ encounter.enemyPartyConfigs.push({
@ -96,7 +96,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = MysteryEncounter
brutalConfig.partyTemplateFunc = null; // Overrides gym leader party template func brutalConfig.partyTemplateFunc = null; // Overrides gym leader party template func
female = false; female = false;
if (brutalConfig.hasGenders) { if (brutalConfig.hasGenders) {
female = !!Utils.randSeedInt(2); female = !!randSeedInt(2);
} }
const brutalSpriteKey = brutalConfig.getSpriteKey(female, brutalConfig.doubleOnly); const brutalSpriteKey = brutalConfig.getSpriteKey(female, brutalConfig.doubleOnly);
encounter.enemyPartyConfigs.push({ encounter.enemyPartyConfigs.push({

View File

@ -5,7 +5,7 @@ import { capitalizeFirstLetter, isNullOrUndefined } from "#app/utils";
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";
import * as Utils from "#app/utils"; import { randSeedInt } from "#app/utils";
import type { StatusEffect } from "#enums/status-effect"; import type { StatusEffect } from "#enums/status-effect";
import type { OptionTextDisplay } from "./mystery-encounter-dialogue"; import type { OptionTextDisplay } from "./mystery-encounter-dialogue";
import type MysteryEncounterDialogue from "./mystery-encounter-dialogue"; import type MysteryEncounterDialogue from "./mystery-encounter-dialogue";
@ -378,13 +378,13 @@ export default class MysteryEncounter implements IMysteryEncounter {
} }
if (truePrimaryPool.length > 0) { if (truePrimaryPool.length > 0) {
// Always choose from the non-overlapping pokemon first // Always choose from the non-overlapping pokemon first
this.primaryPokemon = truePrimaryPool[Utils.randSeedInt(truePrimaryPool.length, 0)]; this.primaryPokemon = truePrimaryPool[randSeedInt(truePrimaryPool.length, 0)];
return true; return true;
} }
// If there are multiple overlapping pokemon, we're okay - just choose one and take it out of the primary pokemon pool // If there are multiple overlapping pokemon, we're okay - just choose one and take it out of the primary pokemon pool
if (overlap.length > 1 || this.secondaryPokemon.length - overlap.length >= 1) { if (overlap.length > 1 || this.secondaryPokemon.length - overlap.length >= 1) {
// is this working? // is this working?
this.primaryPokemon = overlap[Utils.randSeedInt(overlap.length, 0)]; this.primaryPokemon = overlap[randSeedInt(overlap.length, 0)];
this.secondaryPokemon = this.secondaryPokemon.filter(supp => supp !== this.primaryPokemon); this.secondaryPokemon = this.secondaryPokemon.filter(supp => supp !== this.primaryPokemon);
return true; return true;
} }
@ -394,7 +394,7 @@ export default class MysteryEncounter implements IMysteryEncounter {
return false; return false;
} }
// this means we CAN have the same pokemon be a primary and secondary pokemon, so just choose any qualifying one randomly. // this means we CAN have the same pokemon be a primary and secondary pokemon, so just choose any qualifying one randomly.
this.primaryPokemon = qualified[Utils.randSeedInt(qualified.length, 0)]; this.primaryPokemon = qualified[randSeedInt(qualified.length, 0)];
return true; return true;
} }

View File

@ -30,8 +30,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 { Mode } from "#app/ui/ui"; import { Mode } from "#app/ui/ui";
import * as Utils from "#app/utils"; import { isNullOrUndefined, randSeedInt, randomString, randSeedItem } from "#app/utils";
import { isNullOrUndefined, randSeedInt, randSeedItem } from "#app/utils";
import type { BattlerTagType } from "#enums/battler-tag-type"; import type { BattlerTagType } from "#enums/battler-tag-type";
import { Biome } from "#enums/biome"; import { Biome } from "#enums/biome";
import type { TrainerType } from "#enums/trainer-type"; import type { TrainerType } from "#enums/trainer-type";
@ -168,7 +167,7 @@ export async function initBattleWithEnemyConfig(partyConfig: EnemyPartyConfig):
const doubleTrainer = trainerConfig.doubleOnly || (trainerConfig.hasDouble && !!partyConfig.doubleBattle); const doubleTrainer = trainerConfig.doubleOnly || (trainerConfig.hasDouble && !!partyConfig.doubleBattle);
doubleBattle = doubleTrainer; doubleBattle = doubleTrainer;
const trainerFemale = isNullOrUndefined(partyConfig.female) ? !!Utils.randSeedInt(2) : partyConfig.female; const trainerFemale = isNullOrUndefined(partyConfig.female) ? !!randSeedInt(2) : partyConfig.female;
const newTrainer = new Trainer( const newTrainer = new Trainer(
trainerConfig.trainerType, trainerConfig.trainerType,
doubleTrainer ? TrainerVariant.DOUBLE : trainerFemale ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT, doubleTrainer ? TrainerVariant.DOUBLE : trainerFemale ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT,
@ -286,7 +285,7 @@ export async function initBattleWithEnemyConfig(partyConfig: EnemyPartyConfig):
// Generate new id, reset status and HP in case using data source // Generate new id, reset status and HP in case using data source
if (config.dataSource) { if (config.dataSource) {
enemyPokemon.id = Utils.randSeedInt(4294967296); enemyPokemon.id = randSeedInt(4294967296);
} }
// Set form // Set form
@ -1115,7 +1114,7 @@ export function calculateMEAggregateStats(baseSpawnWeight: number) {
const validMEfloorsByBiome = new Map<string, number>(biomes.map(b => [b, 0])); const validMEfloorsByBiome = new Map<string, number>(biomes.map(b => [b, 0]));
let currentBiome = Biome.TOWN; let currentBiome = Biome.TOWN;
let currentArena = globalScene.newArena(currentBiome); let currentArena = globalScene.newArena(currentBiome);
globalScene.setSeed(Utils.randomString(24)); globalScene.setSeed(randomString(24));
globalScene.resetSeed(); globalScene.resetSeed();
for (let i = 10; i < 180; i++) { for (let i = 10; i < 180; i++) {
// Boss // Boss
@ -1130,16 +1129,16 @@ export function calculateMEAggregateStats(baseSpawnWeight: number) {
globalScene.executeWithSeedOffset(() => { globalScene.executeWithSeedOffset(() => {
biomes = (biomeLinks[currentBiome] as (Biome | [Biome, number])[]) biomes = (biomeLinks[currentBiome] as (Biome | [Biome, number])[])
.filter(b => { .filter(b => {
return !Array.isArray(b) || !Utils.randSeedInt(b[1]); return !Array.isArray(b) || !randSeedInt(b[1]);
}) })
.map(b => (!Array.isArray(b) ? b : b[0])); .map(b => (!Array.isArray(b) ? b : b[0]));
}, i * 100); }, i * 100);
if (biomes! && biomes.length > 0) { if (biomes! && biomes.length > 0) {
const specialBiomes = biomes.filter(b => alwaysPickTheseBiomes.includes(b)); const specialBiomes = biomes.filter(b => alwaysPickTheseBiomes.includes(b));
if (specialBiomes.length > 0) { if (specialBiomes.length > 0) {
currentBiome = specialBiomes[Utils.randSeedInt(specialBiomes.length)]; currentBiome = specialBiomes[randSeedInt(specialBiomes.length)];
} else { } else {
currentBiome = biomes[Utils.randSeedInt(biomes.length)]; currentBiome = biomes[randSeedInt(biomes.length)];
} }
} }
} else if (biomeLinks.hasOwnProperty(currentBiome)) { } else if (biomeLinks.hasOwnProperty(currentBiome)) {
@ -1167,7 +1166,7 @@ export function calculateMEAggregateStats(baseSpawnWeight: number) {
// Otherwise, roll encounter // Otherwise, roll encounter
const roll = Utils.randSeedInt(256); const roll = randSeedInt(256);
validMEfloorsByBiome.set(Biome[currentBiome], (validMEfloorsByBiome.get(Biome[currentBiome]) ?? 0) + 1); validMEfloorsByBiome.set(Biome[currentBiome], (validMEfloorsByBiome.get(Biome[currentBiome]) ?? 0) + 1);
// If total number of encounters is lower than expected for the run, slightly favor a new encounter // If total number of encounters is lower than expected for the run, slightly favor a new encounter
@ -1192,7 +1191,7 @@ export function calculateMEAggregateStats(baseSpawnWeight: number) {
tierWeights[1] = tierWeights[1] - 4 * numEncounters[1]; tierWeights[1] = tierWeights[1] - 4 * numEncounters[1];
const totalWeight = tierWeights.reduce((a, b) => a + b); const totalWeight = tierWeights.reduce((a, b) => a + b);
const tierValue = Utils.randSeedInt(totalWeight); const tierValue = randSeedInt(totalWeight);
const commonThreshold = totalWeight - tierWeights[0]; // 64 - 32 = 32 const commonThreshold = totalWeight - tierWeights[0]; // 64 - 32 = 32
const uncommonThreshold = totalWeight - tierWeights[0] - tierWeights[1]; // 64 - 32 - 16 = 16 const uncommonThreshold = totalWeight - tierWeights[0] - tierWeights[1]; // 64 - 32 - 16 = 16
const rareThreshold = totalWeight - tierWeights[0] - tierWeights[1] - tierWeights[2]; // 64 - 32 - 16 - 10 = 6 const rareThreshold = totalWeight - tierWeights[0] - tierWeights[1] - tierWeights[2]; // 64 - 32 - 16 - 10 = 6
@ -1281,7 +1280,7 @@ export function calculateRareSpawnAggregateStats(luckValue: number) {
const calculateNumRareEncounters = (): any[] => { const calculateNumRareEncounters = (): any[] => {
const bossEncountersByRarity = [0, 0, 0, 0]; const bossEncountersByRarity = [0, 0, 0, 0];
globalScene.setSeed(Utils.randomString(24)); globalScene.setSeed(randomString(24));
globalScene.resetSeed(); globalScene.resetSeed();
// There are 12 wild boss floors // There are 12 wild boss floors
for (let i = 0; i < 12; i++) { for (let i = 0; i < 12; i++) {
@ -1291,7 +1290,7 @@ export function calculateRareSpawnAggregateStats(luckValue: number) {
if (!Number.isNaN(luckValue)) { if (!Number.isNaN(luckValue)) {
luckModifier = luckValue * 0.5; luckModifier = luckValue * 0.5;
} }
const tierValue = Utils.randSeedInt(64 - luckModifier); const tierValue = randSeedInt(64 - luckModifier);
const tier = const tier =
tierValue >= 20 tierValue >= 20
? BiomePoolTier.BOSS ? BiomePoolTier.BOSS

View File

@ -1,4 +1,4 @@
import * as Utils from "../utils"; import { toReadableString } from "#app/utils";
import { TextStyle, getBBCodeFrag } from "../ui/text"; import { TextStyle, getBBCodeFrag } from "../ui/text";
import { Nature } from "#enums/nature"; import { Nature } from "#enums/nature";
import { UiTheme } from "#enums/ui-theme"; import { UiTheme } from "#enums/ui-theme";
@ -12,7 +12,7 @@ export function getNatureName(
ignoreBBCode = false, ignoreBBCode = false,
uiTheme: UiTheme = UiTheme.DEFAULT, uiTheme: UiTheme = UiTheme.DEFAULT,
): string { ): string {
let ret = Utils.toReadableString(Nature[nature]); let ret = toReadableString(Nature[nature]);
//Translating nature //Translating nature
if (i18next.exists(`nature:${ret}`)) { if (i18next.exists(`nature:${ret}`)) {
ret = i18next.t(`nature:${ret}` as any); ret = i18next.t(`nature:${ret}` as any);

View File

@ -8,7 +8,7 @@ import type { AnySound } from "#app/battle-scene";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import type { GameMode } from "#app/game-mode"; import type { GameMode } from "#app/game-mode";
import { DexAttr, type StarterMoveset } from "#app/system/game-data"; import { DexAttr, type StarterMoveset } from "#app/system/game-data";
import * as Utils from "#app/utils"; import { isNullOrUndefined, capitalizeString, randSeedInt, randSeedGauss, randSeedItem } from "#app/utils";
import { uncatchableSpecies } from "#app/data/balance/biomes"; import { uncatchableSpecies } from "#app/data/balance/biomes";
import { speciesEggMoves } from "#app/data/balance/egg-moves"; import { speciesEggMoves } from "#app/data/balance/egg-moves";
import { GrowthRate } from "#app/data/exp"; import { GrowthRate } from "#app/data/exp";
@ -290,7 +290,7 @@ export abstract class PokemonSpeciesForm {
* @returns The id of the ability * @returns The id of the ability
*/ */
getPassiveAbility(formIndex?: number): Abilities { getPassiveAbility(formIndex?: number): Abilities {
if (Utils.isNullOrUndefined(formIndex)) { if (isNullOrUndefined(formIndex)) {
formIndex = this.formIndex; formIndex = this.formIndex;
} }
let starterSpeciesId = this.speciesId; let starterSpeciesId = this.speciesId;
@ -626,7 +626,7 @@ export abstract class PokemonSpeciesForm {
const spritePath = this.getSpriteAtlasPath(female, formIndex, shiny, variant, back) const spritePath = this.getSpriteAtlasPath(female, formIndex, shiny, variant, back)
.replace("variant/", "") .replace("variant/", "")
.replace(/_[1-3]$/, ""); .replace(/_[1-3]$/, "");
if (!Utils.isNullOrUndefined(variant)) { if (!isNullOrUndefined(variant)) {
loadPokemonVariantAssets(spriteKey, spritePath, variant).then(() => resolve()); loadPokemonVariantAssets(spriteKey, spritePath, variant).then(() => resolve());
} }
}); });
@ -852,8 +852,8 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali
*/ */
getFormNameToDisplay(formIndex = 0, append = false): string { getFormNameToDisplay(formIndex = 0, append = false): string {
const formKey = this.forms?.[formIndex!]?.formKey; const formKey = this.forms?.[formIndex!]?.formKey;
const formText = Utils.capitalizeString(formKey, "-", false, false) || ""; const formText = capitalizeString(formKey, "-", false, false) || "";
const speciesName = Utils.capitalizeString(Species[this.speciesId], "_", true, false); const speciesName = capitalizeString(Species[this.speciesId], "_", true, false);
let ret = ""; let ret = "";
const region = this.getRegion(); const region = this.getRegion();
@ -884,7 +884,7 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali
if (i18next.exists(i18key)) { if (i18next.exists(i18key)) {
ret = i18next.t(i18key); ret = i18next.t(i18key);
} else { } else {
const rootSpeciesName = Utils.capitalizeString(Species[this.getRootSpeciesId()], "_", true, false); const rootSpeciesName = capitalizeString(Species[this.getRootSpeciesId()], "_", true, false);
const i18RootKey = `pokemonForm:${rootSpeciesName}${formText}`; const i18RootKey = `pokemonForm:${rootSpeciesName}${formText}`;
ret = i18next.exists(i18RootKey) ? i18next.t(i18RootKey) : formText; ret = i18next.exists(i18RootKey) ? i18next.t(i18RootKey) : formText;
} }
@ -1079,7 +1079,7 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali
return this.speciesId; return this.speciesId;
} }
const randValue = evolutionPool.size === 1 ? 0 : Utils.randSeedInt(totalWeight); const randValue = evolutionPool.size === 1 ? 0 : randSeedInt(totalWeight);
for (const weight of evolutionPool.keys()) { for (const weight of evolutionPool.keys()) {
if (randValue < weight) { if (randValue < weight) {
@ -1164,7 +1164,7 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali
Math.min( Math.min(
Math.max( Math.max(
evolution?.level! + evolution?.level! +
Math.round(Utils.randSeedGauss(0.5, 1 + levelDiff * 0.2) * Math.max(evolution?.wildDelay!, 0.5) * 5) - Math.round(randSeedGauss(0.5, 1 + levelDiff * 0.2) * Math.max(evolution?.wildDelay!, 0.5) * 5) -
1, 1,
2, 2,
evolution?.level!, evolution?.level!,
@ -1182,7 +1182,7 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali
Math.min( Math.min(
Math.max( Math.max(
lastPrevolutionLevel + lastPrevolutionLevel +
Math.round(Utils.randSeedGauss(0.5, 1 + levelDiff * 0.2) * Math.max(evolution?.wildDelay!, 0.5) * 5), Math.round(randSeedGauss(0.5, 1 + levelDiff * 0.2) * Math.max(evolution?.wildDelay!, 0.5) * 5),
lastPrevolutionLevel + 1, lastPrevolutionLevel + 1,
evolution?.level!, evolution?.level!,
), ),
@ -1367,7 +1367,7 @@ export function getPokerusStarters(): PokemonSpecies[] {
globalScene.executeWithSeedOffset( globalScene.executeWithSeedOffset(
() => { () => {
while (pokerusStarters.length < POKERUS_STARTER_COUNT) { while (pokerusStarters.length < POKERUS_STARTER_COUNT) {
const randomSpeciesId = Number.parseInt(Utils.randSeedItem(Object.keys(speciesStarterCosts)), 10); const randomSpeciesId = Number.parseInt(randSeedItem(Object.keys(speciesStarterCosts)), 10);
const species = getPokemonSpecies(randomSpeciesId); const species = getPokemonSpecies(randomSpeciesId);
if (!pokerusStarters.includes(species)) { if (!pokerusStarters.includes(species)) {
pokerusStarters.push(species); pokerusStarters.push(species);

View File

@ -1,12 +1,12 @@
import { TrainerType } from "#enums/trainer-type"; import { TrainerType } from "#enums/trainer-type";
import * as Utils from "../utils"; import { toReadableString } from "#app/utils";
class TrainerNameConfig { class TrainerNameConfig {
public urls: string[]; public urls: string[];
public femaleUrls: string[] | null; public femaleUrls: string[] | null;
constructor(type: TrainerType, ...urls: string[]) { constructor(type: TrainerType, ...urls: string[]) {
this.urls = urls.length ? urls : [Utils.toReadableString(TrainerType[type]).replace(/ /g, "_")]; this.urls = urls.length ? urls : [toReadableString(TrainerType[type]).replace(/ /g, "_")];
} }
hasGenderVariant(...femaleUrls: string[]): TrainerNameConfig { hasGenderVariant(...femaleUrls: string[]): TrainerNameConfig {

View File

@ -1,7 +1,7 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { modifierTypes } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type";
import { PokemonMove } from "#app/field/pokemon"; import { PokemonMove } from "#app/field/pokemon";
import * as Utils from "#app/utils"; import { toReadableString, isNullOrUndefined, randSeedItem, randSeedInt } from "#app/utils";
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";
@ -139,7 +139,7 @@ export class TrainerConfig {
constructor(trainerType: TrainerType, allowLegendaries?: boolean) { constructor(trainerType: TrainerType, allowLegendaries?: boolean) {
this.trainerType = trainerType; this.trainerType = trainerType;
this.trainerAI = new TrainerAI(); this.trainerAI = new TrainerAI();
this.name = Utils.toReadableString(TrainerType[this.getDerivedType()]); this.name = toReadableString(TrainerType[this.getDerivedType()]);
this.battleBgm = "battle_trainer"; this.battleBgm = "battle_trainer";
this.mixedBattleBgm = "battle_trainer"; this.mixedBattleBgm = "battle_trainer";
this.victoryBgm = "victory_trainer"; this.victoryBgm = "victory_trainer";
@ -482,10 +482,10 @@ export class TrainerConfig {
.fill(null) .fill(null)
.map((_, i) => i) .map((_, i) => i)
.filter(i => shedinjaCanTera || party[i].species.speciesId !== Species.SHEDINJA); // Shedinja can only Tera on Bug specialty type (or no specialty type) .filter(i => shedinjaCanTera || party[i].species.speciesId !== Species.SHEDINJA); // Shedinja can only Tera on Bug specialty type (or no specialty type)
const setPartySlot = !Utils.isNullOrUndefined(slot) ? Phaser.Math.Wrap(slot, 0, party.length) : -1; // If we have a tera slot defined, wrap it to party size. const setPartySlot = !isNullOrUndefined(slot) ? Phaser.Math.Wrap(slot, 0, party.length) : -1; // If we have a tera slot defined, wrap it to party size.
for (let t = 0; t < Math.min(count(), party.length); t++) { for (let t = 0; t < Math.min(count(), party.length); t++) {
const randomIndex = const randomIndex =
partyMemberIndexes.indexOf(setPartySlot) > -1 ? setPartySlot : Utils.randSeedItem(partyMemberIndexes); partyMemberIndexes.indexOf(setPartySlot) > -1 ? setPartySlot : randSeedItem(partyMemberIndexes);
partyMemberIndexes.splice(partyMemberIndexes.indexOf(randomIndex), 1); partyMemberIndexes.splice(partyMemberIndexes.indexOf(randomIndex), 1);
if (this.hasSpecialtyType()) { if (this.hasSpecialtyType()) {
party[randomIndex].teraType = this.specialtyType; party[randomIndex].teraType = this.specialtyType;
@ -555,7 +555,7 @@ export class TrainerConfig {
initI18n(); initI18n();
} }
if (!Utils.isNullOrUndefined(specialtyType)) { if (!isNullOrUndefined(specialtyType)) {
this.setSpecialtyType(specialtyType); this.setSpecialtyType(specialtyType);
} }
@ -636,7 +636,7 @@ export class TrainerConfig {
} }
this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool)); this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool));
}); });
if (!Utils.isNullOrUndefined(specialtyType)) { if (!isNullOrUndefined(specialtyType)) {
this.setSpeciesFilter(p => p.isOfType(specialtyType)); this.setSpeciesFilter(p => p.isOfType(specialtyType));
this.setSpecialtyType(specialtyType); this.setSpecialtyType(specialtyType);
} }
@ -749,7 +749,7 @@ export class TrainerConfig {
}); });
// 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.
if (!Utils.isNullOrUndefined(specialtyType)) { if (!isNullOrUndefined(specialtyType)) {
this.setSpeciesFilter(p => p.isOfType(specialtyType) && p.baseTotal >= ELITE_FOUR_MINIMUM_BST); this.setSpeciesFilter(p => p.isOfType(specialtyType) && p.baseTotal >= ELITE_FOUR_MINIMUM_BST);
this.setSpecialtyType(specialtyType); this.setSpecialtyType(specialtyType);
} else { } else {
@ -927,7 +927,7 @@ export class TrainerConfig {
* @returns true if specialtyType is defined and not Type.UNKNOWN * @returns true if specialtyType is defined and not Type.UNKNOWN
*/ */
hasSpecialtyType(): boolean { hasSpecialtyType(): boolean {
return !Utils.isNullOrUndefined(this.specialtyType) && this.specialtyType !== PokemonType.UNKNOWN; return !isNullOrUndefined(this.specialtyType) && this.specialtyType !== PokemonType.UNKNOWN;
} }
/** /**
@ -1006,7 +1006,7 @@ export function getRandomPartyMemberFunc(
postProcess?: (enemyPokemon: EnemyPokemon) => void, postProcess?: (enemyPokemon: EnemyPokemon) => void,
) { ) {
return (level: number, strength: PartyMemberStrength) => { return (level: number, strength: PartyMemberStrength) => {
let species = Utils.randSeedItem(speciesPool); let species = randSeedItem(speciesPool);
if (!ignoreEvolution) { if (!ignoreEvolution) {
species = getPokemonSpecies(species).getTrainerSpeciesForLevel( species = getPokemonSpecies(species).getTrainerSpeciesForLevel(
level, level,
@ -3549,7 +3549,7 @@ export const trainerConfigs: TrainerConfigs = {
.setPartyMemberFunc( .setPartyMemberFunc(
5, 5,
getRandomPartyMemberFunc([Species.URSHIFU], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([Species.URSHIFU], TrainerSlot.TRAINER, true, p => {
p.formIndex = Utils.randSeedInt(2, 2); // Random G-Max Urshifu p.formIndex = randSeedInt(2, 2); // Random G-Max Urshifu
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.generateName(); p.generateName();
p.gender = Gender.MALE; p.gender = Gender.MALE;
@ -3659,10 +3659,10 @@ export const trainerConfigs: TrainerConfigs = {
.setPartyMemberFunc( .setPartyMemberFunc(
4, 4,
getRandomPartyMemberFunc([Species.OGERPON], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([Species.OGERPON], TrainerSlot.TRAINER, true, p => {
p.formIndex = Utils.randSeedInt(4); // Random Ogerpon Tera Mask p.formIndex = randSeedInt(4); // Random Ogerpon Tera Mask
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL; p.pokeball = PokeballType.ULTRA_BALL;
if (!p.moveset.some(move => !Utils.isNullOrUndefined(move) && move.moveId === Moves.IVY_CUDGEL)) { if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === Moves.IVY_CUDGEL)) {
// Check if Ivy Cudgel is in the moveset, if not, replace the first move with Ivy Cudgel. // Check if Ivy Cudgel is in the moveset, if not, replace the first move with Ivy Cudgel.
p.moveset[0] = new PokemonMove(Moves.IVY_CUDGEL); p.moveset[0] = new PokemonMove(Moves.IVY_CUDGEL);
} }
@ -4713,10 +4713,10 @@ export const trainerConfigs: TrainerConfigs = {
.setPartyMemberFunc( .setPartyMemberFunc(
2, 2,
getRandomPartyMemberFunc([Species.SILVALLY], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([Species.SILVALLY], TrainerSlot.TRAINER, true, p => {
p.formIndex = Utils.randSeedInt(18); // Random Silvally Form p.formIndex = randSeedInt(18); // Random Silvally Form
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ROGUE_BALL; p.pokeball = PokeballType.ROGUE_BALL;
if (!p.moveset.some(move => !Utils.isNullOrUndefined(move) && move.moveId === Moves.MULTI_ATTACK)) { if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === Moves.MULTI_ATTACK)) {
// Check if Multi Attack is in the moveset, if not, replace the first move with Multi Attack. // Check if Multi Attack is in the moveset, if not, replace the first move with Multi Attack.
p.moveset[0] = new PokemonMove(Moves.MULTI_ATTACK); p.moveset[0] = new PokemonMove(Moves.MULTI_ATTACK);
} }
@ -4833,8 +4833,8 @@ export const trainerConfigs: TrainerConfigs = {
p.setBoss(true, 2); p.setBoss(true, 2);
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL; p.pokeball = PokeballType.ULTRA_BALL;
p.formIndex = Utils.randSeedInt(4, 1); // Shock, Burn, Chill, or Douse Drive p.formIndex = randSeedInt(4, 1); // Shock, Burn, Chill, or Douse Drive
if (!p.moveset.some(move => !Utils.isNullOrUndefined(move) && move.moveId === Moves.TECHNO_BLAST)) { if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === Moves.TECHNO_BLAST)) {
// Check if Techno Blast is in the moveset, if not, replace the first move with Techno Blast. // Check if Techno Blast is in the moveset, if not, replace the first move with Techno Blast.
p.moveset[2] = new PokemonMove(Moves.TECHNO_BLAST); p.moveset[2] = new PokemonMove(Moves.TECHNO_BLAST);
} }
@ -5006,7 +5006,7 @@ export const trainerConfigs: TrainerConfigs = {
1, 1,
getRandomPartyMemberFunc([Species.ROTOM], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([Species.ROTOM], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.formIndex = Utils.randSeedInt(5, 1); // Heat, Wash, Frost, Fan, or Mow p.formIndex = randSeedInt(5, 1); // Heat, Wash, Frost, Fan, or Mow
}), }),
) )
.setPartyMemberFunc( .setPartyMemberFunc(
@ -5019,7 +5019,7 @@ export const trainerConfigs: TrainerConfigs = {
.setPartyMemberFunc( .setPartyMemberFunc(
3, 3,
getRandomPartyMemberFunc([Species.REVAVROOM], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([Species.REVAVROOM], TrainerSlot.TRAINER, true, p => {
p.formIndex = Utils.randSeedInt(5, 1); // Random Starmobile form p.formIndex = randSeedInt(5, 1); // Random Starmobile form
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ROGUE_BALL; p.pokeball = PokeballType.ROGUE_BALL;
}), }),

View File

@ -5,7 +5,7 @@ import type Pokemon from "../field/pokemon";
import { PokemonType } from "#enums/pokemon-type"; import { PokemonType } from "#enums/pokemon-type";
import type Move from "./moves/move"; import type Move from "./moves/move";
import { AttackMove } from "./moves/move"; import { AttackMove } from "./moves/move";
import * as Utils from "../utils"; import { randSeedInt } from "#app/utils";
import { SuppressWeatherEffectAbAttr } from "./ability"; import { SuppressWeatherEffectAbAttr } from "./ability";
import { TerrainType, getTerrainName } from "./terrain"; import { TerrainType, getTerrainName } from "./terrain";
import i18next from "i18next"; import i18next from "i18next";
@ -416,7 +416,7 @@ export function getRandomWeatherType(arena: Arena): WeatherType {
totalWeight += w.weight; totalWeight += w.weight;
} }
const rand = Utils.randSeedInt(totalWeight); const rand = randSeedInt(totalWeight);
let w = 0; let w = 0;
for (const weather of weatherPool) { for (const weather of weatherPool) {
w += weather.weight; w += weather.weight;

View File

@ -1,8 +1,7 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import type { BiomeTierTrainerPools, PokemonPools } from "#app/data/balance/biomes"; import type { BiomeTierTrainerPools, PokemonPools } from "#app/data/balance/biomes";
import { biomePokemonPools, BiomePoolTier, biomeTrainerPools } from "#app/data/balance/biomes"; import { biomePokemonPools, BiomePoolTier, biomeTrainerPools } from "#app/data/balance/biomes";
import type { Constructor } from "#app/utils"; import { randSeedInt, NumberHolder, isNullOrUndefined, type Constructor } from "#app/utils";
import * as Utils from "#app/utils";
import type PokemonSpecies from "#app/data/pokemon-species"; import type PokemonSpecies from "#app/data/pokemon-species";
import { getPokemonSpecies } from "#app/data/pokemon-species"; import { getPokemonSpecies } from "#app/data/pokemon-species";
import { import {
@ -124,7 +123,7 @@ export class Arena {
if (typeof luckValue !== "undefined") { if (typeof luckValue !== "undefined") {
luckModifier = luckValue * (isBossSpecies ? 0.5 : 2); luckModifier = luckValue * (isBossSpecies ? 0.5 : 2);
} }
const tierValue = Utils.randSeedInt(randVal - luckModifier); const tierValue = randSeedInt(randVal - luckModifier);
let tier = !isBossSpecies let tier = !isBossSpecies
? tierValue >= 156 ? tierValue >= 156
? BiomePoolTier.COMMON ? BiomePoolTier.COMMON
@ -153,7 +152,7 @@ export class Arena {
if (!tierPool.length) { if (!tierPool.length) {
ret = globalScene.randomSpecies(waveIndex, level); ret = globalScene.randomSpecies(waveIndex, level);
} else { } else {
const entry = tierPool[Utils.randSeedInt(tierPool.length)]; const entry = tierPool[randSeedInt(tierPool.length)];
let species: Species; let species: Species;
if (typeof entry === "number") { if (typeof entry === "number") {
species = entry as Species; species = entry as Species;
@ -164,7 +163,7 @@ export class Arena {
if (level >= levelThreshold) { if (level >= levelThreshold) {
const speciesIds = entry[levelThreshold]; const speciesIds = entry[levelThreshold];
if (speciesIds.length > 1) { if (speciesIds.length > 1) {
species = speciesIds[Utils.randSeedInt(speciesIds.length)]; species = speciesIds[randSeedInt(speciesIds.length)];
} else { } else {
species = speciesIds[0]; species = speciesIds[0];
} }
@ -211,7 +210,7 @@ export class Arena {
!!this.trainerPool[BiomePoolTier.BOSS].length && !!this.trainerPool[BiomePoolTier.BOSS].length &&
(globalScene.gameMode.isTrainerBoss(waveIndex, this.biomeType, globalScene.offsetGym) || isBoss); (globalScene.gameMode.isTrainerBoss(waveIndex, this.biomeType, globalScene.offsetGym) || isBoss);
console.log(isBoss, this.trainerPool); console.log(isBoss, this.trainerPool);
const tierValue = Utils.randSeedInt(!isTrainerBoss ? 512 : 64); const tierValue = randSeedInt(!isTrainerBoss ? 512 : 64);
let tier = !isTrainerBoss let tier = !isTrainerBoss
? tierValue >= 156 ? tierValue >= 156
? BiomePoolTier.COMMON ? BiomePoolTier.COMMON
@ -235,7 +234,7 @@ export class Arena {
tier--; tier--;
} }
const tierPool = this.trainerPool[tier] || []; const tierPool = this.trainerPool[tier] || [];
return !tierPool.length ? TrainerType.BREEDER : tierPool[Utils.randSeedInt(tierPool.length)]; return !tierPool.length ? TrainerType.BREEDER : tierPool[randSeedInt(tierPool.length)];
} }
getSpeciesFormIndex(species: PokemonSpecies): number { getSpeciesFormIndex(species: PokemonSpecies): number {
@ -336,9 +335,9 @@ export class Arena {
return false; return false;
} }
const weatherDuration = new Utils.NumberHolder(0); const weatherDuration = new NumberHolder(0);
if (!Utils.isNullOrUndefined(user)) { if (!isNullOrUndefined(user)) {
weatherDuration.value = 5; weatherDuration.value = 5;
globalScene.applyModifier(FieldEffectModifier, user.isPlayer(), user, weatherDuration); globalScene.applyModifier(FieldEffectModifier, user.isPlayer(), user, weatherDuration);
} }
@ -417,9 +416,9 @@ export class Arena {
const oldTerrainType = this.terrain?.terrainType || TerrainType.NONE; const oldTerrainType = this.terrain?.terrainType || TerrainType.NONE;
const terrainDuration = new Utils.NumberHolder(0); const terrainDuration = new NumberHolder(0);
if (!Utils.isNullOrUndefined(user)) { if (!isNullOrUndefined(user)) {
terrainDuration.value = 5; terrainDuration.value = 5;
globalScene.applyModifier(FieldEffectModifier, user.isPlayer(), user, terrainDuration); globalScene.applyModifier(FieldEffectModifier, user.isPlayer(), user, terrainDuration);
} }
@ -1013,7 +1012,7 @@ export class ArenaBase extends Phaser.GameObjects.Container {
if (!this.player) { if (!this.player) {
globalScene.executeWithSeedOffset( globalScene.executeWithSeedOffset(
() => { () => {
this.propValue = propValue === undefined ? (hasProps ? Utils.randSeedInt(8) : 0) : propValue; this.propValue = propValue === undefined ? (hasProps ? randSeedInt(8) : 0) : propValue;
this.props.forEach((prop, p) => { this.props.forEach((prop, p) => {
const propKey = `${biomeKey}_b${hasProps ? `_${p + 1}` : ""}`; const propKey = `${biomeKey}_b${hasProps ? `_${p + 1}` : ""}`;
prop.setTexture(propKey); prop.setTexture(propKey);

View File

@ -2,7 +2,7 @@ import { TextStyle, addTextObject } from "../ui/text";
import type { DamageResult } from "./pokemon"; import type { DamageResult } from "./pokemon";
import type Pokemon from "./pokemon"; import type Pokemon from "./pokemon";
import { HitResult } from "./pokemon"; import { HitResult } from "./pokemon";
import * as Utils from "../utils"; import { formatStat, fixedInt } from "#app/utils";
import type { BattlerIndex } from "../battle"; import type { BattlerIndex } from "../battle";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
@ -30,7 +30,7 @@ export default class DamageNumberHandler {
const damageNumber = addTextObject( const damageNumber = addTextObject(
target.x, target.x,
-(globalScene.game.canvas.height / 6) + target.y - target.getSprite().height / 2, -(globalScene.game.canvas.height / 6) + target.y - target.getSprite().height / 2,
Utils.formatStat(amount, true), formatStat(amount, true),
TextStyle.SUMMARY, TextStyle.SUMMARY,
); );
damageNumber.setName("text-damage-number"); damageNumber.setName("text-damage-number");
@ -86,14 +86,14 @@ export default class DamageNumberHandler {
if (globalScene.damageNumbersMode === 1) { if (globalScene.damageNumbersMode === 1) {
globalScene.tweens.add({ globalScene.tweens.add({
targets: damageNumber, targets: damageNumber,
duration: Utils.fixedInt(750), duration: fixedInt(750),
alpha: 1, alpha: 1,
y: "-=32", y: "-=32",
}); });
globalScene.tweens.add({ globalScene.tweens.add({
delay: 375, delay: 375,
targets: damageNumber, targets: damageNumber,
duration: Utils.fixedInt(625), duration: fixedInt(625),
alpha: 0, alpha: 0,
ease: "Sine.easeIn", ease: "Sine.easeIn",
onComplete: () => { onComplete: () => {
@ -110,7 +110,7 @@ export default class DamageNumberHandler {
targets: damageNumber, targets: damageNumber,
tweens: [ tweens: [
{ {
duration: Utils.fixedInt(250), duration: fixedInt(250),
alpha: 1, alpha: 1,
scaleX: 0.75 * baseScale, scaleX: 0.75 * baseScale,
scaleY: 1.25 * baseScale, scaleY: 1.25 * baseScale,
@ -118,7 +118,7 @@ export default class DamageNumberHandler {
ease: "Cubic.easeOut", ease: "Cubic.easeOut",
}, },
{ {
duration: Utils.fixedInt(175), duration: fixedInt(175),
alpha: 1, alpha: 1,
scaleX: 0.875 * baseScale, scaleX: 0.875 * baseScale,
scaleY: 1.125 * baseScale, scaleY: 1.125 * baseScale,
@ -126,59 +126,59 @@ export default class DamageNumberHandler {
ease: "Cubic.easeIn", ease: "Cubic.easeIn",
}, },
{ {
duration: Utils.fixedInt(100), duration: fixedInt(100),
scaleX: 1.25 * baseScale, scaleX: 1.25 * baseScale,
scaleY: 0.75 * baseScale, scaleY: 0.75 * baseScale,
ease: "Cubic.easeOut", ease: "Cubic.easeOut",
}, },
{ {
duration: Utils.fixedInt(175), duration: fixedInt(175),
scaleX: 0.875 * baseScale, scaleX: 0.875 * baseScale,
scaleY: 1.125 * baseScale, scaleY: 1.125 * baseScale,
y: "-=8", y: "-=8",
ease: "Cubic.easeOut", ease: "Cubic.easeOut",
}, },
{ {
duration: Utils.fixedInt(50), duration: fixedInt(50),
scaleX: 0.925 * baseScale, scaleX: 0.925 * baseScale,
scaleY: 1.075 * baseScale, scaleY: 1.075 * baseScale,
y: "+=8", y: "+=8",
ease: "Cubic.easeIn", ease: "Cubic.easeIn",
}, },
{ {
duration: Utils.fixedInt(100), duration: fixedInt(100),
scaleX: 1.125 * baseScale, scaleX: 1.125 * baseScale,
scaleY: 0.875 * baseScale, scaleY: 0.875 * baseScale,
ease: "Cubic.easeOut", ease: "Cubic.easeOut",
}, },
{ {
duration: Utils.fixedInt(175), duration: fixedInt(175),
scaleX: 0.925 * baseScale, scaleX: 0.925 * baseScale,
scaleY: 1.075 * baseScale, scaleY: 1.075 * baseScale,
y: "-=4", y: "-=4",
ease: "Cubic.easeOut", ease: "Cubic.easeOut",
}, },
{ {
duration: Utils.fixedInt(50), duration: fixedInt(50),
scaleX: 0.975 * baseScale, scaleX: 0.975 * baseScale,
scaleY: 1.025 * baseScale, scaleY: 1.025 * baseScale,
y: "+=4", y: "+=4",
ease: "Cubic.easeIn", ease: "Cubic.easeIn",
}, },
{ {
duration: Utils.fixedInt(100), duration: fixedInt(100),
scaleX: 1.075 * baseScale, scaleX: 1.075 * baseScale,
scaleY: 0.925 * baseScale, scaleY: 0.925 * baseScale,
ease: "Cubic.easeOut", ease: "Cubic.easeOut",
}, },
{ {
duration: Utils.fixedInt(25), duration: fixedInt(25),
scaleX: baseScale, scaleX: baseScale,
scaleY: baseScale, scaleY: baseScale,
ease: "Cubic.easeOut", ease: "Cubic.easeOut",
}, },
{ {
delay: Utils.fixedInt(500), delay: fixedInt(500),
alpha: 0, alpha: 0,
onComplete: () => { onComplete: () => {
this.damageNumbers this.damageNumbers

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 * as Utils from "../utils"; import { fixedInt, randInt } from "#app/utils";
export default class PokemonSpriteSparkleHandler { export default class PokemonSpriteSparkleHandler {
private sprites: Set<Phaser.GameObjects.Sprite>; private sprites: Set<Phaser.GameObjects.Sprite>;
@ -9,7 +9,7 @@ export default class PokemonSpriteSparkleHandler {
this.sprites = new Set(); this.sprites = new Set();
globalScene.tweens.addCounter({ globalScene.tweens.addCounter({
duration: Utils.fixedInt(200), duration: fixedInt(200),
from: 0, from: 0,
to: 1, to: 1,
yoyo: true, yoyo: true,
@ -36,7 +36,7 @@ export default class PokemonSpriteSparkleHandler {
const parent = (pokemon || s).parentContainer; const parent = (pokemon || s).parentContainer;
const texture = s.texture; const texture = s.texture;
const [width, height] = [texture.source[0].width, texture.source[0].height]; const [width, height] = [texture.source[0].width, texture.source[0].height];
const [pixelX, pixelY] = [Utils.randInt(width), Utils.randInt(height)]; const [pixelX, pixelY] = [randInt(width), randInt(height)];
const ratioX = s.width / width; const ratioX = s.width / width;
const ratioY = s.height / height; const ratioY = s.height / height;
const pixel = texture.manager.getPixel(pixelX, pixelY, texture.key, "__BASE"); const pixel = texture.manager.getPixel(pixelX, pixelY, texture.key, "__BASE");
@ -51,7 +51,7 @@ export default class PokemonSpriteSparkleHandler {
sparkle.setName("sprite-tera-sparkle"); sparkle.setName("sprite-tera-sparkle");
sparkle.play("tera_sparkle"); sparkle.play("tera_sparkle");
parent.add(sparkle); parent.add(sparkle);
s.scene.time.delayedCall(Utils.fixedInt(Math.floor((1000 / 12) * 13)), () => sparkle.destroy()); s.scene.time.delayedCall(fixedInt(Math.floor((1000 / 12) * 13)), () => sparkle.destroy());
} }
} }
} }

View File

@ -2,7 +2,7 @@ import Phaser from "phaser";
import type { AnySound } from "#app/battle-scene"; import type { AnySound } from "#app/battle-scene";
import type BattleScene from "#app/battle-scene"; import type BattleScene from "#app/battle-scene";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import type { Variant, VariantSet } from "#app/sprites/variant"; import type { Variant } from "#app/sprites/variant";
import { populateVariantColors, variantColorCache } from "#app/sprites/variant"; import { populateVariantColors, variantColorCache } from "#app/sprites/variant";
import { variantData } from "#app/sprites/variant"; import { variantData } from "#app/sprites/variant";
import BattleInfo, { import BattleInfo, {
@ -55,9 +55,7 @@ import {
getStarterValueFriendshipCap, getStarterValueFriendshipCap,
speciesStarterCosts, speciesStarterCosts,
} from "#app/data/balance/starters"; } from "#app/data/balance/starters";
import type { Constructor } from "#app/utils"; import { NumberHolder, randSeedInt, getIvsFromId, BooleanHolder, randSeedItem, isNullOrUndefined, getEnumValues, toDmgValue, fixedInt, rgbaToInt, rgbHexToRgba, rgbToHsv, deltaRgb, isBetween, type nil, type Constructor } from "#app/utils";
import { isNullOrUndefined, randSeedInt, type nil } from "#app/utils";
import * as Utils from "#app/utils";
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";
import { PokemonType } from "#enums/pokemon-type"; import { PokemonType } from "#enums/pokemon-type";
@ -96,7 +94,6 @@ import {
} from "#app/modifier/modifier"; } from "#app/modifier/modifier";
import { PokeballType } from "#enums/pokeball"; import { PokeballType } from "#enums/pokeball";
import { Gender } from "#app/data/gender"; import { Gender } from "#app/data/gender";
import { initMoveAnim, loadMoveAnimAssets } from "#app/data/battle-anims";
import { Status, getRandomStatus } from "#app/data/status-effect"; import { Status, getRandomStatus } from "#app/data/status-effect";
import type { import type {
SpeciesFormEvolution, SpeciesFormEvolution,
@ -176,10 +173,7 @@ import {
MoveTypeChangeAbAttr, MoveTypeChangeAbAttr,
FullHpResistTypeAbAttr, FullHpResistTypeAbAttr,
applyCheckTrappedAbAttrs, applyCheckTrappedAbAttrs,
CheckTrappedAbAttr, CheckTrappedAbAttr, InfiltratorAbAttr,
PostSetStatusAbAttr,
applyPostSetStatusAbAttrs,
InfiltratorAbAttr,
AlliedFieldDamageReductionAbAttr, AlliedFieldDamageReductionAbAttr,
PostDamageAbAttr, PostDamageAbAttr,
applyPostDamageAbAttrs, applyPostDamageAbAttrs,
@ -193,7 +187,7 @@ import {
PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr, PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr,
applyAllyStatMultiplierAbAttrs, applyAllyStatMultiplierAbAttrs,
AllyStatMultiplierAbAttr, AllyStatMultiplierAbAttr,
MoveAbilityBypassAbAttr, MoveAbilityBypassAbAttr
} from "#app/data/ability"; } from "#app/data/ability";
import type PokemonData from "#app/system/pokemon-data"; import type PokemonData from "#app/system/pokemon-data";
import { BattlerIndex } from "#app/battle"; import { BattlerIndex } from "#app/battle";
@ -220,8 +214,7 @@ import {
SpeciesFormChangeActiveTrigger, SpeciesFormChangeActiveTrigger,
SpeciesFormChangeLapseTeraTrigger, SpeciesFormChangeLapseTeraTrigger,
SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangeMoveLearnedTrigger,
SpeciesFormChangePostMoveTrigger, SpeciesFormChangePostMoveTrigger
SpeciesFormChangeStatusEffectTrigger,
} from "#app/data/pokemon-forms"; } from "#app/data/pokemon-forms";
import { TerrainType } from "#app/data/terrain"; import { TerrainType } from "#app/data/terrain";
import type { TrainerSlot } from "#enums/trainer-slot"; import type { TrainerSlot } from "#enums/trainer-slot";
@ -263,7 +256,6 @@ import { Nature } from "#enums/nature";
import { StatusEffect } from "#enums/status-effect"; import { StatusEffect } from "#enums/status-effect";
import { doShinySparkleAnim } from "#app/field/anims"; import { doShinySparkleAnim } from "#app/field/anims";
import { MoveFlags } from "#enums/MoveFlags"; import { MoveFlags } from "#enums/MoveFlags";
import { hasExpSprite } from "#app/sprites/sprite-utils";
import { timedEventManager } from "#app/global-event-manager"; import { timedEventManager } from "#app/global-event-manager";
import { loadMoveAnimations } from "#app/sprites/pokemon-asset-loader"; import { loadMoveAnimations } from "#app/sprites/pokemon-asset-loader";
import { ResetStatusPhase } from "#app/phases/reset-status-phase"; import { ResetStatusPhase } from "#app/phases/reset-status-phase";
@ -369,7 +361,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
throw `Cannot create a player Pokemon for species '${species.getName(formIndex)}'`; throw `Cannot create a player Pokemon for species '${species.getName(formIndex)}'`;
} }
const hiddenAbilityChance = new Utils.NumberHolder( const hiddenAbilityChance = new NumberHolder(
BASE_HIDDEN_ABILITY_CHANCE, BASE_HIDDEN_ABILITY_CHANCE,
); );
if (!this.hasTrainer()) { if (!this.hasTrainer()) {
@ -390,8 +382,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.abilityIndex = abilityIndex; // Use the provided ability index if it is defined this.abilityIndex = abilityIndex; // Use the provided ability index if it is defined
} else { } else {
// If abilityIndex is not provided, determine it based on species and hidden ability // If abilityIndex is not provided, determine it based on species and hidden ability
const hasHiddenAbility = !Utils.randSeedInt(hiddenAbilityChance.value); const hasHiddenAbility = !randSeedInt(hiddenAbilityChance.value);
const randAbilityIndex = Utils.randSeedInt(2); const randAbilityIndex = randSeedInt(2);
if (species.abilityHidden && hasHiddenAbility) { if (species.abilityHidden && hasHiddenAbility) {
// If the species has a hidden ability and the hidden ability is present // If the species has a hidden ability and the hidden ability is present
this.abilityIndex = 2; this.abilityIndex = 2;
@ -467,8 +459,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.isTerastallized = dataSource.isTerastallized; this.isTerastallized = dataSource.isTerastallized;
this.stellarTypesBoosted = dataSource.stellarTypesBoosted ?? []; this.stellarTypesBoosted = dataSource.stellarTypesBoosted ?? [];
} else { } else {
this.id = Utils.randSeedInt(4294967296); this.id = randSeedInt(4294967296);
this.ivs = ivs || Utils.getIvsFromId(this.id); this.ivs = ivs || getIvsFromId(this.id);
if (this.gender === undefined) { if (this.gender === undefined) {
this.generateGender(); this.generateGender();
@ -511,7 +503,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.pokerus = false; this.pokerus = false;
if (level > 1) { if (level > 1) {
const fused = new Utils.BooleanHolder( const fused = new BooleanHolder(
globalScene.gameMode.isSplicedOnly, globalScene.gameMode.isSplicedOnly,
); );
if (!fused.value && !this.isPlayer() && !this.hasTrainer()) { if (!fused.value && !this.isPlayer() && !this.hasTrainer()) {
@ -528,7 +520,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
(this.fusionShiny ? this.fusionVariant + 1 : 0); (this.fusionShiny ? this.fusionVariant + 1 : 0);
this.fusionLuck = this.luck; this.fusionLuck = this.luck;
this.teraType = Utils.randSeedItem(this.getTypes(false, false, true)); this.teraType = randSeedItem(this.getTypes(false, false, true));
this.isTerastallized = false; this.isTerastallized = false;
this.stellarTypesBoosted = []; this.stellarTypesBoosted = [];
} }
@ -636,7 +628,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
* @returns {boolean} `true` if pokemon is allowed in battle * @returns {boolean} `true` if pokemon is allowed in battle
*/ */
public isAllowedInChallenge(): boolean { public isAllowedInChallenge(): boolean {
const challengeAllowed = new Utils.BooleanHolder(true); const challengeAllowed = new BooleanHolder(true);
applyChallenges( applyChallenges(
ChallengeType.POKEMON_IN_BATTLE, ChallengeType.POKEMON_IN_BATTLE,
this, this,
@ -1315,7 +1307,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
* @returns the final critical-hit stage value * @returns the final critical-hit stage value
*/ */
getCritStage(source: Pokemon, move: Move): number { getCritStage(source: Pokemon, move: Move): number {
const critStage = new Utils.NumberHolder(0); const critStage = new NumberHolder(0);
applyMoveAttrs(HighCritAttr, source, this, move, critStage); applyMoveAttrs(HighCritAttr, source, this, move, critStage);
globalScene.applyModifiers( globalScene.applyModifiers(
CritBoosterModifier, CritBoosterModifier,
@ -1370,7 +1362,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
simulated = true, simulated = true,
ignoreHeldItems = false, ignoreHeldItems = false,
): number { ): number {
const statValue = new Utils.NumberHolder(this.getStat(stat, false)); const statValue = new NumberHolder(this.getStat(stat, false));
if (!ignoreHeldItems) { if (!ignoreHeldItems) {
globalScene.applyModifiers( globalScene.applyModifiers(
StatBoosterModifier, StatBoosterModifier,
@ -1382,7 +1374,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
// The Ruin abilities here are never ignored, but they reveal themselves on summon anyway // The Ruin abilities here are never ignored, but they reveal themselves on summon anyway
const fieldApplied = new Utils.BooleanHolder(false); const fieldApplied = new BooleanHolder(false);
for (const pokemon of globalScene.getField(true)) { for (const pokemon of globalScene.getField(true)) {
applyFieldStatMultiplierAbAttrs( applyFieldStatMultiplierAbAttrs(
FieldMultiplyStatAbAttr, FieldMultiplyStatAbAttr,
@ -1408,7 +1400,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
const ally = this.getAlly(); const ally = this.getAlly();
if (!Utils.isNullOrUndefined(ally)) { if (!isNullOrUndefined(ally)) {
applyAllyStatMultiplierAbAttrs(AllyStatMultiplierAbAttr, ally, stat, statValue, simulated, this, move?.hasFlag(MoveFlags.IGNORE_ABILITIES) || ignoreAllyAbility); applyAllyStatMultiplierAbAttrs(AllyStatMultiplierAbAttr, ally, stat, statValue, simulated, this, move?.hasFlag(MoveFlags.IGNORE_ABILITIES) || ignoreAllyAbility);
} }
@ -1495,7 +1487,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const baseStats = this.calculateBaseStats(); const baseStats = this.calculateBaseStats();
// Using base stats, calculate and store stats one by one // Using base stats, calculate and store stats one by one
for (const s of PERMANENT_STATS) { for (const s of PERMANENT_STATS) {
const statHolder = new Utils.NumberHolder( const statHolder = new NumberHolder(
Math.floor((2 * baseStats[s] + this.ivs[s]) * this.level * 0.01), Math.floor((2 * baseStats[s] + this.ivs[s]) * this.level * 0.01),
); );
if (s === Stat.HP) { if (s === Stat.HP) {
@ -1520,7 +1512,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
} else { } else {
statHolder.value += 5; statHolder.value += 5;
const natureStatMultiplier = new Utils.NumberHolder( const natureStatMultiplier = new NumberHolder(
getNatureStatMultiplier(this.getNature(), s), getNatureStatMultiplier(this.getNature(), s),
); );
globalScene.applyModifier( globalScene.applyModifier(
@ -1622,9 +1614,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
generateNature(naturePool?: Nature[]): void { generateNature(naturePool?: Nature[]): void {
if (naturePool === undefined) { if (naturePool === undefined) {
naturePool = Utils.getEnumValues(Nature); naturePool = getEnumValues(Nature);
} }
const nature = naturePool[Utils.randSeedInt(naturePool.length)]; const nature = naturePool[randSeedInt(naturePool.length)];
this.setNature(nature); this.setNature(nature);
} }
@ -1708,7 +1700,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
* @returns `true` if the pokemon is the species or is fused with it, `false` otherwise * @returns `true` if the pokemon is the species or is fused with it, `false` otherwise
*/ */
hasSpecies(species: Species, formKey?: string): boolean { hasSpecies(species: Species, formKey?: string): boolean {
if (Utils.isNullOrUndefined(formKey)) { if (isNullOrUndefined(formKey)) {
return ( return (
this.species.speciesId === species || this.species.speciesId === species ||
this.fusionSpecies?.speciesId === species this.fusionSpecies?.speciesId === species
@ -1870,7 +1862,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if ( if (
secondType === PokemonType.UNKNOWN && secondType === PokemonType.UNKNOWN &&
Utils.isNullOrUndefined(fusionType2) isNullOrUndefined(fusionType2)
) { ) {
// If second pokemon was monotype and shared its primary type // If second pokemon was monotype and shared its primary type
secondType = secondType =
@ -2240,11 +2232,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
public getWeight(): number { public getWeight(): number {
const autotomizedTag = this.getTag(AutotomizedTag); const autotomizedTag = this.getTag(AutotomizedTag);
let weightRemoved = 0; let weightRemoved = 0;
if (!Utils.isNullOrUndefined(autotomizedTag)) { if (!isNullOrUndefined(autotomizedTag)) {
weightRemoved = 100 * autotomizedTag!.autotomizeCount; weightRemoved = 100 * autotomizedTag!.autotomizeCount;
} }
const minWeight = 0.1; const minWeight = 0.1;
const weight = new Utils.NumberHolder(this.species.weight - weightRemoved); const weight = new NumberHolder(this.species.weight - weightRemoved);
// This will trigger the ability overlay so only call this function when necessary // This will trigger the ability overlay so only call this function when necessary
applyAbAttrs(WeightMultiplierAbAttr, this, null, false, weight); applyAbAttrs(WeightMultiplierAbAttr, this, null, false, weight);
@ -2315,7 +2307,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return false; return false;
} }
const trappedByAbility = new Utils.BooleanHolder(false); const trappedByAbility = new BooleanHolder(false);
/** /**
* Contains opposing Pokemon (Enemy/Player Pokemon) depending on perspective * Contains opposing Pokemon (Enemy/Player Pokemon) depending on perspective
* Afterwards, it filters out Pokemon that have been switched out of the field so trapped abilities/moves do not trigger * Afterwards, it filters out Pokemon that have been switched out of the field so trapped abilities/moves do not trigger
@ -2354,7 +2346,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
* @returns The {@linkcode PokemonType} of the move after attributes are applied * @returns The {@linkcode PokemonType} of the move after attributes are applied
*/ */
public getMoveType(move: Move, simulated = true): PokemonType { public getMoveType(move: Move, simulated = true): PokemonType {
const moveTypeHolder = new Utils.NumberHolder(move.type); const moveTypeHolder = new NumberHolder(move.type);
applyMoveAttrs(VariableMoveTypeAttr, this, null, move, moveTypeHolder); applyMoveAttrs(VariableMoveTypeAttr, this, null, move, moveTypeHolder);
applyPreAttackAbAttrs( applyPreAttackAbAttrs(
@ -2385,7 +2377,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
* @param move {@linkcode Move} The move being used by the attacking Pokémon. * @param move {@linkcode Move} The move being used by the attacking Pokémon.
* @param ignoreAbility Whether to ignore abilities that might affect type effectiveness or immunity (defaults to `false`). * @param ignoreAbility Whether to ignore abilities that might affect type effectiveness or immunity (defaults to `false`).
* @param simulated Whether to apply abilities via simulated calls (defaults to `true`) * @param simulated Whether to apply abilities via simulated calls (defaults to `true`)
* @param cancelled {@linkcode Utils.BooleanHolder} Stores whether the move was cancelled by a non-type-based immunity. * @param cancelled {@linkcode BooleanHolder} Stores whether the move was cancelled by a non-type-based immunity.
* Currently only used by {@linkcode Pokemon.apply} to determine whether a "No effect" message should be shown. * Currently only used by {@linkcode Pokemon.apply} to determine whether a "No effect" message should be shown.
* @returns The type damage multiplier, indicating the effectiveness of the move * @returns The type damage multiplier, indicating the effectiveness of the move
*/ */
@ -2394,9 +2386,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
move: Move, move: Move,
ignoreAbility = false, ignoreAbility = false,
simulated = true, simulated = true,
cancelled?: Utils.BooleanHolder, cancelled?: BooleanHolder,
): TypeDamageMultiplier { ): TypeDamageMultiplier {
if (!Utils.isNullOrUndefined(this.turnData?.moveEffectiveness)) { if (!isNullOrUndefined(this.turnData?.moveEffectiveness)) {
return this.turnData?.moveEffectiveness; return this.turnData?.moveEffectiveness;
} }
@ -2405,7 +2397,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
const moveType = source.getMoveType(move); const moveType = source.getMoveType(move);
const typeMultiplier = new Utils.NumberHolder( const typeMultiplier = new NumberHolder(
move.category !== MoveCategory.STATUS || move.category !== MoveCategory.STATUS ||
move.hasAttr(RespectAttackTypeImmunityAttr) move.hasAttr(RespectAttackTypeImmunityAttr)
? this.getAttackTypeEffectiveness( ? this.getAttackTypeEffectiveness(
@ -2435,7 +2427,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
typeMultiplier.value *= 2; typeMultiplier.value *= 2;
} }
const cancelledHolder = cancelled ?? new Utils.BooleanHolder(false); const cancelledHolder = cancelled ?? new BooleanHolder(false);
if (!ignoreAbility) { if (!ignoreAbility) {
applyPreDefendAbAttrs( applyPreDefendAbAttrs(
TypeImmunityAbAttr, TypeImmunityAbAttr,
@ -2549,7 +2541,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
let multiplier = types let multiplier = types
.map(defType => { .map(defType => {
const multiplier = new Utils.NumberHolder( const multiplier = new NumberHolder(
getTypeDamageMultiplier(moveType, defType), getTypeDamageMultiplier(moveType, defType),
); );
applyChallenges( applyChallenges(
@ -2567,7 +2559,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
); );
} }
if (source) { if (source) {
const ignoreImmunity = new Utils.BooleanHolder(false); const ignoreImmunity = new BooleanHolder(false);
if ( if (
source.isActive(true) && source.isActive(true) &&
source.hasAbilityWithAttr(IgnoreTypeImmunityAbAttr) source.hasAbilityWithAttr(IgnoreTypeImmunityAbAttr)
@ -2600,7 +2592,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}) })
.reduce((acc, cur) => acc * cur, 1) as TypeDamageMultiplier; .reduce((acc, cur) => acc * cur, 1) as TypeDamageMultiplier;
const typeMultiplierAgainstFlying = new Utils.NumberHolder( const typeMultiplierAgainstFlying = new NumberHolder(
getTypeDamageMultiplier(moveType, PokemonType.FLYING), getTypeDamageMultiplier(moveType, PokemonType.FLYING),
); );
applyChallenges( applyChallenges(
@ -2943,7 +2935,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const E = globalScene.gameData.trainerId ^ globalScene.gameData.secretId; const E = globalScene.gameData.trainerId ^ globalScene.gameData.secretId;
const F = rand1 ^ rand2; const F = rand1 ^ rand2;
const shinyThreshold = new Utils.NumberHolder(BASE_SHINY_CHANCE); const shinyThreshold = new NumberHolder(BASE_SHINY_CHANCE);
if (thresholdOverride === undefined) { if (thresholdOverride === undefined) {
if (timedEventManager.isEventActive()) { if (timedEventManager.isEventActive()) {
const tchance = timedEventManager.getClassicTrainerShinyChance(); const tchance = timedEventManager.getClassicTrainerShinyChance();
@ -2986,7 +2978,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
thresholdOverride?: number, thresholdOverride?: number,
applyModifiersToOverride?: boolean, applyModifiersToOverride?: boolean,
): boolean { ): boolean {
const shinyThreshold = new Utils.NumberHolder(BASE_SHINY_CHANCE); const shinyThreshold = new NumberHolder(BASE_SHINY_CHANCE);
if (thresholdOverride === undefined || applyModifiersToOverride) { if (thresholdOverride === undefined || applyModifiersToOverride) {
if (thresholdOverride !== undefined && applyModifiersToOverride) { if (thresholdOverride !== undefined && applyModifiersToOverride) {
shinyThreshold.value = thresholdOverride; shinyThreshold.value = thresholdOverride;
@ -3041,10 +3033,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
) { ) {
return 0; return 0;
} }
const rand = new Utils.NumberHolder(0); const rand = new NumberHolder(0);
globalScene.executeWithSeedOffset( globalScene.executeWithSeedOffset(
() => { () => {
rand.value = Utils.randSeedInt(10); rand.value = randSeedInt(10);
}, },
this.id, this.id,
globalScene.waveSeed, globalScene.waveSeed,
@ -3074,7 +3066,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (!this.species.abilityHidden) { if (!this.species.abilityHidden) {
return false; return false;
} }
const haThreshold = new Utils.NumberHolder(BASE_HIDDEN_ABILITY_CHANCE); const haThreshold = new NumberHolder(BASE_HIDDEN_ABILITY_CHANCE);
if (thresholdOverride === undefined || applyModifiersToOverride) { if (thresholdOverride === undefined || applyModifiersToOverride) {
if (thresholdOverride !== undefined && applyModifiersToOverride) { if (thresholdOverride !== undefined && applyModifiersToOverride) {
haThreshold.value = thresholdOverride; haThreshold.value = thresholdOverride;
@ -3098,7 +3090,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
public generateFusionSpecies(forStarter?: boolean): void { public generateFusionSpecies(forStarter?: boolean): void {
const hiddenAbilityChance = new Utils.NumberHolder( const hiddenAbilityChance = new NumberHolder(
BASE_HIDDEN_ABILITY_CHANCE, BASE_HIDDEN_ABILITY_CHANCE,
); );
if (!this.hasTrainer()) { if (!this.hasTrainer()) {
@ -3109,8 +3101,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
); );
} }
const hasHiddenAbility = !Utils.randSeedInt(hiddenAbilityChance.value); const hasHiddenAbility = !randSeedInt(hiddenAbilityChance.value);
const randAbilityIndex = Utils.randSeedInt(2); const randAbilityIndex = randSeedInt(2);
const filter = !forStarter const filter = !forStarter
? this.species.getCompatibleFusionSpeciesFilter() ? this.species.getCompatibleFusionSpeciesFilter()
@ -3427,7 +3419,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (stabMovePool.length) { if (stabMovePool.length) {
const totalWeight = stabMovePool.reduce((v, m) => v + m[1], 0); const totalWeight = stabMovePool.reduce((v, m) => v + m[1], 0);
let rand = Utils.randSeedInt(totalWeight); let rand = randSeedInt(totalWeight);
let index = 0; let index = 0;
while (rand > stabMovePool[index][1]) { while (rand > stabMovePool[index][1]) {
rand -= stabMovePool[index++][1]; rand -= stabMovePool[index++][1];
@ -3441,7 +3433,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
); );
if (attackMovePool.length) { if (attackMovePool.length) {
const totalWeight = attackMovePool.reduce((v, m) => v + m[1], 0); const totalWeight = attackMovePool.reduce((v, m) => v + m[1], 0);
let rand = Utils.randSeedInt(totalWeight); let rand = randSeedInt(totalWeight);
let index = 0; let index = 0;
while (rand > attackMovePool[index][1]) { while (rand > attackMovePool[index][1]) {
rand -= attackMovePool[index++][1]; rand -= attackMovePool[index++][1];
@ -3493,7 +3485,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
movePool = baseWeights.filter(m => !this.moveset.some(mo => m[0] === mo.moveId)); movePool = baseWeights.filter(m => !this.moveset.some(mo => m[0] === mo.moveId));
} }
const totalWeight = movePool.reduce((v, m) => v + m[1], 0); const totalWeight = movePool.reduce((v, m) => v + m[1], 0);
let rand = Utils.randSeedInt(totalWeight); let rand = randSeedInt(totalWeight);
let index = 0; let index = 0;
while (rand > movePool[index][1]) { while (rand > movePool[index][1]) {
rand -= movePool[index++][1]; rand -= movePool[index++][1];
@ -3717,8 +3709,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
simulated = true, simulated = true,
ignoreHeldItems = false, ignoreHeldItems = false,
): number { ): number {
const statStage = new Utils.NumberHolder(this.getStatStage(stat)); const statStage = new NumberHolder(this.getStatStage(stat));
const ignoreStatStage = new Utils.BooleanHolder(false); const ignoreStatStage = new BooleanHolder(false);
if (opponent) { if (opponent) {
if (isCritical) { if (isCritical) {
@ -3755,7 +3747,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
if (!ignoreStatStage.value) { if (!ignoreStatStage.value) {
const statStageMultiplier = new Utils.NumberHolder( const statStageMultiplier = new NumberHolder(
Math.max(2, 2 + statStage.value) / Math.max(2, 2 - statStage.value), Math.max(2, 2 + statStage.value) / Math.max(2, 2 - statStage.value),
); );
if (!ignoreHeldItems) { if (!ignoreHeldItems) {
@ -3787,13 +3779,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return 1; return 1;
} }
const userAccStage = new Utils.NumberHolder(this.getStatStage(Stat.ACC)); const userAccStage = new NumberHolder(this.getStatStage(Stat.ACC));
const targetEvaStage = new Utils.NumberHolder( const targetEvaStage = new NumberHolder(
target.getStatStage(Stat.EVA), target.getStatStage(Stat.EVA),
); );
const ignoreAccStatStage = new Utils.BooleanHolder(false); const ignoreAccStatStage = new BooleanHolder(false);
const ignoreEvaStatStage = new Utils.BooleanHolder(false); const ignoreEvaStatStage = new BooleanHolder(false);
applyAbAttrs( applyAbAttrs(
IgnoreOpponentStatStagesAbAttr, IgnoreOpponentStatStagesAbAttr,
@ -3835,7 +3827,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
targetEvaStage.value = Math.min(0, targetEvaStage.value); targetEvaStage.value = Math.min(0, targetEvaStage.value);
} }
const accuracyMultiplier = new Utils.NumberHolder(1); const accuracyMultiplier = new NumberHolder(1);
if (userAccStage.value !== targetEvaStage.value) { if (userAccStage.value !== targetEvaStage.value) {
accuracyMultiplier.value = accuracyMultiplier.value =
userAccStage.value > targetEvaStage.value userAccStage.value > targetEvaStage.value
@ -3852,7 +3844,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
sourceMove, sourceMove,
); );
const evasionMultiplier = new Utils.NumberHolder(1); const evasionMultiplier = new NumberHolder(1);
applyStatMultiplierAbAttrs( applyStatMultiplierAbAttrs(
StatMultiplierAbAttr, StatMultiplierAbAttr,
target, target,
@ -3907,7 +3899,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
* The attacker's offensive stat for the given move's category. * The attacker's offensive stat for the given move's category.
* Critical hits cause negative stat stages to be ignored. * Critical hits cause negative stat stages to be ignored.
*/ */
const sourceAtk = new Utils.NumberHolder( const sourceAtk = new NumberHolder(
source.getEffectiveStat( source.getEffectiveStat(
isPhysical ? Stat.ATK : Stat.SPATK, isPhysical ? Stat.ATK : Stat.SPATK,
this, this,
@ -3925,7 +3917,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
* This Pokemon's defensive stat for the given move's category. * This Pokemon's defensive stat for the given move's category.
* Critical hits cause positive stat stages to be ignored. * Critical hits cause positive stat stages to be ignored.
*/ */
const targetDef = new Utils.NumberHolder( const targetDef = new NumberHolder(
this.getEffectiveStat( this.getEffectiveStat(
isPhysical ? Stat.DEF : Stat.SPDEF, isPhysical ? Stat.DEF : Stat.SPDEF,
source, source,
@ -3986,12 +3978,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
isCritical = false, isCritical = false,
simulated = true, simulated = true,
): DamageCalculationResult { ): DamageCalculationResult {
const damage = new Utils.NumberHolder(0); const damage = new NumberHolder(0);
const defendingSide = this.isPlayer() const defendingSide = this.isPlayer()
? ArenaTagSide.PLAYER ? ArenaTagSide.PLAYER
: ArenaTagSide.ENEMY; : ArenaTagSide.ENEMY;
const variableCategory = new Utils.NumberHolder(move.category); const variableCategory = new NumberHolder(move.category);
applyMoveAttrs( applyMoveAttrs(
VariableMoveCategoryAttr, VariableMoveCategoryAttr,
source, source,
@ -4005,7 +3997,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const moveType = source.getMoveType(move); const moveType = source.getMoveType(move);
/** If `value` is `true`, cancels the move and suppresses "No Effect" messages */ /** If `value` is `true`, cancels the move and suppresses "No Effect" messages */
const cancelled = new Utils.BooleanHolder(false); const cancelled = new BooleanHolder(false);
/** /**
* The effectiveness of the move being used. Along with type matchups, this * The effectiveness of the move being used. Along with type matchups, this
@ -4025,7 +4017,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const isPhysical = moveCategory === MoveCategory.PHYSICAL; const isPhysical = moveCategory === MoveCategory.PHYSICAL;
/** Combined damage multiplier from field effects such as weather, terrain, etc. */ /** Combined damage multiplier from field effects such as weather, terrain, etc. */
const arenaAttackTypeMultiplier = new Utils.NumberHolder( const arenaAttackTypeMultiplier = new NumberHolder(
globalScene.arena.getAttackTypeMultiplier(moveType, source.isGrounded()), globalScene.arena.getAttackTypeMultiplier(moveType, source.isGrounded()),
); );
applyMoveAttrs( applyMoveAttrs(
@ -4048,10 +4040,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
// If the attack deals fixed damage, return a result with that much damage // If the attack deals fixed damage, return a result with that much damage
const fixedDamage = new Utils.NumberHolder(0); const fixedDamage = new NumberHolder(0);
applyMoveAttrs(FixedDamageAttr, source, this, move, fixedDamage); applyMoveAttrs(FixedDamageAttr, source, this, move, fixedDamage);
if (fixedDamage.value) { if (fixedDamage.value) {
const multiLensMultiplier = new Utils.NumberHolder(1); const multiLensMultiplier = new NumberHolder(1);
globalScene.applyModifiers( globalScene.applyModifiers(
PokemonMultiHitModifier, PokemonMultiHitModifier,
source.isPlayer(), source.isPlayer(),
@ -4060,7 +4052,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
null, null,
multiLensMultiplier, multiLensMultiplier,
); );
fixedDamage.value = Utils.toDmgValue( fixedDamage.value = toDmgValue(
fixedDamage.value * multiLensMultiplier.value, fixedDamage.value * multiLensMultiplier.value,
); );
@ -4072,7 +4064,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
// If the attack is a one-hit KO move, return a result with damage equal to this Pokemon's HP // If the attack is a one-hit KO move, return a result with damage equal to this Pokemon's HP
const isOneHitKo = new Utils.BooleanHolder(false); const isOneHitKo = new BooleanHolder(false);
applyMoveAttrs(OneHitKOAttr, source, this, move, isOneHitKo); applyMoveAttrs(OneHitKOAttr, source, this, move, isOneHitKo);
if (isOneHitKo.value) { if (isOneHitKo.value) {
return { return {
@ -4104,7 +4096,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const targetMultiplier = numTargets > 1 ? 0.75 : 1; const targetMultiplier = numTargets > 1 ? 0.75 : 1;
/** Multiplier for moves enhanced by Multi-Lens and/or Parental Bond */ /** Multiplier for moves enhanced by Multi-Lens and/or Parental Bond */
const multiStrikeEnhancementMultiplier = new Utils.NumberHolder(1); const multiStrikeEnhancementMultiplier = new NumberHolder(1);
globalScene.applyModifiers( globalScene.applyModifiers(
PokemonMultiHitModifier, PokemonMultiHitModifier,
source.isPlayer(), source.isPlayer(),
@ -4126,13 +4118,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
/** Doubles damage if this Pokemon's last move was Glaive Rush */ /** Doubles damage if this Pokemon's last move was Glaive Rush */
const glaiveRushMultiplier = new Utils.NumberHolder(1); const glaiveRushMultiplier = new NumberHolder(1);
if (this.getTag(BattlerTagType.RECEIVE_DOUBLE_DAMAGE)) { if (this.getTag(BattlerTagType.RECEIVE_DOUBLE_DAMAGE)) {
glaiveRushMultiplier.value = 2; glaiveRushMultiplier.value = 2;
} }
/** The damage multiplier when the given move critically hits */ /** The damage multiplier when the given move critically hits */
const criticalMultiplier = new Utils.NumberHolder(isCritical ? 1.5 : 1); const criticalMultiplier = new NumberHolder(isCritical ? 1.5 : 1);
applyAbAttrs(MultCritAbAttr, source, null, simulated, criticalMultiplier); applyAbAttrs(MultCritAbAttr, source, null, simulated, criticalMultiplier);
/** /**
@ -4147,7 +4139,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const sourceTeraType = source.getTeraType(); const sourceTeraType = source.getTeraType();
const matchesSourceType = sourceTypes.includes(moveType); const matchesSourceType = sourceTypes.includes(moveType);
/** A damage multiplier for when the attack is of the attacker's type and/or Tera type. */ /** A damage multiplier for when the attack is of the attacker's type and/or Tera type. */
const stabMultiplier = new Utils.NumberHolder(1); const stabMultiplier = new NumberHolder(1);
if (matchesSourceType && moveType !== PokemonType.STELLAR) { if (matchesSourceType && moveType !== PokemonType.STELLAR) {
stabMultiplier.value += 0.5; stabMultiplier.value += 0.5;
} }
@ -4188,14 +4180,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
stabMultiplier.value = Math.min(stabMultiplier.value, 2.25); stabMultiplier.value = Math.min(stabMultiplier.value, 2.25);
/** Halves damage if the attacker is using a physical attack while burned */ /** Halves damage if the attacker is using a physical attack while burned */
const burnMultiplier = new Utils.NumberHolder(1); const burnMultiplier = new NumberHolder(1);
if ( if (
isPhysical && isPhysical &&
source.status && source.status &&
source.status.effect === StatusEffect.BURN source.status.effect === StatusEffect.BURN
) { ) {
if (!move.hasAttr(BypassBurnDamageReductionAttr)) { if (!move.hasAttr(BypassBurnDamageReductionAttr)) {
const burnDamageReductionCancelled = new Utils.BooleanHolder(false); const burnDamageReductionCancelled = new BooleanHolder(false);
if (!ignoreSourceAbility) { if (!ignoreSourceAbility) {
applyAbAttrs( applyAbAttrs(
BypassBurnDamageReductionAbAttr, BypassBurnDamageReductionAbAttr,
@ -4211,7 +4203,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
/** Reduces damage if this Pokemon has a relevant screen (e.g. Light Screen for special attacks) */ /** Reduces damage if this Pokemon has a relevant screen (e.g. Light Screen for special attacks) */
const screenMultiplier = new Utils.NumberHolder(1); const screenMultiplier = new NumberHolder(1);
// Critical hits should bypass screens // Critical hits should bypass screens
if (!isCritical) { if (!isCritical) {
@ -4231,7 +4223,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
* AND * AND
* The move doubles damage when used against that tag * The move doubles damage when used against that tag
*/ */
const hitsTagMultiplier = new Utils.NumberHolder(1); const hitsTagMultiplier = new NumberHolder(1);
move move
.getAttrs(HitsTagAttr) .getAttrs(HitsTagAttr)
.filter(hta => hta.doubleDamage) .filter(hta => hta.doubleDamage)
@ -4249,7 +4241,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
? 0.5 ? 0.5
: 1; : 1;
damage.value = Utils.toDmgValue( damage.value = toDmgValue(
baseDamage * baseDamage *
targetMultiplier * targetMultiplier *
multiStrikeEnhancementMultiplier.value * multiStrikeEnhancementMultiplier.value *
@ -4358,10 +4350,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const defendingSide = this.isPlayer() const defendingSide = this.isPlayer()
? ArenaTagSide.PLAYER ? ArenaTagSide.PLAYER
: ArenaTagSide.ENEMY; : ArenaTagSide.ENEMY;
const moveCategory = new Utils.NumberHolder(move.category); const moveCategory = new NumberHolder(move.category);
applyMoveAttrs(VariableMoveCategoryAttr, source, this, move, moveCategory); applyMoveAttrs(VariableMoveCategoryAttr, source, this, move, moveCategory);
if (moveCategory.value === MoveCategory.STATUS) { if (moveCategory.value === MoveCategory.STATUS) {
const cancelled = new Utils.BooleanHolder(false); const cancelled = new BooleanHolder(false);
const typeMultiplier = this.getMoveEffectiveness( const typeMultiplier = this.getMoveEffectiveness(
source, source,
move, move,
@ -4381,7 +4373,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
/** Determines whether the attack critically hits */ /** Determines whether the attack critically hits */
let isCritical: boolean; let isCritical: boolean;
const critOnly = new Utils.BooleanHolder(false); const critOnly = new BooleanHolder(false);
const critAlways = source.getTag(BattlerTagType.ALWAYS_CRIT); const critAlways = source.getTag(BattlerTagType.ALWAYS_CRIT);
applyMoveAttrs(CritOnlyAttr, source, this, move, critOnly); applyMoveAttrs(CritOnlyAttr, source, this, move, critOnly);
applyAbAttrs( applyAbAttrs(
@ -4404,7 +4396,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
const noCritTag = globalScene.arena.getTagOnSide(NoCritTag, defendingSide); const noCritTag = globalScene.arena.getTagOnSide(NoCritTag, defendingSide);
const blockCrit = new Utils.BooleanHolder(false); const blockCrit = new BooleanHolder(false);
applyAbAttrs(BlockCritAbAttr, this, null, false, blockCrit); applyAbAttrs(BlockCritAbAttr, this, null, false, blockCrit);
if (noCritTag || blockCrit.value || Overrides.NEVER_CRIT_OVERRIDE) { if (noCritTag || blockCrit.value || Overrides.NEVER_CRIT_OVERRIDE) {
isCritical = false; isCritical = false;
@ -4486,7 +4478,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (damage > 0) { if (damage > 0) {
if (source.isPlayer()) { if (source.isPlayer()) {
globalScene.validateAchvs(DamageAchv, new Utils.NumberHolder(damage)); globalScene.validateAchvs(DamageAchv, new NumberHolder(damage));
if (damage > globalScene.gameData.gameStats.highestDamage) { if (damage > globalScene.gameData.gameStats.highestDamage) {
globalScene.gameData.gameStats.highestDamage = damage; globalScene.gameData.gameStats.highestDamage = damage;
} }
@ -4510,7 +4502,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
DamageMoneyRewardModifier, DamageMoneyRewardModifier,
true, true,
source, source,
new Utils.NumberHolder(damage), new NumberHolder(damage),
); );
} }
} }
@ -4575,7 +4567,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (this.isFainted()) { if (this.isFainted()) {
return 0; return 0;
} }
const surviveDamage = new Utils.BooleanHolder(false); const surviveDamage = new BooleanHolder(false);
if (!preventEndure && this.hp - damage <= 0) { if (!preventEndure && this.hp - damage <= 0) {
if (this.hp >= 1 && this.getTag(BattlerTagType.ENDURING)) { if (this.hp >= 1 && this.getTag(BattlerTagType.ENDURING)) {
@ -4710,7 +4702,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const stubTag = new BattlerTag(tagType, 0, 0); const stubTag = new BattlerTag(tagType, 0, 0);
const cancelled = new Utils.BooleanHolder(false); const cancelled = new BooleanHolder(false);
applyPreApplyBattlerTagAbAttrs( applyPreApplyBattlerTagAbAttrs(
BattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr,
this, this,
@ -4748,7 +4740,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const newTag = getBattlerTag(tagType, turnCount, sourceMove!, sourceId!); // TODO: are the bangs correct? const newTag = getBattlerTag(tagType, turnCount, sourceMove!, sourceId!); // TODO: are the bangs correct?
const cancelled = new Utils.BooleanHolder(false); const cancelled = new BooleanHolder(false);
applyPreApplyBattlerTagAbAttrs( applyPreApplyBattlerTagAbAttrs(
BattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr,
this, this,
@ -5081,12 +5073,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
let fusionCry = this.getFusionSpeciesForm().cry(soundConfig, true); let fusionCry = this.getFusionSpeciesForm().cry(soundConfig, true);
duration = Math.min(duration, fusionCry.totalDuration * 1000); duration = Math.min(duration, fusionCry.totalDuration * 1000);
fusionCry.destroy(); fusionCry.destroy();
scene.time.delayedCall(Utils.fixedInt(Math.ceil(duration * 0.4)), () => { scene.time.delayedCall(fixedInt(Math.ceil(duration * 0.4)), () => {
try { try {
SoundFade.fadeOut( SoundFade.fadeOut(
scene, scene,
cry, cry,
Utils.fixedInt(Math.ceil(duration * 0.2)), fixedInt(Math.ceil(duration * 0.2)),
); );
fusionCry = this.getFusionSpeciesForm().cry( fusionCry = this.getFusionSpeciesForm().cry(
Object.assign( Object.assign(
@ -5097,7 +5089,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
SoundFade.fadeIn( SoundFade.fadeIn(
scene, scene,
fusionCry, fusionCry,
Utils.fixedInt(Math.ceil(duration * 0.2)), fixedInt(Math.ceil(duration * 0.2)),
scene.masterVolume * scene.fieldVolume, scene.masterVolume * scene.fieldVolume,
0, 0,
); );
@ -5137,7 +5129,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
let faintCryTimer: Phaser.Time.TimerEvent | null = let faintCryTimer: Phaser.Time.TimerEvent | null =
globalScene.time.addEvent({ globalScene.time.addEvent({
delay: Utils.fixedInt(delay), delay: fixedInt(delay),
repeat: -1, repeat: -1,
callback: () => { callback: () => {
frameThreshold = sprite.anims.msPerFrame / rate; frameThreshold = sprite.anims.msPerFrame / rate;
@ -5163,7 +5155,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}); });
// Failsafe // Failsafe
globalScene.time.delayedCall(Utils.fixedInt(3000), () => { globalScene.time.delayedCall(fixedInt(3000), () => {
if (!faintCryTimer || !globalScene) { if (!faintCryTimer || !globalScene) {
return; return;
} }
@ -5222,7 +5214,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
let faintCryTimer: Phaser.Time.TimerEvent | null = let faintCryTimer: Phaser.Time.TimerEvent | null =
globalScene.time.addEvent({ globalScene.time.addEvent({
delay: Utils.fixedInt(delay), delay: fixedInt(delay),
repeat: -1, repeat: -1,
callback: () => { callback: () => {
++i; ++i;
@ -5239,7 +5231,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
SoundFade.fadeOut( SoundFade.fadeOut(
globalScene, globalScene,
cry, cry,
Utils.fixedInt(Math.ceil((duration / rate) * 0.2)), fixedInt(Math.ceil((duration / rate) * 0.2)),
); );
fusionCry = globalScene.playSound( fusionCry = globalScene.playSound(
fusionCryKey, fusionCryKey,
@ -5251,7 +5243,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
SoundFade.fadeIn( SoundFade.fadeIn(
globalScene, globalScene,
fusionCry, fusionCry,
Utils.fixedInt(Math.ceil((duration / rate) * 0.2)), fixedInt(Math.ceil((duration / rate) * 0.2)),
globalScene.masterVolume * globalScene.fieldVolume, globalScene.masterVolume * globalScene.fieldVolume,
0, 0,
); );
@ -5277,7 +5269,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}); });
// Failsafe // Failsafe
globalScene.time.delayedCall(Utils.fixedInt(3000), () => { globalScene.time.delayedCall(fixedInt(3000), () => {
if (!faintCryTimer || !globalScene) { if (!faintCryTimer || !globalScene) {
return; return;
} }
@ -5352,7 +5344,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
// Check if the source Pokemon has an ability that cancels the Poison/Toxic immunity // Check if the source Pokemon has an ability that cancels the Poison/Toxic immunity
const cancelImmunity = new Utils.BooleanHolder(false); const cancelImmunity = new BooleanHolder(false);
if (sourcePokemon) { if (sourcePokemon) {
applyAbAttrs( applyAbAttrs(
IgnoreTypeStatusEffectImmunityAbAttr, IgnoreTypeStatusEffectImmunityAbAttr,
@ -5408,7 +5400,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
break; break;
} }
const cancelled = new Utils.BooleanHolder(false); const cancelled = new BooleanHolder(false);
applyPreSetStatusAbAttrs( applyPreSetStatusAbAttrs(
StatusEffectImmunityAbAttr, StatusEffectImmunityAbAttr,
this, this,
@ -5479,10 +5471,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return true; return true;
} }
let sleepTurnsRemaining: Utils.NumberHolder; let sleepTurnsRemaining: NumberHolder;
if (effect === StatusEffect.SLEEP) { if (effect === StatusEffect.SLEEP) {
sleepTurnsRemaining = new Utils.NumberHolder(this.randSeedIntRange(2, 4)); sleepTurnsRemaining = new NumberHolder(this.randSeedIntRange(2, 4));
this.setFrameRate(4); this.setFrameRate(4);
@ -5533,7 +5525,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
? ArenaTagSide.PLAYER ? ArenaTagSide.PLAYER
: ArenaTagSide.ENEMY; : ArenaTagSide.ENEMY;
if (globalScene.arena.getTagOnSide(ArenaTagType.SAFEGUARD, defendingSide)) { if (globalScene.arena.getTagOnSide(ArenaTagType.SAFEGUARD, defendingSide)) {
const bypassed = new Utils.BooleanHolder(false); const bypassed = new BooleanHolder(false);
if (attacker) { if (attacker) {
applyAbAttrs(InfiltratorAbAttr, attacker, null, false, bypassed); applyAbAttrs(InfiltratorAbAttr, attacker, null, false, bypassed);
} }
@ -5829,9 +5821,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (this.shiny && variantColors && variantColors[this.variant]) { if (this.shiny && variantColors && variantColors[this.variant]) {
Object.keys(variantColors[this.variant]).forEach(k => { Object.keys(variantColors[this.variant]).forEach(k => {
variantColorSet.set( variantColorSet.set(
Utils.rgbaToInt(Array.from(Object.values(Utils.rgbHexToRgba(k)))), rgbaToInt(Array.from(Object.values(rgbHexToRgba(k)))),
Array.from( Array.from(
Object.values(Utils.rgbHexToRgba(variantColors[this.variant][k])), Object.values(rgbHexToRgba(variantColors[this.variant][k])),
), ),
); );
}); });
@ -5842,7 +5834,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const pixel = pixelData[f].slice(i, i + 4); const pixel = pixelData[f].slice(i, i + 4);
let [r, g, b, a] = pixel; let [r, g, b, a] = pixel;
if (variantColors) { if (variantColors) {
const color = Utils.rgbaToInt([r, g, b, a]); const color = rgbaToInt([r, g, b, a]);
if (variantColorSet.has(color)) { if (variantColorSet.has(color)) {
const mappedPixel = variantColorSet.get(color); const mappedPixel = variantColorSet.get(color);
if (mappedPixel) { if (mappedPixel) {
@ -5891,10 +5883,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
) { ) {
for (const k of Object.keys(variantColors[this.fusionVariant])) { for (const k of Object.keys(variantColors[this.fusionVariant])) {
variantColorSet.set( variantColorSet.set(
Utils.rgbaToInt(Array.from(Object.values(Utils.rgbHexToRgba(k)))), rgbaToInt(Array.from(Object.values(rgbHexToRgba(k)))),
Array.from( Array.from(
Object.values( Object.values(
Utils.rgbHexToRgba(variantColors[this.fusionVariant][k]), rgbHexToRgba(variantColors[this.fusionVariant][k]),
), ),
), ),
); );
@ -5914,7 +5906,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
pixelData[2 + f][i + 3], pixelData[2 + f][i + 3],
]; ];
if (variantColors) { if (variantColors) {
const color = Utils.rgbaToInt([r, g, b, a]); const color = rgbaToInt([r, g, b, a]);
if (variantColorSet.has(color)) { if (variantColorSet.has(color)) {
const mappedPixel = variantColorSet.get(color); const mappedPixel = variantColorSet.get(color);
if (mappedPixel) { if (mappedPixel) {
@ -5972,7 +5964,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
hsvColors = Array.from(rgbaColors.keys()).reduce( hsvColors = Array.from(rgbaColors.keys()).reduce(
(map: Map<number, number[]>, k: number) => { (map: Map<number, number[]>, k: number) => {
const rgb = rgbaColors.get(k)!.slice(0, 3); const rgb = rgbaColors.get(k)!.slice(0, 3);
map.set(k, Utils.rgbToHsv(rgb[0], rgb[1], rgb[2])); map.set(k, rgbToHsv(rgb[0], rgb[1], rgb[2]));
return map; return map;
}, },
new Map<number, number[]>(), new Map<number, number[]>(),
@ -6052,7 +6044,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
spriteColors.forEach((sc: number[], i: number) => { spriteColors.forEach((sc: number[], i: number) => {
paletteDeltas.push([]); paletteDeltas.push([]);
for (let p = 0; p < palette.length; p++) { for (let p = 0; p < palette.length; p++) {
paletteDeltas[i].push(Utils.deltaRgb(sc, palette[p])); paletteDeltas[i].push(deltaRgb(sc, palette[p]));
} }
}); });
@ -6097,8 +6089,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
* <!-- @import "../battle".Battle --> * <!-- @import "../battle".Battle -->
* This calls either {@linkcode BattleScene.randBattleSeedInt}({@linkcode range}, {@linkcode min}) in `src/battle-scene.ts` * This calls either {@linkcode BattleScene.randBattleSeedInt}({@linkcode range}, {@linkcode min}) in `src/battle-scene.ts`
* which calls {@linkcode Battle.randSeedInt}({@linkcode range}, {@linkcode min}) in `src/battle.ts` * which calls {@linkcode Battle.randSeedInt}({@linkcode range}, {@linkcode min}) in `src/battle.ts`
* which calls {@linkcode Utils.randSeedInt randSeedInt}({@linkcode range}, {@linkcode min}) in `src/utils.ts`, * which calls {@linkcode randSeedInt randSeedInt}({@linkcode range}, {@linkcode min}) in `src/utils.ts`,
* or it directly calls {@linkcode Utils.randSeedInt randSeedInt}({@linkcode range}, {@linkcode min}) in `src/utils.ts` if there is no current battle * or it directly calls {@linkcode randSeedInt randSeedInt}({@linkcode range}, {@linkcode min}) in `src/utils.ts` if there is no current battle
* *
* @param range How large of a range of random numbers to choose from. If {@linkcode range} <= 1, returns {@linkcode min} * @param range How large of a range of random numbers to choose from. If {@linkcode range} <= 1, returns {@linkcode min}
* @param min The minimum integer to pick, default `0` * @param min The minimum integer to pick, default `0`
@ -6107,7 +6099,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
randSeedInt(range: number, min = 0): number { randSeedInt(range: number, min = 0): number {
return globalScene.currentBattle return globalScene.currentBattle
? globalScene.randBattleSeedInt(range, min) ? globalScene.randBattleSeedInt(range, min)
: Utils.randSeedInt(range, min); : randSeedInt(range, min);
} }
/** /**
@ -6403,7 +6395,7 @@ export class PlayerPokemon extends Pokemon {
? globalScene.gameData.starterData[fusionStarterSpeciesId] ? globalScene.gameData.starterData[fusionStarterSpeciesId]
: null, : null,
].filter(d => !!d); ].filter(d => !!d);
const amount = new Utils.NumberHolder(friendship); const amount = new NumberHolder(friendship);
globalScene.applyModifier( globalScene.applyModifier(
PokemonFriendshipBoosterModifier, PokemonFriendshipBoosterModifier,
true, true,
@ -6418,7 +6410,7 @@ export class PlayerPokemon extends Pokemon {
? 1.5 // Divide candy gain for fusions by 1.5 during events ? 1.5 // Divide candy gain for fusions by 1.5 during events
: 2 // 2 for fusions outside events : 2 // 2 for fusions outside events
: 1; // 1 for non-fused mons : 1; // 1 for non-fused mons
const starterAmount = new Utils.NumberHolder( const starterAmount = new NumberHolder(
Math.floor( Math.floor(
(amount.value * candyFriendshipMultiplier) / fusionReduction, (amount.value * candyFriendshipMultiplier) / fusionReduction,
), ),
@ -7381,7 +7373,7 @@ export class EnemyPokemon extends Pokemon {
//console.log('damage', damage, 'segment', segmentsBypassed + 1, 'segment size', segmentSize, 'damage needed', Math.round(segmentSize * Math.pow(2, segmentsBypassed + 1))); //console.log('damage', damage, 'segment', segmentsBypassed + 1, 'segment size', segmentSize, 'damage needed', Math.round(segmentSize * Math.pow(2, segmentsBypassed + 1)));
} }
damage = Utils.toDmgValue( damage = toDmgValue(
this.hp - hpThreshold + segmentSize * segmentsBypassed, this.hp - hpThreshold + segmentSize * segmentsBypassed,
); );
clearedBossSegmentIndex = s - segmentsBypassed; clearedBossSegmentIndex = s - segmentsBypassed;
@ -7459,7 +7451,7 @@ export class EnemyPokemon extends Pokemon {
} }
// Pick a random stat from the leftover stats to increase its stages // Pick a random stat from the leftover stats to increase its stages
const randInt = Utils.randSeedInt(totalWeight); const randInt = randSeedInt(totalWeight);
for (const i in statThresholds) { for (const i in statThresholds) {
if (randInt < statThresholds[i]) { if (randInt < statThresholds[i]) {
boostedStat = leftoverStats[i]; boostedStat = leftoverStats[i];
@ -7530,7 +7522,7 @@ export class EnemyPokemon extends Pokemon {
this, this,
); );
if (Utils.isBetween(slotIndex, 0, PLAYER_PARTY_MAX_SIZE - 1)) { if (isBetween(slotIndex, 0, PLAYER_PARTY_MAX_SIZE - 1)) {
party.splice(slotIndex, 0, newPokemon); party.splice(slotIndex, 0, newPokemon);
} else { } else {
party.push(newPokemon); party.push(newPokemon);
@ -7772,7 +7764,7 @@ export class PokemonMove {
getMovePp(): number { getMovePp(): number {
return ( return (
this.maxPpOverride || this.maxPpOverride ||
this.getMove().pp + this.ppUp * Utils.toDmgValue(this.getMove().pp / 5) this.getMove().pp + this.ppUp * toDmgValue(this.getMove().pp / 5)
); );
} }

View File

@ -11,7 +11,7 @@ import { TrainerSlot } from "#enums/trainer-slot";
import { TrainerPoolTier } from "#enums/trainer-pool-tier"; import { TrainerPoolTier } from "#enums/trainer-pool-tier";
import { TeraAIMode } from "#enums/tera-ai-mode"; import { TeraAIMode } from "#enums/tera-ai-mode";
import type { EnemyPokemon } from "#app/field/pokemon"; import type { EnemyPokemon } from "#app/field/pokemon";
import * as Utils from "#app/utils"; import { randSeedWeightedItem, randSeedItem, randSeedInt } from "#app/utils";
import type { PersistentModifier } from "#app/modifier/modifier"; import type { PersistentModifier } from "#app/modifier/modifier";
import { ArenaTagSide, ArenaTrapTag } from "#app/data/arena-tag"; import { ArenaTagSide, ArenaTrapTag } from "#app/data/arena-tag";
import { getIsInitialized, initI18n } from "#app/plugins/i18n"; import { getIsInitialized, initI18n } from "#app/plugins/i18n";
@ -58,7 +58,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
this.partyTemplateIndex = Math.min( this.partyTemplateIndex = Math.min(
partyTemplateIndex !== undefined partyTemplateIndex !== undefined
? partyTemplateIndex ? partyTemplateIndex
: Utils.randSeedWeightedItem(this.config.partyTemplates.map((_, i) => i)), : randSeedWeightedItem(this.config.partyTemplates.map((_, i) => i)),
this.config.partyTemplates.length - 1, this.config.partyTemplates.length - 1,
); );
const classKey = `trainersCommon:${TrainerType[trainerType]}`; const classKey = `trainersCommon:${TrainerType[trainerType]}`;
@ -71,9 +71,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
? ".FEMALE" ? ".FEMALE"
: ".MALE" : ".MALE"
: ""; : "";
const trainerKey = Utils.randSeedItem( const trainerKey = randSeedItem(Object.keys(i18next.t(`${classKey}${genderKey}`, { returnObjects: true })));
Object.keys(i18next.t(`${classKey}${genderKey}`, { returnObjects: true })),
);
this.nameKey = `${classKey}${genderKey}.${trainerKey}`; this.nameKey = `${classKey}${genderKey}.${trainerKey}`;
} }
this.name = i18next.t(this.nameKey); this.name = i18next.t(this.nameKey);
@ -87,7 +85,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
} }
} else { } else {
const partnerGenderKey = i18next.exists(`${classKey}.FEMALE`) ? ".FEMALE" : ""; const partnerGenderKey = i18next.exists(`${classKey}.FEMALE`) ? ".FEMALE" : "";
const partnerTrainerKey = Utils.randSeedItem( const partnerTrainerKey = randSeedItem(
Object.keys( Object.keys(
i18next.t(`${classKey}${partnerGenderKey}`, { i18next.t(`${classKey}${partnerGenderKey}`, {
returnObjects: true, returnObjects: true,
@ -420,7 +418,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
// If useNewSpeciesPool is true, we need to generate a new species from the new species pool, otherwise we generate a random species // If useNewSpeciesPool is true, we need to generate a new species from the new species pool, otherwise we generate a random species
let species = useNewSpeciesPool let species = useNewSpeciesPool
? getPokemonSpecies(newSpeciesPool[Math.floor(Utils.randSeedInt(newSpeciesPool.length))]) ? getPokemonSpecies(newSpeciesPool[Math.floor(randSeedInt(newSpeciesPool.length))])
: template.isSameSpecies(index) && index > offset : template.isSameSpecies(index) && index > offset
? getPokemonSpecies( ? getPokemonSpecies(
battle.enemyParty[offset].species.getTrainerSpeciesForLevel( battle.enemyParty[offset].species.getTrainerSpeciesForLevel(
@ -461,7 +459,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
let baseSpecies: PokemonSpecies; let baseSpecies: PokemonSpecies;
if (this.config.speciesPools) { if (this.config.speciesPools) {
const tierValue = Utils.randSeedInt(512); const tierValue = randSeedInt(512);
let tier = let tier =
tierValue >= 156 tierValue >= 156
? TrainerPoolTier.COMMON ? TrainerPoolTier.COMMON
@ -480,7 +478,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
tier--; tier--;
} }
const tierPool = this.config.speciesPools[tier]; const tierPool = this.config.speciesPools[tier];
baseSpecies = getPokemonSpecies(Utils.randSeedItem(tierPool)); baseSpecies = getPokemonSpecies(randSeedItem(tierPool));
} else { } else {
baseSpecies = globalScene.randomSpecies(battle.waveIndex, level, false, this.config.speciesFilter); baseSpecies = globalScene.randomSpecies(battle.waveIndex, level, false, this.config.speciesFilter);
} }
@ -619,7 +617,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
if (maxScorePartyMemberIndexes.length > 1) { if (maxScorePartyMemberIndexes.length > 1) {
let rand: number; let rand: number;
globalScene.executeWithSeedOffset( globalScene.executeWithSeedOffset(
() => (rand = Utils.randSeedInt(maxScorePartyMemberIndexes.length)), () => (rand = randSeedInt(maxScorePartyMemberIndexes.length)),
globalScene.currentBattle.turn << 2, globalScene.currentBattle.turn << 2,
); );
return maxScorePartyMemberIndexes[rand!]; return maxScorePartyMemberIndexes[rand!];

View File

@ -7,7 +7,7 @@ import type PokemonSpecies from "./data/pokemon-species";
import { allSpecies } from "./data/pokemon-species"; import { allSpecies } from "./data/pokemon-species";
import type { Arena } from "./field/arena"; import type { Arena } from "./field/arena";
import Overrides from "#app/overrides"; import Overrides from "#app/overrides";
import * as Utils from "./utils"; import { randSeedInt, randSeedItem } from "#app/utils";
import { Biome } from "#enums/biome"; import { Biome } from "#enums/biome";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import { Challenges } from "./enums/challenges"; import { Challenges } from "./enums/challenges";
@ -186,7 +186,7 @@ export class GameMode implements GameModeConfig {
if (w < waveIndex) { if (w < waveIndex) {
globalScene.executeWithSeedOffset(() => { globalScene.executeWithSeedOffset(() => {
const waveTrainerChance = arena.getTrainerChance(); const waveTrainerChance = arena.getTrainerChance();
if (!Utils.randSeedInt(waveTrainerChance)) { if (!randSeedInt(waveTrainerChance)) {
allowTrainerBattle = false; allowTrainerBattle = false;
} }
}, w); }, w);
@ -196,7 +196,7 @@ export class GameMode implements GameModeConfig {
} }
} }
} }
return Boolean(allowTrainerBattle && trainerChance && !Utils.randSeedInt(trainerChance)); return Boolean(allowTrainerBattle && trainerChance && !randSeedInt(trainerChance));
} }
return false; return false;
} }
@ -222,7 +222,7 @@ export class GameMode implements GameModeConfig {
s.speciesId !== Species.ETERNATUS && s.speciesId !== Species.ETERNATUS &&
s.speciesId !== Species.ARCEUS, s.speciesId !== Species.ARCEUS,
); );
return Utils.randSeedItem(allFinalBossSpecies); return randSeedItem(allFinalBossSpecies);
} }
return null; return null;

View File

@ -1,6 +1,5 @@
import Phaser from "phaser"; import Phaser from "phaser";
import * as Utils from "./utils"; import { deepCopy, getEnumValues } from "#app/utils";
import { deepCopy } from "./utils";
import pad_generic from "./configs/inputs/pad_generic"; import pad_generic from "./configs/inputs/pad_generic";
import pad_unlicensedSNES from "./configs/inputs/pad_unlicensedSNES"; import pad_unlicensedSNES from "./configs/inputs/pad_unlicensedSNES";
import pad_xbox360 from "./configs/inputs/pad_xbox360"; import pad_xbox360 from "./configs/inputs/pad_xbox360";
@ -102,7 +101,7 @@ export class InputsController {
[Device.KEYBOARD]: "default", [Device.KEYBOARD]: "default",
}; };
for (const b of Utils.getEnumValues(Button)) { for (const b of getEnumValues(Button)) {
this.interactions[b] = { this.interactions[b] = {
pressTime: false, pressTime: false,
isPressed: false, isPressed: false,

View File

@ -4,7 +4,7 @@ import CacheBustedLoaderPlugin from "#app/plugins/cache-busted-loader-plugin";
import { SceneBase } from "#app/scene-base"; import { SceneBase } from "#app/scene-base";
import { WindowVariant, getWindowVariantSuffix } from "#app/ui/ui-theme"; import { WindowVariant, getWindowVariantSuffix } from "#app/ui/ui-theme";
import { isMobile } from "#app/touch-controls"; import { isMobile } from "#app/touch-controls";
import * as Utils from "#app/utils"; import { localPing, getEnumValues, hasAllLocalizedSprites, getEnumKeys } from "#app/utils";
import { initPokemonPrevolutions, initPokemonStarters } from "#app/data/balance/pokemon-evolutions"; import { initPokemonPrevolutions, initPokemonStarters } from "#app/data/balance/pokemon-evolutions";
import { initBiomes } from "#app/data/balance/biomes"; import { initBiomes } from "#app/data/balance/biomes";
import { initEggMoves } from "#app/data/balance/egg-moves"; import { initEggMoves } from "#app/data/balance/egg-moves";
@ -34,7 +34,7 @@ export class LoadingScene extends SceneBase {
} }
preload() { preload() {
Utils.localPing(); localPing();
this.load["manifest"] = this.game["manifest"]; this.load["manifest"] = this.game["manifest"];
this.loadImage("loading_bg", "arenas"); this.loadImage("loading_bg", "arenas");
@ -49,7 +49,7 @@ export class LoadingScene extends SceneBase {
this.loadImage("friendship_overlay", "ui"); this.loadImage("friendship_overlay", "ui");
this.loadImage("cursor", "ui"); this.loadImage("cursor", "ui");
this.loadImage("cursor_reverse", "ui"); this.loadImage("cursor_reverse", "ui");
for (const wv of Utils.getEnumValues(WindowVariant)) { for (const wv of getEnumValues(WindowVariant)) {
for (let w = 1; w <= 5; w++) { for (let w = 1; w <= 5; w++) {
this.loadImage(`window_${w}${getWindowVariantSuffix(wv)}`, "ui/windows"); this.loadImage(`window_${w}${getWindowVariantSuffix(wv)}`, "ui/windows");
} }
@ -177,7 +177,7 @@ export class LoadingScene extends SceneBase {
this.loadImage("default_bg", "arenas"); this.loadImage("default_bg", "arenas");
// Load arena images // Load arena images
Utils.getEnumValues(Biome).map(bt => { getEnumValues(Biome).map(bt => {
const btKey = Biome[bt].toLowerCase(); const btKey = Biome[bt].toLowerCase();
const isBaseAnimated = btKey === "end"; const isBaseAnimated = btKey === "end";
const baseAKey = `${btKey}_a`; const baseAKey = `${btKey}_a`;
@ -239,7 +239,7 @@ export class LoadingScene extends SceneBase {
// Get current lang and load the types atlas for it. English will only load types while all other languages will load types and types_<lang> // Get current lang and load the types atlas for it. English will only load types while all other languages will load types and types_<lang>
const lang = i18next.resolvedLanguage; const lang = i18next.resolvedLanguage;
if (lang !== "en") { if (lang !== "en") {
if (Utils.hasAllLocalizedSprites(lang)) { if (hasAllLocalizedSprites(lang)) {
this.loadAtlas(`statuses_${lang}`, ""); this.loadAtlas(`statuses_${lang}`, "");
this.loadAtlas(`types_${lang}`, ""); this.loadAtlas(`types_${lang}`, "");
} else { } else {
@ -268,7 +268,7 @@ export class LoadingScene extends SceneBase {
this.loadAtlas("egg_icons", "egg"); this.loadAtlas("egg_icons", "egg");
this.loadAtlas("egg_shard", "egg"); this.loadAtlas("egg_shard", "egg");
this.loadAtlas("egg_lightrays", "egg"); this.loadAtlas("egg_lightrays", "egg");
for (const gt of Utils.getEnumKeys(GachaType)) { for (const gt of getEnumKeys(GachaType)) {
const key = gt.toLowerCase(); const key = gt.toLowerCase();
this.loadImage(`gacha_${key}`, "egg"); this.loadImage(`gacha_${key}`, "egg");
this.loadAtlas(`gacha_underlay_${key}`, "egg"); this.loadAtlas(`gacha_underlay_${key}`, "egg");

View File

@ -297,16 +297,16 @@ export class MoveEffectPhase extends PokemonPhase {
); );
} }
/** Is the target protected by Protect, etc. or a relevant conditional protection effect? */ /** Is the target protected by Protect, etc. or a relevant conditional protection effect? */
const isProtected = const isProtected =
![MoveTarget.ENEMY_SIDE, MoveTarget.BOTH_SIDES].includes(this.move.getMove().moveTarget) && ![MoveTarget.ENEMY_SIDE, MoveTarget.BOTH_SIDES].includes(this.move.getMove().moveTarget) &&
(bypassIgnoreProtect.value || (bypassIgnoreProtect.value ||
!this.move.getMove().doesFlagEffectApply({ flag: MoveFlags.IGNORE_PROTECT, user, target })) && !this.move.getMove().doesFlagEffectApply({ flag: MoveFlags.IGNORE_PROTECT, user, target })) &&
(hasConditionalProtectApplied.value || (hasConditionalProtectApplied.value ||
(!target.findTags(t => t instanceof DamageProtectedTag).length && (!target.findTags(t => t instanceof DamageProtectedTag).length &&
target.findTags(t => t instanceof ProtectedTag).find(t => target.lapseTag(t.tagType))) || target.findTags(t => t instanceof ProtectedTag).find(t => target.lapseTag(t.tagType))) ||
(this.move.getMove().category !== MoveCategory.STATUS && (this.move.getMove().category !== MoveCategory.STATUS &&
target.findTags(t => t instanceof DamageProtectedTag).find(t => target.lapseTag(t.tagType)))); target.findTags(t => t instanceof DamageProtectedTag).find(t => target.lapseTag(t.tagType))));
/** Is the target hidden by the effects of its Commander ability? */ /** Is the target hidden by the effects of its Commander ability? */
const isCommanding = const isCommanding =
@ -316,11 +316,11 @@ export class MoveEffectPhase extends PokemonPhase {
/** Is the target reflecting status moves from the magic coat move? */ /** Is the target reflecting status moves from the magic coat move? */
const isReflecting = !!target.getTag(BattlerTagType.MAGIC_COAT); const isReflecting = !!target.getTag(BattlerTagType.MAGIC_COAT);
/** Is the target's magic bounce ability not ignored and able to reflect this move? */ /** Is the target's magic bounce ability not ignored and able to reflect this move? */
const canMagicBounce = const canMagicBounce =
!isReflecting && !isReflecting &&
!move.doesFlagEffectApply({ flag: MoveFlags.IGNORE_ABILITIES, user, target }) && !move.doesFlagEffectApply({ flag: MoveFlags.IGNORE_ABILITIES, user, target }) &&
target.hasAbilityWithAttr(ReflectStatusMoveAbAttr); target.hasAbilityWithAttr(ReflectStatusMoveAbAttr);
const semiInvulnerableTag = target.getTag(SemiInvulnerableTag); const semiInvulnerableTag = target.getTag(SemiInvulnerableTag);
@ -333,21 +333,19 @@ export class MoveEffectPhase extends PokemonPhase {
(isReflecting || canMagicBounce) && (isReflecting || canMagicBounce) &&
!semiInvulnerableTag; !semiInvulnerableTag;
// If the move will bounce, then queue the bounce and move on to the next target // If the move will bounce, then queue the bounce and move on to the next target
if (!target.switchOutStatus && willBounce) { if (!target.switchOutStatus && willBounce) {
const newTargets = move.isMultiTarget() const newTargets = move.isMultiTarget() ? getMoveTargets(target, move.id).targets : [user.getBattlerIndex()];
? getMoveTargets(target, move.id).targets if (!isReflecting) {
: [user.getBattlerIndex()]; // TODO: Ability displays should be handled by the ability
if (!isReflecting) { queuedPhases.push(
// TODO: Ability displays should be handled by the ability new ShowAbilityPhase(
queuedPhases.push( target.getBattlerIndex(),
new ShowAbilityPhase( target.getPassiveAbility().hasAttr(ReflectStatusMoveAbAttr),
target.getBattlerIndex(), ),
target.getPassiveAbility().hasAttr(ReflectStatusMoveAbAttr), );
), queuedPhases.push(new HideAbilityPhase());
); }
queuedPhases.push(new HideAbilityPhase());
}
queuedPhases.push(new MovePhase(target, newTargets, new PokemonMove(move.id, 0, 0, true), true, true, true)); queuedPhases.push(new MovePhase(target, newTargets, new PokemonMove(move.id, 0, 0, true), true, true, true));
continue; continue;

View File

@ -4,7 +4,7 @@ import type { PartyOption } from "#app/ui/party-ui-handler";
import PartyUiHandler, { PartyUiMode } from "#app/ui/party-ui-handler"; import PartyUiHandler, { PartyUiMode } from "#app/ui/party-ui-handler";
import { Mode } from "#app/ui/ui"; import { Mode } from "#app/ui/ui";
import i18next from "i18next"; import i18next from "i18next";
import * as Utils from "#app/utils"; import { toDmgValue, isNullOrUndefined } from "#app/utils";
import { BattlePhase } from "#app/phases/battle-phase"; import { BattlePhase } from "#app/phases/battle-phase";
import { SwitchSummonPhase } from "#app/phases/switch-summon-phase"; import { SwitchSummonPhase } from "#app/phases/switch-summon-phase";
import { ToggleDoublePositionPhase } from "#app/phases/toggle-double-position-phase"; import { ToggleDoublePositionPhase } from "#app/phases/toggle-double-position-phase";
@ -33,7 +33,7 @@ export class RevivalBlessingPhase extends BattlePhase {
pokemon.resetTurnData(); pokemon.resetTurnData();
pokemon.resetStatus(); pokemon.resetStatus();
pokemon.heal(Math.min(Utils.toDmgValue(0.5 * pokemon.getMaxHp()), pokemon.getMaxHp())); pokemon.heal(Math.min(toDmgValue(0.5 * pokemon.getMaxHp()), pokemon.getMaxHp()));
globalScene.queueMessage( globalScene.queueMessage(
i18next.t("moveTriggers:revivalBlessing", { i18next.t("moveTriggers:revivalBlessing", {
pokemonName: pokemon.name, pokemonName: pokemon.name,
@ -46,7 +46,7 @@ export class RevivalBlessingPhase extends BattlePhase {
if ( if (
globalScene.currentBattle.double && globalScene.currentBattle.double &&
globalScene.getPlayerParty().length > 1 && globalScene.getPlayerParty().length > 1 &&
!Utils.isNullOrUndefined(allyPokemon) !isNullOrUndefined(allyPokemon)
) { ) {
if (slotIndex <= 1) { if (slotIndex <= 1) {
// Revived ally pokemon // Revived ally pokemon

View File

@ -12,7 +12,7 @@ import type { Starter } from "#app/ui/starter-select-ui-handler";
import { Mode } from "#app/ui/ui"; import { Mode } from "#app/ui/ui";
import type { Species } from "#enums/species"; import type { Species } from "#enums/species";
import SoundFade from "phaser3-rex-plugins/plugins/soundfade"; import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
import * as Utils from "../utils"; import { isNullOrUndefined } from "#app/utils";
export class SelectStarterPhase extends Phase { export class SelectStarterPhase extends Phase {
start() { start() {
@ -49,7 +49,7 @@ export class SelectStarterPhase extends Phase {
let starterFormIndex = Math.min(starterProps.formIndex, Math.max(starter.species.forms.length - 1, 0)); let starterFormIndex = Math.min(starterProps.formIndex, Math.max(starter.species.forms.length - 1, 0));
if ( if (
starter.species.speciesId in Overrides.STARTER_FORM_OVERRIDES && starter.species.speciesId in Overrides.STARTER_FORM_OVERRIDES &&
!Utils.isNullOrUndefined(Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]) && !isNullOrUndefined(Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]) &&
starter.species.forms[Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]!] starter.species.forms[Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]!]
) { ) {
starterFormIndex = Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]!; starterFormIndex = Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]!;
@ -87,7 +87,7 @@ export class SelectStarterPhase extends Phase {
starterPokemon.nickname = starter.nickname; starterPokemon.nickname = starter.nickname;
} }
if (!Utils.isNullOrUndefined(starter.teraType)) { if (!isNullOrUndefined(starter.teraType)) {
starterPokemon.teraType = starter.teraType; starterPokemon.teraType = starter.teraType;
} else { } else {
starterPokemon.teraType = starterPokemon.species.type1; starterPokemon.teraType = starterPokemon.species.type1;

View File

@ -1,6 +1,6 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { TerrainType, getTerrainColor } from "../data/terrain"; import { TerrainType, getTerrainColor } from "../data/terrain";
import * as Utils from "../utils"; import { getCurrentTime } from "#app/utils";
import fieldSpriteFragShader from "./glsl/fieldSpriteFragShader.frag?raw"; import fieldSpriteFragShader from "./glsl/fieldSpriteFragShader.frag?raw";
import spriteVertShader from "./glsl/spriteShader.vert?raw"; import spriteVertShader from "./glsl/spriteShader.vert?raw";
@ -34,7 +34,7 @@ export default class FieldSpritePipeline extends Phaser.Renderer.WebGL.Pipelines
const time = globalScene.currentBattle?.waveIndex const time = globalScene.currentBattle?.waveIndex
? ((globalScene.currentBattle.waveIndex + globalScene.waveCycleOffset) % 40) / 40 // ((new Date().getSeconds() * 1000 + new Date().getMilliseconds()) % 10000) / 10000 ? ((globalScene.currentBattle.waveIndex + globalScene.waveCycleOffset) % 40) / 40 // ((new Date().getSeconds() * 1000 + new Date().getMilliseconds()) % 10000) / 10000
: Utils.getCurrentTime(); : getCurrentTime();
this.set1f("time", time); this.set1f("time", time);
this.set1i("ignoreTimeTint", ignoreTimeTint ? 1 : 0); this.set1i("ignoreTimeTint", ignoreTimeTint ? 1 : 0);
this.set1i("isOutside", globalScene.arena.isOutside() ? 1 : 0); this.set1i("isOutside", globalScene.arena.isOutside() ? 1 : 0);

View File

@ -3,7 +3,7 @@ import MysteryEncounterIntroVisuals from "#app/field/mystery-encounter-intro";
import Pokemon from "#app/field/pokemon"; import Pokemon from "#app/field/pokemon";
import Trainer from "#app/field/trainer"; import Trainer from "#app/field/trainer";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import * as Utils from "#app/utils"; import { rgbHexToRgba } from "#app/utils";
import FieldSpritePipeline from "./field-sprite"; import FieldSpritePipeline from "./field-sprite";
import spriteFragShader from "./glsl/spriteFragShader.frag?raw"; import spriteFragShader from "./glsl/spriteFragShader.frag?raw";
import spriteVertShader from "./glsl/spriteShader.vert?raw"; import spriteVertShader from "./glsl/spriteShader.vert?raw";
@ -144,8 +144,8 @@ export default class SpritePipeline extends FieldSpritePipeline {
const baseColors = Object.keys(variantColors[variant]); const baseColors = Object.keys(variantColors[variant]);
for (let c = 0; c < 32; c++) { for (let c = 0; c < 32; c++) {
if (c < baseColors.length) { if (c < baseColors.length) {
const baseColor = Array.from(Object.values(Utils.rgbHexToRgba(baseColors[c]))); const baseColor = Array.from(Object.values(rgbHexToRgba(baseColors[c])));
const variantColor = Array.from(Object.values(Utils.rgbHexToRgba(variantColors[variant][baseColors[c]]))); const variantColor = Array.from(Object.values(rgbHexToRgba(variantColors[variant][baseColors[c]])));
flatBaseColors.splice(flatBaseColors.length, 0, ...baseColor); flatBaseColors.splice(flatBaseColors.length, 0, ...baseColor);
flatVariantColors.splice(flatVariantColors.length, 0, ...variantColor.map(c => c / 255.0)); flatVariantColors.splice(flatVariantColors.length, 0, ...variantColor.map(c => c / 255.0));
} else { } else {

View File

@ -2,7 +2,7 @@ import type { Modifier } from "typescript";
import { TurnHeldItemTransferModifier } from "../modifier/modifier"; import { TurnHeldItemTransferModifier } from "../modifier/modifier";
import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions"; import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions";
import i18next from "i18next"; import i18next from "i18next";
import * as Utils from "../utils"; import { NumberHolder } from "#app/utils";
import { PlayerGender } from "#enums/player-gender"; import { PlayerGender } from "#enums/player-gender";
import type { Challenge } from "#app/data/challenge"; import type { Challenge } from "#app/data/challenge";
import { import {
@ -138,7 +138,7 @@ export class DamageAchv extends Achv {
"", "",
iconImage, iconImage,
score, score,
(args: any[]) => (args[0] instanceof Utils.NumberHolder ? args[0].value : args[0]) >= this.damageAmount, (args: any[]) => (args[0] instanceof NumberHolder ? args[0].value : args[0]) >= this.damageAmount,
); );
this.damageAmount = damageAmount; this.damageAmount = damageAmount;
} }
@ -154,7 +154,7 @@ export class HealAchv extends Achv {
"", "",
iconImage, iconImage,
score, score,
(args: any[]) => (args[0] instanceof Utils.NumberHolder ? args[0].value : args[0]) >= this.healAmount, (args: any[]) => (args[0] instanceof NumberHolder ? args[0].value : args[0]) >= this.healAmount,
); );
this.healAmount = healAmount; this.healAmount = healAmount;
} }
@ -170,7 +170,7 @@ export class LevelAchv extends Achv {
"", "",
iconImage, iconImage,
score, score,
(args: any[]) => (args[0] instanceof Utils.NumberHolder ? args[0].value : args[0]) >= this.level, (args: any[]) => (args[0] instanceof NumberHolder ? args[0].value : args[0]) >= this.level,
); );
this.level = level; this.level = level;
} }

View File

@ -8,7 +8,7 @@ import { pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions";
import type PokemonSpecies from "#app/data/pokemon-species"; import type PokemonSpecies from "#app/data/pokemon-species";
import { allSpecies, getPokemonSpecies } from "#app/data/pokemon-species"; import { allSpecies, getPokemonSpecies } from "#app/data/pokemon-species";
import { speciesStarterCosts } from "#app/data/balance/starters"; import { speciesStarterCosts } from "#app/data/balance/starters";
import * as Utils from "#app/utils"; import { randInt, getEnumKeys, isLocal, executeIf, fixedInt, randSeedItem, NumberHolder } from "#app/utils";
import Overrides from "#app/overrides"; import Overrides from "#app/overrides";
import PokemonData from "#app/system/pokemon-data"; import PokemonData from "#app/system/pokemon-data";
import PersistentModifierData from "#app/system/modifier-data"; import PersistentModifierData from "#app/system/modifier-data";
@ -37,6 +37,7 @@ import { setSettingGamepad, SettingGamepad, settingGamepadDefaults } from "#app/
import type { SettingKeyboard } from "#app/system/settings/settings-keyboard"; import type { SettingKeyboard } from "#app/system/settings/settings-keyboard";
import { setSettingKeyboard } from "#app/system/settings/settings-keyboard"; import { setSettingKeyboard } from "#app/system/settings/settings-keyboard";
import { TagAddedEvent, TerrainChangedEvent, WeatherChangedEvent } from "#app/events/arena"; import { TagAddedEvent, TerrainChangedEvent, WeatherChangedEvent } from "#app/events/arena";
// biome-ignore lint/style/noNamespaceImport: Something weird is going on here and I don't want to touch it
import * as Modifier from "#app/modifier/modifier"; import * as Modifier from "#app/modifier/modifier";
import { StatusEffect } from "#enums/status-effect"; import { StatusEffect } from "#enums/status-effect";
import ChallengeData from "#app/system/challenge-data"; import ChallengeData from "#app/system/challenge-data";
@ -360,8 +361,8 @@ export class GameData {
this.loadSettings(); this.loadSettings();
this.loadGamepadSettings(); this.loadGamepadSettings();
this.loadMappingConfigs(); this.loadMappingConfigs();
this.trainerId = Utils.randInt(65536); this.trainerId = randInt(65536);
this.secretId = Utils.randInt(65536); this.secretId = randInt(65536);
this.starterData = {}; this.starterData = {};
this.gameStats = new GameStats(); this.gameStats = new GameStats();
this.runHistory = {}; this.runHistory = {};
@ -589,7 +590,7 @@ export class GameData {
} }
if (systemData.voucherCounts) { if (systemData.voucherCounts) {
Utils.getEnumKeys(VoucherType).forEach(key => { getEnumKeys(VoucherType).forEach(key => {
const index = VoucherType[key]; const index = VoucherType[key];
this.voucherCounts[index] = systemData.voucherCounts[index] || 0; this.voucherCounts[index] = systemData.voucherCounts[index] || 0;
}); });
@ -617,7 +618,7 @@ export class GameData {
* At the moment, only retrievable from locale cache * At the moment, only retrievable from locale cache
*/ */
async getRunHistoryData(): Promise<RunHistoryData> { async getRunHistoryData(): Promise<RunHistoryData> {
if (!Utils.isLocal) { if (!isLocal) {
/** /**
* Networking Code DO NOT DELETE! * Networking Code DO NOT DELETE!
* Note: Might have to be migrated to `pokerogue-api.ts` * Note: Might have to be migrated to `pokerogue-api.ts`
@ -1035,6 +1036,7 @@ export class GameData {
} }
getSession(slotId: number): Promise<SessionSaveData | null> { getSession(slotId: number): Promise<SessionSaveData | null> {
// biome-ignore lint/suspicious/noAsyncPromiseExecutor: <explanation>
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
if (slotId < 0) { if (slotId < 0) {
return resolve(null); return resolve(null);
@ -1075,6 +1077,7 @@ export class GameData {
} }
loadSession(slotId: number, sessionData?: SessionSaveData): Promise<boolean> { loadSession(slotId: number, sessionData?: SessionSaveData): Promise<boolean> {
// biome-ignore lint/suspicious/noAsyncPromiseExecutor: <explanation>
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
try { try {
const initSessionFromData = async (sessionData: SessionSaveData) => { const initSessionFromData = async (sessionData: SessionSaveData) => {
@ -1406,7 +1409,7 @@ export class GameData {
saveAll(skipVerification = false, sync = false, useCachedSession = false, useCachedSystem = false): Promise<boolean> { saveAll(skipVerification = false, sync = false, useCachedSession = false, useCachedSystem = false): Promise<boolean> {
return new Promise<boolean>(resolve => { return new Promise<boolean>(resolve => {
Utils.executeIf(!skipVerification, updateUserInfo).then(success => { executeIf(!skipVerification, updateUserInfo).then(success => {
if (success !== null && !success) { if (success !== null && !success) {
return resolve(false); return resolve(false);
} }
@ -1586,7 +1589,7 @@ export class GameData {
} }
const displayError = (error: string) => const displayError = (error: string) =>
globalScene.ui.showText(error, null, () => globalScene.ui.showText("", 0), Utils.fixedInt(1500)); globalScene.ui.showText(error, null, () => globalScene.ui.showText("", 0), fixedInt(1500));
dataName = dataName!; // tell TS compiler that dataName is defined! dataName = dataName!; // tell TS compiler that dataName is defined!
if (!valid) { if (!valid) {
@ -1594,7 +1597,7 @@ export class GameData {
`Your ${dataName} data could not be loaded. It may be corrupted.`, `Your ${dataName} data could not be loaded. It may be corrupted.`,
null, null,
() => globalScene.ui.showText("", 0), () => globalScene.ui.showText("", 0),
Utils.fixedInt(1500), fixedInt(1500),
); );
} }
@ -1687,7 +1690,7 @@ export class GameData {
() => { () => {
const neutralNatures = [Nature.HARDY, Nature.DOCILE, Nature.SERIOUS, Nature.BASHFUL, Nature.QUIRKY]; const neutralNatures = [Nature.HARDY, Nature.DOCILE, Nature.SERIOUS, Nature.BASHFUL, Nature.QUIRKY];
for (let s = 0; s < defaultStarterSpecies.length; s++) { for (let s = 0; s < defaultStarterSpecies.length; s++) {
defaultStarterNatures.push(Utils.randSeedItem(neutralNatures)); defaultStarterNatures.push(randSeedItem(neutralNatures));
} }
}, },
0, 0,
@ -2188,7 +2191,7 @@ export class GameData {
value = decrementValue(value); value = decrementValue(value);
} }
const cost = new Utils.NumberHolder(value); const cost = new NumberHolder(value);
applyChallenges(ChallengeType.STARTER_COST, speciesId, cost); applyChallenges(ChallengeType.STARTER_COST, speciesId, cost);
return cost.value; return cost.value;
@ -2216,7 +2219,7 @@ export class GameData {
entry.hatchedCount = 0; entry.hatchedCount = 0;
} }
if (!entry.hasOwnProperty("natureAttr") || (entry.caughtAttr && !entry.natureAttr)) { if (!entry.hasOwnProperty("natureAttr") || (entry.caughtAttr && !entry.natureAttr)) {
entry.natureAttr = this.defaultDexData?.[k].natureAttr || 1 << Utils.randInt(25, 1); entry.natureAttr = this.defaultDexData?.[k].natureAttr || 1 << randInt(25, 1);
} }
} }
} }

View File

@ -3,7 +3,7 @@ import type FadeIn from "phaser3-rex-plugins/plugins/audio/fade/FadeIn";
import type FadeOut from "phaser3-rex-plugins/plugins/audio/fade/FadeOut"; import type FadeOut from "phaser3-rex-plugins/plugins/audio/fade/FadeOut";
import type BattleScene from "#app/battle-scene"; import type BattleScene from "#app/battle-scene";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import * as Utils from "../utils"; import { FixedInt } from "#app/utils";
type FadeInType = typeof FadeIn; type FadeInType = typeof FadeIn;
type FadeOutType = typeof FadeOut; type FadeOutType = typeof FadeOut;
@ -11,9 +11,9 @@ type FadeOutType = typeof FadeOut;
export function initGameSpeed() { export function initGameSpeed() {
const thisArg = this as BattleScene; const thisArg = this as BattleScene;
const transformValue = (value: number | Utils.FixedInt): number => { const transformValue = (value: number | FixedInt): number => {
if (value instanceof Utils.FixedInt) { if (value instanceof FixedInt) {
return (value as Utils.FixedInt).value; return (value as FixedInt).value;
} }
return thisArg.gameSpeed === 1 ? value : Math.ceil((value /= thisArg.gameSpeed)); return thisArg.gameSpeed === 1 ? value : Math.ceil((value /= thisArg.gameSpeed));
}; };

View File

@ -48,12 +48,15 @@ export const settingsMigrators: Readonly<SettingsSaveMigrator[]> = [settingsMigr
// import * as vA_B_C from "./versions/vA_B_C"; // import * as vA_B_C from "./versions/vA_B_C";
// --- v1.0.4 (and below) PATCHES --- // // --- v1.0.4 (and below) PATCHES --- //
// biome-ignore lint/style/noNamespaceImport: Convenience (TODO: make this a file-wide ignore when Biome supports those)
import * as v1_0_4 from "./versions/v1_0_4"; import * as v1_0_4 from "./versions/v1_0_4";
// --- v1.7.0 PATCHES --- // // --- v1.7.0 PATCHES --- //
// biome-ignore lint/style/noNamespaceImport: Convenience
import * as v1_7_0 from "./versions/v1_7_0"; import * as v1_7_0 from "./versions/v1_7_0";
// --- v1.8.3 PATCHES --- // // --- v1.8.3 PATCHES --- //
// biome-ignore lint/style/noNamespaceImport: Convenience
import * as v1_8_3 from "./versions/v1_8_3"; import * as v1_8_3 from "./versions/v1_8_3";
/** Current game version */ /** Current game version */

View File

@ -3,7 +3,7 @@ import { TextStyle, addBBCodeTextObject, getTextColor, getTextStyleOptions } fro
import { Mode } from "./ui"; import { Mode } from "./ui";
import UiHandler from "./ui-handler"; import UiHandler from "./ui-handler";
import { addWindow } from "./ui-theme"; import { addWindow } from "./ui-theme";
import * as Utils from "../utils"; import { rgbHexToRgba, fixedInt } from "#app/utils";
import { argbFromRgba } from "@material/material-color-utilities"; import { argbFromRgba } from "@material/material-color-utilities";
import { Button } from "#enums/buttons"; import { Button } from "#enums/buttons";
import BBCodeText from "phaser3-rex-plugins/plugins/gameobjects/tagtext/bbcodetext/BBCodeText"; import BBCodeText from "phaser3-rex-plugins/plugins/gameobjects/tagtext/bbcodetext/BBCodeText";
@ -178,8 +178,8 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
itemOverlayIcon.setPositionRelative(this.optionSelectText, 36 * this.scale, 7 + i * (114 * this.scale - 3)); itemOverlayIcon.setPositionRelative(this.optionSelectText, 36 * this.scale, 7 + i * (114 * this.scale - 3));
if (option.itemArgs) { if (option.itemArgs) {
itemIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(option.itemArgs[0]))); itemIcon.setTint(argbFromRgba(rgbHexToRgba(option.itemArgs[0])));
itemOverlayIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(option.itemArgs[1]))); itemOverlayIcon.setTint(argbFromRgba(rgbHexToRgba(option.itemArgs[1])));
} }
} }
} }
@ -207,7 +207,7 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
this.blockInput = true; this.blockInput = true;
this.optionSelectTextContainer.setAlpha(0.5); this.optionSelectTextContainer.setAlpha(0.5);
this.cursorObj?.setAlpha(0.8); this.cursorObj?.setAlpha(0.8);
globalScene.time.delayedCall(Utils.fixedInt(this.config.delay), () => this.unblockInput()); globalScene.time.delayedCall(fixedInt(this.config.delay), () => this.unblockInput());
} }
if (this.config?.supportHover) { if (this.config?.supportHover) {

View File

@ -16,7 +16,7 @@ import type { TurnEndEvent } from "../events/battle-scene";
import { BattleSceneEventType } from "../events/battle-scene"; import { BattleSceneEventType } from "../events/battle-scene";
import { ArenaTagType } from "#enums/arena-tag-type"; import { ArenaTagType } from "#enums/arena-tag-type";
import TimeOfDayWidget from "./time-of-day-widget"; import TimeOfDayWidget from "./time-of-day-widget";
import * as Utils from "../utils"; import { toCamelCaseString, formatText, fixedInt } from "#app/utils";
import type { ParseKeys } from "i18next"; import type { ParseKeys } from "i18next";
import i18next from "i18next"; import i18next from "i18next";
@ -47,10 +47,10 @@ export function getFieldEffectText(arenaTagType: string): string {
if (!arenaTagType || arenaTagType === ArenaTagType.NONE) { if (!arenaTagType || arenaTagType === ArenaTagType.NONE) {
return arenaTagType; return arenaTagType;
} }
const effectName = Utils.toCamelCaseString(arenaTagType); const effectName = toCamelCaseString(arenaTagType);
const i18nKey = `arenaFlyout:${effectName}` as ParseKeys; const i18nKey = `arenaFlyout:${effectName}` as ParseKeys;
const resultName = i18next.t(i18nKey); const resultName = i18next.t(i18nKey);
return !resultName || resultName === i18nKey ? Utils.formatText(arenaTagType) : resultName; return !resultName || resultName === i18nKey ? formatText(arenaTagType) : resultName;
} }
export class ArenaFlyout extends Phaser.GameObjects.Container { export class ArenaFlyout extends Phaser.GameObjects.Container {
@ -411,7 +411,7 @@ export class ArenaFlyout extends Phaser.GameObjects.Container {
globalScene.tweens.add({ globalScene.tweens.add({
targets: this.flyoutParent, targets: this.flyoutParent,
x: visible ? this.anchorX : this.anchorX - this.translationX, x: visible ? this.anchorX : this.anchorX - this.translationX,
duration: Utils.fixedInt(125), duration: fixedInt(125),
ease: "Sine.easeInOut", ease: "Sine.easeInOut",
alpha: visible ? 1 : 0, alpha: visible ? 1 : 0,
onComplete: () => (this.timeOfDayWidget.parentVisible = visible), onComplete: () => (this.timeOfDayWidget.parentVisible = visible),

View File

@ -1,7 +1,7 @@
import type { InfoToggle } from "../battle-scene"; import type { InfoToggle } from "../battle-scene";
import { TextStyle, addTextObject } from "./text"; import { TextStyle, addTextObject } from "./text";
import { addWindow } from "./ui-theme"; import { addWindow } from "./ui-theme";
import * as Utils from "../utils"; import { fixedInt } from "#app/utils";
import i18next from "i18next"; import i18next from "i18next";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
@ -93,7 +93,7 @@ export class BaseStatsOverlay extends Phaser.GameObjects.Container implements In
} }
globalScene.tweens.add({ globalScene.tweens.add({
targets: this.statsLabels, targets: this.statsLabels,
duration: Utils.fixedInt(125), duration: fixedInt(125),
ease: "Sine.easeInOut", ease: "Sine.easeInOut",
alpha: visible ? 1 : 0, alpha: visible ? 1 : 0,
}); });

View File

@ -1,6 +1,6 @@
import type { default as Pokemon } from "../field/pokemon"; import type { default as Pokemon } from "../field/pokemon";
import { addTextObject, TextStyle } from "./text"; import { addTextObject, TextStyle } from "./text";
import * as Utils from "../utils"; import { fixedInt } from "#app/utils";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import type Move from "#app/data/moves/move"; import type Move from "#app/data/moves/move";
import type { BerryUsedEvent, MoveUsedEvent } from "../events/battle-scene"; import type { BerryUsedEvent, MoveUsedEvent } from "../events/battle-scene";
@ -201,7 +201,7 @@ export default class BattleFlyout extends Phaser.GameObjects.Container {
globalScene.tweens.add({ globalScene.tweens.add({
targets: this.flyoutParent, targets: this.flyoutParent,
x: visible ? this.anchorX : this.anchorX - this.translationX, x: visible ? this.anchorX : this.anchorX - this.translationX,
duration: Utils.fixedInt(125), duration: fixedInt(125),
ease: "Sine.easeInOut", ease: "Sine.easeInOut",
alpha: visible ? 1 : 0, alpha: visible ? 1 : 0,
}); });

View File

@ -1,6 +1,6 @@
import type { EnemyPokemon, default as Pokemon } from "../field/pokemon"; import type { EnemyPokemon, default as Pokemon } from "../field/pokemon";
import { getLevelTotalExp, getLevelRelExp } from "../data/exp"; import { getLevelTotalExp, getLevelRelExp } from "../data/exp";
import * as Utils from "../utils"; import { getLocalizedSpriteKey, fixedInt } from "#app/utils";
import { addTextObject, TextStyle } from "./text"; import { addTextObject, TextStyle } from "./text";
import { getGenderSymbol, getGenderColor, Gender } from "../data/gender"; import { getGenderSymbol, getGenderColor, Gender } from "../data/gender";
import { StatusEffect } from "#enums/status-effect"; import { StatusEffect } from "#enums/status-effect";
@ -163,7 +163,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
this.splicedIcon.setInteractive(new Phaser.Geom.Rectangle(0, 0, 12, 15), Phaser.Geom.Rectangle.Contains); this.splicedIcon.setInteractive(new Phaser.Geom.Rectangle(0, 0, 12, 15), Phaser.Geom.Rectangle.Contains);
this.add(this.splicedIcon); this.add(this.splicedIcon);
this.statusIndicator = globalScene.add.sprite(0, 0, Utils.getLocalizedSpriteKey("statuses")); this.statusIndicator = globalScene.add.sprite(0, 0, getLocalizedSpriteKey("statuses"));
this.statusIndicator.setName("icon_status"); this.statusIndicator.setName("icon_status");
this.statusIndicator.setVisible(false); this.statusIndicator.setVisible(false);
this.statusIndicator.setOrigin(0, 0); this.statusIndicator.setOrigin(0, 0);
@ -536,7 +536,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
toggleStats(visible: boolean): void { toggleStats(visible: boolean): void {
globalScene.tweens.add({ globalScene.tweens.add({
targets: this.statsContainer, targets: this.statsContainer,
duration: Utils.fixedInt(125), duration: fixedInt(125),
ease: "Sine.easeInOut", ease: "Sine.easeInOut",
alpha: visible ? 1 : 0, alpha: visible ? 1 : 0,
}); });

View File

@ -1,6 +1,6 @@
import { addTextObject, TextStyle } from "./text"; import { addTextObject, TextStyle } from "./text";
import i18next from "i18next"; import i18next from "i18next";
import * as Utils from "#app/utils"; import { formatText } from "#app/utils";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
const hiddenX = -150; const hiddenX = -150;
@ -100,7 +100,7 @@ export default class BgmBar extends Phaser.GameObjects.Container {
getRealBgmName(bgmName: string): string { getRealBgmName(bgmName: string): string {
return i18next.t([`bgmName:${bgmName}`, "bgmName:missing_entries"], { return i18next.t([`bgmName:${bgmName}`, "bgmName:missing_entries"], {
name: Utils.formatText(bgmName), name: formatText(bgmName),
}); });
} }
} }

View File

@ -2,7 +2,7 @@ import { starterColors } from "#app/battle-scene";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { TextStyle, addTextObject } from "./text"; import { TextStyle, addTextObject } from "./text";
import { argbFromRgba } from "@material/material-color-utilities"; import { argbFromRgba } from "@material/material-color-utilities";
import * as Utils from "../utils"; import { rgbHexToRgba } from "#app/utils";
import type { Species } from "#enums/species"; import type { Species } from "#enums/species";
export default class CandyBar extends Phaser.GameObjects.Container { export default class CandyBar extends Phaser.GameObjects.Container {
@ -60,8 +60,8 @@ export default class CandyBar extends Phaser.GameObjects.Container {
const colorScheme = starterColors[starterSpeciesId]; const colorScheme = starterColors[starterSpeciesId];
this.candyIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(colorScheme[0]))); this.candyIcon.setTint(argbFromRgba(rgbHexToRgba(colorScheme[0])));
this.candyOverlayIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(colorScheme[1]))); this.candyOverlayIcon.setTint(argbFromRgba(rgbHexToRgba(colorScheme[1])));
this.countText.setText( this.countText.setText(
`${globalScene.gameData.starterData[starterSpeciesId].candyCount + count} (+${count.toString()})`, `${globalScene.gameData.starterData[starterSpeciesId].candyCount + count} (+${count.toString()})`,

View File

@ -5,7 +5,7 @@ import { addWindow } from "./ui-theme";
import { Button } from "#enums/buttons"; import { Button } from "#enums/buttons";
import i18next from "i18next"; import i18next from "i18next";
import type { Challenge } from "#app/data/challenge"; import type { Challenge } from "#app/data/challenge";
import * as Utils from "../utils"; import { getLocalizedSpriteKey } from "#app/utils";
import { Challenges } from "#app/enums/challenges"; import { Challenges } from "#app/enums/challenges";
import BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext"; import BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext";
import { Color, ShadowColor } from "#app/enums/color"; import { Color, ShadowColor } from "#app/enums/color";
@ -193,7 +193,7 @@ export default class GameChallengesUiHandler extends UiHandler {
}; };
} }
this.monoTypeValue = globalScene.add.sprite(8, 98, Utils.getLocalizedSpriteKey("types")); this.monoTypeValue = globalScene.add.sprite(8, 98, getLocalizedSpriteKey("types"));
this.monoTypeValue.setName("challenge-value-monotype-sprite"); this.monoTypeValue.setName("challenge-value-monotype-sprite");
this.monoTypeValue.setScale(0.86); this.monoTypeValue.setScale(0.86);
this.monoTypeValue.setVisible(false); this.monoTypeValue.setVisible(false);

View File

@ -1,5 +1,5 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import * as Utils from "../utils"; import { MissingTextureKey } from "#app/utils";
export default class CharSprite extends Phaser.GameObjects.Container { export default class CharSprite extends Phaser.GameObjects.Container {
private sprite: Phaser.GameObjects.Sprite; private sprite: Phaser.GameObjects.Sprite;
@ -57,7 +57,7 @@ export default class CharSprite extends Phaser.GameObjects.Container {
}, },
}); });
this.setVisible(globalScene.textures.get(key).key !== Utils.MissingTextureKey); this.setVisible(globalScene.textures.get(key).key !== MissingTextureKey);
this.shown = true; this.shown = true;
this.key = key; this.key = key;

View File

@ -1,6 +1,6 @@
import i18next from "i18next"; import i18next from "i18next";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import * as Utils from "../utils"; import { getEnumKeys, executeIf } from "#app/utils";
import { TextStyle, addTextObject } from "./text"; import { TextStyle, addTextObject } from "./text";
import { WindowVariant, addWindow } from "./ui-theme"; import { WindowVariant, addWindow } from "./ui-theme";
import { pokerogueApi } from "#app/plugins/api/pokerogue-api"; import { pokerogueApi } from "#app/plugins/api/pokerogue-api";
@ -89,7 +89,7 @@ export class DailyRunScoreboard extends Phaser.GameObjects.Container {
this.prevCategoryButton.setInteractive(new Phaser.Geom.Rectangle(0, 0, 6, 10), Phaser.Geom.Rectangle.Contains); this.prevCategoryButton.setInteractive(new Phaser.Geom.Rectangle(0, 0, 6, 10), Phaser.Geom.Rectangle.Contains);
this.prevCategoryButton.on("pointerup", () => { this.prevCategoryButton.on("pointerup", () => {
this.update(this.category ? this.category - 1 : Utils.getEnumKeys(ScoreboardCategory).length - 1); this.update(this.category ? this.category - 1 : getEnumKeys(ScoreboardCategory).length - 1);
}); });
this.nextCategoryButton = globalScene.add.sprite(window.displayWidth - 4, 4, "cursor"); this.nextCategoryButton = globalScene.add.sprite(window.displayWidth - 4, 4, "cursor");
@ -98,7 +98,7 @@ export class DailyRunScoreboard extends Phaser.GameObjects.Container {
this.nextCategoryButton.setInteractive(new Phaser.Geom.Rectangle(0, 0, 6, 10), Phaser.Geom.Rectangle.Contains); this.nextCategoryButton.setInteractive(new Phaser.Geom.Rectangle(0, 0, 6, 10), Phaser.Geom.Rectangle.Contains);
this.nextCategoryButton.on("pointerup", () => { this.nextCategoryButton.on("pointerup", () => {
this.update(this.category < Utils.getEnumKeys(ScoreboardCategory).length - 1 ? this.category + 1 : 0); this.update(this.category < getEnumKeys(ScoreboardCategory).length - 1 ? this.category + 1 : 0);
}); });
this.prevPageButton = globalScene.add.sprite( this.prevPageButton = globalScene.add.sprite(
@ -226,7 +226,7 @@ export class DailyRunScoreboard extends Phaser.GameObjects.Container {
this.page = page = 1; this.page = page = 1;
} }
Utils.executeIf(category !== this.category || this.pageCount === undefined, () => executeIf(category !== this.category || this.pageCount === undefined, () =>
pokerogueApi.daily.getRankingsPageCount({ category }).then(count => (this.pageCount = count)), pokerogueApi.daily.getRankingsPageCount({ category }).then(count => (this.pageCount = count)),
) )
.then(() => { .then(() => {

View File

@ -1,7 +1,7 @@
import { Mode } from "./ui"; import { Mode } from "./ui";
import { TextStyle, addTextObject, getEggTierTextTint, getTextStyleOptions } from "./text"; import { TextStyle, addTextObject, getEggTierTextTint, getTextStyleOptions } from "./text";
import MessageUiHandler from "./message-ui-handler"; import MessageUiHandler from "./message-ui-handler";
import * as Utils from "../utils"; import { getEnumValues, getEnumKeys, fixedInt, randSeedShuffle } from "#app/utils";
import type { IEggOptions } from "../data/egg"; import type { IEggOptions } from "../data/egg";
import { Egg, getLegendaryGachaSpeciesForTimestamp } from "../data/egg"; import { Egg, getLegendaryGachaSpeciesForTimestamp } from "../data/egg";
import { VoucherType, getVoucherTypeIcon } from "../system/voucher"; import { VoucherType, getVoucherTypeIcon } from "../system/voucher";
@ -83,7 +83,7 @@ export default class EggGachaUiHandler extends MessageUiHandler {
}); });
} }
Utils.getEnumValues(GachaType).forEach((gachaType, g) => { getEnumValues(GachaType).forEach((gachaType, g) => {
const gachaTypeKey = GachaType[gachaType].toString().toLowerCase(); const gachaTypeKey = GachaType[gachaType].toString().toLowerCase();
const gachaContainer = globalScene.add.container(180 * g, 18); const gachaContainer = globalScene.add.container(180 * g, 18);
@ -272,7 +272,7 @@ export default class EggGachaUiHandler extends MessageUiHandler {
this.eggGachaContainer.add(this.eggGachaOptionsContainer); this.eggGachaContainer.add(this.eggGachaOptionsContainer);
new Array(Utils.getEnumKeys(VoucherType).length).fill(null).map((_, i) => { new Array(getEnumKeys(VoucherType).length).fill(null).map((_, i) => {
const container = globalScene.add.container(globalScene.game.canvas.width / 6 - 56 * i, 0); const container = globalScene.add.container(globalScene.game.canvas.width / 6 - 56 * i, 0);
const bg = addWindow(0, 0, 56, 22); const bg = addWindow(0, 0, 56, 22);
@ -355,7 +355,7 @@ export default class EggGachaUiHandler extends MessageUiHandler {
if (this.transitioning && this.transitionCancelled) { if (this.transitioning && this.transitionCancelled) {
delay = Math.ceil(delay / 5); delay = Math.ceil(delay / 5);
} }
return Utils.fixedInt(delay); return fixedInt(delay);
} }
pull(pullCount = 0, count = 0, eggs?: Egg[]): void { pull(pullCount = 0, count = 0, eggs?: Egg[]): void {
@ -476,7 +476,7 @@ export default class EggGachaUiHandler extends MessageUiHandler {
eggs.push(egg); eggs.push(egg);
} }
// Shuffle the eggs in case the guaranteed one got added as last egg // Shuffle the eggs in case the guaranteed one got added as last egg
eggs = Utils.randSeedShuffle<Egg>(eggs); eggs = randSeedShuffle<Egg>(eggs);
(globalScene.currentBattle (globalScene.currentBattle
? globalScene.gameData.saveAll(true, true, true) ? globalScene.gameData.saveAll(true, true, true)
@ -643,7 +643,7 @@ export default class EggGachaUiHandler extends MessageUiHandler {
} }
showError(text: string): void { showError(text: string): void {
this.showText(text, undefined, () => this.showText(this.defaultText), Utils.fixedInt(1500)); this.showText(text, undefined, () => this.showText(this.defaultText), fixedInt(1500));
} }
setTransitioning(transitioning: boolean): void { setTransitioning(transitioning: boolean): void {
@ -783,7 +783,7 @@ export default class EggGachaUiHandler extends MessageUiHandler {
} }
break; break;
case Button.RIGHT: case Button.RIGHT:
if (this.gachaCursor < Utils.getEnumKeys(GachaType).length - 1) { if (this.gachaCursor < getEnumKeys(GachaType).length - 1) {
success = this.setGachaCursor(this.gachaCursor + 1); success = this.setGachaCursor(this.gachaCursor + 1);
} }
break; break;

View File

@ -6,7 +6,7 @@ import { PokemonType } from "#enums/pokemon-type";
import { Command } from "./command-ui-handler"; import { Command } from "./command-ui-handler";
import { Mode } from "./ui"; import { Mode } from "./ui";
import UiHandler from "./ui-handler"; import UiHandler from "./ui-handler";
import * as Utils from "../utils"; import { getLocalizedSpriteKey, fixedInt, padInt } from "#app/utils";
import { MoveCategory } from "#enums/MoveCategory"; import { MoveCategory } from "#enums/MoveCategory";
import i18next from "i18next"; import i18next from "i18next";
import { Button } from "#enums/buttons"; import { Button } from "#enums/buttons";
@ -54,7 +54,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle {
this.typeIcon = globalScene.add.sprite( this.typeIcon = globalScene.add.sprite(
globalScene.scaledCanvas.width - 57, globalScene.scaledCanvas.width - 57,
-36, -36,
Utils.getLocalizedSpriteKey("types"), getLocalizedSpriteKey("types"),
"unknown", "unknown",
); );
this.typeIcon.setVisible(false); this.typeIcon.setVisible(false);
@ -199,7 +199,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle {
} }
globalScene.tweens.add({ globalScene.tweens.add({
targets: [this.movesContainer, this.cursorObj], targets: [this.movesContainer, this.cursorObj],
duration: Utils.fixedInt(125), duration: fixedInt(125),
ease: "Sine.easeInOut", ease: "Sine.easeInOut",
alpha: visible ? 0 : 1, alpha: visible ? 0 : 1,
}); });
@ -245,7 +245,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle {
if (hasMove) { if (hasMove) {
const pokemonMove = moveset[cursor]; const pokemonMove = moveset[cursor];
const moveType = pokemon.getMoveType(pokemonMove.getMove()); const moveType = pokemon.getMoveType(pokemonMove.getMove());
const textureKey = Utils.getLocalizedSpriteKey("types"); const textureKey = getLocalizedSpriteKey("types");
this.typeIcon.setTexture(textureKey, PokemonType[moveType].toLowerCase()).setScale(0.8); this.typeIcon.setTexture(textureKey, PokemonType[moveType].toLowerCase()).setScale(0.8);
const moveCategory = pokemonMove.getMove().category; const moveCategory = pokemonMove.getMove().category;
@ -255,8 +255,8 @@ export default class FightUiHandler extends UiHandler implements InfoToggle {
const maxPP = pokemonMove.getMovePp(); const maxPP = pokemonMove.getMovePp();
const pp = maxPP - pokemonMove.ppUsed; const pp = maxPP - pokemonMove.ppUsed;
const ppLeftStr = Utils.padInt(pp, 2, " "); const ppLeftStr = padInt(pp, 2, " ");
const ppMaxStr = Utils.padInt(maxPP, 2, " "); const ppMaxStr = padInt(maxPP, 2, " ");
this.ppText.setText(`${ppLeftStr}/${ppMaxStr}`); this.ppText.setText(`${ppLeftStr}/${ppMaxStr}`);
this.powerText.setText(`${power >= 0 ? power : "---"}`); this.powerText.setText(`${power >= 0 ? power : "---"}`);
this.accuracyText.setText(`${accuracy >= 0 ? accuracy : "---"}`); this.accuracyText.setText(`${accuracy >= 0 ? accuracy : "---"}`);

View File

@ -4,7 +4,7 @@ import type { Mode } from "./ui";
import { TextStyle, addTextInputObject, addTextObject } from "./text"; import { TextStyle, addTextInputObject, addTextObject } from "./text";
import { WindowVariant, addWindow } from "./ui-theme"; import { WindowVariant, addWindow } from "./ui-theme";
import type InputText from "phaser3-rex-plugins/plugins/inputtext"; import type InputText from "phaser3-rex-plugins/plugins/inputtext";
import * as Utils from "../utils"; import { fixedInt } from "#app/utils";
import { Button } from "#enums/buttons"; import { Button } from "#enums/buttons";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
@ -135,7 +135,7 @@ export abstract class FormModalUiHandler extends ModalUiHandler {
this.tween = globalScene.tweens.add({ this.tween = globalScene.tweens.add({
targets: this.modalContainer, targets: this.modalContainer,
duration: Utils.fixedInt(1000), duration: fixedInt(1000),
ease: "Sine.easeInOut", ease: "Sine.easeInOut",
y: "-=24", y: "-=24",
alpha: 1, alpha: 1,

View File

@ -3,7 +3,7 @@ import { TextStyle, addTextObject } from "#app/ui/text";
import type { Mode } from "#app/ui/ui"; import type { Mode } from "#app/ui/ui";
import UiHandler from "#app/ui/ui-handler"; import UiHandler from "#app/ui/ui-handler";
import { addWindow } from "#app/ui/ui-theme"; import { addWindow } from "#app/ui/ui-theme";
import * as Utils from "#app/utils"; import { getPlayTimeString, formatFancyLargeNumber, toReadableString } from "#app/utils";
import type { GameData } from "#app/system/game-data"; import type { GameData } from "#app/system/game-data";
import { DexAttr } from "#app/system/game-data"; import { DexAttr } from "#app/system/game-data";
import { speciesStarterCosts } from "#app/data/balance/starters"; import { speciesStarterCosts } from "#app/data/balance/starters";
@ -25,7 +25,7 @@ interface DisplayStats {
const displayStats: DisplayStats = { const displayStats: DisplayStats = {
playTime: { playTime: {
label_key: "playTime", label_key: "playTime",
sourceFunc: gameData => Utils.getPlayTimeString(gameData.gameStats.playTime), sourceFunc: gameData => getPlayTimeString(gameData.gameStats.playTime),
}, },
battles: { battles: {
label_key: "totalBattles", label_key: "totalBattles",
@ -91,7 +91,7 @@ const displayStats: DisplayStats = {
}, },
highestMoney: { highestMoney: {
label_key: "highestMoney", label_key: "highestMoney",
sourceFunc: gameData => Utils.formatFancyLargeNumber(gameData.gameStats.highestMoney), sourceFunc: gameData => formatFancyLargeNumber(gameData.gameStats.highestMoney),
}, },
highestDamage: { highestDamage: {
label_key: "highestDamage", label_key: "highestDamage",
@ -435,7 +435,7 @@ export function initStatsKeys() {
} }
if (!(displayStats[key] as DisplayStat).label_key) { if (!(displayStats[key] as DisplayStat).label_key) {
const splittableKey = key.replace(/([a-z]{2,})([A-Z]{1}(?:[^A-Z]|$))/g, "$1_$2"); const splittableKey = key.replace(/([a-z]{2,})([A-Z]{1}(?:[^A-Z]|$))/g, "$1_$2");
(displayStats[key] as DisplayStat).label_key = Utils.toReadableString( (displayStats[key] as DisplayStat).label_key = toReadableString(
`${splittableKey[0].toUpperCase()}${splittableKey.slice(1)}`, `${splittableKey[0].toUpperCase()}${splittableKey.slice(1)}`,
); );
} }

View File

@ -1,7 +1,7 @@
import type { InputFieldConfig } from "./form-modal-ui-handler"; import type { InputFieldConfig } from "./form-modal-ui-handler";
import { FormModalUiHandler } from "./form-modal-ui-handler"; import { FormModalUiHandler } from "./form-modal-ui-handler";
import type { ModalConfig } from "./modal-ui-handler"; import type { ModalConfig } from "./modal-ui-handler";
import * as Utils from "../utils"; import { fixedInt } from "#app/utils";
import { Mode } from "./ui"; import { Mode } from "./ui";
import i18next from "i18next"; import i18next from "i18next";
import { addTextObject, TextStyle } from "./text"; import { addTextObject, TextStyle } from "./text";
@ -283,7 +283,7 @@ export default class LoginFormUiHandler extends FormModalUiHandler {
this.externalPartyContainer.setAlpha(0); this.externalPartyContainer.setAlpha(0);
globalScene.tweens.add({ globalScene.tweens.add({
targets: this.externalPartyContainer, targets: this.externalPartyContainer,
duration: Utils.fixedInt(1000), duration: fixedInt(1000),
ease: "Sine.easeInOut", ease: "Sine.easeInOut",
y: "-=24", y: "-=24",
alpha: 1, alpha: 1,
@ -292,7 +292,7 @@ export default class LoginFormUiHandler extends FormModalUiHandler {
this.infoContainer.setAlpha(0); this.infoContainer.setAlpha(0);
globalScene.tweens.add({ globalScene.tweens.add({
targets: this.infoContainer, targets: this.infoContainer,
duration: Utils.fixedInt(1000), duration: fixedInt(1000),
ease: "Sine.easeInOut", ease: "Sine.easeInOut",
y: "-=24", y: "-=24",
alpha: 1, alpha: 1,

View File

@ -2,7 +2,7 @@ import { bypassLogin } from "#app/battle-scene";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { TextStyle, addTextObject, getTextStyleOptions } from "./text"; import { TextStyle, addTextObject, getTextStyleOptions } from "./text";
import { Mode } from "./ui"; import { Mode } from "./ui";
import * as Utils from "../utils"; import { getEnumKeys, isLocal, isBeta, fixedInt, getCookie, sessionIdKey } from "#app/utils";
import { addWindow, WindowVariant } from "./ui-theme"; import { addWindow, WindowVariant } from "./ui-theme";
import MessageUiHandler from "./message-ui-handler"; import MessageUiHandler from "./message-ui-handler";
import type { OptionSelectConfig, OptionSelectItem } from "./abstact-option-select-ui-handler"; import type { OptionSelectConfig, OptionSelectItem } from "./abstact-option-select-ui-handler";
@ -75,7 +75,7 @@ export default class MenuUiHandler extends MessageUiHandler {
{ condition: bypassLogin, options: [MenuOptions.LOG_OUT] }, { condition: bypassLogin, options: [MenuOptions.LOG_OUT] },
]; ];
this.menuOptions = Utils.getEnumKeys(MenuOptions) this.menuOptions = getEnumKeys(MenuOptions)
.map(m => Number.parseInt(MenuOptions[m]) as MenuOptions) .map(m => Number.parseInt(MenuOptions[m]) as MenuOptions)
.filter(m => { .filter(m => {
return !this.excludedMenus().some(exclusion => exclusion.condition && exclusion.options.includes(m)); return !this.excludedMenus().some(exclusion => exclusion.condition && exclusion.options.includes(m));
@ -130,7 +130,7 @@ export default class MenuUiHandler extends MessageUiHandler {
{ condition: bypassLogin, options: [MenuOptions.LOG_OUT] }, { condition: bypassLogin, options: [MenuOptions.LOG_OUT] },
]; ];
this.menuOptions = Utils.getEnumKeys(MenuOptions) this.menuOptions = getEnumKeys(MenuOptions)
.map(m => Number.parseInt(MenuOptions[m]) as MenuOptions) .map(m => Number.parseInt(MenuOptions[m]) as MenuOptions)
.filter(m => { .filter(m => {
return !this.excludedMenus().some(exclusion => exclusion.condition && exclusion.options.includes(m)); return !this.excludedMenus().some(exclusion => exclusion.condition && exclusion.options.includes(m));
@ -238,7 +238,7 @@ export default class MenuUiHandler extends MessageUiHandler {
}); });
}; };
if (Utils.isLocal || Utils.isBeta) { if (isLocal || isBeta) {
manageDataOptions.push({ manageDataOptions.push({
label: i18next.t("menuUiHandler:importSession"), label: i18next.t("menuUiHandler:importSession"),
handler: () => { handler: () => {
@ -292,7 +292,7 @@ export default class MenuUiHandler extends MessageUiHandler {
}, },
keepOpen: true, keepOpen: true,
}); });
if (Utils.isLocal || Utils.isBeta) { if (isLocal || isBeta) {
manageDataOptions.push({ manageDataOptions.push({
label: i18next.t("menuUiHandler:importData"), label: i18next.t("menuUiHandler:importData"),
handler: () => { handler: () => {
@ -328,7 +328,7 @@ export default class MenuUiHandler extends MessageUiHandler {
keepOpen: true, keepOpen: true,
}, },
); );
if (Utils.isLocal || Utils.isBeta) { if (isLocal || isBeta) {
// this should make sure we don't have this option in live // this should make sure we don't have this option in live
manageDataOptions.push({ manageDataOptions.push({
label: "Test Dialogue", label: "Test Dialogue",
@ -510,7 +510,7 @@ export default class MenuUiHandler extends MessageUiHandler {
this.render(); this.render();
super.show(args); super.show(args);
this.menuOptions = Utils.getEnumKeys(MenuOptions) this.menuOptions = getEnumKeys(MenuOptions)
.map(m => Number.parseInt(MenuOptions[m]) as MenuOptions) .map(m => Number.parseInt(MenuOptions[m]) as MenuOptions)
.filter(m => { .filter(m => {
return !this.excludedMenus().some(exclusion => exclusion.condition && exclusion.options.includes(m)); return !this.excludedMenus().some(exclusion => exclusion.condition && exclusion.options.includes(m));
@ -574,7 +574,7 @@ export default class MenuUiHandler extends MessageUiHandler {
ui.setOverlayMode(Mode.EGG_LIST); ui.setOverlayMode(Mode.EGG_LIST);
success = true; success = true;
} else { } else {
ui.showText(i18next.t("menuUiHandler:noEggs"), null, () => ui.showText(""), Utils.fixedInt(1500)); ui.showText(i18next.t("menuUiHandler:noEggs"), null, () => ui.showText(""), fixedInt(1500));
error = true; error = true;
} }
break; break;
@ -607,7 +607,7 @@ export default class MenuUiHandler extends MessageUiHandler {
: i18next.t("menuUiHandler:unlinkDiscord"), : i18next.t("menuUiHandler:unlinkDiscord"),
handler: () => { handler: () => {
if (loggedInUser?.discordId === "") { if (loggedInUser?.discordId === "") {
const token = Utils.getCookie(Utils.sessionIdKey); const token = getCookie(sessionIdKey);
const redirectUri = encodeURIComponent(`${import.meta.env.VITE_SERVER_URL}/auth/discord/callback`); const redirectUri = encodeURIComponent(`${import.meta.env.VITE_SERVER_URL}/auth/discord/callback`);
const discordId = import.meta.env.VITE_DISCORD_CLIENT_ID; const discordId = import.meta.env.VITE_DISCORD_CLIENT_ID;
const discordUrl = `https://discord.com/api/oauth2/authorize?client_id=${discordId}&redirect_uri=${redirectUri}&response_type=code&scope=identify&state=${token}&prompt=none`; const discordUrl = `https://discord.com/api/oauth2/authorize?client_id=${discordId}&redirect_uri=${redirectUri}&response_type=code&scope=identify&state=${token}&prompt=none`;
@ -627,7 +627,7 @@ export default class MenuUiHandler extends MessageUiHandler {
: i18next.t("menuUiHandler:unlinkGoogle"), : i18next.t("menuUiHandler:unlinkGoogle"),
handler: () => { handler: () => {
if (loggedInUser?.googleId === "") { if (loggedInUser?.googleId === "") {
const token = Utils.getCookie(Utils.sessionIdKey); const token = getCookie(sessionIdKey);
const redirectUri = encodeURIComponent(`${import.meta.env.VITE_SERVER_URL}/auth/google/callback`); const redirectUri = encodeURIComponent(`${import.meta.env.VITE_SERVER_URL}/auth/google/callback`);
const googleId = import.meta.env.VITE_GOOGLE_CLIENT_ID; const googleId = import.meta.env.VITE_GOOGLE_CLIENT_ID;
const googleUrl = `https://accounts.google.com/o/oauth2/auth?client_id=${googleId}&response_type=code&redirect_uri=${redirectUri}&scope=openid&state=${token}`; const googleUrl = `https://accounts.google.com/o/oauth2/auth?client_id=${googleId}&response_type=code&redirect_uri=${redirectUri}&scope=openid&state=${token}`;

View File

@ -1,6 +1,6 @@
import AwaitableUiHandler from "./awaitable-ui-handler"; import AwaitableUiHandler from "./awaitable-ui-handler";
import type { Mode } from "./ui"; import type { Mode } from "./ui";
import * as Utils from "../utils"; import { getFrameMs } from "#app/utils";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
export default abstract class MessageUiHandler extends AwaitableUiHandler { export default abstract class MessageUiHandler extends AwaitableUiHandler {
@ -183,7 +183,7 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler {
if (charDelay) { if (charDelay) {
this.textTimer!.paused = true; // TODO: is the bang correct? this.textTimer!.paused = true; // TODO: is the bang correct?
globalScene.tweens.addCounter({ globalScene.tweens.addCounter({
duration: Utils.getFrameMs(charDelay), duration: getFrameMs(charDelay),
onComplete: () => { onComplete: () => {
this.textTimer!.paused = false; // TODO: is the bang correct? this.textTimer!.paused = false; // TODO: is the bang correct?
advance(); advance();
@ -193,7 +193,7 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler {
this.textTimer!.paused = true; this.textTimer!.paused = true;
globalScene.time.delayedCall(150, () => { globalScene.time.delayedCall(150, () => {
globalScene.ui.fadeOut(750).then(() => { globalScene.ui.fadeOut(750).then(() => {
const delay = Utils.getFrameMs(charFade); const delay = getFrameMs(charFade);
globalScene.time.delayedCall(delay, () => { globalScene.time.delayedCall(delay, () => {
globalScene.ui.fadeIn(500).then(() => { globalScene.ui.fadeIn(500).then(() => {
this.textTimer!.paused = false; this.textTimer!.paused = false;

View File

@ -10,11 +10,10 @@ import { handleTutorial, Tutorial } from "../tutorial";
import { Button } from "#enums/buttons"; import { Button } from "#enums/buttons";
import MoveInfoOverlay from "./move-info-overlay"; import MoveInfoOverlay from "./move-info-overlay";
import { allMoves } from "../data/moves/move"; import { allMoves } from "../data/moves/move";
import * as Utils from "./../utils"; import { formatMoney, NumberHolder } from "#app/utils";
import Overrides from "#app/overrides"; import Overrides from "#app/overrides";
import i18next from "i18next"; import i18next from "i18next";
import { ShopCursorTarget } from "#app/enums/shop-cursor-target"; import { ShopCursorTarget } from "#app/enums/shop-cursor-target";
import { NumberHolder } from "./../utils";
import Phaser from "phaser"; import Phaser from "phaser";
import type { PokeballType } from "#enums/pokeball"; import type { PokeballType } from "#enums/pokeball";
@ -645,7 +644,7 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
this.rerollCostText.setVisible(true); this.rerollCostText.setVisible(true);
const canReroll = globalScene.money >= this.rerollCost; const canReroll = globalScene.money >= this.rerollCost;
const formattedMoney = Utils.formatMoney(globalScene.moneyFormat, this.rerollCost); const formattedMoney = formatMoney(globalScene.moneyFormat, this.rerollCost);
this.rerollCostText.setText(i18next.t("modifierSelectUiHandler:rerollCost", { formattedMoney })); this.rerollCostText.setText(i18next.t("modifierSelectUiHandler:rerollCost", { formattedMoney }));
this.rerollCostText.setColor(this.getTextColor(canReroll ? TextStyle.MONEY : TextStyle.PARTY_RED)); this.rerollCostText.setColor(this.getTextColor(canReroll ? TextStyle.MONEY : TextStyle.PARTY_RED));
@ -933,7 +932,7 @@ class ModifierOption extends Phaser.GameObjects.Container {
const cost = Overrides.WAIVE_ROLL_FEE_OVERRIDE ? 0 : this.modifierTypeOption.cost; const cost = Overrides.WAIVE_ROLL_FEE_OVERRIDE ? 0 : this.modifierTypeOption.cost;
const textStyle = cost <= globalScene.money ? TextStyle.MONEY : TextStyle.PARTY_RED; const textStyle = cost <= globalScene.money ? TextStyle.MONEY : TextStyle.PARTY_RED;
const formattedMoney = Utils.formatMoney(globalScene.moneyFormat, cost); const formattedMoney = formatMoney(globalScene.moneyFormat, cost);
this.itemCostText.setText(i18next.t("modifierSelectUiHandler:itemCost", { formattedMoney })); this.itemCostText.setText(i18next.t("modifierSelectUiHandler:itemCost", { formattedMoney }));
this.itemCostText.setColor(getTextColor(textStyle, false, globalScene.uiTheme)); this.itemCostText.setColor(getTextColor(textStyle, false, globalScene.uiTheme));

View File

@ -2,7 +2,7 @@ import type { InfoToggle } from "#app/battle-scene";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { TextStyle, addTextObject } from "./text"; import { TextStyle, addTextObject } from "./text";
import { addWindow } from "./ui-theme"; import { addWindow } from "./ui-theme";
import * as Utils from "../utils"; import { getLocalizedSpriteKey, fixedInt } from "#app/utils";
import type Move from "../data/moves/move"; import type Move from "../data/moves/move";
import { MoveCategory } from "#enums/MoveCategory"; import { MoveCategory } from "#enums/MoveCategory";
import { PokemonType } from "#enums/pokemon-type"; import { PokemonType } from "#enums/pokemon-type";
@ -120,7 +120,7 @@ export default class MoveInfoOverlay extends Phaser.GameObjects.Container implem
valuesBg.setOrigin(0, 0); valuesBg.setOrigin(0, 0);
this.val.add(valuesBg); this.val.add(valuesBg);
this.typ = globalScene.add.sprite(25, EFF_HEIGHT - 35, Utils.getLocalizedSpriteKey("types"), "unknown"); this.typ = globalScene.add.sprite(25, EFF_HEIGHT - 35, getLocalizedSpriteKey("types"), "unknown");
this.typ.setScale(0.8); this.typ.setScale(0.8);
this.val.add(this.typ); this.val.add(this.typ);
@ -175,7 +175,7 @@ export default class MoveInfoOverlay extends Phaser.GameObjects.Container implem
this.pow.setText(move.power >= 0 ? move.power.toString() : "---"); this.pow.setText(move.power >= 0 ? move.power.toString() : "---");
this.acc.setText(move.accuracy >= 0 ? move.accuracy.toString() : "---"); this.acc.setText(move.accuracy >= 0 ? move.accuracy.toString() : "---");
this.pp.setText(move.pp >= 0 ? move.pp.toString() : "---"); this.pp.setText(move.pp >= 0 ? move.pp.toString() : "---");
this.typ.setTexture(Utils.getLocalizedSpriteKey("types"), PokemonType[move.type].toLowerCase()); this.typ.setTexture(getLocalizedSpriteKey("types"), PokemonType[move.type].toLowerCase());
this.cat.setFrame(MoveCategory[move.category].toLowerCase()); this.cat.setFrame(MoveCategory[move.category].toLowerCase());
this.desc.setText(move?.effect || ""); this.desc.setText(move?.effect || "");
@ -193,10 +193,10 @@ export default class MoveInfoOverlay extends Phaser.GameObjects.Container implem
// generate scrolling effects // generate scrolling effects
this.descScroll = globalScene.tweens.add({ this.descScroll = globalScene.tweens.add({
targets: this.desc, targets: this.desc,
delay: Utils.fixedInt(2000), delay: fixedInt(2000),
loop: -1, loop: -1,
hold: Utils.fixedInt(2000), hold: fixedInt(2000),
duration: Utils.fixedInt((moveDescriptionLineCount - 3) * 2000), duration: fixedInt((moveDescriptionLineCount - 3) * 2000),
y: `-=${14.83 * (72 / 96) * (moveDescriptionLineCount - 3)}`, y: `-=${14.83 * (72 / 96) * (moveDescriptionLineCount - 3)}`,
}); });
} }
@ -219,7 +219,7 @@ export default class MoveInfoOverlay extends Phaser.GameObjects.Container implem
} }
globalScene.tweens.add({ globalScene.tweens.add({
targets: this.desc, targets: this.desc,
duration: Utils.fixedInt(125), duration: fixedInt(125),
ease: "Sine.easeInOut", ease: "Sine.easeInOut",
alpha: visible ? 1 : 0, alpha: visible ? 1 : 0,
}); });

View File

@ -6,8 +6,7 @@ import { addWindow, WindowVariant } from "./ui-theme";
import type { MysteryEncounterPhase } from "../phases/mystery-encounter-phases"; import type { MysteryEncounterPhase } from "../phases/mystery-encounter-phases";
import { PartyUiMode } from "./party-ui-handler"; import { PartyUiMode } from "./party-ui-handler";
import type MysteryEncounterOption from "#app/data/mystery-encounters/mystery-encounter-option"; import type MysteryEncounterOption from "#app/data/mystery-encounters/mystery-encounter-option";
import * as Utils from "../utils"; import { fixedInt, isNullOrUndefined } from "#app/utils";
import { isNullOrUndefined } from "../utils";
import { getPokeballAtlasKey } from "../data/pokeball"; import { getPokeballAtlasKey } from "../data/pokeball";
import type { OptionSelectSettings } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import type { OptionSelectSettings } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { getEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { getEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
@ -456,10 +455,10 @@ export default class MysteryEncounterUiHandler extends UiHandler {
if (optionTextWidth > nonScrollWidth) { if (optionTextWidth > nonScrollWidth) {
this.optionScrollTweens[i] = globalScene.tweens.add({ this.optionScrollTweens[i] = globalScene.tweens.add({
targets: optionText, targets: optionText,
delay: Utils.fixedInt(2000), delay: fixedInt(2000),
loop: -1, loop: -1,
hold: Utils.fixedInt(2000), hold: fixedInt(2000),
duration: Utils.fixedInt(((optionTextWidth - nonScrollWidth) / 15) * 2000), duration: fixedInt(((optionTextWidth - nonScrollWidth) / 15) * 2000),
x: `-=${optionTextWidth - nonScrollWidth}`, x: `-=${optionTextWidth - nonScrollWidth}`,
}); });
} }
@ -527,10 +526,10 @@ export default class MysteryEncounterUiHandler extends UiHandler {
if (descriptionLineCount > 6) { if (descriptionLineCount > 6) {
this.descriptionScrollTween = globalScene.tweens.add({ this.descriptionScrollTween = globalScene.tweens.add({
targets: descriptionTextObject, targets: descriptionTextObject,
delay: Utils.fixedInt(2000), delay: fixedInt(2000),
loop: -1, loop: -1,
hold: Utils.fixedInt(2000), hold: fixedInt(2000),
duration: Utils.fixedInt((descriptionLineCount - 6) * 2000), duration: fixedInt((descriptionLineCount - 6) * 2000),
y: `-=${10 * (descriptionLineCount - 6)}`, y: `-=${10 * (descriptionLineCount - 6)}`,
}); });
} }
@ -637,10 +636,10 @@ export default class MysteryEncounterUiHandler extends UiHandler {
if (tooltipLineCount > 3) { if (tooltipLineCount > 3) {
this.tooltipScrollTween = globalScene.tweens.add({ this.tooltipScrollTween = globalScene.tweens.add({
targets: tooltipTextObject, targets: tooltipTextObject,
delay: Utils.fixedInt(1200), delay: fixedInt(1200),
loop: -1, loop: -1,
hold: Utils.fixedInt(1200), hold: fixedInt(1200),
duration: Utils.fixedInt((tooltipLineCount - 3) * 1200), duration: fixedInt((tooltipLineCount - 3) * 1200),
y: `-=${11.2 * (tooltipLineCount - 3)}`, y: `-=${11.2 * (tooltipLineCount - 3)}`,
}); });
} }

View File

@ -5,7 +5,7 @@ import { addBBCodeTextObject, addTextObject, getTextColor, TextStyle } from "#ap
import { Command } from "#app/ui/command-ui-handler"; import { Command } from "#app/ui/command-ui-handler";
import MessageUiHandler from "#app/ui/message-ui-handler"; import MessageUiHandler from "#app/ui/message-ui-handler";
import { Mode } from "#app/ui/ui"; import { Mode } from "#app/ui/ui";
import * as Utils from "#app/utils"; import { BooleanHolder, toReadableString, randInt, getLocalizedSpriteKey } from "#app/utils";
import { import {
PokemonFormChangeItemModifier, PokemonFormChangeItemModifier,
PokemonHeldItemModifier, PokemonHeldItemModifier,
@ -215,7 +215,7 @@ export default class PartyUiHandler extends MessageUiHandler {
* @returns * @returns
*/ */
private FilterChallengeLegal = (pokemon: PlayerPokemon) => { private FilterChallengeLegal = (pokemon: PlayerPokemon) => {
const challengeAllowed = new Utils.BooleanHolder(true); const challengeAllowed = new BooleanHolder(true);
applyChallenges(ChallengeType.POKEMON_IN_BATTLE, pokemon, challengeAllowed); applyChallenges(ChallengeType.POKEMON_IN_BATTLE, pokemon, challengeAllowed);
if (!challengeAllowed.value) { if (!challengeAllowed.value) {
return i18next.t("partyUiHandler:cantBeUsed", { return i18next.t("partyUiHandler:cantBeUsed", {
@ -1201,7 +1201,7 @@ export default class PartyUiHandler extends MessageUiHandler {
if (this.localizedOptions.includes(option)) { if (this.localizedOptions.includes(option)) {
optionName = i18next.t(`partyUiHandler:${PartyOption[option]}`); optionName = i18next.t(`partyUiHandler:${PartyOption[option]}`);
} else { } else {
optionName = Utils.toReadableString(PartyOption[option]); optionName = toReadableString(PartyOption[option]);
} }
} }
break; break;
@ -1309,7 +1309,7 @@ export default class PartyUiHandler extends MessageUiHandler {
} }
getReleaseMessage(pokemonName: string): string { getReleaseMessage(pokemonName: string): string {
const rand = Utils.randInt(128); const rand = randInt(128);
if (rand < 20) { if (rand < 20) {
return i18next.t("partyUiHandler:goodbye", { pokemonName: pokemonName }); return i18next.t("partyUiHandler:goodbye", { pokemonName: pokemonName });
} }
@ -1566,7 +1566,7 @@ class PartySlot extends Phaser.GameObjects.Container {
} }
if (this.pokemon.status) { if (this.pokemon.status) {
const statusIndicator = globalScene.add.sprite(0, 0, Utils.getLocalizedSpriteKey("statuses")); const statusIndicator = globalScene.add.sprite(0, 0, getLocalizedSpriteKey("statuses"));
statusIndicator.setFrame(StatusEffect[this.pokemon.status?.effect].toLowerCase()); statusIndicator.setFrame(StatusEffect[this.pokemon.status?.effect].toLowerCase());
statusIndicator.setOrigin(0, 0); statusIndicator.setOrigin(0, 0);
statusIndicator.setPositionRelative(slotLevelLabel, this.slotIndex >= battlerCount ? 43 : 55, 0); statusIndicator.setPositionRelative(slotLevelLabel, this.slotIndex >= battlerCount ? 43 : 55, 0);

View File

@ -1,7 +1,7 @@
import type { InfoToggle } from "../battle-scene"; import type { InfoToggle } from "../battle-scene";
import { TextStyle, addTextObject } from "./text"; import { TextStyle, addTextObject } from "./text";
import { addWindow } from "./ui-theme"; import { addWindow } from "./ui-theme";
import * as Utils from "../utils"; import { fixedInt } from "#app/utils";
import i18next from "i18next"; import i18next from "i18next";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
@ -128,10 +128,10 @@ export default class PokedexInfoOverlay extends Phaser.GameObjects.Container imp
// generate scrolling effects // generate scrolling effects
this.descScroll = globalScene.tweens.add({ this.descScroll = globalScene.tweens.add({
targets: this.desc, targets: this.desc,
delay: Utils.fixedInt(2000), delay: fixedInt(2000),
loop: -1, loop: -1,
hold: Utils.fixedInt(2000), hold: fixedInt(2000),
duration: Utils.fixedInt((lineCount - 3) * 2000), duration: fixedInt((lineCount - 3) * 2000),
y: `-=${14.83 * (72 / 96) * (lineCount - 3)}`, y: `-=${14.83 * (72 / 96) * (lineCount - 3)}`,
}); });
} }
@ -154,7 +154,7 @@ export default class PokedexInfoOverlay extends Phaser.GameObjects.Container imp
} }
globalScene.tweens.add({ globalScene.tweens.add({
targets: this.desc, targets: this.desc,
duration: Utils.fixedInt(125), duration: fixedInt(125),
ease: "Sine.easeInOut", ease: "Sine.easeInOut",
alpha: visible ? 1 : 0, alpha: visible ? 1 : 0,
}); });

View File

@ -54,7 +54,7 @@ import {
toReadableString, toReadableString,
} from "#app/utils"; } from "#app/utils";
import type { Nature } from "#enums/nature"; import type { Nature } from "#enums/nature";
import * as Utils from "../utils"; import { getEnumKeys } from "#app/utils";
import { speciesTmMoves } from "#app/data/balance/tms"; import { speciesTmMoves } from "#app/data/balance/tms";
import type { BiomeTierTod } from "#app/data/balance/biomes"; import type { BiomeTierTod } from "#app/data/balance/biomes";
import { BiomePoolTier, catchableSpecies } from "#app/data/balance/biomes"; import { BiomePoolTier, catchableSpecies } from "#app/data/balance/biomes";
@ -592,7 +592,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
this.menuContainer.setVisible(false); this.menuContainer.setVisible(false);
this.menuOptions = Utils.getEnumKeys(MenuOptions).map(m => Number.parseInt(MenuOptions[m]) as MenuOptions); this.menuOptions = getEnumKeys(MenuOptions).map(m => Number.parseInt(MenuOptions[m]) as MenuOptions);
this.optionSelectText = addBBCodeTextObject( this.optionSelectText = addBBCodeTextObject(
0, 0,
@ -696,7 +696,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
this.starterAttributes = this.initStarterPrefs(); this.starterAttributes = this.initStarterPrefs();
this.menuOptions = Utils.getEnumKeys(MenuOptions).map(m => Number.parseInt(MenuOptions[m]) as MenuOptions); this.menuOptions = getEnumKeys(MenuOptions).map(m => Number.parseInt(MenuOptions[m]) as MenuOptions);
this.menuContainer.setVisible(true); this.menuContainer.setVisible(true);

View File

@ -1,7 +1,7 @@
import PokemonInfoContainer from "#app/ui/pokemon-info-container"; import PokemonInfoContainer from "#app/ui/pokemon-info-container";
import { Gender } from "#app/data/gender"; import { Gender } from "#app/data/gender";
import { PokemonType } from "#enums/pokemon-type"; import { PokemonType } from "#enums/pokemon-type";
import * as Utils from "#app/utils"; import { rgbHexToRgba, padInt } from "#app/utils";
import { TextStyle, addTextObject } from "#app/ui/text"; import { TextStyle, addTextObject } from "#app/ui/text";
import { speciesEggMoves } from "#app/data/balance/egg-moves"; import { speciesEggMoves } from "#app/data/balance/egg-moves";
import { allMoves } from "#app/data/moves/move"; import { allMoves } from "#app/data/moves/move";
@ -154,14 +154,14 @@ export default class PokemonHatchInfoContainer extends PokemonInfoContainer {
super.show(pokemon, false, 1, hatchInfo.getDex(), hatchInfo.getStarterEntry(), true); super.show(pokemon, false, 1, hatchInfo.getDex(), hatchInfo.getStarterEntry(), true);
const colorScheme = starterColors[species.speciesId]; const colorScheme = starterColors[species.speciesId];
this.pokemonCandyIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(colorScheme[0]))); this.pokemonCandyIcon.setTint(argbFromRgba(rgbHexToRgba(colorScheme[0])));
this.pokemonCandyIcon.setVisible(true); this.pokemonCandyIcon.setVisible(true);
this.pokemonCandyOverlayIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(colorScheme[1]))); this.pokemonCandyOverlayIcon.setTint(argbFromRgba(rgbHexToRgba(colorScheme[1])));
this.pokemonCandyOverlayIcon.setVisible(true); this.pokemonCandyOverlayIcon.setVisible(true);
this.pokemonCandyCountText.setText(`x${globalScene.gameData.starterData[species.speciesId].candyCount}`); this.pokemonCandyCountText.setText(`x${globalScene.gameData.starterData[species.speciesId].candyCount}`);
this.pokemonCandyCountText.setVisible(true); this.pokemonCandyCountText.setVisible(true);
this.pokemonNumberText.setText(Utils.padInt(species.speciesId, 4)); this.pokemonNumberText.setText(padInt(species.speciesId, 4));
this.pokemonNameText.setText(species.name); this.pokemonNameText.setText(species.name);
const hasEggMoves = species && speciesEggMoves.hasOwnProperty(species.speciesId); const hasEggMoves = species && speciesEggMoves.hasOwnProperty(species.speciesId);

View File

@ -1,5 +1,5 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import * as Utils from "../utils"; import { fixedInt } from "#app/utils";
export enum PokemonIconAnimMode { export enum PokemonIconAnimMode {
NONE, NONE,
@ -27,7 +27,7 @@ export default class PokemonIconAnimHandler {
} }
}; };
globalScene.tweens.addCounter({ globalScene.tweens.addCounter({
duration: Utils.fixedInt(200), duration: fixedInt(200),
from: 0, from: 0,
to: 1, to: 1,
yoyo: true, yoyo: true,

View File

@ -8,7 +8,7 @@ import type Pokemon from "../field/pokemon";
import i18next from "i18next"; import i18next from "i18next";
import type { DexEntry, StarterDataEntry } from "../system/game-data"; import type { DexEntry, StarterDataEntry } from "../system/game-data";
import { DexAttr } from "../system/game-data"; import { DexAttr } from "../system/game-data";
import * as Utils from "../utils"; import { fixedInt } from "#app/utils";
import ConfirmUiHandler from "./confirm-ui-handler"; import ConfirmUiHandler from "./confirm-ui-handler";
import { StatsContainer } from "./stats-container"; import { StatsContainer } from "./stats-container";
import { TextStyle, addBBCodeTextObject, addTextObject, getTextColor } from "./text"; import { TextStyle, addBBCodeTextObject, addTextObject, getTextColor } from "./text";
@ -393,7 +393,7 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container {
if (!eggInfo) { if (!eggInfo) {
globalScene.tweens.add({ globalScene.tweens.add({
targets: this, targets: this,
duration: Utils.fixedInt(Math.floor(750 / speedMultiplier)), duration: fixedInt(Math.floor(750 / speedMultiplier)),
ease: "Cubic.easeInOut", ease: "Cubic.easeInOut",
x: this.initialX - this.infoWindowWidth, x: this.initialX - this.infoWindowWidth,
onComplete: () => { onComplete: () => {
@ -403,9 +403,9 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container {
if (showMoves) { if (showMoves) {
globalScene.tweens.add({ globalScene.tweens.add({
delay: Utils.fixedInt(Math.floor(325 / speedMultiplier)), delay: fixedInt(Math.floor(325 / speedMultiplier)),
targets: this.pokemonMovesContainer, targets: this.pokemonMovesContainer,
duration: Utils.fixedInt(Math.floor(325 / speedMultiplier)), duration: fixedInt(Math.floor(325 / speedMultiplier)),
ease: "Cubic.easeInOut", ease: "Cubic.easeInOut",
x: this.movesContainerInitialX - 57, x: this.movesContainerInitialX - 57,
onComplete: () => resolve(), onComplete: () => resolve(),
@ -463,7 +463,7 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container {
return new Promise<void>(resolve => { return new Promise<void>(resolve => {
globalScene.tweens.add({ globalScene.tweens.add({
targets: this, targets: this,
duration: Utils.fixedInt(Math.floor(150 / speedMultiplier)), duration: fixedInt(Math.floor(150 / speedMultiplier)),
ease: "Cubic.easeInOut", ease: "Cubic.easeInOut",
x: xPosition, x: xPosition,
onComplete: () => { onComplete: () => {
@ -482,14 +482,14 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container {
globalScene.tweens.add({ globalScene.tweens.add({
targets: this.pokemonMovesContainer, targets: this.pokemonMovesContainer,
duration: Utils.fixedInt(Math.floor(750 / speedMultiplier)), duration: fixedInt(Math.floor(750 / speedMultiplier)),
ease: "Cubic.easeInOut", ease: "Cubic.easeInOut",
x: this.movesContainerInitialX, x: this.movesContainerInitialX,
}); });
globalScene.tweens.add({ globalScene.tweens.add({
targets: this, targets: this,
duration: Utils.fixedInt(Math.floor(750 / speedMultiplier)), duration: fixedInt(Math.floor(750 / speedMultiplier)),
ease: "Cubic.easeInOut", ease: "Cubic.easeInOut",
x: this.initialX, x: this.initialX,
onComplete: () => { onComplete: () => {

View File

@ -3,7 +3,7 @@ import { GameModes } from "../game-mode";
import { TextStyle, addTextObject } from "./text"; import { TextStyle, addTextObject } from "./text";
import { Mode } from "./ui"; import { Mode } from "./ui";
import { addWindow } from "./ui-theme"; import { addWindow } from "./ui-theme";
import * as Utils from "../utils"; import { fixedInt, formatLargeNumber } from "#app/utils";
import type PokemonData from "../system/pokemon-data"; import type PokemonData from "../system/pokemon-data";
import MessageUiHandler from "./message-ui-handler"; import MessageUiHandler from "./message-ui-handler";
import i18next from "i18next"; import i18next from "i18next";
@ -218,7 +218,7 @@ export default class RunHistoryUiHandler extends MessageUiHandler {
globalScene.tweens.add({ globalScene.tweens.add({
targets: this.runsContainer, targets: this.runsContainer,
y: this.runContainerInitialY - 56 * scrollCursor, y: this.runContainerInitialY - 56 * scrollCursor,
duration: Utils.fixedInt(325), duration: fixedInt(325),
ease: "Sine.easeInOut", ease: "Sine.easeInOut",
}); });
} }
@ -314,7 +314,7 @@ class RunEntryContainer extends Phaser.GameObjects.Container {
const enemyLevel = addTextObject( const enemyLevel = addTextObject(
32, 32,
20, 20,
`${i18next.t("saveSlotSelectUiHandler:lv")}${Utils.formatLargeNumber(enemy.level, 1000)}`, `${i18next.t("saveSlotSelectUiHandler:lv")}${formatLargeNumber(enemy.level, 1000)}`,
TextStyle.PARTY, TextStyle.PARTY,
{ fontSize: "54px", color: "#f8f8f8" }, { fontSize: "54px", color: "#f8f8f8" },
); );
@ -408,7 +408,7 @@ class RunEntryContainer extends Phaser.GameObjects.Container {
const text = addTextObject( const text = addTextObject(
32, 32,
20, 20,
`${i18next.t("saveSlotSelectUiHandler:lv")}${Utils.formatLargeNumber(pokemon.level, 1000)}`, `${i18next.t("saveSlotSelectUiHandler:lv")}${formatLargeNumber(pokemon.level, 1000)}`,
TextStyle.PARTY, TextStyle.PARTY,
{ fontSize: "54px", color: "#f8f8f8" }, { fontSize: "54px", color: "#f8f8f8" },
); );

View File

@ -5,7 +5,7 @@ import { TextStyle, addTextObject, addBBCodeTextObject, getTextColor } from "./t
import { Mode } from "./ui"; import { Mode } from "./ui";
import { addWindow } from "./ui-theme"; import { addWindow } from "./ui-theme";
import { getPokeballAtlasKey } from "#app/data/pokeball"; import { getPokeballAtlasKey } from "#app/data/pokeball";
import * as Utils from "../utils"; import { formatLargeNumber, getPlayTimeString, formatMoney, formatFancyLargeNumber } from "#app/utils";
import type PokemonData from "../system/pokemon-data"; import type PokemonData from "../system/pokemon-data";
import i18next from "i18next"; import i18next from "i18next";
import { Button } from "../enums/buttons"; import { Button } from "../enums/buttons";
@ -19,7 +19,8 @@ import { PokemonType } from "#enums/pokemon-type";
import { TypeColor, TypeShadow } from "#app/enums/color"; import { TypeColor, TypeShadow } from "#app/enums/color";
import { getNatureStatMultiplier, getNatureName } from "../data/nature"; import { getNatureStatMultiplier, getNatureName } from "../data/nature";
import { getVariantTint } from "#app/sprites/variant"; import { getVariantTint } from "#app/sprites/variant";
import * as Modifier from "../modifier/modifier"; // biome-ignore lint/style/noNamespaceImport: See `src/system/game-data.ts`
import * as Modifier from "#app/modifier/modifier";
import type { Species } from "#enums/species"; import type { Species } from "#enums/species";
import { PlayerGender } from "#enums/player-gender"; import { PlayerGender } from "#enums/player-gender";
import { SettingKeyboard } from "#app/system/settings/settings-keyboard"; import { SettingKeyboard } from "#app/system/settings/settings-keyboard";
@ -411,7 +412,7 @@ export default class RunInfoUiHandler extends UiHandler {
const enemyLevel = addTextObject( const enemyLevel = addTextObject(
36, 36,
26, 26,
`${i18next.t("saveSlotSelectUiHandler:lv")}${Utils.formatLargeNumber(enemy.level, 1000)}`, `${i18next.t("saveSlotSelectUiHandler:lv")}${formatLargeNumber(enemy.level, 1000)}`,
enemyLevelStyle, enemyLevelStyle,
{ fontSize: "44px", color: "#f8f8f8" }, { fontSize: "44px", color: "#f8f8f8" },
); );
@ -441,7 +442,7 @@ export default class RunInfoUiHandler extends UiHandler {
const enemyLevel = addTextObject( const enemyLevel = addTextObject(
36, 36,
26, 26,
`${i18next.t("saveSlotSelectUiHandler:lv")}${Utils.formatLargeNumber(enemy.level, 1000)}`, `${i18next.t("saveSlotSelectUiHandler:lv")}${formatLargeNumber(enemy.level, 1000)}`,
bossStatus ? TextStyle.PARTY_RED : TextStyle.PARTY, bossStatus ? TextStyle.PARTY_RED : TextStyle.PARTY,
{ fontSize: "44px", color: "#f8f8f8" }, { fontSize: "44px", color: "#f8f8f8" },
); );
@ -527,7 +528,7 @@ export default class RunInfoUiHandler extends UiHandler {
const enemyLevel = addTextObject( const enemyLevel = addTextObject(
43 * (e % 3), 43 * (e % 3),
27 * (pokemonRowHeight + 1), 27 * (pokemonRowHeight + 1),
`${i18next.t("saveSlotSelectUiHandler:lv")}${Utils.formatLargeNumber(enemy.level, 1000)}`, `${i18next.t("saveSlotSelectUiHandler:lv")}${formatLargeNumber(enemy.level, 1000)}`,
isBoss ? TextStyle.PARTY_RED : TextStyle.PARTY, isBoss ? TextStyle.PARTY_RED : TextStyle.PARTY,
{ fontSize: "54px" }, { fontSize: "54px" },
); );
@ -606,9 +607,9 @@ export default class RunInfoUiHandler extends UiHandler {
fontSize: "50px", fontSize: "50px",
lineSpacing: lineSpacing, lineSpacing: lineSpacing,
}); });
const runTime = Utils.getPlayTimeString(this.runInfo.playTime); const runTime = getPlayTimeString(this.runInfo.playTime);
runInfoText.appendText(`${i18next.t("runHistory:runLength")}: ${runTime}`, false); runInfoText.appendText(`${i18next.t("runHistory:runLength")}: ${runTime}`, false);
const runMoney = Utils.formatMoney(globalScene.moneyFormat, this.runInfo.money); const runMoney = formatMoney(globalScene.moneyFormat, this.runInfo.money);
const moneyTextColor = getTextColor(TextStyle.MONEY_WINDOW, false, globalScene.uiTheme); const moneyTextColor = getTextColor(TextStyle.MONEY_WINDOW, false, globalScene.uiTheme);
runInfoText.appendText( runInfoText.appendText(
`[color=${moneyTextColor}]${i18next.t("battleScene:moneyOwned", { formattedMoney: runMoney })}[/color]`, `[color=${moneyTextColor}]${i18next.t("battleScene:moneyOwned", { formattedMoney: runMoney })}[/color]`,
@ -770,7 +771,7 @@ export default class RunInfoUiHandler extends UiHandler {
lineSpacing: lineSpacing, lineSpacing: lineSpacing,
}); });
pokeInfoText.appendText( pokeInfoText.appendText(
`${i18next.t("saveSlotSelectUiHandler:lv")}${Utils.formatFancyLargeNumber(pokemon.level, 1)} - ${pNatureName}`, `${i18next.t("saveSlotSelectUiHandler:lv")}${formatFancyLargeNumber(pokemon.level, 1)} - ${pNatureName}`,
); );
pokeInfoText.appendText(pAbilityInfo); pokeInfoText.appendText(pAbilityInfo);
pokeInfoText.appendText(pPassiveInfo); pokeInfoText.appendText(pPassiveInfo);
@ -780,7 +781,7 @@ export default class RunInfoUiHandler extends UiHandler {
// Colored Arrows (Red/Blue) are placed by stats that are boosted from natures // Colored Arrows (Red/Blue) are placed by stats that are boosted from natures
const pokeStatTextContainer = globalScene.add.container(-35, 6); const pokeStatTextContainer = globalScene.add.container(-35, 6);
const pStats: string[] = []; const pStats: string[] = [];
pokemon.stats.forEach(element => pStats.push(Utils.formatFancyLargeNumber(element, 1))); pokemon.stats.forEach(element => pStats.push(formatFancyLargeNumber(element, 1)));
for (let i = 0; i < pStats.length; i++) { for (let i = 0; i < pStats.length; i++) {
const isMult = getNatureStatMultiplier(pNature, i); const isMult = getNatureStatMultiplier(pNature, i);
pStats[i] = isMult < 1 ? pStats[i] + "[color=#40c8f8]↓[/color]" : pStats[i]; pStats[i] = isMult < 1 ? pStats[i] + "[color=#40c8f8]↓[/color]" : pStats[i];

View File

@ -2,10 +2,11 @@ import i18next from "i18next";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { Button } from "#enums/buttons"; import { Button } from "#enums/buttons";
import { GameMode } from "../game-mode"; import { GameMode } from "../game-mode";
import * as Modifier from "../modifier/modifier"; // biome-ignore lint/style/noNamespaceImport: See `src/system/game-data.ts`
import * as Modifier from "#app/modifier/modifier";
import type { SessionSaveData } from "../system/game-data"; import type { SessionSaveData } from "../system/game-data";
import type PokemonData from "../system/pokemon-data"; import type PokemonData from "../system/pokemon-data";
import * as Utils from "../utils"; import { isNullOrUndefined, fixedInt, getPlayTimeString, formatLargeNumber } from "#app/utils";
import MessageUiHandler from "./message-ui-handler"; import MessageUiHandler from "./message-ui-handler";
import { TextStyle, addTextObject } from "./text"; import { TextStyle, addTextObject } from "./text";
import { Mode } from "./ui"; import { Mode } from "./ui";
@ -296,7 +297,7 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler {
} }
this.setArrowVisibility(hasData); this.setArrowVisibility(hasData);
} }
if (!Utils.isNullOrUndefined(prevSlotIndex)) { if (!isNullOrUndefined(prevSlotIndex)) {
this.revertSessionSlot(prevSlotIndex); this.revertSessionSlot(prevSlotIndex);
} }
@ -339,7 +340,7 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler {
globalScene.tweens.add({ globalScene.tweens.add({
targets: this.sessionSlotsContainer, targets: this.sessionSlotsContainer,
y: this.sessionSlotsContainerInitialY - 56 * scrollCursor, y: this.sessionSlotsContainerInitialY - 56 * scrollCursor,
duration: Utils.fixedInt(325), duration: fixedInt(325),
ease: "Sine.easeInOut", ease: "Sine.easeInOut",
}); });
} }
@ -407,7 +408,7 @@ class SessionSlot extends Phaser.GameObjects.Container {
const timestampLabel = addTextObject(8, 19, new Date(data.timestamp).toLocaleString(), TextStyle.WINDOW); const timestampLabel = addTextObject(8, 19, new Date(data.timestamp).toLocaleString(), TextStyle.WINDOW);
this.add(timestampLabel); this.add(timestampLabel);
const playTimeLabel = addTextObject(8, 33, Utils.getPlayTimeString(data.playTime), TextStyle.WINDOW); const playTimeLabel = addTextObject(8, 33, getPlayTimeString(data.playTime), TextStyle.WINDOW);
this.add(playTimeLabel); this.add(playTimeLabel);
const pokemonIconsContainer = globalScene.add.container(144, 4); const pokemonIconsContainer = globalScene.add.container(144, 4);
@ -421,7 +422,7 @@ class SessionSlot extends Phaser.GameObjects.Container {
const text = addTextObject( const text = addTextObject(
32, 32,
20, 20,
`${i18next.t("saveSlotSelectUiHandler:lv")}${Utils.formatLargeNumber(pokemon.level, 1000)}`, `${i18next.t("saveSlotSelectUiHandler:lv")}${formatLargeNumber(pokemon.level, 1000)}`,
TextStyle.PARTY, TextStyle.PARTY,
{ fontSize: "54px", color: "#f8f8f8" }, { fontSize: "54px", color: "#f8f8f8" },
); );

View File

@ -1,5 +1,5 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import * as Utils from "../utils"; import { fixedInt } from "#app/utils";
export default class SavingIconHandler extends Phaser.GameObjects.Container { export default class SavingIconHandler extends Phaser.GameObjects.Container {
private icon: Phaser.GameObjects.Sprite; private icon: Phaser.GameObjects.Sprite;
@ -36,10 +36,10 @@ export default class SavingIconHandler extends Phaser.GameObjects.Container {
globalScene.tweens.add({ globalScene.tweens.add({
targets: this, targets: this,
alpha: 1, alpha: 1,
duration: Utils.fixedInt(250), duration: fixedInt(250),
ease: "Sine.easeInOut", ease: "Sine.easeInOut",
onComplete: () => { onComplete: () => {
globalScene.time.delayedCall(Utils.fixedInt(500), () => { globalScene.time.delayedCall(fixedInt(500), () => {
this.animActive = false; this.animActive = false;
if (!this.shown) { if (!this.shown) {
this.hide(); this.hide();
@ -64,7 +64,7 @@ export default class SavingIconHandler extends Phaser.GameObjects.Container {
globalScene.tweens.add({ globalScene.tweens.add({
targets: this, targets: this,
alpha: 0, alpha: 0,
duration: Utils.fixedInt(250), duration: fixedInt(250),
ease: "Sine.easeInOut", ease: "Sine.easeInOut",
onComplete: () => { onComplete: () => {
this.animActive = false; this.animActive = false;

View File

@ -43,7 +43,7 @@ import { Egg } from "#app/data/egg";
import Overrides from "#app/overrides"; import Overrides from "#app/overrides";
import { SettingKeyboard } from "#app/system/settings/settings-keyboard"; import { SettingKeyboard } from "#app/system/settings/settings-keyboard";
import { Passive as PassiveAttr } from "#enums/passive"; import { Passive as PassiveAttr } from "#enums/passive";
import * as Challenge from "#app/data/challenge"; import { applyChallenges, ChallengeType } from "#app/data/challenge";
import MoveInfoOverlay from "#app/ui/move-info-overlay"; import MoveInfoOverlay from "#app/ui/move-info-overlay";
import { getEggTierForSpecies } from "#app/data/egg"; import { getEggTierForSpecies } from "#app/data/egg";
import { Device } from "#enums/devices"; import { Device } from "#enums/devices";
@ -78,7 +78,6 @@ import {
import type { Nature } from "#enums/nature"; import type { Nature } from "#enums/nature";
import { PLAYER_PARTY_MAX_SIZE } from "#app/constants"; import { PLAYER_PARTY_MAX_SIZE } from "#app/constants";
import { achvs } from "#app/system/achv"; import { achvs } from "#app/system/achv";
import * as Utils from "../utils";
import type { GameObjects } from "phaser"; import type { GameObjects } from "phaser";
import { checkStarterValidForChallenge } from "#app/data/challenge"; import { checkStarterValidForChallenge } from "#app/data/challenge";
@ -2518,7 +2517,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
case Button.CYCLE_TERA: case Button.CYCLE_TERA:
if (this.canCycleTera) { if (this.canCycleTera) {
const speciesForm = getPokemonSpeciesForm(this.lastSpecies.speciesId, starterAttributes.form ?? 0); const speciesForm = getPokemonSpeciesForm(this.lastSpecies.speciesId, starterAttributes.form ?? 0);
if (speciesForm.type1 === this.teraCursor && !Utils.isNullOrUndefined(speciesForm.type2)) { if (speciesForm.type1 === this.teraCursor && !isNullOrUndefined(speciesForm.type2)) {
starterAttributes.tera = speciesForm.type2!; starterAttributes.tera = speciesForm.type2!;
this.setSpeciesDetails(this.lastSpecies, { this.setSpeciesDetails(this.lastSpecies, {
teraType: speciesForm.type2!, teraType: speciesForm.type2!,
@ -2960,7 +2959,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
valueLimit.value = 10; valueLimit.value = 10;
} }
Challenge.applyChallenges(Challenge.ChallengeType.STARTER_POINTS, valueLimit); applyChallenges(ChallengeType.STARTER_POINTS, valueLimit);
return valueLimit.value; return valueLimit.value;
} }
@ -3748,7 +3747,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
); // TODO: is this bang correct? ); // TODO: is this bang correct?
this.abilityCursor = abilityIndex !== undefined ? abilityIndex : (abilityIndex = oldAbilityIndex); this.abilityCursor = abilityIndex !== undefined ? abilityIndex : (abilityIndex = oldAbilityIndex);
this.natureCursor = natureIndex !== undefined ? natureIndex : (natureIndex = oldNatureIndex); this.natureCursor = natureIndex !== undefined ? natureIndex : (natureIndex = oldNatureIndex);
this.teraCursor = !Utils.isNullOrUndefined(teraType) ? teraType : (teraType = species.type1); this.teraCursor = !isNullOrUndefined(teraType) ? teraType : (teraType = species.type1);
const [isInParty, partyIndex]: [boolean, number] = this.isInParty(species); // we use this to firstly check if the pokemon is in the party, and if so, to get the party index in order to update the icon image const [isInParty, partyIndex]: [boolean, number] = this.isInParty(species); // we use this to firstly check if the pokemon is in the party, and if so, to get the party index in order to update the icon image
if (isInParty) { if (isInParty) {
this.updatePartyIcon(species, partyIndex); this.updatePartyIcon(species, partyIndex);
@ -3886,7 +3885,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.canCycleTera = this.canCycleTera =
!this.statsMode && !this.statsMode &&
globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id) && globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id) &&
!Utils.isNullOrUndefined(getPokemonSpeciesForm(species.speciesId, formIndex ?? 0).type2); !isNullOrUndefined(getPokemonSpeciesForm(species.speciesId, formIndex ?? 0).type2);
} }
if (dexEntry.caughtAttr && species.malePercent !== null) { if (dexEntry.caughtAttr && species.malePercent !== null) {
@ -4483,7 +4482,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.canCycleTera = this.canCycleTera =
!this.statsMode && !this.statsMode &&
globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id) && globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id) &&
!Utils.isNullOrUndefined(getPokemonSpeciesForm(this.lastSpecies.speciesId, formIndex ?? 0).type2); !isNullOrUndefined(getPokemonSpeciesForm(this.lastSpecies.speciesId, formIndex ?? 0).type2);
this.updateInstructions(); this.updateInstructions();
} }
} }

View File

@ -2,7 +2,16 @@ import { starterColors } from "#app/battle-scene";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { Mode } from "#app/ui/ui"; import { Mode } from "#app/ui/ui";
import UiHandler from "#app/ui/ui-handler"; import UiHandler from "#app/ui/ui-handler";
import * as Utils from "#app/utils"; import {
getLocalizedSpriteKey,
rgbHexToRgba,
padInt,
getEnumValues,
fixedInt,
isNullOrUndefined,
toReadableString,
formatStat,
} from "#app/utils";
import type { PlayerPokemon, PokemonMove } from "#app/field/pokemon"; import type { PlayerPokemon, PokemonMove } from "#app/field/pokemon";
import { getStarterValueFriendshipCap, speciesStarterCosts } from "#app/data/balance/starters"; import { getStarterValueFriendshipCap, speciesStarterCosts } from "#app/data/balance/starters";
import { argbFromRgba } from "@material/material-color-utilities"; import { argbFromRgba } from "@material/material-color-utilities";
@ -255,7 +264,7 @@ export default class SummaryUiHandler extends UiHandler {
this.statusContainer.add(statusLabel); this.statusContainer.add(statusLabel);
this.status = globalScene.add.sprite(91, 4, Utils.getLocalizedSpriteKey("statuses")); this.status = globalScene.add.sprite(91, 4, getLocalizedSpriteKey("statuses"));
this.status.setOrigin(0.5, 0); this.status.setOrigin(0.5, 0);
this.statusContainer.add(this.status); this.statusContainer.add(this.status);
@ -330,10 +339,10 @@ export default class SummaryUiHandler extends UiHandler {
this.shinyOverlay.setVisible(this.pokemon.isShiny()); this.shinyOverlay.setVisible(this.pokemon.isShiny());
const colorScheme = starterColors[this.pokemon.species.getRootSpeciesId()]; const colorScheme = starterColors[this.pokemon.species.getRootSpeciesId()];
this.candyIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(colorScheme[0]))); this.candyIcon.setTint(argbFromRgba(rgbHexToRgba(colorScheme[0])));
this.candyOverlay.setTint(argbFromRgba(Utils.rgbHexToRgba(colorScheme[1]))); this.candyOverlay.setTint(argbFromRgba(rgbHexToRgba(colorScheme[1])));
this.numberText.setText(Utils.padInt(this.pokemon.species.speciesId, 4)); this.numberText.setText(padInt(this.pokemon.species.speciesId, 4));
this.numberText.setColor(this.getTextColor(!this.pokemon.isShiny() ? TextStyle.SUMMARY : TextStyle.SUMMARY_GOLD)); this.numberText.setColor(this.getTextColor(!this.pokemon.isShiny() ? TextStyle.SUMMARY : TextStyle.SUMMARY_GOLD));
this.numberText.setShadowColor( this.numberText.setShadowColor(
this.getTextColor(!this.pokemon.isShiny() ? TextStyle.SUMMARY : TextStyle.SUMMARY_GOLD, true), this.getTextColor(!this.pokemon.isShiny() ? TextStyle.SUMMARY : TextStyle.SUMMARY_GOLD, true),
@ -600,7 +609,7 @@ export default class SummaryUiHandler extends UiHandler {
} }
success = true; success = true;
} else { } else {
const pages = Utils.getEnumValues(Page); const pages = getEnumValues(Page);
switch (button) { switch (button) {
case Button.UP: case Button.UP:
case Button.DOWN: { case Button.DOWN: {
@ -675,10 +684,10 @@ export default class SummaryUiHandler extends UiHandler {
if (moveDescriptionLineCount > 3) { if (moveDescriptionLineCount > 3) {
this.descriptionScrollTween = globalScene.tweens.add({ this.descriptionScrollTween = globalScene.tweens.add({
targets: this.moveDescriptionText, targets: this.moveDescriptionText,
delay: Utils.fixedInt(2000), delay: fixedInt(2000),
loop: -1, loop: -1,
hold: Utils.fixedInt(2000), hold: fixedInt(2000),
duration: Utils.fixedInt((moveDescriptionLineCount - 3) * 2000), duration: fixedInt((moveDescriptionLineCount - 3) * 2000),
y: `-=${14.83 * (moveDescriptionLineCount - 3)}`, y: `-=${14.83 * (moveDescriptionLineCount - 3)}`,
}); });
} }
@ -697,10 +706,10 @@ export default class SummaryUiHandler extends UiHandler {
this.moveCursorObj.setVisible(true); this.moveCursorObj.setVisible(true);
this.moveCursorBlinkTimer = globalScene.time.addEvent({ this.moveCursorBlinkTimer = globalScene.time.addEvent({
loop: true, loop: true,
delay: Utils.fixedInt(600), delay: fixedInt(600),
callback: () => { callback: () => {
this.moveCursorObj?.setVisible(false); this.moveCursorObj?.setVisible(false);
globalScene.time.delayedCall(Utils.fixedInt(100), () => { globalScene.time.delayedCall(fixedInt(100), () => {
if (!this.moveCursorObj) { if (!this.moveCursorObj) {
return; return;
} }
@ -818,7 +827,7 @@ export default class SummaryUiHandler extends UiHandler {
const getTypeIcon = (index: number, type: PokemonType, tera = false) => { const getTypeIcon = (index: number, type: PokemonType, tera = false) => {
const xCoord = typeLabel.width * typeLabel.scale + 9 + 34 * index; const xCoord = typeLabel.width * typeLabel.scale + 9 + 34 * index;
const typeIcon = !tera const typeIcon = !tera
? globalScene.add.sprite(xCoord, 42, Utils.getLocalizedSpriteKey("types"), PokemonType[type].toLowerCase()) ? globalScene.add.sprite(xCoord, 42, getLocalizedSpriteKey("types"), PokemonType[type].toLowerCase())
: globalScene.add.sprite(xCoord, 42, "type_tera"); : globalScene.add.sprite(xCoord, 42, "type_tera");
if (tera) { if (tera) {
typeIcon.setScale(0.5); typeIcon.setScale(0.5);
@ -853,7 +862,7 @@ export default class SummaryUiHandler extends UiHandler {
if ( if (
globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id) && globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id) &&
!Utils.isNullOrUndefined(this.pokemon) !isNullOrUndefined(this.pokemon)
) { ) {
const teraIcon = globalScene.add.sprite(123, 26, "button_tera"); const teraIcon = globalScene.add.sprite(123, 26, "button_tera");
teraIcon.setName("terrastallize-icon"); teraIcon.setName("terrastallize-icon");
@ -925,10 +934,10 @@ export default class SummaryUiHandler extends UiHandler {
abilityInfo.descriptionText.setY(69); abilityInfo.descriptionText.setY(69);
this.descriptionScrollTween = globalScene.tweens.add({ this.descriptionScrollTween = globalScene.tweens.add({
targets: abilityInfo.descriptionText, targets: abilityInfo.descriptionText,
delay: Utils.fixedInt(2000), delay: fixedInt(2000),
loop: -1, loop: -1,
hold: Utils.fixedInt(2000), hold: fixedInt(2000),
duration: Utils.fixedInt((abilityDescriptionLineCount - 2) * 2000), duration: fixedInt((abilityDescriptionLineCount - 2) * 2000),
y: `-=${14.83 * (abilityDescriptionLineCount - 2)}`, y: `-=${14.83 * (abilityDescriptionLineCount - 2)}`,
}); });
} }
@ -939,8 +948,8 @@ export default class SummaryUiHandler extends UiHandler {
this.passiveContainer?.descriptionText?.setVisible(false); this.passiveContainer?.descriptionText?.setVisible(false);
const closeFragment = getBBCodeFrag("", TextStyle.WINDOW_ALT); const closeFragment = getBBCodeFrag("", TextStyle.WINDOW_ALT);
const rawNature = Utils.toReadableString(Nature[this.pokemon?.getNature()!]); // TODO: is this bang correct? const rawNature = toReadableString(Nature[this.pokemon?.getNature()!]); // TODO: is this bang correct?
const nature = `${getBBCodeFrag(Utils.toReadableString(getNatureName(this.pokemon?.getNature()!)), TextStyle.SUMMARY_RED)}${closeFragment}`; // TODO: is this bang correct? const nature = `${getBBCodeFrag(toReadableString(getNatureName(this.pokemon?.getNature()!)), TextStyle.SUMMARY_RED)}${closeFragment}`; // TODO: is this bang correct?
const memoString = i18next.t("pokemonSummary:memoString", { const memoString = i18next.t("pokemonSummary:memoString", {
metFragment: i18next.t( metFragment: i18next.t(
@ -999,8 +1008,8 @@ export default class SummaryUiHandler extends UiHandler {
const statValueText = const statValueText =
stat !== Stat.HP stat !== Stat.HP
? Utils.formatStat(this.pokemon?.getStat(stat)!) // TODO: is this bang correct? ? formatStat(this.pokemon?.getStat(stat)!) // TODO: is this bang correct?
: `${Utils.formatStat(this.pokemon?.hp!, true)}/${Utils.formatStat(this.pokemon?.getMaxHp()!, true)}`; // TODO: are those bangs correct? : `${formatStat(this.pokemon?.hp!, true)}/${formatStat(this.pokemon?.getMaxHp()!, true)}`; // TODO: are those bangs correct?
const ivText = `${this.pokemon?.ivs[stat]}/31`; const ivText = `${this.pokemon?.ivs[stat]}/31`;
const statValue = addTextObject(93 + 88 * colIndex, 16 * rowIndex, statValueText, TextStyle.WINDOW_ALT); const statValue = addTextObject(93 + 88 * colIndex, 16 * rowIndex, statValueText, TextStyle.WINDOW_ALT);
@ -1106,7 +1115,7 @@ export default class SummaryUiHandler extends UiHandler {
this.extraMoveRowContainer.setVisible(true); this.extraMoveRowContainer.setVisible(true);
if (this.newMove && this.pokemon) { if (this.newMove && this.pokemon) {
const spriteKey = Utils.getLocalizedSpriteKey("types"); const spriteKey = getLocalizedSpriteKey("types");
const moveType = this.pokemon.getMoveType(this.newMove); const moveType = this.pokemon.getMoveType(this.newMove);
const newMoveTypeIcon = globalScene.add.sprite(0, 0, spriteKey, PokemonType[moveType].toLowerCase()); const newMoveTypeIcon = globalScene.add.sprite(0, 0, spriteKey, PokemonType[moveType].toLowerCase());
newMoveTypeIcon.setOrigin(0, 1); newMoveTypeIcon.setOrigin(0, 1);
@ -1116,7 +1125,7 @@ export default class SummaryUiHandler extends UiHandler {
ppOverlay.setOrigin(0, 1); ppOverlay.setOrigin(0, 1);
this.extraMoveRowContainer.add(ppOverlay); this.extraMoveRowContainer.add(ppOverlay);
const pp = Utils.padInt(this.newMove?.pp!, 2, " "); // TODO: is this bang correct? const pp = padInt(this.newMove?.pp!, 2, " "); // TODO: is this bang correct?
const ppText = addTextObject(173, 1, `${pp}/${pp}`, TextStyle.WINDOW); const ppText = addTextObject(173, 1, `${pp}/${pp}`, TextStyle.WINDOW);
ppText.setOrigin(0, 1); ppText.setOrigin(0, 1);
this.extraMoveRowContainer.add(ppText); this.extraMoveRowContainer.add(ppText);
@ -1132,7 +1141,7 @@ export default class SummaryUiHandler extends UiHandler {
this.moveRowsContainer.add(moveRowContainer); this.moveRowsContainer.add(moveRowContainer);
if (move && this.pokemon) { if (move && this.pokemon) {
const spriteKey = Utils.getLocalizedSpriteKey("types"); const spriteKey = getLocalizedSpriteKey("types");
const moveType = this.pokemon.getMoveType(move.getMove()); const moveType = this.pokemon.getMoveType(move.getMove());
const typeIcon = globalScene.add.sprite(0, 0, spriteKey, PokemonType[moveType].toLowerCase()); const typeIcon = globalScene.add.sprite(0, 0, spriteKey, PokemonType[moveType].toLowerCase());
typeIcon.setOrigin(0, 1); typeIcon.setOrigin(0, 1);
@ -1153,7 +1162,7 @@ export default class SummaryUiHandler extends UiHandler {
if (move) { if (move) {
const maxPP = move.getMovePp(); const maxPP = move.getMovePp();
const pp = maxPP - move.ppUsed; const pp = maxPP - move.ppUsed;
ppText.setText(`${Utils.padInt(pp, 2, " ")}/${Utils.padInt(maxPP, 2, " ")}`); ppText.setText(`${padInt(pp, 2, " ")}/${padInt(maxPP, 2, " ")}`);
} }
moveRowContainer.add(ppText); moveRowContainer.add(ppText);

View File

@ -1,7 +1,7 @@
import { BattlerIndex } from "../battle"; import { BattlerIndex } from "../battle";
import { Mode } from "./ui"; import { Mode } from "./ui";
import UiHandler from "./ui-handler"; import UiHandler from "./ui-handler";
import * as Utils from "../utils"; import { isNullOrUndefined, fixedInt } from "#app/utils";
import { getMoveTargets } from "../data/moves/move"; import { getMoveTargets } from "../data/moves/move";
import { Button } from "#enums/buttons"; import { Button } from "#enums/buttons";
import type { Moves } from "#enums/moves"; import type { Moves } from "#enums/moves";
@ -70,7 +70,7 @@ export default class TargetSelectUiHandler extends UiHandler {
* @param user the Pokemon using the move * @param user the Pokemon using the move
*/ */
resetCursor(cursorN: number, user: Pokemon): void { resetCursor(cursorN: number, user: Pokemon): void {
if (!Utils.isNullOrUndefined(cursorN)) { if (!isNullOrUndefined(cursorN)) {
if ([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2].includes(cursorN) || user.battleSummonData.waveTurnCount === 1) { if ([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2].includes(cursorN) || user.battleSummonData.waveTurnCount === 1) {
// Reset cursor on the first turn of a fight or if an ally was targeted last turn // Reset cursor on the first turn of a fight or if an ally was targeted last turn
cursorN = -1; cursorN = -1;
@ -89,11 +89,11 @@ export default class TargetSelectUiHandler extends UiHandler {
this.targetSelectCallback(button === Button.ACTION ? targetIndexes : []); this.targetSelectCallback(button === Button.ACTION ? targetIndexes : []);
success = true; success = true;
if (this.fieldIndex === BattlerIndex.PLAYER) { if (this.fieldIndex === BattlerIndex.PLAYER) {
if (Utils.isNullOrUndefined(this.cursor0) || this.cursor0 !== this.cursor) { if (isNullOrUndefined(this.cursor0) || this.cursor0 !== this.cursor) {
this.cursor0 = this.cursor; this.cursor0 = this.cursor;
} }
} else if (this.fieldIndex === BattlerIndex.PLAYER_2) { } else if (this.fieldIndex === BattlerIndex.PLAYER_2) {
if (Utils.isNullOrUndefined(this.cursor1) || this.cursor1 !== this.cursor) { if (isNullOrUndefined(this.cursor1) || this.cursor1 !== this.cursor) {
this.cursor1 = this.cursor; this.cursor1 = this.cursor;
} }
} }
@ -152,7 +152,7 @@ export default class TargetSelectUiHandler extends UiHandler {
key: { start: 1, to: 0.25 }, key: { start: 1, to: 0.25 },
loop: -1, loop: -1,
loopDelay: 150, loopDelay: 150,
duration: Utils.fixedInt(450), duration: fixedInt(450),
ease: "Sine.easeInOut", ease: "Sine.easeInOut",
yoyo: true, yoyo: true,
onUpdate: t => { onUpdate: t => {
@ -178,7 +178,7 @@ export default class TargetSelectUiHandler extends UiHandler {
targets: [info], targets: [info],
y: { start: info.getBaseY(), to: info.getBaseY() + 1 }, y: { start: info.getBaseY(), to: info.getBaseY() + 1 },
loop: -1, loop: -1,
duration: Utils.fixedInt(250), duration: fixedInt(250),
ease: "Linear", ease: "Linear",
yoyo: true, yoyo: true,
}), }),

View File

@ -1,4 +1,4 @@
import * as Utils from "../utils"; import { fixedInt } from "#app/utils";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { BattleSceneEventType } from "../events/battle-scene"; import { BattleSceneEventType } from "../events/battle-scene";
import { EaseType } from "#enums/ease-type"; import { EaseType } from "#enums/ease-type";
@ -75,14 +75,14 @@ export default class TimeOfDayWidget extends Phaser.GameObjects.Container {
const rotate = { const rotate = {
targets: [this.timeOfDayIconMgs[0], this.timeOfDayIconMgs[1]], targets: [this.timeOfDayIconMgs[0], this.timeOfDayIconMgs[1]],
angle: "+=90", angle: "+=90",
duration: Utils.fixedInt(1500), duration: fixedInt(1500),
ease: "Back.easeOut", ease: "Back.easeOut",
paused: !this.parentVisible, paused: !this.parentVisible,
}; };
const fade = { const fade = {
targets: [this.timeOfDayIconBgs[1], this.timeOfDayIconMgs[1], this.timeOfDayIconFgs[1]], targets: [this.timeOfDayIconBgs[1], this.timeOfDayIconMgs[1], this.timeOfDayIconFgs[1]],
alpha: 0, alpha: 0,
duration: Utils.fixedInt(500), duration: fixedInt(500),
ease: "Linear", ease: "Linear",
paused: !this.parentVisible, paused: !this.parentVisible,
}; };
@ -98,14 +98,14 @@ export default class TimeOfDayWidget extends Phaser.GameObjects.Container {
const bounce = { const bounce = {
targets: [this.timeOfDayIconMgs[0], this.timeOfDayIconMgs[1]], targets: [this.timeOfDayIconMgs[0], this.timeOfDayIconMgs[1]],
angle: "+=90", angle: "+=90",
duration: Utils.fixedInt(2000), duration: fixedInt(2000),
ease: "Bounce.easeOut", ease: "Bounce.easeOut",
paused: !this.parentVisible, paused: !this.parentVisible,
}; };
const fade = { const fade = {
targets: [this.timeOfDayIconBgs[1], this.timeOfDayIconMgs[1], this.timeOfDayIconFgs[1]], targets: [this.timeOfDayIconBgs[1], this.timeOfDayIconMgs[1], this.timeOfDayIconFgs[1]],
alpha: 0, alpha: 0,
duration: Utils.fixedInt(800), duration: fixedInt(800),
ease: "Linear", ease: "Linear",
paused: !this.parentVisible, paused: !this.parentVisible,
}; };

View File

@ -1,6 +1,6 @@
import OptionSelectUiHandler from "./settings/option-select-ui-handler"; import OptionSelectUiHandler from "./settings/option-select-ui-handler";
import { Mode } from "./ui"; import { Mode } from "./ui";
import * as Utils from "../utils"; import { fixedInt, randInt, randItem } from "#app/utils";
import { TextStyle, addTextObject } from "./text"; import { TextStyle, addTextObject } from "./text";
import { getSplashMessages } from "../data/splash-messages"; import { getSplashMessages } from "../data/splash-messages";
import i18next from "i18next"; import i18next from "i18next";
@ -72,7 +72,7 @@ export default class TitleUiHandler extends OptionSelectUiHandler {
globalScene.tweens.add({ globalScene.tweens.add({
targets: this.splashMessageText, targets: this.splashMessageText,
duration: Utils.fixedInt(350), duration: fixedInt(350),
scale: originalSplashMessageScale * 1.25, scale: originalSplashMessageScale * 1.25,
loop: -1, loop: -1,
yoyo: true, yoyo: true,
@ -104,7 +104,7 @@ export default class TitleUiHandler extends OptionSelectUiHandler {
/** Used solely to display a random Pokémon name in a splash message. */ /** Used solely to display a random Pokémon name in a splash message. */
randomPokemon(): void { randomPokemon(): void {
const rand = Utils.randInt(1025, 1); const rand = randInt(1025, 1);
const pokemon = getPokemonSpecies(rand as Species); const pokemon = getPokemonSpecies(rand as Species);
if ( if (
this.splashMessage === "splashMessages:underratedPokemon" || this.splashMessage === "splashMessages:underratedPokemon" ||
@ -132,7 +132,7 @@ export default class TitleUiHandler extends OptionSelectUiHandler {
// Moving player count to top of the menu // Moving player count to top of the menu
this.playerCountLabel.setY(globalScene.game.canvas.height / 6 - 13 - this.getWindowHeight()); this.playerCountLabel.setY(globalScene.game.canvas.height / 6 - 13 - this.getWindowHeight());
this.splashMessage = Utils.randItem(getSplashMessages()); this.splashMessage = randItem(getSplashMessages());
this.splashMessageText.setText( this.splashMessageText.setText(
i18next.t(this.splashMessage, { i18next.t(this.splashMessage, {
count: TitleUiHandler.BATTLES_WON_FALLBACK, count: TitleUiHandler.BATTLES_WON_FALLBACK,
@ -159,7 +159,7 @@ export default class TitleUiHandler extends OptionSelectUiHandler {
globalScene.tweens.add({ globalScene.tweens.add({
targets: [this.titleContainer, ui.getMessageHandler().bg], targets: [this.titleContainer, ui.getMessageHandler().bg],
duration: Utils.fixedInt(325), duration: fixedInt(325),
alpha: (target: any) => (target === this.titleContainer ? 1 : 0), alpha: (target: any) => (target === this.titleContainer ? 1 : 0),
ease: "Sine.easeInOut", ease: "Sine.easeInOut",
}); });
@ -180,7 +180,7 @@ export default class TitleUiHandler extends OptionSelectUiHandler {
globalScene.tweens.add({ globalScene.tweens.add({
targets: [this.titleContainer, ui.getMessageHandler().bg], targets: [this.titleContainer, ui.getMessageHandler().bg],
duration: Utils.fixedInt(325), duration: fixedInt(325),
alpha: (target: any) => (target === this.titleContainer ? 0 : 1), alpha: (target: any) => (target === this.titleContainer ? 0 : 1),
ease: "Sine.easeInOut", ease: "Sine.easeInOut",
}); });

View File

@ -28,7 +28,7 @@ import { addWindow } from "./ui-theme";
import LoginFormUiHandler from "./login-form-ui-handler"; import LoginFormUiHandler from "./login-form-ui-handler";
import RegistrationFormUiHandler from "./registration-form-ui-handler"; import RegistrationFormUiHandler from "./registration-form-ui-handler";
import LoadingModalUiHandler from "./loading-modal-ui-handler"; import LoadingModalUiHandler from "./loading-modal-ui-handler";
import * as Utils from "../utils"; import { executeIf } from "#app/utils";
import GameStatsUiHandler from "./game-stats-ui-handler"; import GameStatsUiHandler from "./game-stats-ui-handler";
import AwaitableUiHandler from "./awaitable-ui-handler"; import AwaitableUiHandler from "./awaitable-ui-handler";
import SaveSlotSelectUiHandler from "./save-slot-select-ui-handler"; import SaveSlotSelectUiHandler from "./save-slot-select-ui-handler";
@ -674,7 +674,7 @@ export default class UI extends Phaser.GameObjects.Container {
if (!this?.modeChain?.length) { if (!this?.modeChain?.length) {
return resolve(); return resolve();
} }
this.revertMode().then(success => Utils.executeIf(success, this.revertModes).then(() => resolve())); this.revertMode().then(success => executeIf(success, this.revertModes).then(() => resolve()));
}); });
} }

View File

@ -3,7 +3,7 @@ import { ModalUiHandler } from "./modal-ui-handler";
import { addTextObject, TextStyle } from "./text"; import { addTextObject, TextStyle } from "./text";
import type { Mode } from "./ui"; import type { Mode } from "./ui";
import { updateUserInfo } from "#app/account"; import { updateUserInfo } from "#app/account";
import * as Utils from "#app/utils"; import { removeCookie, sessionIdKey } from "#app/utils";
import i18next from "i18next"; import i18next from "i18next";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
@ -65,7 +65,7 @@ export default class UnavailableModalUiHandler extends ModalUiHandler {
globalScene.playSound("se/pb_bounce_1"); globalScene.playSound("se/pb_bounce_1");
this.reconnectCallback(); this.reconnectCallback();
} else if (response[1] === 401) { } else if (response[1] === 401) {
Utils.removeCookie(Utils.sessionIdKey); removeCookie(sessionIdKey);
globalScene.reset(true, true); globalScene.reset(true, true);
} else { } else {
this.reconnectDuration = Math.min(this.reconnectDuration * 2, this.maxTime); // Set a max delay so it isn't infinite this.reconnectDuration = Math.min(this.reconnectDuration * 2, this.maxTime); // Set a max delay so it isn't infinite

View File

@ -1,7 +1,7 @@
import { AttemptRunPhase } from "#app/phases/attempt-run-phase"; import { AttemptRunPhase } from "#app/phases/attempt-run-phase";
import type { CommandPhase } from "#app/phases/command-phase"; import type { CommandPhase } from "#app/phases/command-phase";
import { Command } from "#app/ui/command-ui-handler"; import { Command } from "#app/ui/command-ui-handler";
import * as Utils from "#app/utils"; import { NumberHolder } from "#app/utils";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/testUtils/gameManager"; import GameManager from "#test/testUtils/gameManager";
@ -45,7 +45,7 @@ describe("Escape chance calculations", () => {
await game.phaseInterceptor.to(AttemptRunPhase, false); await game.phaseInterceptor.to(AttemptRunPhase, false);
const phase = game.scene.getCurrentPhase() as AttemptRunPhase; const phase = game.scene.getCurrentPhase() as AttemptRunPhase;
const escapePercentage = new Utils.NumberHolder(0); const escapePercentage = new NumberHolder(0);
// this sets up an object for multiple attempts. The pokemonSpeedRatio is your speed divided by the enemy speed, the escapeAttempts are the number of escape attempts and the expectedEscapeChance is the chance it should be escaping // this sets up an object for multiple attempts. The pokemonSpeedRatio is your speed divided by the enemy speed, the escapeAttempts are the number of escape attempts and the expectedEscapeChance is the chance it should be escaping
const escapeChances: { const escapeChances: {
@ -118,7 +118,7 @@ describe("Escape chance calculations", () => {
await game.phaseInterceptor.to(AttemptRunPhase, false); await game.phaseInterceptor.to(AttemptRunPhase, false);
const phase = game.scene.getCurrentPhase() as AttemptRunPhase; const phase = game.scene.getCurrentPhase() as AttemptRunPhase;
const escapePercentage = new Utils.NumberHolder(0); const escapePercentage = new NumberHolder(0);
// this sets up an object for multiple attempts. The pokemonSpeedRatio is your speed divided by the enemy speed, the escapeAttempts are the number of escape attempts and the expectedEscapeChance is the chance it should be escaping // this sets up an object for multiple attempts. The pokemonSpeedRatio is your speed divided by the enemy speed, the escapeAttempts are the number of escape attempts and the expectedEscapeChance is the chance it should be escaping
const escapeChances: { const escapeChances: {
@ -197,7 +197,7 @@ describe("Escape chance calculations", () => {
await game.phaseInterceptor.to(AttemptRunPhase, false); await game.phaseInterceptor.to(AttemptRunPhase, false);
const phase = game.scene.getCurrentPhase() as AttemptRunPhase; const phase = game.scene.getCurrentPhase() as AttemptRunPhase;
const escapePercentage = new Utils.NumberHolder(0); const escapePercentage = new NumberHolder(0);
// this sets up an object for multiple attempts. The pokemonSpeedRatio is your speed divided by the enemy speed, the escapeAttempts are the number of escape attempts and the expectedEscapeChance is the chance it should be escaping // this sets up an object for multiple attempts. The pokemonSpeedRatio is your speed divided by the enemy speed, the escapeAttempts are the number of escape attempts and the expectedEscapeChance is the chance it should be escaping
const escapeChances: { const escapeChances: {
@ -284,7 +284,7 @@ describe("Escape chance calculations", () => {
await game.phaseInterceptor.to(AttemptRunPhase, false); await game.phaseInterceptor.to(AttemptRunPhase, false);
const phase = game.scene.getCurrentPhase() as AttemptRunPhase; const phase = game.scene.getCurrentPhase() as AttemptRunPhase;
const escapePercentage = new Utils.NumberHolder(0); const escapePercentage = new NumberHolder(0);
// this sets up an object for multiple attempts. The pokemonSpeedRatio is your speed divided by the enemy speed, the escapeAttempts are the number of escape attempts and the expectedEscapeChance is the chance it should be escaping // this sets up an object for multiple attempts. The pokemonSpeedRatio is your speed divided by the enemy speed, the escapeAttempts are the number of escape attempts and the expectedEscapeChance is the chance it should be escaping
const escapeChances: { const escapeChances: {

View File

@ -1,6 +1,6 @@
import { Abilities } from "#app/enums/abilities"; import { Abilities } from "#app/enums/abilities";
import { PokemonExpBoosterModifier } from "#app/modifier/modifier"; import { PokemonExpBoosterModifier } from "#app/modifier/modifier";
import * as Utils from "#app/utils"; import { NumberHolder } from "#app/utils";
import GameManager from "#test/testUtils/gameManager"; import GameManager from "#test/testUtils/gameManager";
import Phase from "phaser"; import Phase from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
@ -33,7 +33,7 @@ describe("EXP Modifier Items", () => {
const partyMember = game.scene.getPlayerPokemon()!; const partyMember = game.scene.getPlayerPokemon()!;
partyMember.exp = 100; partyMember.exp = 100;
const expHolder = new Utils.NumberHolder(partyMember.exp); const expHolder = new NumberHolder(partyMember.exp);
game.scene.applyModifiers(PokemonExpBoosterModifier, true, partyMember, expHolder); game.scene.applyModifiers(PokemonExpBoosterModifier, true, partyMember, expHolder);
expect(expHolder.value).toBe(440); expect(expHolder.value).toBe(440);
}, 20000); }, 20000);

View File

@ -1,5 +1,5 @@
import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { TurnEndPhase } from "#app/phases/turn-end-phase";
import * as Utils from "#app/utils"; import { randInt } from "#app/utils";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/testUtils/gameManager"; import GameManager from "#test/testUtils/gameManager";
@ -78,7 +78,7 @@ describe("Items - Leek", () => {
// Randomly choose from the Farfetch'd line // Randomly choose from the Farfetch'd line
const species = [Species.FARFETCHD, Species.GALAR_FARFETCHD, Species.SIRFETCHD]; const species = [Species.FARFETCHD, Species.GALAR_FARFETCHD, Species.SIRFETCHD];
await game.startBattle([species[Utils.randInt(species.length)], Species.PIKACHU]); await game.startBattle([species[randInt(species.length)], Species.PIKACHU]);
const [partyMember, ally] = game.scene.getPlayerParty(); const [partyMember, ally] = game.scene.getPlayerParty();
@ -106,7 +106,7 @@ describe("Items - Leek", () => {
// Randomly choose from the Farfetch'd line // Randomly choose from the Farfetch'd line
const species = [Species.FARFETCHD, Species.GALAR_FARFETCHD, Species.SIRFETCHD]; const species = [Species.FARFETCHD, Species.GALAR_FARFETCHD, Species.SIRFETCHD];
await game.startBattle([Species.PIKACHU, species[Utils.randInt(species.length)]]); await game.startBattle([Species.PIKACHU, species[randInt(species.length)]]);
const [partyMember, ally] = game.scene.getPlayerParty(); const [partyMember, ally] = game.scene.getPlayerParty();

View File

@ -2,7 +2,7 @@ import { Stat } from "#enums/stat";
import { SpeciesStatBoosterModifier } from "#app/modifier/modifier"; import { SpeciesStatBoosterModifier } from "#app/modifier/modifier";
import { modifierTypes } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type";
import i18next from "#app/plugins/i18n"; import i18next from "#app/plugins/i18n";
import * as Utils from "#app/utils"; import { NumberHolder } from "#app/utils";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/testUtils/gameManager"; import GameManager from "#test/testUtils/gameManager";
import Phase from "phaser"; import Phase from "phaser";
@ -90,9 +90,9 @@ describe("Items - Light Ball", () => {
const spAtkStat = partyMember.getStat(Stat.SPATK); const spAtkStat = partyMember.getStat(Stat.SPATK);
// Making sure modifier is not applied without holding item // Making sure modifier is not applied without holding item
const atkValue = new Utils.NumberHolder(atkStat); const atkValue = new NumberHolder(atkStat);
game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, atkValue); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, atkValue);
const spAtkValue = new Utils.NumberHolder(spAtkStat); const spAtkValue = new NumberHolder(spAtkStat);
game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPDEF, spAtkValue); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPDEF, spAtkValue);
expect(atkValue.value / atkStat).toBe(1); expect(atkValue.value / atkStat).toBe(1);
@ -129,9 +129,9 @@ describe("Items - Light Ball", () => {
const spAtkStat = partyMember.getStat(Stat.SPATK); const spAtkStat = partyMember.getStat(Stat.SPATK);
// Making sure modifier is not applied without holding item // Making sure modifier is not applied without holding item
const atkValue = new Utils.NumberHolder(atkStat); const atkValue = new NumberHolder(atkStat);
game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, atkValue); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, atkValue);
const spAtkValue = new Utils.NumberHolder(spAtkStat); const spAtkValue = new NumberHolder(spAtkStat);
game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPDEF, spAtkValue); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPDEF, spAtkValue);
expect(atkValue.value / atkStat).toBe(1); expect(atkValue.value / atkStat).toBe(1);
@ -168,9 +168,9 @@ describe("Items - Light Ball", () => {
const spAtkStat = partyMember.getStat(Stat.SPATK); const spAtkStat = partyMember.getStat(Stat.SPATK);
// Making sure modifier is not applied without holding item // Making sure modifier is not applied without holding item
const atkValue = new Utils.NumberHolder(atkStat); const atkValue = new NumberHolder(atkStat);
game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, atkValue); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, atkValue);
const spAtkValue = new Utils.NumberHolder(spAtkStat); const spAtkValue = new NumberHolder(spAtkStat);
game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPDEF, spAtkValue); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPDEF, spAtkValue);
expect(atkValue.value / atkStat).toBe(1); expect(atkValue.value / atkStat).toBe(1);
@ -197,9 +197,9 @@ describe("Items - Light Ball", () => {
const spAtkStat = partyMember.getStat(Stat.SPATK); const spAtkStat = partyMember.getStat(Stat.SPATK);
// Making sure modifier is not applied without holding item // Making sure modifier is not applied without holding item
const atkValue = new Utils.NumberHolder(atkStat); const atkValue = new NumberHolder(atkStat);
game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, atkValue); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, atkValue);
const spAtkValue = new Utils.NumberHolder(spAtkStat); const spAtkValue = new NumberHolder(spAtkStat);
game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPDEF, spAtkValue); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPDEF, spAtkValue);
expect(atkValue.value / atkStat).toBe(1); expect(atkValue.value / atkStat).toBe(1);

View File

@ -2,7 +2,7 @@ import { Stat } from "#enums/stat";
import { SpeciesStatBoosterModifier } from "#app/modifier/modifier"; import { SpeciesStatBoosterModifier } from "#app/modifier/modifier";
import { modifierTypes } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type";
import i18next from "#app/plugins/i18n"; import i18next from "#app/plugins/i18n";
import * as Utils from "#app/utils"; import { NumberHolder } from "#app/utils";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/testUtils/gameManager"; import GameManager from "#test/testUtils/gameManager";
import Phase from "phaser"; import Phase from "phaser";
@ -89,7 +89,7 @@ describe("Items - Metal Powder", () => {
const defStat = partyMember.getStat(Stat.DEF); const defStat = partyMember.getStat(Stat.DEF);
// Making sure modifier is not applied without holding item // Making sure modifier is not applied without holding item
const defValue = new Utils.NumberHolder(defStat); const defValue = new NumberHolder(defStat);
game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, defValue); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, defValue);
expect(defValue.value / defStat).toBe(1); expect(defValue.value / defStat).toBe(1);
@ -122,7 +122,7 @@ describe("Items - Metal Powder", () => {
const defStat = partyMember.getStat(Stat.DEF); const defStat = partyMember.getStat(Stat.DEF);
// Making sure modifier is not applied without holding item // Making sure modifier is not applied without holding item
const defValue = new Utils.NumberHolder(defStat); const defValue = new NumberHolder(defStat);
game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, defValue); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, defValue);
expect(defValue.value / defStat).toBe(1); expect(defValue.value / defStat).toBe(1);
@ -155,7 +155,7 @@ describe("Items - Metal Powder", () => {
const defStat = partyMember.getStat(Stat.DEF); const defStat = partyMember.getStat(Stat.DEF);
// Making sure modifier is not applied without holding item // Making sure modifier is not applied without holding item
const defValue = new Utils.NumberHolder(defStat); const defValue = new NumberHolder(defStat);
game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, defValue); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, defValue);
expect(defValue.value / defStat).toBe(1); expect(defValue.value / defStat).toBe(1);
@ -178,7 +178,7 @@ describe("Items - Metal Powder", () => {
const defStat = partyMember.getStat(Stat.DEF); const defStat = partyMember.getStat(Stat.DEF);
// Making sure modifier is not applied without holding item // Making sure modifier is not applied without holding item
const defValue = new Utils.NumberHolder(defStat); const defValue = new NumberHolder(defStat);
game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, defValue); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, defValue);
expect(defValue.value / defStat).toBe(1); expect(defValue.value / defStat).toBe(1);

View File

@ -2,7 +2,7 @@ import { Stat } from "#enums/stat";
import { SpeciesStatBoosterModifier } from "#app/modifier/modifier"; import { SpeciesStatBoosterModifier } from "#app/modifier/modifier";
import { modifierTypes } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type";
import i18next from "#app/plugins/i18n"; import i18next from "#app/plugins/i18n";
import * as Utils from "#app/utils"; import { NumberHolder } from "#app/utils";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/testUtils/gameManager"; import GameManager from "#test/testUtils/gameManager";
import Phase from "phaser"; import Phase from "phaser";
@ -89,7 +89,7 @@ describe("Items - Quick Powder", () => {
const spdStat = partyMember.getStat(Stat.SPD); const spdStat = partyMember.getStat(Stat.SPD);
// Making sure modifier is not applied without holding item // Making sure modifier is not applied without holding item
const spdValue = new Utils.NumberHolder(spdStat); const spdValue = new NumberHolder(spdStat);
game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPD, spdValue); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPD, spdValue);
expect(spdValue.value / spdStat).toBe(1); expect(spdValue.value / spdStat).toBe(1);
@ -122,7 +122,7 @@ describe("Items - Quick Powder", () => {
const spdStat = partyMember.getStat(Stat.SPD); const spdStat = partyMember.getStat(Stat.SPD);
// Making sure modifier is not applied without holding item // Making sure modifier is not applied without holding item
const spdValue = new Utils.NumberHolder(spdStat); const spdValue = new NumberHolder(spdStat);
game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPD, spdValue); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPD, spdValue);
expect(spdValue.value / spdStat).toBe(1); expect(spdValue.value / spdStat).toBe(1);
@ -155,7 +155,7 @@ describe("Items - Quick Powder", () => {
const spdStat = partyMember.getStat(Stat.SPD); const spdStat = partyMember.getStat(Stat.SPD);
// Making sure modifier is not applied without holding item // Making sure modifier is not applied without holding item
const spdValue = new Utils.NumberHolder(spdStat); const spdValue = new NumberHolder(spdStat);
game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPD, spdValue); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPD, spdValue);
expect(spdValue.value / spdStat).toBe(1); expect(spdValue.value / spdStat).toBe(1);
@ -178,7 +178,7 @@ describe("Items - Quick Powder", () => {
const spdStat = partyMember.getStat(Stat.SPD); const spdStat = partyMember.getStat(Stat.SPD);
// Making sure modifier is not applied without holding item // Making sure modifier is not applied without holding item
const spdValue = new Utils.NumberHolder(spdStat); const spdValue = new NumberHolder(spdStat);
game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPD, spdValue); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPD, spdValue);
expect(spdValue.value / spdStat).toBe(1); expect(spdValue.value / spdStat).toBe(1);

View File

@ -2,7 +2,7 @@ import { Stat } from "#enums/stat";
import { SpeciesStatBoosterModifier } from "#app/modifier/modifier"; import { SpeciesStatBoosterModifier } from "#app/modifier/modifier";
import { modifierTypes } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type";
import i18next from "#app/plugins/i18n"; import i18next from "#app/plugins/i18n";
import * as Utils from "#app/utils"; import { NumberHolder, randInt } from "#app/utils";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/testUtils/gameManager"; import GameManager from "#test/testUtils/gameManager";
import Phase from "phaser"; import Phase from "phaser";
@ -89,7 +89,7 @@ describe("Items - Thick Club", () => {
const atkStat = partyMember.getStat(Stat.ATK); const atkStat = partyMember.getStat(Stat.ATK);
// Making sure modifier is not applied without holding item // Making sure modifier is not applied without holding item
const atkValue = new Utils.NumberHolder(atkStat); const atkValue = new NumberHolder(atkStat);
game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue);
expect(atkValue.value / atkStat).toBe(1); expect(atkValue.value / atkStat).toBe(1);
@ -112,7 +112,7 @@ describe("Items - Thick Club", () => {
const atkStat = partyMember.getStat(Stat.ATK); const atkStat = partyMember.getStat(Stat.ATK);
// Making sure modifier is not applied without holding item // Making sure modifier is not applied without holding item
const atkValue = new Utils.NumberHolder(atkStat); const atkValue = new NumberHolder(atkStat);
game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue);
expect(atkValue.value / atkStat).toBe(1); expect(atkValue.value / atkStat).toBe(1);
@ -135,7 +135,7 @@ describe("Items - Thick Club", () => {
const atkStat = partyMember.getStat(Stat.ATK); const atkStat = partyMember.getStat(Stat.ATK);
// Making sure modifier is not applied without holding item // Making sure modifier is not applied without holding item
const atkValue = new Utils.NumberHolder(atkStat); const atkValue = new NumberHolder(atkStat);
game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue);
expect(atkValue.value / atkStat).toBe(1); expect(atkValue.value / atkStat).toBe(1);
@ -153,7 +153,7 @@ describe("Items - Thick Club", () => {
it("THICK_CLUB held by fused CUBONE line (base)", async () => { it("THICK_CLUB held by fused CUBONE line (base)", async () => {
// Randomly choose from the Cubone line // Randomly choose from the Cubone line
const species = [Species.CUBONE, Species.MAROWAK, Species.ALOLA_MAROWAK]; const species = [Species.CUBONE, Species.MAROWAK, Species.ALOLA_MAROWAK];
const randSpecies = Utils.randInt(species.length); const randSpecies = randInt(species.length);
await game.classicMode.startBattle([species[randSpecies], Species.PIKACHU]); await game.classicMode.startBattle([species[randSpecies], Species.PIKACHU]);
@ -172,7 +172,7 @@ describe("Items - Thick Club", () => {
const atkStat = partyMember.getStat(Stat.ATK); const atkStat = partyMember.getStat(Stat.ATK);
// Making sure modifier is not applied without holding item // Making sure modifier is not applied without holding item
const atkValue = new Utils.NumberHolder(atkStat); const atkValue = new NumberHolder(atkStat);
game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue);
expect(atkValue.value / atkStat).toBe(1); expect(atkValue.value / atkStat).toBe(1);
@ -190,7 +190,7 @@ describe("Items - Thick Club", () => {
it("THICK_CLUB held by fused CUBONE line (part)", async () => { it("THICK_CLUB held by fused CUBONE line (part)", async () => {
// Randomly choose from the Cubone line // Randomly choose from the Cubone line
const species = [Species.CUBONE, Species.MAROWAK, Species.ALOLA_MAROWAK]; const species = [Species.CUBONE, Species.MAROWAK, Species.ALOLA_MAROWAK];
const randSpecies = Utils.randInt(species.length); const randSpecies = randInt(species.length);
await game.classicMode.startBattle([Species.PIKACHU, species[randSpecies]]); await game.classicMode.startBattle([Species.PIKACHU, species[randSpecies]]);
@ -209,7 +209,7 @@ describe("Items - Thick Club", () => {
const atkStat = partyMember.getStat(Stat.ATK); const atkStat = partyMember.getStat(Stat.ATK);
// Making sure modifier is not applied without holding item // Making sure modifier is not applied without holding item
const atkValue = new Utils.NumberHolder(atkStat); const atkValue = new NumberHolder(atkStat);
game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue);
expect(atkValue.value / atkStat).toBe(1); expect(atkValue.value / atkStat).toBe(1);
@ -232,7 +232,7 @@ describe("Items - Thick Club", () => {
const atkStat = partyMember.getStat(Stat.ATK); const atkStat = partyMember.getStat(Stat.ATK);
// Making sure modifier is not applied without holding item // Making sure modifier is not applied without holding item
const atkValue = new Utils.NumberHolder(atkStat); const atkValue = new NumberHolder(atkStat);
game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue);
expect(atkValue.value / atkStat).toBe(1); expect(atkValue.value / atkStat).toBe(1);

View File

@ -1,7 +1,7 @@
import { BattlerIndex } from "#app/battle"; import { BattlerIndex } from "#app/battle";
import { Abilities } from "#app/enums/abilities"; import { Abilities } from "#app/enums/abilities";
import { Species } from "#app/enums/species"; import { Species } from "#app/enums/species";
import * as Utils from "#app/utils"; import { toDmgValue } from "#app/utils";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import GameManager from "#test/testUtils/gameManager"; import GameManager from "#test/testUtils/gameManager";
import Phaser from "phaser"; import Phaser from "phaser";
@ -71,8 +71,8 @@ describe("Multi-target damage reduction", () => {
// Single target moves don't get reduced // Single target moves don't get reduced
expect(tackle1).toBe(tackle2); expect(tackle1).toBe(tackle2);
// Moves that target all enemies get reduced if there's more than one enemy // Moves that target all enemies get reduced if there's more than one enemy
expect(gleam1).toBeLessThanOrEqual(Utils.toDmgValue(gleam2 * 0.75) + 1); expect(gleam1).toBeLessThanOrEqual(toDmgValue(gleam2 * 0.75) + 1);
expect(gleam1).toBeGreaterThanOrEqual(Utils.toDmgValue(gleam2 * 0.75) - 1); expect(gleam1).toBeGreaterThanOrEqual(toDmgValue(gleam2 * 0.75) - 1);
}); });
it("should reduce earthquake when more than one pokemon other than user is not fainted", async () => { it("should reduce earthquake when more than one pokemon other than user is not fainted", async () => {
@ -122,7 +122,7 @@ describe("Multi-target damage reduction", () => {
const damageEnemy1Turn3 = enemy1.getMaxHp() - enemy1.hp; const damageEnemy1Turn3 = enemy1.getMaxHp() - enemy1.hp;
// Turn 3: 1 target, should be no damage reduction // Turn 3: 1 target, should be no damage reduction
expect(damageEnemy1Turn1).toBeLessThanOrEqual(Utils.toDmgValue(damageEnemy1Turn3 * 0.75) + 1); expect(damageEnemy1Turn1).toBeLessThanOrEqual(toDmgValue(damageEnemy1Turn3 * 0.75) + 1);
expect(damageEnemy1Turn1).toBeGreaterThanOrEqual(Utils.toDmgValue(damageEnemy1Turn3 * 0.75) - 1); expect(damageEnemy1Turn1).toBeGreaterThanOrEqual(toDmgValue(damageEnemy1Turn3 * 0.75) - 1);
}); });
}); });

View File

@ -1,3 +1,4 @@
// biome-ignore lint/style/noNamespaceImport: Necessary for mocks
import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { Status } from "#app/data/status-effect"; import { Status } from "#app/data/status-effect";
import { CommandPhase } from "#app/phases/command-phase"; import { CommandPhase } from "#app/phases/command-phase";

View File

@ -2,7 +2,7 @@
import BattleScene, * as battleScene from "#app/battle-scene"; import BattleScene, * as battleScene from "#app/battle-scene";
import { MoveAnim } from "#app/data/battle-anims"; import { MoveAnim } from "#app/data/battle-anims";
import Pokemon from "#app/field/pokemon"; import Pokemon from "#app/field/pokemon";
import * as Utils from "#app/utils"; import { setCookie, sessionIdKey } from "#app/utils";
import { blobToString } from "#test/testUtils/gameManagerUtils"; import { blobToString } from "#test/testUtils/gameManagerUtils";
import { MockClock } from "#test/testUtils/mocks/mockClock"; import { MockClock } from "#test/testUtils/mocks/mockClock";
import { MockFetch } from "#test/testUtils/mocks/mockFetch"; import { MockFetch } from "#test/testUtils/mocks/mockFetch";
@ -29,7 +29,7 @@ window.URL.createObjectURL = (blob: Blob) => {
}; };
navigator.getGamepads = () => []; navigator.getGamepads = () => [];
global.fetch = vi.fn(MockFetch); global.fetch = vi.fn(MockFetch);
Utils.setCookie(Utils.sessionIdKey, "fake_token"); setCookie(sessionIdKey, "fake_token");
window.matchMedia = () => ({ window.matchMedia = () => ({
matches: false, matches: false,