[Dev] Add more Biome rules (#6604)

* Added `noBannedTypes` as a biome rule

* Added `useShorthandAssign` rule

* Added `useConsistentArrayType`

* Update src/field/pokemon.ts

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>

* Update src/data/pokeball.ts

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>

* Apply Biome after merge

---------

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
This commit is contained in:
Bertie690 2025-11-01 23:38:04 -04:00 committed by GitHub
parent b2089012c1
commit d3088c1729
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
44 changed files with 162 additions and 125 deletions

View File

@ -116,7 +116,17 @@
}, },
"useCollapsedIf": "error", "useCollapsedIf": "error",
"useCollapsedElseIf": "error", "useCollapsedElseIf": "error",
"useDeprecatedReason": "error",
"useConsistentArrayType": {
"level": "error",
"fix": "safe",
"options": {}
},
"useShorthandAssign": {
"level": "error",
"fix": "safe",
"options": {}
},
"noSubstr": "error", "noSubstr": "error",
"noYodaExpression": "error", "noYodaExpression": "error",
"useForOf": "error", "useForOf": "error",
@ -205,7 +215,7 @@
"noForEach": "off", // Foreach vs for of is not that simple. "noForEach": "off", // Foreach vs for of is not that simple.
"noUselessSwitchCase": "off", // Explicit > Implicit "noUselessSwitchCase": "off", // Explicit > Implicit
"noUselessConstructor": "error", "noUselessConstructor": "error",
"noBannedTypes": "warn", // TODO: Refactor and make this an error "noBannedTypes": "error",
"noThisInStatic": "error", "noThisInStatic": "error",
"noUselessThisAlias": "error", "noUselessThisAlias": "error",
"noUselessTernary": "error", "noUselessTernary": "error",

View File

