[Dev] Update Biome to 2.0.0 (#6004)

* Run `npm audit fix`

* Update Biome to 2.0.0

* Migrate `biome.jsonc` to 2.0

* Apply Biome and fix some suppression comments

* Fix some suppression comments and update config

* More config updates

Added at "error": `noUnusedLabels`, `noThisInStatic`

Changed `useDefaultParameterLast` from "off" to "warn"

Changed `noDocumentCookie` (from recommended) from "warn" to "off"

Changed `noExcessiveCognitiveComplexity` from "warn" to "info"

* Add a bunch of rules

* Apply Biome safe fixes

* Apply Biome unsafe fixes

* Remove irrelevant `useSelfClosingElements` rule

* Upgrade already followed rules to "error"

* Remove unnecessary type cast

* Disable fixer for `useDefaultParameterLast`

* Disable `useJsonImportAttribute` rule and revert changes

* Fix `mockImage.ts`

* ...there's a `@ts-nocheck` in this file

* Use whole-file lint suppression comment in `version_converter.ts`

* Add a couple comments to `biome.jsonc`

* Remove ESLint packages and GitHub workflow
This commit is contained in:
NightKev 2025-06-20 23:24:11 -07:00 committed by GitHub
parent 9f67e06279
commit 4fc77e4de9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
56 changed files with 309 additions and 2233 deletions

View File

@ -31,9 +31,6 @@ jobs:
- name: Install Node.js dependencies - name: Install Node.js dependencies
run: npm ci run: npm ci
- name: Run ESLint
run: npm run eslint-ci
- name: Lint with Biome - name: Lint with Biome
run: npm run biome-ci run: npm run biome-ci

View File

@ -1,5 +1,5 @@
{ {
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json",
"vcs": { "vcs": {
"enabled": false, "enabled": false,
"clientKind": "git", "clientKind": "git",
@ -10,35 +10,46 @@
"enabled": true, "enabled": true,
"useEditorconfig": true, "useEditorconfig": true,
"indentStyle": "space", "indentStyle": "space",
"ignore": ["src/enums/*", "src/data/balance/*"], "includes": ["**", "!**/src/enums/**/*", "!**/src/data/balance/**/*"],
"lineWidth": 120 "lineWidth": 120
}, },
"files": { "files": {
"ignoreUnknown": true, "ignoreUnknown": true,
// Adding folders to the ignore list is GREAT for performance because it prevents biome from descending into them // Adding folders to the ignore list is GREAT for performance because it prevents biome from descending into them
// and having to verify whether each individual file is ignored // and having to verify whether each individual file is ignored
"ignore": [ "includes": [
"**/*.d.ts", "**",
"dist/*", "!**/*.d.ts",
"build/*", "!**/dist/**/*",
"coverage/*", "!**/build/**/*",
"public/*", "!**/coverage/**/*",
".github/*", "!**/public/**/*",
"node_modules/*", "!**/.github/**/*",
".vscode/*", "!**/node_modules/**/*",
"*.css", // TODO? "!**/.vscode/**/*",
"*.html", // TODO? // TODO: lint css and html?
// TODO: these files are too big and complex, ignore them until their respective refactors "!**/*.css",
"src/data/moves/move.ts", "!**/*.html",
// TODO: enable linting this file
// this file is just too big: "!**/src/data/moves/move.ts",
"src/data/balance/tms.ts" // this file is too big
"!**/src/data/balance/tms.ts"
] ]
}, },
// While it'd be nice to enable consistent sorting, enabling this causes issues due to circular import resolution order // TODO: Configure and enable import sorting
// TODO: Remove if we ever get down to 0 circular imports "assist": {
"organizeImports": { "enabled": false }, "actions": {
"source": {
"organizeImports": {
"level": "off",
"options": {
"groups": []
}
}
}
}
},
"linter": { "linter": {
"enabled": true, "enabled": true,
"rules": { "rules": {
@ -48,10 +59,15 @@
"noUnusedVariables": "error", "noUnusedVariables": "error",
"noSwitchDeclarations": "error", "noSwitchDeclarations": "error",
"noVoidTypeReturn": "error", "noVoidTypeReturn": "error",
"noUnusedImports": "error" "noUnusedImports": {
"level": "error",
"fix": "safe"
},
"noUnusedFunctionParameters": "error",
"noUnusedLabels": "error",
"noPrivateImports": "error"
}, },
"style": { "style": {
"noVar": "error",
"useEnumInitializers": "off", // large enums like Moves/Species would make this cumbersome "useEnumInitializers": "off", // large enums like Moves/Species would make this cumbersome
"useBlockStatements": "error", "useBlockStatements": "error",
"useConst": "error", "useConst": "error",
@ -59,11 +75,31 @@
"noNonNullAssertion": "off", // TODO: Turn this on ASAP and fix all non-null assertions in non-test files "noNonNullAssertion": "off", // TODO: Turn this on ASAP and fix all non-null assertions in non-test files
"noParameterAssign": "off", "noParameterAssign": "off",
"useExponentiationOperator": "off", // Too typo-prone and easy to mixup with standard multiplication (* vs **) "useExponentiationOperator": "off", // Too typo-prone and easy to mixup with standard multiplication (* vs **)
"useDefaultParameterLast": "off", // TODO: Fix spots in the codebase where this flag would be triggered, and then enable "useDefaultParameterLast": {
// TODO: Fix spots in the codebase where this flag would be triggered
// and then set to "error" and re-enable the fixer
"level": "warn",
"fix": "none"
},
"useSingleVarDeclarator": "off", "useSingleVarDeclarator": "off",
"useNodejsImportProtocol": "off", "useNodejsImportProtocol": "off",
"useTemplate": "off", // string concatenation is faster: https://stackoverflow.com/questions/29055518/are-es6-template-literals-faster-than-string-concatenation "useTemplate": "off", // string concatenation is faster: https://stackoverflow.com/questions/29055518/are-es6-template-literals-faster-than-string-concatenation
"noNamespaceImport": "error" "useAsConstAssertion": "error",
"noUnusedTemplateLiteral": "error",
"useNumberNamespace": "error",
"noInferrableTypes": "error",
"noUselessElse": "error",
"noRestrictedTypes": {
"level": "error",
"options": {
"types": {
"integer": {
"message": "This is an alias for 'number' that can provide false impressions of what values can actually be contained in this variable. Use 'number' instead.",
"use": "number"
}
}
}
}
}, },
"suspicious": { "suspicious": {
"noDoubleEquals": "error", "noDoubleEquals": "error",
@ -77,45 +113,62 @@
"noImplicitAnyLet": "warn", // TODO: Refactor and make this an error "noImplicitAnyLet": "warn", // TODO: Refactor and make this an error
"noRedeclare": "info", // TODO: Refactor and make this an error "noRedeclare": "info", // TODO: Refactor and make this an error
"noGlobalIsNan": "off", "noGlobalIsNan": "off",
"noAsyncPromiseExecutor": "warn" // TODO: Refactor and make this an error "noAsyncPromiseExecutor": "warn", // TODO: Refactor and make this an error
"noVar": "error",
"noDocumentCookie": "off" // Firefox has minimal support for the "Cookie Store API"
}, },
"complexity": { "complexity": {
"noExcessiveCognitiveComplexity": "warn", // TODO: Refactor and make this an error "noExcessiveCognitiveComplexity": "info", // TODO: Refactor and make this an error
"useLiteralKeys": "off", "useLiteralKeys": "off",
"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": "warn", // TODO: Refactor and make this an error
"noThisInStatic": "error",
"noUselessThisAlias": "error",
"noUselessTernary": "error"
},
"performance": {
"noNamespaceImport": "error",
"noDelete": "error"
}, },
"nursery": { "nursery": {
"noRestrictedTypes": { "useAdjacentGetterSetter": "error",
"level": "error", "noConstantBinaryExpression": "error",
"options": { "noTsIgnore": "error",
"types": { "noAwaitInLoop": "warn",
"integer": { "useJsonImportAttribute": "off", // "Import attributes are only supported when the '--module' option is set to 'esnext', 'node18', 'nodenext', or 'preserve'. ts(2823)"
"message": "This is an alias for 'number' that can provide false impressions of what values can actually be contained in this variable. Use 'number' instead.", "useIndexOf": "error",
"use": "number" "useObjectSpread": "error",
} "useNumericSeparators": "off", // TODO: enable?
} "useIterableCallbackReturn": "warn", // TODO: refactor and make "error"
} "noShadow": "warn" // TODO: refactor and make "error"
}
} }
} }
}, },
"javascript": { "javascript": {
"formatter": { "quoteStyle": "double", "arrowParentheses": "asNeeded" } "formatter": {
"quoteStyle": "double",
"arrowParentheses": "asNeeded"
},
"parser": {
"jsxEverywhere": false
}
}, },
"overrides": [ "overrides": [
{ {
"include": ["test/**/*.test.ts"], "includes": ["**/test/**/*.test.ts"],
"javascript": { "globals": [] },
"linter": { "linter": {
"rules": { "rules": {
"performance": { "performance": {
"noDelete": "off" // TODO: evaluate if this is necessary for the test(s) to function "noDelete": "off", // TODO: evaluate if this is necessary for the test(s) to function
"noNamespaceImport": "off" // this is required for `vi.spyOn` to work in some tests
}, },
"style": { "style": {
"noNamespaceImport": "off" // this is required for `vi.spyOn` to work in some tests "noNonNullAssertion": "off"
},
"nursery": {
"noFloatingPromises": "error"
} }
} }
} }
@ -123,7 +176,7 @@
// Overrides to prevent unused import removal inside `overrides.ts` and enums files (for TSDoc linkcodes) // Overrides to prevent unused import removal inside `overrides.ts` and enums files (for TSDoc linkcodes)
{ {
"include": ["src/overrides.ts", "src/enums/*"], "includes": ["**/src/overrides.ts", "**/src/enums/**/*"],
"linter": { "linter": {
"rules": { "rules": {
"correctness": { "correctness": {
@ -133,7 +186,7 @@
} }
}, },
{ {
"include": ["src/overrides.ts"], "includes": ["**/src/overrides.ts"],
"linter": { "linter": {
"rules": { "rules": {
"style": { "style": {

View File

@ -1,43 +0,0 @@
/** @ts-check */
import tseslint from "typescript-eslint";
import stylisticTs from "@stylistic/eslint-plugin-ts";
import parser from "@typescript-eslint/parser";
import importX from "eslint-plugin-import-x";
export default tseslint.config(
{
name: "eslint-config",
files: ["src/**/*.{ts,tsx,js,jsx}", "test/**/*.{ts,tsx,js,jsx}"],
ignores: ["dist/*", "build/*", "coverage/*", "public/*", ".github/*", "node_modules/*", ".vscode/*"],
languageOptions: {
parser: parser,
},
plugins: {
"import-x": importX,
"@stylistic/ts": stylisticTs,
"@typescript-eslint": tseslint.plugin,
},
rules: {
"no-undef": "off", // Disables the rule that disallows the use of undeclared variables (TypeScript handles this)
"no-extra-semi": "error", // Disallows unnecessary semicolons for TypeScript-specific syntax
"import-x/extensions": ["error", "never", { json: "always" }], // Enforces no extension for imports unless json
},
},
{
name: "eslint-tests",
files: ["test/**/**.test.ts"],
languageOptions: {
parser: parser,
parserOptions: {
project: ["./tsconfig.json"],
},
},
plugins: {
"@typescript-eslint": tseslint.plugin,
},
rules: {
"@typescript-eslint/no-floating-promises": "error", // Require Promise-like statements to be handled appropriately. - https://typescript-eslint.io/rules/no-floating-promises/
"@typescript-eslint/no-misused-promises": "error", // Disallow Promises in places not designed to handle them. - https://typescript-eslint.io/rules/no-misused-promises/
},
},
);

2053
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -28,18 +28,12 @@
"update-locales:remote": "git submodule update --progress --init --recursive --force --remote" "update-locales:remote": "git submodule update --progress --init --recursive --force --remote"
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "1.9.4", "@biomejs/biome": "2.0.0",
"@eslint/js": "^9.23.0",
"@hpcc-js/wasm": "^2.22.4", "@hpcc-js/wasm": "^2.22.4",
"@stylistic/eslint-plugin-ts": "^4.1.0",
"@types/jsdom": "^21.1.7", "@types/jsdom": "^21.1.7",
"@types/node": "^22.13.14", "@types/node": "^22.13.14",
"@typescript-eslint/eslint-plugin": "^8.28.0",
"@typescript-eslint/parser": "^8.28.0",
"@vitest/coverage-istanbul": "^3.0.9", "@vitest/coverage-istanbul": "^3.0.9",
"dependency-cruiser": "^16.3.10", "dependency-cruiser": "^16.3.10",
"eslint": "^9.23.0",
"eslint-plugin-import-x": "^4.9.4",
"inquirer": "^12.4.2", "inquirer": "^12.4.2",
"jsdom": "^26.0.0", "jsdom": "^26.0.0",
"lefthook": "^1.11.5", "lefthook": "^1.11.5",
@ -47,7 +41,6 @@
"phaser3spectorjs": "^0.0.8", "phaser3spectorjs": "^0.0.8",
"typedoc": "^0.28.1", "typedoc": "^0.28.1",
"typescript": "^5.8.2", "typescript": "^5.8.2",
"typescript-eslint": "^8.28.0",
"vite": "^6.3.4", "vite": "^6.3.4",
"vite-tsconfig-paths": "^5.1.4", "vite-tsconfig-paths": "^5.1.4",
"vitest": "^3.0.9", "vitest": "^3.0.9",

View File

@ -468,7 +468,7 @@ export default class BattleScene extends SceneBase {
true, true,
); );
//@ts-ignore (the defined types in the package are incromplete...) //@ts-expect-error (the defined types in the package are incromplete...)
transition.transit({ transition.transit({
mode: "blinds", mode: "blinds",
ease: "Cubic.easeInOut", ease: "Cubic.easeInOut",
@ -1167,7 +1167,7 @@ export default class BattleScene extends SceneBase {
this.field.remove(this.currentBattle.mysteryEncounter?.introVisuals, true); this.field.remove(this.currentBattle.mysteryEncounter?.introVisuals, true);
} }
//@ts-ignore - allowing `null` for currentBattle causes a lot of trouble //@ts-expect-error - allowing `null` for currentBattle causes a lot of trouble
this.currentBattle = null; // TODO: resolve ts-ignore this.currentBattle = null; // TODO: resolve ts-ignore
// Reset RNG after end of game or save & quit. // Reset RNG after end of game or save & quit.
@ -3237,7 +3237,7 @@ export default class BattleScene extends SceneBase {
(!this.gameData.achvUnlocks.hasOwnProperty(achv.id) || Overrides.ACHIEVEMENTS_REUNLOCK_OVERRIDE) && (!this.gameData.achvUnlocks.hasOwnProperty(achv.id) || Overrides.ACHIEVEMENTS_REUNLOCK_OVERRIDE) &&
achv.validate(args) achv.validate(args)
) { ) {
this.gameData.achvUnlocks[achv.id] = new Date().getTime(); this.gameData.achvUnlocks[achv.id] = Date.now();
this.ui.achvBar.showAchv(achv); this.ui.achvBar.showAchv(achv);
if (vouchers.hasOwnProperty(achv.id)) { if (vouchers.hasOwnProperty(achv.id)) {
this.validateVoucher(vouchers[achv.id]); this.validateVoucher(vouchers[achv.id]);
@ -3250,7 +3250,7 @@ export default class BattleScene extends SceneBase {
validateVoucher(voucher: Voucher, args?: unknown[]): boolean { validateVoucher(voucher: Voucher, args?: unknown[]): boolean {
if (!this.gameData.voucherUnlocks.hasOwnProperty(voucher.id) && voucher.validate(args)) { if (!this.gameData.voucherUnlocks.hasOwnProperty(voucher.id) && voucher.validate(args)) {
this.gameData.voucherUnlocks[voucher.id] = new Date().getTime(); this.gameData.voucherUnlocks[voucher.id] = Date.now();
this.ui.achvBar.showAchv(voucher); this.ui.achvBar.showAchv(voucher);
this.gameData.voucherCounts[voucher.voucherType]++; this.gameData.voucherCounts[voucher.voucherType]++;
return true; return true;

View File

@ -178,7 +178,7 @@ export default class Battle {
) )
.map(i => { .map(i => {
const ret = i as PokemonHeldItemModifier; const ret = i as PokemonHeldItemModifier;
//@ts-ignore - this is awful to fix/change //@ts-expect-error - this is awful to fix/change
ret.pokemonId = null; ret.pokemonId = null;
return ret; return ret;
}), }),

View File

@ -595,13 +595,13 @@ function parseEggMoves(content: string): void {
const cols = line.split(",").slice(0, 5); const cols = line.split(",").slice(0, 5);
const moveNames = allMoves.map(m => m.name.replace(/ \([A-Z]\)$/, "").toLowerCase()); const moveNames = allMoves.map(m => m.name.replace(/ \([A-Z]\)$/, "").toLowerCase());
const enumSpeciesName = cols[0].toUpperCase().replace(/[ -]/g, "_"); const enumSpeciesName = cols[0].toUpperCase().replace(/[ -]/g, "_");
const species = speciesValues[speciesNames.findIndex(s => s === enumSpeciesName)]; const species = speciesValues[speciesNames.indexOf(enumSpeciesName)];
const eggMoves: MoveId[] = []; const eggMoves: MoveId[] = [];
for (let m = 0; m < 4; m++) { for (let m = 0; m < 4; m++) {
const moveName = cols[m + 1].trim(); const moveName = cols[m + 1].trim();
const moveIndex = moveName !== "N/A" ? moveNames.findIndex(mn => mn === moveName.toLowerCase()) : -1; const moveIndex = moveName !== "N/A" ? moveNames.indexOf(moveName.toLowerCase()) : -1;
eggMoves.push(moveIndex > -1 ? moveIndex as MoveId : MoveId.NONE); eggMoves.push(moveIndex > -1 ? moveIndex as MoveId : MoveId.NONE);
if (moveIndex === -1) { if (moveIndex === -1) {

View File

@ -346,7 +346,7 @@ abstract class AnimTimedBgEvent extends AnimTimedEvent {
} }
class AnimTimedUpdateBgEvent extends AnimTimedBgEvent { class AnimTimedUpdateBgEvent extends AnimTimedBgEvent {
// biome-ignore lint/correctness/noUnusedVariables: seems intentional // biome-ignore lint/correctness/noUnusedFunctionParameters: seems intentional
execute(moveAnim: MoveAnim, priority?: number): number { execute(moveAnim: MoveAnim, priority?: number): number {
const tweenProps = {}; const tweenProps = {};
if (this.bgX !== undefined) { if (this.bgX !== undefined) {
@ -359,15 +359,11 @@ class AnimTimedUpdateBgEvent extends AnimTimedBgEvent {
tweenProps["alpha"] = (this.opacity || 0) / 255; tweenProps["alpha"] = (this.opacity || 0) / 255;
} }
if (Object.keys(tweenProps).length) { if (Object.keys(tweenProps).length) {
globalScene.tweens.add( globalScene.tweens.add({
Object.assign( targets: moveAnim.bgSprite,
{ duration: getFrameMs(this.duration * 3),
targets: moveAnim.bgSprite, ...tweenProps,
duration: getFrameMs(this.duration * 3), });
},
tweenProps,
),
);
} }
return this.duration * 2; return this.duration * 2;
} }
@ -423,7 +419,7 @@ export function initCommonAnims(): Promise<void> {
const commonAnimId = commonAnimIds[ca]; const commonAnimId = commonAnimIds[ca];
commonAnimFetches.push( commonAnimFetches.push(
globalScene globalScene
.cachedFetch(`./battle-anims/common-${commonAnimNames[ca].toLowerCase().replace(/\_/g, "-")}.json`) .cachedFetch(`./battle-anims/common-${commonAnimNames[ca].toLowerCase().replace(/_/g, "-")}.json`)
.then(response => response.json()) .then(response => response.json())
.then(cas => commonAnims.set(commonAnimId, new AnimConfig(cas))), .then(cas => commonAnims.set(commonAnimId, new AnimConfig(cas))),
); );
@ -535,7 +531,7 @@ export async function initEncounterAnims(encounterAnim: EncounterAnim | Encounte
} }
encounterAnimFetches.push( encounterAnimFetches.push(
globalScene globalScene
.cachedFetch(`./battle-anims/encounter-${encounterAnimNames[anim].toLowerCase().replace(/\_/g, "-")}.json`) .cachedFetch(`./battle-anims/encounter-${encounterAnimNames[anim].toLowerCase().replace(/_/g, "-")}.json`)
.then(response => response.json()) .then(response => response.json())
.then(cas => encounterAnims.set(anim, new AnimConfig(cas))), .then(cas => encounterAnims.set(anim, new AnimConfig(cas))),
); );
@ -559,7 +555,7 @@ export function initMoveChargeAnim(chargeAnim: ChargeAnim): Promise<void> {
} else { } else {
chargeAnims.set(chargeAnim, null); chargeAnims.set(chargeAnim, null);
globalScene globalScene
.cachedFetch(`./battle-anims/${ChargeAnim[chargeAnim].toLowerCase().replace(/\_/g, "-")}.json`) .cachedFetch(`./battle-anims/${ChargeAnim[chargeAnim].toLowerCase().replace(/_/g, "-")}.json`)
.then(response => response.json()) .then(response => response.json())
.then(ca => { .then(ca => {
if (Array.isArray(ca)) { if (Array.isArray(ca)) {
@ -1405,15 +1401,15 @@ export class EncounterBattleAnim extends BattleAnim {
export async function populateAnims() { export async function populateAnims() {
const commonAnimNames = getEnumKeys(CommonAnim).map(k => k.toLowerCase()); const commonAnimNames = getEnumKeys(CommonAnim).map(k => k.toLowerCase());
const commonAnimMatchNames = commonAnimNames.map(k => k.replace(/\_/g, "")); const commonAnimMatchNames = commonAnimNames.map(k => k.replace(/_/g, ""));
const commonAnimIds = getEnumValues(CommonAnim) as CommonAnim[]; const commonAnimIds = getEnumValues(CommonAnim) as CommonAnim[];
const chargeAnimNames = getEnumKeys(ChargeAnim).map(k => k.toLowerCase()); const chargeAnimNames = getEnumKeys(ChargeAnim).map(k => k.toLowerCase());
const chargeAnimMatchNames = chargeAnimNames.map(k => k.replace(/\_/g, " ")); const chargeAnimMatchNames = chargeAnimNames.map(k => k.replace(/_/g, " "));
const chargeAnimIds = getEnumValues(ChargeAnim) as ChargeAnim[]; const chargeAnimIds = getEnumValues(ChargeAnim) as ChargeAnim[];
const commonNamePattern = /name: (?:Common:)?(Opp )?(.*)/; const commonNamePattern = /name: (?:Common:)?(Opp )?(.*)/;
const moveNameToId = {}; const moveNameToId = {};
for (const move of getEnumValues(MoveId).slice(1)) { for (const move of getEnumValues(MoveId).slice(1)) {
const moveName = MoveId[move].toUpperCase().replace(/\_/g, ""); const moveName = MoveId[move].toUpperCase().replace(/_/g, "");
moveNameToId[moveName] = move; moveNameToId[moveName] = move;
} }
@ -1469,7 +1465,7 @@ export async function populateAnims() {
const frameData = framesData[fd]; const frameData = framesData[fd];
const focusFramesData = frameData.split(" - - "); const focusFramesData = frameData.split(" - - ");
for (let tf = 0; tf < focusFramesData.length; tf++) { for (let tf = 0; tf < focusFramesData.length; tf++) {
const values = focusFramesData[tf].replace(/ {6}\- /g, "").split("\n"); const values = focusFramesData[tf].replace(/ {6}- /g, "").split("\n");
const targetFrame = new AnimFrame( const targetFrame = new AnimFrame(
Number.parseFloat(values[0]), Number.parseFloat(values[0]),
Number.parseFloat(values[1]), Number.parseFloat(values[1]),
@ -1516,7 +1512,7 @@ export async function populateAnims() {
.replace(/[a-z]+: ! '', /gi, "") .replace(/[a-z]+: ! '', /gi, "")
.replace(/name: (.*?),/, 'name: "$1",') .replace(/name: (.*?),/, 'name: "$1",')
.replace( .replace(
/flashColor: !ruby\/object:Color { alpha: ([\d\.]+), blue: ([\d\.]+), green: ([\d\.]+), red: ([\d\.]+)}/, /flashColor: !ruby\/object:Color { alpha: ([\d.]+), blue: ([\d.]+), green: ([\d.]+), red: ([\d.]+)}/,
"flashRed: $4, flashGreen: $3, flashBlue: $2, flashAlpha: $1", "flashRed: $4, flashGreen: $3, flashBlue: $2, flashAlpha: $1",
); );
const frameIndex = Number.parseInt(/frame: (\d+)/.exec(timingData)![1]); // TODO: is the bang correct? const frameIndex = Number.parseInt(/frame: (\d+)/.exec(timingData)![1]); // TODO: is the bang correct?
@ -1641,12 +1637,12 @@ export async function populateAnims() {
let props: string[]; let props: string[];
for (let p = 0; p < propSets.length; p++) { for (let p = 0; p < propSets.length; p++) {
props = propSets[p]; props = propSets[p];
// @ts-ignore TODO // @ts-expect-error TODO
const ai = props.indexOf(a.key); const ai = props.indexOf(a.key);
if (ai === -1) { if (ai === -1) {
continue; continue;
} }
// @ts-ignore TODO // @ts-expect-error TODO
const bi = props.indexOf(b.key); const bi = props.indexOf(b.key);
return ai < bi ? -1 : ai > bi ? 1 : 0; return ai < bi ? -1 : ai > bi ? 1 : 0;

View File

@ -175,7 +175,7 @@ export class Egg {
this._sourceType = eggOptions?.sourceType ?? undefined; this._sourceType = eggOptions?.sourceType ?? undefined;
this._hatchWaves = eggOptions?.hatchWaves ?? this.getEggTierDefaultHatchWaves(); this._hatchWaves = eggOptions?.hatchWaves ?? this.getEggTierDefaultHatchWaves();
this._timestamp = eggOptions?.timestamp ?? new Date().getTime(); this._timestamp = eggOptions?.timestamp ?? Date.now();
// First roll shiny and variant so we can filter if species with an variant exist // First roll shiny and variant so we can filter if species with an variant exist
this._isShiny = eggOptions?.isShiny ?? (Overrides.EGG_SHINY_OVERRIDE || this.rollShiny()); this._isShiny = eggOptions?.isShiny ?? (Overrides.EGG_SHINY_OVERRIDE || this.rollShiny());
@ -255,7 +255,7 @@ export class Egg {
// Sets the hidden ability if a hidden ability exists and // Sets the hidden ability if a hidden ability exists and
// the override is set or the egg hits the chance // the override is set or the egg hits the chance
let abilityIndex: number | undefined = undefined; let abilityIndex: number | undefined;
const sameSpeciesEggHACheck = const sameSpeciesEggHACheck =
this._sourceType === EggSourceType.SAME_SPECIES_EGG && !randSeedInt(SAME_SPECIES_EGG_HA_RATE); this._sourceType === EggSourceType.SAME_SPECIES_EGG && !randSeedInt(SAME_SPECIES_EGG_HA_RATE);
const gachaEggHACheck = !(this._sourceType === EggSourceType.SAME_SPECIES_EGG) && !randSeedInt(GACHA_EGG_HA_RATE); const gachaEggHACheck = !(this._sourceType === EggSourceType.SAME_SPECIES_EGG) && !randSeedInt(GACHA_EGG_HA_RATE);
@ -524,7 +524,7 @@ export class Egg {
/** /**
* Rolls whether the egg is shiny or not. * Rolls whether the egg is shiny or not.
* @returns `true` if the egg is shiny * @returns `true` if the egg is shiny
**/ */
private rollShiny(): boolean { private rollShiny(): boolean {
let shinyChance = GACHA_DEFAULT_SHINY_RATE; let shinyChance = GACHA_DEFAULT_SHINY_RATE;
switch (this._sourceType) { switch (this._sourceType) {

View File

@ -16,7 +16,7 @@ import type Move from "./move";
* @see {@linkcode getMovePp} - returns amount of PP a move currently has. * @see {@linkcode getMovePp} - returns amount of PP a move currently has.
* @see {@linkcode getPpRatio} - returns the current PP amount / max PP amount. * @see {@linkcode getPpRatio} - returns the current PP amount / max PP amount.
* @see {@linkcode getName} - returns name of {@linkcode Move}. * @see {@linkcode getName} - returns name of {@linkcode Move}.
**/ */
export class PokemonMove { export class PokemonMove {
public moveId: MoveId; public moveId: MoveId;
public ppUsed: number; public ppUsed: number;

View File

@ -135,7 +135,7 @@ export const ClowningAroundEncounter: MysteryEncounter = MysteryEncounterBuilder
); );
clownConfig.setPartyTemplates(clownPartyTemplate); clownConfig.setPartyTemplates(clownPartyTemplate);
clownConfig.setDoubleOnly(); clownConfig.setDoubleOnly();
// @ts-ignore // @ts-expect-error
clownConfig.partyTemplateFunc = null; // Overrides party template func if it exists clownConfig.partyTemplateFunc = null; // Overrides party template func if it exists
// Generate random ability for Blacephalon from pool // Generate random ability for Blacephalon from pool

View File

@ -92,7 +92,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = MysteryEncounter
const brutalConfig = trainerConfigs[brutalTrainerType].clone(); const brutalConfig = trainerConfigs[brutalTrainerType].clone();
brutalConfig.title = trainerConfigs[brutalTrainerType].title; brutalConfig.title = trainerConfigs[brutalTrainerType].title;
brutalConfig.setPartyTemplates(e4Template); brutalConfig.setPartyTemplates(e4Template);
// @ts-ignore // @ts-expect-error
brutalConfig.partyTemplateFunc = null; // Overrides gym leader party template func brutalConfig.partyTemplateFunc = null; // Overrides gym leader party template func
female = false; female = false;
if (brutalConfig.hasGenders) { if (brutalConfig.hasGenders) {

View File

@ -1226,7 +1226,7 @@ export function calculateMEAggregateStats(baseSpawnWeight: number) {
); );
for (const value of meanEncountersPerRunPerBiomeSorted) { for (const value of meanEncountersPerRunPerBiomeSorted) {
stats += value[0] + "avg valid floors " + meanMEFloorsPerRunPerBiome.get(value[0]) + ", avg MEs ${value[1]},\n"; stats += value[0] + "avg valid floors " + meanMEFloorsPerRunPerBiome.get(value[0]) + `, avg MEs ${value[1]},\n`;
} }
console.log(stats); console.log(stats);

View File

@ -96,8 +96,8 @@ export function getPokemonSpeciesForm(species: SpeciesId, formIndex: number): Po
} }
export function getFusedSpeciesName(speciesAName: string, speciesBName: string): string { export function getFusedSpeciesName(speciesAName: string, speciesBName: string): string {
const fragAPattern = /([a-z]{2}.*?[aeiou(?:y$)\-\']+)(.*?)$/i; const fragAPattern = /([a-z]{2}.*?[aeiou(?:y$)\-']+)(.*?)$/i;
const fragBPattern = /([a-z]{2}.*?[aeiou(?:y$)\-\'])(.*?)$/i; const fragBPattern = /([a-z]{2}.*?[aeiou(?:y$)\-'])(.*?)$/i;
const [speciesAPrefixMatch, speciesBPrefixMatch] = [speciesAName, speciesBName].map(n => /^(?:[^ ]+) /.exec(n)); const [speciesAPrefixMatch, speciesBPrefixMatch] = [speciesAName, speciesBName].map(n => /^(?:[^ ]+) /.exec(n));
const [speciesAPrefix, speciesBPrefix] = [speciesAPrefixMatch, speciesBPrefixMatch].map(m => (m ? m[0] : "")); const [speciesAPrefix, speciesBPrefix] = [speciesAPrefixMatch, speciesBPrefixMatch].map(m => (m ? m[0] : ""));
@ -134,7 +134,7 @@ export function getFusedSpeciesName(speciesAName: string, speciesBName: string):
if (fragBMatch) { if (fragBMatch) {
const lastCharA = fragA.slice(fragA.length - 1); const lastCharA = fragA.slice(fragA.length - 1);
const prevCharB = fragBMatch[1].slice(fragBMatch.length - 1); const prevCharB = fragBMatch[1].slice(fragBMatch.length - 1);
fragB = (/[\-']/.test(prevCharB) ? prevCharB : "") + fragBMatch[2] || prevCharB; fragB = (/[-']/.test(prevCharB) ? prevCharB : "") + fragBMatch[2] || prevCharB;
if (lastCharA === fragB[0]) { if (lastCharA === fragB[0]) {
if (/[aiu]/.test(lastCharA)) { if (/[aiu]/.test(lastCharA)) {
fragB = fragB.slice(1); fragB = fragB.slice(1);
@ -379,7 +379,7 @@ export abstract class PokemonSpeciesForm {
} }
getSpriteAtlasPath(female: boolean, formIndex?: number, shiny?: boolean, variant?: number, back?: boolean): string { getSpriteAtlasPath(female: boolean, formIndex?: number, shiny?: boolean, variant?: number, back?: boolean): string {
const spriteId = this.getSpriteId(female, formIndex, shiny, variant, back).replace(/\_{2}/g, "/"); const spriteId = this.getSpriteId(female, formIndex, shiny, variant, back).replace(/_{2}/g, "/");
return `${/_[1-3]$/.test(spriteId) ? "variant/" : ""}${spriteId}`; return `${/_[1-3]$/.test(spriteId) ? "variant/" : ""}${spriteId}`;
} }
@ -478,8 +478,8 @@ export abstract class PokemonSpeciesForm {
case SpeciesId.DUDUNSPARCE: case SpeciesId.DUDUNSPARCE:
break; break;
case SpeciesId.ZACIAN: case SpeciesId.ZACIAN:
// biome-ignore lint/suspicious/noFallthroughSwitchClause: Intentionally falls through
case SpeciesId.ZAMAZENTA: case SpeciesId.ZAMAZENTA:
// biome-ignore lint/suspicious/noFallthroughSwitchClause: Falls through
if (formSpriteKey.startsWith("behemoth")) { if (formSpriteKey.startsWith("behemoth")) {
formSpriteKey = "crowned"; formSpriteKey = "crowned";
} }
@ -569,7 +569,7 @@ export abstract class PokemonSpeciesForm {
const rootSpeciesId = this.getRootSpeciesId(); const rootSpeciesId = this.getRootSpeciesId();
for (const moveId of moveset) { for (const moveId of moveset) {
if (speciesEggMoves.hasOwnProperty(rootSpeciesId)) { if (speciesEggMoves.hasOwnProperty(rootSpeciesId)) {
const eggMoveIndex = speciesEggMoves[rootSpeciesId].findIndex(m => m === moveId); const eggMoveIndex = speciesEggMoves[rootSpeciesId].indexOf(moveId);
if (eggMoveIndex > -1 && eggMoves & (1 << eggMoveIndex)) { if (eggMoveIndex > -1 && eggMoves & (1 << eggMoveIndex)) {
continue; continue;
} }

View File

@ -290,7 +290,7 @@ export class TrainerConfig {
* @param {string} [nameFemale] The name of the female trainer. If 'Ivy', a localized name will be assigned. * @param {string} [nameFemale] The name of the female trainer. If 'Ivy', a localized name will be assigned.
* @param {TrainerType | string} [femaleEncounterBgm] The encounter BGM for the female trainer, which can be a TrainerType or a string. * @param {TrainerType | string} [femaleEncounterBgm] The encounter BGM for the female trainer, which can be a TrainerType or a string.
* @returns {TrainerConfig} The updated TrainerConfig instance. * @returns {TrainerConfig} The updated TrainerConfig instance.
**/ */
setHasGenders(nameFemale?: string, femaleEncounterBgm?: TrainerType | string): TrainerConfig { setHasGenders(nameFemale?: string, femaleEncounterBgm?: TrainerType | string): TrainerConfig {
// If the female name is 'Ivy' (the rival), assign a localized name. // If the female name is 'Ivy' (the rival), assign a localized name.
if (nameFemale === "Ivy") { if (nameFemale === "Ivy") {
@ -335,7 +335,7 @@ export class TrainerConfig {
if (doubleEncounterBgm) { if (doubleEncounterBgm) {
this.doubleEncounterBgm = this.doubleEncounterBgm =
typeof doubleEncounterBgm === "number" typeof doubleEncounterBgm === "number"
? TrainerType[doubleEncounterBgm].toString().replace(/\_/g, " ").toLowerCase() ? TrainerType[doubleEncounterBgm].toString().replace(/_/g, " ").toLowerCase()
: doubleEncounterBgm; : doubleEncounterBgm;
} }
return this; return this;
@ -540,7 +540,7 @@ export class TrainerConfig {
* @param {SpeciesId | SpeciesId[]} signatureSpecies The signature species for the evil team leader. * @param {SpeciesId | SpeciesId[]} signatureSpecies The signature species for the evil team leader.
* @param specialtyType The specialty Type of the admin, if they have one * @param specialtyType The specialty Type of the admin, if they have one
* @returns {TrainerConfig} The updated TrainerConfig instance. * @returns {TrainerConfig} The updated TrainerConfig instance.
* **/ */
initForEvilTeamAdmin( initForEvilTeamAdmin(
title: string, title: string,
poolName: EvilTeam, poolName: EvilTeam,
@ -581,7 +581,7 @@ export class TrainerConfig {
* Initializes the trainer configuration for a Stat Trainer, as part of the Trainer's Test Mystery Encounter. * Initializes the trainer configuration for a Stat Trainer, as part of the Trainer's Test Mystery Encounter.
* @param _isMale Whether the stat trainer is Male or Female (for localization of the title). * @param _isMale Whether the stat trainer is Male or Female (for localization of the title).
* @returns {TrainerConfig} The updated TrainerConfig instance. * @returns {TrainerConfig} The updated TrainerConfig instance.
**/ */
initForStatTrainer(_isMale = false): TrainerConfig { initForStatTrainer(_isMale = false): TrainerConfig {
if (!getIsInitialized()) { if (!getIsInitialized()) {
initI18n(); initI18n();
@ -608,7 +608,7 @@ export class TrainerConfig {
* @param {PokemonType} specialtyType The specialty type for the evil team Leader. * @param {PokemonType} specialtyType The specialty type for the evil team Leader.
* @param boolean Whether or not this is the rematch fight * @param boolean Whether or not this is the rematch fight
* @returns {TrainerConfig} The updated TrainerConfig instance. * @returns {TrainerConfig} The updated TrainerConfig instance.
* **/ */
initForEvilTeamLeader( initForEvilTeamLeader(
title: string, title: string,
signatureSpecies: (SpeciesId | SpeciesId[])[], signatureSpecies: (SpeciesId | SpeciesId[])[],
@ -651,7 +651,7 @@ export class TrainerConfig {
* @param ignoreMinTeraWave Whether the Gym Leader always uses Tera (true), or only Teras after {@linkcode GYM_LEADER_TERA_WAVE} (false). Defaults to false. * @param ignoreMinTeraWave Whether the Gym Leader always uses Tera (true), or only Teras after {@linkcode GYM_LEADER_TERA_WAVE} (false). Defaults to false.
* @param teraSlot Optional, sets the party member in this slot to Terastallize. Wraps based on party size. * @param teraSlot Optional, sets the party member in this slot to Terastallize. Wraps based on party size.
* @returns {TrainerConfig} The updated TrainerConfig instance. * @returns {TrainerConfig} The updated TrainerConfig instance.
* **/ */
initForGymLeader( initForGymLeader(
signatureSpecies: (SpeciesId | SpeciesId[])[], signatureSpecies: (SpeciesId | SpeciesId[])[],
isMale: boolean, isMale: boolean,
@ -709,7 +709,7 @@ export class TrainerConfig {
* @param specialtyType - The specialty type for the Elite Four member. * @param specialtyType - The specialty type for the Elite Four member.
* @param teraSlot - Optional, sets the party member in this slot to Terastallize. * @param teraSlot - Optional, sets the party member in this slot to Terastallize.
* @returns The updated TrainerConfig instance. * @returns The updated TrainerConfig instance.
**/ */
initForEliteFour( initForEliteFour(
signatureSpecies: (SpeciesId | SpeciesId[])[], signatureSpecies: (SpeciesId | SpeciesId[])[],
isMale: boolean, isMale: boolean,
@ -765,7 +765,7 @@ export class TrainerConfig {
* @param {SpeciesId | SpeciesId[]} signatureSpecies The signature species for the Champion. * @param {SpeciesId | SpeciesId[]} signatureSpecies The signature species for the Champion.
* @param isMale Whether the Champion is Male or Female (for localization of the title). * @param isMale Whether the Champion is Male or Female (for localization of the title).
* @returns {TrainerConfig} The updated TrainerConfig instance. * @returns {TrainerConfig} The updated TrainerConfig instance.
**/ */
initForChampion(isMale: boolean): TrainerConfig { initForChampion(isMale: boolean): TrainerConfig {
// Check if the internationalization (i18n) system is initialized. // Check if the internationalization (i18n) system is initialized.
if (!getIsInitialized()) { if (!getIsInitialized()) {
@ -815,7 +815,7 @@ export class TrainerConfig {
* @param {TrainerSlot} trainerSlot - The slot to determine which title to use. Defaults to TrainerSlot.NONE. * @param {TrainerSlot} trainerSlot - The slot to determine which title to use. Defaults to TrainerSlot.NONE.
* @param {TrainerVariant} variant - The variant of the trainer to determine the specific title. * @param {TrainerVariant} variant - The variant of the trainer to determine the specific title.
* @returns {string} - The title of the trainer. * @returns {string} - The title of the trainer.
**/ */
getTitle(trainerSlot: TrainerSlot = TrainerSlot.NONE, variant: TrainerVariant): string { getTitle(trainerSlot: TrainerSlot = TrainerSlot.NONE, variant: TrainerVariant): string {
const ret = this.name; const ret = this.name;

View File

@ -898,12 +898,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
getSpriteAtlasPath(ignoreOverride?: boolean): string { getSpriteAtlasPath(ignoreOverride?: boolean): string {
const spriteId = this.getSpriteId(ignoreOverride).replace(/\_{2}/g, "/"); const spriteId = this.getSpriteId(ignoreOverride).replace(/_{2}/g, "/");
return `${/_[1-3]$/.test(spriteId) ? "variant/" : ""}${spriteId}`; return `${/_[1-3]$/.test(spriteId) ? "variant/" : ""}${spriteId}`;
} }
getBattleSpriteAtlasPath(back?: boolean, ignoreOverride?: boolean): string { getBattleSpriteAtlasPath(back?: boolean, ignoreOverride?: boolean): string {
const spriteId = this.getBattleSpriteId(back, ignoreOverride).replace(/\_{2}/g, "/"); const spriteId = this.getBattleSpriteId(back, ignoreOverride).replace(/_{2}/g, "/");
return `${/_[1-3]$/.test(spriteId) ? "variant/" : ""}${spriteId}`; return `${/_[1-3]$/.test(spriteId) ? "variant/" : ""}${spriteId}`;
} }
@ -977,7 +977,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
getFusionBattleSpriteAtlasPath(back?: boolean, ignoreOverride?: boolean): string { getFusionBattleSpriteAtlasPath(back?: boolean, ignoreOverride?: boolean): string {
return this.getFusionBattleSpriteId(back, ignoreOverride).replace(/\_{2}/g, "/"); return this.getFusionBattleSpriteId(back, ignoreOverride).replace(/_{2}/g, "/");
} }
getIconAtlasKey(ignoreOverride = false, useIllusion = true): string { getIconAtlasKey(ignoreOverride = false, useIllusion = true): string {
@ -2905,7 +2905,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
); );
}; };
let fusionOverride: PokemonSpecies | undefined = undefined; let fusionOverride: PokemonSpecies | undefined;
if (forStarter && this.isPlayer() && Overrides.STARTER_FUSION_SPECIES_OVERRIDE) { if (forStarter && this.isPlayer() && Overrides.STARTER_FUSION_SPECIES_OVERRIDE) {
fusionOverride = getPokemonSpecies(Overrides.STARTER_FUSION_SPECIES_OVERRIDE); fusionOverride = getPokemonSpecies(Overrides.STARTER_FUSION_SPECIES_OVERRIDE);
@ -4398,9 +4398,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
scene.time.delayedCall(fixedInt(Math.ceil(duration * 0.4)), () => { scene.time.delayedCall(fixedInt(Math.ceil(duration * 0.4)), () => {
try { try {
SoundFade.fadeOut(scene, cry, fixedInt(Math.ceil(duration * 0.2))); SoundFade.fadeOut(scene, cry, fixedInt(Math.ceil(duration * 0.2)));
fusionCry = this.getFusionSpeciesForm(undefined, true).cry( fusionCry = this.getFusionSpeciesForm(undefined, true).cry({
Object.assign({ seek: Math.max(fusionCry.totalDuration * 0.4, 0) }, soundConfig), seek: Math.max(fusionCry.totalDuration * 0.4, 0),
); ...soundConfig,
});
SoundFade.fadeIn( SoundFade.fadeIn(
scene, scene,
fusionCry, fusionCry,
@ -4542,13 +4543,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
if (i === transitionIndex && fusionCryKey) { if (i === transitionIndex && fusionCryKey) {
SoundFade.fadeOut(globalScene, cry, fixedInt(Math.ceil((duration / rate) * 0.2))); SoundFade.fadeOut(globalScene, cry, fixedInt(Math.ceil((duration / rate) * 0.2)));
fusionCry = globalScene.playSound( fusionCry = globalScene.playSound(fusionCryKey, {
fusionCryKey, seek: Math.max(fusionCry.totalDuration * 0.4, 0),
Object.assign({ rate: rate,
seek: Math.max(fusionCry.totalDuration * 0.4, 0), });
rate: rate,
}),
);
SoundFade.fadeIn( SoundFade.fadeIn(
globalScene, globalScene,
fusionCry, fusionCry,
@ -5341,10 +5339,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
for (let sc = 0; sc < spriteColors.length; sc++) { for (let sc = 0; sc < spriteColors.length; sc++) {
const delta = Math.min(...paletteDeltas[sc]); const delta = Math.min(...paletteDeltas[sc]);
const paletteIndex = Math.min( const paletteIndex = Math.min(paletteDeltas[sc].indexOf(delta), fusionPalette.length - 1);
paletteDeltas[sc].findIndex(pd => pd === delta),
fusionPalette.length - 1,
);
if (delta < 255) { if (delta < 255) {
const ratio = easeFunc(delta / 255); const ratio = easeFunc(delta / 255);
const color = [0, 0, 0, fusionSpriteColors[sc][3]]; const color = [0, 0, 0, fusionSpriteColors[sc][3]];

View File

@ -158,7 +158,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
* @param {TrainerSlot} trainerSlot - The slot to determine which name to use. Defaults to TrainerSlot.NONE. * @param {TrainerSlot} trainerSlot - The slot to determine which name to use. Defaults to TrainerSlot.NONE.
* @param {boolean} includeTitle - Whether to include the title in the returned name. Defaults to false. * @param {boolean} includeTitle - Whether to include the title in the returned name. Defaults to false.
* @returns {string} - The formatted name of the trainer. * @returns {string} - The formatted name of the trainer.
**/ */
getName(trainerSlot: TrainerSlot = TrainerSlot.NONE, includeTitle = false): string { getName(trainerSlot: TrainerSlot = TrainerSlot.NONE, includeTitle = false): string {
// Get the base title based on the trainer slot and variant. // Get the base title based on the trainer slot and variant.
let name = this.config.getTitle(trainerSlot, this.variant); let name = this.config.getTitle(trainerSlot, this.variant);

View File

@ -70,20 +70,20 @@ 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> = new Array(); private gamepads: Array<Phaser.Input.Gamepad.Gamepad> = [];
public events: Phaser.Events.EventEmitter; public events: Phaser.Events.EventEmitter;
private buttonLock: Button[] = new Array(); private buttonLock: Button[] = [];
private interactions: Map<Button, Map<string, boolean>> = new Map(); private interactions: Map<Button, Map<string, boolean>> = new Map();
private configs: Map<string, InterfaceConfig> = new Map(); private configs: Map<string, InterfaceConfig> = new Map();
public gamepadSupport = true; public gamepadSupport = true;
public selectedDevice; public selectedDevice;
private disconnectedGamepads: Array<string> = new Array(); private disconnectedGamepads: Array<string> = [];
public lastSource = "keyboard"; public lastSource = "keyboard";
private inputInterval: NodeJS.Timeout[] = new Array(); private inputInterval: NodeJS.Timeout[] = [];
private touchControls: TouchControl; private touchControls: TouchControl;
public moveTouchControlsHandler: MoveTouchControlsHandler; public moveTouchControlsHandler: MoveTouchControlsHandler;

View File

@ -100,7 +100,7 @@ import { UnlockPhase } from "#app/phases/unlock-phase";
import { VictoryPhase } from "#app/phases/victory-phase"; import { VictoryPhase } from "#app/phases/victory-phase";
import { WeatherEffectPhase } from "#app/phases/weather-effect-phase"; import { WeatherEffectPhase } from "#app/phases/weather-effect-phase";
/** /*
* Manager for phases used by battle scene. * 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.* * *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

@ -38,14 +38,11 @@ export class AttemptRunPhase extends PokemonPhase {
alpha: 0, alpha: 0,
duration: 250, duration: 250,
ease: "Sine.easeIn", ease: "Sine.easeIn",
onComplete: () => onComplete: () => enemyField.forEach(enemyPokemon => enemyPokemon.destroy()),
// biome-ignore lint/complexity/noForEach: TODO
enemyField.forEach(enemyPokemon => enemyPokemon.destroy()),
}); });
globalScene.clearEnemyHeldItemModifiers(); globalScene.clearEnemyHeldItemModifiers();
// biome-ignore lint/complexity/noForEach: TODO
enemyField.forEach(enemyPokemon => { enemyField.forEach(enemyPokemon => {
enemyPokemon.hideInfo().then(() => enemyPokemon.destroy()); enemyPokemon.hideInfo().then(() => enemyPokemon.destroy());
enemyPokemon.hp = 0; enemyPokemon.hp = 0;

View File

@ -299,7 +299,7 @@ export class GameOverPhase extends BattlePhase {
battleType: globalScene.currentBattle.battleType, battleType: globalScene.currentBattle.battleType,
trainer: globalScene.currentBattle.trainer ? new TrainerData(globalScene.currentBattle.trainer) : null, trainer: globalScene.currentBattle.trainer ? new TrainerData(globalScene.currentBattle.trainer) : null,
gameVersion: globalScene.game.config.gameVersion, gameVersion: globalScene.game.config.gameVersion,
timestamp: new Date().getTime(), timestamp: Date.now(),
challenges: globalScene.gameMode.challenges.map(c => new ChallengeData(c)), challenges: globalScene.gameMode.challenges.map(c => new ChallengeData(c)),
mysteryEncounterType: globalScene.currentBattle.mysteryEncounter?.encounterType ?? -1, mysteryEncounterType: globalScene.currentBattle.mysteryEncounter?.encounterType ?? -1,
mysteryEncounterSaveData: globalScene.mysteryEncounterSaveData, mysteryEncounterSaveData: globalScene.mysteryEncounterSaveData,

View File

@ -696,12 +696,9 @@ export class MoveEffectPhase extends PokemonPhase {
* @param target - The {@linkcode Pokemon} to be removed * @param target - The {@linkcode Pokemon} to be removed
*/ */
protected removeTarget(target: Pokemon): void { protected removeTarget(target: Pokemon): void {
const targetIndex = this.targets.findIndex(ind => ind === target.getBattlerIndex()); const targetIndex = this.targets.indexOf(target.getBattlerIndex());
if (targetIndex !== -1) { if (targetIndex !== -1) {
this.targets.splice( this.targets.splice(this.targets.indexOf(target.getBattlerIndex()), 1);
this.targets.findIndex(ind => ind === target.getBattlerIndex()),
1,
);
} }
} }

View File

@ -44,7 +44,7 @@ export class SwitchSummonPhase extends SummonPhase {
preSummon(): void { preSummon(): void {
if (!this.player) { if (!this.player) {
if (this.slotIndex === -1) { if (this.slotIndex === -1) {
//@ts-ignore //@ts-expect-error
this.slotIndex = globalScene.currentBattle.trainer?.getNextSummonIndex( this.slotIndex = globalScene.currentBattle.trainer?.getNextSummonIndex(
!this.fieldIndex ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER, !this.fieldIndex ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER,
); // TODO: what would be the default trainer-slot fallback? ); // TODO: what would be the default trainer-slot fallback?

View File

@ -33,7 +33,7 @@ export abstract class ApiBase {
* @param dataType The data-type of the {@linkcode bodyData}. * @param dataType The data-type of the {@linkcode bodyData}.
*/ */
protected async doPost<D = undefined>(path: string, bodyData?: D, dataType: DataType = "json") { protected async doPost<D = undefined>(path: string, bodyData?: D, dataType: DataType = "json") {
let body: string | undefined = undefined; let body: string | undefined;
const headers: HeadersInit = {}; const headers: HeadersInit = {};
if (bodyData) { if (bodyData) {

View File

@ -9,7 +9,7 @@ import type BattleScene from "#app/battle-scene";
// Regex patterns // Regex patterns
/** Regex matching double underscores */ /** Regex matching double underscores */
const DUNDER_REGEX = /\_{2}/g; const DUNDER_REGEX = /_{2}/g;
/** /**
* Calculate the sprite ID from a pokemon form. * Calculate the sprite ID from a pokemon form.

View File

@ -1,6 +1,6 @@
import { expSpriteKeys } from "#app/sprites/sprite-keys"; import { expSpriteKeys } from "#app/sprites/sprite-keys";
const expKeyRegex = /^pkmn__?(back__)?(shiny__)?(female__)?(\d+)(\-.*?)?(?:_[1-3])?$/; const expKeyRegex = /^pkmn__?(back__)?(shiny__)?(female__)?(\d+)(-.*?)?(?:_[1-3])?$/;
export function hasExpSprite(key: string): boolean { export function hasExpSprite(key: string): boolean {
const keyMatch = expKeyRegex.exec(key); const keyMatch = expKeyRegex.exec(key);

View File

@ -39,7 +39,7 @@ import { setSettingGamepad, SettingGamepad, settingGamepadDefaults } from "#app/
import type { SettingKeyboard } from "#app/system/settings/settings-keyboard"; import type { SettingKeyboard } from "#app/system/settings/settings-keyboard";
import { setSettingKeyboard } from "#app/system/settings/settings-keyboard"; import { setSettingKeyboard } from "#app/system/settings/settings-keyboard";
import { TagAddedEvent, TerrainChangedEvent, WeatherChangedEvent } from "#app/events/arena"; import { TagAddedEvent, TerrainChangedEvent, WeatherChangedEvent } from "#app/events/arena";
// biome-ignore lint/style/noNamespaceImport: Something weird is going on here and I don't want to touch it // biome-ignore lint/performance/noNamespaceImport: Something weird is going on here and I don't want to touch it
import * as Modifier from "#app/modifier/modifier"; import * as Modifier from "#app/modifier/modifier";
import { StatusEffect } from "#enums/status-effect"; import { StatusEffect } from "#enums/status-effect";
import ChallengeData from "#app/system/challenge-data"; import ChallengeData from "#app/system/challenge-data";
@ -300,7 +300,7 @@ export class GameData {
voucherCounts: this.voucherCounts, voucherCounts: this.voucherCounts,
eggs: this.eggs.map(e => new EggData(e)), eggs: this.eggs.map(e => new EggData(e)),
gameVersion: globalScene.game.config.gameVersion, gameVersion: globalScene.game.config.gameVersion,
timestamp: new Date().getTime(), timestamp: Date.now(),
eggPity: this.eggPity.slice(0), eggPity: this.eggPity.slice(0),
unlockPity: this.unlockPity.slice(0), unlockPity: this.unlockPity.slice(0),
}; };
@ -930,7 +930,7 @@ export class GameData {
? new TrainerData(globalScene.currentBattle.trainer) ? new TrainerData(globalScene.currentBattle.trainer)
: null, : null,
gameVersion: globalScene.game.config.gameVersion, gameVersion: globalScene.game.config.gameVersion,
timestamp: new Date().getTime(), timestamp: Date.now(),
challenges: globalScene.gameMode.challenges.map(c => new ChallengeData(c)), challenges: globalScene.gameMode.challenges.map(c => new ChallengeData(c)),
mysteryEncounterType: globalScene.currentBattle.mysteryEncounter?.encounterType ?? -1, mysteryEncounterType: globalScene.currentBattle.mysteryEncounter?.encounterType ?? -1,
mysteryEncounterSaveData: globalScene.mysteryEncounterSaveData, mysteryEncounterSaveData: globalScene.mysteryEncounterSaveData,
@ -939,7 +939,7 @@ export class GameData {
} }
getSession(slotId: number): Promise<SessionSaveData | null> { getSession(slotId: number): Promise<SessionSaveData | null> {
// biome-ignore lint/suspicious/noAsyncPromiseExecutor: <explanation> // biome-ignore lint/suspicious/noAsyncPromiseExecutor: TODO: fix this
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
if (slotId < 0) { if (slotId < 0) {
return resolve(null); return resolve(null);
@ -980,7 +980,7 @@ export class GameData {
} }
loadSession(slotId: number, sessionData?: SessionSaveData): Promise<boolean> { loadSession(slotId: number, sessionData?: SessionSaveData): Promise<boolean> {
// biome-ignore lint/suspicious/noAsyncPromiseExecutor: <explanation> // biome-ignore lint/suspicious/noAsyncPromiseExecutor: TODO: fix this
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
try { try {
const initSessionFromData = async (sessionData: SessionSaveData) => { const initSessionFromData = async (sessionData: SessionSaveData) => {
@ -1610,7 +1610,7 @@ export class GameData {
} }
} }
this.defaultDexData = Object.assign({}, data); this.defaultDexData = { ...data };
this.dexData = data; this.dexData = data;
} }

View File

@ -1,3 +1,5 @@
/** biome-ignore-all lint/performance/noNamespaceImport: Convenience */
import type { SessionSaveMigrator } from "#app/@types/SessionSaveMigrator"; import type { SessionSaveMigrator } from "#app/@types/SessionSaveMigrator";
import type { SettingsSaveMigrator } from "#app/@types/SettingsSaveMigrator"; import type { SettingsSaveMigrator } from "#app/@types/SettingsSaveMigrator";
import type { SystemSaveMigrator } from "#app/@types/SystemSaveMigrator"; import type { SystemSaveMigrator } from "#app/@types/SystemSaveMigrator";
@ -48,23 +50,18 @@ export const settingsMigrators: Readonly<SettingsSaveMigrator[]> = [settingsMigr
// import * as vA_B_C from "./versions/vA_B_C"; // import * as vA_B_C from "./versions/vA_B_C";
// --- v1.0.4 (and below) PATCHES --- // // --- v1.0.4 (and below) PATCHES --- //
// biome-ignore lint/style/noNamespaceImport: Convenience (TODO: make this a file-wide ignore when Biome supports those)
import * as v1_0_4 from "./versions/v1_0_4"; import * as v1_0_4 from "./versions/v1_0_4";
// --- v1.7.0 PATCHES --- // // --- v1.7.0 PATCHES --- //
// biome-ignore lint/style/noNamespaceImport: Convenience
import * as v1_7_0 from "./versions/v1_7_0"; import * as v1_7_0 from "./versions/v1_7_0";
// --- v1.8.3 PATCHES --- // // --- v1.8.3 PATCHES --- //
// biome-ignore lint/style/noNamespaceImport: Convenience
import * as v1_8_3 from "./versions/v1_8_3"; import * as v1_8_3 from "./versions/v1_8_3";
// --- v1.9.0 PATCHES --- // // --- v1.9.0 PATCHES --- //
// biome-ignore lint/style/noNamespaceImport: Convenience
import * as v1_9_0 from "./versions/v1_9_0"; import * as v1_9_0 from "./versions/v1_9_0";
// --- v1.10.0 PATCHES --- // // --- v1.10.0 PATCHES --- //
// biome-ignore lint/style/noNamespaceImport: Convenience
import * as v1_10_0 from "./versions/v1_10_0"; import * as v1_10_0 from "./versions/v1_10_0";
/** Current game version */ /** Current game version */

View File

@ -6,8 +6,8 @@ const repeatInputDelayMillis = 250;
export default class TouchControl { export default class TouchControl {
events: EventEmitter; events: EventEmitter;
private buttonLock: string[] = new Array(); private buttonLock: string[] = [];
private inputInterval: NodeJS.Timeout[] = new Array(); private inputInterval: NodeJS.Timeout[] = [];
/** Whether touch controls are disabled */ /** Whether touch controls are disabled */
private disabled = false; private disabled = false;
/** Whether the last touch event has finished before disabling */ /** Whether the last touch event has finished before disabling */
@ -42,7 +42,7 @@ export default class TouchControl {
document.querySelectorAll(".apad-button").forEach(element => this.preventElementZoom(element as HTMLElement)); document.querySelectorAll(".apad-button").forEach(element => this.preventElementZoom(element as HTMLElement));
// Select all elements with the 'data-key' attribute and bind keys to them // Select all elements with the 'data-key' attribute and bind keys to them
for (const button of document.querySelectorAll("[data-key]")) { for (const button of document.querySelectorAll("[data-key]")) {
// @ts-ignore - Bind the key to the button using the dataset key // @ts-expect-error - Bind the key to the button using the dataset key
this.bindKey(button, button.dataset.key); this.bindKey(button, button.dataset.key);
} }
} }
@ -208,7 +208,7 @@ export function isMobile(): boolean {
/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test( /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(
a, a,
) || ) ||
/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test( /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw-(n|u)|c55\/|capi|ccwa|cdm-|cell|chtm|cldc|cmd-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc-s|devi|dica|dmob|do(c|p)o|ds(12|-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(-|_)|g1 u|g560|gene|gf-5|g-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd-(m|p|t)|hei-|hi(pt|ta)|hp( i|ip)|hs-c|ht(c(-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i-(20|go|ma)|i230|iac( |-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|-[a-w])|libw|lynx|m1-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|-([1-8]|c))|phil|pire|pl(ay|uc)|pn-2|po(ck|rt|se)|prox|psio|pt-g|qa-a|qc(07|12|21|32|60|-[2-7]|i-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h-|oo|p-)|sdk\/|se(c(-|0|1)|47|mc|nd|ri)|sgh-|shar|sie(-|m)|sk-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h-|v-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl-|tdg-|tel(i|m)|tim-|t-mo|to(pl|sh)|ts(70|m-|m3|m5)|tx-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas-|your|zeto|zte-/i.test(
a.substr(0, 4), a.substr(0, 4),
) )
) { ) {

View File

@ -176,12 +176,12 @@ export class UiInputs {
return; return;
} }
switch (globalScene.ui?.getMode()) { switch (globalScene.ui?.getMode()) {
// biome-ignore lint/suspicious/noFallthroughSwitchClause: falls through to show menu overlay
case UiMode.MESSAGE: { case UiMode.MESSAGE: {
const messageHandler = globalScene.ui.getHandler<MessageUiHandler>(); const messageHandler = globalScene.ui.getHandler<MessageUiHandler>();
if (!messageHandler.pendingPrompt || messageHandler.isTextAnimationInProgress()) { if (!messageHandler.pendingPrompt || messageHandler.isTextAnimationInProgress()) {
return; return;
} }
// biome-ignore lint/suspicious/noFallthroughSwitchClause: falls through to show menu overlay
} }
case UiMode.TITLE: case UiMode.TITLE:
case UiMode.COMMAND: case UiMode.COMMAND:

View File

@ -52,7 +52,7 @@ export default class BattleFlyout extends Phaser.GameObjects.Container {
/** The array of {@linkcode Phaser.GameObjects.Text} objects which are drawn on the flyout */ /** The array of {@linkcode Phaser.GameObjects.Text} objects which are drawn on the flyout */
private flyoutText: Phaser.GameObjects.Text[] = new Array(4); private flyoutText: Phaser.GameObjects.Text[] = new Array(4);
/** The array of {@linkcode MoveInfo} used to track moves for the {@linkcode Pokemon} linked to the flyout */ /** The array of {@linkcode MoveInfo} used to track moves for the {@linkcode Pokemon} linked to the flyout */
private moveInfo: MoveInfo[] = new Array(); private moveInfo: MoveInfo[] = [];
/** Current state of the flyout's visibility */ /** Current state of the flyout's visibility */
public flyoutVisible = false; public flyoutVisible = false;

View File

@ -41,24 +41,15 @@ export class DailyRunScoreboard extends Phaser.GameObjects.Container {
this.setup(); this.setup();
} }
/** /** When set to `true`, disables the buttons; when set to `false`, enables the buttons. */
* Sets the updating state and updates button states accordingly. get isUpdating(): boolean {
* If value is true (updating), disables the buttons; if false, enables the buttons. return this._isUpdating;
* @param {boolean} value - The new updating state. }
*/ set isUpdating(value: boolean) {
set isUpdating(value) {
this._isUpdating = value; this._isUpdating = value;
this.setButtonsState(!value); this.setButtonsState(!value);
} }
/**
* Gets the current updating state.
* @returns {boolean} - The current updating state.
*/
get isUpdating() {
return this._isUpdating;
}
setup() { setup() {
const titleWindow = addWindow(0, 0, 114, 18, false, false, undefined, undefined, WindowVariant.THIN); const titleWindow = addWindow(0, 0, 114, 18, false, false, undefined, undefined, WindowVariant.THIN);
this.add(titleWindow); this.add(titleWindow);

View File

@ -625,7 +625,7 @@ export default class EggGachaUiHandler extends MessageUiHandler {
const infoContainer = this.gachaInfoContainers[gachaType]; const infoContainer = this.gachaInfoContainers[gachaType];
switch (gachaType as GachaType) { switch (gachaType as GachaType) {
case GachaType.LEGENDARY: { case GachaType.LEGENDARY: {
const species = getPokemonSpecies(getLegendaryGachaSpeciesForTimestamp(new Date().getTime())); const species = getPokemonSpecies(getLegendaryGachaSpeciesForTimestamp(Date.now()));
const pokemonIcon = infoContainer.getAt(1) as Phaser.GameObjects.Sprite; const pokemonIcon = infoContainer.getAt(1) as Phaser.GameObjects.Sprite;
pokemonIcon.setTexture(species.getIconAtlasKey(), species.getIconId(false)); pokemonIcon.setTexture(species.getIconAtlasKey(), species.getIconId(false));
break; break;

View File

@ -591,9 +591,9 @@ export default class MysteryEncounterUiHandler extends UiHandler {
// Auto-color options green/blue for good/bad by looking for (+)/(-) // Auto-color options green/blue for good/bad by looking for (+)/(-)
if (text) { if (text) {
const primaryStyleString = [...text.match(new RegExp(/\[color=[^\[]*\]\[shadow=[^\[]*\]/i))!][0]; const primaryStyleString = [...text.match(new RegExp(/\[color=[^[]*\]\[shadow=[^[]*\]/i))!][0];
text = text.replace( text = text.replace(
/(\(\+\)[^\(\[]*)/gi, /(\(\+\)[^([]*)/gi,
substring => substring =>
"[/color][/shadow]" + "[/color][/shadow]" +
getBBCodeFrag(substring, TextStyle.SUMMARY_GREEN) + getBBCodeFrag(substring, TextStyle.SUMMARY_GREEN) +
@ -601,7 +601,7 @@ export default class MysteryEncounterUiHandler extends UiHandler {
primaryStyleString, primaryStyleString,
); );
text = text.replace( text = text.replace(
/(\(\-\)[^\(\[]*)/gi, /(\(-\)[^([]*)/gi,
substring => substring =>
"[/color][/shadow]" + "[/color][/shadow]" +
getBBCodeFrag(substring, TextStyle.SUMMARY_BLUE) + getBBCodeFrag(substring, TextStyle.SUMMARY_BLUE) +

View File

@ -2057,7 +2057,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
} }
let newSpecies: PokemonSpecies; let newSpecies: PokemonSpecies;
if (this.filteredIndices) { if (this.filteredIndices) {
const index = this.filteredIndices.findIndex(id => id === this.species.speciesId); const index = this.filteredIndices.indexOf(this.species.speciesId);
const newIndex = index <= 0 ? this.filteredIndices.length - 1 : index - 1; const newIndex = index <= 0 ? this.filteredIndices.length - 1 : index - 1;
newSpecies = getPokemonSpecies(this.filteredIndices[newIndex]); newSpecies = getPokemonSpecies(this.filteredIndices[newIndex]);
} else { } else {
@ -2096,7 +2096,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
} }
let newSpecies: PokemonSpecies; let newSpecies: PokemonSpecies;
if (this.filteredIndices) { if (this.filteredIndices) {
const index = this.filteredIndices.findIndex(id => id === this.species.speciesId); const index = this.filteredIndices.indexOf(this.species.speciesId);
const newIndex = index >= this.filteredIndices.length - 1 ? 0 : index + 1; const newIndex = index >= this.filteredIndices.length - 1 ? 0 : index + 1;
newSpecies = getPokemonSpecies(this.filteredIndices[newIndex]); newSpecies = getPokemonSpecies(this.filteredIndices[newIndex]);
} else { } else {
@ -2321,7 +2321,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
this.showStats(); this.showStats();
} else { } else {
this.statsContainer.setVisible(false); this.statsContainer.setVisible(false);
//@ts-ignore //@ts-expect-error
this.statsContainer.updateIvs(null); // TODO: resolve ts-ignore. what. how? huh? this.statsContainer.updateIvs(null); // TODO: resolve ts-ignore. what. how? huh?
} }
} }
@ -2786,7 +2786,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
this.statsMode = false; this.statsMode = false;
this.statsContainer.setVisible(false); this.statsContainer.setVisible(false);
this.pokemonSprite.setVisible(true); this.pokemonSprite.setVisible(true);
//@ts-ignore //@ts-expect-error
this.statsContainer.updateIvs(null); // TODO: resolve ts-ignore. !?!? this.statsContainer.updateIvs(null); // TODO: resolve ts-ignore. !?!?
} }
} }

View File

@ -1389,7 +1389,7 @@ export default class PokedexUiHandler extends MessageUiHandler {
const fitsMoves = fitsMove1 && fitsMove2; const fitsMoves = fitsMove1 && fitsMove2;
if (fitsEggMove1 && !fitsLevelMove1) { if (fitsEggMove1 && !fitsLevelMove1) {
const em1 = eggMoves.findIndex(name => name === selectedMove1); const em1 = eggMoves.indexOf(selectedMove1);
if ((starterData.eggMoves & (1 << em1)) === 0) { if ((starterData.eggMoves & (1 << em1)) === 0) {
data.eggMove1 = false; data.eggMove1 = false;
} else { } else {
@ -1399,7 +1399,7 @@ export default class PokedexUiHandler extends MessageUiHandler {
data.tmMove1 = true; data.tmMove1 = true;
} }
if (fitsEggMove2 && !fitsLevelMove2) { if (fitsEggMove2 && !fitsLevelMove2) {
const em2 = eggMoves.findIndex(name => name === selectedMove2); const em2 = eggMoves.indexOf(selectedMove2);
if ((starterData.eggMoves & (1 << em2)) === 0) { if ((starterData.eggMoves & (1 << em2)) === 0) {
data.eggMove2 = false; data.eggMove2 = false;
} else { } else {

View File

@ -19,7 +19,7 @@ import { PokemonType } from "#enums/pokemon-type";
import { TypeColor, TypeShadow } from "#app/enums/color"; import { TypeColor, TypeShadow } from "#app/enums/color";
import { getNatureStatMultiplier, getNatureName } from "../data/nature"; import { getNatureStatMultiplier, getNatureName } from "../data/nature";
import { getVariantTint } from "#app/sprites/variant"; import { getVariantTint } from "#app/sprites/variant";
// biome-ignore lint/style/noNamespaceImport: See `src/system/game-data.ts` // biome-ignore lint/performance/noNamespaceImport: See `src/system/game-data.ts`
import * as Modifier from "#app/modifier/modifier"; import * as Modifier from "#app/modifier/modifier";
import type { SpeciesId } from "#enums/species-id"; import type { SpeciesId } from "#enums/species-id";
import { PlayerGender } from "#enums/player-gender"; import { PlayerGender } from "#enums/player-gender";

View File

@ -2,7 +2,7 @@ import i18next from "i18next";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { Button } from "#enums/buttons"; import { Button } from "#enums/buttons";
import { GameMode } from "../game-mode"; import { GameMode } from "../game-mode";
// biome-ignore lint/style/noNamespaceImport: See `src/system/game-data.ts` // biome-ignore lint/performance/noNamespaceImport: See `src/system/game-data.ts`
import * as Modifier from "#app/modifier/modifier"; import * as Modifier from "#app/modifier/modifier";
import type { SessionSaveData } from "../system/game-data"; import type { SessionSaveData } from "../system/game-data";
import type PokemonData from "../system/pokemon-data"; import type PokemonData from "../system/pokemon-data";

View File

@ -209,7 +209,7 @@ export default abstract class AbstractControlSettingsUiHandler extends UiHandler
settingFiltered.forEach((setting, s) => { settingFiltered.forEach((setting, s) => {
// Convert the setting key from format 'Key_Name' to 'Key name' for display. // Convert the setting key from format 'Key_Name' to 'Key name' for display.
const settingName = setting.replace(/\_/g, " "); const settingName = setting.replace(/_/g, " ");
// Create and add a text object for the setting name to the scene. // Create and add a text object for the setting name to the scene.
const isLock = this.settingBlacklisted.includes(this.setting[setting]); const isLock = this.settingBlacklisted.includes(this.setting[setting]);

View File

@ -16,7 +16,7 @@ export class NavigationManager {
private static instance: NavigationManager; private static instance: NavigationManager;
public modes: UiMode[]; public modes: UiMode[];
public selectedMode: UiMode = UiMode.SETTINGS; public selectedMode: UiMode = UiMode.SETTINGS;
public navigationMenus: NavigationMenu[] = new Array<NavigationMenu>(); public navigationMenus: NavigationMenu[] = [];
public labels: string[]; public labels: string[];
/** /**
@ -105,7 +105,7 @@ export class NavigationManager {
export default class NavigationMenu extends Phaser.GameObjects.Container { export default class NavigationMenu extends Phaser.GameObjects.Container {
private navigationIcons: InputsIcons; private navigationIcons: InputsIcons;
protected headerTitles: Phaser.GameObjects.Text[] = new Array<Phaser.GameObjects.Text>(); protected headerTitles: Phaser.GameObjects.Text[] = [];
/** /**
* Creates an instance of NavigationMenu. * Creates an instance of NavigationMenu.

View File

@ -2822,7 +2822,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
iconElement: GameObjects.Sprite, iconElement: GameObjects.Sprite,
controlLabel: GameObjects.Text, controlLabel: GameObjects.Text,
): void { ): void {
// biome-ignore lint/suspicious/noImplicitAnyLet: TODO
let iconPath: string; let iconPath: string;
// touch controls cannot be rebound as is, and are just emulating a keyboard event. // touch controls cannot be rebound as is, and are just emulating a keyboard event.
// Additionally, since keyboard controls can be rebound (and will be displayed when they are), we need to have special handling for the touch controls // Additionally, since keyboard controls can be rebound (and will be displayed when they are), we need to have special handling for the touch controls
@ -2856,7 +2855,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
} else { } else {
iconPath = globalScene.inputController?.getIconForLatestInputRecorded(iconSetting); iconPath = globalScene.inputController?.getIconForLatestInputRecorded(iconSetting);
} }
// @ts-ignore: TODO can iconPath actually be undefined? // @ts-expect-error: TODO can iconPath actually be undefined?
iconElement.setTexture(gamepadType, iconPath); iconElement.setTexture(gamepadType, iconPath);
iconElement.setPosition(this.instructionRowX, this.instructionRowY); iconElement.setPosition(this.instructionRowX, this.instructionRowY);
controlLabel.setPosition(this.instructionRowX + this.instructionRowTextOffset, this.instructionRowY); controlLabel.setPosition(this.instructionRowX + this.instructionRowTextOffset, this.instructionRowY);
@ -3481,7 +3480,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.showStats(); this.showStats();
} else { } else {
this.statsContainer.setVisible(false); this.statsContainer.setVisible(false);
//@ts-ignore //@ts-expect-error
this.statsContainer.updateIvs(null); // TODO: resolve ts-ignore. what. how? huh? this.statsContainer.updateIvs(null); // TODO: resolve ts-ignore. what. how? huh?
} }
} }
@ -4489,7 +4488,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.statsMode = false; this.statsMode = false;
this.statsContainer.setVisible(false); this.statsContainer.setVisible(false);
this.pokemonSprite.setVisible(!!this.speciesStarterDexEntry?.caughtAttr); this.pokemonSprite.setVisible(!!this.speciesStarterDexEntry?.caughtAttr);
//@ts-ignore //@ts-expect-error
this.statsContainer.updateIvs(null); // TODO: resolve ts-ignore. !?!? this.statsContainer.updateIvs(null); // TODO: resolve ts-ignore. !?!?
this.teraIcon.setVisible(globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id)); this.teraIcon.setVisible(globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id));
const props = globalScene.gameData.getSpeciesDexAttrProps( const props = globalScene.gameData.getSpeciesDexAttrProps(

View File

@ -117,7 +117,7 @@ export default class SummaryUiHandler extends UiHandler {
private pokemon: PlayerPokemon | null; private pokemon: PlayerPokemon | null;
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: Function | null;
private transitioning: boolean; private transitioning: boolean;

View File

@ -300,7 +300,7 @@ export function getTextWithColors(
): string { ): string {
// Apply primary styling before anything else // Apply primary styling before anything else
let text = getBBCodeFrag(content, primaryStyle, uiTheme) + "[/color][/shadow]"; let text = getBBCodeFrag(content, primaryStyle, uiTheme) + "[/color][/shadow]";
const primaryStyleString = [...text.match(new RegExp(/\[color=[^\[]*\]\[shadow=[^\[]*\]/i))!][0]; const primaryStyleString = [...text.match(new RegExp(/\[color=[^[]*\]\[shadow=[^[]*\]/i))!][0];
/* For money text displayed in game windows, we can't use the default {@linkcode TextStyle.MONEY} /* For money text displayed in game windows, we can't use the default {@linkcode TextStyle.MONEY}
* or it will look wrong in legacy mode because of the different window background color * or it will look wrong in legacy mode because of the different window background color
@ -320,7 +320,7 @@ export function getTextWithColors(
}); });
// Remove extra style block at the end // Remove extra style block at the end
return text.replace(/\[color=[^\[]*\]\[shadow=[^\[]*\]\[\/color\]\[\/shadow\]/gi, ""); return text.replace(/\[color=[^[]*\]\[shadow=[^[]*\]\[\/color\]\[\/shadow\]/gi, "");
} }
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: This is a giant switch which is the best option. // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: This is a giant switch which is the best option.

View File

@ -10,7 +10,7 @@ export const MissingTextureKey = "__MISSING";
export function toReadableString(str: string): string { export function toReadableString(str: string): string {
return str return str
.replace(/\_/g, " ") .replace(/_/g, " ")
.split(" ") .split(" ")
.map(s => `${s.slice(0, 1)}${s.slice(1).toLowerCase()}`) .map(s => `${s.slice(0, 1)}${s.slice(1).toLowerCase()}`)
.join(" "); .join(" ");
@ -583,7 +583,7 @@ export function isBetween(num: number, min: number, max: number): boolean {
* @param move the move for which the animation filename is needed * @param move the move for which the animation filename is needed
*/ */
export function animationFileName(move: MoveId): string { export function animationFileName(move: MoveId): string {
return MoveId[move].toLowerCase().replace(/\_/g, "-"); return MoveId[move].toLowerCase().replace(/_/g, "-");
} }
/** /**

View File

@ -2,7 +2,7 @@ import { isBeta } from "./utility-vars";
export function setCookie(cName: string, cValue: string): void { export function setCookie(cName: string, cValue: string): void {
const expiration = new Date(); const expiration = new Date();
expiration.setTime(new Date().getTime() + 3600000 * 24 * 30 * 3 /*7*/); expiration.setTime(Date.now() + 3600000 * 24 * 30 * 3 /*7*/);
document.cookie = `${cName}=${cValue};Secure;SameSite=Strict;Domain=${window.location.hostname};Path=/;Expires=${expiration.toUTCString()}`; document.cookie = `${cName}=${cValue};Secure;SameSite=Strict;Domain=${window.location.hostname};Path=/;Expires=${expiration.toUTCString()}`;
} }

View File

@ -40,7 +40,7 @@ describe("Abilities - Mycelium Might", () => {
* https://bulbapedia.bulbagarden.net/wiki/Mycelium_Might_(Ability) * https://bulbapedia.bulbagarden.net/wiki/Mycelium_Might_(Ability)
* https://bulbapedia.bulbagarden.net/wiki/Priority * https://bulbapedia.bulbagarden.net/wiki/Priority
* https://www.smogon.com/forums/threads/scarlet-violet-battle-mechanics-research.3709545/page-24 * https://www.smogon.com/forums/threads/scarlet-violet-battle-mechanics-research.3709545/page-24
**/ */
it("will move last in its priority bracket and ignore protective abilities", async () => { it("will move last in its priority bracket and ignore protective abilities", async () => {
await game.classicMode.startBattle([SpeciesId.REGIELEKI]); await game.classicMode.startBattle([SpeciesId.REGIELEKI]);

View File

@ -35,7 +35,7 @@ describe("Abilities - Stall", () => {
* References: * References:
* https://bulbapedia.bulbagarden.net/wiki/Stall_(Ability) * https://bulbapedia.bulbagarden.net/wiki/Stall_(Ability)
* https://bulbapedia.bulbagarden.net/wiki/Priority * https://bulbapedia.bulbagarden.net/wiki/Priority
**/ */
it("Pokemon with Stall should move last in its priority bracket regardless of speed", async () => { it("Pokemon with Stall should move last in its priority bracket regardless of speed", async () => {
await game.classicMode.startBattle([SpeciesId.SHUCKLE]); await game.classicMode.startBattle([SpeciesId.SHUCKLE]);

View File

@ -66,7 +66,7 @@ describe("Abilities - Wonder Skin", () => {
it(`does not affect pokemon with ${ability[1]}`, async () => { it(`does not affect pokemon with ${ability[1]}`, async () => {
const moveToCheck = allMoves[MoveId.CHARM]; const moveToCheck = allMoves[MoveId.CHARM];
// @ts-ignore ts doesn't know that ability[0] is an ability and not a string... // @ts-expect-error ts doesn't know that ability[0] is an ability and not a string...
game.override.ability(ability[0]); game.override.ability(ability[0]);
vi.spyOn(moveToCheck, "calculateBattleAccuracy"); vi.spyOn(moveToCheck, "calculateBattleAccuracy");

View File

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

View File

@ -26,9 +26,9 @@ describe("check if every variant's sprite are correctly set", () => {
femaleVariant = masterlist.female; femaleVariant = masterlist.female;
backVariant = masterlist.back; backVariant = masterlist.back;
// @ts-ignore // @ts-expect-error
delete masterlist.female; // TODO: resolve ts-ignore delete masterlist.female; // TODO: resolve ts-ignore
//@ts-ignore //@ts-expect-error
delete masterlist.back; //TODO: resolve ts-ignore delete masterlist.back; //TODO: resolve ts-ignore
}); });

View File

@ -15,15 +15,15 @@ import { vi } from "vitest";
import { version } from "../../package.json"; import { version } from "../../package.json";
import { MockGameObjectCreator } from "./mocks/mockGameObjectCreator"; import { MockGameObjectCreator } from "./mocks/mockGameObjectCreator";
import { MockTimedEventManager } from "./mocks/mockTimedEventManager"; import { MockTimedEventManager } from "./mocks/mockTimedEventManager";
import { PokedexMonContainer } from "#app/ui/pokedex-mon-container";
import MockContainer from "./mocks/mocksContainer/mockContainer";
import InputManager = Phaser.Input.InputManager; import InputManager = Phaser.Input.InputManager;
import KeyboardManager = Phaser.Input.Keyboard.KeyboardManager; import KeyboardManager = Phaser.Input.Keyboard.KeyboardManager;
import KeyboardPlugin = Phaser.Input.Keyboard.KeyboardPlugin; import KeyboardPlugin = Phaser.Input.Keyboard.KeyboardPlugin;
import GamepadPlugin = Phaser.Input.Gamepad.GamepadPlugin; import GamepadPlugin = Phaser.Input.Gamepad.GamepadPlugin;
import EventEmitter = Phaser.Events.EventEmitter; import EventEmitter = Phaser.Events.EventEmitter;
import UpdateList = Phaser.GameObjects.UpdateList; import UpdateList = Phaser.GameObjects.UpdateList;
import { PokedexMonContainer } from "#app/ui/pokedex-mon-container"; // biome-ignore lint/performance/noNamespaceImport: Necessary in order to mock the var
import MockContainer from "./mocks/mocksContainer/mockContainer";
// biome-ignore lint/style/noNamespaceImport: Necessary in order to mock the var
import * as bypassLoginModule from "#app/global-vars/bypass-login"; import * as bypassLoginModule from "#app/global-vars/bypass-login";
window.URL.createObjectURL = (blob: Blob) => { window.URL.createObjectURL = (blob: Blob) => {

View File

@ -89,7 +89,7 @@ class Fakepad extends Phaser.Input.Gamepad.Gamepad {
public index: number; public index: number;
constructor(pad) { constructor(pad) {
//@ts-ignore //@ts-expect-error
super(undefined, { ...pad, buttons: pad.deviceMapping, axes: [] }); //TODO: resolve ts-ignore super(undefined, { ...pad, buttons: pad.deviceMapping, axes: [] }); //TODO: resolve ts-ignore
this.id = "xbox_360_fakepad"; this.id = "xbox_360_fakepad";
this.index = 0; this.index = 0;

View File

@ -1,6 +1,7 @@
import MockContainer from "#test/testUtils/mocks/mocksContainer/mockContainer"; import MockContainer from "#test/testUtils/mocks/mocksContainer/mockContainer";
export class MockImage extends MockContainer { export class MockImage extends MockContainer {
// biome-ignore lint/correctness/noUnusedPrivateClassMembers: this is intentional (?)
private texture; private texture;
constructor(textureManager, x, y, texture) { constructor(textureManager, x, y, texture) {

View File

@ -19,13 +19,13 @@ export default class MockSprite implements MockGameObject {
constructor(textureManager, x, y, texture) { constructor(textureManager, x, y, texture) {
this.textureManager = textureManager; this.textureManager = textureManager;
this.scene = textureManager.scene; this.scene = textureManager.scene;
// @ts-ignore // @ts-expect-error
Phaser.GameObjects.Sprite.prototype.setInteractive = this.setInteractive; Phaser.GameObjects.Sprite.prototype.setInteractive = this.setInteractive;
// @ts-ignore // @ts-expect-error
Phaser.GameObjects.Sprite.prototype.setTexture = this.setTexture; Phaser.GameObjects.Sprite.prototype.setTexture = this.setTexture;
// @ts-ignore // @ts-expect-error
Phaser.GameObjects.Sprite.prototype.setSizeToFrame = this.setSizeToFrame; Phaser.GameObjects.Sprite.prototype.setSizeToFrame = this.setSizeToFrame;
// @ts-ignore // @ts-expect-error
Phaser.GameObjects.Sprite.prototype.setFrame = this.setFrame; Phaser.GameObjects.Sprite.prototype.setFrame = this.setFrame;
// Phaser.GameObjects.Sprite.prototype.disable = this.disable; // Phaser.GameObjects.Sprite.prototype.disable = this.disable;

View File

@ -47,7 +47,7 @@ export function initTestFile() {
}); });
BBCodeText.prototype.destroy = () => null; BBCodeText.prototype.destroy = () => null;
// @ts-ignore // @ts-expect-error
BBCodeText.prototype.resize = () => null; BBCodeText.prototype.resize = () => null;
InputText.prototype.setElement = () => null as any; InputText.prototype.setElement = () => null as any;
InputText.prototype.resize = () => null as any; InputText.prototype.resize = () => null as any;