Compare commits

...

3 Commits

Author SHA1 Message Date
Bertie690
d06eb1bcc7 Partially fixed some private property issues
Left some mocks alone because IDFK what they mean
2025-08-14 00:18:47 -04:00
Bertie690
618a4b5fc3 Applied linter fixes 2025-08-14 00:06:36 -04:00
Bertie690
5d267d045e dd 2025-08-14 00:04:36 -04:00
72 changed files with 778 additions and 900 deletions

View File

@ -3,7 +3,7 @@
# top-most EditorConfig file
root = true
[src/*.{js,ts}]
[**/*.{js,ts,json,jsonc}]
indent_style = space
indent_size = 2
end_of_line = lf

View File

@ -1,4 +1,5 @@
{
// ! Just ignore the errors for now guys.
"$schema": "https://biomejs.dev/schemas/2.1.4/schema.json",
"vcs": {
"enabled": true,
@ -66,6 +67,7 @@
},
"style": {
"useCollapsedIf": "error",
"useCollapsedElseIf": "error",
"noDoneCallback": "error",
"noSubstr": "error",
"noYodaExpression": "error",
@ -86,7 +88,10 @@
"level": "warn",
"fix": "none"
},
"useSingleVarDeclarator": "error",
"useSingleVarDeclarator": {
"level": "error",
"fix": "safe"
},
"useNodejsImportProtocol": "off",
"useTemplate": "off", // string concatenation is faster: https://stackoverflow.com/questions/29055518/are-es6-template-literals-faster-than-string-concatenation
"useAsConstAssertion": "error",

View File

@ -19,23 +19,22 @@ Generally speaking, most users shouldn't need to run Biome directly; in addition
> ![WARNING]
> You will **not** be able to commit code if any staged files contain `error`-level linting problems. \
> If you, for whatever reason, _absolutely need_ to bypass Lefthook while committing,
> `LEFTHOOK=0 git commit` will skip all pre-commit hooks for the given operation.
> If you, for whatever reason, _absolutely need_ to bypass Lefthook for a given commit,
> `LEFTHOOK=0 git commit` will skip running all pre-commit hooks during the commit process.
We also have a [Github Action](../.github/workflows/quality.yml) to verify code quality each time a PR is updated, preventing bad code from inadvertently making its way upstream. \
We also have a [Github Action](../.github/workflows/linting.yml) to verify code quality each time a PR is updated, preventing bad code from inadvertently making its way upstream. \
These are effectively the same commands as run by Lefthook, merely on a project-wide scale.
## Running Biome via CLI
If you want Biome to check your files manually, you have 2 options:
1. Run the `biome` script included in `package.json` (`pnpm biome`).
This has sensible defaults for command-line options, but does not allow altering certain flags (as some cannot be specified twice in the same command)
To run you Biome on your files manually, you have 2 main options:
1. Run the scripts included in `package.json` (`pnpm biome` and `pnpm biome:all`). \
These have sensible defaults for command-line options, but do not allow altering certain flags (as some cannot be specified twice in the same command)
2. Execute the Biome executable manually from the command line like so:
```sh
pnpm exec biome check --[flags]
```
This allows customizing flags non-overridable flags like `--diagnostic-level` on a more granular level, but requires slightly more verbosity.
This allows customizing non-overridable flags like `--diagnostic-level` on a more granular level, but requires slightly more verbosity and specifying more options.
A full list of flags and options can be found on [their website](https://biomejs.dev/reference/cli/), but here's a few useful ones to keep in mind:

View File

@ -18,6 +18,7 @@
"eslint": "eslint --fix .",
"eslint-ci": "eslint .",
"biome": "biome check --write --changed --no-errors-on-unmatched --diagnostic-level=error",
"biome:all": "biome check --write --no-errors-on-unmatched --diagnostic-level=error",
"biome-ci": "biome ci --diagnostic-level=error --reporter=github --no-errors-on-unmatched",
"docs": "typedoc",
"depcruise": "depcruise src test",

View File

@ -1463,7 +1463,6 @@ export class PostDefendAbilityGiveAbAttr extends PostDefendAbAttr {
export class PostDefendMoveDisableAbAttr extends PostDefendAbAttr {
private chance: number;
private attacker: Pokemon;
private move: Move;
constructor(chance: number) {
super();
@ -1479,11 +1478,9 @@ export class PostDefendMoveDisableAbAttr extends PostDefendAbAttr {
);
}
override apply({ simulated, opponent: attacker, move, pokemon }: PostMoveInteractionAbAttrParams): void {
// TODO: investigate why this is setting properties
override apply({ simulated, opponent: attacker, pokemon }: PostMoveInteractionAbAttrParams): void {
if (!simulated) {
this.attacker = attacker;
this.move = move;
this.attacker.addTag(BattlerTagType.DISABLED, 4, 0, pokemon.id);
}
}
@ -6345,10 +6342,13 @@ class ForceSwitchOutHelper {
return !blockedByAbility.value;
}
if (!player && globalScene.currentBattle.battleType === BattleType.WILD) {
if (!globalScene.currentBattle.waveIndex && globalScene.currentBattle.waveIndex % 10 === 0) {
return false;
}
if (
!player &&
globalScene.currentBattle.battleType === BattleType.WILD &&
!globalScene.currentBattle.waveIndex &&
globalScene.currentBattle.waveIndex % 10 === 0
) {
return false;
}
if (

View File

@ -616,7 +616,7 @@ export const speciesStarterCosts = {
[SpeciesId.PALDEA_TAUROS]: 5,
[SpeciesId.PALDEA_WOOPER]: 3,
[SpeciesId.BLOODMOON_URSALUNA]: 5,
};
} as const;
const starterCandyCosts: { passive: number; costReduction: [number, number]; egg: number; }[] = [
{ passive: 40, costReduction: [ 25, 60 ], egg: 30 }, // 1 Cost
@ -657,4 +657,3 @@ export function getValueReductionCandyCounts(starterCost: number): [number, numb
export function getSameSpeciesEggCandyCounts(starterCost: number): number {
return starterCandyCosts[starterCost - 1].egg;
}

View File

@ -1397,6 +1397,7 @@ export class EncounterBattleAnim extends BattleAnim {
}
}
// biome-ignore-start lint/style/useForOf: This is being removed
export async function populateAnims() {
const commonAnimNames = getEnumKeys(CommonAnim).map(k => k.toLowerCase());
const commonAnimMatchNames = commonAnimNames.map(k => k.replace(/_/g, ""));
@ -1672,3 +1673,5 @@ export async function populateAnims() {
})();
}*/
}
// biome-ignore-end lint/style/useForOf: This is being removed

View File

@ -2537,12 +2537,10 @@ export class RoostedTag extends BattlerTag {
let modifiedTypes: PokemonType[];
if (this.isBasePureFlying && !isCurrentlyDualType) {
modifiedTypes = [PokemonType.NORMAL];
} else if (!!pokemon.getTag(RemovedTypeTag) && isOriginallyDualType && !isCurrentlyDualType) {
modifiedTypes = [PokemonType.UNKNOWN];
} else {
if (!!pokemon.getTag(RemovedTypeTag) && isOriginallyDualType && !isCurrentlyDualType) {
modifiedTypes = [PokemonType.UNKNOWN];
} else {
modifiedTypes = currentTypes.filter(type => type !== PokemonType.FLYING);
}
modifiedTypes = currentTypes.filter(type => type !== PokemonType.FLYING);
}
pokemon.summonData.types = modifiedTypes;
pokemon.updateInfo();

View File

@ -42,10 +42,9 @@ export function getDailyRunStarters(seed: string): Starter[] {
starterCosts.push(randSeedInt(9 - starterCosts[0], 1));
starterCosts.push(10 - (starterCosts[0] + starterCosts[1]));
for (let c = 0; c < starterCosts.length; c++) {
const cost = starterCosts[c];
for (const cost of starterCosts) {
const costSpecies = Object.keys(speciesStarterCosts)
.map(s => Number.parseInt(s) as SpeciesId)
.map(s => Number.parseInt(s) as SpeciesId) // TODO: Remove
.filter(s => speciesStarterCosts[s] === cost);
const randPkmSpecies = getPokemonSpecies(randSeedItem(costSpecies));
const starterSpecies = getPokemonSpecies(

View File

@ -419,10 +419,8 @@ export class Egg {
const rand = randSeedInt(MANAPHY_EGG_MANAPHY_RATE) !== 1;
return rand ? SpeciesId.PHIONE : SpeciesId.MANAPHY;
}
if (this.tier === EggTier.LEGENDARY && this._sourceType === EggSourceType.GACHA_LEGENDARY) {
if (!randSeedInt(2)) {
return getLegendaryGachaSpeciesForTimestamp(this.timestamp);
}
if (this.tier === EggTier.LEGENDARY && this._sourceType === EggSourceType.GACHA_LEGENDARY && !randSeedInt(2)) {
return getLegendaryGachaSpeciesForTimestamp(this.timestamp);
}
let minStarterValue: number;

View File

@ -527,7 +527,8 @@ function doBerrySpritePile(isEat = false) {
const encounter = globalScene.currentBattle.mysteryEncounter!;
animationOrder.forEach((berry, i) => {
const introVisualsIndex = encounter.spriteConfigs.findIndex(config => config.spriteKey?.includes(berry));
let sprite: Phaser.GameObjects.Sprite, tintSprite: Phaser.GameObjects.Sprite;
let sprite: Phaser.GameObjects.Sprite;
let tintSprite: Phaser.GameObjects.Sprite;
const sprites = encounter.introVisuals?.getSpriteAtIndex(introVisualsIndex);
if (sprites) {
sprite = sprites[0];

View File

@ -213,7 +213,8 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
female: true,
});
let beedrillKeys: { spriteKey: string; fileRoot: string }, butterfreeKeys: { spriteKey: string; fileRoot: string };
let beedrillKeys: { spriteKey: string; fileRoot: string };
let butterfreeKeys: { spriteKey: string; fileRoot: string };
if (globalScene.currentBattle.waveIndex < WAVE_LEVEL_BREAKPOINTS[3]) {
beedrillKeys = getSpriteKeysFromSpecies(SpeciesId.BEEDRILL, false);
butterfreeKeys = getSpriteKeysFromSpecies(SpeciesId.BUTTERFREE, false);

View File

@ -289,16 +289,14 @@ export const GlobalTradeSystemEncounter: MysteryEncounter = MysteryEncounterBuil
// Extra HA roll at base 1/64 odds (boosted by events and charms)
const hiddenIndex = tradePokemon.species.ability2 ? 2 : 1;
if (tradePokemon.species.abilityHidden) {
if (tradePokemon.abilityIndex < hiddenIndex) {
const hiddenAbilityChance = new NumberHolder(64);
globalScene.applyModifiers(HiddenAbilityRateBoosterModifier, true, hiddenAbilityChance);
if (tradePokemon.species.abilityHidden && tradePokemon.abilityIndex < hiddenIndex) {
const hiddenAbilityChance = new NumberHolder(64);
globalScene.applyModifiers(HiddenAbilityRateBoosterModifier, true, hiddenAbilityChance);
const hasHiddenAbility = !randSeedInt(hiddenAbilityChance.value);
const hasHiddenAbility = !randSeedInt(hiddenAbilityChance.value);
if (hasHiddenAbility) {
tradePokemon.abilityIndex = hiddenIndex;
}
if (hasHiddenAbility) {
tradePokemon.abilityIndex = hiddenIndex;
}
}

View File

@ -1107,12 +1107,10 @@ export function calculateMEAggregateStats(baseSpawnWeight: number) {
}
} else if (biomeLinks.hasOwnProperty(currentBiome)) {
currentBiome = biomeLinks[currentBiome] as BiomeId;
} else if (!(i % 50)) {
currentBiome = BiomeId.END;
} else {
if (!(i % 50)) {
currentBiome = BiomeId.END;
} else {
currentBiome = globalScene.generateRandomBiome(i);
}
currentBiome = globalScene.generateRandomBiome(i);
}
currentArena = globalScene.newArena(currentBiome);

View File

@ -986,41 +986,39 @@ export class PokemonSpecies extends PokemonSpeciesForm implements Localizable {
if (!forTrainer && isRegionalEvolution) {
evolutionChance = 0;
} else {
if (ev.wildDelay === SpeciesWildEvolutionDelay.NONE) {
if (strength === PartyMemberStrength.STRONGER) {
evolutionChance = 1;
} else {
const maxLevelDiff = this.getStrengthLevelDiff(strength); //The maximum distance from the evolution level tolerated for the mon to not evolve
const minChance: number = 0.875 - 0.125 * strength;
evolutionChance = Math.min(
minChance + easeInFunc(Math.min(level - ev.level, maxLevelDiff) / maxLevelDiff) * (1 - minChance),
1,
);
}
} else if (ev.wildDelay === SpeciesWildEvolutionDelay.NONE) {
if (strength === PartyMemberStrength.STRONGER) {
evolutionChance = 1;
} else {
const preferredMinLevel = Math.max(ev.level - 1 + ev.wildDelay! * this.getStrengthLevelDiff(strength), 1); // TODO: is the bang correct?
let evolutionLevel = Math.max(ev.level > 1 ? ev.level : Math.floor(preferredMinLevel / 2), 1);
if (ev.level <= 1 && pokemonPrevolutions.hasOwnProperty(this.speciesId)) {
const prevolutionLevel = pokemonEvolutions[pokemonPrevolutions[this.speciesId]].find(
ev => ev.speciesId === this.speciesId,
)!.level; // TODO: is the bang correct?
if (prevolutionLevel > 1) {
evolutionLevel = prevolutionLevel;
}
}
const maxLevelDiff = this.getStrengthLevelDiff(strength); //The maximum distance from the evolution level tolerated for the mon to not evolve
const minChance: number = 0.875 - 0.125 * strength;
evolutionChance = Math.min(
0.65 * easeInFunc(Math.min(Math.max(level - evolutionLevel, 0), preferredMinLevel) / preferredMinLevel) +
0.35 *
easeOutFunc(
Math.min(Math.max(level - evolutionLevel, 0), preferredMinLevel * 2.5) / (preferredMinLevel * 2.5),
),
minChance + easeInFunc(Math.min(level - ev.level, maxLevelDiff) / maxLevelDiff) * (1 - minChance),
1,
);
}
} else {
const preferredMinLevel = Math.max(ev.level - 1 + ev.wildDelay! * this.getStrengthLevelDiff(strength), 1); // TODO: is the bang correct?
let evolutionLevel = Math.max(ev.level > 1 ? ev.level : Math.floor(preferredMinLevel / 2), 1);
if (ev.level <= 1 && pokemonPrevolutions.hasOwnProperty(this.speciesId)) {
const prevolutionLevel = pokemonEvolutions[pokemonPrevolutions[this.speciesId]].find(
ev => ev.speciesId === this.speciesId,
)!.level; // TODO: is the bang correct?
if (prevolutionLevel > 1) {
evolutionLevel = prevolutionLevel;
}
}
evolutionChance = Math.min(
0.65 * easeInFunc(Math.min(Math.max(level - evolutionLevel, 0), preferredMinLevel) / preferredMinLevel) +
0.35 *
easeOutFunc(
Math.min(Math.max(level - evolutionLevel, 0), preferredMinLevel * 2.5) / (preferredMinLevel * 2.5),
),
1,
);
}
//TODO: Adjust templates and delays so we don't have to hardcode it
@ -1210,9 +1208,9 @@ export class PokemonSpecies extends PokemonSpeciesForm implements Localizable {
}
/**
* Generates a {@linkcode bigint} corresponding to the maximum unlocks possible for this species,
* Generates a {@linkcode BigInt} corresponding to the maximum unlocks possible for this species,
* taking into account if the species has a male/female gender, and which variants are implemented.
* @returns {@linkcode bigint} Maximum unlocks, can be compared with {@linkcode DexEntry.caughtAttr}.
* @returns The maximum unlocks for the species as a `BigInt`; can be compared with {@linkcode DexEntry.caughtAttr}.
*/
getFullUnlocksData(): bigint {
let caughtAttr = 0n;

View File

@ -6,6 +6,7 @@ import type { MysteryEncounter } from "#mystery-encounters/mystery-encounter";
import { loadPokemonVariantAssets } from "#sprites/pokemon-sprite";
import type { Variant } from "#sprites/variant";
import { isNullOrUndefined } from "#utils/common";
import console from "node:console";
import type { GameObjects } from "phaser";
type PlayAnimationConfig = Phaser.Types.Animations.PlayAnimationConfig;
@ -87,6 +88,7 @@ export class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Container {
variant: Variant;
}[];
// TODO: Refactor
constructor(encounter: MysteryEncounter) {
super(globalScene, -72, 76);
this.encounter = encounter;
@ -193,17 +195,15 @@ export class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Container {
sprite.setPosition(sprite.x, sprite.y + y);
tintSprite.setPosition(tintSprite.x, tintSprite.y + y);
}
} else {
// Single sprite
if (this.spriteConfigs.length === 1) {
sprite.x = origin;
tintSprite.x = origin;
} else {
// Do standard sprite spacing (not including offset sprites)
sprite.x = minX + (n + 0.5) * spacingValue + origin;
tintSprite.x = minX + (n + 0.5) * spacingValue + origin;
n++;
}
} else if (this.spriteConfigs.length === 1) {
sprite.x = origin;
tintSprite.x = origin;
} else {
// Do standard sprite spacing (not including offset sprites)
sprite.x = minX + (n + 0.5) * spacingValue + origin;
tintSprite.x = minX + (n + 0.5) * spacingValue + origin;
n++;
}
if (!isNullOrUndefined(pokemonShinySparkle)) {

View File

@ -2511,17 +2511,13 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
defenderType,
});
}
if (ignoreImmunity.value) {
if (multiplier.value === 0) {
return 1;
}
if (ignoreImmunity.value && multiplier.value === 0) {
return 1;
}
const exposedTags = this.findTags(tag => tag instanceof ExposedTag) as ExposedTag[];
if (exposedTags.some(t => t.ignoreImmunity(defenderType, moveType))) {
if (multiplier.value === 0) {
return 1;
}
if (exposedTags.some(t => t.ignoreImmunity(defenderType, moveType)) && multiplier.value === 0) {
return 1;
}
}
return multiplier.value;
@ -2960,10 +2956,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
return false;
}
const haThreshold = new NumberHolder(thresholdOverride ?? BASE_HIDDEN_ABILITY_CHANCE);
if (applyModifiersToOverride) {
if (!this.hasTrainer()) {
globalScene.applyModifiers(HiddenAbilityRateBoosterModifier, true, haThreshold);
}
if (applyModifiersToOverride && !this.hasTrainer()) {
globalScene.applyModifiers(HiddenAbilityRateBoosterModifier, true, haThreshold);
}
if (randSeedInt(65536) < haThreshold.value) {
@ -3063,8 +3057,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
return;
}
for (let m = 0; m < allLevelMoves.length; m++) {
const levelMove = allLevelMoves[m];
for (const levelMove of allLevelMoves) {
if (this.level < levelMove[0]) {
break;
}
@ -4829,11 +4822,9 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
return true;
});
if (this.isOfType(PokemonType.POISON) || this.isOfType(PokemonType.STEEL)) {
if (poisonImmunity.includes(true)) {
this.queueStatusImmuneMessage(quiet);
return false;
}
if ((this.isOfType(PokemonType.POISON) || this.isOfType(PokemonType.STEEL)) && poisonImmunity.includes(true)) {
this.queueStatusImmuneMessage(quiet);
return false;
}
break;
}
@ -5013,10 +5004,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
this.lapseTag(BattlerTagType.NIGHTMARE);
}
}
if (confusion) {
if (this.getTag(BattlerTagType.CONFUSED)) {
this.lapseTag(BattlerTagType.CONFUSED);
}
if (confusion && this.getTag(BattlerTagType.CONFUSED)) {
this.lapseTag(BattlerTagType.CONFUSED);
}
if (reloadAssets) {
this.loadAssets(false).then(() => this.playAnim());
@ -5500,8 +5489,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
spriteColors.forEach((sc: number[], i: number) => {
paletteDeltas.push([]);
for (let p = 0; p < palette.length; p++) {
paletteDeltas[i].push(deltaRgb(sc, palette[p]));
for (const p of palette) {
paletteDeltas[i].push(deltaRgb(sc, p));
}
});
@ -6774,10 +6763,12 @@ export class EnemyPokemon extends Pokemon {
}
canBypassBossSegments(segmentCount = 1): boolean {
if (globalScene.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) {
if (!this.formIndex && this.bossSegmentIndex - segmentCount < 1) {
return false;
}
if (
globalScene.currentBattle.battleSpec === BattleSpec.FINAL_BOSS &&
!this.formIndex &&
this.bossSegmentIndex - segmentCount < 1
) {
return false;
}
return true;

View File

@ -403,16 +403,14 @@ export class Trainer extends Phaser.GameObjects.Container {
} else {
newSpeciesPool = speciesPoolFiltered;
}
} else {
// If the index is odd, use the species pool for the partner trainer (that way he only uses his own pokemon in battle)
// Since the only currently allowed double battle with named trainers is Tate & Liza, we need to make sure that Solrock is the first pokemon in the party for Tate and Lunatone for Liza
if (index === 1 && TrainerType[this.config.trainerTypeDouble] === TrainerType[TrainerType.TATE]) {
newSpeciesPool = [SpeciesId.SOLROCK];
} else if (index === 1 && TrainerType[this.config.trainerTypeDouble] === TrainerType[TrainerType.LIZA]) {
newSpeciesPool = [SpeciesId.LUNATONE];
} else {
newSpeciesPool = speciesPoolPartnerFiltered;
}
} else if (index === 1 && TrainerType[this.config.trainerTypeDouble] === TrainerType[TrainerType.TATE]) {
newSpeciesPool = [SpeciesId.SOLROCK];
} else if (index === 1 && TrainerType[this.config.trainerTypeDouble] === TrainerType[TrainerType.LIZA]) {
newSpeciesPool = [SpeciesId.LUNATONE];
} else {
newSpeciesPool = speciesPoolPartnerFiltered;
}
// Fallback for when the species pool is empty
if (newSpeciesPool.length === 0) {
@ -794,10 +792,12 @@ export class Trainer extends Phaser.GameObjects.Container {
* @returns boolean Whether the EnemyPokemon should Terastalize this turn
*/
shouldTera(pokemon: EnemyPokemon): boolean {
if (this.config.trainerAI.teraMode === TeraAIMode.INSTANT_TERA) {
if (!pokemon.isTerastallized && this.config.trainerAI.instantTeras.includes(pokemon.initialTeamIndex)) {
return true;
}
if (
this.config.trainerAI.teraMode === TeraAIMode.INSTANT_TERA &&
!pokemon.isTerastallized &&
this.config.trainerAI.instantTeras.includes(pokemon.initialTeamIndex)
) {
return true;
}
return false;
}

View File

@ -1634,9 +1634,9 @@ export class FormChangeItemModifierTypeGenerator extends ModifierTypeGenerator {
if (p.species.speciesId === SpeciesId.NECROZMA) {
// technically we could use a simplified version and check for formChanges.length > 3, but in case any code changes later, this might break...
let foundULTRA_Z = false,
foundN_LUNA = false,
foundN_SOLAR = false;
let foundULTRA_Z = false;
let foundN_LUNA = false;
let foundN_SOLAR = false;
formChangeItemTriggers.forEach((fc, _i) => {
console.log("Checking ", fc.item);
switch (fc.item) {

View File

@ -102,10 +102,13 @@ import { WeatherEffectPhase } from "#phases/weather-effect-phase";
import type { PhaseMap, PhaseString } from "#types/phase-types";
import { type Constructor, coerceArray } from "#utils/common";
/*
/**
* @module
* Manager for phases used by battle scene.
*
* *This file must not be imported or used directly. The manager is exclusively used by the battle scene and is not intended for external use.*
* @remarks
* **This file must not be imported or used directly.**
* The manager is exclusively used by the Battle Scene and is NOT intended for external use.
*/
/**

View File

@ -604,9 +604,8 @@ export class CommandPhase extends FieldPhase {
* @returns Whether the command was successful
*/
handleCommand(command: Command.FIGHT | Command.TERA, cursor: number, useMode?: MoveUseMode, move?: TurnMove): boolean;
handleCommand(command: Command.BALL, cursor: number): boolean;
handleCommand(command: Command.POKEMON, cursor: number, useBaton: boolean): boolean;
handleCommand(command: Command.RUN, cursor: number): boolean;
handleCommand(command: Command.BALL | Command.RUN, cursor: number): boolean;
handleCommand(command: Command, cursor: number, useMode?: boolean | MoveUseMode, move?: TurnMove): boolean;
public handleCommand(

View File

@ -10,19 +10,12 @@ export class CommonAnimPhase extends PokemonPhase {
public readonly phaseName: "CommonAnimPhase" | "PokemonHealPhase" | "WeatherEffectPhase" = "CommonAnimPhase";
private anim: CommonAnim | null;
private targetIndex?: BattlerIndex;
private playOnEmptyField: boolean;
constructor(
battlerIndex?: BattlerIndex,
targetIndex?: BattlerIndex,
anim: CommonAnim | null = null,
playOnEmptyField = false,
) {
constructor(battlerIndex?: BattlerIndex, targetIndex?: BattlerIndex, anim: CommonAnim | null = null) {
super(battlerIndex);
this.anim = anim;
this.targetIndex = targetIndex;
this.playOnEmptyField = playOnEmptyField;
}
setAnimation(anim: CommonAnim) {

View File

@ -559,10 +559,11 @@ export class MoveEffectPhase extends PokemonPhase {
// Strikes after the first in a multi-strike move are guaranteed to hit,
// unless the move is flagged to check all hits and the user does not have Skill Link.
if (user.turnData.hitsLeft < user.turnData.hitCount) {
if (!move.hasFlag(MoveFlags.CHECK_ALL_HITS) || user.hasAbilityWithAttr("MaxMultiHitAbAttr")) {
return [HitCheckResult.HIT, effectiveness];
}
if (
user.turnData.hitsLeft < user.turnData.hitCount &&
(!move.hasFlag(MoveFlags.CHECK_ALL_HITS) || user.hasAbilityWithAttr("MaxMultiHitAbAttr"))
) {
return [HitCheckResult.HIT, effectiveness];
}
const bypassAccuracy =

View File

@ -23,25 +23,24 @@ export class ScanIvsPhase extends PokemonPhase {
let enemyIvs: number[] = [];
let statsContainer: Phaser.GameObjects.Sprite[] = [];
let statsContainerLabels: Phaser.GameObjects.Sprite[] = [];
const enemyField = globalScene.getEnemyField();
const uiTheme = globalScene.uiTheme; // Assuming uiTheme is accessible
for (let e = 0; e < enemyField.length; e++) {
enemyIvs = enemyField[e].ivs;
for (const enemy of globalScene.getEnemyField()) {
enemyIvs = enemy.ivs;
// we are using getRootSpeciesId() here because we want to check against the baby form, not the mid form if it exists
const currentIvs = globalScene.gameData.dexData[enemyField[e].species.getRootSpeciesId()].ivs;
statsContainer = enemyField[e].getBattleInfo().getStatsValueContainer().list as Phaser.GameObjects.Sprite[];
const currentIvs = globalScene.gameData.dexData[enemy.species.getRootSpeciesId()].ivs;
statsContainer = enemy.getBattleInfo().getStatsValueContainer().list as Phaser.GameObjects.Sprite[];
statsContainerLabels = statsContainer.filter(m => m.name.indexOf("icon_stat_label") >= 0);
for (let s = 0; s < statsContainerLabels.length; s++) {
const ivStat = Stat[statsContainerLabels[s].frame.name];
for (const statContainer of statsContainerLabels) {
const ivStat = Stat[statContainer.frame.name];
if (enemyIvs[ivStat] > currentIvs[ivStat] && PERMANENT_STATS.indexOf(Number(ivStat)) >= 0) {
const hexColour =
enemyIvs[ivStat] === 31
? getTextColor(TextStyle.PERFECT_IV, false, uiTheme)
: getTextColor(TextStyle.SUMMARY_GREEN, false, uiTheme);
const hexTextColour = Phaser.Display.Color.HexStringToColor(hexColour).color;
statsContainerLabels[s].setTint(hexTextColour);
statContainer.setTint(hexTextColour);
}
statsContainerLabels[s].setVisible(true);
statContainer.setVisible(true);
}
}

View File

@ -22,6 +22,7 @@ export type StatStageChangeCallback = (
relativeChanges: number[],
) => void;
// TODO: Refactor this mess of a phase
export class StatStageChangePhase extends PokemonPhase {
public readonly phaseName = "StatStageChangePhase";
private stats: BattleStat[];
@ -62,13 +63,12 @@ export class StatStageChangePhase extends PokemonPhase {
start() {
// Check if multiple stats are being changed at the same time, then run SSCPhase for each of them
if (this.stats.length > 1) {
for (let i = 0; i < this.stats.length; i++) {
const stat = [this.stats[i]];
for (const stat of this.stats) {
globalScene.phaseManager.unshiftNew(
"StatStageChangePhase",
this.battlerIndex,
this.selfTarget,
stat,
[stat],
this.stages,
this.showMessage,
this.ignoreAbilities,
@ -100,20 +100,18 @@ export class StatStageChangePhase extends PokemonPhase {
}
});
}
} else if (!this.comingFromStickyWeb) {
opponentPokemon = globalScene.getPlayerField()[globalScene.currentBattle.lastPlayerInvolved];
} else {
if (!this.comingFromStickyWeb) {
opponentPokemon = globalScene.getPlayerField()[globalScene.currentBattle.lastPlayerInvolved];
} else {
const stickyTagID = globalScene.arena.findTagsOnSide(
(t: ArenaTag) => t.tagType === ArenaTagType.STICKY_WEB,
ArenaTagSide.ENEMY,
)[0].sourceId;
globalScene.getPlayerField().forEach(e => {
if (e.id === stickyTagID) {
opponentPokemon = e;
}
});
}
const stickyTagID = globalScene.arena.findTagsOnSide(
(t: ArenaTag) => t.tagType === ArenaTagType.STICKY_WEB,
ArenaTagSide.ENEMY,
)[0].sourceId;
globalScene.getPlayerField().forEach(e => {
if (e.id === stickyTagID) {
opponentPokemon = e;
}
});
}
if (!pokemon.isActive(true)) {

View File

@ -27,29 +27,28 @@ export class TrainerVictoryPhase extends BattlePhase {
const trainerType = globalScene.currentBattle.trainer?.config.trainerType!; // TODO: is this bang correct?
// Validate Voucher for boss trainers
if (vouchers.hasOwnProperty(TrainerType[trainerType])) {
if (
!globalScene.validateVoucher(vouchers[TrainerType[trainerType]]) &&
globalScene.currentBattle.trainer?.config.isBoss
) {
if (timedEventManager.getUpgradeUnlockedVouchers()) {
globalScene.phaseManager.unshiftNew(
"ModifierRewardPhase",
[
modifierTypes.VOUCHER_PLUS,
modifierTypes.VOUCHER_PLUS,
modifierTypes.VOUCHER_PLUS,
modifierTypes.VOUCHER_PREMIUM,
][vouchers[TrainerType[trainerType]].voucherType],
);
} else {
globalScene.phaseManager.unshiftNew(
"ModifierRewardPhase",
[modifierTypes.VOUCHER, modifierTypes.VOUCHER, modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PREMIUM][
vouchers[TrainerType[trainerType]].voucherType
],
);
}
if (
vouchers.hasOwnProperty(TrainerType[trainerType]) &&
!globalScene.validateVoucher(vouchers[TrainerType[trainerType]]) &&
globalScene.currentBattle.trainer?.config.isBoss
) {
if (timedEventManager.getUpgradeUnlockedVouchers()) {
globalScene.phaseManager.unshiftNew(
"ModifierRewardPhase",
[
modifierTypes.VOUCHER_PLUS,
modifierTypes.VOUCHER_PLUS,
modifierTypes.VOUCHER_PLUS,
modifierTypes.VOUCHER_PREMIUM,
][vouchers[TrainerType[trainerType]].voucherType],
);
} else {
globalScene.phaseManager.unshiftNew(
"ModifierRewardPhase",
[modifierTypes.VOUCHER, modifierTypes.VOUCHER, modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PREMIUM][
vouchers[TrainerType[trainerType]].voucherType
],
);
}
}
// Breeders in Space achievement

View File

@ -16,8 +16,8 @@ export class PokerogueSessionSavedataApi extends ApiBase {
//#region Public
/**
* Mark a session as cleared aka "newclear".\
* *This is **NOT** the same as {@linkcode clear | clear()}.*
* Mark a session as cleared aka "newclear". \
* _This is **NOT** the same as {@linkcode clear | clear()}._
* @param params The {@linkcode NewClearSessionSavedataRequest} to send
* @returns The raw savedata as `string`.
* @throws Error if the request fails
@ -94,8 +94,8 @@ export class PokerogueSessionSavedataApi extends ApiBase {
}
/**
* Clears the session savedata of the given slot.\
* *This is **NOT** the same as {@linkcode newclear | newclear()}.*
* Clears the session savedata of the given slot. \
* _This is **NOT** the same as {@linkcode newclear | newclear()}._
* @param params The {@linkcode ClearSessionSavedataRequest} to send
* @param sessionData The {@linkcode SessionSaveData} object
*/

View File

@ -121,8 +121,8 @@ async function initFonts(language: string | undefined) {
}
/**
* I18n money formatter with. (useful for BBCode coloring of text)\
* *If you don't want the BBCode tag applied, just use 'number' formatter*
* I18n money formatter with. (useful for BBCode coloring of text) \
* _If you don't want the BBCode tag applied, just use 'number' formatter_
* @example Input: `{{myMoneyValue, money}}`
* Output: `@[MONEY]{₽100,000,000}`
* @param amount the money amount

View File

@ -1595,7 +1595,7 @@ export class GameData {
globalScene.executeWithSeedOffset(
() => {
const neutralNatures = [Nature.HARDY, Nature.DOCILE, Nature.SERIOUS, Nature.BASHFUL, Nature.QUIRKY];
for (let s = 0; s < defaultStarterSpecies.length; s++) {
for (const _ of defaultStarterSpecies) {
defaultStarterNatures.push(randSeedItem(neutralNatures));
}
},

View File

@ -104,18 +104,16 @@ export function setSettingGamepad(setting: SettingGamepad, value: number): boole
case SettingGamepad.Button_Speed_Up:
case SettingGamepad.Button_Slow_Down:
case SettingGamepad.Button_Submit:
if (value) {
if (globalScene.ui) {
const cancelHandler = (success = false): boolean => {
globalScene.ui.revertMode();
(globalScene.ui.getHandler() as SettingsGamepadUiHandler).updateBindings();
return success;
};
globalScene.ui.setOverlayMode(UiMode.GAMEPAD_BINDING, {
target: setting,
cancelHandler: cancelHandler,
});
}
if (value && globalScene.ui) {
const cancelHandler = (success = false): boolean => {
globalScene.ui.revertMode();
(globalScene.ui.getHandler() as SettingsGamepadUiHandler).updateBindings();
return success;
};
globalScene.ui.setOverlayMode(UiMode.GAMEPAD_BINDING, {
target: setting,
cancelHandler: cancelHandler,
});
}
break;
case SettingGamepad.Controller:

View File

@ -167,18 +167,16 @@ export function setSettingKeyboard(setting: SettingKeyboard, value: number): boo
case SettingKeyboard.Alt_Button_Speed_Up:
case SettingKeyboard.Alt_Button_Slow_Down:
case SettingKeyboard.Alt_Button_Submit:
if (value) {
if (globalScene.ui) {
const cancelHandler = (success = false): boolean => {
globalScene.ui.revertMode();
(globalScene.ui.getHandler() as SettingsKeyboardUiHandler).updateBindings();
return success;
};
globalScene.ui.setOverlayMode(UiMode.KEYBOARD_BINDING, {
target: setting,
cancelHandler: cancelHandler,
});
}
if (value && globalScene.ui) {
const cancelHandler = (success = false): boolean => {
globalScene.ui.revertMode();
(globalScene.ui.getHandler() as SettingsKeyboardUiHandler).updateBindings();
return success;
};
globalScene.ui.setOverlayMode(UiMode.KEYBOARD_BINDING, {
target: setting,
cancelHandler: cancelHandler,
});
}
break;
}

View File

@ -896,104 +896,102 @@ export function setSetting(setting: string, value: number): boolean {
globalScene.typeHints = Setting[index].options[value].value === "On";
break;
case SettingKeys.Language:
if (value) {
if (globalScene.ui) {
const cancelHandler = () => {
globalScene.ui.revertMode();
(globalScene.ui.getHandler() as SettingsUiHandler).setOptionCursor(-1, 0, true);
};
const changeLocaleHandler = (locale: string): boolean => {
try {
i18next.changeLanguage(locale);
localStorage.setItem("prLang", locale);
cancelHandler();
// Reload the whole game to apply the new locale since also some constants are translated
window.location.reload();
return true;
} catch (error) {
console.error("Error changing locale:", error);
return false;
}
};
globalScene.ui.setOverlayMode(UiMode.OPTION_SELECT, {
options: [
{
label: "English",
handler: () => changeLocaleHandler("en"),
},
{
label: "Español (ES)",
handler: () => changeLocaleHandler("es-ES"),
},
{
label: "Español (LATAM)",
handler: () => changeLocaleHandler("es-MX"),
},
{
label: "Français",
handler: () => changeLocaleHandler("fr"),
},
{
label: "Deutsch",
handler: () => changeLocaleHandler("de"),
},
{
label: "Italiano",
handler: () => changeLocaleHandler("it"),
},
{
label: "Português (BR)",
handler: () => changeLocaleHandler("pt-BR"),
},
{
label: "한국어",
handler: () => changeLocaleHandler("ko"),
},
{
label: "日本語",
handler: () => changeLocaleHandler("ja"),
},
{
label: "简体中文",
handler: () => changeLocaleHandler("zh-CN"),
},
{
label: "繁體中文",
handler: () => changeLocaleHandler("zh-TW"),
},
{
label: "Català (Needs Help)",
handler: () => changeLocaleHandler("ca"),
},
{
label: "Türkçe (Needs Help)",
handler: () => changeLocaleHandler("tr"),
},
{
label: "Русский (Needs Help)",
handler: () => changeLocaleHandler("ru"),
},
{
label: "Dansk (Needs Help)",
handler: () => changeLocaleHandler("da"),
},
{
label: "Română (Needs Help)",
handler: () => changeLocaleHandler("ro"),
},
{
label: "Tagalog (Needs Help)",
handler: () => changeLocaleHandler("tl"),
},
{
label: i18next.t("settings:back"),
handler: () => cancelHandler(),
},
],
maxOptions: 7,
});
return false;
}
if (value && globalScene.ui) {
const cancelHandler = () => {
globalScene.ui.revertMode();
(globalScene.ui.getHandler() as SettingsUiHandler).setOptionCursor(-1, 0, true);
};
const changeLocaleHandler = (locale: string): boolean => {
try {
i18next.changeLanguage(locale);
localStorage.setItem("prLang", locale);
cancelHandler();
// Reload the whole game to apply the new locale since also some constants are translated
window.location.reload();
return true;
} catch (error) {
console.error("Error changing locale:", error);
return false;
}
};
globalScene.ui.setOverlayMode(UiMode.OPTION_SELECT, {
options: [
{
label: "English",
handler: () => changeLocaleHandler("en"),
},
{
label: "Español (ES)",
handler: () => changeLocaleHandler("es-ES"),
},
{
label: "Español (LATAM)",
handler: () => changeLocaleHandler("es-MX"),
},
{
label: "Français",
handler: () => changeLocaleHandler("fr"),
},
{
label: "Deutsch",
handler: () => changeLocaleHandler("de"),
},
{
label: "Italiano",
handler: () => changeLocaleHandler("it"),
},
{
label: "Português (BR)",
handler: () => changeLocaleHandler("pt-BR"),
},
{
label: "한국어",
handler: () => changeLocaleHandler("ko"),
},
{
label: "日本語",
handler: () => changeLocaleHandler("ja"),
},
{
label: "简体中文",
handler: () => changeLocaleHandler("zh-CN"),
},
{
label: "繁體中文",
handler: () => changeLocaleHandler("zh-TW"),
},
{
label: "Català (Needs Help)",
handler: () => changeLocaleHandler("ca"),
},
{
label: "Türkçe (Needs Help)",
handler: () => changeLocaleHandler("tr"),
},
{
label: "Русский (Needs Help)",
handler: () => changeLocaleHandler("ru"),
},
{
label: "Dansk (Needs Help)",
handler: () => changeLocaleHandler("da"),
},
{
label: "Română (Needs Help)",
handler: () => changeLocaleHandler("ro"),
},
{
label: "Tagalog (Needs Help)",
handler: () => changeLocaleHandler("tl"),
},
{
label: i18next.t("settings:back"),
handler: () => cancelHandler(),
},
],
maxOptions: 7,
});
return false;
}
break;
case SettingKeys.Shop_Overlay_Opacity:

View File

@ -17,8 +17,6 @@ export class AdminUiHandler extends FormModalUiHandler {
private config: ModalConfig;
private readonly buttonGap = 10;
// http response from the server when a username isn't found in the server
private readonly httpUserNotFoundErrorCode: number = 404;
private readonly ERR_REQUIRED_FIELD = (field: string) => {
if (field === "username") {
return `${toTitleCase(field)} is required`;

View File

@ -241,9 +241,7 @@ export class ArenaFlyout extends Phaser.GameObjects.Container {
this.fieldEffectInfo.sort((infoA, infoB) => infoA.duration - infoB.duration);
for (let i = 0; i < this.fieldEffectInfo.length; i++) {
const fieldEffectInfo = this.fieldEffectInfo[i];
for (const fieldEffectInfo of this.fieldEffectInfo) {
// Creates a proxy object to decide which text object needs to be updated
let textObject: Phaser.GameObjects.Text;
switch (fieldEffectInfo.effectType) {
@ -389,9 +387,7 @@ export class ArenaFlyout extends Phaser.GameObjects.Container {
const fieldEffectInfo: ArenaEffectInfo[] = [];
this.fieldEffectInfo.forEach(i => fieldEffectInfo.push(i));
for (let i = 0; i < fieldEffectInfo.length; i++) {
const info = fieldEffectInfo[i];
for (const info of fieldEffectInfo) {
if (info.maxDuration === 0) {
continue;
}

View File

@ -68,14 +68,14 @@ export class BaseStatsOverlay extends Phaser.GameObjects.Container implements In
// show this component with infos for the specific move
show(values: number[], total: number): boolean {
for (let i = 0; i < 6; i++) {
this.statsLabels[i].setText(i18next.t(`pokemonInfo:Stat.${shortStats[i]}shortened`) + ": " + `${values[i]}`);
this.statsLabels[i].setText(`${i18next.t(`pokemonInfo:Stat.${shortStats[i]}shortened`)}: ${values[i]}`);
// This accounts for base stats up to 200, might not be enough.
// TODO: change color based on value.
this.statsShadows[i].setSize(values[i] / 2, 5);
this.statsRectangles[i].setSize(values[i] / 2, 5);
}
this.statsTotalLabel.setText(i18next.t("pokedexUiHandler:baseTotal") + ": " + `${total}`);
this.statsTotalLabel.setText(`${i18next.t("pokedexUiHandler:baseTotal")}: ${total}`);
this.setVisible(true);
this.active = true;

View File

@ -153,16 +153,12 @@ export class BattleMessageUiHandler extends MessageUiHandler {
processInput(button: Button): boolean {
const ui = this.getUi();
if (this.awaitingActionInput) {
if (button === Button.CANCEL || button === Button.ACTION) {
if (this.onActionInput) {
ui.playSelect();
const originalOnActionInput = this.onActionInput;
this.onActionInput = null;
originalOnActionInput();
return true;
}
}
if (this.awaitingActionInput && (button === Button.CANCEL || button === Button.ACTION) && this.onActionInput) {
ui.playSelect();
const originalOnActionInput = this.onActionInput;
this.onActionInput = null;
originalOnActionInput();
return true;
}
return false;

View File

@ -400,75 +400,73 @@ export class GameChallengesUiHandler extends UiHandler {
} else {
success = false;
}
} else {
if (this.cursorObj?.visible && !this.startCursor.visible) {
switch (button) {
case Button.UP:
if (this.cursor === 0) {
if (this.scrollCursor === 0) {
// When at the top of the menu and pressing UP, move to the bottommost item.
if (globalScene.gameMode.challenges.length > rowsToDisplay) {
// If there are more than 9 challenges, scroll to the bottom
// First, set the cursor to the last visible element, preparing for the scroll to the end.
const successA = this.setCursor(rowsToDisplay - 1);
// Then, adjust the scroll to display the bottommost elements of the menu.
const successB = this.setScrollCursor(globalScene.gameMode.challenges.length - rowsToDisplay);
success = successA && successB; // success is just there to play the little validation sound effect
} else {
// If there are 9 or less challenges, just move to the bottom one
success = this.setCursor(globalScene.gameMode.challenges.length - 1);
}
} else {
success = this.setScrollCursor(this.scrollCursor - 1);
}
} else {
success = this.setCursor(this.cursor - 1);
}
if (success) {
this.updateText();
}
break;
case Button.DOWN:
if (this.cursor === rowsToDisplay - 1) {
if (this.scrollCursor < globalScene.gameMode.challenges.length - rowsToDisplay) {
// When at the bottom and pressing DOWN, scroll if possible.
success = this.setScrollCursor(this.scrollCursor + 1);
} else {
// When at the bottom of a scrolling menu and pressing DOWN, move to the topmost item.
// First, set the cursor to the first visible element, preparing for the scroll to the top.
const successA = this.setCursor(0);
// Then, adjust the scroll to display the topmost elements of the menu.
const successB = this.setScrollCursor(0);
} else if (this.cursorObj?.visible && !this.startCursor.visible) {
switch (button) {
case Button.UP:
if (this.cursor === 0) {
if (this.scrollCursor === 0) {
// When at the top of the menu and pressing UP, move to the bottommost item.
if (globalScene.gameMode.challenges.length > rowsToDisplay) {
// If there are more than 9 challenges, scroll to the bottom
// First, set the cursor to the last visible element, preparing for the scroll to the end.
const successA = this.setCursor(rowsToDisplay - 1);
// Then, adjust the scroll to display the bottommost elements of the menu.
const successB = this.setScrollCursor(globalScene.gameMode.challenges.length - rowsToDisplay);
success = successA && successB; // success is just there to play the little validation sound effect
} else {
// If there are 9 or less challenges, just move to the bottom one
success = this.setCursor(globalScene.gameMode.challenges.length - 1);
}
} else if (
globalScene.gameMode.challenges.length < rowsToDisplay &&
this.cursor === globalScene.gameMode.challenges.length - 1
) {
// When at the bottom of a non-scrolling menu and pressing DOWN, move to the topmost item.
success = this.setCursor(0);
} else {
success = this.setCursor(this.cursor + 1);
success = this.setScrollCursor(this.scrollCursor - 1);
}
if (success) {
this.updateText();
} else {
success = this.setCursor(this.cursor - 1);
}
if (success) {
this.updateText();
}
break;
case Button.DOWN:
if (this.cursor === rowsToDisplay - 1) {
if (this.scrollCursor < globalScene.gameMode.challenges.length - rowsToDisplay) {
// When at the bottom and pressing DOWN, scroll if possible.
success = this.setScrollCursor(this.scrollCursor + 1);
} else {
// When at the bottom of a scrolling menu and pressing DOWN, move to the topmost item.
// First, set the cursor to the first visible element, preparing for the scroll to the top.
const successA = this.setCursor(0);
// Then, adjust the scroll to display the topmost elements of the menu.
const successB = this.setScrollCursor(0);
success = successA && successB; // success is just there to play the little validation sound effect
}
break;
case Button.LEFT:
// Moves the option cursor left, if possible.
success = this.getActiveChallenge().decreaseValue();
if (success) {
this.updateText();
}
break;
case Button.RIGHT:
// Moves the option cursor right, if possible.
success = this.getActiveChallenge().increaseValue();
if (success) {
this.updateText();
}
break;
}
} else if (
globalScene.gameMode.challenges.length < rowsToDisplay &&
this.cursor === globalScene.gameMode.challenges.length - 1
) {
// When at the bottom of a non-scrolling menu and pressing DOWN, move to the topmost item.
success = this.setCursor(0);
} else {
success = this.setCursor(this.cursor + 1);
}
if (success) {
this.updateText();
}
break;
case Button.LEFT:
// Moves the option cursor left, if possible.
success = this.getActiveChallenge().decreaseValue();
if (success) {
this.updateText();
}
break;
case Button.RIGHT:
// Moves the option cursor right, if possible.
success = this.getActiveChallenge().increaseValue();
if (success) {
this.updateText();
}
break;
}
}

View File

@ -504,13 +504,11 @@ export class DropDown extends Phaser.GameObjects.Container {
if (index === 0) {
// we are on the All option > put all other options to the newState
this.setAllOptions(newState);
} else {
} else if (newState === DropDownState.ON && this.checkForAllOn()) {
// select the "all" option if all others are selected, other unselect it
if (newState === DropDownState.ON && this.checkForAllOn()) {
this.options[0].setOptionState(DropDownState.ON);
} else {
this.options[0].setOptionState(DropDownState.OFF);
}
this.options[0].setOptionState(DropDownState.ON);
} else {
this.options[0].setOptionState(DropDownState.OFF);
}
} else if (this.dropDownType === DropDownType.SINGLE) {
if (option.state === DropDownState.OFF) {
@ -653,10 +651,8 @@ export class DropDown extends Phaser.GameObjects.Container {
this.options[i].setDirection(SortDirection.ASC);
this.options[i].toggle.setVisible(true);
}
} else {
if (this.defaultSettings[i]) {
this.options[i].setOptionState(this.defaultSettings[i]["state"]);
}
} else if (this.defaultSettings[i]) {
this.options[i].setOptionState(this.defaultSettings[i]["state"]);
}
}
@ -699,11 +695,11 @@ export class DropDown extends Phaser.GameObjects.Container {
autoSize(): void {
let maxWidth = 0;
let x = 0;
for (let i = 0; i < this.options.length; i++) {
const optionWidth = this.options[i].getWidth();
for (const option of this.options) {
const optionWidth = option.getWidth();
if (optionWidth > maxWidth) {
maxWidth = optionWidth;
x = this.options[i].getCurrentLabelX() ?? 0;
x = option.getCurrentLabelX() ?? 0;
}
}
this.window.width = maxWidth + x - this.window.x + 9;

View File

@ -62,16 +62,12 @@ export class EvolutionSceneHandler extends MessageUiHandler {
}
const ui = this.getUi();
if (this.awaitingActionInput) {
if (button === Button.CANCEL || button === Button.ACTION) {
if (this.onActionInput) {
ui.playSelect();
const originalOnActionInput = this.onActionInput;
this.onActionInput = null;
originalOnActionInput();
return true;
}
}
if (this.awaitingActionInput && (button === Button.CANCEL || button === Button.ACTION) && this.onActionInput) {
ui.playSelect();
const originalOnActionInput = this.onActionInput;
this.onActionInput = null;
originalOnActionInput();
return true;
}
return false;

View File

@ -130,22 +130,20 @@ export class FilterBar extends Phaser.GameObjects.Container {
* Move the leftmost dropdown to the left of the FilterBar instead of below it
*/
offsetHybridFilters(): void {
for (let i = 0; i < this.dropDowns.length; i++) {
if (this.dropDowns[i].dropDownType === DropDownType.HYBRID) {
this.dropDowns[i].autoSize();
this.dropDowns[i].x = -this.dropDowns[i].getWidth();
this.dropDowns[i].y = 0;
for (const dropDown of this.dropDowns) {
if (dropDown.dropDownType === DropDownType.HYBRID) {
dropDown.autoSize();
dropDown.x = -dropDown.getWidth();
dropDown.y = 0;
}
}
}
setCursor(cursor: number): void {
if (this.lastCursor > -1) {
if (this.dropDowns[this.lastCursor].visible) {
this.dropDowns[this.lastCursor].setVisible(false);
this.dropDowns[cursor].setVisible(true);
this.dropDowns[cursor].resetCursor();
}
if (this.lastCursor > -1 && this.dropDowns[this.lastCursor].visible) {
this.dropDowns[this.lastCursor].setVisible(false);
this.dropDowns[cursor].setVisible(true);
this.dropDowns[cursor].resetCursor();
}
this.cursorObj.setPosition(this.labels[cursor].x - this.cursorOffset + 2, 6);

View File

@ -24,14 +24,12 @@ export class FilterText extends Phaser.GameObjects.Container {
private rows: FilterTextRow[] = [];
public cursorObj: Phaser.GameObjects.Image;
public numFilters = 0;
private lastCursor = -1;
private uiTheme: UiTheme;
private menuMessageBoxContainer: Phaser.GameObjects.Container;
private dialogueMessageBox: Phaser.GameObjects.NineSlice;
message: any;
private readonly textPadding = 8;
private readonly defaultWordWrapWidth = 1224;
private onChange: () => void;
@ -158,7 +156,6 @@ export class FilterText extends Phaser.GameObjects.Container {
const cursorOffset = 8;
this.cursorObj.setPosition(cursorOffset, this.labels[cursor].y + 3);
this.lastCursor = cursor;
}
/**

View File

@ -234,9 +234,9 @@ export class LoginFormUiHandler extends FormModalUiHandler {
const dataKeys = localStorageKeys.filter(ls => ls.indexOf(keyToFind) >= 0);
if (dataKeys.length > 0 && dataKeys.length <= 2) {
const options: OptionSelectItem[] = [];
for (let i = 0; i < dataKeys.length; i++) {
for (const key of dataKeys) {
options.push({
label: dataKeys[i].replace(keyToFind, ""),
label: key.replace(keyToFind, ""),
handler: () => {
globalScene.ui.revertMode();
this.infoContainer.disableInteractive();
@ -261,7 +261,7 @@ export class LoginFormUiHandler extends FormModalUiHandler {
}
});
this.saveDownloadImage.on("pointerdown", () => {
this.saveDownloadImage.on("pointerdown", async () => {
// find all data_ and sessionData keys, put them in a .txt file and download everything in a single zip
const localStorageKeys = Object.keys(localStorage); // this gets the keys for localStorage
const keyToFind = "data_";
@ -270,20 +270,19 @@ export class LoginFormUiHandler extends FormModalUiHandler {
const sessionKeys = localStorageKeys.filter(ls => ls.indexOf(sessionKeyToFind) >= 0);
if (dataKeys.length > 0 || sessionKeys.length > 0) {
const zip = new JSZip();
for (let i = 0; i < dataKeys.length; i++) {
zip.file(dataKeys[i] + ".prsv", localStorage.getItem(dataKeys[i])!);
for (const dataKey of dataKeys) {
zip.file(dataKey + ".prsv", localStorage.getItem(dataKey)!);
}
for (let i = 0; i < sessionKeys.length; i++) {
zip.file(sessionKeys[i] + ".prsv", localStorage.getItem(sessionKeys[i])!);
for (const sessionKey of sessionKeys) {
zip.file(sessionKey + ".prsv", localStorage.getItem(sessionKey)!);
}
zip.generateAsync({ type: "blob" }).then(content => {
const url = URL.createObjectURL(content);
const a = document.createElement("a");
a.href = url;
a.download = "pokerogue_saves.zip";
a.click();
URL.revokeObjectURL(url);
});
const content = await zip.generateAsync({ type: "blob" });
const url = URL.createObjectURL(content);
const a = document.createElement("a");
a.href = url;
a.download = "pokerogue_saves.zip";
a.click();
URL.revokeObjectURL(url);
} else {
return onFail(this.ERR_NO_SAVES);
}

View File

@ -108,17 +108,17 @@ export abstract class MessageUiHandler extends AwaitableUiHandler {
const textWords = text.split(" ");
let lastLineCount = 1;
let newText = "";
for (let w = 0; w < textWords.length; w++) {
const nextWordText = newText ? `${newText} ${textWords[w]}` : textWords[w];
for (const textWord of textWords) {
const nextWordText = newText ? `${newText} ${textWord}` : textWord;
if (textWords[w].includes("\n")) {
if (textWord.includes("\n")) {
newText = nextWordText;
lastLineCount++;
} else {
const lineCount = this.message.runWordWrap(nextWordText).split(/\n/g).length;
if (lineCount > lastLineCount) {
lastLineCount = lineCount;
newText = `${newText}\n${textWords[w]}`;
newText = `${newText}\n${textWord}`;
} else {
newText = nextWordText;
}

View File

@ -480,12 +480,10 @@ export class ModifierSelectUiHandler extends AwaitableUiHandler {
}
} else if (this.cursor) {
success = this.setCursor(this.cursor - 1);
} else if (this.rowCursor === 1 && this.options.length === 0) {
success = false;
} else {
if (this.rowCursor === 1 && this.options.length === 0) {
success = false;
} else {
success = this.setCursor(this.getRowItems(this.rowCursor) - 1);
}
success = this.setCursor(this.getRowItems(this.rowCursor) - 1);
}
break;
case Button.RIGHT:
@ -514,12 +512,10 @@ export class ModifierSelectUiHandler extends AwaitableUiHandler {
}
} else if (this.cursor < this.getRowItems(this.rowCursor) - 1) {
success = this.setCursor(this.cursor + 1);
} else if (this.rowCursor === 1 && this.options.length === 0) {
success = this.setRowCursor(0);
} else {
if (this.rowCursor === 1 && this.options.length === 0) {
success = this.setRowCursor(0);
} else {
success = this.setCursor(0);
}
success = this.setCursor(0);
}
break;
}

View File

@ -41,8 +41,6 @@ const GLOBAL_SCALE = 6;
export class MoveInfoOverlay extends Phaser.GameObjects.Container implements InfoToggle {
public active = false;
private move: Move;
private desc: Phaser.GameObjects.Text;
private descScroll: Phaser.Tweens.Tween | null = null;
@ -177,7 +175,6 @@ export class MoveInfoOverlay extends Phaser.GameObjects.Container implements Inf
if (!globalScene.enableMoveInfo) {
return false; // move infos have been disabled // TODO:: is `false` correct? i used to be `undeefined`
}
this.move = move;
this.pow.setText(move.power >= 0 ? move.power.toString() : "---");
this.acc.setText(move.accuracy >= 0 ? move.accuracy.toString() : "---");
this.pp.setText(move.pp >= 0 ? move.pp.toString() : "---");

View File

@ -156,14 +156,12 @@ export class MysteryEncounterUiHandler extends UiHandler {
selected.optionMode === MysteryEncounterOptionMode.DISABLED_OR_SPECIAL))
) {
success = false;
} else if (
(globalScene.phaseManager.getCurrentPhase() as MysteryEncounterPhase).handleOptionSelect(selected, cursor)
) {
success = true;
} else {
if (
(globalScene.phaseManager.getCurrentPhase() as MysteryEncounterPhase).handleOptionSelect(selected, cursor)
) {
success = true;
} else {
ui.playError();
}
ui.playError();
}
} else {
// TODO: If we need to handle cancel option? Maybe default logic to leave/run from encounter idk

View File

@ -614,34 +614,32 @@ export class PartyUiHandler extends MessageUiHandler {
// TODO: Might need to check here for when this.transferMode is active.
private processModifierTransferModeLeftRightInput(button: Button) {
if (!this.isItemManageMode()) {
return false;
}
let success = false;
const option = this.options[this.optionsCursor];
if (button === Button.LEFT) {
/** Decrease quantity for the current item and update UI */
if (this.isItemManageMode()) {
this.transferQuantities[option] =
this.transferQuantities[option] === 1
? this.transferQuantitiesMax[option]
: this.transferQuantities[option] - 1;
this.updateOptions();
success = this.setCursor(
this.optionsCursor,
); /** Place again the cursor at the same position. Necessary, otherwise the cursor disappears */
}
this.transferQuantities[option] =
this.transferQuantities[option] === 1
? this.transferQuantitiesMax[option]
: this.transferQuantities[option] - 1;
this.updateOptions();
success = this.setCursor(
this.optionsCursor,
); /** Place again the cursor at the same position. Necessary, otherwise the cursor disappears */
}
if (button === Button.RIGHT) {
/** Increase quantity for the current item and update UI */
if (this.isItemManageMode()) {
this.transferQuantities[option] =
this.transferQuantities[option] === this.transferQuantitiesMax[option]
? 1
: this.transferQuantities[option] + 1;
this.updateOptions();
success = this.setCursor(
this.optionsCursor,
); /** Place again the cursor at the same position. Necessary, otherwise the cursor disappears */
}
this.transferQuantities[option] =
this.transferQuantities[option] === this.transferQuantitiesMax[option]
? 1
: this.transferQuantities[option] + 1;
this.updateOptions();
success = this.setCursor(
this.optionsCursor,
); /** Place again the cursor at the same position. Necessary, otherwise the cursor disappears */
}
return success;
}
@ -930,10 +928,8 @@ export class PartyUiHandler extends MessageUiHandler {
return this.moveOptionCursor(button);
}
if (button === Button.LEFT || button === Button.RIGHT) {
if (this.isItemManageMode()) {
return this.processModifierTransferModeLeftRightInput(button);
}
if ((button === Button.LEFT || button === Button.RIGHT) && this.isItemManageMode()) {
return this.processModifierTransferModeLeftRightInput(button);
}
return false;
@ -1215,11 +1211,9 @@ export class PartyUiHandler extends MessageUiHandler {
isScroll = true;
this.optionsScrollCursor++;
}
} else {
if (!cursor && this.optionsScrollCursor) {
isScroll = true;
this.optionsScrollCursor--;
}
} else if (!cursor && this.optionsScrollCursor) {
isScroll = true;
this.optionsScrollCursor--;
}
if (isScroll && this.optionsScrollCursor === 1) {
this.optionsScrollCursor += isDown ? 1 : -1;
@ -1573,12 +1567,10 @@ export class PartyUiHandler extends MessageUiHandler {
optionName = `${modifier.active ? i18next.t("partyUiHandler:DEACTIVATE") : i18next.t("partyUiHandler:ACTIVATE")} ${modifier.type.name}`;
} else if (option === PartyOption.UNPAUSE_EVOLUTION) {
optionName = `${pokemon.pauseEvolutions ? i18next.t("partyUiHandler:UNPAUSE_EVOLUTION") : i18next.t("partyUiHandler:PAUSE_EVOLUTION")}`;
} else if (this.localizedOptions.includes(option)) {
optionName = i18next.t(`partyUiHandler:${PartyOption[option]}`);
} else {
if (this.localizedOptions.includes(option)) {
optionName = i18next.t(`partyUiHandler:${PartyOption[option]}`);
} else {
optionName = toTitleCase(PartyOption[option]);
}
optionName = toTitleCase(PartyOption[option]);
}
break;
}
@ -1654,11 +1646,11 @@ export class PartyUiHandler extends MessageUiHandler {
this.transferMode = false;
this.transferAll = false;
this.partySlots[this.transferCursor].setTransfer(false);
for (let i = 0; i < this.partySlots.length; i++) {
this.partySlots[i].slotDescriptionLabel.setVisible(false);
this.partySlots[i].slotHpBar.setVisible(true);
this.partySlots[i].slotHpOverlay.setVisible(true);
this.partySlots[i].slotHpText.setVisible(true);
for (const partySlot of this.partySlots) {
partySlot.slotDescriptionLabel.setVisible(false);
partySlot.slotHpBar.setVisible(true);
partySlot.slotHpOverlay.setVisible(true);
partySlot.slotHpText.setVisible(true);
}
}

View File

@ -259,8 +259,6 @@ export class PokedexPageUiHandler extends MessageUiHandler {
private instructionRowX = 0;
private instructionRowY = 0;
private instructionRowTextOffset = 9;
private filterInstructionRowX = 0;
private filterInstructionRowY = 0;
private starterAttributes: StarterAttributes;
private savedStarterAttributes: StarterAttributes;
@ -1069,12 +1067,10 @@ export class PokedexPageUiHandler extends MessageUiHandler {
) {
starterAttributes.female = !starterAttributes.female;
}
} else {
if (caughtAttr & DexAttr.FEMALE) {
starterAttributes.female = true;
} else if (caughtAttr & DexAttr.MALE) {
starterAttributes.female = false;
}
} else if (caughtAttr & DexAttr.FEMALE) {
starterAttributes.female = true;
} else if (caughtAttr & DexAttr.MALE) {
starterAttributes.female = false;
}
return starterAttributes;
@ -1839,10 +1835,8 @@ export class PokedexPageUiHandler extends MessageUiHandler {
if (this.isCaught() & DexAttr.VARIANT_2) {
break;
}
} else {
if (this.isCaught() & DexAttr.VARIANT_3) {
break;
}
} else if (this.isCaught() & DexAttr.VARIANT_3) {
break;
}
} while (newVariant !== props.variant);
@ -2204,8 +2198,6 @@ export class PokedexPageUiHandler extends MessageUiHandler {
updateInstructions(): void {
this.instructionRowX = 0;
this.instructionRowY = 0;
this.filterInstructionRowX = 0;
this.filterInstructionRowY = 0;
this.hideInstructions();
this.instructionsContainer.removeAll();
this.filterInstructionsContainer.removeAll();
@ -2362,10 +2354,8 @@ export class PokedexPageUiHandler extends MessageUiHandler {
const defaultDexAttr = this.getCurrentDexProps(species.speciesId);
// Set default attributes if for some reason starterAttributes does not exist or attributes missing
const props: StarterAttributes = globalScene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr);
if (starterAttributes?.variant && !Number.isNaN(starterAttributes.variant)) {
if (props.shiny) {
props.variant = starterAttributes.variant as Variant;
}
if (starterAttributes?.variant && !Number.isNaN(starterAttributes.variant) && props.shiny) {
props.variant = starterAttributes.variant as Variant;
}
props.form = starterAttributes?.form ?? props.form;
props.female = starterAttributes?.female ?? props.female;
@ -2778,17 +2768,15 @@ export class PokedexPageUiHandler extends MessageUiHandler {
props += DexAttr.SHINY;
if (this.starterAttributes?.variant !== undefined) {
props += BigInt(Math.pow(2, this.starterAttributes?.variant)) * DexAttr.DEFAULT_VARIANT;
} else {
/* This calculates the correct variant if there's no starter preferences for it.
/* This chunk calculates the correct variant if there's no starter preferences for it.
* This gets the highest tier variant that you've caught and adds it to the temp props
*/
if ((caughtAttr & DexAttr.VARIANT_3) > 0) {
props += DexAttr.VARIANT_3;
} else if ((caughtAttr & DexAttr.VARIANT_2) > 0) {
props += DexAttr.VARIANT_2;
} else {
props += DexAttr.DEFAULT_VARIANT;
}
} else if ((caughtAttr & DexAttr.VARIANT_3) > 0) {
props += DexAttr.VARIANT_3;
} else if ((caughtAttr & DexAttr.VARIANT_2) > 0) {
props += DexAttr.VARIANT_2;
} else {
props += DexAttr.DEFAULT_VARIANT;
}
} else {
props += DexAttr.NON_SHINY;

View File

@ -709,11 +709,12 @@ export class PokedexUiHandler extends MessageUiHandler {
}
}
if (starterAttributes.female !== undefined) {
if (!(starterAttributes.female ? caughtAttr & DexAttr.FEMALE : caughtAttr & DexAttr.MALE)) {
// requested gender wasn't unlocked, purging setting
starterAttributes.female = undefined;
}
if (
starterAttributes.female !== undefined &&
!(starterAttributes.female ? caughtAttr & DexAttr.FEMALE : caughtAttr & DexAttr.MALE)
) {
// requested gender wasn't unlocked, purging setting
starterAttributes.female = undefined;
}
if (starterAttributes.ability !== undefined) {
@ -1187,78 +1188,76 @@ export class PokedexUiHandler extends MessageUiHandler {
break;
}
}
} else if (button === Button.ACTION) {
ui.setOverlayMode(UiMode.POKEDEX_PAGE, this.lastSpecies, null, this.filteredIndices);
success = true;
} else {
if (button === Button.ACTION) {
ui.setOverlayMode(UiMode.POKEDEX_PAGE, this.lastSpecies, null, this.filteredIndices);
success = true;
} else {
switch (button) {
case Button.UP:
if (currentRow > 0) {
if (this.scrollCursor > 0 && currentRow - this.scrollCursor === 0) {
this.scrollCursor--;
this.updateScroll();
success = this.setCursor(this.cursor);
} else {
success = this.setCursor(this.cursor - 9);
}
} else {
this.filterBarCursor = this.filterBar.getNearestFilter(this.pokemonContainers[this.cursor]);
this.setFilterMode(true);
success = true;
}
break;
case Button.DOWN:
if (currentRow < numOfRows - 1 && this.cursor + 9 < this.filteredPokemonData.length) {
// not last row
if (currentRow - this.scrollCursor === 8) {
// last row of visible pokemon
this.scrollCursor++;
this.updateScroll();
success = this.setCursor(this.cursor);
} else {
success = this.setCursor(this.cursor + 9);
}
} else if (numOfRows > 1) {
// DOWN from last row of pokemon > Wrap around to first row
this.scrollCursor = 0;
switch (button) {
case Button.UP:
if (currentRow > 0) {
if (this.scrollCursor > 0 && currentRow - this.scrollCursor === 0) {
this.scrollCursor--;
this.updateScroll();
success = this.setCursor(this.cursor % 9);
success = this.setCursor(this.cursor);
} else {
// DOWN from single row of pokemon > Go to filters
this.filterBarCursor = this.filterBar.getNearestFilter(this.pokemonContainers[this.cursor]);
this.setFilterMode(true);
success = true;
success = this.setCursor(this.cursor - 9);
}
break;
case Button.LEFT:
if (this.cursor % 9 !== 0) {
success = this.setCursor(this.cursor - 1);
} else {
// LEFT from filtered pokemon, on the left edge
this.filterTextCursor = this.filterText.getNearestFilter(this.pokemonContainers[this.cursor]);
this.setFilterTextMode(true);
success = true;
}
break;
case Button.RIGHT:
// is not right edge
if (this.cursor % 9 < (currentRow < numOfRows - 1 ? 8 : (numberOfStarters - 1) % 9)) {
success = this.setCursor(this.cursor + 1);
} else {
// RIGHT from filtered pokemon, on the right edge
this.filterTextCursor = this.filterText.getNearestFilter(this.pokemonContainers[this.cursor]);
this.setFilterTextMode(true);
success = true;
}
break;
case Button.CYCLE_FORM: {
const species = this.pokemonContainers[this.cursor].species;
if (this.canShowFormTray) {
success = this.openFormTray(species);
}
break;
} else {
this.filterBarCursor = this.filterBar.getNearestFilter(this.pokemonContainers[this.cursor]);
this.setFilterMode(true);
success = true;
}
break;
case Button.DOWN:
if (currentRow < numOfRows - 1 && this.cursor + 9 < this.filteredPokemonData.length) {
// not last row
if (currentRow - this.scrollCursor === 8) {
// last row of visible pokemon
this.scrollCursor++;
this.updateScroll();
success = this.setCursor(this.cursor);
} else {
success = this.setCursor(this.cursor + 9);
}
} else if (numOfRows > 1) {
// DOWN from last row of pokemon > Wrap around to first row
this.scrollCursor = 0;
this.updateScroll();
success = this.setCursor(this.cursor % 9);
} else {
// DOWN from single row of pokemon > Go to filters
this.filterBarCursor = this.filterBar.getNearestFilter(this.pokemonContainers[this.cursor]);
this.setFilterMode(true);
success = true;
}
break;
case Button.LEFT:
if (this.cursor % 9 !== 0) {
success = this.setCursor(this.cursor - 1);
} else {
// LEFT from filtered pokemon, on the left edge
this.filterTextCursor = this.filterText.getNearestFilter(this.pokemonContainers[this.cursor]);
this.setFilterTextMode(true);
success = true;
}
break;
case Button.RIGHT:
// is not right edge
if (this.cursor % 9 < (currentRow < numOfRows - 1 ? 8 : (numberOfStarters - 1) % 9)) {
success = this.setCursor(this.cursor + 1);
} else {
// RIGHT from filtered pokemon, on the right edge
this.filterTextCursor = this.filterText.getNearestFilter(this.pokemonContainers[this.cursor]);
this.setFilterTextMode(true);
success = true;
}
break;
case Button.CYCLE_FORM: {
const species = this.pokemonContainers[this.cursor].species;
if (this.canShowFormTray) {
success = this.openFormTray(species);
}
break;
}
}
}
@ -1453,12 +1452,10 @@ export class PokedexUiHandler extends MessageUiHandler {
} else {
data.passive1 = false;
}
} else if (starterData.passiveAttr > 0) {
data.passive2 = true;
} else {
if (starterData.passiveAttr > 0) {
data.passive2 = true;
} else {
data.passive2 = false;
}
data.passive2 = false;
}
}
@ -2334,17 +2331,15 @@ export class PokedexUiHandler extends MessageUiHandler {
props += DexAttr.SHINY;
if (this.starterPreferences[speciesId]?.variant !== undefined) {
props += BigInt(Math.pow(2, this.starterPreferences[speciesId]?.variant)) * DexAttr.DEFAULT_VARIANT;
} else {
} else if ((caughtAttr & DexAttr.VARIANT_3) > 0) {
/* This calculates the correct variant if there's no starter preferences for it.
* This gets the highest tier variant that you've caught and adds it to the temp props
*/
if ((caughtAttr & DexAttr.VARIANT_3) > 0) {
props += DexAttr.VARIANT_3;
} else if ((caughtAttr & DexAttr.VARIANT_2) > 0) {
props += DexAttr.VARIANT_2;
} else {
props += DexAttr.DEFAULT_VARIANT;
}
props += DexAttr.VARIANT_3;
} else if ((caughtAttr & DexAttr.VARIANT_2) > 0) {
props += DexAttr.VARIANT_2;
} else {
props += DexAttr.DEFAULT_VARIANT;
}
} else {
props += DexAttr.NON_SHINY;

View File

@ -32,8 +32,6 @@ export class RunHistoryUiHandler extends MessageUiHandler {
private runsContainer: Phaser.GameObjects.Container;
private runs: RunEntryContainer[];
private runSelectCallback: RunSelectCallback | null;
private scrollCursor = 0;
private cursorObj: Phaser.GameObjects.NineSlice | null;
@ -118,7 +116,6 @@ export class RunHistoryUiHandler extends MessageUiHandler {
success = true;
return success;
}
this.runSelectCallback = null;
success = true;
globalScene.ui.revertMode();
} else if (this.runs.length > 0) {
@ -235,7 +232,6 @@ export class RunHistoryUiHandler extends MessageUiHandler {
this.runSelectContainer.setVisible(false);
this.setScrollCursor(0);
this.clearCursor();
this.runSelectCallback = null;
this.clearRuns();
}
@ -258,13 +254,11 @@ export class RunHistoryUiHandler extends MessageUiHandler {
* entryData: the data of an individual run
*/
class RunEntryContainer extends Phaser.GameObjects.Container {
private slotId: number;
public entryData: RunEntry;
constructor(entryData: RunEntry, slotId: number) {
super(globalScene, 0, slotId * 56);
this.slotId = slotId;
this.entryData = entryData;
this.setup(this.entryData);

View File

@ -683,32 +683,33 @@ export class RunInfoUiHandler extends UiHandler {
*/
private challengeParser(): string[] {
const rules: string[] = [];
for (let i = 0; i < this.runInfo.challenges.length; i++) {
if (this.runInfo.challenges[i].value !== 0) {
switch (this.runInfo.challenges[i].id) {
case Challenges.SINGLE_GENERATION:
rules.push(i18next.t(`runHistory:challengeMonoGen${this.runInfo.challenges[i].value}`));
break;
case Challenges.SINGLE_TYPE: {
const typeRule = PokemonType[this.runInfo.challenges[i].value - 1];
const typeTextColor = `[color=${TypeColor[typeRule]}]`;
const typeShadowColor = `[shadow=${TypeShadow[typeRule]}]`;
const typeText =
typeTextColor + typeShadowColor + i18next.t(`pokemonInfo:Type.${typeRule}`)! + "[/color]" + "[/shadow]";
rules.push(typeText);
break;
}
case Challenges.INVERSE_BATTLE:
rules.push(i18next.t("challenges:inverseBattle.shortName"));
break;
default: {
const localizationKey = Challenges[this.runInfo.challenges[i].id]
.split("_")
.map((f, i) => (i ? `${f[0]}${f.slice(1).toLowerCase()}` : f.toLowerCase()))
.join("");
rules.push(i18next.t(`challenges:${localizationKey}.name`));
break;
}
for (const challenge of this.runInfo.challenges) {
if (challenge.value === 0) {
continue;
}
switch (challenge.id) {
case Challenges.SINGLE_GENERATION:
rules.push(i18next.t(`runHistory:challengeMonoGen${challenge.value}`));
break;
case Challenges.SINGLE_TYPE: {
const typeRule = PokemonType[challenge.value - 1];
const typeTextColor = `[color=${TypeColor[typeRule]}]`;
const typeShadowColor = `[shadow=${TypeShadow[typeRule]}]`;
const typeText =
typeTextColor + typeShadowColor + i18next.t(`pokemonInfo:Type.${typeRule}`)! + "[/color][/shadow]";
rules.push(typeText);
break;
}
case Challenges.INVERSE_BATTLE:
rules.push(i18next.t("challenges:inverseBattle.shortName"));
break;
default: {
const localizationKey = Challenges[challenge.id]
.split("_")
.map((f, i) => (i ? `${f[0]}${f.slice(1).toLowerCase()}` : f.toLowerCase()))
.join("");
rules.push(i18next.t(`challenges:${localizationKey}.name`));
break;
}
}
}

View File

@ -34,8 +34,6 @@ export class AbstractSettingsUiHandler extends MessageUiHandler {
protected navigationIcons: InputsIcons;
private cursorObj: Phaser.GameObjects.NineSlice | null;
private reloadSettings: Array<Setting>;
private reloadRequired: boolean;
protected rowsToDisplay: number;
@ -107,8 +105,6 @@ export class AbstractSettingsUiHandler extends MessageUiHandler {
this.settingLabels = [];
this.optionValueLabels = [];
this.reloadSettings = this.settings.filter(s => s?.requireReload);
let anyReloadRequired = false;
this.settings.forEach((setting, s) => {
let settingName = setting.label;

View File

@ -336,7 +336,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
private teraLabel: Phaser.GameObjects.Text;
private goFilterLabel: Phaser.GameObjects.Text;
/** Group holding the UI elements appearing in the instructionsContainer */
/* TODO: Uncomment this once our testing infra supports mocks of `Phaser.GameObject.Group`
/* TODO: Uncomment this once our testing infra supports mocks of `Phaser.GameObject.Group`
private instructionElemGroup: Phaser.GameObjects.Group;
*/
@ -1217,11 +1217,12 @@ export class StarterSelectUiHandler extends MessageUiHandler {
}
}
if (starterAttributes.female !== undefined) {
if (!(starterAttributes.female ? caughtAttr & DexAttr.FEMALE : caughtAttr & DexAttr.MALE)) {
// requested gender wasn't unlocked, purging setting
starterAttributes.female = undefined;
}
if (
starterAttributes.female !== undefined &&
!(starterAttributes.female ? caughtAttr & DexAttr.FEMALE : caughtAttr & DexAttr.MALE)
) {
// requested gender wasn't unlocked, purging setting
starterAttributes.female = undefined;
}
if (starterAttributes.ability !== undefined) {
@ -2342,11 +2343,9 @@ export class StarterSelectUiHandler extends MessageUiHandler {
// TODO: is this bang correct?
break;
}
} else {
if (this.speciesStarterDexEntry!.caughtAttr & DexAttr.VARIANT_3) {
// TODO: is this bang correct?
break;
}
} else if (this.speciesStarterDexEntry!.caughtAttr & DexAttr.VARIANT_3) {
// TODO: is this bang correct?
break;
}
} while (newVariant !== props.variant);
starterAttributes.variant = newVariant; // store the selected variant
@ -2422,10 +2421,8 @@ export class StarterSelectUiHandler extends MessageUiHandler {
newAbilityIndex = (newAbilityIndex + 1) % abilityCount;
}
break;
} else {
if (abilityAttr & AbilityAttr.ABILITY_HIDDEN) {
break;
}
} else if (abilityAttr & AbilityAttr.ABILITY_HIDDEN) {
break;
}
} while (newAbilityIndex !== this.abilityCursor);
starterAttributes.ability = newAbilityIndex; // store the selected ability
@ -2972,8 +2969,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
}
// this updates icons for previously saved pokemon
for (let i = 0; i < this.validStarterContainers.length; i++) {
const currentFilteredContainer = this.validStarterContainers[i];
for (const currentFilteredContainer of this.validStarterContainers) {
const starterSprite = currentFilteredContainer.icon as Phaser.GameObjects.Sprite;
const currentDexAttr = this.getCurrentDexProps(currentFilteredContainer.species.speciesId);
@ -3562,10 +3558,8 @@ export class StarterSelectUiHandler extends MessageUiHandler {
// load default nature from stater save data, if set
const defaultNature = starterAttributes?.nature || globalScene.gameData.getSpeciesDefaultNature(species);
props = globalScene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr);
if (starterAttributes?.variant && !Number.isNaN(starterAttributes.variant)) {
if (props.shiny) {
props.variant = starterAttributes.variant as Variant;
}
if (starterAttributes?.variant && !Number.isNaN(starterAttributes.variant) && props.shiny) {
props.variant = starterAttributes.variant as Variant;
}
props.formIndex = starterAttributes?.form ?? props.formIndex;
props.female = starterAttributes?.female ?? props.female;
@ -4350,13 +4344,13 @@ export class StarterSelectUiHandler extends MessageUiHandler {
return true;
}
/* This block checks to see if your party is valid
/**
* This block checks to see if your party is valid
* It checks each pokemon against the challenge - noting that due to monotype challenges it needs to check the pokemon while ignoring their evolutions/form change items
*/
isPartyValid(): boolean {
let canStart = false;
for (let s = 0; s < this.starterSpecies.length; s++) {
const species = this.starterSpecies[s];
for (const species of this.starterSpecies) {
const isValidForChallenge = checkStarterValidForChallenge(
species,
globalScene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)),
@ -4400,17 +4394,15 @@ export class StarterSelectUiHandler extends MessageUiHandler {
props += DexAttr.SHINY;
if (this.starterPreferences[speciesId]?.variant !== undefined) {
props += BigInt(Math.pow(2, this.starterPreferences[speciesId]?.variant)) * DexAttr.DEFAULT_VARIANT;
} else {
} else if ((caughtAttr & DexAttr.VARIANT_3) > 0) {
/* This calculates the correct variant if there's no starter preferences for it.
* This gets the highest tier variant that you've caught and adds it to the temp props
*/
if ((caughtAttr & DexAttr.VARIANT_3) > 0) {
props += DexAttr.VARIANT_3;
} else if ((caughtAttr & DexAttr.VARIANT_2) > 0) {
props += DexAttr.VARIANT_2;
} else {
props += DexAttr.DEFAULT_VARIANT;
}
props += DexAttr.VARIANT_3;
} else if ((caughtAttr & DexAttr.VARIANT_2) > 0) {
props += DexAttr.VARIANT_2;
} else {
props += DexAttr.DEFAULT_VARIANT;
}
} else {
props += DexAttr.NON_SHINY;

View File

@ -515,33 +515,31 @@ export class SummaryUiHandler extends UiHandler {
if (this.pokemon && this.moveCursor < this.pokemon.moveset.length) {
if (this.summaryUiMode === SummaryUiMode.LEARN_MOVE) {
this.moveSelectFunction?.(this.moveCursor);
} else if (this.selectedMoveIndex === -1) {
this.selectedMoveIndex = this.moveCursor;
this.setCursor(this.moveCursor);
} else {
if (this.selectedMoveIndex === -1) {
this.selectedMoveIndex = this.moveCursor;
this.setCursor(this.moveCursor);
} else {
if (this.selectedMoveIndex !== this.moveCursor) {
const tempMove = this.pokemon?.moveset[this.selectedMoveIndex];
this.pokemon.moveset[this.selectedMoveIndex] = this.pokemon.moveset[this.moveCursor];
this.pokemon.moveset[this.moveCursor] = tempMove;
if (this.selectedMoveIndex !== this.moveCursor) {
const tempMove = this.pokemon?.moveset[this.selectedMoveIndex];
this.pokemon.moveset[this.selectedMoveIndex] = this.pokemon.moveset[this.moveCursor];
this.pokemon.moveset[this.moveCursor] = tempMove;
const selectedMoveRow = this.moveRowsContainer.getAt(
this.selectedMoveIndex,
) as Phaser.GameObjects.Container;
const switchMoveRow = this.moveRowsContainer.getAt(this.moveCursor) as Phaser.GameObjects.Container;
const selectedMoveRow = this.moveRowsContainer.getAt(
this.selectedMoveIndex,
) as Phaser.GameObjects.Container;
const switchMoveRow = this.moveRowsContainer.getAt(this.moveCursor) as Phaser.GameObjects.Container;
this.moveRowsContainer.moveTo(selectedMoveRow, this.moveCursor);
this.moveRowsContainer.moveTo(switchMoveRow, this.selectedMoveIndex);
this.moveRowsContainer.moveTo(selectedMoveRow, this.moveCursor);
this.moveRowsContainer.moveTo(switchMoveRow, this.selectedMoveIndex);
selectedMoveRow.setY(this.moveCursor * 16);
switchMoveRow.setY(this.selectedMoveIndex * 16);
}
selectedMoveRow.setY(this.moveCursor * 16);
switchMoveRow.setY(this.selectedMoveIndex * 16);
}
this.selectedMoveIndex = -1;
if (this.selectedMoveCursorObj) {
this.selectedMoveCursorObj.destroy();
this.selectedMoveCursorObj = null;
}
this.selectedMoveIndex = -1;
if (this.selectedMoveCursorObj) {
this.selectedMoveCursorObj.destroy();
this.selectedMoveCursorObj = null;
}
}
success = true;
@ -575,78 +573,76 @@ export class SummaryUiHandler extends UiHandler {
break;
}
}
} else {
if (button === Button.ACTION) {
if (this.cursor === Page.MOVES) {
this.showMoveSelect();
success = true;
} else if (this.cursor === Page.PROFILE && this.pokemon?.hasPassive()) {
// if we're on the PROFILE page and this pokemon has a passive unlocked..
// Since abilities are displayed by default, all we need to do is toggle visibility on all elements to show passives
this.abilityContainer.nameText?.setVisible(!this.abilityContainer.descriptionText?.visible);
this.abilityContainer.descriptionText?.setVisible(!this.abilityContainer.descriptionText.visible);
this.abilityContainer.labelImage.setVisible(!this.abilityContainer.labelImage.visible);
this.passiveContainer.nameText?.setVisible(!this.passiveContainer.descriptionText?.visible);
this.passiveContainer.descriptionText?.setVisible(!this.passiveContainer.descriptionText.visible);
this.passiveContainer.labelImage.setVisible(!this.passiveContainer.labelImage.visible);
} else if (this.cursor === Page.STATS) {
//Show IVs
this.permStatsContainer.setVisible(!this.permStatsContainer.visible);
this.ivContainer.setVisible(!this.ivContainer.visible);
}
} else if (button === Button.CANCEL) {
if (this.summaryUiMode === SummaryUiMode.LEARN_MOVE) {
this.hideMoveSelect();
} else {
if (this.selectCallback instanceof Function) {
const selectCallback = this.selectCallback;
this.selectCallback = null;
selectCallback();
}
if (!fromPartyMode) {
ui.setMode(UiMode.MESSAGE);
} else {
ui.setMode(UiMode.PARTY);
}
}
} else if (button === Button.ACTION) {
if (this.cursor === Page.MOVES) {
this.showMoveSelect();
success = true;
} else if (this.cursor === Page.PROFILE && this.pokemon?.hasPassive()) {
// if we're on the PROFILE page and this pokemon has a passive unlocked..
// Since abilities are displayed by default, all we need to do is toggle visibility on all elements to show passives
this.abilityContainer.nameText?.setVisible(!this.abilityContainer.descriptionText?.visible);
this.abilityContainer.descriptionText?.setVisible(!this.abilityContainer.descriptionText.visible);
this.abilityContainer.labelImage.setVisible(!this.abilityContainer.labelImage.visible);
this.passiveContainer.nameText?.setVisible(!this.passiveContainer.descriptionText?.visible);
this.passiveContainer.descriptionText?.setVisible(!this.passiveContainer.descriptionText.visible);
this.passiveContainer.labelImage.setVisible(!this.passiveContainer.labelImage.visible);
} else if (this.cursor === Page.STATS) {
//Show IVs
this.permStatsContainer.setVisible(!this.permStatsContainer.visible);
this.ivContainer.setVisible(!this.ivContainer.visible);
}
} else if (button === Button.CANCEL) {
if (this.summaryUiMode === SummaryUiMode.LEARN_MOVE) {
this.hideMoveSelect();
} else {
const pages = getEnumValues(Page);
switch (button) {
case Button.UP:
case Button.DOWN: {
if (this.summaryUiMode === SummaryUiMode.LEARN_MOVE) {
break;
}
if (!fromPartyMode) {
break;
}
const isDown = button === Button.DOWN;
const party = globalScene.getPlayerParty();
const partyMemberIndex = this.pokemon ? party.indexOf(this.pokemon) : -1;
if ((isDown && partyMemberIndex < party.length - 1) || (!isDown && partyMemberIndex)) {
const page = this.cursor;
this.clear();
this.show([party[partyMemberIndex + (isDown ? 1 : -1)], this.summaryUiMode, page]);
}
if (this.selectCallback instanceof Function) {
const selectCallback = this.selectCallback;
this.selectCallback = null;
selectCallback();
}
if (!fromPartyMode) {
ui.setMode(UiMode.MESSAGE);
} else {
ui.setMode(UiMode.PARTY);
}
}
success = true;
} else {
const pages = getEnumValues(Page);
switch (button) {
case Button.UP:
case Button.DOWN: {
if (this.summaryUiMode === SummaryUiMode.LEARN_MOVE) {
break;
}
case Button.LEFT:
if (this.cursor) {
success = this.setCursor(this.cursor - 1);
}
break;
case Button.RIGHT:
if (this.cursor < pages.length - 1) {
success = this.setCursor(this.cursor + 1);
if (this.summaryUiMode === SummaryUiMode.LEARN_MOVE && this.cursor === Page.MOVES) {
this.moveSelect = true;
}
}
if (!fromPartyMode) {
break;
}
const isDown = button === Button.DOWN;
const party = globalScene.getPlayerParty();
const partyMemberIndex = this.pokemon ? party.indexOf(this.pokemon) : -1;
if ((isDown && partyMemberIndex < party.length - 1) || (!isDown && partyMemberIndex)) {
const page = this.cursor;
this.clear();
this.show([party[partyMemberIndex + (isDown ? 1 : -1)], this.summaryUiMode, page]);
}
break;
}
case Button.LEFT:
if (this.cursor) {
success = this.setCursor(this.cursor - 1);
}
break;
case Button.RIGHT:
if (this.cursor < pages.length - 1) {
success = this.setCursor(this.cursor + 1);
if (this.summaryUiMode === SummaryUiMode.LEARN_MOVE && this.cursor === Page.MOVES) {
this.moveSelect = true;
}
}
break;
}
}

View File

@ -70,11 +70,12 @@ export class TargetSelectUiHandler extends UiHandler {
* @param user the Pokemon using the move
*/
resetCursor(cursorN: number, user: Pokemon): void {
if (!isNullOrUndefined(cursorN)) {
if ([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2].includes(cursorN) || user.tempSummonData.waveTurnCount === 1) {
// Reset cursor on the first turn of a fight or if an ally was targeted last turn
cursorN = -1;
}
if (
!isNullOrUndefined(cursorN) &&
([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2].includes(cursorN) || user.tempSummonData.waveTurnCount === 1)
) {
// Reset cursor on the first turn of a fight or if an ally was targeted last turn
cursorN = -1;
}
this.setCursor(this.targets.includes(cursorN) ? cursorN : this.targets[0]);
}
@ -92,10 +93,11 @@ export class TargetSelectUiHandler extends UiHandler {
if (isNullOrUndefined(this.cursor0) || this.cursor0 !== this.cursor) {
this.cursor0 = this.cursor;
}
} else if (this.fieldIndex === BattlerIndex.PLAYER_2) {
if (isNullOrUndefined(this.cursor1) || this.cursor1 !== this.cursor) {
this.cursor1 = this.cursor;
}
} else if (
this.fieldIndex === BattlerIndex.PLAYER_2 &&
(isNullOrUndefined(this.cursor1) || this.cursor1 !== this.cursor)
) {
this.cursor1 = this.cursor;
}
} else if (this.isMultipleTargets) {
success = false;

View File

@ -117,10 +117,8 @@ export function updateWindowType(windowTypeIndex: number): void {
} else if (object.texture?.key === "namebox") {
themedObjects.push(object);
}
} else if (object instanceof Phaser.GameObjects.Sprite) {
if (object.texture?.key === "bg") {
themedObjects.push(object);
}
} else if (object instanceof Phaser.GameObjects.Sprite && object.texture?.key === "bg") {
themedObjects.push(object);
}
};

View File

@ -374,10 +374,12 @@ export class UI extends Phaser.GameObjects.Container {
}
shouldSkipDialogue(i18nKey: string): boolean {
if (i18next.exists(i18nKey)) {
if (globalScene.skipSeenDialogues && globalScene.gameData.getSeenDialogues()[i18nKey] === true) {
return true;
}
if (
i18next.exists(i18nKey) &&
globalScene.skipSeenDialogues &&
globalScene.gameData.getSeenDialogues()[i18nKey] === true
) {
return true;
}
return false;
}

View File

@ -10,7 +10,6 @@ import { removeCookie } from "#utils/cookies";
import i18next from "i18next";
export class UnavailableModalUiHandler extends ModalUiHandler {
private reconnectTimer: NodeJS.Timeout | null;
private reconnectDuration: number;
private reconnectCallback: () => void;
@ -62,7 +61,6 @@ export class UnavailableModalUiHandler extends ModalUiHandler {
tryReconnect(): void {
updateUserInfo().then(response => {
if (response[0] || [200, 400].includes(response[1])) {
this.reconnectTimer = null;
this.reconnectDuration = this.minTime;
globalScene.playSound("se/pb_bounce_1");
this.reconnectCallback();
@ -71,7 +69,7 @@ export class UnavailableModalUiHandler extends ModalUiHandler {
globalScene.reset(true, true);
} else {
this.reconnectDuration = Math.min(this.reconnectDuration * 2, this.maxTime); // Set a max delay so it isn't infinite
this.reconnectTimer = setTimeout(
setTimeout(
() => this.tryReconnect(),
// Adds a random factor to avoid pendulum effect during long total breakdown
this.reconnectDuration + Math.random() * this.randVarianceTime,
@ -88,7 +86,7 @@ export class UnavailableModalUiHandler extends ModalUiHandler {
this.reconnectCallback = args[0];
this.reconnectDuration = this.minTime;
this.reconnectTimer = setTimeout(() => this.tryReconnect(), this.reconnectDuration);
setTimeout(() => this.tryReconnect(), this.reconnectDuration);
return super.show([config]);
}

View File

@ -1,3 +1,5 @@
// biome-ignore-all lint/nursery/useUnifiedTypeSignature: Rule does not allow stuff with JSDoc comments
import type { FixedBattleConfig } from "#app/battle";
import { globalScene } from "#app/global-scene";
import { pokemonEvolutions } from "#balance/pokemon-evolutions";

View File

@ -23,13 +23,11 @@ export function getCookie(cName: string): string {
}
const name = `${cName}=`;
const ca = document.cookie.split(";");
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) === " ") {
c = c.substring(1);
}
if (c.indexOf(name) === 0) {
return c.substring(name.length, c.length);
// Check all cookies in the document and see if any of them match, grabbing the first one whose value lines up
for (const c of ca) {
const cTrimmed = c.trim();
if (cTrimmed.startsWith(name)) {
return c.slice(name.length, c.length);
}
}
return "";

View File

@ -33,8 +33,8 @@ describe("Abilities - POWER CONSTRUCT", () => {
});
test("check if fainted 50% Power Construct Pokemon switches to base form on arena reset", async () => {
const baseForm = 2,
completeForm = 4;
const baseForm = 2;
const completeForm = 4;
game.override.startingWave(4).starterForms({
[SpeciesId.ZYGARDE]: completeForm,
});
@ -59,8 +59,8 @@ describe("Abilities - POWER CONSTRUCT", () => {
});
test("check if fainted 10% Power Construct Pokemon switches to base form on arena reset", async () => {
const baseForm = 3,
completeForm = 5;
const baseForm = 3;
const completeForm = 5;
game.override.startingWave(4).starterForms({
[SpeciesId.ZYGARDE]: completeForm,
});

View File

@ -29,8 +29,8 @@ describe("Abilities - SCHOOLING", () => {
});
test("check if fainted pokemon switches to base form on arena reset", async () => {
const soloForm = 0,
schoolForm = 1;
const soloForm = 0;
const schoolForm = 1;
game.override.startingWave(4).starterForms({
[SpeciesId.WISHIWASHI]: schoolForm,
});

View File

@ -34,8 +34,8 @@ describe("Abilities - SHIELDS DOWN", () => {
});
test("check if fainted pokemon switched to base form on arena reset", async () => {
const meteorForm = 0,
coreForm = 7;
const meteorForm = 0;
const coreForm = 7;
game.override.startingWave(4).starterForms({
[SpeciesId.MINIOR]: coreForm,
});

View File

@ -76,9 +76,9 @@ describe("Escape chance calculations", () => {
{ pokemonSpeedRatio: 2, escapeAttempts: 3, expectedEscapeChance: 80 },
];
for (let i = 0; i < escapeChances.length; i++) {
// sets the number of escape attempts to the required amount
game.scene.currentBattle.escapeAttempts = escapeChances[i].escapeAttempts;
for (const check of escapeChances) {
// set the number of escape attempts to the required amount
game.scene.currentBattle.escapeAttempts = check.escapeAttempts;
// set playerPokemon's speed to a multiple of the enemySpeed
vi.spyOn(playerPokemon[0], "stats", "get").mockReturnValue([
20,
@ -86,10 +86,10 @@ describe("Escape chance calculations", () => {
20,
20,
20,
escapeChances[i].pokemonSpeedRatio * enemySpeed,
check.pokemonSpeedRatio * enemySpeed,
]);
const chance = phase.calculateEscapeChance(game.scene.currentBattle.escapeAttempts);
expect(chance).toBe(escapeChances[i].expectedEscapeChance);
expect(chance).toBe(check.expectedEscapeChance);
}
});
@ -146,9 +146,9 @@ describe("Escape chance calculations", () => {
{ pokemonSpeedRatio: 2, escapeAttempts: 10, expectedEscapeChance: 95 },
];
for (let i = 0; i < escapeChances.length; i++) {
for (const check of escapeChances) {
// sets the number of escape attempts to the required amount
game.scene.currentBattle.escapeAttempts = escapeChances[i].escapeAttempts;
game.scene.currentBattle.escapeAttempts = check.escapeAttempts;
// set the first playerPokemon's speed to a multiple of the enemySpeed
vi.spyOn(playerPokemon[0], "stats", "get").mockReturnValue([
20,
@ -156,7 +156,7 @@ describe("Escape chance calculations", () => {
20,
20,
20,
Math.floor(escapeChances[i].pokemonSpeedRatio * totalEnemySpeed * playerASpeedPercentage),
Math.floor(check.pokemonSpeedRatio * totalEnemySpeed * playerASpeedPercentage),
]);
// set the second playerPokemon's speed to the remaining value of speed
vi.spyOn(playerPokemon[1], "stats", "get").mockReturnValue([
@ -165,15 +165,13 @@ describe("Escape chance calculations", () => {
20,
20,
20,
escapeChances[i].pokemonSpeedRatio * totalEnemySpeed - playerPokemon[0].stats[5],
check.pokemonSpeedRatio * totalEnemySpeed - playerPokemon[0].stats[5],
]);
const chance = phase.calculateEscapeChance(game.scene.currentBattle.escapeAttempts);
// checks to make sure the escape values are the same
expect(chance).toBe(escapeChances[i].expectedEscapeChance);
expect(chance).toBe(check.expectedEscapeChance);
// checks to make sure the sum of the player's speed for all pokemon is equal to the appropriate ratio of the total enemy speed
expect(playerPokemon[0].stats[5] + playerPokemon[1].stats[5]).toBe(
escapeChances[i].pokemonSpeedRatio * totalEnemySpeed,
);
expect(playerPokemon[0].stats[5] + playerPokemon[1].stats[5]).toBe(check.pokemonSpeedRatio * totalEnemySpeed);
}
});
@ -238,9 +236,9 @@ describe("Escape chance calculations", () => {
{ pokemonSpeedRatio: 6.1, escapeAttempts: 3, expectedEscapeChance: 25 },
];
for (let i = 0; i < escapeChances.length; i++) {
for (const check of escapeChances) {
// sets the number of escape attempts to the required amount
game.scene.currentBattle.escapeAttempts = escapeChances[i].escapeAttempts;
game.scene.currentBattle.escapeAttempts = check.escapeAttempts;
// set playerPokemon's speed to a multiple of the enemySpeed
vi.spyOn(playerPokemon[0], "stats", "get").mockReturnValue([
20,
@ -248,10 +246,10 @@ describe("Escape chance calculations", () => {
20,
20,
20,
escapeChances[i].pokemonSpeedRatio * enemySpeed,
check.pokemonSpeedRatio * enemySpeed,
]);
const chance = phase.calculateEscapeChance(game.scene.currentBattle.escapeAttempts);
expect(chance).toBe(escapeChances[i].expectedEscapeChance);
expect(chance).toBe(check.expectedEscapeChance);
}
});
@ -321,9 +319,9 @@ describe("Escape chance calculations", () => {
{ pokemonSpeedRatio: 5.2, escapeAttempts: 2, expectedEscapeChance: 25 },
];
for (let i = 0; i < escapeChances.length; i++) {
for (const check of escapeChances) {
// sets the number of escape attempts to the required amount
game.scene.currentBattle.escapeAttempts = escapeChances[i].escapeAttempts;
game.scene.currentBattle.escapeAttempts = check.escapeAttempts;
// set the first playerPokemon's speed to a multiple of the enemySpeed
vi.spyOn(playerPokemon[0], "stats", "get").mockReturnValue([
20,
@ -331,7 +329,7 @@ describe("Escape chance calculations", () => {
20,
20,
20,
Math.floor(escapeChances[i].pokemonSpeedRatio * totalEnemySpeed * playerASpeedPercentage),
Math.floor(check.pokemonSpeedRatio * totalEnemySpeed * playerASpeedPercentage),
]);
// set the second playerPokemon's speed to the remaining value of speed
vi.spyOn(playerPokemon[1], "stats", "get").mockReturnValue([
@ -340,15 +338,13 @@ describe("Escape chance calculations", () => {
20,
20,
20,
escapeChances[i].pokemonSpeedRatio * totalEnemySpeed - playerPokemon[0].stats[5],
check.pokemonSpeedRatio * totalEnemySpeed - playerPokemon[0].stats[5],
]);
const chance = phase.calculateEscapeChance(game.scene.currentBattle.escapeAttempts);
// checks to make sure the escape values are the same
expect(chance).toBe(escapeChances[i].expectedEscapeChance);
expect(chance).toBe(check.expectedEscapeChance);
// checks to make sure the sum of the player's speed for all pokemon is equal to the appropriate ratio of the total enemy speed
expect(playerPokemon[0].stats[5] + playerPokemon[1].stats[5]).toBe(
escapeChances[i].pokemonSpeedRatio * totalEnemySpeed,
);
expect(playerPokemon[0].stats[5] + playerPokemon[1].stats[5]).toBe(check.pokemonSpeedRatio * totalEnemySpeed);
}
});
});

View File

@ -139,17 +139,15 @@ const getMockedMoveDamage = (defender: Pokemon, attacker: Pokemon, move: Move) =
const multiplierHolder = new NumberHolder(1);
const side = defender.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
if (globalScene.arena.getTagOnSide(ArenaTagType.AURORA_VEIL, side)) {
if (move.getAttrs("CritOnlyAttr").length === 0) {
globalScene.arena.applyTagsForSide(
ArenaTagType.AURORA_VEIL,
side,
false,
attacker,
move.category,
multiplierHolder,
);
}
if (globalScene.arena.getTagOnSide(ArenaTagType.AURORA_VEIL, side) && move.getAttrs("CritOnlyAttr").length === 0) {
globalScene.arena.applyTagsForSide(
ArenaTagType.AURORA_VEIL,
side,
false,
attacker,
move.category,
multiplierHolder,
);
}
return move.power * multiplierHolder.value;

View File

@ -127,17 +127,15 @@ const getMockedMoveDamage = (defender: Pokemon, attacker: Pokemon, move: Move) =
const multiplierHolder = new NumberHolder(1);
const side = defender.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
if (globalScene.arena.getTagOnSide(ArenaTagType.LIGHT_SCREEN, side)) {
if (move.getAttrs("CritOnlyAttr").length === 0) {
globalScene.arena.applyTagsForSide(
ArenaTagType.LIGHT_SCREEN,
side,
false,
attacker,
move.category,
multiplierHolder,
);
}
if (globalScene.arena.getTagOnSide(ArenaTagType.LIGHT_SCREEN, side) && move.getAttrs("CritOnlyAttr").length === 0) {
globalScene.arena.applyTagsForSide(
ArenaTagType.LIGHT_SCREEN,
side,
false,
attacker,
move.category,
multiplierHolder,
);
}
return move.power * multiplierHolder.value;

View File

@ -143,10 +143,8 @@ const getMockedMoveDamage = (defender: Pokemon, attacker: Pokemon, move: Move) =
const multiplierHolder = new NumberHolder(1);
const side = defender.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
if (globalScene.arena.getTagOnSide(ArenaTagType.REFLECT, side)) {
if (move.getAttrs("CritOnlyAttr").length === 0) {
globalScene.arena.applyTagsForSide(ArenaTagType.REFLECT, side, false, attacker, move.category, multiplierHolder);
}
if (globalScene.arena.getTagOnSide(ArenaTagType.REFLECT, side) && move.getAttrs("CritOnlyAttr").length === 0) {
globalScene.arena.applyTagsForSide(ArenaTagType.REFLECT, side, false, attacker, move.category, multiplierHolder);
}
return move.power * multiplierHolder.value;

View File

@ -17,16 +17,12 @@ export class MenuManip {
private config;
private settingName;
private keycode;
private icon;
private iconDisplayed;
private specialCaseIcon;
constructor(config) {
this.config = config;
this.settingName = null;
this.icon = null;
this.iconDisplayed = null;
this.specialCaseIcon = null;
}
// TODO: Review this

View File

@ -18,8 +18,10 @@ import { GameManagerHelper } from "#test/test-utils/helpers/game-manager-helper"
export class ClassicModeHelper extends GameManagerHelper {
/**
* Runs the classic game to the summon phase.
* @param species - An array of {@linkcode Species} to summon.
* @param species - An array of {@linkcode SpeciesId} to summon.
* @returns A promise that resolves when the summon phase is reached.
* @remarks
* Do not use this when {@linkcode startBattle} can be used!
*/
async runToSummon(species: SpeciesId[]): Promise<void>;
/**
@ -29,6 +31,7 @@ export class ClassicModeHelper extends GameManagerHelper {
* @returns A promise that resolves when the summon phase is reached.
* @deprecated - Specifying the starters helps prevent inconsistencies from internal RNG changes.
*/
// biome-ignore lint/nursery/useUnifiedTypeSignature: Marks the overload for deprecation
async runToSummon(): Promise<void>;
async runToSummon(species: SpeciesId[] | undefined): Promise<void>;
async runToSummon(species?: SpeciesId[]): Promise<void> {
@ -60,7 +63,7 @@ export class ClassicModeHelper extends GameManagerHelper {
/**
* Transitions to the start of a battle.
* @param species - An array of {@linkcode Species} to start the battle with.
* @param species - An array of {@linkcode SpeciesId} to start the battle with.
* @returns A promise that resolves when the battle is started.
*/
async startBattle(species: SpeciesId[]): Promise<void>;
@ -71,6 +74,7 @@ export class ClassicModeHelper extends GameManagerHelper {
* @returns A promise that resolves when the battle is started.
* @deprecated - Specifying the starters helps prevent inconsistencies from internal RNG changes.
*/
// biome-ignore lint/nursery/useUnifiedTypeSignature: Marks the overload for deprecation
async startBattle(): Promise<void>;
async startBattle(species?: SpeciesId[]): Promise<void> {
await this.runToSummon(species);

View File

@ -227,11 +227,9 @@ export class MoveHelper extends GameManagerHelper {
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([]);
console.warn("Player moveset override disabled due to use of `game.move.changeMoveset`!");
}
} else {
if (coerceArray(Overrides.OPP_MOVESET_OVERRIDE).length > 0) {
vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([]);
console.warn("Enemy moveset override disabled due to use of `game.move.changeMoveset`!");
}
} else if (coerceArray(Overrides.OPP_MOVESET_OVERRIDE).length > 0) {
vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([]);
console.warn("Enemy moveset override disabled due to use of `game.move.changeMoveset`!");
}
moveset = coerceArray(moveset);
expect(moveset.length, "Cannot assign more than 4 moves to a moveset!").toBeLessThanOrEqual(4);

View File

@ -53,13 +53,11 @@ export class MockText implements MockGameObject {
wordWidthWithSpace += whiteSpaceWidth;
}
if (wordWidthWithSpace > spaceLeft) {
// Skip printing the newline if it's the first word of the line that is greater
// than the word wrap width.
if (j > 0) {
result += "\n";
spaceLeft = this.wordWrapWidth;
}
// Skip printing the newline if it's the first word of the line that is greater
// than the word wrap width.
if (wordWidthWithSpace > spaceLeft && j > 0) {
result += "\n";
spaceLeft = this.wordWrapWidth;
}
result += word;

View File

@ -2,10 +2,8 @@
* Class will intercept any text or dialogue message calls and log them for test purposes
*/
export class TextInterceptor {
private scene;
public logs: string[] = [];
constructor(scene) {
this.scene = scene;
scene.messageWrapper = this;
}