@ -3625,9 +3625,9 @@ export class BattleScene extends SceneBase {
// biome-ignore format: biome sucks at formatting this line // biome-ignore format: biome sucks at formatting this line
for (const seenEncounterData of this.mysteryEncounterSaveData.encounteredEvents) { for (const seenEncounterData of this.mysteryEncounterSaveData.encounteredEvents) {
if (seenEncounterData.tier === MysteryEncounterTier.COMMON) { if (seenEncounterData.tier === MysteryEncounterTier.COMMON) {
tierWeights[0] = tierWeights[0] - 6; tierWeights[0] -= 6;
} else if (seenEncounterData.tier === MysteryEncounterTier.GREAT) { } else if (seenEncounterData.tier === MysteryEncounterTier.GREAT) {
tierWeights[1] = tierWeights[1] - 4; tierWeights[1] -= 4;
} }
} }

View File

@ -821,7 +821,7 @@ export abstract class BattleAnim {
frame.target === AnimFrameTarget.GRAPHIC frame.target === AnimFrameTarget.GRAPHIC
&& isReversed(this.srcLine[0], this.srcLine[2], this.dstLine[0], this.dstLine[2]) && isReversed(this.srcLine[0], this.srcLine[2], this.dstLine[0], this.dstLine[2])
) { ) {
scaleX = scaleX * -1; scaleX *= -1;
} }
} }
break; break;
@ -835,7 +835,7 @@ export abstract class BattleAnim {
} }
// biome-ignore lint/complexity/noBannedTypes: callback is used liberally // biome-ignore lint/complexity/noBannedTypes: callback is used liberally
play(onSubstitute?: boolean, callback?: Function) { play(onSubstitute?: boolean, callback?: () => void) {
const isOppAnim = this.isOppAnim(); const isOppAnim = this.isOppAnim();
const user = isOppAnim ? this.target! : this.user!; const user = isOppAnim ? this.target! : this.user!;
const target = isOppAnim ? this.user! : this.target!; // TODO: These bangs are LITERALLY not correct at all const target = isOppAnim ? this.user! : this.target!; // TODO: These bangs are LITERALLY not correct at all
@ -1179,7 +1179,7 @@ export abstract class BattleAnim {
frameTimeMult: number, frameTimeMult: number,
frameTimedEventPriority?: 0 | 1 | 3 | 5, frameTimedEventPriority?: 0 | 1 | 3 | 5,
// biome-ignore lint/complexity/noBannedTypes: callback is used liberally // biome-ignore lint/complexity/noBannedTypes: callback is used liberally
callback?: Function, callback?: () => void,
) { ) {
const spriteCache: SpriteCache = { const spriteCache: SpriteCache = {
[AnimFrameTarget.GRAPHIC]: [], [AnimFrameTarget.GRAPHIC]: [],

View File

@ -933,7 +933,7 @@ export class FreshStartChallenge extends Challenge {
} }
applyStarterModify(pokemon: Pokemon): boolean { applyStarterModify(pokemon: Pokemon): boolean {
pokemon.abilityIndex = pokemon.abilityIndex % 2; // Always base ability, if you set it to hidden it wraps to first ability pokemon.abilityIndex %= 2; // Always base ability, if you set it to hidden it wraps to first ability
pokemon.passive = false; // Passive isn't unlocked pokemon.passive = false; // Passive isn't unlocked
let validMoves = pokemon.species let validMoves = pokemon.species
.getLevelMoves() .getLevelMoves()

View File

@ -10,7 +10,7 @@ export interface TrainerTypeMessages {
} }
export interface TrainerTypeDialogue { export interface TrainerTypeDialogue {
[key: number]: TrainerTypeMessages | Array<TrainerTypeMessages>; [key: number]: TrainerTypeMessages | TrainerTypeMessages[];
} }
export function getTrainerTypeDialogue(): TrainerTypeDialogue { export function getTrainerTypeDialogue(): TrainerTypeDialogue {

View File

@ -567,7 +567,7 @@ function doBerryBounce(berrySprites: Phaser.GameObjects.Sprite[], yd: number, ba
bouncePower = bouncePower > 0.01 ? bouncePower * 0.5 : 0; bouncePower = bouncePower > 0.01 ? bouncePower * 0.5 : 0;
if (bouncePower) { if (bouncePower) {
bounceYOffset = bounceYOffset * bouncePower; bounceYOffset *= bouncePower;
globalScene.tweens.add({ globalScene.tweens.add({
targets: berrySprites, targets: berrySprites,

View File

@ -739,7 +739,7 @@ export function selectOptionThenPokemon(
export function setEncounterRewards( export function setEncounterRewards(
customShopRewards?: CustomModifierSettings, customShopRewards?: CustomModifierSettings,
eggRewards?: IEggOptions[], eggRewards?: IEggOptions[],
preRewardsCallback?: Function, preRewardsCallback?: () => void,
): void { ): void {
globalScene.currentBattle.mysteryEncounter!.doEncounterRewards = () => { globalScene.currentBattle.mysteryEncounter!.doEncounterRewards = () => {
if (preRewardsCallback) { if (preRewardsCallback) {
@ -1172,8 +1172,8 @@ export function calculateMEAggregateStats(baseSpawnWeight: number): void {
const tierWeights = [66, 40, 19, 3]; const tierWeights = [66, 40, 19, 3];
// Adjust tier weights by currently encountered events (pity system that lowers odds of multiple Common/Great) // Adjust tier weights by currently encountered events (pity system that lowers odds of multiple Common/Great)
tierWeights[0] = tierWeights[0] - 6 * numEncounters[0]; tierWeights[0] -= 6 * numEncounters[0];
tierWeights[1] = tierWeights[1] - 4 * numEncounters[1]; tierWeights[1] -= 4 * numEncounters[1];
const totalWeight = tierWeights.reduce((a, b) => a + b); const totalWeight = tierWeights.reduce((a, b) => a + b);
const tierValue = randSeedInt(totalWeight); const tierValue = randSeedInt(totalWeight);

View File

@ -115,8 +115,7 @@ export function doPokeballBounceAnim(
y1: number, y1: number,
y2: number, y2: number,
baseBounceDuration: number, baseBounceDuration: number,
// biome-ignore lint/complexity/noBannedTypes: TODO callback: () => void,
callback: Function,
isCritical = false, isCritical = false,
) { ) {
let bouncePower = 1; let bouncePower = 1;

View File

@ -421,7 +421,7 @@ export abstract class PokemonSpeciesForm {
case SpeciesId.BLOODMOON_URSALUNA: case SpeciesId.BLOODMOON_URSALUNA:
break; break;
default: default:
speciesId = speciesId % 2000; speciesId %= 2000;
break; break;
} }
} }

View File

@ -158,7 +158,7 @@ export function getRandomStatus(statusA: Status | null, statusB: Status | null):
* Gets all non volatile status effects * Gets all non volatile status effects
* @returns A list containing all non volatile status effects * @returns A list containing all non volatile status effects
*/ */
export function getNonVolatileStatusEffects(): Array<StatusEffect> { export function getNonVolatileStatusEffects(): StatusEffect[] {
return [ return [
StatusEffect.POISON, StatusEffect.POISON,
StatusEffect.TOXIC, StatusEffect.TOXIC,

View File

@ -134,7 +134,7 @@ function doFanOutParticle(
} }
particle.x = x + sin(trigIndex, f * xSpeed); particle.x = x + sin(trigIndex, f * xSpeed);
particle.y = y + cos(trigIndex, f * ySpeed); particle.y = y + cos(trigIndex, f * ySpeed);
trigIndex = trigIndex + angle; trigIndex += angle;
f++; f++;
}; };

View File

@ -1847,20 +1847,20 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
* @returns An array of {@linkcode PokemonMove}, as described above. * @returns An array of {@linkcode PokemonMove}, as described above.
*/ */
getMoveset(ignoreOverride = false): PokemonMove[] { getMoveset(ignoreOverride = false): PokemonMove[] {
// Overrides moveset based on arrays specified in overrides.ts // Override moveset based on arrays specified in overrides.ts
let overrideArray: MoveId | Array<MoveId> = this.isPlayer() const overrideArray = coerceArray(this.isPlayer() ? Overrides.MOVESET_OVERRIDE : Overrides.ENEMY_MOVESET_OVERRIDE);
? Overrides.MOVESET_OVERRIDE if (overrideArray.length === 0) {
: Overrides.ENEMY_MOVESET_OVERRIDE; return !ignoreOverride && this.summonData.moveset ? this.summonData.moveset : this.moveset;
overrideArray = coerceArray(overrideArray); }
if (overrideArray.length > 0) {
if (!this.isPlayer()) { if (!this.isPlayer()) {
this.moveset = []; this.moveset = [];
} }
// TODO: Preserve PP used while the moveset override is active
overrideArray.forEach((move: MoveId, index: number) => { overrideArray.forEach((move: MoveId, index: number) => {
const ppUsed = this.moveset[index]?.ppUsed ?? 0; const ppUsed = this.moveset[index]?.ppUsed ?? 0;
this.moveset[index] = new PokemonMove(move, Math.min(ppUsed, allMoves[move].pp)); this.moveset[index] = new PokemonMove(move, Math.min(ppUsed, allMoves[move].pp));
}); });
}
return !ignoreOverride && this.summonData.moveset ? this.summonData.moveset : this.moveset; return !ignoreOverride && this.summonData.moveset ? this.summonData.moveset : this.moveset;
} }
@ -2658,10 +2658,10 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
hpDiffRatio = 1 - hpRatio + (outspeed ? 0.2 : 0.1); hpDiffRatio = 1 - hpRatio + (outspeed ? 0.2 : 0.1);
} }
} else if (outspeed) { } else if (outspeed) {
hpDiffRatio = hpDiffRatio * 1.25; hpDiffRatio *= 1.25;
} else if (hpRatio > 0.2 && hpRatio <= 0.4) { } else if (hpRatio > 0.2 && hpRatio <= 0.4) {
// Might be considered to be switched because it's not in low enough health // Might be considered to be switched because it's not in low enough health
hpDiffRatio = hpDiffRatio * 0.5; hpDiffRatio *= 0.5;
} }
return (atkScore + defScore) * Math.min(hpDiffRatio, 1); return (atkScore + defScore) * Math.min(hpDiffRatio, 1);
} }
@ -3909,7 +3909,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
} }
damage = Math.min(damage, this.hp); damage = Math.min(damage, this.hp);
this.hp = this.hp - damage; this.hp -= damage;
if (this.isFainted() && !ignoreFaintPhase) { if (this.isFainted() && !ignoreFaintPhase) {
globalScene.phaseManager.queueFaintPhase(this.getBattlerIndex(), preventEndure); globalScene.phaseManager.queueFaintPhase(this.getBattlerIndex(), preventEndure);
this.destroySubstitute(); this.destroySubstitute();

View File

@ -70,7 +70,7 @@ const repeatInputDelayMillis = 250;
* providing a unified interface for all input-related interactions. * providing a unified interface for all input-related interactions.
*/ */
export class InputsController { export class InputsController {
private gamepads: Array<Phaser.Input.Gamepad.Gamepad> = []; private gamepads: Phaser.Input.Gamepad.Gamepad[] = [];
public events: Phaser.Events.EventEmitter; public events: Phaser.Events.EventEmitter;
private buttonLock: Button[] = []; private buttonLock: Button[] = [];
@ -80,7 +80,7 @@ export class InputsController {
public gamepadSupport = true; public gamepadSupport = true;
public selectedDevice; public selectedDevice;
private disconnectedGamepads: Array<string> = []; private disconnectedGamepads: string[] = [];
public lastSource = "keyboard"; public lastSource = "keyboard";
private inputInterval: NodeJS.Timeout[] = []; private inputInterval: NodeJS.Timeout[] = [];
@ -223,7 +223,7 @@ export class InputsController {
* Retrieves the identifiers of all connected gamepads, excluding any that are currently marked as disconnected. * Retrieves the identifiers of all connected gamepads, excluding any that are currently marked as disconnected.
* @returns Array<String> An array of strings representing the IDs of the connected gamepads. * @returns Array<String> An array of strings representing the IDs of the connected gamepads.
*/ */
getGamepadsName(): Array<string> { getGamepadsName(): string[] {
return this.gamepads.filter(g => !this.disconnectedGamepads.includes(g.id)).map(g => g.id); return this.gamepads.filter(g => !this.disconnectedGamepads.includes(g.id)).map(g => g.id);
} }

View File

@ -479,7 +479,7 @@ export class DoubleBattleChanceBoosterModifier extends LapsingPersistentModifier
override apply(doubleBattleChance: NumberHolder): boolean { override apply(doubleBattleChance: NumberHolder): boolean {
// This is divided because the chance is generated as a number from 0 to doubleBattleChance.value using randSeedInt // This is divided because the chance is generated as a number from 0 to doubleBattleChance.value using randSeedInt
// A double battle will initiate if the generated number is 0 // A double battle will initiate if the generated number is 0
doubleBattleChance.value = doubleBattleChance.value / 4; doubleBattleChance.value /= 4;
return true; return true;
} }
@ -2684,7 +2684,7 @@ export class PokemonMoveAccuracyBoosterModifier extends PokemonHeldItemModifier
* @returns always `true` * @returns always `true`
*/ */
override apply(_pokemon: Pokemon, moveAccuracy: NumberHolder): boolean { override apply(_pokemon: Pokemon, moveAccuracy: NumberHolder): boolean {
moveAccuracy.value = moveAccuracy.value + this.accuracyAmount * this.getStackCount(); moveAccuracy.value += this.accuracyAmount * this.getStackCount();
return true; return true;
} }

View File

@ -159,7 +159,7 @@ class DefaultOverrides {
readonly HAS_PASSIVE_ABILITY_OVERRIDE: boolean | null = null; readonly HAS_PASSIVE_ABILITY_OVERRIDE: boolean | null = null;
readonly STATUS_OVERRIDE: StatusEffect = StatusEffect.NONE; readonly STATUS_OVERRIDE: StatusEffect = StatusEffect.NONE;
readonly GENDER_OVERRIDE: Gender | null = null; readonly GENDER_OVERRIDE: Gender | null = null;
readonly MOVESET_OVERRIDE: MoveId | Array<MoveId> = []; readonly MOVESET_OVERRIDE: MoveId | MoveId[] = [];
readonly SHINY_OVERRIDE: boolean | null = null; readonly SHINY_OVERRIDE: boolean | null = null;
readonly VARIANT_OVERRIDE: Variant | null = null; readonly VARIANT_OVERRIDE: Variant | null = null;
/** /**
@ -186,7 +186,7 @@ class DefaultOverrides {
readonly ENEMY_HAS_PASSIVE_ABILITY_OVERRIDE: boolean | null = null; readonly ENEMY_HAS_PASSIVE_ABILITY_OVERRIDE: boolean | null = null;
readonly ENEMY_STATUS_OVERRIDE: StatusEffect = StatusEffect.NONE; readonly ENEMY_STATUS_OVERRIDE: StatusEffect = StatusEffect.NONE;
readonly ENEMY_GENDER_OVERRIDE: Gender | null = null; readonly ENEMY_GENDER_OVERRIDE: Gender | null = null;
readonly ENEMY_MOVESET_OVERRIDE: MoveId | Array<MoveId> = []; readonly ENEMY_MOVESET_OVERRIDE: MoveId | MoveId[] = [];
readonly ENEMY_SHINY_OVERRIDE: boolean | null = null; readonly ENEMY_SHINY_OVERRIDE: boolean | null = null;
readonly ENEMY_VARIANT_OVERRIDE: Variant | null = null; readonly ENEMY_VARIANT_OVERRIDE: Variant | null = null;

View File

@ -11,7 +11,7 @@ import { namespaceMap } from "./utils-plugins";
interface LoadingFontFaceProperty { interface LoadingFontFaceProperty {
face: FontFace; face: FontFace;
extraOptions?: { [key: string]: any }; extraOptions?: { [key: string]: any };
only?: Array<string>; only?: string[];
} }
//#region Constants //#region Constants
@ -35,7 +35,7 @@ const rangesByLanguage = {
), ),
}; };
const fonts: Array<LoadingFontFaceProperty> = [ const fonts: LoadingFontFaceProperty[] = [
// unicode (special character from PokePT) // unicode (special character from PokePT)
{ {
face: new FontFace("emerald", "url(./fonts/PokePT_Wansung.woff2)", { face: new FontFace("emerald", "url(./fonts/PokePT_Wansung.woff2)", {

View File

@ -199,7 +199,7 @@ for (let i = 0; i < 5; i++) {
/** /**
* All Settings not related to controls * All Settings not related to controls
*/ */
export const Setting: Array<Setting> = [ export const Setting: Setting[] = [
{ {
key: SettingKeys.Game_Speed, key: SettingKeys.Game_Speed,
label: i18next.t("settings:gameSpeed"), label: i18next.t("settings:gameSpeed"),

View File

@ -1,11 +1,14 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { Button } from "#enums/buttons"; import { Button } from "#enums/buttons";
import type { UiMode } from "#enums/ui-mode"; import type { UiMode } from "#enums/ui-mode";
import type { AnyFn } from "#types/type-helpers";
import { UiHandler } from "#ui/ui-handler"; import { UiHandler } from "#ui/ui-handler";
// TODO: Why does this class exist?
export abstract class AwaitableUiHandler extends UiHandler { export abstract class AwaitableUiHandler extends UiHandler {
protected awaitingActionInput: boolean; protected awaitingActionInput: boolean;
protected onActionInput: Function | null; // TODO: Add strong typing for subclasses rather than using `AnyFn`
protected onActionInput: AnyFn | null;
public tutorialActive = false; public tutorialActive = false;
public tutorialOverlay: Phaser.GameObjects.Rectangle; public tutorialOverlay: Phaser.GameObjects.Rectangle;

View File

@ -171,7 +171,7 @@ export class BattleMessageUiHandler extends MessageUiHandler {
showText( showText(
text: string, text: string,
delay?: number | null, delay?: number | null,
callback?: Function | null, callback?: (() => void) | null,
callbackDelay?: number | null, callbackDelay?: number | null,
prompt?: boolean | null, prompt?: boolean | null,
promptDelay?: number | null, promptDelay?: number | null,
@ -184,7 +184,7 @@ export class BattleMessageUiHandler extends MessageUiHandler {
text: string, text: string,
name?: string, name?: string,
delay?: number | null, delay?: number | null,
callback?: Function, callback?: () => void,
callbackDelay?: number, callbackDelay?: number,
prompt?: boolean, prompt?: boolean,
promptDelay?: number, promptDelay?: number,

View File

@ -660,7 +660,7 @@ export class EggGachaUiHandler extends MessageUiHandler {
showText( showText(
text: string, text: string,
delay?: number, delay?: number,
callback?: Function, callback?: () => void,
callbackDelay?: number, callbackDelay?: number,
prompt?: boolean, prompt?: boolean,
promptDelay?: number, promptDelay?: number,

View File

@ -1,7 +1,6 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { Button } from "#enums/buttons"; import { Button } from "#enums/buttons";
import { TextStyle } from "#enums/text-style"; import { TextStyle } from "#enums/text-style";
import type { AnyFn } from "#types/type-helpers";
import type { ModalConfig } from "#ui/modal-ui-handler"; import type { ModalConfig } from "#ui/modal-ui-handler";
import { ModalUiHandler } from "#ui/modal-ui-handler"; import { ModalUiHandler } from "#ui/modal-ui-handler";
import { addTextInputObject, addTextObject, getTextColor } from "#ui/text"; import { addTextInputObject, addTextObject, getTextColor } from "#ui/text";
@ -18,7 +17,7 @@ export abstract class FormModalUiHandler extends ModalUiHandler {
protected inputContainers: Phaser.GameObjects.Container[] = []; protected inputContainers: Phaser.GameObjects.Container[] = [];
protected inputs: InputText[] = []; protected inputs: InputText[] = [];
protected errorMessage: Phaser.GameObjects.Text; protected errorMessage: Phaser.GameObjects.Text;
protected submitAction: AnyFn | undefined; protected submitAction: (() => void) | undefined;
protected cancelAction: (() => void) | undefined; protected cancelAction: (() => void) | undefined;
protected tween: Phaser.Tweens.Tween | undefined; protected tween: Phaser.Tweens.Tween | undefined;
protected formLabels: Phaser.GameObjects.Text[] = []; protected formLabels: Phaser.GameObjects.Text[] = [];

View File

@ -7,7 +7,6 @@ import { PlayerGender } from "#enums/player-gender";
import { TextStyle } from "#enums/text-style"; import { TextStyle } from "#enums/text-style";
import { UiTheme } from "#enums/ui-theme"; import { UiTheme } from "#enums/ui-theme";
import type { GameData } from "#system/game-data"; import type { GameData } from "#system/game-data";
import type { AnyFn } from "#types/type-helpers";
import { addTextObject } from "#ui/text"; import { addTextObject } from "#ui/text";
import { UiHandler } from "#ui/ui-handler"; import { UiHandler } from "#ui/ui-handler";
import { addWindow } from "#ui/ui-theme"; import { addWindow } from "#ui/ui-theme";
@ -244,7 +243,7 @@ export class GameStatsUiHandler extends UiHandler {
private gameData: GameData; private gameData: GameData;
/** A callback invoked when {@linkcode clear} is called */ /** A callback invoked when {@linkcode clear} is called */
private exitCallback?: AnyFn | undefined; private exitCallback?: (() => void) | undefined;
/** Whether the UI is single column mode */ /** Whether the UI is single column mode */
private get singleCol(): boolean { private get singleCol(): boolean {
@ -402,7 +401,7 @@ export class GameStatsUiHandler extends UiHandler {
this.gameStatsContainer.setVisible(false); this.gameStatsContainer.setVisible(false);
} }
show([username, data, callback]: [] | [username: string, data: GameData, callback?: AnyFn]): boolean { show([username, data, callback]: [] | [username: string, data: GameData, callback?: () => void]): boolean {
super.show([]); super.show([]);
if (username != null && data != null) { if (username != null && data != null) {

View File

@ -165,8 +165,10 @@ export class LoginFormUiHandler extends FormModalUiHandler {
const config = args[0] as ModalConfig; const config = args[0] as ModalConfig;
this.processExternalProvider(config); this.processExternalProvider(config);
const originalLoginAction = this.submitAction; const originalLoginAction = this.submitAction;
this.submitAction = _ => { this.submitAction = () => {
if (globalScene.tweens.getTweensOf(this.modalContainer).length === 0) { if (globalScene.tweens.getTweensOf(this.modalContainer).length > 0) {
return;
}
// Prevent overlapping overrides on action modification // Prevent overlapping overrides on action modification
this.submitAction = originalLoginAction; this.submitAction = originalLoginAction;
this.sanitizeInputs(); this.sanitizeInputs();
@ -193,7 +195,6 @@ export class LoginFormUiHandler extends FormModalUiHandler {
onFail(error); onFail(error);
} }
}); });
}
}; };
return true; return true;

View File

@ -781,7 +781,7 @@ export class MenuUiHandler extends MessageUiHandler {
showText( showText(
text: string, text: string,
delay?: number, delay?: number,
callback?: Function, callback?: () => void,
callbackDelay?: number, callbackDelay?: number,
prompt?: boolean, prompt?: boolean,
promptDelay?: number, promptDelay?: number,

View File

@ -37,7 +37,7 @@ export abstract class MessageUiHandler extends AwaitableUiHandler {
showText( showText(
text: string, text: string,
delay?: number | null, delay?: number | null,
callback?: Function | null, callback?: (() => void) | null,
callbackDelay?: number | null, callbackDelay?: number | null,
prompt?: boolean | null, prompt?: boolean | null,
promptDelay?: number | null, promptDelay?: number | null,
@ -49,7 +49,7 @@ export abstract class MessageUiHandler extends AwaitableUiHandler {
text: string, text: string,
_name?: string, _name?: string,
delay?: number | null, delay?: number | null,
callback?: Function | null, callback?: (() => void) | null,
callbackDelay?: number | null, callbackDelay?: number | null,
prompt?: boolean | null, prompt?: boolean | null,
promptDelay?: number | null, promptDelay?: number | null,
@ -60,7 +60,7 @@ export abstract class MessageUiHandler extends AwaitableUiHandler {
private showTextInternal( private showTextInternal(
text: string, text: string,
delay?: number | null, delay?: number | null,
callback?: Function | null, callback?: (() => void) | null,
callbackDelay?: number | null, callbackDelay?: number | null,
prompt?: boolean | null, prompt?: boolean | null,
promptDelay?: number | null, promptDelay?: number | null,
@ -219,7 +219,7 @@ export abstract class MessageUiHandler extends AwaitableUiHandler {
} }
} }
showPrompt(callback?: Function | null, callbackDelay?: number | null) { showPrompt(callback?: (() => void) | null, callbackDelay?: number | null) {
const wrappedTextLines = this.message.runWordWrap(this.message.text).split(/\n/g); const wrappedTextLines = this.message.runWordWrap(this.message.text).split(/\n/g);
const textLinesCount = wrappedTextLines.length; const textLinesCount = wrappedTextLines.length;
const lastTextLine = wrappedTextLines.at(-1) ?? ""; const lastTextLine = wrappedTextLines.at(-1) ?? "";

View File

@ -11,6 +11,7 @@ import { UiMode } from "#enums/ui-mode";
import { HealShopCostModifier, LockModifierTiersModifier, PokemonHeldItemModifier } from "#modifiers/modifier"; import { HealShopCostModifier, LockModifierTiersModifier, PokemonHeldItemModifier } from "#modifiers/modifier";
import type { ModifierTypeOption } from "#modifiers/modifier-type"; import type { ModifierTypeOption } from "#modifiers/modifier-type";
import { getPlayerShopModifierTypeOptionsForWave, TmModifierType } from "#modifiers/modifier-type"; import { getPlayerShopModifierTypeOptionsForWave, TmModifierType } from "#modifiers/modifier-type";
import type { ModifierSelectCallback } from "#phases/select-modifier-phase";
import { AwaitableUiHandler } from "#ui/awaitable-ui-handler"; import { AwaitableUiHandler } from "#ui/awaitable-ui-handler";
import { MoveInfoOverlay } from "#ui/move-info-overlay"; import { MoveInfoOverlay } from "#ui/move-info-overlay";
import { addTextObject, getModifierTierTextTint, getTextColor, getTextStyleOptions } from "#ui/text"; import { addTextObject, getModifierTierTextTint, getTextColor, getTextStyleOptions } from "#ui/text";
@ -34,6 +35,7 @@ export class ModifierSelectUiHandler extends AwaitableUiHandler {
private lockRarityButtonText: Phaser.GameObjects.Text; private lockRarityButtonText: Phaser.GameObjects.Text;
private moveInfoOverlay: MoveInfoOverlay; private moveInfoOverlay: MoveInfoOverlay;
private moveInfoOverlayActive = false; private moveInfoOverlayActive = false;
protected declare onActionInput: ModifierSelectCallback | null;
private rowCursor = 0; private rowCursor = 0;
private player: boolean; private player: boolean;
@ -424,7 +426,8 @@ export class ModifierSelectUiHandler extends AwaitableUiHandler {
const originalOnActionInput = this.onActionInput; const originalOnActionInput = this.onActionInput;
this.awaitingActionInput = false; this.awaitingActionInput = false;
this.onActionInput = null; this.onActionInput = null;
originalOnActionInput(-1); // TODO: What is a good fallback to pass to this?
originalOnActionInput(-1, -1);
this.moveInfoOverlayActive = this.moveInfoOverlay.active; this.moveInfoOverlayActive = this.moveInfoOverlay.active;
this.moveInfoOverlay.setVisible(false); this.moveInfoOverlay.setVisible(false);
this.moveInfoOverlay.active = false; // don't clear here as we might need to restore the UI in case the user cancels the action this.moveInfoOverlay.active = false; // don't clear here as we might need to restore the UI in case the user cancels the action

View File

@ -1289,7 +1289,7 @@ export class PartyUiHandler extends MessageUiHandler {
showText( showText(
text: string, text: string,
delay?: number | null, delay?: number | null,
callback?: Function | null, callback?: (() => void) | null,
callbackDelay?: number | null, callbackDelay?: number | null,
prompt?: boolean | null, prompt?: boolean | null,
promptDelay?: number | null, promptDelay?: number | null,

View File

@ -1085,7 +1085,7 @@ export class PokedexPageUiHandler extends MessageUiHandler {
showText( showText(
text: string, text: string,
delay?: number, delay?: number,
callback?: Function, callback?: () => void,
callbackDelay?: number, callbackDelay?: number,
prompt?: boolean, prompt?: boolean,
promptDelay?: number, promptDelay?: number,

View File

@ -165,7 +165,7 @@ export class PokedexScanUiHandler extends FormModalUiHandler {
} else { } else {
this.inputs[0].text = args[1]; this.inputs[0].text = args[1];
} }
this.submitAction = _ => { this.submitAction = () => {
if (ui.getMode() === UiMode.POKEDEX_SCAN) { if (ui.getMode() === UiMode.POKEDEX_SCAN) {
this.sanitizeInputs(); this.sanitizeInputs();
const outputName = this.reducedKeys.includes(this.inputs[0].text) ? this.inputs[0].text : ""; const outputName = this.reducedKeys.includes(this.inputs[0].text) ? this.inputs[0].text : "";

View File

@ -34,7 +34,6 @@ import type { GameData } from "#system/game-data";
import { SettingKeyboard } from "#system/settings-keyboard"; import { SettingKeyboard } from "#system/settings-keyboard";
import type { DexEntry } from "#types/dex-data"; import type { DexEntry } from "#types/dex-data";
import type { DexAttrProps, StarterAttributes } from "#types/save-data"; import type { DexAttrProps, StarterAttributes } from "#types/save-data";
import type { AnyFn } from "#types/type-helpers";
import type { OptionSelectConfig } from "#ui/abstract-option-select-ui-handler"; import type { OptionSelectConfig } from "#ui/abstract-option-select-ui-handler";
import { DropDown, DropDownLabel, DropDownOption, DropDownState, DropDownType, SortCriteria } from "#ui/dropdown"; import { DropDown, DropDownLabel, DropDownOption, DropDownState, DropDownType, SortCriteria } from "#ui/dropdown";
import { FilterBar } from "#ui/filter-bar"; import { FilterBar } from "#ui/filter-bar";
@ -239,7 +238,7 @@ export class PokedexUiHandler extends MessageUiHandler {
private filteredIndices: SpeciesId[]; private filteredIndices: SpeciesId[];
private gameData: GameData; private gameData: GameData;
private exitCallback?: AnyFn; private exitCallback?: () => void;
private blockOpenPage = false; private blockOpenPage = false;
constructor() { constructor() {
@ -793,7 +792,7 @@ export class PokedexUiHandler extends MessageUiHandler {
showText( showText(
text: string, text: string,
delay?: number, delay?: number,
callback?: Function, callback?: () => void,
callbackDelay?: number, callbackDelay?: number,
prompt?: boolean, prompt?: boolean,
promptDelay?: number, promptDelay?: number,

View File

@ -76,7 +76,7 @@ export class RegistrationFormUiHandler extends FormModalUiHandler {
const config = args[0] as ModalConfig; const config = args[0] as ModalConfig;
const originalRegistrationAction = this.submitAction; const originalRegistrationAction = this.submitAction;
this.submitAction = _ => { this.submitAction = () => {
if (globalScene.tweens.getTweensOf(this.modalContainer).length === 0) { if (globalScene.tweens.getTweensOf(this.modalContainer).length === 0) {
// Prevent overlapping overrides on action modification // Prevent overlapping overrides on action modification
this.submitAction = originalRegistrationAction; this.submitAction = originalRegistrationAction;

View File

@ -42,7 +42,7 @@ export class RenameFormUiHandler extends FormModalUiHandler {
} else { } else {
this.inputs[0].text = args[1]; this.inputs[0].text = args[1];
} }
this.submitAction = _ => { this.submitAction = () => {
this.sanitizeInputs(); this.sanitizeInputs();
const sanitizedName = btoa(unescape(encodeURIComponent(this.inputs[0].text))); const sanitizedName = btoa(unescape(encodeURIComponent(this.inputs[0].text)));
config.buttonActions[0](sanitizedName); config.buttonActions[0](sanitizedName);

View File

@ -42,7 +42,7 @@ export class RenameRunFormUiHandler extends FormModalUiHandler {
}); });
} }
const config = args[0] as ModalConfig; const config = args[0] as ModalConfig;
this.submitAction = _ => { this.submitAction = () => {
this.sanitizeInputs(); this.sanitizeInputs();
const sanitizedName = btoa(encodeURIComponent(this.inputs[0].text)); const sanitizedName = btoa(encodeURIComponent(this.inputs[0].text));
config.buttonActions[0](sanitizedName); config.buttonActions[0](sanitizedName);

View File

@ -343,7 +343,7 @@ export class SaveSlotSelectUiHandler extends MessageUiHandler {
showText( showText(
text: string, text: string,
delay?: number, delay?: number,
callback?: Function, callback?: () => void,
callbackDelay?: number, callbackDelay?: number,
prompt?: boolean, prompt?: boolean,
promptDelay?: number, promptDelay?: number,

View File

@ -1334,7 +1334,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
showText( showText(
text: string, text: string,
delay?: number, delay?: number,
callback?: Function, callback?: () => void,
callbackDelay?: number, callbackDelay?: number,
prompt?: boolean, prompt?: boolean,
promptDelay?: number, promptDelay?: number,

View File

@ -126,7 +126,7 @@ export class SummaryUiHandler extends UiHandler {
private playerParty: boolean; private playerParty: boolean;
/**This is set to false when checking the summary of a freshly caught Pokemon as it is not part of a player's party yet but still needs to display its items*/ /**This is set to false when checking the summary of a freshly caught Pokemon as it is not part of a player's party yet but still needs to display its items*/
private newMove: Move | null; private newMove: Move | null;
private moveSelectFunction: Function | null; private moveSelectFunction: ((cursor: number) => void) | null;
private transitioning: boolean; private transitioning: boolean;
private statusVisible: boolean; private statusVisible: boolean;
private moveEffectsVisible: boolean; private moveEffectsVisible: boolean;
@ -134,7 +134,7 @@ export class SummaryUiHandler extends UiHandler {
private moveSelect: boolean; private moveSelect: boolean;
private moveCursor: number; private moveCursor: number;
private selectedMoveIndex: number; private selectedMoveIndex: number;
private selectCallback: Function | null; private selectCallback: ((cursor: number) => void) | null;
constructor() { constructor() {
super(UiMode.SUMMARY); super(UiMode.SUMMARY);
@ -335,18 +335,44 @@ export class SummaryUiHandler extends UiHandler {
return `summary_${Page[page].toLowerCase()}`; return `summary_${Page[page].toLowerCase()}`;
} }
show(args: any[]): boolean { show(
args: [
pokemon: PlayerPokemon,
uiMode?: SummaryUiMode.DEFAULT,
startPage?: Page,
selectCallback?: (cursor: number) => void,
player?: boolean,
],
): boolean;
show(
args: [
pokemon: PlayerPokemon,
uiMode: SummaryUiMode.LEARN_MOVE,
move?: Move,
moveSelectCallback?: (cursor: number) => void,
player?: boolean,
],
): boolean;
show(
args: [
pokemon: PlayerPokemon,
uiMode?: SummaryUiMode,
startPage?: Page | Move,
callback?: (cursor: number) => void,
player?: boolean,
],
): boolean {
super.show(args); super.show(args);
/* args[] information /* args[] information
* args[0] : the Pokemon displayed in the Summary-UI * args[0] : the Pokemon displayed in the Summary-UI
* args[1] : the summaryUiMode (defaults to 0) * args[1] : the summaryUiMode (defaults to 0)
* args[2] : the start page (defaults to Page.PROFILE) * args[2] : the start page (defaults to Page.PROFILE), or the move being selected
* args[3] : contains the function executed when the user exits out of Summary UI * args[3] : contains the function executed when the user exits out of Summary UI
* args[4] : optional boolean used to determine if the Pokemon is part of the player's party or not (defaults to true, necessary for PR #2921 to display all relevant information) * args[4] : optional boolean used to determine if the Pokemon is part of the player's party or not (defaults to true, necessary for PR #2921 to display all relevant information)
*/ */
this.pokemon = args[0] as PlayerPokemon; this.pokemon = args[0] as PlayerPokemon;
this.summaryUiMode = args.length > 1 ? (args[1] as SummaryUiMode) : SummaryUiMode.DEFAULT; this.summaryUiMode = (args[1] as SummaryUiMode) ?? SummaryUiMode.DEFAULT;
this.playerParty = args[4] ?? true; this.playerParty = args[4] ?? true;
globalScene.ui.bringToTop(this.summaryContainer); globalScene.ui.bringToTop(this.summaryContainer);
@ -486,17 +512,15 @@ export class SummaryUiHandler extends UiHandler {
switch (this.summaryUiMode) { switch (this.summaryUiMode) {
case SummaryUiMode.DEFAULT: { case SummaryUiMode.DEFAULT: {
const page = args.length < 2 ? Page.PROFILE : (args[2] as Page); const page = (args[2] as Page) ?? Page.PROFILE;
this.hideMoveEffect(true); this.hideMoveEffect(true);
this.setCursor(page); this.setCursor(page);
if (args.length > 3) { this.selectCallback = args[3] ?? null;
this.selectCallback = args[3];
}
break; break;
} }
case SummaryUiMode.LEARN_MOVE: case SummaryUiMode.LEARN_MOVE:
this.newMove = args[2] as Move; this.newMove = args[2] as Move;
this.moveSelectFunction = args[3] as Function; this.moveSelectFunction = args[3] ?? null;
this.showMoveEffect(true); this.showMoveEffect(true);
this.setCursor(Page.MOVES); this.setCursor(Page.MOVES);
@ -615,7 +639,7 @@ export class SummaryUiHandler extends UiHandler {
if (this.selectCallback instanceof Function) { if (this.selectCallback instanceof Function) {
const selectCallback = this.selectCallback; const selectCallback = this.selectCallback;
this.selectCallback = null; this.selectCallback = null;
selectCallback(); selectCallback(-1);
} }
if (!fromPartyMode) { if (!fromPartyMode) {

View File

@ -12,7 +12,7 @@ export class TestDialogueUiHandler extends FormModalUiHandler {
setup() { setup() {
super.setup(); super.setup();
const flattenKeys = (object?: any, topKey?: string, middleKey?: string[]): Array<any> => { const flattenKeys = (object?: any, topKey?: string, middleKey?: string[]): any[] => {
return Object.keys(object ?? {}) return Object.keys(object ?? {})
.map((t, i) => { .map((t, i) => {
const value = Object.values(object)[i]; const value = Object.values(object)[i];
@ -141,7 +141,7 @@ export class TestDialogueUiHandler extends FormModalUiHandler {
} else { } else {
this.inputs[0].text = args[1]; this.inputs[0].text = args[1];
} }
this.submitAction = _ => { this.submitAction = () => {
if (ui.getMode() === UiMode.TEST_DIALOGUE) { if (ui.getMode() === UiMode.TEST_DIALOGUE) {
this.sanitizeInputs(); this.sanitizeInputs();
const sanitizedName = btoa(unescape(encodeURIComponent(this.inputs[0].text))); const sanitizedName = btoa(unescape(encodeURIComponent(this.inputs[0].text)));

View File

@ -24,7 +24,7 @@ export interface LayoutConfig {
optionValueLabels: Phaser.GameObjects.Text[][]; optionValueLabels: Phaser.GameObjects.Text[][];
optionCursors: number[]; optionCursors: number[];
keys: string[]; keys: string[];
bindingSettings: Array<string>; bindingSettings: string[];
} }
/** /**
* Abstract class for handling UI elements related to control settings. * Abstract class for handling UI elements related to control settings.
@ -51,10 +51,10 @@ export abstract class AbstractControlSettingsUiHandler extends UiHandler {
protected inputsIcons: InputsIcons; protected inputsIcons: InputsIcons;
protected navigationIcons: InputsIcons; protected navigationIcons: InputsIcons;
// list all the setting keys used in the selected layout (because dualshock has more buttons than xbox) // list all the setting keys used in the selected layout (because dualshock has more buttons than xbox)
protected keys: Array<string>; protected keys: string[];
// Store the specific settings related to key bindings for the current gamepad configuration. // Store the specific settings related to key bindings for the current gamepad configuration.
protected bindingSettings: Array<string>; protected bindingSettings: string[];
protected setting; protected setting;
protected settingBlacklisted; protected settingBlacklisted;

View File

@ -4,7 +4,6 @@ import { TextStyle } from "#enums/text-style";
import { UiMode } from "#enums/ui-mode"; import { UiMode } from "#enums/ui-mode";
import type { SettingType } from "#system/settings"; import type { SettingType } from "#system/settings";
import { Setting, SettingKeys } from "#system/settings"; import { Setting, SettingKeys } from "#system/settings";
import type { AnyFn } from "#types/type-helpers";
import type { InputsIcons } from "#ui/abstract-control-settings-ui-handler"; import type { InputsIcons } from "#ui/abstract-control-settings-ui-handler";
import { MessageUiHandler } from "#ui/message-ui-handler"; import { MessageUiHandler } from "#ui/message-ui-handler";
import { NavigationManager, NavigationMenu } from "#ui/navigation-menu"; import { NavigationManager, NavigationMenu } from "#ui/navigation-menu";
@ -40,7 +39,7 @@ export class AbstractSettingsUiHandler extends MessageUiHandler {
protected rowsToDisplay: number; protected rowsToDisplay: number;
protected title: string; protected title: string;
protected settings: Array<Setting>; protected settings: Setting[];
protected localStorageKey: string; protected localStorageKey: string;
constructor(type: SettingType, mode: UiMode | null = null) { constructor(type: SettingType, mode: UiMode | null = null) {
@ -518,7 +517,7 @@ export class AbstractSettingsUiHandler extends MessageUiHandler {
override showText( override showText(
text: string, text: string,
delay?: number, delay?: number,
callback?: AnyFn, callback?: () => void,
callbackDelay?: number, callbackDelay?: number,
prompt?: boolean, prompt?: boolean,
promptDelay?: number, promptDelay?: number,

View File

@ -277,7 +277,7 @@ export class UI extends Phaser.GameObjects.Container {
showText( showText(
text: string, text: string,
delay?: number | null, delay?: number | null,
callback?: Function | null, callback?: (() => void) | null,
callbackDelay?: number | null, callbackDelay?: number | null,
prompt?: boolean | null, prompt?: boolean | null,
promptDelay?: number | null, promptDelay?: number | null,
@ -316,7 +316,7 @@ export class UI extends Phaser.GameObjects.Container {
keyOrText: string, keyOrText: string,
name: string | undefined, name: string | undefined,
delay: number | null = 0, delay: number | null = 0,
callback: Function, callback: () => void,
callbackDelay?: number, callbackDelay?: number,
promptDelay?: number, promptDelay?: number,
): void { ): void {

View File

@ -148,7 +148,7 @@ describe("Abilities - Dry Skin", () => {
const enemy = game.field.getEnemyPokemon(); const enemy = game.field.getEnemyPokemon();
game.move.select(MoveId.WATER_GUN); game.move.select(MoveId.WATER_GUN);
enemy.hp = enemy.hp - 1; enemy.hp -= 1;
await game.phaseInterceptor.to("MoveEffectPhase"); await game.phaseInterceptor.to("MoveEffectPhase");
await game.move.forceMiss(); await game.move.forceMiss();

View File

@ -65,7 +65,7 @@ describe("Abilities - Volt Absorb", () => {
const enemyPokemon = game.field.getEnemyPokemon(); const enemyPokemon = game.field.getEnemyPokemon();
game.move.select(MoveId.THUNDERBOLT); game.move.select(MoveId.THUNDERBOLT);
enemyPokemon.hp = enemyPokemon.hp - 1; enemyPokemon.hp -= 1;
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await game.phaseInterceptor.to("MoveEffectPhase"); await game.phaseInterceptor.to("MoveEffectPhase");
@ -86,7 +86,7 @@ describe("Abilities - Volt Absorb", () => {
const enemyPokemon = game.field.getEnemyPokemon(); const enemyPokemon = game.field.getEnemyPokemon();
game.move.select(MoveId.THUNDERBOLT); game.move.select(MoveId.THUNDERBOLT);
enemyPokemon.hp = enemyPokemon.hp - 1; enemyPokemon.hp -= 1;
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await game.phaseInterceptor.to("BerryPhase", false); await game.phaseInterceptor.to("BerryPhase", false);

View File

@ -2,6 +2,7 @@ import type { MockGameObject } from "#test/test-utils/mocks/mock-game-object";
import type { MockTextureManager } from "#test/test-utils/mocks/mock-texture-manager"; import type { MockTextureManager } from "#test/test-utils/mocks/mock-texture-manager";
import { coerceArray } from "#utils/array"; import { coerceArray } from "#utils/array";
// TODO: Make this implement Phaser.GameObjects.Container
export class MockContainer implements MockGameObject { export class MockContainer implements MockGameObject {
protected x: number; protected x: number;
protected y: number; protected y: number;

View File

@ -82,7 +82,7 @@ export class MockText implements MockGameObject {
showText( showText(
text: string, text: string,
_delay?: number | null, _delay?: number | null,
callback?: Function | null, callback?: (() => void) | null,
_callbackDelay?: number | null, _callbackDelay?: number | null,
_prompt?: boolean | null, _prompt?: boolean | null,
_promptDelay?: number | null, _promptDelay?: number | null,
@ -98,7 +98,7 @@ export class MockText implements MockGameObject {
keyOrText: string, keyOrText: string,
name: string, name: string,
_delay: number | null, _delay: number | null,
callback: Function, callback: () => void,
_callbackDelay?: number, _callbackDelay?: number,
_promptDelay?: number, _promptDelay?: number,
) { ) {
@ -354,7 +354,7 @@ export class MockText implements MockGameObject {
} }
// biome-ignore lint/complexity/noBannedTypes: This matches the signature of the class this mocks // biome-ignore lint/complexity/noBannedTypes: This matches the signature of the class this mocks
on(_event: string | symbol, _fn: Function, _context?: any) {} on(_event: string | symbol, _fn: () => void, _context?: any) {}
setActive(_active: boolean): this { setActive(_active: boolean): this {
return this; return this;