diff --git a/.dependency-cruiser.cjs b/.dependency-cruiser.cjs
index 08daf98fca4..8b956a11a11 100644
--- a/.dependency-cruiser.cjs
+++ b/.dependency-cruiser.cjs
@@ -5,9 +5,7 @@ module.exports = {
name: "no-non-type-@type-exports",
severity: "error",
comment:
- "Files in @types should not export anything but types and interfaces. " +
- "The folder is intended to house imports that are removed at runtime, " +
- "and thus should not contain anything with a bearing on runtime code.",
+ "Files in @types should not export anything but types and interfaces. The folder is intended to house imports that are removed at runtime, and thus should not contain anything with a bearing on runtime code.",
from: {},
to: {
path: "(^|/)src/@types",
@@ -29,8 +27,7 @@ module.exports = {
name: "no-circular-at-runtime",
severity: "error",
comment:
- "This dependency is part of a circular relationship. You might want to revise " +
- "your solution (i.e. use dependency inversion, make sure the modules have a single responsibility) ",
+ "This dependency is part of a circular relationship. You might want to revise your solution (i.e. use dependency inversion, make sure the modules have a single responsibility) ",
from: {},
to: {
circular: true,
@@ -42,11 +39,7 @@ module.exports = {
{
name: "no-orphans",
comment:
- "This is an orphan module - it's likely not used (anymore?). Either use it or " +
- "remove it. If it's logical this module is an orphan (i.e. it's a config file), " +
- "add an exception for it in your dependency-cruiser configuration. By default " +
- "this rule does not scrutinize dot-files (e.g. .eslintrc.js), TypeScript declaration " +
- "files (.d.ts), tsconfig.json and some of the babel and webpack configs.",
+ "This is an orphan module - it's likely not used (anymore?). Either use it or remove it. If it's logical this module is an orphan (i.e. it's a config file), add an exception for it in your dependency-cruiser configuration. By default this rule does not scrutinize dot-files (e.g. .eslintrc.js), TypeScript declaration files (.d.ts), tsconfig.json and some of the babel and webpack configs.",
severity: "error",
from: {
orphan: true,
@@ -63,8 +56,7 @@ module.exports = {
{
name: "no-deprecated-core",
comment:
- "A module depends on a node core module that has been deprecated. Find an alternative - these are " +
- "bound to exist - node doesn't deprecate lightly.",
+ "A module depends on a node core module that has been deprecated. Find an alternative - these are bound to exist - node doesn't deprecate lightly.",
severity: "error",
from: {},
to: {
@@ -96,8 +88,7 @@ module.exports = {
{
name: "not-to-deprecated",
comment:
- "This module uses a (version of an) npm module that has been deprecated. Either upgrade to a later " +
- "version of that module, or find an alternative. Deprecated modules are a security risk.",
+ "This module uses a (version of an) npm module that has been deprecated. Either upgrade to a later version of that module, or find an alternative. Deprecated modules are a security risk.",
severity: "error",
from: {},
to: {
@@ -108,10 +99,7 @@ module.exports = {
name: "no-non-package-json",
severity: "error",
comment:
- "This module depends on an npm package that isn't in the 'dependencies' section of your package.json. " +
- "That's problematic as the package either (1) won't be available on live (2 - worse) will be " +
- "available on live with an non-guaranteed version. Fix it by adding the package to the dependencies " +
- "in your package.json.",
+ "This module depends on an npm package that isn't in the 'dependencies' section of your package.json. That's problematic as the package either (1) won't be available on live (2 - worse) will be available on live with an non-guaranteed version. Fix it by adding the package to the dependencies in your package.json.",
from: {},
to: {
dependencyTypes: ["npm-no-pkg", "npm-unknown"],
@@ -120,8 +108,7 @@ module.exports = {
{
name: "not-to-unresolvable",
comment:
- "This module depends on a module that cannot be found ('resolved to disk'). If it's an npm " +
- "module: add it to your package.json. In all other cases you likely already know what to do.",
+ "This module depends on a module that cannot be found ('resolved to disk'). If it's an npm module: add it to your package.json. In all other cases you likely already know what to do.",
severity: "error",
from: {},
to: {
@@ -131,9 +118,7 @@ module.exports = {
{
name: "no-duplicate-dep-types",
comment:
- "Likely this module depends on an external ('npm') package that occurs more than once " +
- "in your package.json i.e. bot as a devDependencies and in dependencies. This will cause " +
- "maintenance problems later on.",
+ "Likely this module depends on an external ('npm') package that occurs more than once in your package.json i.e. bot as a devDependencies and in dependencies. This will cause maintenance problems later on.",
severity: "error",
from: {},
to: {
@@ -150,9 +135,7 @@ module.exports = {
{
name: "not-to-spec",
comment:
- "This module depends on a spec (test) file. The sole responsibility of a spec file is to test code. " +
- "If there's something in a spec that's of use to other modules, it doesn't have that single " +
- "responsibility anymore. Factor it out into (e.g.) a separate utility/ helper or a mock.",
+ "This module depends on a spec (test) file. The sole responsibility of a spec file is to test code. If there's something in a spec that's of use to other modules, it doesn't have that single responsibility anymore. Factor it out into (e.g.) a separate utility/ helper or a mock.",
severity: "error",
from: {},
to: {
@@ -163,11 +146,7 @@ module.exports = {
name: "not-to-dev-dep",
severity: "error",
comment:
- "This module depends on an npm package from the 'devDependencies' section of your " +
- "package.json. It looks like something that ships to production, though. To prevent problems " +
- "with npm packages that aren't there on production declare it (only!) in the 'dependencies'" +
- "section of your package.json. If this module is development only - add it to the " +
- "from.pathNot re of the not-to-dev-dep rule in the dependency-cruiser configuration",
+ "This module depends on an npm package from the 'devDependencies' section of your package.json. It looks like something that ships to production, though. To prevent problems with npm packages that aren't there on production declare it (only!) in the 'dependencies'section of your package.json. If this module is development only - add it to the from.pathNot re of the not-to-dev-dep rule in the dependency-cruiser configuration",
from: {
path: "^(src)",
pathNot: ["[.](?:spec|test|setup|script)[.](?:js|mjs|cjs|jsx|ts|mts|cts|tsx)$", "./test"],
@@ -184,10 +163,7 @@ module.exports = {
name: "optional-deps-used",
severity: "info",
comment:
- "This module depends on an npm package that is declared as an optional dependency " +
- "in your package.json. As this makes sense in limited situations only, it's flagged here. " +
- "If you're using an optional dependency here by design - add an exception to your" +
- "dependency-cruiser configuration.",
+ "This module depends on an npm package that is declared as an optional dependency in your package.json. As this makes sense in limited situations only, it's flagged here. If you're using an optional dependency here by design - add an exception to yourdependency-cruiser configuration.",
from: {},
to: {
dependencyTypes: ["npm-optional"],
@@ -196,10 +172,7 @@ module.exports = {
{
name: "peer-deps-used",
comment:
- "This module depends on an npm package that is declared as a peer dependency " +
- "in your package.json. This makes sense if your package is e.g. a plugin, but in " +
- "other cases - maybe not so much. If the use of a peer dependency is intentional " +
- "add an exception to your dependency-cruiser configuration.",
+ "This module depends on an npm package that is declared as a peer dependency in your package.json. This makes sense if your package is e.g. a plugin, but in other cases - maybe not so much. If the use of a peer dependency is intentional add an exception to your dependency-cruiser configuration.",
severity: "error",
from: {},
to: {
diff --git a/.editorconfig b/.editorconfig
index be478a2b5fa..fc5cfbe61e3 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -3,7 +3,7 @@
# top-most EditorConfig file
root = true
-[src/*.{js,ts}]
+[**/*.{js,ts,json,jsonc}]
indent_style = space
indent_size = 2
end_of_line = lf
diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml
index b7b1aad5ae7..6e056bc4032 100644
--- a/.github/workflows/github-pages.yml
+++ b/.github/workflows/github-pages.yml
@@ -77,9 +77,7 @@ jobs:
cd pokerogue_gh
git config user.email "github-actions[bot]@users.noreply.github.com"
git config user.name "github-actions[bot]"
- mkdir -p $GITHUB_REF_NAME
- rm -rf $GITHUB_REF_NAME/*
- cp -r /tmp/docs $GITHUB_REF_NAME
+ rsync -rd --delete /tmp/docs/ $GITHUB_REF_NAME
git add $GITHUB_REF_NAME
git commit -m "[skip ci] Deploy docs"
git push
diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml
index 08327ee3653..edecae64f95 100644
--- a/.github/workflows/linting.yml
+++ b/.github/workflows/linting.yml
@@ -18,7 +18,7 @@ on:
jobs:
run-linters:
- name: Run linters
+ name: Run all linters
timeout-minutes: 10
runs-on: ubuntu-latest
@@ -26,27 +26,86 @@ jobs:
- name: Check out Git repository
uses: actions/checkout@v4
with:
- submodules: 'recursive'
+ submodules: "recursive"
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10
- - name: Set up Node.js
+ - name: Set up Node
uses: actions/setup-node@v4
with:
- node-version-file: '.nvmrc'
- cache: 'pnpm'
+ node-version-file: ".nvmrc"
+ cache: "pnpm"
- - name: Install Node.js dependencies
+ - name: Install Node modules
run: pnpm i
- - name: Lint with Biome
+ # Lint files with Biome-Lint - https://biomejs.dev/linter/
+ - name: Run Biome-Lint
run: pnpm biome-ci
+ id: biome_lint
+ continue-on-error: true
- - name: Check dependencies with depcruise
+ # Validate dependencies with dependency-cruiser - https://github.com/sverweij/dependency-cruiser
+ - name: Run Dependency-Cruise
run: pnpm depcruise
-
- - name: Lint with ls-lint
- run: pnpm ls-lint
\ No newline at end of file
+ id: depcruise
+ continue-on-error: true
+
+ # Validate types with tsc - https://www.typescriptlang.org/docs/handbook/compiler-options.html#using-the-cli
+ - name: Run Typecheck
+ run: pnpm typecheck
+ id: typecheck
+ continue-on-error: true
+
+ # The exact same thing
+ - name: Run Typecheck (scripts)
+ run: pnpm typecheck:scripts
+ id: typecheck-scripts
+ continue-on-error: true
+
+ - name: Evaluate for Errors
+ env:
+ BIOME_LINT_OUTCOME: ${{ steps.biome_lint.outcome }}
+ DEPCRUISE_OUTCOME: ${{ steps.depcruise.outcome }}
+ TYPECHECK_OUTCOME: ${{ steps.typecheck.outcome }}
+ TYPECHECK_SCRIPTS_OUTCOME: ${{ steps.typecheck-scripts.outcome }}
+ run: |
+ # Check for Errors
+
+ # Make text red.
+ red () {
+ printf "\e[31m%s\e[0m" "$1"
+ }
+
+ # Make text green.
+ green () {
+ printf "\e[32m%s\e[0m" "$1"
+ }
+
+ print_result() {
+ local name=$1
+ local outcome=$2
+ if [ "$outcome" == "success" ]; then
+ printf "$(green "✅ $name: $outcome")\n"
+ else
+ printf "$(red "❌ $name: $outcome")\n"
+ fi
+ }
+
+ print_result "Biome" "$BIOME_LINT_OUTCOME"
+ print_result "Depcruise" "$DEPCRUISE_OUTCOME"
+ print_result "Typecheck" "$TYPECHECK_OUTCOME"
+ print_result "Typecheck scripts" "$TYPECHECK_SCRIPTS_OUTCOME"
+
+ if [[ "$BIOME_LINT_OUTCOME" != "success" || \
+ "$DEPCRUISE_OUTCOME" != "success" || \
+ "$TYPECHECK_OUTCOME" != "success" || \
+ "$TYPECHECK_SCRIPTS_OUTCOME" != "success" ]]; then
+ printf "$(red "❌ One or more checks failed!")\n" >&2
+ exit 1
+ fi
+
+ printf "$(green "✅ All checks passed!")\n"
diff --git a/.gitignore b/.gitignore
index 299767e742a..cdc0660d68c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,7 @@ node_modules
dist
dist-ssr
*.local
+build
# Editor directories and files (excluding `extensions.json` for devcontainer)
*.code-workspace
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index 81abc8df2c0..2197ad03ef2 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -10,4 +10,4 @@
"aaron-bond.better-comments",
"MuTsunTsai.jsdoc-link"
]
-}
\ No newline at end of file
+}
diff --git a/README.md b/README.md
index cf70b5d9335..73477968bc0 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,9 @@
-
+
-
+[](https://discord.gg/pokerogue)
[](https://pagefaultgames.github.io/pokerogue/beta)
[](https://github.com/pagefaultgames/pokerogue/actions/workflows/tests.yml)
-[](https://www.gnu.org/licenses/agpl-3.0)
+[](https://www.gnu.org/licenses/agpl-3.0)
PokéRogue is a browser based Pokémon fangame heavily inspired by the roguelite genre. Battle endlessly while gathering stacking items, exploring many different biomes, fighting trainers, bosses, and more!
diff --git a/biome.jsonc b/biome.jsonc
index a63ce0ee07d..e1aac032597 100644
--- a/biome.jsonc
+++ b/biome.jsonc
@@ -1,7 +1,7 @@
{
- "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json",
+ "$schema": "https://biomejs.dev/schemas/2.2.3/schema.json",
"vcs": {
- "enabled": false,
+ "enabled": true,
"clientKind": "git",
"useIgnoreFile": true,
"defaultBranch": "beta"
@@ -10,7 +10,7 @@
"enabled": true,
"useEditorconfig": true,
"indentStyle": "space",
- "includes": ["**", "!**/src/enums/**/*", "!**/src/data/balance/**/*"],
+ "includes": ["**", "!**/src/data/balance/**"],
"lineWidth": 120
},
"files": {
@@ -19,14 +19,12 @@
// and having to verify whether each individual file is ignored
"includes": [
"**",
- "!**/dist/**/*",
- "!**/build/**/*",
- "!**/coverage/**/*",
- "!**/public/**/*",
- "!**/.github/**/*",
- "!**/node_modules/**/*",
- "!**/.vscode/**/*",
- "!**/typedoc/**/*",
+ "!**/dist",
+ "!**/coverage",
+ "!**/public",
+ "!**/.github",
+ "!**/node_modules",
+ "!**/typedoc",
// TODO: lint css and html?
"!**/*.css",
"!**/*.html",
@@ -48,28 +46,75 @@
}
}
},
+ // TODO: Remove unneeded `options` blocks once biome's JSON schema is fixed to not require them
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"correctness": {
- "noUndeclaredVariables": "off",
+ "noUndeclaredVariables": "error",
"noUnusedVariables": "error",
"noSwitchDeclarations": "error",
"noVoidTypeReturn": "error",
"noUnusedImports": {
"level": "error",
- "fix": "safe"
+ "fix": "safe",
+ "options": {}
},
"noUnusedFunctionParameters": "error",
"noUnusedLabels": "error",
- "noPrivateImports": "error"
+ "noPrivateImports": "error",
+ "useSingleJsDocAsterisk": "error",
+ "useJsonImportAttributes": "off" // "Import attributes are only supported when the '--module' option is set to 'esnext', 'node18', 'nodenext', or 'preserve'. ts(2823)"
},
"style": {
- "useEnumInitializers": "off", // large enums like Moves/Species would make this cumbersome
+ "useExplicitLengthCheck": {
+ "level": "error",
+ "fix": "safe",
+ "options": {}
+ },
+ "useAtIndex": "error",
+ "noNegationElse": {
+ "level": "info", // TODO: Promote to error eventually
+ "fix": "unsafe", // duplicates else blocks
+ "options": {}
+ },
+ // TODO: Fix all instances of this and promote to `error` - this and enums are the 2 things
+ // barring us from `esModuleInterop`
+ "noParameterProperties": "warn",
+ "useConsistentBuiltinInstantiation": {
+ "level": "error",
+ "fix": "safe",
+ "options": {}
+ },
+ "noDefaultExport": "warn", // TODO: Fix `overrides.ts` and enable
+ "noShoutyConstants": "error",
+ "useThrowNewError": {
+ "level": "error",
+ "fix": "safe",
+ "options": {}
+ },
+ "useThrowOnlyError": "error",
+ "useTrimStartEnd": "error",
+ "useReadonlyClassProperties": {
+ "level": "info", // TODO: Graduate to error eventually
+ "options": { "checkAllProperties": true }
+ },
+ "useConsistentObjectDefinitions": {
+ "level": "error",
+ "options": { "syntax": "shorthand" }
+ },
+ "useCollapsedIf": "error",
+ "useCollapsedElseIf": "error",
+
+ "noSubstr": "error",
+ "noYodaExpression": "error",
+ "useForOf": "error",
+ "useEnumInitializers": "off", // large enums like MoveId/SpeciesId would make this cumbersome
"useBlockStatements": {
"level": "error",
- "fix": "safe"
+ "fix": "safe",
+ "options": {}
},
"useConst": "error",
"useImportType": "error",
@@ -80,9 +125,14 @@
// 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"
+ "fix": "none",
+ "options": {}
+ },
+ "useSingleVarDeclarator": {
+ "level": "error",
+ "fix": "safe",
+ "options": {}
},
- "useSingleVarDeclarator": "off",
"useNodejsImportProtocol": "off",
"useTemplate": "off", // string concatenation is faster: https://stackoverflow.com/questions/29055518/are-es6-template-literals-faster-than-string-concatenation
"useAsConstAssertion": "error",
@@ -100,58 +150,80 @@
}
}
}
- }
+ },
+
+ // TODO: Wait until the rule gets options for ignoring doc comments and/or different parameter names,
+ // and THEN enable it codebase-wide
+ "useUnifiedTypeSignatures": {
+ "level": "info",
+ "fix": "none",
+ "options": {}
+ },
+ "useGroupedAccessorPairs": "error",
+ "useObjectSpread": "error",
+ "useNumericSeparators": "off" // TODO: Consider enabling?
},
"suspicious": {
+ "useErrorMessage": "error",
+ "noEvolvingTypes": "warn", // TODO: Review and enable ASAP - this is VERY VERY BAD
+ "useNumberToFixedDigitsArgument": "error",
+ "useGuardForIn": "warn", // TODO: Review and enable ASAP - this is EVEN FRICKING WORSE
"noDoubleEquals": "error",
// While this would be a nice rule to enable, the current structure of the codebase makes this infeasible
// due to being used for move/ability `args` params and save data-related code.
// This can likely be enabled for all non-utils files once these are eventually reworked, but until then we leave it off.
"noExplicitAny": "off",
"noAssignInExpressions": "off",
- "noPrototypeBuiltins": "off",
+ "noPrototypeBuiltins": "off", // TODO: enable this
"noFallthroughSwitchClause": "error", // Prevents accidental automatic fallthroughs in switch cases (use disable comment if needed)
"noImplicitAnyLet": "warn", // TODO: Refactor and make this an error
"noRedeclare": "info", // TODO: Refactor and make this an error
- "noGlobalIsNan": "off",
+ "noGlobalIsNan": "error",
"noAsyncPromiseExecutor": "warn", // TODO: Refactor and make this an error
"noVar": "error",
- "noDocumentCookie": "off" // Firefox has minimal support for the "Cookie Store API"
+ "noDocumentCookie": "off", // Firefox has minimal support for the "Cookie Store API"
+ "noConstantBinaryExpressions": "error",
+ "noTsIgnore": "error",
+ "useIterableCallbackReturn": "warn" // TODO: Refactor and change to error
},
"complexity": {
+ "useWhile": "error",
+ "noVoid": "warn", // TODO: Review and enable ASAP - this is also bad
+ "noUselessStringConcat": "error",
"noExcessiveCognitiveComplexity": "info", // TODO: Refactor and make this an error
- "useLiteralKeys": "off",
+ "useLiteralKeys": "off", // TODO: enable?
"noForEach": "off", // Foreach vs for of is not that simple.
"noUselessSwitchCase": "off", // Explicit > Implicit
"noUselessConstructor": "error",
"noBannedTypes": "warn", // TODO: Refactor and make this an error
"noThisInStatic": "error",
"noUselessThisAlias": "error",
- "noUselessTernary": "error"
+ "noUselessTernary": "error",
+ "useIndexOf": "error"
},
"performance": {
"noNamespaceImport": "error",
- "noDelete": "error"
+ "noDelete": "error",
+ "noBarrelFile": "error"
},
"nursery": {
- "useAdjacentGetterSetter": "error",
- "noConstantBinaryExpression": "error",
- "noTsIgnore": "error",
- "noAwaitInLoop": "off",
- "useJsonImportAttribute": "off", // "Import attributes are only supported when the '--module' option is set to 'esnext', 'node18', 'nodenext', or 'preserve'. ts(2823)"
- "useIndexOf": "error",
- "useObjectSpread": "error",
- "useNumericSeparators": "off", // TODO: enable?
- "useIterableCallbackReturn": "warn", // TODO: refactor and make "error"
- "noShadow": "warn" // TODO: refactor and make "error"
+ "noUselessUndefined": "error",
+ "useMaxParams": {
+ "level": "warn", // TODO: Change to "error"... eventually...
+ "options": { "max": 4 } // A lot of stuff has a few params, but
+ },
+ "noShadow": "warn", // TODO: refactor and make "error"
+ "noNonNullAssertedOptionalChain": "warn" // TODO: refactor and make "error"
}
}
},
"javascript": {
"formatter": {
"quoteStyle": "double",
- "arrowParentheses": "asNeeded"
+ "arrowParentheses": "asNeeded",
+ "operatorLinebreak": "before"
},
+ "globals": ["Phaser"],
"parser": {
"jsxEverywhere": false
}
@@ -166,7 +238,7 @@
"noNamespaceImport": "off" // this is required for `vi.spyOn` to work in some tests
},
"style": {
- "noNonNullAssertion": "off"
+ "noNonNullAssertion": "off" // tedious in some tests
},
"nursery": {
"noFloatingPromises": "error"
@@ -175,10 +247,17 @@
}
},
- // Overrides to prevent unused import removal inside `overrides.ts` and enums files (for TSDoc linkcodes),
- // as well as in all TS files in `scripts/` (which are assumed to be boilerplate templates).
+ // Overrides to prevent unused import removal inside `overrides.ts`, enums & `.d.ts` files (for TSDoc linkcodes),
+ // as well as inside script boilerplate files.
{
- "includes": ["**/src/overrides.ts", "**/src/enums/**/*", "**/scripts/**/*.ts", "**/*.d.ts"],
+ // TODO: Rename existing boilerplates in the folder and remove this last alias
+ "includes": [
+ "**/src/overrides.ts",
+ "**/src/enums/**/*",
+ "**/*.d.ts",
+ "scripts/**/*.boilerplate.ts",
+ "**/boilerplates/*.ts"
+ ],
"linter": {
"rules": {
"correctness": {
@@ -188,7 +267,7 @@
}
},
{
- "includes": ["**/src/overrides.ts", "**/scripts/**/*.ts"],
+ "includes": ["**/src/overrides.ts"],
"linter": {
"rules": {
"style": {
diff --git a/docs/linting.md b/docs/linting.md
index d925b2f29af..9301917ae79 100644
--- a/docs/linting.md
+++ b/docs/linting.md
@@ -1,48 +1,57 @@
# Linting & Formatting
-Writing clean, readable code is important, and linters and formatters are an integral part of ensuring code quality and readability.
+Writing clean, readable code is important, and linters and formatters are an integral part of ensuring code quality and readability. \
It is for this reason we are using [Biome](https://biomejs.dev), an opinionated linter/formatter (akin to Prettier) with a heavy focus on speed and performance.
### Installation
-You probably installed Biome already without noticing it - it's included inside `package.json` and should've been downloaded when you ran `pnpm install` after cloning the repo. If you haven't done that yet, go do it.
+You probably installed Biome already without noticing it - it's included inside `package.json` and should've been downloaded when you ran `pnpm install` after cloning the repo. If you haven't done that yet, go do that first.
# Using Biome
-For the most part, Biome attempts to stay "out of your hair", letting you write code while enforcing a consistent formatting standard and only notifying for errors it can't automatically fix.\
+For the most part, Biome attempts to stay "out of your hair", letting you write code while enforcing a consistent formatting standard and only notifying for errors it can't automatically fix. \
On the other hand, if Biome complains about a piece of code, **there's probably a good reason why**. Disable comments should be used sparingly or when readabilty demands it - your first instinct should be to fix the code in question, not disable the rule.
## Editor Integration
Biome has integration with many popular code editors. See [these](https://biomejs.dev/guides/editors/first-party-extensions/) [pages](https://biomejs.dev/guides/editors/third-party-extensions/) for information about enabling Biome in your editor of choice.
## Automated Runs
-Generally speaking, most users shouldn't need to run Biome directly; in addition to editor integration, [pre-commit hook](../lefthook.yml) will periodically run Biome before each commit.
-You will **not** be able to push code with `error`-level linting problems - fix them beforehand.
+Generally speaking, most users shouldn't need to run Biome directly; in addition to editor integration, a [pre-commit hook](../lefthook.yml) will automatically format and lint all staged files before each commit.
-We also have a [Github Action](../.github/workflows/quality.yml) to verify code quality each time a PR is updated, preventing bad code from inadvertently making its way upstream.
+> ![WARNING]
+> You will **not** be able to commit code if any staged files contain `error`-level linting problems. \
+> If you, for whatever reason, _absolutely need_ to bypass Lefthook for a given commit,
+> pass the `--no-verify` flag to `git commit`.
+
+We also have a [Github Action](../.github/workflows/linting.yml) to verify code quality each time a PR is updated, preventing bad code from inadvertently making its way upstream. \
+These are effectively the same commands as run by Lefthook, merely on a project-wide scale.
## Running Biome via CLI
-If you want Biome to check your files manually, you can run it from the command line like so:
+To run you Biome on your files manually, you have 2 main options:
+1. Run the scripts included in `package.json` (`pnpm biome` and `pnpm biome:all`). \
+ These have sensible defaults for command-line options, but do not allow altering certain flags (as some cannot be specified twice in the same command)
-```sh
-pnpm exec biome check --[flags]
-```
+2. Execute the Biome executable manually from the command line like so:
+ ```sh
+ pnpm exec biome check --[flags]
+ ```
+ This allows customizing non-overridable flags like `--diagnostic-level` on a more granular level, but requires slightly more verbosity and specifying more options.
A full list of flags and options can be found on [their website](https://biomejs.dev/reference/cli/), but here's a few useful ones to keep in mind:
-- `--write` will cause Biome to write all "safe" fixes and formatting changes directly to your files (rather than just complaining and doing nothing).
-- `--changed` and `--staged` will only perform checks on all changed or staged files respectively. Biome sources this info from the relevant version control system (in this case Git).
+- `--write` will cause Biome to write all "safe" fixes and formatting changes directly to your files (rather than just complaining and erroring out).
+- `--changed` and `--staged` will limit checking to all changed or staged files respectively. Biome sources this info from the relevant version control system (in this case `git`).
- `diagnostic-level=XXX` will only show diagnostics with at least the given severity level (`info/warn/error`). Useful to only focus on errors causing a failed workflow run or similar.
## Linting Rules
-We primarily use Biome's [recommended ruleset](https://biomejs.dev/linter/rules/) for linting JS/TS, with some customizations to better suit our project's needs[^1].
+We primarily use Biome's [recommended ruleset](https://biomejs.dev/linter/rules/) for linting JS/TS files, with some customizations to better suit our project's needs[^1].
Some things to consider:
- We have disabled rules that prioritize style over performance, such as `useTemplate`.
-- Some rules are currently disabled or marked as warnings (`warn`) to allow for gradual refactoring without blocking development. **Do not write new code that triggers these warnings.**
+- Some rules are currently marked as warnings (`warn`) to allow for gradual refactoring without blocking development. **Do not write new code that triggers these rules!**
- The linter is configured to ignore specific files and folders (such as excessively large files or ones in need of refactoring) to improve performance and focus on actionable areas.
-Any questions about linting rules should be brought up in the `#dev-corner` channel in the discord.
+Any questions about linting rules can be brought up in the `#dev-corner` channel in the community Discord.
-[^1]: A complete list of rules can be found in the `biome.jsonc` file in the project root.
+[^1]: A complete list of rules can be found in the [`biome.jsonc`](../biome.jsonc) file in the project root. Many rules are accompanied by comments explaining the reasons for their inclusion (or lack thereof).
diff --git a/docs/localization.md b/docs/localization.md
index c325aaf55a9..e153d070818 100644
--- a/docs/localization.md
+++ b/docs/localization.md
@@ -1,6 +1,6 @@
# Localization 101
-PokéRogue's localization team puts immense effort into making the game accessible around the world, supporting over 12 different languages at the time of writing this document.
+PokéRogue's localization team puts immense effort into making the game accessible around the world, supporting over 12 different languages at the time of writing this document. \
As a developer, it's important to help maintain global accessibility by effectively coordinating with the Translation Team on any new features or enhancements.
This document aims to cover everything you need to know to help keep the integration process for localization smooth and simple.
@@ -19,11 +19,12 @@ This repository is integrated into the main one as a [git submodule](https://git
## What Is a Submodule?
-In essence, a submodule is a way for one repository (i.e. `pokerogue`) to use another repository (i.e. `pokerogue-locales`) internally.
+In essence, a submodule is a way for one repository (i.e. `pokerogue`) to use another repository (i.e. `pokerogue-locales`) internally.
The parent repo (the "superproject") houses a cloned version of the 2nd repository (the "submodule") inside it, making locales effectively a "repository within a repository", so to speak.
>[!TIP]
> Many popular IDEs have integrated `git` support with special handling around submodules:
+>
> 
>
> 
@@ -32,14 +33,14 @@ The parent repo (the "superproject") houses a cloned version of the 2nd reposito
The following command will initialize your branch's locales repository and update its HEAD:
```bash
-git submodule update --init --recursive
+pnpm update-locales
```
> [!TIP]
> This command is run _automatically_ after cloning, merging or changing branches, so you should rarely have to run it manually.
> [!IMPORTANT]
-> If you run into issues with the `locales` submodule, try deleting the `.git/modules/public` and `public/locales` folders before re-running the command.
+> If you EVER run into issues with the `locales` submodule, try deleting the `.git/modules/public` and `public/locales` folders before re-initializing it again.
## How Are Translations Integrated?
@@ -65,7 +66,7 @@ The basic process for fetching translated text goes roughly as follows:
```
# Submitting Locales Changes
-If you have a feature or enhancement that requires additions or changes to in-game text, you will need to make a fork of the `pokerogue-locales` repo and submit your text changes as a pull request _in addition_ to your pull request to the main project.
+If you have a feature or enhancement that requires additions or changes to in-game text, you will need to make a fork of the `pokerogue-locales` repo and submit your text changes as a pull request _in addition_ to your pull request to the main project. \
Since these two PRs aren't _technically_ linked, it's important to coordinate with the Translation Team to ensure that both PRs are integrated safely into the project.
> [!CAUTION]
@@ -73,29 +74,29 @@ Since these two PRs aren't _technically_ linked, it's important to coordinate wi
## Making Changes
-One perk of submodules is you don't actually _need_ to clone the locales repository to start contributing - initializing the submodule already does that for you.
+One perk of submodules is you don't actually _need_ to clone the locales repository to start contributing - `git` already does that for you on initialization.
Given `pokerogue-locales` is a full-fledged `git` repository _inside_ `pokerogue`, making changes is roughly the same as normal, merely using `public/locales` as your root directory.
> [!WARNING]
-> Make sure to checkout or rebase onto `upstream/HEAD` **BEFORE** creating a PR!
+> Make sure to checkout or rebase onto `upstream/main` (`pnpm update-locales:remote`) **BEFORE** creating a locales PR!
> The checked-out commit is based on the superproject's SHA-1 by default, so hastily making changes may see you basing your commits on last week's `HEAD`.
## Requirements for Adding Translated Text
-When your new feature or enhancement requires adding a new locales key **without changing text in existing keys**, we require the following workflow with regards to localization:
+When a new feature or enhancement requires adding a new locales key **without changing text in existing keys**, we have the following workflow with regards to localization:
1. You (the developer) make a pull request to the main repository for your new feature.
If this feature requires new text, the text should be integrated into the code with a new `i18next` key pointing to where you plan to add it into the locales repository.
2. You then make another pull request — this time to the `pokerogue-locales` repository — adding a new entry with text for each key you added to your main PR.
- - You must add the corresponding **English keys** while making the PR; the Translation Team can take care of the rest[^2].
- - For any feature pulled from the mainline Pokémon games (e.g. a Move or Ability implementation), it's best practice to include a source link for any added text.
- [Poké Corpus](https://abcboy101.github.io/poke-corpus/) is a great resource for finding text from the mainline games; otherwise, a video/picture showing the text being displayed should suffice.
- - You should also [notify the current Head of Translation](#notifying-translation) to ensure a fast response.
+ - You must add the corresponding **English keys** while making the PR; the Translation Team can take care of the rest[^2].
+ - For any feature pulled from the mainline Pokémon games (e.g. a Move or Ability implementation), it's best practice to include a source link for any added text. \
+ [Poké Corpus](https://abcboy101.github.io/poke-corpus/) is a great resource for finding text from the mainline games; otherwise, a video/picture showing the text being displayed should suffice.
+ - You should also [notify the current Head of Translation](#notifying-translation) to ensure a fast response.
3. Your locales should use the following format:
- File names should be in `kebab-case`. Example: `trainer-names.json`
- Key names should be in `camelCase`. Example: `aceTrainer`
- If you make use of i18next's inbuilt [context support](https://www.i18next.com/translation-function/context), you need to use `snake_case` for the context key. Example: `aceTrainer_male`
4. At this point, you may begin [testing locales integration in your main PR](#documenting-locales-changes).
-5. The Translation Team will approve the locale PR (after corrections, if necessary), then merge it into `pokerogue-locales`.
+5. The Translation Team will approve the locales PR (after corrections, if necessary), then merge it into `pokerogue-locales`.
6. The Dev Team will approve your main PR for your feature, then merge it into PokéRogue's beta environment.
[^2]: For those wondering, the reason for choosing English specifically is due to it being the master language set in Pontoon (the program used by the Translation Team to perform locale updates).
@@ -106,7 +107,7 @@ If a key is present in any language _except_ the master language, it won't appea
PRs that modify existing text have different risks with respect to coordination between development and translation, so their requirements are slightly different:
- As above, you set up 2 PRs: one for the feature itself in the main repo, and another for the associated locales changes in the locale repo.
- Now, however, you need to have your main PR be approved by the Dev Team **before** your corresponding locale changes are merged in.
-- After your main PR is approved, the Translation Team will merge your locale PR, and you may update the submodule and post video evidence of integration into the **locales PR**.
+- After your main PR is approved, you may update the submodule and post video evidence of integration into the **locales PR**.
- A Lead or Senior Translator from the Translation Team will then approve your main PR (if all is well), clearing your feature for merging into `beta`.
## Documenting Locales Changes
@@ -115,12 +116,12 @@ After making a PR involving any outwards-facing behavior (but _especially_ local
The basic procedure is roughly as follows:
1. Update your locales submodule to point to **the branch you used to make the locales PR**. \
- Many IDEs with `git` integration support doing this from the GUI, \
- or you can simply do it via command-line:
- ```bash
- cd public/locales
- git checkout your-branch-name-here
- ```
+ Many IDEs with `git` integration support doing this from the GUI, \
+ or you can simply do it via command-line:
+ ```bash
+ cd public/locales
+ git checkout your-branch-name-here
+ ```
2. Set some of the [in-game overrides](../CONTRIBUTING.md#1---manual-testing) inside `overrides.ts` to values corresponding to the interactions being tested.
3. Start a local dev server (`pnpm start:dev`) and open localhost in your browser.
4. Take screenshots or record a video of the locales changes being displayed in-game using the software of your choice[^2].
diff --git a/lefthook.yml b/lefthook.yml
index 8b5ad2234ed..c26ea8705b9 100644
--- a/lefthook.yml
+++ b/lefthook.yml
@@ -1,10 +1,12 @@
pre-commit:
- skip:
+ skip:
- merge
- rebase
commands:
biome-lint:
- run: pnpm exec biome check --write --reporter=summary --staged --no-errors-on-unmatched
+ # Disable colors as certain IDEs don't support it in the output pane.
+ # Summary mode looks decent in plain ASCII anyhow
+ run: pnpm exec biome check --write --colors=off --reporter=summary --staged --no-errors-on-unmatched --diagnostic-level=error
stage_fixed: true
ls-lint:
run: pnpm exec ls-lint
@@ -12,11 +14,11 @@ pre-commit:
post-merge:
commands:
update-submodules:
- run: git submodule update --init --recursive
+ run: pnpm update-locales
post-checkout:
commands:
update-submodules:
# cf https://git-scm.com/docs/githooks#_post_checkout:
# The 3rd argument is 1 for branch checkouts and 0 for file checkouts.
- run: if test {3} -eq "1"; then git submodule update --init --recursive; fi
\ No newline at end of file
+ run: if test {3} -eq "1"; then pnpm update-locales; fi
\ No newline at end of file
diff --git a/package.json b/package.json
index 0620cf6a88c..65936f2599a 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "pokemon-rogue-battle",
"private": true,
- "version": "1.10.6",
+ "version": "1.10.7",
"type": "module",
"scripts": {
"start:prod": "vite --mode production",
@@ -15,25 +15,30 @@
"test:watch": "vitest watch --coverage --no-isolate",
"test:silent": "vitest run --silent='passed-only' --no-isolate",
"test:create": "node scripts/create-test/create-test.js",
+ "eggMoves:parse": "node scripts/parse-egg-moves/main.js",
"scrape-trainers": "node scripts/scrape-trainer-names/main.js",
"typecheck": "tsc --noEmit",
+ "typecheck:scripts": "tsc -p scripts/jsconfig.json",
"biome": "biome check --write --changed --no-errors-on-unmatched --diagnostic-level=error",
+ "biome:all": "biome check --write --no-errors-on-unmatched --diagnostic-level=error",
"biome-ci": "biome ci --diagnostic-level=error --reporter=github --no-errors-on-unmatched",
"typedoc": "typedoc",
"depcruise": "depcruise src test",
"postinstall": "lefthook install; git submodule update --init --recursive",
"update-version:patch": "pnpm version patch --force --no-git-tag-version",
"update-version:minor": "pnpm version minor --force --no-git-tag-version",
+ "update-locales": "git submodule update --progress --init --recursive",
"update-locales:remote": "git submodule update --progress --init --recursive --force --remote"
},
"devDependencies": {
- "@biomejs/biome": "2.0.0",
+ "@biomejs/biome": "2.2.3",
"@ls-lint/ls-lint": "2.3.1",
"@types/crypto-js": "^4.2.0",
"@types/jsdom": "^21.1.7",
"@types/node": "^22.16.5",
"@vitest/coverage-istanbul": "^3.2.4",
"@vitest/expect": "^3.2.4",
+ "@vitest/utils": "^3.2.4",
"chalk": "^5.4.1",
"dependency-cruiser": "^16.10.4",
"inquirer": "^12.8.2",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 089689818ac..54012c3dd86 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -43,8 +43,8 @@ importers:
version: 1.80.16(graphology-types@0.24.8)
devDependencies:
'@biomejs/biome':
- specifier: 2.0.0
- version: 2.0.0
+ specifier: 2.2.3
+ version: 2.2.3
'@ls-lint/ls-lint':
specifier: 2.3.1
version: 2.3.1
@@ -63,6 +63,9 @@ importers:
'@vitest/expect':
specifier: ^3.2.4
version: 3.2.4
+ '@vitest/utils':
+ specifier: ^3.2.4
+ version: 3.2.4
chalk:
specifier: ^5.4.1
version: 5.4.1
@@ -192,55 +195,55 @@ packages:
resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==}
engines: {node: '>=6.9.0'}
- '@biomejs/biome@2.0.0':
- resolution: {integrity: sha512-BlUoXEOI/UQTDEj/pVfnkMo8SrZw3oOWBDrXYFT43V7HTkIUDkBRY53IC5Jx1QkZbaB+0ai1wJIfYwp9+qaJTQ==}
+ '@biomejs/biome@2.2.3':
+ resolution: {integrity: sha512-9w0uMTvPrIdvUrxazZ42Ib7t8Y2yoGLKLdNne93RLICmaHw7mcLv4PPb5LvZLJF3141gQHiCColOh/v6VWlWmg==}
engines: {node: '>=14.21.3'}
hasBin: true
- '@biomejs/cli-darwin-arm64@2.0.0':
- resolution: {integrity: sha512-QvqWYtFFhhxdf8jMAdJzXW+Frc7X8XsnHQLY+TBM1fnT1TfeV/v9vsFI5L2J7GH6qN1+QEEJ19jHibCY2Ypplw==}
+ '@biomejs/cli-darwin-arm64@2.2.3':
+ resolution: {integrity: sha512-OrqQVBpadB5eqzinXN4+Q6honBz+tTlKVCsbEuEpljK8ASSItzIRZUA02mTikl3H/1nO2BMPFiJ0nkEZNy3B1w==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [darwin]
- '@biomejs/cli-darwin-x64@2.0.0':
- resolution: {integrity: sha512-5JFhls1EfmuIH4QGFPlNpxJQFC6ic3X1ltcoLN+eSRRIPr6H/lUS1ttuD0Fj7rPgPhZqopK/jfH8UVj/1hIsQw==}
+ '@biomejs/cli-darwin-x64@2.2.3':
+ resolution: {integrity: sha512-OCdBpb1TmyfsTgBAM1kPMXyYKTohQ48WpiN9tkt9xvU6gKVKHY4oVwteBebiOqyfyzCNaSiuKIPjmHjUZ2ZNMg==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [darwin]
- '@biomejs/cli-linux-arm64-musl@2.0.0':
- resolution: {integrity: sha512-Bxsz8ki8+b3PytMnS5SgrGV+mbAWwIxI3ydChb/d1rURlJTMdxTTq5LTebUnlsUWAX6OvJuFeiVq9Gjn1YbCyA==}
+ '@biomejs/cli-linux-arm64-musl@2.2.3':
+ resolution: {integrity: sha512-q3w9jJ6JFPZPeqyvwwPeaiS/6NEszZ+pXKF+IczNo8Xj6fsii45a4gEEicKyKIytalV+s829ACZujQlXAiVLBQ==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [linux]
- '@biomejs/cli-linux-arm64@2.0.0':
- resolution: {integrity: sha512-BAH4QVi06TzAbVchXdJPsL0Z/P87jOfes15rI+p3EX9/EGTfIjaQ9lBVlHunxcmoptaA5y1Hdb9UYojIhmnjIw==}
+ '@biomejs/cli-linux-arm64@2.2.3':
+ resolution: {integrity: sha512-g/Uta2DqYpECxG+vUmTAmUKlVhnGEcY7DXWgKP8ruLRa8Si1QHsWknPY3B/wCo0KgYiFIOAZ9hjsHfNb9L85+g==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [linux]
- '@biomejs/cli-linux-x64-musl@2.0.0':
- resolution: {integrity: sha512-tiQ0ABxMJb9I6GlfNp0ulrTiQSFacJRJO8245FFwE3ty3bfsfxlU/miblzDIi+qNrgGsLq5wIZcVYGp4c+HXZA==}
+ '@biomejs/cli-linux-x64-musl@2.2.3':
+ resolution: {integrity: sha512-y76Dn4vkP1sMRGPFlNc+OTETBhGPJ90jY3il6jAfur8XWrYBQV3swZ1Jo0R2g+JpOeeoA0cOwM7mJG6svDz79w==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [linux]
- '@biomejs/cli-linux-x64@2.0.0':
- resolution: {integrity: sha512-09PcOGYTtkopWRm6mZ/B6Mr6UHdkniUgIG/jLBv+2J8Z61ezRE+xQmpi3yNgUrFIAU4lPA9atg7mhvE/5Bo7Wg==}
+ '@biomejs/cli-linux-x64@2.2.3':
+ resolution: {integrity: sha512-LEtyYL1fJsvw35CxrbQ0gZoxOG3oZsAjzfRdvRBRHxOpQ91Q5doRVjvWW/wepgSdgk5hlaNzfeqpyGmfSD0Eyw==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [linux]
- '@biomejs/cli-win32-arm64@2.0.0':
- resolution: {integrity: sha512-vrTtuGu91xNTEQ5ZcMJBZuDlqr32DWU1r14UfePIGndF//s2WUAmer4FmgoPgruo76rprk37e8S2A2c0psXdxw==}
+ '@biomejs/cli-win32-arm64@2.2.3':
+ resolution: {integrity: sha512-Ms9zFYzjcJK7LV+AOMYnjN3pV3xL8Prxf9aWdDVL74onLn5kcvZ1ZMQswE5XHtnd/r/0bnUd928Rpbs14BzVmA==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [win32]
- '@biomejs/cli-win32-x64@2.0.0':
- resolution: {integrity: sha512-2USVQ0hklNsph/KIR72ZdeptyXNnQ3JdzPn3NbjI4Sna34CnxeiYAaZcZzXPDl5PYNFBivV4xmvT3Z3rTmyDBg==}
+ '@biomejs/cli-win32-x64@2.2.3':
+ resolution: {integrity: sha512-gvCpewE7mBwBIpqk1YrUqNR4mCiyJm6UI3YWQQXkedSSEwzRdodRpaKhbdbHw1/hmTWOVXQ+Eih5Qctf4TCVOQ==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [win32]
@@ -2151,39 +2154,39 @@ snapshots:
'@babel/helper-string-parser': 7.27.1
'@babel/helper-validator-identifier': 7.27.1
- '@biomejs/biome@2.0.0':
+ '@biomejs/biome@2.2.3':
optionalDependencies:
- '@biomejs/cli-darwin-arm64': 2.0.0
- '@biomejs/cli-darwin-x64': 2.0.0
- '@biomejs/cli-linux-arm64': 2.0.0
- '@biomejs/cli-linux-arm64-musl': 2.0.0
- '@biomejs/cli-linux-x64': 2.0.0
- '@biomejs/cli-linux-x64-musl': 2.0.0
- '@biomejs/cli-win32-arm64': 2.0.0
- '@biomejs/cli-win32-x64': 2.0.0
+ '@biomejs/cli-darwin-arm64': 2.2.3
+ '@biomejs/cli-darwin-x64': 2.2.3
+ '@biomejs/cli-linux-arm64': 2.2.3
+ '@biomejs/cli-linux-arm64-musl': 2.2.3
+ '@biomejs/cli-linux-x64': 2.2.3
+ '@biomejs/cli-linux-x64-musl': 2.2.3
+ '@biomejs/cli-win32-arm64': 2.2.3
+ '@biomejs/cli-win32-x64': 2.2.3
- '@biomejs/cli-darwin-arm64@2.0.0':
+ '@biomejs/cli-darwin-arm64@2.2.3':
optional: true
- '@biomejs/cli-darwin-x64@2.0.0':
+ '@biomejs/cli-darwin-x64@2.2.3':
optional: true
- '@biomejs/cli-linux-arm64-musl@2.0.0':
+ '@biomejs/cli-linux-arm64-musl@2.2.3':
optional: true
- '@biomejs/cli-linux-arm64@2.0.0':
+ '@biomejs/cli-linux-arm64@2.2.3':
optional: true
- '@biomejs/cli-linux-x64-musl@2.0.0':
+ '@biomejs/cli-linux-x64-musl@2.2.3':
optional: true
- '@biomejs/cli-linux-x64@2.0.0':
+ '@biomejs/cli-linux-x64@2.2.3':
optional: true
- '@biomejs/cli-win32-arm64@2.0.0':
+ '@biomejs/cli-win32-arm64@2.2.3':
optional: true
- '@biomejs/cli-win32-x64@2.0.0':
+ '@biomejs/cli-win32-x64@2.2.3':
optional: true
'@bundled-es-modules/cookie@2.0.1':
diff --git a/public/images/ui/legacy/numbers_alt.png b/public/images/ui/legacy/numbers_alt.png
deleted file mode 100644
index fb510465471..00000000000
Binary files a/public/images/ui/legacy/numbers_alt.png and /dev/null differ
diff --git a/public/images/ui/legacy/numbers_red_alt.png b/public/images/ui/legacy/numbers_red_alt.png
deleted file mode 100644
index d9edb0468d8..00000000000
Binary files a/public/images/ui/legacy/numbers_red_alt.png and /dev/null differ
diff --git a/public/images/ui/legacy/overlay_lv.png b/public/images/ui/legacy/overlay_lv.png
deleted file mode 100644
index fdcbb1c7082..00000000000
Binary files a/public/images/ui/legacy/overlay_lv.png and /dev/null differ
diff --git a/public/images/ui/legacy/overlay_lv_alt.png b/public/images/ui/legacy/overlay_lv_alt.png
deleted file mode 100644
index 92ec684bf75..00000000000
Binary files a/public/images/ui/legacy/overlay_lv_alt.png and /dev/null differ
diff --git a/public/images/ui/legacy/party_slot_hp_bar.png b/public/images/ui/legacy/party_slot_hp_bar.png
index 6a37002744c..7ec53ae806b 100644
Binary files a/public/images/ui/legacy/party_slot_hp_bar.png and b/public/images/ui/legacy/party_slot_hp_bar.png differ
diff --git a/public/images/ui/legacy/party_slot_overlay_lv_alt.png b/public/images/ui/legacy/party_slot_overlay_lv_alt.png
deleted file mode 100644
index 7aa9a590a13..00000000000
Binary files a/public/images/ui/legacy/party_slot_overlay_lv_alt.png and /dev/null differ
diff --git a/public/images/ui/legacy/pbinfo_enemy_boss.png b/public/images/ui/legacy/pbinfo_enemy_boss.png
index 98b2f09f941..20eb74c59b3 100644
Binary files a/public/images/ui/legacy/pbinfo_enemy_boss.png and b/public/images/ui/legacy/pbinfo_enemy_boss.png differ
diff --git a/public/images/ui/legacy/pbinfo_enemy_mini.png b/public/images/ui/legacy/pbinfo_enemy_mini.png
index c1c002a4b21..7beddd98d55 100644
Binary files a/public/images/ui/legacy/pbinfo_enemy_mini.png and b/public/images/ui/legacy/pbinfo_enemy_mini.png differ
diff --git a/public/images/ui/legacy/pbinfo_player.png b/public/images/ui/legacy/pbinfo_player.png
index 60c92f886aa..f9e16a9aa0c 100644
Binary files a/public/images/ui/legacy/pbinfo_player.png and b/public/images/ui/legacy/pbinfo_player.png differ
diff --git a/public/images/ui/legacy/pbinfo_player_mini.png b/public/images/ui/legacy/pbinfo_player_mini.png
index 120e9592ab9..183db0d44f9 100644
Binary files a/public/images/ui/legacy/pbinfo_player_mini.png and b/public/images/ui/legacy/pbinfo_player_mini.png differ
diff --git a/public/images/ui/legacy/pbinfo_stat.png b/public/images/ui/legacy/pbinfo_stat.png
deleted file mode 100644
index 25c94f9a807..00000000000
Binary files a/public/images/ui/legacy/pbinfo_stat.png and /dev/null differ
diff --git a/public/images/ui/legacy/text_images/ca/battle_ui/overlay_exp_label_ca.png b/public/images/ui/legacy/text_images/ca/battle_ui/overlay_exp_label_ca.png
new file mode 100644
index 00000000000..acb04a84a31
Binary files /dev/null and b/public/images/ui/legacy/text_images/ca/battle_ui/overlay_exp_label_ca.png differ
diff --git a/public/images/ui/legacy/text_images/ca/battle_ui/overlay_hp_label_boss_ca.png b/public/images/ui/legacy/text_images/ca/battle_ui/overlay_hp_label_boss_ca.png
new file mode 100644
index 00000000000..283d63fb235
Binary files /dev/null and b/public/images/ui/legacy/text_images/ca/battle_ui/overlay_hp_label_boss_ca.png differ
diff --git a/public/images/ui/legacy/text_images/ca/battle_ui/overlay_hp_label_ca.png b/public/images/ui/legacy/text_images/ca/battle_ui/overlay_hp_label_ca.png
new file mode 100644
index 00000000000..4f388b70a75
Binary files /dev/null and b/public/images/ui/legacy/text_images/ca/battle_ui/overlay_hp_label_ca.png differ
diff --git a/public/images/ui/legacy/text_images/ca/battle_ui/overlay_lv_ca.png b/public/images/ui/legacy/text_images/ca/battle_ui/overlay_lv_ca.png
new file mode 100644
index 00000000000..7fdf26388bf
Binary files /dev/null and b/public/images/ui/legacy/text_images/ca/battle_ui/overlay_lv_ca.png differ
diff --git a/public/images/ui/legacy/text_images/ca/battle_ui/pbinfo_stat_ca.json b/public/images/ui/legacy/text_images/ca/battle_ui/pbinfo_stat_ca.json
new file mode 100644
index 00000000000..4bae82011ea
--- /dev/null
+++ b/public/images/ui/legacy/text_images/ca/battle_ui/pbinfo_stat_ca.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_ca.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 112,
+ "h": 8
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 18,
+ "h": 8
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 18,
+ "h": 8
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 18,
+ "h": 8
+ },
+ "frame": {
+ "x": 18,
+ "y": 0,
+ "w": 18,
+ "h": 8
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 16,
+ "h": 8
+ },
+ "frame": {
+ "x": 36,
+ "y": 0,
+ "w": 16,
+ "h": 8
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ },
+ "frame": {
+ "x": 52,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ },
+ "frame": {
+ "x": 64,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ },
+ "frame": {
+ "x": 76,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ },
+ "frame": {
+ "x": 88,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ },
+ "frame": {
+ "x": 100,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 8,
+ "h": 8
+ },
+ "frame": {
+ "x": 112,
+ "y": 0,
+ "w": 8,
+ "h": 8
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:40d30205ce8efd40dfa86cd11b0491d6:7076db6ed74199dcfb38fc8cd4d4a0e8:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/legacy/text_images/ca/battle_ui/pbinfo_stat_ca.png b/public/images/ui/legacy/text_images/ca/battle_ui/pbinfo_stat_ca.png
new file mode 100644
index 00000000000..a6ccf90c284
Binary files /dev/null and b/public/images/ui/legacy/text_images/ca/battle_ui/pbinfo_stat_ca.png differ
diff --git a/public/images/ui/legacy/text_images/ca/party_ui/party_slot_overlay_hp_ca.png b/public/images/ui/legacy/text_images/ca/party_ui/party_slot_overlay_hp_ca.png
new file mode 100644
index 00000000000..981d8573aca
Binary files /dev/null and b/public/images/ui/legacy/text_images/ca/party_ui/party_slot_overlay_hp_ca.png differ
diff --git a/public/images/ui/legacy/text_images/ca/party_ui/party_slot_overlay_lv_ca.png b/public/images/ui/legacy/text_images/ca/party_ui/party_slot_overlay_lv_ca.png
new file mode 100644
index 00000000000..512db34fa85
Binary files /dev/null and b/public/images/ui/legacy/text_images/ca/party_ui/party_slot_overlay_lv_ca.png differ
diff --git a/public/images/ui/legacy/text_images/da/battle_ui/overlay_exp_label_da.png b/public/images/ui/legacy/text_images/da/battle_ui/overlay_exp_label_da.png
new file mode 100644
index 00000000000..4c456fff94e
Binary files /dev/null and b/public/images/ui/legacy/text_images/da/battle_ui/overlay_exp_label_da.png differ
diff --git a/public/images/ui/legacy/text_images/da/battle_ui/overlay_hp_label_boss_da.png b/public/images/ui/legacy/text_images/da/battle_ui/overlay_hp_label_boss_da.png
new file mode 100644
index 00000000000..283d63fb235
Binary files /dev/null and b/public/images/ui/legacy/text_images/da/battle_ui/overlay_hp_label_boss_da.png differ
diff --git a/public/images/ui/legacy/text_images/da/battle_ui/overlay_hp_label_da.png b/public/images/ui/legacy/text_images/da/battle_ui/overlay_hp_label_da.png
new file mode 100644
index 00000000000..67824c7ee4e
Binary files /dev/null and b/public/images/ui/legacy/text_images/da/battle_ui/overlay_hp_label_da.png differ
diff --git a/public/images/ui/legacy/text_images/da/battle_ui/overlay_lv_da.png b/public/images/ui/legacy/text_images/da/battle_ui/overlay_lv_da.png
new file mode 100644
index 00000000000..ea32ac03ee2
Binary files /dev/null and b/public/images/ui/legacy/text_images/da/battle_ui/overlay_lv_da.png differ
diff --git a/public/images/ui/legacy/text_images/da/battle_ui/pbinfo_stat_da.json b/public/images/ui/legacy/text_images/da/battle_ui/pbinfo_stat_da.json
new file mode 100644
index 00000000000..eca2a9071ac
--- /dev/null
+++ b/public/images/ui/legacy/text_images/da/battle_ui/pbinfo_stat_da.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_da.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 112,
+ "h": 6
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 18,
+ "h": 6
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 18,
+ "h": 6
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 18,
+ "h": 6
+ },
+ "frame": {
+ "x": 18,
+ "y": 0,
+ "w": 18,
+ "h": 6
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 16,
+ "h": 6
+ },
+ "frame": {
+ "x": 36,
+ "y": 0,
+ "w": 16,
+ "h": 6
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 52,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 64,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 76,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 88,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 100,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 8,
+ "h": 6
+ },
+ "frame": {
+ "x": 112,
+ "y": 0,
+ "w": 8,
+ "h": 6
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:40d30205ce8efd40dfa86cd11b0491d6:7076db6ed74199dcfb38fc8cd4d4a0e8:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/legacy/text_images/da/battle_ui/pbinfo_stat_da.png b/public/images/ui/legacy/text_images/da/battle_ui/pbinfo_stat_da.png
new file mode 100644
index 00000000000..c729e7a2207
Binary files /dev/null and b/public/images/ui/legacy/text_images/da/battle_ui/pbinfo_stat_da.png differ
diff --git a/public/images/ui/legacy/text_images/da/party_ui/party_slot_overlay_hp_da.png b/public/images/ui/legacy/text_images/da/party_ui/party_slot_overlay_hp_da.png
new file mode 100644
index 00000000000..a78ac090d3b
Binary files /dev/null and b/public/images/ui/legacy/text_images/da/party_ui/party_slot_overlay_hp_da.png differ
diff --git a/public/images/ui/legacy/party_slot_overlay_lv.png b/public/images/ui/legacy/text_images/da/party_ui/party_slot_overlay_lv_da.png
similarity index 100%
rename from public/images/ui/legacy/party_slot_overlay_lv.png
rename to public/images/ui/legacy/text_images/da/party_ui/party_slot_overlay_lv_da.png
diff --git a/public/images/ui/legacy/text_images/de/battle_ui/overlay_exp_label_de.png b/public/images/ui/legacy/text_images/de/battle_ui/overlay_exp_label_de.png
new file mode 100644
index 00000000000..4c456fff94e
Binary files /dev/null and b/public/images/ui/legacy/text_images/de/battle_ui/overlay_exp_label_de.png differ
diff --git a/public/images/ui/legacy/text_images/de/battle_ui/overlay_hp_label_boss_de.png b/public/images/ui/legacy/text_images/de/battle_ui/overlay_hp_label_boss_de.png
new file mode 100644
index 00000000000..283d63fb235
Binary files /dev/null and b/public/images/ui/legacy/text_images/de/battle_ui/overlay_hp_label_boss_de.png differ
diff --git a/public/images/ui/legacy/text_images/de/battle_ui/overlay_hp_label_de.png b/public/images/ui/legacy/text_images/de/battle_ui/overlay_hp_label_de.png
new file mode 100644
index 00000000000..b8404159bc9
Binary files /dev/null and b/public/images/ui/legacy/text_images/de/battle_ui/overlay_hp_label_de.png differ
diff --git a/public/images/ui/legacy/text_images/de/battle_ui/overlay_lv_de.png b/public/images/ui/legacy/text_images/de/battle_ui/overlay_lv_de.png
new file mode 100644
index 00000000000..ea32ac03ee2
Binary files /dev/null and b/public/images/ui/legacy/text_images/de/battle_ui/overlay_lv_de.png differ
diff --git a/public/images/ui/legacy/text_images/de/battle_ui/pbinfo_stat_de.json b/public/images/ui/legacy/text_images/de/battle_ui/pbinfo_stat_de.json
new file mode 100644
index 00000000000..c5ace776596
--- /dev/null
+++ b/public/images/ui/legacy/text_images/de/battle_ui/pbinfo_stat_de.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_de.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 112,
+ "h": 6
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 18,
+ "h": 6
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 18,
+ "h": 6
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 18,
+ "h": 6
+ },
+ "frame": {
+ "x": 18,
+ "y": 0,
+ "w": 18,
+ "h": 6
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 16,
+ "h": 6
+ },
+ "frame": {
+ "x": 36,
+ "y": 0,
+ "w": 16,
+ "h": 6
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 52,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 64,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 76,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 88,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 100,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 8,
+ "h": 6
+ },
+ "frame": {
+ "x": 112,
+ "y": 0,
+ "w": 8,
+ "h": 6
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:40d30205ce8efd40dfa86cd11b0491d6:7076db6ed74199dcfb38fc8cd4d4a0e8:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/legacy/text_images/de/battle_ui/pbinfo_stat_de.png b/public/images/ui/legacy/text_images/de/battle_ui/pbinfo_stat_de.png
new file mode 100644
index 00000000000..8de02e9f16e
Binary files /dev/null and b/public/images/ui/legacy/text_images/de/battle_ui/pbinfo_stat_de.png differ
diff --git a/public/images/ui/legacy/text_images/de/party_ui/party_slot_overlay_hp_de.png b/public/images/ui/legacy/text_images/de/party_ui/party_slot_overlay_hp_de.png
new file mode 100644
index 00000000000..8265dfda0d2
Binary files /dev/null and b/public/images/ui/legacy/text_images/de/party_ui/party_slot_overlay_hp_de.png differ
diff --git a/public/images/ui/legacy/text_images/de/party_ui/party_slot_overlay_lv_de.png b/public/images/ui/legacy/text_images/de/party_ui/party_slot_overlay_lv_de.png
new file mode 100644
index 00000000000..11bb545c7af
Binary files /dev/null and b/public/images/ui/legacy/text_images/de/party_ui/party_slot_overlay_lv_de.png differ
diff --git a/public/images/ui/legacy/text_images/en/battle_ui/overlay_exp_label.png b/public/images/ui/legacy/text_images/en/battle_ui/overlay_exp_label.png
new file mode 100644
index 00000000000..40b5e8925a1
Binary files /dev/null and b/public/images/ui/legacy/text_images/en/battle_ui/overlay_exp_label.png differ
diff --git a/public/images/ui/legacy/text_images/en/battle_ui/overlay_hp_label.png b/public/images/ui/legacy/text_images/en/battle_ui/overlay_hp_label.png
new file mode 100644
index 00000000000..67824c7ee4e
Binary files /dev/null and b/public/images/ui/legacy/text_images/en/battle_ui/overlay_hp_label.png differ
diff --git a/public/images/ui/legacy/text_images/en/battle_ui/overlay_hp_label_boss.png b/public/images/ui/legacy/text_images/en/battle_ui/overlay_hp_label_boss.png
new file mode 100644
index 00000000000..283d63fb235
Binary files /dev/null and b/public/images/ui/legacy/text_images/en/battle_ui/overlay_hp_label_boss.png differ
diff --git a/public/images/ui/legacy/text_images/en/battle_ui/overlay_lv.png b/public/images/ui/legacy/text_images/en/battle_ui/overlay_lv.png
new file mode 100644
index 00000000000..ea32ac03ee2
Binary files /dev/null and b/public/images/ui/legacy/text_images/en/battle_ui/overlay_lv.png differ
diff --git a/public/images/ui/legacy/pbinfo_stat.json b/public/images/ui/legacy/text_images/en/battle_ui/pbinfo_stat.json
similarity index 100%
rename from public/images/ui/legacy/pbinfo_stat.json
rename to public/images/ui/legacy/text_images/en/battle_ui/pbinfo_stat.json
diff --git a/public/images/ui/legacy/text_images/en/battle_ui/pbinfo_stat.png b/public/images/ui/legacy/text_images/en/battle_ui/pbinfo_stat.png
new file mode 100644
index 00000000000..c729e7a2207
Binary files /dev/null and b/public/images/ui/legacy/text_images/en/battle_ui/pbinfo_stat.png differ
diff --git a/public/images/ui/legacy/text_images/en/party_ui/party_slot_overlay_hp.png b/public/images/ui/legacy/text_images/en/party_ui/party_slot_overlay_hp.png
new file mode 100644
index 00000000000..a78ac090d3b
Binary files /dev/null and b/public/images/ui/legacy/text_images/en/party_ui/party_slot_overlay_hp.png differ
diff --git a/public/images/ui/legacy/text_images/en/party_ui/party_slot_overlay_lv.png b/public/images/ui/legacy/text_images/en/party_ui/party_slot_overlay_lv.png
new file mode 100644
index 00000000000..11bb545c7af
Binary files /dev/null and b/public/images/ui/legacy/text_images/en/party_ui/party_slot_overlay_lv.png differ
diff --git a/public/images/ui/legacy/text_images/es-ES/battle_ui/overlay_exp_label_es-ES.png b/public/images/ui/legacy/text_images/es-ES/battle_ui/overlay_exp_label_es-ES.png
new file mode 100644
index 00000000000..acb04a84a31
Binary files /dev/null and b/public/images/ui/legacy/text_images/es-ES/battle_ui/overlay_exp_label_es-ES.png differ
diff --git a/public/images/ui/legacy/text_images/es-ES/battle_ui/overlay_hp_label_boss_es-ES.png b/public/images/ui/legacy/text_images/es-ES/battle_ui/overlay_hp_label_boss_es-ES.png
new file mode 100644
index 00000000000..6018011d75b
Binary files /dev/null and b/public/images/ui/legacy/text_images/es-ES/battle_ui/overlay_hp_label_boss_es-ES.png differ
diff --git a/public/images/ui/legacy/text_images/es-ES/battle_ui/overlay_hp_label_es-ES.png b/public/images/ui/legacy/text_images/es-ES/battle_ui/overlay_hp_label_es-ES.png
new file mode 100644
index 00000000000..4f388b70a75
Binary files /dev/null and b/public/images/ui/legacy/text_images/es-ES/battle_ui/overlay_hp_label_es-ES.png differ
diff --git a/public/images/ui/legacy/text_images/es-ES/battle_ui/overlay_lv_es-ES.png b/public/images/ui/legacy/text_images/es-ES/battle_ui/overlay_lv_es-ES.png
new file mode 100644
index 00000000000..7fdf26388bf
Binary files /dev/null and b/public/images/ui/legacy/text_images/es-ES/battle_ui/overlay_lv_es-ES.png differ
diff --git a/public/images/ui/legacy/text_images/es-ES/battle_ui/pbinfo_stat_es_ES.json b/public/images/ui/legacy/text_images/es-ES/battle_ui/pbinfo_stat_es_ES.json
new file mode 100644
index 00000000000..e7e6318b3b5
--- /dev/null
+++ b/public/images/ui/legacy/text_images/es-ES/battle_ui/pbinfo_stat_es_ES.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_es-ES.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 112,
+ "h": 8
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 18,
+ "h": 8
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 18,
+ "h": 8
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 18,
+ "h": 8
+ },
+ "frame": {
+ "x": 18,
+ "y": 0,
+ "w": 18,
+ "h": 8
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 16,
+ "h": 8
+ },
+ "frame": {
+ "x": 36,
+ "y": 0,
+ "w": 16,
+ "h": 8
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ },
+ "frame": {
+ "x": 52,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ },
+ "frame": {
+ "x": 64,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ },
+ "frame": {
+ "x": 76,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ },
+ "frame": {
+ "x": 88,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ },
+ "frame": {
+ "x": 100,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 8,
+ "h": 8
+ },
+ "frame": {
+ "x": 112,
+ "y": 0,
+ "w": 8,
+ "h": 8
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:40d30205ce8efd40dfa86cd11b0491d6:7076db6ed74199dcfb38fc8cd4d4a0e8:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/legacy/text_images/es-ES/battle_ui/pbinfo_stat_es_ES.png b/public/images/ui/legacy/text_images/es-ES/battle_ui/pbinfo_stat_es_ES.png
new file mode 100644
index 00000000000..0a66f1a7137
Binary files /dev/null and b/public/images/ui/legacy/text_images/es-ES/battle_ui/pbinfo_stat_es_ES.png differ
diff --git a/public/images/ui/legacy/text_images/es-ES/party_ui/party_slot_overlay_hp_es-ES.png b/public/images/ui/legacy/text_images/es-ES/party_ui/party_slot_overlay_hp_es-ES.png
new file mode 100644
index 00000000000..981d8573aca
Binary files /dev/null and b/public/images/ui/legacy/text_images/es-ES/party_ui/party_slot_overlay_hp_es-ES.png differ
diff --git a/public/images/ui/legacy/text_images/es-ES/party_ui/party_slot_overlay_lv_es-ES.png b/public/images/ui/legacy/text_images/es-ES/party_ui/party_slot_overlay_lv_es-ES.png
new file mode 100644
index 00000000000..512db34fa85
Binary files /dev/null and b/public/images/ui/legacy/text_images/es-ES/party_ui/party_slot_overlay_lv_es-ES.png differ
diff --git a/public/images/ui/legacy/text_images/es-MX/battle_ui/overlay_exp_label_es-MX.png b/public/images/ui/legacy/text_images/es-MX/battle_ui/overlay_exp_label_es-MX.png
new file mode 100644
index 00000000000..acb04a84a31
Binary files /dev/null and b/public/images/ui/legacy/text_images/es-MX/battle_ui/overlay_exp_label_es-MX.png differ
diff --git a/public/images/ui/legacy/text_images/es-MX/battle_ui/overlay_hp_label_boss_es-MX.png b/public/images/ui/legacy/text_images/es-MX/battle_ui/overlay_hp_label_boss_es-MX.png
new file mode 100644
index 00000000000..6018011d75b
Binary files /dev/null and b/public/images/ui/legacy/text_images/es-MX/battle_ui/overlay_hp_label_boss_es-MX.png differ
diff --git a/public/images/ui/legacy/text_images/es-MX/battle_ui/overlay_hp_label_es-MX.png b/public/images/ui/legacy/text_images/es-MX/battle_ui/overlay_hp_label_es-MX.png
new file mode 100644
index 00000000000..4f388b70a75
Binary files /dev/null and b/public/images/ui/legacy/text_images/es-MX/battle_ui/overlay_hp_label_es-MX.png differ
diff --git a/public/images/ui/legacy/text_images/es-MX/battle_ui/overlay_lv_es-MX.png b/public/images/ui/legacy/text_images/es-MX/battle_ui/overlay_lv_es-MX.png
new file mode 100644
index 00000000000..7fdf26388bf
Binary files /dev/null and b/public/images/ui/legacy/text_images/es-MX/battle_ui/overlay_lv_es-MX.png differ
diff --git a/public/images/ui/legacy/text_images/es-MX/battle_ui/pbinfo_stat_es_MX.json b/public/images/ui/legacy/text_images/es-MX/battle_ui/pbinfo_stat_es_MX.json
new file mode 100644
index 00000000000..98bd43e7dd9
--- /dev/null
+++ b/public/images/ui/legacy/text_images/es-MX/battle_ui/pbinfo_stat_es_MX.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_es-MX.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 112,
+ "h": 8
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 18,
+ "h": 8
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 18,
+ "h": 8
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 18,
+ "h": 8
+ },
+ "frame": {
+ "x": 18,
+ "y": 0,
+ "w": 18,
+ "h": 8
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 16,
+ "h": 8
+ },
+ "frame": {
+ "x": 36,
+ "y": 0,
+ "w": 16,
+ "h": 8
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ },
+ "frame": {
+ "x": 52,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ },
+ "frame": {
+ "x": 64,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ },
+ "frame": {
+ "x": 76,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ },
+ "frame": {
+ "x": 88,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ },
+ "frame": {
+ "x": 100,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 8,
+ "h": 8
+ },
+ "frame": {
+ "x": 112,
+ "y": 0,
+ "w": 8,
+ "h": 8
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:40d30205ce8efd40dfa86cd11b0491d6:7076db6ed74199dcfb38fc8cd4d4a0e8:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/legacy/text_images/es-MX/battle_ui/pbinfo_stat_es_MX.png b/public/images/ui/legacy/text_images/es-MX/battle_ui/pbinfo_stat_es_MX.png
new file mode 100644
index 00000000000..0a66f1a7137
Binary files /dev/null and b/public/images/ui/legacy/text_images/es-MX/battle_ui/pbinfo_stat_es_MX.png differ
diff --git a/public/images/ui/legacy/text_images/es-MX/party_ui/party_slot_overlay_hp_es-MX.png b/public/images/ui/legacy/text_images/es-MX/party_ui/party_slot_overlay_hp_es-MX.png
new file mode 100644
index 00000000000..981d8573aca
Binary files /dev/null and b/public/images/ui/legacy/text_images/es-MX/party_ui/party_slot_overlay_hp_es-MX.png differ
diff --git a/public/images/ui/legacy/text_images/es-MX/party_ui/party_slot_overlay_lv_es-MX.png b/public/images/ui/legacy/text_images/es-MX/party_ui/party_slot_overlay_lv_es-MX.png
new file mode 100644
index 00000000000..512db34fa85
Binary files /dev/null and b/public/images/ui/legacy/text_images/es-MX/party_ui/party_slot_overlay_lv_es-MX.png differ
diff --git a/public/images/ui/legacy/text_images/fr/battle_ui/overlay_exp_label_fr.png b/public/images/ui/legacy/text_images/fr/battle_ui/overlay_exp_label_fr.png
new file mode 100644
index 00000000000..40b5e8925a1
Binary files /dev/null and b/public/images/ui/legacy/text_images/fr/battle_ui/overlay_exp_label_fr.png differ
diff --git a/public/images/ui/legacy/text_images/fr/battle_ui/overlay_hp_label_boss_fr.png b/public/images/ui/legacy/text_images/fr/battle_ui/overlay_hp_label_boss_fr.png
new file mode 100644
index 00000000000..283d63fb235
Binary files /dev/null and b/public/images/ui/legacy/text_images/fr/battle_ui/overlay_hp_label_boss_fr.png differ
diff --git a/public/images/ui/legacy/text_images/fr/battle_ui/overlay_hp_label_fr.png b/public/images/ui/legacy/text_images/fr/battle_ui/overlay_hp_label_fr.png
new file mode 100644
index 00000000000..3f7e12c3246
Binary files /dev/null and b/public/images/ui/legacy/text_images/fr/battle_ui/overlay_hp_label_fr.png differ
diff --git a/public/images/ui/legacy/text_images/fr/battle_ui/overlay_lv_fr.png b/public/images/ui/legacy/text_images/fr/battle_ui/overlay_lv_fr.png
new file mode 100644
index 00000000000..5a31182069c
Binary files /dev/null and b/public/images/ui/legacy/text_images/fr/battle_ui/overlay_lv_fr.png differ
diff --git a/public/images/ui/legacy/text_images/fr/battle_ui/pbinfo_stat_fr.json b/public/images/ui/legacy/text_images/fr/battle_ui/pbinfo_stat_fr.json
new file mode 100644
index 00000000000..00cc9f7ea0e
--- /dev/null
+++ b/public/images/ui/legacy/text_images/fr/battle_ui/pbinfo_stat_fr.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_fr.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 112,
+ "h": 8
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 18,
+ "h": 8
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 18,
+ "h": 8
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 18,
+ "h": 8
+ },
+ "frame": {
+ "x": 18,
+ "y": 0,
+ "w": 18,
+ "h": 8
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 16,
+ "h": 8
+ },
+ "frame": {
+ "x": 36,
+ "y": 0,
+ "w": 16,
+ "h": 8
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ },
+ "frame": {
+ "x": 52,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ },
+ "frame": {
+ "x": 64,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ },
+ "frame": {
+ "x": 76,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ },
+ "frame": {
+ "x": 88,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ },
+ "frame": {
+ "x": 100,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 8,
+ "h": 8
+ },
+ "frame": {
+ "x": 112,
+ "y": 0,
+ "w": 8,
+ "h": 8
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:40d30205ce8efd40dfa86cd11b0491d6:7076db6ed74199dcfb38fc8cd4d4a0e8:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/legacy/text_images/fr/battle_ui/pbinfo_stat_fr.png b/public/images/ui/legacy/text_images/fr/battle_ui/pbinfo_stat_fr.png
new file mode 100644
index 00000000000..1919561ddfe
Binary files /dev/null and b/public/images/ui/legacy/text_images/fr/battle_ui/pbinfo_stat_fr.png differ
diff --git a/public/images/ui/legacy/text_images/fr/party_ui/party_slot_overlay_hp_fr.png b/public/images/ui/legacy/text_images/fr/party_ui/party_slot_overlay_hp_fr.png
new file mode 100644
index 00000000000..55468e4b1d1
Binary files /dev/null and b/public/images/ui/legacy/text_images/fr/party_ui/party_slot_overlay_hp_fr.png differ
diff --git a/public/images/ui/legacy/text_images/fr/party_ui/party_slot_overlay_lv_fr.png b/public/images/ui/legacy/text_images/fr/party_ui/party_slot_overlay_lv_fr.png
new file mode 100644
index 00000000000..e7bbec23b07
Binary files /dev/null and b/public/images/ui/legacy/text_images/fr/party_ui/party_slot_overlay_lv_fr.png differ
diff --git a/public/images/ui/legacy/text_images/it/battle_ui/overlay_exp_label_it.png b/public/images/ui/legacy/text_images/it/battle_ui/overlay_exp_label_it.png
new file mode 100644
index 00000000000..3a888a5ffb0
Binary files /dev/null and b/public/images/ui/legacy/text_images/it/battle_ui/overlay_exp_label_it.png differ
diff --git a/public/images/ui/legacy/text_images/it/battle_ui/overlay_hp_label_boss_it.png b/public/images/ui/legacy/text_images/it/battle_ui/overlay_hp_label_boss_it.png
new file mode 100644
index 00000000000..283d63fb235
Binary files /dev/null and b/public/images/ui/legacy/text_images/it/battle_ui/overlay_hp_label_boss_it.png differ
diff --git a/public/images/ui/legacy/text_images/it/battle_ui/overlay_hp_label_it.png b/public/images/ui/legacy/text_images/it/battle_ui/overlay_hp_label_it.png
new file mode 100644
index 00000000000..4f388b70a75
Binary files /dev/null and b/public/images/ui/legacy/text_images/it/battle_ui/overlay_hp_label_it.png differ
diff --git a/public/images/ui/legacy/text_images/it/battle_ui/overlay_lv_it.png b/public/images/ui/legacy/text_images/it/battle_ui/overlay_lv_it.png
new file mode 100644
index 00000000000..579c684d766
Binary files /dev/null and b/public/images/ui/legacy/text_images/it/battle_ui/overlay_lv_it.png differ
diff --git a/public/images/ui/legacy/text_images/it/battle_ui/pbinfo_stat_it.json b/public/images/ui/legacy/text_images/it/battle_ui/pbinfo_stat_it.json
new file mode 100644
index 00000000000..1971bb61221
--- /dev/null
+++ b/public/images/ui/legacy/text_images/it/battle_ui/pbinfo_stat_it.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_it.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 112,
+ "h": 6
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 18,
+ "h": 6
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 18,
+ "h": 6
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 18,
+ "h": 6
+ },
+ "frame": {
+ "x": 18,
+ "y": 0,
+ "w": 18,
+ "h": 6
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 16,
+ "h": 6
+ },
+ "frame": {
+ "x": 36,
+ "y": 0,
+ "w": 16,
+ "h": 6
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 52,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 64,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 76,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 88,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 100,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 8,
+ "h": 6
+ },
+ "frame": {
+ "x": 112,
+ "y": 0,
+ "w": 8,
+ "h": 6
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:40d30205ce8efd40dfa86cd11b0491d6:7076db6ed74199dcfb38fc8cd4d4a0e8:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/legacy/text_images/it/battle_ui/pbinfo_stat_it.png b/public/images/ui/legacy/text_images/it/battle_ui/pbinfo_stat_it.png
new file mode 100644
index 00000000000..ced53e91a6e
Binary files /dev/null and b/public/images/ui/legacy/text_images/it/battle_ui/pbinfo_stat_it.png differ
diff --git a/public/images/ui/legacy/text_images/it/party_ui/party_slot_overlay_hp_it.png b/public/images/ui/legacy/text_images/it/party_ui/party_slot_overlay_hp_it.png
new file mode 100644
index 00000000000..981d8573aca
Binary files /dev/null and b/public/images/ui/legacy/text_images/it/party_ui/party_slot_overlay_hp_it.png differ
diff --git a/public/images/ui/legacy/text_images/it/party_ui/party_slot_overlay_lv_it.png b/public/images/ui/legacy/text_images/it/party_ui/party_slot_overlay_lv_it.png
new file mode 100644
index 00000000000..5338254b4d0
Binary files /dev/null and b/public/images/ui/legacy/text_images/it/party_ui/party_slot_overlay_lv_it.png differ
diff --git a/public/images/ui/legacy/text_images/ja/battle_ui/overlay_exp_label_ja.png b/public/images/ui/legacy/text_images/ja/battle_ui/overlay_exp_label_ja.png
new file mode 100644
index 00000000000..40b5e8925a1
Binary files /dev/null and b/public/images/ui/legacy/text_images/ja/battle_ui/overlay_exp_label_ja.png differ
diff --git a/public/images/ui/legacy/text_images/ja/battle_ui/overlay_hp_label_boss_ja.png b/public/images/ui/legacy/text_images/ja/battle_ui/overlay_hp_label_boss_ja.png
new file mode 100644
index 00000000000..283d63fb235
Binary files /dev/null and b/public/images/ui/legacy/text_images/ja/battle_ui/overlay_hp_label_boss_ja.png differ
diff --git a/public/images/ui/legacy/text_images/ja/battle_ui/overlay_hp_label_ja.png b/public/images/ui/legacy/text_images/ja/battle_ui/overlay_hp_label_ja.png
new file mode 100644
index 00000000000..67824c7ee4e
Binary files /dev/null and b/public/images/ui/legacy/text_images/ja/battle_ui/overlay_hp_label_ja.png differ
diff --git a/public/images/ui/legacy/text_images/ja/battle_ui/overlay_lv_ja.png b/public/images/ui/legacy/text_images/ja/battle_ui/overlay_lv_ja.png
new file mode 100644
index 00000000000..ea32ac03ee2
Binary files /dev/null and b/public/images/ui/legacy/text_images/ja/battle_ui/overlay_lv_ja.png differ
diff --git a/public/images/ui/legacy/text_images/ja/battle_ui/pbinfo_stat_ja.json b/public/images/ui/legacy/text_images/ja/battle_ui/pbinfo_stat_ja.json
new file mode 100644
index 00000000000..d8907e8e68c
--- /dev/null
+++ b/public/images/ui/legacy/text_images/ja/battle_ui/pbinfo_stat_ja.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_ja.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 112,
+ "h": 6
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 18,
+ "h": 6
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 18,
+ "h": 6
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 18,
+ "h": 6
+ },
+ "frame": {
+ "x": 18,
+ "y": 0,
+ "w": 18,
+ "h": 6
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 16,
+ "h": 6
+ },
+ "frame": {
+ "x": 36,
+ "y": 0,
+ "w": 16,
+ "h": 6
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 52,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 64,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 76,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 88,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 100,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 8,
+ "h": 6
+ },
+ "frame": {
+ "x": 112,
+ "y": 0,
+ "w": 8,
+ "h": 6
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:40d30205ce8efd40dfa86cd11b0491d6:7076db6ed74199dcfb38fc8cd4d4a0e8:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/legacy/text_images/ja/battle_ui/pbinfo_stat_ja.png b/public/images/ui/legacy/text_images/ja/battle_ui/pbinfo_stat_ja.png
new file mode 100644
index 00000000000..c729e7a2207
Binary files /dev/null and b/public/images/ui/legacy/text_images/ja/battle_ui/pbinfo_stat_ja.png differ
diff --git a/public/images/ui/legacy/text_images/ja/party_ui/party_slot_overlay_hp_ja.png b/public/images/ui/legacy/text_images/ja/party_ui/party_slot_overlay_hp_ja.png
new file mode 100644
index 00000000000..a78ac090d3b
Binary files /dev/null and b/public/images/ui/legacy/text_images/ja/party_ui/party_slot_overlay_hp_ja.png differ
diff --git a/public/images/ui/legacy/text_images/ja/party_ui/party_slot_overlay_lv_ja.png b/public/images/ui/legacy/text_images/ja/party_ui/party_slot_overlay_lv_ja.png
new file mode 100644
index 00000000000..11bb545c7af
Binary files /dev/null and b/public/images/ui/legacy/text_images/ja/party_ui/party_slot_overlay_lv_ja.png differ
diff --git a/public/images/ui/legacy/text_images/ko/battle_ui/overlay_exp_label_ko.png b/public/images/ui/legacy/text_images/ko/battle_ui/overlay_exp_label_ko.png
new file mode 100644
index 00000000000..40b5e8925a1
Binary files /dev/null and b/public/images/ui/legacy/text_images/ko/battle_ui/overlay_exp_label_ko.png differ
diff --git a/public/images/ui/legacy/text_images/ko/battle_ui/overlay_hp_label_boss_ko.png b/public/images/ui/legacy/text_images/ko/battle_ui/overlay_hp_label_boss_ko.png
new file mode 100644
index 00000000000..283d63fb235
Binary files /dev/null and b/public/images/ui/legacy/text_images/ko/battle_ui/overlay_hp_label_boss_ko.png differ
diff --git a/public/images/ui/legacy/text_images/ko/battle_ui/overlay_hp_label_ko.png b/public/images/ui/legacy/text_images/ko/battle_ui/overlay_hp_label_ko.png
new file mode 100644
index 00000000000..67824c7ee4e
Binary files /dev/null and b/public/images/ui/legacy/text_images/ko/battle_ui/overlay_hp_label_ko.png differ
diff --git a/public/images/ui/legacy/text_images/ko/battle_ui/overlay_lv_ko.png b/public/images/ui/legacy/text_images/ko/battle_ui/overlay_lv_ko.png
new file mode 100644
index 00000000000..ea32ac03ee2
Binary files /dev/null and b/public/images/ui/legacy/text_images/ko/battle_ui/overlay_lv_ko.png differ
diff --git a/public/images/ui/legacy/text_images/ko/battle_ui/pbinfo_stat_ko.json b/public/images/ui/legacy/text_images/ko/battle_ui/pbinfo_stat_ko.json
new file mode 100644
index 00000000000..359e3a5b76f
--- /dev/null
+++ b/public/images/ui/legacy/text_images/ko/battle_ui/pbinfo_stat_ko.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_ko.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 112,
+ "h": 6
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 18,
+ "h": 6
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 18,
+ "h": 6
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 18,
+ "h": 6
+ },
+ "frame": {
+ "x": 18,
+ "y": 0,
+ "w": 18,
+ "h": 6
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 16,
+ "h": 6
+ },
+ "frame": {
+ "x": 36,
+ "y": 0,
+ "w": 16,
+ "h": 6
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 52,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 64,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 76,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 88,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 100,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 8,
+ "h": 6
+ },
+ "frame": {
+ "x": 112,
+ "y": 0,
+ "w": 8,
+ "h": 6
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:40d30205ce8efd40dfa86cd11b0491d6:7076db6ed74199dcfb38fc8cd4d4a0e8:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/legacy/text_images/ko/battle_ui/pbinfo_stat_ko.png b/public/images/ui/legacy/text_images/ko/battle_ui/pbinfo_stat_ko.png
new file mode 100644
index 00000000000..c729e7a2207
Binary files /dev/null and b/public/images/ui/legacy/text_images/ko/battle_ui/pbinfo_stat_ko.png differ
diff --git a/public/images/ui/legacy/text_images/ko/party_ui/party_slot_overlay_hp_ko.png b/public/images/ui/legacy/text_images/ko/party_ui/party_slot_overlay_hp_ko.png
new file mode 100644
index 00000000000..a78ac090d3b
Binary files /dev/null and b/public/images/ui/legacy/text_images/ko/party_ui/party_slot_overlay_hp_ko.png differ
diff --git a/public/images/ui/legacy/text_images/ko/party_ui/party_slot_overlay_lv_ko.png b/public/images/ui/legacy/text_images/ko/party_ui/party_slot_overlay_lv_ko.png
new file mode 100644
index 00000000000..11bb545c7af
Binary files /dev/null and b/public/images/ui/legacy/text_images/ko/party_ui/party_slot_overlay_lv_ko.png differ
diff --git a/public/images/ui/legacy/text_images/pt-BR/battle_ui/overlay_exp_label_pt-BR.png b/public/images/ui/legacy/text_images/pt-BR/battle_ui/overlay_exp_label_pt-BR.png
new file mode 100644
index 00000000000..acb04a84a31
Binary files /dev/null and b/public/images/ui/legacy/text_images/pt-BR/battle_ui/overlay_exp_label_pt-BR.png differ
diff --git a/public/images/ui/legacy/text_images/pt-BR/battle_ui/overlay_hp_label_boss_pt-BR.png b/public/images/ui/legacy/text_images/pt-BR/battle_ui/overlay_hp_label_boss_pt-BR.png
new file mode 100644
index 00000000000..283d63fb235
Binary files /dev/null and b/public/images/ui/legacy/text_images/pt-BR/battle_ui/overlay_hp_label_boss_pt-BR.png differ
diff --git a/public/images/ui/legacy/text_images/pt-BR/battle_ui/overlay_hp_label_pt-BR.png b/public/images/ui/legacy/text_images/pt-BR/battle_ui/overlay_hp_label_pt-BR.png
new file mode 100644
index 00000000000..4f388b70a75
Binary files /dev/null and b/public/images/ui/legacy/text_images/pt-BR/battle_ui/overlay_hp_label_pt-BR.png differ
diff --git a/public/images/ui/legacy/text_images/pt-BR/battle_ui/overlay_lv_pt-BR.png b/public/images/ui/legacy/text_images/pt-BR/battle_ui/overlay_lv_pt-BR.png
new file mode 100644
index 00000000000..7fdf26388bf
Binary files /dev/null and b/public/images/ui/legacy/text_images/pt-BR/battle_ui/overlay_lv_pt-BR.png differ
diff --git a/public/images/ui/legacy/text_images/pt-BR/battle_ui/pbinfo_stat_pt-BR.json b/public/images/ui/legacy/text_images/pt-BR/battle_ui/pbinfo_stat_pt-BR.json
new file mode 100644
index 00000000000..dc7eecf1970
--- /dev/null
+++ b/public/images/ui/legacy/text_images/pt-BR/battle_ui/pbinfo_stat_pt-BR.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_pt-BR.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 112,
+ "h": 8
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 18,
+ "h": 8
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 18,
+ "h": 8
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 18,
+ "h": 8
+ },
+ "frame": {
+ "x": 18,
+ "y": 0,
+ "w": 18,
+ "h": 8
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 16,
+ "h": 8
+ },
+ "frame": {
+ "x": 36,
+ "y": 0,
+ "w": 16,
+ "h": 8
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ },
+ "frame": {
+ "x": 52,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ },
+ "frame": {
+ "x": 64,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ },
+ "frame": {
+ "x": 76,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ },
+ "frame": {
+ "x": 88,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ },
+ "frame": {
+ "x": 100,
+ "y": 0,
+ "w": 12,
+ "h": 8
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 8,
+ "h": 8
+ },
+ "frame": {
+ "x": 112,
+ "y": 0,
+ "w": 8,
+ "h": 8
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:40d30205ce8efd40dfa86cd11b0491d6:7076db6ed74199dcfb38fc8cd4d4a0e8:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/legacy/text_images/pt-BR/battle_ui/pbinfo_stat_pt-BR.png b/public/images/ui/legacy/text_images/pt-BR/battle_ui/pbinfo_stat_pt-BR.png
new file mode 100644
index 00000000000..3dcd273bcc9
Binary files /dev/null and b/public/images/ui/legacy/text_images/pt-BR/battle_ui/pbinfo_stat_pt-BR.png differ
diff --git a/public/images/ui/legacy/text_images/pt-BR/party_ui/party_slot_overlay_hp_pt-BR.png b/public/images/ui/legacy/text_images/pt-BR/party_ui/party_slot_overlay_hp_pt-BR.png
new file mode 100644
index 00000000000..981d8573aca
Binary files /dev/null and b/public/images/ui/legacy/text_images/pt-BR/party_ui/party_slot_overlay_hp_pt-BR.png differ
diff --git a/public/images/ui/legacy/text_images/pt-BR/party_ui/party_slot_overlay_lv_pt-BR.png b/public/images/ui/legacy/text_images/pt-BR/party_ui/party_slot_overlay_lv_pt-BR.png
new file mode 100644
index 00000000000..512db34fa85
Binary files /dev/null and b/public/images/ui/legacy/text_images/pt-BR/party_ui/party_slot_overlay_lv_pt-BR.png differ
diff --git a/public/images/ui/legacy/text_images/ro/battle_ui/overlay_exp_label_ro.png b/public/images/ui/legacy/text_images/ro/battle_ui/overlay_exp_label_ro.png
new file mode 100644
index 00000000000..40b5e8925a1
Binary files /dev/null and b/public/images/ui/legacy/text_images/ro/battle_ui/overlay_exp_label_ro.png differ
diff --git a/public/images/ui/legacy/text_images/ro/battle_ui/overlay_hp_label_boss_ro.png b/public/images/ui/legacy/text_images/ro/battle_ui/overlay_hp_label_boss_ro.png
new file mode 100644
index 00000000000..283d63fb235
Binary files /dev/null and b/public/images/ui/legacy/text_images/ro/battle_ui/overlay_hp_label_boss_ro.png differ
diff --git a/public/images/ui/legacy/text_images/ro/battle_ui/overlay_hp_label_ro.png b/public/images/ui/legacy/text_images/ro/battle_ui/overlay_hp_label_ro.png
new file mode 100644
index 00000000000..67824c7ee4e
Binary files /dev/null and b/public/images/ui/legacy/text_images/ro/battle_ui/overlay_hp_label_ro.png differ
diff --git a/public/images/ui/legacy/text_images/ro/battle_ui/overlay_lv_ro.png b/public/images/ui/legacy/text_images/ro/battle_ui/overlay_lv_ro.png
new file mode 100644
index 00000000000..ea32ac03ee2
Binary files /dev/null and b/public/images/ui/legacy/text_images/ro/battle_ui/overlay_lv_ro.png differ
diff --git a/public/images/ui/legacy/text_images/ro/battle_ui/pbinfo_stat_ro.json b/public/images/ui/legacy/text_images/ro/battle_ui/pbinfo_stat_ro.json
new file mode 100644
index 00000000000..8c268a77098
--- /dev/null
+++ b/public/images/ui/legacy/text_images/ro/battle_ui/pbinfo_stat_ro.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_ro.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 112,
+ "h": 6
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 18,
+ "h": 6
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 18,
+ "h": 6
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 18,
+ "h": 6
+ },
+ "frame": {
+ "x": 18,
+ "y": 0,
+ "w": 18,
+ "h": 6
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 16,
+ "h": 6
+ },
+ "frame": {
+ "x": 36,
+ "y": 0,
+ "w": 16,
+ "h": 6
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 52,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 64,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 76,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 88,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 100,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 8,
+ "h": 6
+ },
+ "frame": {
+ "x": 112,
+ "y": 0,
+ "w": 8,
+ "h": 6
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:40d30205ce8efd40dfa86cd11b0491d6:7076db6ed74199dcfb38fc8cd4d4a0e8:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/legacy/text_images/ro/battle_ui/pbinfo_stat_ro.png b/public/images/ui/legacy/text_images/ro/battle_ui/pbinfo_stat_ro.png
new file mode 100644
index 00000000000..c729e7a2207
Binary files /dev/null and b/public/images/ui/legacy/text_images/ro/battle_ui/pbinfo_stat_ro.png differ
diff --git a/public/images/ui/legacy/text_images/ro/party_ui/party_slot_overlay_hp_ro.png b/public/images/ui/legacy/text_images/ro/party_ui/party_slot_overlay_hp_ro.png
new file mode 100644
index 00000000000..a78ac090d3b
Binary files /dev/null and b/public/images/ui/legacy/text_images/ro/party_ui/party_slot_overlay_hp_ro.png differ
diff --git a/public/images/ui/legacy/text_images/ro/party_ui/party_slot_overlay_lv_ro.png b/public/images/ui/legacy/text_images/ro/party_ui/party_slot_overlay_lv_ro.png
new file mode 100644
index 00000000000..11bb545c7af
Binary files /dev/null and b/public/images/ui/legacy/text_images/ro/party_ui/party_slot_overlay_lv_ro.png differ
diff --git a/public/images/ui/legacy/text_images/ru/battle_ui/overlay_exp_label_ru.png b/public/images/ui/legacy/text_images/ru/battle_ui/overlay_exp_label_ru.png
new file mode 100644
index 00000000000..d8817108408
Binary files /dev/null and b/public/images/ui/legacy/text_images/ru/battle_ui/overlay_exp_label_ru.png differ
diff --git a/public/images/ui/legacy/text_images/ru/battle_ui/overlay_hp_label_boss_ru.png b/public/images/ui/legacy/text_images/ru/battle_ui/overlay_hp_label_boss_ru.png
new file mode 100644
index 00000000000..26c4d570bb1
Binary files /dev/null and b/public/images/ui/legacy/text_images/ru/battle_ui/overlay_hp_label_boss_ru.png differ
diff --git a/public/images/ui/legacy/text_images/ru/battle_ui/overlay_hp_label_ru.png b/public/images/ui/legacy/text_images/ru/battle_ui/overlay_hp_label_ru.png
new file mode 100644
index 00000000000..490c93f8d39
Binary files /dev/null and b/public/images/ui/legacy/text_images/ru/battle_ui/overlay_hp_label_ru.png differ
diff --git a/public/images/ui/legacy/text_images/ru/battle_ui/overlay_lv_ru.png b/public/images/ui/legacy/text_images/ru/battle_ui/overlay_lv_ru.png
new file mode 100644
index 00000000000..e8760560dfa
Binary files /dev/null and b/public/images/ui/legacy/text_images/ru/battle_ui/overlay_lv_ru.png differ
diff --git a/public/images/ui/legacy/text_images/ru/battle_ui/pbinfo_stat_ru.json b/public/images/ui/legacy/text_images/ru/battle_ui/pbinfo_stat_ru.json
new file mode 100644
index 00000000000..e4e67b4da18
--- /dev/null
+++ b/public/images/ui/legacy/text_images/ru/battle_ui/pbinfo_stat_ru.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_ru.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 112,
+ "h": 7
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 18,
+ "h": 7
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 18,
+ "h": 7
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 18,
+ "h": 7
+ },
+ "frame": {
+ "x": 18,
+ "y": 0,
+ "w": 18,
+ "h": 7
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 16,
+ "h": 7
+ },
+ "frame": {
+ "x": 36,
+ "y": 0,
+ "w": 16,
+ "h": 7
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 7
+ },
+ "frame": {
+ "x": 52,
+ "y": 0,
+ "w": 12,
+ "h": 7
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 7
+ },
+ "frame": {
+ "x": 64,
+ "y": 0,
+ "w": 12,
+ "h": 7
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 7
+ },
+ "frame": {
+ "x": 76,
+ "y": 0,
+ "w": 12,
+ "h": 7
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 7
+ },
+ "frame": {
+ "x": 88,
+ "y": 0,
+ "w": 12,
+ "h": 7
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 7
+ },
+ "frame": {
+ "x": 100,
+ "y": 0,
+ "w": 12,
+ "h": 7
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 8,
+ "h": 7
+ },
+ "frame": {
+ "x": 112,
+ "y": 0,
+ "w": 8,
+ "h": 7
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:40d30205ce8efd40dfa86cd11b0491d6:7076db6ed74199dcfb38fc8cd4d4a0e8:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/legacy/text_images/ru/battle_ui/pbinfo_stat_ru.png b/public/images/ui/legacy/text_images/ru/battle_ui/pbinfo_stat_ru.png
new file mode 100644
index 00000000000..0899fbdbfc1
Binary files /dev/null and b/public/images/ui/legacy/text_images/ru/battle_ui/pbinfo_stat_ru.png differ
diff --git a/public/images/ui/legacy/text_images/ru/party_ui/party_slot_overlay_hp_ru.png b/public/images/ui/legacy/text_images/ru/party_ui/party_slot_overlay_hp_ru.png
new file mode 100644
index 00000000000..24bf5a8923f
Binary files /dev/null and b/public/images/ui/legacy/text_images/ru/party_ui/party_slot_overlay_hp_ru.png differ
diff --git a/public/images/ui/legacy/text_images/ru/party_ui/party_slot_overlay_lv_ru.png b/public/images/ui/legacy/text_images/ru/party_ui/party_slot_overlay_lv_ru.png
new file mode 100644
index 00000000000..319d7a75fb8
Binary files /dev/null and b/public/images/ui/legacy/text_images/ru/party_ui/party_slot_overlay_lv_ru.png differ
diff --git a/public/images/ui/legacy/text_images/tl/battle_ui/overlay_exp_label_tl.png b/public/images/ui/legacy/text_images/tl/battle_ui/overlay_exp_label_tl.png
new file mode 100644
index 00000000000..40b5e8925a1
Binary files /dev/null and b/public/images/ui/legacy/text_images/tl/battle_ui/overlay_exp_label_tl.png differ
diff --git a/public/images/ui/legacy/text_images/tl/battle_ui/overlay_hp_label_boss_tl.png b/public/images/ui/legacy/text_images/tl/battle_ui/overlay_hp_label_boss_tl.png
new file mode 100644
index 00000000000..283d63fb235
Binary files /dev/null and b/public/images/ui/legacy/text_images/tl/battle_ui/overlay_hp_label_boss_tl.png differ
diff --git a/public/images/ui/legacy/text_images/tl/battle_ui/overlay_hp_label_tl.png b/public/images/ui/legacy/text_images/tl/battle_ui/overlay_hp_label_tl.png
new file mode 100644
index 00000000000..67824c7ee4e
Binary files /dev/null and b/public/images/ui/legacy/text_images/tl/battle_ui/overlay_hp_label_tl.png differ
diff --git a/public/images/ui/legacy/text_images/tl/battle_ui/overlay_lv_tl.png b/public/images/ui/legacy/text_images/tl/battle_ui/overlay_lv_tl.png
new file mode 100644
index 00000000000..ea32ac03ee2
Binary files /dev/null and b/public/images/ui/legacy/text_images/tl/battle_ui/overlay_lv_tl.png differ
diff --git a/public/images/ui/legacy/text_images/tl/battle_ui/pbinfo_stat_tl.json b/public/images/ui/legacy/text_images/tl/battle_ui/pbinfo_stat_tl.json
new file mode 100644
index 00000000000..023a5ee45f9
--- /dev/null
+++ b/public/images/ui/legacy/text_images/tl/battle_ui/pbinfo_stat_tl.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_tl.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 112,
+ "h": 6
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 18,
+ "h": 6
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 18,
+ "h": 6
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 18,
+ "h": 6
+ },
+ "frame": {
+ "x": 18,
+ "y": 0,
+ "w": 18,
+ "h": 6
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 16,
+ "h": 6
+ },
+ "frame": {
+ "x": 36,
+ "y": 0,
+ "w": 16,
+ "h": 6
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 52,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 64,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 76,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 88,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 100,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 8,
+ "h": 6
+ },
+ "frame": {
+ "x": 112,
+ "y": 0,
+ "w": 8,
+ "h": 6
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:40d30205ce8efd40dfa86cd11b0491d6:7076db6ed74199dcfb38fc8cd4d4a0e8:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/legacy/text_images/tl/battle_ui/pbinfo_stat_tl.png b/public/images/ui/legacy/text_images/tl/battle_ui/pbinfo_stat_tl.png
new file mode 100644
index 00000000000..c729e7a2207
Binary files /dev/null and b/public/images/ui/legacy/text_images/tl/battle_ui/pbinfo_stat_tl.png differ
diff --git a/public/images/ui/legacy/text_images/tl/party_ui/party_slot_overlay_hp_tl.png b/public/images/ui/legacy/text_images/tl/party_ui/party_slot_overlay_hp_tl.png
new file mode 100644
index 00000000000..a78ac090d3b
Binary files /dev/null and b/public/images/ui/legacy/text_images/tl/party_ui/party_slot_overlay_hp_tl.png differ
diff --git a/public/images/ui/legacy/text_images/tl/party_ui/party_slot_overlay_lv_tl.png b/public/images/ui/legacy/text_images/tl/party_ui/party_slot_overlay_lv_tl.png
new file mode 100644
index 00000000000..11bb545c7af
Binary files /dev/null and b/public/images/ui/legacy/text_images/tl/party_ui/party_slot_overlay_lv_tl.png differ
diff --git a/public/images/ui/legacy/text_images/tr/battle_ui/overlay_exp_label_tr.png b/public/images/ui/legacy/text_images/tr/battle_ui/overlay_exp_label_tr.png
new file mode 100644
index 00000000000..5b9bd882581
Binary files /dev/null and b/public/images/ui/legacy/text_images/tr/battle_ui/overlay_exp_label_tr.png differ
diff --git a/public/images/ui/legacy/text_images/tr/battle_ui/overlay_hp_label_boss_tr.png b/public/images/ui/legacy/text_images/tr/battle_ui/overlay_hp_label_boss_tr.png
new file mode 100644
index 00000000000..283d63fb235
Binary files /dev/null and b/public/images/ui/legacy/text_images/tr/battle_ui/overlay_hp_label_boss_tr.png differ
diff --git a/public/images/ui/legacy/text_images/tr/battle_ui/overlay_hp_label_tr.png b/public/images/ui/legacy/text_images/tr/battle_ui/overlay_hp_label_tr.png
new file mode 100644
index 00000000000..da11c11cb50
Binary files /dev/null and b/public/images/ui/legacy/text_images/tr/battle_ui/overlay_hp_label_tr.png differ
diff --git a/public/images/ui/legacy/text_images/tr/battle_ui/overlay_lv_tr.png b/public/images/ui/legacy/text_images/tr/battle_ui/overlay_lv_tr.png
new file mode 100644
index 00000000000..6d8ccbb3f3a
Binary files /dev/null and b/public/images/ui/legacy/text_images/tr/battle_ui/overlay_lv_tr.png differ
diff --git a/public/images/ui/legacy/text_images/tr/battle_ui/pbinfo_stat_tr.json b/public/images/ui/legacy/text_images/tr/battle_ui/pbinfo_stat_tr.json
new file mode 100644
index 00000000000..6de50500767
--- /dev/null
+++ b/public/images/ui/legacy/text_images/tr/battle_ui/pbinfo_stat_tr.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_tr.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 112,
+ "h": 6
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 18,
+ "h": 6
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 18,
+ "h": 6
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 18,
+ "h": 6
+ },
+ "frame": {
+ "x": 18,
+ "y": 0,
+ "w": 18,
+ "h": 6
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 16,
+ "h": 6
+ },
+ "frame": {
+ "x": 36,
+ "y": 0,
+ "w": 16,
+ "h": 6
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 52,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 64,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 76,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 88,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 100,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 8,
+ "h": 6
+ },
+ "frame": {
+ "x": 112,
+ "y": 0,
+ "w": 8,
+ "h": 6
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:40d30205ce8efd40dfa86cd11b0491d6:7076db6ed74199dcfb38fc8cd4d4a0e8:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/legacy/text_images/tr/battle_ui/pbinfo_stat_tr.png b/public/images/ui/legacy/text_images/tr/battle_ui/pbinfo_stat_tr.png
new file mode 100644
index 00000000000..c729e7a2207
Binary files /dev/null and b/public/images/ui/legacy/text_images/tr/battle_ui/pbinfo_stat_tr.png differ
diff --git a/public/images/ui/legacy/text_images/tr/party_ui/party_slot_overlay_hp_tr.png b/public/images/ui/legacy/text_images/tr/party_ui/party_slot_overlay_hp_tr.png
new file mode 100644
index 00000000000..2833fa27fb4
Binary files /dev/null and b/public/images/ui/legacy/text_images/tr/party_ui/party_slot_overlay_hp_tr.png differ
diff --git a/public/images/ui/legacy/text_images/tr/party_ui/party_slot_overlay_lv_tr.png b/public/images/ui/legacy/text_images/tr/party_ui/party_slot_overlay_lv_tr.png
new file mode 100644
index 00000000000..958a750a665
Binary files /dev/null and b/public/images/ui/legacy/text_images/tr/party_ui/party_slot_overlay_lv_tr.png differ
diff --git a/public/images/ui/legacy/text_images/zh-CN/battle_ui/overlay_exp_label_zh-CN.png b/public/images/ui/legacy/text_images/zh-CN/battle_ui/overlay_exp_label_zh-CN.png
new file mode 100644
index 00000000000..40b5e8925a1
Binary files /dev/null and b/public/images/ui/legacy/text_images/zh-CN/battle_ui/overlay_exp_label_zh-CN.png differ
diff --git a/public/images/ui/legacy/text_images/zh-CN/battle_ui/overlay_hp_label_boss_zh-CN.png b/public/images/ui/legacy/text_images/zh-CN/battle_ui/overlay_hp_label_boss_zh-CN.png
new file mode 100644
index 00000000000..283d63fb235
Binary files /dev/null and b/public/images/ui/legacy/text_images/zh-CN/battle_ui/overlay_hp_label_boss_zh-CN.png differ
diff --git a/public/images/ui/legacy/text_images/zh-CN/battle_ui/overlay_hp_label_zh-CN.png b/public/images/ui/legacy/text_images/zh-CN/battle_ui/overlay_hp_label_zh-CN.png
new file mode 100644
index 00000000000..67824c7ee4e
Binary files /dev/null and b/public/images/ui/legacy/text_images/zh-CN/battle_ui/overlay_hp_label_zh-CN.png differ
diff --git a/public/images/ui/legacy/text_images/zh-CN/battle_ui/overlay_lv_zh-CN.png b/public/images/ui/legacy/text_images/zh-CN/battle_ui/overlay_lv_zh-CN.png
new file mode 100644
index 00000000000..ea32ac03ee2
Binary files /dev/null and b/public/images/ui/legacy/text_images/zh-CN/battle_ui/overlay_lv_zh-CN.png differ
diff --git a/public/images/ui/legacy/text_images/zh-CN/battle_ui/pbinfo_stat_zh-CN.json b/public/images/ui/legacy/text_images/zh-CN/battle_ui/pbinfo_stat_zh-CN.json
new file mode 100644
index 00000000000..49649bbc315
--- /dev/null
+++ b/public/images/ui/legacy/text_images/zh-CN/battle_ui/pbinfo_stat_zh-CN.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_zh-CN.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 112,
+ "h": 6
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 18,
+ "h": 6
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 18,
+ "h": 6
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 18,
+ "h": 6
+ },
+ "frame": {
+ "x": 18,
+ "y": 0,
+ "w": 18,
+ "h": 6
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 16,
+ "h": 6
+ },
+ "frame": {
+ "x": 36,
+ "y": 0,
+ "w": 16,
+ "h": 6
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 52,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 64,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 76,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 88,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 100,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 8,
+ "h": 6
+ },
+ "frame": {
+ "x": 112,
+ "y": 0,
+ "w": 8,
+ "h": 6
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:40d30205ce8efd40dfa86cd11b0491d6:7076db6ed74199dcfb38fc8cd4d4a0e8:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/legacy/text_images/zh-CN/battle_ui/pbinfo_stat_zh-CN.png b/public/images/ui/legacy/text_images/zh-CN/battle_ui/pbinfo_stat_zh-CN.png
new file mode 100644
index 00000000000..c729e7a2207
Binary files /dev/null and b/public/images/ui/legacy/text_images/zh-CN/battle_ui/pbinfo_stat_zh-CN.png differ
diff --git a/public/images/ui/legacy/text_images/zh-CN/party_ui/party_slot_overlay_hp_zh-CN.png b/public/images/ui/legacy/text_images/zh-CN/party_ui/party_slot_overlay_hp_zh-CN.png
new file mode 100644
index 00000000000..a78ac090d3b
Binary files /dev/null and b/public/images/ui/legacy/text_images/zh-CN/party_ui/party_slot_overlay_hp_zh-CN.png differ
diff --git a/public/images/ui/legacy/text_images/zh-CN/party_ui/party_slot_overlay_lv_zh-CN.png b/public/images/ui/legacy/text_images/zh-CN/party_ui/party_slot_overlay_lv_zh-CN.png
new file mode 100644
index 00000000000..11bb545c7af
Binary files /dev/null and b/public/images/ui/legacy/text_images/zh-CN/party_ui/party_slot_overlay_lv_zh-CN.png differ
diff --git a/public/images/ui/legacy/text_images/zh-TW/battle_ui/overlay_exp_label_zh-TW.png b/public/images/ui/legacy/text_images/zh-TW/battle_ui/overlay_exp_label_zh-TW.png
new file mode 100644
index 00000000000..40b5e8925a1
Binary files /dev/null and b/public/images/ui/legacy/text_images/zh-TW/battle_ui/overlay_exp_label_zh-TW.png differ
diff --git a/public/images/ui/legacy/text_images/zh-TW/battle_ui/overlay_hp_label_boss_zh-TW.png b/public/images/ui/legacy/text_images/zh-TW/battle_ui/overlay_hp_label_boss_zh-TW.png
new file mode 100644
index 00000000000..283d63fb235
Binary files /dev/null and b/public/images/ui/legacy/text_images/zh-TW/battle_ui/overlay_hp_label_boss_zh-TW.png differ
diff --git a/public/images/ui/legacy/text_images/zh-TW/battle_ui/overlay_hp_label_zh-TW.png b/public/images/ui/legacy/text_images/zh-TW/battle_ui/overlay_hp_label_zh-TW.png
new file mode 100644
index 00000000000..67824c7ee4e
Binary files /dev/null and b/public/images/ui/legacy/text_images/zh-TW/battle_ui/overlay_hp_label_zh-TW.png differ
diff --git a/public/images/ui/legacy/text_images/zh-TW/battle_ui/overlay_lv_zh-TW.png b/public/images/ui/legacy/text_images/zh-TW/battle_ui/overlay_lv_zh-TW.png
new file mode 100644
index 00000000000..ea32ac03ee2
Binary files /dev/null and b/public/images/ui/legacy/text_images/zh-TW/battle_ui/overlay_lv_zh-TW.png differ
diff --git a/public/images/ui/legacy/text_images/zh-TW/battle_ui/pbinfo_stat_zh-TW.json b/public/images/ui/legacy/text_images/zh-TW/battle_ui/pbinfo_stat_zh-TW.json
new file mode 100644
index 00000000000..5a2e0fe2c30
--- /dev/null
+++ b/public/images/ui/legacy/text_images/zh-TW/battle_ui/pbinfo_stat_zh-TW.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_zh-TW.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 112,
+ "h": 6
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 18,
+ "h": 6
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 18,
+ "h": 6
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 18,
+ "h": 6
+ },
+ "frame": {
+ "x": 18,
+ "y": 0,
+ "w": 18,
+ "h": 6
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 16,
+ "h": 6
+ },
+ "frame": {
+ "x": 36,
+ "y": 0,
+ "w": 16,
+ "h": 6
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 52,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 64,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 76,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 88,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 12,
+ "h": 6
+ },
+ "frame": {
+ "x": 100,
+ "y": 0,
+ "w": 12,
+ "h": 6
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 8,
+ "h": 6
+ },
+ "frame": {
+ "x": 112,
+ "y": 0,
+ "w": 8,
+ "h": 6
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:40d30205ce8efd40dfa86cd11b0491d6:7076db6ed74199dcfb38fc8cd4d4a0e8:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/legacy/text_images/zh-TW/battle_ui/pbinfo_stat_zh-TW.png b/public/images/ui/legacy/text_images/zh-TW/battle_ui/pbinfo_stat_zh-TW.png
new file mode 100644
index 00000000000..c729e7a2207
Binary files /dev/null and b/public/images/ui/legacy/text_images/zh-TW/battle_ui/pbinfo_stat_zh-TW.png differ
diff --git a/public/images/ui/legacy/text_images/zh-TW/party_ui/party_slot_overlay_hp_zh-TW.png b/public/images/ui/legacy/text_images/zh-TW/party_ui/party_slot_overlay_hp_zh-TW.png
new file mode 100644
index 00000000000..a78ac090d3b
Binary files /dev/null and b/public/images/ui/legacy/text_images/zh-TW/party_ui/party_slot_overlay_hp_zh-TW.png differ
diff --git a/public/images/ui/legacy/text_images/zh-TW/party_ui/party_slot_overlay_lv_zh-TW.png b/public/images/ui/legacy/text_images/zh-TW/party_ui/party_slot_overlay_lv_zh-TW.png
new file mode 100644
index 00000000000..11bb545c7af
Binary files /dev/null and b/public/images/ui/legacy/text_images/zh-TW/party_ui/party_slot_overlay_lv_zh-TW.png differ
diff --git a/public/images/ui/overlay_lv.png b/public/images/ui/overlay_lv.png
deleted file mode 100644
index 6ced2da2660..00000000000
Binary files a/public/images/ui/overlay_lv.png and /dev/null differ
diff --git a/public/images/ui/party_slot_hp_bar.png b/public/images/ui/party_slot_hp_bar.png
index 181bd04c0ea..c1818439e75 100644
Binary files a/public/images/ui/party_slot_hp_bar.png and b/public/images/ui/party_slot_hp_bar.png differ
diff --git a/public/images/ui/pbinfo_enemy_boss.png b/public/images/ui/pbinfo_enemy_boss.png
index ce829bf4631..421edabba03 100644
Binary files a/public/images/ui/pbinfo_enemy_boss.png and b/public/images/ui/pbinfo_enemy_boss.png differ
diff --git a/public/images/ui/pbinfo_enemy_mini.png b/public/images/ui/pbinfo_enemy_mini.png
index ddf10776778..bf60bb0f964 100644
Binary files a/public/images/ui/pbinfo_enemy_mini.png and b/public/images/ui/pbinfo_enemy_mini.png differ
diff --git a/public/images/ui/pbinfo_player.png b/public/images/ui/pbinfo_player.png
index c7b2227e800..55c381bd436 100644
Binary files a/public/images/ui/pbinfo_player.png and b/public/images/ui/pbinfo_player.png differ
diff --git a/public/images/ui/pbinfo_player_mini.png b/public/images/ui/pbinfo_player_mini.png
index 90d5e03dae8..255ad00f8ca 100644
Binary files a/public/images/ui/pbinfo_player_mini.png and b/public/images/ui/pbinfo_player_mini.png differ
diff --git a/public/images/ui/pbinfo_stat.png b/public/images/ui/pbinfo_stat.png
deleted file mode 100644
index 1f86cc6a958..00000000000
Binary files a/public/images/ui/pbinfo_stat.png and /dev/null differ
diff --git a/public/images/ui/text_images/ca/battle_ui/overlay_exp_label_ca.png b/public/images/ui/text_images/ca/battle_ui/overlay_exp_label_ca.png
new file mode 100644
index 00000000000..fde37213eff
Binary files /dev/null and b/public/images/ui/text_images/ca/battle_ui/overlay_exp_label_ca.png differ
diff --git a/public/images/ui/text_images/ca/battle_ui/overlay_hp_label_boss_ca.png b/public/images/ui/text_images/ca/battle_ui/overlay_hp_label_boss_ca.png
new file mode 100644
index 00000000000..0bcec679e05
Binary files /dev/null and b/public/images/ui/text_images/ca/battle_ui/overlay_hp_label_boss_ca.png differ
diff --git a/public/images/ui/text_images/ca/battle_ui/overlay_hp_label_ca.png b/public/images/ui/text_images/ca/battle_ui/overlay_hp_label_ca.png
new file mode 100644
index 00000000000..7c7ccba752f
Binary files /dev/null and b/public/images/ui/text_images/ca/battle_ui/overlay_hp_label_ca.png differ
diff --git a/public/images/ui/text_images/ca/battle_ui/overlay_lv_ca.png b/public/images/ui/text_images/ca/battle_ui/overlay_lv_ca.png
new file mode 100644
index 00000000000..869a1ee0051
Binary files /dev/null and b/public/images/ui/text_images/ca/battle_ui/overlay_lv_ca.png differ
diff --git a/public/images/ui/text_images/ca/battle_ui/pbinfo_stat_ca.json b/public/images/ui/text_images/ca/battle_ui/pbinfo_stat_ca.json
new file mode 100644
index 00000000000..488321effd7
--- /dev/null
+++ b/public/images/ui/text_images/ca/battle_ui/pbinfo_stat_ca.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_ca.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 120,
+ "h": 9
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 19,
+ "h": 9
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 19,
+ "h": 9
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 19,
+ "h": 9
+ },
+ "frame": {
+ "x": 19,
+ "y": 0,
+ "w": 19,
+ "h": 9
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 17,
+ "h": 9
+ },
+ "frame": {
+ "x": 38,
+ "y": 0,
+ "w": 17,
+ "h": 9
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 13,
+ "h": 9
+ },
+ "frame": {
+ "x": 55,
+ "y": 0,
+ "w": 13,
+ "h": 9
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 13,
+ "h": 9
+ },
+ "frame": {
+ "x": 68,
+ "y": 0,
+ "w": 13,
+ "h": 9
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 13,
+ "h": 9
+ },
+ "frame": {
+ "x": 81,
+ "y": 0,
+ "w": 13,
+ "h": 9
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 13,
+ "h": 9
+ },
+ "frame": {
+ "x": 94,
+ "y": 0,
+ "w": 13,
+ "h": 9
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 13,
+ "h": 9
+ },
+ "frame": {
+ "x": 107,
+ "y": 0,
+ "w": 13,
+ "h": 9
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 9,
+ "h": 9
+ },
+ "frame": {
+ "x": 120,
+ "y": 0,
+ "w": 9,
+ "h": 9
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:86fbd1b45d46271597a7d9de482aaa74:df702dd9d88db50369f1a096f82fd915:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/text_images/ca/battle_ui/pbinfo_stat_ca.png b/public/images/ui/text_images/ca/battle_ui/pbinfo_stat_ca.png
new file mode 100644
index 00000000000..2b22b4f4d6f
Binary files /dev/null and b/public/images/ui/text_images/ca/battle_ui/pbinfo_stat_ca.png differ
diff --git a/public/images/ui/text_images/ca/party_ui/party_slot_overlay_hp_ca.png b/public/images/ui/text_images/ca/party_ui/party_slot_overlay_hp_ca.png
new file mode 100644
index 00000000000..4bc95e4f95e
Binary files /dev/null and b/public/images/ui/text_images/ca/party_ui/party_slot_overlay_hp_ca.png differ
diff --git a/public/images/ui/text_images/ca/party_ui/party_slot_overlay_lv_ca.png b/public/images/ui/text_images/ca/party_ui/party_slot_overlay_lv_ca.png
new file mode 100644
index 00000000000..c5971de4fd0
Binary files /dev/null and b/public/images/ui/text_images/ca/party_ui/party_slot_overlay_lv_ca.png differ
diff --git a/public/images/ui/text_images/da/battle_ui/overlay_exp_label_da.png b/public/images/ui/text_images/da/battle_ui/overlay_exp_label_da.png
new file mode 100644
index 00000000000..39a92725bc0
Binary files /dev/null and b/public/images/ui/text_images/da/battle_ui/overlay_exp_label_da.png differ
diff --git a/public/images/ui/text_images/da/battle_ui/overlay_hp_label_boss_da.png b/public/images/ui/text_images/da/battle_ui/overlay_hp_label_boss_da.png
new file mode 100644
index 00000000000..0bcec679e05
Binary files /dev/null and b/public/images/ui/text_images/da/battle_ui/overlay_hp_label_boss_da.png differ
diff --git a/public/images/ui/text_images/da/battle_ui/overlay_hp_label_da.png b/public/images/ui/text_images/da/battle_ui/overlay_hp_label_da.png
new file mode 100644
index 00000000000..38a34761381
Binary files /dev/null and b/public/images/ui/text_images/da/battle_ui/overlay_hp_label_da.png differ
diff --git a/public/images/ui/text_images/da/battle_ui/overlay_lv_da.png b/public/images/ui/text_images/da/battle_ui/overlay_lv_da.png
new file mode 100644
index 00000000000..9ad4312d561
Binary files /dev/null and b/public/images/ui/text_images/da/battle_ui/overlay_lv_da.png differ
diff --git a/public/images/ui/text_images/da/battle_ui/pbinfo_stat_da.json b/public/images/ui/text_images/da/battle_ui/pbinfo_stat_da.json
new file mode 100644
index 00000000000..5108fa59582
--- /dev/null
+++ b/public/images/ui/text_images/da/battle_ui/pbinfo_stat_da.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_da.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 120,
+ "h": 7
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 19,
+ "h": 7
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 19,
+ "h": 7
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 19,
+ "h": 7
+ },
+ "frame": {
+ "x": 19,
+ "y": 0,
+ "w": 19,
+ "h": 7
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 17,
+ "h": 7
+ },
+ "frame": {
+ "x": 38,
+ "y": 0,
+ "w": 17,
+ "h": 7
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 55,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 68,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 81,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 94,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 107,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 9,
+ "h": 7
+ },
+ "frame": {
+ "x": 120,
+ "y": 0,
+ "w": 9,
+ "h": 7
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:86fbd1b45d46271597a7d9de482aaa74:df702dd9d88db50369f1a096f82fd915:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/text_images/da/battle_ui/pbinfo_stat_da.png b/public/images/ui/text_images/da/battle_ui/pbinfo_stat_da.png
new file mode 100644
index 00000000000..9656c5f04b9
Binary files /dev/null and b/public/images/ui/text_images/da/battle_ui/pbinfo_stat_da.png differ
diff --git a/public/images/ui/text_images/da/party_ui/party_slot_overlay_hp_da.png b/public/images/ui/text_images/da/party_ui/party_slot_overlay_hp_da.png
new file mode 100644
index 00000000000..9be90b5c6bb
Binary files /dev/null and b/public/images/ui/text_images/da/party_ui/party_slot_overlay_hp_da.png differ
diff --git a/public/images/ui/party_slot_overlay_lv.png b/public/images/ui/text_images/da/party_ui/party_slot_overlay_lv_da.png
similarity index 100%
rename from public/images/ui/party_slot_overlay_lv.png
rename to public/images/ui/text_images/da/party_ui/party_slot_overlay_lv_da.png
diff --git a/public/images/ui/text_images/de/battle_ui/overlay_exp_label_de.png b/public/images/ui/text_images/de/battle_ui/overlay_exp_label_de.png
new file mode 100644
index 00000000000..39a92725bc0
Binary files /dev/null and b/public/images/ui/text_images/de/battle_ui/overlay_exp_label_de.png differ
diff --git a/public/images/ui/text_images/de/battle_ui/overlay_hp_label_boss_de.png b/public/images/ui/text_images/de/battle_ui/overlay_hp_label_boss_de.png
new file mode 100644
index 00000000000..0bcec679e05
Binary files /dev/null and b/public/images/ui/text_images/de/battle_ui/overlay_hp_label_boss_de.png differ
diff --git a/public/images/ui/text_images/de/battle_ui/overlay_hp_label_de.png b/public/images/ui/text_images/de/battle_ui/overlay_hp_label_de.png
new file mode 100644
index 00000000000..8b227eebd7a
Binary files /dev/null and b/public/images/ui/text_images/de/battle_ui/overlay_hp_label_de.png differ
diff --git a/public/images/ui/text_images/de/battle_ui/overlay_lv_de.png b/public/images/ui/text_images/de/battle_ui/overlay_lv_de.png
new file mode 100644
index 00000000000..9ad4312d561
Binary files /dev/null and b/public/images/ui/text_images/de/battle_ui/overlay_lv_de.png differ
diff --git a/public/images/ui/text_images/de/battle_ui/pbinfo_stat_de.json b/public/images/ui/text_images/de/battle_ui/pbinfo_stat_de.json
new file mode 100644
index 00000000000..dbf39c94059
--- /dev/null
+++ b/public/images/ui/text_images/de/battle_ui/pbinfo_stat_de.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_de.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 120,
+ "h": 7
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 19,
+ "h": 7
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 19,
+ "h": 7
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 19,
+ "h": 7
+ },
+ "frame": {
+ "x": 19,
+ "y": 0,
+ "w": 19,
+ "h": 7
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 17,
+ "h": 7
+ },
+ "frame": {
+ "x": 38,
+ "y": 0,
+ "w": 17,
+ "h": 7
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 55,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 68,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 81,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 94,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 107,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 9,
+ "h": 7
+ },
+ "frame": {
+ "x": 120,
+ "y": 0,
+ "w": 9,
+ "h": 7
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:86fbd1b45d46271597a7d9de482aaa74:df702dd9d88db50369f1a096f82fd915:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/text_images/de/battle_ui/pbinfo_stat_de.png b/public/images/ui/text_images/de/battle_ui/pbinfo_stat_de.png
new file mode 100644
index 00000000000..b8bcb6138b9
Binary files /dev/null and b/public/images/ui/text_images/de/battle_ui/pbinfo_stat_de.png differ
diff --git a/public/images/ui/text_images/de/party_ui/party_slot_overlay_hp_de.png b/public/images/ui/text_images/de/party_ui/party_slot_overlay_hp_de.png
new file mode 100644
index 00000000000..47ac22e52cb
Binary files /dev/null and b/public/images/ui/text_images/de/party_ui/party_slot_overlay_hp_de.png differ
diff --git a/public/images/ui/text_images/de/party_ui/party_slot_overlay_lv_de.png b/public/images/ui/text_images/de/party_ui/party_slot_overlay_lv_de.png
new file mode 100644
index 00000000000..122d3f7151c
Binary files /dev/null and b/public/images/ui/text_images/de/party_ui/party_slot_overlay_lv_de.png differ
diff --git a/public/images/ui/text_images/en/battle_ui/overlay_exp_label.png b/public/images/ui/text_images/en/battle_ui/overlay_exp_label.png
new file mode 100644
index 00000000000..fde37213eff
Binary files /dev/null and b/public/images/ui/text_images/en/battle_ui/overlay_exp_label.png differ
diff --git a/public/images/ui/text_images/en/battle_ui/overlay_hp_label.png b/public/images/ui/text_images/en/battle_ui/overlay_hp_label.png
new file mode 100644
index 00000000000..38a34761381
Binary files /dev/null and b/public/images/ui/text_images/en/battle_ui/overlay_hp_label.png differ
diff --git a/public/images/ui/text_images/en/battle_ui/overlay_hp_label_boss.png b/public/images/ui/text_images/en/battle_ui/overlay_hp_label_boss.png
new file mode 100644
index 00000000000..0bcec679e05
Binary files /dev/null and b/public/images/ui/text_images/en/battle_ui/overlay_hp_label_boss.png differ
diff --git a/public/images/ui/text_images/en/battle_ui/overlay_lv.png b/public/images/ui/text_images/en/battle_ui/overlay_lv.png
new file mode 100644
index 00000000000..9ad4312d561
Binary files /dev/null and b/public/images/ui/text_images/en/battle_ui/overlay_lv.png differ
diff --git a/public/images/ui/pbinfo_stat.json b/public/images/ui/text_images/en/battle_ui/pbinfo_stat.json
similarity index 100%
rename from public/images/ui/pbinfo_stat.json
rename to public/images/ui/text_images/en/battle_ui/pbinfo_stat.json
diff --git a/public/images/ui/text_images/en/battle_ui/pbinfo_stat.png b/public/images/ui/text_images/en/battle_ui/pbinfo_stat.png
new file mode 100644
index 00000000000..9656c5f04b9
Binary files /dev/null and b/public/images/ui/text_images/en/battle_ui/pbinfo_stat.png differ
diff --git a/public/images/ui/text_images/en/party_ui/party_slot_overlay_hp.png b/public/images/ui/text_images/en/party_ui/party_slot_overlay_hp.png
new file mode 100644
index 00000000000..9be90b5c6bb
Binary files /dev/null and b/public/images/ui/text_images/en/party_ui/party_slot_overlay_hp.png differ
diff --git a/public/images/ui/text_images/en/party_ui/party_slot_overlay_lv.png b/public/images/ui/text_images/en/party_ui/party_slot_overlay_lv.png
new file mode 100644
index 00000000000..122d3f7151c
Binary files /dev/null and b/public/images/ui/text_images/en/party_ui/party_slot_overlay_lv.png differ
diff --git a/public/images/ui/text_images/es-ES/battle_ui/overlay_exp_label_es-ES.png b/public/images/ui/text_images/es-ES/battle_ui/overlay_exp_label_es-ES.png
new file mode 100644
index 00000000000..fde37213eff
Binary files /dev/null and b/public/images/ui/text_images/es-ES/battle_ui/overlay_exp_label_es-ES.png differ
diff --git a/public/images/ui/text_images/es-ES/battle_ui/overlay_hp_label_boss_es-ES.png b/public/images/ui/text_images/es-ES/battle_ui/overlay_hp_label_boss_es-ES.png
new file mode 100644
index 00000000000..440ba6136dc
Binary files /dev/null and b/public/images/ui/text_images/es-ES/battle_ui/overlay_hp_label_boss_es-ES.png differ
diff --git a/public/images/ui/text_images/es-ES/battle_ui/overlay_hp_label_es-ES.png b/public/images/ui/text_images/es-ES/battle_ui/overlay_hp_label_es-ES.png
new file mode 100644
index 00000000000..7c7ccba752f
Binary files /dev/null and b/public/images/ui/text_images/es-ES/battle_ui/overlay_hp_label_es-ES.png differ
diff --git a/public/images/ui/text_images/es-ES/battle_ui/overlay_lv_es-ES.png b/public/images/ui/text_images/es-ES/battle_ui/overlay_lv_es-ES.png
new file mode 100644
index 00000000000..869a1ee0051
Binary files /dev/null and b/public/images/ui/text_images/es-ES/battle_ui/overlay_lv_es-ES.png differ
diff --git a/public/images/ui/text_images/es-ES/battle_ui/pbinfo_stat_es-ES.json b/public/images/ui/text_images/es-ES/battle_ui/pbinfo_stat_es-ES.json
new file mode 100644
index 00000000000..1af1d7108bc
--- /dev/null
+++ b/public/images/ui/text_images/es-ES/battle_ui/pbinfo_stat_es-ES.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_es-ES.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 120,
+ "h": 9
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 19,
+ "h": 9
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 19,
+ "h": 9
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 19,
+ "h": 9
+ },
+ "frame": {
+ "x": 19,
+ "y": 0,
+ "w": 19,
+ "h": 9
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 17,
+ "h": 9
+ },
+ "frame": {
+ "x": 38,
+ "y": 0,
+ "w": 17,
+ "h": 9
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 13,
+ "h": 9
+ },
+ "frame": {
+ "x": 55,
+ "y": 0,
+ "w": 13,
+ "h": 9
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 13,
+ "h": 9
+ },
+ "frame": {
+ "x": 68,
+ "y": 0,
+ "w": 13,
+ "h": 9
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 13,
+ "h": 9
+ },
+ "frame": {
+ "x": 81,
+ "y": 0,
+ "w": 13,
+ "h": 9
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 13,
+ "h": 9
+ },
+ "frame": {
+ "x": 94,
+ "y": 0,
+ "w": 13,
+ "h": 9
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 13,
+ "h": 9
+ },
+ "frame": {
+ "x": 107,
+ "y": 0,
+ "w": 13,
+ "h": 9
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 9,
+ "h": 9
+ },
+ "frame": {
+ "x": 120,
+ "y": 0,
+ "w": 9,
+ "h": 9
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:86fbd1b45d46271597a7d9de482aaa74:df702dd9d88db50369f1a096f82fd915:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/text_images/es-ES/battle_ui/pbinfo_stat_es-ES.png b/public/images/ui/text_images/es-ES/battle_ui/pbinfo_stat_es-ES.png
new file mode 100644
index 00000000000..63f8215113f
Binary files /dev/null and b/public/images/ui/text_images/es-ES/battle_ui/pbinfo_stat_es-ES.png differ
diff --git a/public/images/ui/text_images/es-ES/party_ui/party_slot_overlay_hp_es-ES.png b/public/images/ui/text_images/es-ES/party_ui/party_slot_overlay_hp_es-ES.png
new file mode 100644
index 00000000000..4bc95e4f95e
Binary files /dev/null and b/public/images/ui/text_images/es-ES/party_ui/party_slot_overlay_hp_es-ES.png differ
diff --git a/public/images/ui/text_images/es-ES/party_ui/party_slot_overlay_lv_es-ES.png b/public/images/ui/text_images/es-ES/party_ui/party_slot_overlay_lv_es-ES.png
new file mode 100644
index 00000000000..c5971de4fd0
Binary files /dev/null and b/public/images/ui/text_images/es-ES/party_ui/party_slot_overlay_lv_es-ES.png differ
diff --git a/public/images/ui/text_images/es-MX/battle_ui/overlay_exp_label_es-MX.png b/public/images/ui/text_images/es-MX/battle_ui/overlay_exp_label_es-MX.png
new file mode 100644
index 00000000000..fde37213eff
Binary files /dev/null and b/public/images/ui/text_images/es-MX/battle_ui/overlay_exp_label_es-MX.png differ
diff --git a/public/images/ui/text_images/es-MX/battle_ui/overlay_hp_label_boss_es-MX.png b/public/images/ui/text_images/es-MX/battle_ui/overlay_hp_label_boss_es-MX.png
new file mode 100644
index 00000000000..440ba6136dc
Binary files /dev/null and b/public/images/ui/text_images/es-MX/battle_ui/overlay_hp_label_boss_es-MX.png differ
diff --git a/public/images/ui/text_images/es-MX/battle_ui/overlay_hp_label_es-MX.png b/public/images/ui/text_images/es-MX/battle_ui/overlay_hp_label_es-MX.png
new file mode 100644
index 00000000000..7c7ccba752f
Binary files /dev/null and b/public/images/ui/text_images/es-MX/battle_ui/overlay_hp_label_es-MX.png differ
diff --git a/public/images/ui/text_images/es-MX/battle_ui/overlay_lv_es-MX.png b/public/images/ui/text_images/es-MX/battle_ui/overlay_lv_es-MX.png
new file mode 100644
index 00000000000..869a1ee0051
Binary files /dev/null and b/public/images/ui/text_images/es-MX/battle_ui/overlay_lv_es-MX.png differ
diff --git a/public/images/ui/text_images/es-MX/battle_ui/pbinfo_stat_es-MX.json b/public/images/ui/text_images/es-MX/battle_ui/pbinfo_stat_es-MX.json
new file mode 100644
index 00000000000..b372566656b
--- /dev/null
+++ b/public/images/ui/text_images/es-MX/battle_ui/pbinfo_stat_es-MX.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_es-MX.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 120,
+ "h": 9
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 19,
+ "h": 9
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 19,
+ "h": 9
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 19,
+ "h": 9
+ },
+ "frame": {
+ "x": 19,
+ "y": 0,
+ "w": 19,
+ "h": 9
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 17,
+ "h": 9
+ },
+ "frame": {
+ "x": 38,
+ "y": 0,
+ "w": 17,
+ "h": 9
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 13,
+ "h": 9
+ },
+ "frame": {
+ "x": 55,
+ "y": 0,
+ "w": 13,
+ "h": 9
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 13,
+ "h": 9
+ },
+ "frame": {
+ "x": 68,
+ "y": 0,
+ "w": 13,
+ "h": 9
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 13,
+ "h": 9
+ },
+ "frame": {
+ "x": 81,
+ "y": 0,
+ "w": 13,
+ "h": 9
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 13,
+ "h": 9
+ },
+ "frame": {
+ "x": 94,
+ "y": 0,
+ "w": 13,
+ "h": 9
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 13,
+ "h": 9
+ },
+ "frame": {
+ "x": 107,
+ "y": 0,
+ "w": 13,
+ "h": 9
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 9,
+ "h": 9
+ },
+ "frame": {
+ "x": 120,
+ "y": 0,
+ "w": 9,
+ "h": 9
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:86fbd1b45d46271597a7d9de482aaa74:df702dd9d88db50369f1a096f82fd915:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/text_images/es-MX/battle_ui/pbinfo_stat_es-MX.png b/public/images/ui/text_images/es-MX/battle_ui/pbinfo_stat_es-MX.png
new file mode 100644
index 00000000000..63f8215113f
Binary files /dev/null and b/public/images/ui/text_images/es-MX/battle_ui/pbinfo_stat_es-MX.png differ
diff --git a/public/images/ui/text_images/es-MX/party_ui/party_slot_overlay_hp_es-MX.png b/public/images/ui/text_images/es-MX/party_ui/party_slot_overlay_hp_es-MX.png
new file mode 100644
index 00000000000..4bc95e4f95e
Binary files /dev/null and b/public/images/ui/text_images/es-MX/party_ui/party_slot_overlay_hp_es-MX.png differ
diff --git a/public/images/ui/text_images/es-MX/party_ui/party_slot_overlay_lv_es-MX.png b/public/images/ui/text_images/es-MX/party_ui/party_slot_overlay_lv_es-MX.png
new file mode 100644
index 00000000000..c5971de4fd0
Binary files /dev/null and b/public/images/ui/text_images/es-MX/party_ui/party_slot_overlay_lv_es-MX.png differ
diff --git a/public/images/ui/text_images/fr/battle_ui/overlay_exp_label_fr.png b/public/images/ui/text_images/fr/battle_ui/overlay_exp_label_fr.png
new file mode 100644
index 00000000000..fde37213eff
Binary files /dev/null and b/public/images/ui/text_images/fr/battle_ui/overlay_exp_label_fr.png differ
diff --git a/public/images/ui/text_images/fr/battle_ui/overlay_hp_label_boss_fr.png b/public/images/ui/text_images/fr/battle_ui/overlay_hp_label_boss_fr.png
new file mode 100644
index 00000000000..0bcec679e05
Binary files /dev/null and b/public/images/ui/text_images/fr/battle_ui/overlay_hp_label_boss_fr.png differ
diff --git a/public/images/ui/text_images/fr/battle_ui/overlay_hp_label_fr.png b/public/images/ui/text_images/fr/battle_ui/overlay_hp_label_fr.png
new file mode 100644
index 00000000000..e086339f047
Binary files /dev/null and b/public/images/ui/text_images/fr/battle_ui/overlay_hp_label_fr.png differ
diff --git a/public/images/ui/text_images/fr/battle_ui/overlay_lv_fr.png b/public/images/ui/text_images/fr/battle_ui/overlay_lv_fr.png
new file mode 100644
index 00000000000..9a9ccb6d02d
Binary files /dev/null and b/public/images/ui/text_images/fr/battle_ui/overlay_lv_fr.png differ
diff --git a/public/images/ui/text_images/fr/battle_ui/pbinfo_stat_fr.json b/public/images/ui/text_images/fr/battle_ui/pbinfo_stat_fr.json
new file mode 100644
index 00000000000..1275fe16ec3
--- /dev/null
+++ b/public/images/ui/text_images/fr/battle_ui/pbinfo_stat_fr.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_fr.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 120,
+ "h": 9
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 19,
+ "h": 9
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 19,
+ "h": 9
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 19,
+ "h": 9
+ },
+ "frame": {
+ "x": 19,
+ "y": 0,
+ "w": 19,
+ "h": 9
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 17,
+ "h": 9
+ },
+ "frame": {
+ "x": 38,
+ "y": 0,
+ "w": 17,
+ "h": 9
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 13,
+ "h": 9
+ },
+ "frame": {
+ "x": 55,
+ "y": 0,
+ "w": 13,
+ "h": 9
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 13,
+ "h": 9
+ },
+ "frame": {
+ "x": 68,
+ "y": 0,
+ "w": 13,
+ "h": 9
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 13,
+ "h": 9
+ },
+ "frame": {
+ "x": 81,
+ "y": 0,
+ "w": 13,
+ "h": 9
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 13,
+ "h": 9
+ },
+ "frame": {
+ "x": 94,
+ "y": 0,
+ "w": 13,
+ "h": 9
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 13,
+ "h": 9
+ },
+ "frame": {
+ "x": 107,
+ "y": 0,
+ "w": 13,
+ "h": 9
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 9,
+ "h": 9
+ },
+ "frame": {
+ "x": 120,
+ "y": 0,
+ "w": 9,
+ "h": 9
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:86fbd1b45d46271597a7d9de482aaa74:df702dd9d88db50369f1a096f82fd915:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/text_images/fr/battle_ui/pbinfo_stat_fr.png b/public/images/ui/text_images/fr/battle_ui/pbinfo_stat_fr.png
new file mode 100644
index 00000000000..baea5c8d93c
Binary files /dev/null and b/public/images/ui/text_images/fr/battle_ui/pbinfo_stat_fr.png differ
diff --git a/public/images/ui/text_images/fr/party_ui/party_slot_overlay_hp_fr.png b/public/images/ui/text_images/fr/party_ui/party_slot_overlay_hp_fr.png
new file mode 100644
index 00000000000..140c99eef68
Binary files /dev/null and b/public/images/ui/text_images/fr/party_ui/party_slot_overlay_hp_fr.png differ
diff --git a/public/images/ui/text_images/fr/party_ui/party_slot_overlay_lv_fr.png b/public/images/ui/text_images/fr/party_ui/party_slot_overlay_lv_fr.png
new file mode 100644
index 00000000000..ff489e33712
Binary files /dev/null and b/public/images/ui/text_images/fr/party_ui/party_slot_overlay_lv_fr.png differ
diff --git a/public/images/ui/text_images/it/battle_ui/overlay_exp_label_it.png b/public/images/ui/text_images/it/battle_ui/overlay_exp_label_it.png
new file mode 100644
index 00000000000..6ad5855cc46
Binary files /dev/null and b/public/images/ui/text_images/it/battle_ui/overlay_exp_label_it.png differ
diff --git a/public/images/ui/text_images/it/battle_ui/overlay_hp_label_boss_it.png b/public/images/ui/text_images/it/battle_ui/overlay_hp_label_boss_it.png
new file mode 100644
index 00000000000..0bcec679e05
Binary files /dev/null and b/public/images/ui/text_images/it/battle_ui/overlay_hp_label_boss_it.png differ
diff --git a/public/images/ui/text_images/it/battle_ui/overlay_hp_label_it.png b/public/images/ui/text_images/it/battle_ui/overlay_hp_label_it.png
new file mode 100644
index 00000000000..7c7ccba752f
Binary files /dev/null and b/public/images/ui/text_images/it/battle_ui/overlay_hp_label_it.png differ
diff --git a/public/images/ui/text_images/it/battle_ui/overlay_lv_it.png b/public/images/ui/text_images/it/battle_ui/overlay_lv_it.png
new file mode 100644
index 00000000000..987d806b93a
Binary files /dev/null and b/public/images/ui/text_images/it/battle_ui/overlay_lv_it.png differ
diff --git a/public/images/ui/text_images/it/battle_ui/pbinfo_stat_it.json b/public/images/ui/text_images/it/battle_ui/pbinfo_stat_it.json
new file mode 100644
index 00000000000..111a88ba365
--- /dev/null
+++ b/public/images/ui/text_images/it/battle_ui/pbinfo_stat_it.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_it.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 120,
+ "h": 7
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 19,
+ "h": 7
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 19,
+ "h": 7
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 19,
+ "h": 7
+ },
+ "frame": {
+ "x": 19,
+ "y": 0,
+ "w": 19,
+ "h": 7
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 17,
+ "h": 7
+ },
+ "frame": {
+ "x": 38,
+ "y": 0,
+ "w": 17,
+ "h": 7
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 55,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 68,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 81,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 94,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 107,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 9,
+ "h": 7
+ },
+ "frame": {
+ "x": 120,
+ "y": 0,
+ "w": 9,
+ "h": 7
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:86fbd1b45d46271597a7d9de482aaa74:df702dd9d88db50369f1a096f82fd915:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/text_images/it/battle_ui/pbinfo_stat_it.png b/public/images/ui/text_images/it/battle_ui/pbinfo_stat_it.png
new file mode 100644
index 00000000000..c2ac58da184
Binary files /dev/null and b/public/images/ui/text_images/it/battle_ui/pbinfo_stat_it.png differ
diff --git a/public/images/ui/text_images/it/party_ui/party_slot_overlay_hp_it.png b/public/images/ui/text_images/it/party_ui/party_slot_overlay_hp_it.png
new file mode 100644
index 00000000000..4bc95e4f95e
Binary files /dev/null and b/public/images/ui/text_images/it/party_ui/party_slot_overlay_hp_it.png differ
diff --git a/public/images/ui/text_images/it/party_ui/party_slot_overlay_lv_it.png b/public/images/ui/text_images/it/party_ui/party_slot_overlay_lv_it.png
new file mode 100644
index 00000000000..31a2a31dd41
Binary files /dev/null and b/public/images/ui/text_images/it/party_ui/party_slot_overlay_lv_it.png differ
diff --git a/public/images/ui/text_images/ja/battle_ui/overlay_exp_label_ja.png b/public/images/ui/text_images/ja/battle_ui/overlay_exp_label_ja.png
new file mode 100644
index 00000000000..fde37213eff
Binary files /dev/null and b/public/images/ui/text_images/ja/battle_ui/overlay_exp_label_ja.png differ
diff --git a/public/images/ui/text_images/ja/battle_ui/overlay_hp_label_boss_ja.png b/public/images/ui/text_images/ja/battle_ui/overlay_hp_label_boss_ja.png
new file mode 100644
index 00000000000..0bcec679e05
Binary files /dev/null and b/public/images/ui/text_images/ja/battle_ui/overlay_hp_label_boss_ja.png differ
diff --git a/public/images/ui/text_images/ja/battle_ui/overlay_hp_label_ja.png b/public/images/ui/text_images/ja/battle_ui/overlay_hp_label_ja.png
new file mode 100644
index 00000000000..38a34761381
Binary files /dev/null and b/public/images/ui/text_images/ja/battle_ui/overlay_hp_label_ja.png differ
diff --git a/public/images/ui/text_images/ja/battle_ui/overlay_lv_ja.png b/public/images/ui/text_images/ja/battle_ui/overlay_lv_ja.png
new file mode 100644
index 00000000000..9ad4312d561
Binary files /dev/null and b/public/images/ui/text_images/ja/battle_ui/overlay_lv_ja.png differ
diff --git a/public/images/ui/text_images/ja/battle_ui/pbinfo_stat_ja.json b/public/images/ui/text_images/ja/battle_ui/pbinfo_stat_ja.json
new file mode 100644
index 00000000000..d8de5c788ef
--- /dev/null
+++ b/public/images/ui/text_images/ja/battle_ui/pbinfo_stat_ja.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_ja.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 120,
+ "h": 7
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 19,
+ "h": 7
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 19,
+ "h": 7
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 19,
+ "h": 7
+ },
+ "frame": {
+ "x": 19,
+ "y": 0,
+ "w": 19,
+ "h": 7
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 17,
+ "h": 7
+ },
+ "frame": {
+ "x": 38,
+ "y": 0,
+ "w": 17,
+ "h": 7
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 55,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 68,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 81,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 94,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 107,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 9,
+ "h": 7
+ },
+ "frame": {
+ "x": 120,
+ "y": 0,
+ "w": 9,
+ "h": 7
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:86fbd1b45d46271597a7d9de482aaa74:df702dd9d88db50369f1a096f82fd915:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/text_images/ja/battle_ui/pbinfo_stat_ja.png b/public/images/ui/text_images/ja/battle_ui/pbinfo_stat_ja.png
new file mode 100644
index 00000000000..9656c5f04b9
Binary files /dev/null and b/public/images/ui/text_images/ja/battle_ui/pbinfo_stat_ja.png differ
diff --git a/public/images/ui/text_images/ja/party_ui/party_slot_overlay_hp_ja.png b/public/images/ui/text_images/ja/party_ui/party_slot_overlay_hp_ja.png
new file mode 100644
index 00000000000..9be90b5c6bb
Binary files /dev/null and b/public/images/ui/text_images/ja/party_ui/party_slot_overlay_hp_ja.png differ
diff --git a/public/images/ui/text_images/ja/party_ui/party_slot_overlay_lv_ja.png b/public/images/ui/text_images/ja/party_ui/party_slot_overlay_lv_ja.png
new file mode 100644
index 00000000000..122d3f7151c
Binary files /dev/null and b/public/images/ui/text_images/ja/party_ui/party_slot_overlay_lv_ja.png differ
diff --git a/public/images/ui/text_images/ko/battle_ui/overlay_exp_label_ko.png b/public/images/ui/text_images/ko/battle_ui/overlay_exp_label_ko.png
new file mode 100644
index 00000000000..fde37213eff
Binary files /dev/null and b/public/images/ui/text_images/ko/battle_ui/overlay_exp_label_ko.png differ
diff --git a/public/images/ui/text_images/ko/battle_ui/overlay_hp_label_boss_ko.png b/public/images/ui/text_images/ko/battle_ui/overlay_hp_label_boss_ko.png
new file mode 100644
index 00000000000..0bcec679e05
Binary files /dev/null and b/public/images/ui/text_images/ko/battle_ui/overlay_hp_label_boss_ko.png differ
diff --git a/public/images/ui/text_images/ko/battle_ui/overlay_hp_label_ko.png b/public/images/ui/text_images/ko/battle_ui/overlay_hp_label_ko.png
new file mode 100644
index 00000000000..38a34761381
Binary files /dev/null and b/public/images/ui/text_images/ko/battle_ui/overlay_hp_label_ko.png differ
diff --git a/public/images/ui/text_images/ko/battle_ui/overlay_lv_ko.png b/public/images/ui/text_images/ko/battle_ui/overlay_lv_ko.png
new file mode 100644
index 00000000000..9ad4312d561
Binary files /dev/null and b/public/images/ui/text_images/ko/battle_ui/overlay_lv_ko.png differ
diff --git a/public/images/ui/text_images/ko/battle_ui/pbinfo_stat_ko.json b/public/images/ui/text_images/ko/battle_ui/pbinfo_stat_ko.json
new file mode 100644
index 00000000000..a1d660dfca3
--- /dev/null
+++ b/public/images/ui/text_images/ko/battle_ui/pbinfo_stat_ko.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_ko.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 120,
+ "h": 7
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 19,
+ "h": 7
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 19,
+ "h": 7
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 19,
+ "h": 7
+ },
+ "frame": {
+ "x": 19,
+ "y": 0,
+ "w": 19,
+ "h": 7
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 17,
+ "h": 7
+ },
+ "frame": {
+ "x": 38,
+ "y": 0,
+ "w": 17,
+ "h": 7
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 55,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 68,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 81,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 94,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 107,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 9,
+ "h": 7
+ },
+ "frame": {
+ "x": 120,
+ "y": 0,
+ "w": 9,
+ "h": 7
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:86fbd1b45d46271597a7d9de482aaa74:df702dd9d88db50369f1a096f82fd915:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/text_images/ko/battle_ui/pbinfo_stat_ko.png b/public/images/ui/text_images/ko/battle_ui/pbinfo_stat_ko.png
new file mode 100644
index 00000000000..9656c5f04b9
Binary files /dev/null and b/public/images/ui/text_images/ko/battle_ui/pbinfo_stat_ko.png differ
diff --git a/public/images/ui/text_images/ko/party_ui/party_slot_overlay_hp_ko.png b/public/images/ui/text_images/ko/party_ui/party_slot_overlay_hp_ko.png
new file mode 100644
index 00000000000..9be90b5c6bb
Binary files /dev/null and b/public/images/ui/text_images/ko/party_ui/party_slot_overlay_hp_ko.png differ
diff --git a/public/images/ui/text_images/ko/party_ui/party_slot_overlay_lv_ko.png b/public/images/ui/text_images/ko/party_ui/party_slot_overlay_lv_ko.png
new file mode 100644
index 00000000000..122d3f7151c
Binary files /dev/null and b/public/images/ui/text_images/ko/party_ui/party_slot_overlay_lv_ko.png differ
diff --git a/public/images/ui/text_images/pt-BR/battle_ui/overlay_exp_label_pt-BR.png b/public/images/ui/text_images/pt-BR/battle_ui/overlay_exp_label_pt-BR.png
new file mode 100644
index 00000000000..fde37213eff
Binary files /dev/null and b/public/images/ui/text_images/pt-BR/battle_ui/overlay_exp_label_pt-BR.png differ
diff --git a/public/images/ui/text_images/pt-BR/battle_ui/overlay_hp_label_boss_pt-BR.png b/public/images/ui/text_images/pt-BR/battle_ui/overlay_hp_label_boss_pt-BR.png
new file mode 100644
index 00000000000..0bcec679e05
Binary files /dev/null and b/public/images/ui/text_images/pt-BR/battle_ui/overlay_hp_label_boss_pt-BR.png differ
diff --git a/public/images/ui/text_images/pt-BR/battle_ui/overlay_hp_label_pt-BR.png b/public/images/ui/text_images/pt-BR/battle_ui/overlay_hp_label_pt-BR.png
new file mode 100644
index 00000000000..7c7ccba752f
Binary files /dev/null and b/public/images/ui/text_images/pt-BR/battle_ui/overlay_hp_label_pt-BR.png differ
diff --git a/public/images/ui/text_images/pt-BR/battle_ui/overlay_lv_pt-BR.png b/public/images/ui/text_images/pt-BR/battle_ui/overlay_lv_pt-BR.png
new file mode 100644
index 00000000000..869a1ee0051
Binary files /dev/null and b/public/images/ui/text_images/pt-BR/battle_ui/overlay_lv_pt-BR.png differ
diff --git a/public/images/ui/text_images/pt-BR/battle_ui/pbinfo_stat_pt-BR.json b/public/images/ui/text_images/pt-BR/battle_ui/pbinfo_stat_pt-BR.json
new file mode 100644
index 00000000000..ca97288795e
--- /dev/null
+++ b/public/images/ui/text_images/pt-BR/battle_ui/pbinfo_stat_pt-BR.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_pt-BR.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 120,
+ "h": 9
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 19,
+ "h": 9
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 19,
+ "h": 9
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 19,
+ "h": 9
+ },
+ "frame": {
+ "x": 19,
+ "y": 0,
+ "w": 19,
+ "h": 9
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 17,
+ "h": 9
+ },
+ "frame": {
+ "x": 38,
+ "y": 0,
+ "w": 17,
+ "h": 9
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 13,
+ "h": 9
+ },
+ "frame": {
+ "x": 55,
+ "y": 0,
+ "w": 13,
+ "h": 9
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 13,
+ "h": 9
+ },
+ "frame": {
+ "x": 68,
+ "y": 0,
+ "w": 13,
+ "h": 9
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 13,
+ "h": 9
+ },
+ "frame": {
+ "x": 81,
+ "y": 0,
+ "w": 13,
+ "h": 9
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 13,
+ "h": 9
+ },
+ "frame": {
+ "x": 94,
+ "y": 0,
+ "w": 13,
+ "h": 9
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 13,
+ "h": 9
+ },
+ "frame": {
+ "x": 107,
+ "y": 0,
+ "w": 13,
+ "h": 9
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": -1,
+ "w": 9,
+ "h": 9
+ },
+ "frame": {
+ "x": 120,
+ "y": 0,
+ "w": 9,
+ "h": 9
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:86fbd1b45d46271597a7d9de482aaa74:df702dd9d88db50369f1a096f82fd915:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/text_images/pt-BR/battle_ui/pbinfo_stat_pt-BR.png b/public/images/ui/text_images/pt-BR/battle_ui/pbinfo_stat_pt-BR.png
new file mode 100644
index 00000000000..c20f4441983
Binary files /dev/null and b/public/images/ui/text_images/pt-BR/battle_ui/pbinfo_stat_pt-BR.png differ
diff --git a/public/images/ui/text_images/pt-BR/party_ui/party_slot_overlay_hp_pt-BR.png b/public/images/ui/text_images/pt-BR/party_ui/party_slot_overlay_hp_pt-BR.png
new file mode 100644
index 00000000000..4bc95e4f95e
Binary files /dev/null and b/public/images/ui/text_images/pt-BR/party_ui/party_slot_overlay_hp_pt-BR.png differ
diff --git a/public/images/ui/text_images/pt-BR/party_ui/party_slot_overlay_lv_pt-BR.png b/public/images/ui/text_images/pt-BR/party_ui/party_slot_overlay_lv_pt-BR.png
new file mode 100644
index 00000000000..c5971de4fd0
Binary files /dev/null and b/public/images/ui/text_images/pt-BR/party_ui/party_slot_overlay_lv_pt-BR.png differ
diff --git a/public/images/ui/text_images/ro/battle_ui/overlay_exp_label_ro.png b/public/images/ui/text_images/ro/battle_ui/overlay_exp_label_ro.png
new file mode 100644
index 00000000000..fde37213eff
Binary files /dev/null and b/public/images/ui/text_images/ro/battle_ui/overlay_exp_label_ro.png differ
diff --git a/public/images/ui/text_images/ro/battle_ui/overlay_hp_label_boss_ro.png b/public/images/ui/text_images/ro/battle_ui/overlay_hp_label_boss_ro.png
new file mode 100644
index 00000000000..0bcec679e05
Binary files /dev/null and b/public/images/ui/text_images/ro/battle_ui/overlay_hp_label_boss_ro.png differ
diff --git a/public/images/ui/text_images/ro/battle_ui/overlay_hp_label_ro.png b/public/images/ui/text_images/ro/battle_ui/overlay_hp_label_ro.png
new file mode 100644
index 00000000000..38a34761381
Binary files /dev/null and b/public/images/ui/text_images/ro/battle_ui/overlay_hp_label_ro.png differ
diff --git a/public/images/ui/text_images/ro/battle_ui/overlay_lv_ro.png b/public/images/ui/text_images/ro/battle_ui/overlay_lv_ro.png
new file mode 100644
index 00000000000..9ad4312d561
Binary files /dev/null and b/public/images/ui/text_images/ro/battle_ui/overlay_lv_ro.png differ
diff --git a/public/images/ui/text_images/ro/battle_ui/pbinfo_stat_ro.json b/public/images/ui/text_images/ro/battle_ui/pbinfo_stat_ro.json
new file mode 100644
index 00000000000..b5f74fdd7cc
--- /dev/null
+++ b/public/images/ui/text_images/ro/battle_ui/pbinfo_stat_ro.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_ro.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 120,
+ "h": 7
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 19,
+ "h": 7
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 19,
+ "h": 7
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 19,
+ "h": 7
+ },
+ "frame": {
+ "x": 19,
+ "y": 0,
+ "w": 19,
+ "h": 7
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 17,
+ "h": 7
+ },
+ "frame": {
+ "x": 38,
+ "y": 0,
+ "w": 17,
+ "h": 7
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 55,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 68,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 81,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 94,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 107,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 9,
+ "h": 7
+ },
+ "frame": {
+ "x": 120,
+ "y": 0,
+ "w": 9,
+ "h": 7
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:86fbd1b45d46271597a7d9de482aaa74:df702dd9d88db50369f1a096f82fd915:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/text_images/ro/battle_ui/pbinfo_stat_ro.png b/public/images/ui/text_images/ro/battle_ui/pbinfo_stat_ro.png
new file mode 100644
index 00000000000..9656c5f04b9
Binary files /dev/null and b/public/images/ui/text_images/ro/battle_ui/pbinfo_stat_ro.png differ
diff --git a/public/images/ui/text_images/ro/party_ui/party_slot_overlay_hp_ro.png b/public/images/ui/text_images/ro/party_ui/party_slot_overlay_hp_ro.png
new file mode 100644
index 00000000000..9be90b5c6bb
Binary files /dev/null and b/public/images/ui/text_images/ro/party_ui/party_slot_overlay_hp_ro.png differ
diff --git a/public/images/ui/text_images/ro/party_ui/party_slot_overlay_lv_ro.png b/public/images/ui/text_images/ro/party_ui/party_slot_overlay_lv_ro.png
new file mode 100644
index 00000000000..122d3f7151c
Binary files /dev/null and b/public/images/ui/text_images/ro/party_ui/party_slot_overlay_lv_ro.png differ
diff --git a/public/images/ui/text_images/ru/battle_ui/overlay_exp_label_ru.png b/public/images/ui/text_images/ru/battle_ui/overlay_exp_label_ru.png
new file mode 100644
index 00000000000..8342acb74fb
Binary files /dev/null and b/public/images/ui/text_images/ru/battle_ui/overlay_exp_label_ru.png differ
diff --git a/public/images/ui/text_images/ru/battle_ui/overlay_hp_label_boss_ru.png b/public/images/ui/text_images/ru/battle_ui/overlay_hp_label_boss_ru.png
new file mode 100644
index 00000000000..af85409a084
Binary files /dev/null and b/public/images/ui/text_images/ru/battle_ui/overlay_hp_label_boss_ru.png differ
diff --git a/public/images/ui/text_images/ru/battle_ui/overlay_hp_label_ru.png b/public/images/ui/text_images/ru/battle_ui/overlay_hp_label_ru.png
new file mode 100644
index 00000000000..b040247cd64
Binary files /dev/null and b/public/images/ui/text_images/ru/battle_ui/overlay_hp_label_ru.png differ
diff --git a/public/images/ui/text_images/ru/battle_ui/overlay_lv_ru.png b/public/images/ui/text_images/ru/battle_ui/overlay_lv_ru.png
new file mode 100644
index 00000000000..65ec593d656
Binary files /dev/null and b/public/images/ui/text_images/ru/battle_ui/overlay_lv_ru.png differ
diff --git a/public/images/ui/text_images/ru/battle_ui/pbinfo_stat_ru.json b/public/images/ui/text_images/ru/battle_ui/pbinfo_stat_ru.json
new file mode 100644
index 00000000000..61618578d25
--- /dev/null
+++ b/public/images/ui/text_images/ru/battle_ui/pbinfo_stat_ru.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_ru.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 120,
+ "h": 8
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 19,
+ "h": 8
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 19,
+ "h": 8
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 19,
+ "h": 8
+ },
+ "frame": {
+ "x": 19,
+ "y": 0,
+ "w": 19,
+ "h": 8
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 17,
+ "h": 8
+ },
+ "frame": {
+ "x": 38,
+ "y": 0,
+ "w": 17,
+ "h": 8
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 8
+ },
+ "frame": {
+ "x": 55,
+ "y": 0,
+ "w": 13,
+ "h": 8
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 8
+ },
+ "frame": {
+ "x": 68,
+ "y": 0,
+ "w": 13,
+ "h": 8
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 8
+ },
+ "frame": {
+ "x": 81,
+ "y": 0,
+ "w": 13,
+ "h": 8
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 8
+ },
+ "frame": {
+ "x": 94,
+ "y": 0,
+ "w": 13,
+ "h": 8
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 8
+ },
+ "frame": {
+ "x": 107,
+ "y": 0,
+ "w": 13,
+ "h": 8
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 9,
+ "h": 8
+ },
+ "frame": {
+ "x": 120,
+ "y": 0,
+ "w": 9,
+ "h": 8
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:86fbd1b45d46271597a7d9de482aaa74:df702dd9d88db50369f1a096f82fd915:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/text_images/ru/battle_ui/pbinfo_stat_ru.png b/public/images/ui/text_images/ru/battle_ui/pbinfo_stat_ru.png
new file mode 100644
index 00000000000..9688d78d425
Binary files /dev/null and b/public/images/ui/text_images/ru/battle_ui/pbinfo_stat_ru.png differ
diff --git a/public/images/ui/text_images/ru/party_ui/party_slot_overlay_hp_ru.png b/public/images/ui/text_images/ru/party_ui/party_slot_overlay_hp_ru.png
new file mode 100644
index 00000000000..5d9e62ac79a
Binary files /dev/null and b/public/images/ui/text_images/ru/party_ui/party_slot_overlay_hp_ru.png differ
diff --git a/public/images/ui/text_images/ru/party_ui/party_slot_overlay_lv_ru.png b/public/images/ui/text_images/ru/party_ui/party_slot_overlay_lv_ru.png
new file mode 100644
index 00000000000..65ec593d656
Binary files /dev/null and b/public/images/ui/text_images/ru/party_ui/party_slot_overlay_lv_ru.png differ
diff --git a/public/images/ui/text_images/tl/battle_ui/overlay_exp_label_tl.png b/public/images/ui/text_images/tl/battle_ui/overlay_exp_label_tl.png
new file mode 100644
index 00000000000..fde37213eff
Binary files /dev/null and b/public/images/ui/text_images/tl/battle_ui/overlay_exp_label_tl.png differ
diff --git a/public/images/ui/text_images/tl/battle_ui/overlay_hp_label_boss_tl.png b/public/images/ui/text_images/tl/battle_ui/overlay_hp_label_boss_tl.png
new file mode 100644
index 00000000000..0bcec679e05
Binary files /dev/null and b/public/images/ui/text_images/tl/battle_ui/overlay_hp_label_boss_tl.png differ
diff --git a/public/images/ui/text_images/tl/battle_ui/overlay_hp_label_tl.png b/public/images/ui/text_images/tl/battle_ui/overlay_hp_label_tl.png
new file mode 100644
index 00000000000..38a34761381
Binary files /dev/null and b/public/images/ui/text_images/tl/battle_ui/overlay_hp_label_tl.png differ
diff --git a/public/images/ui/text_images/tl/battle_ui/overlay_lv_tl.png b/public/images/ui/text_images/tl/battle_ui/overlay_lv_tl.png
new file mode 100644
index 00000000000..9ad4312d561
Binary files /dev/null and b/public/images/ui/text_images/tl/battle_ui/overlay_lv_tl.png differ
diff --git a/public/images/ui/text_images/tl/battle_ui/pbinfo_stat_tl.json b/public/images/ui/text_images/tl/battle_ui/pbinfo_stat_tl.json
new file mode 100644
index 00000000000..d2277c79f24
--- /dev/null
+++ b/public/images/ui/text_images/tl/battle_ui/pbinfo_stat_tl.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_tl.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 120,
+ "h": 7
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 19,
+ "h": 7
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 19,
+ "h": 7
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 19,
+ "h": 7
+ },
+ "frame": {
+ "x": 19,
+ "y": 0,
+ "w": 19,
+ "h": 7
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 17,
+ "h": 7
+ },
+ "frame": {
+ "x": 38,
+ "y": 0,
+ "w": 17,
+ "h": 7
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 55,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 68,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 81,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 94,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 107,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 9,
+ "h": 7
+ },
+ "frame": {
+ "x": 120,
+ "y": 0,
+ "w": 9,
+ "h": 7
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:86fbd1b45d46271597a7d9de482aaa74:df702dd9d88db50369f1a096f82fd915:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/text_images/tl/battle_ui/pbinfo_stat_tl.png b/public/images/ui/text_images/tl/battle_ui/pbinfo_stat_tl.png
new file mode 100644
index 00000000000..9656c5f04b9
Binary files /dev/null and b/public/images/ui/text_images/tl/battle_ui/pbinfo_stat_tl.png differ
diff --git a/public/images/ui/text_images/tl/party_ui/party_slot_overlay_hp_tl.png b/public/images/ui/text_images/tl/party_ui/party_slot_overlay_hp_tl.png
new file mode 100644
index 00000000000..9be90b5c6bb
Binary files /dev/null and b/public/images/ui/text_images/tl/party_ui/party_slot_overlay_hp_tl.png differ
diff --git a/public/images/ui/text_images/tl/party_ui/party_slot_overlay_lv_tl.png b/public/images/ui/text_images/tl/party_ui/party_slot_overlay_lv_tl.png
new file mode 100644
index 00000000000..122d3f7151c
Binary files /dev/null and b/public/images/ui/text_images/tl/party_ui/party_slot_overlay_lv_tl.png differ
diff --git a/public/images/ui/text_images/tr/battle_ui/overlay_exp_label_tr.png b/public/images/ui/text_images/tr/battle_ui/overlay_exp_label_tr.png
new file mode 100644
index 00000000000..0920a95fba2
Binary files /dev/null and b/public/images/ui/text_images/tr/battle_ui/overlay_exp_label_tr.png differ
diff --git a/public/images/ui/text_images/tr/battle_ui/overlay_hp_label_boss_tr.png b/public/images/ui/text_images/tr/battle_ui/overlay_hp_label_boss_tr.png
new file mode 100644
index 00000000000..0bcec679e05
Binary files /dev/null and b/public/images/ui/text_images/tr/battle_ui/overlay_hp_label_boss_tr.png differ
diff --git a/public/images/ui/text_images/tr/battle_ui/overlay_hp_label_tr.png b/public/images/ui/text_images/tr/battle_ui/overlay_hp_label_tr.png
new file mode 100644
index 00000000000..e28aceaf0fa
Binary files /dev/null and b/public/images/ui/text_images/tr/battle_ui/overlay_hp_label_tr.png differ
diff --git a/public/images/ui/text_images/tr/battle_ui/overlay_lv_tr.png b/public/images/ui/text_images/tr/battle_ui/overlay_lv_tr.png
new file mode 100644
index 00000000000..5140444ec15
Binary files /dev/null and b/public/images/ui/text_images/tr/battle_ui/overlay_lv_tr.png differ
diff --git a/public/images/ui/text_images/tr/battle_ui/pbinfo_stat_tr.json b/public/images/ui/text_images/tr/battle_ui/pbinfo_stat_tr.json
new file mode 100644
index 00000000000..c3ccb4a5391
--- /dev/null
+++ b/public/images/ui/text_images/tr/battle_ui/pbinfo_stat_tr.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_tr.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 120,
+ "h": 7
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 19,
+ "h": 7
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 19,
+ "h": 7
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 19,
+ "h": 7
+ },
+ "frame": {
+ "x": 19,
+ "y": 0,
+ "w": 19,
+ "h": 7
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 17,
+ "h": 7
+ },
+ "frame": {
+ "x": 38,
+ "y": 0,
+ "w": 17,
+ "h": 7
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 55,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 68,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 81,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 94,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 107,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 9,
+ "h": 7
+ },
+ "frame": {
+ "x": 120,
+ "y": 0,
+ "w": 9,
+ "h": 7
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:86fbd1b45d46271597a7d9de482aaa74:df702dd9d88db50369f1a096f82fd915:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/text_images/tr/battle_ui/pbinfo_stat_tr.png b/public/images/ui/text_images/tr/battle_ui/pbinfo_stat_tr.png
new file mode 100644
index 00000000000..9656c5f04b9
Binary files /dev/null and b/public/images/ui/text_images/tr/battle_ui/pbinfo_stat_tr.png differ
diff --git a/public/images/ui/text_images/tr/party_ui/party_slot_overlay_hp_tr.png b/public/images/ui/text_images/tr/party_ui/party_slot_overlay_hp_tr.png
new file mode 100644
index 00000000000..bb0017bcb58
Binary files /dev/null and b/public/images/ui/text_images/tr/party_ui/party_slot_overlay_hp_tr.png differ
diff --git a/public/images/ui/text_images/tr/party_ui/party_slot_overlay_lv_tr.png b/public/images/ui/text_images/tr/party_ui/party_slot_overlay_lv_tr.png
new file mode 100644
index 00000000000..12782430b9e
Binary files /dev/null and b/public/images/ui/text_images/tr/party_ui/party_slot_overlay_lv_tr.png differ
diff --git a/public/images/ui/text_images/zh-CN/battle_ui/overlay_exp_label_zh-CN.png b/public/images/ui/text_images/zh-CN/battle_ui/overlay_exp_label_zh-CN.png
new file mode 100644
index 00000000000..fde37213eff
Binary files /dev/null and b/public/images/ui/text_images/zh-CN/battle_ui/overlay_exp_label_zh-CN.png differ
diff --git a/public/images/ui/text_images/zh-CN/battle_ui/overlay_hp_label_boss_zh-CN.png b/public/images/ui/text_images/zh-CN/battle_ui/overlay_hp_label_boss_zh-CN.png
new file mode 100644
index 00000000000..0bcec679e05
Binary files /dev/null and b/public/images/ui/text_images/zh-CN/battle_ui/overlay_hp_label_boss_zh-CN.png differ
diff --git a/public/images/ui/text_images/zh-CN/battle_ui/overlay_hp_label_zh-CN.png b/public/images/ui/text_images/zh-CN/battle_ui/overlay_hp_label_zh-CN.png
new file mode 100644
index 00000000000..38a34761381
Binary files /dev/null and b/public/images/ui/text_images/zh-CN/battle_ui/overlay_hp_label_zh-CN.png differ
diff --git a/public/images/ui/text_images/zh-CN/battle_ui/overlay_lv_zh-CN.png b/public/images/ui/text_images/zh-CN/battle_ui/overlay_lv_zh-CN.png
new file mode 100644
index 00000000000..9ad4312d561
Binary files /dev/null and b/public/images/ui/text_images/zh-CN/battle_ui/overlay_lv_zh-CN.png differ
diff --git a/public/images/ui/text_images/zh-CN/battle_ui/pbinfo_stat_zh-CN.json b/public/images/ui/text_images/zh-CN/battle_ui/pbinfo_stat_zh-CN.json
new file mode 100644
index 00000000000..22a1da0b536
--- /dev/null
+++ b/public/images/ui/text_images/zh-CN/battle_ui/pbinfo_stat_zh-CN.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_zh-CN.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 120,
+ "h": 7
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 19,
+ "h": 7
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 19,
+ "h": 7
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 19,
+ "h": 7
+ },
+ "frame": {
+ "x": 19,
+ "y": 0,
+ "w": 19,
+ "h": 7
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 17,
+ "h": 7
+ },
+ "frame": {
+ "x": 38,
+ "y": 0,
+ "w": 17,
+ "h": 7
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 55,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 68,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 81,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 94,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 107,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 9,
+ "h": 7
+ },
+ "frame": {
+ "x": 120,
+ "y": 0,
+ "w": 9,
+ "h": 7
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:86fbd1b45d46271597a7d9de482aaa74:df702dd9d88db50369f1a096f82fd915:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/text_images/zh-CN/battle_ui/pbinfo_stat_zh-CN.png b/public/images/ui/text_images/zh-CN/battle_ui/pbinfo_stat_zh-CN.png
new file mode 100644
index 00000000000..9656c5f04b9
Binary files /dev/null and b/public/images/ui/text_images/zh-CN/battle_ui/pbinfo_stat_zh-CN.png differ
diff --git a/public/images/ui/text_images/zh-CN/party_ui/party_slot_overlay_hp_zh-CN.png b/public/images/ui/text_images/zh-CN/party_ui/party_slot_overlay_hp_zh-CN.png
new file mode 100644
index 00000000000..9be90b5c6bb
Binary files /dev/null and b/public/images/ui/text_images/zh-CN/party_ui/party_slot_overlay_hp_zh-CN.png differ
diff --git a/public/images/ui/text_images/zh-CN/party_ui/party_slot_overlay_lv_zh-CN.png b/public/images/ui/text_images/zh-CN/party_ui/party_slot_overlay_lv_zh-CN.png
new file mode 100644
index 00000000000..122d3f7151c
Binary files /dev/null and b/public/images/ui/text_images/zh-CN/party_ui/party_slot_overlay_lv_zh-CN.png differ
diff --git a/public/images/ui/text_images/zh-TW/battle_ui/overlay_exp_label_zh-TW.png b/public/images/ui/text_images/zh-TW/battle_ui/overlay_exp_label_zh-TW.png
new file mode 100644
index 00000000000..fde37213eff
Binary files /dev/null and b/public/images/ui/text_images/zh-TW/battle_ui/overlay_exp_label_zh-TW.png differ
diff --git a/public/images/ui/text_images/zh-TW/battle_ui/overlay_hp_label_boss_zh-TW.png b/public/images/ui/text_images/zh-TW/battle_ui/overlay_hp_label_boss_zh-TW.png
new file mode 100644
index 00000000000..0bcec679e05
Binary files /dev/null and b/public/images/ui/text_images/zh-TW/battle_ui/overlay_hp_label_boss_zh-TW.png differ
diff --git a/public/images/ui/text_images/zh-TW/battle_ui/overlay_hp_label_zh-TW.png b/public/images/ui/text_images/zh-TW/battle_ui/overlay_hp_label_zh-TW.png
new file mode 100644
index 00000000000..38a34761381
Binary files /dev/null and b/public/images/ui/text_images/zh-TW/battle_ui/overlay_hp_label_zh-TW.png differ
diff --git a/public/images/ui/text_images/zh-TW/battle_ui/overlay_lv_zh-TW.png b/public/images/ui/text_images/zh-TW/battle_ui/overlay_lv_zh-TW.png
new file mode 100644
index 00000000000..9ad4312d561
Binary files /dev/null and b/public/images/ui/text_images/zh-TW/battle_ui/overlay_lv_zh-TW.png differ
diff --git a/public/images/ui/text_images/zh-TW/battle_ui/pbinfo_stat_zh-TW.json b/public/images/ui/text_images/zh-TW/battle_ui/pbinfo_stat_zh-TW.json
new file mode 100644
index 00000000000..26c01d8bcc2
--- /dev/null
+++ b/public/images/ui/text_images/zh-TW/battle_ui/pbinfo_stat_zh-TW.json
@@ -0,0 +1,209 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat_zh-TW.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 120,
+ "h": 7
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 19,
+ "h": 7
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 19,
+ "h": 7
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 19,
+ "h": 7
+ },
+ "frame": {
+ "x": 19,
+ "y": 0,
+ "w": 19,
+ "h": 7
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 17,
+ "h": 7
+ },
+ "frame": {
+ "x": 38,
+ "y": 0,
+ "w": 17,
+ "h": 7
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 55,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 68,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 81,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 94,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 107,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "HP",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 9,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 9,
+ "h": 7
+ },
+ "frame": {
+ "x": 120,
+ "y": 0,
+ "w": 9,
+ "h": 7
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:86fbd1b45d46271597a7d9de482aaa74:df702dd9d88db50369f1a096f82fd915:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/text_images/zh-TW/battle_ui/pbinfo_stat_zh-TW.png b/public/images/ui/text_images/zh-TW/battle_ui/pbinfo_stat_zh-TW.png
new file mode 100644
index 00000000000..9656c5f04b9
Binary files /dev/null and b/public/images/ui/text_images/zh-TW/battle_ui/pbinfo_stat_zh-TW.png differ
diff --git a/public/images/ui/text_images/zh-TW/party_ui/party_slot_overlay_hp_zh-TW.png b/public/images/ui/text_images/zh-TW/party_ui/party_slot_overlay_hp_zh-TW.png
new file mode 100644
index 00000000000..9be90b5c6bb
Binary files /dev/null and b/public/images/ui/text_images/zh-TW/party_ui/party_slot_overlay_hp_zh-TW.png differ
diff --git a/public/images/ui/text_images/zh-TW/party_ui/party_slot_overlay_lv_zh-TW.png b/public/images/ui/text_images/zh-TW/party_ui/party_slot_overlay_lv_zh-TW.png
new file mode 100644
index 00000000000..122d3f7151c
Binary files /dev/null and b/public/images/ui/text_images/zh-TW/party_ui/party_slot_overlay_lv_zh-TW.png differ
diff --git a/public/locales b/public/locales
index 2686cd3edc0..090bfefaf7e 160000
--- a/public/locales
+++ b/public/locales
@@ -1 +1 @@
-Subproject commit 2686cd3edc0bd2c7a7f12cc54c00c109e51a48d7
+Subproject commit 090bfefaf7e9d4efcbca61fa78a9cdf5d701830b
diff --git a/scripts/create-test/create-test.js b/scripts/create-test/create-test.js
index 765993959d1..5e395783da7 100644
--- a/scripts/create-test/create-test.js
+++ b/scripts/create-test/create-test.js
@@ -156,7 +156,7 @@ async function runInteractive() {
console.log(chalk.green.bold(`✔ File created at: test/${localDir}/${fileName}.test.ts\n`));
console.groupEnd();
} catch (err) {
- console.error(chalk.red("✗ Error: ", err.message));
+ console.error(chalk.red("✗ Error: ", err));
}
}
diff --git a/scripts/decrypt-save.js b/scripts/decrypt-save.js
index e50f152f159..26b0a311378 100644
--- a/scripts/decrypt-save.js
+++ b/scripts/decrypt-save.js
@@ -1,7 +1,6 @@
// Usage: node decrypt-save.js [save-file]
-// biome-ignore lint/performance/noNamespaceImport: This is how you import fs from node
-import * as fs from "node:fs";
+import fs from "node:fs";
import crypto_js from "crypto-js";
const { AES, enc } = crypto_js;
@@ -60,6 +59,11 @@ function decryptSave(path) {
try {
fileData = fs.readFileSync(path, "utf8");
} catch (e) {
+ if (!(e instanceof Error)) {
+ console.error(`Unrecognized error: ${e}`);
+ process.exit(1);
+ }
+ // @ts-expect-error - e is usually a SystemError (all of which have codes)
switch (e.code) {
case "ENOENT":
console.error(`File not found: ${path}`);
@@ -104,6 +108,13 @@ function writeToFile(filePath, data) {
try {
fs.writeFileSync(filePath, data);
} catch (e) {
+ if (!(e instanceof Error)) {
+ console.error("Unknown error detected: ", e);
+ process.exitCode = 1;
+ return;
+ }
+
+ // @ts-expect-error - e is usually a SystemError (all of which have codes)
switch (e.code) {
case "EACCES":
console.error(`Could not open ${filePath}: Permission denied`);
@@ -114,7 +125,8 @@ function writeToFile(filePath, data) {
default:
console.error(`Error writing file: ${e.message}`);
}
- process.exit(1);
+ process.exitCode = 1;
+ return;
}
}
diff --git a/scripts/jsconfig.json b/scripts/jsconfig.json
new file mode 100644
index 00000000000..aed71f4f576
--- /dev/null
+++ b/scripts/jsconfig.json
@@ -0,0 +1,17 @@
+{
+ "include": ["**/*.js"],
+ "compilerOptions": {
+ "allowJs": true,
+ "checkJs": true,
+ "rootDir": ".",
+ "target": "esnext",
+ "module": "nodenext",
+ "moduleResolution": "nodenext",
+ "erasableSyntaxOnly": true,
+ "strict": true,
+ "noEmit": true,
+ // Forcibly disable `node_modules` recursion to prevent TSC from typechecking random JS files.
+ // This is disabled by default in `tsconfig.json`, but needs to be explicitly disabled from the default of `2`
+ "maxNodeModuleJsDepth": 0
+ }
+}
diff --git a/scripts/parse-egg-moves/egg-move-template.boilerplate.ts b/scripts/parse-egg-moves/egg-move-template.boilerplate.ts
new file mode 100644
index 00000000000..bfac05f4bde
--- /dev/null
+++ b/scripts/parse-egg-moves/egg-move-template.boilerplate.ts
@@ -0,0 +1,10 @@
+//! DO NOT EDIT THIS FILE - CREATED BY THE `eggMoves:parse` script automatically
+import { MoveId } from "#enums/move-id";
+import { SpeciesId } from "#enums/species-id";
+
+/**
+ * An object mapping all base form {@linkcode SpeciesId}s to an array of {@linkcode MoveId}s corresponding
+ * to their current egg moves.
+ * Generated by the `eggMoves:parse` script using a CSV sourced from the current Balance Team spreadsheet.
+ */
+export const speciesEggMoves = "{{table}}";
diff --git a/scripts/parse-egg-moves/help-message.js b/scripts/parse-egg-moves/help-message.js
new file mode 100644
index 00000000000..b498acdf23c
--- /dev/null
+++ b/scripts/parse-egg-moves/help-message.js
@@ -0,0 +1,17 @@
+import chalk from "chalk";
+
+/** Show help/usage text for the `eggMoves:parse` CLI. */
+export function showHelpText() {
+ console.log(`
+Usage: ${chalk.cyan("pnpm eggMoves:parse [options]")}
+If given no options, assumes ${chalk.blue("`--interactive`")}.
+If given only a file path, assumes ${chalk.blue("`--file`")}.
+
+${chalk.hex("#ffa500")("Options:")}
+ ${chalk.blue("-h, --help")} Show this help message.
+ ${chalk.blue("-f, --file[=PATH]")} Specify a path to a CSV file to read, or provide one from stdin.
+ ${chalk.blue("-t, --text[=TEXT]")}
+ ${chalk.blue("-c, --console[=TEXT]")} Specify CSV text to read, or provide it from stdin.
+ ${chalk.blue("-i, --interactive")} Run in interactive mode (default)
+`);
+}
diff --git a/scripts/parse-egg-moves/interactive.js b/scripts/parse-egg-moves/interactive.js
new file mode 100644
index 00000000000..68ee41e7900
--- /dev/null
+++ b/scripts/parse-egg-moves/interactive.js
@@ -0,0 +1,108 @@
+import fs from "fs";
+import chalk from "chalk";
+import inquirer from "inquirer";
+import { showHelpText } from "./help-message.js";
+
+/**
+ * @import { Option } from "./main.js"
+ */
+
+/**
+ * Prompt the user to interactively select an option (console/file) to retrieve the egg move CSV.
+ * @returns {Promise} The selected option with value
+ */
+export async function runInteractive() {
+ /** @type {"Console" | "File" | "Help" | "Exit"} */
+ const answer = await inquirer
+ .prompt([
+ {
+ type: "list",
+ name: "type",
+ message: "Select the method to obtain egg moves.",
+ choices: ["Console", "File", "Help", "Exit"],
+ },
+ ])
+ .then(a => a.type);
+
+ if (answer === "Exit") {
+ console.log("Exiting...");
+ process.exitCode = 1;
+ return { type: "Exit" };
+ }
+
+ if (answer === "Help") {
+ showHelpText();
+ return { type: "Exit" };
+ }
+
+ if (!["Console", "File"].includes(answer)) {
+ console.error(chalk.red("Please provide a valid type!"));
+ return await runInteractive();
+ }
+
+ return { type: answer, value: await promptForValue(answer) };
+}
+
+/**
+ * Prompt the user to give a value (either the direct CSV or the file path).
+ * @param {"Console" | "File"} type - The input method
+ * @returns {Promise} A Promise resolving with the CSV/file path.
+ */
+function promptForValue(type) {
+ switch (type) {
+ case "Console":
+ return doPromptConsole();
+ case "File":
+ return getFilePath();
+ }
+}
+
+/**
+ * Prompt the user to enter a file path from the console.
+ * @returns {Promise} The file path inputted by the user.
+ */
+async function getFilePath() {
+ return await inquirer
+ .prompt([
+ {
+ type: "input",
+ name: "path",
+ message: "Please enter the path to the egg move CSV file.",
+ validate: input => {
+ if (input.trim() === "") {
+ return "File path cannot be empty!";
+ }
+ if (!fs.existsSync(input)) {
+ return "File does not exist!";
+ }
+ return true;
+ },
+ },
+ ])
+ .then(answer => answer.path);
+}
+
+/**
+ * Prompt the user for CSV input from the console.
+ * @returns {Promise} The CSV input from the user.
+ */
+async function doPromptConsole() {
+ return await inquirer
+ .prompt([
+ {
+ type: "input",
+ name: "csv",
+ message: "Please enter the egg move CSV text.",
+ validate: input => {
+ if (input.trim() === "") {
+ return "CSV text cannot be empty!";
+ }
+ if (!input.match(/^[^,]+(,[^,]+){4}$/gm)) {
+ return "CSV text malformed - should contain 5 consecutive comma-separated values per line!";
+ }
+ return true;
+ },
+ },
+ ])
+ .then(answer => answer.csv);
+}
diff --git a/scripts/parse-egg-moves/main.js b/scripts/parse-egg-moves/main.js
new file mode 100644
index 00000000000..a009c81a041
--- /dev/null
+++ b/scripts/parse-egg-moves/main.js
@@ -0,0 +1,168 @@
+/*
+ * This script accepts a CSV value or file path as input, parses the egg moves,
+ * and writes the output to a TypeScript file.
+ * It can be run interactively or with command line arguments.
+ * Usage: `pnpm eggMoves:parse`
+ */
+
+import fs from "node:fs";
+import path from "node:path";
+import { fileURLToPath } from "node:url";
+import chalk from "chalk";
+import { showHelpText } from "./help-message.js";
+import { runInteractive } from "./interactive.js";
+import { parseEggMoves } from "./parse.js";
+
+const version = "1.0.0";
+
+// Get the directory name of the current module file
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = path.dirname(__filename);
+const projectRoot = path.join(__dirname, "..", "..");
+const templatePath = path.join(__dirname, "egg-move-template.ts");
+// TODO: Do we want this to be configurable?
+const eggMoveTargetPath = path.join(projectRoot, "src/data/balance/egg-moves.ts");
+
+/**
+ * @typedef {{type: "Console" | "File", value: string} | {type: "Exit"}}
+ * Option
+ * An option selected by the user.
+ */
+
+/**
+ * Runs the interactive eggMoves:parse CLI.
+ * @returns {Promise}
+ */
+async function start() {
+ console.log(chalk.yellow(`🥚 Egg Move Parser - v${version}`));
+
+ if (process.argv.length > 4) {
+ console.error(
+ chalk.redBright.bold(
+ `✗ Error: Too many arguments provided!\nArgs: ${chalk.hex("#7310fdff")(process.argv.slice(2).join(" "))}`,
+ ),
+ );
+ showHelpText();
+ process.exitCode = 1;
+ return;
+ }
+
+ let csv = "";
+ const inputType = await parseArguments();
+ if (process.exitCode) {
+ // If exit code is non-zero, return to allow it to propagate up the chain.
+ return;
+ }
+ switch (inputType.type) {
+ case "Console":
+ csv = inputType.value;
+ break;
+ case "File":
+ csv = await fs.promises.readFile(inputType.value, "utf-8");
+ break;
+ case "Exit":
+ // Help screen triggered; break out
+ return;
+ }
+
+ await writeToFile(parseEggMoves(csv));
+}
+
+/**
+ * Handle the arguments passed to the script and obtain the CSV input type.
+ * @returns {Promise<{type: "Console" | "File", value: string} | {type: "Exit"}>} The input method selected by the user
+ */
+async function parseArguments() {
+ const args = process.argv.slice(2); // first 2 args are node and script name (irrelevant)
+
+ /** @type {string | undefined} */
+ const arg = args[0].split("=")[0]; // Yoink everything up to the first "=" to get the raw command
+ switch (arg) {
+ case "-f":
+ case "--file":
+ return { type: "File", value: getArgValue() };
+ case "-t":
+ case "--text":
+ case "-c":
+ case "--console":
+ return { type: "Console", value: getArgValue() };
+ case "-h":
+ case "--help":
+ showHelpText();
+ process.exitCode = 0;
+ return { type: "Exit" };
+ case "--interactive":
+ case "-i":
+ case undefined:
+ return await runInteractive();
+ default:
+ // If no arguments are found, check if it's a file path
+ if (fs.existsSync(arg)) {
+ console.log(chalk.green(`Using file path from stdin: ${chalk.blue(arg)}`));
+ return { type: "File", value: arg };
+ }
+ badArgs();
+ return { type: "Exit" };
+ }
+}
+
+/**
+ * Get the value of the argument provided.
+ * @returns {string} The CSV or file path from the arguments
+ * @throws {Error} If arguments are malformed
+ */
+function getArgValue() {
+ // If the user provided a value as argument 2, take that as the argument.
+ // Otherwise, check the 1st argument to see if it contains an `=` and extract everything afterwards.
+ /** @type {string | undefined} */
+ let filePath = process.argv[3];
+ const equalsIndex = process.argv[2].indexOf("=");
+ if (equalsIndex > -1) {
+ // If arg 3 was aleady existing and someone used `=` notation to assign a property, throw an error.
+ filePath = filePath ? undefined : process.argv[2].slice(equalsIndex + 1);
+ }
+
+ if (!filePath?.trim()) {
+ badArgs();
+ return "";
+ }
+ // NB: It doesn't really matter that this can be `undefined` - we'll always break out by lieu of setting the exit code
+ return filePath;
+}
+
+/**
+ * Write out the parsed CSV to a file.
+ * @param {string} moves - The parsed CSV
+ * @returns {Promise}
+ */
+export async function writeToFile(moves) {
+ try {
+ // Read the template file, replacing the placeholder with the move table.
+ const content = fs.readFileSync(templatePath, "utf8").replace(`"{{table}}"`, moves);
+
+ if (fs.existsSync(eggMoveTargetPath)) {
+ console.warn(chalk.hex("#ffa500")("\nEgg moves file already exists, overwriting...\n"));
+ }
+
+ // Write the template content to the file
+ fs.writeFileSync(eggMoveTargetPath, content, "utf8");
+
+ console.log(chalk.green.bold(`\n✔ Egg Moves written to ${eggMoveTargetPath}`));
+ console.groupEnd();
+ } catch (err) {
+ console.error(chalk.red(`✗ Error while writing egg moves: ${err}`));
+ process.exitCode = 1;
+ }
+}
+
+/**
+ * Do logging for incorrect or malformed CLI arguments.
+ * @returns {void}
+ */
+function badArgs() {
+ chalk.red.bold(`✗ Error: Malformed arguments!\nArgs: ${chalk.hex("#7310fdff")(process.argv.slice(2).join(" "))}`);
+ showHelpText();
+ process.exitCode = 1;
+}
+
+start();
diff --git a/scripts/parse-egg-moves/parse.js b/scripts/parse-egg-moves/parse.js
new file mode 100644
index 00000000000..fe7511f8b08
--- /dev/null
+++ b/scripts/parse-egg-moves/parse.js
@@ -0,0 +1,79 @@
+import chalk from "chalk";
+
+/**
+ * A single line of the inputted CSV.
+ * @typedef {[speciesName: string, move1: string, move2: string, move3: string, move4: string]}
+ * CSVLine
+ */
+
+/**
+ * Regex to determine if a string follows the required CSV format.
+ */
+const csvRegex = /^((?:[^,]+?,){4}(?:\w|\s)+?,?\n?)+$/g;
+
+/**
+ * Given a CSV string, parse it and return a structured table ready to be inputted into code.
+ * @param {string} csv - The formatted CSV string.
+ * @returns {string} The fully formatted table.
+ */
+export function parseEggMoves(csv) {
+ console.log(chalk.grey("⚙️ Parsing egg moves..."));
+ if (!csvRegex.test(csv)) {
+ console.error(chalk.redBright("! Input was not proper CSV!"));
+ process.exitCode = 1;
+ return "";
+ }
+
+ let output = "{\n";
+
+ const lines = csv.split(/\n/g);
+
+ for (const line of lines) {
+ /**
+ * The individual CSV column for this species.
+ */
+ const cols =
+ /** @type {CSVLine} */
+ (line.split(",").slice(0, 5));
+ const speciesName = toUpperSnakeCase(cols[0]);
+
+ const eggMoves =
+ /** @type {string[]} */
+ ([]);
+
+ for (let m = 1; m < 5; m++) {
+ const moveName = cols[m].trim();
+ if (!moveName || moveName === "N/A") {
+ console.warn(`Species ${speciesName} missing ${m}th egg move!`);
+ eggMoves.push("MoveId.NONE");
+ continue;
+ }
+
+ // Remove (N) and (P) from the ends of move names before UPPER_SNAKE_CASE-ing them
+ const moveNameTitle = toUpperSnakeCase(moveName.replace(/ \([A-Z]\)$/, ""));
+ eggMoves.push("MoveId." + moveNameTitle);
+ }
+
+ if (eggMoves.every(move => move === "MoveId.NONE")) {
+ console.warn(`Species ${speciesName} could not be parsed, excluding from output...`);
+ output += ` // [SpeciesId.${speciesName}]: [ MoveId.NONE, MoveId.NONE, MoveId.NONE, MoveId.NONE ],\n`;
+ } else {
+ output += ` [SpeciesId.${speciesName}]: [ ${eggMoves.join(", ")} ],\n`;
+ }
+ }
+
+ // NB: We omit the semicolon as it is contained in the template string itself
+ return output + "} satisfies Partial>";
+}
+
+/**
+ * Helper method to convert a string into `UPPER_SNAKE_CASE`.
+ * @param {string} str - The string being converted
+ * @returns {string} The result of converting `str` into upper snake case.
+ */
+function toUpperSnakeCase(str) {
+ return str
+ .split(/[_ -]+/g)
+ .map(word => word.toUpperCase())
+ .join("_");
+}
diff --git a/scripts/scrape-trainer-names/fetch-names.js b/scripts/scrape-trainer-names/fetch-names.js
index 9e6bd0c4d2b..3f7d0393f5b 100644
--- a/scripts/scrape-trainer-names/fetch-names.js
+++ b/scripts/scrape-trainer-names/fetch-names.js
@@ -31,11 +31,11 @@ export function fetchNames(trainerListHeader, knownFemale = false) {
// Grab all the trainer name tables sorted by generation
const tables = elements.slice(startChildIndex, endChildIndex).filter(
- /** @type {(t: ChildNode) => t is Element} */
+ /** @type {(t: ChildNode) => t is HTMLTableElement} */
(
t =>
// Only grab expandable tables within the header block
- t.nodeName === "TABLE" && t["className"] === "expandable"
+ t.nodeName === "TABLE" && /** @type {HTMLTableElement} */ (t)["className"] === "expandable"
),
);
@@ -48,7 +48,7 @@ export function fetchNames(trainerListHeader, knownFemale = false) {
/**
* Parse the table in question.
- * @param {Element[]} tables - The array of Elements forming the current table
+ * @param {HTMLTableElement[]} tables - The array of Elements forming the current table
* @param {boolean} isFemale - Whether the trainer is known to be female or not
* @param {Set} trainerNames A Set containing the male trainer names
* @param {Set} femaleTrainerNames - A Set containing the female trainer names
@@ -56,7 +56,7 @@ export function fetchNames(trainerListHeader, knownFemale = false) {
function parseTable(tables, isFemale, trainerNames, femaleTrainerNames) {
for (const table of tables) {
// Grab all rows past the first header with exactly 9 children in them (Name, Battle, Winnings, 6 party slots)
- const trainerRows = [...table.querySelectorAll("tr:not(:first-child)")].filter(r => r.children.length === 9);
+ const trainerRows = [...table.rows].slice(1).filter(r => r.children.length === 9);
for (const row of trainerRows) {
const content = row.firstElementChild?.innerHTML;
// Skip empty elements & ones without anchors
diff --git a/scripts/scrape-trainer-names/main.js b/scripts/scrape-trainer-names/main.js
index 43989eebab9..4d0f12a0e63 100644
--- a/scripts/scrape-trainer-names/main.js
+++ b/scripts/scrape-trainer-names/main.js
@@ -129,7 +129,7 @@ async function scrapeTrainerNames(classes) {
reason = `Server produced error code of ${+errCode}`;
}
throw new Error(
- chalk.red.bold(`Failed to parse URL for ${chalk.hex("#7fff00")(`\"${trainerClass}\"`)}!\nReason: ${reason}`),
+ chalk.red.bold(`Failed to parse URL for ${chalk.hex("#7fff00")(`"${trainerClass}"`)}!\nReason: ${reason}`),
);
}
}),
@@ -191,9 +191,7 @@ async function doFetch(trainerClass, seenClasses) {
const [female, counterpartURLs] = checkGenderAndType(document);
const names = fetchNames(trainerListHeader, female);
if (names === INVALID_URL) {
- return Promise.reject(
- new Error(chalk.red.bold(`URL \"${classURL}\" did not correspond to a valid trainer class!`)),
- );
+ return Promise.reject(new Error(chalk.red.bold(`URL "${classURL}" did not correspond to a valid trainer class!`)));
}
// Recurse into all unseen gender counterparts' URLs, using the first male name we find
@@ -285,7 +283,7 @@ async function promptExisting(outFile) {
{
type: "confirm",
name: "continue",
- message: `File ${chalk.blue(outFile)} already exists!` + "\nDo you want to replace it?",
+ message: `File ${chalk.blue(outFile)} already exists!\nDo you want to replace it?`,
default: false,
},
])
diff --git a/src/@types/api/pokerogue-daily-api.ts b/src/@types/api/pokerogue-daily-api.ts
index 838af2a2a34..862ff2f51a3 100644
--- a/src/@types/api/pokerogue-daily-api.ts
+++ b/src/@types/api/pokerogue-daily-api.ts
@@ -1,4 +1,4 @@
-import type { ScoreboardCategory } from "#ui/daily-run-scoreboard";
+import type { ScoreboardCategory } from "#ui/containers/daily-run-scoreboard";
export interface GetDailyRankingsRequest {
category: ScoreboardCategory;
diff --git a/src/battle-scene.ts b/src/battle-scene.ts
index 9bb76b6fd23..d7681f5ff85 100644
--- a/src/battle-scene.ts
+++ b/src/battle-scene.ts
@@ -121,13 +121,13 @@ import { vouchers } from "#system/voucher";
import { trainerConfigs } from "#trainers/trainer-config";
import type { HeldModifierConfig } from "#types/held-modifier-config";
import type { Localizable } from "#types/locales";
-import { AbilityBar } from "#ui/ability-bar";
-import { ArenaFlyout } from "#ui/arena-flyout";
-import { CandyBar } from "#ui/candy-bar";
-import { CharSprite } from "#ui/char-sprite";
-import { PartyExpBar } from "#ui/party-exp-bar";
-import { PokeballTray } from "#ui/pokeball-tray";
-import { PokemonInfoContainer } from "#ui/pokemon-info-container";
+import { AbilityBar } from "#ui/containers/ability-bar";
+import { ArenaFlyout } from "#ui/containers/arena-flyout";
+import { CandyBar } from "#ui/containers/candy-bar";
+import { CharSprite } from "#ui/containers/char-sprite";
+import { PartyExpBar } from "#ui/containers/party-exp-bar";
+import { PokeballTray } from "#ui/containers/pokeball-tray";
+import { PokemonInfoContainer } from "#ui/containers/pokemon-info-container";
import { addTextObject, getTextColor } from "#ui/text";
import { UI } from "#ui/ui";
import { addUiThemeOverrides } from "#ui/ui-theme";
@@ -804,7 +804,7 @@ export class BattleScene extends SceneBase {
* @returns An array of {@linkcode Pokemon}, as described above.
*/
public getField(activeOnly = false): Pokemon[] {
- const ret = new Array(4).fill(null);
+ const ret: Pokemon[] = new Array(4).fill(null);
const playerField = this.getPlayerField();
const enemyField = this.getEnemyField();
ret.splice(0, playerField.length, ...playerField);
@@ -827,10 +827,10 @@ export class BattleScene extends SceneBase {
do {
targetingMovePhase = this.phaseManager.findPhase(
mp =>
- mp.is("MovePhase") &&
- mp.targets.length === 1 &&
- mp.targets[0] === removedPokemon.getBattlerIndex() &&
- mp.pokemon.isPlayer() !== allyPokemon.isPlayer(),
+ mp.is("MovePhase")
+ && mp.targets.length === 1
+ && mp.targets[0] === removedPokemon.getBattlerIndex()
+ && mp.pokemon.isPlayer() !== allyPokemon.isPlayer(),
) as MovePhase;
if (targetingMovePhase && targetingMovePhase.targets[0] !== allyPokemon.getBattlerIndex()) {
targetingMovePhase.targets[0] = allyPokemon.getBattlerIndex();
@@ -863,6 +863,8 @@ export class BattleScene extends SceneBase {
* @param pokemonId - The ID whose Pokemon will be retrieved.
* @returns The {@linkcode Pokemon} associated with the given id.
* Returns `null` if the ID is `undefined` or not present in either party.
+ * @todo Change the `null` to `undefined` and update callers' signatures -
+ * this is weird and causes a lot of random jank
*/
getPokemonById(pokemonId: number | undefined): Pokemon | null {
if (isNullOrUndefined(pokemonId)) {
@@ -1315,16 +1317,16 @@ export class BattleScene extends SceneBase {
}
} else {
if (
- !this.gameMode.hasTrainers ||
- Overrides.BATTLE_TYPE_OVERRIDE === BattleType.WILD ||
- (Overrides.DISABLE_STANDARD_TRAINERS_OVERRIDE && isNullOrUndefined(trainerData))
+ !this.gameMode.hasTrainers
+ || Overrides.BATTLE_TYPE_OVERRIDE === BattleType.WILD
+ || (Overrides.DISABLE_STANDARD_TRAINERS_OVERRIDE && isNullOrUndefined(trainerData))
) {
newBattleType = BattleType.WILD;
} else {
newBattleType =
- Overrides.BATTLE_TYPE_OVERRIDE ??
- battleType ??
- (this.gameMode.isWaveTrainer(newWaveIndex, this.arena) ? BattleType.TRAINER : BattleType.WILD);
+ Overrides.BATTLE_TYPE_OVERRIDE
+ ?? battleType
+ ?? (this.gameMode.isWaveTrainer(newWaveIndex, this.arena) ? BattleType.TRAINER : BattleType.WILD);
}
if (newBattleType === BattleType.TRAINER) {
@@ -1335,12 +1337,12 @@ export class BattleScene extends SceneBase {
doubleTrainer = true;
} else if (trainerConfigs[trainerType].hasDouble) {
doubleTrainer =
- Overrides.RANDOM_TRAINER_OVERRIDE?.alwaysDouble ||
- !randSeedInt(this.getDoubleBattleChance(newWaveIndex, playerField));
+ Overrides.RANDOM_TRAINER_OVERRIDE?.alwaysDouble
+ || !randSeedInt(this.getDoubleBattleChance(newWaveIndex, playerField));
// Add a check that special trainers can't be double except for tate and liza - they should use the normal double chance
if (
- trainerConfigs[trainerType].trainerTypeDouble &&
- ![TrainerType.TATE, TrainerType.LIZA].includes(trainerType)
+ trainerConfigs[trainerType].trainerTypeDouble
+ && ![TrainerType.TATE, TrainerType.LIZA].includes(trainerType)
) {
doubleTrainer = false;
}
@@ -1357,8 +1359,8 @@ export class BattleScene extends SceneBase {
// Check for mystery encounter
// Can only occur in place of a standard (non-boss) wild battle, waves 10-180
if (
- !Overrides.BATTLE_TYPE_OVERRIDE &&
- (this.isWaveMysteryEncounter(newBattleType, newWaveIndex) || newBattleType === BattleType.MYSTERY_ENCOUNTER)
+ !Overrides.BATTLE_TYPE_OVERRIDE
+ && (this.isWaveMysteryEncounter(newBattleType, newWaveIndex) || newBattleType === BattleType.MYSTERY_ENCOUNTER)
) {
newBattleType = BattleType.MYSTERY_ENCOUNTER;
// Reset to base spawn weight
@@ -1448,9 +1450,9 @@ export class BattleScene extends SceneBase {
const isNewBiome = this.isNewBiome(lastBattle);
/** Whether to reset and recall pokemon */
const resetArenaState =
- isNewBiome ||
- [BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(this.currentBattle.battleType) ||
- this.currentBattle.battleSpec === BattleSpec.FINAL_BOSS;
+ isNewBiome
+ || [BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(this.currentBattle.battleType)
+ || this.currentBattle.battleSpec === BattleSpec.FINAL_BOSS;
for (const enemyPokemon of this.getEnemyParty()) {
enemyPokemon.destroy();
@@ -1476,6 +1478,7 @@ export class BattleScene extends SceneBase {
pokemon.resetBattleAndWaveData();
pokemon.resetTera();
applyAbAttrs("PostBattleInitAbAttr", { pokemon });
+ // Terapagos resets tera on each fight
if (pokemon.hasSpecies(SpeciesId.TERAPAGOS)) {
this.arena.playerTerasUsed = 0;
}
@@ -1521,8 +1524,8 @@ export class BattleScene extends SceneBase {
const fieldScale =
Math.floor(
Math.pow(
- 1 /
- this.getField(true)
+ 1
+ / this.getField(true)
.map(p => p.getSpriteScale())
.reduce((highestScale: number, scale: number) => (highestScale = Math.max(scale, highestScale)), 0),
0.7,
@@ -1546,10 +1549,10 @@ export class BattleScene extends SceneBase {
this.tweens.add({
targets: this.field,
- scale: scale,
+ scale,
x: (defaultWidth - scaledWidth) / 2,
y: defaultHeight - scaledHeight,
- duration: !instant ? fixedInt(Math.abs(this.field.scale - scale) * 200) : 0,
+ duration: instant ? 0 : fixedInt(Math.abs(this.field.scale - scale) * 200),
ease: "Sine.easeInOut",
onComplete: () => resolve(),
});
@@ -1557,20 +1560,20 @@ export class BattleScene extends SceneBase {
}
getSpeciesFormIndex(species: PokemonSpecies, gender?: Gender, nature?: Nature, ignoreArena?: boolean): number {
- if (!species.forms?.length) {
+ if (species.forms?.length === 0) {
return 0;
}
const isEggPhase =
- this.phaseManager.getCurrentPhase().is("EggLapsePhase") ||
- this.phaseManager.getCurrentPhase().is("EggHatchPhase");
+ this.phaseManager.getCurrentPhase().is("EggLapsePhase")
+ || this.phaseManager.getCurrentPhase().is("EggHatchPhase");
if (
// Give trainers with specialty types an appropriately-typed form for Wormadam, Rotom, Arceus, Oricorio, Silvally, or Paldean Tauros.
- !isEggPhase &&
- this.currentBattle?.battleType === BattleType.TRAINER &&
- !isNullOrUndefined(this.currentBattle.trainer) &&
- this.currentBattle.trainer.config.hasSpecialtyType()
+ !isEggPhase
+ && this.currentBattle?.battleType === BattleType.TRAINER
+ && !isNullOrUndefined(this.currentBattle.trainer)
+ && this.currentBattle.trainer.config.hasSpecialtyType()
) {
if (species.speciesId === SpeciesId.WORMADAM) {
switch (this.currentBattle.trainer.config.specialtyType) {
@@ -1662,9 +1665,9 @@ export class BattleScene extends SceneBase {
return randSeedInt(8);
case SpeciesId.EEVEE:
if (
- this.currentBattle?.battleType === BattleType.TRAINER &&
- this.currentBattle?.waveIndex < 30 &&
- !isEggPhase
+ this.currentBattle?.battleType === BattleType.TRAINER
+ && this.currentBattle?.waveIndex < 30
+ && !isEggPhase
) {
return 0; // No Partner Eevee for Wave 12 Preschoolers
}
@@ -1774,9 +1777,9 @@ export class BattleScene extends SceneBase {
} else {
this.executeWithSeedOffset(() => {
isBoss =
- waveIndex % 10 === 0 ||
- (this.gameMode.hasRandomBosses &&
- randSeedInt(100) < Math.min(Math.max(Math.ceil((waveIndex - 250) / 50), 0) * 2, 30));
+ waveIndex % 10 === 0
+ || (this.gameMode.hasRandomBosses
+ && randSeedInt(100) < Math.min(Math.max(Math.ceil((waveIndex - 250) / 50), 0) * 2, 30));
}, waveIndex << 2);
}
if (!isBoss) {
@@ -1788,10 +1791,8 @@ export class BattleScene extends SceneBase {
if (level >= 100) {
ret++;
}
- if (species) {
- if (species.baseTotal >= 670) {
- ret++;
- }
+ if (species && species.baseTotal >= 670) {
+ ret++;
}
ret += Math.floor(waveIndex / 250);
@@ -1835,12 +1836,7 @@ export class BattleScene extends SceneBase {
this.rngCounter = 0;
}
- executeWithSeedOffset(
- // biome-ignore lint/complexity/noBannedTypes: Refactor to not use Function
- func: Function,
- offset: number,
- seedOverride?: string,
- ): void {
+ executeWithSeedOffset(func: () => void, offset: number, seedOverride?: string): void {
if (!func) {
return;
}
@@ -1897,8 +1893,8 @@ export class BattleScene extends SceneBase {
): Phaser.GameObjects.Sprite {
sprite.setPipeline(this.spritePipeline, {
tone: [0.0, 0.0, 0.0, 0.0],
- hasShadow: hasShadow,
- ignoreOverride: ignoreOverride,
+ hasShadow,
+ ignoreOverride,
teraColor: pokemon ? getTypeRgb(pokemon.getTeraType()) : undefined,
isTerastallized: pokemon ? pokemon.isTerastallized : false,
});
@@ -1919,7 +1915,7 @@ export class BattleScene extends SceneBase {
targets: this.fieldOverlay,
alpha: 0.5,
ease: "Sine.easeOut",
- duration: duration,
+ duration,
onComplete: () => resolve(),
});
});
@@ -1930,7 +1926,7 @@ export class BattleScene extends SceneBase {
this.tweens.add({
targets: this.fieldOverlay,
alpha: 0,
- duration: duration,
+ duration,
ease: "Cubic.easeIn",
onComplete: () => resolve(),
});
@@ -1964,7 +1960,7 @@ export class BattleScene extends SceneBase {
this.tweens.add({
targets: this.shopOverlay,
alpha: 0,
- duration: duration,
+ duration,
ease: "Cubic.easeIn",
onComplete: () => resolve(),
});
@@ -2041,7 +2037,7 @@ export class BattleScene extends SceneBase {
this.luckLabelText.setX(this.scaledCanvas.width - 2 - (this.luckText.displayWidth + 2));
this.tweens.add({
targets: labels,
- duration: duration,
+ duration,
alpha: 1,
onComplete: () => {
for (const label of labels) {
@@ -2058,7 +2054,7 @@ export class BattleScene extends SceneBase {
const labels = [this.luckLabelText, this.luckText];
this.tweens.add({
targets: labels,
- duration: duration,
+ duration,
alpha: 0,
onComplete: () => {
for (const label of labels) {
@@ -2072,9 +2068,9 @@ export class BattleScene extends SceneBase {
const enemyModifierCount = this.enemyModifiers.filter(m => m.isIconVisible()).length;
const biomeWaveTextHeight = this.biomeWaveText.getBottomLeft().y - this.biomeWaveText.getTopLeft().y;
this.biomeWaveText.setY(
- -this.scaledCanvas.height +
- (enemyModifierCount ? (enemyModifierCount <= 12 ? 15 : 24) : 0) +
- biomeWaveTextHeight / 2,
+ -this.scaledCanvas.height
+ + (enemyModifierCount ? (enemyModifierCount <= 12 ? 15 : 24) : 0)
+ + biomeWaveTextHeight / 2,
);
this.moneyText.setY(this.biomeWaveText.y + 10);
this.scoreText.setY(this.moneyText.y + 10);
@@ -2098,9 +2094,9 @@ export class BattleScene extends SceneBase {
addFaintedEnemyScore(enemy: EnemyPokemon): void {
let scoreIncrease =
- enemy.getSpeciesForm().getBaseExp() *
- (enemy.level / this.getMaxExpLevel()) *
- ((enemy.ivs.reduce((iv: number, total: number) => (total += iv), 0) / 93) * 0.2 + 0.8);
+ enemy.getSpeciesForm().getBaseExp()
+ * (enemy.level / this.getMaxExpLevel())
+ * ((enemy.ivs.reduce((iv: number, total: number) => (total += iv), 0) / 93) * 0.2 + 0.8);
this.findModifiers(m => m instanceof PokemonHeldItemModifier && m.pokemonId === enemy.id, false).map(
m => (scoreIncrease *= (m as PokemonHeldItemModifier).getScoreMultiplier()),
);
@@ -2621,8 +2617,8 @@ export class BattleScene extends SceneBase {
const waveIndex = this.currentBattle.waveIndex;
const waveSetIndex = Math.ceil(waveIndex / 10) - 1;
const moneyValue =
- Math.pow((waveSetIndex + 1 + (0.75 + (((waveIndex - 1) % 10) + 1) / 10)) * 100, 1 + 0.005 * waveSetIndex) *
- moneyMultiplier;
+ Math.pow((waveSetIndex + 1 + (0.75 + (((waveIndex - 1) % 10) + 1) / 10)) * 100, 1 + 0.005 * waveSetIndex)
+ * moneyMultiplier;
return Math.floor(moneyValue / 10) * 10;
}
@@ -2736,10 +2732,8 @@ export class BattleScene extends SceneBase {
}
if (!ignoreUpdate) {
this.updateModifiers(false, instant);
- resolve();
- } else {
- resolve();
}
+ resolve();
});
}
@@ -2936,8 +2930,8 @@ export class BattleScene extends SceneBase {
}
} else {
const isBoss =
- enemyPokemon.isBoss() ||
- (this.currentBattle.battleType === BattleType.TRAINER && !!this.currentBattle.trainer?.config.isBoss);
+ enemyPokemon.isBoss()
+ || (this.currentBattle.battleType === BattleType.TRAINER && !!this.currentBattle.trainer?.config.isBoss);
let upgradeChance = 32;
if (isBoss) {
upgradeChance /= 2;
@@ -3006,15 +3000,15 @@ export class BattleScene extends SceneBase {
for (let m = 0; m < modifiers.length; m++) {
const modifier = modifiers[m];
if (
- modifier instanceof PokemonHeldItemModifier &&
- !this.getPokemonById((modifier as PokemonHeldItemModifier).pokemonId)
+ modifier instanceof PokemonHeldItemModifier
+ && !this.getPokemonById((modifier as PokemonHeldItemModifier).pokemonId)
) {
modifiers.splice(m--, 1);
}
if (
- modifier instanceof PokemonHeldItemModifier &&
- !isNullOrUndefined(modifier.getSpecies()) &&
- !this.getPokemonById(modifier.pokemonId)?.hasSpecies(modifier.getSpecies()!)
+ modifier instanceof PokemonHeldItemModifier
+ && !isNullOrUndefined(modifier.getSpecies())
+ && !this.getPokemonById(modifier.pokemonId)?.hasSpecies(modifier.getSpecies()!)
) {
modifiers.splice(m--, 1);
}
@@ -3128,7 +3122,7 @@ export class BattleScene extends SceneBase {
this.executeWithSeedOffset(
() => {
const shuffleModifiers = mods => {
- if (mods.length < 1) {
+ if (mods.length === 0) {
return mods;
}
const rand = randSeedInt(mods.length);
@@ -3278,8 +3272,8 @@ export class BattleScene extends SceneBase {
validateAchv(achv: Achv, args?: unknown[]): boolean {
if (
- (!this.gameData.achvUnlocks.hasOwnProperty(achv.id) || Overrides.ACHIEVEMENTS_REUNLOCK_OVERRIDE) &&
- achv.validate(args)
+ (!this.gameData.achvUnlocks.hasOwnProperty(achv.id) || Overrides.ACHIEVEMENTS_REUNLOCK_OVERRIDE)
+ && achv.validate(args)
) {
this.gameData.achvUnlocks[achv.id] = Date.now();
this.ui.achvBar.showAchv(achv);
@@ -3417,8 +3411,8 @@ export class BattleScene extends SceneBase {
if (participantIds.size > 0) {
if (
- this.currentBattle.battleType === BattleType.TRAINER ||
- this.currentBattle.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE
+ this.currentBattle.battleType === BattleType.TRAINER
+ || this.currentBattle.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE
) {
expValue = Math.floor(expValue * 1.5);
} else if (this.currentBattle.isBattleMysteryEncounter() && this.currentBattle.mysteryEncounter) {
@@ -3514,12 +3508,12 @@ export class BattleScene extends SceneBase {
isMysteryEncounterValidForWave(battleType: BattleType, waveIndex: number): boolean {
const [lowestMysteryEncounterWave, highestMysteryEncounterWave] = this.gameMode.getMysteryEncounterLegalWaves();
return (
- this.gameMode.hasMysteryEncounters &&
- battleType === BattleType.WILD &&
- !this.gameMode.isBoss(waveIndex) &&
- waveIndex % 10 !== 1 &&
- waveIndex < highestMysteryEncounterWave &&
- waveIndex > lowestMysteryEncounterWave
+ this.gameMode.hasMysteryEncounters
+ && battleType === BattleType.WILD
+ && !this.gameMode.isBoss(waveIndex)
+ && waveIndex % 10 !== 1
+ && waveIndex < highestMysteryEncounterWave
+ && waveIndex > lowestMysteryEncounterWave
);
}
@@ -3541,18 +3535,17 @@ export class BattleScene extends SceneBase {
// Reduces occurrence of runs with total encounters significantly different from AVERAGE_ENCOUNTERS_PER_RUN_TARGET
// Favored rate changes can never exceed 50%. So if base rate is 15/256 and favored rate would add 200/256, result will be (15 + 128)/256
const expectedEncountersByFloor =
- (AVERAGE_ENCOUNTERS_PER_RUN_TARGET / (highestMysteryEncounterWave - lowestMysteryEncounterWave)) *
- (waveIndex - lowestMysteryEncounterWave);
+ (AVERAGE_ENCOUNTERS_PER_RUN_TARGET / (highestMysteryEncounterWave - lowestMysteryEncounterWave))
+ * (waveIndex - lowestMysteryEncounterWave);
const currentRunDiffFromAvg = expectedEncountersByFloor - encounteredEvents.length;
const favoredEncounterRate =
- sessionEncounterRate +
- Math.min(currentRunDiffFromAvg * ANTI_VARIANCE_WEIGHT_MODIFIER, MYSTERY_ENCOUNTER_SPAWN_MAX_WEIGHT / 2);
+ sessionEncounterRate
+ + Math.min(currentRunDiffFromAvg * ANTI_VARIANCE_WEIGHT_MODIFIER, MYSTERY_ENCOUNTER_SPAWN_MAX_WEIGHT / 2);
const successRate = Overrides.MYSTERY_ENCOUNTER_RATE_OVERRIDE ?? favoredEncounterRate;
// MEs can only spawn 3 or more waves after the previous ME, barring overrides
- const canSpawn =
- encounteredEvents.length === 0 || waveIndex - encounteredEvents[encounteredEvents.length - 1].waveIndex > 3;
+ const canSpawn = encounteredEvents.length === 0 || waveIndex - encounteredEvents.at(-1)!.waveIndex > 3;
if (canSpawn || Overrides.MYSTERY_ENCOUNTER_RATE_OVERRIDE !== null) {
let roll = MYSTERY_ENCOUNTER_SPAWN_MAX_WEIGHT;
@@ -3580,8 +3573,8 @@ export class BattleScene extends SceneBase {
// Loading override or session encounter
let encounter: MysteryEncounter | null;
if (
- !isNullOrUndefined(Overrides.MYSTERY_ENCOUNTER_OVERRIDE) &&
- allMysteryEncounters.hasOwnProperty(Overrides.MYSTERY_ENCOUNTER_OVERRIDE)
+ !isNullOrUndefined(Overrides.MYSTERY_ENCOUNTER_OVERRIDE)
+ && allMysteryEncounters.hasOwnProperty(Overrides.MYSTERY_ENCOUNTER_OVERRIDE)
) {
encounter = allMysteryEncounters[Overrides.MYSTERY_ENCOUNTER_OVERRIDE];
if (canBypass) {
@@ -3596,9 +3589,9 @@ export class BattleScene extends SceneBase {
// Check for queued encounters first
if (
- !encounter &&
- this.mysteryEncounterSaveData?.queuedEncounters &&
- this.mysteryEncounterSaveData.queuedEncounters.length > 0
+ !encounter
+ && this.mysteryEncounterSaveData?.queuedEncounters
+ && this.mysteryEncounterSaveData.queuedEncounters.length > 0
) {
let i = 0;
while (i < this.mysteryEncounterSaveData.queuedEncounters.length && !!encounter) {
@@ -3655,11 +3648,7 @@ export class BattleScene extends SceneBase {
}
let availableEncounters: MysteryEncounter[] = [];
- const previousEncounter =
- this.mysteryEncounterSaveData.encounteredEvents.length > 0
- ? this.mysteryEncounterSaveData.encounteredEvents[this.mysteryEncounterSaveData.encounteredEvents.length - 1]
- .type
- : null;
+ const previousEncounter = this.mysteryEncounterSaveData.encounteredEvents.at(-1)?.type ?? null; // TODO: This being `null` is a bit weird
const disabledEncounters = this.eventManager.getEventMysteryEncountersDisabled();
const biomeMysteryEncounters =
mysteryEncountersByBiome.get(this.arena.biomeType)?.filter(enc => !disabledEncounters.includes(enc)) ?? [];
@@ -3678,9 +3667,9 @@ export class BattleScene extends SceneBase {
}
const disallowedGameModes = encounterCandidate.disallowedGameModes;
if (
- disallowedGameModes &&
- disallowedGameModes.length > 0 &&
- disallowedGameModes.includes(this.gameMode.modeId)
+ disallowedGameModes
+ && disallowedGameModes.length > 0
+ && disallowedGameModes.includes(this.gameMode.modeId)
) {
return false;
}
@@ -3694,11 +3683,11 @@ export class BattleScene extends SceneBase {
return false;
}
return !(
- this.mysteryEncounterSaveData.encounteredEvents.length > 0 &&
- encounterCandidate.maxAllowedEncounters &&
- encounterCandidate.maxAllowedEncounters > 0 &&
- this.mysteryEncounterSaveData.encounteredEvents.filter(e => e.type === encounterType).length >=
- encounterCandidate.maxAllowedEncounters
+ this.mysteryEncounterSaveData.encounteredEvents.length > 0
+ && encounterCandidate.maxAllowedEncounters
+ && encounterCandidate.maxAllowedEncounters > 0
+ && this.mysteryEncounterSaveData.encounteredEvents.filter(e => e.type === encounterType).length
+ >= encounterCandidate.maxAllowedEncounters
);
})
.map(m => allMysteryEncounters[m]);
diff --git a/src/battle.ts b/src/battle.ts
index 7b6a58cbaca..1b789707806 100644
--- a/src/battle.ts
+++ b/src/battle.ts
@@ -237,11 +237,11 @@ export class Battle {
return null;
}
if (
- this.battleType === BattleType.TRAINER ||
- this.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE
+ this.battleType === BattleType.TRAINER
+ || this.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE
) {
- if (!this.started && this.trainer?.config.encounterBgm && this.trainer?.getEncounterMessages()?.length) {
- return `encounter_${this.trainer?.getEncounterBgm()}`;
+ if (!this.started && this.trainer?.config.encounterBgm && this.trainer.getEncounterMessages().length > 0) {
+ return `encounter_${this.trainer.getEncounterBgm()}`;
}
if (globalScene.musicPreference === MusicPreference.GENFIVE) {
return this.trainer?.getBattleBgm() ?? null;
diff --git a/src/configs/inputs/config-handler.ts b/src/configs/inputs/config-handler.ts
index 227c2b964b9..11af770f969 100644
--- a/src/configs/inputs/config-handler.ts
+++ b/src/configs/inputs/config-handler.ts
@@ -116,8 +116,8 @@ export function getIconForLatestInput(configs, source, devices, settingName) {
export function assign(config, settingNameTarget, keycode): boolean {
// first, we need to check if this keycode is already used on another settingName
if (
- !canIAssignThisKey(config, getKeyWithKeycode(config, keycode)) ||
- !canIOverrideThisSetting(config, settingNameTarget)
+ !canIAssignThisKey(config, getKeyWithKeycode(config, keycode))
+ || !canIOverrideThisSetting(config, settingNameTarget)
) {
return false;
}
diff --git a/src/constants/colors.ts b/src/constants/colors.ts
new file mode 100644
index 00000000000..717c5fa5f0d
--- /dev/null
+++ b/src/constants/colors.ts
@@ -0,0 +1,25 @@
+/**
+ * @module
+ * A big file storing colors used in logging.
+ * Minified by Terser during production builds, so has no overhead.
+ */
+
+// Colors used in prod
+/** Color used for "Start Phase " logs */
+export const PHASE_START_COLOR = "green" as const;
+/** Color used for logs in `MovePhase` */
+export const MOVE_COLOR = "orchid" as const;
+
+// Colors used for testing code
+export const NEW_TURN_COLOR = "#ffad00ff" as const;
+export const UI_MSG_COLOR = "#009dffff" as const;
+export const OVERRIDES_COLOR = "#b0b01eff" as const;
+export const SETTINGS_COLOR = "#008844ff" as const;
+
+// Colors used for Vitest-related test utils
+export const TEST_NAME_COLOR = "#008886ff" as const;
+export const VITEST_PINK_COLOR = "#c162de" as const;
+
+// Mock console log stuff
+export const TRACE_COLOR = "#b700ff" as const;
+export const DEBUG_COLOR = "#874600ff" as const;
diff --git a/src/data/abilities/ability.ts b/src/data/abilities/ability.ts
index ad84348fe0c..a083956a948 100644
--- a/src/data/abilities/ability.ts
+++ b/src/data/abilities/ability.ts
@@ -396,7 +396,23 @@ export abstract class AbAttr {
}
}
-export class BlockRecoilDamageAttr extends AbAttr {
+/**
+ * Abstract class for ability attributes that simply cancel an interaction
+ *
+ * @remarks
+ * Abilities that have simple cancel interactions (e.g. {@linkcode BlockRecoilDamageAttr}) can extend this class to reuse the `canApply` and `apply` logic
+ */
+abstract class CancelInteractionAbAttr extends AbAttr {
+ override canApply({ cancelled }: AbAttrParamsWithCancel): boolean {
+ return !cancelled.value;
+ }
+
+ override apply({ cancelled }: AbAttrParamsWithCancel): void {
+ cancelled.value = true;
+ }
+}
+
+export class BlockRecoilDamageAttr extends CancelInteractionAbAttr {
private declare readonly _: never;
constructor() {
super(false);
@@ -575,13 +591,10 @@ export abstract class PreDefendAbAttr extends AbAttr {
export class PreDefendFullHpEndureAbAttr extends PreDefendAbAttr {
override canApply({ pokemon, damage }: PreDefendModifyDamageAbAttrParams): boolean {
return (
- pokemon.isFullHp() &&
- // Checks if pokemon has wonder_guard (which forces 1hp)
- pokemon.getMaxHp() > 1 &&
- // Damage >= hp
- damage.value >= pokemon.hp &&
- // Cannot apply if the pokemon already has sturdy from some other source
- !pokemon.getTag(BattlerTagType.STURDY)
+ pokemon.isFullHp() // Checks if pokemon has wonder_guard (which forces 1hp)
+ && pokemon.getMaxHp() > 1 // Damage >= hp
+ && damage.value >= pokemon.hp // Cannot apply if the pokemon already has sturdy from some other source
+ && !pokemon.getTag(BattlerTagType.STURDY)
);
}
@@ -592,11 +605,7 @@ export class PreDefendFullHpEndureAbAttr extends PreDefendAbAttr {
}
}
-export class BlockItemTheftAbAttr extends AbAttr {
- override apply({ cancelled }: AbAttrParamsWithCancel): void {
- cancelled.value = true;
- }
-
+export class BlockItemTheftAbAttr extends CancelInteractionAbAttr {
getTriggerMessage({ pokemon }: AbAttrBaseParams, abilityName: string) {
return i18next.t("abilityTriggers:blockItemTheft", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
@@ -699,9 +708,9 @@ export class TypeImmunityAbAttr extends PreDefendAbAttr {
override canApply({ move, opponent: attacker, pokemon }: TypeMultiplierAbAttrParams): boolean {
return (
- ![MoveTarget.BOTH_SIDES, MoveTarget.ENEMY_SIDE, MoveTarget.USER_SIDE].includes(move.moveTarget) &&
- attacker !== pokemon &&
- attacker.getMoveType(move) === this.immuneType
+ ![MoveTarget.BOTH_SIDES, MoveTarget.ENEMY_SIDE, MoveTarget.USER_SIDE].includes(move.moveTarget)
+ && attacker !== pokemon
+ && attacker.getMoveType(move) === this.immuneType
);
}
@@ -727,7 +736,10 @@ export class AttackTypeImmunityAbAttr extends TypeImmunityAbAttr {
override canApply(params: TypeMultiplierAbAttrParams): boolean {
const { move } = params;
return (
- move.category !== MoveCategory.STATUS && !move.hasAttr("VariableMoveTypeChartAttr") && super.canApply(params)
+ move.category !== MoveCategory.STATUS
+ // TODO: make thousand arrows ignore levitate in a different manner
+ && !move.hasAttr("NeutralDamageAgainstFlyingTypeAttr")
+ && super.canApply(params)
);
}
}
@@ -839,10 +851,10 @@ export class FullHpResistTypeAbAttr extends PreDefendAbAttr {
*/
override canApply({ typeMultiplier, move, pokemon }: TypeMultiplierAbAttrParams): boolean {
return (
- typeMultiplier instanceof NumberHolder &&
- !move?.hasAttr("FixedDamageAttr") &&
- pokemon.isFullHp() &&
- typeMultiplier.value > 0.5
+ typeMultiplier instanceof NumberHolder
+ && !move?.hasAttr("FixedDamageAttr")
+ && pokemon.isFullHp()
+ && typeMultiplier.value > 0.5
);
}
@@ -867,11 +879,12 @@ export interface FieldPriorityMoveImmunityAbAttrParams extends AugmentMoveIntera
}
export class FieldPriorityMoveImmunityAbAttr extends PreDefendAbAttr {
- override canApply({ move, opponent: attacker }: FieldPriorityMoveImmunityAbAttrParams): boolean {
+ override canApply({ move, opponent: attacker, cancelled }: FieldPriorityMoveImmunityAbAttrParams): boolean {
return (
- !(move.moveTarget === MoveTarget.USER || move.moveTarget === MoveTarget.NEAR_ALLY) &&
- move.getPriority(attacker) > 0 &&
- !move.isMultiTarget()
+ !cancelled.value
+ && !(move.moveTarget === MoveTarget.USER || move.moveTarget === MoveTarget.NEAR_ALLY)
+ && move.getPriority(attacker) > 0
+ && !move.isMultiTarget()
);
}
@@ -895,10 +908,8 @@ export class MoveImmunityAbAttr extends PreDefendAbAttr {
this.immuneCondition = immuneCondition;
}
- override canApply({ pokemon, opponent: attacker, move }: MoveImmunityAbAttrParams): boolean {
- // TODO: Investigate whether this method should be checking against `cancelled`, specifically
- // if not checking this results in multiple flyouts showing when multiple abilities block the move.
- return this.immuneCondition(pokemon, attacker, move);
+ override canApply({ pokemon, opponent: attacker, move, cancelled }: MoveImmunityAbAttrParams): boolean {
+ return !cancelled.value && this.immuneCondition(pokemon, attacker, move);
}
override apply({ cancelled }: MoveImmunityAbAttrParams): void {
@@ -1079,9 +1090,13 @@ export class PostDefendHpGatedStatStageChangeAbAttr extends PostDefendAbAttr {
this.selfTarget = selfTarget;
}
- override canApply({ pokemon, opponent: attacker, move, damage }: PostMoveInteractionAbAttrParams): boolean {
+ override canApply({ pokemon, opponent: attacker, move }: PostMoveInteractionAbAttrParams): boolean {
const hpGateFlat: number = Math.ceil(pokemon.getMaxHp() * this.hpGate);
- return this.condition(pokemon, attacker, move) && pokemon.hp <= hpGateFlat && pokemon.hp + damage > hpGateFlat;
+ const lastAttackReceived = pokemon.turnData.attacksReceived.at(-1);
+ const damageReceived = lastAttackReceived?.damage ?? 0;
+ return (
+ this.condition(pokemon, attacker, move) && pokemon.hp <= hpGateFlat && pokemon.hp + damageReceived > hpGateFlat
+ );
}
override apply({ simulated, pokemon, opponent }: PostMoveInteractionAbAttrParams): void {
@@ -1111,8 +1126,8 @@ export class PostDefendApplyArenaTrapTagAbAttr extends PostDefendAbAttr {
override canApply({ pokemon, opponent: attacker, move }: PostMoveInteractionAbAttrParams): boolean {
const tag = globalScene.arena.getTag(this.arenaTagType) as EntryHazardTag;
return (
- this.condition(pokemon, attacker, move) &&
- (!globalScene.arena.getTag(this.arenaTagType) || tag.layers < tag.maxLayers)
+ this.condition(pokemon, attacker, move)
+ && (!globalScene.arena.getTag(this.arenaTagType) || tag.layers < tag.maxLayers)
);
}
@@ -1220,10 +1235,10 @@ export class PostDefendContactApplyStatusEffectAbAttr extends PostDefendAbAttr {
const effect =
this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randBattleSeedInt(this.effects.length)];
return (
- move.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon }) &&
- !attacker.status &&
- (this.chance === -1 || pokemon.randBattleSeedInt(100) < this.chance) &&
- attacker.canSetStatus(effect, true, false, pokemon)
+ move.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon })
+ && !attacker.status
+ && (this.chance === -1 || pokemon.randBattleSeedInt(100) < this.chance)
+ && attacker.canSetStatus(effect, true, false, pokemon)
);
}
@@ -1261,9 +1276,9 @@ export class PostDefendContactApplyTagChanceAbAttr extends PostDefendAbAttr {
override canApply({ move, pokemon, opponent }: PostMoveInteractionAbAttrParams): boolean {
return (
- move.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user: opponent, target: pokemon }) &&
- pokemon.randBattleSeedInt(100) < this.chance &&
- opponent.canAddTag(this.tagType)
+ move.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user: opponent, target: pokemon })
+ && pokemon.randBattleSeedInt(100) < this.chance
+ && opponent.canAddTag(this.tagType)
);
}
@@ -1318,9 +1333,9 @@ export class PostDefendContactDamageAbAttr extends PostDefendAbAttr {
override canApply({ simulated, move, opponent: attacker, pokemon }: PostMoveInteractionAbAttrParams): boolean {
return (
- !simulated &&
- move.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon }) &&
- !attacker.hasAbilityWithAttr("BlockNonDirectDamageAbAttr")
+ !simulated
+ && move.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon })
+ && !attacker.hasAbilityWithAttr("BlockNonDirectDamageAbAttr")
);
}
@@ -1354,8 +1369,8 @@ export class PostDefendPerishSongAbAttr extends PostDefendAbAttr {
override canApply({ move, opponent: attacker, pokemon }: PostMoveInteractionAbAttrParams): boolean {
return (
- move.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon }) &&
- !attacker.getTag(BattlerTagType.PERISH_SONG)
+ move.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon })
+ && !attacker.getTag(BattlerTagType.PERISH_SONG)
);
}
@@ -1369,7 +1384,7 @@ export class PostDefendPerishSongAbAttr extends PostDefendAbAttr {
override getTriggerMessage({ pokemon }: PostMoveInteractionAbAttrParams, abilityName: string): string {
return i18next.t("abilityTriggers:perishBody", {
pokemonName: getPokemonNameWithAffix(pokemon),
- abilityName: abilityName,
+ abilityName,
});
}
}
@@ -1387,9 +1402,9 @@ export class PostDefendWeatherChangeAbAttr extends PostDefendAbAttr {
override canApply({ pokemon, opponent: attacker, move }: PostMoveInteractionAbAttrParams): boolean {
return (
- !(this.condition && !this.condition(pokemon, attacker, move)) &&
- !globalScene.arena.weather?.isImmutable() &&
- globalScene.arena.canSetWeather(this.weatherType)
+ !(this.condition && !this.condition(pokemon, attacker, move))
+ && !globalScene.arena.weather?.isImmutable()
+ && globalScene.arena.canSetWeather(this.weatherType)
);
}
@@ -1403,8 +1418,8 @@ export class PostDefendWeatherChangeAbAttr extends PostDefendAbAttr {
export class PostDefendAbilitySwapAbAttr extends PostDefendAbAttr {
override canApply({ move, opponent: attacker, pokemon }: PostMoveInteractionAbAttrParams): boolean {
return (
- move.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon }) &&
- attacker.getAbility().isSwappable
+ move.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon })
+ && attacker.getAbility().isSwappable
);
}
@@ -1433,9 +1448,9 @@ export class PostDefendAbilityGiveAbAttr extends PostDefendAbAttr {
override canApply({ move, opponent: attacker, pokemon }: PostMoveInteractionAbAttrParams): boolean {
return (
- move.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon }) &&
- attacker.getAbility().isSuppressable &&
- !attacker.getAbility().hasAttr("PostDefendAbilityGiveAbAttr")
+ move.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon })
+ && attacker.getAbility().isSuppressable
+ && !attacker.getAbility().hasAttr("PostDefendAbilityGiveAbAttr")
);
}
@@ -1456,7 +1471,6 @@ export class PostDefendAbilityGiveAbAttr extends PostDefendAbAttr {
export class PostDefendMoveDisableAbAttr extends PostDefendAbAttr {
private chance: number;
private attacker: Pokemon;
- private move: Move;
constructor(chance: number) {
super();
@@ -1466,17 +1480,15 @@ export class PostDefendMoveDisableAbAttr extends PostDefendAbAttr {
override canApply({ move, opponent: attacker, pokemon }: PostMoveInteractionAbAttrParams): boolean {
return (
- isNullOrUndefined(attacker.getTag(BattlerTagType.DISABLED)) &&
- move.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon }) &&
- (this.chance === -1 || pokemon.randBattleSeedInt(100) < this.chance)
+ isNullOrUndefined(attacker.getTag(BattlerTagType.DISABLED))
+ && move.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon })
+ && (this.chance === -1 || pokemon.randBattleSeedInt(100) < this.chance)
);
}
- override apply({ simulated, opponent: attacker, move, pokemon }: PostMoveInteractionAbAttrParams): void {
- // TODO: investigate why this is setting properties
+ override apply({ simulated, opponent: attacker, pokemon }: PostMoveInteractionAbAttrParams): void {
if (!simulated) {
this.attacker = attacker;
- this.move = move;
this.attacker.addTag(BattlerTagType.DISABLED, 4, 0, pokemon.id);
}
}
@@ -1589,12 +1601,7 @@ export interface FieldPreventExplosiveMovesAbAttrParams extends AbAttrBaseParams
cancelled: BooleanHolder;
}
-export class FieldPreventExplosiveMovesAbAttr extends AbAttr {
- // TODO: investigate whether we need to check against `cancelled` in a `canApply` method
- override apply({ cancelled }: FieldPreventExplosiveMovesAbAttrParams): void {
- cancelled.value = true;
- }
-}
+export class FieldPreventExplosiveMovesAbAttr extends CancelInteractionAbAttr {}
export interface FieldMultiplyStatAbAttrParams extends AbAttrBaseParams {
/** The kind of stat that is being checked for modification */
@@ -1635,10 +1642,10 @@ export class FieldMultiplyStatAbAttr extends AbAttr {
canApply({ hasApplied, target, stat }: FieldMultiplyStatAbAttrParams): boolean {
return (
- this.canStack ||
- (!hasApplied.value &&
- this.stat === stat &&
- target.getAbilityAttrs("FieldMultiplyStatAbAttr").every(attr => attr.stat !== stat))
+ this.canStack
+ || (!hasApplied.value
+ && this.stat === stat
+ && target.getAbilityAttrs("FieldMultiplyStatAbAttr").every(attr => attr.stat !== stat))
);
}
@@ -1680,14 +1687,14 @@ export class MoveTypeChangeAbAttr extends PreAttackAbAttr {
*/
override canApply({ pokemon, opponent: target, move }: MoveTypeChangeAbAttrParams): boolean {
return (
- (!this.condition || this.condition(pokemon, target, move)) &&
- !noAbilityTypeOverrideMoves.has(move.id) &&
- !(
- pokemon.isTerastallized &&
- (move.id === MoveId.TERA_BLAST ||
- (move.id === MoveId.TERA_STARSTORM &&
- pokemon.getTeraType() === PokemonType.STELLAR &&
- pokemon.hasSpecies(SpeciesId.TERAPAGOS)))
+ (!this.condition || this.condition(pokemon, target, move))
+ && !noAbilityTypeOverrideMoves.has(move.id)
+ && !(
+ pokemon.isTerastallized
+ && (move.id === MoveId.TERA_BLAST
+ || (move.id === MoveId.TERA_STARSTORM
+ && pokemon.getTeraType() === PokemonType.STELLAR
+ && pokemon.hasSpecies(SpeciesId.TERAPAGOS)))
)
);
}
@@ -1710,14 +1717,13 @@ export class PokemonTypeChangeAbAttr extends PreAttackAbAttr {
override canApply({ move, pokemon }: AugmentMoveInteractionAbAttrParams): boolean {
if (
- pokemon.isTerastallized ||
- move.id === MoveId.STRUGGLE ||
- /*
+ pokemon.isTerastallized
+ || move.id === MoveId.STRUGGLE /*
* Skip moves that call other moves because these moves generate a following move that will trigger this ability attribute
* See: https://bulbapedia.bulbagarden.net/wiki/Category:Moves_that_call_other_moves
*/
- move.hasAttr("CallMoveAttr") ||
- move.hasAttr("NaturePowerAttr") // TODO: remove this line when nature power is made to extend from `CallMoveAttr`
+ || move.hasAttr("CallMoveAttr")
+ || move.hasAttr("NaturePowerAttr") // TODO: remove this line when nature power is made to extend from `CallMoveAttr`
) {
return false;
}
@@ -2145,13 +2151,13 @@ export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr {
// The PostAttackAbAttr should should only be invoked in cases where the move successfully connected,
// calling `super.canApply` already checks that the move was a damage move and not a status move.
if (
- super.canApply(params) &&
- !simulated &&
- hitResult < HitResult.NO_EFFECT &&
- (!this.stealCondition || this.stealCondition(pokemon, opponent, move))
+ super.canApply(params)
+ && !simulated
+ && hitResult < HitResult.NO_EFFECT
+ && (!this.stealCondition || this.stealCondition(pokemon, opponent, move))
) {
const heldItems = this.getTargetHeldItems(opponent).filter(i => i.isTransferable);
- if (heldItems.length) {
+ if (heldItems.length > 0) {
// Ensure that the stolen item in testing is the same as when the effect is applied
this.stolenItem = heldItems[pokemon.randBattleSeedInt(heldItems.length)];
if (globalScene.canTransferHeldItemModifier(this.stolenItem, pokemon)) {
@@ -2204,14 +2210,14 @@ export class PostAttackApplyStatusEffectAbAttr extends PostAttackAbAttr {
override canApply(params: PostMoveInteractionAbAttrParams): boolean {
const { simulated, pokemon, move, opponent } = params;
if (
- super.canApply(params) &&
- (simulated ||
- (!opponent.hasAbilityWithAttr("IgnoreMoveEffectsAbAttr") &&
- pokemon !== opponent &&
- (!this.contactRequired ||
- move.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user: pokemon, target: opponent })) &&
- pokemon.randBattleSeedInt(100) < this.chance &&
- !pokemon.status))
+ super.canApply(params)
+ && (simulated
+ || (!opponent.hasAbilityWithAttr("IgnoreMoveEffectsAbAttr")
+ && pokemon !== opponent
+ && (!this.contactRequired
+ || move.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user: pokemon, target: opponent }))
+ && pokemon.randBattleSeedInt(100) < this.chance
+ && !pokemon.status))
) {
const effect =
this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randBattleSeedInt(this.effects.length)];
@@ -2255,13 +2261,13 @@ export class PostAttackApplyBattlerTagAbAttr extends PostAttackAbAttr {
const { pokemon, move, opponent } = params;
/**Battler tags inflicted by abilities post attacking are also considered additional effects.*/
return (
- super.canApply(params) &&
- !opponent.hasAbilityWithAttr("IgnoreMoveEffectsAbAttr") &&
- pokemon !== opponent &&
- (!this.contactRequired ||
- move.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user: opponent, target: pokemon })) &&
- pokemon.randBattleSeedInt(100) < this.chance(opponent, pokemon, move) &&
- !pokemon.status
+ super.canApply(params)
+ && !opponent.hasAbilityWithAttr("IgnoreMoveEffectsAbAttr")
+ && pokemon !== opponent
+ && (!this.contactRequired
+ || move.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user: opponent, target: pokemon }))
+ && pokemon.randBattleSeedInt(100) < this.chance(opponent, pokemon, move)
+ && !pokemon.status
);
}
@@ -2287,7 +2293,7 @@ export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr {
override canApply({ simulated, pokemon, opponent, move, hitResult }: PostMoveInteractionAbAttrParams): boolean {
if (!simulated && hitResult < HitResult.NO_EFFECT && (!this.condition || this.condition(pokemon, opponent, move))) {
const heldItems = this.getTargetHeldItems(opponent).filter(i => i.isTransferable);
- if (heldItems.length) {
+ if (heldItems.length > 0) {
this.stolenItem = heldItems[pokemon.randBattleSeedInt(heldItems.length)];
if (globalScene.canTransferHeldItemModifier(this.stolenItem, pokemon)) {
return true;
@@ -2533,15 +2539,11 @@ export class IgnoreOpponentStatStagesAbAttr extends AbAttr {
* Abilities with this attribute prevent the user from being affected by Intimidate.
* @sealed
*/
-export class IntimidateImmunityAbAttr extends AbAttr {
+export class IntimidateImmunityAbAttr extends CancelInteractionAbAttr {
constructor() {
super(false);
}
- override apply({ cancelled }: AbAttrParamsWithCancel): void {
- cancelled.value = true;
- }
-
getTriggerMessage({ pokemon }: AbAttrParamsWithCancel, abilityName: string, ..._args: any[]): string {
return i18next.t("abilityTriggers:intimidateImmunity", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
@@ -2918,10 +2920,10 @@ export class PostSummonWeatherChangeAbAttr extends PostSummonAbAttr {
override canApply(_params: AbAttrBaseParams): boolean {
const weatherReplaceable =
- this.weatherType === WeatherType.HEAVY_RAIN ||
- this.weatherType === WeatherType.HARSH_SUN ||
- this.weatherType === WeatherType.STRONG_WINDS ||
- !globalScene.arena.weather?.isImmutable();
+ this.weatherType === WeatherType.HEAVY_RAIN
+ || this.weatherType === WeatherType.HARSH_SUN
+ || this.weatherType === WeatherType.STRONG_WINDS
+ || !globalScene.arena.weather?.isImmutable();
return weatherReplaceable && globalScene.arena.canSetWeather(this.weatherType);
}
@@ -2969,7 +2971,7 @@ export class PostSummonHealStatusAbAttr extends PostSummonRemoveEffectAbAttr {
public override canApply({ pokemon }: AbAttrBaseParams): boolean {
const status = pokemon.status?.effect;
- return !isNullOrUndefined(status) && (this.immuneEffects.length < 1 || this.immuneEffects.includes(status));
+ return !isNullOrUndefined(status) && (this.immuneEffects.length === 0 || this.immuneEffects.includes(status));
}
public override apply({ pokemon }: AbAttrBaseParams): void {
@@ -3026,7 +3028,7 @@ export class PostSummonCopyAbilityAbAttr extends PostSummonAbAttr {
const targets = pokemon
.getOpponents()
.filter(t => t.getAbility().isCopiable || t.getAbility().id === AbilityId.WONDER_GUARD);
- if (!targets.length) {
+ if (targets.length === 0) {
return false;
}
@@ -3157,7 +3159,7 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr {
// If none are eligible to copy, it will not activate.
const targets = user.getOpponents().filter(opp => user.canTransformInto(opp));
if (targets.length === 0) {
- return undefined;
+ return;
}
const mon = targets[user.randBattleSeedInt(targets.length)];
@@ -3250,10 +3252,10 @@ export class CommanderAbAttr extends AbAttr {
// TODO: Should this work with X + Dondozo fusions?
const ally = pokemon.getAlly();
return (
- globalScene.currentBattle?.double &&
- !isNullOrUndefined(ally) &&
- ally.species.speciesId === SpeciesId.DONDOZO &&
- !(ally.isFainted() || ally.getTag(BattlerTagType.COMMANDED))
+ globalScene.currentBattle?.double
+ && !isNullOrUndefined(ally)
+ && ally.species.speciesId === SpeciesId.DONDOZO
+ && !(ally.isFainted() || ally.getTag(BattlerTagType.COMMANDED))
);
}
@@ -3319,8 +3321,8 @@ export class PreSwitchOutClearWeatherAbAttr extends PreSwitchOutAbAttr {
switch (weatherType) {
case WeatherType.HARSH_SUN:
if (
- pokemon.hasAbility(AbilityId.DESOLATE_LAND) &&
- globalScene
+ pokemon.hasAbility(AbilityId.DESOLATE_LAND)
+ && globalScene
.getField(true)
.filter(p => p !== pokemon)
.filter(p => p.hasAbility(AbilityId.DESOLATE_LAND)).length === 0
@@ -3330,8 +3332,8 @@ export class PreSwitchOutClearWeatherAbAttr extends PreSwitchOutAbAttr {
break;
case WeatherType.HEAVY_RAIN:
if (
- pokemon.hasAbility(AbilityId.PRIMORDIAL_SEA) &&
- globalScene
+ pokemon.hasAbility(AbilityId.PRIMORDIAL_SEA)
+ && globalScene
.getField(true)
.filter(p => p !== pokemon)
.filter(p => p.hasAbility(AbilityId.PRIMORDIAL_SEA)).length === 0
@@ -3341,8 +3343,8 @@ export class PreSwitchOutClearWeatherAbAttr extends PreSwitchOutAbAttr {
break;
case WeatherType.STRONG_WINDS:
if (
- pokemon.hasAbility(AbilityId.DELTA_STREAM) &&
- globalScene
+ pokemon.hasAbility(AbilityId.DELTA_STREAM)
+ && globalScene
.getField(true)
.filter(p => p !== pokemon)
.filter(p => p.hasAbility(AbilityId.DELTA_STREAM)).length === 0
@@ -3427,8 +3429,8 @@ export class PreLeaveFieldClearWeatherAbAttr extends PreLeaveFieldAbAttr {
switch (weatherType) {
case WeatherType.HARSH_SUN:
if (
- pokemon.hasAbility(AbilityId.DESOLATE_LAND) &&
- globalScene
+ pokemon.hasAbility(AbilityId.DESOLATE_LAND)
+ && globalScene
.getField(true)
.filter(p => p !== pokemon)
.filter(p => p.hasAbility(AbilityId.DESOLATE_LAND)).length === 0
@@ -3438,8 +3440,8 @@ export class PreLeaveFieldClearWeatherAbAttr extends PreLeaveFieldAbAttr {
break;
case WeatherType.HEAVY_RAIN:
if (
- pokemon.hasAbility(AbilityId.PRIMORDIAL_SEA) &&
- globalScene
+ pokemon.hasAbility(AbilityId.PRIMORDIAL_SEA)
+ && globalScene
.getField(true)
.filter(p => p !== pokemon)
.filter(p => p.hasAbility(AbilityId.PRIMORDIAL_SEA)).length === 0
@@ -3449,8 +3451,8 @@ export class PreLeaveFieldClearWeatherAbAttr extends PreLeaveFieldAbAttr {
break;
case WeatherType.STRONG_WINDS:
if (
- pokemon.hasAbility(AbilityId.DELTA_STREAM) &&
- globalScene
+ pokemon.hasAbility(AbilityId.DELTA_STREAM)
+ && globalScene
.getField(true)
.filter(p => p !== pokemon)
.filter(p => p.hasAbility(AbilityId.DELTA_STREAM)).length === 0
@@ -3575,8 +3577,8 @@ export class ProtectStatAbAttr extends PreStatStageChangeAbAttr {
this.protectedStat = protectedStat;
}
- override canApply({ stat }: PreStatStageChangeAbAttrParams): boolean {
- return isNullOrUndefined(this.protectedStat) || stat === this.protectedStat;
+ override canApply({ stat, cancelled }: PreStatStageChangeAbAttrParams): boolean {
+ return !cancelled.value && (isNullOrUndefined(this.protectedStat) || stat === this.protectedStat);
}
/**
@@ -3667,8 +3669,11 @@ export class PreSetStatusEffectImmunityAbAttr extends PreSetStatusAbAttr {
this.immuneEffects = immuneEffects;
}
- override canApply({ effect }: PreSetStatusAbAttrParams): boolean {
- return (this.immuneEffects.length === 0 && effect !== StatusEffect.FAINT) || this.immuneEffects.includes(effect);
+ override canApply({ effect, cancelled }: PreSetStatusAbAttrParams): boolean {
+ return (
+ !cancelled.value
+ && ((this.immuneEffects.length === 0 && effect !== StatusEffect.FAINT) || this.immuneEffects.includes(effect))
+ );
}
/**
@@ -3679,7 +3684,7 @@ export class PreSetStatusEffectImmunityAbAttr extends PreSetStatusAbAttr {
}
override getTriggerMessage({ pokemon, effect }: PreSetStatusAbAttrParams, abilityName: string): string {
- return this.immuneEffects.length
+ return this.immuneEffects.length > 0
? i18next.t("abilityTriggers:statusEffectImmunityWithName", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
abilityName,
@@ -3718,7 +3723,8 @@ export interface UserFieldStatusEffectImmunityAbAttrParams extends AbAttrBasePar
/**
* Provides immunity to status effects to the user's field.
*/
-export class UserFieldStatusEffectImmunityAbAttr extends AbAttr {
+export class UserFieldStatusEffectImmunityAbAttr extends CancelInteractionAbAttr {
+ private declare readonly _: never;
protected immuneEffects: StatusEffect[];
/**
@@ -3733,17 +3739,13 @@ export class UserFieldStatusEffectImmunityAbAttr extends AbAttr {
override canApply({ effect, cancelled }: UserFieldStatusEffectImmunityAbAttrParams): boolean {
return (
- (!cancelled.value && this.immuneEffects.length === 0 && effect !== StatusEffect.FAINT) ||
- this.immuneEffects.includes(effect)
+ (!cancelled.value && this.immuneEffects.length === 0 && effect !== StatusEffect.FAINT)
+ || this.immuneEffects.includes(effect)
);
}
- /**
- * Set the `cancelled` value to true, indicating that the status effect is prevented.
- */
- override apply({ cancelled }: UserFieldStatusEffectImmunityAbAttrParams): void {
- cancelled.value = true;
- }
+ // declare here to allow typescript to allow us to override `canApply` method without adjusting params
+ declare apply: (params: UserFieldStatusEffectImmunityAbAttrParams) => void;
}
/**
@@ -3774,14 +3776,7 @@ export class ConditionalUserFieldStatusEffectImmunityAbAttr extends UserFieldSta
* @returns Whether the ability can be applied to cancel the status effect.
*/
override canApply(params: UserFieldStatusEffectImmunityAbAttrParams): boolean {
- return this.condition(params.target, params.source) && super.canApply(params);
- }
-
- /**
- * Set the `cancelled` value to true, indicating that the status effect is prevented.
- */
- override apply({ cancelled }: UserFieldStatusEffectImmunityAbAttrParams): void {
- cancelled.value = true;
+ return !params.cancelled.value && this.condition(params.target, params.source) && super.canApply(params);
}
}
@@ -3820,9 +3815,9 @@ export class ConditionalUserFieldProtectStatAbAttr extends PreStatStageChangeAbA
return false;
}
return (
- !cancelled.value &&
- (isNullOrUndefined(this.protectedStat) || stat === this.protectedStat) &&
- this.condition(target)
+ !cancelled.value
+ && (isNullOrUndefined(this.protectedStat) || stat === this.protectedStat)
+ && this.condition(target)
);
}
@@ -4017,20 +4012,16 @@ export class ConditionalCritAbAttr extends AbAttr {
}
}
-export class BlockNonDirectDamageAbAttr extends AbAttr {
+export class BlockNonDirectDamageAbAttr extends CancelInteractionAbAttr {
constructor() {
super(false);
}
-
- override apply({ cancelled }: AbAttrParamsWithCancel): void {
- cancelled.value = true;
- }
}
/**
* This attribute will block any status damage that you put in the parameter.
*/
-export class BlockStatusDamageAbAttr extends AbAttr {
+export class BlockStatusDamageAbAttr extends CancelInteractionAbAttr {
private effects: StatusEffect[];
/**
@@ -4042,20 +4033,12 @@ export class BlockStatusDamageAbAttr extends AbAttr {
this.effects = effects;
}
- override canApply({ pokemon }: AbAttrParamsWithCancel): boolean {
- return !!pokemon.status?.effect && this.effects.includes(pokemon.status.effect);
- }
-
- override apply({ cancelled }: AbAttrParamsWithCancel): void {
- cancelled.value = true;
+ override canApply({ pokemon, cancelled }: AbAttrParamsWithCancel): boolean {
+ return !cancelled.value && !!pokemon.status?.effect && this.effects.includes(pokemon.status.effect);
}
}
-export class BlockOneHitKOAbAttr extends AbAttr {
- override apply({ cancelled }: AbAttrParamsWithCancel): void {
- cancelled.value = true;
- }
-}
+export class BlockOneHitKOAbAttr extends CancelInteractionAbAttr {}
export interface ChangeMovePriorityAbAttrParams extends AbAttrBaseParams {
/** The move being used */
@@ -4129,12 +4112,12 @@ export class BlockWeatherDamageAttr extends PreWeatherDamageAbAttr {
this.weatherTypes = weatherTypes;
}
- override canApply({ weather }: PreWeatherEffectAbAttrParams): boolean {
- if (!weather) {
+ override canApply({ weather, cancelled }: PreWeatherEffectAbAttrParams): boolean {
+ if (!weather || cancelled.value) {
return false;
}
const weatherType = weather.weatherType;
- return !this.weatherTypes.length || this.weatherTypes.includes(weatherType);
+ return this.weatherTypes.length === 0 || this.weatherTypes.includes(weatherType);
}
override apply({ cancelled }: PreWeatherEffectAbAttrParams): void {
@@ -4151,8 +4134,8 @@ export class SuppressWeatherEffectAbAttr extends PreWeatherEffectAbAttr {
this.affectsImmutable = affectsImmutable;
}
- override canApply({ weather }: PreWeatherEffectAbAttrParams): boolean {
- if (!weather) {
+ override canApply({ weather, cancelled }: PreWeatherEffectAbAttrParams): boolean {
+ if (!weather || cancelled.value) {
return false;
}
return this.affectsImmutable || weather.isImmutable();
@@ -4270,9 +4253,9 @@ export class ForewarnAbAttr extends PostSummonAbAttr {
} else if (move?.getMove().hasAttr("OneHitKOAttr")) {
movePower = 150;
} else if (
- move?.getMove().id === MoveId.COUNTER ||
- move?.getMove().id === MoveId.MIRROR_COAT ||
- move?.getMove().id === MoveId.METAL_BURST
+ move?.getMove().id === MoveId.COUNTER
+ || move?.getMove().id === MoveId.MIRROR_COAT
+ || move?.getMove().id === MoveId.METAL_BURST
) {
movePower = 120;
} else if (move?.getMove().power === -1) {
@@ -4648,7 +4631,7 @@ export class PostTurnRestoreBerryAbAttr extends PostTurnAbAttr {
this.berriesUnderCap = pokemon.battleData.berriesEaten.filter(bt => !cappedBerries.has(bt));
- if (!this.berriesUnderCap.length) {
+ if (this.berriesUnderCap.length === 0) {
return false;
}
@@ -4714,7 +4697,7 @@ export class CudChewConsumeBerryAbAttr extends AbAttr {
* @returns `true` if the pokemon ate anything last turn
*/
override canApply({ pokemon }: AbAttrBaseParams): boolean {
- return !!pokemon.summonData.berriesEatenLast.length;
+ return pokemon.summonData.berriesEatenLast.length > 0;
}
override apply({ pokemon }: AbAttrBaseParams): void {
@@ -4863,9 +4846,9 @@ export class PostTurnHurtIfSleepingAbAttr extends PostTurnAbAttr {
.getOpponents()
.some(
opp =>
- (opp.status?.effect === StatusEffect.SLEEP || opp.hasAbility(AbilityId.COMATOSE)) &&
- !opp.hasAbilityWithAttr("BlockNonDirectDamageAbAttr") &&
- !opp.switchOutStatus,
+ (opp.status?.effect === StatusEffect.SLEEP || opp.hasAbility(AbilityId.COMATOSE))
+ && !opp.hasAbilityWithAttr("BlockNonDirectDamageAbAttr")
+ && !opp.switchOutStatus,
);
}
@@ -4999,8 +4982,8 @@ export class PostDancingMoveAbAttr extends PostMoveUsedAbAttr {
];
// The move to replicate cannot come from the Dancer
return (
- source.getBattlerIndex() !== pokemon.getBattlerIndex() &&
- !pokemon.summonData.tags.some(tag => forbiddenTags.includes(tag.tagType))
+ source.getBattlerIndex() !== pokemon.getBattlerIndex()
+ && !pokemon.summonData.tags.some(tag => forbiddenTags.includes(tag.tagType))
);
}
@@ -5121,15 +5104,11 @@ export class StatStageChangeCopyAbAttr extends AbAttr {
}
}
-export class BypassBurnDamageReductionAbAttr extends AbAttr {
+export class BypassBurnDamageReductionAbAttr extends CancelInteractionAbAttr {
private declare readonly _: never;
constructor() {
super(false);
}
-
- override apply({ cancelled }: AbAttrParamsWithCancel): void {
- cancelled.value = true;
- }
}
export interface ReduceBurnDamageAbAttrParams extends AbAttrBaseParams {
@@ -5169,14 +5148,7 @@ export class DoubleBerryEffectAbAttr extends AbAttr {
* Attribute to prevent opposing berry use while on the field.
* Used by {@linkcode AbilityId.UNNERVE}, {@linkcode AbilityId.AS_ONE_GLASTRIER} and {@linkcode AbilityId.AS_ONE_SPECTRIER}
*/
-export class PreventBerryUseAbAttr extends AbAttr {
- /**
- * Prevent use of opposing berries.
- */
- override apply({ cancelled }: AbAttrParamsWithCancel): void {
- cancelled.value = true;
- }
-}
+export class PreventBerryUseAbAttr extends CancelInteractionAbAttr {}
/**
* A Pokemon with this ability heals by a percentage of their maximum hp after eating a berry
@@ -5260,12 +5232,12 @@ export interface CheckTrappedAbAttrParams extends AbAttrBaseParams {
export class ArenaTrapAbAttr extends CheckTrappedAbAttr {
override canApply({ pokemon, opponent }: CheckTrappedAbAttrParams): boolean {
return (
- this.arenaTrapCondition(pokemon, opponent) &&
- !(
- opponent.getTypes(true).includes(PokemonType.GHOST) ||
- (opponent.getTypes(true).includes(PokemonType.STELLAR) && opponent.getTypes().includes(PokemonType.GHOST))
- ) &&
- !opponent.hasAbility(AbilityId.RUN_AWAY)
+ this.arenaTrapCondition(pokemon, opponent)
+ && !(
+ opponent.getTypes(true).includes(PokemonType.GHOST)
+ || (opponent.getTypes(true).includes(PokemonType.STELLAR) && opponent.getTypes().includes(PokemonType.GHOST))
+ )
+ && !opponent.hasAbility(AbilityId.RUN_AWAY)
);
}
@@ -5326,7 +5298,7 @@ export class PostBattleLootAbAttr extends PostBattleAbAttr {
override canApply({ simulated, victory, pokemon }: PostBattleAbAttrParams): boolean {
const postBattleLoot = globalScene.currentBattle.postBattleLoot;
- if (!simulated && postBattleLoot.length && victory) {
+ if (!simulated && postBattleLoot.length > 0 && victory) {
this.randItem = randSeedItem(postBattleLoot);
return globalScene.canTransferHeldItemModifier(this.randItem, pokemon, 1);
}
@@ -5425,9 +5397,9 @@ export class PostFaintContactDamageAbAttr extends PostFaintAbAttr {
override canApply({ pokemon, attacker, move, simulated }: PostFaintAbAttrParams): boolean {
if (
- move === undefined ||
- attacker === undefined ||
- !move.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon })
+ move === undefined
+ || attacker === undefined
+ || !move.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon })
) {
return false;
}
@@ -5634,11 +5606,7 @@ export class IncreasePpAbAttr extends AbAttr {
}
/** @sealed */
-export class ForceSwitchOutImmunityAbAttr extends AbAttr {
- override apply({ cancelled }: AbAttrParamsWithCancel): void {
- cancelled.value = true;
- }
-}
+export class ForceSwitchOutImmunityAbAttr extends CancelInteractionAbAttr {}
export interface ReduceBerryUseThresholdAbAttrParams extends AbAttrBaseParams {
/** Holds the hp ratio for the berry to proc, which may be modified by ability application */
@@ -5717,8 +5685,8 @@ export class MoveAbilityBypassAbAttr extends AbAttr {
this.moveIgnoreFunc = moveIgnoreFunc || ((_pokemon, _move) => true);
}
- override canApply({ pokemon, move }: MoveAbilityBypassAbAttrParams): boolean {
- return this.moveIgnoreFunc(pokemon, move);
+ override canApply({ pokemon, move, cancelled }: MoveAbilityBypassAbAttrParams): boolean {
+ return !cancelled.value && this.moveIgnoreFunc(pokemon, move);
}
override apply({ cancelled }: MoveAbilityBypassAbAttrParams): void {
@@ -5812,8 +5780,8 @@ export class IgnoreTypeImmunityAbAttr extends AbAttr {
this.allowedMoveTypes = allowedMoveTypes;
}
- override canApply({ moveType, defenderType }: IgnoreTypeImmunityAbAttrParams): boolean {
- return this.defenderType === defenderType && this.allowedMoveTypes.includes(moveType);
+ override canApply({ moveType, defenderType, cancelled }: IgnoreTypeImmunityAbAttrParams): boolean {
+ return !cancelled.value && this.defenderType === defenderType && this.allowedMoveTypes.includes(moveType);
}
override apply({ cancelled }: IgnoreTypeImmunityAbAttrParams): void {
@@ -6002,9 +5970,9 @@ export class IllusionPreSummonAbAttr extends PreSummonAbAttr {
// If the last conscious Pokémon in the party is a Terastallized Ogerpon or Terapagos, Illusion will not activate.
// Illusion will also not activate if the Pokémon with Illusion is Terastallized and the last Pokémon in the party is Ogerpon or Terapagos.
if (
- lastPokemon === pokemon ||
- ((speciesId === SpeciesId.OGERPON || speciesId === SpeciesId.TERAPAGOS) &&
- (lastPokemon.isTerastallized || pokemon.isTerastallized))
+ lastPokemon === pokemon
+ || ((speciesId === SpeciesId.OGERPON || speciesId === SpeciesId.TERAPAGOS)
+ && (lastPokemon.isTerastallized || pokemon.isTerastallized))
) {
return false;
}
@@ -6158,7 +6126,7 @@ export class TerrainEventTypeChangeAbAttr extends PostSummonAbAttr {
override apply({ pokemon }: AbAttrBaseParams): void {
const currentTerrain = globalScene.arena.getTerrainType();
const typeChange: PokemonType[] = this.determineTypeChange(pokemon, currentTerrain);
- if (typeChange.length !== 0) {
+ if (typeChange.length > 0) {
if (pokemon.summonData.addedType && typeChange.includes(pokemon.summonData.addedType)) {
pokemon.summonData.addedType = null;
}
@@ -6228,7 +6196,7 @@ class ForceSwitchOutHelper {
* - If the Pokémon is still alive (hp > 0), and if so, it leaves the field and a new SwitchPhase is initiated.
*/
if (switchOutTarget.isPlayer()) {
- if (globalScene.getPlayerParty().filter(p => p.isAllowedInBattle() && !p.isOnField()).length < 1) {
+ if (globalScene.getPlayerParty().filter(p => p.isAllowedInBattle() && !p.isOnField()).length === 0) {
return false;
}
@@ -6249,7 +6217,7 @@ class ForceSwitchOutHelper {
* If yes, the Pokémon leaves the field and a new SwitchSummonPhase is initiated.
*/
} else if (globalScene.currentBattle.battleType !== BattleType.WILD) {
- if (globalScene.getEnemyParty().filter(p => p.isAllowedInBattle() && !p.isOnField()).length < 1) {
+ if (globalScene.getEnemyParty().filter(p => p.isAllowedInBattle() && !p.isOnField()).length === 0) {
return false;
}
if (switchOutTarget.hp > 0) {
@@ -6326,28 +6294,31 @@ class ForceSwitchOutHelper {
return !blockedByAbility.value;
}
- if (!player && globalScene.currentBattle.battleType === BattleType.WILD) {
- if (!globalScene.currentBattle.waveIndex && globalScene.currentBattle.waveIndex % 10 === 0) {
- return false;
- }
+ if (
+ !player
+ && globalScene.currentBattle.battleType === BattleType.WILD
+ && !globalScene.currentBattle.waveIndex
+ && globalScene.currentBattle.waveIndex % 10 === 0
+ ) {
+ return false;
}
if (
- !player &&
- globalScene.currentBattle.isBattleMysteryEncounter() &&
- !globalScene.currentBattle.mysteryEncounter?.fleeAllowed
+ !player
+ && globalScene.currentBattle.isBattleMysteryEncounter()
+ && !globalScene.currentBattle.mysteryEncounter?.fleeAllowed
) {
return false;
}
const party = player ? globalScene.getPlayerParty() : globalScene.getEnemyParty();
return (
- (!player && globalScene.currentBattle.battleType === BattleType.WILD) ||
- party.filter(
+ (!player && globalScene.currentBattle.battleType === BattleType.WILD)
+ || party.filter(
p =>
- p.isAllowedInBattle() &&
- !p.isOnField() &&
- (player || (p as EnemyPokemon).trainerSlot === (switchOutTarget as EnemyPokemon).trainerSlot),
+ p.isAllowedInBattle()
+ && !p.isOnField()
+ && (player || (p as EnemyPokemon).trainerSlot === (switchOutTarget as EnemyPokemon).trainerSlot),
).length > 0
);
}
@@ -6423,26 +6394,22 @@ export class PostDamageForceSwitchAbAttr extends PostDamageAbAttr {
// TODO: Refactor to use more early returns
public override canApply({ pokemon, source, damage }: PostDamageAbAttrParams): boolean {
- const moveHistory = pokemon.getMoveHistory();
// Will not activate when the Pokémon's HP is lowered by cutting its own HP
const forbiddenAttackingMoves = [MoveId.BELLY_DRUM, MoveId.SUBSTITUTE, MoveId.CURSE, MoveId.PAIN_SPLIT];
- if (moveHistory.length > 0) {
- const lastMoveUsed = moveHistory[moveHistory.length - 1];
- if (forbiddenAttackingMoves.includes(lastMoveUsed.move)) {
- return false;
- }
+ const lastMoveUsed = pokemon.getLastXMoves()[0];
+ if (forbiddenAttackingMoves.includes(lastMoveUsed?.move)) {
+ return false;
}
// Dragon Tail and Circle Throw switch out Pokémon before the Ability activates.
const forbiddenDefendingMoves = [MoveId.DRAGON_TAIL, MoveId.CIRCLE_THROW];
if (source) {
- const enemyMoveHistory = source.getMoveHistory();
- if (enemyMoveHistory.length > 0) {
- const enemyLastMoveUsed = enemyMoveHistory[enemyMoveHistory.length - 1];
+ const enemyLastMoveUsed = source.getLastXMoves()[0];
+ if (enemyLastMoveUsed) {
// Will not activate if the Pokémon's HP falls below half while it is in the air during Sky Drop.
if (
- forbiddenDefendingMoves.includes(enemyLastMoveUsed.move) ||
- (enemyLastMoveUsed.move === MoveId.SKY_DROP && enemyLastMoveUsed.result === MoveResult.OTHER)
+ forbiddenDefendingMoves.includes(enemyLastMoveUsed.move)
+ || (enemyLastMoveUsed.move === MoveId.SKY_DROP && enemyLastMoveUsed.result === MoveResult.OTHER)
) {
return false;
// Will not activate if the Pokémon's HP falls below half by a move affected by Sheer Force.
@@ -6731,8 +6698,8 @@ function getPokemonWithWeatherBasedForms() {
.getField(true)
.filter(
p =>
- (p.hasAbility(AbilityId.FORECAST) && p.species.speciesId === SpeciesId.CASTFORM) ||
- (p.hasAbility(AbilityId.FLOWER_GIFT) && p.species.speciesId === SpeciesId.CHERRIM),
+ (p.hasAbility(AbilityId.FORECAST) && p.species.speciesId === SpeciesId.CASTFORM)
+ || (p.hasAbility(AbilityId.FLOWER_GIFT) && p.species.speciesId === SpeciesId.CHERRIM),
);
}
@@ -7431,7 +7398,7 @@ export function initAbilities() {
.conditionalAttr(pokemon => pokemon.formIndex === 0, PostSummonAddBattlerTagAbAttr, BattlerTagType.DISGUISE, 0, false)
.attr(FormBlockDamageAbAttr,
(target, user, move) => !!target.getTag(BattlerTagType.DISGUISE) && target.getMoveEffectiveness(user, move) > 0, 0, BattlerTagType.DISGUISE,
- (pokemon, abilityName) => i18next.t("abilityTriggers:disguiseAvoidedDamage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName: abilityName }),
+ (pokemon, abilityName) => i18next.t("abilityTriggers:disguiseAvoidedDamage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }),
(pokemon) => toDmgValue(pokemon.getMaxHp() / 8))
.attr(PostBattleInitFormChangeAbAttr, () => 0)
.attr(PostFaintFormChangeAbAttr, () => 0)
@@ -7604,7 +7571,7 @@ export function initAbilities() {
.attr(PostWeatherChangeAddBattlerTagAttr, BattlerTagType.ICE_FACE, 0, WeatherType.HAIL, WeatherType.SNOW)
.attr(FormBlockDamageAbAttr,
(target, _user, move) => move.category === MoveCategory.PHYSICAL && !!target.getTag(BattlerTagType.ICE_FACE), 0, BattlerTagType.ICE_FACE,
- (pokemon, abilityName) => i18next.t("abilityTriggers:iceFaceAvoidedDamage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName: abilityName }))
+ (pokemon, abilityName) => i18next.t("abilityTriggers:iceFaceAvoidedDamage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }))
.attr(PostBattleInitFormChangeAbAttr, () => 0)
.uncopiable()
.unreplaceable()
diff --git a/src/data/arena-tag.ts b/src/data/arena-tag.ts
index fd5ab607195..c13ebf95ea0 100644
--- a/src/data/arena-tag.ts
+++ b/src/data/arena-tag.ts
@@ -572,10 +572,10 @@ class MatBlockTag extends ConditionalProtectTag {
const CraftyShieldConditionFunc: ProtectConditionFunc = (_arena, moveId) => {
const move = allMoves[moveId];
return (
- move.category === MoveCategory.STATUS &&
- move.moveTarget !== MoveTarget.ENEMY_SIDE &&
- move.moveTarget !== MoveTarget.BOTH_SIDES &&
- move.moveTarget !== MoveTarget.ALL
+ move.category === MoveCategory.STATUS
+ && move.moveTarget !== MoveTarget.ENEMY_SIDE
+ && move.moveTarget !== MoveTarget.BOTH_SIDES
+ && move.moveTarget !== MoveTarget.ALL
);
};
@@ -765,9 +765,10 @@ export abstract class EntryHazardTag extends SerializableArenaTag {
const source = this.getSourcePokemon();
if (!source) {
console.warn(
- "Failed to get source Pokemon for AernaTrapTag on add message!" +
- `\nTag type: ${this.tagType}` +
- `\nPID: ${this.sourceId}`,
+ // biome-ignore lint/complexity/noUselessStringConcat: Rule bugs out with operator linebreaks set to `before`
+ "Failed to get source Pokemon for AernaTrapTag on add message!"
+ + `\nTag type: ${this.tagType}`
+ + `\nPID: ${this.sourceId}`,
);
return;
}
diff --git a/src/data/balance/biomes.ts b/src/data/balance/biomes.ts
index c0c57cb15fb..b253b0ded6e 100644
--- a/src/data/balance/biomes.ts
+++ b/src/data/balance/biomes.ts
@@ -7649,7 +7649,7 @@ export function initBiomes() {
? pokemonEvolutions[speciesId]
: [];
- if (!biomeEntries.filter(b => b[0] !== BiomeId.END).length && !speciesEvolutions.filter(es => !!((pokemonBiomes.find(p => p[0] === es.speciesId)!)[3] as any[]).filter(b => b[0] !== BiomeId.END).length).length) { // TODO: is the bang on the `find()` correct?
+ if (biomeEntries.filter(b => b[0] !== BiomeId.END).length === 0&& speciesEvolutions.filter(es => ((pokemonBiomes.find(p => p[0] === es.speciesId)!)[3] as any[]).filter(b => b[0] !== BiomeId.END).length > 0).length === 0) { // TODO: is the bang on the `find()` correct?
uncatchableSpecies.push(speciesId);
}
diff --git a/src/data/balance/egg-moves.ts b/src/data/balance/egg-moves.ts
index 5dd7bcbd9e2..1184de70b07 100644
--- a/src/data/balance/egg-moves.ts
+++ b/src/data/balance/egg-moves.ts
@@ -1,9 +1,12 @@
-import { allMoves } from "#data/data-lists";
+//! DO NOT EDIT THIS FILE - CREATED BY THE `eggMoves:parse` script automatically
import { MoveId } from "#enums/move-id";
import { SpeciesId } from "#enums/species-id";
-import { getEnumKeys, getEnumValues } from "#utils/enums";
-import { toTitleCase } from "#utils/strings";
+/**
+ * An object mapping all base form {@linkcode SpeciesId}s to an array of {@linkcode MoveId}s corresponding
+ * to their current egg moves.
+ * Generated by the `eggMoves:parse` script using a CSV sourced from the current Balance Team spreadsheet.
+ */
export const speciesEggMoves = {
[SpeciesId.BULBASAUR]: [ MoveId.SAPPY_SEED, MoveId.MALIGNANT_CHAIN, MoveId.EARTH_POWER, MoveId.MATCHA_GOTCHA ],
[SpeciesId.CHARMANDER]: [ MoveId.DRAGON_DANCE, MoveId.AEROBLAST, MoveId.EARTH_POWER, MoveId.BITTER_BLADE ],
@@ -582,55 +585,4 @@ export const speciesEggMoves = {
[SpeciesId.PALDEA_TAUROS]: [ MoveId.NO_RETREAT, MoveId.BLAZING_TORQUE, MoveId.AQUA_STEP, MoveId.THUNDEROUS_KICK ],
[SpeciesId.PALDEA_WOOPER]: [ MoveId.STONE_AXE, MoveId.RECOVER, MoveId.BANEFUL_BUNKER, MoveId.BARB_BARRAGE ],
[SpeciesId.BLOODMOON_URSALUNA]: [ MoveId.NASTY_PLOT, MoveId.ROCK_POLISH, MoveId.SANDSEAR_STORM, MoveId.BOOMBURST ]
-};
-
-/**
- * Parse a CSV-separated list of Egg Moves (such as one sourced from a Google Sheets)
- * into code able to form the `speciesEggMoves` const object as above.
- * @param content - The CSV-formatted string to convert into code.
- */
-// TODO: Move this into the scripts folder and stop running it on initialization
-function parseEggMoves(content: string): void {
- let output = "";
-
- const speciesNames = getEnumKeys(SpeciesId);
- const speciesValues = getEnumValues(SpeciesId);
- const moveNames = allMoves.map(m => m.name.replace(/ \([A-Z]\)$/, "").toLowerCase());
- const lines = content.split(/\n/g);
-
- for (const line of lines) {
- const cols = line.split(",").slice(0, 5);
- const enumSpeciesName = cols[0].toUpperCase().replace(/[ -]/g, "_") as keyof typeof SpeciesId;
- // TODO: This should use reverse mapping instead of `indexOf`
- const species = speciesValues[speciesNames.indexOf(enumSpeciesName)];
-
- const eggMoves: MoveId[] = [];
-
- for (let m = 0; m < 4; m++) {
- const moveName = cols[m + 1].trim();
- const moveIndex = moveName !== "N/A" ? moveNames.indexOf(moveName.toLowerCase()) : -1;
- if (moveIndex === -1) {
- console.warn(moveName, "could not be parsed");
- }
-
- eggMoves.push(moveIndex > -1 ? moveIndex as MoveId : MoveId.NONE);
- }
-
- if (eggMoves.every(m => m === MoveId.NONE)) {
- console.warn(`Species ${toTitleCase(SpeciesId[species])} could not be parsed, excluding from output...`)
- } else {
- output += `[SpeciesId.${SpeciesId[species]}]: [ ${eggMoves.map(m => `MoveId.${MoveId[m]}`).join(", ")} ],\n`;
- }
- }
-
- console.log(output);
-}
-
-export function initEggMoves() {
- const eggMovesStr = "";
- if (eggMovesStr) {
- setTimeout(() => {
- parseEggMoves(eggMovesStr);
- }, 1000);
- }
-}
+} satisfies Partial>;
diff --git a/src/data/balance/pokemon-evolutions.ts b/src/data/balance/pokemon-evolutions.ts
index bf588784f24..d364dc036b1 100644
--- a/src/data/balance/pokemon-evolutions.ts
+++ b/src/data/balance/pokemon-evolutions.ts
@@ -78,7 +78,7 @@ export enum EvolutionItem {
}
const tyrogueMoves = [MoveId.LOW_SWEEP, MoveId.MACH_PUNCH, MoveId.RAPID_SPIN] as const;
-type TyrogueMove = typeof tyrogueMoves[number];
+type TyrogueMove = (typeof tyrogueMoves)[number];
/**
* Pokemon Evolution tuple type consisting of:
@@ -136,7 +136,7 @@ export class SpeciesEvolutionCondition {
case EvoCondKey.FRIENDSHIP:
return i18next.t("pokemonEvolutions:friendship");
case EvoCondKey.TIME:
- return i18next.t(`pokemonEvolutions:timeOfDay.${toCamelCase(TimeOfDay[cond.time[cond.time.length - 1]])}`); // For Day and Night evos, the key we want goes last
+ return i18next.t(`pokemonEvolutions:timeOfDay.${toCamelCase(TimeOfDay[cond.time.at(-1)!])}`); // For Day and Night evos, the key we want goes last
case EvoCondKey.MOVE_TYPE:
return i18next.t("pokemonEvolutions:moveType", {type: i18next.t(`pokemonInfo:type.${toCamelCase(PokemonType[cond.pkmnType])}`)});
case EvoCondKey.PARTY_TYPE:
@@ -193,7 +193,10 @@ export class SpeciesEvolutionCondition {
case EvoCondKey.WEATHER:
return cond.weather.includes(globalScene.arena.getWeatherType());
case EvoCondKey.TYROGUE:
- return pokemon.getMoveset(true).find(m => (tyrogueMoves as readonly MoveId[]) .includes(m.moveId))?.moveId === cond.move;
+ return (
+ pokemon.getMoveset(true).find(m => (tyrogueMoves as readonly MoveId[]).includes(m.moveId))?.moveId
+ === cond.move
+ );
case EvoCondKey.NATURE:
return cond.nature.includes(pokemon.getNature());
case EvoCondKey.RANDOM_FORM: {
@@ -656,18 +659,10 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(SpeciesId.GARDEVOIR, 30, null, null),
new SpeciesEvolution(SpeciesId.GALLADE, 1, EvolutionItem.DAWN_STONE, {key: EvoCondKey.GENDER, gender: Gender.MALE}, SpeciesWildEvolutionDelay.LONG),
],
- [SpeciesId.SURSKIT]: [
- new SpeciesEvolution(SpeciesId.MASQUERAIN, 22, null, null)
- ],
- [SpeciesId.SHROOMISH]: [
- new SpeciesEvolution(SpeciesId.BRELOOM, 23, null, null)
- ],
- [SpeciesId.SLAKOTH]: [
- new SpeciesEvolution(SpeciesId.VIGOROTH, 18, null, null)
- ],
- [SpeciesId.VIGOROTH]: [
- new SpeciesEvolution(SpeciesId.SLAKING, 36, null, null)
- ],
+ [SpeciesId.SURSKIT]: [new SpeciesEvolution(SpeciesId.MASQUERAIN, 22, null, null)],
+ [SpeciesId.SHROOMISH]: [new SpeciesEvolution(SpeciesId.BRELOOM, 23, null, null)],
+ [SpeciesId.SLAKOTH]: [new SpeciesEvolution(SpeciesId.VIGOROTH, 18, null, null)],
+ [SpeciesId.VIGOROTH]: [new SpeciesEvolution(SpeciesId.SLAKING, 36, null, null)],
[SpeciesId.NINCADA]: [
new SpeciesEvolution(SpeciesId.NINJASK, 20, null, null),
new SpeciesEvolution(SpeciesId.SHEDINJA, 20, null, {key: EvoCondKey.SHEDINJA})
@@ -745,66 +740,26 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(SpeciesId.GLALIE, 42, null, null),
new SpeciesEvolution(SpeciesId.FROSLASS, 1, EvolutionItem.DAWN_STONE, {key: EvoCondKey.GENDER, gender: Gender.FEMALE}, SpeciesWildEvolutionDelay.LONG),
],
- [SpeciesId.SPHEAL]: [
- new SpeciesEvolution(SpeciesId.SEALEO, 32, null, null)
- ],
- [SpeciesId.SEALEO]: [
- new SpeciesEvolution(SpeciesId.WALREIN, 44, null, null)
- ],
- [SpeciesId.BAGON]: [
- new SpeciesEvolution(SpeciesId.SHELGON, 30, null, null)
- ],
- [SpeciesId.SHELGON]: [
- new SpeciesEvolution(SpeciesId.SALAMENCE, 50, null, null)
- ],
- [SpeciesId.BELDUM]: [
- new SpeciesEvolution(SpeciesId.METANG, 20, null, null)
- ],
- [SpeciesId.METANG]: [
- new SpeciesEvolution(SpeciesId.METAGROSS, 45, null, null)
- ],
- [SpeciesId.TURTWIG]: [
- new SpeciesEvolution(SpeciesId.GROTLE, 18, null, null)
- ],
- [SpeciesId.GROTLE]: [
- new SpeciesEvolution(SpeciesId.TORTERRA, 32, null, null)
- ],
- [SpeciesId.CHIMCHAR]: [
- new SpeciesEvolution(SpeciesId.MONFERNO, 14, null, null)
- ],
- [SpeciesId.MONFERNO]: [
- new SpeciesEvolution(SpeciesId.INFERNAPE, 36, null, null)
- ],
- [SpeciesId.PIPLUP]: [
- new SpeciesEvolution(SpeciesId.PRINPLUP, 16, null, null)
- ],
- [SpeciesId.PRINPLUP]: [
- new SpeciesEvolution(SpeciesId.EMPOLEON, 36, null, null)
- ],
- [SpeciesId.STARLY]: [
- new SpeciesEvolution(SpeciesId.STARAVIA, 14, null, null)
- ],
- [SpeciesId.STARAVIA]: [
- new SpeciesEvolution(SpeciesId.STARAPTOR, 34, null, null)
- ],
- [SpeciesId.BIDOOF]: [
- new SpeciesEvolution(SpeciesId.BIBAREL, 15, null, null)
- ],
- [SpeciesId.KRICKETOT]: [
- new SpeciesEvolution(SpeciesId.KRICKETUNE, 10, null, null)
- ],
- [SpeciesId.SHINX]: [
- new SpeciesEvolution(SpeciesId.LUXIO, 15, null, null)
- ],
- [SpeciesId.LUXIO]: [
- new SpeciesEvolution(SpeciesId.LUXRAY, 30, null, null)
- ],
- [SpeciesId.CRANIDOS]: [
- new SpeciesEvolution(SpeciesId.RAMPARDOS, 30, null, null)
- ],
- [SpeciesId.SHIELDON]: [
- new SpeciesEvolution(SpeciesId.BASTIODON, 30, null, null)
- ],
+ [SpeciesId.SPHEAL]: [new SpeciesEvolution(SpeciesId.SEALEO, 32, null, null)],
+ [SpeciesId.SEALEO]: [new SpeciesEvolution(SpeciesId.WALREIN, 44, null, null)],
+ [SpeciesId.BAGON]: [new SpeciesEvolution(SpeciesId.SHELGON, 30, null, null)],
+ [SpeciesId.SHELGON]: [new SpeciesEvolution(SpeciesId.SALAMENCE, 50, null, null)],
+ [SpeciesId.BELDUM]: [new SpeciesEvolution(SpeciesId.METANG, 20, null, null)],
+ [SpeciesId.METANG]: [new SpeciesEvolution(SpeciesId.METAGROSS, 45, null, null)],
+ [SpeciesId.TURTWIG]: [new SpeciesEvolution(SpeciesId.GROTLE, 18, null, null)],
+ [SpeciesId.GROTLE]: [new SpeciesEvolution(SpeciesId.TORTERRA, 32, null, null)],
+ [SpeciesId.CHIMCHAR]: [new SpeciesEvolution(SpeciesId.MONFERNO, 14, null, null)],
+ [SpeciesId.MONFERNO]: [new SpeciesEvolution(SpeciesId.INFERNAPE, 36, null, null)],
+ [SpeciesId.PIPLUP]: [new SpeciesEvolution(SpeciesId.PRINPLUP, 16, null, null)],
+ [SpeciesId.PRINPLUP]: [new SpeciesEvolution(SpeciesId.EMPOLEON, 36, null, null)],
+ [SpeciesId.STARLY]: [new SpeciesEvolution(SpeciesId.STARAVIA, 14, null, null)],
+ [SpeciesId.STARAVIA]: [new SpeciesEvolution(SpeciesId.STARAPTOR, 34, null, null)],
+ [SpeciesId.BIDOOF]: [new SpeciesEvolution(SpeciesId.BIBAREL, 15, null, null)],
+ [SpeciesId.KRICKETOT]: [new SpeciesEvolution(SpeciesId.KRICKETUNE, 10, null, null)],
+ [SpeciesId.SHINX]: [new SpeciesEvolution(SpeciesId.LUXIO, 15, null, null)],
+ [SpeciesId.LUXIO]: [new SpeciesEvolution(SpeciesId.LUXRAY, 30, null, null)],
+ [SpeciesId.CRANIDOS]: [new SpeciesEvolution(SpeciesId.RAMPARDOS, 30, null, null)],
+ [SpeciesId.SHIELDON]: [new SpeciesEvolution(SpeciesId.BASTIODON, 30, null, null)],
[SpeciesId.BURMY]: [
new SpeciesEvolution(SpeciesId.MOTHIM, 20, null, {key: EvoCondKey.GENDER, gender: Gender.MALE}),
new SpeciesEvolution(SpeciesId.WORMADAM, 20, null, {key: EvoCondKey.GENDER, gender: Gender.FEMALE})
@@ -1870,7 +1825,7 @@ export const pokemonPrevolutions: PokemonPrevolutions = {};
export function initPokemonPrevolutions(): void {
// TODO: Why do we have empty strings in our array?
- const megaFormKeys = [ SpeciesFormKey.MEGA, "", SpeciesFormKey.MEGA_X, "", SpeciesFormKey.MEGA_Y ];
+ const megaFormKeys = [SpeciesFormKey.MEGA, "", SpeciesFormKey.MEGA_X, "", SpeciesFormKey.MEGA_Y];
for (const [pk, evolutions] of Object.entries(pokemonEvolutions)) {
for (const ev of evolutions) {
if (ev.evoFormKey && megaFormKeys.indexOf(ev.evoFormKey) > -1) {
diff --git a/src/data/battle-anims.ts b/src/data/battle-anims.ts
index 5ff4472d148..1dcb7d7eebf 100644
--- a/src/data/battle-anims.ts
+++ b/src/data/battle-anims.ts
@@ -139,8 +139,8 @@ class AnimFrame {
focus: AnimFocus,
init?: boolean,
) {
- this.x = !init ? ((x || 0) - 128) * 0.5 : x;
- this.y = !init ? ((y || 0) - 224) * 0.5 : y;
+ this.x = init ? x : ((x || 0) - 128) * 0.5;
+ this.y = init ? y : ((y || 0) - 224) * 0.5;
if (zoomX) {
this.zoomX = zoomX;
} else if (init) {
@@ -360,7 +360,7 @@ class AnimTimedUpdateBgEvent extends AnimTimedBgEvent {
if (this.opacity !== undefined) {
tweenProps["alpha"] = (this.opacity || 0) / 255;
}
- if (Object.keys(tweenProps).length) {
+ if (Object.keys(tweenProps).length > 0) {
globalScene.tweens.add({
targets: moveAnim.bgSprite,
duration: getFrameMs(this.duration * 3),
@@ -625,7 +625,7 @@ function loadAnimAssets(anims: AnimConfig[], startLoad?: boolean): Promise
const backgrounds = new Set();
const sounds = new Set();
for (const a of anims) {
- if (!a.frames?.length) {
+ if (a.frames?.length === 0) {
continue;
}
const animSounds = a.getSoundResourceNames();
@@ -816,8 +816,8 @@ export abstract class BattleAnim {
x = point[0];
y = point[1];
if (
- frame.target === AnimFrameTarget.GRAPHIC &&
- isReversed(this.srcLine[0], this.srcLine[2], this.dstLine[0], this.dstLine[2])
+ frame.target === AnimFrameTarget.GRAPHIC
+ && isReversed(this.srcLine[0], this.srcLine[2], this.dstLine[0], this.dstLine[2])
) {
scaleX = scaleX * -1;
}
@@ -826,7 +826,7 @@ export abstract class BattleAnim {
}
const angle = -frame.angle;
const key = frame.target === AnimFrameTarget.GRAPHIC ? g++ : frame.target === AnimFrameTarget.USER ? u++ : t++;
- ret.get(frame.target)!.set(key, { x: x, y: y, scaleX: scaleX, scaleY: scaleY, angle: angle }); // TODO: is the bang correct?
+ ret.get(frame.target)!.set(key, { x, y, scaleX, scaleY, angle }); // TODO: is the bang correct?
}
return ret;
@@ -835,8 +835,8 @@ export abstract class BattleAnim {
// biome-ignore lint/complexity/noBannedTypes: callback is used liberally
play(onSubstitute?: boolean, callback?: Function) {
const isOppAnim = this.isOppAnim();
- const user = !isOppAnim ? this.user! : this.target!; // TODO: are those bangs correct?
- const target = !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
if (!target?.isOnField() && !this.playRegardlessOfIssues) {
if (callback) {
@@ -888,8 +888,8 @@ export abstract class BattleAnim {
* and `this.target` prevent the target's Substitute doll from disappearing
* after being the target of an animation.
*/
- const userSpriteToShow = !isOppAnim ? userSprite : targetSprite;
- const targetSpriteToShow = !isOppAnim ? targetSprite : userSprite;
+ const userSpriteToShow = isOppAnim ? targetSprite : userSprite;
+ const targetSpriteToShow = isOppAnim ? userSprite : targetSprite;
if (!this.isHideUser() && userSpriteToShow) {
userSpriteToShow.setVisible(true);
}
@@ -1142,18 +1142,18 @@ export abstract class BattleAnim {
for (const frame of frames) {
let { x, y } = frame;
- const scaleX = (frame.zoomX / 100) * (!frame.mirror ? 1 : -1);
+ const scaleX = (frame.zoomX / 100) * (frame.mirror ? -1 : 1);
const scaleY = frame.zoomY / 100;
x += targetInitialX;
y += targetInitialY;
const angle = -frame.angle;
const key = frame.target === AnimFrameTarget.GRAPHIC ? g++ : frame.target === AnimFrameTarget.USER ? u++ : t++;
ret.get(frame.target)?.set(key, {
- x: x,
- y: y,
- scaleX: scaleX,
- scaleY: scaleY,
- angle: angle,
+ x,
+ y,
+ scaleX,
+ scaleY,
+ angle,
});
}
diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts
index 5484eba7271..cc2a403cd53 100644
--- a/src/data/battler-tags.ts
+++ b/src/data/battler-tags.ts
@@ -1135,8 +1135,8 @@ export class PowderTag extends BattlerTag {
const move = movePhase.move.getMove();
const weather = globalScene.arena.weather;
if (
- pokemon.getMoveType(move) !== PokemonType.FIRE ||
- (weather?.weatherType === WeatherType.HEAVY_RAIN && !weather.isEffectSuppressed()) // Heavy rain takes priority over powder
+ pokemon.getMoveType(move) !== PokemonType.FIRE
+ || (weather?.weatherType === WeatherType.HEAVY_RAIN && !weather.isEffectSuppressed()) // Heavy rain takes priority over powder
) {
return true;
}
@@ -1793,9 +1793,9 @@ export abstract class ContactProtectedTag extends ProtectedTag {
const moveData = getMoveEffectPhaseData(pokemon);
if (
- lapseType === BattlerTagLapseType.CUSTOM &&
- moveData &&
- moveData.move.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user: moveData.attacker, target: pokemon })
+ lapseType === BattlerTagLapseType.CUSTOM
+ && moveData
+ && moveData.move.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user: moveData.attacker, target: pokemon })
) {
this.onContact(moveData.attacker, pokemon);
}
@@ -2538,12 +2538,10 @@ export class RoostedTag extends BattlerTag {
let modifiedTypes: PokemonType[];
if (this.isBasePureFlying && !isCurrentlyDualType) {
modifiedTypes = [PokemonType.NORMAL];
+ } else if (!!pokemon.getTag(RemovedTypeTag) && isOriginallyDualType && !isCurrentlyDualType) {
+ modifiedTypes = [PokemonType.UNKNOWN];
} else {
- if (!!pokemon.getTag(RemovedTypeTag) && isOriginallyDualType && !isCurrentlyDualType) {
- modifiedTypes = [PokemonType.UNKNOWN];
- } else {
- modifiedTypes = currentTypes.filter(type => type !== PokemonType.FLYING);
- }
+ modifiedTypes = currentTypes.filter(type => type !== PokemonType.FLYING);
}
pokemon.summonData.types = modifiedTypes;
pokemon.updateInfo();
@@ -2819,9 +2817,9 @@ export class GulpMissileTag extends SerializableBattlerTag {
// Bang here is OK as if sourceMove was undefined, this would just evaluate to false
const isSurfOrDive = [MoveId.SURF, MoveId.DIVE].includes(this.sourceMove!);
const isNormalForm =
- pokemon.formIndex === 0 &&
- !pokemon.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA) &&
- !pokemon.getTag(BattlerTagType.GULP_MISSILE_PIKACHU);
+ pokemon.formIndex === 0
+ && !pokemon.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)
+ && !pokemon.getTag(BattlerTagType.GULP_MISSILE_PIKACHU);
const isCramorant = pokemon.species.speciesId === SpeciesId.CRAMORANT;
return isSurfOrDive && isNormalForm && isCramorant;
@@ -3862,7 +3860,7 @@ function getMoveEffectPhaseData(_pokemon: Pokemon): { phase: MoveEffectPhase; at
const phase = globalScene.phaseManager.getCurrentPhase();
if (phase?.is("MoveEffectPhase")) {
return {
- phase: phase,
+ phase,
attacker: phase.getPokemon(),
move: phase.move,
};
diff --git a/src/data/berry.ts b/src/data/berry.ts
index 762423799fe..1f1364f2f6b 100644
--- a/src/data/berry.ts
+++ b/src/data/berry.ts
@@ -28,7 +28,7 @@ export function getBerryPredicate(berryType: BerryType): BerryPredicate {
return (pokemon: Pokemon) => !!pokemon.status || !!pokemon.getTag(BattlerTagType.CONFUSED);
case BerryType.ENIGMA:
return (pokemon: Pokemon) =>
- !!pokemon.turnData.attacksReceived.filter(a => a.result === HitResult.SUPER_EFFECTIVE).length;
+ pokemon.turnData.attacksReceived.filter(a => a.result === HitResult.SUPER_EFFECTIVE).length > 0;
case BerryType.LIECHI:
case BerryType.GANLON:
case BerryType.PETAYA:
@@ -141,8 +141,8 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
{
// Pick the first move completely out of PP, or else the first one that has any PP missing
const ppRestoreMove =
- consumer.getMoveset().find(m => m.ppUsed === m.getMovePp()) ??
- consumer.getMoveset().find(m => m.ppUsed < m.getMovePp());
+ consumer.getMoveset().find(m => m.ppUsed === m.getMovePp())
+ ?? consumer.getMoveset().find(m => m.ppUsed < m.getMovePp());
if (ppRestoreMove) {
ppRestoreMove.ppUsed = Math.max(ppRestoreMove.ppUsed - 10, 0);
globalScene.phaseManager.queueMessage(
diff --git a/src/data/challenge.ts b/src/data/challenge.ts
index cea8661e78c..a8ec92df57d 100644
--- a/src/data/challenge.ts
+++ b/src/data/challenge.ts
@@ -467,8 +467,8 @@ export class SingleGenerationChallenge extends Challenge {
const baseGeneration = getPokemonSpecies(pokemon.species.speciesId).generation;
const fusionGeneration = pokemon.isFusion() ? getPokemonSpecies(pokemon.fusionSpecies!.speciesId).generation : 0;
if (
- pokemon.isPlayer() &&
- (baseGeneration !== this.value || (pokemon.isFusion() && fusionGeneration !== this.value))
+ pokemon.isPlayer()
+ && (baseGeneration !== this.value || (pokemon.isFusion() && fusionGeneration !== this.value))
) {
valid.value = false;
return true;
@@ -741,12 +741,12 @@ export class SingleTypeChallenge extends Challenge {
applyPokemonInBattle(pokemon: Pokemon, valid: BooleanHolder): boolean {
if (
- pokemon.isPlayer() &&
- !pokemon.isOfType(this.value - 1, false, false, true) &&
- !SingleTypeChallenge.TYPE_OVERRIDES.some(
+ pokemon.isPlayer()
+ && !pokemon.isOfType(this.value - 1, false, false, true)
+ && !SingleTypeChallenge.TYPE_OVERRIDES.some(
o =>
- o.type === this.value - 1 &&
- (pokemon.isFusion() && o.fusion ? pokemon.fusionSpecies! : pokemon.species).speciesId === o.species,
+ o.type === this.value - 1
+ && (pokemon.isFusion() && o.fusion ? pokemon.fusionSpecies! : pokemon.species).speciesId === o.species,
)
) {
// TODO: is the bang on fusionSpecies correct?
@@ -764,7 +764,7 @@ export class SingleTypeChallenge extends Challenge {
}
getValue(overrideValue: number = this.value): string {
- return i18next.t(`pokemonInfo:type.${toCamelCase(PokemonType[overrideValue - 1])}`);
+ return PokemonType[overrideValue - 1].toLowerCase();
}
getDescription(overrideValue: number = this.value): string {
@@ -823,11 +823,11 @@ export class FreshStartChallenge extends Challenge {
// Remove natures except for the default ones
const neutralNaturesAttr =
- (1 << (Nature.HARDY + 1)) |
- (1 << (Nature.DOCILE + 1)) |
- (1 << (Nature.SERIOUS + 1)) |
- (1 << (Nature.BASHFUL + 1)) |
- (1 << (Nature.QUIRKY + 1));
+ (1 << (Nature.HARDY + 1))
+ | (1 << (Nature.DOCILE + 1))
+ | (1 << (Nature.SERIOUS + 1))
+ | (1 << (Nature.BASHFUL + 1))
+ | (1 << (Nature.QUIRKY + 1));
dexEntry.natureAttr &= neutralNaturesAttr;
// Cap all ivs at 15
@@ -882,8 +882,8 @@ export class FreshStartChallenge extends Challenge {
if (pokemon.species.speciesId === SpeciesId.ZYGARDE && pokemon.formIndex >= 2) {
pokemon.formIndex -= 2; // Sets 10%-PC to 10%-AB and 50%-PC to 50%-AB
} else if (
- pokemon.formIndex > 0 &&
- [
+ pokemon.formIndex > 0
+ && [
SpeciesId.PIKACHU,
SpeciesId.EEVEE,
SpeciesId.PICHU,
diff --git a/src/data/daily-run.ts b/src/data/daily-run.ts
index f0a20a0b02b..a0d3358ecb0 100644
--- a/src/data/daily-run.ts
+++ b/src/data/daily-run.ts
@@ -6,7 +6,7 @@ import { PokemonSpecies } from "#data/pokemon-species";
import { BiomeId } from "#enums/biome-id";
import { PartyMemberStrength } from "#enums/party-member-strength";
import { SpeciesId } from "#enums/species-id";
-import type { Starter } from "#ui/starter-select-ui-handler";
+import type { Starter } from "#ui/handlers/starter-select-ui-handler";
import { isNullOrUndefined, randSeedGauss, randSeedInt, randSeedItem } from "#utils/common";
import { getEnumValues } from "#utils/enums";
import { getPokemonSpecies, getPokemonSpeciesForm } from "#utils/pokemon-utils";
@@ -42,10 +42,9 @@ export function getDailyRunStarters(seed: string): Starter[] {
starterCosts.push(randSeedInt(9 - starterCosts[0], 1));
starterCosts.push(10 - (starterCosts[0] + starterCosts[1]));
- for (let c = 0; c < starterCosts.length; c++) {
- const cost = starterCosts[c];
+ for (const cost of starterCosts) {
const costSpecies = Object.keys(speciesStarterCosts)
- .map(s => Number.parseInt(s) as SpeciesId)
+ .map(s => Number.parseInt(s) as SpeciesId) // TODO: Remove
.filter(s => speciesStarterCosts[s] === cost);
const randPkmSpecies = getPokemonSpecies(randSeedItem(costSpecies));
const starterSpecies = getPokemonSpecies(
diff --git a/src/data/egg.ts b/src/data/egg.ts
index 5fab276f327..d4d37071d11 100644
--- a/src/data/egg.ts
+++ b/src/data/egg.ts
@@ -220,9 +220,9 @@ export class Egg {
public isManaphyEgg(): boolean {
return (
- this._species === SpeciesId.PHIONE ||
- this._species === SpeciesId.MANAPHY ||
- (this._tier === EggTier.COMMON && !(this._id % 204) && !this._species)
+ this._species === SpeciesId.PHIONE
+ || this._species === SpeciesId.MANAPHY
+ || (this._tier === EggTier.COMMON && !(this._id % 204) && !this._species)
);
}
@@ -324,15 +324,15 @@ export class Egg {
switch (this.sourceType) {
case EggSourceType.SAME_SPECIES_EGG:
return (
- this._eggDescriptor ??
- i18next.t("egg:sameSpeciesEgg", {
+ this._eggDescriptor
+ ?? i18next.t("egg:sameSpeciesEgg", {
species: getPokemonSpecies(this._species).getName(),
})
);
case EggSourceType.GACHA_LEGENDARY:
return (
- this._eggDescriptor ??
- `${i18next.t("egg:gachaTypeLegendary")} (${getPokemonSpecies(getLegendaryGachaSpeciesForTimestamp(this.timestamp)).getName()})`
+ this._eggDescriptor
+ ?? `${i18next.t("egg:gachaTypeLegendary")} (${getPokemonSpecies(getLegendaryGachaSpeciesForTimestamp(this.timestamp)).getName()})`
);
case EggSourceType.GACHA_SHINY:
return this._eggDescriptor ?? i18next.t("egg:gachaTypeShiny");
@@ -419,10 +419,8 @@ export class Egg {
const rand = randSeedInt(MANAPHY_EGG_MANAPHY_RATE) !== 1;
return rand ? SpeciesId.PHIONE : SpeciesId.MANAPHY;
}
- if (this.tier === EggTier.LEGENDARY && this._sourceType === EggSourceType.GACHA_LEGENDARY) {
- if (!randSeedInt(2)) {
- return getLegendaryGachaSpeciesForTimestamp(this.timestamp);
- }
+ if (this.tier === EggTier.LEGENDARY && this._sourceType === EggSourceType.GACHA_LEGENDARY && !randSeedInt(2)) {
+ return getLegendaryGachaSpeciesForTimestamp(this.timestamp);
}
let minStarterValue: number;
@@ -454,9 +452,9 @@ export class Egg {
.map(s => Number.parseInt(s) as SpeciesId)
.filter(
s =>
- !pokemonPrevolutions.hasOwnProperty(s) &&
- getPokemonSpecies(s).isObtainable() &&
- ignoredSpecies.indexOf(s) === -1,
+ !pokemonPrevolutions.hasOwnProperty(s)
+ && getPokemonSpecies(s).isObtainable()
+ && ignoredSpecies.indexOf(s) === -1,
);
// If this is the 10th egg without unlocking something new, attempt to force it.
@@ -464,7 +462,7 @@ export class Egg {
const lockedPool = speciesPool.filter(
s => !globalScene.gameData.dexData[s].caughtAttr && !globalScene.gameData.eggs.some(e => e.species === s),
);
- if (lockedPool.length) {
+ if (lockedPool.length > 0) {
// Skip this if everything is unlocked
speciesPool = lockedPool;
}
@@ -510,8 +508,8 @@ export class Egg {
species = species!; // tell TS compiled it's defined now!
if (
- globalScene.gameData.dexData[species].caughtAttr ||
- globalScene.gameData.eggs.some(e => e.species === species)
+ globalScene.gameData.dexData[species].caughtAttr
+ || globalScene.gameData.eggs.some(e => e.species === species)
) {
globalScene.gameData.unlockPity[this.tier] = Math.min(globalScene.gameData.unlockPity[this.tier] + 1, 10);
} else {
@@ -567,8 +565,8 @@ export class Egg {
globalScene.gameData.eggPity[EggTier.LEGENDARY] += 1 + tierValueOffset;
// These numbers are roughly the 80% mark. That is, 80% of the time you'll get an egg before this gets triggered.
if (
- globalScene.gameData.eggPity[EggTier.LEGENDARY] >= EGG_PITY_LEGENDARY_THRESHOLD &&
- this._tier === EggTier.COMMON
+ globalScene.gameData.eggPity[EggTier.LEGENDARY] >= EGG_PITY_LEGENDARY_THRESHOLD
+ && this._tier === EggTier.COMMON
) {
this._tier = EggTier.LEGENDARY;
} else if (globalScene.gameData.eggPity[EggTier.EPIC] >= EGG_PITY_EPIC_THRESHOLD && this._tier === EggTier.COMMON) {
diff --git a/src/data/moves/move-utils.ts b/src/data/moves/move-utils.ts
index 241144599e5..eedeea53087 100644
--- a/src/data/moves/move-utils.ts
+++ b/src/data/moves/move-utils.ts
@@ -126,7 +126,7 @@ export function getMoveTargets(user: Pokemon, move: MoveId, replaceTarget?: Move
}
export const frenzyMissFunc: UserMoveConditionFunc = (user: Pokemon, move: Move) => {
- while (user.getMoveQueue().length && user.getMoveQueue()[0].move === move.id) {
+ while (user.getMoveQueue().length > 0 && user.getMoveQueue()[0].move === move.id) {
user.getMoveQueue().shift();
}
user.removeTag(BattlerTagType.FRENZY); // FRENZY tag should be disrupted on miss/no effect
diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts
index 392be028dd8..ab63149786c 100644
--- a/src/data/moves/move.ts
+++ b/src/data/moves/move.ts
@@ -8149,9 +8149,12 @@ const failIfSingleBattle: MoveConditionFunc = (user, target, move) => globalScen
const failIfDampCondition: MoveConditionFunc = (user, target, move) => {
const cancelled = new BooleanHolder(false);
- globalScene.getField(true).map(p=>applyAbAttrs("FieldPreventExplosiveMovesAbAttr", {pokemon: p, cancelled}));
+ // temporary workaround to prevent displaying the message during enemy command phase
+ // TODO: either move this, or make the move condition func have a `simulated` param
+ const simulated = globalScene.phaseManager.getCurrentPhase()?.is('EnemyCommandPhase');
+ globalScene.getField(true).map(p=>applyAbAttrs("FieldPreventExplosiveMovesAbAttr", {pokemon: p, cancelled, simulated}));
// Queue a message if an ability prevented usage of the move
- if (cancelled.value) {
+ if (!simulated && cancelled.value) {
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:cannotUseMove", { pokemonName: getPokemonNameWithAffix(user), moveName: move.name }));
}
return !cancelled.value;
@@ -8173,6 +8176,9 @@ const failIfGhostTypeCondition: MoveConditionFunc = (user: Pokemon, target: Poke
const failIfNoTargetHeldItemsCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => target.getHeldItems().filter(i => i.isTransferable)?.length > 0;
const attackedByItemMessageFunc = (user: Pokemon, target: Pokemon, move: Move) => {
+ if (isNullOrUndefined(target)) { // Fix bug when used against targets that have both fainted
+ return "";
+ }
const heldItems = target.getHeldItems().filter(i => i.isTransferable);
if (heldItems.length === 0) {
return "";
diff --git a/src/data/moves/pokemon-move.ts b/src/data/moves/pokemon-move.ts
index cdb8d628be1..23daf0a971b 100644
--- a/src/data/moves/pokemon-move.ts
+++ b/src/data/moves/pokemon-move.ts
@@ -50,10 +50,9 @@ export class PokemonMove {
const move = this.getMove();
// TODO: Add Sky Drop's 1 turn stall
const usability = new BooleanHolder(
- !move.name.endsWith(" (N)") &&
- (ignorePp || this.ppUsed < this.getMovePp() || move.pp === -1) &&
- // TODO: Review if the `MoveId.NONE` check is even necessary anymore
- !(this.moveId !== MoveId.NONE && !ignoreRestrictionTags && pokemon.isMoveRestricted(this.moveId, pokemon)),
+ !move.name.endsWith(" (N)")
+ && (ignorePp || this.ppUsed < this.getMovePp() || move.pp === -1) // TODO: Review if the `MoveId.NONE` check is even necessary anymore
+ && !(this.moveId !== MoveId.NONE && !ignoreRestrictionTags && pokemon.isMoveRestricted(this.moveId, pokemon)),
);
if (pokemon.isPlayer()) {
applyChallenges(ChallengeType.POKEMON_MOVE, move.id, usability);
diff --git a/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts b/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts
index 66364bfc485..98b4d06723a 100644
--- a/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts
+++ b/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts
@@ -111,7 +111,7 @@ export const ATrainersTestEncounter: MysteryEncounter = MysteryEncounterBuilder.
const trainerSpriteKey = trainerConfig.getSpriteKey();
encounter.enemyPartyConfigs.push({
levelAdditiveModifier: 1,
- trainerConfig: trainerConfig,
+ trainerConfig,
});
encounter.spriteConfigs = [
diff --git a/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts b/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts
index bf9c49e8c5b..8b28065dad1 100644
--- a/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts
+++ b/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts
@@ -527,7 +527,8 @@ function doBerrySpritePile(isEat = false) {
const encounter = globalScene.currentBattle.mysteryEncounter!;
animationOrder.forEach((berry, i) => {
const introVisualsIndex = encounter.spriteConfigs.findIndex(config => config.spriteKey?.includes(berry));
- let sprite: Phaser.GameObjects.Sprite, tintSprite: Phaser.GameObjects.Sprite;
+ let sprite: Phaser.GameObjects.Sprite;
+ let tintSprite: Phaser.GameObjects.Sprite;
const sprites = encounter.introVisuals?.getSpriteAtIndex(introVisualsIndex);
if (sprites) {
sprite = sprites[0];
diff --git a/src/data/mystery-encounters/encounters/an-offer-you-cant-refuse-encounter.ts b/src/data/mystery-encounters/encounters/an-offer-you-cant-refuse-encounter.ts
index 7d4fb0ef98f..0c47850f2b7 100644
--- a/src/data/mystery-encounters/encounters/an-offer-you-cant-refuse-encounter.ts
+++ b/src/data/mystery-encounters/encounters/an-offer-you-cant-refuse-encounter.ts
@@ -93,8 +93,8 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter = MysteryEncounterB
// Store pokemon and price
encounter.misc = {
- pokemon: pokemon,
- price: price,
+ pokemon,
+ price,
};
// If player meets the combo OR requirements for option 2, populate the token
diff --git a/src/data/mystery-encounters/encounters/berries-abound-encounter.ts b/src/data/mystery-encounters/encounters/berries-abound-encounter.ts
index 358bba92a09..a4f2b00b04b 100644
--- a/src/data/mystery-encounters/encounters/berries-abound-encounter.ts
+++ b/src/data/mystery-encounters/encounters/berries-abound-encounter.ts
@@ -71,7 +71,7 @@ export const BerriesAboundEncounter: MysteryEncounter = MysteryEncounterBuilder.
const config: EnemyPartyConfig = {
pokemonConfigs: [
{
- level: level,
+ level,
species: bossPokemon.species,
dataSource: new PokemonData(bossPokemon),
isBoss: true,
@@ -105,8 +105,8 @@ export const BerriesAboundEncounter: MysteryEncounter = MysteryEncounterBuilder.
hasShadow: true,
},
{
- spriteKey: spriteKey,
- fileRoot: fileRoot,
+ spriteKey,
+ fileRoot,
hasShadow: true,
tint: 0.25,
x: -5,
@@ -320,9 +320,9 @@ function tryGiveBerry(prioritizedPokemon?: PlayerPokemon) {
if (prioritizedPokemon) {
const heldBerriesOfType = globalScene.findModifier(
m =>
- m instanceof BerryModifier &&
- m.pokemonId === prioritizedPokemon.id &&
- (m as BerryModifier).berryType === berryType,
+ m instanceof BerryModifier
+ && m.pokemonId === prioritizedPokemon.id
+ && (m as BerryModifier).berryType === berryType,
true,
) as BerryModifier;
diff --git a/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts b/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts
index 6750051c3c4..5462c0eb336 100644
--- a/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts
+++ b/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts
@@ -46,8 +46,8 @@ import {
} from "#mystery-encounters/mystery-encounter-requirements";
import { getRandomPartyMemberFunc, trainerConfigs } from "#trainers/trainer-config";
import { TrainerPartyCompoundTemplate, TrainerPartyTemplate } from "#trainers/trainer-party-template";
-import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
-import { MoveInfoOverlay } from "#ui/move-info-overlay";
+import { MoveInfoOverlay } from "#ui/containers/move-info-overlay";
+import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler";
import { isNullOrUndefined, randSeedInt, randSeedShuffle } from "#utils/common";
import i18next from "i18next";
@@ -213,7 +213,8 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
female: true,
});
- let beedrillKeys: { spriteKey: string; fileRoot: string }, butterfreeKeys: { spriteKey: string; fileRoot: string };
+ let beedrillKeys: { spriteKey: string; fileRoot: string };
+ let butterfreeKeys: { spriteKey: string; fileRoot: string };
if (globalScene.currentBattle.waveIndex < WAVE_LEVEL_BREAKPOINTS[3]) {
beedrillKeys = getSpriteKeysFromSpecies(SpeciesId.BEEDRILL, false);
butterfreeKeys = getSpriteKeysFromSpecies(SpeciesId.BUTTERFREE, false);
@@ -247,7 +248,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
yShadow: -4,
},
{
- spriteKey: spriteKey,
+ spriteKey,
fileRoot: "trainer",
hasShadow: true,
x: 4,
@@ -440,11 +441,11 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
// Get Pokemon held items and filter for valid ones
const validItems = pokemon.getHeldItems().filter(item => {
return (
- (item instanceof BypassSpeedChanceModifier ||
- item instanceof ContactHeldItemTransferChanceModifier ||
- (item instanceof AttackTypeBoosterModifier &&
- (item.type as AttackTypeBoosterModifierType).moveType === PokemonType.BUG)) &&
- item.isTransferable
+ (item instanceof BypassSpeedChanceModifier
+ || item instanceof ContactHeldItemTransferChanceModifier
+ || (item instanceof AttackTypeBoosterModifier
+ && (item.type as AttackTypeBoosterModifierType).moveType === PokemonType.BUG))
+ && item.isTransferable
);
});
@@ -469,10 +470,10 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
// If pokemon has valid item, it can be selected
const hasValidItem = pokemon.getHeldItems().some(item => {
return (
- item instanceof BypassSpeedChanceModifier ||
- item instanceof ContactHeldItemTransferChanceModifier ||
- (item instanceof AttackTypeBoosterModifier &&
- (item.type as AttackTypeBoosterModifierType).moveType === PokemonType.BUG)
+ item instanceof BypassSpeedChanceModifier
+ || item instanceof ContactHeldItemTransferChanceModifier
+ || (item instanceof AttackTypeBoosterModifier
+ && (item.type as AttackTypeBoosterModifierType).moveType === PokemonType.BUG)
);
});
if (!hasValidItem) {
diff --git a/src/data/mystery-encounters/encounters/clowning-around-encounter.ts b/src/data/mystery-encounters/encounters/clowning-around-encounter.ts
index 09e59c7e391..42907455e22 100644
--- a/src/data/mystery-encounters/encounters/clowning-around-encounter.ts
+++ b/src/data/mystery-encounters/encounters/clowning-around-encounter.ts
@@ -45,7 +45,7 @@ import { MysteryEncounterBuilder } from "#mystery-encounters/mystery-encounter";
import { MysteryEncounterOptionBuilder } from "#mystery-encounters/mystery-encounter-option";
import { trainerConfigs } from "#trainers/trainer-config";
import { TrainerPartyCompoundTemplate, TrainerPartyTemplate } from "#trainers/trainer-party-template";
-import type { OptionSelectConfig } from "#ui/abstract-option-select-ui-handler";
+import type { OptionSelectConfig } from "#ui/handlers/abstract-option-select-ui-handler";
import { randSeedInt, randSeedShuffle } from "#utils/common";
import { getPokemonSpecies } from "#utils/pokemon-utils";
import i18next from "i18next";
@@ -163,7 +163,7 @@ export const ClowningAroundEncounter: MysteryEncounter = MysteryEncounterBuilder
// Blacephalon has the random ability from pool, and 2 entirely random types to fit with the theme of the encounter
species: getPokemonSpecies(SpeciesId.BLACEPHALON),
customPokemonData: new CustomPokemonData({
- ability: ability,
+ ability,
types: [firstType, secondType],
}),
isBoss: true,
diff --git a/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts b/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts
index e2c330a1106..598f9d496a2 100644
--- a/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts
+++ b/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts
@@ -37,7 +37,7 @@ import { MysteryEncounterOptionBuilder } from "#mystery-encounters/mystery-encou
import { MoveRequirement } from "#mystery-encounters/mystery-encounter-requirements";
import { DANCING_MOVES } from "#mystery-encounters/requirement-groups";
import { PokemonData } from "#system/pokemon-data";
-import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
+import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler";
import { getPokemonSpecies } from "#utils/pokemon-utils";
import i18next from "i18next";
@@ -168,7 +168,7 @@ export const DancingLessonsEncounter: MysteryEncounter = MysteryEncounterBuilder
const config: EnemyPartyConfig = {
pokemonConfigs: [
{
- species: species,
+ species,
dataSource: oricorioData,
isBoss: true,
// Gets +1 to all stats except SPD on battle start
diff --git a/src/data/mystery-encounters/encounters/delibirdy-encounter.ts b/src/data/mystery-encounters/encounters/delibirdy-encounter.ts
index 8cd4c8bee66..79cccd91b26 100644
--- a/src/data/mystery-encounters/encounters/delibirdy-encounter.ts
+++ b/src/data/mystery-encounters/encounters/delibirdy-encounter.ts
@@ -33,7 +33,7 @@ import {
MoneyRequirement,
} from "#mystery-encounters/mystery-encounter-requirements";
import i18next from "#plugins/i18n";
-import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
+import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler";
import { randSeedItem } from "#utils/common";
import { getPokemonSpecies } from "#utils/pokemon-utils";
diff --git a/src/data/mystery-encounters/encounters/field-trip-encounter.ts b/src/data/mystery-encounters/encounters/field-trip-encounter.ts
index 67a7cad3466..30c4026fcad 100644
--- a/src/data/mystery-encounters/encounters/field-trip-encounter.ts
+++ b/src/data/mystery-encounters/encounters/field-trip-encounter.ts
@@ -18,7 +18,7 @@ import {
import type { MysteryEncounter } from "#mystery-encounters/mystery-encounter";
import { MysteryEncounterBuilder } from "#mystery-encounters/mystery-encounter";
import { MysteryEncounterOptionBuilder } from "#mystery-encounters/mystery-encounter-option";
-import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
+import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler";
import i18next from "i18next";
/** i18n namespace for the encounter */
@@ -249,6 +249,6 @@ function pokemonAndMoveChosen(pokemon: PlayerPokemon, move: PokemonMove, correct
setEncounterExp([pokemon.id], 100);
}
encounter.misc = {
- correctMove: correctMove,
+ correctMove,
};
}
diff --git a/src/data/mystery-encounters/encounters/fight-or-flight-encounter.ts b/src/data/mystery-encounters/encounters/fight-or-flight-encounter.ts
index f7dc89b44fd..a46bac013cc 100644
--- a/src/data/mystery-encounters/encounters/fight-or-flight-encounter.ts
+++ b/src/data/mystery-encounters/encounters/fight-or-flight-encounter.ts
@@ -63,7 +63,7 @@ export const FightOrFlightEncounter: MysteryEncounter = MysteryEncounterBuilder.
const config: EnemyPartyConfig = {
pokemonConfigs: [
{
- level: level,
+ level,
species: bossPokemon.species,
dataSource: new PokemonData(bossPokemon),
isBoss: true,
@@ -120,8 +120,8 @@ export const FightOrFlightEncounter: MysteryEncounter = MysteryEncounterBuilder.
disableAnimation: true,
},
{
- spriteKey: spriteKey,
- fileRoot: fileRoot,
+ spriteKey,
+ fileRoot,
hasShadow: true,
tint: 0.25,
x: -5,
diff --git a/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts b/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts
index a8dafdaa848..7dbbe24fb69 100644
--- a/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts
+++ b/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts
@@ -42,7 +42,7 @@ import { MysteryEncounterOptionBuilder } from "#mystery-encounters/mystery-encou
import { PartySizeRequirement } from "#mystery-encounters/mystery-encounter-requirements";
import { PokemonData } from "#system/pokemon-data";
import { MusicPreference } from "#system/settings";
-import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
+import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler";
import { isNullOrUndefined, NumberHolder, randInt, randSeedInt, randSeedItem, randSeedShuffle } from "#utils/common";
import { getEnumKeys } from "#utils/enums";
import { getRandomLocaleEntry } from "#utils/i18n";
@@ -195,10 +195,10 @@ export const GlobalTradeSystemEncounter: MysteryEncounter = MysteryEncounterBuil
: ""
}`;
const line2 =
- i18next.t("pokemonInfoContainer:nature") +
- " " +
- getNatureName(tradePokemon.getNature()) +
- (formName ? ` | ${i18next.t("pokemonInfoContainer:form")} ${formName}` : "");
+ i18next.t("pokemonInfoContainer:nature")
+ + " "
+ + getNatureName(tradePokemon.getNature())
+ + (formName ? ` | ${i18next.t("pokemonInfoContainer:form")} ${formName}` : "");
showEncounterText(`${line1}\n${line2}`, 0, 0, false);
},
};
@@ -292,16 +292,14 @@ export const GlobalTradeSystemEncounter: MysteryEncounter = MysteryEncounterBuil
// Extra HA roll at base 1/64 odds (boosted by events and charms)
const hiddenIndex = tradePokemon.species.ability2 ? 2 : 1;
- if (tradePokemon.species.abilityHidden) {
- if (tradePokemon.abilityIndex < hiddenIndex) {
- const hiddenAbilityChance = new NumberHolder(64);
- globalScene.applyModifiers(HiddenAbilityRateBoosterModifier, true, hiddenAbilityChance);
+ if (tradePokemon.species.abilityHidden && tradePokemon.abilityIndex < hiddenIndex) {
+ const hiddenAbilityChance = new NumberHolder(64);
+ globalScene.applyModifiers(HiddenAbilityRateBoosterModifier, true, hiddenAbilityChance);
- const hasHiddenAbility = !randSeedInt(hiddenAbilityChance.value);
+ const hasHiddenAbility = !randSeedInt(hiddenAbilityChance.value);
- if (hasHiddenAbility) {
- tradePokemon.abilityIndex = hiddenIndex;
- }
+ if (hasHiddenAbility) {
+ tradePokemon.abilityIndex = hiddenIndex;
}
}
diff --git a/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts b/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts
index 6f15f150d8b..7db55010bef 100644
--- a/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts
+++ b/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts
@@ -50,7 +50,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = MysteryEncounter
const normalSpriteKey = normalConfig.getSpriteKey(female, normalConfig.doubleOnly);
encounter.enemyPartyConfigs.push({
trainerConfig: normalConfig,
- female: female,
+ female,
});
// Hard difficulty trainer is another random trainer, but with AVERAGE_BALANCED config
@@ -81,7 +81,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = MysteryEncounter
encounter.enemyPartyConfigs.push({
trainerConfig: hardConfig,
levelAdditiveModifier: 1,
- female: female,
+ female,
});
// Brutal trainer is pulled from pool of boss trainers (gym leaders) for the biome
@@ -101,7 +101,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = MysteryEncounter
encounter.enemyPartyConfigs.push({
trainerConfig: brutalConfig,
levelAdditiveModifier: 1.5,
- female: female,
+ female,
});
encounter.spriteConfigs = [
diff --git a/src/data/mystery-encounters/encounters/mysterious-chest-encounter.ts b/src/data/mystery-encounters/encounters/mysterious-chest-encounter.ts
index 1bc2404dc27..88d00f05ca8 100644
--- a/src/data/mystery-encounters/encounters/mysterious-chest-encounter.ts
+++ b/src/data/mystery-encounters/encounters/mysterious-chest-encounter.ts
@@ -163,8 +163,12 @@ export const MysteriousChestEncounter: MysteryEncounter = MysteryEncounterBuilde
queueEncounterMessage(`${namespace}:option.1.great`);
leaveEncounterWithoutBattle();
} else if (
- roll >=
- RAND_LENGTH - COMMON_REWARDS_PERCENT - ULTRA_REWARDS_PERCENT - ROGUE_REWARDS_PERCENT - MASTER_REWARDS_PERCENT
+ roll
+ >= RAND_LENGTH
+ - COMMON_REWARDS_PERCENT
+ - ULTRA_REWARDS_PERCENT
+ - ROGUE_REWARDS_PERCENT
+ - MASTER_REWARDS_PERCENT
) {
// Choose 1 MASTER tier item (5%)
setEncounterRewards({
diff --git a/src/data/mystery-encounters/encounters/shady-vitamin-dealer-encounter.ts b/src/data/mystery-encounters/encounters/shady-vitamin-dealer-encounter.ts
index bf232c616d5..fa65164ecfd 100644
--- a/src/data/mystery-encounters/encounters/shady-vitamin-dealer-encounter.ts
+++ b/src/data/mystery-encounters/encounters/shady-vitamin-dealer-encounter.ts
@@ -104,7 +104,7 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter = MysteryEncounterBui
encounter.setDialogueToken("boost2", modifiers[1].name);
encounter.misc = {
chosenPokemon: pokemon,
- modifiers: modifiers,
+ modifiers,
};
};
@@ -187,7 +187,7 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter = MysteryEncounterBui
encounter.setDialogueToken("boost2", modifiers[1].name);
encounter.misc = {
chosenPokemon: pokemon,
- modifiers: modifiers,
+ modifiers,
};
};
diff --git a/src/data/mystery-encounters/encounters/teleporting-hijinks-encounter.ts b/src/data/mystery-encounters/encounters/teleporting-hijinks-encounter.ts
index 58ab3f2ec2d..b280f827b5c 100644
--- a/src/data/mystery-encounters/encounters/teleporting-hijinks-encounter.ts
+++ b/src/data/mystery-encounters/encounters/teleporting-hijinks-encounter.ts
@@ -165,7 +165,7 @@ export const TeleportingHijinksEncounter: MysteryEncounter = MysteryEncounterBui
const config: EnemyPartyConfig = {
pokemonConfigs: [
{
- level: level,
+ level,
species: bossSpecies,
dataSource: new PokemonData(bossPokemon),
isBoss: true,
@@ -221,7 +221,7 @@ async function doBiomeTransitionDialogueAndBattleInit() {
const config: EnemyPartyConfig = {
pokemonConfigs: [
{
- level: level,
+ level,
species: bossSpecies,
dataSource: new PokemonData(bossPokemon),
isBoss: true,
diff --git a/src/data/mystery-encounters/encounters/the-pokemon-salesman-encounter.ts b/src/data/mystery-encounters/encounters/the-pokemon-salesman-encounter.ts
index 99f6e671052..292c866c0ee 100644
--- a/src/data/mystery-encounters/encounters/the-pokemon-salesman-encounter.ts
+++ b/src/data/mystery-encounters/encounters/the-pokemon-salesman-encounter.ts
@@ -92,11 +92,11 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter = MysteryEncounterBui
.getEventEncounters()
.filter(
s =>
- !getPokemonSpecies(s.species).legendary &&
- !getPokemonSpecies(s.species).subLegendary &&
- !getPokemonSpecies(s.species).mythical &&
- !NON_LEGEND_PARADOX_POKEMON.includes(s.species) &&
- !NON_LEGEND_ULTRA_BEASTS.includes(s.species),
+ !getPokemonSpecies(s.species).legendary
+ && !getPokemonSpecies(s.species).subLegendary
+ && !getPokemonSpecies(s.species).mythical
+ && !NON_LEGEND_PARADOX_POKEMON.includes(s.species)
+ && !NON_LEGEND_ULTRA_BEASTS.includes(s.species),
);
let pokemon: PlayerPokemon;
@@ -109,16 +109,16 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter = MysteryEncounterBui
* Mons rolled from the event encounter pool get 3 extra shiny rolls
*/
if (
- r === 0 ||
- ((isNullOrUndefined(species.abilityHidden) || species.abilityHidden === AbilityId.NONE) &&
- validEventEncounters.length === 0)
+ r === 0
+ || ((isNullOrUndefined(species.abilityHidden) || species.abilityHidden === AbilityId.NONE)
+ && validEventEncounters.length === 0)
) {
// If you roll 1%, give shiny Magikarp with random variant
species = getPokemonSpecies(SpeciesId.MAGIKARP);
pokemon = new PlayerPokemon(species, 5, 2, undefined, undefined, true);
} else if (
- validEventEncounters.length > 0 &&
- (r <= EVENT_THRESHOLD || isNullOrUndefined(species.abilityHidden) || species.abilityHidden === AbilityId.NONE)
+ validEventEncounters.length > 0
+ && (r <= EVENT_THRESHOLD || isNullOrUndefined(species.abilityHidden) || species.abilityHidden === AbilityId.NONE)
) {
tries = 0;
do {
@@ -162,8 +162,8 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter = MysteryEncounterBui
const { spriteKey, fileRoot } = getSpriteKeysFromPokemon(pokemon);
encounter.spriteConfigs.push({
- spriteKey: spriteKey,
- fileRoot: fileRoot,
+ spriteKey,
+ fileRoot,
hasShadow: true,
repeat: true,
isPokemon: true,
@@ -185,8 +185,8 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter = MysteryEncounterBui
encounter.setDialogueToken("purchasePokemon", pokemon.getNameToRender());
encounter.setDialogueToken("price", price.toString());
encounter.misc = {
- price: price,
- pokemon: pokemon,
+ price,
+ pokemon,
};
pokemon.calculateStats();
diff --git a/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts b/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts
index 71fe961f053..fbdc1c8f714 100644
--- a/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts
+++ b/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts
@@ -212,9 +212,9 @@ function endTrainerBattleAndShowDialogue(): Promise {
// Only trigger form change when Eiscue is in Noice form
// Hardcoded Eiscue for now in case it is fused with another pokemon
if (
- pokemon.species.speciesId === SpeciesId.EISCUE &&
- pokemon.hasAbility(AbilityId.ICE_FACE) &&
- pokemon.formIndex === 1
+ pokemon.species.speciesId === SpeciesId.EISCUE
+ && pokemon.hasAbility(AbilityId.ICE_FACE)
+ && pokemon.formIndex === 1
) {
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeAbilityTrigger);
}
diff --git a/src/data/mystery-encounters/encounters/training-session-encounter.ts b/src/data/mystery-encounters/encounters/training-session-encounter.ts
index 02e7a5c5575..796840c431f 100644
--- a/src/data/mystery-encounters/encounters/training-session-encounter.ts
+++ b/src/data/mystery-encounters/encounters/training-session-encounter.ts
@@ -27,7 +27,7 @@ import { MysteryEncounterBuilder } from "#mystery-encounters/mystery-encounter";
import { MysteryEncounterOptionBuilder } from "#mystery-encounters/mystery-encounter-option";
import { PokemonData } from "#system/pokemon-data";
import type { HeldModifierConfig } from "#types/held-modifier-config";
-import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
+import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler";
import { isNullOrUndefined, randSeedShuffle } from "#utils/common";
import { getEnumValues } from "#utils/enums";
import i18next from "i18next";
@@ -113,7 +113,7 @@ export const TrainingSessionEncounter: MysteryEncounter = MysteryEncounterBuilde
let ivIndexes: any[] = [];
playerPokemon.ivs.forEach((iv, index) => {
if (iv < 31) {
- ivIndexes.push({ iv: iv, index: index });
+ ivIndexes.push({ iv, index });
}
});
@@ -324,9 +324,9 @@ export const TrainingSessionEncounter: MysteryEncounter = MysteryEncounterBuilde
// Only update the fusion's dex data if the Pokemon is already caught in dex (ignore rentals)
const rootFusionSpecies = playerPokemon.fusionSpecies?.getRootSpeciesId();
if (
- !isNullOrUndefined(rootFusionSpecies) &&
- speciesStarterCosts.hasOwnProperty(rootFusionSpecies) &&
- !!globalScene.gameData.dexData[rootFusionSpecies].caughtAttr
+ !isNullOrUndefined(rootFusionSpecies)
+ && speciesStarterCosts.hasOwnProperty(rootFusionSpecies)
+ && !!globalScene.gameData.dexData[rootFusionSpecies].caughtAttr
) {
globalScene.gameData.starterData[rootFusionSpecies].abilityAttr |=
playerPokemon.fusionAbilityIndex !== 1 || playerPokemon.fusionSpecies?.ability2
@@ -396,7 +396,7 @@ function getEnemyConfig(playerPokemon: PlayerPokemon, segments: number, modifier
formIndex: playerPokemon.formIndex,
level: playerPokemon.level,
dataSource: data,
- modifierConfigs: modifierConfigs,
+ modifierConfigs,
},
],
};
diff --git a/src/data/mystery-encounters/encounters/uncommon-breed-encounter.ts b/src/data/mystery-encounters/encounters/uncommon-breed-encounter.ts
index 6aeff852de7..7bbc4a57757 100644
--- a/src/data/mystery-encounters/encounters/uncommon-breed-encounter.ts
+++ b/src/data/mystery-encounters/encounters/uncommon-breed-encounter.ts
@@ -71,7 +71,7 @@ export const UncommonBreedEncounter: MysteryEncounter = MysteryEncounterBuilder.
const randomEggMove: MoveId = eggMoves[eggMoveIndex];
encounter.misc = {
eggMove: randomEggMove,
- pokemon: pokemon,
+ pokemon,
};
if (pokemon.moveset.length < 4) {
pokemon.moveset.push(new PokemonMove(randomEggMove));
@@ -91,7 +91,7 @@ export const UncommonBreedEncounter: MysteryEncounter = MysteryEncounterBuilder.
const config: EnemyPartyConfig = {
pokemonConfigs: [
{
- level: level,
+ level,
species: pokemon.species,
dataSource: new PokemonData(pokemon),
isBoss: false,
@@ -114,8 +114,8 @@ export const UncommonBreedEncounter: MysteryEncounter = MysteryEncounterBuilder.
const { spriteKey, fileRoot } = getSpriteKeysFromPokemon(pokemon);
encounter.spriteConfigs = [
{
- spriteKey: spriteKey,
- fileRoot: fileRoot,
+ spriteKey,
+ fileRoot,
hasShadow: true,
x: -5,
repeat: true,
diff --git a/src/data/mystery-encounters/encounters/weird-dream-encounter.ts b/src/data/mystery-encounters/encounters/weird-dream-encounter.ts
index 240a0df9e95..1fcbd2961d1 100644
--- a/src/data/mystery-encounters/encounters/weird-dream-encounter.ts
+++ b/src/data/mystery-encounters/encounters/weird-dream-encounter.ts
@@ -285,7 +285,7 @@ export const WeirdDreamEncounter: MysteryEncounter = MysteryEncounterBuilder.wit
species: transformation.newSpecies,
isBoss: newPokemon.getSpeciesForm().getBaseStatTotal() > NON_LEGENDARY_BST_THRESHOLD,
level: previousPokemon.level,
- dataSource: dataSource,
+ dataSource,
modifierConfigs: newPokemonHeldItemConfigs,
};
@@ -299,7 +299,7 @@ export const WeirdDreamEncounter: MysteryEncounter = MysteryEncounterBuilder.wit
].clone();
trainerConfig.setPartyTemplates(new TrainerPartyTemplate(transformations.length, PartyMemberStrength.STRONG));
const enemyPartyConfig: EnemyPartyConfig = {
- trainerConfig: trainerConfig,
+ trainerConfig,
pokemonConfigs: enemyPokemonConfigs,
female: genderIndex === PlayerGender.FEMALE,
};
@@ -541,12 +541,12 @@ async function postProcessTransformedPokemon(
// For pokemon at/below 570 BST or any shiny pokemon, unlock it permanently as if you had caught it
if (
- !forBattle &&
- (newPokemon.getSpeciesForm().getBaseStatTotal() <= NON_LEGENDARY_BST_THRESHOLD || newPokemon.isShiny())
+ !forBattle
+ && (newPokemon.getSpeciesForm().getBaseStatTotal() <= NON_LEGENDARY_BST_THRESHOLD || newPokemon.isShiny())
) {
if (
- newPokemon.getSpeciesForm().abilityHidden &&
- newPokemon.abilityIndex === newPokemon.getSpeciesForm().getAbilityCount() - 1
+ newPokemon.getSpeciesForm().abilityHidden
+ && newPokemon.abilityIndex === newPokemon.getSpeciesForm().getAbilityCount() - 1
) {
globalScene.validateAchv(achvs.HIDDEN_ABILITY);
}
@@ -644,10 +644,10 @@ function getTransformedSpecies(
const bstInRange = speciesBst >= bstMin && speciesBst <= bstCap;
// Checks that a Pokemon has not already been added in the +600 or 570-600 slots;
const validBst =
- (!hasPokemonBstBetween570And600 ||
- speciesBst < NON_LEGENDARY_BST_THRESHOLD ||
- speciesBst > SUPER_LEGENDARY_BST_THRESHOLD) &&
- (!hasPokemonBstHigherThan600 || speciesBst <= SUPER_LEGENDARY_BST_THRESHOLD);
+ (!hasPokemonBstBetween570And600
+ || speciesBst < NON_LEGENDARY_BST_THRESHOLD
+ || speciesBst > SUPER_LEGENDARY_BST_THRESHOLD)
+ && (!hasPokemonBstHigherThan600 || speciesBst <= SUPER_LEGENDARY_BST_THRESHOLD);
return bstInRange && validBst && !EXCLUDED_TRANSFORMATION_SPECIES.includes(s.speciesId);
});
@@ -792,9 +792,9 @@ async function addEggMoveToNewPokemonMoveset(
// For pokemon that the player owns (including ones just caught), unlock the egg move
if (
- !forBattle &&
- !isNullOrUndefined(randomEggMoveIndex) &&
- !!globalScene.gameData.dexData[speciesRootForm].caughtAttr
+ !forBattle
+ && !isNullOrUndefined(randomEggMoveIndex)
+ && !!globalScene.gameData.dexData[speciesRootForm].caughtAttr
) {
await globalScene.gameData.setEggMoveUnlocked(getPokemonSpecies(speciesRootForm), randomEggMoveIndex, true);
}
diff --git a/src/data/mystery-encounters/mystery-encounter-option.ts b/src/data/mystery-encounters/mystery-encounter-option.ts
index 6ab2f8dae00..fc7bb15d343 100644
--- a/src/data/mystery-encounters/mystery-encounter-option.ts
+++ b/src/data/mystery-encounters/mystery-encounter-option.ts
@@ -76,9 +76,9 @@ export class MysteryEncounterOption implements IMysteryEncounterOption {
*/
hasRequirements(): boolean {
return (
- this.requirements.length > 0 ||
- this.primaryPokemonRequirements.length > 0 ||
- this.secondaryPokemonRequirements.length > 0
+ this.requirements.length > 0
+ || this.primaryPokemonRequirements.length > 0
+ || this.secondaryPokemonRequirements.length > 0
);
}
@@ -87,9 +87,9 @@ export class MysteryEncounterOption implements IMysteryEncounterOption {
*/
meetsRequirements(): boolean {
return (
- !this.requirements.some(requirement => !requirement.meetsRequirement()) &&
- this.meetsSupportingRequirementAndSupportingPokemonSelected() &&
- this.meetsPrimaryRequirementAndPrimaryPokemonSelected()
+ !this.requirements.some(requirement => !requirement.meetsRequirement())
+ && this.meetsSupportingRequirementAndSupportingPokemonSelected()
+ && this.meetsPrimaryRequirementAndPrimaryPokemonSelected()
);
}
@@ -209,7 +209,7 @@ export class MysteryEncounterOptionBuilder implements Partial> {
- return Object.assign(this, { hasDexProgress: hasDexProgress });
+ return Object.assign(this, { hasDexProgress });
}
/**
@@ -220,7 +220,7 @@ export class MysteryEncounterOptionBuilder implements Partial> {
if (requirement instanceof EncounterPokemonRequirement) {
- Error("Incorrectly added pokemon requirement as scene requirement.");
+ new Error("Incorrectly added pokemon requirement as scene requirement.");
}
this.requirements.push(requirement);
@@ -240,7 +240,7 @@ export class MysteryEncounterOptionBuilder implements Partial> {
- return Object.assign(this, { onPreOptionPhase: onPreOptionPhase });
+ return Object.assign(this, { onPreOptionPhase });
}
/**
@@ -248,13 +248,13 @@ export class MysteryEncounterOptionBuilder implements Partial> {
- return Object.assign(this, { onOptionPhase: onOptionPhase });
+ return Object.assign(this, { onOptionPhase });
}
withPostOptionPhase(
onPostOptionPhase: OptionPhaseCallback,
): this & Required> {
- return Object.assign(this, { onPostOptionPhase: onPostOptionPhase });
+ return Object.assign(this, { onPostOptionPhase });
}
/**
@@ -265,7 +265,7 @@ export class MysteryEncounterOptionBuilder implements Partial> {
if (requirement instanceof EncounterSceneRequirement) {
- Error("Incorrectly added scene requirement as pokemon requirement.");
+ new Error("Incorrectly added scene requirement as pokemon requirement.");
}
this.primaryPokemonRequirements.push(requirement);
@@ -315,7 +315,7 @@ export class MysteryEncounterOptionBuilder implements Partial> {
if (requirement instanceof EncounterSceneRequirement) {
- Error("Incorrectly added scene requirement as pokemon requirement.");
+ new Error("Incorrectly added scene requirement as pokemon requirement.");
}
this.secondaryPokemonRequirements.push(requirement);
diff --git a/src/data/mystery-encounters/mystery-encounter-requirements.ts b/src/data/mystery-encounters/mystery-encounter-requirements.ts
index d71964db4b8..f20d513419e 100644
--- a/src/data/mystery-encounters/mystery-encounter-requirements.ts
+++ b/src/data/mystery-encounters/mystery-encounter-requirements.ts
@@ -222,8 +222,8 @@ export class WaveRangeRequirement extends EncounterSceneRequirement {
if (!isNullOrUndefined(this.waveRange) && this.waveRange[0] <= this.waveRange[1]) {
const waveIndex = globalScene.currentBattle.waveIndex;
if (
- (waveIndex >= 0 && this.waveRange[0] >= 0 && this.waveRange[0] > waveIndex) ||
- (this.waveRange[1] >= 0 && this.waveRange[1] < waveIndex)
+ (waveIndex >= 0 && this.waveRange[0] >= 0 && this.waveRange[0] > waveIndex)
+ || (this.waveRange[1] >= 0 && this.waveRange[1] < waveIndex)
) {
return false;
}
@@ -276,9 +276,9 @@ export class TimeOfDayRequirement extends EncounterSceneRequirement {
override meetsRequirement(): boolean {
const timeOfDay = globalScene.arena?.getTimeOfDay();
return !(
- !isNullOrUndefined(timeOfDay) &&
- this.requiredTimeOfDay?.length > 0 &&
- !this.requiredTimeOfDay.includes(timeOfDay)
+ !isNullOrUndefined(timeOfDay)
+ && this.requiredTimeOfDay?.length > 0
+ && !this.requiredTimeOfDay.includes(timeOfDay)
);
}
@@ -298,9 +298,9 @@ export class WeatherRequirement extends EncounterSceneRequirement {
override meetsRequirement(): boolean {
const currentWeather = globalScene.arena.weather?.weatherType;
return !(
- !isNullOrUndefined(currentWeather) &&
- this.requiredWeather?.length > 0 &&
- !this.requiredWeather.includes(currentWeather!)
+ !isNullOrUndefined(currentWeather)
+ && this.requiredWeather?.length > 0
+ && !this.requiredWeather.includes(currentWeather!)
);
}
@@ -336,8 +336,8 @@ export class PartySizeRequirement extends EncounterSceneRequirement {
? globalScene.getPokemonAllowedInBattle().length
: globalScene.getPlayerParty().length;
if (
- (partySize >= 0 && this.partySizeRange[0] >= 0 && this.partySizeRange[0] > partySize) ||
- (this.partySizeRange[1] >= 0 && this.partySizeRange[1] < partySize)
+ (partySize >= 0 && this.partySizeRange[0] >= 0 && this.partySizeRange[0] > partySize)
+ || (this.partySizeRange[1] >= 0 && this.partySizeRange[1] < partySize)
) {
return false;
}
@@ -572,15 +572,15 @@ export class MoveRequirement extends EncounterPokemonRequirement {
// get the Pokemon with at least one move in the required moves list
return partyPokemon.filter(
pokemon =>
- (!this.excludeDisallowedPokemon || pokemon.isAllowedInBattle()) &&
- pokemon.moveset.some(move => move.moveId && this.requiredMoves.includes(move.moveId)),
+ (!this.excludeDisallowedPokemon || pokemon.isAllowedInBattle())
+ && pokemon.moveset.some(move => move.moveId && this.requiredMoves.includes(move.moveId)),
);
}
// for an inverted query, we only want to get the pokemon that don't have ANY of the listed moves
return partyPokemon.filter(
pokemon =>
- (!this.excludeDisallowedPokemon || pokemon.isAllowedInBattle()) &&
- !pokemon.moveset.some(move => move.moveId && this.requiredMoves.includes(move.moveId)),
+ (!this.excludeDisallowedPokemon || pokemon.isAllowedInBattle())
+ && !pokemon.moveset.some(move => move.moveId && this.requiredMoves.includes(move.moveId)),
);
}
@@ -678,15 +678,15 @@ export class AbilityRequirement extends EncounterPokemonRequirement {
if (!this.invertQuery) {
return partyPokemon.filter(
pokemon =>
- (!this.excludeDisallowedPokemon || pokemon.isAllowedInBattle()) &&
- this.requiredAbilities.some(ability => pokemon.hasAbility(ability, false)),
+ (!this.excludeDisallowedPokemon || pokemon.isAllowedInBattle())
+ && this.requiredAbilities.some(ability => pokemon.hasAbility(ability, false)),
);
}
// for an inverted query, we only want to get the pokemon that don't have ANY of the listed abilities
return partyPokemon.filter(
pokemon =>
- (!this.excludeDisallowedPokemon || pokemon.isAllowedInBattle()) &&
- this.requiredAbilities.filter(ability => pokemon.hasAbility(ability, false)).length === 0,
+ (!this.excludeDisallowedPokemon || pokemon.isAllowedInBattle())
+ && this.requiredAbilities.filter(ability => pokemon.hasAbility(ability, false)).length === 0,
);
}
@@ -728,9 +728,9 @@ export class StatusEffectRequirement extends EncounterPokemonRequirement {
if (statusEffect === StatusEffect.NONE) {
// StatusEffect.NONE also checks for null or undefined status
return (
- isNullOrUndefined(pokemon.status) ||
- isNullOrUndefined(pokemon.status.effect) ||
- pokemon.status.effect === statusEffect
+ isNullOrUndefined(pokemon.status)
+ || isNullOrUndefined(pokemon.status.effect)
+ || pokemon.status.effect === statusEffect
);
}
return pokemon.status?.effect === statusEffect;
@@ -743,9 +743,9 @@ export class StatusEffectRequirement extends EncounterPokemonRequirement {
if (statusEffect === StatusEffect.NONE) {
// StatusEffect.NONE also checks for null or undefined status
return (
- isNullOrUndefined(pokemon.status) ||
- isNullOrUndefined(pokemon.status.effect) ||
- pokemon.status.effect === statusEffect
+ isNullOrUndefined(pokemon.status)
+ || isNullOrUndefined(pokemon.status.effect)
+ || pokemon.status.effect === statusEffect
);
}
return pokemon.status?.effect === statusEffect;
@@ -796,9 +796,8 @@ export class CanFormChangeWithItemRequirement extends EncounterPokemonRequiremen
filterByForm(pokemon, formChangeItem) {
return (
- pokemonFormChanges.hasOwnProperty(pokemon.species.speciesId) &&
- // Get all form changes for this species with an item trigger, including any compound triggers
- pokemonFormChanges[pokemon.species.speciesId]
+ pokemonFormChanges.hasOwnProperty(pokemon.species.speciesId) // Get all form changes for this species with an item trigger, including any compound triggers
+ && pokemonFormChanges[pokemon.species.speciesId]
.filter(fc => fc.trigger.hasTriggerType(SpeciesFormChangeItemTrigger))
// Returns true if any form changes match this item
.flatMap(fc => fc.findTrigger(SpeciesFormChangeItemTrigger) as SpeciesFormChangeItemTrigger)
@@ -870,8 +869,8 @@ export class HeldItemRequirement extends EncounterPokemonRequirement {
pokemon =>
pokemon.getHeldItems().filter(it => {
return (
- !this.requiredHeldItemModifiers.some(heldItem => it.constructor.name === heldItem) &&
- (!this.requireTransferable || it.isTransferable)
+ !this.requiredHeldItemModifiers.some(heldItem => it.constructor.name === heldItem)
+ && (!this.requireTransferable || it.isTransferable)
);
}).length > 0,
);
@@ -880,8 +879,8 @@ export class HeldItemRequirement extends EncounterPokemonRequirement {
override getDialogueToken(pokemon?: PlayerPokemon): [string, string] {
const requiredItems = pokemon?.getHeldItems().filter(it => {
return (
- this.requiredHeldItemModifiers.some(heldItem => it.constructor.name === heldItem) &&
- (!this.requireTransferable || it.isTransferable)
+ this.requiredHeldItemModifiers.some(heldItem => it.constructor.name === heldItem)
+ && (!this.requireTransferable || it.isTransferable)
);
});
if (requiredItems && requiredItems.length > 0) {
@@ -924,9 +923,9 @@ export class AttackTypeBoosterHeldItemTypeRequirement extends EncounterPokemonRe
this.requiredHeldItemTypes.some(heldItemType => {
return pokemon.getHeldItems().some(it => {
return (
- it instanceof AttackTypeBoosterModifier &&
- (it.type as AttackTypeBoosterModifierType).moveType === heldItemType &&
- (!this.requireTransferable || it.isTransferable)
+ it instanceof AttackTypeBoosterModifier
+ && (it.type as AttackTypeBoosterModifierType).moveType === heldItemType
+ && (!this.requireTransferable || it.isTransferable)
);
});
}),
@@ -939,9 +938,9 @@ export class AttackTypeBoosterHeldItemTypeRequirement extends EncounterPokemonRe
pokemon.getHeldItems().filter(it => {
return !this.requiredHeldItemTypes.some(
heldItemType =>
- it instanceof AttackTypeBoosterModifier &&
- (it.type as AttackTypeBoosterModifierType).moveType === heldItemType &&
- (!this.requireTransferable || it.isTransferable),
+ it instanceof AttackTypeBoosterModifier
+ && (it.type as AttackTypeBoosterModifierType).moveType === heldItemType
+ && (!this.requireTransferable || it.isTransferable),
);
}).length > 0,
);
@@ -952,10 +951,10 @@ export class AttackTypeBoosterHeldItemTypeRequirement extends EncounterPokemonRe
return (
this.requiredHeldItemTypes.some(
heldItemType =>
- it instanceof AttackTypeBoosterModifier &&
- (it.type as AttackTypeBoosterModifierType).moveType === heldItemType,
- ) &&
- (!this.requireTransferable || it.isTransferable)
+ it instanceof AttackTypeBoosterModifier
+ && (it.type as AttackTypeBoosterModifierType).moveType === heldItemType,
+ )
+ && (!this.requireTransferable || it.isTransferable)
);
});
if (requiredItems && requiredItems.length > 0) {
@@ -1021,8 +1020,8 @@ export class FriendshipRequirement extends EncounterPokemonRequirement {
override meetsRequirement(): boolean {
// Party Pokemon inside required friendship range
if (
- !isNullOrUndefined(this.requiredFriendshipRange) &&
- this.requiredFriendshipRange[0] <= this.requiredFriendshipRange[1]
+ !isNullOrUndefined(this.requiredFriendshipRange)
+ && this.requiredFriendshipRange[0] <= this.requiredFriendshipRange[1]
) {
const partyPokemon = globalScene.getPlayerParty();
const pokemonInRange = this.queryParty(partyPokemon);
@@ -1037,8 +1036,8 @@ export class FriendshipRequirement extends EncounterPokemonRequirement {
if (!this.invertQuery) {
return partyPokemon.filter(
pokemon =>
- pokemon.friendship >= this.requiredFriendshipRange[0] &&
- pokemon.friendship <= this.requiredFriendshipRange[1],
+ pokemon.friendship >= this.requiredFriendshipRange[0]
+ && pokemon.friendship <= this.requiredFriendshipRange[1],
);
}
// for an inverted query, we only want to get the pokemon that don't have ANY of the listed requiredFriendshipRanges
diff --git a/src/data/mystery-encounters/mystery-encounter.ts b/src/data/mystery-encounters/mystery-encounter.ts
index 580fdc2ca38..ea621238121 100644
--- a/src/data/mystery-encounters/mystery-encounter.ts
+++ b/src/data/mystery-encounters/mystery-encounter.ts
@@ -658,7 +658,7 @@ export class MysteryEncounterBuilder implements Partial {
withIntroSpriteConfigs(
spriteConfigs: MysteryEncounterSpriteConfig[],
): this & Pick {
- return Object.assign(this, { spriteConfigs: spriteConfigs });
+ return Object.assign(this, { spriteConfigs });
}
withIntroDialogue(dialogue: MysteryEncounterDialogue["intro"] = []): this {
@@ -703,7 +703,7 @@ export class MysteryEncounterBuilder implements Partial {
* @returns
*/
withEncounterTier(encounterTier: MysteryEncounterTier): this & Pick {
- return Object.assign(this, { encounterTier: encounterTier });
+ return Object.assign(this, { encounterTier });
}
/**
@@ -753,7 +753,7 @@ export class MysteryEncounterBuilder implements Partial {
withContinuousEncounter(
continuousEncounter: boolean,
): this & Required> {
- return Object.assign(this, { continuousEncounter: continuousEncounter });
+ return Object.assign(this, { continuousEncounter });
}
/**
@@ -807,7 +807,7 @@ export class MysteryEncounterBuilder implements Partial {
withMaxAllowedEncounters(
maxAllowedEncounters: number,
): this & Required> {
- return Object.assign(this, { maxAllowedEncounters: maxAllowedEncounters });
+ return Object.assign(this, { maxAllowedEncounters });
}
/**
@@ -821,7 +821,7 @@ export class MysteryEncounterBuilder implements Partial {
requirement: EncounterSceneRequirement,
): this & Required> {
if (requirement instanceof EncounterPokemonRequirement) {
- Error("Incorrectly added pokemon requirement as scene requirement.");
+ new Error("Incorrectly added pokemon requirement as scene requirement.");
}
this.requirements.push(requirement);
return this;
@@ -864,7 +864,7 @@ export class MysteryEncounterBuilder implements Partial {
requirement: EncounterPokemonRequirement,
): this & Required> {
if (requirement instanceof EncounterSceneRequirement) {
- Error("Incorrectly added scene requirement as pokemon requirement.");
+ new Error("Incorrectly added scene requirement as pokemon requirement.");
}
this.primaryPokemonRequirements.push(requirement);
@@ -917,7 +917,7 @@ export class MysteryEncounterBuilder implements Partial {
excludePrimaryFromSecondaryRequirements = false,
): this & Required> {
if (requirement instanceof EncounterSceneRequirement) {
- Error("Incorrectly added scene requirement as pokemon requirement.");
+ new Error("Incorrectly added scene requirement as pokemon requirement.");
}
this.secondaryPokemonRequirements.push(requirement);
@@ -939,7 +939,7 @@ export class MysteryEncounterBuilder implements Partial {
* @returns
*/
withRewards(doEncounterRewards: () => boolean): this & Required> {
- return Object.assign(this, { doEncounterRewards: doEncounterRewards });
+ return Object.assign(this, { doEncounterRewards });
}
/**
@@ -953,7 +953,7 @@ export class MysteryEncounterBuilder implements Partial {
* @returns
*/
withExp(doEncounterExp: () => boolean): this & Required> {
- return Object.assign(this, { doEncounterExp: doEncounterExp });
+ return Object.assign(this, { doEncounterExp });
}
/**
@@ -974,7 +974,7 @@ export class MysteryEncounterBuilder implements Partial {
* @returns
*/
withOnVisualsStart(onVisualsStart: () => boolean): this & Required> {
- return Object.assign(this, { onVisualsStart: onVisualsStart });
+ return Object.assign(this, { onVisualsStart });
}
/**
@@ -984,7 +984,7 @@ export class MysteryEncounterBuilder implements Partial {
* @returns
*/
withCatchAllowed(catchAllowed: boolean): this & Required> {
- return Object.assign(this, { catchAllowed: catchAllowed });
+ return Object.assign(this, { catchAllowed });
}
/**
@@ -1004,7 +1004,7 @@ export class MysteryEncounterBuilder implements Partial {
hideBattleIntroMessage: boolean,
): this & Required> {
return Object.assign(this, {
- hideBattleIntroMessage: hideBattleIntroMessage,
+ hideBattleIntroMessage,
});
}
@@ -1015,7 +1015,7 @@ export class MysteryEncounterBuilder implements Partial {
withAutoHideIntroVisuals(
autoHideIntroVisuals: boolean,
): this & Required> {
- return Object.assign(this, { autoHideIntroVisuals: autoHideIntroVisuals });
+ return Object.assign(this, { autoHideIntroVisuals });
}
/**
@@ -1027,7 +1027,7 @@ export class MysteryEncounterBuilder implements Partial {
enterIntroVisualsFromRight: boolean,
): this & Required> {
return Object.assign(this, {
- enterIntroVisualsFromRight: enterIntroVisualsFromRight,
+ enterIntroVisualsFromRight,
});
}
diff --git a/src/data/mystery-encounters/utils/encounter-phase-utils.ts b/src/data/mystery-encounters/utils/encounter-phase-utils.ts
index 5c976cbc8cd..fdc92994e66 100644
--- a/src/data/mystery-encounters/utils/encounter-phase-utils.ts
+++ b/src/data/mystery-encounters/utils/encounter-phase-utils.ts
@@ -46,9 +46,9 @@ import type { PokemonData } from "#system/pokemon-data";
import type { TrainerConfig } from "#trainers/trainer-config";
import { trainerConfigs } from "#trainers/trainer-config";
import type { HeldModifierConfig } from "#types/held-modifier-config";
-import type { OptionSelectConfig, OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
-import type { PartyOption, PokemonSelectFilter } from "#ui/party-ui-handler";
-import { PartyUiMode } from "#ui/party-ui-handler";
+import type { OptionSelectConfig, OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler";
+import type { PartyOption, PokemonSelectFilter } from "#ui/handlers/party-ui-handler";
+import { PartyUiMode } from "#ui/handlers/party-ui-handler";
import { coerceArray, isNullOrUndefined, randomString, randSeedInt, randSeedItem } from "#utils/common";
import { getPokemonSpecies } from "#utils/pokemon-utils";
import i18next from "i18next";
@@ -193,7 +193,7 @@ export async function initBattleWithEnemyConfig(partyConfig: EnemyPartyConfig):
// This can be amplified or counteracted by setting levelAdditiveModifier in config
// levelAdditiveModifier value of 0.5 will halve the modifier scaling, 2 will double it, etc.
// Leaving null/undefined will disable level scaling
- const mult: number = !isNullOrUndefined(partyConfig.levelAdditiveModifier) ? partyConfig.levelAdditiveModifier : 0;
+ const mult = partyConfig.levelAdditiveModifier ?? 0;
const additive = Math.max(Math.round((globalScene.currentBattle.waveIndex / 10) * mult), 0);
battle.enemyLevels = battle.enemyLevels.map(level => level + additive);
@@ -297,9 +297,9 @@ export async function initBattleWithEnemyConfig(partyConfig: EnemyPartyConfig):
// Set Boss
if (config.isBoss) {
- let segments = !isNullOrUndefined(config.bossSegments)
- ? config.bossSegments!
- : globalScene.getEncounterBossSegments(globalScene.currentBattle.waveIndex, level, enemySpecies, true);
+ let segments =
+ config.bossSegments
+ ?? globalScene.getEncounterBossSegments(globalScene.currentBattle.waveIndex, level, enemySpecies, true);
if (!isNullOrUndefined(config.bossSegmentModifier)) {
segments += config.bossSegmentModifier;
}
@@ -545,83 +545,74 @@ export function selectPokemonForOption(
UiMode.PARTY,
PartyUiMode.SELECT,
-1,
- (slotIndex: number, _option: PartyOption) => {
- if (slotIndex < globalScene.getPlayerParty().length) {
- globalScene.ui.setMode(modeToSetOnExit).then(() => {
- const pokemon = globalScene.getPlayerParty()[slotIndex];
- const secondaryOptions = onPokemonSelected(pokemon);
- if (!secondaryOptions) {
- globalScene.currentBattle.mysteryEncounter!.setDialogueToken(
- "selectedPokemon",
- pokemon.getNameToRender(),
- );
- resolve(true);
- return;
- }
-
- // There is a second option to choose after selecting the Pokemon
- globalScene.ui.setMode(UiMode.MESSAGE).then(() => {
- const displayOptions = () => {
- // Always appends a cancel option to bottom of options
- const fullOptions = secondaryOptions
- .map(option => {
- // Update handler to resolve promise
- const onSelect = option.handler;
- option.handler = () => {
- onSelect();
- globalScene.currentBattle.mysteryEncounter!.setDialogueToken(
- "selectedPokemon",
- pokemon.getNameToRender(),
- );
- resolve(true);
- return true;
- };
- return option;
- })
- .concat({
- label: i18next.t("menu:cancel"),
- handler: () => {
- globalScene.ui.clearText();
- globalScene.ui.setMode(modeToSetOnExit);
- resolve(false);
- return true;
- },
- onHover: () => {
- showEncounterText(i18next.t("mysteryEncounterMessages:cancelOption"), 0, 0, false);
- },
- });
-
- const config: OptionSelectConfig = {
- options: fullOptions,
- maxOptions: 7,
- yOffset: 0,
- supportHover: true,
- };
-
- // Do hover over the starting selection option
- if (fullOptions[0].onHover) {
- fullOptions[0].onHover();
- }
- globalScene.ui.setModeWithoutClear(UiMode.OPTION_SELECT, config, null, true);
- };
-
- const textPromptKey =
- globalScene.currentBattle.mysteryEncounter?.selectedOption?.dialogue?.secondOptionPrompt;
- if (!textPromptKey) {
- displayOptions();
- } else {
- showEncounterText(textPromptKey).then(() => displayOptions());
- }
- });
- });
- } else {
- globalScene.ui.setMode(modeToSetOnExit).then(() => {
- if (onPokemonNotSelected) {
- onPokemonNotSelected();
- }
- resolve(false);
- });
+ async (slotIndex: number, _option: PartyOption) => {
+ await globalScene.ui.setMode(modeToSetOnExit);
+ if (slotIndex >= globalScene.getPlayerParty().length) {
+ onPokemonNotSelected?.();
+ resolve(false);
+ return;
}
+
+ const pokemon = globalScene.getPlayerParty()[slotIndex];
+ const secondaryOptions = onPokemonSelected(pokemon);
+ if (!secondaryOptions) {
+ globalScene.currentBattle.mysteryEncounter!.setDialogueToken("selectedPokemon", pokemon.getNameToRender());
+ resolve(true);
+ return;
+ }
+
+ // There is a second option to choose after selecting the Pokemon
+ await globalScene.ui.setMode(UiMode.MESSAGE);
+ // TODO: fix this
+ const displayOptions = () => {
+ // Always appends a cancel option to bottom of options
+ const fullOptions = secondaryOptions
+ .map(option => {
+ // Update handler to resolve promise
+ const onSelect = option.handler;
+ option.handler = () => {
+ onSelect();
+ globalScene.currentBattle.mysteryEncounter!.setDialogueToken(
+ "selectedPokemon",
+ pokemon.getNameToRender(),
+ );
+ resolve(true);
+ return true;
+ };
+ return option;
+ })
+ .concat({
+ label: i18next.t("menu:cancel"),
+ handler: () => {
+ globalScene.ui.clearText();
+ globalScene.ui.setMode(modeToSetOnExit);
+ resolve(false);
+ return true;
+ },
+ onHover: () => {
+ showEncounterText(i18next.t("mysteryEncounterMessages:cancelOption"), 0, 0, false);
+ },
+ });
+
+ const config: OptionSelectConfig = {
+ options: fullOptions,
+ maxOptions: 7,
+ yOffset: 0,
+ supportHover: true,
+ };
+
+ // Do hover over the starting selection option
+ if (fullOptions[0]?.onHover) {
+ fullOptions[0].onHover();
+ }
+ globalScene.ui.setModeWithoutClear(UiMode.OPTION_SELECT, config, null, true);
+ };
+
+ const textPromptKey = globalScene.currentBattle.mysteryEncounter?.selectedOption?.dialogue?.secondOptionPrompt;
+ if (textPromptKey) {
+ await showEncounterText(textPromptKey);
+ }
+ displayOptions();
},
selectablePokemonFilter,
);
@@ -651,24 +642,16 @@ export function selectOptionThenPokemon(
return new Promise(resolve => {
const modeToSetOnExit = globalScene.ui.getMode();
- const displayOptions = (config: OptionSelectConfig) => {
- globalScene.ui.setMode(UiMode.MESSAGE).then(() => {
- if (!optionSelectPromptKey) {
- // Do hover over the starting selection option
- if (fullOptions[0].onHover) {
- fullOptions[0].onHover();
- }
- globalScene.ui.setMode(UiMode.OPTION_SELECT, config);
- } else {
- showEncounterText(optionSelectPromptKey).then(() => {
- // Do hover over the starting selection option
- if (fullOptions[0].onHover) {
- fullOptions[0].onHover();
- }
- globalScene.ui.setMode(UiMode.OPTION_SELECT, config);
- });
- }
- });
+ const displayOptions = async (config: OptionSelectConfig) => {
+ await globalScene.ui.setMode(UiMode.MESSAGE);
+ if (optionSelectPromptKey) {
+ showEncounterText(optionSelectPromptKey);
+ }
+ // Do hover over the starting selection option
+ if (fullOptions[0]?.onHover) {
+ fullOptions[0].onHover();
+ }
+ globalScene.ui.setMode(UiMode.OPTION_SELECT, config);
};
const selectPokemonAfterOption = (selectedOptionIndex: number) => {
@@ -683,7 +666,7 @@ export function selectOptionThenPokemon(
globalScene.ui.setMode(modeToSetOnExit).then(() => {
const result: PokemonAndOptionSelected = {
selectedPokemonIndex: slotIndex,
- selectedOptionIndex: selectedOptionIndex,
+ selectedOptionIndex,
};
resolve(result);
});
@@ -965,10 +948,10 @@ export function transitionMysteryEncounterIntroVisuals(hide = true, destroy = tr
export function handleMysteryEncounterBattleStartEffects() {
const encounter = globalScene.currentBattle.mysteryEncounter;
if (
- globalScene.currentBattle.isBattleMysteryEncounter() &&
- encounter &&
- encounter.encounterMode !== MysteryEncounterMode.NO_BATTLE &&
- !encounter.startOfBattleEffectsComplete
+ globalScene.currentBattle.isBattleMysteryEncounter()
+ && encounter
+ && encounter.encounterMode !== MysteryEncounterMode.NO_BATTLE
+ && !encounter.startOfBattleEffectsComplete
) {
const effects = encounter.startOfBattleEffects;
effects.forEach(effect => {
@@ -1093,7 +1076,7 @@ export function calculateMEAggregateStats(baseSpawnWeight: number) {
.filter(b => {
return !Array.isArray(b) || !randSeedInt(b[1]);
})
- .map(b => (!Array.isArray(b) ? b : b[0]));
+ .map(b => (Array.isArray(b) ? b[0] : b));
}, i * 100);
if (biomes! && biomes.length > 0) {
const specialBiomes = biomes.filter(b => alwaysPickTheseBiomes.includes(b));
@@ -1107,12 +1090,10 @@ export function calculateMEAggregateStats(baseSpawnWeight: number) {
}
} else if (biomeLinks.hasOwnProperty(currentBiome)) {
currentBiome = biomeLinks[currentBiome] as BiomeId;
+ } else if (i % 50 === 0) {
+ currentBiome = BiomeId.END;
} else {
- if (!(i % 50)) {
- currentBiome = BiomeId.END;
- } else {
- currentBiome = globalScene.generateRandomBiome(i);
- }
+ currentBiome = globalScene.generateRandomBiome(i);
}
currentArena = globalScene.newArena(currentBiome);
diff --git a/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts b/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts
index 93ef59d6ee7..0d07300d00d 100644
--- a/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts
+++ b/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts
@@ -31,9 +31,9 @@ import {
showEncounterText,
} from "#mystery-encounters/encounter-dialogue-utils";
import { achvs } from "#system/achv";
-import type { PartyOption } from "#ui/party-ui-handler";
-import { PartyUiMode } from "#ui/party-ui-handler";
-import { SummaryUiMode } from "#ui/summary-ui-handler";
+import type { PartyOption } from "#ui/handlers/party-ui-handler";
+import { PartyUiMode } from "#ui/handlers/party-ui-handler";
+import { SummaryUiMode } from "#ui/handlers/summary-ui-handler";
import { applyChallenges } from "#utils/challenge-utils";
import { BooleanHolder, isNullOrUndefined, randSeedInt } from "#utils/common";
import { getPokemonSpecies } from "#utils/pokemon-utils";
@@ -265,11 +265,11 @@ export function getRandomSpeciesByStarterCost(
.filter(s => {
const pokemonSpecies = getPokemonSpecies(s[0]);
return (
- pokemonSpecies &&
- (!excludedSpecies || !excludedSpecies.includes(s[0])) &&
- (allowSubLegendary || !pokemonSpecies.subLegendary) &&
- (allowLegendary || !pokemonSpecies.legendary) &&
- (allowMythical || !pokemonSpecies.mythical)
+ pokemonSpecies
+ && (!excludedSpecies || !excludedSpecies.includes(s[0]))
+ && (allowSubLegendary || !pokemonSpecies.subLegendary)
+ && (allowLegendary || !pokemonSpecies.legendary)
+ && (allowMythical || !pokemonSpecies.mythical)
);
})
.map(s => [getPokemonSpecies(s[0]), s[1]]);
@@ -409,10 +409,10 @@ export async function applyModifierTypeToPlayerPokemon(
const modifier = modType.newModifier(pokemon);
const existing = globalScene.findModifier(
(m): m is PokemonHeldItemModifier =>
- m instanceof PokemonHeldItemModifier &&
- m.type.id === modType.id &&
- m.pokemonId === pokemon.id &&
- m.matchType(modifier),
+ m instanceof PokemonHeldItemModifier
+ && m.type.id === modType.id
+ && m.pokemonId === pokemon.id
+ && m.matchType(modifier),
) as PokemonHeldItemModifier | undefined;
// At max stacks
@@ -650,8 +650,8 @@ export async function catchPokemon(
const speciesForm = !pokemon.fusionSpecies ? pokemon.getSpeciesForm() : pokemon.getFusionSpeciesForm();
if (
- speciesForm.abilityHidden &&
- (pokemon.fusionSpecies ? pokemon.fusionAbilityIndex : pokemon.abilityIndex) === speciesForm.getAbilityCount() - 1
+ speciesForm.abilityHidden
+ && (pokemon.fusionSpecies ? pokemon.fusionAbilityIndex : pokemon.abilityIndex) === speciesForm.getAbilityCount() - 1
) {
globalScene.validateAchv(achvs.HIDDEN_ABILITY);
}
@@ -988,8 +988,8 @@ export async function addPokemonDataToDexAndValidateAchievements(pokemon: Player
const speciesForm = !pokemon.fusionSpecies ? pokemon.getSpeciesForm() : pokemon.getFusionSpeciesForm();
if (
- speciesForm.abilityHidden &&
- (pokemon.fusionSpecies ? pokemon.fusionAbilityIndex : pokemon.abilityIndex) === speciesForm.getAbilityCount() - 1
+ speciesForm.abilityHidden
+ && (pokemon.fusionSpecies ? pokemon.fusionAbilityIndex : pokemon.abilityIndex) === speciesForm.getAbilityCount() - 1
) {
globalScene.validateAchv(achvs.HIDDEN_ABILITY);
}
diff --git a/src/data/phase-priority-queue.ts b/src/data/phase-priority-queue.ts
index 012344d59f6..2c83348cc7b 100644
--- a/src/data/phase-priority-queue.ts
+++ b/src/data/phase-priority-queue.ts
@@ -86,8 +86,8 @@ export class PostSummonPhasePriorityQueue extends PhasePriorityQueue {
this.queue.sort((phaseA: PostSummonPhase, phaseB: PostSummonPhase) => {
if (phaseA.getPriority() === phaseB.getPriority()) {
return (
- (phaseB.getPokemon().getEffectiveStat(Stat.SPD) - phaseA.getPokemon().getEffectiveStat(Stat.SPD)) *
- (isTrickRoom() ? -1 : 1)
+ (phaseB.getPokemon().getEffectiveStat(Stat.SPD) - phaseA.getPokemon().getEffectiveStat(Stat.SPD))
+ * (isTrickRoom() ? -1 : 1)
);
}
diff --git a/src/data/pokemon-forms.ts b/src/data/pokemon-forms.ts
index 5a50713c5a9..7eb8ed263d5 100644
--- a/src/data/pokemon-forms.ts
+++ b/src/data/pokemon-forms.ts
@@ -58,7 +58,7 @@ export class SpeciesFormChange {
return false;
}
- if (!pokemon.species.forms.length) {
+ if (pokemon.species.forms.length === 0) {
return false;
}
diff --git a/src/data/pokemon-forms/form-change-triggers.ts b/src/data/pokemon-forms/form-change-triggers.ts
index 7c042b27058..9da3538741c 100644
--- a/src/data/pokemon-forms/form-change-triggers.ts
+++ b/src/data/pokemon-forms/form-change-triggers.ts
@@ -82,10 +82,10 @@ export class SpeciesFormChangeItemTrigger extends SpeciesFormChangeTrigger {
// Assume that if m has the `formChangeItem` property, then it is a PokemonFormChangeItemModifier
const m = r as PokemonFormChangeItemModifier;
return (
- "formChangeItem" in m &&
- m.pokemonId === pokemon.id &&
- m.formChangeItem === this.item &&
- m.active === this.active
+ "formChangeItem" in m
+ && m.pokemonId === pokemon.id
+ && m.formChangeItem === this.item
+ && m.active === this.active
);
});
}
@@ -155,7 +155,7 @@ export class SpeciesFormChangeMoveLearnedTrigger extends SpeciesFormChangeTrigge
}
canChange(pokemon: Pokemon): boolean {
- return !!pokemon.moveset.filter(m => m.moveId === this.move).length === this.known;
+ return pokemon.moveset.filter(m => m.moveId === this.move).length > 0 === this.known;
}
}
@@ -182,7 +182,7 @@ export class SpeciesFormChangePostMoveTrigger extends SpeciesFormChangeMoveTrigg
description = i18next.t("pokemonEvolutions:forms.postMove");
canChange(pokemon: Pokemon): boolean {
return (
- pokemon.summonData && !!pokemon.getLastXMoves(1).filter(m => this.movePredicate(m.move)).length === this.used
+ pokemon.summonData && pokemon.getLastXMoves(1).filter(m => this.movePredicate(m.move)).length > 0 === this.used
);
}
}
@@ -211,9 +211,10 @@ export class SpeciesDefaultFormMatchTrigger extends SpeciesFormChangeTrigger {
canChange(pokemon: Pokemon): boolean {
return (
- this.formKey ===
- pokemon.species.forms[globalScene.getSpeciesFormIndex(pokemon.species, pokemon.gender, pokemon.getNature(), true)]
- .formKey
+ this.formKey
+ === pokemon.species.forms[
+ globalScene.getSpeciesFormIndex(pokemon.species, pokemon.gender, pokemon.getNature(), true)
+ ].formKey
);
}
}
@@ -259,10 +260,10 @@ export class SpeciesFormChangeWeatherTrigger extends SpeciesFormChangeTrigger {
const isAbilitySuppressed = pokemon.summonData.abilitySuppressed;
return (
- !isAbilitySuppressed &&
- !isWeatherSuppressed &&
- pokemon.hasAbility(this.ability) &&
- this.weathers.includes(currentWeather)
+ !isAbilitySuppressed
+ && !isWeatherSuppressed
+ && pokemon.hasAbility(this.ability)
+ && this.weathers.includes(currentWeather)
);
}
}
diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts
index d5049569e61..f91d3aaf1f2 100644
--- a/src/data/pokemon-species.ts
+++ b/src/data/pokemon-species.ts
@@ -202,8 +202,8 @@ export abstract class PokemonSpeciesForm {
}
let starterSpeciesId = this.speciesId;
while (
- !(starterSpeciesId in starterPassiveAbilities) ||
- !(formIndex in starterPassiveAbilities[starterSpeciesId])
+ !(starterSpeciesId in starterPassiveAbilities)
+ || !(formIndex in starterPassiveAbilities[starterSpeciesId])
) {
if (pokemonPrevolutions.hasOwnProperty(starterSpeciesId)) {
starterSpeciesId = pokemonPrevolutions[starterSpeciesId];
@@ -221,8 +221,8 @@ export abstract class PokemonSpeciesForm {
getLevelMoves(): LevelMoves {
if (
- pokemonSpeciesFormLevelMoves.hasOwnProperty(this.speciesId) &&
- pokemonSpeciesFormLevelMoves[this.speciesId].hasOwnProperty(this.formIndex)
+ pokemonSpeciesFormLevelMoves.hasOwnProperty(this.speciesId)
+ && pokemonSpeciesFormLevelMoves[this.speciesId].hasOwnProperty(this.formIndex)
) {
return pokemonSpeciesFormLevelMoves[this.speciesId][this.formIndex].slice(0);
}
@@ -302,9 +302,9 @@ export abstract class PokemonSpeciesForm {
const formSpriteKey = this.getFormSpriteKey(formIndex);
const showGenderDiffs =
- this.genderDiffs &&
- female &&
- ![SpeciesFormKey.MEGA, SpeciesFormKey.GIGANTAMAX].includes(formSpriteKey as SpeciesFormKey);
+ this.genderDiffs
+ && female
+ && ![SpeciesFormKey.MEGA, SpeciesFormKey.GIGANTAMAX].includes(formSpriteKey as SpeciesFormKey);
return `${showGenderDiffs ? "female__" : ""}${this.speciesId}${formSpriteKey ? `-${formSpriteKey}` : ""}`;
}
@@ -425,7 +425,7 @@ export abstract class PokemonSpeciesForm {
}
let ret = speciesId.toString();
const forms = getPokemonSpecies(speciesId).forms;
- if (forms.length) {
+ if (forms.length > 0) {
if (formIndex !== undefined && formIndex >= forms.length) {
console.warn(
`Attempted accessing form with index ${formIndex} of species ${getPokemonSpecies(speciesId).getName()} with only ${forms.length || 0} forms`,
@@ -487,8 +487,8 @@ export abstract class PokemonSpeciesForm {
}
}
if (
- pokemonFormLevelMoves.hasOwnProperty(this.speciesId) &&
- pokemonFormLevelMoves[this.speciesId].hasOwnProperty(this.formIndex)
+ pokemonFormLevelMoves.hasOwnProperty(this.speciesId)
+ && pokemonFormLevelMoves[this.speciesId].hasOwnProperty(this.formIndex)
) {
if (!pokemonFormLevelMoves[this.speciesId][this.formIndex].find(lm => lm[0] <= 5 && lm[1] === moveId)) {
return false;
@@ -758,7 +758,7 @@ export class PokemonSpecies extends PokemonSpeciesForm implements Localizable {
}
getName(formIndex?: number): string {
- if (formIndex !== undefined && this.forms.length) {
+ if (formIndex !== undefined && this.forms.length > 0) {
const form = this.forms[formIndex];
let key: string | null;
switch (form.formKey) {
@@ -846,9 +846,9 @@ export class PokemonSpecies extends PokemonSpeciesForm implements Localizable {
? i18next.t(`battlePokemonForm:${toCamelCase(formKey)}`, { pokemonName: this.name })
: i18next.t(`pokemonForm:battleForm.${toCamelCase(formKey)}`);
} else if (
- region === Region.NORMAL ||
- (this.speciesId === SpeciesId.GALAR_DARMANITAN && formIndex > 0) ||
- this.speciesId === SpeciesId.PALDEA_TAUROS
+ region === Region.NORMAL
+ || (this.speciesId === SpeciesId.GALAR_DARMANITAN && formIndex > 0)
+ || this.speciesId === SpeciesId.PALDEA_TAUROS
) {
// More special cases can be added here
const i18key = `pokemonForm:${speciesName}${formText}`;
@@ -947,7 +947,7 @@ export class PokemonSpecies extends PokemonSpeciesForm implements Localizable {
): SpeciesId {
const prevolutionLevels = this.getPrevolutionLevels();
- if (prevolutionLevels.length) {
+ if (prevolutionLevels.length > 0) {
for (let pl = prevolutionLevels.length - 1; pl >= 0; pl--) {
const prevolutionLevel = prevolutionLevels[pl];
if (level < prevolutionLevel[1]) {
@@ -958,11 +958,11 @@ export class PokemonSpecies extends PokemonSpeciesForm implements Localizable {
if (
// If evolutions shouldn't happen, add more cases here :)
- !allowEvolving ||
- !pokemonEvolutions.hasOwnProperty(this.speciesId) ||
- (globalScene.currentBattle?.waveIndex === 20 &&
- globalScene.gameMode.isClassic &&
- globalScene.currentBattle.trainer)
+ !allowEvolving
+ || !pokemonEvolutions.hasOwnProperty(this.speciesId)
+ || (globalScene.currentBattle?.waveIndex === 20
+ && globalScene.gameMode.isClassic
+ && globalScene.currentBattle.trainer)
) {
return this.speciesId;
}
@@ -988,41 +988,39 @@ export class PokemonSpecies extends PokemonSpeciesForm implements Localizable {
if (!forTrainer && isRegionalEvolution) {
evolutionChance = 0;
- } else {
- if (ev.wildDelay === SpeciesWildEvolutionDelay.NONE) {
- if (strength === PartyMemberStrength.STRONGER) {
- evolutionChance = 1;
- } else {
- const maxLevelDiff = this.getStrengthLevelDiff(strength); //The maximum distance from the evolution level tolerated for the mon to not evolve
- const minChance: number = 0.875 - 0.125 * strength;
-
- evolutionChance = Math.min(
- minChance + easeInFunc(Math.min(level - ev.level, maxLevelDiff) / maxLevelDiff) * (1 - minChance),
- 1,
- );
- }
+ } else if (ev.wildDelay === SpeciesWildEvolutionDelay.NONE) {
+ if (strength === PartyMemberStrength.STRONGER) {
+ evolutionChance = 1;
} else {
- const preferredMinLevel = Math.max(ev.level - 1 + ev.wildDelay! * this.getStrengthLevelDiff(strength), 1); // TODO: is the bang correct?
- let evolutionLevel = Math.max(ev.level > 1 ? ev.level : Math.floor(preferredMinLevel / 2), 1);
-
- if (ev.level <= 1 && pokemonPrevolutions.hasOwnProperty(this.speciesId)) {
- const prevolutionLevel = pokemonEvolutions[pokemonPrevolutions[this.speciesId]].find(
- ev => ev.speciesId === this.speciesId,
- )!.level; // TODO: is the bang correct?
- if (prevolutionLevel > 1) {
- evolutionLevel = prevolutionLevel;
- }
- }
+ const maxLevelDiff = this.getStrengthLevelDiff(strength); //The maximum distance from the evolution level tolerated for the mon to not evolve
+ const minChance: number = 0.875 - 0.125 * strength;
evolutionChance = Math.min(
- 0.65 * easeInFunc(Math.min(Math.max(level - evolutionLevel, 0), preferredMinLevel) / preferredMinLevel) +
- 0.35 *
- easeOutFunc(
- Math.min(Math.max(level - evolutionLevel, 0), preferredMinLevel * 2.5) / (preferredMinLevel * 2.5),
- ),
+ minChance + easeInFunc(Math.min(level - ev.level, maxLevelDiff) / maxLevelDiff) * (1 - minChance),
1,
);
}
+ } else {
+ const preferredMinLevel = Math.max(ev.level - 1 + ev.wildDelay! * this.getStrengthLevelDiff(strength), 1); // TODO: is the bang correct?
+ let evolutionLevel = Math.max(ev.level > 1 ? ev.level : Math.floor(preferredMinLevel / 2), 1);
+
+ if (ev.level <= 1 && pokemonPrevolutions.hasOwnProperty(this.speciesId)) {
+ const prevolutionLevel = pokemonEvolutions[pokemonPrevolutions[this.speciesId]].find(
+ ev => ev.speciesId === this.speciesId,
+ )!.level; // TODO: is the bang correct?
+ if (prevolutionLevel > 1) {
+ evolutionLevel = prevolutionLevel;
+ }
+ }
+
+ evolutionChance = Math.min(
+ 0.65 * easeInFunc(Math.min(Math.max(level - evolutionLevel, 0), preferredMinLevel) / preferredMinLevel)
+ + 0.35
+ * easeOutFunc(
+ Math.min(Math.max(level - evolutionLevel, 0), preferredMinLevel * 2.5) / (preferredMinLevel * 2.5),
+ ),
+ 1,
+ );
}
//TODO: Adjust templates and delays so we don't have to hardcode it
@@ -1097,9 +1095,9 @@ export class PokemonSpecies extends PokemonSpeciesForm implements Localizable {
for (const p of allEvolvingPokemon) {
for (const e of pokemonEvolutions[p]) {
if (
- e.speciesId === this.speciesId &&
- (!this.forms.length || !e.evoFormKey || e.evoFormKey === this.forms[this.formIndex].formKey) &&
- prevolutionLevels.every(pe => pe[0] !== Number.parseInt(p))
+ e.speciesId === this.speciesId
+ && (this.forms.length === 0 || !e.evoFormKey || e.evoFormKey === this.forms[this.formIndex].formKey)
+ && prevolutionLevels.every(pe => pe[0] !== Number.parseInt(p))
) {
const speciesId = Number.parseInt(p) as SpeciesId;
const level = e.level;
@@ -1135,9 +1133,9 @@ export class PokemonSpecies extends PokemonSpeciesForm implements Localizable {
prevolutionLevels[l][0],
Math.min(
Math.max(
- evolution?.level! +
- Math.round(randSeedGauss(0.5, 1 + levelDiff * 0.2) * Math.max(evolution?.wildDelay!, 0.5) * 5) -
- 1,
+ evolution?.level!
+ + Math.round(randSeedGauss(0.5, 1 + levelDiff * 0.2) * Math.max(evolution?.wildDelay!, 0.5) * 5)
+ - 1,
2,
evolution?.level!,
),
@@ -1146,15 +1144,13 @@ export class PokemonSpecies extends PokemonSpeciesForm implements Localizable {
]); // TODO: are those bangs correct?
}
const lastPrevolutionLevel = ret[prevolutionLevels.length - 1][1];
- const evolution = pokemonEvolutions[prevolutionLevels[prevolutionLevels.length - 1][0]].find(
- e => e.speciesId === this.speciesId,
- );
+ const evolution = pokemonEvolutions[prevolutionLevels.at(-1)![0]].find(e => e.speciesId === this.speciesId);
ret.push([
this.speciesId,
Math.min(
Math.max(
- lastPrevolutionLevel +
- Math.round(randSeedGauss(0.5, 1 + levelDiff * 0.2) * Math.max(evolution?.wildDelay!, 0.5) * 5),
+ lastPrevolutionLevel
+ + Math.round(randSeedGauss(0.5, 1 + levelDiff * 0.2) * Math.max(evolution?.wildDelay!, 0.5) * 5),
lastPrevolutionLevel + 1,
evolution?.level!,
),
@@ -1176,16 +1172,16 @@ export class PokemonSpecies extends PokemonSpeciesForm implements Localizable {
const mythical = this.mythical;
return species => {
return (
- (subLegendary ||
- legendary ||
- mythical ||
- (pokemonEvolutions.hasOwnProperty(species.speciesId) === hasEvolution &&
- pokemonPrevolutions.hasOwnProperty(species.speciesId) === hasPrevolution)) &&
- species.subLegendary === subLegendary &&
- species.legendary === legendary &&
- species.mythical === mythical &&
- (this.isTrainerForbidden() || !species.isTrainerForbidden()) &&
- species.speciesId !== SpeciesId.DITTO
+ (subLegendary
+ || legendary
+ || mythical
+ || (pokemonEvolutions.hasOwnProperty(species.speciesId) === hasEvolution
+ && pokemonPrevolutions.hasOwnProperty(species.speciesId) === hasPrevolution))
+ && species.subLegendary === subLegendary
+ && species.legendary === legendary
+ && species.mythical === mythical
+ && (this.isTrainerForbidden() || !species.isTrainerForbidden())
+ && species.speciesId !== SpeciesId.DITTO
);
};
}
@@ -1202,19 +1198,19 @@ export class PokemonSpecies extends PokemonSpeciesForm implements Localizable {
}
getFormSpriteKey(formIndex?: number) {
- if (this.forms.length && formIndex !== undefined && formIndex >= this.forms.length) {
+ if (this.forms.length > 0 && formIndex !== undefined && formIndex >= this.forms.length) {
console.warn(
`Attempted accessing form with index ${formIndex} of species ${this.getName()} with only ${this.forms.length || 0} forms`,
);
formIndex = Math.min(formIndex, this.forms.length - 1);
}
- return this.forms?.length ? this.forms[formIndex || 0].getFormSpriteKey() : "";
+ return this.forms?.length > 0 ? this.forms[formIndex || 0].getFormSpriteKey() : "";
}
/**
- * Generates a {@linkcode bigint} corresponding to the maximum unlocks possible for this species,
+ * Generates a {@linkcode BigInt} corresponding to the maximum unlocks possible for this species,
* taking into account if the species has a male/female gender, and which variants are implemented.
- * @returns {@linkcode bigint} Maximum unlocks, can be compared with {@linkcode DexEntry.caughtAttr}.
+ * @returns The maximum unlocks for the species as a `BigInt`; can be compared with {@linkcode DexEntry.caughtAttr}.
*/
getFullUnlocksData(): bigint {
let caughtAttr = 0n;
diff --git a/src/data/positional-tags/positional-tag.ts b/src/data/positional-tags/positional-tag.ts
index 77ca6f0e9eb..a877b45b045 100644
--- a/src/data/positional-tags/positional-tag.ts
+++ b/src/data/positional-tags/positional-tag.ts
@@ -126,7 +126,9 @@ export class DelayedAttackTag extends PositionalTag implements DelayedAttackArgs
// Silently disappear if either source or target are missing or happen to be the same pokemon
// (i.e. targeting oneself)
// We also need to check for fainted targets as they don't technically leave the field until _after_ the turn ends
- return !!source && !!target && source !== target && !target.isFainted();
+ // TODO: Figure out a way to store the target's offensive stat if they faint to allow pending attacks to persist
+ // TODO: Remove the `?.scene` checks once battle anims are cleaned up - needed to avoid catch+release crash
+ return !!source?.scene && !!target?.scene && source !== target && !target.isFainted();
}
}
diff --git a/src/data/splash-messages.ts b/src/data/splash-messages.ts
index 55ba185bfb2..21e7e5d05e6 100644
--- a/src/data/splash-messages.ts
+++ b/src/data/splash-messages.ts
@@ -53,8 +53,8 @@ const SEASONAL_WEIGHT_MULTIPLIER = 15;
//#region Common Messages
const commonSplashMessages = [
- ...Array(BATTLES_WON_WEIGHT_MULTIPLIER).fill("battlesWon"),
- ...Array(POKEMON_NAMES_WEIGHT_MULTIPLIER).fill("underratedPokemon"),
+ ...new Array(BATTLES_WON_WEIGHT_MULTIPLIER).fill("battlesWon"),
+ ...new Array(POKEMON_NAMES_WEIGHT_MULTIPLIER).fill("underratedPokemon"),
"joinTheDiscord",
"infiniteLevels",
"everythingIsStackable",
@@ -333,7 +333,7 @@ export function getSplashMessages(): string[] {
if (now >= startDate && now <= endDate) {
console.log(`Adding ${messages.length} ${name} splash messages (weight: x${SEASONAL_WEIGHT_MULTIPLIER})`);
for (const message of messages) {
- const weightedMessage = Array(SEASONAL_WEIGHT_MULTIPLIER).fill(message);
+ const weightedMessage = new Array(SEASONAL_WEIGHT_MULTIPLIER).fill(message);
splashMessages.push(...weightedMessage);
}
}
diff --git a/src/data/status-effect.ts b/src/data/status-effect.ts
index 211e265ccf6..34cd2d87617 100644
--- a/src/data/status-effect.ts
+++ b/src/data/status-effect.ts
@@ -59,12 +59,12 @@ export function getStatusEffectObtainText(
if (!sourceText) {
const i18nKey = `${getStatusEffectMessageKey(statusEffect)}.obtain` as ParseKeys;
- return i18next.t(i18nKey, { pokemonNameWithAffix: pokemonNameWithAffix });
+ return i18next.t(i18nKey, { pokemonNameWithAffix });
}
const i18nKey = `${getStatusEffectMessageKey(statusEffect)}.obtainSource` as ParseKeys;
return i18next.t(i18nKey, {
- pokemonNameWithAffix: pokemonNameWithAffix,
- sourceText: sourceText,
+ pokemonNameWithAffix,
+ sourceText,
});
}
@@ -73,7 +73,7 @@ export function getStatusEffectActivationText(statusEffect: StatusEffect, pokemo
return "";
}
const i18nKey = `${getStatusEffectMessageKey(statusEffect)}.activation` as ParseKeys;
- return i18next.t(i18nKey, { pokemonNameWithAffix: pokemonNameWithAffix });
+ return i18next.t(i18nKey, { pokemonNameWithAffix });
}
export function getStatusEffectOverlapText(statusEffect: StatusEffect, pokemonNameWithAffix: string): string {
@@ -81,7 +81,7 @@ export function getStatusEffectOverlapText(statusEffect: StatusEffect, pokemonNa
return "";
}
const i18nKey = `${getStatusEffectMessageKey(statusEffect)}.overlap` as ParseKeys;
- return i18next.t(i18nKey, { pokemonNameWithAffix: pokemonNameWithAffix });
+ return i18next.t(i18nKey, { pokemonNameWithAffix });
}
export function getStatusEffectHealText(statusEffect: StatusEffect, pokemonNameWithAffix: string): string {
@@ -89,7 +89,7 @@ export function getStatusEffectHealText(statusEffect: StatusEffect, pokemonNameW
return "";
}
const i18nKey = `${getStatusEffectMessageKey(statusEffect)}.heal` as ParseKeys;
- return i18next.t(i18nKey, { pokemonNameWithAffix: pokemonNameWithAffix });
+ return i18next.t(i18nKey, { pokemonNameWithAffix });
}
export function getStatusEffectDescriptor(statusEffect: StatusEffect): string {
diff --git a/src/data/terrain.ts b/src/data/terrain.ts
index 7906450d0ea..139230605bf 100644
--- a/src/data/terrain.ts
+++ b/src/data/terrain.ts
@@ -65,14 +65,10 @@ export class Terrain {
// Psychic terrain will only cancel a move if it:
return (
// ... is neither spread nor field-targeted,
- !isFieldTargeted(move) &&
- !isSpreadMove(move) &&
- // .. has positive final priority,
- move.getPriority(user) > 0 &&
- // ...and is targeting at least 1 grounded opponent
- user
- .getOpponents(true)
- .some(o => targets.includes(o.getBattlerIndex()) && o.isGrounded())
+ !isFieldTargeted(move)
+ && !isSpreadMove(move) // .. has positive final priority,
+ && move.getPriority(user) > 0 // ...and is targeting at least 1 grounded opponent
+ && user.getOpponents(true).some(o => targets.includes(o.getBattlerIndex()) && o.isGrounded())
);
}
diff --git a/src/data/trainers/trainer-config.ts b/src/data/trainers/trainer-config.ts
index f0042e0af91..2870fd7f808 100644
--- a/src/data/trainers/trainer-config.ts
+++ b/src/data/trainers/trainer-config.ts
@@ -140,8 +140,8 @@ export class TrainerConfig {
this.victoryBgm = "victory_trainer";
this.partyTemplates = [trainerPartyTemplates.TWO_AVG];
this.speciesFilter = species =>
- (allowLegendaries || (!species.legendary && !species.subLegendary && !species.mythical)) &&
- !species.isTrainerForbidden();
+ (allowLegendaries || (!species.legendary && !species.subLegendary && !species.mythical))
+ && !species.isTrainerForbidden();
}
getKey(): string {
@@ -816,8 +816,8 @@ export class TrainerConfig {
if (this.nameFemale) {
// Check if the variant is either female or this is for the partner in a double battle
if (
- variant === TrainerVariant.FEMALE ||
- (variant === TrainerVariant.DOUBLE && trainerSlot === TrainerSlot.TRAINER_PARTNER)
+ variant === TrainerVariant.FEMALE
+ || (variant === TrainerVariant.DOUBLE && trainerSlot === TrainerSlot.TRAINER_PARTNER)
) {
return this.nameFemale;
}
@@ -1088,8 +1088,8 @@ export const trainerConfigs: TrainerConfigs = {
s =>
[s.ability1, s.ability2, s.abilityHidden].some(
a =>
- !!a &&
- [
+ !!a
+ && [
AbilityId.WHITE_SMOKE,
AbilityId.GLUTTONY,
AbilityId.HONEY_GATHER,
@@ -1102,8 +1102,8 @@ export const trainerConfigs: TrainerConfigs = {
AbilityId.SUPERSWEET_SYRUP,
AbilityId.HOSPITALITY,
].includes(a),
- ) ||
- s
+ )
+ || s
.getLevelMoves()
.some(plm =>
[MoveId.SOFT_BOILED, MoveId.SPORE, MoveId.MILK_DRINK, MoveId.OVERHEAT, MoveId.TEATIME].includes(plm[1]),
@@ -1566,8 +1566,8 @@ export const trainerConfigs: TrainerConfigs = {
s =>
[s.ability1, s.ability2, s.abilityHidden].some(
a =>
- !!a &&
- [
+ !!a
+ && [
AbilityId.DRIZZLE,
AbilityId.SWIFT_SWIM,
AbilityId.HYDRATION,
@@ -4642,9 +4642,9 @@ export const trainerConfigs: TrainerConfigs = {
2,
getSpeciesFilterRandomPartyMemberFunc(
(species: PokemonSpecies) =>
- !pokemonEvolutions.hasOwnProperty(species.speciesId) &&
- !pokemonPrevolutions.hasOwnProperty(species.speciesId) &&
- species.baseTotal >= 450,
+ !pokemonEvolutions.hasOwnProperty(species.speciesId)
+ && !pokemonPrevolutions.hasOwnProperty(species.speciesId)
+ && species.baseTotal >= 450,
),
),
[TrainerType.RIVAL_3]: new TrainerConfig(++t)
@@ -4717,9 +4717,9 @@ export const trainerConfigs: TrainerConfigs = {
2,
getSpeciesFilterRandomPartyMemberFunc(
(species: PokemonSpecies) =>
- !pokemonEvolutions.hasOwnProperty(species.speciesId) &&
- !pokemonPrevolutions.hasOwnProperty(species.speciesId) &&
- species.baseTotal >= 450,
+ !pokemonEvolutions.hasOwnProperty(species.speciesId)
+ && !pokemonPrevolutions.hasOwnProperty(species.speciesId)
+ && species.baseTotal >= 450,
),
)
.setSpeciesFilter(species => species.baseTotal >= 540),
@@ -4798,9 +4798,9 @@ export const trainerConfigs: TrainerConfigs = {
2,
getSpeciesFilterRandomPartyMemberFunc(
(species: PokemonSpecies) =>
- !pokemonEvolutions.hasOwnProperty(species.speciesId) &&
- !pokemonPrevolutions.hasOwnProperty(species.speciesId) &&
- species.baseTotal >= 450,
+ !pokemonEvolutions.hasOwnProperty(species.speciesId)
+ && !pokemonPrevolutions.hasOwnProperty(species.speciesId)
+ && species.baseTotal >= 450,
),
)
.setSpeciesFilter(species => species.baseTotal >= 540)
@@ -4880,9 +4880,9 @@ export const trainerConfigs: TrainerConfigs = {
2,
getSpeciesFilterRandomPartyMemberFunc(
(species: PokemonSpecies) =>
- !pokemonEvolutions.hasOwnProperty(species.speciesId) &&
- !pokemonPrevolutions.hasOwnProperty(species.speciesId) &&
- species.baseTotal >= 450,
+ !pokemonEvolutions.hasOwnProperty(species.speciesId)
+ && !pokemonPrevolutions.hasOwnProperty(species.speciesId)
+ && species.baseTotal >= 450,
),
)
.setSpeciesFilter(species => species.baseTotal >= 540)
@@ -4976,9 +4976,9 @@ export const trainerConfigs: TrainerConfigs = {
2,
getSpeciesFilterRandomPartyMemberFunc(
(species: PokemonSpecies) =>
- !pokemonEvolutions.hasOwnProperty(species.speciesId) &&
- !pokemonPrevolutions.hasOwnProperty(species.speciesId) &&
- species.baseTotal >= 450,
+ !pokemonEvolutions.hasOwnProperty(species.speciesId)
+ && !pokemonPrevolutions.hasOwnProperty(species.speciesId)
+ && species.baseTotal >= 450,
),
)
.setSpeciesFilter(species => species.baseTotal >= 540)
diff --git a/src/data/type.ts b/src/data/type.ts
index 8dd51a887b0..e4c7465412e 100644
--- a/src/data/type.ts
+++ b/src/data/type.ts
@@ -303,7 +303,7 @@ export function getTypeDamageMultiplierColor(
case 0.5:
return "#FE8E00";
case 1:
- return undefined;
+ return;
case 2:
return "#4AA500";
case 4:
@@ -323,7 +323,7 @@ export function getTypeDamageMultiplierColor(
case 0.5:
return "#0093FF";
case 1:
- return undefined;
+ return;
case 2:
return "#FE8E00";
case 4:
diff --git a/src/data/weather.ts b/src/data/weather.ts
index 59be56826a4..84a5e1ba4f8 100644
--- a/src/data/weather.ts
+++ b/src/data/weather.ts
@@ -386,5 +386,5 @@ export function getRandomWeatherType(arena: Arena): WeatherType {
}
}
- return weatherPool.length ? weatherPool[0].weatherType : WeatherType.NONE;
+ return weatherPool.length > 0 ? weatherPool[0].weatherType : WeatherType.NONE;
}
diff --git a/src/enums/ability-attr.ts b/src/enums/ability-attr.ts
index a3b9511ad02..64b955e963d 100644
--- a/src/enums/ability-attr.ts
+++ b/src/enums/ability-attr.ts
@@ -10,4 +10,4 @@ export const AbilityAttr = Object.freeze({
ABILITY_HIDDEN: 4,
});
-export type AbilityAttr = ObjectValues;
\ No newline at end of file
+export type AbilityAttr = ObjectValues;
diff --git a/src/enums/ai-type.ts b/src/enums/ai-type.ts
index 13931172a4a..5438a026c2f 100644
--- a/src/enums/ai-type.ts
+++ b/src/enums/ai-type.ts
@@ -1,5 +1,5 @@
export enum AiType {
RANDOM,
SMART_RANDOM,
- SMART
+ SMART,
}
diff --git a/src/enums/arena-tag-side.ts b/src/enums/arena-tag-side.ts
index 3e326ce158a..5f25a74ab36 100644
--- a/src/enums/arena-tag-side.ts
+++ b/src/enums/arena-tag-side.ts
@@ -1,5 +1,5 @@
export enum ArenaTagSide {
BOTH,
PLAYER,
- ENEMY
+ ENEMY,
}
diff --git a/src/enums/arena-tag-type.ts b/src/enums/arena-tag-type.ts
index 7f9364395c0..30f053b98bd 100644
--- a/src/enums/arena-tag-type.ts
+++ b/src/enums/arena-tag-type.ts
@@ -1,13 +1,10 @@
-import type { ArenaTagTypeMap } from "#data/arena-tag";
-import type { NonSerializableArenaTagType, SerializableArenaTagType } from "#types/arena-tags";
-
/**
* Enum representing all different types of {@linkcode ArenaTag}s.
* @privateRemarks
* ⚠️ When modifying the fields in this enum, ensure that:
- * - The entry is added to / removed from {@linkcode ArenaTagTypeMap}
+ * - The entry is added to / removed from {@linkcode ArenaTagTypeMap}
* - The tag is added to / removed from {@linkcode NonSerializableArenaTagType} or {@linkcode SerializableArenaTagType}
-*/
+ */
export enum ArenaTagType {
NONE = "NONE",
MUD_SPORT = "MUD_SPORT",
@@ -36,5 +33,5 @@ export enum ArenaTagType {
WATER_FIRE_PLEDGE = "WATER_FIRE_PLEDGE",
GRASS_WATER_PLEDGE = "GRASS_WATER_PLEDGE",
FAIRY_LOCK = "FAIRY_LOCK",
- NEUTRALIZING_GAS = "NEUTRALIZING_GAS"
+ NEUTRALIZING_GAS = "NEUTRALIZING_GAS",
}
diff --git a/src/enums/battle-spec.ts b/src/enums/battle-spec.ts
index 00bc7f92fea..24d7d211d83 100644
--- a/src/enums/battle-spec.ts
+++ b/src/enums/battle-spec.ts
@@ -1,4 +1,4 @@
export enum BattleSpec {
- DEFAULT,
- FINAL_BOSS
+ DEFAULT,
+ FINAL_BOSS,
}
diff --git a/src/enums/battle-style.ts b/src/enums/battle-style.ts
index 2fba10f1bf9..d9545515497 100644
--- a/src/enums/battle-style.ts
+++ b/src/enums/battle-style.ts
@@ -3,5 +3,5 @@ export enum BattleStyle {
/** Display option to switch active pokemon at battle start. */
SWITCH,
/** Hide option to switch active pokemon at battle start. */
- SET
+ SET,
}
diff --git a/src/enums/battle-type.ts b/src/enums/battle-type.ts
index 81cf89ef488..225f795f123 100644
--- a/src/enums/battle-type.ts
+++ b/src/enums/battle-type.ts
@@ -2,5 +2,5 @@ export enum BattleType {
WILD,
TRAINER,
CLEAR,
- MYSTERY_ENCOUNTER
+ MYSTERY_ENCOUNTER,
}
diff --git a/src/enums/battler-index.ts b/src/enums/battler-index.ts
index 97c44f51c5c..1d7635c89dc 100644
--- a/src/enums/battler-index.ts
+++ b/src/enums/battler-index.ts
@@ -7,5 +7,5 @@ export enum BattlerIndex {
PLAYER,
PLAYER_2,
ENEMY,
- ENEMY_2
+ ENEMY_2,
}
diff --git a/src/enums/berry-type.ts b/src/enums/berry-type.ts
index 97c69148146..3844ee61b9b 100644
--- a/src/enums/berry-type.ts
+++ b/src/enums/berry-type.ts
@@ -9,5 +9,5 @@ export enum BerryType {
SALAC,
LANSAT,
STARF,
- LEPPA
+ LEPPA,
}
diff --git a/src/enums/biome-id.ts b/src/enums/biome-id.ts
index 08a0d742738..8b086cb1cd5 100644
--- a/src/enums/biome-id.ts
+++ b/src/enums/biome-id.ts
@@ -34,5 +34,5 @@ export enum BiomeId {
SNOWY_FOREST,
ISLAND = 40,
LABORATORY,
- END = 50
+ END = 50,
}
diff --git a/src/enums/buttons.ts b/src/enums/buttons.ts
index f828b280d45..3b725b99a17 100644
--- a/src/enums/buttons.ts
+++ b/src/enums/buttons.ts
@@ -1,19 +1,19 @@
export enum Button {
- UP,
- DOWN,
- LEFT,
- RIGHT,
- SUBMIT,
- ACTION,
- CANCEL,
- MENU,
- STATS,
- CYCLE_SHINY,
- CYCLE_FORM,
- CYCLE_GENDER,
- CYCLE_ABILITY,
- CYCLE_NATURE,
- CYCLE_TERA,
- SPEED_UP,
- SLOW_DOWN,
+ UP,
+ DOWN,
+ LEFT,
+ RIGHT,
+ SUBMIT,
+ ACTION,
+ CANCEL,
+ MENU,
+ STATS,
+ CYCLE_SHINY,
+ CYCLE_FORM,
+ CYCLE_GENDER,
+ CYCLE_ABILITY,
+ CYCLE_NATURE,
+ CYCLE_TERA,
+ SPEED_UP,
+ SLOW_DOWN,
}
diff --git a/src/enums/challenges.ts b/src/enums/challenges.ts
index 8d4f4c7a22a..3d1484cb416 100644
--- a/src/enums/challenges.ts
+++ b/src/enums/challenges.ts
@@ -1,12 +1,12 @@
export enum Challenges {
- SINGLE_GENERATION,
- SINGLE_TYPE,
- LOWER_MAX_STARTER_COST,
- LOWER_STARTER_POINTS,
- FRESH_START,
- INVERSE_BATTLE,
- FLIP_STAT,
- LIMITED_CATCH,
- LIMITED_SUPPORT,
- HARDCORE,
+ SINGLE_GENERATION,
+ SINGLE_TYPE,
+ LOWER_MAX_STARTER_COST,
+ LOWER_STARTER_POINTS,
+ FRESH_START,
+ INVERSE_BATTLE,
+ FLIP_STAT,
+ LIMITED_CATCH,
+ LIMITED_SUPPORT,
+ HARDCORE,
}
diff --git a/src/enums/color.ts b/src/enums/color.ts
index 99c2d14cb63..ec16a10d5e9 100644
--- a/src/enums/color.ts
+++ b/src/enums/color.ts
@@ -1,83 +1,83 @@
export enum Color {
- WHITE = "#ffffff",
- OFF_WHITE = "#f8f8f8",
- LIGHT_GREY = "#a0a0a0",
- GREY = "#484848",
- DARK_GREY = "#404040",
- PINK = "#f89890",
- RED = "#e13d3d",
- RED2 = "#e70808",
- REDORANGE = "#d64b00",
- ORANGE = "#f8b050",
- LIGHT_YELLOW = "#e8e8a8",
- YELLOW = "#ccbe00",
- DARK_YELLOW = "#a68e17",
- GREEN = "#78c850",
- BLUE = "#40c8f8",
- COMMON = "#ffffff",
- GREAT = "#3890f8",
- ULTRA = "#f8d038",
- ROGUE = "#d52929",
- MASTER = "#e020c0",
- LUXURY = "#e64a18"
+ WHITE = "#ffffff",
+ OFF_WHITE = "#f8f8f8",
+ LIGHT_GREY = "#a0a0a0",
+ GREY = "#484848",
+ DARK_GREY = "#404040",
+ PINK = "#f89890",
+ RED = "#e13d3d",
+ RED2 = "#e70808",
+ REDORANGE = "#d64b00",
+ ORANGE = "#f8b050",
+ LIGHT_YELLOW = "#e8e8a8",
+ YELLOW = "#ccbe00",
+ DARK_YELLOW = "#a68e17",
+ GREEN = "#78c850",
+ BLUE = "#40c8f8",
+ COMMON = "#ffffff",
+ GREAT = "#3890f8",
+ ULTRA = "#f8d038",
+ ROGUE = "#d52929",
+ MASTER = "#e020c0",
+ LUXURY = "#e64a18",
}
export enum TypeColor {
- NORMAL = "#ADA594",
- FIGHTING = "#A55239",
- FLYING = "#9CADF7",
- POISON = "#9141CB",
- GROUND = "#AE7A3B",
- ROCK = "#BDA55A",
- BUG = "#ADBD21",
- GHOST = "#6363B5",
- STEEL = "#81A6BE",
- FIRE = "#F75231",
- WATER = "#399CFF",
- GRASS = "#7BCE52",
- ELECTRIC = "#FFC631",
- PSYCHIC = "#EF4179",
- ICE = "#5ACEE7",
- DRAGON = "#7B63E7",
- DARK = "#735A4A",
- FAIRY = "#EF70EF",
+ NORMAL = "#ADA594",
+ FIGHTING = "#A55239",
+ FLYING = "#9CADF7",
+ POISON = "#9141CB",
+ GROUND = "#AE7A3B",
+ ROCK = "#BDA55A",
+ BUG = "#ADBD21",
+ GHOST = "#6363B5",
+ STEEL = "#81A6BE",
+ FIRE = "#F75231",
+ WATER = "#399CFF",
+ GRASS = "#7BCE52",
+ ELECTRIC = "#FFC631",
+ PSYCHIC = "#EF4179",
+ ICE = "#5ACEE7",
+ DRAGON = "#7B63E7",
+ DARK = "#735A4A",
+ FAIRY = "#EF70EF",
}
export enum TypeShadow {
- NORMAL = "#574F4A",
- FIGHTING = "#4E637C",
- FLYING = "#4E637C",
- POISON = "#352166",
- GROUND = "#572D1E",
- ROCK = "#5F442D",
- BUG = "#5F5010",
- GHOST = "#323D5B",
- STEEL = "#415C5F",
- FIRE = "#7C1818",
- WATER = "#1C4E80",
- GRASS = "#4F6729",
- ELECTRIC = "#804618",
- PSYCHIC = "#782155",
- ICE = "#2D5C74",
- DRAGON = "#313874",
- DARK = "#392725",
- FAIRY = "#663878",
+ NORMAL = "#574F4A",
+ FIGHTING = "#4E637C",
+ FLYING = "#4E637C",
+ POISON = "#352166",
+ GROUND = "#572D1E",
+ ROCK = "#5F442D",
+ BUG = "#5F5010",
+ GHOST = "#323D5B",
+ STEEL = "#415C5F",
+ FIRE = "#7C1818",
+ WATER = "#1C4E80",
+ GRASS = "#4F6729",
+ ELECTRIC = "#804618",
+ PSYCHIC = "#782155",
+ ICE = "#2D5C74",
+ DRAGON = "#313874",
+ DARK = "#392725",
+ FAIRY = "#663878",
}
export enum ShadowColor {
- GREY = "#636363",
- PURPLE = "#6b5a73",
- LIGHT_GREY = "#d0d0c8",
- BROWN = "#69402a",
- PINK = "#fca2a2",
- BRIGHT_RED = "#f83018",
- RED = "#984038",
- MAROON = "#632929",
- GREEN = "#306850",
- BLUE = "#006090",
- LIGHT_YELLOW = "#ded6b5",
- YELLOW = "#ebd773",
- DARK_YELLOW = "#a0a060",
- ORANGE = "#c07800",
- LIGHT_ORANGE = "#ffbd73",
+ GREY = "#636363",
+ PURPLE = "#6b5a73",
+ LIGHT_GREY = "#d0d0c8",
+ BROWN = "#69402a",
+ PINK = "#fca2a2",
+ BRIGHT_RED = "#f83018",
+ RED = "#984038",
+ MAROON = "#632929",
+ GREEN = "#306850",
+ BLUE = "#006090",
+ LIGHT_YELLOW = "#ded6b5",
+ YELLOW = "#ebd773",
+ DARK_YELLOW = "#a0a060",
+ ORANGE = "#c07800",
+ LIGHT_ORANGE = "#ffbd73",
}
diff --git a/src/enums/command.ts b/src/enums/command.ts
index 4cd626bb066..a1ac4501a0b 100644
--- a/src/enums/command.ts
+++ b/src/enums/command.ts
@@ -3,5 +3,5 @@ export enum Command {
BALL,
POKEMON,
RUN,
- TERA
+ TERA,
}
diff --git a/src/enums/devices.ts b/src/enums/devices.ts
index b085dfbada3..fafe929655e 100644
--- a/src/enums/devices.ts
+++ b/src/enums/devices.ts
@@ -1,4 +1,4 @@
export enum Device {
- GAMEPAD,
- KEYBOARD,
+ GAMEPAD,
+ KEYBOARD,
}
diff --git a/src/enums/drop-down-column.ts b/src/enums/drop-down-column.ts
index b413d1f0bf4..0adf0327e4c 100644
--- a/src/enums/drop-down-column.ts
+++ b/src/enums/drop-down-column.ts
@@ -5,5 +5,5 @@ export enum DropDownColumn {
CAUGHT,
UNLOCKS,
MISC,
- SORT
+ SORT,
}
diff --git a/src/enums/dynamic-phase-type.ts b/src/enums/dynamic-phase-type.ts
index b9ea6bf197d..3146b136dac 100644
--- a/src/enums/dynamic-phase-type.ts
+++ b/src/enums/dynamic-phase-type.ts
@@ -3,5 +3,5 @@
*/
// TODO: We currently assume these are in order
export enum DynamicPhaseType {
- POST_SUMMON
+ POST_SUMMON,
}
diff --git a/src/enums/ease-type.ts b/src/enums/ease-type.ts
index fbe06fd536d..638a21dbb96 100644
--- a/src/enums/ease-type.ts
+++ b/src/enums/ease-type.ts
@@ -1,15 +1,15 @@
export enum EaseType {
- NONE,
- LINEAR = "Linear",
- QUADRATIC = "Quad",
- CUBIC = "Cubic",
- QUARTIC = "Quart",
- QUINTIC = "Quint",
- SINUSOIDAL = "Sine",
- EXPONENTIAL = "Expo",
- CIRCULAR = "Circ",
- ELASTIC = "Elastic",
- BACK = "Back",
- BOUNCE = "Bounce",
- STEPPED = "Stepped",
+ NONE,
+ LINEAR = "Linear",
+ QUADRATIC = "Quad",
+ CUBIC = "Cubic",
+ QUARTIC = "Quart",
+ QUINTIC = "Quint",
+ SINUSOIDAL = "Sine",
+ EXPONENTIAL = "Expo",
+ CIRCULAR = "Circ",
+ ELASTIC = "Elastic",
+ BACK = "Back",
+ BOUNCE = "Bounce",
+ STEPPED = "Stepped",
}
diff --git a/src/enums/egg-source-types.ts b/src/enums/egg-source-types.ts
index a670d86704b..8956e8c9795 100644
--- a/src/enums/egg-source-types.ts
+++ b/src/enums/egg-source-types.ts
@@ -1,7 +1,7 @@
export enum EggSourceType {
- GACHA_MOVE,
- GACHA_LEGENDARY,
- GACHA_SHINY,
- SAME_SPECIES_EGG,
- EVENT
+ GACHA_MOVE,
+ GACHA_LEGENDARY,
+ GACHA_SHINY,
+ SAME_SPECIES_EGG,
+ EVENT,
}
diff --git a/src/enums/egg-type.ts b/src/enums/egg-type.ts
index 901e60b3c76..8244bba4ad1 100644
--- a/src/enums/egg-type.ts
+++ b/src/enums/egg-type.ts
@@ -2,5 +2,5 @@ export enum EggTier {
COMMON,
RARE,
EPIC,
- LEGENDARY
+ LEGENDARY,
}
diff --git a/src/enums/encounter-anims.ts b/src/enums/encounter-anims.ts
index bd1461473c9..55c64e2a90e 100644
--- a/src/enums/encounter-anims.ts
+++ b/src/enums/encounter-anims.ts
@@ -7,5 +7,5 @@ export enum EncounterAnim {
MAGMA_BG,
MAGMA_SPOUT,
SMOKESCREEN,
- DANCE
+ DANCE,
}
diff --git a/src/enums/exp-gains-speed.ts b/src/enums/exp-gains-speed.ts
index f5f36a1c78d..b98345552ae 100644
--- a/src/enums/exp-gains-speed.ts
+++ b/src/enums/exp-gains-speed.ts
@@ -7,5 +7,5 @@ export enum ExpGainsSpeed {
/** Faster speed. */
FASTER,
/** Skip gaining exp animation. */
- SKIP
+ SKIP,
}
diff --git a/src/enums/exp-notification.ts b/src/enums/exp-notification.ts
index a64d8591e76..491578ec49a 100644
--- a/src/enums/exp-notification.ts
+++ b/src/enums/exp-notification.ts
@@ -5,5 +5,5 @@ export enum ExpNotification {
/** Display smaller flyout showing level gained on gaining a new level. */
ONLY_LEVEL_UP,
/** Do not show any flyouts for EXP gains or levelups. */
- SKIP
+ SKIP,
}
diff --git a/src/enums/field-position.ts b/src/enums/field-position.ts
index 5b7f9c6c570..5ca5ee9ac66 100644
--- a/src/enums/field-position.ts
+++ b/src/enums/field-position.ts
@@ -1,5 +1,5 @@
export enum FieldPosition {
CENTER,
LEFT,
- RIGHT
+ RIGHT,
}
diff --git a/src/enums/fixed-boss-waves.ts b/src/enums/fixed-boss-waves.ts
index 623d9035472..b1725d14215 100644
--- a/src/enums/fixed-boss-waves.ts
+++ b/src/enums/fixed-boss-waves.ts
@@ -18,5 +18,5 @@ export enum ClassicFixedBossWaves {
ELITE_FOUR_3 = 186,
ELITE_FOUR_4 = 188,
CHAMPION = 190,
- RIVAL_6 = 195
+ RIVAL_6 = 195,
}
diff --git a/src/enums/form-change-item.ts b/src/enums/form-change-item.ts
index 15620eafd0a..77818ca3488 100644
--- a/src/enums/form-change-item.ts
+++ b/src/enums/form-change-item.ts
@@ -96,8 +96,8 @@ export enum FormChangeItem {
DRACO_PLATE,
DREAD_PLATE,
PIXIE_PLATE,
- BLANK_PLATE,// TODO: Find a potential use for this
- LEGEND_PLATE,// TODO: Find a potential use for this
+ BLANK_PLATE, // TODO: Find a potential use for this
+ LEGEND_PLATE, // TODO: Find a potential use for this
FIGHTING_MEMORY,
FLYING_MEMORY,
POISON_MEMORY,
@@ -115,5 +115,5 @@ export enum FormChangeItem {
DRAGON_MEMORY,
DARK_MEMORY,
FAIRY_MEMORY,
- NORMAL_MEMORY
+ NORMAL_MEMORY,
}
diff --git a/src/enums/gacha-types.ts b/src/enums/gacha-types.ts
index 08f147b27b1..b5b60f35d21 100644
--- a/src/enums/gacha-types.ts
+++ b/src/enums/gacha-types.ts
@@ -1,9 +1,9 @@
import type { ObjectValues } from "#types/type-helpers";
export const GachaType = Object.freeze({
- MOVE: 0,
- LEGENDARY: 1,
- SHINY: 2
+ MOVE: 0,
+ LEGENDARY: 1,
+ SHINY: 2,
});
export type GachaType = ObjectValues;
diff --git a/src/enums/game-data-type.ts b/src/enums/game-data-type.ts
index d672253794a..d671c7666f3 100644
--- a/src/enums/game-data-type.ts
+++ b/src/enums/game-data-type.ts
@@ -7,5 +7,5 @@ export enum GameDataType {
SETTINGS,
TUTORIALS,
SEEN_DIALOGUES,
- RUN_HISTORY
+ RUN_HISTORY,
}
diff --git a/src/enums/game-modes.ts b/src/enums/game-modes.ts
index 837b634621c..061f622cae2 100644
--- a/src/enums/game-modes.ts
+++ b/src/enums/game-modes.ts
@@ -3,5 +3,5 @@ export enum GameModes {
ENDLESS,
SPLICED_ENDLESS,
DAILY,
- CHALLENGE
+ CHALLENGE,
}
diff --git a/src/enums/hit-result.ts b/src/enums/hit-result.ts
index 3e62587dd6c..9df8ca6121a 100644
--- a/src/enums/hit-result.ts
+++ b/src/enums/hit-result.ts
@@ -11,5 +11,5 @@ export enum HitResult {
INDIRECT,
IMMUNE,
CONFUSION,
- INDIRECT_KO
+ INDIRECT_KO,
}
diff --git a/src/enums/learn-move-situation.ts b/src/enums/learn-move-situation.ts
index 9b329d0f3de..e12aef5a11b 100644
--- a/src/enums/learn-move-situation.ts
+++ b/src/enums/learn-move-situation.ts
@@ -3,6 +3,6 @@ export enum LearnMoveSituation {
LEVEL_UP,
RELEARN,
EVOLUTION,
- EVOLUTION_FUSED,// If fusionSpecies has Evolved
- EVOLUTION_FUSED_BASE
+ EVOLUTION_FUSED, // If fusionSpecies has Evolved
+ EVOLUTION_FUSED_BASE,
}
diff --git a/src/enums/learn-move-type.ts b/src/enums/learn-move-type.ts
index 442639c1bc7..3162d8d7e73 100644
--- a/src/enums/learn-move-type.ts
+++ b/src/enums/learn-move-type.ts
@@ -4,5 +4,5 @@ export enum LearnMoveType {
/** For learning a move via Memory Mushroom */
MEMORY,
/** For learning a move via TM */
- TM
+ TM,
}
diff --git a/src/enums/modifier-pool-type.ts b/src/enums/modifier-pool-type.ts
index 0d2b92ba80d..ca3ed3a11c7 100644
--- a/src/enums/modifier-pool-type.ts
+++ b/src/enums/modifier-pool-type.ts
@@ -3,5 +3,5 @@ export enum ModifierPoolType {
WILD,
TRAINER,
ENEMY_BUFF,
- DAILY_STARTER
+ DAILY_STARTER,
}
diff --git a/src/enums/money-format.ts b/src/enums/money-format.ts
index 643247194a7..228e3f9d9f0 100644
--- a/src/enums/money-format.ts
+++ b/src/enums/money-format.ts
@@ -1,4 +1,4 @@
export enum MoneyFormat {
NORMAL,
- ABBREVIATED
+ ABBREVIATED,
}
diff --git a/src/enums/move-anims-common.ts b/src/enums/move-anims-common.ts
index f21e4c8be4a..96498f6d294 100644
--- a/src/enums/move-anims-common.ts
+++ b/src/enums/move-anims-common.ts
@@ -1,20 +1,20 @@
export enum AnimFrameTarget {
USER,
TARGET,
- GRAPHIC
+ GRAPHIC,
}
export enum AnimFocus {
TARGET = 1,
USER,
USER_TARGET,
- SCREEN
+ SCREEN,
}
export enum AnimBlendType {
NORMAL,
ADD,
- SUBTRACT
+ SUBTRACT,
}
export enum ChargeAnim {
@@ -38,7 +38,7 @@ export enum ChargeAnim {
SOLAR_BLADE_CHARGING,
BEAK_BLAST_CHARGING,
METEOR_BEAM_CHARGING,
- ELECTRO_SHOT_CHARGING
+ ELECTRO_SHOT_CHARGING,
}
export enum CommonAnim {
@@ -91,5 +91,5 @@ export enum CommonAnim {
ELECTRIC_TERRAIN,
GRASSY_TERRAIN,
PSYCHIC_TERRAIN,
- LOCK_ON = 2120
+ LOCK_ON = 2120,
}
diff --git a/src/enums/move-category.ts b/src/enums/move-category.ts
index 0408655e6db..f0a171b2fea 100644
--- a/src/enums/move-category.ts
+++ b/src/enums/move-category.ts
@@ -1,5 +1,5 @@
export enum MoveCategory {
PHYSICAL,
SPECIAL,
- STATUS
+ STATUS,
}
diff --git a/src/enums/move-effect-trigger.ts b/src/enums/move-effect-trigger.ts
index d22953c3690..a33a6766bef 100644
--- a/src/enums/move-effect-trigger.ts
+++ b/src/enums/move-effect-trigger.ts
@@ -2,5 +2,5 @@ export enum MoveEffectTrigger {
PRE_APPLY,
POST_APPLY,
/** Triggers one time after all target effects have applied */
- POST_TARGET
+ POST_TARGET,
}
diff --git a/src/enums/move-flags.ts b/src/enums/move-flags.ts
index 6cdc1e5f8cc..e639a1eb190 100644
--- a/src/enums/move-flags.ts
+++ b/src/enums/move-flags.ts
@@ -50,5 +50,5 @@ export enum MoveFlags {
/** Indicates a move is able to be redirected to allies in a double battle if the attacker faints */
REDIRECT_COUNTER = 1 << 18,
/** Indicates a move is able to be reflected by {@linkcode AbilityId.MAGIC_BOUNCE} and {@linkcode MoveId.MAGIC_COAT} */
- REFLECTABLE = 1 << 19
+ REFLECTABLE = 1 << 19,
}
diff --git a/src/enums/move-result.ts b/src/enums/move-result.ts
index d402f5b1aed..c213b6378ca 100644
--- a/src/enums/move-result.ts
+++ b/src/enums/move-result.ts
@@ -3,5 +3,5 @@ export enum MoveResult {
SUCCESS,
FAIL,
MISS,
- OTHER
+ OTHER,
}
diff --git a/src/enums/move-source-type.ts b/src/enums/move-source-type.ts
index d9afb07e7f7..745d4d058ba 100644
--- a/src/enums/move-source-type.ts
+++ b/src/enums/move-source-type.ts
@@ -2,11 +2,11 @@
* Used for challenge types that modify movesets, these denote the various sources of moves for pokemon.
*/
export enum MoveSourceType {
- LEVEL_UP,// Currently unimplemented for move access
- RELEARNER,// Relearner moves currently unimplemented
+ LEVEL_UP, // Currently unimplemented for move access
+ RELEARNER, // Relearner moves currently unimplemented
COMMON_TM,
GREAT_TM,
ULTRA_TM,
COMMON_EGG,
- RARE_EGG
+ RARE_EGG,
}
diff --git a/src/enums/move-target.ts b/src/enums/move-target.ts
index 615628cf4e8..91ea9e8cac9 100644
--- a/src/enums/move-target.ts
+++ b/src/enums/move-target.ts
@@ -25,5 +25,5 @@ export enum MoveTarget {
ENEMY_SIDE,
BOTH_SIDES,
PARTY,
- CURSE
+ CURSE,
}
diff --git a/src/enums/move-use-mode.ts b/src/enums/move-use-mode.ts
index 13ea5248853..b08977195f0 100644
--- a/src/enums/move-use-mode.ts
+++ b/src/enums/move-use-mode.ts
@@ -1,6 +1,3 @@
-import type { PostDancingMoveAbAttr } from "#abilities/ability";
-import type { DelayedAttackAttr } from "#app/@types/move-types";
-import type { BattlerTagLapseType } from "#enums/battler-tag-lapse-type";
import type { ObjectValues } from "#types/type-helpers";
/**
@@ -15,9 +12,9 @@ import type { ObjectValues } from "#types/type-helpers";
*/
export const MoveUseMode = {
/**
- * This move was used normally (i.e. clicking on the button) or called via Instruct.
- * It deducts PP from the user's moveset (failing if out of PP), and interacts normally with other moves and abilities.
- */
+ * This move was used normally (i.e. clicking on the button) or called via Instruct.
+ * It deducts PP from the user's moveset (failing if out of PP), and interacts normally with other moves and abilities.
+ */
NORMAL: 1,
/**
@@ -71,7 +68,7 @@ export const MoveUseMode = {
* @todo Consider other means of implementing FS/DD than this - we currently only use it
* to prevent pushing to move history and avoid re-delaying the attack portion
*/
- DELAYED_ATTACK: 6
+ DELAYED_ATTACK: 6,
} as const;
export type MoveUseMode = ObjectValues;
@@ -96,7 +93,7 @@ export type MoveUseMode = ObjectValues;
* | {@linkcode MoveUseMode.DELAYED_ATTACK} | `true` |
*/
export function isVirtual(useMode: MoveUseMode): boolean {
- return useMode >= MoveUseMode.INDIRECT
+ return useMode >= MoveUseMode.INDIRECT;
}
/**
@@ -161,4 +158,4 @@ export function isIgnorePP(useMode: MoveUseMode): boolean {
*/
export function isReflected(useMode: MoveUseMode): boolean {
return useMode === MoveUseMode.REFLECTED;
-}
\ No newline at end of file
+}
diff --git a/src/enums/multi-hit-type.ts b/src/enums/multi-hit-type.ts
index 27e8214112e..1f737df6ca9 100644
--- a/src/enums/multi-hit-type.ts
+++ b/src/enums/multi-hit-type.ts
@@ -3,5 +3,5 @@ export enum MultiHitType {
_2_TO_5,
_3,
_10,
- BEAT_UP
+ BEAT_UP,
}
diff --git a/src/enums/mystery-encounter-mode.ts b/src/enums/mystery-encounter-mode.ts
index f1e98ca5b18..c8f58354b6c 100644
--- a/src/enums/mystery-encounter-mode.ts
+++ b/src/enums/mystery-encounter-mode.ts
@@ -8,5 +8,5 @@ export enum MysteryEncounterMode {
/** Enables special boss music during encounter */
BOSS_BATTLE,
/** If there is no battle in the {@linkcode MysteryEncounter} or option selected */
- NO_BATTLE
+ NO_BATTLE,
}
diff --git a/src/enums/mystery-encounter-option-mode.ts b/src/enums/mystery-encounter-option-mode.ts
index a994c30581b..4c41f1f06ca 100644
--- a/src/enums/mystery-encounter-option-mode.ts
+++ b/src/enums/mystery-encounter-option-mode.ts
@@ -6,5 +6,5 @@ export enum MysteryEncounterOptionMode {
/** Default style on requirements not met, special style on requirements met */
DEFAULT_OR_SPECIAL,
/** Disabled on requirements not met, special style on requirements met */
- DISABLED_OR_SPECIAL
+ DISABLED_OR_SPECIAL,
}
diff --git a/src/enums/mystery-encounter-tier.ts b/src/enums/mystery-encounter-tier.ts
index 484acc7aba9..aa9e7290381 100644
--- a/src/enums/mystery-encounter-tier.ts
+++ b/src/enums/mystery-encounter-tier.ts
@@ -7,5 +7,5 @@ export enum MysteryEncounterTier {
GREAT = 40,
ULTRA = 19,
ROGUE = 3,
- MASTER = 0 // Not currently used
+ MASTER = 0, // Not currently used
}
diff --git a/src/enums/mystery-encounter-type.ts b/src/enums/mystery-encounter-type.ts
index b973652b113..2286b15f5c3 100644
--- a/src/enums/mystery-encounter-type.ts
+++ b/src/enums/mystery-encounter-type.ts
@@ -29,5 +29,5 @@ export enum MysteryEncounterType {
FUN_AND_GAMES,
UNCOMMON_BREED,
GLOBAL_TRADE_SYSTEM,
- THE_EXPERT_POKEMON_BREEDER
+ THE_EXPERT_POKEMON_BREEDER,
}
diff --git a/src/enums/party-member-strength.ts b/src/enums/party-member-strength.ts
index 793796a65b4..24e78e4d3d6 100644
--- a/src/enums/party-member-strength.ts
+++ b/src/enums/party-member-strength.ts
@@ -4,5 +4,5 @@ export enum PartyMemberStrength {
WEAK,
AVERAGE,
STRONG,
- STRONGER
+ STRONGER,
}
diff --git a/src/enums/passive.ts b/src/enums/passive.ts
index b9c2dacd463..88ff0d960c7 100644
--- a/src/enums/passive.ts
+++ b/src/enums/passive.ts
@@ -3,5 +3,5 @@
*/
export enum Passive {
UNLOCKED = 1,
- ENABLED = 2
+ ENABLED = 2,
}
diff --git a/src/enums/player-gender.ts b/src/enums/player-gender.ts
index b6cd550b1f2..72f9c556f5e 100644
--- a/src/enums/player-gender.ts
+++ b/src/enums/player-gender.ts
@@ -4,5 +4,5 @@
export enum PlayerGender {
UNSET,
MALE,
- FEMALE
+ FEMALE,
}
diff --git a/src/enums/pokemon-anim-type.ts b/src/enums/pokemon-anim-type.ts
index b153fb2e652..daee1d1ae31 100644
--- a/src/enums/pokemon-anim-type.ts
+++ b/src/enums/pokemon-anim-type.ts
@@ -22,5 +22,5 @@ export enum PokemonAnimType {
* Dondozo "spits out" Tatsugiri, moving Tatsugiri back to its original
* field position.
*/
- COMMANDER_REMOVE
+ COMMANDER_REMOVE,
}
diff --git a/src/enums/pokemon-type.ts b/src/enums/pokemon-type.ts
index 034bf81c33f..f4002d91491 100644
--- a/src/enums/pokemon-type.ts
+++ b/src/enums/pokemon-type.ts
@@ -19,8 +19,8 @@ export enum PokemonType {
DRAGON,
DARK,
FAIRY,
- STELLAR
+ STELLAR,
}
/** The largest legal value for a {@linkcode PokemonType} (includes Stellar) */
-export const MAX_POKEMON_TYPE = PokemonType.STELLAR;
\ No newline at end of file
+export const MAX_POKEMON_TYPE = PokemonType.STELLAR;
diff --git a/src/enums/shop-cursor-target.ts b/src/enums/shop-cursor-target.ts
index 11f524399b2..2d788f50883 100644
--- a/src/enums/shop-cursor-target.ts
+++ b/src/enums/shop-cursor-target.ts
@@ -9,5 +9,5 @@ export enum ShopCursorTarget {
/** Cursor points to Shop row */
SHOP,
/** Cursor points to Check Team row */
- CHECK_TEAM
+ CHECK_TEAM,
}
diff --git a/src/enums/stat.ts b/src/enums/stat.ts
index 72ccc065850..36e9891f23c 100644
--- a/src/enums/stat.ts
+++ b/src/enums/stat.ts
@@ -15,28 +15,28 @@ export enum Stat {
/** Accuracy */
ACC,
/** Evasiveness */
- EVA
+ EVA,
}
/** A constant array comprised of the {@linkcode Stat} values that make up {@linkcode PermanentStat}. */
-export const PERMANENT_STATS = [ Stat.HP, Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD ] as const;
+export const PERMANENT_STATS = [Stat.HP, Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD] as const;
/** Type used to describe the core, permanent stats of a Pokemon. */
-export type PermanentStat = typeof PERMANENT_STATS[number];
+export type PermanentStat = (typeof PERMANENT_STATS)[number];
/** A constant array comprised of the {@linkcode Stat} values that make up {@linkcode EFfectiveStat}. */
-export const EFFECTIVE_STATS = [ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD ] as const;
+export const EFFECTIVE_STATS = [Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD] as const;
/** Type used to describe the intersection of core stats and stats that have stages in battle. */
-export type EffectiveStat = typeof EFFECTIVE_STATS[number];
+export type EffectiveStat = (typeof EFFECTIVE_STATS)[number];
/** A constant array comprised of {@linkcode Stat} the values that make up {@linkcode BattleStat}. */
-export const BATTLE_STATS = [ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD, Stat.ACC, Stat.EVA ] as const;
+export const BATTLE_STATS = [Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD, Stat.ACC, Stat.EVA] as const;
/** Type used to describe the stats that have stages which can be incremented and decremented in battle. */
-export type BattleStat = typeof BATTLE_STATS[number];
+export type BattleStat = (typeof BATTLE_STATS)[number];
/** A constant array comprised of {@linkcode Stat} the values that make up {@linkcode TempBattleStat}. */
-export const TEMP_BATTLE_STATS = [ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD, Stat.ACC ] as const;
+export const TEMP_BATTLE_STATS = [Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD, Stat.ACC] as const;
/** Type used to describe the stats that have X item (`TEMP_STAT_STAGE_BOOSTER`) equivalents. */
-export type TempBattleStat = typeof TEMP_BATTLE_STATS[number];
+export type TempBattleStat = (typeof TEMP_BATTLE_STATS)[number];
/**
* Provides the translation key corresponding to the amount of stat stages and whether those stat stages
diff --git a/src/enums/tera-ai-mode.ts b/src/enums/tera-ai-mode.ts
index 35d4e4f3420..a31ad9fd810 100644
--- a/src/enums/tera-ai-mode.ts
+++ b/src/enums/tera-ai-mode.ts
@@ -1,5 +1,5 @@
export enum TeraAIMode {
NO_TERA,
INSTANT_TERA,
- SMART_TERA
+ SMART_TERA,
}
diff --git a/src/enums/text-style.ts b/src/enums/text-style.ts
index 964a985cdd6..1c6f4e8ca1b 100644
--- a/src/enums/text-style.ts
+++ b/src/enums/text-style.ts
@@ -54,6 +54,6 @@ export const TextStyle = Object.freeze({
PERFECT_IV: 53,
ME_OPTION_DEFAULT: 54, // Default style for choices in ME
ME_OPTION_SPECIAL: 55, // Style for choices with special requirements in ME
- SHADOW_TEXT: 56 // to obscure unavailable options
-})
-export type TextStyle = typeof TextStyle[keyof typeof TextStyle];
\ No newline at end of file
+ SHADOW_TEXT: 56, // to obscure unavailable options
+});
+export type TextStyle = (typeof TextStyle)[keyof typeof TextStyle];
diff --git a/src/enums/time-of-day.ts b/src/enums/time-of-day.ts
index 3fd05308cc6..a5a15f39ef8 100644
--- a/src/enums/time-of-day.ts
+++ b/src/enums/time-of-day.ts
@@ -3,5 +3,5 @@ export enum TimeOfDay {
DAWN,
DAY,
DUSK,
- NIGHT
+ NIGHT,
}
diff --git a/src/enums/trainer-pool-tier.ts b/src/enums/trainer-pool-tier.ts
index da6355d021b..08f37062d85 100644
--- a/src/enums/trainer-pool-tier.ts
+++ b/src/enums/trainer-pool-tier.ts
@@ -3,5 +3,5 @@ export enum TrainerPoolTier {
UNCOMMON,
RARE,
SUPER_RARE,
- ULTRA_RARE
+ ULTRA_RARE,
}
diff --git a/src/enums/trainer-slot.ts b/src/enums/trainer-slot.ts
index 2dfa468f74c..8e801e03d0f 100644
--- a/src/enums/trainer-slot.ts
+++ b/src/enums/trainer-slot.ts
@@ -1,5 +1,5 @@
export enum TrainerSlot {
NONE,
TRAINER,
- TRAINER_PARTNER
+ TRAINER_PARTNER,
}
diff --git a/src/enums/trainer-type.ts b/src/enums/trainer-type.ts
index e22dc5d81c7..9e8705e9886 100644
--- a/src/enums/trainer-type.ts
+++ b/src/enums/trainer-type.ts
@@ -255,5 +255,5 @@ export enum TrainerType {
RIVAL_3,
RIVAL_4,
RIVAL_5,
- RIVAL_6
+ RIVAL_6,
}
diff --git a/src/enums/trainer-variant.ts b/src/enums/trainer-variant.ts
index cd8d71cc1b9..074079458a6 100644
--- a/src/enums/trainer-variant.ts
+++ b/src/enums/trainer-variant.ts
@@ -1,5 +1,5 @@
export enum TrainerVariant {
DEFAULT,
FEMALE,
- DOUBLE
+ DOUBLE,
}
diff --git a/src/enums/ui-theme.ts b/src/enums/ui-theme.ts
index 50b5c4f65a3..0592db13b6e 100644
--- a/src/enums/ui-theme.ts
+++ b/src/enums/ui-theme.ts
@@ -1,4 +1,4 @@
export enum UiTheme {
DEFAULT,
- LEGACY
+ LEGACY,
}
diff --git a/src/enums/unlockables.ts b/src/enums/unlockables.ts
index 77b39a17e90..7ff21285870 100644
--- a/src/enums/unlockables.ts
+++ b/src/enums/unlockables.ts
@@ -1,7 +1,6 @@
-
export enum Unlockables {
ENDLESS_MODE,
MINI_BLACK_HOLE,
SPLICED_ENDLESS_MODE,
- EVIOLITE
+ EVIOLITE,
}
diff --git a/src/enums/variant-tier.ts b/src/enums/variant-tier.ts
index 279846d5f60..67c04eda3da 100644
--- a/src/enums/variant-tier.ts
+++ b/src/enums/variant-tier.ts
@@ -1,5 +1,5 @@
export enum VariantTier {
- STANDARD,
- RARE,
- EPIC
+ STANDARD,
+ RARE,
+ EPIC,
}
diff --git a/src/field/arena.ts b/src/field/arena.ts
index 5ae092b562a..ed23e42b119 100644
--- a/src/field/arena.ts
+++ b/src/field/arena.ts
@@ -116,9 +116,11 @@ export class Arena {
return overrideSpecies;
}
const isBossSpecies =
- !!globalScene.getEncounterBossSegments(waveIndex, level) &&
- !!this.pokemonPool[BiomePoolTier.BOSS].length &&
- (this.biomeType !== BiomeId.END || globalScene.gameMode.isClassic || globalScene.gameMode.isWaveFinal(waveIndex));
+ !!globalScene.getEncounterBossSegments(waveIndex, level)
+ && this.pokemonPool[BiomePoolTier.BOSS].length > 0
+ && (this.biomeType !== BiomeId.END
+ || globalScene.gameMode.isClassic
+ || globalScene.gameMode.isWaveFinal(waveIndex));
const randVal = isBossSpecies ? 64 : 512;
// luck influences encounter rarity
let luckModifier = 0;
@@ -144,14 +146,14 @@ export class Arena {
? BiomePoolTier.BOSS_SUPER_RARE
: BiomePoolTier.BOSS_ULTRA_RARE;
console.log(BiomePoolTier[tier]);
- while (!this.pokemonPool[tier]?.length) {
+ while (this.pokemonPool[tier]?.length === 0) {
console.log(`Downgraded rarity tier from ${BiomePoolTier[tier]} to ${BiomePoolTier[tier - 1]}`);
tier--;
}
const tierPool = this.pokemonPool[tier];
let ret: PokemonSpecies;
let regen = false;
- if (!tierPool.length) {
+ if (tierPool.length === 0) {
ret = globalScene.randomSpecies(waveIndex, level);
} else {
// TODO: should this use `randSeedItem`?
@@ -203,8 +205,8 @@ export class Arena {
randomTrainerType(waveIndex: number, isBoss = false): TrainerType {
const isTrainerBoss =
- !!this.trainerPool[BiomePoolTier.BOSS].length &&
- (globalScene.gameMode.isTrainerBoss(waveIndex, this.biomeType, globalScene.offsetGym) || isBoss);
+ this.trainerPool[BiomePoolTier.BOSS].length > 0
+ && (globalScene.gameMode.isTrainerBoss(waveIndex, this.biomeType, globalScene.offsetGym) || isBoss);
console.log(isBoss, this.trainerPool);
const tierValue = randSeedInt(!isTrainerBoss ? 512 : 64);
let tier = !isTrainerBoss
@@ -225,12 +227,12 @@ export class Arena {
? BiomePoolTier.BOSS_SUPER_RARE
: BiomePoolTier.BOSS_ULTRA_RARE;
console.log(BiomePoolTier[tier]);
- while (tier && !this.trainerPool[tier].length) {
+ while (tier && this.trainerPool[tier].length === 0) {
console.log(`Downgraded trainer rarity tier from ${BiomePoolTier[tier]} to ${BiomePoolTier[tier - 1]}`);
tier--;
}
const tierPool = this.trainerPool[tier] || [];
- return !tierPool.length ? TrainerType.BREEDER : tierPool[randSeedInt(tierPool.length)];
+ return tierPool.length === 0 ? TrainerType.BREEDER : tierPool[randSeedInt(tierPool.length)];
}
getSpeciesFormIndex(species: PokemonSpecies): number {
@@ -322,15 +324,14 @@ export class Arena {
const oldWeatherType = this.weather?.weatherType || WeatherType.NONE;
if (
- this.weather?.isImmutable() &&
- ![WeatherType.HARSH_SUN, WeatherType.HEAVY_RAIN, WeatherType.STRONG_WINDS, WeatherType.NONE].includes(weather)
+ this.weather?.isImmutable()
+ && ![WeatherType.HARSH_SUN, WeatherType.HEAVY_RAIN, WeatherType.STRONG_WINDS, WeatherType.NONE].includes(weather)
) {
globalScene.phaseManager.unshiftNew(
"CommonAnimPhase",
undefined,
undefined,
CommonAnim.SUNNY + (oldWeatherType - 1),
- true,
);
globalScene.phaseManager.queueMessage(getLegendaryWeatherContinuesMessage(oldWeatherType)!);
return false;
@@ -349,13 +350,7 @@ export class Arena {
); // TODO: is this bang correct?
if (this.weather) {
- globalScene.phaseManager.unshiftNew(
- "CommonAnimPhase",
- undefined,
- undefined,
- CommonAnim.SUNNY + (weather - 1),
- true,
- );
+ globalScene.phaseManager.unshiftNew("CommonAnimPhase", undefined, undefined, CommonAnim.SUNNY + (weather - 1));
globalScene.phaseManager.queueMessage(getWeatherStartMessage(weather)!); // TODO: is this bang correct?
} else {
globalScene.phaseManager.queueMessage(getWeatherClearMessage(oldWeatherType)!); // TODO: is this bang correct?
@@ -835,7 +830,7 @@ export class Arena {
}
removeAllTags(): void {
- while (this.tags.length) {
+ while (this.tags.length > 0) {
this.tags[0].onRemove(this);
this.eventTarget.dispatchEvent(
new TagRemovedEvent(this.tags[0].tagType, this.tags[0].side, this.tags[0].turnCount),
diff --git a/src/field/mystery-encounter-intro.ts b/src/field/mystery-encounter-intro.ts
index d3776f349e6..cf0a0f30529 100644
--- a/src/field/mystery-encounter-intro.ts
+++ b/src/field/mystery-encounter-intro.ts
@@ -87,6 +87,7 @@ export class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Container {
variant: Variant;
}[];
+ // TODO: Refactor
constructor(encounter: MysteryEncounter) {
super(globalScene, -72, 76);
this.encounter = encounter;
@@ -193,17 +194,15 @@ export class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Container {
sprite.setPosition(sprite.x, sprite.y + y);
tintSprite.setPosition(tintSprite.x, tintSprite.y + y);
}
- } else {
// Single sprite
- if (this.spriteConfigs.length === 1) {
- sprite.x = origin;
- tintSprite.x = origin;
- } else {
- // Do standard sprite spacing (not including offset sprites)
- sprite.x = minX + (n + 0.5) * spacingValue + origin;
- tintSprite.x = minX + (n + 0.5) * spacingValue + origin;
- n++;
- }
+ } else if (this.spriteConfigs.length === 1) {
+ sprite.x = origin;
+ tintSprite.x = origin;
+ } else {
+ // Do standard sprite spacing (not including offset sprites)
+ sprite.x = minX + (n + 0.5) * spacingValue + origin;
+ tintSprite.x = minX + (n + 0.5) * spacingValue + origin;
+ n++;
}
if (!isNullOrUndefined(pokemonShinySparkle)) {
@@ -457,7 +456,7 @@ export class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Container {
globalScene.tweens.add({
targets: sprite,
alpha: alpha || 1,
- duration: duration,
+ duration,
ease: ease || "Linear",
});
} else {
@@ -490,7 +489,7 @@ export class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Container {
globalScene.tweens.add({
targets: sprite,
alpha: 0,
- duration: duration,
+ duration,
ease: ease || "Linear",
onComplete: () => {
sprite.setVisible(false);
diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts
index 65ffd223fa5..1ed1515f18b 100644
--- a/src/field/pokemon.ts
+++ b/src/field/pokemon.ts
@@ -148,8 +148,8 @@ import type { IllusionData } from "#types/illusion-data";
import type { TurnMove } from "#types/turn-move";
import { BattleInfo } from "#ui/battle-info";
import { EnemyBattleInfo } from "#ui/enemy-battle-info";
-import type { PartyOption } from "#ui/party-ui-handler";
-import { PartyUiHandler, PartyUiMode } from "#ui/party-ui-handler";
+import type { PartyOption } from "#ui/handlers/party-ui-handler";
+import { PartyUiHandler, PartyUiMode } from "#ui/handlers/party-ui-handler";
import { PlayerBattleInfo } from "#ui/player-battle-info";
import { applyChallenges } from "#utils/challenge-utils";
import {
@@ -348,7 +348,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
super(globalScene, x, y);
if (!species.isObtainable() && this.isPlayer()) {
- throw `Cannot create a player Pokemon for species "${species.getName(formIndex)}"`;
+ throw new Error(`Cannot create a player Pokemon for species "${species.getName(formIndex)}"`);
}
this.species = species;
@@ -926,7 +926,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
}
getFormKey(): string {
- if (!this.species.forms.length || this.species.forms.length <= this.formIndex) {
+ if (this.species.forms.length === 0 || this.species.forms.length <= this.formIndex) {
return "";
}
return this.species.forms[this.formIndex].formKey;
@@ -936,7 +936,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
if (!this.fusionSpecies) {
return null;
}
- if (!this.fusionSpecies.forms.length || this.fusionSpecies.forms.length <= this.fusionFormIndex) {
+ if (this.fusionSpecies.forms.length === 0 || this.fusionSpecies.forms.length <= this.fusionFormIndex) {
return "";
}
return this.fusionSpecies.forms[this.fusionFormIndex].formKey;
@@ -1112,17 +1112,13 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
return !(
// Neither pokemon can be already transformed
(
- this.isTransformed() ||
- target.isTransformed() ||
- // Neither pokemon can be behind an illusion
- target.summonData.illusion ||
- this.summonData.illusion ||
- // The target cannot be behind a substitute
- target.getTag(BattlerTagType.SUBSTITUTE) ||
- // Transforming to/from fusion pokemon causes various problems (crashes, etc.)
- // TODO: Consider lifting restriction once bug is fixed
- this.isFusion() ||
- target.isFusion()
+ this.isTransformed()
+ || target.isTransformed() // Neither pokemon can be behind an illusion
+ || target.summonData.illusion
+ || this.summonData.illusion // The target cannot be behind a substitute
+ || target.getTag(BattlerTagType.SUBSTITUTE) // Transforming to/from fusion pokemon causes various problems (crashes, etc.) // TODO: Consider lifting restriction once bug is fixed
+ || this.isFusion()
+ || target.isFusion()
)
);
}
@@ -1142,7 +1138,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
if (!ignoreOverride && this.summonData.fusionSpeciesForm) {
return this.summonData.fusionSpeciesForm;
}
- if (!fusionSpecies?.forms?.length || fusionFormIndex >= fusionSpecies?.forms.length) {
+ if (fusionSpecies?.forms?.length === 0 || fusionFormIndex >= fusionSpecies?.forms.length) {
return fusionSpecies;
}
return fusionSpecies?.forms[fusionFormIndex];
@@ -1159,12 +1155,12 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
getSpriteScale(): number {
const formKey = this.getFormKey();
if (
- this.isMax() === true ||
- formKey === "segin-starmobile" ||
- formKey === "schedar-starmobile" ||
- formKey === "navi-starmobile" ||
- formKey === "ruchbah-starmobile" ||
- formKey === "caph-starmobile"
+ this.isMax() === true
+ || formKey === "segin-starmobile"
+ || formKey === "schedar-starmobile"
+ || formKey === "navi-starmobile"
+ || formKey === "ruchbah-starmobile"
+ || formKey === "caph-starmobile"
) {
// G-Max and starmobiles have flat 1.5x scale
return 1.5;
@@ -1324,10 +1320,10 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
targets.push(subTag.sprite);
}
globalScene.tweens.add({
- targets: targets,
+ targets,
x: (_target, _key, value: number) => value + relX,
y: (_target, _key, value: number) => value + relY,
- duration: duration,
+ duration,
ease: "Sine.easeOut",
onComplete: () => resolve(),
});
@@ -1525,8 +1521,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
}
let ret =
- statVal.value *
- this.getStatStageMultiplier(stat, opponent, move, ignoreOppAbility, isCritical, simulated, ignoreHeldItems);
+ statVal.value
+ * this.getStatStageMultiplier(stat, opponent, move, ignoreOppAbility, isCritical, simulated, ignoreHeldItems);
switch (stat) {
case Stat.ATK:
@@ -1835,8 +1831,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
}
return (
- (this.species.speciesId === species && this.getFormKey() === formKey) ||
- (this.fusionSpecies?.speciesId === species && this.getFusionFormKey() === formKey)
+ (this.species.speciesId === species && this.getFormKey() === formKey)
+ || (this.fusionSpecies?.speciesId === species && this.getFusionFormKey() === formKey)
);
}
@@ -1933,12 +1929,12 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
}
}
}
- if (!types.length || !includeTeraType) {
+ if (types.length === 0 || !includeTeraType) {
if (
- !ignoreOverride &&
- this.summonData.types &&
- this.summonData.types.length > 0 &&
- (!this.summonData.illusion || !useIllusion)
+ !ignoreOverride
+ && this.summonData.types
+ && this.summonData.types.length > 0
+ && (!this.summonData.illusion || !useIllusion)
) {
this.summonData.types.forEach(t => types.push(t));
} else {
@@ -1959,15 +1955,15 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
if (fusionSpeciesForm) {
// Check if the fusion Pokemon also has permanent changes from ME when determining the fusion types
const fusionType1 =
- this.fusionCustomPokemonData?.types &&
- this.fusionCustomPokemonData.types.length > 0 &&
- this.fusionCustomPokemonData.types[0] !== PokemonType.UNKNOWN
+ this.fusionCustomPokemonData?.types
+ && this.fusionCustomPokemonData.types.length > 0
+ && this.fusionCustomPokemonData.types[0] !== PokemonType.UNKNOWN
? this.fusionCustomPokemonData.types[0]
: fusionSpeciesForm.type1;
const fusionType2 =
- this.fusionCustomPokemonData?.types &&
- this.fusionCustomPokemonData.types.length > 1 &&
- this.fusionCustomPokemonData.types[1] !== PokemonType.UNKNOWN
+ this.fusionCustomPokemonData?.types
+ && this.fusionCustomPokemonData.types.length > 1
+ && this.fusionCustomPokemonData.types[1] !== PokemonType.UNKNOWN
? this.fusionCustomPokemonData.types[1]
: fusionSpeciesForm.type2;
@@ -1981,18 +1977,18 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
if (secondType === PokemonType.UNKNOWN && isNullOrUndefined(fusionType2)) {
// If second pokemon was monotype and shared its primary type
secondType =
- customTypes &&
- this.customPokemonData.types.length > 1 &&
- this.customPokemonData.types[1] !== PokemonType.UNKNOWN
+ customTypes
+ && this.customPokemonData.types.length > 1
+ && this.customPokemonData.types[1] !== PokemonType.UNKNOWN
? this.customPokemonData.types[1]
: (speciesForm.type2 ?? PokemonType.UNKNOWN);
}
} else {
// If not a fusion, just get the second type from the species, checking for permanent changes from ME
secondType =
- customTypes &&
- this.customPokemonData.types.length > 1 &&
- this.customPokemonData.types[1] !== PokemonType.UNKNOWN
+ customTypes
+ && this.customPokemonData.types.length > 1
+ && this.customPokemonData.types[1] !== PokemonType.UNKNOWN
? this.customPokemonData.types[1]
: (speciesForm.type2 ?? PokemonType.UNKNOWN);
}
@@ -2004,7 +2000,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
}
// become UNKNOWN if no types are present
- if (!types.length) {
+ if (types.length === 0) {
types.push(PokemonType.UNKNOWN);
}
@@ -2154,16 +2150,16 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
public hasPassive(): boolean {
// returns override if valid for current case
if (
- (Overrides.HAS_PASSIVE_ABILITY_OVERRIDE === false && this.isPlayer()) ||
- (Overrides.ENEMY_HAS_PASSIVE_ABILITY_OVERRIDE === false && this.isEnemy())
+ (Overrides.HAS_PASSIVE_ABILITY_OVERRIDE === false && this.isPlayer())
+ || (Overrides.ENEMY_HAS_PASSIVE_ABILITY_OVERRIDE === false && this.isEnemy())
) {
return false;
}
if (
- ((Overrides.PASSIVE_ABILITY_OVERRIDE !== AbilityId.NONE || Overrides.HAS_PASSIVE_ABILITY_OVERRIDE) &&
- this.isPlayer()) ||
- ((Overrides.ENEMY_PASSIVE_ABILITY_OVERRIDE !== AbilityId.NONE || Overrides.ENEMY_HAS_PASSIVE_ABILITY_OVERRIDE) &&
- this.isEnemy())
+ ((Overrides.PASSIVE_ABILITY_OVERRIDE !== AbilityId.NONE || Overrides.HAS_PASSIVE_ABILITY_OVERRIDE)
+ && this.isPlayer())
+ || ((Overrides.ENEMY_PASSIVE_ABILITY_OVERRIDE !== AbilityId.NONE || Overrides.ENEMY_HAS_PASSIVE_ABILITY_OVERRIDE)
+ && this.isEnemy())
) {
return true;
}
@@ -2172,10 +2168,10 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
const { currentBattle, gameMode } = globalScene;
const waveIndex = currentBattle?.waveIndex;
if (
- this.isEnemy() &&
- (currentBattle?.battleSpec === BattleSpec.FINAL_BOSS ||
- gameMode.isEndlessMinorBoss(waveIndex) ||
- gameMode.isEndlessMajorBoss(waveIndex))
+ this.isEnemy()
+ && (currentBattle?.battleSpec === BattleSpec.FINAL_BOSS
+ || gameMode.isEndlessMinorBoss(waveIndex)
+ || gameMode.isEndlessMajorBoss(waveIndex))
) {
return false;
}
@@ -2214,9 +2210,9 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
// (Balance decided that the other ability of a neutralizing gas pokemon should not be neutralized)
// If the ability itself is neutralizing gas, don't suppress it (handled through arena tag)
const unsuppressable =
- !ability.isSuppressable ||
- thisAbilitySuppressing ||
- (hasSuppressingAbility && !suppressAbilitiesTag.shouldApplyToSelf());
+ !ability.isSuppressable
+ || thisAbilitySuppressing
+ || (hasSuppressingAbility && !suppressAbilitiesTag.shouldApplyToSelf());
if (!unsuppressable) {
return false;
}
@@ -2317,11 +2313,11 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
public isGrounded(): boolean {
return (
- !!this.getTag(GroundedTag) ||
- (!this.isOfType(PokemonType.FLYING, true, true) &&
- !this.hasAbility(AbilityId.LEVITATE) &&
- !this.getTag(BattlerTagType.FLOATING) &&
- !this.getTag(SemiInvulnerableTag))
+ !!this.getTag(GroundedTag)
+ || (!this.isOfType(PokemonType.FLYING, true, true)
+ && !this.hasAbility(AbilityId.LEVITATE)
+ && !this.getTag(BattlerTagType.FLOATING)
+ && !this.getTag(SemiInvulnerableTag))
);
}
@@ -2387,9 +2383,9 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
// If the user is terastallized and the move is tera blast, or tera starstorm that is stellar type,
// then bypass the check for ion deluge and electrify
if (
- this.isTerastallized &&
- (move.id === MoveId.TERA_BLAST ||
- (move.id === MoveId.TERA_STARSTORM && moveTypeHolder.value === PokemonType.STELLAR))
+ this.isTerastallized
+ && (move.id === MoveId.TERA_BLAST
+ || (move.id === MoveId.TERA_STARSTORM && moveTypeHolder.value === PokemonType.STELLAR))
) {
return moveTypeHolder.value as PokemonType;
}
@@ -2556,11 +2552,11 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
// Handle strong winds lowering effectiveness of types super effective against pure flying
if (
- !ignoreStrongWinds &&
- arena.getWeatherType() === WeatherType.STRONG_WINDS &&
- !arena.weather?.isEffectSuppressed() &&
- types.includes(PokemonType.FLYING) &&
- getTypeDamageMultiplier(moveType, PokemonType.FLYING) === 2
+ !ignoreStrongWinds
+ && arena.getWeatherType() === WeatherType.STRONG_WINDS
+ && !arena.weather.isEffectSuppressed()
+ && this.isOfType(PokemonType.FLYING)
+ && getTypeDamageMultiplier(moveType, PokemonType.FLYING) === 2
) {
multi.value /= 2;
if (!simulated) {
@@ -2616,8 +2612,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
const enemyTypes = opponent.getTypes(true, false, false, true);
/** Is this Pokemon faster than the opponent? */
const outspeed =
- (this.isActive(true) ? this.getEffectiveStat(Stat.SPD, opponent) : this.getStat(Stat.SPD, false)) >=
- opponent.getEffectiveStat(Stat.SPD, this);
+ (this.isActive(true) ? this.getEffectiveStat(Stat.SPD, opponent) : this.getStat(Stat.SPD, false))
+ >= opponent.getEffectiveStat(Stat.SPD, this);
/**
* Based on how effectively this Pokemon defends against the opponent's types.
@@ -2746,9 +2742,9 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
.getLevelMoves()
.filter(
lm =>
- (includeEvolutionMoves && lm[0] === EVOLVE_MOVE) ||
- (includeRelearnerMoves && lm[0] === RELEARN_MOVE) ||
- lm[0] > 0,
+ (includeEvolutionMoves && lm[0] === EVOLVE_MOVE)
+ || (includeRelearnerMoves && lm[0] === RELEARN_MOVE)
+ || lm[0] > 0,
);
} else {
if (simulateEvolutionChain) {
@@ -2767,8 +2763,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
levelMoves.push(
...speciesLevelMoves.filter(
lm =>
- (includeEvolutionMoves && lm[0] === EVOLVE_MOVE) ||
- ((!e || lm[0] > 1) && (e === evolutionChain.length - 1 || lm[0] <= evolutionChain[e + 1][1])),
+ (includeEvolutionMoves && lm[0] === EVOLVE_MOVE)
+ || ((!e || lm[0] > 1) && (e === evolutionChain.length - 1 || lm[0] <= evolutionChain[e + 1][1])),
),
);
}
@@ -2778,9 +2774,9 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
.getLevelMoves()
.filter(
lm =>
- (includeEvolutionMoves && lm[0] === EVOLVE_MOVE) ||
- (includeRelearnerMoves && lm[0] === RELEARN_MOVE) ||
- lm[0] > 0,
+ (includeEvolutionMoves && lm[0] === EVOLVE_MOVE)
+ || (includeRelearnerMoves && lm[0] === RELEARN_MOVE)
+ || lm[0] > 0,
);
}
if (this.fusionSpecies && learnSituation !== LearnMoveSituation.EVOLUTION_FUSED_BASE) {
@@ -2808,9 +2804,9 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
levelMoves.push(
...speciesLevelMoves.filter(
lm =>
- (includeEvolutionMoves && lm[0] === EVOLVE_MOVE) ||
- ((!e || lm[0] > 1) &&
- (e === fusionEvolutionChain.length - 1 || lm[0] <= fusionEvolutionChain[e + 1][1])),
+ (includeEvolutionMoves && lm[0] === EVOLVE_MOVE)
+ || ((!e || lm[0] > 1)
+ && (e === fusionEvolutionChain.length - 1 || lm[0] <= fusionEvolutionChain[e + 1][1])),
),
);
}
@@ -2821,9 +2817,9 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
.getLevelMoves()
.filter(
lm =>
- (includeEvolutionMoves && lm[0] === EVOLVE_MOVE) ||
- (includeRelearnerMoves && lm[0] === RELEARN_MOVE) ||
- lm[0] > 0,
+ (includeEvolutionMoves && lm[0] === EVOLVE_MOVE)
+ || (includeRelearnerMoves && lm[0] === RELEARN_MOVE)
+ || lm[0] > 0,
),
);
}
@@ -2993,8 +2989,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
}
// Checks if there is no variant data for both the index or index with form
if (
- !this.shiny ||
- (!variantData.hasOwnProperty(variantDataIndex) && !variantData.hasOwnProperty(this.species.speciesId))
+ !this.shiny
+ || (!variantData.hasOwnProperty(variantDataIndex) && !variantData.hasOwnProperty(this.species.speciesId))
) {
return 0;
}
@@ -3029,10 +3025,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
return false;
}
const haThreshold = new NumberHolder(thresholdOverride ?? BASE_HIDDEN_ABILITY_CHANCE);
- if (applyModifiersToOverride) {
- if (!this.hasTrainer()) {
- globalScene.applyModifiers(HiddenAbilityRateBoosterModifier, true, haThreshold);
- }
+ if (applyModifiersToOverride && !this.hasTrainer()) {
+ globalScene.applyModifiers(HiddenAbilityRateBoosterModifier, true, haThreshold);
}
if (randSeedInt(65536) < haThreshold.value) {
@@ -3055,14 +3049,14 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
? this.species.getCompatibleFusionSpeciesFilter()
: (species: PokemonSpecies) => {
return (
- pokemonEvolutions.hasOwnProperty(species.speciesId) &&
- !pokemonPrevolutions.hasOwnProperty(species.speciesId) &&
- !species.subLegendary &&
- !species.legendary &&
- !species.mythical &&
- !species.isTrainerForbidden() &&
- species.speciesId !== this.species.speciesId &&
- species.speciesId !== SpeciesId.DITTO
+ pokemonEvolutions.hasOwnProperty(species.speciesId)
+ && !pokemonPrevolutions.hasOwnProperty(species.speciesId)
+ && !species.subLegendary
+ && !species.legendary
+ && !species.mythical
+ && !species.isTrainerForbidden()
+ && species.speciesId !== this.species.speciesId
+ && species.speciesId !== SpeciesId.DITTO
);
};
@@ -3075,8 +3069,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
}
this.fusionSpecies =
- fusionOverride ??
- globalScene.randomSpecies(globalScene.currentBattle?.waveIndex || 0, this.level, false, filter, true);
+ fusionOverride
+ ?? globalScene.randomSpecies(globalScene.currentBattle?.waveIndex || 0, this.level, false, filter, true);
this.fusionAbilityIndex =
this.fusionSpecies.abilityHidden && hasHiddenAbility
? 2
@@ -3126,14 +3120,13 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
public generateAndPopulateMoveset(): void {
this.moveset = [];
let movePool: [MoveId, number][] = [];
- const allLevelMoves = this.getLevelMoves(1, true, true);
+ const allLevelMoves = this.getLevelMoves(1, true, true, this.hasTrainer());
if (!allLevelMoves) {
console.warn("Error encountered trying to generate moveset for:", this.species.name);
return;
}
- for (let m = 0; m < allLevelMoves.length; m++) {
- const levelMove = allLevelMoves[m];
+ for (const levelMove of allLevelMoves) {
if (this.level < levelMove[0]) {
break;
}
@@ -3144,8 +3137,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
}
// Assume level 1 moves with 80+ BP are "move reminder" moves and bump their weight. Trainers use actual relearn moves.
if (
- (levelMove[0] === 1 && allMoves[levelMove[1]].power >= 80) ||
- (levelMove[0] === RELEARN_MOVE && this.hasTrainer())
+ (levelMove[0] === 1 && allMoves[levelMove[1]].power >= 80)
+ || (levelMove[0] === RELEARN_MOVE && this.hasTrainer())
) {
weight = 60;
}
@@ -3162,10 +3155,10 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
for (const p of tmSpecies[tm]) {
if (Array.isArray(p)) {
if (
- p[0] === this.species.speciesId ||
- (this.fusionSpecies &&
- p[0] === this.fusionSpecies.speciesId &&
- p.slice(1).indexOf(this.species.forms[this.formIndex]) > -1)
+ p[0] === this.species.speciesId
+ || (this.fusionSpecies
+ && p[0] === this.fusionSpecies.speciesId
+ && p.slice(1).indexOf(this.species.forms[this.formIndex]) > -1)
) {
compatible = true;
break;
@@ -3197,10 +3190,10 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
const moveId = speciesEggMoves[this.species.getRootSpeciesId()][3];
// No rare egg moves before e4
if (
- this.level >= 170 &&
- !movePool.some(m => m[0] === moveId) &&
- !allMoves[moveId].name.endsWith(" (N)") &&
- !this.isBoss()
+ this.level >= 170
+ && !movePool.some(m => m[0] === moveId)
+ && !allMoves[moveId].name.endsWith(" (N)")
+ && !this.isBoss()
) {
movePool.push([moveId, 50]);
}
@@ -3214,10 +3207,10 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
const moveId = speciesEggMoves[this.fusionSpecies.getRootSpeciesId()][3];
// No rare egg moves before e4
if (
- this.level >= 170 &&
- !movePool.some(m => m[0] === moveId) &&
- !allMoves[moveId].name.endsWith(" (N)") &&
- !this.isBoss()
+ this.level >= 170
+ && !movePool.some(m => m[0] === moveId)
+ && !allMoves[moveId].name.endsWith(" (N)")
+ && !this.isBoss()
) {
movePool.push([moveId, 50]);
}
@@ -3259,8 +3252,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
);
movePool = movePool.map(m => [
m[0],
- m[1] *
- (allMoves[m[0]].category === MoveCategory.STATUS
+ m[1]
+ * (allMoves[m[0]].category === MoveCategory.STATUS
? 1
: Math.max(Math.min(allMoves[m[0]].calculateEffectivePower() / maxPower, 1), 0.5)),
]);
@@ -3292,7 +3285,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
m => allMoves[m[0]].category !== MoveCategory.STATUS && this.isOfType(allMoves[m[0]].type),
);
- if (stabMovePool.length) {
+ if (stabMovePool.length > 0) {
const totalWeight = stabMovePool.reduce((v, m) => v + m[1], 0);
let rand = randSeedInt(totalWeight);
let index = 0;
@@ -3303,7 +3296,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
} else {
// If there are no damaging STAB moves, just force a random damaging move
const attackMovePool = baseWeights.filter(m => allMoves[m[0]].category !== MoveCategory.STATUS);
- if (attackMovePool.length) {
+ if (attackMovePool.length > 0) {
const totalWeight = attackMovePool.reduce((v, m) => v + m[1], 0);
let rand = randSeedInt(totalWeight);
let index = 0;
@@ -3324,8 +3317,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
m =>
!this.moveset.some(
mo =>
- m[0] === mo.moveId ||
- (allMoves[m[0]].hasAttr("SacrificialAttr") && mo.getMove().hasAttr("SacrificialAttr")), // Only one self-KO move allowed
+ m[0] === mo.moveId
+ || (allMoves[m[0]].hasAttr("SacrificialAttr") && mo.getMove().hasAttr("SacrificialAttr")), // Only one self-KO move allowed
),
)
.map(m => {
@@ -3338,9 +3331,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
ret = Math.ceil(Math.sqrt(m[1]));
} else if (allMoves[m[0]].category !== MoveCategory.STATUS) {
ret = Math.ceil(
- (m[1] /
- Math.max(Math.pow(4, this.moveset.filter(mo => (mo.getMove().power ?? 0) > 1).length) / 8, 0.5)) *
- (this.isOfType(allMoves[m[0]].type) ? 20 : 1),
+ (m[1] / Math.max(Math.pow(4, this.moveset.filter(mo => (mo.getMove().power ?? 0) > 1).length) / 8, 0.5))
+ * (this.isOfType(allMoves[m[0]].type) ? 20 : 1),
);
} else {
ret = m[1];
@@ -3353,8 +3345,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
m =>
!this.moveset.some(
mo =>
- m[0] === mo.moveId ||
- (allMoves[m[0]].hasAttr("SacrificialAttr") && mo.getMove().hasAttr("SacrificialAttr")), // Only one self-KO move allowed
+ m[0] === mo.moveId
+ || (allMoves[m[0]].hasAttr("SacrificialAttr") && mo.getMove().hasAttr("SacrificialAttr")), // Only one self-KO move allowed
),
);
}
@@ -3369,9 +3361,9 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
// Trigger FormChange, except for enemy Pokemon during Mystery Encounters, to avoid crashes
if (
- this.isPlayer() ||
- !globalScene.currentBattle?.isBattleMysteryEncounter() ||
- !globalScene.currentBattle?.mysteryEncounter
+ this.isPlayer()
+ || !globalScene.currentBattle?.isBattleMysteryEncounter()
+ || !globalScene.currentBattle?.mysteryEncounter
) {
globalScene.triggerPokemonFormChange(this, SpeciesFormChangeMoveLearnedTrigger);
}
@@ -3777,9 +3769,9 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
}
if (
- source.isTerastallized &&
- source.getTeraType() === PokemonType.STELLAR &&
- (!source.stellarTypesBoosted.includes(moveType) || source.hasSpecies(SpeciesId.TERAPAGOS))
+ source.isTerastallized
+ && source.getTeraType() === PokemonType.STELLAR
+ && (!source.stellarTypesBoosted.includes(moveType) || source.hasSpecies(SpeciesId.TERAPAGOS))
) {
stabMultiplier.value += matchesSourceType ? 0.5 : 0.2;
}
@@ -3948,10 +3940,10 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
/** Halves damage if the attacker is using a physical attack while burned */
let burnMultiplier = 1;
if (
- isPhysical &&
- source.status &&
- source.status.effect === StatusEffect.BURN &&
- !move.hasAttr("BypassBurnDamageReductionAttr")
+ isPhysical
+ && source.status
+ && source.status.effect === StatusEffect.BURN
+ && !move.hasAttr("BypassBurnDamageReductionAttr")
) {
const burnDamageReductionCancelled = new BooleanHolder(false);
if (!ignoreSourceAbility) {
@@ -3999,26 +3991,26 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
/** Halves damage if this Pokemon is grounded in Misty Terrain against a Dragon-type attack */
const mistyTerrainMultiplier =
- globalScene.arena.terrain?.terrainType === TerrainType.MISTY &&
- this.isGrounded() &&
- moveType === PokemonType.DRAGON
+ globalScene.arena.terrain?.terrainType === TerrainType.MISTY
+ && this.isGrounded()
+ && moveType === PokemonType.DRAGON
? 0.5
: 1;
damage.value = toDmgValue(
- baseDamage *
- targetMultiplier *
- multiStrikeEnhancementMultiplier.value *
- arenaAttackTypeMultiplier.value *
- glaiveRushMultiplier.value *
- criticalMultiplier.value *
- randomMultiplier *
- stabMultiplier *
- typeMultiplier *
- burnMultiplier *
- screenMultiplier.value *
- hitsTagMultiplier.value *
- mistyTerrainMultiplier,
+ baseDamage
+ * targetMultiplier
+ * multiStrikeEnhancementMultiplier.value
+ * arenaAttackTypeMultiplier.value
+ * glaiveRushMultiplier.value
+ * criticalMultiplier.value
+ * randomMultiplier
+ * stabMultiplier
+ * typeMultiplier
+ * burnMultiplier
+ * screenMultiplier.value
+ * hitsTagMultiplier.value
+ * mistyTerrainMultiplier,
);
/** Doubles damage if the attacker has Tinted Lens and is using a resisted move */
@@ -4193,7 +4185,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
isCritical = false,
ignoreSegments = false,
ignoreFaintPhase = false,
- source = undefined,
+ source,
}: {
result?: DamageResult;
isCritical?: boolean;
@@ -4262,8 +4254,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
SpeciesFormKey.PRIMAL,
] as string[];
return (
- megaForms.includes(this.getFormKey()) ||
- (!!this.getFusionFormKey() && megaForms.includes(this.getFusionFormKey()!))
+ megaForms.includes(this.getFormKey())
+ || (!!this.getFusionFormKey() && megaForms.includes(this.getFusionFormKey()!))
);
}
@@ -4382,8 +4374,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
tags
.filter(
t =>
- lapseType === BattlerTagLapseType.FAINT ||
- (t.lapseTypes.some(lType => lType === lapseType) && !t.lapse(this, lapseType)),
+ lapseType === BattlerTagLapseType.FAINT
+ || (t.lapseTypes.some(lType => lType === lapseType) && !t.lapse(this, lapseType)),
)
.forEach(t => {
t.onRemove(this);
@@ -4446,10 +4438,10 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
for (const tag of source.summonData.tags) {
if (
- !tag.isBatonPassable ||
- (tag.tagType === BattlerTagType.TELEKINESIS &&
- this.species.speciesId === SpeciesId.GENGAR &&
- this.getFormKey() === "mega")
+ !tag.isBatonPassable
+ || (tag.tagType === BattlerTagType.TELEKINESIS
+ && this.species.speciesId === SpeciesId.GENGAR
+ && this.getFormKey() === "mega")
) {
continue;
}
@@ -4564,9 +4556,9 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
getLastNonVirtualMove(ignoreStruggle = false, ignoreFollowUp = true): TurnMove | undefined {
return this.getLastXMoves(-1).find(
m =>
- m.move !== MoveId.NONE &&
- (!ignoreStruggle || m.move !== MoveId.STRUGGLE) &&
- (!isVirtual(m.useMode) || (!ignoreFollowUp && m.useMode === MoveUseMode.FOLLOW_UP)),
+ m.move !== MoveId.NONE
+ && (!ignoreStruggle || m.move !== MoveId.STRUGGLE)
+ && (!isVirtual(m.useMode) || (!ignoreFollowUp && m.useMode === MoveUseMode.FOLLOW_UP)),
);
}
@@ -4725,13 +4717,13 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
const key = this.species.getCryKey(this.formIndex);
let i = 0;
let rate = 0.85;
- const cry = globalScene.playSound(key, { rate: rate });
+ const cry = globalScene.playSound(key, { rate });
const sprite = this.getSprite();
const tintSprite = this.getTintSprite();
const fusionCryKey = this.fusionSpecies!.getCryKey(this.fusionFormIndex);
let fusionCry = globalScene.playSound(fusionCryKey, {
- rate: rate,
+ rate,
});
if (!cry || !fusionCry || globalScene.fieldVolume === 0) {
callback();
@@ -4784,7 +4776,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
// TODO: This bang is correct as this callback can only be called once, but
// this whole block with conditionally reassigning fusionCry needs a second lock.
seek: Math.max(fusionCry!.totalDuration * 0.4, 0),
- rate: rate,
+ rate,
});
if (fusionCry) {
SoundFade.fadeIn(
@@ -4833,8 +4825,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
isOppositeGender(pokemon: Pokemon): boolean {
return (
- this.gender !== Gender.GENDERLESS &&
- pokemon.gender === (this.gender === Gender.MALE ? Gender.FEMALE : Gender.MALE)
+ this.gender !== Gender.GENDERLESS
+ && pokemon.gender === (this.gender === Gender.MALE ? Gender.FEMALE : Gender.MALE)
);
}
@@ -4949,8 +4941,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
case StatusEffect.FREEZE: {
const weatherType = globalScene.arena.getWeatherType();
isImmune =
- this.isOfType(PokemonType.ICE) ||
- (!ignoreField && (weatherType === WeatherType.SUNNY || weatherType === WeatherType.HARSH_SUN));
+ this.isOfType(PokemonType.ICE)
+ || (!ignoreField && (weatherType === WeatherType.SUNNY || weatherType === WeatherType.HARSH_SUN));
break;
}
case StatusEffect.BURN:
@@ -5183,15 +5175,11 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
const lastStatus = this.status?.effect;
this.status = null;
this.setFrameRate(10);
- if (lastStatus === StatusEffect.SLEEP) {
- if (this.getTag(BattlerTagType.NIGHTMARE)) {
- this.lapseTag(BattlerTagType.NIGHTMARE);
- }
+ if (lastStatus === StatusEffect.SLEEP && this.getTag(BattlerTagType.NIGHTMARE)) {
+ this.lapseTag(BattlerTagType.NIGHTMARE);
}
- if (confusion) {
- if (this.getTag(BattlerTagType.CONFUSED)) {
- this.lapseTag(BattlerTagType.CONFUSED);
- }
+ if (confusion && this.getTag(BattlerTagType.CONFUSED)) {
+ this.lapseTag(BattlerTagType.CONFUSED);
}
if (reloadAssets) {
this.loadAssets(false).then(() => this.playAnim());
@@ -5233,9 +5221,9 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
// If this Pokemon has Commander and Dondozo as an active ally, hide this Pokemon's sprite.
if (
- this.hasAbilityWithAttr("CommanderAbAttr") &&
- globalScene.currentBattle.double &&
- this.getAlly()?.species.speciesId === SpeciesId.DONDOZO
+ this.hasAbilityWithAttr("CommanderAbAttr")
+ && globalScene.currentBattle.double
+ && this.getAlly()?.species.speciesId === SpeciesId.DONDOZO
) {
this.setVisible(false);
}
@@ -5325,7 +5313,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
globalScene.tweens.add({
targets: tintSprite,
alpha: alpha || 1,
- duration: duration,
+ duration,
ease: ease || "Linear",
});
} else {
@@ -5340,7 +5328,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
globalScene.tweens.add({
targets: tintSprite,
alpha: 0,
- duration: duration,
+ duration,
ease: ease || "Linear",
onComplete: () => {
tintSprite?.setVisible(false);
@@ -5666,7 +5654,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
keys = Array.from(paletteColors.keys()).sort((a: number, b: number) =>
paletteColors.get(a)! < paletteColors.get(b)! ? 1 : -1,
);
- } while (mappedColors.size);
+ } while (mappedColors.size > 0);
return keys.map(c => Object.values(rgbaFromArgb(c)));
});
@@ -5675,8 +5663,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
spriteColors.forEach((sc: number[], i: number) => {
paletteDeltas.push([]);
- for (let p = 0; p < palette.length; p++) {
- paletteDeltas[i].push(deltaRgb(sc, palette[p]));
+ for (const p of palette) {
+ paletteDeltas[i].push(deltaRgb(sc, p));
}
});
@@ -5841,8 +5829,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
getPersistentTreasureCount(): number {
return (
- this.getHeldItems().filter(m => m.is("DamageMoneyRewardModifier")).length +
- globalScene.findModifiers(m => m.is("MoneyMultiplierModifier") || m.is("ExtraModifierModifier")).length
+ this.getHeldItems().filter(m => m.is("DamageMoneyRewardModifier")).length
+ + globalScene.findModifiers(m => m.is("MoneyMultiplierModifier") || m.is("ExtraModifierModifier")).length
);
}
}
@@ -5882,9 +5870,8 @@ export class PlayerPokemon extends Pokemon {
if (!dataSource) {
if (
- globalScene.gameMode.isDaily ||
- // Keldeo is excluded due to crashes involving its signature move and the associated form change
- (Overrides.STARTER_SPECIES_OVERRIDE && Overrides.STARTER_SPECIES_OVERRIDE !== SpeciesId.KELDEO)
+ globalScene.gameMode.isDaily // Keldeo is excluded due to crashes involving its signature move and the associated form change
+ || (Overrides.STARTER_SPECIES_OVERRIDE && Overrides.STARTER_SPECIES_OVERRIDE !== SpeciesId.KELDEO)
) {
this.generateAndPopulateMoveset();
} else {
@@ -5934,8 +5921,8 @@ export class PlayerPokemon extends Pokemon {
if (Array.isArray(p)) {
const [pkm, form] = p;
if (
- (pkm === this.species.speciesId || (this.fusionSpecies && pkm === this.fusionSpecies.speciesId)) &&
- form === this.getFormKey()
+ (pkm === this.species.speciesId || (this.fusionSpecies && pkm === this.fusionSpecies.speciesId))
+ && form === this.getFormKey()
) {
compatible = true;
break;
@@ -6445,9 +6432,9 @@ export class EnemyPokemon extends Pokemon {
const speciesId = this.species.speciesId;
if (
- speciesId in Overrides.ENEMY_FORM_OVERRIDES &&
- !isNullOrUndefined(Overrides.ENEMY_FORM_OVERRIDES[speciesId]) &&
- this.species.forms[Overrides.ENEMY_FORM_OVERRIDES[speciesId]]
+ speciesId in Overrides.ENEMY_FORM_OVERRIDES
+ && !isNullOrUndefined(Overrides.ENEMY_FORM_OVERRIDES[speciesId])
+ && this.species.forms[Overrides.ENEMY_FORM_OVERRIDES[speciesId]]
) {
this.formIndex = Overrides.ENEMY_FORM_OVERRIDES[speciesId];
} else if (globalScene.gameMode.isDaily && globalScene.gameMode.isWaveFinal(globalScene.currentBattle.waveIndex)) {
@@ -6517,8 +6504,8 @@ export class EnemyPokemon extends Pokemon {
}
this.bossSegments =
- bossSegments ??
- globalScene.getEncounterBossSegments(globalScene.currentBattle.waveIndex, this.level, this.species, true);
+ bossSegments
+ ?? globalScene.getEncounterBossSegments(globalScene.currentBattle.waveIndex, this.level, this.species, true);
this.bossSegmentIndex = this.bossSegments - 1;
}
@@ -6583,7 +6570,7 @@ export class EnemyPokemon extends Pokemon {
// Filter out any moves this Pokemon cannot use
let movePool = this.getMoveset().filter(m => m.isUsable(this));
// If no moves are left, use Struggle. Otherwise, continue with move selection
- if (movePool.length) {
+ if (movePool.length > 0) {
// If there's only 1 move in the move pool, use it.
if (movePool.length === 1) {
return {
@@ -6636,14 +6623,14 @@ export class EnemyPokemon extends Pokemon {
const isCritical = move.hasAttr("CritOnlyAttr") || !!this.getTag(BattlerTagType.ALWAYS_CRIT);
return (
- move.category !== MoveCategory.STATUS &&
- moveTargets.some(p => {
+ move.category !== MoveCategory.STATUS
+ && moveTargets.some(p => {
const doesNotFail =
- move.applyConditions(this, p, move) ||
- [MoveId.SUCKER_PUNCH, MoveId.UPPER_HAND, MoveId.THUNDERCLAP].includes(move.id);
+ move.applyConditions(this, p, move)
+ || [MoveId.SUCKER_PUNCH, MoveId.UPPER_HAND, MoveId.THUNDERCLAP].includes(move.id);
return (
- doesNotFail &&
- p.getAttackDamage({
+ doesNotFail
+ && p.getAttackDamage({
source: this,
move,
ignoreAbility: !p.waveData.abilityRevealed,
@@ -6651,6 +6638,7 @@ export class EnemyPokemon extends Pokemon {
ignoreAllyAbility: !p.getAlly()?.waveData.abilityRevealed,
ignoreSourceAllyAbility: false,
isCritical,
+ simulated: true,
}).damage >= p.hp
);
})
@@ -6687,8 +6675,9 @@ export class EnemyPokemon extends Pokemon {
* If the target is an ally, the target benefit score is multiplied by -1.
*/
let targetScore =
- move.getUserBenefitScore(this, target, move) +
- move.getTargetBenefitScore(this, target, move) * (mt < BattlerIndex.ENEMY === this.isPlayer() ? 1 : -1);
+ move.getUserBenefitScore(this, target, move)
+ + move.getTargetBenefitScore(this, target, move)
+ * (mt < BattlerIndex.ENEMY === this.isPlayer() ? 1 : -1);
if (Number.isNaN(targetScore)) {
console.error(`Move ${move.name} returned score of NaN`);
targetScore = 0;
@@ -6698,8 +6687,8 @@ export class EnemyPokemon extends Pokemon {
* target score to -20
*/
if (
- (move.name.endsWith(" (N)") || !move.applyConditions(this, target, move)) &&
- ![MoveId.SUCKER_PUNCH, MoveId.UPPER_HAND, MoveId.THUNDERCLAP].includes(move.id)
+ (move.name.endsWith(" (N)") || !move.applyConditions(this, target, move))
+ && ![MoveId.SUCKER_PUNCH, MoveId.UPPER_HAND, MoveId.THUNDERCLAP].includes(move.id)
) {
targetScore = -20;
} else if (move.is("AttackMove")) {
@@ -6759,14 +6748,14 @@ export class EnemyPokemon extends Pokemon {
} else if (this.aiType === AiType.SMART) {
// The chance to advance to the next best move increases when the compared moves' scores are closer to each other.
while (
- r < sortedMovePool.length - 1 &&
- moveScores[movePool.indexOf(sortedMovePool[r + 1])] / moveScores[movePool.indexOf(sortedMovePool[r])] >=
- 0 &&
- globalScene.randBattleSeedInt(100) <
- Math.round(
- (moveScores[movePool.indexOf(sortedMovePool[r + 1])] /
- moveScores[movePool.indexOf(sortedMovePool[r])]) *
- 50,
+ r < sortedMovePool.length - 1
+ && moveScores[movePool.indexOf(sortedMovePool[r + 1])] / moveScores[movePool.indexOf(sortedMovePool[r])]
+ >= 0
+ && globalScene.randBattleSeedInt(100)
+ < Math.round(
+ (moveScores[movePool.indexOf(sortedMovePool[r + 1])]
+ / moveScores[movePool.indexOf(sortedMovePool[r])])
+ * 50,
)
) {
r++;
@@ -6826,7 +6815,7 @@ export class EnemyPokemon extends Pokemon {
return scoreA < scoreB ? 1 : scoreA > scoreB ? -1 : 0;
});
- if (!sortedBenefitScores.length) {
+ if (sortedBenefitScores.length === 0) {
// Set target to BattlerIndex.ATTACKER when using a counter move
// This is the same as when the player does so
if (move.hasAttr("CounterDamageAttr")) {
@@ -6837,7 +6826,7 @@ export class EnemyPokemon extends Pokemon {
}
let targetWeights = sortedBenefitScores.map(s => s[1]);
- const lowestWeight = targetWeights[targetWeights.length - 1];
+ const lowestWeight = targetWeights.at(-1) ?? 0;
// If the lowest target weight (i.e. benefit score) is negative, add abs(lowestWeight) to all target weights
if (lowestWeight < 1) {
@@ -6927,9 +6916,9 @@ export class EnemyPokemon extends Pokemon {
const hpRemainder = this.hp - roundedHpThreshold;
let segmentsBypassed = 0;
while (
- segmentsBypassed < this.bossSegmentIndex &&
- this.canBypassBossSegments(segmentsBypassed + 1) &&
- damage - hpRemainder >= Math.round(segmentSize * Math.pow(2, segmentsBypassed + 1))
+ segmentsBypassed < this.bossSegmentIndex
+ && this.canBypassBossSegments(segmentsBypassed + 1)
+ && damage - hpRemainder >= Math.round(segmentSize * Math.pow(2, segmentsBypassed + 1))
) {
segmentsBypassed++;
//console.log('damage', damage, 'segment', segmentsBypassed + 1, 'segment size', segmentSize, 'damage needed', Math.round(segmentSize * Math.pow(2, segmentsBypassed + 1)));
@@ -6967,10 +6956,12 @@ export class EnemyPokemon extends Pokemon {
}
canBypassBossSegments(segmentCount = 1): boolean {
- if (globalScene.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) {
- if (!this.formIndex && this.bossSegmentIndex - segmentCount < 1) {
- return false;
- }
+ if (
+ globalScene.currentBattle.battleSpec === BattleSpec.FINAL_BOSS
+ && !this.formIndex
+ && this.bossSegmentIndex - segmentCount < 1
+ ) {
+ return false;
}
return true;
diff --git a/src/field/trainer.ts b/src/field/trainer.ts
index 6d427585a87..f5b2e5dad99 100644
--- a/src/field/trainer.ts
+++ b/src/field/trainer.ts
@@ -54,8 +54,8 @@ export class Trainer extends Phaser.GameObjects.Container {
) {
super(globalScene, -72, 80);
this.config =
- trainerConfigOverride ??
- (trainerConfigs.hasOwnProperty(trainerType)
+ trainerConfigOverride
+ ?? (trainerConfigs.hasOwnProperty(trainerType)
? trainerConfigs[trainerType]
: trainerConfigs[TrainerType.ACE_TRAINER]);
@@ -233,8 +233,8 @@ export class Trainer extends Phaser.GameObjects.Container {
getEncounterBgm(): string {
return !this.variant
? this.config.encounterBgm
- : (this.variant === TrainerVariant.DOUBLE ? this.config.doubleEncounterBgm : this.config.femaleEncounterBgm) ||
- this.config.encounterBgm;
+ : (this.variant === TrainerVariant.DOUBLE ? this.config.doubleEncounterBgm : this.config.femaleEncounterBgm)
+ || this.config.encounterBgm;
}
getEncounterMessages(): string[] {
@@ -248,17 +248,15 @@ export class Trainer extends Phaser.GameObjects.Container {
getVictoryMessages(): string[] {
return !this.variant
? this.config.victoryMessages
- : (this.variant === TrainerVariant.DOUBLE
- ? this.config.doubleVictoryMessages
- : this.config.femaleVictoryMessages) || this.config.victoryMessages;
+ : (this.variant === TrainerVariant.DOUBLE ? this.config.doubleVictoryMessages : this.config.femaleVictoryMessages)
+ || this.config.victoryMessages;
}
getDefeatMessages(): string[] {
return !this.variant
? this.config.defeatMessages
- : (this.variant === TrainerVariant.DOUBLE
- ? this.config.doubleDefeatMessages
- : this.config.femaleDefeatMessages) || this.config.defeatMessages;
+ : (this.variant === TrainerVariant.DOUBLE ? this.config.doubleDefeatMessages : this.config.femaleDefeatMessages)
+ || this.config.defeatMessages;
}
getPartyTemplate(): TrainerPartyTemplate {
@@ -397,16 +395,14 @@ export class Trainer extends Phaser.GameObjects.Container {
} else {
newSpeciesPool = speciesPoolFiltered;
}
- } else {
// If the index is odd, use the species pool for the partner trainer (that way he only uses his own pokemon in battle)
// Since the only currently allowed double battle with named trainers is Tate & Liza, we need to make sure that Solrock is the first pokemon in the party for Tate and Lunatone for Liza
- if (index === 1 && TrainerType[this.config.trainerTypeDouble] === TrainerType[TrainerType.TATE]) {
- newSpeciesPool = [SpeciesId.SOLROCK];
- } else if (index === 1 && TrainerType[this.config.trainerTypeDouble] === TrainerType[TrainerType.LIZA]) {
- newSpeciesPool = [SpeciesId.LUNATONE];
- } else {
- newSpeciesPool = speciesPoolPartnerFiltered;
- }
+ } else if (index === 1 && TrainerType[this.config.trainerTypeDouble] === TrainerType[TrainerType.TATE]) {
+ newSpeciesPool = [SpeciesId.SOLROCK];
+ } else if (index === 1 && TrainerType[this.config.trainerTypeDouble] === TrainerType[TrainerType.LIZA]) {
+ newSpeciesPool = [SpeciesId.LUNATONE];
+ } else {
+ newSpeciesPool = speciesPoolPartnerFiltered;
}
// Fallback for when the species pool is empty
if (newSpeciesPool.length === 0) {
@@ -445,9 +441,9 @@ export class Trainer extends Phaser.GameObjects.Container {
},
this.config.hasStaticParty
? this.config.getDerivedType() + ((index + 1) << 8)
- : globalScene.currentBattle.waveIndex +
- (this.config.getDerivedType() << 10) +
- (((!this.config.useSameSeedForAllMembers ? index : 0) + 1) << 8),
+ : globalScene.currentBattle.waveIndex
+ + (this.config.getDerivedType() << 10)
+ + (((!this.config.useSameSeedForAllMembers ? index : 0) + 1) << 8),
);
return ret!; // TODO: is this bang correct?
@@ -471,7 +467,7 @@ export class Trainer extends Phaser.GameObjects.Container {
? TrainerPoolTier.SUPER_RARE
: TrainerPoolTier.ULTRA_RARE;
console.log(TrainerPoolTier[tier]);
- while (!this.config.speciesPools.hasOwnProperty(tier) || !this.config.speciesPools[tier].length) {
+ while (!this.config.speciesPools.hasOwnProperty(tier) || this.config.speciesPools[tier].length === 0) {
console.log(
`Downgraded trainer Pokemon rarity tier from ${TrainerPoolTier[tier]} to ${TrainerPoolTier[tier - 1]}`,
);
@@ -495,8 +491,8 @@ export class Trainer extends Phaser.GameObjects.Container {
} else if (template.isBalanced(battle.enemyParty.length)) {
const partyMemberTypes = battle.enemyParty.flatMap(p => p.getTypes(true));
if (
- partyMemberTypes.indexOf(ret.type1) > -1 ||
- (ret.type2 !== null && partyMemberTypes.indexOf(ret.type2) > -1)
+ partyMemberTypes.indexOf(ret.type1) > -1
+ || (ret.type2 !== null && partyMemberTypes.indexOf(ret.type2) > -1)
) {
retry = true;
}
@@ -752,7 +748,7 @@ export class Trainer extends Phaser.GameObjects.Container {
globalScene.tweens.add({
targets: tintSprite,
alpha: alpha || 1,
- duration: duration,
+ duration,
ease: ease || "Linear",
});
} else {
@@ -768,7 +764,7 @@ export class Trainer extends Phaser.GameObjects.Container {
globalScene.tweens.add({
targets: tintSprite,
alpha: 0,
- duration: duration,
+ duration,
ease: ease || "Linear",
onComplete: () => {
tintSprite.setVisible(false);
@@ -788,10 +784,12 @@ export class Trainer extends Phaser.GameObjects.Container {
* @returns boolean Whether the EnemyPokemon should Terastalize this turn
*/
shouldTera(pokemon: EnemyPokemon): boolean {
- if (this.config.trainerAI.teraMode === TeraAIMode.INSTANT_TERA) {
- if (!pokemon.isTerastallized && this.config.trainerAI.instantTeras.includes(pokemon.initialTeamIndex)) {
- return true;
- }
+ if (
+ this.config.trainerAI.teraMode === TeraAIMode.INSTANT_TERA
+ && !pokemon.isTerastallized
+ && this.config.trainerAI.instantTeras.includes(pokemon.initialTeamIndex)
+ ) {
+ return true;
}
return false;
}
diff --git a/src/game-mode.ts b/src/game-mode.ts
index 59af1c8f06e..ebe1d4f4bff 100644
--- a/src/game-mode.ts
+++ b/src/game-mode.ts
@@ -234,8 +234,8 @@ export class GameMode implements GameModeConfig {
return waveIndex > 10 && waveIndex < 50 && !(waveIndex % 10);
default:
return (
- waveIndex % 30 === (offsetGym ? 0 : 20) &&
- (biomeType !== BiomeId.END || this.isClassic || this.isWaveFinal(waveIndex))
+ waveIndex % 30 === (offsetGym ? 0 : 20)
+ && (biomeType !== BiomeId.END || this.isClassic || this.isWaveFinal(waveIndex))
);
}
}
@@ -250,10 +250,10 @@ export class GameMode implements GameModeConfig {
const allFinalBossSpecies = allSpecies.filter(
s =>
- (s.subLegendary || s.legendary || s.mythical) &&
- s.baseTotal >= 600 &&
- s.speciesId !== SpeciesId.ETERNATUS &&
- s.speciesId !== SpeciesId.ARCEUS,
+ (s.subLegendary || s.legendary || s.mythical)
+ && s.baseTotal >= 600
+ && s.speciesId !== SpeciesId.ETERNATUS
+ && s.speciesId !== SpeciesId.ARCEUS,
);
return randSeedItem(allFinalBossSpecies);
}
@@ -330,8 +330,8 @@ export class GameMode implements GameModeConfig {
isFixedBattle(waveIndex: number): boolean {
const dummyConfig = new FixedBattleConfig();
return (
- this.battleConfig.hasOwnProperty(waveIndex) ||
- applyChallenges(ChallengeType.FIXED_BATTLES, waveIndex, dummyConfig)
+ this.battleConfig.hasOwnProperty(waveIndex)
+ || applyChallenges(ChallengeType.FIXED_BATTLES, waveIndex, dummyConfig)
);
}
diff --git a/src/init/init.ts b/src/init/init.ts
index ba9738e2be8..b717664b654 100644
--- a/src/init/init.ts
+++ b/src/init/init.ts
@@ -1,6 +1,5 @@
import { initAbilities } from "#abilities/ability";
import { initBiomes } from "#balance/biomes";
-import { initEggMoves } from "#balance/egg-moves";
import { initPokemonPrevolutions, initPokemonStarters } from "#balance/pokemon-evolutions";
import { initSpecies } from "#balance/pokemon-species";
import { initChallenges } from "#data/challenge";
@@ -12,7 +11,7 @@ import { initMoves } from "#moves/move";
import { initMysteryEncounters } from "#mystery-encounters/mystery-encounters";
import { initAchievements } from "#system/achv";
import { initVouchers } from "#system/voucher";
-import { initStatsKeys } from "#ui/game-stats-ui-handler";
+import { initStatsKeys } from "#ui/handlers/game-stats-ui-handler";
/** Initialize the game. */
export function initializeGame() {
@@ -24,7 +23,6 @@ export function initializeGame() {
initPokemonPrevolutions();
initPokemonStarters();
initBiomes();
- initEggMoves();
initPokemonForms();
initTrainerTypeDialogue();
initSpecies();
diff --git a/src/inputs-controller.ts b/src/inputs-controller.ts
index 03d2278f26c..0207297fd58 100644
--- a/src/inputs-controller.ts
+++ b/src/inputs-controller.ts
@@ -406,9 +406,9 @@ export class InputsController {
}
this.lastSource = "gamepad";
if (
- !this.selectedDevice[Device.GAMEPAD] ||
- (globalScene.ui.getMode() !== UiMode.GAMEPAD_BINDING &&
- this.selectedDevice[Device.GAMEPAD] !== pad.id.toLowerCase())
+ !this.selectedDevice[Device.GAMEPAD]
+ || (globalScene.ui.getMode() !== UiMode.GAMEPAD_BINDING
+ && this.selectedDevice[Device.GAMEPAD] !== pad.id.toLowerCase())
) {
this.setChosenGamepad(pad.id);
}
@@ -585,7 +585,7 @@ export class InputsController {
resetConfigs(): void {
this.configs = new Map();
- if (this.getGamepadsName()?.length) {
+ if (this.getGamepadsName()?.length > 0) {
this.setupGamepad(this.selectedDevice[Device.GAMEPAD]);
}
this.setupKeyboard();
diff --git a/src/loading-scene.ts b/src/loading-scene.ts
index e1b658f578a..c01c5287dc5 100644
--- a/src/loading-scene.ts
+++ b/src/loading-scene.ts
@@ -60,9 +60,7 @@ export class LoadingScene extends SceneBase {
this.loadAtlas("pbinfo_enemy_type", "ui");
this.loadAtlas("pbinfo_enemy_type1", "ui");
this.loadAtlas("pbinfo_enemy_type2", "ui");
- this.loadAtlas("pbinfo_stat", "ui");
this.loadAtlas("pbinfo_stat_numbers", "ui");
- this.loadImage("overlay_lv", "ui");
this.loadAtlas("numbers", "ui");
this.loadAtlas("numbers_red", "ui");
this.loadAtlas("overlay_hp", "ui");
@@ -125,7 +123,6 @@ export class LoadingScene extends SceneBase {
this.loadAtlas("party_slot_main", "ui");
this.loadAtlas("party_slot_main_short", "ui");
this.loadAtlas("party_slot", "ui");
- this.loadImage("party_slot_overlay_lv", "ui");
this.loadImage("party_slot_hp_bar", "ui");
this.loadAtlas("party_slot_hp_overlay", "ui");
this.loadAtlas("party_pb", "ui");
@@ -134,7 +131,6 @@ export class LoadingScene extends SceneBase {
this.loadAtlas("party_transfer", "ui");
this.loadImage("summary_bg", "ui");
- this.loadImage("summary_overlay_shiny", "ui");
this.loadImage("summary_profile", "ui");
this.loadImage("summary_profile_prompt_z", "ui"); // The pixel Z button prompt
this.loadImage("summary_profile_prompt_a", "ui"); // The pixel A button prompt
@@ -309,6 +305,34 @@ export class LoadingScene extends SceneBase {
`text_images/${lang}/summary/summary_moves_effect_title${keySuffix}.png`,
); // Pixel text 'EFFECT'
+ this.loadAtlas(`pbinfo_stat${keySuffix}`, "ui", `text_images/${lang}/battle_ui/pbinfo_stat${keySuffix}`); // Pixel text for in-battle stats info tab
+ this.loadImage(`overlay_lv${keySuffix}`, "ui", `text_images/${lang}/battle_ui/overlay_lv${keySuffix}.png`); // Pixel text in-battle 'Lv.'
+ this.loadImage(
+ `overlay_hp_label${keySuffix}`,
+ "ui",
+ `text_images/${lang}/battle_ui/overlay_hp_label${keySuffix}.png`,
+ ); // Pixel text in-battle 'HP'
+ this.loadImage(
+ `overlay_hp_label_boss${keySuffix}`,
+ "ui",
+ `text_images/${lang}/battle_ui/overlay_hp_label_boss${keySuffix}.png`,
+ ); // Pixel text in-battle 'BOSS'
+ this.loadImage(
+ `overlay_exp_label${keySuffix}`,
+ "ui",
+ `text_images/${lang}/battle_ui/overlay_exp_label${keySuffix}.png`,
+ ); // Pixel text in-battle 'EXP'
+ this.loadImage(
+ `party_slot_overlay_lv${keySuffix}`,
+ "ui",
+ `text_images/${lang}/party_ui/party_slot_overlay_lv${keySuffix}.png`,
+ ); // Pixel text party 'Lv.'
+ this.loadImage(
+ `party_slot_overlay_hp${keySuffix}`,
+ "ui",
+ `text_images/${lang}/party_ui/party_slot_overlay_hp${keySuffix}.png`,
+ ); // Pixel text party 'HP'
+
if (timedEventManager.activeEventHasBanner()) {
const availableLangs = timedEventManager.getEventBannerLangs();
if (lang && availableLangs.includes(lang)) {
diff --git a/src/main.ts b/src/main.ts
index 80f2ca3ed8b..fe510eafb64 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -105,7 +105,7 @@ const startGame = async () => {
antialias: false,
pipeline: [InvertPostFX] as unknown as Phaser.Types.Core.PipelineConfig,
scene: [LoadingScene, BattleScene],
- version: version,
+ version,
});
game.sound.pauseOnBlur = false;
if (manifest) {
diff --git a/src/modifier/init-modifier-pools.ts b/src/modifier/init-modifier-pools.ts
index 3e180846183..ba12920407d 100644
--- a/src/modifier/init-modifier-pools.ts
+++ b/src/modifier/init-modifier-pools.ts
@@ -97,12 +97,12 @@ function initCommonModifierPool() {
const thresholdPartyMemberCount = Math.min(
party.filter(
p =>
- p.hp &&
- !p.getHeldItems().some(m => m instanceof BerryModifier && m.berryType === BerryType.LEPPA) &&
- p
+ p.hp
+ && !p.getHeldItems().some(m => m instanceof BerryModifier && m.berryType === BerryType.LEPPA)
+ && p
.getMoveset()
.filter(m => m.ppUsed && m.getMovePp() - m.ppUsed <= 5 && m.ppUsed > Math.floor(m.getMovePp() / 2))
- .length,
+ .length > 0,
).length,
3,
);
@@ -116,12 +116,12 @@ function initCommonModifierPool() {
const thresholdPartyMemberCount = Math.min(
party.filter(
p =>
- p.hp &&
- !p.getHeldItems().some(m => m instanceof BerryModifier && m.berryType === BerryType.LEPPA) &&
- p
+ p.hp
+ && !p.getHeldItems().some(m => m instanceof BerryModifier && m.berryType === BerryType.LEPPA)
+ && p
.getMoveset()
.filter(m => m.ppUsed && m.getMovePp() - m.ppUsed <= 5 && m.ppUsed > Math.floor(m.getMovePp() / 2))
- .length,
+ .length > 0,
).length,
3,
);
@@ -152,9 +152,9 @@ function initGreatModifierPool() {
const statusEffectPartyMemberCount = Math.min(
party.filter(
p =>
- p.hp &&
- !!p.status &&
- !p.getHeldItems().some(i => {
+ p.hp
+ && !!p.status
+ && !p.getHeldItems().some(i => {
if (i instanceof TurnStatusEffectModifier) {
return (i as TurnStatusEffectModifier).getStatusEffect() === p.status?.effect;
}
@@ -218,9 +218,9 @@ function initGreatModifierPool() {
const statusEffectPartyMemberCount = Math.min(
party.filter(
p =>
- p.hp &&
- !!p.status &&
- !p.getHeldItems().some(i => {
+ p.hp
+ && !!p.status
+ && !p.getHeldItems().some(i => {
if (i instanceof TurnStatusEffectModifier) {
return (i as TurnStatusEffectModifier).getStatusEffect() === p.status?.effect;
}
@@ -230,9 +230,9 @@ function initGreatModifierPool() {
3,
);
const thresholdPartyMemberCount = Math.floor(
- (Math.min(party.filter(p => p.getInverseHp() >= 100 && p.getHpRatio() <= 0.5 && !p.isFainted()).length, 3) +
- statusEffectPartyMemberCount) /
- 2,
+ (Math.min(party.filter(p => p.getInverseHp() >= 100 && p.getHpRatio() <= 0.5 && !p.isFainted()).length, 3)
+ + statusEffectPartyMemberCount)
+ / 2,
);
return thresholdPartyMemberCount;
},
@@ -244,12 +244,12 @@ function initGreatModifierPool() {
const thresholdPartyMemberCount = Math.min(
party.filter(
p =>
- p.hp &&
- !p.getHeldItems().some(m => m instanceof BerryModifier && m.berryType === BerryType.LEPPA) &&
- p
+ p.hp
+ && !p.getHeldItems().some(m => m instanceof BerryModifier && m.berryType === BerryType.LEPPA)
+ && p
.getMoveset()
.filter(m => m.ppUsed && m.getMovePp() - m.ppUsed <= 5 && m.ppUsed > Math.floor(m.getMovePp() / 2))
- .length,
+ .length > 0,
).length,
3,
);
@@ -263,12 +263,12 @@ function initGreatModifierPool() {
const thresholdPartyMemberCount = Math.min(
party.filter(
p =>
- p.hp &&
- !p.getHeldItems().some(m => m instanceof BerryModifier && m.berryType === BerryType.LEPPA) &&
- p
+ p.hp
+ && !p.getHeldItems().some(m => m instanceof BerryModifier && m.berryType === BerryType.LEPPA)
+ && p
.getMoveset()
.filter(m => m.ppUsed && m.getMovePp() - m.ppUsed <= 5 && m.ppUsed > Math.floor(m.getMovePp() / 2))
- .length,
+ .length > 0,
).length,
3,
);
@@ -369,9 +369,9 @@ function initUltraModifierPool() {
return party.some(p => {
// Check if Pokemon's species (or fusion species, if applicable) can evolve or if they're G-Max'd
if (
- !p.isMax() &&
- (p.getSpeciesForm(true).speciesId in pokemonEvolutions ||
- (p.isFusion() && p.getFusionSpeciesForm(true).speciesId in pokemonEvolutions))
+ !p.isMax()
+ && (p.getSpeciesForm(true).speciesId in pokemonEvolutions
+ || (p.isFusion() && p.getFusionSpeciesForm(true).speciesId in pokemonEvolutions))
) {
// Check if Pokemon is already holding an Eviolite
return !p.getHeldItems().some(i => i.type.id === "EVIOLITE");
@@ -391,9 +391,9 @@ function initUltraModifierPool() {
// If a party member doesn't already have a Leek and is one of the relevant species, Leek can appear
return party.some(
p =>
- !p.getHeldItems().some(i => i instanceof SpeciesCritBoosterModifier) &&
- (checkedSpecies.includes(p.getSpeciesForm(true).speciesId) ||
- (p.isFusion() && checkedSpecies.includes(p.getFusionSpeciesForm(true).speciesId))),
+ !p.getHeldItems().some(i => i instanceof SpeciesCritBoosterModifier)
+ && (checkedSpecies.includes(p.getSpeciesForm(true).speciesId)
+ || (p.isFusion() && checkedSpecies.includes(p.getFusionSpeciesForm(true).speciesId))),
)
? 12
: 0;
@@ -633,9 +633,9 @@ function initMasterModifierPool() {
new WeightedModifierType(
modifierTypes.DNA_SPLICERS,
(party: Pokemon[]) =>
- !(globalScene.gameMode.isClassic && timedEventManager.areFusionsBoosted()) &&
- !globalScene.gameMode.isSplicedOnly &&
- party.filter(p => !p.fusionSpecies).length > 1
+ !(globalScene.gameMode.isClassic && timedEventManager.areFusionsBoosted())
+ && !globalScene.gameMode.isSplicedOnly
+ && party.filter(p => !p.fusionSpecies).length > 1
? 24
: 0,
24,
@@ -643,8 +643,9 @@ function initMasterModifierPool() {
new WeightedModifierType(
modifierTypes.MINI_BLACK_HOLE,
() =>
- globalScene.gameMode.isDaily ||
- (!globalScene.gameMode.isFreshStartChallenge() && globalScene.gameData.isUnlocked(Unlockables.MINI_BLACK_HOLE))
+ globalScene.gameMode.isDaily
+ || (!globalScene.gameMode.isFreshStartChallenge()
+ && globalScene.gameData.isUnlocked(Unlockables.MINI_BLACK_HOLE))
? 1
: 0,
1,
@@ -842,9 +843,9 @@ function skipInLastClassicWaveOrDefault(defaultWeight: number): WeightedModifier
function lureWeightFunc(maxBattles: number, weight: number): WeightedModifierTypeWeightFunc {
return () => {
const lures = globalScene.getModifiers(DoubleBattleChanceBoosterModifier);
- return !(globalScene.gameMode.isClassic && globalScene.currentBattle.waveIndex === 199) &&
- (lures.length === 0 ||
- lures.filter(m => m.getMaxBattles() === maxBattles && m.getBattleCount() >= maxBattles * 0.6).length === 0)
+ return !(globalScene.gameMode.isClassic && globalScene.currentBattle.waveIndex === 199)
+ && (lures.length === 0
+ || lures.filter(m => m.getMaxBattles() === maxBattles && m.getBattleCount() >= maxBattles * 0.6).length === 0)
? weight
: 0;
};
diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts
index 8b77900cb62..4b7c40e1a7f 100644
--- a/src/modifier/modifier-type.ts
+++ b/src/modifier/modifier-type.ts
@@ -115,8 +115,8 @@ import {
import type { PokemonMove } from "#moves/pokemon-move";
import { getVoucherTypeIcon, getVoucherTypeName, VoucherType } from "#system/voucher";
import type { ModifierTypeFunc, WeightedModifierTypeWeightFunc } from "#types/modifier-types";
-import type { PokemonMoveSelectFilter, PokemonSelectFilter } from "#ui/party-ui-handler";
-import { PartyUiHandler } from "#ui/party-ui-handler";
+import type { PokemonMoveSelectFilter, PokemonSelectFilter } from "#ui/handlers/party-ui-handler";
+import { PartyUiHandler } from "#ui/handlers/party-ui-handler";
import { getModifierTierTextTint } from "#ui/text";
import { applyChallenges } from "#utils/challenge-utils";
import {
@@ -485,8 +485,8 @@ export class PokemonHpRestoreModifierType extends PokemonModifierType {
super(
localeKey,
iconImage,
- newModifierFunc ||
- ((_type, args) =>
+ newModifierFunc
+ || ((_type, args) =>
new PokemonHpRestoreModifier(
this,
(args[0] as PlayerPokemon).id,
@@ -495,11 +495,12 @@ export class PokemonHpRestoreModifierType extends PokemonModifierType {
this.healStatus,
false,
)),
- selectFilter ||
- ((pokemon: PlayerPokemon) => {
+ selectFilter
+ || ((pokemon: PlayerPokemon) => {
if (
- !pokemon.hp ||
- (pokemon.isFullHp() && (!this.healStatus || (!pokemon.status && !pokemon.getTag(BattlerTagType.CONFUSED))))
+ !pokemon.hp
+ || (pokemon.isFullHp()
+ && (!this.healStatus || (!pokemon.status && !pokemon.getTag(BattlerTagType.CONFUSED))))
) {
return PartyUiHandler.NoEffectMessage;
}
@@ -640,7 +641,7 @@ export class PokemonAllMovePpRestoreModifierType extends PokemonModifierType {
iconImage,
(_type, args) => new PokemonAllMovePpRestoreModifier(this, (args[0] as PlayerPokemon).id, this.restorePoints),
(pokemon: PlayerPokemon) => {
- if (!pokemon.getMoveset().filter(m => m.ppUsed).length) {
+ if (pokemon.getMoveset().filter(m => m.ppUsed).length === 0) {
return PartyUiHandler.NoEffectMessage;
}
return null;
@@ -732,7 +733,7 @@ export class RememberMoveModifierType extends PokemonModifierType {
iconImage,
(type, args) => new RememberMoveModifier(type, (args[0] as PlayerPokemon).id, args[1] as number),
(pokemon: PlayerPokemon) => {
- if (!pokemon.getLearnableLevelMoves().length) {
+ if (pokemon.getLearnableLevelMoves().length === 0) {
return PartyUiHandler.NoEffectMessage;
}
return null;
@@ -1144,8 +1145,8 @@ export class TmModifierType extends PokemonModifierType {
(_type, args) => new TmModifier(this, (args[0] as PlayerPokemon).id),
(pokemon: PlayerPokemon) => {
if (
- pokemon.compatibleTms.indexOf(moveId) === -1 ||
- pokemon.getMoveset().filter(m => m.moveId === moveId).length
+ pokemon.compatibleTms.indexOf(moveId) === -1
+ || pokemon.getMoveset().filter(m => m.moveId === moveId).length > 0
) {
return PartyUiHandler.NoEffectMessage;
}
@@ -1184,20 +1185,21 @@ export class EvolutionItemModifierType extends PokemonModifierType implements Ge
(_type, args) => new EvolutionItemModifier(this, (args[0] as PlayerPokemon).id),
(pokemon: PlayerPokemon) => {
if (
- pokemonEvolutions.hasOwnProperty(pokemon.species.speciesId) &&
- pokemonEvolutions[pokemon.species.speciesId].filter(e => e.validate(pokemon, false, this.evolutionItem))
- .length &&
- pokemon.getFormKey() !== SpeciesFormKey.GIGANTAMAX
+ pokemonEvolutions.hasOwnProperty(pokemon.species.speciesId)
+ && pokemonEvolutions[pokemon.species.speciesId].filter(e => e.validate(pokemon, false, this.evolutionItem))
+ .length > 0
+ && pokemon.getFormKey() !== SpeciesFormKey.GIGANTAMAX
) {
return null;
}
if (
- pokemon.isFusion() &&
- pokemon.fusionSpecies &&
- pokemonEvolutions.hasOwnProperty(pokemon.fusionSpecies.speciesId) &&
- pokemonEvolutions[pokemon.fusionSpecies.speciesId].filter(e => e.validate(pokemon, true, this.evolutionItem))
- .length &&
- pokemon.getFusionFormKey() !== SpeciesFormKey.GIGANTAMAX
+ pokemon.isFusion()
+ && pokemon.fusionSpecies
+ && pokemonEvolutions.hasOwnProperty(pokemon.fusionSpecies.speciesId)
+ && pokemonEvolutions[pokemon.fusionSpecies.speciesId].filter(e =>
+ e.validate(pokemon, true, this.evolutionItem),
+ ).length > 0
+ && pokemon.getFusionFormKey() !== SpeciesFormKey.GIGANTAMAX
) {
return null;
}
@@ -1236,9 +1238,8 @@ export class FormChangeItemModifierType extends PokemonModifierType implements G
(pokemon: PlayerPokemon) => {
// Make sure the Pokemon has alternate forms
if (
- pokemonFormChanges.hasOwnProperty(pokemon.species.speciesId) &&
- // Get all form changes for this species with an item trigger, including any compound triggers
- pokemonFormChanges[pokemon.species.speciesId]
+ pokemonFormChanges.hasOwnProperty(pokemon.species.speciesId) // Get all form changes for this species with an item trigger, including any compound triggers
+ && pokemonFormChanges[pokemon.species.speciesId]
.filter(
fc => fc.trigger.hasTriggerType(SpeciesFormChangeItemTrigger) && fc.preFormKey === pokemon.getFormKey(),
)
@@ -1306,7 +1307,7 @@ class AttackTypeBoosterModifierTypeGenerator extends ModifierTypeGenerator {
.filter(m => m.is("AttackMove"))
.map(m => m.type),
);
- if (!attackMoveTypes.length) {
+ if (attackMoveTypes.length === 0) {
return null;
}
@@ -1473,8 +1474,8 @@ class SpeciesStatBoosterModifierTypeGenerator extends ModifierTypeGenerator {
.getHeldItems()
.some(
m =>
- m instanceof SpeciesStatBoosterModifier &&
- (m as SpeciesStatBoosterModifier).contains(checkedSpecies[0], checkedStats[0]),
+ m instanceof SpeciesStatBoosterModifier
+ && (m as SpeciesStatBoosterModifier).contains(checkedSpecies[0], checkedStats[0]),
);
if (!hasItem) {
@@ -1531,7 +1532,7 @@ class TmModifierTypeGenerator extends ModifierTypeGenerator {
.filter(tm => tmPoolTiers[tm] === tier)
.filter(tm => !allMoves[tm].name.endsWith(" (N)"))
.filter((tm, i, array) => array.indexOf(tm) === i);
- if (!tierUniqueCompatibleTms.length) {
+ if (tierUniqueCompatibleTms.length === 0) {
return null;
}
// TODO: should this use `randSeedItem`?
@@ -1552,12 +1553,12 @@ class EvolutionItemModifierTypeGenerator extends ModifierTypeGenerator {
party
.filter(
p =>
- pokemonEvolutions.hasOwnProperty(p.species.speciesId) &&
- (!p.pauseEvolutions ||
- p.species.speciesId === SpeciesId.SLOWPOKE ||
- p.species.speciesId === SpeciesId.EEVEE ||
- p.species.speciesId === SpeciesId.KIRLIA ||
- p.species.speciesId === SpeciesId.SNORUNT),
+ pokemonEvolutions.hasOwnProperty(p.species.speciesId)
+ && (!p.pauseEvolutions
+ || p.species.speciesId === SpeciesId.SLOWPOKE
+ || p.species.speciesId === SpeciesId.EEVEE
+ || p.species.speciesId === SpeciesId.KIRLIA
+ || p.species.speciesId === SpeciesId.SNORUNT),
)
.flatMap(p => {
const evolutions = pokemonEvolutions[p.species.speciesId];
@@ -1566,14 +1567,14 @@ class EvolutionItemModifierTypeGenerator extends ModifierTypeGenerator {
party
.filter(
p =>
- p.isFusion() &&
- p.fusionSpecies &&
- pokemonEvolutions.hasOwnProperty(p.fusionSpecies.speciesId) &&
- (!p.pauseEvolutions ||
- p.fusionSpecies.speciesId === SpeciesId.SLOWPOKE ||
- p.fusionSpecies.speciesId === SpeciesId.EEVEE ||
- p.fusionSpecies.speciesId === SpeciesId.KIRLIA ||
- p.fusionSpecies.speciesId === SpeciesId.SNORUNT),
+ p.isFusion()
+ && p.fusionSpecies
+ && pokemonEvolutions.hasOwnProperty(p.fusionSpecies.speciesId)
+ && (!p.pauseEvolutions
+ || p.fusionSpecies.speciesId === SpeciesId.SLOWPOKE
+ || p.fusionSpecies.speciesId === SpeciesId.EEVEE
+ || p.fusionSpecies.speciesId === SpeciesId.KIRLIA
+ || p.fusionSpecies.speciesId === SpeciesId.SNORUNT),
)
.flatMap(p => {
const evolutions = pokemonEvolutions[p.fusionSpecies!.speciesId];
@@ -1584,7 +1585,7 @@ class EvolutionItemModifierTypeGenerator extends ModifierTypeGenerator {
.flatMap(e => e.evoItem)
.filter(i => !!i && i > 50 === rare);
- if (!evolutionItemPool.length) {
+ if (evolutionItemPool.length === 0) {
return null;
}
@@ -1610,34 +1611,34 @@ export class FormChangeItemModifierTypeGenerator extends ModifierTypeGenerator {
let formChangeItemTriggers = formChanges
.filter(
fc =>
- ((fc.formKey.indexOf(SpeciesFormKey.MEGA) === -1 &&
- fc.formKey.indexOf(SpeciesFormKey.PRIMAL) === -1) ||
- globalScene.getModifiers(MegaEvolutionAccessModifier).length) &&
- ((fc.formKey.indexOf(SpeciesFormKey.GIGANTAMAX) === -1 &&
- fc.formKey.indexOf(SpeciesFormKey.ETERNAMAX) === -1) ||
- globalScene.getModifiers(GigantamaxAccessModifier).length) &&
- (!fc.conditions.length ||
- fc.conditions.filter(cond => cond instanceof SpeciesFormChangeCondition && cond.predicate(p))
- .length) &&
- fc.preFormKey === p.getFormKey(),
+ ((fc.formKey.indexOf(SpeciesFormKey.MEGA) === -1
+ && fc.formKey.indexOf(SpeciesFormKey.PRIMAL) === -1)
+ || globalScene.getModifiers(MegaEvolutionAccessModifier).length > 0)
+ && ((fc.formKey.indexOf(SpeciesFormKey.GIGANTAMAX) === -1
+ && fc.formKey.indexOf(SpeciesFormKey.ETERNAMAX) === -1)
+ || globalScene.getModifiers(GigantamaxAccessModifier).length > 0)
+ && (fc.conditions.length === 0
+ || fc.conditions.filter(cond => cond instanceof SpeciesFormChangeCondition && cond.predicate(p))
+ .length > 0)
+ && fc.preFormKey === p.getFormKey(),
)
.map(fc => fc.findTrigger(SpeciesFormChangeItemTrigger) as SpeciesFormChangeItemTrigger)
.filter(
t =>
- t?.active &&
- !globalScene.findModifier(
+ t?.active
+ && !globalScene.findModifier(
m =>
- m instanceof PokemonFormChangeItemModifier &&
- m.pokemonId === p.id &&
- m.formChangeItem === t.item,
+ m instanceof PokemonFormChangeItemModifier
+ && m.pokemonId === p.id
+ && m.formChangeItem === t.item,
),
);
if (p.species.speciesId === SpeciesId.NECROZMA) {
// technically we could use a simplified version and check for formChanges.length > 3, but in case any code changes later, this might break...
- let foundULTRA_Z = false,
- foundN_LUNA = false,
- foundN_SOLAR = false;
+ let foundULTRA_Z = false;
+ let foundN_LUNA = false;
+ let foundN_SOLAR = false;
formChangeItemTriggers.forEach((fc, _i) => {
console.log("Checking ", fc.item);
switch (fc.item) {
@@ -1670,7 +1671,7 @@ export class FormChangeItemModifierTypeGenerator extends ModifierTypeGenerator {
.filter(i => (i && i < 100) === isRareFormChangeItem);
// convert it into a set to remove duplicate values, which can appear when the same species with a potential form change is in the party.
- if (!formChangeItemPool.length) {
+ if (formChangeItemPool.length === 0) {
return null;
}
@@ -1960,7 +1961,7 @@ const modifierTypeInitObj = Object.freeze({
if (pregenArgs && pregenArgs.length === 1 && pregenArgs[0] in PokemonType) {
return new TerastallizeModifierType(pregenArgs[0] as PokemonType);
}
- if (!globalScene.getModifiers(TerastallizeAccessModifier).length) {
+ if (globalScene.getModifiers(TerastallizeAccessModifier).length === 0) {
return null;
}
const teraTypes: PokemonType[] = [];
@@ -2399,10 +2400,10 @@ export function regenerateModifierPoolThresholds(party: Pokemon[], poolType: Mod
? weightedModifierType.modifierType.generateType(party)
: weightedModifierType.modifierType;
const weight =
- !existingModifiers.length ||
- itemModifierType instanceof PokemonHeldItemModifierType ||
- itemModifierType instanceof FormChangeItemModifierType ||
- existingModifiers.find(m => m.stackCount < m.getMaxStackCount(true))
+ existingModifiers.length === 0
+ || itemModifierType instanceof PokemonHeldItemModifierType
+ || itemModifierType instanceof FormChangeItemModifierType
+ || existingModifiers.find(m => m.stackCount < m.getMaxStackCount(true))
? weightedModifierType.weight instanceof Function
? // biome-ignore lint/complexity/noBannedTypes: TODO: refactor to not use Function type
(weightedModifierType.weight as Function)(party, rerollCount)
@@ -2524,16 +2525,16 @@ export function getPlayerModifierTypeOptions(
} else {
// Guaranteed mod options first
if (
- customModifierSettings?.guaranteedModifierTypeOptions &&
- customModifierSettings.guaranteedModifierTypeOptions.length > 0
+ customModifierSettings?.guaranteedModifierTypeOptions
+ && customModifierSettings.guaranteedModifierTypeOptions.length > 0
) {
options.push(...customModifierSettings.guaranteedModifierTypeOptions!);
}
// Guaranteed mod functions second
if (
- customModifierSettings.guaranteedModifierTypeFuncs &&
- customModifierSettings.guaranteedModifierTypeFuncs.length > 0
+ customModifierSettings.guaranteedModifierTypeFuncs
+ && customModifierSettings.guaranteedModifierTypeFuncs.length > 0
) {
customModifierSettings.guaranteedModifierTypeFuncs!.forEach((mod, _i) => {
const modifierId = Object.keys(modifierTypeInitObj).find(k => modifierTypeInitObj[k] === mod) as string;
@@ -2595,11 +2596,11 @@ function getModifierTypeOptionWithRetry(
applyChallenges(ChallengeType.WAVE_REWARD, candidate, candidateValidity);
let r = 0;
while (
- (existingOptions.length &&
- ++r < retryCount &&
- existingOptions.filter(o => o.type.name === candidate?.type.name || o.type.group === candidate?.type.group)
- .length) ||
- !candidateValidity.value
+ (existingOptions.length > 0
+ && ++r < retryCount
+ && existingOptions.filter(o => o.type.name === candidate?.type.name || o.type.group === candidate?.type.group)
+ .length > 0)
+ || !candidateValidity.value
) {
candidate = getNewModifierTypeOption(
party,
@@ -2703,9 +2704,9 @@ export function getEnemyBuffModifierForWave(
let r = 0;
let matchingModifier: PersistentModifier | undefined;
while (
- ++r < retryCount &&
- (matchingModifier = enemyModifiers.find(m => m.type.id === candidate?.type?.id)) &&
- matchingModifier.getMaxStackCount() < matchingModifier.stackCount + (r < 10 ? tierStackCount : 1)
+ ++r < retryCount
+ && (matchingModifier = enemyModifiers.find(m => m.type.id === candidate?.type?.id))
+ && matchingModifier.getMaxStackCount() < matchingModifier.stackCount + (r < 10 ? tierStackCount : 1)
) {
candidate = getNewModifierTypeOption([], ModifierPoolType.ENEMY_BUFF, tier);
}
@@ -2832,7 +2833,7 @@ function getNewModifierTypeOption(
}
tier += upgradeCount;
- while (tier && (!pool.hasOwnProperty(tier) || !pool[tier].length)) {
+ while (tier && (!pool.hasOwnProperty(tier) || pool[tier].length === 0)) {
tier--;
if (upgradeCount) {
upgradeCount--;
@@ -2843,7 +2844,7 @@ function getNewModifierTypeOption(
if (tier < ModifierTier.MASTER && allowLuckUpgrades) {
const partyLuckValue = getPartyLuckValue(party);
const upgradeOdds = Math.floor(128 / ((partyLuckValue + 4) / 4));
- while (pool.hasOwnProperty(tier + upgradeCount + 1) && pool[tier + upgradeCount + 1].length) {
+ while (pool.hasOwnProperty(tier + upgradeCount + 1) && pool[tier + upgradeCount + 1].length > 0) {
if (randSeedInt(upgradeOdds) < 4) {
upgradeCount++;
} else {
@@ -2858,7 +2859,7 @@ function getNewModifierTypeOption(
}
const tierThresholds = Object.keys(thresholds[tier]);
- const totalWeight = Number.parseInt(tierThresholds[tierThresholds.length - 1]);
+ const totalWeight = Number.parseInt(tierThresholds.at(-1)!);
const value = randSeedInt(totalWeight);
let index: number | undefined;
for (const t of tierThresholds) {
diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts
index 7d0478628b4..97291d4ed66 100644
--- a/src/modifier/modifier.ts
+++ b/src/modifier/modifier.ts
@@ -1302,9 +1302,9 @@ export class SpeciesStatBoosterModifier extends StatBoosterModifier {
*/
override shouldApply(pokemon: Pokemon, stat: Stat, statValue: NumberHolder): boolean {
return (
- super.shouldApply(pokemon, stat, statValue) &&
- (this.species.includes(pokemon.getSpeciesForm(true).speciesId) ||
- (pokemon.isFusion() && this.species.includes(pokemon.getFusionSpeciesForm(true).speciesId)))
+ super.shouldApply(pokemon, stat, statValue)
+ && (this.species.includes(pokemon.getSpeciesForm(true).speciesId)
+ || (pokemon.isFusion() && this.species.includes(pokemon.getFusionSpeciesForm(true).speciesId)))
);
}
@@ -1415,9 +1415,9 @@ export class SpeciesCritBoosterModifier extends CritBoosterModifier {
*/
override shouldApply(pokemon: Pokemon, critStage: NumberHolder): boolean {
return (
- super.shouldApply(pokemon, critStage) &&
- (this.species.includes(pokemon.getSpeciesForm(true).speciesId) ||
- (pokemon.isFusion() && this.species.includes(pokemon.getFusionSpeciesForm(true).speciesId)))
+ super.shouldApply(pokemon, critStage)
+ && (this.species.includes(pokemon.getSpeciesForm(true).speciesId)
+ || (pokemon.isFusion() && this.species.includes(pokemon.getFusionSpeciesForm(true).speciesId)))
);
}
}
@@ -1440,8 +1440,8 @@ export class AttackTypeBoosterModifier extends PokemonHeldItemModifier {
if (modifier instanceof AttackTypeBoosterModifier) {
const attackTypeBoosterModifier = modifier as AttackTypeBoosterModifier;
return (
- attackTypeBoosterModifier.moveType === this.moveType &&
- attackTypeBoosterModifier.boostMultiplier === this.boostMultiplier
+ attackTypeBoosterModifier.moveType === this.moveType
+ && attackTypeBoosterModifier.boostMultiplier === this.boostMultiplier
);
}
@@ -1471,10 +1471,10 @@ export class AttackTypeBoosterModifier extends PokemonHeldItemModifier {
*/
override shouldApply(pokemon?: Pokemon, moveType?: PokemonType, movePower?: NumberHolder): boolean {
return (
- super.shouldApply(pokemon, moveType, movePower) &&
- typeof moveType === "number" &&
- movePower instanceof NumberHolder &&
- this.moveType === moveType
+ super.shouldApply(pokemon, moveType, movePower)
+ && typeof moveType === "number"
+ && movePower instanceof NumberHolder
+ && this.moveType === moveType
);
}
@@ -2090,8 +2090,8 @@ export class TerastallizeModifier extends ConsumablePokemonModifier {
*/
override shouldApply(playerPokemon?: PlayerPokemon): boolean {
return (
- super.shouldApply(playerPokemon) &&
- [playerPokemon?.species.speciesId, playerPokemon?.fusionSpecies?.speciesId].filter(
+ super.shouldApply(playerPokemon)
+ && [playerPokemon?.species.speciesId, playerPokemon?.fusionSpecies?.speciesId].filter(
s => s === SpeciesId.TERAPAGOS || s === SpeciesId.OGERPON || s === SpeciesId.SHEDINJA,
).length === 0
);
@@ -2138,8 +2138,8 @@ export class PokemonHpRestoreModifier extends ConsumablePokemonModifier {
*/
override shouldApply(playerPokemon?: PlayerPokemon, multiplier?: number): boolean {
return (
- super.shouldApply(playerPokemon) &&
- (this.fainted || (!isNullOrUndefined(multiplier) && typeof multiplier === "number"))
+ super.shouldApply(playerPokemon)
+ && (this.fainted || (!isNullOrUndefined(multiplier) && typeof multiplier === "number"))
);
}
@@ -2159,8 +2159,11 @@ export class PokemonHpRestoreModifier extends ConsumablePokemonModifier {
pokemon.resetStatus(true, true, false, false);
}
pokemon.hp = Math.min(
- pokemon.hp +
- Math.max(Math.ceil(Math.max(Math.floor(this.restorePercent * 0.01 * pokemon.getMaxHp()), restorePoints)), 1),
+ pokemon.hp
+ + Math.max(
+ Math.ceil(Math.max(Math.floor(this.restorePercent * 0.01 * pokemon.getMaxHp()), restorePoints)),
+ 1,
+ ),
pokemon.getMaxHp(),
);
return true;
@@ -3210,7 +3213,7 @@ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier {
override apply(pokemon: Pokemon, target?: Pokemon, ..._args: unknown[]): boolean {
const opponents = this.getTargets(pokemon, target);
- if (!opponents.length) {
+ if (opponents.length === 0) {
return false;
}
@@ -3228,7 +3231,7 @@ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier {
) as PokemonHeldItemModifier[];
for (let i = 0; i < transferredItemCount; i++) {
- if (!itemModifiers.length) {
+ if (itemModifiers.length === 0) {
break;
}
const randItemIndex = pokemon.randBattleSeedInt(itemModifiers.length);
@@ -3243,7 +3246,7 @@ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier {
globalScene.phaseManager.queueMessage(this.getTransferMessage(pokemon, targetPokemon, mt));
}
- return !!transferredModifierTypes.length;
+ return transferredModifierTypes.length > 0;
}
abstract getTransferredItemCount(): number;
diff --git a/src/phase-manager.ts b/src/phase-manager.ts
index 281ac8bd671..4bb7e0a4b37 100644
--- a/src/phase-manager.ts
+++ b/src/phase-manager.ts
@@ -1,3 +1,4 @@
+import { PHASE_START_COLOR } from "#app/constants/colors";
import { globalScene } from "#app/global-scene";
import type { Phase } from "#app/phase";
import { type PhasePriorityQueue, PostSummonPhasePriorityQueue } from "#data/phase-priority-queue";
@@ -102,10 +103,13 @@ import { WeatherEffectPhase } from "#phases/weather-effect-phase";
import type { PhaseMap, PhaseString } from "#types/phase-types";
import { type Constructor, coerceArray } from "#utils/common";
-/*
+/**
+ * @module
* Manager for phases used by battle scene.
*
- * *This file must not be imported or used directly. The manager is exclusively used by the battle scene and is not intended for external use.*
+ * @remarks
+ * **This file must not be imported or used directly.**
+ * The manager is exclusively used by the Battle Scene and is NOT intended for external use.
*/
/**
@@ -376,7 +380,7 @@ export class PhaseManager {
this.conditionalQueue = unactivatedConditionalPhases;
// If no phases are left, unshift phases to start a new turn.
- if (!this.phaseQueue.length) {
+ if (this.phaseQueue.length === 0) {
this.populatePhaseQueue();
// Clear the conditionalQueue if there are no phases left in the phaseQueue
this.conditionalQueue = [];
@@ -392,7 +396,7 @@ export class PhaseManager {
* Helper method to start and log the current phase.
*/
private startCurrentPhase(): void {
- console.log(`%cStart Phase ${this.currentPhase.phaseName}`, "color:green;");
+ console.log(`%cStart Phase ${this.currentPhase.phaseName}`, `color:${PHASE_START_COLOR};`);
this.currentPhase.start();
}
@@ -619,7 +623,7 @@ export class PhaseManager {
* Moves everything from nextCommandPhaseQueue to phaseQueue (keeping order)
*/
private populatePhaseQueue(): void {
- if (this.nextCommandPhaseQueue.length) {
+ if (this.nextCommandPhaseQueue.length > 0) {
this.phaseQueue.push(...this.nextCommandPhaseQueue);
this.nextCommandPhaseQueue.splice(0, this.nextCommandPhaseQueue.length);
}
diff --git a/src/phases/attempt-capture-phase.ts b/src/phases/attempt-capture-phase.ts
index 699caa2af21..81f85850e88 100644
--- a/src/phases/attempt-capture-phase.ts
+++ b/src/phases/attempt-capture-phase.ts
@@ -21,9 +21,9 @@ import type { EnemyPokemon } from "#field/pokemon";
import { PokemonHeldItemModifier } from "#modifiers/modifier";
import { PokemonPhase } from "#phases/pokemon-phase";
import { achvs } from "#system/achv";
-import type { PartyOption } from "#ui/party-ui-handler";
-import { PartyUiMode } from "#ui/party-ui-handler";
-import { SummaryUiMode } from "#ui/summary-ui-handler";
+import type { PartyOption } from "#ui/handlers/party-ui-handler";
+import { PartyUiMode } from "#ui/handlers/party-ui-handler";
+import { SummaryUiMode } from "#ui/handlers/summary-ui-handler";
import { applyChallenges } from "#utils/challenge-utils";
import { BooleanHolder } from "#utils/common";
import i18next from "i18next";
@@ -136,10 +136,10 @@ export class AttemptCapturePhase extends PokemonPhase {
} else if (shakeCount++ < (isCritical ? 1 : 3)) {
// Shake check (skip check for critical or guaranteed captures, but still play the sound)
if (
- pokeballMultiplier === -1 ||
- isCritical ||
- modifiedCatchRate >= 255 ||
- pokemon.randBattleSeedInt(65536) < shakeProbability
+ pokeballMultiplier === -1
+ || isCritical
+ || modifiedCatchRate >= 255
+ || pokemon.randBattleSeedInt(65536) < shakeProbability
) {
globalScene.playSound("se/pb_move");
} else {
@@ -231,8 +231,9 @@ export class AttemptCapturePhase extends PokemonPhase {
const speciesForm = !pokemon.fusionSpecies ? pokemon.getSpeciesForm() : pokemon.getFusionSpeciesForm();
if (
- speciesForm.abilityHidden &&
- (pokemon.fusionSpecies ? pokemon.fusionAbilityIndex : pokemon.abilityIndex) === speciesForm.getAbilityCount() - 1
+ speciesForm.abilityHidden
+ && (pokemon.fusionSpecies ? pokemon.fusionAbilityIndex : pokemon.abilityIndex)
+ === speciesForm.getAbilityCount() - 1
) {
globalScene.validateAchv(achvs.HIDDEN_ABILITY);
}
diff --git a/src/phases/battle-end-phase.ts b/src/phases/battle-end-phase.ts
index 2dbb74c4a85..8a798d67554 100644
--- a/src/phases/battle-end-phase.ts
+++ b/src/phases/battle-end-phase.ts
@@ -38,8 +38,8 @@ export class BattleEndPhase extends BattlePhase {
globalScene.gameData.gameStats.battles++;
if (
- globalScene.gameMode.isEndless &&
- globalScene.currentBattle.waveIndex + 1 > globalScene.gameData.gameStats.highestEndlessWave
+ globalScene.gameMode.isEndless
+ && globalScene.currentBattle.waveIndex + 1 > globalScene.gameData.gameStats.highestEndlessWave
) {
globalScene.gameData.gameStats.highestEndlessWave = globalScene.currentBattle.waveIndex + 1;
}
diff --git a/src/phases/check-switch-phase.ts b/src/phases/check-switch-phase.ts
index f4e8ee56c55..504bb6eb4bd 100644
--- a/src/phases/check-switch-phase.ts
+++ b/src/phases/check-switch-phase.ts
@@ -39,19 +39,19 @@ export class CheckSwitchPhase extends BattlePhase {
// ...if there are no other allowed Pokemon in the player's party to switch with
if (
- !globalScene
+ globalScene
.getPlayerParty()
.slice(1)
- .filter(p => p.isActive()).length
+ .filter(p => p.isActive()).length === 0
) {
return super.end();
}
// ...or if any player Pokemon has an effect that prevents the checked Pokemon from switching
if (
- pokemon.getTag(BattlerTagType.FRENZY) ||
- pokemon.isTrapped() ||
- globalScene.getPlayerField().some(p => p.getTag(BattlerTagType.COMMANDED))
+ pokemon.getTag(BattlerTagType.FRENZY)
+ || pokemon.isTrapped()
+ || globalScene.getPlayerField().some(p => p.getTag(BattlerTagType.COMMANDED))
) {
return super.end();
}
diff --git a/src/phases/command-phase.ts b/src/phases/command-phase.ts
index 37e07c6c282..b9867e22522 100644
--- a/src/phases/command-phase.ts
+++ b/src/phases/command-phase.ts
@@ -62,8 +62,8 @@ export class CommandPhase extends FieldPhase {
return;
}
if (
- (turn === 1 && (!commandCursorMemory || cursorResetEvent)) ||
- commandUiHandler.getCursor() === Command.POKEMON
+ (turn === 1 && (!commandCursorMemory || cursorResetEvent))
+ || commandUiHandler.getCursor() === Command.POKEMON
) {
commandUiHandler.setCursor(Command.FIGHT);
}
@@ -98,8 +98,8 @@ export class CommandPhase extends FieldPhase {
private checkCommander(): void {
// If the Pokemon has applied Commander's effects to its ally, skip this command
if (
- globalScene.currentBattle?.double &&
- this.getPokemon().getAlly()?.getTag(BattlerTagType.COMMANDED)?.getSourcePokemon() === this.getPokemon()
+ globalScene.currentBattle?.double
+ && this.getPokemon().getAlly()?.getTag(BattlerTagType.COMMANDED)?.getSourcePokemon() === this.getPokemon()
) {
globalScene.currentBattle.turnCommands[this.fieldIndex] = {
command: Command.FIGHT,
@@ -125,9 +125,9 @@ export class CommandPhase extends FieldPhase {
for (const queuedMove of moveQueue) {
const movesetQueuedMove = moveset.find(m => m.moveId === queuedMove.move);
if (
- queuedMove.move !== MoveId.NONE &&
- !isVirtual(queuedMove.useMode) &&
- !movesetQueuedMove?.isUsable(playerPokemon, isIgnorePP(queuedMove.useMode))
+ queuedMove.move !== MoveId.NONE
+ && !isVirtual(queuedMove.useMode)
+ && !movesetQueuedMove?.isUsable(playerPokemon, isIgnorePP(queuedMove.useMode))
) {
entriesToDelete++;
} else {
@@ -194,8 +194,8 @@ export class CommandPhase extends FieldPhase {
}
if (
- globalScene.currentBattle.isBattleMysteryEncounter() &&
- globalScene.currentBattle.mysteryEncounter?.skipToFightInput
+ globalScene.currentBattle.isBattleMysteryEncounter()
+ && globalScene.currentBattle.mysteryEncounter?.skipToFightInput
) {
globalScene.ui.clearText();
globalScene.ui.setMode(UiMode.FIGHT, this.fieldIndex);
@@ -233,7 +233,7 @@ export class CommandPhase extends FieldPhase {
const moveName = move.getName().replace(" (N)", ""); // Trims off the indicator
globalScene.ui.showText(
- i18next.t(cannotSelectKey, { moveName: moveName }),
+ i18next.t(cannotSelectKey, { moveName }),
null,
() => {
globalScene.ui.clearText();
@@ -335,9 +335,9 @@ export class CommandPhase extends FieldPhase {
if (turnCommand.move && (moveTargets.targets.length <= 1 || moveTargets.multiple)) {
turnCommand.move.targets = moveTargets.targets;
} else if (
- turnCommand.move &&
- playerPokemon.getTag(BattlerTagType.CHARGING) &&
- playerPokemon.getMoveQueue().length >= 1
+ turnCommand.move
+ && playerPokemon.getTag(BattlerTagType.CHARGING)
+ && playerPokemon.getMoveQueue().length > 0
) {
turnCommand.move.targets = playerPokemon.getMoveQueue()[0].targets;
} else {
@@ -402,17 +402,17 @@ export class CommandPhase extends FieldPhase {
if (biomeType === BiomeId.END && battleType === BattleType.WILD) {
if (
- (isClassic && !isClassicFinalBoss && someUncaughtSpeciesOnField) ||
- (isFullFreshStart && !isClassicFinalBoss) ||
- (isEndless && !isEndlessMinorBoss)
+ (isClassic && !isClassicFinalBoss && someUncaughtSpeciesOnField)
+ || (isFullFreshStart && !isClassicFinalBoss)
+ || (isEndless && !isEndlessMinorBoss)
) {
// Uncatchable paradox mons in classic and endless
this.queueShowText("battle:noPokeballForce");
} else if (
- (isClassic && isClassicFinalBoss && missingMultipleStarters) ||
- (isFullFreshStart && isClassicFinalBoss) ||
- (isEndless && isEndlessMinorBoss) ||
- isDaily
+ (isClassic && isClassicFinalBoss && missingMultipleStarters)
+ || (isFullFreshStart && isClassicFinalBoss)
+ || (isEndless && isEndlessMinorBoss)
+ || isDaily
) {
// Uncatchable final boss in classic, endless and daily
this.queueShowText("battle:noPokeballForceFinalBoss");
@@ -458,16 +458,15 @@ export class CommandPhase extends FieldPhase {
if (cursor < numBallTypes) {
const targetPokemon = globalScene.getEnemyPokemon(false);
if (
- targetPokemon?.isBoss() &&
- targetPokemon?.bossSegmentIndex >= 1 &&
- // TODO: Decouple this hardcoded exception for wonder guard and just check the target...
- !targetPokemon?.hasAbility(AbilityId.WONDER_GUARD, false, true)
+ targetPokemon?.isBoss()
+ && targetPokemon?.bossSegmentIndex >= 1 // TODO: Decouple this hardcoded exception for wonder guard and just check the target...
+ && !targetPokemon?.hasAbility(AbilityId.WONDER_GUARD, false, true)
) {
// When facing the final boss, it must be weakened unless a Master Ball is used AND no challenges are active.
// The message is customized for the final boss.
if (
- isFinalBoss &&
- (cursor < PokeballType.MASTER_BALL || (cursor === PokeballType.MASTER_BALL && isChallengeActive))
+ isFinalBoss
+ && (cursor < PokeballType.MASTER_BALL || (cursor === PokeballType.MASTER_BALL && isChallengeActive))
) {
this.queueShowText("battle:noPokeballForceFinalBossCatchable");
return false;
@@ -481,7 +480,7 @@ export class CommandPhase extends FieldPhase {
globalScene.currentBattle.turnCommands[this.fieldIndex] = {
command: Command.BALL,
- cursor: cursor,
+ cursor,
};
globalScene.currentBattle.turnCommands[this.fieldIndex]!.targets = targets;
if (this.fieldIndex) {
@@ -593,8 +592,8 @@ export class CommandPhase extends FieldPhase {
return false;
}
if (
- currentBattle.battleType === BattleType.TRAINER ||
- currentBattle.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE
+ currentBattle.battleType === BattleType.TRAINER
+ || currentBattle.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE
) {
this.queueShowText("battle:noEscapeTrainer");
return false;
@@ -641,9 +640,8 @@ export class CommandPhase extends FieldPhase {
* @returns Whether the command was successful
*/
handleCommand(command: Command.FIGHT | Command.TERA, cursor: number, useMode?: MoveUseMode, move?: TurnMove): boolean;
- handleCommand(command: Command.BALL, cursor: number): boolean;
handleCommand(command: Command.POKEMON, cursor: number, useBaton: boolean): boolean;
- handleCommand(command: Command.RUN, cursor: number): boolean;
+ handleCommand(command: Command.BALL | Command.RUN, cursor: number): boolean;
handleCommand(command: Command, cursor: number, useMode?: boolean | MoveUseMode, move?: TurnMove): boolean;
public handleCommand(
diff --git a/src/phases/common-anim-phase.ts b/src/phases/common-anim-phase.ts
index 78da1dcfa2f..c5359fac0f3 100644
--- a/src/phases/common-anim-phase.ts
+++ b/src/phases/common-anim-phase.ts
@@ -10,19 +10,12 @@ export class CommonAnimPhase extends PokemonPhase {
public readonly phaseName: "CommonAnimPhase" | "PokemonHealPhase" | "WeatherEffectPhase" = "CommonAnimPhase";
private anim: CommonAnim | null;
private targetIndex?: BattlerIndex;
- private playOnEmptyField: boolean;
- constructor(
- battlerIndex?: BattlerIndex,
- targetIndex?: BattlerIndex,
- anim: CommonAnim | null = null,
- playOnEmptyField = false,
- ) {
+ constructor(battlerIndex?: BattlerIndex, targetIndex?: BattlerIndex, anim: CommonAnim | null = null) {
super(battlerIndex);
this.anim = anim;
this.targetIndex = targetIndex;
- this.playOnEmptyField = playOnEmptyField;
}
setAnimation(anim: CommonAnim) {
diff --git a/src/phases/egg-hatch-phase.ts b/src/phases/egg-hatch-phase.ts
index 547ca778c6b..68c60abc0dc 100644
--- a/src/phases/egg-hatch-phase.ts
+++ b/src/phases/egg-hatch-phase.ts
@@ -9,9 +9,9 @@ import { doShinySparkleAnim } from "#field/anims";
import type { PlayerPokemon } from "#field/pokemon";
import type { EggLapsePhase } from "#phases/egg-lapse-phase";
import { achvs } from "#system/achv";
-import { EggCounterContainer } from "#ui/egg-counter-container";
-import type { EggHatchSceneHandler } from "#ui/egg-hatch-scene-handler";
-import { PokemonInfoContainer } from "#ui/pokemon-info-container";
+import { EggCounterContainer } from "#ui/containers/egg-counter-container";
+import { PokemonInfoContainer } from "#ui/containers/pokemon-info-container";
+import type { EggHatchSceneHandler } from "#ui/handlers/egg-hatch-scene-handler";
import { fixedInt, getFrameMs, randInt } from "#utils/common";
import i18next from "i18next";
import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
@@ -230,6 +230,7 @@ export class EggHatchPhase extends Phase {
} else {
globalScene.time.delayedCall(250, () => globalScene.setModifiersVisible(true));
}
+ this.pokemon?.destroy();
super.end();
}
diff --git a/src/phases/egg-summary-phase.ts b/src/phases/egg-summary-phase.ts
index c236c5c3abc..d771c8599b4 100644
--- a/src/phases/egg-summary-phase.ts
+++ b/src/phases/egg-summary-phase.ts
@@ -39,6 +39,10 @@ export class EggSummaryPhase extends Phase {
}
end() {
+ this.eggHatchData.forEach(data => {
+ data.pokemon?.destroy();
+ });
+ this.eggHatchData = [];
globalScene.time.delayedCall(250, () => globalScene.setModifiersVisible(true));
globalScene.ui.setModeForceTransition(UiMode.MESSAGE).then(() => {
super.end();
diff --git a/src/phases/encounter-phase.ts b/src/phases/encounter-phase.ts
index b870f7f6e7a..0918ced65e5 100644
--- a/src/phases/encounter-phase.ts
+++ b/src/phases/encounter-phase.ts
@@ -111,10 +111,10 @@ export class EncounterPhase extends BattlePhase {
let enemySpecies = globalScene.randomSpecies(battle.waveIndex, level, true);
// If player has golden bug net, rolls 10% chance to replace non-boss wave wild species from the golden bug net bug pool
if (
- globalScene.findModifier(m => m instanceof BoostBugSpawnModifier) &&
- !globalScene.gameMode.isBoss(battle.waveIndex) &&
- globalScene.arena.biomeType !== BiomeId.END &&
- randSeedInt(10) === 0
+ globalScene.findModifier(m => m instanceof BoostBugSpawnModifier)
+ && !globalScene.gameMode.isBoss(battle.waveIndex)
+ && globalScene.arena.biomeType !== BiomeId.END
+ && randSeedInt(10) === 0
) {
enemySpecies = getGoldenBugNetSpecies(level);
}
@@ -146,15 +146,15 @@ export class EncounterPhase extends BattlePhase {
globalScene.gameData.setPokemonSeen(
enemyPokemon,
true,
- battle.battleType === BattleType.TRAINER ||
- battle?.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE,
+ battle.battleType === BattleType.TRAINER
+ || battle?.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE,
);
}
if (enemyPokemon.species.speciesId === SpeciesId.ETERNATUS) {
if (
- globalScene.gameMode.isClassic &&
- (battle.battleSpec === BattleSpec.FINAL_BOSS || globalScene.gameMode.isWaveFinal(battle.waveIndex))
+ globalScene.gameMode.isClassic
+ && (battle.battleSpec === BattleSpec.FINAL_BOSS || globalScene.gameMode.isWaveFinal(battle.waveIndex))
) {
if (battle.battleSpec !== BattleSpec.FINAL_BOSS) {
enemyPokemon.formIndex = 1;
@@ -320,8 +320,8 @@ export class EncounterPhase extends BattlePhase {
const { battleType, waveIndex } = globalScene.currentBattle;
if (
- globalScene.isMysteryEncounterValidForWave(battleType, waveIndex) &&
- !globalScene.currentBattle.isBattleMysteryEncounter()
+ globalScene.isMysteryEncounterValidForWave(battleType, waveIndex)
+ && !globalScene.currentBattle.isBattleMysteryEncounter()
) {
// Increment ME spawn chance if an ME could have spawned but did not
// Only do this AFTER session has been saved to avoid duplicating increments
@@ -442,28 +442,27 @@ export class EncounterPhase extends BattlePhase {
}
};
- const encounterMessages = globalScene.currentBattle.trainer?.getEncounterMessages();
+ const encounterMessages = trainer?.getEncounterMessages() ?? [];
- if (!encounterMessages?.length) {
+ if (encounterMessages.length === 0) {
doSummon();
} else {
- let message: string;
+ let message = "";
globalScene.executeWithSeedOffset(
() => (message = randSeedItem(encounterMessages)),
globalScene.currentBattle.waveIndex,
);
- message = message!; // tell TS compiler it's defined now
const showDialogueAndSummon = () => {
globalScene.ui.showDialogue(message, trainer?.getName(TrainerSlot.NONE, true), null, () => {
globalScene.charSprite.hide().then(() => globalScene.hideFieldOverlay(250).then(() => doSummon()));
});
};
- if (globalScene.currentBattle.trainer?.config.hasCharSprite && !globalScene.ui.shouldSkipDialogue(message)) {
+ if (trainer?.config.hasCharSprite && !globalScene.ui.shouldSkipDialogue(message)) {
globalScene
.showFieldOverlay(500)
.then(() =>
globalScene.charSprite
- .showCharacter(trainer?.getKey()!, getCharVariantFromDialogue(encounterMessages[0]))
+ .showCharacter(trainer.getKey()!, getCharVariantFromDialogue(encounterMessages[0]))
.then(() => showDialogueAndSummon()),
); // TODO: is this bang correct?
} else {
@@ -549,9 +548,9 @@ export class EncounterPhase extends BattlePhase {
}
/** This sets Eternatus' held item to be untransferrable, preventing it from being stolen */
if (
- enemyPokemon.species.speciesId === SpeciesId.ETERNATUS &&
- (globalScene.gameMode.isBattleClassicFinalBoss(globalScene.currentBattle.waveIndex) ||
- globalScene.gameMode.isEndlessMajorBoss(globalScene.currentBattle.waveIndex))
+ enemyPokemon.species.speciesId === SpeciesId.ETERNATUS
+ && (globalScene.gameMode.isBattleClassicFinalBoss(globalScene.currentBattle.waveIndex)
+ || globalScene.gameMode.isEndlessMajorBoss(globalScene.currentBattle.waveIndex))
) {
const enemyMBH = globalScene.findModifier(
m => m instanceof TurnHeldItemTransferModifier,
@@ -571,7 +570,7 @@ export class EncounterPhase extends BattlePhase {
globalScene.phaseManager.create("PostSummonPhase", p.getBattlerIndex()),
() => {
// if there is not a player party, we can't continue
- if (!globalScene.getPlayerParty().length) {
+ if (globalScene.getPlayerParty().length === 0) {
return false;
}
// how many player pokemon are on the field ?
@@ -617,8 +616,8 @@ export class EncounterPhase extends BattlePhase {
}
if (
- globalScene.currentBattle.battleType !== BattleType.TRAINER &&
- (globalScene.currentBattle.waveIndex > 1 || !globalScene.gameMode.isDaily)
+ globalScene.currentBattle.battleType !== BattleType.TRAINER
+ && (globalScene.currentBattle.waveIndex > 1 || !globalScene.gameMode.isDaily)
) {
const minPartySize = globalScene.currentBattle.double ? 2 : 1;
if (availablePartyMembers.length > minPartySize) {
@@ -651,7 +650,7 @@ export class EncounterPhase extends BattlePhase {
const ordinalUsed =
!i18next.exists(localizationKey, { fallbackLng: [] }) || i18next.resolvedLanguage === "en"
? i18next.t("battleSpecDialogue:key", {
- count: count,
+ count,
ordinal: true,
})
: "";
@@ -660,7 +659,7 @@ export class EncounterPhase extends BattlePhase {
const genderStr = PlayerGender[genderIndex].toLowerCase();
const encounterDialogue = i18next.t(localizationKey, {
context: genderStr,
- cycleCount: cycleCount,
+ cycleCount,
});
if (!globalScene.gameData.getSeenDialogues()[localizationKey]) {
globalScene.gameData.saveSeenDialogue(localizationKey);
diff --git a/src/phases/enemy-command-phase.ts b/src/phases/enemy-command-phase.ts
index 7e4dff37b0f..1214ce67937 100644
--- a/src/phases/enemy-command-phase.ts
+++ b/src/phases/enemy-command-phase.ts
@@ -38,9 +38,9 @@ export class EnemyCommandPhase extends FieldPhase {
const trainer = battle.trainer;
if (
- battle.double &&
- enemyPokemon.hasAbility(AbilityId.COMMANDER) &&
- enemyPokemon.getAlly()?.getTag(BattlerTagType.COMMANDED)
+ battle.double
+ && enemyPokemon.hasAbility(AbilityId.COMMANDER)
+ && enemyPokemon.getAlly()?.getTag(BattlerTagType.COMMANDED)
) {
this.skipTurn = true;
}
@@ -54,13 +54,13 @@ export class EnemyCommandPhase extends FieldPhase {
* member's matchup score is 3x the active enemy's score (or 2x for "boss" trainers),
* the enemy will switch to that Pokemon.
*/
- if (trainer && !enemyPokemon.getMoveQueue().length) {
+ if (trainer && enemyPokemon.getMoveQueue().length === 0) {
const opponents = enemyPokemon.getOpponents();
if (!enemyPokemon.isTrapped()) {
const partyMemberScores = trainer.getPartyMemberMatchupScores(enemyPokemon.trainerSlot, true);
- if (partyMemberScores.length) {
+ if (partyMemberScores.length > 0) {
const matchupScores = opponents.map(opp => enemyPokemon.getMatchupScore(opp));
const matchupScore = matchupScores.reduce((total, score) => (total += score), 0) / matchupScores.length;
diff --git a/src/phases/evolution-phase.ts b/src/phases/evolution-phase.ts
index 6095dfafa21..7d7301bbeca 100644
--- a/src/phases/evolution-phase.ts
+++ b/src/phases/evolution-phase.ts
@@ -10,7 +10,7 @@ import { LearnMoveSituation } from "#enums/learn-move-situation";
import { UiMode } from "#enums/ui-mode";
import { cos, sin } from "#field/anims";
import type { PlayerPokemon, Pokemon } from "#field/pokemon";
-import type { EvolutionSceneHandler } from "#ui/evolution-scene-handler";
+import type { EvolutionSceneHandler } from "#ui/handlers/evolution-scene-handler";
import { fixedInt, getFrameMs, randInt } from "#utils/common";
import i18next from "i18next";
import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
diff --git a/src/phases/faint-phase.ts b/src/phases/faint-phase.ts
index 2d953043866..349dfcfa8e5 100644
--- a/src/phases/faint-phase.ts
+++ b/src/phases/faint-phase.ts
@@ -89,13 +89,13 @@ export class FaintPhase extends PokemonPhase {
if (pokemon.isPlayer()) {
globalScene.arena.playerFaints += 1;
globalScene.currentBattle.playerFaintsHistory.push({
- pokemon: pokemon,
+ pokemon,
turn: globalScene.currentBattle.turn,
});
} else {
globalScene.currentBattle.enemyFaints += 1;
globalScene.currentBattle.enemyFaintsHistory.push({
- pokemon: pokemon,
+ pokemon,
turn: globalScene.currentBattle.turn,
});
}
@@ -112,10 +112,10 @@ export class FaintPhase extends PokemonPhase {
pokemon.resetTera();
// TODO: this can be simplified by just checking whether lastAttack is defined
- if (pokemon.turnData.attacksReceived?.length) {
+ if (pokemon.turnData.attacksReceived?.length > 0) {
const lastAttack = pokemon.turnData.attacksReceived[0];
applyAbAttrs("PostFaintAbAttr", {
- pokemon: pokemon,
+ pokemon,
// TODO: We should refactor lastAttack's sourceId to forbid null and just use undefined
attacker: globalScene.getPokemonById(lastAttack.sourceId) ?? undefined,
// TODO: improve the way that we provide the move that knocked out the pokemon...
@@ -131,14 +131,14 @@ export class FaintPhase extends PokemonPhase {
for (const p of alivePlayField) {
applyAbAttrs("PostKnockOutAbAttr", { pokemon: p, victim: pokemon });
}
- if (pokemon.turnData.attacksReceived?.length) {
+ if (pokemon.turnData.attacksReceived?.length > 0) {
const defeatSource = this.source;
if (defeatSource?.isOnField()) {
applyAbAttrs("PostVictoryAbAttr", { pokemon: defeatSource });
const pvmove = allMoves[pokemon.turnData.attacksReceived[0].move];
const pvattrs = pvmove.getAttrs("PostVictoryStatStageChangeAttr");
- if (pvattrs.length) {
+ if (pvattrs.length > 0) {
for (const pvattr of pvattrs) {
pvattr.applyPostVictory(defeatSource, defeatSource, pvmove);
}
@@ -151,13 +151,13 @@ export class FaintPhase extends PokemonPhase {
const legalPlayerPokemon = globalScene.getPokemonAllowedInBattle();
/** The total number of legal player Pokemon that aren't currently on the field */
const legalPlayerPartyPokemon = legalPlayerPokemon.filter(p => !p.isActive(true));
- if (!legalPlayerPokemon.length) {
+ if (legalPlayerPokemon.length === 0) {
/** If the player doesn't have any legal Pokemon, end the game */
globalScene.phaseManager.unshiftNew("GameOverPhase");
} else if (
- globalScene.currentBattle.double &&
- legalPlayerPokemon.length === 1 &&
- legalPlayerPartyPokemon.length === 0
+ globalScene.currentBattle.double
+ && legalPlayerPokemon.length === 1
+ && legalPlayerPartyPokemon.length === 0
) {
/**
* If the player has exactly one Pokemon in total at this point in a double battle, and that Pokemon
@@ -174,10 +174,11 @@ export class FaintPhase extends PokemonPhase {
} else {
globalScene.phaseManager.unshiftNew("VictoryPhase", this.battlerIndex);
if ([BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(globalScene.currentBattle.battleType)) {
- const hasReservePartyMember = !!globalScene
- .getEnemyParty()
- .filter(p => p.isActive() && !p.isOnField() && p.trainerSlot === (pokemon as EnemyPokemon).trainerSlot)
- .length;
+ const hasReservePartyMember =
+ globalScene
+ .getEnemyParty()
+ .filter(p => p.isActive() && !p.isOnField() && p.trainerSlot === (pokemon as EnemyPokemon).trainerSlot)
+ .length > 0;
if (hasReservePartyMember) {
globalScene.phaseManager.pushNew("SwitchSummonPhase", SwitchType.SWITCH, this.fieldIndex, -1, false, false);
}
diff --git a/src/phases/form-change-phase.ts b/src/phases/form-change-phase.ts
index 7b7f5a6dac6..7521adee6c9 100644
--- a/src/phases/form-change-phase.ts
+++ b/src/phases/form-change-phase.ts
@@ -8,7 +8,7 @@ import { UiMode } from "#enums/ui-mode";
import type { PlayerPokemon, Pokemon } from "#field/pokemon";
import { EvolutionPhase } from "#phases/evolution-phase";
import { achvs } from "#system/achv";
-import type { PartyUiHandler } from "#ui/party-ui-handler";
+import type { PartyUiHandler } from "#ui/handlers/party-ui-handler";
import { fixedInt } from "#utils/common";
export class FormChangePhase extends EvolutionPhase {
@@ -76,8 +76,8 @@ export class FormChangePhase extends EvolutionPhase {
globalScene.validateAchv(achvs.MEGA_EVOLVE);
playEvolutionFanfare = true;
} else if (
- this.formChange.formKey.indexOf(SpeciesFormKey.GIGANTAMAX) > -1 ||
- this.formChange.formKey.indexOf(SpeciesFormKey.ETERNAMAX) > -1
+ this.formChange.formKey.indexOf(SpeciesFormKey.GIGANTAMAX) > -1
+ || this.formChange.formKey.indexOf(SpeciesFormKey.ETERNAMAX) > -1
) {
globalScene.validateAchv(achvs.GIGANTAMAX);
playEvolutionFanfare = true;
diff --git a/src/phases/game-over-phase.ts b/src/phases/game-over-phase.ts
index 89162e591fc..57ebd40b559 100644
--- a/src/phases/game-over-phase.ts
+++ b/src/phases/game-over-phase.ts
@@ -52,9 +52,9 @@ export class GameOverPhase extends BattlePhase {
// Handle Mystery Encounter special Game Over cases
// Situations such as when player lost a battle, but it isn't treated as full Game Over
if (
- !this.isVictory &&
- globalScene.currentBattle.mysteryEncounter?.onGameOver &&
- !globalScene.currentBattle.mysteryEncounter.onGameOver()
+ !this.isVictory
+ && globalScene.currentBattle.mysteryEncounter?.onGameOver
+ && !globalScene.currentBattle.mysteryEncounter.onGameOver()
) {
// Do not end the game
return this.end();
@@ -90,8 +90,8 @@ export class GameOverPhase extends BattlePhase {
globalScene.phaseManager.pushNew("SummonPhase", 1);
}
if (
- globalScene.currentBattle.waveIndex > 1 &&
- globalScene.currentBattle.battleType !== BattleType.TRAINER
+ globalScene.currentBattle.waveIndex > 1
+ && globalScene.currentBattle.battleType !== BattleType.TRAINER
) {
globalScene.phaseManager.pushNew("CheckSwitchPhase", 0, globalScene.currentBattle.double);
if (globalScene.currentBattle.double && availablePartyMembers > 1) {
@@ -204,7 +204,7 @@ export class GameOverPhase extends BattlePhase {
}
this.getRunHistoryEntry().then(runHistoryEntry => {
globalScene.gameData.saveRunHistory(runHistoryEntry, this.isVictory);
- globalScene.phaseManager.pushNew("PostGameOverPhase", endCardPhase);
+ globalScene.phaseManager.pushNew("PostGameOverPhase", globalScene.sessionSlotId, endCardPhase);
this.end();
});
};
@@ -262,7 +262,7 @@ export class GameOverPhase extends BattlePhase {
.newclear({
slot: globalScene.sessionSlotId,
isVictory: this.isVictory,
- clientSessionId: clientSessionId,
+ clientSessionId,
})
.then(success => doGameOver(!globalScene.gameMode.isDaily || !!success))
.catch(_err => {
@@ -290,8 +290,8 @@ export class GameOverPhase extends BattlePhase {
globalScene.phaseManager.unshiftNew("UnlockPhase", Unlockables.ENDLESS_MODE);
}
if (
- globalScene.getPlayerParty().filter(p => p.fusionSpecies).length &&
- !globalScene.gameData.unlocks[Unlockables.SPLICED_ENDLESS_MODE]
+ globalScene.getPlayerParty().filter(p => p.fusionSpecies).length > 0
+ && !globalScene.gameData.unlocks[Unlockables.SPLICED_ENDLESS_MODE]
) {
globalScene.phaseManager.unshiftNew("UnlockPhase", Unlockables.SPLICED_ENDLESS_MODE);
}
@@ -299,8 +299,8 @@ export class GameOverPhase extends BattlePhase {
globalScene.phaseManager.unshiftNew("UnlockPhase", Unlockables.MINI_BLACK_HOLE);
}
if (
- !globalScene.gameData.unlocks[Unlockables.EVIOLITE] &&
- globalScene.getPlayerParty().some(p => p.getSpeciesForm(true).speciesId in pokemonEvolutions)
+ !globalScene.gameData.unlocks[Unlockables.EVIOLITE]
+ && globalScene.getPlayerParty().some(p => p.getSpeciesForm(true).speciesId in pokemonEvolutions)
) {
globalScene.phaseManager.unshiftNew("UnlockPhase", Unlockables.EVIOLITE);
}
diff --git a/src/phases/learn-move-phase.ts b/src/phases/learn-move-phase.ts
index a714d247730..a16e12ba058 100644
--- a/src/phases/learn-move-phase.ts
+++ b/src/phases/learn-move-phase.ts
@@ -10,8 +10,8 @@ import { UiMode } from "#enums/ui-mode";
import type { Pokemon } from "#field/pokemon";
import type { Move } from "#moves/move";
import { PlayerPartyMemberPokemonPhase } from "#phases/player-party-member-pokemon-phase";
-import { EvolutionSceneHandler } from "#ui/evolution-scene-handler";
-import { SummaryUiMode } from "#ui/summary-ui-handler";
+import { EvolutionSceneHandler } from "#ui/handlers/evolution-scene-handler";
+import { SummaryUiMode } from "#ui/handlers/summary-ui-handler";
import i18next from "i18next";
export class LearnMovePhase extends PlayerPartyMemberPokemonPhase {
diff --git a/src/phases/move-effect-phase.ts b/src/phases/move-effect-phase.ts
index c8dcbae907c..0600f7d5ecf 100644
--- a/src/phases/move-effect-phase.ts
+++ b/src/phases/move-effect-phase.ts
@@ -92,7 +92,7 @@ export class MoveEffectPhase extends PokemonPhase {
}
this.targets = targets;
- this.hitChecks = Array(this.targets.length).fill([HitCheckResult.PENDING, 0]);
+ this.hitChecks = new Array(this.targets.length).fill([HitCheckResult.PENDING, 0]);
}
/**
@@ -309,8 +309,8 @@ export class MoveEffectPhase extends PokemonPhase {
// Play the animation if the move was successful against any of its targets or it has a POST_TARGET effect (like self destruct)
if (
- this.moveHistoryEntry.result === MoveResult.SUCCESS ||
- move.getAttrs("MoveEffectAttr").some(attr => attr.trigger === MoveEffectTrigger.POST_TARGET)
+ this.moveHistoryEntry.result === MoveResult.SUCCESS
+ || move.getAttrs("MoveEffectAttr").some(attr => attr.trigger === MoveEffectTrigger.POST_TARGET)
) {
const firstTarget = this.getFirstTarget();
new MoveAnim(
@@ -344,7 +344,7 @@ export class MoveEffectPhase extends PokemonPhase {
return;
}
- if (this.queuedPhases.length) {
+ if (this.queuedPhases.length > 0) {
globalScene.phaseManager.appendToPhase(this.queuedPhases, "MoveEndPhase");
}
const moveType = user.getMoveType(this.move, true);
@@ -431,9 +431,9 @@ export class MoveEffectPhase extends PokemonPhase {
}
if (
- dealsDamage &&
- !target.hasAbilityWithAttr("IgnoreMoveEffectsAbAttr") &&
- !this.move.hitsSubstitute(user, target)
+ dealsDamage
+ && !target.hasAbilityWithAttr("IgnoreMoveEffectsAbAttr")
+ && !this.move.hitsSubstitute(user, target)
) {
const flinched = new BooleanHolder(false);
globalScene.applyModifiers(FlinchChanceModifier, user.isPlayer(), user, flinched);
@@ -472,13 +472,13 @@ export class MoveEffectPhase extends PokemonPhase {
// TODO: Break up this chunky boolean to make it more palatable
return (
- ![MoveTarget.ENEMY_SIDE, MoveTarget.BOTH_SIDES].includes(this.move.moveTarget) &&
- (bypassIgnoreProtect.value || !this.move.doesFlagEffectApply({ flag: MoveFlags.IGNORE_PROTECT, user, target })) &&
- (hasConditionalProtectApplied.value ||
- (!target.findTags(t => t instanceof DamageProtectedTag).length &&
- target.findTags(t => t instanceof ProtectedTag).some(t => target.lapseTag(t.tagType))) ||
- (this.move.category !== MoveCategory.STATUS &&
- target.findTags(t => t instanceof DamageProtectedTag).some(t => target.lapseTag(t.tagType))))
+ ![MoveTarget.ENEMY_SIDE, MoveTarget.BOTH_SIDES].includes(this.move.moveTarget)
+ && (bypassIgnoreProtect.value || !this.move.doesFlagEffectApply({ flag: MoveFlags.IGNORE_PROTECT, user, target }))
+ && (hasConditionalProtectApplied.value
+ || (target.findTags(t => t instanceof DamageProtectedTag).length === 0
+ && target.findTags(t => t instanceof ProtectedTag).some(t => target.lapseTag(t.tagType)))
+ || (this.move.category !== MoveCategory.STATUS
+ && target.findTags(t => t instanceof DamageProtectedTag).some(t => target.lapseTag(t.tagType))))
);
}
@@ -519,9 +519,9 @@ export class MoveEffectPhase extends PokemonPhase {
// Commander causes moves used against the target to miss
if (
- !fieldTargeted &&
- globalScene.currentBattle.double &&
- target.getAlly()?.getTag(BattlerTagType.COMMANDED)?.getSourcePokemon() === target
+ !fieldTargeted
+ && globalScene.currentBattle.double
+ && target.getAlly()?.getTag(BattlerTagType.COMMANDED)?.getSourcePokemon() === target
) {
return [HitCheckResult.MISS, 0];
}
@@ -566,16 +566,17 @@ export class MoveEffectPhase extends PokemonPhase {
// Strikes after the first in a multi-strike move are guaranteed to hit,
// unless the move is flagged to check all hits and the user does not have Skill Link.
- if (user.turnData.hitsLeft < user.turnData.hitCount) {
- if (!move.hasFlag(MoveFlags.CHECK_ALL_HITS) || user.hasAbilityWithAttr("MaxMultiHitAbAttr")) {
- return [HitCheckResult.HIT, effectiveness];
- }
+ if (
+ user.turnData.hitsLeft < user.turnData.hitCount
+ && (!move.hasFlag(MoveFlags.CHECK_ALL_HITS) || user.hasAbilityWithAttr("MaxMultiHitAbAttr"))
+ ) {
+ return [HitCheckResult.HIT, effectiveness];
}
const bypassAccuracy =
- bypassAccAndInvuln ||
- target.getTag(BattlerTagType.ALWAYS_GET_HIT) ||
- (target.getTag(BattlerTagType.TELEKINESIS) && !this.move.hasAttr("OneHitKOAttr"));
+ bypassAccAndInvuln
+ || target.getTag(BattlerTagType.ALWAYS_GET_HIT)
+ || (target.getTag(BattlerTagType.TELEKINESIS) && !this.move.hasAttr("OneHitKOAttr"));
if (moveAccuracy === -1 || bypassAccuracy) {
return [HitCheckResult.HIT, effectiveness];
@@ -621,8 +622,8 @@ export class MoveEffectPhase extends PokemonPhase {
}
// TODO: Fix lock on / mind reader check.
if (
- user.getTag(BattlerTagType.IGNORE_ACCURACY) &&
- (user.getLastXMoves().find(() => true)?.targets || []).indexOf(target.getBattlerIndex()) !== -1
+ user.getTag(BattlerTagType.IGNORE_ACCURACY)
+ && (user.getLastXMoves().find(() => true)?.targets || []).indexOf(target.getBattlerIndex()) !== -1
) {
return true;
}
@@ -737,12 +738,12 @@ export class MoveEffectPhase extends PokemonPhase {
): void {
applyFilteredMoveAttrs(
(attr: MoveAttr) =>
- attr.is("MoveEffectAttr") &&
- attr.trigger === triggerType &&
- (isNullOrUndefined(selfTarget) || attr.selfTarget === selfTarget) &&
- (!attr.firstHitOnly || this.firstHit) &&
- (!attr.lastHitOnly || this.lastHit) &&
- (!attr.firstTargetOnly || (firstTarget ?? true)),
+ attr.is("MoveEffectAttr")
+ && attr.trigger === triggerType
+ && (isNullOrUndefined(selfTarget) || attr.selfTarget === selfTarget)
+ && (!attr.firstHitOnly || this.firstHit)
+ && (!attr.lastHitOnly || this.lastHit)
+ && (!attr.firstTargetOnly || (firstTarget ?? true)),
user,
target,
this.move,
@@ -880,7 +881,7 @@ export class MoveEffectPhase extends PokemonPhase {
target.turnData.attacksReceived.unshift({
move: this.move.id,
result: result as DamageResult,
- damage: damage,
+ damage,
critical: isCritical,
sourceId: user.id,
sourceBattlerIndex: user.getBattlerIndex(),
@@ -998,7 +999,7 @@ export class MoveEffectPhase extends PokemonPhase {
this.triggerMoveEffects(MoveEffectTrigger.POST_APPLY, user, target, firstTarget, false);
this.applyHeldItemFlinchCheck(user, target, dealsDamage);
this.applyOnGetHitAbEffects(user, target, hitResult, damage, wasCritical);
- applyAbAttrs("PostAttackAbAttr", { pokemon: user, opponent: target, move: this.move, hitResult, damage: damage });
+ applyAbAttrs("PostAttackAbAttr", { pokemon: user, opponent: target, move: this.move, hitResult, damage });
// We assume only enemy Pokemon are able to have the EnemyAttackStatusEffectChanceModifier from tokens
if (!user.isPlayer() && this.move.is("AttackMove")) {
diff --git a/src/phases/move-phase.ts b/src/phases/move-phase.ts
index 9a8e509e302..96943065ff0 100644
--- a/src/phases/move-phase.ts
+++ b/src/phases/move-phase.ts
@@ -1,4 +1,5 @@
import { applyAbAttrs } from "#abilities/apply-ab-attrs";
+import { MOVE_COLOR } from "#app/constants/colors";
import { globalScene } from "#app/global-scene";
import { getPokemonNameWithAffix } from "#app/messages";
import Overrides from "#app/overrides";
@@ -24,6 +25,7 @@ import { applyMoveAttrs } from "#moves/apply-attrs";
import { frenzyMissFunc } from "#moves/move-utils";
import type { PokemonMove } from "#moves/pokemon-move";
import { BattlePhase } from "#phases/battle-phase";
+import type { TurnMove } from "#types/turn-move";
import { NumberHolder } from "#utils/common";
import { enumValueToKey } from "#utils/enums";
import i18next from "i18next";
@@ -41,6 +43,13 @@ export class MovePhase extends BattlePhase {
/** Whether the current move should fail and retain PP. */
protected cancelled = false;
+ /** The move history entry object that is pushed to the pokemon's move history
+ *
+ * @remarks
+ * Can be edited _after_ being pushed to the history to adjust the result, targets, etc, for this move phase.
+ */
+ protected moveHistoryEntry: TurnMove;
+
public get pokemon(): Pokemon {
return this._pokemon;
}
@@ -82,6 +91,11 @@ export class MovePhase extends BattlePhase {
this.move = move;
this.useMode = useMode;
this.forcedLast = forcedLast;
+ this.moveHistoryEntry = {
+ move: MoveId.NONE,
+ targets,
+ useMode,
+ };
}
/**
@@ -91,9 +105,9 @@ export class MovePhase extends BattlePhase {
*/
public canMove(ignoreDisableTags = false): boolean {
return (
- this.pokemon.isActive(true) &&
- this.move.isUsable(this.pokemon, isIgnorePP(this.useMode), ignoreDisableTags) &&
- this.targets.length > 0
+ this.pokemon.isActive(true)
+ && this.move.isUsable(this.pokemon, isIgnorePP(this.useMode), ignoreDisableTags)
+ && this.targets.length > 0
);
}
@@ -118,7 +132,10 @@ export class MovePhase extends BattlePhase {
public start(): void {
super.start();
- console.log(MoveId[this.move.moveId], enumValueToKey(MoveUseMode, this.useMode));
+ console.log(
+ `%cMove: ${MoveId[this.move.moveId]}\nUse Mode: ${enumValueToKey(MoveUseMode, this.useMode)}`,
+ `color:${MOVE_COLOR}`,
+ );
// Check if move is unusable (e.g. running out of PP due to a mid-turn Spite
// or the user no longer being on field), ending the phase early if not.
@@ -181,8 +198,8 @@ export class MovePhase extends BattlePhase {
const moveQueue = this.pokemon.getMoveQueue();
if (
- (targets.length === 0 && !this.move.getMove().hasAttr("AddArenaTrapTagAttr")) ||
- (moveQueue.length > 0 && moveQueue[0].move === MoveId.NONE)
+ (targets.length === 0 && !this.move.getMove().hasAttr("AddArenaTrapTagAttr"))
+ || (moveQueue.length > 0 && moveQueue[0].move === MoveId.NONE)
) {
this.showMoveText();
this.showFailedText();
@@ -204,8 +221,8 @@ export class MovePhase extends BattlePhase {
}
if (
- this.useMode === MoveUseMode.INDIRECT &&
- [StatusEffect.SLEEP, StatusEffect.FREEZE].includes(this.pokemon.status.effect)
+ this.useMode === MoveUseMode.INDIRECT
+ && [StatusEffect.SLEEP, StatusEffect.FREEZE].includes(this.pokemon.status.effect)
) {
// Dancer thaws out or wakes up a frozen/sleeping user prior to use
this.pokemon.resetStatus(false);
@@ -222,8 +239,8 @@ export class MovePhase extends BattlePhase {
switch (this.pokemon.status.effect) {
case StatusEffect.PARALYSIS:
activated =
- (this.pokemon.randBattleSeedInt(4) === 0 || Overrides.STATUS_ACTIVATION_OVERRIDE === true) &&
- Overrides.STATUS_ACTIVATION_OVERRIDE !== false;
+ (this.pokemon.randBattleSeedInt(4) === 0 || Overrides.STATUS_ACTIVATION_OVERRIDE === true)
+ && Overrides.STATUS_ACTIVATION_OVERRIDE !== false;
break;
case StatusEffect.SLEEP: {
applyMoveAttrs("BypassSleepAttr", this.pokemon, null, this.move.getMove());
@@ -244,9 +261,9 @@ export class MovePhase extends BattlePhase {
.getMove()
.findAttr(
attr => attr.is("HealStatusEffectAttr") && attr.selfTarget && attr.isOfEffect(StatusEffect.FREEZE),
- ) ||
- (!this.pokemon.randBattleSeedInt(5) && Overrides.STATUS_ACTIVATION_OVERRIDE !== true) ||
- Overrides.STATUS_ACTIVATION_OVERRIDE === false;
+ )
+ || (!this.pokemon.randBattleSeedInt(5) && Overrides.STATUS_ACTIVATION_OVERRIDE !== true)
+ || Overrides.STATUS_ACTIVATION_OVERRIDE === false;
activated = !healed;
break;
@@ -397,8 +414,8 @@ export class MovePhase extends BattlePhase {
// even on failure, as will all moves blocked by terrain.
// TODO: Verify if this also applies to primal weather failures
if (
- failedDueToTerrain ||
- [MoveId.ROAR, MoveId.WHIRLWIND, MoveId.TRICK_OR_TREAT, MoveId.FORESTS_CURSE].includes(this.move.moveId)
+ failedDueToTerrain
+ || [MoveId.ROAR, MoveId.WHIRLWIND, MoveId.TRICK_OR_TREAT, MoveId.FORESTS_CURSE].includes(this.move.moveId)
) {
applyAbAttrs("PokemonTypeChangeAbAttr", {
pokemon: this.pokemon,
@@ -410,19 +427,15 @@ export class MovePhase extends BattlePhase {
if (showText) {
this.showMoveText();
}
-
- this.pokemon.pushMoveHistory({
- move: this.move.moveId,
- targets: this.targets,
- result: MoveResult.FAIL,
- useMode: this.useMode,
- });
+ const moveHistoryEntry = this.moveHistoryEntry;
+ moveHistoryEntry.result = MoveResult.FAIL;
+ this.pokemon.pushMoveHistory(moveHistoryEntry);
// Use move-specific failure messages if present before checking terrain/weather blockage
// and falling back to the classic "But it failed!".
const failureMessage =
- move.getFailedText(this.pokemon, targets[0], move) ||
- (failedDueToTerrain
+ move.getFailedText(this.pokemon, targets[0], move)
+ || (failedDueToTerrain
? getTerrainBlockMessage(targets[0], globalScene.arena.getTerrainType())
: failedDueToWeather
? getWeatherBlockMessage(globalScene.arena.getWeatherType())
@@ -528,9 +541,9 @@ export class MovePhase extends BattlePhase {
// TODO: don't hardcode this interaction.
// Handle interaction between the rage powder center-of-attention tag and moves used by grass types/overcoat-havers (which are immune to RP's redirect)
if (
- redirectTag &&
- (!redirectTag.powder ||
- (!this.pokemon.isOfType(PokemonType.GRASS) && !this.pokemon.hasAbility(AbilityId.OVERCOAT)))
+ redirectTag
+ && (!redirectTag.powder
+ || (!this.pokemon.isOfType(PokemonType.GRASS) && !this.pokemon.hasAbility(AbilityId.OVERCOAT)))
) {
redirectTarget.value = p.getBattlerIndex();
redirectedByAbility = false;
@@ -591,9 +604,9 @@ export class MovePhase extends BattlePhase {
// account for metal burst and comeuppance hitting remaining targets in double battles
// counterattack will redirect to remaining ally if original attacker faints
if (
- globalScene.currentBattle.double &&
- this.move.getMove().hasFlag(MoveFlags.REDIRECT_COUNTER) &&
- globalScene.getField()[this.targets[0]].hp === 0
+ globalScene.currentBattle.double
+ && this.move.getMove().hasFlag(MoveFlags.REDIRECT_COUNTER)
+ && globalScene.getField()[this.targets[0]].hp === 0
) {
const opposingField = this.pokemon.isPlayer() ? globalScene.getEnemyField() : globalScene.getPlayerField();
this.targets[0] = opposingField.find(p => p.hp > 0)?.getBattlerIndex() ?? BattlerIndex.ATTACKER;
@@ -630,12 +643,9 @@ export class MovePhase extends BattlePhase {
frenzyMissFunc(this.pokemon, this.move.getMove());
}
- this.pokemon.pushMoveHistory({
- move: MoveId.NONE,
- result: MoveResult.FAIL,
- targets: this.targets,
- useMode: this.useMode,
- });
+ const moveHistoryEntry = this.moveHistoryEntry;
+ moveHistoryEntry.result = MoveResult.FAIL;
+ this.pokemon.pushMoveHistory(moveHistoryEntry);
this.pokemon.lapseTags(BattlerTagLapseType.MOVE_EFFECT);
this.pokemon.lapseTags(BattlerTagLapseType.AFTER_MOVE);
@@ -649,13 +659,16 @@ export class MovePhase extends BattlePhase {
* Displays the move's usage text to the player as applicable for the move being used.
*/
public showMoveText(): void {
+ const moveId = this.move.moveId;
if (
- this.move.moveId === MoveId.NONE ||
- this.pokemon.getTag(BattlerTagType.RECHARGING) ||
- this.pokemon.getTag(BattlerTagType.INTERRUPTED)
+ moveId === MoveId.NONE
+ || this.pokemon.getTag(BattlerTagType.RECHARGING)
+ || this.pokemon.getTag(BattlerTagType.INTERRUPTED)
) {
return;
}
+ // Showing move text always adjusts the move history entry's move id
+ this.moveHistoryEntry.move = moveId;
// TODO: This should be done by the move...
globalScene.phaseManager.queueMessage(
@@ -668,7 +681,7 @@ export class MovePhase extends BattlePhase {
// Moves with pre-use messages (Magnitude, Chilly Reception, Fickle Beam, etc.) always display their messages even on failure
// TODO: This assumes single target for message funcs - is this sustainable?
- applyMoveAttrs("PreMoveMessageAttr", this.pokemon, this.pokemon.getOpponents(false)[0], this.move.getMove());
+ applyMoveAttrs("PreMoveMessageAttr", this.pokemon, this.getActiveTargetPokemon()[0], this.move.getMove());
}
/**
diff --git a/src/phases/mystery-encounter-phases.ts b/src/phases/mystery-encounter-phases.ts
index 9363efcb460..6a0c01f857a 100644
--- a/src/phases/mystery-encounter-phases.ts
+++ b/src/phases/mystery-encounter-phases.ts
@@ -77,10 +77,7 @@ export class MysteryEncounterPhase extends Phase {
if (!this.optionSelectSettings) {
// Saves the selected option in the ME save data, only if this is not a followup option select phase
// Can be used for analytics purposes to track what options are popular on certain encounters
- const encounterSaveData =
- globalScene.mysteryEncounterSaveData.encounteredEvents[
- globalScene.mysteryEncounterSaveData.encounteredEvents.length - 1
- ];
+ const encounterSaveData = globalScene.mysteryEncounterSaveData.encounteredEvents.at(-1)!;
if (encounterSaveData.type === globalScene.currentBattle.mysteryEncounter?.encounterType) {
encounterSaveData.selectedOption = index;
}
@@ -225,9 +222,9 @@ export class MysteryEncounterBattleStartCleanupPhase extends Phase {
tags
.filter(
t =>
- includedLapseTags.includes(t.tagType) &&
- t.lapseTypes.includes(BattlerTagLapseType.TURN_END) &&
- !t.lapse(pokemon, BattlerTagLapseType.TURN_END),
+ includedLapseTags.includes(t.tagType)
+ && t.lapseTypes.includes(BattlerTagLapseType.TURN_END)
+ && !t.lapse(pokemon, BattlerTagLapseType.TURN_END),
)
.forEach(t => {
t.onRemove(pokemon);
@@ -244,7 +241,7 @@ export class MysteryEncounterBattleStartCleanupPhase extends Phase {
const legalPlayerPokemon = globalScene.getPokemonAllowedInBattle();
// The total number of legal player Pokemon that aren't currently on the field
const legalPlayerPartyPokemon = legalPlayerPokemon.filter(p => !p.isActive(true));
- if (!legalPlayerPokemon.length) {
+ if (legalPlayerPokemon.length === 0) {
globalScene.phaseManager.unshiftNew("GameOverPhase");
return this.end();
}
@@ -372,7 +369,7 @@ export class MysteryEncounterBattlePhase extends Phase {
const encounterMessages = globalScene.currentBattle.trainer?.getEncounterMessages();
- if (!encounterMessages || !encounterMessages.length) {
+ if (!encounterMessages || encounterMessages.length === 0) {
doSummon();
} else {
const trainer = globalScene.currentBattle.trainer;
diff --git a/src/phases/pokemon-phase.ts b/src/phases/pokemon-phase.ts
index 9739c58d667..1a1a7e2efa3 100644
--- a/src/phases/pokemon-phase.ts
+++ b/src/phases/pokemon-phase.ts
@@ -16,8 +16,8 @@ export abstract class PokemonPhase extends FieldPhase {
super();
battlerIndex =
- battlerIndex ??
- globalScene
+ battlerIndex
+ ?? globalScene
.getField()
.find(p => p?.isActive())
?.getBattlerIndex();
diff --git a/src/phases/post-game-over-phase.ts b/src/phases/post-game-over-phase.ts
index 3ac112a8a8b..a69ec2d468b 100644
--- a/src/phases/post-game-over-phase.ts
+++ b/src/phases/post-game-over-phase.ts
@@ -5,10 +5,11 @@ import type { EndCardPhase } from "#phases/end-card-phase";
export class PostGameOverPhase extends Phase {
public readonly phaseName = "PostGameOverPhase";
private endCardPhase?: EndCardPhase;
+ private slotId: number;
- constructor(endCardPhase?: EndCardPhase) {
+ constructor(slotId: number, endCardPhase?: EndCardPhase) {
super();
-
+ this.slotId = slotId;
this.endCardPhase = endCardPhase;
}
@@ -20,16 +21,14 @@ export class PostGameOverPhase extends Phase {
if (!success) {
return globalScene.reset(true);
}
- globalScene.gameData
- .tryClearSession(globalScene.sessionSlotId)
- .then((success: boolean | [boolean, boolean]) => {
- if (!success[0]) {
- return globalScene.reset(true);
- }
- globalScene.reset();
- globalScene.phaseManager.unshiftNew("TitlePhase");
- this.end();
- });
+ globalScene.gameData.tryClearSession(this.slotId).then((success: boolean | [boolean, boolean]) => {
+ if (!success[0]) {
+ return globalScene.reset(true);
+ }
+ globalScene.reset();
+ globalScene.phaseManager.unshiftNew("TitlePhase");
+ this.end();
+ });
});
};
diff --git a/src/phases/post-summon-phase.ts b/src/phases/post-summon-phase.ts
index 913a29cded8..5de068f2ae5 100644
--- a/src/phases/post-summon-phase.ts
+++ b/src/phases/post-summon-phase.ts
@@ -20,8 +20,8 @@ export class PostSummonPhase extends PokemonPhase {
// If this is mystery encounter and has post summon phase tag, apply post summon effects
if (
- globalScene.currentBattle.isBattleMysteryEncounter() &&
- pokemon.findTags(t => t instanceof MysteryEncounterPostSummonTag).length > 0
+ globalScene.currentBattle.isBattleMysteryEncounter()
+ && pokemon.findTags(t => t instanceof MysteryEncounterPostSummonTag).length > 0
) {
pokemon.lapseTag(BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON);
}
diff --git a/src/phases/revival-blessing-phase.ts b/src/phases/revival-blessing-phase.ts
index 0235fb51da3..a9dedf4c325 100644
--- a/src/phases/revival-blessing-phase.ts
+++ b/src/phases/revival-blessing-phase.ts
@@ -3,8 +3,8 @@ import { SwitchType } from "#enums/switch-type";
import { UiMode } from "#enums/ui-mode";
import type { PlayerPokemon } from "#field/pokemon";
import { BattlePhase } from "#phases/battle-phase";
-import type { PartyOption } from "#ui/party-ui-handler";
-import { PartyUiHandler, PartyUiMode } from "#ui/party-ui-handler";
+import type { PartyOption } from "#ui/handlers/party-ui-handler";
+import { PartyUiHandler, PartyUiMode } from "#ui/handlers/party-ui-handler";
import { isNullOrUndefined, toDmgValue } from "#utils/common";
import i18next from "i18next";
@@ -43,9 +43,9 @@ export class RevivalBlessingPhase extends BattlePhase {
const allyPokemon = this.user.getAlly();
if (
- globalScene.currentBattle.double &&
- globalScene.getPlayerParty().length > 1 &&
- !isNullOrUndefined(allyPokemon)
+ globalScene.currentBattle.double
+ && globalScene.getPlayerParty().length > 1
+ && !isNullOrUndefined(allyPokemon)
) {
if (slotIndex <= 1) {
// Revived ally pokemon
diff --git a/src/phases/scan-ivs-phase.ts b/src/phases/scan-ivs-phase.ts
index 38b39b310e1..eb84345fa6b 100644
--- a/src/phases/scan-ivs-phase.ts
+++ b/src/phases/scan-ivs-phase.ts
@@ -20,57 +20,54 @@ export class ScanIvsPhase extends PokemonPhase {
const pokemon = this.getPokemon();
- let enemyIvs: number[] = [];
- let statsContainer: Phaser.GameObjects.Sprite[] = [];
- let statsContainerLabels: Phaser.GameObjects.Sprite[] = [];
- const enemyField = globalScene.getEnemyField();
- for (let e = 0; e < enemyField.length; e++) {
- enemyIvs = enemyField[e].ivs;
+ for (const enemy of globalScene.getEnemyField()) {
+ const enemyIvs = enemy.ivs;
// we are using getRootSpeciesId() here because we want to check against the baby form, not the mid form if it exists
- const currentIvs = globalScene.gameData.dexData[enemyField[e].species.getRootSpeciesId()].ivs;
- statsContainer = enemyField[e].getBattleInfo().getStatsValueContainer().list as Phaser.GameObjects.Sprite[];
- statsContainerLabels = statsContainer.filter(m => m.name.indexOf("icon_stat_label") >= 0);
- for (let s = 0; s < statsContainerLabels.length; s++) {
- const ivStat = Stat[statsContainerLabels[s].frame.name];
- if (enemyIvs[ivStat] > currentIvs[ivStat] && PERMANENT_STATS.indexOf(Number(ivStat)) >= 0) {
+ const currentIvs = globalScene.gameData.dexData[enemy.species.getRootSpeciesId()].ivs;
+ const statsContainer = enemy.getBattleInfo().getStatsValueContainer().list as Phaser.GameObjects.Sprite[];
+ const statsContainerLabels = statsContainer.filter(m => m.name.includes("icon_stat_label"));
+ for (const statContainer of statsContainerLabels) {
+ const ivStat = Stat[statContainer.frame.name] as Stat;
+ if (enemyIvs[ivStat] > currentIvs[ivStat] && PERMANENT_STATS.includes(Number(ivStat))) {
const hexColour =
enemyIvs[ivStat] === 31
? getTextColor(TextStyle.PERFECT_IV, false)
: getTextColor(TextStyle.SUMMARY_GREEN, false);
const hexTextColour = Phaser.Display.Color.HexStringToColor(hexColour).color;
- statsContainerLabels[s].setTint(hexTextColour);
+ statContainer.setTint(hexTextColour);
}
- statsContainerLabels[s].setVisible(true);
+ statContainer.setVisible(true);
}
}
- if (!globalScene.hideIvs) {
- globalScene.ui.showText(
- i18next.t("battle:ivScannerUseQuestion", {
- pokemonName: getPokemonNameWithAffix(pokemon),
- }),
- null,
- () => {
- globalScene.ui.setMode(
- UiMode.CONFIRM,
- () => {
- globalScene.ui.setMode(UiMode.MESSAGE);
- globalScene.ui.clearText();
- globalScene.ui
- .getMessageHandler()
- .promptIvs(pokemon.id, pokemon.ivs)
- .then(() => this.end());
- },
- () => {
- globalScene.ui.setMode(UiMode.MESSAGE);
- globalScene.ui.clearText();
- this.end();
- },
- );
- },
- );
- } else {
+ if (globalScene.hideIvs) {
this.end();
+ return;
}
+
+ globalScene.ui.showText(
+ i18next.t("battle:ivScannerUseQuestion", {
+ pokemonName: getPokemonNameWithAffix(pokemon),
+ }),
+ null,
+ () => {
+ globalScene.ui.setMode(
+ UiMode.CONFIRM,
+ () => {
+ globalScene.ui.setMode(UiMode.MESSAGE);
+ globalScene.ui.clearText();
+ globalScene.ui
+ .getMessageHandler()
+ .promptIvs(pokemon.id, pokemon.ivs)
+ .then(() => this.end());
+ },
+ () => {
+ globalScene.ui.setMode(UiMode.MESSAGE);
+ globalScene.ui.clearText();
+ this.end();
+ },
+ );
+ },
+ );
}
}
diff --git a/src/phases/select-biome-phase.ts b/src/phases/select-biome-phase.ts
index d02d69fc934..3276c34306c 100644
--- a/src/phases/select-biome-phase.ts
+++ b/src/phases/select-biome-phase.ts
@@ -5,7 +5,7 @@ import { ChallengeType } from "#enums/challenge-type";
import { UiMode } from "#enums/ui-mode";
import { MapModifier, MoneyInterestModifier } from "#modifiers/modifier";
import { BattlePhase } from "#phases/battle-phase";
-import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
+import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler";
import { applyChallenges } from "#utils/challenge-utils";
import { BooleanHolder, randSeedInt } from "#utils/common";
@@ -44,9 +44,9 @@ export class SelectBiomePhase extends BattlePhase {
};
if (
- (gameMode.isClassic && gameMode.isWaveFinal(nextWaveIndex + 9)) ||
- (gameMode.isDaily && gameMode.isWaveFinal(nextWaveIndex)) ||
- (gameMode.hasShortBiomes && !(nextWaveIndex % 50))
+ (gameMode.isClassic && gameMode.isWaveFinal(nextWaveIndex + 9))
+ || (gameMode.isDaily && gameMode.isWaveFinal(nextWaveIndex))
+ || (gameMode.hasShortBiomes && !(nextWaveIndex % 50))
) {
setNextBiome(BiomeId.END);
} else if (gameMode.hasRandomBiomes) {
diff --git a/src/phases/select-modifier-phase.ts b/src/phases/select-modifier-phase.ts
index 06a02af38b0..51adeb21af0 100644
--- a/src/phases/select-modifier-phase.ts
+++ b/src/phases/select-modifier-phase.ts
@@ -24,9 +24,9 @@ import {
TmModifierType,
} from "#modifiers/modifier-type";
import { BattlePhase } from "#phases/battle-phase";
-import type { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
-import { SHOP_OPTIONS_ROW_LIMIT } from "#ui/modifier-select-ui-handler";
-import { PartyOption, PartyUiHandler, PartyUiMode } from "#ui/party-ui-handler";
+import type { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler";
+import { SHOP_OPTIONS_ROW_LIMIT } from "#ui/handlers/modifier-select-ui-handler";
+import { PartyOption, PartyUiHandler, PartyUiMode } from "#ui/handlers/party-ui-handler";
import { isNullOrUndefined, NumberHolder } from "#utils/common";
import i18next from "i18next";
@@ -215,11 +215,11 @@ export class SelectModifierPhase extends BattlePhase {
-1,
(fromSlotIndex: number, itemIndex: number, itemQuantity: number, toSlotIndex: number) => {
if (
- toSlotIndex !== undefined &&
- fromSlotIndex < 6 &&
- toSlotIndex < 6 &&
- fromSlotIndex !== toSlotIndex &&
- itemIndex > -1
+ toSlotIndex !== undefined
+ && fromSlotIndex < 6
+ && toSlotIndex < 6
+ && fromSlotIndex !== toSlotIndex
+ && itemIndex > -1
) {
const itemModifiers = globalScene.findModifiers(
m => m instanceof PokemonHeldItemModifier && m.isTransferable && m.pokemonId === party[fromSlotIndex].id,
@@ -306,10 +306,10 @@ export class SelectModifierPhase extends BattlePhase {
-1,
(fromSlotIndex: number, spliceSlotIndex: number) => {
if (
- spliceSlotIndex !== undefined &&
- fromSlotIndex < 6 &&
- spliceSlotIndex < 6 &&
- fromSlotIndex !== spliceSlotIndex
+ spliceSlotIndex !== undefined
+ && fromSlotIndex < 6
+ && spliceSlotIndex < 6
+ && fromSlotIndex !== spliceSlotIndex
) {
globalScene.ui.setMode(UiMode.MODIFIER_SELECT, this.isPlayer()).then(() => {
const modifier = modifierType.newModifier(party[fromSlotIndex], party[spliceSlotIndex])!; //TODO: is the bang correct?
@@ -380,9 +380,9 @@ export class SelectModifierPhase extends BattlePhase {
// If custom modifiers are specified, overrides default item count
if (this.customModifierSettings) {
const newItemCount =
- (this.customModifierSettings.guaranteedModifierTiers?.length ?? 0) +
- (this.customModifierSettings.guaranteedModifierTypeOptions?.length ?? 0) +
- (this.customModifierSettings.guaranteedModifierTypeFuncs?.length ?? 0);
+ (this.customModifierSettings.guaranteedModifierTiers?.length ?? 0)
+ + (this.customModifierSettings.guaranteedModifierTypeOptions?.length ?? 0)
+ + (this.customModifierSettings.guaranteedModifierTypeFuncs?.length ?? 0);
if (this.customModifierSettings.fillRemaining) {
const originalCount = modifierCountHolder.value;
modifierCountHolder.value = originalCount > newItemCount ? originalCount : newItemCount;
diff --git a/src/phases/select-starter-phase.ts b/src/phases/select-starter-phase.ts
index ef3fa74bd44..50c06f96a77 100644
--- a/src/phases/select-starter-phase.ts
+++ b/src/phases/select-starter-phase.ts
@@ -7,8 +7,8 @@ import { ChallengeType } from "#enums/challenge-type";
import type { SpeciesId } from "#enums/species-id";
import { UiMode } from "#enums/ui-mode";
import { overrideHeldItems, overrideModifiers } from "#modifiers/modifier";
-import { SaveSlotUiMode } from "#ui/save-slot-select-ui-handler";
-import type { Starter } from "#ui/starter-select-ui-handler";
+import { SaveSlotUiMode } from "#ui/handlers/save-slot-select-ui-handler";
+import type { Starter } from "#ui/handlers/starter-select-ui-handler";
import { applyChallenges } from "#utils/challenge-utils";
import { isNullOrUndefined } from "#utils/common";
import { getPokemonSpecies } from "#utils/pokemon-utils";
@@ -50,9 +50,9 @@ export class SelectStarterPhase extends Phase {
const starterProps = globalScene.gameData.getSpeciesDexAttrProps(starter.species, starter.dexAttr);
let starterFormIndex = Math.min(starterProps.formIndex, Math.max(starter.species.forms.length - 1, 0));
if (
- starter.species.speciesId in Overrides.STARTER_FORM_OVERRIDES &&
- !isNullOrUndefined(Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]) &&
- starter.species.forms[Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]!]
+ starter.species.speciesId in Overrides.STARTER_FORM_OVERRIDES
+ && !isNullOrUndefined(Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId])
+ && starter.species.forms[Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]!]
) {
starterFormIndex = Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]!;
}
diff --git a/src/phases/select-target-phase.ts b/src/phases/select-target-phase.ts
index 3805cb919b2..2f439419cd0 100644
--- a/src/phases/select-target-phase.ts
+++ b/src/phases/select-target-phase.ts
@@ -30,7 +30,7 @@ export class SelectTargetPhase extends PokemonPhase {
globalScene.phaseManager.queueMessage(i18next.t(errorMessage, { moveName: moveObject.name }), 0, true);
targets = [];
}
- if (targets.length < 1) {
+ if (targets.length === 0) {
globalScene.currentBattle.turnCommands[this.fieldIndex] = null;
globalScene.phaseManager.unshiftNew("CommandPhase", this.fieldIndex);
} else {
diff --git a/src/phases/stat-stage-change-phase.ts b/src/phases/stat-stage-change-phase.ts
index 140ef841929..6c15342ddeb 100644
--- a/src/phases/stat-stage-change-phase.ts
+++ b/src/phases/stat-stage-change-phase.ts
@@ -22,6 +22,7 @@ export type StatStageChangeCallback = (
relativeChanges: number[],
) => void;
+// TODO: Refactor this mess of a phase
export class StatStageChangePhase extends PokemonPhase {
public readonly phaseName = "StatStageChangePhase";
private stats: BattleStat[];
@@ -62,13 +63,12 @@ export class StatStageChangePhase extends PokemonPhase {
start() {
// Check if multiple stats are being changed at the same time, then run SSCPhase for each of them
if (this.stats.length > 1) {
- for (let i = 0; i < this.stats.length; i++) {
- const stat = [this.stats[i]];
+ for (const stat of this.stats) {
globalScene.phaseManager.unshiftNew(
"StatStageChangePhase",
this.battlerIndex,
this.selfTarget,
- stat,
+ [stat],
this.stages,
this.showMessage,
this.ignoreAbilities,
@@ -100,20 +100,18 @@ export class StatStageChangePhase extends PokemonPhase {
}
});
}
+ } else if (!this.comingFromStickyWeb) {
+ opponentPokemon = globalScene.getPlayerField()[globalScene.currentBattle.lastPlayerInvolved];
} else {
- if (!this.comingFromStickyWeb) {
- opponentPokemon = globalScene.getPlayerField()[globalScene.currentBattle.lastPlayerInvolved];
- } else {
- const stickyTagID = globalScene.arena.findTagsOnSide(
- (t: ArenaTag) => t.tagType === ArenaTagType.STICKY_WEB,
- ArenaTagSide.ENEMY,
- )[0].sourceId;
- globalScene.getPlayerField().forEach(e => {
- if (e.id === stickyTagID) {
- opponentPokemon = e;
- }
- });
- }
+ const stickyTagID = globalScene.arena.findTagsOnSide(
+ (t: ArenaTag) => t.tagType === ArenaTagType.STICKY_WEB,
+ ArenaTagSide.ENEMY,
+ )[0].sourceId;
+ globalScene.getPlayerField().forEach(e => {
+ if (e.id === stickyTagID) {
+ opponentPokemon = e;
+ }
+ });
}
if (!pokemon.isActive(true)) {
@@ -161,11 +159,9 @@ export class StatStageChangePhase extends PokemonPhase {
/** Potential stat reflection due to Mirror Armor, does not apply to Octolock end of turn effect */
if (
- opponentPokemon !== undefined &&
- // TODO: investigate whether this is stoping mirror armor from applying to non-octolock
- // reasons for stat drops if the user has the Octolock tag
- !pokemon.findTag(t => t instanceof OctolockTag) &&
- !this.comingFromMirrorArmorUser
+ opponentPokemon !== undefined // TODO: investigate whether this is stoping mirror armor from applying to non-octolock // reasons for stat drops if the user has the Octolock tag
+ && !pokemon.findTag(t => t instanceof OctolockTag)
+ && !this.comingFromMirrorArmorUser
) {
applyAbAttrs("ReflectStatStageChangeAbAttr", {
pokemon,
@@ -249,7 +245,7 @@ export class StatStageChangePhase extends PokemonPhase {
handleTutorial(Tutorial.Stat_Change).then(() => super.end());
};
- if (relLevels.filter(l => l).length && globalScene.moveAnimations) {
+ if (relLevels.filter(l => l).length > 0 && globalScene.moveAnimations) {
pokemon.enableMask();
const pokemonMaskSprite = pokemon.maskSprite;
@@ -309,13 +305,13 @@ export class StatStageChangePhase extends PokemonPhase {
while (
(existingPhase = globalScene.phaseManager.findPhase(
p =>
- p.is("StatStageChangePhase") &&
- p.battlerIndex === this.battlerIndex &&
- p.stats.length === 1 &&
- p.stats[0] === this.stats[0] &&
- p.selfTarget === this.selfTarget &&
- p.showMessage === this.showMessage &&
- p.ignoreAbilities === this.ignoreAbilities,
+ p.is("StatStageChangePhase")
+ && p.battlerIndex === this.battlerIndex
+ && p.stats.length === 1
+ && p.stats[0] === this.stats[0]
+ && p.selfTarget === this.selfTarget
+ && p.showMessage === this.showMessage
+ && p.ignoreAbilities === this.ignoreAbilities,
) as StatStageChangePhase)
) {
this.stages += existingPhase.stages;
@@ -328,13 +324,13 @@ export class StatStageChangePhase extends PokemonPhase {
while (
(existingPhase = globalScene.phaseManager.findPhase(
p =>
- p.is("StatStageChangePhase") &&
- p.battlerIndex === this.battlerIndex &&
- p.selfTarget === this.selfTarget &&
- accEva.some(s => p.stats.includes(s)) === isAccEva &&
- p.stages === this.stages &&
- p.showMessage === this.showMessage &&
- p.ignoreAbilities === this.ignoreAbilities,
+ p.is("StatStageChangePhase")
+ && p.battlerIndex === this.battlerIndex
+ && p.selfTarget === this.selfTarget
+ && accEva.some(s => p.stats.includes(s)) === isAccEva
+ && p.stages === this.stages
+ && p.showMessage === this.showMessage
+ && p.ignoreAbilities === this.ignoreAbilities,
) as StatStageChangePhase)
) {
this.stats.push(...existingPhase.stats);
@@ -369,7 +365,8 @@ export class StatStageChangePhase extends PokemonPhase {
.map(s => i18next.t(getStatKey(s)))
.join(
", ",
- )}${relStageStats.length > 2 ? "," : ""} ${i18next.t("battle:statsAnd")} ${i18next.t(getStatKey(relStageStats[relStageStats.length - 1]))}`;
+ // Bang is justified as we explicitly check for the existence of 2+ args
+ )}${relStageStats.length > 2 ? "," : ""} ${i18next.t("battle:statsAnd")} ${i18next.t(getStatKey(relStageStats.at(-1)!))}`;
messages.push(
i18next.t(getStatStageChangeDescriptionKey(Math.abs(Number.parseInt(rl)), stages >= 1), {
pokemonNameWithAffix: getPokemonNameWithAffix(this.getPokemon()),
diff --git a/src/phases/summon-phase.ts b/src/phases/summon-phase.ts
index e4c8aa9af7a..dda70f46ec9 100644
--- a/src/phases/summon-phase.ts
+++ b/src/phases/summon-phase.ts
@@ -97,8 +97,8 @@ export class SummonPhase extends PartyMemberPokemonPhase {
});
globalScene.time.delayedCall(750, () => this.summon());
} else if (
- globalScene.currentBattle.battleType === BattleType.TRAINER ||
- globalScene.currentBattle.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE
+ globalScene.currentBattle.battleType === BattleType.TRAINER
+ || globalScene.currentBattle.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE
) {
const trainerName = globalScene.currentBattle.trainer?.getName(
!(this.fieldIndex % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER,
@@ -278,9 +278,9 @@ export class SummonPhase extends PartyMemberPokemonPhase {
pokemon.resetTurnData();
if (
- !this.loaded ||
- [BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(globalScene.currentBattle.battleType) ||
- globalScene.currentBattle.waveIndex % 10 === 1
+ !this.loaded
+ || [BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(globalScene.currentBattle.battleType)
+ || globalScene.currentBattle.waveIndex % 10 === 1
) {
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true);
this.queuePostSummon();
diff --git a/src/phases/switch-phase.ts b/src/phases/switch-phase.ts
index eaa8a723745..8b03f5ec5ce 100644
--- a/src/phases/switch-phase.ts
+++ b/src/phases/switch-phase.ts
@@ -3,7 +3,7 @@ import { DynamicPhaseType } from "#enums/dynamic-phase-type";
import { SwitchType } from "#enums/switch-type";
import { UiMode } from "#enums/ui-mode";
import { BattlePhase } from "#phases/battle-phase";
-import { PartyOption, PartyUiHandler, PartyUiMode } from "#ui/party-ui-handler";
+import { PartyOption, PartyUiHandler, PartyUiMode } from "#ui/handlers/party-ui-handler";
/**
* Opens the party selector UI and transitions into a {@linkcode SwitchSummonPhase}
@@ -38,7 +38,10 @@ export class SwitchPhase extends BattlePhase {
super.start();
// Skip modal switch if impossible (no remaining party members that aren't in battle)
- if (this.isModal && !globalScene.getPlayerParty().filter(p => p.isAllowedInBattle() && !p.isActive(true)).length) {
+ if (
+ this.isModal
+ && globalScene.getPlayerParty().filter(p => p.isAllowedInBattle() && !p.isActive(true)).length === 0
+ ) {
return super.end();
}
@@ -55,9 +58,9 @@ export class SwitchPhase extends BattlePhase {
// Check if there is any space still in field
if (
- this.isModal &&
- globalScene.getPlayerField().filter(p => p.isAllowedInBattle() && p.isActive(true)).length >=
- globalScene.currentBattle.getBattlerCount()
+ this.isModal
+ && globalScene.getPlayerField().filter(p => p.isAllowedInBattle() && p.isActive(true)).length
+ >= globalScene.currentBattle.getBattlerCount()
) {
return super.end();
}
diff --git a/src/phases/switch-summon-phase.ts b/src/phases/switch-summon-phase.ts
index b7460e77569..ac47068c619 100644
--- a/src/phases/switch-summon-phase.ts
+++ b/src/phases/switch-summon-phase.ts
@@ -56,9 +56,9 @@ export class SwitchSummonPhase extends SummonPhase {
}
if (
- !this.doReturn ||
- (this.slotIndex !== -1 &&
- !(this.player ? globalScene.getPlayerParty() : globalScene.getEnemyParty())[this.slotIndex])
+ !this.doReturn
+ || (this.slotIndex !== -1
+ && !(this.player ? globalScene.getPlayerParty() : globalScene.getEnemyParty())[this.slotIndex])
) {
if (this.player) {
this.switchAndSummon();
@@ -141,14 +141,14 @@ export class SwitchSummonPhase extends SummonPhase {
if (
!globalScene.findModifier(
m =>
- m instanceof SwitchEffectTransferModifier &&
- (m as SwitchEffectTransferModifier).pokemonId === switchedInPokemon.id,
+ m instanceof SwitchEffectTransferModifier
+ && (m as SwitchEffectTransferModifier).pokemonId === switchedInPokemon.id,
)
) {
const batonPassModifier = globalScene.findModifier(
m =>
- m instanceof SwitchEffectTransferModifier &&
- (m as SwitchEffectTransferModifier).pokemonId === this.lastPokemon.id,
+ m instanceof SwitchEffectTransferModifier
+ && (m as SwitchEffectTransferModifier).pokemonId === this.lastPokemon.id,
) as SwitchEffectTransferModifier;
if (batonPassModifier) {
@@ -214,9 +214,9 @@ export class SwitchSummonPhase extends SummonPhase {
// Compensate for turn spent summoning/forced switch if switched out pokemon is not fainted.
// Needed as we increment turn counters in `TurnEndPhase`.
if (
- currentCommand === Command.POKEMON ||
- lastPokemonIsForceSwitchedAndNotFainted ||
- lastPokemonHasForceSwitchAbAttr
+ currentCommand === Command.POKEMON
+ || lastPokemonIsForceSwitchedAndNotFainted
+ || lastPokemonHasForceSwitchAbAttr
) {
pokemon.tempSummonData.turnCount--;
pokemon.tempSummonData.waveTurnCount--;
diff --git a/src/phases/title-phase.ts b/src/phases/title-phase.ts
index 15d92ba2812..fd12ec3bd6b 100644
--- a/src/phases/title-phase.ts
+++ b/src/phases/title-phase.ts
@@ -16,8 +16,8 @@ import type { Modifier } from "#modifiers/modifier";
import { getDailyRunStarterModifiers, regenerateModifierPoolThresholds } from "#modifiers/modifier-type";
import type { SessionSaveData } from "#system/game-data";
import { vouchers } from "#system/voucher";
-import type { OptionSelectConfig, OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
-import { SaveSlotUiMode } from "#ui/save-slot-select-ui-handler";
+import type { OptionSelectConfig, OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler";
+import { SaveSlotUiMode } from "#ui/handlers/save-slot-select-ui-handler";
import { isLocal, isLocalServerConnected, isNullOrUndefined } from "#utils/common";
import i18next from "i18next";
@@ -125,7 +125,7 @@ export class TitlePhase extends Phase {
});
globalScene.ui.showText(i18next.t("menu:selectGameMode"), null, () =>
globalScene.ui.setOverlayMode(UiMode.OPTION_SELECT, {
- options: options,
+ options,
}),
);
return true;
@@ -161,7 +161,7 @@ export class TitlePhase extends Phase {
},
);
const config: OptionSelectConfig = {
- options: options,
+ options,
noCancel: true,
yOffset: 47,
};
@@ -177,6 +177,9 @@ export class TitlePhase extends Phase {
.then((success: boolean) => {
if (success) {
this.loaded = true;
+ if (loggedInUser) {
+ loggedInUser.lastSessionSlot = slotId;
+ }
globalScene.ui.showText(i18next.t("menu:sessionSuccess"), null, () => this.end());
} else {
this.end();
@@ -241,11 +244,11 @@ export class TitlePhase extends Phase {
regenerateModifierPoolThresholds(party, ModifierPoolType.DAILY_STARTER);
- const modifiers: Modifier[] = Array(3)
+ const modifiers: Modifier[] = new Array(3)
.fill(null)
.map(() => modifierTypes.EXP_SHARE().withIdFromFunc(modifierTypes.EXP_SHARE).newModifier())
.concat(
- Array(3)
+ new Array(3)
.fill(null)
.map(() => modifierTypes.GOLDEN_EXP_CHARM().withIdFromFunc(modifierTypes.GOLDEN_EXP_CHARM).newModifier()),
)
@@ -319,8 +322,8 @@ export class TitlePhase extends Phase {
}
if (
- globalScene.currentBattle.battleType !== BattleType.TRAINER &&
- (globalScene.currentBattle.waveIndex > 1 || !globalScene.gameMode.isDaily)
+ globalScene.currentBattle.battleType !== BattleType.TRAINER
+ && (globalScene.currentBattle.waveIndex > 1 || !globalScene.gameMode.isDaily)
) {
const minPartySize = globalScene.currentBattle.double ? 2 : 1;
if (availablePartyMembers > minPartySize) {
diff --git a/src/phases/trainer-victory-phase.ts b/src/phases/trainer-victory-phase.ts
index 6f92dbe496d..909c1535140 100644
--- a/src/phases/trainer-victory-phase.ts
+++ b/src/phases/trainer-victory-phase.ts
@@ -27,35 +27,34 @@ export class TrainerVictoryPhase extends BattlePhase {
const trainerType = globalScene.currentBattle.trainer?.config.trainerType!; // TODO: is this bang correct?
// Validate Voucher for boss trainers
- if (vouchers.hasOwnProperty(TrainerType[trainerType])) {
- if (
- !globalScene.validateVoucher(vouchers[TrainerType[trainerType]]) &&
- globalScene.currentBattle.trainer?.config.isBoss
- ) {
- if (timedEventManager.getUpgradeUnlockedVouchers()) {
- globalScene.phaseManager.unshiftNew(
- "ModifierRewardPhase",
- [
- modifierTypes.VOUCHER_PLUS,
- modifierTypes.VOUCHER_PLUS,
- modifierTypes.VOUCHER_PLUS,
- modifierTypes.VOUCHER_PREMIUM,
- ][vouchers[TrainerType[trainerType]].voucherType],
- );
- } else {
- globalScene.phaseManager.unshiftNew(
- "ModifierRewardPhase",
- [modifierTypes.VOUCHER, modifierTypes.VOUCHER, modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PREMIUM][
- vouchers[TrainerType[trainerType]].voucherType
- ],
- );
- }
+ if (
+ vouchers.hasOwnProperty(TrainerType[trainerType])
+ && !globalScene.validateVoucher(vouchers[TrainerType[trainerType]])
+ && globalScene.currentBattle.trainer?.config.isBoss
+ ) {
+ if (timedEventManager.getUpgradeUnlockedVouchers()) {
+ globalScene.phaseManager.unshiftNew(
+ "ModifierRewardPhase",
+ [
+ modifierTypes.VOUCHER_PLUS,
+ modifierTypes.VOUCHER_PLUS,
+ modifierTypes.VOUCHER_PLUS,
+ modifierTypes.VOUCHER_PREMIUM,
+ ][vouchers[TrainerType[trainerType]].voucherType],
+ );
+ } else {
+ globalScene.phaseManager.unshiftNew(
+ "ModifierRewardPhase",
+ [modifierTypes.VOUCHER, modifierTypes.VOUCHER, modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PREMIUM][
+ vouchers[TrainerType[trainerType]].voucherType
+ ],
+ );
}
}
// Breeders in Space achievement
if (
- globalScene.arena.biomeType === BiomeId.SPACE &&
- (trainerType === TrainerType.BREEDER || trainerType === TrainerType.EXPERT_POKEMON_BREEDER)
+ globalScene.arena.biomeType === BiomeId.SPACE
+ && (trainerType === TrainerType.BREEDER || trainerType === TrainerType.EXPERT_POKEMON_BREEDER)
) {
globalScene.validateAchv(achvs.BREEDERS_IN_SPACE);
}
@@ -87,7 +86,7 @@ export class TrainerVictoryPhase extends BattlePhase {
showMessageOrEnd();
};
let showMessageOrEnd = () => this.end();
- if (victoryMessages?.length) {
+ if (victoryMessages?.length > 0) {
if (globalScene.currentBattle.trainer?.config.hasCharSprite && !globalScene.ui.shouldSkipDialogue(message)) {
const originalFunc = showMessageOrEnd;
showMessageOrEnd = () =>
diff --git a/src/phases/turn-init-phase.ts b/src/phases/turn-init-phase.ts
index b2ab096102c..d1b1f01c130 100644
--- a/src/phases/turn-init-phase.ts
+++ b/src/phases/turn-init-phase.ts
@@ -25,13 +25,13 @@ export class TurnInitPhase extends FieldPhase {
const allowedPokemon = globalScene.getPokemonAllowedInBattle();
- if (!allowedPokemon.length) {
+ if (allowedPokemon.length === 0) {
// If there are no longer any legal pokemon in the party, game over.
globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.unshiftNew("GameOverPhase");
} else if (
- allowedPokemon.length >= globalScene.currentBattle.getBattlerCount() ||
- (globalScene.currentBattle.double && !allowedPokemon[0].isActive(true))
+ allowedPokemon.length >= globalScene.currentBattle.getBattlerCount()
+ || (globalScene.currentBattle.double && !allowedPokemon[0].isActive(true))
) {
// If there is at least one pokemon in the back that is legal to switch in, force a switch.
p.switchOut();
diff --git a/src/phases/turn-start-phase.ts b/src/phases/turn-start-phase.ts
index 59211a9eb03..1733901d527 100644
--- a/src/phases/turn-start-phase.ts
+++ b/src/phases/turn-start-phase.ts
@@ -72,7 +72,7 @@ export class TurnStartPhase extends FieldPhase {
applyAbAttrs("PreventBypassSpeedChanceAbAttr", {
pokemon: p,
bypass: bypassSpeed,
- canCheckHeldItems: canCheckHeldItems,
+ canCheckHeldItems,
});
if (canCheckHeldItems.value) {
globalScene.applyModifiers(BypassSpeedChanceModifier, p.isPlayer(), p, bypassSpeed);
@@ -226,8 +226,8 @@ export class TurnStartPhase extends FieldPhase {
// TODO: This seems somewhat dubious
const move =
- pokemon.getMoveset().find(m => m.moveId === queuedMove.move && m.ppUsed < m.getMovePp()) ??
- new PokemonMove(queuedMove.move);
+ pokemon.getMoveset().find(m => m.moveId === queuedMove.move && m.ppUsed < m.getMovePp())
+ ?? new PokemonMove(queuedMove.move);
if (move.getMove().hasAttr("MoveHeaderAttr")) {
globalScene.phaseManager.unshiftNew("MoveHeaderPhase", pokemon, move);
diff --git a/src/phases/weather-effect-phase.ts b/src/phases/weather-effect-phase.ts
index 81db543001b..27cd787a08d 100644
--- a/src/phases/weather-effect-phase.ts
+++ b/src/phases/weather-effect-phase.ts
@@ -48,9 +48,9 @@ export class WeatherEffectPhase extends CommonAnimPhase {
applyAbAttrs("BlockNonDirectDamageAbAttr", { pokemon, cancelled });
if (
- cancelled.value ||
- pokemon.getTag(BattlerTagType.UNDERGROUND) ||
- pokemon.getTag(BattlerTagType.UNDERWATER)
+ cancelled.value
+ || pokemon.getTag(BattlerTagType.UNDERGROUND)
+ || pokemon.getTag(BattlerTagType.UNDERWATER)
) {
return;
}
@@ -63,9 +63,9 @@ export class WeatherEffectPhase extends CommonAnimPhase {
this.executeForAll((pokemon: Pokemon) => {
const immune =
- !pokemon ||
- !!pokemon.getTypes(true, true).filter(t => this.weather?.isTypeDamageImmune(t)).length ||
- pokemon.switchOutStatus;
+ !pokemon
+ || pokemon.getTypes(true, true).filter(t => this.weather?.isTypeDamageImmune(t)).length > 0
+ || pokemon.switchOutStatus;
if (!immune) {
inflictDamage(pokemon);
}
diff --git a/src/pipelines/field-sprite.ts b/src/pipelines/field-sprite.ts
index b20bacf6a5e..9132fd585ec 100644
--- a/src/pipelines/field-sprite.ts
+++ b/src/pipelines/field-sprite.ts
@@ -9,7 +9,7 @@ export class FieldSpritePipeline extends Phaser.Renderer.WebGL.Pipelines.MultiPi
constructor(game: Phaser.Game, config?: Phaser.Types.Renderer.WebGL.WebGLPipelineConfig) {
super(
config || {
- game: game,
+ game,
name: "field-sprite",
fragShader: fieldSpriteFragShader,
vertShader: spriteVertShader,
diff --git a/src/pipelines/sprite.ts b/src/pipelines/sprite.ts
index 8d38eda562d..65f8007e2f8 100644
--- a/src/pipelines/sprite.ts
+++ b/src/pipelines/sprite.ts
@@ -13,7 +13,7 @@ export class SpritePipeline extends FieldSpritePipeline {
constructor(game: Phaser.Game) {
super(game, {
- game: game,
+ game,
name: "sprite",
fragShader: spriteFragShader,
vertShader: spriteVertShader,
@@ -52,9 +52,9 @@ export class SpritePipeline extends FieldSpritePipeline {
const ignoreOverride = data["ignoreOverride"] as boolean;
const isEntityObj =
- sprite.parentContainer instanceof Pokemon ||
- sprite.parentContainer instanceof Trainer ||
- sprite.parentContainer instanceof MysteryEncounterIntroVisuals;
+ sprite.parentContainer instanceof Pokemon
+ || sprite.parentContainer instanceof Trainer
+ || sprite.parentContainer instanceof MysteryEncounterIntroVisuals;
const field = isEntityObj ? sprite.parentContainer.parentContainer : sprite.parentContainer;
const position = isEntityObj ? [sprite.parentContainer.x, sprite.parentContainer.y] : [sprite.x, sprite.y];
if (field) {
@@ -65,8 +65,8 @@ export class SpritePipeline extends FieldSpritePipeline {
-(sprite.width - sprite.frame.width) / 2 + sprite.frame.x + (!ignoreFieldPos ? sprite.x - field.x : 0);
if (sprite.originY === 0.5) {
position[1] +=
- (sprite.height / 2) * ((isEntityObj ? sprite.parentContainer : sprite).scale - 1) +
- (!ignoreFieldPos ? sprite.y - field.y : 0);
+ (sprite.height / 2) * ((isEntityObj ? sprite.parentContainer : sprite).scale - 1)
+ + (!ignoreFieldPos ? sprite.y - field.y : 0);
}
this.set1f("teraTime", (this.game.getTime() % 500000) / 500000);
this.set3fv(
@@ -90,9 +90,9 @@ export class SpritePipeline extends FieldSpritePipeline {
if (globalScene.fusionPaletteSwaps) {
const spriteColors = ((ignoreOverride && data["spriteColorsBase"]) || data["spriteColors"] || []) as number[][];
- const fusionSpriteColors = ((ignoreOverride && data["fusionSpriteColorsBase"]) ||
- data["fusionSpriteColors"] ||
- []) as number[][];
+ const fusionSpriteColors = ((ignoreOverride && data["fusionSpriteColorsBase"])
+ || data["fusionSpriteColors"]
+ || []) as number[][];
const emptyColors = [0, 0, 0, 0];
const flatSpriteColors: number[] = [];
@@ -132,14 +132,14 @@ export class SpritePipeline extends FieldSpritePipeline {
const flatVariantColors: number[] = [];
if (
- (sprite.parentContainer instanceof Pokemon ? sprite.parentContainer.shiny : !!data["shiny"]) &&
- (variantColors =
+ (sprite.parentContainer instanceof Pokemon ? sprite.parentContainer.shiny : !!data["shiny"])
+ && (variantColors =
variantColorCache[
sprite.parentContainer instanceof Pokemon
? sprite.parentContainer.getSprite().texture.key
: data["spriteKey"]
- ]) &&
- variantColors.hasOwnProperty(variant)
+ ])
+ && variantColors.hasOwnProperty(variant)
) {
const baseColors = Object.keys(variantColors[variant]);
for (let c = 0; c < 32; c++) {
@@ -197,9 +197,9 @@ export class SpritePipeline extends FieldSpritePipeline {
const yShadowOffset = (sprite.pipelineData["yShadowOffset"] as number) ?? 0;
if (hasShadow) {
const isEntityObj =
- sprite.parentContainer instanceof Pokemon ||
- sprite.parentContainer instanceof Trainer ||
- sprite.parentContainer instanceof MysteryEncounterIntroVisuals;
+ sprite.parentContainer instanceof Pokemon
+ || sprite.parentContainer instanceof Trainer
+ || sprite.parentContainer instanceof MysteryEncounterIntroVisuals;
const field = isEntityObj ? sprite.parentContainer.parentContainer : sprite.parentContainer;
const fieldScaleRatio = field.scale / 6;
const baseY = ((isEntityObj ? sprite.parentContainer.y : sprite.y + sprite.height) * 6) / fieldScaleRatio;
diff --git a/src/plugins/api/pokerogue-daily-api.ts b/src/plugins/api/pokerogue-daily-api.ts
index 5ea3846e60e..dfde4720730 100644
--- a/src/plugins/api/pokerogue-daily-api.ts
+++ b/src/plugins/api/pokerogue-daily-api.ts
@@ -1,6 +1,6 @@
import { ApiBase } from "#api/api-base";
import type { GetDailyRankingsPageCountRequest, GetDailyRankingsRequest } from "#types/api/pokerogue-daily-api";
-import type { RankingEntry } from "#ui/daily-run-scoreboard";
+import type { RankingEntry } from "#ui/containers/daily-run-scoreboard";
/**
* A wrapper for daily-run PokéRogue API requests.
diff --git a/src/plugins/api/pokerogue-session-savedata-api.ts b/src/plugins/api/pokerogue-session-savedata-api.ts
index 39fa292f9f1..87960339671 100644
--- a/src/plugins/api/pokerogue-session-savedata-api.ts
+++ b/src/plugins/api/pokerogue-session-savedata-api.ts
@@ -16,8 +16,8 @@ export class PokerogueSessionSavedataApi extends ApiBase {
//#region Public
/**
- * Mark a session as cleared aka "newclear".\
- * *This is **NOT** the same as {@linkcode clear | clear()}.*
+ * Mark a session as cleared aka "newclear". \
+ * _This is **NOT** the same as {@linkcode clear | clear()}._
* @param params The {@linkcode NewClearSessionSavedataRequest} to send
* @returns The raw savedata as `string`.
* @throws Error if the request fails
@@ -82,6 +82,7 @@ export class PokerogueSessionSavedataApi extends ApiBase {
try {
const urlSearchParams = this.toUrlSearchParams(params);
const response = await this.doGet(`/savedata/session/delete?${urlSearchParams}`);
+ console.debug("%cSending a request to delete session in slot %d", "color: blue", params.slot);
if (response.ok) {
return null;
@@ -94,8 +95,8 @@ export class PokerogueSessionSavedataApi extends ApiBase {
}
/**
- * Clears the session savedata of the given slot.\
- * *This is **NOT** the same as {@linkcode newclear | newclear()}.*
+ * Clears the session savedata of the given slot. \
+ * _This is **NOT** the same as {@linkcode newclear | newclear()}._
* @param params The {@linkcode ClearSessionSavedataRequest} to send
* @param sessionData The {@linkcode SessionSaveData} object
*/
diff --git a/src/plugins/i18n.ts b/src/plugins/i18n.ts
index 62fc73a10a3..b6a5bacc7ba 100644
--- a/src/plugins/i18n.ts
+++ b/src/plugins/i18n.ts
@@ -121,8 +121,8 @@ async function initFonts(language: string | undefined) {
}
/**
- * I18n money formatter with. (useful for BBCode coloring of text)\
- * *If you don't want the BBCode tag applied, just use 'number' formatter*
+ * I18n money formatter with. (useful for BBCode coloring of text) \
+ * _If you don't want the BBCode tag applied, just use 'number' formatter_
* @example Input: `{{myMoneyValue, money}}`
* Output: `@[MONEY]{₽100,000,000}`
* @param amount the money amount
diff --git a/src/system/achv.ts b/src/system/achv.ts
index 4e9bb54c304..1a66dc83878 100644
--- a/src/system/achv.ts
+++ b/src/system/achv.ts
@@ -519,9 +519,9 @@ export const achvs = {
"reviver_seed",
100,
c =>
- c instanceof FreshStartChallenge &&
- c.value === 1 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof FreshStartChallenge
+ && c.value === 1
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -546,9 +546,9 @@ export const achvs = {
"ribbon_gen1",
100,
c =>
- c instanceof SingleGenerationChallenge &&
- c.value === 1 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleGenerationChallenge
+ && c.value === 1
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -558,9 +558,9 @@ export const achvs = {
"ribbon_gen2",
100,
c =>
- c instanceof SingleGenerationChallenge &&
- c.value === 2 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleGenerationChallenge
+ && c.value === 2
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -570,9 +570,9 @@ export const achvs = {
"ribbon_gen3",
100,
c =>
- c instanceof SingleGenerationChallenge &&
- c.value === 3 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleGenerationChallenge
+ && c.value === 3
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -582,9 +582,9 @@ export const achvs = {
"ribbon_gen4",
100,
c =>
- c instanceof SingleGenerationChallenge &&
- c.value === 4 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleGenerationChallenge
+ && c.value === 4
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -594,9 +594,9 @@ export const achvs = {
"ribbon_gen5",
100,
c =>
- c instanceof SingleGenerationChallenge &&
- c.value === 5 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleGenerationChallenge
+ && c.value === 5
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -606,9 +606,9 @@ export const achvs = {
"ribbon_gen6",
100,
c =>
- c instanceof SingleGenerationChallenge &&
- c.value === 6 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleGenerationChallenge
+ && c.value === 6
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -618,9 +618,9 @@ export const achvs = {
"ribbon_gen7",
100,
c =>
- c instanceof SingleGenerationChallenge &&
- c.value === 7 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleGenerationChallenge
+ && c.value === 7
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -630,9 +630,9 @@ export const achvs = {
"ribbon_gen8",
100,
c =>
- c instanceof SingleGenerationChallenge &&
- c.value === 8 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleGenerationChallenge
+ && c.value === 8
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -642,9 +642,9 @@ export const achvs = {
"ribbon_gen9",
100,
c =>
- c instanceof SingleGenerationChallenge &&
- c.value === 9 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleGenerationChallenge
+ && c.value === 9
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -654,9 +654,9 @@ export const achvs = {
"silk_scarf",
100,
c =>
- c instanceof SingleTypeChallenge &&
- c.value === 1 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleTypeChallenge
+ && c.value === 1
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -666,9 +666,9 @@ export const achvs = {
"black_belt",
100,
c =>
- c instanceof SingleTypeChallenge &&
- c.value === 2 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleTypeChallenge
+ && c.value === 2
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -678,9 +678,9 @@ export const achvs = {
"sharp_beak",
100,
c =>
- c instanceof SingleTypeChallenge &&
- c.value === 3 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleTypeChallenge
+ && c.value === 3
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -690,9 +690,9 @@ export const achvs = {
"poison_barb",
100,
c =>
- c instanceof SingleTypeChallenge &&
- c.value === 4 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleTypeChallenge
+ && c.value === 4
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -702,9 +702,9 @@ export const achvs = {
"soft_sand",
100,
c =>
- c instanceof SingleTypeChallenge &&
- c.value === 5 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleTypeChallenge
+ && c.value === 5
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -714,9 +714,9 @@ export const achvs = {
"hard_stone",
100,
c =>
- c instanceof SingleTypeChallenge &&
- c.value === 6 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleTypeChallenge
+ && c.value === 6
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -726,9 +726,9 @@ export const achvs = {
"silver_powder",
100,
c =>
- c instanceof SingleTypeChallenge &&
- c.value === 7 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleTypeChallenge
+ && c.value === 7
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -738,9 +738,9 @@ export const achvs = {
"spell_tag",
100,
c =>
- c instanceof SingleTypeChallenge &&
- c.value === 8 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleTypeChallenge
+ && c.value === 8
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -750,9 +750,9 @@ export const achvs = {
"metal_coat",
100,
c =>
- c instanceof SingleTypeChallenge &&
- c.value === 9 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleTypeChallenge
+ && c.value === 9
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -762,9 +762,9 @@ export const achvs = {
"charcoal",
100,
c =>
- c instanceof SingleTypeChallenge &&
- c.value === 10 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleTypeChallenge
+ && c.value === 10
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -774,9 +774,9 @@ export const achvs = {
"mystic_water",
100,
c =>
- c instanceof SingleTypeChallenge &&
- c.value === 11 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleTypeChallenge
+ && c.value === 11
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -786,9 +786,9 @@ export const achvs = {
"miracle_seed",
100,
c =>
- c instanceof SingleTypeChallenge &&
- c.value === 12 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleTypeChallenge
+ && c.value === 12
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -798,9 +798,9 @@ export const achvs = {
"magnet",
100,
c =>
- c instanceof SingleTypeChallenge &&
- c.value === 13 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleTypeChallenge
+ && c.value === 13
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -810,9 +810,9 @@ export const achvs = {
"twisted_spoon",
100,
c =>
- c instanceof SingleTypeChallenge &&
- c.value === 14 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleTypeChallenge
+ && c.value === 14
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -822,9 +822,9 @@ export const achvs = {
"never_melt_ice",
100,
c =>
- c instanceof SingleTypeChallenge &&
- c.value === 15 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleTypeChallenge
+ && c.value === 15
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -834,9 +834,9 @@ export const achvs = {
"dragon_fang",
100,
c =>
- c instanceof SingleTypeChallenge &&
- c.value === 16 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleTypeChallenge
+ && c.value === 16
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -846,9 +846,9 @@ export const achvs = {
"black_glasses",
100,
c =>
- c instanceof SingleTypeChallenge &&
- c.value === 17 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleTypeChallenge
+ && c.value === 17
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -858,9 +858,9 @@ export const achvs = {
"fairy_feather",
100,
c =>
- c instanceof SingleTypeChallenge &&
- c.value === 18 &&
- !globalScene.gameMode.challenges.some(
+ c instanceof SingleTypeChallenge
+ && c.value === 18
+ && !globalScene.gameMode.challenges.some(
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
),
),
@@ -877,9 +877,9 @@ export const achvs = {
"cracked_pot",
50,
c =>
- c instanceof FlipStatChallenge &&
- c.value > 0 &&
- globalScene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0),
+ c instanceof FlipStatChallenge
+ && c.value > 0
+ && globalScene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0),
).setSecret(),
BREEDERS_IN_SPACE: new Achv("breedersInSpace", "breedersInSpace.description", "moon_stone", 50).setSecret(),
};
diff --git a/src/system/game-data.ts b/src/system/game-data.ts
index 47d3c2df2f5..3442748c9ab 100644
--- a/src/system/game-data.ts
+++ b/src/system/game-data.ts
@@ -62,12 +62,13 @@ import {
import { VoucherType, vouchers } from "#system/voucher";
import { trainerConfigs } from "#trainers/trainer-config";
import type { DexData, DexEntry } from "#types/dex-data";
-import { RUN_HISTORY_LIMIT } from "#ui/run-history-ui-handler";
+import { RUN_HISTORY_LIMIT } from "#ui/handlers/run-history-ui-handler";
import { applyChallenges } from "#utils/challenge-utils";
import { executeIf, fixedInt, isLocal, NumberHolder, randInt, randSeedItem } from "#utils/common";
import { decrypt, encrypt } from "#utils/data";
import { getEnumKeys } from "#utils/enums";
import { getPokemonSpecies } from "#utils/pokemon-utils";
+import { isBeta } from "#utils/utility-vars";
import { AES, enc } from "crypto-js";
import i18next from "i18next";
@@ -367,10 +368,10 @@ export class GameData {
if (!bypassLogin) {
pokerogueApi.savedata.system.get({ clientSessionId }).then(saveDataOrErr => {
if (
- typeof saveDataOrErr === "number" ||
- !saveDataOrErr ||
- saveDataOrErr.length === 0 ||
- saveDataOrErr[0] !== "{"
+ typeof saveDataOrErr === "number"
+ || !saveDataOrErr
+ || saveDataOrErr.length === 0
+ || saveDataOrErr[0] !== "{"
) {
if (saveDataOrErr === 404) {
globalScene.phaseManager.queueMessage(
@@ -419,7 +420,15 @@ export class GameData {
}
}
- console.debug(systemData);
+ if (isLocal || isBeta) {
+ try {
+ console.debug(
+ this.parseSystemData(JSON.stringify(systemData, (_, v: any) => (typeof v === "bigint" ? v.toString() : v))),
+ );
+ } catch (err) {
+ console.debug("Attempt to log system data failed:", err);
+ }
+ }
localStorage.setItem(`data_${loggedInUser?.username}`, encrypt(systemDataStr, bypassLogin));
@@ -590,7 +599,7 @@ export class GameData {
const timestamp = runEntry.timestamp.toString();
runHistoryData[timestamp] = {
entry: runEntry,
- isVictory: isVictory,
+ isVictory,
isFavorite: false,
};
localStorage.setItem(
@@ -945,45 +954,46 @@ export class GameData {
} as SessionSaveData;
}
- getSession(slotId: number): Promise {
- // biome-ignore lint/suspicious/noAsyncPromiseExecutor: TODO: fix this
- return new Promise(async (resolve, reject) => {
- if (slotId < 0) {
- return resolve(null);
+ async getSession(slotId: number): Promise {
+ const { promise, resolve, reject } = Promise.withResolvers();
+ if (slotId < 0) {
+ resolve(null);
+ return promise;
+ }
+ const handleSessionData = async (sessionDataStr: string) => {
+ try {
+ const sessionData = this.parseSessionData(sessionDataStr);
+ resolve(sessionData);
+ } catch (err) {
+ reject(err);
+ return;
}
- const handleSessionData = async (sessionDataStr: string) => {
- try {
- const sessionData = this.parseSessionData(sessionDataStr);
- resolve(sessionData);
- } catch (err) {
- reject(err);
- return;
- }
- };
+ };
- if (!bypassLogin && !localStorage.getItem(`sessionData${slotId ? slotId : ""}_${loggedInUser?.username}`)) {
- pokerogueApi.savedata.session.get({ slot: slotId, clientSessionId }).then(async response => {
- if (!response || response?.length === 0 || response?.[0] !== "{") {
- console.error(response);
- return resolve(null);
- }
+ if (!bypassLogin && !localStorage.getItem(`sessionData${slotId ? slotId : ""}_${loggedInUser?.username}`)) {
+ const response = await pokerogueApi.savedata.session.get({ slot: slotId, clientSessionId });
- localStorage.setItem(
- `sessionData${slotId ? slotId : ""}_${loggedInUser?.username}`,
- encrypt(response, bypassLogin),
- );
-
- await handleSessionData(response);
- });
- } else {
- const sessionData = localStorage.getItem(`sessionData${slotId ? slotId : ""}_${loggedInUser?.username}`);
- if (sessionData) {
- await handleSessionData(decrypt(sessionData, bypassLogin));
- } else {
- return resolve(null);
- }
+ if (!response || response?.length === 0 || response?.[0] !== "{") {
+ console.error(response);
+ resolve(null);
+ return promise;
}
- });
+
+ localStorage.setItem(
+ `sessionData${slotId ? slotId : ""}_${loggedInUser?.username}`,
+ encrypt(response, bypassLogin),
+ );
+
+ await handleSessionData(response);
+ return promise;
+ }
+ const sessionData = localStorage.getItem(`sessionData${slotId ? slotId : ""}_${loggedInUser?.username}`);
+ if (sessionData) {
+ await handleSessionData(decrypt(sessionData, bypassLogin));
+ return promise;
+ }
+ resolve(null);
+ return promise;
}
async renameSession(slotId: number, newName: string): Promise {
@@ -1028,166 +1038,177 @@ export class GameData {
return !(success !== null && !success);
}
- loadSession(slotId: number, sessionData?: SessionSaveData): Promise {
- // biome-ignore lint/suspicious/noAsyncPromiseExecutor: TODO: fix this
- return new Promise(async (resolve, reject) => {
- try {
- const initSessionFromData = async (sessionData: SessionSaveData) => {
- console.debug(sessionData);
-
- globalScene.gameMode = getGameMode(sessionData.gameMode || GameModes.CLASSIC);
- if (sessionData.challenges) {
- globalScene.gameMode.challenges = sessionData.challenges.map(c => c.toChallenge());
+ async loadSession(slotId: number, sessionData?: SessionSaveData): Promise {
+ const { promise, resolve, reject } = Promise.withResolvers();
+ try {
+ const initSessionFromData = (fromSession: SessionSaveData) => {
+ if (isLocal || isBeta) {
+ try {
+ console.debug(
+ this.parseSessionData(
+ JSON.stringify(fromSession, (_, v: any) => (typeof v === "bigint" ? v.toString() : v)),
+ ),
+ );
+ } catch (err) {
+ console.debug("Attempt to log session data failed:", err);
}
-
- globalScene.setSeed(sessionData.seed || globalScene.game.config.seed[0]);
- globalScene.resetSeed();
-
- console.log("Seed:", globalScene.seed);
-
- globalScene.sessionPlayTime = sessionData.playTime || 0;
- globalScene.lastSavePlayTime = 0;
-
- const loadPokemonAssets: Promise[] = [];
-
- const party = globalScene.getPlayerParty();
- party.splice(0, party.length);
-
- for (const p of sessionData.party) {
- const pokemon = p.toPokemon() as PlayerPokemon;
- pokemon.setVisible(false);
- loadPokemonAssets.push(pokemon.loadAssets(false));
- party.push(pokemon);
- }
-
- Object.keys(globalScene.pokeballCounts).forEach((key: string) => {
- globalScene.pokeballCounts[key] = sessionData.pokeballCounts[key] || 0;
- });
- if (Overrides.POKEBALL_OVERRIDE.active) {
- globalScene.pokeballCounts = Overrides.POKEBALL_OVERRIDE.pokeballs;
- }
-
- globalScene.money = Math.floor(sessionData.money || 0);
- globalScene.updateMoneyText();
-
- if (globalScene.money > this.gameStats.highestMoney) {
- this.gameStats.highestMoney = globalScene.money;
- }
-
- globalScene.score = sessionData.score;
- globalScene.updateScoreText();
-
- globalScene.mysteryEncounterSaveData = new MysteryEncounterSaveData(sessionData.mysteryEncounterSaveData);
-
- globalScene.newArena(sessionData.arena.biome, sessionData.playerFaints);
-
- const battleType = sessionData.battleType || 0;
- const trainerConfig = sessionData.trainer ? trainerConfigs[sessionData.trainer.trainerType] : null;
- const mysteryEncounterType =
- sessionData.mysteryEncounterType !== -1 ? sessionData.mysteryEncounterType : undefined;
- const battle = globalScene.newBattle(
- sessionData.waveIndex,
- battleType,
- sessionData.trainer,
- battleType === BattleType.TRAINER
- ? trainerConfig?.doubleOnly || sessionData.trainer?.variant === TrainerVariant.DOUBLE
- : sessionData.enemyParty.length > 1,
- mysteryEncounterType,
- );
- battle.enemyLevels = sessionData.enemyParty.map(p => p.level);
-
- globalScene.arena.init();
-
- sessionData.enemyParty.forEach((enemyData, e) => {
- const enemyPokemon = enemyData.toPokemon(
- battleType,
- e,
- sessionData.trainer?.variant === TrainerVariant.DOUBLE,
- ) as EnemyPokemon;
- battle.enemyParty[e] = enemyPokemon;
- if (battleType === BattleType.WILD) {
- battle.seenEnemyPartyMemberIds.add(enemyPokemon.id);
- }
-
- loadPokemonAssets.push(enemyPokemon.loadAssets());
- });
-
- globalScene.arena.weather = sessionData.arena.weather;
- globalScene.arena.eventTarget.dispatchEvent(
- new WeatherChangedEvent(
- WeatherType.NONE,
- globalScene.arena.weather?.weatherType!,
- globalScene.arena.weather?.turnsLeft!,
- ),
- ); // TODO: is this bang correct?
-
- globalScene.arena.terrain = sessionData.arena.terrain;
- globalScene.arena.eventTarget.dispatchEvent(
- new TerrainChangedEvent(
- TerrainType.NONE,
- globalScene.arena.terrain?.terrainType!,
- globalScene.arena.terrain?.turnsLeft!,
- ),
- ); // TODO: is this bang correct?
-
- globalScene.arena.playerTerasUsed = sessionData.arena.playerTerasUsed;
-
- globalScene.arena.tags = sessionData.arena.tags;
- if (globalScene.arena.tags) {
- for (const tag of globalScene.arena.tags) {
- if (tag instanceof EntryHazardTag) {
- const { tagType, side, turnCount, layers, maxLayers } = tag as EntryHazardTag;
- globalScene.arena.eventTarget.dispatchEvent(
- new TagAddedEvent(tagType, side, turnCount, layers, maxLayers),
- );
- } else {
- globalScene.arena.eventTarget.dispatchEvent(new TagAddedEvent(tag.tagType, tag.side, tag.turnCount));
- }
- }
- }
-
- globalScene.arena.positionalTagManager.tags = sessionData.arena.positionalTags.map(tag =>
- loadPositionalTag(tag),
- );
-
- if (globalScene.modifiers.length) {
- console.warn("Existing modifiers not cleared on session load, deleting...");
- globalScene.modifiers = [];
- }
- for (const modifierData of sessionData.modifiers) {
- const modifier = modifierData.toModifier(Modifier[modifierData.className]);
- if (modifier) {
- globalScene.addModifier(modifier, true);
- }
- }
- globalScene.updateModifiers(true);
-
- for (const enemyModifierData of sessionData.enemyModifiers) {
- const modifier = enemyModifierData.toModifier(Modifier[enemyModifierData.className]);
- if (modifier) {
- globalScene.addEnemyModifier(modifier, true);
- }
- }
-
- globalScene.updateModifiers(false);
-
- Promise.all(loadPokemonAssets).then(() => resolve(true));
- };
- if (sessionData) {
- initSessionFromData(sessionData);
- } else {
- this.getSession(slotId)
- .then(data => data && initSessionFromData(data))
- .catch(err => {
- reject(err);
- return;
- });
}
- } catch (err) {
- reject(err);
- return;
+
+ globalScene.gameMode = getGameMode(fromSession.gameMode || GameModes.CLASSIC);
+ if (fromSession.challenges) {
+ globalScene.gameMode.challenges = fromSession.challenges.map(c => c.toChallenge());
+ }
+
+ globalScene.setSeed(fromSession.seed || globalScene.game.config.seed[0]);
+ globalScene.resetSeed();
+
+ console.log("Seed:", globalScene.seed);
+
+ globalScene.sessionPlayTime = fromSession.playTime || 0;
+ globalScene.lastSavePlayTime = 0;
+
+ const loadPokemonAssets: Promise[] = [];
+
+ const party = globalScene.getPlayerParty();
+ party.splice(0, party.length);
+
+ for (const p of fromSession.party) {
+ const pokemon = p.toPokemon() as PlayerPokemon;
+ pokemon.setVisible(false);
+ loadPokemonAssets.push(pokemon.loadAssets(false));
+ party.push(pokemon);
+ }
+
+ Object.keys(globalScene.pokeballCounts).forEach((key: string) => {
+ globalScene.pokeballCounts[key] = fromSession.pokeballCounts[key] || 0;
+ });
+ if (Overrides.POKEBALL_OVERRIDE.active) {
+ globalScene.pokeballCounts = Overrides.POKEBALL_OVERRIDE.pokeballs;
+ }
+
+ globalScene.money = Math.floor(fromSession.money || 0);
+ globalScene.updateMoneyText();
+
+ if (globalScene.money > this.gameStats.highestMoney) {
+ this.gameStats.highestMoney = globalScene.money;
+ }
+
+ globalScene.score = fromSession.score;
+ globalScene.updateScoreText();
+
+ globalScene.mysteryEncounterSaveData = new MysteryEncounterSaveData(fromSession.mysteryEncounterSaveData);
+
+ globalScene.newArena(fromSession.arena.biome, fromSession.playerFaints);
+
+ const battleType = fromSession.battleType || 0;
+ const trainerConfig = fromSession.trainer ? trainerConfigs[fromSession.trainer.trainerType] : null;
+ const mysteryEncounterType =
+ fromSession.mysteryEncounterType !== -1 ? fromSession.mysteryEncounterType : undefined;
+ const battle = globalScene.newBattle(
+ fromSession.waveIndex,
+ battleType,
+ fromSession.trainer,
+ battleType === BattleType.TRAINER
+ ? trainerConfig?.doubleOnly || fromSession.trainer?.variant === TrainerVariant.DOUBLE
+ : fromSession.enemyParty.length > 1,
+ mysteryEncounterType,
+ );
+ battle.enemyLevels = fromSession.enemyParty.map(p => p.level);
+
+ globalScene.arena.init();
+
+ fromSession.enemyParty.forEach((enemyData, e) => {
+ const enemyPokemon = enemyData.toPokemon(
+ battleType,
+ e,
+ fromSession.trainer?.variant === TrainerVariant.DOUBLE,
+ ) as EnemyPokemon;
+ battle.enemyParty[e] = enemyPokemon;
+ if (battleType === BattleType.WILD) {
+ battle.seenEnemyPartyMemberIds.add(enemyPokemon.id);
+ }
+
+ loadPokemonAssets.push(enemyPokemon.loadAssets());
+ });
+
+ globalScene.arena.weather = fromSession.arena.weather;
+ globalScene.arena.eventTarget.dispatchEvent(
+ new WeatherChangedEvent(
+ WeatherType.NONE,
+ globalScene.arena.weather?.weatherType!,
+ globalScene.arena.weather?.turnsLeft!,
+ ),
+ ); // TODO: is this bang correct?
+
+ globalScene.arena.terrain = fromSession.arena.terrain;
+ globalScene.arena.eventTarget.dispatchEvent(
+ new TerrainChangedEvent(
+ TerrainType.NONE,
+ globalScene.arena.terrain?.terrainType!,
+ globalScene.arena.terrain?.turnsLeft!,
+ ),
+ ); // TODO: is this bang correct?
+
+ globalScene.arena.playerTerasUsed = fromSession.arena.playerTerasUsed;
+
+ globalScene.arena.tags = fromSession.arena.tags;
+ if (globalScene.arena.tags) {
+ for (const tag of globalScene.arena.tags) {
+ if (tag instanceof EntryHazardTag) {
+ const { tagType, side, turnCount, layers, maxLayers } = tag as EntryHazardTag;
+ globalScene.arena.eventTarget.dispatchEvent(
+ new TagAddedEvent(tagType, side, turnCount, layers, maxLayers),
+ );
+ } else {
+ globalScene.arena.eventTarget.dispatchEvent(new TagAddedEvent(tag.tagType, tag.side, tag.turnCount));
+ }
+ }
+ }
+
+ globalScene.arena.positionalTagManager.tags = fromSession.arena.positionalTags.map(tag =>
+ loadPositionalTag(tag),
+ );
+
+ if (globalScene.modifiers.length > 0) {
+ console.warn("Existing modifiers not cleared on session load, deleting...");
+ globalScene.modifiers = [];
+ }
+ for (const modifierData of fromSession.modifiers) {
+ const modifier = modifierData.toModifier(Modifier[modifierData.className]);
+ if (modifier) {
+ globalScene.addModifier(modifier, true);
+ }
+ }
+ globalScene.updateModifiers(true);
+
+ for (const enemyModifierData of fromSession.enemyModifiers) {
+ const modifier = enemyModifierData.toModifier(Modifier[enemyModifierData.className]);
+ if (modifier) {
+ globalScene.addEnemyModifier(modifier, true);
+ }
+ }
+
+ globalScene.updateModifiers(false);
+
+ Promise.all(loadPokemonAssets).then(() => resolve(true));
+ };
+ if (sessionData) {
+ initSessionFromData(sessionData);
+ } else {
+ this.getSession(slotId)
+ .then(data => {
+ return data && initSessionFromData(data);
+ })
+ .catch(err => {
+ reject(err);
+ return;
+ });
}
- });
+ } catch (err) {
+ reject(err);
+ }
+
+ return promise;
}
/**
@@ -1326,8 +1347,8 @@ export class GameData {
}
if (
- md instanceof Modifier.EnemyAttackStatusEffectChanceModifier &&
- (md.effect === StatusEffect.FREEZE || md.effect === StatusEffect.SLEEP)
+ md instanceof Modifier.EnemyAttackStatusEffectChanceModifier
+ && (md.effect === StatusEffect.FREEZE || md.effect === StatusEffect.SLEEP)
) {
// Discard any old "sleep/freeze chance tokens".
// TODO: make this migrate script
@@ -1394,7 +1415,7 @@ export class GameData {
system: systemData,
session: sessionData,
sessionSlotId: globalScene.sessionSlotId,
- clientSessionId: clientSessionId,
+ clientSessionId,
};
localStorage.setItem(
@@ -1470,8 +1491,9 @@ export class GameData {
});
}
+ // TODO: this is a really shit way of checking JSON validity
promise.then(response => {
- if (typeof response === "number" || !response?.length || response[0] !== "{") {
+ if (typeof response !== "string" || response.length === 0 || response.charAt(0) !== "{") {
console.error(response);
resolve(false);
return;
@@ -1646,7 +1668,7 @@ export class GameData {
globalScene.executeWithSeedOffset(
() => {
const neutralNatures = [Nature.HARDY, Nature.DOCILE, Nature.SERIOUS, Nature.BASHFUL, Nature.QUIRKY];
- for (let s = 0; s < defaultStarterSpecies.length; s++) {
+ for (const _ of defaultStarterSpecies) {
defaultStarterNatures.push(randSeedItem(neutralNatures));
}
},
@@ -1692,8 +1714,8 @@ export class GameData {
setPokemonSeen(pokemon: Pokemon, incrementCount = true, trainer = false): void {
// Some Mystery Encounters block updates to these stats
if (
- globalScene.currentBattle?.isBattleMysteryEncounter() &&
- globalScene.currentBattle.mysteryEncounter?.preventGameStatsUpdates
+ globalScene.currentBattle?.isBattleMysteryEncounter()
+ && globalScene.currentBattle.mysteryEncounter?.preventGameStatsUpdates
) {
return;
}
@@ -1973,8 +1995,8 @@ export class GameData {
let message = prependSpeciesToMessage ? species.getName() + " " : "";
message +=
eggMoveIndex === 3
- ? i18next.t("egg:rareEggMoveUnlock", { moveName: moveName })
- : i18next.t("egg:eggMoveUnlock", { moveName: moveName });
+ ? i18next.t("egg:rareEggMoveUnlock", { moveName })
+ : i18next.t("egg:eggMoveUnlock", { moveName });
globalScene.ui.showText(message, null, () => resolve(true), null, true);
});
@@ -2197,9 +2219,9 @@ export class GameData {
for (const s of starterIds) {
const dexAttr = dexData[s].caughtAttr;
starterData[s].abilityAttr =
- (dexAttr & DexAttr.DEFAULT_VARIANT ? AbilityAttr.ABILITY_1 : 0) |
- (dexAttr & DexAttr.VARIANT_2 ? AbilityAttr.ABILITY_2 : 0) |
- (dexAttr & DexAttr.VARIANT_3 ? AbilityAttr.ABILITY_HIDDEN : 0);
+ (dexAttr & DexAttr.DEFAULT_VARIANT ? AbilityAttr.ABILITY_1 : 0)
+ | (dexAttr & DexAttr.VARIANT_2 ? AbilityAttr.ABILITY_2 : 0)
+ | (dexAttr & DexAttr.VARIANT_3 ? AbilityAttr.ABILITY_HIDDEN : 0);
if (dexAttr) {
if (!(dexAttr & DexAttr.DEFAULT_VARIANT)) {
dexData[s].caughtAttr ^= DexAttr.DEFAULT_VARIANT;
diff --git a/src/system/settings/settings-gamepad.ts b/src/system/settings/settings-gamepad.ts
index c334159cc3c..f16928f8c6c 100644
--- a/src/system/settings/settings-gamepad.ts
+++ b/src/system/settings/settings-gamepad.ts
@@ -104,18 +104,16 @@ export function setSettingGamepad(setting: SettingGamepad, value: number): boole
case SettingGamepad.Button_Speed_Up:
case SettingGamepad.Button_Slow_Down:
case SettingGamepad.Button_Submit:
- if (value) {
- if (globalScene.ui) {
- const cancelHandler = (success = false): boolean => {
- globalScene.ui.revertMode();
- (globalScene.ui.getHandler() as SettingsGamepadUiHandler).updateBindings();
- return success;
- };
- globalScene.ui.setOverlayMode(UiMode.GAMEPAD_BINDING, {
- target: setting,
- cancelHandler: cancelHandler,
- });
- }
+ if (value && globalScene.ui) {
+ const cancelHandler = (success = false): boolean => {
+ globalScene.ui.revertMode();
+ (globalScene.ui.getHandler() as SettingsGamepadUiHandler).updateBindings();
+ return success;
+ };
+ globalScene.ui.setOverlayMode(UiMode.GAMEPAD_BINDING, {
+ target: setting,
+ cancelHandler,
+ });
}
break;
case SettingGamepad.Controller:
diff --git a/src/system/settings/settings-keyboard.ts b/src/system/settings/settings-keyboard.ts
index 07f4f86bdb0..b5e7fc0be2f 100644
--- a/src/system/settings/settings-keyboard.ts
+++ b/src/system/settings/settings-keyboard.ts
@@ -167,18 +167,16 @@ export function setSettingKeyboard(setting: SettingKeyboard, value: number): boo
case SettingKeyboard.Alt_Button_Speed_Up:
case SettingKeyboard.Alt_Button_Slow_Down:
case SettingKeyboard.Alt_Button_Submit:
- if (value) {
- if (globalScene.ui) {
- const cancelHandler = (success = false): boolean => {
- globalScene.ui.revertMode();
- (globalScene.ui.getHandler() as SettingsKeyboardUiHandler).updateBindings();
- return success;
- };
- globalScene.ui.setOverlayMode(UiMode.KEYBOARD_BINDING, {
- target: setting,
- cancelHandler: cancelHandler,
- });
- }
+ if (value && globalScene.ui) {
+ const cancelHandler = (success = false): boolean => {
+ globalScene.ui.revertMode();
+ (globalScene.ui.getHandler() as SettingsKeyboardUiHandler).updateBindings();
+ return success;
+ };
+ globalScene.ui.setOverlayMode(UiMode.KEYBOARD_BINDING, {
+ target: setting,
+ cancelHandler,
+ });
}
break;
}
diff --git a/src/system/settings/settings.ts b/src/system/settings/settings.ts
index 86305b3f7ed..cf3a5fb0eee 100644
--- a/src/system/settings/settings.ts
+++ b/src/system/settings/settings.ts
@@ -896,104 +896,102 @@ export function setSetting(setting: string, value: number): boolean {
globalScene.typeHints = Setting[index].options[value].value === "On";
break;
case SettingKeys.Language:
- if (value) {
- if (globalScene.ui) {
- const cancelHandler = () => {
- globalScene.ui.revertMode();
- (globalScene.ui.getHandler() as SettingsUiHandler).setOptionCursor(-1, 0, true);
- };
- const changeLocaleHandler = (locale: string): boolean => {
- try {
- i18next.changeLanguage(locale);
- localStorage.setItem("prLang", locale);
- cancelHandler();
- // Reload the whole game to apply the new locale since also some constants are translated
- window.location.reload();
- return true;
- } catch (error) {
- console.error("Error changing locale:", error);
- return false;
- }
- };
- globalScene.ui.setOverlayMode(UiMode.OPTION_SELECT, {
- options: [
- {
- label: "English",
- handler: () => changeLocaleHandler("en"),
- },
- {
- label: "Español (ES)",
- handler: () => changeLocaleHandler("es-ES"),
- },
- {
- label: "Español (LATAM)",
- handler: () => changeLocaleHandler("es-MX"),
- },
- {
- label: "Français",
- handler: () => changeLocaleHandler("fr"),
- },
- {
- label: "Deutsch",
- handler: () => changeLocaleHandler("de"),
- },
- {
- label: "Italiano",
- handler: () => changeLocaleHandler("it"),
- },
- {
- label: "Português (BR)",
- handler: () => changeLocaleHandler("pt-BR"),
- },
- {
- label: "한국어",
- handler: () => changeLocaleHandler("ko"),
- },
- {
- label: "日本語",
- handler: () => changeLocaleHandler("ja"),
- },
- {
- label: "简体中文",
- handler: () => changeLocaleHandler("zh-CN"),
- },
- {
- label: "繁體中文",
- handler: () => changeLocaleHandler("zh-TW"),
- },
- {
- label: "Català (Needs Help)",
- handler: () => changeLocaleHandler("ca"),
- },
- {
- label: "Türkçe (Needs Help)",
- handler: () => changeLocaleHandler("tr"),
- },
- {
- label: "Русский (Needs Help)",
- handler: () => changeLocaleHandler("ru"),
- },
- {
- label: "Dansk (Needs Help)",
- handler: () => changeLocaleHandler("da"),
- },
- {
- label: "Română (Needs Help)",
- handler: () => changeLocaleHandler("ro"),
- },
- {
- label: "Tagalog (Needs Help)",
- handler: () => changeLocaleHandler("tl"),
- },
- {
- label: i18next.t("settings:back"),
- handler: () => cancelHandler(),
- },
- ],
- maxOptions: 7,
- });
- return false;
- }
+ if (value && globalScene.ui) {
+ const cancelHandler = () => {
+ globalScene.ui.revertMode();
+ (globalScene.ui.getHandler() as SettingsUiHandler).setOptionCursor(-1, 0, true);
+ };
+ const changeLocaleHandler = (locale: string): boolean => {
+ try {
+ i18next.changeLanguage(locale);
+ localStorage.setItem("prLang", locale);
+ cancelHandler();
+ // Reload the whole game to apply the new locale since also some constants are translated
+ window.location.reload();
+ return true;
+ } catch (error) {
+ console.error("Error changing locale:", error);
+ return false;
+ }
+ };
+ globalScene.ui.setOverlayMode(UiMode.OPTION_SELECT, {
+ options: [
+ {
+ label: "English",
+ handler: () => changeLocaleHandler("en"),
+ },
+ {
+ label: "Español (ES)",
+ handler: () => changeLocaleHandler("es-ES"),
+ },
+ {
+ label: "Español (LATAM)",
+ handler: () => changeLocaleHandler("es-MX"),
+ },
+ {
+ label: "Français",
+ handler: () => changeLocaleHandler("fr"),
+ },
+ {
+ label: "Deutsch",
+ handler: () => changeLocaleHandler("de"),
+ },
+ {
+ label: "Italiano",
+ handler: () => changeLocaleHandler("it"),
+ },
+ {
+ label: "Português (BR)",
+ handler: () => changeLocaleHandler("pt-BR"),
+ },
+ {
+ label: "한국어",
+ handler: () => changeLocaleHandler("ko"),
+ },
+ {
+ label: "日本語",
+ handler: () => changeLocaleHandler("ja"),
+ },
+ {
+ label: "简体中文",
+ handler: () => changeLocaleHandler("zh-CN"),
+ },
+ {
+ label: "繁體中文",
+ handler: () => changeLocaleHandler("zh-TW"),
+ },
+ {
+ label: "Català (Needs Help)",
+ handler: () => changeLocaleHandler("ca"),
+ },
+ {
+ label: "Türkçe (Needs Help)",
+ handler: () => changeLocaleHandler("tr"),
+ },
+ {
+ label: "Русский (Needs Help)",
+ handler: () => changeLocaleHandler("ru"),
+ },
+ {
+ label: "Dansk (Needs Help)",
+ handler: () => changeLocaleHandler("da"),
+ },
+ {
+ label: "Română (Needs Help)",
+ handler: () => changeLocaleHandler("ro"),
+ },
+ {
+ label: "Tagalog (Needs Help)",
+ handler: () => changeLocaleHandler("tl"),
+ },
+ {
+ label: i18next.t("settings:back"),
+ handler: () => cancelHandler(),
+ },
+ ],
+ maxOptions: 7,
+ });
+ return false;
}
break;
case SettingKeys.Shop_Overlay_Opacity:
diff --git a/src/system/version-migration/versions/v1_0_4.ts b/src/system/version-migration/versions/v1_0_4.ts
index 2c50e05d40f..6d65df29970 100644
--- a/src/system/version-migration/versions/v1_0_4.ts
+++ b/src/system/version-migration/versions/v1_0_4.ts
@@ -35,9 +35,9 @@ const fixLegendaryStats: SystemSaveMigrator = {
version: "1.0.4",
migrate: (data: SystemSaveData): void => {
if (
- data.gameStats &&
- data.gameStats.legendaryPokemonCaught !== undefined &&
- data.gameStats.subLegendaryPokemonCaught === undefined
+ data.gameStats
+ && data.gameStats.legendaryPokemonCaught !== undefined
+ && data.gameStats.subLegendaryPokemonCaught === undefined
) {
data.gameStats.subLegendaryPokemonSeen = 0;
data.gameStats.subLegendaryPokemonCaught = 0;
diff --git a/src/system/version-migration/versions/v1_9_0.ts b/src/system/version-migration/versions/v1_9_0.ts
index fb24b9af837..60e299ed458 100644
--- a/src/system/version-migration/versions/v1_9_0.ts
+++ b/src/system/version-migration/versions/v1_9_0.ts
@@ -22,9 +22,9 @@ const migratePartyData: SessionSaveMigrator = {
pkmnData.summonData.moveset &&= pkmnData.summonData.moveset.filter(m => !!m).map(m => PokemonMove.loadMove(m));
if (
- pkmnData.customPokemonData &&
- "hitsRecCount" in pkmnData.customPokemonData &&
- typeof pkmnData.customPokemonData["hitsRecCount"] === "number"
+ pkmnData.customPokemonData
+ && "hitsRecCount" in pkmnData.customPokemonData
+ && typeof pkmnData.customPokemonData["hitsRecCount"] === "number"
) {
// transfer old hit count stat to battleData.
pkmnData.battleData.hitCount = pkmnData.customPokemonData["hitsRecCount"];
diff --git a/src/system/voucher.ts b/src/system/voucher.ts
index 79e95f0b07b..18188269e71 100644
--- a/src/system/voucher.ts
+++ b/src/system/voucher.ts
@@ -103,9 +103,9 @@ export function initVouchers() {
const bossTrainerTypes = Object.keys(trainerConfigs).filter(
tt =>
- trainerConfigs[tt].isBoss &&
- trainerConfigs[tt].getDerivedType() !== TrainerType.RIVAL &&
- trainerConfigs[tt].hasVoucher,
+ trainerConfigs[tt].isBoss
+ && trainerConfigs[tt].getDerivedType() !== TrainerType.RIVAL
+ && trainerConfigs[tt].hasVoucher,
);
for (const trainerType of bossTrainerTypes) {
diff --git a/src/touch-controls.ts b/src/touch-controls.ts
index faee9ea232e..370b1748653 100644
--- a/src/touch-controls.ts
+++ b/src/touch-controls.ts
@@ -61,12 +61,12 @@ export class TouchControl {
* event, removes the keydown state, and removes the 'active' class from the node and the last touched element.
*/
bindKey(node: HTMLElement, key: string) {
- node.addEventListener("touchstart", event => {
+ node.addEventListener("pointerdown", event => {
event.preventDefault();
this.touchButtonDown(node, key);
});
- node.addEventListener("touchend", event => {
+ node.addEventListener("pointerup", event => {
event.preventDefault();
this.touchButtonUp(node, key, event.target?.["id"]);
});
@@ -124,14 +124,14 @@ export class TouchControl {
case "keydown":
this.events.emit("input_down", {
controller_type: "keyboard",
- button: button,
+ button,
isTouch: true,
});
break;
case "keyup":
this.events.emit("input_up", {
controller_type: "keyboard",
- button: button,
+ button,
isTouch: true,
});
break;
@@ -207,8 +207,8 @@ export function isMobile(): boolean {
if (
/(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,
- ) ||
- /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),
)
) {
diff --git a/src/tutorial.ts b/src/tutorial.ts
index 018d0927da0..5ab0be116f8 100644
--- a/src/tutorial.ts
+++ b/src/tutorial.ts
@@ -1,8 +1,8 @@
import { globalScene } from "#app/global-scene";
import Overrides from "#app/overrides";
import { UiMode } from "#enums/ui-mode";
-import { AwaitableUiHandler } from "#ui/awaitable-ui-handler";
-import type { UiHandler } from "#ui/ui-handler";
+import { AwaitableUiHandler } from "#ui/handlers/awaitable-ui-handler";
+import type { UiHandler } from "#ui/handlers/ui-handler";
import i18next from "i18next";
export enum Tutorial {
diff --git a/src/ui-inputs.ts b/src/ui-inputs.ts
index 72ae59faaec..34a08db8fbc 100644
--- a/src/ui-inputs.ts
+++ b/src/ui-inputs.ts
@@ -3,16 +3,16 @@ import type { InputsController } from "#app/inputs-controller";
import { Button } from "#enums/buttons";
import { UiMode } from "#enums/ui-mode";
import { Setting, SettingKeys, settingIndex } from "#system/settings";
-import type { MessageUiHandler } from "#ui/message-ui-handler";
-import { PokedexPageUiHandler } from "#ui/pokedex-page-ui-handler";
-import { PokedexUiHandler } from "#ui/pokedex-ui-handler";
-import { RunInfoUiHandler } from "#ui/run-info-ui-handler";
+import { PokedexPageUiHandler } from "#ui/containers/pokedex-page-ui-handler";
+import type { MessageUiHandler } from "#ui/handlers/message-ui-handler";
+import { PokedexUiHandler } from "#ui/handlers/pokedex-ui-handler";
+import { RunInfoUiHandler } from "#ui/handlers/run-info-ui-handler";
+import { StarterSelectUiHandler } from "#ui/handlers/starter-select-ui-handler";
import { SettingsAudioUiHandler } from "#ui/settings-audio-ui-handler";
import { SettingsDisplayUiHandler } from "#ui/settings-display-ui-handler";
import { SettingsGamepadUiHandler } from "#ui/settings-gamepad-ui-handler";
import { SettingsKeyboardUiHandler } from "#ui/settings-keyboard-ui-handler";
import { SettingsUiHandler } from "#ui/settings-ui-handler";
-import { StarterSelectUiHandler } from "#ui/starter-select-ui-handler";
import Phaser from "phaser";
type ActionKeys = Record void>;
@@ -103,23 +103,23 @@ export class UiInputs {
getActionsKeyUp(): ActionKeys {
const actions: ActionKeys = {
- [Button.UP]: () => undefined,
- [Button.DOWN]: () => undefined,
- [Button.LEFT]: () => undefined,
- [Button.RIGHT]: () => undefined,
- [Button.SUBMIT]: () => undefined,
- [Button.ACTION]: () => undefined,
- [Button.CANCEL]: () => undefined,
- [Button.MENU]: () => undefined,
+ [Button.UP]: () => {},
+ [Button.DOWN]: () => {},
+ [Button.LEFT]: () => {},
+ [Button.RIGHT]: () => {},
+ [Button.SUBMIT]: () => {},
+ [Button.ACTION]: () => {},
+ [Button.CANCEL]: () => {},
+ [Button.MENU]: () => {},
[Button.STATS]: () => this.buttonStats(false),
- [Button.CYCLE_SHINY]: () => undefined,
- [Button.CYCLE_FORM]: () => undefined,
- [Button.CYCLE_GENDER]: () => undefined,
- [Button.CYCLE_ABILITY]: () => undefined,
- [Button.CYCLE_NATURE]: () => undefined,
+ [Button.CYCLE_SHINY]: () => {},
+ [Button.CYCLE_FORM]: () => {},
+ [Button.CYCLE_GENDER]: () => {},
+ [Button.CYCLE_ABILITY]: () => {},
+ [Button.CYCLE_NATURE]: () => {},
[Button.CYCLE_TERA]: () => this.buttonInfo(false),
- [Button.SPEED_UP]: () => undefined,
- [Button.SLOW_DOWN]: () => undefined,
+ [Button.SPEED_UP]: () => {},
+ [Button.SLOW_DOWN]: () => {},
};
return actions;
}
diff --git a/src/ui/battle-info/battle-info.ts b/src/ui/battle-info/battle-info.ts
index 4d2cf597ed2..66e0830a731 100644
--- a/src/ui/battle-info/battle-info.ts
+++ b/src/ui/battle-info/battle-info.ts
@@ -72,6 +72,7 @@ export abstract class BattleInfo extends Phaser.GameObjects.Container {
protected splicedIcon: Phaser.GameObjects.Sprite;
protected statusIndicator: Phaser.GameObjects.Sprite;
protected levelContainer: Phaser.GameObjects.Container;
+ protected hpLabel: Phaser.GameObjects.Image;
protected hpBar: Phaser.GameObjects.Image;
protected levelNumbersContainer: Phaser.GameObjects.Container;
protected type1Icon: Phaser.GameObjects.Sprite;
@@ -178,7 +179,7 @@ export abstract class BattleInfo extends Phaser.GameObjects.Container {
}
const statLabel = globalScene.add
- .sprite(statX, statY, "pbinfo_stat", Stat[s])
+ .sprite(statX, statY, getLocalizedSpriteKey("pbinfo_stat"), Stat[s])
.setName("icon_stat_label_" + i.toString())
.setOrigin(0);
statLabels.push(statLabel);
@@ -259,12 +260,17 @@ export abstract class BattleInfo extends Phaser.GameObjects.Container {
.setName("container_level");
this.add(this.levelContainer);
- const levelOverlay = globalScene.add.image(0, 0, "overlay_lv");
+ const levelOverlay = globalScene.add.image(5.5, 0, getLocalizedSpriteKey("overlay_lv")).setOrigin(1, 0.5);
this.levelContainer.add(levelOverlay);
this.hpBar = globalScene.add.image(posParams.hpBarX, posParams.hpBarY, "overlay_hp").setName("hp_bar").setOrigin(0);
this.add(this.hpBar);
+ this.hpLabel = globalScene.add
+ .image(posParams.hpBarX - 1, posParams.hpBarY - 3, getLocalizedSpriteKey("overlay_hp_label"))
+ .setOrigin(1, 0);
+ this.add(this.hpLabel);
+
this.levelNumbersContainer = globalScene.add
.container(9.5, globalScene.uiTheme === UiTheme.LEGACY ? 0 : -0.5)
.setName("container_level");
@@ -309,11 +315,11 @@ export abstract class BattleInfo extends Phaser.GameObjects.Container {
this.shinyIcon.setPositionRelative(
this.nameText,
- xOffset +
- this.genderText.displayWidth +
- 1 +
- (this.teraIcon.visible ? this.teraIcon.displayWidth + 1 : 0) +
- (this.splicedIcon.visible ? this.splicedIcon.displayWidth + 1 : 0),
+ xOffset
+ + this.genderText.displayWidth
+ + 1
+ + (this.teraIcon.visible ? this.teraIcon.displayWidth + 1 : 0)
+ + (this.splicedIcon.visible ? this.splicedIcon.displayWidth + 1 : 0),
2.5,
);
this.shinyIcon
@@ -500,19 +506,19 @@ export abstract class BattleInfo extends Phaser.GameObjects.Container {
.setVisible(isFusion)
.setPositionRelative(
this.nameText,
- this.nameText.displayWidth +
- this.genderText.displayWidth +
- 1 +
- (this.teraIcon.visible ? this.teraIcon.displayWidth + 1 : 0),
+ this.nameText.displayWidth
+ + this.genderText.displayWidth
+ + 1
+ + (this.teraIcon.visible ? this.teraIcon.displayWidth + 1 : 0),
1.5,
);
this.shinyIcon.setPositionRelative(
this.nameText,
- this.nameText.displayWidth +
- this.genderText.displayWidth +
- 1 +
- (this.teraIcon.visible ? this.teraIcon.displayWidth + 1 : 0) +
- (this.splicedIcon.visible ? this.splicedIcon.displayWidth + 1 : 0),
+ this.nameText.displayWidth
+ + this.genderText.displayWidth
+ + 1
+ + (this.teraIcon.visible ? this.teraIcon.displayWidth + 1 : 0)
+ + (this.splicedIcon.visible ? this.splicedIcon.displayWidth + 1 : 0),
2.5,
);
}
@@ -549,7 +555,7 @@ export abstract class BattleInfo extends Phaser.GameObjects.Container {
targets: this.hpBar,
ease: "Sine.easeOut",
scaleX: pokemon.getHpRatio(true),
- duration: duration,
+ duration,
onUpdate: () => {
this.onHpTweenUpdate(pokemon);
},
@@ -629,12 +635,12 @@ export abstract class BattleInfo extends Phaser.GameObjects.Container {
const gender = pokemon.summonData.illusion?.gender ?? pokemon.gender;
while (
- nameTextWidth >
- (this.player || !this.boss ? 60 : 98) -
- ((gender !== Gender.GENDERLESS ? 6 : 0) +
- (pokemon.fusionSpecies ? 8 : 0) +
- (pokemon.isShiny() ? 8 : 0) +
- (Math.min(pokemon.level.toString().length, 3) - 3) * 8)
+ nameTextWidth
+ > (this.player || !this.boss ? 60 : 98)
+ - ((gender !== Gender.GENDERLESS ? 6 : 0)
+ + (pokemon.fusionSpecies ? 8 : 0)
+ + (pokemon.isShiny() ? 8 : 0)
+ + (Math.min(pokemon.level.toString().length, 3) - 3) * 8)
) {
displayName = `${displayName.slice(0, displayName.endsWith(".") ? -2 : -1).trimEnd()}.`;
nameSizeTest.setText(displayName);
diff --git a/src/ui/battle-info/enemy-battle-info.ts b/src/ui/battle-info/enemy-battle-info.ts
index 0feb314a2e7..ad72afedc38 100644
--- a/src/ui/battle-info/enemy-battle-info.ts
+++ b/src/ui/battle-info/enemy-battle-info.ts
@@ -3,11 +3,12 @@ import { Stat } from "#enums/stat";
import { TextStyle } from "#enums/text-style";
import { UiTheme } from "#enums/ui-theme";
import type { EnemyPokemon } from "#field/pokemon";
-import { BattleFlyout } from "#ui/battle-flyout";
import type { BattleInfoParamList } from "#ui/battle-info";
import { BattleInfo } from "#ui/battle-info";
+import { BattleFlyout } from "#ui/containers/battle-flyout";
import { addTextObject } from "#ui/text";
import { addWindow, WindowVariant } from "#ui/ui-theme";
+import { getLocalizedSpriteKey } from "#utils/common";
import i18next from "i18next";
import type { GameObjects } from "phaser";
@@ -112,9 +113,9 @@ export class EnemyBattleInfo extends BattleInfo {
this.ownedIcon.setVisible(!!dexEntry.caughtAttr);
const opponentPokemonDexAttr = pokemon.getDexAttr();
if (
- globalScene.gameMode.isClassic &&
- globalScene.gameData.starterData[pokemon.species.getRootSpeciesId()].classicWinCount > 0 &&
- globalScene.gameData.starterData[pokemon.species.getRootSpeciesId(true)].classicWinCount > 0
+ globalScene.gameMode.isClassic
+ && globalScene.gameData.starterData[pokemon.species.getRootSpeciesId()].classicWinCount > 0
+ && globalScene.gameData.starterData[pokemon.species.getRootSpeciesId(true)].classicWinCount > 0
) {
// move the ribbon to the left if there is no owned icon
const championRibbonX = this.ownedIcon.visible ? 8 : 0;
@@ -189,6 +190,9 @@ export class EnemyBattleInfo extends BattleInfo {
this.hpBar.x += 38 * (boss ? -1 : 1);
this.hpBar.y += 2 * (this.boss ? -1 : 1);
this.hpBar.setTexture(`overlay_hp${boss ? "_boss" : ""}`);
+ this.hpLabel.x += 38 * (boss ? -1 : 1);
+ this.hpLabel.y += 1 * (this.boss ? -1 : 1);
+ this.hpLabel.setTexture(getLocalizedSpriteKey(`overlay_hp_label${boss ? "_boss" : ""}`));
this.levelContainer.x += 2 * (boss ? -1 : 1);
this.box.setTexture(this.getTextureName());
this.statsBox.setTexture(`${this.getTextureName()}_stats`);
@@ -199,7 +203,7 @@ export class EnemyBattleInfo extends BattleInfo {
}
updateBossSegmentDividers(pokemon: EnemyPokemon): void {
- while (this.hpBarSegmentDividers.length) {
+ while (this.hpBarSegmentDividers.length > 0) {
this.hpBarSegmentDividers.pop()?.destroy();
}
diff --git a/src/ui/battle-info/player-battle-info.ts b/src/ui/battle-info/player-battle-info.ts
index f0b50748154..ec6332c54f3 100644
--- a/src/ui/battle-info/player-battle-info.ts
+++ b/src/ui/battle-info/player-battle-info.ts
@@ -5,10 +5,12 @@ import { Stat } from "#enums/stat";
import type { PlayerPokemon } from "#field/pokemon";
import type { BattleInfoParamList } from "#ui/battle-info";
import { BattleInfo } from "#ui/battle-info";
+import { getLocalizedSpriteKey } from "#utils/common";
export class PlayerBattleInfo extends BattleInfo {
protected player: true = true;
protected hpNumbersContainer: Phaser.GameObjects.Container;
+ protected expBarLabel: Phaser.GameObjects.Image;
override get statOrder(): Stat[] {
return [Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.ACC, Stat.EVA, Stat.SPD];
@@ -46,6 +48,12 @@ export class PlayerBattleInfo extends BattleInfo {
// hp number container must be beneath the stat container for overlay to display properly
this.addAt(this.hpNumbersContainer, this.getIndex(this.statsContainer));
+ const expBarLabel = globalScene.add
+ .image(-91, 20, getLocalizedSpriteKey("overlay_exp_label"))
+ .setName("overlay_exp_label")
+ .setOrigin(1, 1);
+ this.add(expBarLabel);
+
const expBar = globalScene.add.image(-98, 18, "overlay_exp").setName("overlay_exp").setOrigin(0);
this.add(expBar);
@@ -60,6 +68,7 @@ export class PlayerBattleInfo extends BattleInfo {
expBar.setMask(expMask);
+ this.expBarLabel = expBarLabel;
this.expBar = expBar;
this.expMaskRect = expMaskRect;
}
@@ -108,7 +117,7 @@ export class PlayerBattleInfo extends BattleInfo {
this.statValuesContainer.x += 2 * (mini ? 1 : -1);
this.statValuesContainer.y += -7 * (mini ? 1 : -1);
- const toggledElements = [this.hpNumbersContainer, this.expBar];
+ const toggledElements = [this.hpNumbersContainer, this.expBarLabel, this.expBar];
toggledElements.forEach(el => el.setVisible(!mini));
}
@@ -138,10 +147,10 @@ export class PlayerBattleInfo extends BattleInfo {
);
let duration =
this.visible && !instant
- ? ((levelExp - this.lastLevelExp) / relLevelExp) *
- BattleInfo.EXP_GAINS_DURATION_BASE *
- durationMultiplier *
- levelDurationMultiplier
+ ? ((levelExp - this.lastLevelExp) / relLevelExp)
+ * BattleInfo.EXP_GAINS_DURATION_BASE
+ * durationMultiplier
+ * levelDurationMultiplier
: 0;
const speed = globalScene.expGainsSpeed;
if (speed && speed >= ExpGainsSpeed.DEFAULT) {
@@ -162,7 +171,7 @@ export class PlayerBattleInfo extends BattleInfo {
targets: this.expMaskRect,
ease: "Sine.easeIn",
x: ratio * 510,
- duration: duration,
+ duration,
onComplete: () => {
if (!globalScene) {
return resolve();
diff --git a/src/ui/ability-bar.ts b/src/ui/containers/ability-bar.ts
similarity index 96%
rename from src/ui/ability-bar.ts
rename to src/ui/containers/ability-bar.ts
index 4b868d4e66c..2495bf190a5 100644
--- a/src/ui/ability-bar.ts
+++ b/src/ui/containers/ability-bar.ts
@@ -67,7 +67,7 @@ export class AbilityBar extends Phaser.GameObjects.Container {
}
public async showAbility(pokemonName: string, abilityName: string, passive = false, player = true): Promise {
- const text = `${i18next.t("fightUiHandler:abilityFlyInText", { pokemonName: pokemonName, passive: passive ? i18next.t("fightUiHandler:passive") : "", abilityName: abilityName })}`;
+ const text = `${i18next.t("fightUiHandler:abilityFlyInText", { pokemonName, passive: passive ? i18next.t("fightUiHandler:passive") : "", abilityName })}`;
this.screenRight = globalScene.scaledCanvas.width;
if (player !== this.player) {
// Move the bar if it has changed from the player to enemy side (or vice versa)
diff --git a/src/ui/achv-bar.ts b/src/ui/containers/achv-bar.ts
similarity index 99%
rename from src/ui/achv-bar.ts
rename to src/ui/containers/achv-bar.ts
index 0f71bcbfde0..5a3e16d6088 100644
--- a/src/ui/achv-bar.ts
+++ b/src/ui/containers/achv-bar.ts
@@ -142,7 +142,7 @@ export class AchvBar extends Phaser.GameObjects.Container {
onComplete: () => {
this.shown = false;
this.setVisible(false);
- if (this.queue.length) {
+ if (this.queue.length > 0) {
const shifted = this.queue.shift();
shifted && this.showAchv(shifted);
}
diff --git a/src/ui/arena-flyout.ts b/src/ui/containers/arena-flyout.ts
similarity index 98%
rename from src/ui/arena-flyout.ts
rename to src/ui/containers/arena-flyout.ts
index da062f5c96f..3555694760d 100644
--- a/src/ui/arena-flyout.ts
+++ b/src/ui/containers/arena-flyout.ts
@@ -15,8 +15,8 @@ import {
} from "#events/arena";
import type { TurnEndEvent } from "#events/battle-scene";
import { BattleSceneEventType } from "#events/battle-scene";
+import { TimeOfDayWidget } from "#ui/containers/time-of-day-widget";
import { addTextObject } from "#ui/text";
-import { TimeOfDayWidget } from "#ui/time-of-day-widget";
import { addWindow, WindowVariant } from "#ui/ui-theme";
import { fixedInt } from "#utils/common";
import { toCamelCase, toTitleCase } from "#utils/strings";
@@ -241,9 +241,7 @@ export class ArenaFlyout extends Phaser.GameObjects.Container {
this.fieldEffectInfo.sort((infoA, infoB) => infoA.duration - infoB.duration);
- for (let i = 0; i < this.fieldEffectInfo.length; i++) {
- const fieldEffectInfo = this.fieldEffectInfo[i];
-
+ for (const fieldEffectInfo of this.fieldEffectInfo) {
// Creates a proxy object to decide which text object needs to be updated
let textObject: Phaser.GameObjects.Text;
switch (fieldEffectInfo.effectType) {
@@ -389,9 +387,7 @@ export class ArenaFlyout extends Phaser.GameObjects.Container {
const fieldEffectInfo: ArenaEffectInfo[] = [];
this.fieldEffectInfo.forEach(i => fieldEffectInfo.push(i));
- for (let i = 0; i < fieldEffectInfo.length; i++) {
- const info = fieldEffectInfo[i];
-
+ for (const info of fieldEffectInfo) {
if (info.maxDuration === 0) {
continue;
}
diff --git a/src/ui/base-stats-overlay.ts b/src/ui/containers/base-stats-overlay.ts
similarity index 96%
rename from src/ui/base-stats-overlay.ts
rename to src/ui/containers/base-stats-overlay.ts
index b3cccf34298..9ddc8533feb 100644
--- a/src/ui/base-stats-overlay.ts
+++ b/src/ui/containers/base-stats-overlay.ts
@@ -70,7 +70,7 @@ export class BaseStatsOverlay extends Phaser.GameObjects.Container implements In
show(values: number[], total: number): boolean {
for (let i = 0; i < 6; i++) {
this.statsLabels[i].setText(
- i18next.t(`pokemonInfo:stat.${toCamelCase(shortStats[i])}Shortened`) + ": " + `${values[i]}`,
+ i18next.t(`pokemonInfo:stat.${toCamelCase(shortStats[i])}Shortened`) + `: ${values[i]}`,
);
// This accounts for base stats up to 200, might not be enough.
// TODO: change color based on value.
@@ -78,7 +78,7 @@ export class BaseStatsOverlay extends Phaser.GameObjects.Container implements In
this.statsRectangles[i].setSize(values[i] / 2, 5);
}
- this.statsTotalLabel.setText(i18next.t("pokedexUiHandler:baseTotal") + ": " + `${total}`);
+ this.statsTotalLabel.setText(`${i18next.t("pokedexUiHandler:baseTotal")}: ${total}`);
this.setVisible(true);
this.active = true;
diff --git a/src/ui/battle-flyout.ts b/src/ui/containers/battle-flyout.ts
similarity index 97%
rename from src/ui/battle-flyout.ts
rename to src/ui/containers/battle-flyout.ts
index 0a67dc9ad37..c0c118b8560 100644
--- a/src/ui/battle-flyout.ts
+++ b/src/ui/containers/battle-flyout.ts
@@ -177,9 +177,9 @@ export class BattleFlyout extends Phaser.GameObjects.Container {
private onBerryUsed(event: Event) {
const berryUsedEvent = event as BerryUsedEvent;
if (
- !berryUsedEvent ||
- berryUsedEvent.berryModifier.pokemonId !== this.pokemon?.id ||
- berryUsedEvent.berryModifier.berryType !== BerryType.LEPPA
+ !berryUsedEvent
+ || berryUsedEvent.berryModifier.pokemonId !== this.pokemon?.id
+ || berryUsedEvent.berryModifier.berryType !== BerryType.LEPPA
) {
// We only care about Leppa berries
return;
diff --git a/src/ui/bgm-bar.ts b/src/ui/containers/bgm-bar.ts
similarity index 100%
rename from src/ui/bgm-bar.ts
rename to src/ui/containers/bgm-bar.ts
diff --git a/src/ui/candy-bar.ts b/src/ui/containers/candy-bar.ts
similarity index 100%
rename from src/ui/candy-bar.ts
rename to src/ui/containers/candy-bar.ts
diff --git a/src/ui/char-sprite.ts b/src/ui/containers/char-sprite.ts
similarity index 100%
rename from src/ui/char-sprite.ts
rename to src/ui/containers/char-sprite.ts
diff --git a/src/ui/daily-run-scoreboard.ts b/src/ui/containers/daily-run-scoreboard.ts
similarity index 100%
rename from src/ui/daily-run-scoreboard.ts
rename to src/ui/containers/daily-run-scoreboard.ts
diff --git a/src/ui/dropdown.ts b/src/ui/containers/dropdown.ts
similarity index 96%
rename from src/ui/dropdown.ts
rename to src/ui/containers/dropdown.ts
index c13d1ab6482..bf589085d2e 100644
--- a/src/ui/dropdown.ts
+++ b/src/ui/containers/dropdown.ts
@@ -1,6 +1,6 @@
import { globalScene } from "#app/global-scene";
import { TextStyle } from "#enums/text-style";
-import { ScrollBar } from "#ui/scroll-bar";
+import { ScrollBar } from "#ui/containers/scroll-bar";
import { addTextObject } from "#ui/text";
import { addWindow, WindowVariant } from "#ui/ui-theme";
import i18next from "i18next";
@@ -504,13 +504,11 @@ export class DropDown extends Phaser.GameObjects.Container {
if (index === 0) {
// we are on the All option > put all other options to the newState
this.setAllOptions(newState);
- } else {
+ } else if (newState === DropDownState.ON && this.checkForAllOn()) {
// select the "all" option if all others are selected, other unselect it
- if (newState === DropDownState.ON && this.checkForAllOn()) {
- this.options[0].setOptionState(DropDownState.ON);
- } else {
- this.options[0].setOptionState(DropDownState.OFF);
- }
+ this.options[0].setOptionState(DropDownState.ON);
+ } else {
+ this.options[0].setOptionState(DropDownState.OFF);
}
} else if (this.dropDownType === DropDownType.SINGLE) {
if (option.state === DropDownState.OFF) {
@@ -612,8 +610,8 @@ export class DropDown extends Phaser.GameObjects.Container {
const compareValues = (keys: string[]): boolean => {
return (
- currentValues.length === this.defaultSettings.length &&
- currentValues.every((value, index) => keys.every(key => value[key] === this.defaultSettings[index][key]))
+ currentValues.length === this.defaultSettings.length
+ && currentValues.every((value, index) => keys.every(key => value[key] === this.defaultSettings[index][key]))
);
};
@@ -653,10 +651,8 @@ export class DropDown extends Phaser.GameObjects.Container {
this.options[i].setDirection(SortDirection.ASC);
this.options[i].toggle.setVisible(true);
}
- } else {
- if (this.defaultSettings[i]) {
- this.options[i].setOptionState(this.defaultSettings[i]["state"]);
- }
+ } else if (this.defaultSettings[i]) {
+ this.options[i].setOptionState(this.defaultSettings[i]["state"]);
}
}
@@ -699,11 +695,11 @@ export class DropDown extends Phaser.GameObjects.Container {
autoSize(): void {
let maxWidth = 0;
let x = 0;
- for (let i = 0; i < this.options.length; i++) {
- const optionWidth = this.options[i].getWidth();
+ for (const option of this.options) {
+ const optionWidth = option.getWidth();
if (optionWidth > maxWidth) {
maxWidth = optionWidth;
- x = this.options[i].getCurrentLabelX() ?? 0;
+ x = option.getCurrentLabelX() ?? 0;
}
}
this.window.width = maxWidth + x - this.window.x + 9;
diff --git a/src/ui/egg-counter-container.ts b/src/ui/containers/egg-counter-container.ts
similarity index 96%
rename from src/ui/egg-counter-container.ts
rename to src/ui/containers/egg-counter-container.ts
index da394e73b28..811b6b3bc3a 100644
--- a/src/ui/egg-counter-container.ts
+++ b/src/ui/containers/egg-counter-container.ts
@@ -2,7 +2,7 @@ import { globalScene } from "#app/global-scene";
import { TextStyle } from "#enums/text-style";
import type { EggCountChangedEvent } from "#events/egg";
import { EggEventType } from "#events/egg";
-import type { EggHatchSceneHandler } from "#ui/egg-hatch-scene-handler";
+import type { EggHatchSceneHandler } from "#ui/handlers/egg-hatch-scene-handler";
import { addTextObject } from "#ui/text";
import { addWindow } from "#ui/ui-theme";
diff --git a/src/ui/filter-bar.ts b/src/ui/containers/filter-bar.ts
similarity index 91%
rename from src/ui/filter-bar.ts
rename to src/ui/containers/filter-bar.ts
index f33c2902295..bbca38c3f53 100644
--- a/src/ui/filter-bar.ts
+++ b/src/ui/containers/filter-bar.ts
@@ -2,9 +2,9 @@ import { globalScene } from "#app/global-scene";
import type { DropDownColumn } from "#enums/drop-down-column";
import { TextStyle } from "#enums/text-style";
import type { UiTheme } from "#enums/ui-theme";
-import type { DropDown } from "#ui/dropdown";
-import { DropDownType } from "#ui/dropdown";
-import type { StarterContainer } from "#ui/starter-container";
+import type { DropDown } from "#ui/containers/dropdown";
+import { DropDownType } from "#ui/containers/dropdown";
+import type { StarterContainer } from "#ui/containers/starter-container";
import { addTextObject, getTextColor } from "#ui/text";
import { addWindow, WindowVariant } from "#ui/ui-theme";
@@ -130,22 +130,20 @@ export class FilterBar extends Phaser.GameObjects.Container {
* Move the leftmost dropdown to the left of the FilterBar instead of below it
*/
offsetHybridFilters(): void {
- for (let i = 0; i < this.dropDowns.length; i++) {
- if (this.dropDowns[i].dropDownType === DropDownType.HYBRID) {
- this.dropDowns[i].autoSize();
- this.dropDowns[i].x = -this.dropDowns[i].getWidth();
- this.dropDowns[i].y = 0;
+ for (const dropDown of this.dropDowns) {
+ if (dropDown.dropDownType === DropDownType.HYBRID) {
+ dropDown.autoSize();
+ dropDown.x = -dropDown.getWidth();
+ dropDown.y = 0;
}
}
}
setCursor(cursor: number): void {
- if (this.lastCursor > -1) {
- if (this.dropDowns[this.lastCursor].visible) {
- this.dropDowns[this.lastCursor].setVisible(false);
- this.dropDowns[cursor].setVisible(true);
- this.dropDowns[cursor].resetCursor();
- }
+ if (this.lastCursor > -1 && this.dropDowns[this.lastCursor].visible) {
+ this.dropDowns[this.lastCursor].setVisible(false);
+ this.dropDowns[cursor].setVisible(true);
+ this.dropDowns[cursor].resetCursor();
}
this.cursorObj.setPosition(this.labels[cursor].x - this.cursorOffset + 2, 6);
diff --git a/src/ui/filter-text.ts b/src/ui/containers/filter-text.ts
similarity index 96%
rename from src/ui/filter-text.ts
rename to src/ui/containers/filter-text.ts
index c9849469d5d..0d15aca8530 100644
--- a/src/ui/filter-text.ts
+++ b/src/ui/containers/filter-text.ts
@@ -2,8 +2,8 @@ import { globalScene } from "#app/global-scene";
import { TextStyle } from "#enums/text-style";
import { UiMode } from "#enums/ui-mode";
import type { UiTheme } from "#enums/ui-theme";
-import type { AwaitableUiHandler } from "#ui/awaitable-ui-handler";
-import type { StarterContainer } from "#ui/starter-container";
+import type { StarterContainer } from "#ui/containers/starter-container";
+import type { AwaitableUiHandler } from "#ui/handlers/awaitable-ui-handler";
import { addTextObject, getTextColor } from "#ui/text";
import type { UI } from "#ui/ui";
import { addWindow, WindowVariant } from "#ui/ui-theme";
@@ -24,14 +24,12 @@ export class FilterText extends Phaser.GameObjects.Container {
private rows: FilterTextRow[] = [];
public cursorObj: Phaser.GameObjects.Image;
public numFilters = 0;
- private lastCursor = -1;
private uiTheme: UiTheme;
private menuMessageBoxContainer: Phaser.GameObjects.Container;
private dialogueMessageBox: Phaser.GameObjects.NineSlice;
message: any;
private readonly textPadding = 8;
- private readonly defaultWordWrapWidth = 1224;
private onChange: () => void;
@@ -158,7 +156,6 @@ export class FilterText extends Phaser.GameObjects.Container {
const cursorOffset = 8;
this.cursorObj.setPosition(cursorOffset, this.labels[cursor].y + 3);
- this.lastCursor = cursor;
}
/**
diff --git a/src/ui/hatched-pokemon-container.ts b/src/ui/containers/hatched-pokemon-container.ts
similarity index 97%
rename from src/ui/hatched-pokemon-container.ts
rename to src/ui/containers/hatched-pokemon-container.ts
index a5919348a94..4ed67477a3f 100644
--- a/src/ui/hatched-pokemon-container.ts
+++ b/src/ui/containers/hatched-pokemon-container.ts
@@ -4,8 +4,8 @@ import { Gender } from "#data/gender";
import type { PokemonSpecies } from "#data/pokemon-species";
import { DexAttr } from "#enums/dex-attr";
import { getVariantTint } from "#sprites/variant";
-import type { PokemonIconAnimHandler } from "#ui/pokemon-icon-anim-handler";
-import { PokemonIconAnimMode } from "#ui/pokemon-icon-anim-handler";
+import type { PokemonIconAnimHandler } from "#ui/handlers/pokemon-icon-anim-handler";
+import { PokemonIconAnimMode } from "#ui/handlers/pokemon-icon-anim-handler";
/**
* A container for a Pokemon's sprite and icons to get displayed in the egg summary screen
diff --git a/src/ui/move-info-overlay.ts b/src/ui/containers/move-info-overlay.ts
similarity index 99%
rename from src/ui/move-info-overlay.ts
rename to src/ui/containers/move-info-overlay.ts
index f98630260db..b321fcfc041 100644
--- a/src/ui/move-info-overlay.ts
+++ b/src/ui/containers/move-info-overlay.ts
@@ -41,8 +41,6 @@ const GLOBAL_SCALE = 6;
export class MoveInfoOverlay extends Phaser.GameObjects.Container implements InfoToggle {
public active = false;
- private move: Move;
-
private desc: Phaser.GameObjects.Text;
private descScroll: Phaser.Tweens.Tween | null = null;
@@ -177,7 +175,6 @@ export class MoveInfoOverlay extends Phaser.GameObjects.Container implements Inf
if (!globalScene.enableMoveInfo) {
return false; // move infos have been disabled // TODO:: is `false` correct? i used to be `undeefined`
}
- this.move = move;
this.pow.setText(move.power >= 0 ? move.power.toString() : "---");
this.acc.setText(move.accuracy >= 0 ? move.accuracy.toString() : "---");
this.pp.setText(move.pp >= 0 ? move.pp.toString() : "---");
diff --git a/src/ui/party-exp-bar.ts b/src/ui/containers/party-exp-bar.ts
similarity index 100%
rename from src/ui/party-exp-bar.ts
rename to src/ui/containers/party-exp-bar.ts
diff --git a/src/ui/pokeball-tray.ts b/src/ui/containers/pokeball-tray.ts
similarity index 95%
rename from src/ui/pokeball-tray.ts
rename to src/ui/containers/pokeball-tray.ts
index b1522af0e27..1a89e22f294 100644
--- a/src/ui/pokeball-tray.ts
+++ b/src/ui/containers/pokeball-tray.ts
@@ -35,9 +35,9 @@ export class PokeballTray extends Phaser.GameObjects.Container {
.fill(null)
.map((_, i) =>
globalScene.add.sprite(
- (this.player ? -83 : 76) +
- globalScene.scaledCanvas.width * (this.player ? -1 : 1) +
- 10 * i * (this.player ? 1 : -1),
+ (this.player ? -83 : 76)
+ + globalScene.scaledCanvas.width * (this.player ? -1 : 1)
+ + 10 * i * (this.player ? 1 : -1),
-8,
"pb_tray_ball",
"empty",
diff --git a/src/ui/pokedex-info-overlay.ts b/src/ui/containers/pokedex-info-overlay.ts
similarity index 100%
rename from src/ui/pokedex-info-overlay.ts
rename to src/ui/containers/pokedex-info-overlay.ts
diff --git a/src/ui/pokedex-mon-container.ts b/src/ui/containers/pokedex-mon-container.ts
similarity index 100%
rename from src/ui/pokedex-mon-container.ts
rename to src/ui/containers/pokedex-mon-container.ts
diff --git a/src/ui/pokedex-page-ui-handler.ts b/src/ui/containers/pokedex-page-ui-handler.ts
similarity index 95%
rename from src/ui/pokedex-page-ui-handler.ts
rename to src/ui/containers/pokedex-page-ui-handler.ts
index 672968bd953..ef1c1a6896c 100644
--- a/src/ui/pokedex-page-ui-handler.ts
+++ b/src/ui/containers/pokedex-page-ui-handler.ts
@@ -46,12 +46,12 @@ import { getVariantIcon, getVariantTint } from "#sprites/variant";
import type { StarterAttributes } from "#system/game-data";
import { SettingKeyboard } from "#system/settings-keyboard";
import type { DexEntry } from "#types/dex-data";
-import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
-import { BaseStatsOverlay } from "#ui/base-stats-overlay";
-import { MessageUiHandler } from "#ui/message-ui-handler";
-import { MoveInfoOverlay } from "#ui/move-info-overlay";
-import { PokedexInfoOverlay } from "#ui/pokedex-info-overlay";
-import { StatsContainer } from "#ui/stats-container";
+import { BaseStatsOverlay } from "#ui/containers/base-stats-overlay";
+import { MoveInfoOverlay } from "#ui/containers/move-info-overlay";
+import { PokedexInfoOverlay } from "#ui/containers/pokedex-info-overlay";
+import { StatsContainer } from "#ui/containers/stats-container";
+import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler";
+import { MessageUiHandler } from "#ui/handlers/message-ui-handler";
import { addBBCodeTextObject, addTextObject, getTextColor, getTextStyleOptions } from "#ui/text";
import { addWindow } from "#ui/ui-theme";
import { BooleanHolder, getLocalizedSpriteKey, isNullOrUndefined, padInt, rgbHexToRgba } from "#utils/common";
@@ -260,8 +260,6 @@ export class PokedexPageUiHandler extends MessageUiHandler {
private instructionRowX = 0;
private instructionRowY = 0;
private instructionRowTextOffset = 9;
- private filterInstructionRowX = 0;
- private filterInstructionRowY = 0;
private starterAttributes: StarterAttributes;
private savedStarterAttributes: StarterAttributes;
@@ -713,7 +711,7 @@ export class PokedexPageUiHandler extends MessageUiHandler {
globalScene.phaseManager.getCurrentPhase().phaseName,
);
- if (args.length >= 1 && args[0] === "refresh") {
+ if (args.length > 0 && args[0] === "refresh") {
return false;
}
this.species = args[0];
@@ -764,9 +762,9 @@ export class PokedexPageUiHandler extends MessageUiHandler {
.map(o => {
const label = i18next.t(`pokedexUiHandler:${toCamelCase(`menu${MenuOptions[o]}`)}`);
const isDark =
- !isSeen ||
- (!isStarterCaught && (o === MenuOptions.TOGGLE_IVS || o === MenuOptions.NATURES)) ||
- (this.tmMoves.length < 1 && o === MenuOptions.TM_MOVES);
+ !isSeen
+ || (!isStarterCaught && (o === MenuOptions.TOGGLE_IVS || o === MenuOptions.NATURES))
+ || (this.tmMoves.length === 0 && o === MenuOptions.TM_MOVES);
const color = getTextColor(isDark ? TextStyle.SHADOW_TEXT : TextStyle.SETTINGS_VALUE, false);
const shadow = getTextColor(isDark ? TextStyle.SHADOW_TEXT : TextStyle.SETTINGS_VALUE, true);
return `[shadow=${shadow}][color=${color}]${label}[/color][/shadow]`;
@@ -784,9 +782,9 @@ export class PokedexPageUiHandler extends MessageUiHandler {
let formKey = this.species?.forms.length > 0 ? this.species.forms[this.formIndex].formKey : "";
this.isFormGender = formKey === "male" || formKey === "female";
if (
- this.isFormGender &&
- ((this.savedStarterAttributes.female === true && formKey === "male") ||
- (this.savedStarterAttributes.female === false && formKey === "female"))
+ this.isFormGender
+ && ((this.savedStarterAttributes.female === true && formKey === "male")
+ || (this.savedStarterAttributes.female === false && formKey === "female"))
) {
this.formIndex = (this.formIndex + 1) % 2;
formKey = this.species.forms[this.formIndex].formKey;
@@ -805,9 +803,9 @@ export class PokedexPageUiHandler extends MessageUiHandler {
// If this form has a specific set of moves, we get them.
this.levelMoves =
- formIndex > 0 &&
- pokemonFormLevelMoves.hasOwnProperty(species.speciesId) &&
- pokemonFormLevelMoves[species.speciesId].hasOwnProperty(formIndex)
+ formIndex > 0
+ && pokemonFormLevelMoves.hasOwnProperty(species.speciesId)
+ && pokemonFormLevelMoves[species.speciesId].hasOwnProperty(formIndex)
? pokemonFormLevelMoves[species.speciesId][formIndex]
: pokemonSpeciesLevelMoves[species.speciesId];
this.ability1 = form.ability1;
@@ -881,17 +879,13 @@ export class PokedexPageUiHandler extends MessageUiHandler {
: [];
this.prevolutions = preEvolutions.filter(
e =>
- e.speciesId === species.speciesId &&
- (((e.evoFormKey === "" || e.evoFormKey === null) &&
- // This takes care of Cosplay Pikachu (Pichu is not shown)
- (preSpecies.forms.some(form => form.formKey === species.forms[formIndex]?.formKey) ||
- // This takes care of Gholdengo
- (preSpecies.forms.length > 0 && species.forms.length === 0) ||
- // This takes care of everything else
- (preSpecies.forms.length === 0 &&
- (species.forms.length === 0 || species.forms[formIndex]?.formKey === "")))) ||
- // This takes care of Burmy, Shellos etc
- e.evoFormKey === species.forms[formIndex]?.formKey),
+ e.speciesId === species.speciesId
+ && (((e.evoFormKey === "" || e.evoFormKey === null) // This takes care of Cosplay Pikachu (Pichu is not shown)
+ && (preSpecies.forms.some(form => form.formKey === species.forms[formIndex]?.formKey) // This takes care of Gholdengo
+ || (preSpecies.forms.length > 0 && species.forms.length === 0) // This takes care of everything else
+ || (preSpecies.forms.length === 0
+ && (species.forms.length === 0 || species.forms[formIndex]?.formKey === "")))) // This takes care of Burmy, Shellos etc
+ || e.evoFormKey === species.forms[formIndex]?.formKey),
);
}
@@ -992,7 +986,7 @@ export class PokedexPageUiHandler extends MessageUiHandler {
const formIndex = otherFormIndex !== undefined ? otherFormIndex : this.formIndex;
const caughtAttr = this.isCaught(species);
- if (caughtAttr && (!species.forms.length || species.forms.length === 1)) {
+ if (caughtAttr && (species.forms.length === 0 || species.forms.length === 1)) {
return true;
}
@@ -1043,9 +1037,9 @@ export class PokedexPageUiHandler extends MessageUiHandler {
!!(hasShiny && caughtAttr & DexAttr.VARIANT_3),
];
if (
- starterAttributes.variant === undefined ||
- Number.isNaN(starterAttributes.variant) ||
- starterAttributes.variant < 0
+ starterAttributes.variant === undefined
+ || Number.isNaN(starterAttributes.variant)
+ || starterAttributes.variant < 0
) {
starterAttributes.variant = 0;
} else if (!this.unlockedVariants[starterAttributes.variant]) {
@@ -1061,17 +1055,15 @@ export class PokedexPageUiHandler extends MessageUiHandler {
if (starterAttributes.female !== undefined) {
if (
- (starterAttributes.female && !(caughtAttr & DexAttr.FEMALE)) ||
- (!starterAttributes.female && !(caughtAttr & DexAttr.MALE))
+ (starterAttributes.female && !(caughtAttr & DexAttr.FEMALE))
+ || (!starterAttributes.female && !(caughtAttr & DexAttr.MALE))
) {
starterAttributes.female = !starterAttributes.female;
}
- } else {
- if (caughtAttr & DexAttr.FEMALE) {
- starterAttributes.female = true;
- } else if (caughtAttr & DexAttr.MALE) {
- starterAttributes.female = false;
- }
+ } else if (caughtAttr & DexAttr.FEMALE) {
+ starterAttributes.female = true;
+ } else if (caughtAttr & DexAttr.MALE) {
+ starterAttributes.female = false;
}
return starterAttributes;
@@ -1102,7 +1094,7 @@ export class PokedexPageUiHandler extends MessageUiHandler {
this.message.setY(singleLine ? -22 : -37);
}
- this.starterSelectMessageBoxContainer.setVisible(!!text?.length);
+ this.starterSelectMessageBoxContainer.setVisible(text?.length > 0);
}
/**
@@ -1358,7 +1350,7 @@ export class PokedexPageUiHandler extends MessageUiHandler {
case MenuOptions.TM_MOVES:
if (!isSeen) {
error = true;
- } else if (this.tmMoves.length < 1) {
+ } else if (this.tmMoves.length === 0) {
ui.showText(i18next.t("pokedexUiHandler:noTmMoves"));
error = true;
} else {
@@ -1481,7 +1473,7 @@ export class PokedexPageUiHandler extends MessageUiHandler {
});
ui.setModeWithoutClear(UiMode.OPTION_SELECT, {
- options: options,
+ options,
supportHover: true,
maxOptions: 8,
yOffset: 19,
@@ -1514,14 +1506,14 @@ export class PokedexPageUiHandler extends MessageUiHandler {
this.biomes.map(b => {
options.push({
label:
- i18next.t(`biome:${toCamelCase(BiomeId[b.biome])}`) +
- " - " +
- i18next.t(`biome:${toCamelCase(BiomePoolTier[b.tier])}`) +
- (b.tod.length === 1 && b.tod[0] === -1
+ i18next.t(`biome:${toCamelCase(BiomeId[b.biome])}`)
+ + " - "
+ + i18next.t(`biome:${toCamelCase(BiomePoolTier[b.tier])}`)
+ + (b.tod.length === 1 && b.tod[0] === -1
? ""
- : " (" +
- b.tod.map(tod => i18next.t(`biome:${toCamelCase(TimeOfDay[tod])}`)).join(", ") +
- ")"),
+ : " ("
+ + b.tod.map(tod => i18next.t(`biome:${toCamelCase(TimeOfDay[tod])}`)).join(", ")
+ + ")"),
handler: () => false,
});
});
@@ -1535,14 +1527,14 @@ export class PokedexPageUiHandler extends MessageUiHandler {
this.preBiomes.map(b => {
options.push({
label:
- i18next.t(`biome:${toCamelCase(BiomeId[b.biome])}`) +
- " - " +
- i18next.t(`biome:${toCamelCase(BiomePoolTier[b.tier])}`) +
- (b.tod.length === 1 && b.tod[0] === -1
+ i18next.t(`biome:${toCamelCase(BiomeId[b.biome])}`)
+ + " - "
+ + i18next.t(`biome:${toCamelCase(BiomePoolTier[b.tier])}`)
+ + (b.tod.length === 1 && b.tod[0] === -1
? ""
- : " (" +
- b.tod.map(tod => i18next.t(`biome:${toCamelCase(TimeOfDay[tod])}`)).join(", ") +
- ")"),
+ : " ("
+ + b.tod.map(tod => i18next.t(`biome:${toCamelCase(TimeOfDay[tod])}`)).join(", ")
+ + ")"),
handler: () => false,
});
});
@@ -1560,7 +1552,7 @@ export class PokedexPageUiHandler extends MessageUiHandler {
});
ui.setModeWithoutClear(UiMode.OPTION_SELECT, {
- options: options,
+ options,
supportHover: true,
maxOptions: 8,
yOffset: 19,
@@ -1583,9 +1575,9 @@ export class PokedexPageUiHandler extends MessageUiHandler {
const options: any[] = [];
if (
- (!this.prevolutions || this.prevolutions?.length === 0) &&
- (!this.evolutions || this.evolutions?.length === 0) &&
- (!this.battleForms || this.battleForms?.length === 0)
+ (!this.prevolutions || this.prevolutions?.length === 0)
+ && (!this.evolutions || this.evolutions?.length === 0)
+ && (!this.battleForms || this.battleForms?.length === 0)
) {
ui.showText(i18next.t("pokedexUiHandler:noEvolutions"));
ui.playError();
@@ -1707,7 +1699,7 @@ export class PokedexPageUiHandler extends MessageUiHandler {
if (conditionText) {
options.push({
- label: label,
+ label,
style: isFormCaught ? TextStyle.WINDOW : TextStyle.SHADOW_TEXT,
handler: () => {
this.previousSpecies.push(this.species);
@@ -1744,7 +1736,7 @@ export class PokedexPageUiHandler extends MessageUiHandler {
});
ui.setModeWithoutClear(UiMode.OPTION_SELECT, {
- options: options,
+ options,
supportHover: true,
maxOptions: 8,
yOffset: 19,
@@ -1838,10 +1830,8 @@ export class PokedexPageUiHandler extends MessageUiHandler {
if (this.isCaught() & DexAttr.VARIANT_2) {
break;
}
- } else {
- if (this.isCaught() & DexAttr.VARIANT_3) {
- break;
- }
+ } else if (this.isCaught() & DexAttr.VARIANT_3) {
+ break;
}
} while (newVariant !== props.variant);
@@ -2040,7 +2030,7 @@ export class PokedexPageUiHandler extends MessageUiHandler {
},
});
ui.setModeWithoutClear(UiMode.OPTION_SELECT, {
- options: options,
+ options,
yOffset: 47,
});
success = true;
@@ -2203,8 +2193,6 @@ export class PokedexPageUiHandler extends MessageUiHandler {
updateInstructions(): void {
this.instructionRowX = 0;
this.instructionRowY = 0;
- this.filterInstructionRowX = 0;
- this.filterInstructionRowY = 0;
this.hideInstructions();
this.instructionsContainer.removeAll();
this.filterInstructionsContainer.removeAll();
@@ -2304,8 +2292,8 @@ export class PokedexPageUiHandler extends MessageUiHandler {
const starterData = globalScene.gameData.starterData[this.starterId];
return (
- starterData.candyCount >= getPassiveCandyCount(speciesStarterCosts[this.starterId]) &&
- !(starterData.passiveAttr & PassiveAttr.UNLOCKED)
+ starterData.candyCount >= getPassiveCandyCount(speciesStarterCosts[this.starterId])
+ && !(starterData.passiveAttr & PassiveAttr.UNLOCKED)
);
}
@@ -2318,9 +2306,9 @@ export class PokedexPageUiHandler extends MessageUiHandler {
const starterData = globalScene.gameData.starterData[this.starterId];
return (
- starterData.candyCount >=
- getValueReductionCandyCounts(speciesStarterCosts[this.starterId])[starterData.valueReduction] &&
- starterData.valueReduction < valueReductionMax
+ starterData.candyCount
+ >= getValueReductionCandyCounts(speciesStarterCosts[this.starterId])[starterData.valueReduction]
+ && starterData.valueReduction < valueReductionMax
);
}
@@ -2361,10 +2349,8 @@ export class PokedexPageUiHandler extends MessageUiHandler {
const defaultDexAttr = this.getCurrentDexProps(species.speciesId);
// Set default attributes if for some reason starterAttributes does not exist or attributes missing
const props: StarterAttributes = globalScene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr);
- if (starterAttributes?.variant && !Number.isNaN(starterAttributes.variant)) {
- if (props.shiny) {
- props.variant = starterAttributes.variant as Variant;
- }
+ if (starterAttributes?.variant && !Number.isNaN(starterAttributes.variant) && props.shiny) {
+ props.variant = starterAttributes.variant as Variant;
}
props.form = starterAttributes?.form ?? props.form;
props.female = starterAttributes?.female ?? props.female;
@@ -2438,11 +2424,11 @@ export class PokedexPageUiHandler extends MessageUiHandler {
// We will only update the sprite if there is a change to form, shiny/variant
// or gender for species with gender sprite differences
const shouldUpdateSprite =
- (species?.genderDiffs && !isNullOrUndefined(female)) ||
- !isNullOrUndefined(formIndex) ||
- !isNullOrUndefined(shiny) ||
- !isNullOrUndefined(variant) ||
- forceUpdate;
+ (species?.genderDiffs && !isNullOrUndefined(female))
+ || !isNullOrUndefined(formIndex)
+ || !isNullOrUndefined(shiny)
+ || !isNullOrUndefined(variant)
+ || forceUpdate;
if (this.activeTooltip === "CANDY") {
if (this.species && this.pokemonCandyContainer.visible) {
@@ -2754,9 +2740,9 @@ export class PokedexPageUiHandler extends MessageUiHandler {
let props = 0n;
const species = allSpecies.find(sp => sp.speciesId === speciesId);
const caughtAttr =
- globalScene.gameData.dexData[speciesId].caughtAttr &
- globalScene.gameData.dexData[this.getStarterSpeciesId(speciesId)].caughtAttr &
- (species?.getFullUnlocksData() ?? 0n);
+ globalScene.gameData.dexData[speciesId].caughtAttr
+ & globalScene.gameData.dexData[this.getStarterSpeciesId(speciesId)].caughtAttr
+ & (species?.getFullUnlocksData() ?? 0n);
/* this checks the gender of the pokemon; this works by checking a) that the starter preferences for the species exist, and if so, is it female. If so, it'll add DexAttr.FEMALE to our temp props
* It then checks b) if the caughtAttr for the pokemon is female and NOT male - this means that the ONLY gender we've gotten is female, and we need to add DexAttr.FEMALE to our temp props
@@ -2771,23 +2757,21 @@ export class PokedexPageUiHandler extends MessageUiHandler {
* If they're not there, it enables shiny state by default if any shiny was caught
*/
if (
- this.starterAttributes?.shiny ||
- ((caughtAttr & DexAttr.SHINY) > 0n && this.starterAttributes?.shiny !== false)
+ this.starterAttributes?.shiny
+ || ((caughtAttr & DexAttr.SHINY) > 0n && this.starterAttributes?.shiny !== false)
) {
props += DexAttr.SHINY;
if (this.starterAttributes?.variant !== undefined) {
props += BigInt(Math.pow(2, this.starterAttributes?.variant)) * DexAttr.DEFAULT_VARIANT;
- } else {
- /* This calculates the correct variant if there's no starter preferences for it.
+ /* This chunk calculates the correct variant if there's no starter preferences for it.
* This gets the highest tier variant that you've caught and adds it to the temp props
*/
- if ((caughtAttr & DexAttr.VARIANT_3) > 0) {
- props += DexAttr.VARIANT_3;
- } else if ((caughtAttr & DexAttr.VARIANT_2) > 0) {
- props += DexAttr.VARIANT_2;
- } else {
- props += DexAttr.DEFAULT_VARIANT;
- }
+ } else if ((caughtAttr & DexAttr.VARIANT_3) > 0) {
+ props += DexAttr.VARIANT_3;
+ } else if ((caughtAttr & DexAttr.VARIANT_2) > 0) {
+ props += DexAttr.VARIANT_2;
+ } else {
+ props += DexAttr.DEFAULT_VARIANT;
}
} else {
props += DexAttr.NON_SHINY;
diff --git a/src/ui/pokemon-hatch-info-container.ts b/src/ui/containers/pokemon-hatch-info-container.ts
similarity index 99%
rename from src/ui/pokemon-hatch-info-container.ts
rename to src/ui/containers/pokemon-hatch-info-container.ts
index bb1cc22e9fd..8ddd9df9836 100644
--- a/src/ui/pokemon-hatch-info-container.ts
+++ b/src/ui/containers/pokemon-hatch-info-container.ts
@@ -9,7 +9,7 @@ import { PokemonType } from "#enums/pokemon-type";
import { SpeciesId } from "#enums/species-id";
import { TextStyle } from "#enums/text-style";
import type { PlayerPokemon } from "#field/pokemon";
-import { PokemonInfoContainer } from "#ui/pokemon-info-container";
+import { PokemonInfoContainer } from "#ui/containers/pokemon-info-container";
import { addTextObject } from "#ui/text";
import { padInt, rgbHexToRgba } from "#utils/common";
import { getPokemonSpeciesForm } from "#utils/pokemon-utils";
diff --git a/src/ui/pokemon-info-container.ts b/src/ui/containers/pokemon-info-container.ts
similarity index 99%
rename from src/ui/pokemon-info-container.ts
rename to src/ui/containers/pokemon-info-container.ts
index d232100ffaa..2b214229992 100644
--- a/src/ui/pokemon-info-container.ts
+++ b/src/ui/containers/pokemon-info-container.ts
@@ -8,8 +8,8 @@ import type { Pokemon } from "#field/pokemon";
import { getVariantTint } from "#sprites/variant";
import type { StarterDataEntry } from "#system/game-data";
import type { DexEntry } from "#types/dex-data";
-import { ConfirmUiHandler } from "#ui/confirm-ui-handler";
-import { StatsContainer } from "#ui/stats-container";
+import { StatsContainer } from "#ui/containers/stats-container";
+import { ConfirmUiHandler } from "#ui/handlers/confirm-ui-handler";
import { addBBCodeTextObject, addTextObject, getTextColor } from "#ui/text";
import { addWindow } from "#ui/ui-theme";
import { fixedInt, getShinyDescriptor } from "#utils/common";
diff --git a/src/ui/saving-icon-handler.ts b/src/ui/containers/saving-icon-handler.ts
similarity index 100%
rename from src/ui/saving-icon-handler.ts
rename to src/ui/containers/saving-icon-handler.ts
diff --git a/src/ui/scroll-bar.ts b/src/ui/containers/scroll-bar.ts
similarity index 100%
rename from src/ui/scroll-bar.ts
rename to src/ui/containers/scroll-bar.ts
diff --git a/src/ui/starter-container.ts b/src/ui/containers/starter-container.ts
similarity index 100%
rename from src/ui/starter-container.ts
rename to src/ui/containers/starter-container.ts
diff --git a/src/ui/stats-container.ts b/src/ui/containers/stats-container.ts
similarity index 97%
rename from src/ui/stats-container.ts
rename to src/ui/containers/stats-container.ts
index f5221d38991..fa53c8c8fd4 100644
--- a/src/ui/stats-container.ts
+++ b/src/ui/containers/stats-container.ts
@@ -82,10 +82,10 @@ export class StatsContainer extends Phaser.GameObjects.Container {
for (const s of PERMANENT_STATS) {
const statLabel = addTextObject(
ivChartBg.x + ivChartSize * ivChartStatCoordMultipliers[s][0] * 1.325 + (this.showDiff ? 0 : ivLabelOffset[s]),
- ivChartBg.y +
- ivChartSize * ivChartStatCoordMultipliers[s][1] * 1.325 -
- 4 +
- (this.showDiff ? 0 : ivChartLabelyOffset[s]),
+ ivChartBg.y
+ + ivChartSize * ivChartStatCoordMultipliers[s][1] * 1.325
+ - 4
+ + (this.showDiff ? 0 : ivChartLabelyOffset[s]),
i18next.t(getStatKey(s)),
TextStyle.STATS_HEXAGON,
);
diff --git a/src/ui/time-of-day-widget.ts b/src/ui/containers/time-of-day-widget.ts
similarity index 100%
rename from src/ui/time-of-day-widget.ts
rename to src/ui/containers/time-of-day-widget.ts
diff --git a/src/ui/settings/abstract-binding-ui-handler.ts b/src/ui/handlers/abstract-binding-ui-handler.ts
similarity index 99%
rename from src/ui/settings/abstract-binding-ui-handler.ts
rename to src/ui/handlers/abstract-binding-ui-handler.ts
index 6b747a10d2b..d106ff6f914 100644
--- a/src/ui/settings/abstract-binding-ui-handler.ts
+++ b/src/ui/handlers/abstract-binding-ui-handler.ts
@@ -2,9 +2,9 @@ import { globalScene } from "#app/global-scene";
import { Button } from "#enums/buttons";
import { TextStyle } from "#enums/text-style";
import type { UiMode } from "#enums/ui-mode";
+import { UiHandler } from "#ui/handlers/ui-handler";
import { NavigationManager } from "#ui/navigation-menu";
import { addTextObject, getTextColor } from "#ui/text";
-import { UiHandler } from "#ui/ui-handler";
import { addWindow } from "#ui/ui-theme";
import i18next from "i18next";
diff --git a/src/ui/abstract-option-select-ui-handler.ts b/src/ui/handlers/abstract-option-select-ui-handler.ts
similarity index 97%
rename from src/ui/abstract-option-select-ui-handler.ts
rename to src/ui/handlers/abstract-option-select-ui-handler.ts
index 914dfca6ef3..1e102010e4a 100644
--- a/src/ui/abstract-option-select-ui-handler.ts
+++ b/src/ui/handlers/abstract-option-select-ui-handler.ts
@@ -2,8 +2,8 @@ import { globalScene } from "#app/global-scene";
import { Button } from "#enums/buttons";
import { TextStyle } from "#enums/text-style";
import { UiMode } from "#enums/ui-mode";
+import { UiHandler } from "#ui/handlers/ui-handler";
import { addBBCodeTextObject, getTextColor, getTextStyleOptions } from "#ui/text";
-import { UiHandler } from "#ui/ui-handler";
import { addWindow } from "#ui/ui-theme";
import { fixedInt, rgbHexToRgba } from "#utils/common";
import { argbFromRgba } from "@material/material-color-utilities";
@@ -105,7 +105,7 @@ export abstract class AbstractOptionSelectUiHandler extends UiHandler {
}
}
- if (this.optionSelectIcons?.length) {
+ if (this.optionSelectIcons?.length > 0) {
this.optionSelectIcons.map(i => i.destroy());
this.optionSelectIcons.splice(0, this.optionSelectIcons.length);
}
@@ -184,7 +184,7 @@ export abstract class AbstractOptionSelectUiHandler extends UiHandler {
}
show(args: any[]): boolean {
- if (!args.length || !args[0].hasOwnProperty("options") || !args[0].options.length) {
+ if (args.length === 0 || !args[0].hasOwnProperty("options") || args[0].options.length === 0) {
return false;
}
@@ -315,8 +315,8 @@ export abstract class AbstractOptionSelectUiHandler extends UiHandler {
const optionStartIndex = this.scrollCursor;
const optionEndIndex = Math.min(
optionsScrollTotal,
- optionStartIndex +
- (!optionStartIndex || this.scrollCursor + (this.config.maxOptions - 1) >= optionsScrollTotal
+ optionStartIndex
+ + (!optionStartIndex || this.scrollCursor + (this.config.maxOptions - 1) >= optionsScrollTotal
? this.config.maxOptions - 1
: this.config.maxOptions - 2),
);
diff --git a/src/ui/achvs-ui-handler.ts b/src/ui/handlers/achvs-ui-handler.ts
similarity index 99%
rename from src/ui/achvs-ui-handler.ts
rename to src/ui/handlers/achvs-ui-handler.ts
index b0f49d13c86..f8f73dd2078 100644
--- a/src/ui/achvs-ui-handler.ts
+++ b/src/ui/handlers/achvs-ui-handler.ts
@@ -8,8 +8,8 @@ import { achvs, getAchievementDescription } from "#system/achv";
import type { AchvUnlocks, VoucherUnlocks } from "#system/game-data";
import type { Voucher } from "#system/voucher";
import { getVoucherTypeIcon, getVoucherTypeName, vouchers } from "#system/voucher";
-import { MessageUiHandler } from "#ui/message-ui-handler";
-import { ScrollBar } from "#ui/scroll-bar";
+import { ScrollBar } from "#ui/containers/scroll-bar";
+import { MessageUiHandler } from "#ui/handlers/message-ui-handler";
import { addTextObject } from "#ui/text";
import { addWindow } from "#ui/ui-theme";
import i18next from "i18next";
diff --git a/src/ui/admin-ui-handler.ts b/src/ui/handlers/admin-ui-handler.ts
similarity index 95%
rename from src/ui/admin-ui-handler.ts
rename to src/ui/handlers/admin-ui-handler.ts
index 3af34f14e2d..9ca30e35313 100644
--- a/src/ui/admin-ui-handler.ts
+++ b/src/ui/handlers/admin-ui-handler.ts
@@ -3,11 +3,11 @@ import { globalScene } from "#app/global-scene";
import { Button } from "#enums/buttons";
import { TextStyle } from "#enums/text-style";
import { UiMode } from "#enums/ui-mode";
-import type { InputFieldConfig } from "#ui/form-modal-ui-handler";
-import { FormModalUiHandler } from "#ui/form-modal-ui-handler";
-import type { ModalConfig } from "#ui/modal-ui-handler";
+import type { InputFieldConfig } from "#ui/handlers/form-modal-ui-handler";
+import { FormModalUiHandler } from "#ui/handlers/form-modal-ui-handler";
+import type { ModalConfig } from "#ui/handlers/modal-ui-handler";
+import { getTextColor } from "#ui/text";
import { toTitleCase } from "#utils/strings";
-import { getTextColor } from "./text";
type AdminUiHandlerService = "discord" | "google";
type AdminUiHandlerServiceMode = "Link" | "Unlink";
@@ -18,8 +18,6 @@ export class AdminUiHandler extends FormModalUiHandler {
private config: ModalConfig;
private readonly buttonGap = 10;
- // http response from the server when a username isn't found in the server
- private readonly httpUserNotFoundErrorCode: number = 404;
private readonly ERR_REQUIRED_FIELD = (field: string) => {
if (field === "username") {
return `${toTitleCase(field)} is required`;
@@ -322,7 +320,7 @@ export class AdminUiHandler extends FormModalUiHandler {
});
if (errorType || !adminInfo) {
// error - if adminInfo.status === this.httpUserNotFoundErrorCode that means the username can't be found in the db
- return { adminSearchResult: adminSearchResult, error: true, errorType };
+ return { adminSearchResult, error: true, errorType };
}
// success
return { adminSearchResult: adminInfo, error: false };
@@ -374,10 +372,10 @@ export class AdminUiHandler extends FormModalUiHandler {
if (errorType) {
// error - if response.status === this.httpUserNotFoundErrorCode that means the username can't be found in the db
- return { adminSearchResult: adminSearchResult, error: true, errorType };
+ return { adminSearchResult, error: true, errorType };
}
// success!
- return { adminSearchResult: adminSearchResult, error: false };
+ return { adminSearchResult, error: false };
} catch (err) {
console.error(err);
return { error: true, errorType: err };
@@ -421,9 +419,9 @@ export class AdminUiHandler extends FormModalUiHandler {
* and if either of these conditions are met, the element is destroyed.
*/
if (
- itemsToRemove.some(iTR => mC[i].name.includes(iTR)) ||
- (mC[i].type === "Container" &&
- (mC[i] as Phaser.GameObjects.Container).list.find(m => m.type === "rexInputText"))
+ itemsToRemove.some(iTR => mC[i].name.includes(iTR))
+ || (mC[i].type === "Container"
+ && (mC[i] as Phaser.GameObjects.Container).list.find(m => m.type === "rexInputText"))
) {
removeArray.push(mC[i]);
}
diff --git a/src/ui/autocomplete-ui-handler.ts b/src/ui/handlers/autocomplete-ui-handler.ts
similarity index 94%
rename from src/ui/autocomplete-ui-handler.ts
rename to src/ui/handlers/autocomplete-ui-handler.ts
index 337b17048dc..914fe23a123 100644
--- a/src/ui/autocomplete-ui-handler.ts
+++ b/src/ui/handlers/autocomplete-ui-handler.ts
@@ -1,6 +1,6 @@
import { Button } from "#enums/buttons";
import { UiMode } from "#enums/ui-mode";
-import { AbstractOptionSelectUiHandler } from "#ui/abstract-option-select-ui-handler";
+import { AbstractOptionSelectUiHandler } from "#ui/handlers/abstract-option-select-ui-handler";
export class AutoCompleteUiHandler extends AbstractOptionSelectUiHandler {
modalContainer: Phaser.GameObjects.Container;
diff --git a/src/ui/awaitable-ui-handler.ts b/src/ui/handlers/awaitable-ui-handler.ts
similarity index 96%
rename from src/ui/awaitable-ui-handler.ts
rename to src/ui/handlers/awaitable-ui-handler.ts
index e8513b4acc1..9dcd3377da2 100644
--- a/src/ui/awaitable-ui-handler.ts
+++ b/src/ui/handlers/awaitable-ui-handler.ts
@@ -1,7 +1,7 @@
import { globalScene } from "#app/global-scene";
import { Button } from "#enums/buttons";
import type { UiMode } from "#enums/ui-mode";
-import { UiHandler } from "#ui/ui-handler";
+import { UiHandler } from "#ui/handlers/ui-handler";
export abstract class AwaitableUiHandler extends UiHandler {
protected awaitingActionInput: boolean;
diff --git a/src/ui/ball-ui-handler.ts b/src/ui/handlers/ball-ui-handler.ts
similarity index 98%
rename from src/ui/ball-ui-handler.ts
rename to src/ui/handlers/ball-ui-handler.ts
index 3d8efca96b8..3d1868c207e 100644
--- a/src/ui/ball-ui-handler.ts
+++ b/src/ui/handlers/ball-ui-handler.ts
@@ -5,8 +5,8 @@ import { Command } from "#enums/command";
import { TextStyle } from "#enums/text-style";
import { UiMode } from "#enums/ui-mode";
import type { CommandPhase } from "#phases/command-phase";
+import { UiHandler } from "#ui/handlers/ui-handler";
import { addTextObject, getTextStyleOptions } from "#ui/text";
-import { UiHandler } from "#ui/ui-handler";
import { addWindow } from "#ui/ui-theme";
import i18next from "i18next";
diff --git a/src/ui/battle-message-ui-handler.ts b/src/ui/handlers/battle-message-ui-handler.ts
similarity index 95%
rename from src/ui/battle-message-ui-handler.ts
rename to src/ui/handlers/battle-message-ui-handler.ts
index bf4360b37bf..6912109c7e7 100644
--- a/src/ui/battle-message-ui-handler.ts
+++ b/src/ui/handlers/battle-message-ui-handler.ts
@@ -3,7 +3,7 @@ import { Button } from "#enums/buttons";
import { getStatKey, PERMANENT_STATS } from "#enums/stat";
import { TextStyle } from "#enums/text-style";
import { UiMode } from "#enums/ui-mode";
-import { MessageUiHandler } from "#ui/message-ui-handler";
+import { MessageUiHandler } from "#ui/handlers/message-ui-handler";
import { addBBCodeTextObject, addTextObject, getTextColor } from "#ui/text";
import { addWindow } from "#ui/ui-theme";
import i18next from "i18next";
@@ -153,16 +153,12 @@ export class BattleMessageUiHandler extends MessageUiHandler {
processInput(button: Button): boolean {
const ui = this.getUi();
- if (this.awaitingActionInput) {
- if (button === Button.CANCEL || button === Button.ACTION) {
- if (this.onActionInput) {
- ui.playSelect();
- const originalOnActionInput = this.onActionInput;
- this.onActionInput = null;
- originalOnActionInput();
- return true;
- }
- }
+ if (this.awaitingActionInput && (button === Button.CANCEL || button === Button.ACTION) && this.onActionInput) {
+ ui.playSelect();
+ const originalOnActionInput = this.onActionInput;
+ this.onActionInput = null;
+ originalOnActionInput();
+ return true;
}
return false;
diff --git a/src/ui/challenges-select-ui-handler.ts b/src/ui/handlers/challenges-select-ui-handler.ts
similarity index 82%
rename from src/ui/challenges-select-ui-handler.ts
rename to src/ui/handlers/challenges-select-ui-handler.ts
index 68559b92439..5cc91285a74 100644
--- a/src/ui/challenges-select-ui-handler.ts
+++ b/src/ui/handlers/challenges-select-ui-handler.ts
@@ -5,8 +5,8 @@ import { Challenges } from "#enums/challenges";
import { Color, ShadowColor } from "#enums/color";
import { TextStyle } from "#enums/text-style";
import type { UiMode } from "#enums/ui-mode";
+import { UiHandler } from "#ui/handlers/ui-handler";
import { addTextObject } from "#ui/text";
-import { UiHandler } from "#ui/ui-handler";
import { addWindow } from "#ui/ui-theme";
import { getLocalizedSpriteKey } from "#utils/common";
import i18next from "i18next";
@@ -185,10 +185,10 @@ export class GameChallengesUiHandler extends UiHandler {
this.valuesContainer.add(value);
this.challengeLabels[i] = {
- label: label,
- value: value,
- leftArrow: leftArrow,
- rightArrow: rightArrow,
+ label,
+ value,
+ leftArrow,
+ rightArrow,
};
}
@@ -272,17 +272,17 @@ export class GameChallengesUiHandler extends UiHandler {
challengeLabel.leftArrow.setVisible(challenge.value !== 0);
challengeLabel.rightArrow.setPositionRelative(
challengeLabel.leftArrow,
- Math.max(this.monoTypeValue.width, this.widestTextBox) +
- challengeLabel.leftArrow.displayWidth +
- 2 * this.arrowSpacing,
+ Math.max(this.monoTypeValue.width, this.widestTextBox)
+ + challengeLabel.leftArrow.displayWidth
+ + 2 * this.arrowSpacing,
0,
);
challengeLabel.rightArrow.setVisible(challenge.value !== challenge.maxValue);
// this check looks to make sure that the arrows and value textbox don't take up too much space that they'll clip the right edge of the options background
if (
- challengeLabel.rightArrow.x + challengeLabel.rightArrow.width + this.optionsBg.rightWidth + this.arrowSpacing >
- this.optionsWidth
+ challengeLabel.rightArrow.x + challengeLabel.rightArrow.width + this.optionsBg.rightWidth + this.arrowSpacing
+ > this.optionsWidth
) {
// if we go out of bounds of the box, set the x position as far right as we can without going past the box, with this.arrowSpacing to allow a small gap between the arrow and border
challengeLabel.rightArrow.setX(this.optionsWidth - this.arrowSpacing - this.optionsBg.rightWidth);
@@ -400,75 +400,73 @@ export class GameChallengesUiHandler extends UiHandler {
} else {
success = false;
}
- } else {
- if (this.cursorObj?.visible && !this.startCursor.visible) {
- switch (button) {
- case Button.UP:
- if (this.cursor === 0) {
- if (this.scrollCursor === 0) {
- // When at the top of the menu and pressing UP, move to the bottommost item.
- if (globalScene.gameMode.challenges.length > rowsToDisplay) {
- // If there are more than 9 challenges, scroll to the bottom
- // First, set the cursor to the last visible element, preparing for the scroll to the end.
- const successA = this.setCursor(rowsToDisplay - 1);
- // Then, adjust the scroll to display the bottommost elements of the menu.
- const successB = this.setScrollCursor(globalScene.gameMode.challenges.length - rowsToDisplay);
- success = successA && successB; // success is just there to play the little validation sound effect
- } else {
- // If there are 9 or less challenges, just move to the bottom one
- success = this.setCursor(globalScene.gameMode.challenges.length - 1);
- }
- } else {
- success = this.setScrollCursor(this.scrollCursor - 1);
- }
- } else {
- success = this.setCursor(this.cursor - 1);
- }
- if (success) {
- this.updateText();
- }
- break;
- case Button.DOWN:
- if (this.cursor === rowsToDisplay - 1) {
- if (this.scrollCursor < globalScene.gameMode.challenges.length - rowsToDisplay) {
- // When at the bottom and pressing DOWN, scroll if possible.
- success = this.setScrollCursor(this.scrollCursor + 1);
- } else {
- // When at the bottom of a scrolling menu and pressing DOWN, move to the topmost item.
- // First, set the cursor to the first visible element, preparing for the scroll to the top.
- const successA = this.setCursor(0);
- // Then, adjust the scroll to display the topmost elements of the menu.
- const successB = this.setScrollCursor(0);
+ } else if (this.cursorObj?.visible && !this.startCursor.visible) {
+ switch (button) {
+ case Button.UP:
+ if (this.cursor === 0) {
+ if (this.scrollCursor === 0) {
+ // When at the top of the menu and pressing UP, move to the bottommost item.
+ if (globalScene.gameMode.challenges.length > rowsToDisplay) {
+ // If there are more than 9 challenges, scroll to the bottom
+ // First, set the cursor to the last visible element, preparing for the scroll to the end.
+ const successA = this.setCursor(rowsToDisplay - 1);
+ // Then, adjust the scroll to display the bottommost elements of the menu.
+ const successB = this.setScrollCursor(globalScene.gameMode.challenges.length - rowsToDisplay);
success = successA && successB; // success is just there to play the little validation sound effect
+ } else {
+ // If there are 9 or less challenges, just move to the bottom one
+ success = this.setCursor(globalScene.gameMode.challenges.length - 1);
}
- } else if (
- globalScene.gameMode.challenges.length < rowsToDisplay &&
- this.cursor === globalScene.gameMode.challenges.length - 1
- ) {
- // When at the bottom of a non-scrolling menu and pressing DOWN, move to the topmost item.
- success = this.setCursor(0);
} else {
- success = this.setCursor(this.cursor + 1);
+ success = this.setScrollCursor(this.scrollCursor - 1);
}
- if (success) {
- this.updateText();
+ } else {
+ success = this.setCursor(this.cursor - 1);
+ }
+ if (success) {
+ this.updateText();
+ }
+ break;
+ case Button.DOWN:
+ if (this.cursor === rowsToDisplay - 1) {
+ if (this.scrollCursor < globalScene.gameMode.challenges.length - rowsToDisplay) {
+ // When at the bottom and pressing DOWN, scroll if possible.
+ success = this.setScrollCursor(this.scrollCursor + 1);
+ } else {
+ // When at the bottom of a scrolling menu and pressing DOWN, move to the topmost item.
+ // First, set the cursor to the first visible element, preparing for the scroll to the top.
+ const successA = this.setCursor(0);
+ // Then, adjust the scroll to display the topmost elements of the menu.
+ const successB = this.setScrollCursor(0);
+ success = successA && successB; // success is just there to play the little validation sound effect
}
- break;
- case Button.LEFT:
- // Moves the option cursor left, if possible.
- success = this.getActiveChallenge().decreaseValue();
- if (success) {
- this.updateText();
- }
- break;
- case Button.RIGHT:
- // Moves the option cursor right, if possible.
- success = this.getActiveChallenge().increaseValue();
- if (success) {
- this.updateText();
- }
- break;
- }
+ } else if (
+ globalScene.gameMode.challenges.length < rowsToDisplay
+ && this.cursor === globalScene.gameMode.challenges.length - 1
+ ) {
+ // When at the bottom of a non-scrolling menu and pressing DOWN, move to the topmost item.
+ success = this.setCursor(0);
+ } else {
+ success = this.setCursor(this.cursor + 1);
+ }
+ if (success) {
+ this.updateText();
+ }
+ break;
+ case Button.LEFT:
+ // Moves the option cursor left, if possible.
+ success = this.getActiveChallenge().decreaseValue();
+ if (success) {
+ this.updateText();
+ }
+ break;
+ case Button.RIGHT:
+ // Moves the option cursor right, if possible.
+ success = this.getActiveChallenge().increaseValue();
+ if (success) {
+ this.updateText();
+ }
+ break;
}
}
diff --git a/src/ui/change-password-form-ui-handler.ts b/src/ui/handlers/change-password-form-ui-handler.ts
similarity index 94%
rename from src/ui/change-password-form-ui-handler.ts
rename to src/ui/handlers/change-password-form-ui-handler.ts
index eccc67ffb04..f4fdf349978 100644
--- a/src/ui/change-password-form-ui-handler.ts
+++ b/src/ui/handlers/change-password-form-ui-handler.ts
@@ -1,9 +1,9 @@
import { globalScene } from "#app/global-scene";
import { pokerogueApi } from "#app/plugins/api/pokerogue-api";
import { UiMode } from "#enums/ui-mode";
-import type { InputFieldConfig } from "#ui/form-modal-ui-handler";
-import { FormModalUiHandler } from "#ui/form-modal-ui-handler";
-import type { ModalConfig } from "#ui/modal-ui-handler";
+import type { InputFieldConfig } from "#ui/handlers/form-modal-ui-handler";
+import { FormModalUiHandler } from "#ui/handlers/form-modal-ui-handler";
+import type { ModalConfig } from "#ui/handlers/modal-ui-handler";
import i18next from "i18next";
export class ChangePasswordFormUiHandler extends FormModalUiHandler {
diff --git a/src/ui/command-ui-handler.ts b/src/ui/handlers/command-ui-handler.ts
similarity index 96%
rename from src/ui/command-ui-handler.ts
rename to src/ui/handlers/command-ui-handler.ts
index b702bcd0803..de5e51a4210 100644
--- a/src/ui/command-ui-handler.ts
+++ b/src/ui/handlers/command-ui-handler.ts
@@ -9,9 +9,9 @@ import { TextStyle } from "#enums/text-style";
import { UiMode } from "#enums/ui-mode";
import { TerastallizeAccessModifier } from "#modifiers/modifier";
import type { CommandPhase } from "#phases/command-phase";
-import { PartyUiHandler, PartyUiMode } from "#ui/party-ui-handler";
+import { PartyUiHandler, PartyUiMode } from "#ui/handlers/party-ui-handler";
+import { UiHandler } from "#ui/handlers/ui-handler";
import { addTextObject } from "#ui/text";
-import { UiHandler } from "#ui/ui-handler";
import i18next from "i18next";
export class CommandUiHandler extends UiHandler {
@@ -68,7 +68,7 @@ export class CommandUiHandler extends UiHandler {
show(args: any[]): boolean {
super.show(args);
- this.fieldIndex = args.length ? (args[0] as number) : 0;
+ this.fieldIndex = args.length > 0 ? (args[0] as number) : 0;
this.commandsContainer.setVisible(true);
@@ -198,7 +198,7 @@ export class CommandUiHandler extends UiHandler {
}
canTera(): boolean {
- const hasTeraMod = !!globalScene.getModifiers(TerastallizeAccessModifier).length;
+ const hasTeraMod = globalScene.getModifiers(TerastallizeAccessModifier).length > 0;
const activePokemon = globalScene.getField()[this.fieldIndex];
const isBlockedForm =
activePokemon.isMega() || activePokemon.isMax() || activePokemon.hasSpecies(SpeciesId.NECROZMA, "ultra");
diff --git a/src/ui/confirm-ui-handler.ts b/src/ui/handlers/confirm-ui-handler.ts
similarity index 89%
rename from src/ui/confirm-ui-handler.ts
rename to src/ui/handlers/confirm-ui-handler.ts
index 529d1bd8bbb..77f1f182514 100644
--- a/src/ui/confirm-ui-handler.ts
+++ b/src/ui/handlers/confirm-ui-handler.ts
@@ -1,8 +1,8 @@
import { globalScene } from "#app/global-scene";
import { Button } from "#enums/buttons";
import { UiMode } from "#enums/ui-mode";
-import type { OptionSelectConfig } from "#ui/abstract-option-select-ui-handler";
-import { AbstractOptionSelectUiHandler } from "#ui/abstract-option-select-ui-handler";
+import type { OptionSelectConfig } from "#ui/handlers/abstract-option-select-ui-handler";
+import { AbstractOptionSelectUiHandler } from "#ui/handlers/abstract-option-select-ui-handler";
import i18next from "i18next";
export class ConfirmUiHandler extends AbstractOptionSelectUiHandler {
@@ -21,12 +21,12 @@ export class ConfirmUiHandler extends AbstractOptionSelectUiHandler {
show(args: any[]): boolean {
if (
- args.length === 5 &&
- args[0] instanceof Function &&
- args[1] instanceof Function &&
- args[2] instanceof Function &&
- args[3] instanceof Function &&
- args[4] === "fullParty"
+ args.length === 5
+ && args[0] instanceof Function
+ && args[1] instanceof Function
+ && args[2] instanceof Function
+ && args[3] instanceof Function
+ && args[4] === "fullParty"
) {
const config: OptionSelectConfig = {
options: [
diff --git a/src/ui/egg-gacha-ui-handler.ts b/src/ui/handlers/egg-gacha-ui-handler.ts
similarity index 99%
rename from src/ui/egg-gacha-ui-handler.ts
rename to src/ui/handlers/egg-gacha-ui-handler.ts
index d94ddcd6ee5..bd96b4d9392 100644
--- a/src/ui/egg-gacha-ui-handler.ts
+++ b/src/ui/handlers/egg-gacha-ui-handler.ts
@@ -9,7 +9,7 @@ import { GachaType } from "#enums/gacha-types";
import { TextStyle } from "#enums/text-style";
import { UiMode } from "#enums/ui-mode";
import { getVoucherTypeIcon, VoucherType } from "#system/voucher";
-import { MessageUiHandler } from "#ui/message-ui-handler";
+import { MessageUiHandler } from "#ui/handlers/message-ui-handler";
import { addTextObject, getEggTierTextTint, getTextStyleOptions } from "#ui/text";
import { addWindow } from "#ui/ui-theme";
import { fixedInt, randSeedShuffle } from "#utils/common";
@@ -525,7 +525,7 @@ export class EggGachaUiHandler extends MessageUiHandler {
}
const eggSprite = globalScene.add.sprite(127, 75, "egg", `egg_${eggs[i].getKey()}`).setScale(0.5);
gachaContainer.addAt(eggSprite, 2);
- // biome-ignore lint/nursery/noAwaitInLoop: The point of this loop is to play the animations, one after another
+ // biome-ignore lint/performance/noAwaitInLoops: The point of this loop is to play the animations, one after another
await this.doPullAnim(eggSprite, i).finally(() => gachaContainer.remove(eggSprite, true));
}
diff --git a/src/ui/egg-hatch-scene-handler.ts b/src/ui/handlers/egg-hatch-scene-handler.ts
similarity index 96%
rename from src/ui/egg-hatch-scene-handler.ts
rename to src/ui/handlers/egg-hatch-scene-handler.ts
index 1733b64144b..b7b5b78641f 100644
--- a/src/ui/egg-hatch-scene-handler.ts
+++ b/src/ui/handlers/egg-hatch-scene-handler.ts
@@ -1,7 +1,7 @@
import { globalScene } from "#app/global-scene";
import { Button } from "#enums/buttons";
import { UiMode } from "#enums/ui-mode";
-import { UiHandler } from "#ui/ui-handler";
+import { UiHandler } from "#ui/handlers/ui-handler";
export class EggHatchSceneHandler extends UiHandler {
public eggHatchContainer: Phaser.GameObjects.Container;
diff --git a/src/ui/egg-list-ui-handler.ts b/src/ui/handlers/egg-list-ui-handler.ts
similarity index 96%
rename from src/ui/egg-list-ui-handler.ts
rename to src/ui/handlers/egg-list-ui-handler.ts
index 2516903f631..2161073e6b1 100644
--- a/src/ui/egg-list-ui-handler.ts
+++ b/src/ui/handlers/egg-list-ui-handler.ts
@@ -2,10 +2,10 @@ import { globalScene } from "#app/global-scene";
import { Button } from "#enums/buttons";
import { TextStyle } from "#enums/text-style";
import { UiMode } from "#enums/ui-mode";
-import { MessageUiHandler } from "#ui/message-ui-handler";
-import { PokemonIconAnimHandler, PokemonIconAnimMode } from "#ui/pokemon-icon-anim-handler";
-import { ScrollBar } from "#ui/scroll-bar";
-import { ScrollableGridUiHandler } from "#ui/scrollable-grid-handler";
+import { ScrollBar } from "#ui/containers/scroll-bar";
+import { MessageUiHandler } from "#ui/handlers/message-ui-handler";
+import { PokemonIconAnimHandler, PokemonIconAnimMode } from "#ui/handlers/pokemon-icon-anim-handler";
+import { ScrollableGridUiHandler } from "#ui/handlers/scrollable-grid-handler";
import { addTextObject } from "#ui/text";
import { addWindow } from "#ui/ui-theme";
import i18next from "i18next";
diff --git a/src/ui/egg-summary-ui-handler.ts b/src/ui/handlers/egg-summary-ui-handler.ts
similarity index 95%
rename from src/ui/egg-summary-ui-handler.ts
rename to src/ui/handlers/egg-summary-ui-handler.ts
index db357b849c3..046f3b80ea4 100644
--- a/src/ui/egg-summary-ui-handler.ts
+++ b/src/ui/handlers/egg-summary-ui-handler.ts
@@ -3,12 +3,12 @@ import { getEggTierForSpecies } from "#data/egg";
import type { EggHatchData } from "#data/egg-hatch-data";
import { Button } from "#enums/buttons";
import { UiMode } from "#enums/ui-mode";
-import { HatchedPokemonContainer } from "#ui/hatched-pokemon-container";
-import { MessageUiHandler } from "#ui/message-ui-handler";
-import { PokemonHatchInfoContainer } from "#ui/pokemon-hatch-info-container";
-import { PokemonIconAnimHandler, PokemonIconAnimMode } from "#ui/pokemon-icon-anim-handler";
-import { ScrollBar } from "#ui/scroll-bar";
-import { ScrollableGridUiHandler } from "#ui/scrollable-grid-handler";
+import { HatchedPokemonContainer } from "#ui/containers/hatched-pokemon-container";
+import { PokemonHatchInfoContainer } from "#ui/containers/pokemon-hatch-info-container";
+import { ScrollBar } from "#ui/containers/scroll-bar";
+import { MessageUiHandler } from "#ui/handlers/message-ui-handler";
+import { PokemonIconAnimHandler, PokemonIconAnimMode } from "#ui/handlers/pokemon-icon-anim-handler";
+import { ScrollableGridUiHandler } from "#ui/handlers/scrollable-grid-handler";
const iconContainerX = 112;
const iconContainerY = 9;
@@ -144,7 +144,7 @@ export class EggSummaryUiHandler extends MessageUiHandler {
*/
show(args: EggHatchData[][]): boolean {
super.show(args);
- if (args.length >= 1) {
+ if (args.length > 0) {
// sort the egg hatch data by egg tier then by species number (then by order hatched)
this.eggHatchData = args[0].sort(function sortHatchData(a: EggHatchData, b: EggHatchData) {
const speciesA = a.pokemon.species;
diff --git a/src/ui/evolution-scene-handler.ts b/src/ui/handlers/evolution-scene-handler.ts
similarity index 84%
rename from src/ui/evolution-scene-handler.ts
rename to src/ui/handlers/evolution-scene-handler.ts
index 0333594dc36..55405d8f437 100644
--- a/src/ui/evolution-scene-handler.ts
+++ b/src/ui/handlers/evolution-scene-handler.ts
@@ -2,7 +2,7 @@ import { globalScene } from "#app/global-scene";
import { Button } from "#enums/buttons";
import { TextStyle } from "#enums/text-style";
import { UiMode } from "#enums/ui-mode";
-import { MessageUiHandler } from "#ui/message-ui-handler";
+import { MessageUiHandler } from "#ui/handlers/message-ui-handler";
import { addTextObject } from "#ui/text";
export class EvolutionSceneHandler extends MessageUiHandler {
@@ -62,16 +62,12 @@ export class EvolutionSceneHandler extends MessageUiHandler {
}
const ui = this.getUi();
- if (this.awaitingActionInput) {
- if (button === Button.CANCEL || button === Button.ACTION) {
- if (this.onActionInput) {
- ui.playSelect();
- const originalOnActionInput = this.onActionInput;
- this.onActionInput = null;
- originalOnActionInput();
- return true;
- }
- }
+ if (this.awaitingActionInput && (button === Button.CANCEL || button === Button.ACTION) && this.onActionInput) {
+ ui.playSelect();
+ const originalOnActionInput = this.onActionInput;
+ this.onActionInput = null;
+ originalOnActionInput();
+ return true;
}
return false;
diff --git a/src/ui/fight-ui-handler.ts b/src/ui/handlers/fight-ui-handler.ts
similarity index 98%
rename from src/ui/fight-ui-handler.ts
rename to src/ui/handlers/fight-ui-handler.ts
index d1b85a29b14..9dd00a90b66 100644
--- a/src/ui/fight-ui-handler.ts
+++ b/src/ui/handlers/fight-ui-handler.ts
@@ -12,9 +12,9 @@ import { UiMode } from "#enums/ui-mode";
import type { EnemyPokemon, Pokemon } from "#field/pokemon";
import type { PokemonMove } from "#moves/pokemon-move";
import type { CommandPhase } from "#phases/command-phase";
-import { MoveInfoOverlay } from "#ui/move-info-overlay";
+import { MoveInfoOverlay } from "#ui/containers/move-info-overlay";
+import { UiHandler } from "#ui/handlers/ui-handler";
import { addTextObject, getTextColor } from "#ui/text";
-import { UiHandler } from "#ui/ui-handler";
import { fixedInt, getLocalizedSpriteKey, padInt } from "#utils/common";
import i18next from "i18next";
@@ -372,12 +372,12 @@ export class FightUiHandler extends UiHandler implements InfoToggle {
*/
private getMoveColor(pokemon: Pokemon, pokemonMove: PokemonMove): string | undefined {
if (!globalScene.typeHints) {
- return undefined;
+ return;
}
const opponents = pokemon.getOpponents();
if (opponents.length <= 0) {
- return undefined;
+ return;
}
const moveColors = opponents
@@ -394,7 +394,7 @@ export class FightUiHandler extends UiHandler implements InfoToggle {
.sort((a, b) => b - a)
.map(effectiveness => {
if (pokemonMove.getMove().category === MoveCategory.STATUS && effectiveness !== 0) {
- return undefined;
+ return;
}
return getTypeDamageMultiplierColor(effectiveness ?? 0, "offense");
});
diff --git a/src/ui/form-modal-ui-handler.ts b/src/ui/handlers/form-modal-ui-handler.ts
similarity index 90%
rename from src/ui/form-modal-ui-handler.ts
rename to src/ui/handlers/form-modal-ui-handler.ts
index 092a0c85bb2..af1d8653df7 100644
--- a/src/ui/form-modal-ui-handler.ts
+++ b/src/ui/handlers/form-modal-ui-handler.ts
@@ -2,8 +2,8 @@ import { globalScene } from "#app/global-scene";
import { Button } from "#enums/buttons";
import { TextStyle } from "#enums/text-style";
import type { UiMode } from "#enums/ui-mode";
-import type { ModalConfig } from "#ui/modal-ui-handler";
-import { ModalUiHandler } from "#ui/modal-ui-handler";
+import type { ModalConfig } from "#ui/handlers/modal-ui-handler";
+import { ModalUiHandler } from "#ui/handlers/modal-ui-handler";
import { addTextInputObject, addTextObject, getTextColor } from "#ui/text";
import { addWindow, WindowVariant } from "#ui/ui-theme";
import { fixedInt } from "#utils/common";
@@ -41,11 +41,11 @@ export abstract class FormModalUiHandler extends ModalUiHandler {
getHeight(config?: ModalConfig): number {
return (
- 20 * this.getInputFieldConfigs().length +
- (this.getModalTitle() ? 26 : 0) +
- ((config as FormModalConfig)?.errorMessage ? 12 : 0) +
- this.getButtonTopMargin() +
- 28
+ 20 * this.getInputFieldConfigs().length
+ + (this.getModalTitle() ? 26 : 0)
+ + ((config as FormModalConfig)?.errorMessage ? 12 : 0)
+ + this.getButtonTopMargin()
+ + 28
);
}
@@ -64,7 +64,7 @@ export abstract class FormModalUiHandler extends ModalUiHandler {
const hasTitle = !!this.getModalTitle();
- if (config.length >= 1) {
+ if (config.length > 0) {
this.updateFields(config, hasTitle);
}
@@ -100,7 +100,7 @@ export abstract class FormModalUiHandler extends ModalUiHandler {
label.name = "formLabel" + f;
this.formLabels.push(label);
- this.modalContainer.add(this.formLabels[this.formLabels.length - 1]);
+ this.modalContainer.add(label);
const inputWidth = label.width < 320 ? 80 : 80 - (label.width - 320) / 5.5;
const inputContainer = globalScene.add.container(70 + (80 - inputWidth), (hasTitle ? 28 : 2) + 20 * f);
@@ -133,9 +133,14 @@ export abstract class FormModalUiHandler extends ModalUiHandler {
const config = args[0] as FormModalConfig;
- this.submitAction = config.buttonActions.length ? config.buttonActions[0] : null;
+ this.submitAction = config.buttonActions.length > 0 ? config.buttonActions[0] : null;
this.cancelAction = config.buttonActions[1] ?? null;
+ // Auto focus the first input field after a short delay, to prevent accidental inputs
+ setTimeout(() => {
+ this.inputs[0].setFocus();
+ }, 50);
+
// #region: Override button pointerDown
// Override the pointerDown event for the buttonBgs to call the `submitAction` and `cancelAction`
// properties that we set above, allowing their behavior to change after this method terminates
diff --git a/src/ui/game-stats-ui-handler.ts b/src/ui/handlers/game-stats-ui-handler.ts
similarity index 99%
rename from src/ui/game-stats-ui-handler.ts
rename to src/ui/handlers/game-stats-ui-handler.ts
index be41e4d21b9..9ffb7346b4d 100644
--- a/src/ui/game-stats-ui-handler.ts
+++ b/src/ui/handlers/game-stats-ui-handler.ts
@@ -7,8 +7,8 @@ import { PlayerGender } from "#enums/player-gender";
import { TextStyle } from "#enums/text-style";
import { UiTheme } from "#enums/ui-theme";
import type { GameData } from "#system/game-data";
+import { UiHandler } from "#ui/handlers/ui-handler";
import { addTextObject } from "#ui/text";
-import { UiHandler } from "#ui/ui-handler";
import { addWindow } from "#ui/ui-theme";
import { formatFancyLargeNumber, getPlayTimeString } from "#utils/common";
import { toTitleCase } from "#utils/strings";
@@ -529,7 +529,7 @@ export function initStatsKeys() {
displayStats[key] = {
label_key: label,
sourceFunc: gameData => gameData.gameStats[key].toString(),
- hidden: hidden,
+ hidden,
};
} else if (displayStats[key] === null) {
displayStats[key] = {
diff --git a/src/ui/loading-modal-ui-handler.ts b/src/ui/handlers/loading-modal-ui-handler.ts
similarity index 92%
rename from src/ui/loading-modal-ui-handler.ts
rename to src/ui/handlers/loading-modal-ui-handler.ts
index de00d911c47..9b401e17f91 100644
--- a/src/ui/loading-modal-ui-handler.ts
+++ b/src/ui/handlers/loading-modal-ui-handler.ts
@@ -1,6 +1,6 @@
import { TextStyle } from "#enums/text-style";
import type { UiMode } from "#enums/ui-mode";
-import { ModalUiHandler } from "#ui/modal-ui-handler";
+import { ModalUiHandler } from "#ui/handlers/modal-ui-handler";
import { addTextObject } from "#ui/text";
import i18next from "i18next";
diff --git a/src/ui/login-form-ui-handler.ts b/src/ui/handlers/login-form-ui-handler.ts
similarity index 91%
rename from src/ui/login-form-ui-handler.ts
rename to src/ui/handlers/login-form-ui-handler.ts
index 0f55faba5c4..aeebd23ce43 100644
--- a/src/ui/login-form-ui-handler.ts
+++ b/src/ui/handlers/login-form-ui-handler.ts
@@ -2,10 +2,10 @@ import { pokerogueApi } from "#api/pokerogue-api";
import { globalScene } from "#app/global-scene";
import { TextStyle } from "#enums/text-style";
import { UiMode } from "#enums/ui-mode";
-import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
-import type { InputFieldConfig } from "#ui/form-modal-ui-handler";
-import { FormModalUiHandler } from "#ui/form-modal-ui-handler";
-import type { ModalConfig } from "#ui/modal-ui-handler";
+import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler";
+import type { InputFieldConfig } from "#ui/handlers/form-modal-ui-handler";
+import { FormModalUiHandler } from "#ui/handlers/form-modal-ui-handler";
+import type { ModalConfig } from "#ui/handlers/modal-ui-handler";
import { addTextObject } from "#ui/text";
import { addWindow } from "#ui/ui-theme";
import { fixedInt } from "#utils/common";
@@ -234,9 +234,9 @@ export class LoginFormUiHandler extends FormModalUiHandler {
const dataKeys = localStorageKeys.filter(ls => ls.indexOf(keyToFind) >= 0);
if (dataKeys.length > 0 && dataKeys.length <= 2) {
const options: OptionSelectItem[] = [];
- for (let i = 0; i < dataKeys.length; i++) {
+ for (const key of dataKeys) {
options.push({
- label: dataKeys[i].replace(keyToFind, ""),
+ label: key.replace(keyToFind, ""),
handler: () => {
globalScene.ui.revertMode();
this.infoContainer.disableInteractive();
@@ -245,7 +245,7 @@ export class LoginFormUiHandler extends FormModalUiHandler {
});
}
globalScene.ui.setOverlayMode(UiMode.OPTION_SELECT, {
- options: options,
+ options,
delay: 1000,
});
this.infoContainer.setInteractive(
@@ -261,7 +261,7 @@ export class LoginFormUiHandler extends FormModalUiHandler {
}
});
- this.saveDownloadImage.on("pointerdown", () => {
+ this.saveDownloadImage.on("pointerdown", async () => {
// find all data_ and sessionData keys, put them in a .txt file and download everything in a single zip
const localStorageKeys = Object.keys(localStorage); // this gets the keys for localStorage
const keyToFind = "data_";
@@ -270,20 +270,19 @@ export class LoginFormUiHandler extends FormModalUiHandler {
const sessionKeys = localStorageKeys.filter(ls => ls.indexOf(sessionKeyToFind) >= 0);
if (dataKeys.length > 0 || sessionKeys.length > 0) {
const zip = new JSZip();
- for (let i = 0; i < dataKeys.length; i++) {
- zip.file(dataKeys[i] + ".prsv", localStorage.getItem(dataKeys[i])!);
+ for (const dataKey of dataKeys) {
+ zip.file(dataKey + ".prsv", localStorage.getItem(dataKey)!);
}
- for (let i = 0; i < sessionKeys.length; i++) {
- zip.file(sessionKeys[i] + ".prsv", localStorage.getItem(sessionKeys[i])!);
+ for (const sessionKey of sessionKeys) {
+ zip.file(sessionKey + ".prsv", localStorage.getItem(sessionKey)!);
}
- zip.generateAsync({ type: "blob" }).then(content => {
- const url = URL.createObjectURL(content);
- const a = document.createElement("a");
- a.href = url;
- a.download = "pokerogue_saves.zip";
- a.click();
- URL.revokeObjectURL(url);
- });
+ const content = await zip.generateAsync({ type: "blob" });
+ const url = URL.createObjectURL(content);
+ const a = document.createElement("a");
+ a.href = url;
+ a.download = "pokerogue_saves.zip";
+ a.click();
+ URL.revokeObjectURL(url);
} else {
return onFail(this.ERR_NO_SAVES);
}
diff --git a/src/ui/menu-ui-handler.ts b/src/ui/handlers/menu-ui-handler.ts
similarity index 97%
rename from src/ui/menu-ui-handler.ts
rename to src/ui/handlers/menu-ui-handler.ts
index 66465f76445..df1908bae39 100644
--- a/src/ui/menu-ui-handler.ts
+++ b/src/ui/handlers/menu-ui-handler.ts
@@ -7,11 +7,10 @@ import { Button } from "#enums/buttons";
import { GameDataType } from "#enums/game-data-type";
import { TextStyle } from "#enums/text-style";
import { UiMode } from "#enums/ui-mode";
-import type { OptionSelectConfig, OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
-import { AdminMode, getAdminModeName } from "#ui/admin-ui-handler";
-import type { AwaitableUiHandler } from "#ui/awaitable-ui-handler";
-import { BgmBar } from "#ui/bgm-bar";
-import { MessageUiHandler } from "#ui/message-ui-handler";
+import { BgmBar } from "#ui/containers/bgm-bar";
+import type { OptionSelectConfig, OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler";
+import type { AwaitableUiHandler } from "#ui/handlers/awaitable-ui-handler";
+import { MessageUiHandler } from "#ui/handlers/message-ui-handler";
import { addTextObject, getTextStyleOptions } from "#ui/text";
import { addWindow, WindowVariant } from "#ui/ui-theme";
import { fixedInt, isLocal, sessionIdKey } from "#utils/common";
@@ -20,6 +19,7 @@ import { getEnumValues } from "#utils/enums";
import { toCamelCase } from "#utils/strings";
import { isBeta } from "#utils/utility-vars";
import i18next from "i18next";
+import { AdminMode, getAdminModeName } from "./admin-ui-handler";
enum MenuOptions {
GAME_SETTINGS,
@@ -495,7 +495,7 @@ export class MenuUiHandler extends MessageUiHandler {
},
});
globalScene.ui.setOverlayMode(UiMode.OPTION_SELECT, {
- options: options,
+ options,
delay: 0,
});
return true;
@@ -578,7 +578,7 @@ export class MenuUiHandler extends MessageUiHandler {
success = true;
break;
case MenuOptions.EGG_LIST:
- if (globalScene.gameData.eggs.length) {
+ if (globalScene.gameData.eggs.length > 0) {
ui.revertMode();
ui.setOverlayMode(UiMode.EGG_LIST);
success = true;
@@ -599,11 +599,11 @@ export class MenuUiHandler extends MessageUiHandler {
break;
case MenuOptions.MANAGE_DATA:
if (
- !bypassLogin &&
- !this.manageDataConfig.options.some(
+ !bypassLogin
+ && !this.manageDataConfig.options.some(
o =>
- o.label === i18next.t("menuUiHandler:linkDiscord") ||
- o.label === i18next.t("menuUiHandler:unlinkDiscord"),
+ o.label === i18next.t("menuUiHandler:linkDiscord")
+ || o.label === i18next.t("menuUiHandler:unlinkDiscord"),
)
) {
this.manageDataConfig.options.splice(
diff --git a/src/ui/message-ui-handler.ts b/src/ui/handlers/message-ui-handler.ts
similarity index 95%
rename from src/ui/message-ui-handler.ts
rename to src/ui/handlers/message-ui-handler.ts
index 57f054c9bf9..b8e3f983cca 100644
--- a/src/ui/message-ui-handler.ts
+++ b/src/ui/handlers/message-ui-handler.ts
@@ -1,6 +1,6 @@
import { globalScene } from "#app/global-scene";
import type { UiMode } from "#enums/ui-mode";
-import { AwaitableUiHandler } from "#ui/awaitable-ui-handler";
+import { AwaitableUiHandler } from "#ui/handlers/awaitable-ui-handler";
import { getFrameMs } from "#utils/common";
export abstract class MessageUiHandler extends AwaitableUiHandler {
@@ -108,17 +108,17 @@ export abstract class MessageUiHandler extends AwaitableUiHandler {
const textWords = text.split(" ");
let lastLineCount = 1;
let newText = "";
- for (let w = 0; w < textWords.length; w++) {
- const nextWordText = newText ? `${newText} ${textWords[w]}` : textWords[w];
+ for (const textWord of textWords) {
+ const nextWordText = newText ? `${newText} ${textWord}` : textWord;
- if (textWords[w].includes("\n")) {
+ if (textWord.includes("\n")) {
newText = nextWordText;
lastLineCount++;
} else {
const lineCount = this.message.runWordWrap(nextWordText).split(/\n/g).length;
if (lineCount > lastLineCount) {
lastLineCount = lineCount;
- newText = `${newText}\n${textWords[w]}`;
+ newText = `${newText}\n${textWord}`;
} else {
newText = nextWordText;
}
@@ -151,7 +151,7 @@ export abstract class MessageUiHandler extends AwaitableUiHandler {
this.pendingPrompt = true;
}
this.textTimer = globalScene.time.addEvent({
- delay: delay,
+ delay,
callback: () => {
const charIndex = text.length - this.textTimer?.repeatCount!; // TODO: is this bang correct?
const charVar = charVarMap.get(charIndex);
@@ -222,7 +222,7 @@ export abstract class MessageUiHandler extends AwaitableUiHandler {
showPrompt(callback?: Function | null, callbackDelay?: number | null) {
const wrappedTextLines = this.message.runWordWrap(this.message.text).split(/\n/g);
const textLinesCount = wrappedTextLines.length;
- const lastTextLine = wrappedTextLines[wrappedTextLines.length - 1];
+ const lastTextLine = wrappedTextLines.at(-1) ?? "";
const lastLineTest = globalScene.add.text(0, 0, lastTextLine, {
font: "96px emerald",
});
diff --git a/src/ui/modal-ui-handler.ts b/src/ui/handlers/modal-ui-handler.ts
similarity index 98%
rename from src/ui/modal-ui-handler.ts
rename to src/ui/handlers/modal-ui-handler.ts
index 51a6a21a29c..e6eecece9a2 100644
--- a/src/ui/modal-ui-handler.ts
+++ b/src/ui/handlers/modal-ui-handler.ts
@@ -2,8 +2,8 @@ import { globalScene } from "#app/global-scene";
import type { Button } from "#enums/buttons";
import { TextStyle } from "#enums/text-style";
import type { UiMode } from "#enums/ui-mode";
+import { UiHandler } from "#ui/handlers/ui-handler";
import { addTextObject } from "#ui/text";
-import { UiHandler } from "#ui/ui-handler";
import { addWindow, WindowVariant } from "#ui/ui-theme";
export interface ModalConfig {
@@ -97,7 +97,7 @@ export abstract class ModalUiHandler extends UiHandler {
}
show(args: any[]): boolean {
- if (args.length >= 1 && "buttonActions" in args[0]) {
+ if (args.length > 0 && "buttonActions" in args[0]) {
super.show(args);
if (args[0].hasOwnProperty("fadeOut") && typeof args[0].fadeOut === "function") {
const [marginTop, marginRight, marginBottom, marginLeft] = this.getMargin();
diff --git a/src/ui/modifier-select-ui-handler.ts b/src/ui/handlers/modifier-select-ui-handler.ts
similarity index 96%
rename from src/ui/modifier-select-ui-handler.ts
rename to src/ui/handlers/modifier-select-ui-handler.ts
index 9ddc892add6..a721bf9e7db 100644
--- a/src/ui/modifier-select-ui-handler.ts
+++ b/src/ui/handlers/modifier-select-ui-handler.ts
@@ -11,8 +11,8 @@ import { UiMode } from "#enums/ui-mode";
import { HealShopCostModifier, LockModifierTiersModifier, PokemonHeldItemModifier } from "#modifiers/modifier";
import type { ModifierTypeOption } from "#modifiers/modifier-type";
import { getPlayerShopModifierTypeOptionsForWave, TmModifierType } from "#modifiers/modifier-type";
-import { AwaitableUiHandler } from "#ui/awaitable-ui-handler";
-import { MoveInfoOverlay } from "#ui/move-info-overlay";
+import { MoveInfoOverlay } from "#ui/containers/move-info-overlay";
+import { AwaitableUiHandler } from "#ui/handlers/awaitable-ui-handler";
import { addTextObject, getModifierTierTextTint, getTextColor, getTextStyleOptions } from "#ui/text";
import { formatMoney, NumberHolder } from "#utils/common";
import i18next from "i18next";
@@ -179,7 +179,8 @@ export class ModifierSelectUiHandler extends AwaitableUiHandler {
this.player = args[0];
const partyHasHeldItem =
- this.player && !!globalScene.findModifiers(m => m instanceof PokemonHeldItemModifier && m.isTransferable).length;
+ this.player
+ && globalScene.findModifiers(m => m instanceof PokemonHeldItemModifier && m.isTransferable).length > 0;
const canLockRarities = !!globalScene.findModifier(m => m instanceof LockModifierTiersModifier);
this.transferButtonContainer.setVisible(false);
@@ -480,12 +481,10 @@ export class ModifierSelectUiHandler extends AwaitableUiHandler {
}
} else if (this.cursor) {
success = this.setCursor(this.cursor - 1);
+ } else if (this.rowCursor === 1 && this.options.length === 0) {
+ success = false;
} else {
- if (this.rowCursor === 1 && this.options.length === 0) {
- success = false;
- } else {
- success = this.setCursor(this.getRowItems(this.rowCursor) - 1);
- }
+ success = this.setCursor(this.getRowItems(this.rowCursor) - 1);
}
break;
case Button.RIGHT:
@@ -514,12 +513,10 @@ export class ModifierSelectUiHandler extends AwaitableUiHandler {
}
} else if (this.cursor < this.getRowItems(this.rowCursor) - 1) {
success = this.setCursor(this.cursor + 1);
+ } else if (this.rowCursor === 1 && this.options.length === 0) {
+ success = this.setRowCursor(0);
} else {
- if (this.rowCursor === 1 && this.options.length === 0) {
- success = this.setRowCursor(0);
- } else {
- success = this.setCursor(0);
- }
+ success = this.setCursor(0);
}
break;
}
@@ -541,8 +538,7 @@ export class ModifierSelectUiHandler extends AwaitableUiHandler {
this.modifierContainer.add(this.cursorObj);
}
- const options =
- this.rowCursor === 1 ? this.options : this.shopOptionsRows[this.shopOptionsRows.length - (this.rowCursor - 1)];
+ const options = this.rowCursor === 1 ? this.options : this.shopOptionsRows.at(-(this.rowCursor - 1))!;
this.cursorObj.setScale(this.rowCursor === 1 ? 2 : this.rowCursor >= 2 ? 1.5 : 1);
@@ -554,8 +550,8 @@ export class ModifierSelectUiHandler extends AwaitableUiHandler {
this.cursorObj.setScale(1.25);
this.cursorObj.setPosition(
globalScene.scaledCanvas.width / 3 + 23,
- -globalScene.scaledCanvas.height / 2 -
- (this.shopOptionsRows.length > 1 ? SINGLE_SHOP_ROW_YOFFSET - 2 : DOUBLE_SHOP_ROW_YOFFSET - 2),
+ -globalScene.scaledCanvas.height / 2
+ - (this.shopOptionsRows.length > 1 ? SINGLE_SHOP_ROW_YOFFSET - 2 : DOUBLE_SHOP_ROW_YOFFSET - 2),
);
ui.showText(i18next.t("modifierSelectUiHandler:continueNextWaveDescription"));
return ret;
@@ -566,16 +562,16 @@ export class ModifierSelectUiHandler extends AwaitableUiHandler {
// Cursor on free items
this.cursorObj.setPosition(
sliceWidth * (cursor + 1) + sliceWidth * 0.5 - 20,
- -globalScene.scaledCanvas.height / 2 -
- (this.shopOptionsRows.length > 1 ? SINGLE_SHOP_ROW_YOFFSET - 2 : DOUBLE_SHOP_ROW_YOFFSET - 2),
+ -globalScene.scaledCanvas.height / 2
+ - (this.shopOptionsRows.length > 1 ? SINGLE_SHOP_ROW_YOFFSET - 2 : DOUBLE_SHOP_ROW_YOFFSET - 2),
);
} else {
// Cursor on paying items
this.cursorObj.setPosition(
sliceWidth * (cursor + 1) + sliceWidth * 0.5 - 16,
- -globalScene.scaledCanvas.height / 2 -
- globalScene.game.canvas.height / 32 -
- (-14 + 28 * (this.rowCursor - (this.shopOptionsRows.length - 1))),
+ -globalScene.scaledCanvas.height / 2
+ - globalScene.game.canvas.height / 32
+ - (-14 + 28 * (this.rowCursor - (this.shopOptionsRows.length - 1))),
);
}
@@ -657,7 +653,7 @@ export class ModifierSelectUiHandler extends AwaitableUiHandler {
case 1:
return this.options.length;
default:
- return this.shopOptionsRows[this.shopOptionsRows.length - (rowCursor - 1)].length;
+ return this.shopOptionsRows.at(-(rowCursor - 1))!.length;
}
}
@@ -747,7 +743,7 @@ export class ModifierSelectUiHandler extends AwaitableUiHandler {
duration: 250,
ease: "Cubic.easeIn",
onComplete: () => {
- if (!this.options.length) {
+ if (this.options.length === 0) {
container.setVisible(false);
} else {
container.setAlpha(1);
diff --git a/src/ui/mystery-encounter-ui-handler.ts b/src/ui/handlers/mystery-encounter-ui-handler.ts
similarity index 93%
rename from src/ui/mystery-encounter-ui-handler.ts
rename to src/ui/handlers/mystery-encounter-ui-handler.ts
index 37f77cf43b9..9bc6f0681ee 100644
--- a/src/ui/mystery-encounter-ui-handler.ts
+++ b/src/ui/handlers/mystery-encounter-ui-handler.ts
@@ -9,9 +9,9 @@ import { getEncounterText } from "#mystery-encounters/encounter-dialogue-utils";
import type { OptionSelectSettings } from "#mystery-encounters/encounter-phase-utils";
import type { MysteryEncounterOption } from "#mystery-encounters/mystery-encounter-option";
import type { MysteryEncounterPhase } from "#phases/mystery-encounter-phases";
-import { PartyUiMode } from "#ui/party-ui-handler";
+import { PartyUiMode } from "#ui/handlers/party-ui-handler";
+import { UiHandler } from "#ui/handlers/ui-handler";
import { addBBCodeTextObject, getBBCodeFrag } from "#ui/text";
-import { UiHandler } from "#ui/ui-handler";
import { addWindow, WindowVariant } from "#ui/ui-theme";
import { fixedInt, isNullOrUndefined } from "#utils/common";
import i18next from "i18next";
@@ -150,20 +150,18 @@ export class MysteryEncounterUiHandler extends UiHandler {
}, 300);
});
} else if (
- this.blockInput ||
- (!this.optionsMeetsReqs[cursor] &&
- (selected.optionMode === MysteryEncounterOptionMode.DISABLED_OR_DEFAULT ||
- selected.optionMode === MysteryEncounterOptionMode.DISABLED_OR_SPECIAL))
+ this.blockInput
+ || (!this.optionsMeetsReqs[cursor]
+ && (selected.optionMode === MysteryEncounterOptionMode.DISABLED_OR_DEFAULT
+ || selected.optionMode === MysteryEncounterOptionMode.DISABLED_OR_SPECIAL))
) {
success = false;
+ } else if (
+ (globalScene.phaseManager.getCurrentPhase() as MysteryEncounterPhase).handleOptionSelect(selected, cursor)
+ ) {
+ success = true;
} else {
- if (
- (globalScene.phaseManager.getCurrentPhase() as MysteryEncounterPhase).handleOptionSelect(selected, cursor)
- ) {
- success = true;
- } else {
- ui.playError();
- }
+ ui.playError();
}
} else {
// TODO: If we need to handle cancel option? Maybe default logic to leave/run from encounter idk
@@ -306,9 +304,9 @@ export class MysteryEncounterUiHandler extends UiHandler {
for (let i = 0; i < this.optionsContainer.length - 1; i++) {
const optionMode = this.encounterOptions[i].optionMode;
if (
- !this.optionsMeetsReqs[i] &&
- (optionMode === MysteryEncounterOptionMode.DISABLED_OR_DEFAULT ||
- optionMode === MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)
+ !this.optionsMeetsReqs[i]
+ && (optionMode === MysteryEncounterOptionMode.DISABLED_OR_DEFAULT
+ || optionMode === MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)
) {
continue;
}
@@ -409,10 +407,10 @@ export class MysteryEncounterUiHandler extends UiHandler {
: optionDialogue.buttonLabel;
let text: string | null;
if (
- option.hasRequirements() &&
- this.optionsMeetsReqs[i] &&
- (option.optionMode === MysteryEncounterOptionMode.DEFAULT_OR_SPECIAL ||
- option.optionMode === MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)
+ option.hasRequirements()
+ && this.optionsMeetsReqs[i]
+ && (option.optionMode === MysteryEncounterOptionMode.DEFAULT_OR_SPECIAL
+ || option.optionMode === MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)
) {
// Options with special requirements that are met are automatically colored green
text = getEncounterText(label, TextStyle.ME_OPTION_SPECIAL);
@@ -425,9 +423,9 @@ export class MysteryEncounterUiHandler extends UiHandler {
}
if (
- !this.optionsMeetsReqs[i] &&
- (option.optionMode === MysteryEncounterOptionMode.DISABLED_OR_DEFAULT ||
- option.optionMode === MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)
+ !this.optionsMeetsReqs[i]
+ && (option.optionMode === MysteryEncounterOptionMode.DISABLED_OR_DEFAULT
+ || option.optionMode === MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)
) {
optionText.setAlpha(0.5);
}
@@ -580,10 +578,10 @@ export class MysteryEncounterUiHandler extends UiHandler {
const cursorOption = this.encounterOptions[cursor];
const optionDialogue = cursorOption.dialogue!;
if (
- !this.optionsMeetsReqs[cursor] &&
- (cursorOption.optionMode === MysteryEncounterOptionMode.DISABLED_OR_DEFAULT ||
- cursorOption.optionMode === MysteryEncounterOptionMode.DISABLED_OR_SPECIAL) &&
- optionDialogue.disabledButtonTooltip
+ !this.optionsMeetsReqs[cursor]
+ && (cursorOption.optionMode === MysteryEncounterOptionMode.DISABLED_OR_DEFAULT
+ || cursorOption.optionMode === MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)
+ && optionDialogue.disabledButtonTooltip
) {
text = getEncounterText(optionDialogue.disabledButtonTooltip, TextStyle.TOOLTIP_CONTENT);
} else {
@@ -596,18 +594,18 @@ export class MysteryEncounterUiHandler extends UiHandler {
text = text.replace(
/(\(\+\)[^([]*)/gi,
substring =>
- "[/color][/shadow]" +
- getBBCodeFrag(substring, TextStyle.SUMMARY_GREEN) +
- "[/color][/shadow]" +
- primaryStyleString,
+ "[/color][/shadow]"
+ + getBBCodeFrag(substring, TextStyle.SUMMARY_GREEN)
+ + "[/color][/shadow]"
+ + primaryStyleString,
);
text = text.replace(
/(\(-\)[^([]*)/gi,
substring =>
- "[/color][/shadow]" +
- getBBCodeFrag(substring, TextStyle.SUMMARY_BLUE) +
- "[/color][/shadow]" +
- primaryStyleString,
+ "[/color][/shadow]"
+ + getBBCodeFrag(substring, TextStyle.SUMMARY_BLUE)
+ + "[/color][/shadow]"
+ + primaryStyleString,
);
}
diff --git a/src/ui/party-ui-handler.ts b/src/ui/handlers/party-ui-handler.ts
similarity index 94%
rename from src/ui/party-ui-handler.ts
rename to src/ui/handlers/party-ui-handler.ts
index b77710d8140..ef5ed099153 100644
--- a/src/ui/party-ui-handler.ts
+++ b/src/ui/handlers/party-ui-handler.ts
@@ -21,9 +21,9 @@ import type { PokemonMove } from "#moves/pokemon-move";
import type { CommandPhase } from "#phases/command-phase";
import { getVariantTint } from "#sprites/variant";
import type { TurnMove } from "#types/turn-move";
-import { MessageUiHandler } from "#ui/message-ui-handler";
-import { MoveInfoOverlay } from "#ui/move-info-overlay";
-import { PokemonIconAnimHandler, PokemonIconAnimMode } from "#ui/pokemon-icon-anim-handler";
+import { MoveInfoOverlay } from "#ui/containers/move-info-overlay";
+import { MessageUiHandler } from "#ui/handlers/message-ui-handler";
+import { PokemonIconAnimHandler, PokemonIconAnimMode } from "#ui/handlers/pokemon-icon-anim-handler";
import { addBBCodeTextObject, addTextObject, getTextColor } from "#ui/text";
import { addWindow } from "#ui/ui-theme";
import { applyChallenges } from "#utils/challenge-utils";
@@ -342,7 +342,7 @@ export class PartyUiHandler extends MessageUiHandler {
}
show(args: any[]): boolean {
- if (!args.length || this.active) {
+ if (args.length === 0 || this.active) {
return false;
}
@@ -441,7 +441,7 @@ export class PartyUiHandler extends MessageUiHandler {
ui.setMode(UiMode.PARTY);
this.showText(
i18next.t("partyUiHandler:wasReverted", {
- fusionName: fusionName,
+ fusionName,
pokemonName: pokemon.getName(false),
}),
undefined,
@@ -595,9 +595,9 @@ export class PartyUiHandler extends MessageUiHandler {
matchingModifiers.push(
globalScene.findModifier(
m =>
- m.is("PokemonHeldItemModifier") &&
- m.pokemonId === newPokemon.id &&
- m.matchType(allItems[this.transferOptionCursor]),
+ m.is("PokemonHeldItemModifier")
+ && m.pokemonId === newPokemon.id
+ && m.matchType(allItems[this.transferOptionCursor]),
) as PokemonHeldItemModifier | undefined,
);
}
@@ -631,6 +631,7 @@ export class PartyUiHandler extends MessageUiHandler {
// this else relates to the transfer pokemon. We set the text to be blank so there's no "Able"/"Not able" text
ableToTransferText = "";
}
+ partySlot.slotHpLabel.setVisible(false);
partySlot.slotHpBar.setVisible(false);
partySlot.slotHpOverlay.setVisible(false);
partySlot.slotHpText.setVisible(false);
@@ -660,34 +661,32 @@ export class PartyUiHandler extends MessageUiHandler {
// TODO: Might need to check here for when this.transferMode is active.
private processModifierTransferModeLeftRightInput(button: Button) {
+ if (!this.isItemManageMode()) {
+ return false;
+ }
let success = false;
const option = this.options[this.optionsCursor];
if (button === Button.LEFT) {
/** Decrease quantity for the current item and update UI */
- if (this.isItemManageMode()) {
- this.transferQuantities[option] =
- this.transferQuantities[option] === 1
- ? this.transferQuantitiesMax[option]
- : this.transferQuantities[option] - 1;
- this.updateOptions();
- success = this.setCursor(
- this.optionsCursor,
- ); /** Place again the cursor at the same position. Necessary, otherwise the cursor disappears */
- }
+ this.transferQuantities[option] =
+ this.transferQuantities[option] === 1
+ ? this.transferQuantitiesMax[option]
+ : this.transferQuantities[option] - 1;
+ this.updateOptions();
+ success = this.setCursor(
+ this.optionsCursor,
+ ); /** Place again the cursor at the same position. Necessary, otherwise the cursor disappears */
}
-
if (button === Button.RIGHT) {
/** Increase quantity for the current item and update UI */
- if (this.isItemManageMode()) {
- this.transferQuantities[option] =
- this.transferQuantities[option] === this.transferQuantitiesMax[option]
- ? 1
- : this.transferQuantities[option] + 1;
- this.updateOptions();
- success = this.setCursor(
- this.optionsCursor,
- ); /** Place again the cursor at the same position. Necessary, otherwise the cursor disappears */
- }
+ this.transferQuantities[option] =
+ this.transferQuantities[option] === this.transferQuantitiesMax[option]
+ ? 1
+ : this.transferQuantities[option] + 1;
+ this.updateOptions();
+ success = this.setCursor(
+ this.optionsCursor,
+ ); /** Place again the cursor at the same position. Necessary, otherwise the cursor disappears */
}
return success;
}
@@ -861,9 +860,9 @@ export class PartyUiHandler extends MessageUiHandler {
// This is only relevant for PartyUiMode.CHECK
// TODO: This risks hitting the other options (.MOVE_i and ALL) so does it? Do we need an extra check?
if (
- option >= PartyOption.FORM_CHANGE_ITEM &&
- globalScene.phaseManager.getCurrentPhase().is("SelectModifierPhase") &&
- this.partyUiMode === PartyUiMode.CHECK
+ option >= PartyOption.FORM_CHANGE_ITEM
+ && globalScene.phaseManager.getCurrentPhase().is("SelectModifierPhase")
+ && this.partyUiMode === PartyUiMode.CHECK
) {
const formChangeItemModifiers = this.getFormChangeItemsModifiers(pokemon);
const modifier = formChangeItemModifiers[option - PartyOption.FORM_CHANGE_ITEM];
@@ -913,8 +912,8 @@ export class PartyUiHandler extends MessageUiHandler {
// This is used when switching out using the Pokemon command (possibly holding a Baton held item). In this case there is no callback.
if (
- (option === PartyOption.PASS_BATON || option === PartyOption.SEND_OUT) &&
- this.partyUiMode === PartyUiMode.SWITCH
+ (option === PartyOption.PASS_BATON || option === PartyOption.SEND_OUT)
+ && this.partyUiMode === PartyUiMode.SWITCH
) {
this.clearOptions();
(globalScene.phaseManager.getCurrentPhase() as CommandPhase).handleCommand(
@@ -936,8 +935,8 @@ export class PartyUiHandler extends MessageUiHandler {
PartyOption.MOVE_3,
PartyOption.MOVE_4,
PartyOption.SELECT,
- ].includes(option) &&
- this.selectCallback
+ ].includes(option)
+ && this.selectCallback
) {
this.clearOptions();
const selectCallback = this.selectCallback;
@@ -976,10 +975,8 @@ export class PartyUiHandler extends MessageUiHandler {
return this.moveOptionCursor(button);
}
- if (button === Button.LEFT || button === Button.RIGHT) {
- if (this.isItemManageMode()) {
- return this.processModifierTransferModeLeftRightInput(button);
- }
+ if ((button === Button.LEFT || button === Button.RIGHT) && this.isItemManageMode()) {
+ return this.processModifierTransferModeLeftRightInput(button);
}
return false;
@@ -1045,15 +1042,15 @@ export class PartyUiHandler extends MessageUiHandler {
const ui = this.getUi();
if (this.cursor < 6) {
if (
- (this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER && !this.transferMode) ||
- this.partyUiMode === PartyUiMode.DISCARD
+ (this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER && !this.transferMode)
+ || this.partyUiMode === PartyUiMode.DISCARD
) {
/** Initialize item quantities for the selected Pokemon */
const itemModifiers = globalScene.findModifiers(
m =>
- m.is("PokemonHeldItemModifier") &&
- m.isTransferable &&
- m.pokemonId === globalScene.getPlayerParty()[this.cursor].id,
+ m.is("PokemonHeldItemModifier")
+ && m.isTransferable
+ && m.pokemonId === globalScene.getPlayerParty()[this.cursor].id,
) as PokemonHeldItemModifier[];
this.transferQuantities = itemModifiers.map(item => item.getStackCount());
this.transferQuantitiesMax = itemModifiers.map(item => item.getStackCount());
@@ -1095,8 +1092,8 @@ export class PartyUiHandler extends MessageUiHandler {
private processPartyCancelInput(): boolean {
const ui = this.getUi();
if (
- (this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER || this.partyUiMode === PartyUiMode.SPLICE) &&
- this.transferMode
+ (this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER || this.partyUiMode === PartyUiMode.SPLICE)
+ && this.transferMode
) {
this.clearTransfer();
ui.playSelect();
@@ -1262,11 +1259,9 @@ export class PartyUiHandler extends MessageUiHandler {
isScroll = true;
this.optionsScrollCursor++;
}
- } else {
- if (!cursor && this.optionsScrollCursor) {
- isScroll = true;
- this.optionsScrollCursor--;
- }
+ } else if (!cursor && this.optionsScrollCursor) {
+ isScroll = true;
+ this.optionsScrollCursor--;
}
if (isScroll && this.optionsScrollCursor === 1) {
this.optionsScrollCursor += isDown ? 1 : -1;
@@ -1371,8 +1366,8 @@ export class PartyUiHandler extends MessageUiHandler {
private allowBatonModifierSwitch(): boolean {
return !!(
- this.partyUiMode !== PartyUiMode.FAINT_SWITCH &&
- globalScene.findModifier(
+ this.partyUiMode !== PartyUiMode.FAINT_SWITCH
+ && globalScene.findModifier(
m => m.is("SwitchEffectTransferModifier") && m.pokemonId === globalScene.getPlayerField()[this.fieldIndex].id,
)
);
@@ -1383,9 +1378,9 @@ export class PartyUiHandler extends MessageUiHandler {
private isBatonPassMove(): boolean {
const lastMove: TurnMove | undefined = globalScene.getPlayerField()[this.fieldIndex].getLastXMoves()[0];
return (
- this.partyUiMode === PartyUiMode.FAINT_SWITCH &&
- lastMove?.result === MoveResult.SUCCESS &&
- allMoves[lastMove.move].getAttrs("ForceSwitchOutAttr")[0]?.isBatonPass()
+ this.partyUiMode === PartyUiMode.FAINT_SWITCH
+ && lastMove?.result === MoveResult.SUCCESS
+ && allMoves[lastMove.move].getAttrs("ForceSwitchOutAttr")[0]?.isBatonPass()
);
}
@@ -1402,7 +1397,7 @@ export class PartyUiHandler extends MessageUiHandler {
for (let m = 0; m < learnableMoves.length; m++) {
this.options.push(m);
}
- if (learnableMoves?.length) {
+ if (learnableMoves?.length > 0) {
// show the move overlay with info for the first move
this.moveInfoOverlay.show(allMoves[learnableMoves[0]]);
}
@@ -1431,8 +1426,10 @@ export class PartyUiHandler extends MessageUiHandler {
this.options.push(PartyOption.RENAME);
if (
- pokemonEvolutions.hasOwnProperty(pokemon.species.speciesId) ||
- (pokemon.isFusion() && pokemon.fusionSpecies && pokemonEvolutions.hasOwnProperty(pokemon.fusionSpecies.speciesId))
+ pokemonEvolutions.hasOwnProperty(pokemon.species.speciesId)
+ || (pokemon.isFusion()
+ && pokemon.fusionSpecies
+ && pokemonEvolutions.hasOwnProperty(pokemon.fusionSpecies.speciesId))
) {
this.options.push(PartyOption.UNPAUSE_EVOLUTION);
}
@@ -1465,7 +1462,7 @@ export class PartyUiHandler extends MessageUiHandler {
updateOptions(): void {
const pokemon = globalScene.getPlayerParty()[this.cursor];
- if (this.options.length) {
+ if (this.options.length > 0) {
this.options.splice(0, this.options.length);
this.optionsContainer.removeAll(true);
this.eraseOptionsCursor();
@@ -1611,14 +1608,12 @@ export class PartyUiHandler extends MessageUiHandler {
this.optionsContainer.add(this.optionsBg);
- const optionStartIndex = 0;
- const optionEndIndex = this.options.length;
-
let widestOptionWidth = 0;
const optionTexts: BBCodeText[] = [];
- for (let o = optionStartIndex; o < optionEndIndex; o++) {
- const option = this.options[this.options.length - (o + 1)];
+ // TODO: Refactor this iteration to not be fucking bizarre
+ for (let o = 0; o < this.options.length; o++) {
+ const option = this.options.at(-(o + 1))!;
let altText = false;
let optionName: string;
if (option === PartyOption.SCROLL_UP) {
@@ -1626,10 +1621,10 @@ export class PartyUiHandler extends MessageUiHandler {
} else if (option === PartyOption.SCROLL_DOWN) {
optionName = "↓";
} else if (
- (this.partyUiMode !== PartyUiMode.REMEMBER_MOVE_MODIFIER &&
- (this.partyUiMode !== PartyUiMode.MODIFIER_TRANSFER || this.transferMode) &&
- this.partyUiMode !== PartyUiMode.DISCARD) ||
- option === PartyOption.CANCEL
+ (this.partyUiMode !== PartyUiMode.REMEMBER_MOVE_MODIFIER
+ && (this.partyUiMode !== PartyUiMode.MODIFIER_TRANSFER || this.transferMode)
+ && this.partyUiMode !== PartyUiMode.DISCARD)
+ || option === PartyOption.CANCEL
) {
switch (option) {
case PartyOption.MOVE_1:
@@ -1653,12 +1648,10 @@ export class PartyUiHandler extends MessageUiHandler {
optionName = `${modifier.active ? i18next.t("partyUiHandler:deactivate") : i18next.t("partyUiHandler:activate")} ${modifier.type.name}`;
} else if (option === PartyOption.UNPAUSE_EVOLUTION) {
optionName = `${pokemon.pauseEvolutions ? i18next.t("partyUiHandler:unpauseEvolution") : i18next.t("partyUiHandler:pauseEvolution")}`;
+ } else if (this.localizedOptions.includes(option)) {
+ optionName = i18next.t(`partyUiHandler:${toCamelCase(PartyOption[option])}`);
} else {
- if (this.localizedOptions.includes(option)) {
- optionName = i18next.t(`partyUiHandler:${toCamelCase(PartyOption[option])}`);
- } else {
- optionName = toTitleCase(PartyOption[option]);
- }
+ optionName = toTitleCase(PartyOption[option]);
}
break;
}
@@ -1693,11 +1686,11 @@ export class PartyUiHandler extends MessageUiHandler {
const itemModifiers = this.getItemModifiers(pokemon);
const itemModifier = itemModifiers[option];
if (
- this.isItemManageMode() &&
- this.transferQuantitiesMax[option] > 1 &&
- !this.transferMode &&
- itemModifier !== undefined &&
- itemModifier.type.name === optionName
+ this.isItemManageMode()
+ && this.transferQuantitiesMax[option] > 1
+ && !this.transferMode
+ && itemModifier !== undefined
+ && itemModifier.type.name === optionName
) {
let amountText = ` (${this.transferQuantities[option]})`;
@@ -1736,11 +1729,12 @@ export class PartyUiHandler extends MessageUiHandler {
this.transferMode = false;
this.transferAll = false;
this.partySlots[this.transferCursor].setTransfer(false);
- for (let i = 0; i < this.partySlots.length; i++) {
- this.partySlots[i].slotDescriptionLabel.setVisible(false);
- this.partySlots[i].slotHpBar.setVisible(true);
- this.partySlots[i].slotHpOverlay.setVisible(true);
- this.partySlots[i].slotHpText.setVisible(true);
+ for (const partySlot of this.partySlots) {
+ partySlot.slotDescriptionLabel.setVisible(false);
+ partySlot.slotHpLabel.setVisible(true);
+ partySlot.slotHpBar.setVisible(true);
+ partySlot.slotHpOverlay.setVisible(true);
+ partySlot.slotHpText.setVisible(true);
}
}
@@ -1772,42 +1766,42 @@ export class PartyUiHandler extends MessageUiHandler {
getReleaseMessage(pokemonName: string): string {
const rand = randInt(128);
if (rand < 20) {
- return i18next.t("partyUiHandler:goodbye", { pokemonName: pokemonName });
+ return i18next.t("partyUiHandler:goodbye", { pokemonName });
}
if (rand < 40) {
- return i18next.t("partyUiHandler:byebye", { pokemonName: pokemonName });
+ return i18next.t("partyUiHandler:byebye", { pokemonName });
}
if (rand < 60) {
- return i18next.t("partyUiHandler:farewell", { pokemonName: pokemonName });
+ return i18next.t("partyUiHandler:farewell", { pokemonName });
}
if (rand < 80) {
- return i18next.t("partyUiHandler:soLong", { pokemonName: pokemonName });
+ return i18next.t("partyUiHandler:soLong", { pokemonName });
}
if (rand < 100) {
return i18next.t("partyUiHandler:thisIsWhereWePart", {
- pokemonName: pokemonName,
+ pokemonName,
});
}
if (rand < 108) {
return i18next.t("partyUiHandler:illMissYou", {
- pokemonName: pokemonName,
+ pokemonName,
});
}
if (rand < 116) {
return i18next.t("partyUiHandler:illNeverForgetYou", {
- pokemonName: pokemonName,
+ pokemonName,
});
}
if (rand < 124) {
return i18next.t("partyUiHandler:untilWeMeetAgain", {
- pokemonName: pokemonName,
+ pokemonName,
});
}
if (rand < 127) {
- return i18next.t("partyUiHandler:sayonara", { pokemonName: pokemonName });
+ return i18next.t("partyUiHandler:sayonara", { pokemonName });
}
return i18next.t("partyUiHandler:smellYaLater", {
- pokemonName: pokemonName,
+ pokemonName,
});
}
@@ -1838,9 +1832,9 @@ export class PartyUiHandler extends MessageUiHandler {
getOptionsCursorWithScroll(): number {
return (
- this.optionsCursor +
- this.optionsScrollCursor +
- (this.options && this.options[0] === PartyOption.SCROLL_UP ? -1 : 0)
+ this.optionsCursor
+ + this.optionsScrollCursor
+ + (this.options && this.options[0] === PartyOption.SCROLL_UP ? -1 : 0)
);
}
@@ -1890,6 +1884,7 @@ class PartySlot extends Phaser.GameObjects.Container {
private slotBg: Phaser.GameObjects.Image;
private slotPb: Phaser.GameObjects.Sprite;
public slotName: Phaser.GameObjects.Text;
+ public slotHpLabel: Phaser.GameObjects.Image;
public slotHpBar: Phaser.GameObjects.Image;
public slotHpOverlay: Phaser.GameObjects.Sprite;
public slotHpText: Phaser.GameObjects.Text;
@@ -2042,7 +2037,7 @@ class PartySlot extends Phaser.GameObjects.Container {
this.slotName.setOrigin(0);
const slotLevelLabel = globalScene.add
- .image(0, 0, "party_slot_overlay_lv")
+ .image(0, 0, getLocalizedSpriteKey("party_slot_overlay_lv"))
.setPositionRelative(this.slotBg, levelLabelPosition.x, levelLabelPosition.y)
.setOrigin(0);
@@ -2104,6 +2099,12 @@ class PartySlot extends Phaser.GameObjects.Container {
}
}
+ this.slotHpLabel = globalScene.add
+ .image(0, 0, getLocalizedSpriteKey("party_slot_overlay_hp"))
+ .setOrigin(1, 0)
+ .setVisible(false)
+ .setPositionRelative(this.slotBg, hpBarPosition.x + 15, hpBarPosition.y);
+
this.slotHpBar = globalScene.add
.image(0, 0, "party_slot_hp_bar")
.setOrigin(0)
@@ -2133,14 +2134,22 @@ class PartySlot extends Phaser.GameObjects.Container {
.setVisible(false)
.setPositionRelative(this.slotBg, descriptionLabelPosition.x, descriptionLabelPosition.y);
- slotInfoContainer.add([this.slotHpBar, this.slotHpOverlay, this.slotHpText, this.slotDescriptionLabel]);
+ slotInfoContainer.add([
+ this.slotHpLabel,
+ this.slotHpBar,
+ this.slotHpOverlay,
+ this.slotHpText,
+ this.slotDescriptionLabel,
+ ]);
if (partyUiMode !== PartyUiMode.TM_MODIFIER) {
this.slotDescriptionLabel.setVisible(false);
+ this.slotHpLabel.setVisible(true);
this.slotHpBar.setVisible(true);
this.slotHpOverlay.setVisible(true);
this.slotHpText.setVisible(true);
} else {
+ this.slotHpLabel.setVisible(false);
this.slotHpBar.setVisible(false);
this.slotHpOverlay.setVisible(false);
this.slotHpText.setVisible(false);
diff --git a/src/ui/pokedex-scan-ui-handler.ts b/src/ui/handlers/pokedex-scan-ui-handler.ts
similarity index 90%
rename from src/ui/pokedex-scan-ui-handler.ts
rename to src/ui/handlers/pokedex-scan-ui-handler.ts
index 4f606cbcbb0..bb3cec5bb56 100644
--- a/src/ui/pokedex-scan-ui-handler.ts
+++ b/src/ui/handlers/pokedex-scan-ui-handler.ts
@@ -1,11 +1,11 @@
import { allAbilities, allMoves, allSpecies } from "#data/data-lists";
import { UiMode } from "#enums/ui-mode";
import type { PlayerPokemon } from "#field/pokemon";
-import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
-import { FilterTextRow } from "#ui/filter-text";
-import type { InputFieldConfig } from "#ui/form-modal-ui-handler";
-import { FormModalUiHandler } from "#ui/form-modal-ui-handler";
-import type { ModalConfig } from "#ui/modal-ui-handler";
+import { FilterTextRow } from "#ui/containers/filter-text";
+import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler";
+import type { InputFieldConfig } from "#ui/handlers/form-modal-ui-handler";
+import { FormModalUiHandler } from "#ui/handlers/form-modal-ui-handler";
+import type { ModalConfig } from "#ui/handlers/modal-ui-handler";
import { isNullOrUndefined } from "#utils/common";
import i18next from "i18next";
@@ -106,14 +106,10 @@ export class PokedexScanUiHandler extends FormModalUiHandler {
this.reduceKeys();
- setTimeout(() => {
- input.setFocus(); // Focus after a short delay to avoid unwanted input
- }, 50);
-
input.on("keydown", (inputObject, evt: KeyboardEvent) => {
if (
- ["escape", "space"].some(v => v === evt.key.toLowerCase() || v === evt.code.toLowerCase()) &&
- ui.getMode() === UiMode.AUTO_COMPLETE
+ ["escape", "space"].some(v => v === evt.key.toLowerCase() || v === evt.code.toLowerCase())
+ && ui.getMode() === UiMode.AUTO_COMPLETE
) {
// Delete autocomplete list and recovery focus.
inputObject.on("blur", () => inputObject.node.focus(), { once: true });
@@ -148,7 +144,7 @@ export class PokedexScanUiHandler extends FormModalUiHandler {
if (options.length > 0) {
const modalOpts = {
- options: options,
+ options,
maxOptions: 5,
modalContainer: this.modalContainer,
};
diff --git a/src/ui/pokedex-ui-handler.ts b/src/ui/handlers/pokedex-ui-handler.ts
similarity index 92%
rename from src/ui/pokedex-ui-handler.ts
rename to src/ui/handlers/pokedex-ui-handler.ts
index 046ca564709..3500fa97436 100644
--- a/src/ui/pokedex-ui-handler.ts
+++ b/src/ui/handlers/pokedex-ui-handler.ts
@@ -34,14 +34,21 @@ import { getVariantIcon, getVariantTint } from "#sprites/variant";
import type { DexAttrProps, StarterAttributes } from "#system/game-data";
import { SettingKeyboard } from "#system/settings-keyboard";
import type { DexEntry } from "#types/dex-data";
-import type { OptionSelectConfig } from "#ui/abstract-option-select-ui-handler";
-import { DropDown, DropDownLabel, DropDownOption, DropDownState, DropDownType, SortCriteria } from "#ui/dropdown";
-import { FilterBar } from "#ui/filter-bar";
-import { FilterText, FilterTextRow } from "#ui/filter-text";
-import { MessageUiHandler } from "#ui/message-ui-handler";
-import { PokedexMonContainer } from "#ui/pokedex-mon-container";
-import { PokemonIconAnimHandler, PokemonIconAnimMode } from "#ui/pokemon-icon-anim-handler";
-import { ScrollBar } from "#ui/scroll-bar";
+import {
+ DropDown,
+ DropDownLabel,
+ DropDownOption,
+ DropDownState,
+ DropDownType,
+ SortCriteria,
+} from "#ui/containers/dropdown";
+import { FilterBar } from "#ui/containers/filter-bar";
+import { FilterText, FilterTextRow } from "#ui/containers/filter-text";
+import { PokedexMonContainer } from "#ui/containers/pokedex-mon-container";
+import { ScrollBar } from "#ui/containers/scroll-bar";
+import type { OptionSelectConfig } from "#ui/handlers/abstract-option-select-ui-handler";
+import { MessageUiHandler } from "#ui/handlers/message-ui-handler";
+import { PokemonIconAnimHandler, PokemonIconAnimMode } from "#ui/handlers/pokemon-icon-anim-handler";
import { addTextObject, getTextColor } from "#ui/text";
import { addWindow } from "#ui/ui-theme";
import { BooleanHolder, fixedInt, getLocalizedSpriteKey, padInt, randIntRange, rgbHexToRgba } from "#utils/common";
@@ -148,7 +155,7 @@ function calcStarterPosition(index: number): { x: number; y: number } {
const x = (index % 9) * 18;
const y = yOffset + Math.floor(index / 9) * height;
- return { x: x, y: y };
+ return { x, y };
}
interface SpeciesDetails {
@@ -642,7 +649,7 @@ export class PokedexUiHandler extends MessageUiHandler {
this.pokerusSpecies = getPokerusStarters();
// When calling with "refresh", we do not reset the cursor and filters
- if (args.length >= 1 && args[0] === "refresh") {
+ if (args.length > 0 && args[0] === "refresh") {
return false;
}
@@ -714,20 +721,21 @@ export class PokedexUiHandler extends MessageUiHandler {
hasShiny && caughtAttr & DexAttr.VARIANT_3,
];
if (
- Number.isNaN(starterAttributes.variant) ||
- starterAttributes.variant < 0 ||
- !unlockedVariants[starterAttributes.variant]
+ Number.isNaN(starterAttributes.variant)
+ || starterAttributes.variant < 0
+ || !unlockedVariants[starterAttributes.variant]
) {
// variant value is invalid or requested variant wasn't unlocked, purging setting
starterAttributes.variant = undefined;
}
}
- if (starterAttributes.female !== undefined) {
- if (!(starterAttributes.female ? caughtAttr & DexAttr.FEMALE : caughtAttr & DexAttr.MALE)) {
- // requested gender wasn't unlocked, purging setting
- starterAttributes.female = undefined;
- }
+ if (
+ starterAttributes.female !== undefined
+ && !(starterAttributes.female ? caughtAttr & DexAttr.FEMALE : caughtAttr & DexAttr.MALE)
+ ) {
+ // requested gender wasn't unlocked, purging setting
+ starterAttributes.female = undefined;
}
if (starterAttributes.ability !== undefined) {
@@ -751,9 +759,9 @@ export class PokedexUiHandler extends MessageUiHandler {
const selectedForm = starterAttributes.form;
if (
- selectedForm !== undefined &&
- (!species.forms[selectedForm]?.isStarterSelectable ||
- !(caughtAttr & globalScene.gameData.getFormAttr(selectedForm)))
+ selectedForm !== undefined
+ && (!species.forms[selectedForm]?.isStarterSelectable
+ || !(caughtAttr & globalScene.gameData.getFormAttr(selectedForm)))
) {
// requested form wasn't unlocked/isn't a starter form, purging setting
starterAttributes.form = undefined;
@@ -803,7 +811,7 @@ export class PokedexUiHandler extends MessageUiHandler {
this.message.setY(singleLine ? -22 : -37);
}
- this.starterSelectMessageBoxContainer.setVisible(!!text?.length);
+ this.starterSelectMessageBoxContainer.setVisible(text?.length > 0);
}
isSeen(species: PokemonSpecies, dexEntry: DexEntry, seenFilter?: boolean): boolean {
@@ -853,8 +861,8 @@ export class PokedexUiHandler extends MessageUiHandler {
const starterData = globalScene.gameData.starterData[this.getStarterSpeciesId(speciesId)];
return (
- starterData.candyCount >= getPassiveCandyCount(speciesStarterCosts[this.getStarterSpeciesId(speciesId)]) &&
- !(starterData.passiveAttr & PassiveAttr.UNLOCKED)
+ starterData.candyCount >= getPassiveCandyCount(speciesStarterCosts[this.getStarterSpeciesId(speciesId)])
+ && !(starterData.passiveAttr & PassiveAttr.UNLOCKED)
);
}
@@ -868,8 +876,8 @@ export class PokedexUiHandler extends MessageUiHandler {
const starterData = globalScene.gameData.starterData[this.getStarterSpeciesId(speciesId)];
return (
- starterData.candyCount >=
- getValueReductionCandyCounts(speciesStarterCosts[this.getStarterSpeciesId(speciesId)])[
+ starterData.candyCount
+ >= getValueReductionCandyCounts(speciesStarterCosts[this.getStarterSpeciesId(speciesId)])[
starterData.valueReduction
] && starterData.valueReduction < valueReductionMax
);
@@ -930,9 +938,9 @@ export class PokedexUiHandler extends MessageUiHandler {
};
if (
- this.isPassiveAvailable(species.speciesId) ||
- (globalScene.candyUpgradeNotification === 2 &&
- (this.isValueReductionAvailable(species.speciesId) || this.isSameSpeciesEggAvailable(species.speciesId)))
+ this.isPassiveAvailable(species.speciesId)
+ || (globalScene.candyUpgradeNotification === 2
+ && (this.isValueReductionAvailable(species.speciesId) || this.isSameSpeciesEggAvailable(species.speciesId)))
) {
const chain = globalScene.tweens.chain(tweenChain);
if (!startPaused) {
@@ -949,9 +957,9 @@ export class PokedexUiHandler extends MessageUiHandler {
const slotVisible = !!species?.speciesId;
if (
- !species ||
- globalScene.candyUpgradeNotification === 0 ||
- species.speciesId !== species.getRootSpeciesId(false)
+ !species
+ || globalScene.candyUpgradeNotification === 0
+ || species.speciesId !== species.getRootSpeciesId(false)
) {
starter.candyUpgradeIcon.setVisible(false);
starter.candyUpgradeOverlayIcon.setVisible(false);
@@ -1018,8 +1026,8 @@ export class PokedexUiHandler extends MessageUiHandler {
this.updateStarters();
success = true;
} else if (
- this.filterTextMode &&
- !(this.filterText.getValue(this.filterTextCursor) === this.filterText.defaultText)
+ this.filterTextMode
+ && !(this.filterText.getValue(this.filterTextCursor) === this.filterText.defaultText)
) {
this.filterText.resetSelection(this.filterTextCursor);
success = true;
@@ -1207,78 +1215,76 @@ export class PokedexUiHandler extends MessageUiHandler {
break;
}
}
+ } else if (button === Button.ACTION) {
+ ui.setOverlayMode(UiMode.POKEDEX_PAGE, this.lastSpecies, null, this.filteredIndices);
+ success = true;
} else {
- if (button === Button.ACTION) {
- ui.setOverlayMode(UiMode.POKEDEX_PAGE, this.lastSpecies, null, this.filteredIndices);
- success = true;
- } else {
- switch (button) {
- case Button.UP:
- if (currentRow > 0) {
- if (this.scrollCursor > 0 && currentRow - this.scrollCursor === 0) {
- this.scrollCursor--;
- this.updateScroll();
- success = this.setCursor(this.cursor);
- } else {
- success = this.setCursor(this.cursor - 9);
- }
- } else {
- this.filterBarCursor = this.filterBar.getNearestFilter(this.pokemonContainers[this.cursor]);
- this.setFilterMode(true);
- success = true;
- }
- break;
- case Button.DOWN:
- if (currentRow < numOfRows - 1 && this.cursor + 9 < this.filteredPokemonData.length) {
- // not last row
- if (currentRow - this.scrollCursor === 8) {
- // last row of visible pokemon
- this.scrollCursor++;
- this.updateScroll();
- success = this.setCursor(this.cursor);
- } else {
- success = this.setCursor(this.cursor + 9);
- }
- } else if (numOfRows > 1) {
- // DOWN from last row of pokemon > Wrap around to first row
- this.scrollCursor = 0;
+ switch (button) {
+ case Button.UP:
+ if (currentRow > 0) {
+ if (this.scrollCursor > 0 && currentRow - this.scrollCursor === 0) {
+ this.scrollCursor--;
this.updateScroll();
- success = this.setCursor(this.cursor % 9);
+ success = this.setCursor(this.cursor);
} else {
- // DOWN from single row of pokemon > Go to filters
- this.filterBarCursor = this.filterBar.getNearestFilter(this.pokemonContainers[this.cursor]);
- this.setFilterMode(true);
- success = true;
+ success = this.setCursor(this.cursor - 9);
}
- break;
- case Button.LEFT:
- if (this.cursor % 9 !== 0) {
- success = this.setCursor(this.cursor - 1);
- } else {
- // LEFT from filtered pokemon, on the left edge
- this.filterTextCursor = this.filterText.getNearestFilter(this.pokemonContainers[this.cursor]);
- this.setFilterTextMode(true);
- success = true;
- }
- break;
- case Button.RIGHT:
- // is not right edge
- if (this.cursor % 9 < (currentRow < numOfRows - 1 ? 8 : (numberOfStarters - 1) % 9)) {
- success = this.setCursor(this.cursor + 1);
- } else {
- // RIGHT from filtered pokemon, on the right edge
- this.filterTextCursor = this.filterText.getNearestFilter(this.pokemonContainers[this.cursor]);
- this.setFilterTextMode(true);
- success = true;
- }
- break;
- case Button.CYCLE_FORM: {
- const species = this.pokemonContainers[this.cursor].species;
- if (this.canShowFormTray) {
- success = this.openFormTray(species);
- }
- break;
+ } else {
+ this.filterBarCursor = this.filterBar.getNearestFilter(this.pokemonContainers[this.cursor]);
+ this.setFilterMode(true);
+ success = true;
}
+ break;
+ case Button.DOWN:
+ if (currentRow < numOfRows - 1 && this.cursor + 9 < this.filteredPokemonData.length) {
+ // not last row
+ if (currentRow - this.scrollCursor === 8) {
+ // last row of visible pokemon
+ this.scrollCursor++;
+ this.updateScroll();
+ success = this.setCursor(this.cursor);
+ } else {
+ success = this.setCursor(this.cursor + 9);
+ }
+ } else if (numOfRows > 1) {
+ // DOWN from last row of pokemon > Wrap around to first row
+ this.scrollCursor = 0;
+ this.updateScroll();
+ success = this.setCursor(this.cursor % 9);
+ } else {
+ // DOWN from single row of pokemon > Go to filters
+ this.filterBarCursor = this.filterBar.getNearestFilter(this.pokemonContainers[this.cursor]);
+ this.setFilterMode(true);
+ success = true;
+ }
+ break;
+ case Button.LEFT:
+ if (this.cursor % 9 !== 0) {
+ success = this.setCursor(this.cursor - 1);
+ } else {
+ // LEFT from filtered pokemon, on the left edge
+ this.filterTextCursor = this.filterText.getNearestFilter(this.pokemonContainers[this.cursor]);
+ this.setFilterTextMode(true);
+ success = true;
+ }
+ break;
+ case Button.RIGHT:
+ // is not right edge
+ if (this.cursor % 9 < (currentRow < numOfRows - 1 ? 8 : (numberOfStarters - 1) % 9)) {
+ success = this.setCursor(this.cursor + 1);
+ } else {
+ // RIGHT from filtered pokemon, on the right edge
+ this.filterTextCursor = this.filterText.getNearestFilter(this.pokemonContainers[this.cursor]);
+ this.setFilterTextMode(true);
+ success = true;
+ }
+ break;
+ case Button.CYCLE_FORM: {
+ const species = this.pokemonContainers[this.cursor].species;
+ if (this.canShowFormTray) {
+ success = this.openFormTray(species);
+ }
+ break;
}
}
}
@@ -1349,8 +1355,8 @@ export class PokedexUiHandler extends MessageUiHandler {
// Returns true if one of the forms has the requested move
hasFormLevelMove(form: PokemonForm, selectedMove: string): boolean {
if (
- !pokemonFormLevelMoves.hasOwnProperty(form.speciesId) ||
- !pokemonFormLevelMoves[form.speciesId].hasOwnProperty(form.formIndex)
+ !pokemonFormLevelMoves.hasOwnProperty(form.speciesId)
+ || !pokemonFormLevelMoves[form.speciesId].hasOwnProperty(form.formIndex)
) {
return false;
}
@@ -1376,17 +1382,17 @@ export class PokedexUiHandler extends MessageUiHandler {
const props = this.getSanitizedProps(globalScene.gameData.getSpeciesDexAttrProps(species, currentDexAttr));
const data: ContainerData = {
- species: species,
+ species,
cost: globalScene.gameData.getSpeciesStarterValue(starterId),
- props: props,
+ props,
};
// First, ensure you have the caught attributes for the species else default to bigint 0
// TODO: This might be removed depending on how accessible we want the pokedex function to be
const caughtAttr =
- (globalScene.gameData.dexData[species.speciesId]?.caughtAttr || BigInt(0)) &
- (globalScene.gameData.dexData[this.getStarterSpeciesId(species.speciesId)]?.caughtAttr || BigInt(0)) &
- species.getFullUnlocksData();
+ (globalScene.gameData.dexData[species.speciesId]?.caughtAttr || BigInt(0))
+ & (globalScene.gameData.dexData[this.getStarterSpeciesId(species.speciesId)]?.caughtAttr || BigInt(0))
+ & species.getFullUnlocksData();
const starterData = globalScene.gameData.starterData[starterId];
const isStarterProgressable = speciesEggMoves.hasOwnProperty(starterId);
@@ -1463,8 +1469,8 @@ export class PokedexUiHandler extends MessageUiHandler {
// If both fields have been set to the same ability, show both ability and passive
const fitsAbilities =
- (fitsAbility1 && (fitsPassive2 || selectedAbility2 === this.filterText.defaultText)) ||
- (fitsAbility2 && (fitsPassive1 || selectedAbility1 === this.filterText.defaultText));
+ (fitsAbility1 && (fitsPassive2 || selectedAbility2 === this.filterText.defaultText))
+ || (fitsAbility2 && (fitsPassive1 || selectedAbility1 === this.filterText.defaultText));
if (fitsPassive1 || fitsPassive2) {
if (fitsPassive1) {
@@ -1473,12 +1479,10 @@ export class PokedexUiHandler extends MessageUiHandler {
} else {
data.passive1 = false;
}
+ } else if (starterData.passiveAttr > 0) {
+ data.passive2 = true;
} else {
- if (starterData.passiveAttr > 0) {
- data.passive2 = true;
- } else {
- data.passive2 = false;
- }
+ data.passive2 = false;
}
}
@@ -1506,8 +1510,8 @@ export class PokedexUiHandler extends MessageUiHandler {
}
const showNoBiome = !!(biomes.length === 0 && this.filterBar.getVals(DropDownColumn.BIOME).length === 36);
const fitsBiome =
- this.filterBar.getVals(DropDownColumn.BIOME).some(item => biomes.includes(indexToBiome.get(item) ?? "")) ||
- showNoBiome;
+ this.filterBar.getVals(DropDownColumn.BIOME).some(item => biomes.includes(indexToBiome.get(item) ?? ""))
+ || showNoBiome;
// Caught / Shiny filter
const isNonShinyCaught = !!(caughtAttr & DexAttr.NON_SHINY);
@@ -1694,23 +1698,23 @@ export class PokedexUiHandler extends MessageUiHandler {
});
if (
- fitsName &&
- fitsAbilities &&
- fitsMoves &&
- fitsGen &&
- fitsBiome &&
- fitsType &&
- fitsCaught &&
- fitsPassive &&
- fitsCostReduction &&
- fitsStarter &&
- fitsFavorite &&
- fitsWin &&
- fitsHA &&
- fitsSeen &&
- fitsEncountered &&
- fitsEgg &&
- fitsPokerus
+ fitsName
+ && fitsAbilities
+ && fitsMoves
+ && fitsGen
+ && fitsBiome
+ && fitsType
+ && fitsCaught
+ && fitsPassive
+ && fitsCostReduction
+ && fitsStarter
+ && fitsFavorite
+ && fitsWin
+ && fitsHA
+ && fitsSeen
+ && fitsEncountered
+ && fitsEgg
+ && fitsPokerus
) {
this.filteredPokemonData.push(data);
}
@@ -1736,26 +1740,26 @@ export class PokedexUiHandler extends MessageUiHandler {
}
case SortCriteria.IV: {
const avgIVsA =
- globalScene.gameData.dexData[a.species.speciesId].ivs.reduce((a, b) => a + b, 0) /
- globalScene.gameData.dexData[a.species.speciesId].ivs.length;
+ globalScene.gameData.dexData[a.species.speciesId].ivs.reduce((a, b) => a + b, 0)
+ / globalScene.gameData.dexData[a.species.speciesId].ivs.length;
const avgIVsB =
- globalScene.gameData.dexData[b.species.speciesId].ivs.reduce((a, b) => a + b, 0) /
- globalScene.gameData.dexData[b.species.speciesId].ivs.length;
+ globalScene.gameData.dexData[b.species.speciesId].ivs.reduce((a, b) => a + b, 0)
+ / globalScene.gameData.dexData[b.species.speciesId].ivs.length;
return (avgIVsA - avgIVsB) * -sort.dir;
}
case SortCriteria.NAME:
return a.species.name.localeCompare(b.species.name) * -sort.dir;
case SortCriteria.CAUGHT:
return (
- (globalScene.gameData.dexData[a.species.speciesId].caughtCount -
- globalScene.gameData.dexData[b.species.speciesId].caughtCount) *
- -sort.dir
+ (globalScene.gameData.dexData[a.species.speciesId].caughtCount
+ - globalScene.gameData.dexData[b.species.speciesId].caughtCount)
+ * -sort.dir
);
case SortCriteria.HATCHED:
return (
- (globalScene.gameData.dexData[this.getStarterSpeciesId(a.species.speciesId)].hatchedCount -
- globalScene.gameData.dexData[this.getStarterSpeciesId(b.species.speciesId)].hatchedCount) *
- -sort.dir
+ (globalScene.gameData.dexData[this.getStarterSpeciesId(a.species.speciesId)].hatchedCount
+ - globalScene.gameData.dexData[this.getStarterSpeciesId(b.species.speciesId)].hatchedCount)
+ * -sort.dir
);
default:
break;
@@ -1800,9 +1804,9 @@ export class PokedexUiHandler extends MessageUiHandler {
const speciesId = data.species.speciesId;
const dexEntry = globalScene.gameData.dexData[speciesId];
const caughtAttr =
- dexEntry.caughtAttr &
- globalScene.gameData.dexData[this.getStarterSpeciesId(speciesId)].caughtAttr &
- data.species.getFullUnlocksData();
+ dexEntry.caughtAttr
+ & globalScene.gameData.dexData[this.getStarterSpeciesId(speciesId)].caughtAttr
+ & data.species.getFullUnlocksData();
if (caughtAttr & data.species.getFullUnlocksData() || globalScene.dexForDevs) {
container.icon.clearTint();
@@ -2063,7 +2067,7 @@ export class PokedexUiHandler extends MessageUiHandler {
const species = this.lastSpecies;
const formIndex = this.trayForms[cursor].formIndex;
- this.setSpeciesDetails(species, { formIndex: formIndex });
+ this.setSpeciesDetails(species, { formIndex });
return changed;
}
@@ -2121,8 +2125,8 @@ export class PokedexUiHandler extends MessageUiHandler {
}
if (
- species &&
- (this.speciesStarterDexEntry?.seenAttr || this.speciesStarterDexEntry?.caughtAttr || globalScene.dexForDevs)
+ species
+ && (this.speciesStarterDexEntry?.seenAttr || this.speciesStarterDexEntry?.caughtAttr || globalScene.dexForDevs)
) {
this.pokemonNumberText.setText(i18next.t("pokedexUiHandler:pokemonNumber") + padInt(species.speciesId, 4));
@@ -2187,9 +2191,9 @@ export class PokedexUiHandler extends MessageUiHandler {
if (species) {
const dexEntry = globalScene.gameData.dexData[species.speciesId];
const caughtAttr =
- dexEntry.caughtAttr &
- globalScene.gameData.dexData[this.getStarterSpeciesId(species.speciesId)].caughtAttr &
- species.getFullUnlocksData();
+ dexEntry.caughtAttr
+ & globalScene.gameData.dexData[this.getStarterSpeciesId(species.speciesId)].caughtAttr
+ & species.getFullUnlocksData();
if (caughtAttr) {
const props = this.getSanitizedProps(
@@ -2359,17 +2363,17 @@ export class PokedexUiHandler extends MessageUiHandler {
let props = 0n;
const species = allSpecies.find(sp => sp.speciesId === speciesId);
const caughtAttr =
- globalScene.gameData.dexData[speciesId].caughtAttr &
- globalScene.gameData.dexData[this.getStarterSpeciesId(speciesId)].caughtAttr &
- (species?.getFullUnlocksData() ?? 0n);
+ globalScene.gameData.dexData[speciesId].caughtAttr
+ & globalScene.gameData.dexData[this.getStarterSpeciesId(speciesId)].caughtAttr
+ & (species?.getFullUnlocksData() ?? 0n);
/* this checks the gender of the pokemon; this works by checking a) that the starter preferences for the species exist, and if so, is it female. If so, it'll add DexAttr.FEMALE to our temp props
* It then checks b) if the caughtAttr for the pokemon is female and NOT male - this means that the ONLY gender we've gotten is female, and we need to add DexAttr.FEMALE to our temp props
* If neither of these pass, we add DexAttr.MALE to our temp props
*/
if (
- this.starterPreferences[speciesId]?.female ||
- ((caughtAttr & DexAttr.FEMALE) > 0n && (caughtAttr & DexAttr.MALE) === 0n)
+ this.starterPreferences[speciesId]?.female
+ || ((caughtAttr & DexAttr.FEMALE) > 0n && (caughtAttr & DexAttr.MALE) === 0n)
) {
props += DexAttr.FEMALE;
} else {
@@ -2379,23 +2383,21 @@ export class PokedexUiHandler extends MessageUiHandler {
* If they're not there, it enables shiny state by default if any shiny was caught
*/
if (
- this.starterPreferences[speciesId]?.shiny ||
- ((caughtAttr & DexAttr.SHINY) > 0n && this.starterPreferences[speciesId]?.shiny !== false)
+ this.starterPreferences[speciesId]?.shiny
+ || ((caughtAttr & DexAttr.SHINY) > 0n && this.starterPreferences[speciesId]?.shiny !== false)
) {
props += DexAttr.SHINY;
if (this.starterPreferences[speciesId]?.variant !== undefined) {
props += BigInt(Math.pow(2, this.starterPreferences[speciesId]?.variant)) * DexAttr.DEFAULT_VARIANT;
- } else {
+ } else if ((caughtAttr & DexAttr.VARIANT_3) > 0) {
/* This calculates the correct variant if there's no starter preferences for it.
* This gets the highest tier variant that you've caught and adds it to the temp props
*/
- if ((caughtAttr & DexAttr.VARIANT_3) > 0) {
- props += DexAttr.VARIANT_3;
- } else if ((caughtAttr & DexAttr.VARIANT_2) > 0) {
- props += DexAttr.VARIANT_2;
- } else {
- props += DexAttr.DEFAULT_VARIANT;
- }
+ props += DexAttr.VARIANT_3;
+ } else if ((caughtAttr & DexAttr.VARIANT_2) > 0) {
+ props += DexAttr.VARIANT_2;
+ } else {
+ props += DexAttr.DEFAULT_VARIANT;
}
} else {
props += DexAttr.NON_SHINY;
diff --git a/src/ui/pokemon-icon-anim-handler.ts b/src/ui/handlers/pokemon-icon-anim-handler.ts
similarity index 100%
rename from src/ui/pokemon-icon-anim-handler.ts
rename to src/ui/handlers/pokemon-icon-anim-handler.ts
diff --git a/src/ui/registration-form-ui-handler.ts b/src/ui/handlers/registration-form-ui-handler.ts
similarity index 94%
rename from src/ui/registration-form-ui-handler.ts
rename to src/ui/handlers/registration-form-ui-handler.ts
index 2c8080d534d..d424e44b455 100644
--- a/src/ui/registration-form-ui-handler.ts
+++ b/src/ui/handlers/registration-form-ui-handler.ts
@@ -2,9 +2,9 @@ import { pokerogueApi } from "#api/pokerogue-api";
import { globalScene } from "#app/global-scene";
import { TextStyle } from "#enums/text-style";
import { UiMode } from "#enums/ui-mode";
-import type { InputFieldConfig } from "#ui/form-modal-ui-handler";
-import { FormModalUiHandler } from "#ui/form-modal-ui-handler";
-import type { ModalConfig } from "#ui/modal-ui-handler";
+import type { InputFieldConfig } from "#ui/handlers/form-modal-ui-handler";
+import { FormModalUiHandler } from "#ui/handlers/form-modal-ui-handler";
+import type { ModalConfig } from "#ui/handlers/modal-ui-handler";
import { addTextObject } from "#ui/text";
import i18next from "i18next";
diff --git a/src/ui/rename-form-ui-handler.ts b/src/ui/handlers/rename-form-ui-handler.ts
similarity index 87%
rename from src/ui/rename-form-ui-handler.ts
rename to src/ui/handlers/rename-form-ui-handler.ts
index 9da5b0e8554..f1d9ae3c981 100644
--- a/src/ui/rename-form-ui-handler.ts
+++ b/src/ui/handlers/rename-form-ui-handler.ts
@@ -1,7 +1,7 @@
import type { PlayerPokemon } from "#field/pokemon";
-import type { InputFieldConfig } from "#ui/form-modal-ui-handler";
-import { FormModalUiHandler } from "#ui/form-modal-ui-handler";
-import type { ModalConfig } from "#ui/modal-ui-handler";
+import type { InputFieldConfig } from "#ui/handlers/form-modal-ui-handler";
+import { FormModalUiHandler } from "#ui/handlers/form-modal-ui-handler";
+import type { ModalConfig } from "#ui/handlers/modal-ui-handler";
import i18next from "i18next";
export class RenameFormUiHandler extends FormModalUiHandler {
diff --git a/src/ui/rename-run-ui-handler.ts b/src/ui/handlers/rename-run-ui-handler.ts
similarity index 89%
rename from src/ui/rename-run-ui-handler.ts
rename to src/ui/handlers/rename-run-ui-handler.ts
index a94b7b08fb9..43094d3cf60 100644
--- a/src/ui/rename-run-ui-handler.ts
+++ b/src/ui/handlers/rename-run-ui-handler.ts
@@ -1,6 +1,5 @@
import i18next from "i18next";
-import type { InputFieldConfig } from "./form-modal-ui-handler";
-import { FormModalUiHandler } from "./form-modal-ui-handler";
+import { FormModalUiHandler, type InputFieldConfig } from "./form-modal-ui-handler";
import type { ModalConfig } from "./modal-ui-handler";
export class RenameRunFormUiHandler extends FormModalUiHandler {
@@ -37,7 +36,7 @@ export class RenameRunFormUiHandler extends FormModalUiHandler {
if (!super.show(args)) {
return false;
}
- if (this.inputs?.length) {
+ if (this.inputs?.length > 0) {
this.inputs.forEach(input => {
input.text = "";
});
diff --git a/src/ui/run-history-ui-handler.ts b/src/ui/handlers/run-history-ui-handler.ts
similarity index 97%
rename from src/ui/run-history-ui-handler.ts
rename to src/ui/handlers/run-history-ui-handler.ts
index 6f4d9024832..cec2b95cdd5 100644
--- a/src/ui/run-history-ui-handler.ts
+++ b/src/ui/handlers/run-history-ui-handler.ts
@@ -8,8 +8,8 @@ import { TrainerVariant } from "#enums/trainer-variant";
import { UiMode } from "#enums/ui-mode";
import type { RunEntry } from "#system/game-data";
import type { PokemonData } from "#system/pokemon-data";
-import { MessageUiHandler } from "#ui/message-ui-handler";
-import { RunDisplayMode } from "#ui/run-info-ui-handler";
+import { MessageUiHandler } from "#ui/handlers/message-ui-handler";
+import { RunDisplayMode } from "#ui/handlers/run-info-ui-handler";
import { addTextObject } from "#ui/text";
import { addWindow } from "#ui/ui-theme";
import { fixedInt, formatLargeNumber } from "#utils/common";
@@ -32,8 +32,6 @@ export class RunHistoryUiHandler extends MessageUiHandler {
private runsContainer: Phaser.GameObjects.Container;
private runs: RunEntryContainer[];
- private runSelectCallback: RunSelectCallback | null;
-
private scrollCursor = 0;
private cursorObj: Phaser.GameObjects.NineSlice | null;
@@ -118,7 +116,6 @@ export class RunHistoryUiHandler extends MessageUiHandler {
success = true;
return success;
}
- this.runSelectCallback = null;
success = true;
globalScene.ui.revertMode();
} else if (this.runs.length > 0) {
@@ -235,7 +232,6 @@ export class RunHistoryUiHandler extends MessageUiHandler {
this.runSelectContainer.setVisible(false);
this.setScrollCursor(0);
this.clearCursor();
- this.runSelectCallback = null;
this.clearRuns();
}
@@ -258,13 +254,11 @@ export class RunHistoryUiHandler extends MessageUiHandler {
* entryData: the data of an individual run
*/
class RunEntryContainer extends Phaser.GameObjects.Container {
- private slotId: number;
public entryData: RunEntry;
constructor(entryData: RunEntry, slotId: number) {
super(globalScene, 0, slotId * 56);
- this.slotId = slotId;
this.entryData = entryData;
this.setup(this.entryData);
@@ -329,8 +323,8 @@ class RunEntryContainer extends Phaser.GameObjects.Container {
});
this.add(enemyContainer);
} else if (
- data.battleType === BattleType.TRAINER ||
- (data.battleType === BattleType.MYSTERY_ENCOUNTER && data.trainer)
+ data.battleType === BattleType.TRAINER
+ || (data.battleType === BattleType.MYSTERY_ENCOUNTER && data.trainer)
) {
// Defeats from Trainers show the trainer's title and name
const tObj = data.trainer.toTrainer();
diff --git a/src/ui/run-info-ui-handler.ts b/src/ui/handlers/run-info-ui-handler.ts
similarity index 95%
rename from src/ui/run-info-ui-handler.ts
rename to src/ui/handlers/run-info-ui-handler.ts
index 8b2190c3b4a..3693a58bf48 100644
--- a/src/ui/run-info-ui-handler.ts
+++ b/src/ui/handlers/run-info-ui-handler.ts
@@ -22,8 +22,8 @@ import { getVariantTint } from "#sprites/variant";
import type { SessionSaveData } from "#system/game-data";
import type { PokemonData } from "#system/pokemon-data";
import { SettingKeyboard } from "#system/settings-keyboard";
+import { UiHandler } from "#ui/handlers/ui-handler";
import { addBBCodeTextObject, addTextObject, getTextColor } from "#ui/text";
-import { UiHandler } from "#ui/ui-handler";
import { addWindow } from "#ui/ui-theme";
import { formatFancyLargeNumber, formatLargeNumber, formatMoney, getPlayTimeString } from "#utils/common";
import { toCamelCase } from "#utils/strings";
@@ -178,7 +178,7 @@ export class RunInfoUiHandler extends UiHandler {
const headerBg = addWindow(0, 0, globalScene.scaledCanvas.width - 2, 24);
headerBg.setOrigin(0, 0);
this.runContainer.add(headerBg);
- if (this.runInfo.modifiers.length !== 0) {
+ if (this.runInfo.modifiers.length > 0) {
const headerBgCoords = headerBg.getTopRight();
const abilityButtonContainer = globalScene.add.container(0, 0);
const abilityButtonText = addTextObject(8, 0, i18next.t("runHistory:viewHeldItems"), TextStyle.WINDOW, {
@@ -282,8 +282,8 @@ export class RunInfoUiHandler extends UiHandler {
const enemyContainer = globalScene.add.container(0, 0);
// Wild - Single and Doubles
if (
- this.runInfo.battleType === BattleType.WILD ||
- (this.runInfo.battleType === BattleType.MYSTERY_ENCOUNTER && !this.runInfo.trainer)
+ this.runInfo.battleType === BattleType.WILD
+ || (this.runInfo.battleType === BattleType.MYSTERY_ENCOUNTER && !this.runInfo.trainer)
) {
switch (this.runInfo.enemyParty.length) {
case 1:
@@ -296,8 +296,8 @@ export class RunInfoUiHandler extends UiHandler {
break;
}
} else if (
- this.runInfo.battleType === BattleType.TRAINER ||
- (this.runInfo.battleType === BattleType.MYSTERY_ENCOUNTER && this.runInfo.trainer)
+ this.runInfo.battleType === BattleType.TRAINER
+ || (this.runInfo.battleType === BattleType.MYSTERY_ENCOUNTER && this.runInfo.trainer)
) {
this.parseTrainerDefeat(enemyContainer);
}
@@ -344,7 +344,7 @@ export class RunInfoUiHandler extends UiHandler {
}
const boxString = i18next
.t(trainerObj.variant !== TrainerVariant.DOUBLE ? "battle:trainerAppeared" : "battle:trainerAppearedDouble", {
- trainerName: trainerName,
+ trainerName,
})
.replace(/\n/g, " ");
const descContainer = globalScene.add.container(0, 0);
@@ -363,8 +363,8 @@ export class RunInfoUiHandler extends UiHandler {
subSprite.setScale(0.65);
subSprite.setPosition(34, 46);
const mysteryEncounterTitle = i18next.t(
- globalScene.getMysteryEncounter(this.runInfo.mysteryEncounterType as MysteryEncounterType, true)
- .localizationKey + ":title",
+ globalScene.getMysteryEncounter(this.runInfo.mysteryEncounterType as MysteryEncounterType, true).localizationKey
+ + ":title",
);
const descContainer = globalScene.add.container(0, 0);
const textBox = addTextObject(0, 0, mysteryEncounterTitle, TextStyle.WINDOW, {
@@ -600,8 +600,8 @@ export class RunInfoUiHandler extends UiHandler {
// If the player achieves a personal best in Endless, the mode text will be tinted similarly to SSS luck to celebrate their achievement.
if (
- (this.runInfo.gameMode === GameModes.ENDLESS || this.runInfo.gameMode === GameModes.SPLICED_ENDLESS) &&
- this.runInfo.waveIndex === globalScene.gameData.gameStats.highestEndlessWave
+ (this.runInfo.gameMode === GameModes.ENDLESS || this.runInfo.gameMode === GameModes.SPLICED_ENDLESS)
+ && this.runInfo.waveIndex === globalScene.gameData.gameStats.highestEndlessWave
) {
modeText.appendText(` [${i18next.t("runHistory:personalBest")}]`);
modeText.setTint(0xffef5c, 0x47ff69, 0x6b6bff, 0xff6969);
@@ -613,7 +613,7 @@ export class RunInfoUiHandler extends UiHandler {
const lineSpacing = i18next.resolvedLanguage === "ja" ? 3 : 3;
const runInfoText = addBBCodeTextObject(7, 0, "", TextStyle.WINDOW, {
fontSize: "50px",
- lineSpacing: lineSpacing,
+ lineSpacing,
});
const runTime = getPlayTimeString(this.runInfo.playTime);
runInfoText.appendText(`${i18next.t("runHistory:runLength")}: ${runTime}`, false);
@@ -648,7 +648,7 @@ export class RunInfoUiHandler extends UiHandler {
// Player Held Items
// A max of 20 items can be displayed. A + sign will be added if the run's held items pushes past this maximum to show the user that there are more.
- if (this.runInfo.modifiers.length) {
+ if (this.runInfo.modifiers.length > 0) {
let visibleModifierIndex = 0;
const modifierIconsContainer = globalScene.add.container(
@@ -689,33 +689,34 @@ export class RunInfoUiHandler extends UiHandler {
*/
private challengeParser(): string[] {
const rules: string[] = [];
- for (let i = 0; i < this.runInfo.challenges.length; i++) {
- if (this.runInfo.challenges[i].value !== 0) {
- switch (this.runInfo.challenges[i].id) {
- case Challenges.SINGLE_GENERATION:
- rules.push(i18next.t(`runHistory:challengeMonoGen${this.runInfo.challenges[i].value}`));
- break;
- case Challenges.SINGLE_TYPE: {
- const typeRule = PokemonType[this.runInfo.challenges[i].value - 1];
- const typeTextColor = `[color=${TypeColor[typeRule]}]`;
- const typeShadowColor = `[shadow=${TypeShadow[typeRule]}]`;
- const typeText =
- typeTextColor +
- typeShadowColor +
- i18next.t(`pokemonInfo:type.${toCamelCase(typeRule)}`)! +
- "[/color]" +
- "[/shadow]";
- rules.push(typeText);
- break;
- }
- case Challenges.INVERSE_BATTLE:
- rules.push(i18next.t("challenges:inverseBattle.shortName"));
- break;
- default: {
- const localizationKey = toCamelCase(Challenges[this.runInfo.challenges[i].id]);
- rules.push(i18next.t(`challenges:${localizationKey}.name`));
- break;
- }
+ for (const chal of this.runInfo.challenges) {
+ if (chal.value === 0) {
+ continue;
+ }
+
+ switch (chal.id) {
+ case Challenges.SINGLE_GENERATION:
+ rules.push(i18next.t(`runHistory:challengeMonoGen${chal.value}`));
+ break;
+ case Challenges.SINGLE_TYPE: {
+ const typeRule = PokemonType[chal.value - 1];
+ const typeTextColor = `[color=${TypeColor[typeRule]}]`;
+ const typeShadowColor = `[shadow=${TypeShadow[typeRule]}]`;
+ const typeText =
+ typeTextColor
+ + typeShadowColor
+ + i18next.t(`pokemonInfo:type.${toCamelCase(typeRule)}`)!
+ + "[/color][/shadow]";
+ rules.push(typeText);
+ break;
+ }
+ case Challenges.INVERSE_BATTLE:
+ rules.push(i18next.t("challenges:inverseBattle.shortName"));
+ break;
+ default: {
+ const localizationKey = toCamelCase(Challenges[chal.id]);
+ rules.push(i18next.t(`challenges:${localizationKey}.name`));
+ break;
}
}
}
@@ -779,7 +780,7 @@ export class RunInfoUiHandler extends UiHandler {
const lineSpacing = i18next.resolvedLanguage === "ja" ? 3 : 3;
const pokeInfoText = addBBCodeTextObject(0, 0, pName, TextStyle.SUMMARY, {
fontSize: textContainerFontSize,
- lineSpacing: lineSpacing,
+ lineSpacing,
});
pokeInfoText.appendText(
`${i18next.t("saveSlotSelectUiHandler:lv")}${formatFancyLargeNumber(pokemon.level, 1)} - ${pNatureName}`,
@@ -811,7 +812,7 @@ export class RunInfoUiHandler extends UiHandler {
// Column 1: HP Atk Def
const pokeStatText1 = addBBCodeTextObject(-5, 0, hp, TextStyle.SUMMARY, {
fontSize: textContainerFontSize,
- lineSpacing: lineSpacing,
+ lineSpacing,
});
pokeStatText1.appendText(atk);
pokeStatText1.appendText(def);
@@ -819,7 +820,7 @@ export class RunInfoUiHandler extends UiHandler {
// Column 2: SpAtk SpDef Speed
const pokeStatText2 = addBBCodeTextObject(25, 0, spatk, TextStyle.SUMMARY, {
fontSize: textContainerFontSize,
- lineSpacing: lineSpacing,
+ lineSpacing,
});
pokeStatText2.appendText(spdef);
pokeStatText2.appendText(speed);
@@ -893,7 +894,7 @@ export class RunInfoUiHandler extends UiHandler {
this.runInfo.gameMode === GameModes.SPLICED_ENDLESS || this.runInfo.gameMode === GameModes.ENDLESS ? 0.25 : 0.5;
const heldItemsContainer = globalScene.add.container(-82, 2);
const heldItemsList: Modifier.PokemonHeldItemModifier[] = [];
- if (this.runInfo.modifiers.length) {
+ if (this.runInfo.modifiers.length > 0) {
for (const m of this.runInfo.modifiers) {
const modifier = m.toModifier(this.modifiersModule[m.className]);
if (modifier instanceof Modifier.PokemonHeldItemModifier && modifier.pokemonId === pokemon.id) {
@@ -912,8 +913,8 @@ export class RunInfoUiHandler extends UiHandler {
}
const itemIcon = item?.getIcon(true);
if (
- item?.stackCount < item?.getMaxHeldItemCount(pokemon) &&
- itemIcon.list[1] instanceof Phaser.GameObjects.BitmapText
+ item?.stackCount < item?.getMaxHeldItemCount(pokemon)
+ && itemIcon.list[1] instanceof Phaser.GameObjects.BitmapText
) {
itemIcon.list[1].clearTint();
}
@@ -1150,7 +1151,7 @@ export class RunInfoUiHandler extends UiHandler {
}
break;
case Button.CYCLE_ABILITY:
- if (this.runInfo.modifiers.length !== 0 && this.pageMode === RunInfoUiMode.MAIN) {
+ if (this.runInfo.modifiers.length > 0 && this.pageMode === RunInfoUiMode.MAIN) {
if (this.partyVisibility) {
this.showParty(false);
} else {
diff --git a/src/ui/save-slot-select-ui-handler.ts b/src/ui/handlers/save-slot-select-ui-handler.ts
similarity index 98%
rename from src/ui/save-slot-select-ui-handler.ts
rename to src/ui/handlers/save-slot-select-ui-handler.ts
index 97cd3016479..1b062e964be 100644
--- a/src/ui/save-slot-select-ui-handler.ts
+++ b/src/ui/handlers/save-slot-select-ui-handler.ts
@@ -8,9 +8,9 @@ import { UiMode } from "#enums/ui-mode";
import * as Modifier from "#modifiers/modifier";
import type { SessionSaveData } from "#system/game-data";
import type { PokemonData } from "#system/pokemon-data";
-import type { OptionSelectConfig } from "#ui/abstract-option-select-ui-handler";
-import { MessageUiHandler } from "#ui/message-ui-handler";
-import { RunDisplayMode } from "#ui/run-info-ui-handler";
+import type { OptionSelectConfig } from "#ui/handlers/abstract-option-select-ui-handler";
+import { MessageUiHandler } from "#ui/handlers/message-ui-handler";
+import { RunDisplayMode } from "#ui/handlers/run-info-ui-handler";
import { addTextObject } from "#ui/text";
import { addWindow } from "#ui/ui-theme";
import { fixedInt, formatLargeNumber, getPlayTimeString, isNullOrUndefined } from "#utils/common";
@@ -293,8 +293,8 @@ export class SaveSlotSelectUiHandler extends MessageUiHandler {
} else if (this.scrollCursor < SESSION_SLOTS_COUNT - SLOTS_ON_SCREEN) {
success = this.setScrollCursor(this.scrollCursor + 1, cursorPosition);
} else if (
- this.cursor === SLOTS_ON_SCREEN - 1 &&
- this.scrollCursor === SESSION_SLOTS_COUNT - SLOTS_ON_SCREEN
+ this.cursor === SLOTS_ON_SCREEN - 1
+ && this.scrollCursor === SESSION_SLOTS_COUNT - SLOTS_ON_SCREEN
) {
this.setScrollCursor(0);
this.revertSessionSlot(SLOTS_ON_SCREEN - 1);
@@ -357,7 +357,7 @@ export class SaveSlotSelectUiHandler extends MessageUiHandler {
this.message.setY(-37);
}
- this.saveSlotSelectMessageBoxContainer.setVisible(!!text?.length);
+ this.saveSlotSelectMessageBoxContainer.setVisible(text?.length > 0);
}
/**
diff --git a/src/ui/scrollable-grid-handler.ts b/src/ui/handlers/scrollable-grid-handler.ts
similarity index 98%
rename from src/ui/scrollable-grid-handler.ts
rename to src/ui/handlers/scrollable-grid-handler.ts
index 3c6458f5083..12bbaa32e98 100644
--- a/src/ui/scrollable-grid-handler.ts
+++ b/src/ui/handlers/scrollable-grid-handler.ts
@@ -1,6 +1,6 @@
import { Button } from "#enums/buttons";
-import type { ScrollBar } from "#ui/scroll-bar";
-import type { UiHandler } from "#ui/ui-handler";
+import type { ScrollBar } from "#ui/containers/scroll-bar";
+import type { UiHandler } from "#ui/handlers/ui-handler";
type UpdateGridCallbackFunction = () => void;
type UpdateDetailsCallbackFunction = (index: number) => void;
diff --git a/src/ui/session-reload-modal-ui-handler.ts b/src/ui/handlers/session-reload-modal-ui-handler.ts
similarity index 88%
rename from src/ui/session-reload-modal-ui-handler.ts
rename to src/ui/handlers/session-reload-modal-ui-handler.ts
index 1f5a205f990..33c18b1974a 100644
--- a/src/ui/session-reload-modal-ui-handler.ts
+++ b/src/ui/handlers/session-reload-modal-ui-handler.ts
@@ -1,7 +1,7 @@
import { TextStyle } from "#enums/text-style";
import type { UiMode } from "#enums/ui-mode";
-import type { ModalConfig } from "#ui/modal-ui-handler";
-import { ModalUiHandler } from "#ui/modal-ui-handler";
+import type { ModalConfig } from "#ui/handlers/modal-ui-handler";
+import { ModalUiHandler } from "#ui/handlers/modal-ui-handler";
import { addTextObject } from "#ui/text";
export class SessionReloadModalUiHandler extends ModalUiHandler {
diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/handlers/starter-select-ui-handler.ts
similarity index 97%
rename from src/ui/starter-select-ui-handler.ts
rename to src/ui/handlers/starter-select-ui-handler.ts
index 3b4b2716369..60d8a4dc4d6 100644
--- a/src/ui/starter-select-ui-handler.ts
+++ b/src/ui/handlers/starter-select-ui-handler.ts
@@ -50,15 +50,22 @@ import type { DexAttrProps, StarterAttributes, StarterDataEntry, StarterMoveset
import { RibbonData } from "#system/ribbons/ribbon-data";
import { SettingKeyboard } from "#system/settings-keyboard";
import type { DexEntry } from "#types/dex-data";
-import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
-import { DropDown, DropDownLabel, DropDownOption, DropDownState, DropDownType, SortCriteria } from "#ui/dropdown";
-import { FilterBar } from "#ui/filter-bar";
-import { MessageUiHandler } from "#ui/message-ui-handler";
-import { MoveInfoOverlay } from "#ui/move-info-overlay";
-import { PokemonIconAnimHandler, PokemonIconAnimMode } from "#ui/pokemon-icon-anim-handler";
-import { ScrollBar } from "#ui/scroll-bar";
-import { StarterContainer } from "#ui/starter-container";
-import { StatsContainer } from "#ui/stats-container";
+import {
+ DropDown,
+ DropDownLabel,
+ DropDownOption,
+ DropDownState,
+ DropDownType,
+ SortCriteria,
+} from "#ui/containers/dropdown";
+import { FilterBar } from "#ui/containers/filter-bar";
+import { MoveInfoOverlay } from "#ui/containers/move-info-overlay";
+import { ScrollBar } from "#ui/containers/scroll-bar";
+import { StarterContainer } from "#ui/containers/starter-container";
+import { StatsContainer } from "#ui/containers/stats-container";
+import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler";
+import { MessageUiHandler } from "#ui/handlers/message-ui-handler";
+import { PokemonIconAnimHandler, PokemonIconAnimMode } from "#ui/handlers/pokemon-icon-anim-handler";
import { addBBCodeTextObject, addTextObject, getTextColor } from "#ui/text";
import { addWindow } from "#ui/ui-theme";
import { applyChallenges, checkStarterValidForChallenge } from "#utils/challenge-utils";
@@ -207,7 +214,7 @@ function calcStarterPosition(index: number, scrollCursor = 0): { x: number; y: n
const x = (index % 9) * 18;
const y = yOffset + (Math.floor(index / 9) - scrollCursor) * height;
- return { x: x, y: y };
+ return { x, y };
}
/**
@@ -1150,7 +1157,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
this.allowTera = globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id);
- if (args.length >= 1 && args[0] instanceof Function) {
+ if (args.length > 0 && args[0] instanceof Function) {
super.show(args);
this.starterSelectCallback = args[0] as StarterSelectCallback;
@@ -1252,20 +1259,21 @@ export class StarterSelectUiHandler extends MessageUiHandler {
hasShiny && caughtAttr & DexAttr.VARIANT_3,
];
if (
- Number.isNaN(starterAttributes.variant) ||
- starterAttributes.variant < 0 ||
- !unlockedVariants[starterAttributes.variant]
+ Number.isNaN(starterAttributes.variant)
+ || starterAttributes.variant < 0
+ || !unlockedVariants[starterAttributes.variant]
) {
// variant value is invalid or requested variant wasn't unlocked, purging setting
starterAttributes.variant = undefined;
}
}
- if (starterAttributes.female !== undefined) {
- if (!(starterAttributes.female ? caughtAttr & DexAttr.FEMALE : caughtAttr & DexAttr.MALE)) {
- // requested gender wasn't unlocked, purging setting
- starterAttributes.female = undefined;
- }
+ if (
+ starterAttributes.female !== undefined
+ && !(starterAttributes.female ? caughtAttr & DexAttr.FEMALE : caughtAttr & DexAttr.MALE)
+ ) {
+ // requested gender wasn't unlocked, purging setting
+ starterAttributes.female = undefined;
}
if (starterAttributes.ability !== undefined) {
@@ -1289,9 +1297,9 @@ export class StarterSelectUiHandler extends MessageUiHandler {
const selectedForm = starterAttributes.form;
if (
- selectedForm !== undefined &&
- (!species.forms[selectedForm]?.isStarterSelectable ||
- !(caughtAttr & globalScene.gameData.getFormAttr(selectedForm)))
+ selectedForm !== undefined
+ && (!species.forms[selectedForm]?.isStarterSelectable
+ || !(caughtAttr & globalScene.gameData.getFormAttr(selectedForm)))
) {
// requested form wasn't unlocked/isn't a starter form, purging setting
starterAttributes.form = undefined;
@@ -1369,7 +1377,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
this.message.setY(singleLine ? -22 : -37);
}
- this.starterSelectMessageBoxContainer.setVisible(!!text?.length);
+ this.starterSelectMessageBoxContainer.setVisible(text?.length > 0);
}
/**
@@ -1397,8 +1405,8 @@ export class StarterSelectUiHandler extends MessageUiHandler {
const starterData = globalScene.gameData.starterData[speciesId];
return (
- starterData.candyCount >= getPassiveCandyCount(speciesStarterCosts[speciesId]) &&
- !(starterData.passiveAttr & PassiveAttr.UNLOCKED)
+ starterData.candyCount >= getPassiveCandyCount(speciesStarterCosts[speciesId])
+ && !(starterData.passiveAttr & PassiveAttr.UNLOCKED)
);
}
@@ -1412,9 +1420,8 @@ export class StarterSelectUiHandler extends MessageUiHandler {
const starterData = globalScene.gameData.starterData[speciesId];
return (
- starterData.candyCount >=
- getValueReductionCandyCounts(speciesStarterCosts[speciesId])[starterData.valueReduction] &&
- starterData.valueReduction < valueReductionMax
+ starterData.candyCount >= getValueReductionCandyCounts(speciesStarterCosts[speciesId])[starterData.valueReduction]
+ && starterData.valueReduction < valueReductionMax
);
}
@@ -1471,9 +1478,9 @@ export class StarterSelectUiHandler extends MessageUiHandler {
};
if (
- this.isPassiveAvailable(species.speciesId) ||
- (globalScene.candyUpgradeNotification === 2 &&
- (this.isValueReductionAvailable(species.speciesId) || this.isSameSpeciesEggAvailable(species.speciesId)))
+ this.isPassiveAvailable(species.speciesId)
+ || (globalScene.candyUpgradeNotification === 2
+ && (this.isValueReductionAvailable(species.speciesId) || this.isSameSpeciesEggAvailable(species.speciesId)))
) {
const chain = globalScene.tweens.chain(tweenChain);
if (!startPaused) {
@@ -1490,9 +1497,9 @@ export class StarterSelectUiHandler extends MessageUiHandler {
const slotVisible = !!species?.speciesId;
if (
- !species ||
- globalScene.candyUpgradeNotification === 0 ||
- species.speciesId !== species.getRootSpeciesId(false)
+ !species
+ || globalScene.candyUpgradeNotification === 0
+ || species.speciesId !== species.getRootSpeciesId(false)
) {
starter.candyUpgradeIcon.setVisible(false);
starter.candyUpgradeOverlayIcon.setVisible(false);
@@ -1593,8 +1600,8 @@ export class StarterSelectUiHandler extends MessageUiHandler {
this.filterBar.toggleDropDown(this.filterBarCursor);
success = true;
} else if (
- this.filterMode &&
- !this.filterBar.getFilter(this.filterBar.getColumn(this.filterBarCursor)).hasDefaultValues()
+ this.filterMode
+ && !this.filterBar.getFilter(this.filterBar.getColumn(this.filterBarCursor)).hasDefaultValues()
) {
if (this.filterBar.getColumn(this.filterBarCursor) === DropDownColumn.CAUGHT) {
this.resetCaughtDropdown();
@@ -1606,7 +1613,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
} else if (this.statsMode) {
this.toggleStatsMode(false);
success = true;
- } else if (this.starterSpecies.length) {
+ } else if (this.starterSpecies.length > 0) {
this.popStarter(this.starterSpecies.length - 1);
success = true;
this.updateInstructions();
@@ -1891,10 +1898,10 @@ export class StarterSelectUiHandler extends MessageUiHandler {
);
const newCost = globalScene.gameData.getSpeciesStarterValue(this.lastSpecies.speciesId);
if (
- !isDupe &&
- isValidForChallenge &&
- currentPartyValue + newCost <= this.getValueLimit() &&
- this.starterSpecies.length < PLAYER_PARTY_MAX_SIZE
+ !isDupe
+ && isValidForChallenge
+ && currentPartyValue + newCost <= this.getValueLimit()
+ && this.starterSpecies.length < PLAYER_PARTY_MAX_SIZE
) {
options = [
{
@@ -2331,7 +2338,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
},
});
ui.setModeWithoutClear(UiMode.OPTION_SELECT, {
- options: options,
+ options,
yOffset: 47,
});
};
@@ -2378,7 +2385,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
},
});
ui.setModeWithoutClear(UiMode.OPTION_SELECT, {
- options: options,
+ options,
yOffset: 47,
});
success = true;
@@ -2428,11 +2435,9 @@ export class StarterSelectUiHandler extends MessageUiHandler {
// TODO: is this bang correct?
break;
}
- } else {
- if (this.speciesStarterDexEntry!.caughtAttr & DexAttr.VARIANT_3) {
- // TODO: is this bang correct?
- break;
- }
+ } else if (this.speciesStarterDexEntry!.caughtAttr & DexAttr.VARIANT_3) {
+ // TODO: is this bang correct?
+ break;
}
} while (newVariant !== props.variant);
starterAttributes.variant = newVariant; // store the selected variant
@@ -2467,8 +2472,8 @@ export class StarterSelectUiHandler extends MessageUiHandler {
do {
newFormIndex = (newFormIndex + 1) % formCount;
if (
- this.lastSpecies.forms[newFormIndex].isStarterSelectable &&
- this.speciesStarterDexEntry!.caughtAttr! & globalScene.gameData.getFormAttr(newFormIndex)
+ this.lastSpecies.forms[newFormIndex].isStarterSelectable
+ && this.speciesStarterDexEntry!.caughtAttr! & globalScene.gameData.getFormAttr(newFormIndex)
) {
// TODO: are those bangs correct?
break;
@@ -2513,10 +2518,8 @@ export class StarterSelectUiHandler extends MessageUiHandler {
newAbilityIndex = (newAbilityIndex + 1) % abilityCount;
}
break;
- } else {
- if (abilityAttr & AbilityAttr.ABILITY_HIDDEN) {
- break;
- }
+ } else if (abilityAttr & AbilityAttr.ABILITY_HIDDEN) {
+ break;
}
} while (newAbilityIndex !== this.abilityCursor);
starterAttributes.ability = newAbilityIndex; // store the selected ability
@@ -3017,10 +3020,10 @@ export class StarterSelectUiHandler extends MessageUiHandler {
this.filteredStarterContainers = [];
this.validStarterContainers = [];
- // biome-ignore-start lint/nursery/useIterableCallbackReturn: benign
+ // biome-ignore-start lint/suspicious/useIterableCallbackReturn: benign
this.pokerusCursorObjs.forEach(cursor => cursor.setVisible(false));
this.starterCursorObjs.forEach(cursor => cursor.setVisible(false));
- // biome-ignore-end lint/nursery/useIterableCallbackReturn: benign
+ // biome-ignore-end lint/suspicious/useIterableCallbackReturn: benign
this.filterBar.updateFilterLabels();
@@ -3067,8 +3070,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
}
// this updates icons for previously saved pokemon
- for (let i = 0; i < this.validStarterContainers.length; i++) {
- const currentFilteredContainer = this.validStarterContainers[i];
+ for (const currentFilteredContainer of this.validStarterContainers) {
const starterSprite = currentFilteredContainer.icon as Phaser.GameObjects.Sprite;
const currentDexAttr = this.getCurrentDexProps(currentFilteredContainer.species.speciesId);
@@ -3200,8 +3202,8 @@ export class StarterSelectUiHandler extends MessageUiHandler {
// HA Filter
const speciesHasHiddenAbility =
- container.species.abilityHidden !== container.species.ability1 &&
- container.species.abilityHidden !== AbilityId.NONE;
+ container.species.abilityHidden !== container.species.ability1
+ && container.species.abilityHidden !== AbilityId.NONE;
const hasHA = starterData.abilityAttr & AbilityAttr.ABILITY_HIDDEN;
const fitsHA = this.filterBar.getVals(DropDownColumn.MISC).some(misc => {
if (misc.val === "HIDDEN_ABILITY" && misc.state === DropDownState.ON) {
@@ -3243,16 +3245,16 @@ export class StarterSelectUiHandler extends MessageUiHandler {
});
if (
- fitsGen &&
- fitsType &&
- fitsCaught &&
- fitsPassive &&
- fitsCostReduction &&
- fitsFavorite &&
- fitsWin &&
- fitsHA &&
- fitsEgg &&
- fitsPokerus
+ fitsGen
+ && fitsType
+ && fitsCaught
+ && fitsPassive
+ && fitsCostReduction
+ && fitsFavorite
+ && fitsWin
+ && fitsHA
+ && fitsEgg
+ && fitsPokerus
) {
this.filteredStarterContainers.push(container);
}
@@ -3276,26 +3278,26 @@ export class StarterSelectUiHandler extends MessageUiHandler {
}
case SortCriteria.IV: {
const avgIVsA =
- globalScene.gameData.dexData[a.species.speciesId].ivs.reduce((a, b) => a + b, 0) /
- globalScene.gameData.dexData[a.species.speciesId].ivs.length;
+ globalScene.gameData.dexData[a.species.speciesId].ivs.reduce((a, b) => a + b, 0)
+ / globalScene.gameData.dexData[a.species.speciesId].ivs.length;
const avgIVsB =
- globalScene.gameData.dexData[b.species.speciesId].ivs.reduce((a, b) => a + b, 0) /
- globalScene.gameData.dexData[b.species.speciesId].ivs.length;
+ globalScene.gameData.dexData[b.species.speciesId].ivs.reduce((a, b) => a + b, 0)
+ / globalScene.gameData.dexData[b.species.speciesId].ivs.length;
return (avgIVsA - avgIVsB) * -sort.dir;
}
case SortCriteria.NAME:
return a.species.name.localeCompare(b.species.name) * -sort.dir;
case SortCriteria.CAUGHT:
return (
- (globalScene.gameData.dexData[a.species.speciesId].caughtCount -
- globalScene.gameData.dexData[b.species.speciesId].caughtCount) *
- -sort.dir
+ (globalScene.gameData.dexData[a.species.speciesId].caughtCount
+ - globalScene.gameData.dexData[b.species.speciesId].caughtCount)
+ * -sort.dir
);
case SortCriteria.HATCHED:
return (
- (globalScene.gameData.dexData[a.species.speciesId].hatchedCount -
- globalScene.gameData.dexData[b.species.speciesId].hatchedCount) *
- -sort.dir
+ (globalScene.gameData.dexData[a.species.speciesId].hatchedCount
+ - globalScene.gameData.dexData[b.species.speciesId].hatchedCount)
+ * -sort.dir
);
}
return 0;
@@ -3671,10 +3673,8 @@ export class StarterSelectUiHandler extends MessageUiHandler {
const defaultNature =
starterAttributes?.nature || globalScene.gameData.getSpeciesDefaultNature(species, dexEntry);
props = globalScene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr);
- if (starterAttributes?.variant && !Number.isNaN(starterAttributes.variant)) {
- if (props.shiny) {
- props.variant = starterAttributes.variant as Variant;
- }
+ if (starterAttributes?.variant && !Number.isNaN(starterAttributes.variant) && props.shiny) {
+ props.variant = starterAttributes.variant as Variant;
}
props.formIndex = starterAttributes?.form ?? props.formIndex;
props.female = starterAttributes?.female ?? props.female;
@@ -3816,10 +3816,10 @@ export class StarterSelectUiHandler extends MessageUiHandler {
// We will only update the sprite if there is a change to form, shiny/variant
// or gender for species with gender sprite differences
const shouldUpdateSprite =
- (species?.genderDiffs && !isNullOrUndefined(female)) ||
- !isNullOrUndefined(formIndex) ||
- !isNullOrUndefined(shiny) ||
- !isNullOrUndefined(variant);
+ (species?.genderDiffs && !isNullOrUndefined(female))
+ || !isNullOrUndefined(formIndex)
+ || !isNullOrUndefined(shiny)
+ || !isNullOrUndefined(variant);
const isFreshStartChallenge = globalScene.gameMode.hasChallenge(Challenges.FRESH_START);
@@ -3996,10 +3996,10 @@ export class StarterSelectUiHandler extends MessageUiHandler {
.filter(f => f).length > 1;
this.canCycleNature = globalScene.gameData.getNaturesForAttr(dexEntry.natureAttr).length > 1;
this.canCycleTera =
- !this.statsMode &&
- this.allowTera &&
- !isNullOrUndefined(getPokemonSpeciesForm(species.speciesId, formIndex ?? 0).type2) &&
- !globalScene.gameMode.hasChallenge(Challenges.FRESH_START);
+ !this.statsMode
+ && this.allowTera
+ && !isNullOrUndefined(getPokemonSpeciesForm(species.speciesId, formIndex ?? 0).type2)
+ && !globalScene.gameMode.hasChallenge(Challenges.FRESH_START);
}
if (dexEntry.caughtAttr && species.malePercent !== null) {
@@ -4096,9 +4096,9 @@ export class StarterSelectUiHandler extends MessageUiHandler {
let levelMoves: LevelMoves;
if (
- pokemonFormLevelMoves.hasOwnProperty(species.speciesId) &&
- formIndex &&
- pokemonFormLevelMoves[species.speciesId].hasOwnProperty(formIndex)
+ pokemonFormLevelMoves.hasOwnProperty(species.speciesId)
+ && formIndex
+ && pokemonFormLevelMoves[species.speciesId].hasOwnProperty(formIndex)
) {
levelMoves = pokemonFormLevelMoves[species.speciesId][formIndex];
} else {
@@ -4431,7 +4431,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
}
tryStart(manualTrigger = false): boolean {
- if (!this.starterSpecies.length) {
+ if (this.starterSpecies.length === 0) {
return false;
}
@@ -4497,13 +4497,13 @@ export class StarterSelectUiHandler extends MessageUiHandler {
return true;
}
- /* This block checks to see if your party is valid
+ /**
+ * This block checks to see if your party is valid
* It checks each pokemon against the challenge - noting that due to monotype challenges it needs to check the pokemon while ignoring their evolutions/form change items
*/
isPartyValid(): boolean {
let canStart = false;
- for (let s = 0; s < this.starterSpecies.length; s++) {
- const species = this.starterSpecies[s];
+ for (const species of this.starterSpecies) {
const isValidForChallenge = checkStarterValidForChallenge(
species,
globalScene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)),
@@ -4531,8 +4531,8 @@ export class StarterSelectUiHandler extends MessageUiHandler {
* If neither of these pass, we add DexAttr.MALE to our temp props
*/
if (
- this.starterPreferences[speciesId]?.female ||
- ((caughtAttr & DexAttr.FEMALE) > 0n && (caughtAttr & DexAttr.MALE) === 0n)
+ this.starterPreferences[speciesId]?.female
+ || ((caughtAttr & DexAttr.FEMALE) > 0n && (caughtAttr & DexAttr.MALE) === 0n)
) {
props += DexAttr.FEMALE;
} else {
@@ -4542,23 +4542,21 @@ export class StarterSelectUiHandler extends MessageUiHandler {
* If they're not there, it enables shiny state by default if any shiny was caught
*/
if (
- this.starterPreferences[speciesId]?.shiny ||
- ((caughtAttr & DexAttr.SHINY) > 0n && this.starterPreferences[speciesId]?.shiny !== false)
+ this.starterPreferences[speciesId]?.shiny
+ || ((caughtAttr & DexAttr.SHINY) > 0n && this.starterPreferences[speciesId]?.shiny !== false)
) {
props += DexAttr.SHINY;
if (this.starterPreferences[speciesId]?.variant !== undefined) {
props += BigInt(Math.pow(2, this.starterPreferences[speciesId]?.variant)) * DexAttr.DEFAULT_VARIANT;
- } else {
+ } else if ((caughtAttr & DexAttr.VARIANT_3) > 0) {
/* This calculates the correct variant if there's no starter preferences for it.
* This gets the highest tier variant that you've caught and adds it to the temp props
*/
- if ((caughtAttr & DexAttr.VARIANT_3) > 0) {
- props += DexAttr.VARIANT_3;
- } else if ((caughtAttr & DexAttr.VARIANT_2) > 0) {
- props += DexAttr.VARIANT_2;
- } else {
- props += DexAttr.DEFAULT_VARIANT;
- }
+ props += DexAttr.VARIANT_3;
+ } else if ((caughtAttr & DexAttr.VARIANT_2) > 0) {
+ props += DexAttr.VARIANT_2;
+ } else {
+ props += DexAttr.DEFAULT_VARIANT;
}
} else {
props += DexAttr.NON_SHINY;
@@ -4599,10 +4597,10 @@ export class StarterSelectUiHandler extends MessageUiHandler {
);
const formIndex = props.formIndex;
this.canCycleTera =
- !this.statsMode &&
- this.allowTera &&
- !isNullOrUndefined(getPokemonSpeciesForm(this.lastSpecies.speciesId, formIndex ?? 0).type2) &&
- !globalScene.gameMode.hasChallenge(Challenges.FRESH_START);
+ !this.statsMode
+ && this.allowTera
+ && !isNullOrUndefined(getPokemonSpeciesForm(this.lastSpecies.speciesId, formIndex ?? 0).type2)
+ && !globalScene.gameMode.hasChallenge(Challenges.FRESH_START);
this.updateInstructions();
}
}
@@ -4655,7 +4653,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
this.starterSelectContainer.setVisible(false);
this.blockInput = false;
- while (this.starterSpecies.length) {
+ while (this.starterSpecies.length > 0) {
this.popStarter(this.starterSpecies.length - 1);
}
diff --git a/src/ui/summary-ui-handler.ts b/src/ui/handlers/summary-ui-handler.ts
similarity index 92%
rename from src/ui/summary-ui-handler.ts
rename to src/ui/handlers/summary-ui-handler.ts
index f737411896e..e73c5bae431 100644
--- a/src/ui/summary-ui-handler.ts
+++ b/src/ui/handlers/summary-ui-handler.ts
@@ -25,8 +25,8 @@ import type { PokemonMove } from "#moves/pokemon-move";
import type { Variant } from "#sprites/variant";
import { getVariantTint } from "#sprites/variant";
import { achvs } from "#system/achv";
+import { UiHandler } from "#ui/handlers/ui-handler";
import { addBBCodeTextObject, addTextObject, getBBCodeFrag, getTextColor } from "#ui/text";
-import { UiHandler } from "#ui/ui-handler";
import {
fixedInt,
formatStat,
@@ -405,8 +405,8 @@ export class SummaryUiHandler extends UiHandler {
}
if (
- globalScene.gameData.starterData[this.pokemon.species.getRootSpeciesId()].classicWinCount > 0 &&
- globalScene.gameData.starterData[this.pokemon.species.getRootSpeciesId(true)].classicWinCount > 0
+ globalScene.gameData.starterData[this.pokemon.species.getRootSpeciesId()].classicWinCount > 0
+ && globalScene.gameData.starterData[this.pokemon.species.getRootSpeciesId(true)].classicWinCount > 0
) {
this.championRibbon.setVisible(true);
} else {
@@ -532,33 +532,31 @@ export class SummaryUiHandler extends UiHandler {
if (this.pokemon && this.moveCursor < this.pokemon.moveset.length) {
if (this.summaryUiMode === SummaryUiMode.LEARN_MOVE) {
this.moveSelectFunction?.(this.moveCursor);
+ } else if (this.selectedMoveIndex === -1) {
+ this.selectedMoveIndex = this.moveCursor;
+ this.setCursor(this.moveCursor);
} else {
- if (this.selectedMoveIndex === -1) {
- this.selectedMoveIndex = this.moveCursor;
- this.setCursor(this.moveCursor);
- } else {
- if (this.selectedMoveIndex !== this.moveCursor) {
- const tempMove = this.pokemon?.moveset[this.selectedMoveIndex];
- this.pokemon.moveset[this.selectedMoveIndex] = this.pokemon.moveset[this.moveCursor];
- this.pokemon.moveset[this.moveCursor] = tempMove;
+ if (this.selectedMoveIndex !== this.moveCursor) {
+ const tempMove = this.pokemon?.moveset[this.selectedMoveIndex];
+ this.pokemon.moveset[this.selectedMoveIndex] = this.pokemon.moveset[this.moveCursor];
+ this.pokemon.moveset[this.moveCursor] = tempMove;
- const selectedMoveRow = this.moveRowsContainer.getAt(
- this.selectedMoveIndex,
- ) as Phaser.GameObjects.Container;
- const switchMoveRow = this.moveRowsContainer.getAt(this.moveCursor) as Phaser.GameObjects.Container;
+ const selectedMoveRow = this.moveRowsContainer.getAt(
+ this.selectedMoveIndex,
+ ) as Phaser.GameObjects.Container;
+ const switchMoveRow = this.moveRowsContainer.getAt(this.moveCursor) as Phaser.GameObjects.Container;
- this.moveRowsContainer.moveTo(selectedMoveRow, this.moveCursor);
- this.moveRowsContainer.moveTo(switchMoveRow, this.selectedMoveIndex);
+ this.moveRowsContainer.moveTo(selectedMoveRow, this.moveCursor);
+ this.moveRowsContainer.moveTo(switchMoveRow, this.selectedMoveIndex);
- selectedMoveRow.setY(this.moveCursor * 16);
- switchMoveRow.setY(this.selectedMoveIndex * 16);
- }
+ selectedMoveRow.setY(this.moveCursor * 16);
+ switchMoveRow.setY(this.selectedMoveIndex * 16);
+ }
- this.selectedMoveIndex = -1;
- if (this.selectedMoveCursorObj) {
- this.selectedMoveCursorObj.destroy();
- this.selectedMoveCursorObj = null;
- }
+ this.selectedMoveIndex = -1;
+ if (this.selectedMoveCursorObj) {
+ this.selectedMoveCursorObj.destroy();
+ this.selectedMoveCursorObj = null;
}
}
success = true;
@@ -592,78 +590,76 @@ export class SummaryUiHandler extends UiHandler {
break;
}
}
- } else {
- if (button === Button.ACTION) {
- if (this.cursor === Page.MOVES) {
- this.showMoveSelect();
- success = true;
- } else if (this.cursor === Page.PROFILE && this.pokemon?.hasPassive()) {
- // if we're on the PROFILE page and this pokemon has a passive unlocked..
- // Since abilities are displayed by default, all we need to do is toggle visibility on all elements to show passives
- this.abilityContainer.nameText?.setVisible(!this.abilityContainer.descriptionText?.visible);
- this.abilityContainer.descriptionText?.setVisible(!this.abilityContainer.descriptionText.visible);
- this.abilityContainer.labelImage.setVisible(!this.abilityContainer.labelImage.visible);
-
- this.passiveContainer.nameText?.setVisible(!this.passiveContainer.descriptionText?.visible);
- this.passiveContainer.descriptionText?.setVisible(!this.passiveContainer.descriptionText.visible);
- this.passiveContainer.labelImage.setVisible(!this.passiveContainer.labelImage.visible);
- } else if (this.cursor === Page.STATS) {
- //Show IVs
- this.permStatsContainer.setVisible(!this.permStatsContainer.visible);
- this.ivContainer.setVisible(!this.ivContainer.visible);
- }
- } else if (button === Button.CANCEL) {
- if (this.summaryUiMode === SummaryUiMode.LEARN_MOVE) {
- this.hideMoveSelect();
- } else {
- if (this.selectCallback instanceof Function) {
- const selectCallback = this.selectCallback;
- this.selectCallback = null;
- selectCallback();
- }
-
- if (!fromPartyMode) {
- ui.setMode(UiMode.MESSAGE);
- } else {
- ui.setMode(UiMode.PARTY);
- }
- }
+ } else if (button === Button.ACTION) {
+ if (this.cursor === Page.MOVES) {
+ this.showMoveSelect();
success = true;
+ } else if (this.cursor === Page.PROFILE && this.pokemon?.hasPassive()) {
+ // if we're on the PROFILE page and this pokemon has a passive unlocked..
+ // Since abilities are displayed by default, all we need to do is toggle visibility on all elements to show passives
+ this.abilityContainer.nameText?.setVisible(!this.abilityContainer.descriptionText?.visible);
+ this.abilityContainer.descriptionText?.setVisible(!this.abilityContainer.descriptionText.visible);
+ this.abilityContainer.labelImage.setVisible(!this.abilityContainer.labelImage.visible);
+
+ this.passiveContainer.nameText?.setVisible(!this.passiveContainer.descriptionText?.visible);
+ this.passiveContainer.descriptionText?.setVisible(!this.passiveContainer.descriptionText.visible);
+ this.passiveContainer.labelImage.setVisible(!this.passiveContainer.labelImage.visible);
+ } else if (this.cursor === Page.STATS) {
+ //Show IVs
+ this.permStatsContainer.setVisible(!this.permStatsContainer.visible);
+ this.ivContainer.setVisible(!this.ivContainer.visible);
+ }
+ } else if (button === Button.CANCEL) {
+ if (this.summaryUiMode === SummaryUiMode.LEARN_MOVE) {
+ this.hideMoveSelect();
} else {
- const pages = getEnumValues(Page);
- switch (button) {
- case Button.UP:
- case Button.DOWN: {
- if (this.summaryUiMode === SummaryUiMode.LEARN_MOVE) {
- break;
- }
- if (!fromPartyMode) {
- break;
- }
- const isDown = button === Button.DOWN;
- const party = globalScene.getPlayerParty();
- const partyMemberIndex = this.pokemon ? party.indexOf(this.pokemon) : -1;
- if ((isDown && partyMemberIndex < party.length - 1) || (!isDown && partyMemberIndex)) {
- const page = this.cursor;
- this.clear();
- this.show([party[partyMemberIndex + (isDown ? 1 : -1)], this.summaryUiMode, page]);
- }
+ if (this.selectCallback instanceof Function) {
+ const selectCallback = this.selectCallback;
+ this.selectCallback = null;
+ selectCallback();
+ }
+
+ if (!fromPartyMode) {
+ ui.setMode(UiMode.MESSAGE);
+ } else {
+ ui.setMode(UiMode.PARTY);
+ }
+ }
+ success = true;
+ } else {
+ const pages = getEnumValues(Page);
+ switch (button) {
+ case Button.UP:
+ case Button.DOWN: {
+ if (this.summaryUiMode === SummaryUiMode.LEARN_MOVE) {
break;
}
- case Button.LEFT:
- if (this.cursor) {
- success = this.setCursor(this.cursor - 1);
- }
- break;
- case Button.RIGHT:
- if (this.cursor < pages.length - 1) {
- success = this.setCursor(this.cursor + 1);
- if (this.summaryUiMode === SummaryUiMode.LEARN_MOVE && this.cursor === Page.MOVES) {
- this.moveSelect = true;
- }
- }
+ if (!fromPartyMode) {
break;
+ }
+ const isDown = button === Button.DOWN;
+ const party = globalScene.getPlayerParty();
+ const partyMemberIndex = this.pokemon ? party.indexOf(this.pokemon) : -1;
+ if ((isDown && partyMemberIndex < party.length - 1) || (!isDown && partyMemberIndex)) {
+ const page = this.cursor;
+ this.clear();
+ this.show([party[partyMemberIndex + (isDown ? 1 : -1)], this.summaryUiMode, page]);
+ }
+ break;
}
+ case Button.LEFT:
+ if (this.cursor) {
+ success = this.setCursor(this.cursor - 1);
+ }
+ break;
+ case Button.RIGHT:
+ if (this.cursor < pages.length - 1) {
+ success = this.setCursor(this.cursor + 1);
+ if (this.summaryUiMode === SummaryUiMode.LEARN_MOVE && this.cursor === Page.MOVES) {
+ this.moveSelect = true;
+ }
+ }
+ break;
}
}
@@ -900,8 +896,8 @@ export class SummaryUiHandler extends UiHandler {
}
if (
- globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id) &&
- !isNullOrUndefined(this.pokemon)
+ globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id)
+ && !isNullOrUndefined(this.pokemon)
) {
const teraIcon = globalScene.add.sprite(123, 26, "button_tera");
teraIcon.setName("terastallize-icon");
@@ -1007,7 +1003,7 @@ export class SummaryUiHandler extends UiHandler {
wave: `${getBBCodeFrag(this.pokemon?.metWave ? this.pokemon.metWave.toString()! : i18next.t("pokemonSummary:unknownTrainer"), TextStyle.SUMMARY_RED)}${closeFragment}`,
},
),
- natureFragment: i18next.t(`pokemonSummary:natureFragment.${rawNature}`, { nature: nature }),
+ natureFragment: i18next.t(`pokemonSummary:natureFragment.${rawNature}`, { nature }),
});
const memoText = addBBCodeTextObject(7, 113, String(memoString), TextStyle.WINDOW_ALT);
diff --git a/src/ui/target-select-ui-handler.ts b/src/ui/handlers/target-select-ui-handler.ts
similarity index 90%
rename from src/ui/target-select-ui-handler.ts
rename to src/ui/handlers/target-select-ui-handler.ts
index 5ea89929cda..777a6734383 100644
--- a/src/ui/target-select-ui-handler.ts
+++ b/src/ui/handlers/target-select-ui-handler.ts
@@ -7,7 +7,7 @@ import { UiMode } from "#enums/ui-mode";
import type { Pokemon } from "#field/pokemon";
import type { ModifierBar } from "#modifiers/modifier";
import { getMoveTargets } from "#moves/move-utils";
-import { UiHandler } from "#ui/ui-handler";
+import { UiHandler } from "#ui/handlers/ui-handler";
import { fixedInt, isNullOrUndefined } from "#utils/common";
export type TargetSelectCallback = (targets: BattlerIndex[]) => void;
@@ -50,7 +50,7 @@ export class TargetSelectUiHandler extends UiHandler {
this.targets = moveTargets.targets;
this.isMultipleTargets = moveTargets.multiple ?? false;
- if (!this.targets.length) {
+ if (this.targets.length === 0) {
return false;
}
@@ -70,11 +70,12 @@ export class TargetSelectUiHandler extends UiHandler {
* @param user the Pokemon using the move
*/
resetCursor(cursorN: number, user: Pokemon): void {
- if (!isNullOrUndefined(cursorN)) {
- if ([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2].includes(cursorN) || user.tempSummonData.waveTurnCount === 1) {
- // Reset cursor on the first turn of a fight or if an ally was targeted last turn
- cursorN = -1;
- }
+ if (
+ !isNullOrUndefined(cursorN)
+ && ([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2].includes(cursorN) || user.tempSummonData.waveTurnCount === 1)
+ ) {
+ // Reset cursor on the first turn of a fight or if an ally was targeted last turn
+ cursorN = -1;
}
this.setCursor(this.targets.includes(cursorN) ? cursorN : this.targets[0]);
}
@@ -92,10 +93,11 @@ export class TargetSelectUiHandler extends UiHandler {
if (isNullOrUndefined(this.cursor0) || this.cursor0 !== this.cursor) {
this.cursor0 = this.cursor;
}
- } else if (this.fieldIndex === BattlerIndex.PLAYER_2) {
- if (isNullOrUndefined(this.cursor1) || this.cursor1 !== this.cursor) {
- this.cursor1 = this.cursor;
- }
+ } else if (
+ this.fieldIndex === BattlerIndex.PLAYER_2
+ && (isNullOrUndefined(this.cursor1) || this.cursor1 !== this.cursor)
+ ) {
+ this.cursor1 = this.cursor;
}
} else if (this.isMultipleTargets) {
success = false;
@@ -163,7 +165,7 @@ export class TargetSelectUiHandler extends UiHandler {
},
});
- if (this.targetBattleInfoMoveTween.length >= 1) {
+ if (this.targetBattleInfoMoveTween.length > 0) {
this.targetBattleInfoMoveTween.filter(t => t !== undefined).forEach(tween => tween.stop());
for (const pokemon of multipleTargets) {
pokemon.getBattleInfo().resetY();
@@ -198,7 +200,7 @@ export class TargetSelectUiHandler extends UiHandler {
this.highlightItems(pokemon.id, 1);
}
- if (this.targetBattleInfoMoveTween.length >= 1) {
+ if (this.targetBattleInfoMoveTween.length > 0) {
this.targetBattleInfoMoveTween.filter(t => t !== undefined).forEach(tween => tween.stop());
this.targetBattleInfoMoveTween = [];
}
diff --git a/src/ui/test-dialogue-ui-handler.ts b/src/ui/handlers/test-dialogue-ui-handler.ts
similarity index 91%
rename from src/ui/test-dialogue-ui-handler.ts
rename to src/ui/handlers/test-dialogue-ui-handler.ts
index 6f7c79a151b..d72de64ef70 100644
--- a/src/ui/test-dialogue-ui-handler.ts
+++ b/src/ui/handlers/test-dialogue-ui-handler.ts
@@ -1,9 +1,9 @@
import { UiMode } from "#enums/ui-mode";
import type { PlayerPokemon } from "#field/pokemon";
-import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
-import type { InputFieldConfig } from "#ui/form-modal-ui-handler";
-import { FormModalUiHandler } from "#ui/form-modal-ui-handler";
-import type { ModalConfig } from "#ui/modal-ui-handler";
+import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler";
+import type { InputFieldConfig } from "#ui/handlers/form-modal-ui-handler";
+import { FormModalUiHandler } from "#ui/handlers/form-modal-ui-handler";
+import type { ModalConfig } from "#ui/handlers/modal-ui-handler";
import { isNullOrUndefined } from "#utils/common";
import i18next from "i18next";
@@ -83,8 +83,8 @@ export class TestDialogueUiHandler extends FormModalUiHandler {
input.on("keydown", (inputObject, evt: KeyboardEvent) => {
if (
- ["escape", "space"].some(v => v === evt.key.toLowerCase() || v === evt.code.toLowerCase()) &&
- ui.getMode() === UiMode.AUTO_COMPLETE
+ ["escape", "space"].some(v => v === evt.key.toLowerCase() || v === evt.code.toLowerCase())
+ && ui.getMode() === UiMode.AUTO_COMPLETE
) {
// Delete autocomplete list and recovery focus.
inputObject.on("blur", () => inputObject.node.focus(), { once: true });
@@ -100,9 +100,7 @@ export class TestDialogueUiHandler extends FormModalUiHandler {
let options: OptionSelectItem[] = [];
const splitArr = inputObject.text.split(" ");
- const filteredKeys = this.keys.filter(command =>
- command.toLowerCase().includes(splitArr[splitArr.length - 1].toLowerCase()),
- );
+ const filteredKeys = this.keys.filter(command => command.toLowerCase().includes(splitArr.at(-1)!.toLowerCase()));
if (inputObject.text !== "" && filteredKeys.length > 0) {
// if performance is required, you could reduce the number of total results by changing the slice below to not have all ~8000 inputs going
options = filteredKeys.slice(0).map(value => {
@@ -125,7 +123,7 @@ export class TestDialogueUiHandler extends FormModalUiHandler {
if (options.length > 0) {
const modalOpts = {
- options: options,
+ options,
maxOptions: 5,
modalContainer: this.modalContainer,
};
diff --git a/src/ui/title-ui-handler.ts b/src/ui/handlers/title-ui-handler.ts
similarity index 95%
rename from src/ui/title-ui-handler.ts
rename to src/ui/handlers/title-ui-handler.ts
index ef814167631..28165a33db7 100644
--- a/src/ui/title-ui-handler.ts
+++ b/src/ui/handlers/title-ui-handler.ts
@@ -109,10 +109,10 @@ export class TitleUiHandler extends OptionSelectUiHandler {
const rand = randInt(1025, 1);
const pokemon = getPokemonSpecies(rand as SpeciesId);
if (
- this.splashMessage === "splashMessages:underratedPokemon" ||
- this.splashMessage === "splashMessages:dontTalkAboutThePokemonIncident" ||
- this.splashMessage === "splashMessages:aWildPokemonAppeared" ||
- this.splashMessage === "splashMessages:aprilFools.removedPokemon"
+ this.splashMessage === "splashMessages:underratedPokemon"
+ || this.splashMessage === "splashMessages:dontTalkAboutThePokemonIncident"
+ || this.splashMessage === "splashMessages:aWildPokemonAppeared"
+ || this.splashMessage === "splashMessages:aprilFools.removedPokemon"
) {
this.splashMessageText.setText(i18next.t(this.splashMessage, { pokemonName: pokemon.name }));
}
diff --git a/src/ui/ui-handler.ts b/src/ui/handlers/ui-handler.ts
similarity index 100%
rename from src/ui/ui-handler.ts
rename to src/ui/handlers/ui-handler.ts
diff --git a/src/ui/unavailable-modal-ui-handler.ts b/src/ui/handlers/unavailable-modal-ui-handler.ts
similarity index 85%
rename from src/ui/unavailable-modal-ui-handler.ts
rename to src/ui/handlers/unavailable-modal-ui-handler.ts
index 5c3dc513473..5b885bfff77 100644
--- a/src/ui/unavailable-modal-ui-handler.ts
+++ b/src/ui/handlers/unavailable-modal-ui-handler.ts
@@ -2,15 +2,14 @@ import { updateUserInfo } from "#app/account";
import { globalScene } from "#app/global-scene";
import { TextStyle } from "#enums/text-style";
import type { UiMode } from "#enums/ui-mode";
-import type { ModalConfig } from "#ui/modal-ui-handler";
-import { ModalUiHandler } from "#ui/modal-ui-handler";
+import type { ModalConfig } from "#ui/handlers/modal-ui-handler";
+import { ModalUiHandler } from "#ui/handlers/modal-ui-handler";
import { addTextObject } from "#ui/text";
import { sessionIdKey } from "#utils/common";
import { removeCookie } from "#utils/cookies";
import i18next from "i18next";
export class UnavailableModalUiHandler extends ModalUiHandler {
- private reconnectTimer: NodeJS.Timeout | null;
private reconnectDuration: number;
private reconnectCallback: () => void;
@@ -62,7 +61,6 @@ export class UnavailableModalUiHandler extends ModalUiHandler {
tryReconnect(): void {
updateUserInfo().then(response => {
if (response[0] || [200, 400].includes(response[1])) {
- this.reconnectTimer = null;
this.reconnectDuration = this.minTime;
globalScene.playSound("se/pb_bounce_1");
this.reconnectCallback();
@@ -71,7 +69,7 @@ export class UnavailableModalUiHandler extends ModalUiHandler {
globalScene.reset(true, true);
} else {
this.reconnectDuration = Math.min(this.reconnectDuration * 2, this.maxTime); // Set a max delay so it isn't infinite
- this.reconnectTimer = setTimeout(
+ setTimeout(
() => this.tryReconnect(),
// Adds a random factor to avoid pendulum effect during long total breakdown
this.reconnectDuration + Math.random() * this.randVarianceTime,
@@ -81,14 +79,14 @@ export class UnavailableModalUiHandler extends ModalUiHandler {
}
show(args: any[]): boolean {
- if (args.length >= 1 && args[0] instanceof Function) {
+ if (args.length > 0 && args[0] instanceof Function) {
const config: ModalConfig = {
buttonActions: [],
};
this.reconnectCallback = args[0];
this.reconnectDuration = this.minTime;
- this.reconnectTimer = setTimeout(() => this.tryReconnect(), this.reconnectDuration);
+ setTimeout(() => this.tryReconnect(), this.reconnectDuration);
return super.show([config]);
}
diff --git a/src/ui/settings/abstract-control-settings-ui-handler.ts b/src/ui/settings/abstract-control-settings-ui-handler.ts
index c08f1570b75..2d9f3e6a6bd 100644
--- a/src/ui/settings/abstract-control-settings-ui-handler.ts
+++ b/src/ui/settings/abstract-control-settings-ui-handler.ts
@@ -5,10 +5,10 @@ import type { Device } from "#enums/devices";
import { TextStyle } from "#enums/text-style";
import type { UiMode } from "#enums/ui-mode";
import { getIconWithSettingName } from "#inputs/config-handler";
+import { ScrollBar } from "#ui/containers/scroll-bar";
+import { UiHandler } from "#ui/handlers/ui-handler";
import { NavigationManager, NavigationMenu } from "#ui/navigation-menu";
-import { ScrollBar } from "#ui/scroll-bar";
import { addTextObject, getTextColor } from "#ui/text";
-import { UiHandler } from "#ui/ui-handler";
import { addWindow } from "#ui/ui-theme";
import { toCamelCase } from "#utils/strings";
import i18next from "i18next";
@@ -544,8 +544,13 @@ export abstract class AbstractControlSettingsUiHandler extends UiHandler {
}
if (this.settingBlacklisted.includes(setting) || setting.includes("BUTTON_")) {
success = false;
- } else if (this.optionCursors[cursor]) {
- success = this.setOptionCursor(cursor, this.optionCursors[cursor] - 1, true);
+ } else {
+ // Cycle to the rightmost position when at the leftmost, otherwise move left
+ success = this.setOptionCursor(
+ cursor,
+ Phaser.Math.Wrap(this.optionCursors[cursor] - 1, 0, this.optionValueLabels[cursor].length),
+ true,
+ );
}
break;
case Button.RIGHT: // Move selection right within the current option set.
@@ -554,8 +559,13 @@ export abstract class AbstractControlSettingsUiHandler extends UiHandler {
}
if (this.settingBlacklisted.includes(setting) || setting.includes("BUTTON_")) {
success = false;
- } else if (this.optionCursors[cursor] < this.optionValueLabels[cursor].length - 1) {
- success = this.setOptionCursor(cursor, this.optionCursors[cursor] + 1, true);
+ } else {
+ // Cycle to the leftmost position when at the rightmost, otherwise move right
+ success = this.setOptionCursor(
+ cursor,
+ Phaser.Math.Wrap(this.optionCursors[cursor] + 1, 0, this.optionValueLabels[cursor].length),
+ true,
+ );
}
break;
case Button.CYCLE_FORM:
diff --git a/src/ui/settings/abstract-settings-ui-handler.ts b/src/ui/settings/abstract-settings-ui-handler.ts
index ae1bb40dbeb..ef117fb6a34 100644
--- a/src/ui/settings/abstract-settings-ui-handler.ts
+++ b/src/ui/settings/abstract-settings-ui-handler.ts
@@ -5,9 +5,9 @@ import { UiMode } from "#enums/ui-mode";
import type { SettingType } from "#system/settings";
import { Setting, SettingKeys } from "#system/settings";
import type { InputsIcons } from "#ui/abstract-control-settings-ui-handler";
-import { MessageUiHandler } from "#ui/message-ui-handler";
+import { ScrollBar } from "#ui/containers/scroll-bar";
+import { MessageUiHandler } from "#ui/handlers/message-ui-handler";
import { NavigationManager, NavigationMenu } from "#ui/navigation-menu";
-import { ScrollBar } from "#ui/scroll-bar";
import { addTextObject, getTextColor } from "#ui/text";
import { addWindow } from "#ui/ui-theme";
import i18next from "i18next";
@@ -34,8 +34,6 @@ export class AbstractSettingsUiHandler extends MessageUiHandler {
protected navigationIcons: InputsIcons;
private cursorObj: Phaser.GameObjects.NineSlice | null;
-
- private reloadSettings: Array;
private reloadRequired: boolean;
protected rowsToDisplay: number;
@@ -107,8 +105,6 @@ export class AbstractSettingsUiHandler extends MessageUiHandler {
this.settingLabels = [];
this.optionValueLabels = [];
- this.reloadSettings = this.settings.filter(s => s?.requireReload);
-
let anyReloadRequired = false;
this.settings.forEach((setting, s) => {
let settingName = setting.label;
@@ -318,16 +314,20 @@ export class AbstractSettingsUiHandler extends MessageUiHandler {
}
break;
case Button.LEFT:
- if (this.optionCursors[cursor]) {
- // Moves the option cursor left, if possible.
- success = this.setOptionCursor(cursor, this.optionCursors[cursor] - 1, true);
- }
+ // Cycle to the rightmost position when at the leftmost, otherwise move left
+ success = this.setOptionCursor(
+ cursor,
+ Phaser.Math.Wrap(this.optionCursors[cursor] - 1, 0, this.optionValueLabels[cursor].length),
+ true,
+ );
break;
case Button.RIGHT:
- // Moves the option cursor right, if possible.
- if (this.optionCursors[cursor] < this.optionValueLabels[cursor].length - 1) {
- success = this.setOptionCursor(cursor, this.optionCursors[cursor] + 1, true);
- }
+ // Cycle to the leftmost position when at the rightmost, otherwise move right
+ success = this.setOptionCursor(
+ cursor,
+ Phaser.Math.Wrap(this.optionCursors[cursor] + 1, 0, this.optionValueLabels[cursor].length),
+ true,
+ );
break;
case Button.CYCLE_FORM:
case Button.CYCLE_SHINY:
@@ -516,7 +516,7 @@ export class AbstractSettingsUiHandler extends MessageUiHandler {
prompt?: boolean,
promptDelay?: number,
) {
- this.messageBoxContainer.setVisible(!!text?.length);
+ this.messageBoxContainer.setVisible(text?.length > 0);
super.showText(text, delay, callback, callbackDelay, prompt, promptDelay);
}
}
diff --git a/src/ui/settings/gamepad-binding-ui-handler.ts b/src/ui/settings/gamepad-binding-ui-handler.ts
index 53d606b6f84..4fdc4abdbfe 100644
--- a/src/ui/settings/gamepad-binding-ui-handler.ts
+++ b/src/ui/settings/gamepad-binding-ui-handler.ts
@@ -3,7 +3,7 @@ import { Device } from "#enums/devices";
import { TextStyle } from "#enums/text-style";
import type { UiMode } from "#enums/ui-mode";
import { getIconWithSettingName, getKeyWithKeycode } from "#inputs/config-handler";
-import { AbstractBindingUiHandler } from "#ui/abstract-binding-ui-handler";
+import { AbstractBindingUiHandler } from "#ui/handlers/abstract-binding-ui-handler";
import { addTextObject } from "#ui/text";
import i18next from "i18next";
@@ -53,10 +53,10 @@ export class GamepadBindingUiHandler extends AbstractBindingUiHandler {
const blacklist = [12, 13, 14, 15]; // d-pad buttons are blacklisted.
// Check conditions before processing the button press.
if (
- !this.listening ||
- pad.id.toLowerCase() !== this.getSelectedDevice() ||
- blacklist.includes(button.index) ||
- this.buttonPressed !== null
+ !this.listening
+ || pad.id.toLowerCase() !== this.getSelectedDevice()
+ || blacklist.includes(button.index)
+ || this.buttonPressed !== null
) {
return;
}
diff --git a/src/ui/settings/keyboard-binding-ui-handler.ts b/src/ui/settings/keyboard-binding-ui-handler.ts
index b339ac16188..b1fd153461f 100644
--- a/src/ui/settings/keyboard-binding-ui-handler.ts
+++ b/src/ui/settings/keyboard-binding-ui-handler.ts
@@ -3,7 +3,7 @@ import { Device } from "#enums/devices";
import { TextStyle } from "#enums/text-style";
import type { UiMode } from "#enums/ui-mode";
import { getKeyWithKeycode } from "#inputs/config-handler";
-import { AbstractBindingUiHandler } from "#ui/abstract-binding-ui-handler";
+import { AbstractBindingUiHandler } from "#ui/handlers/abstract-binding-ui-handler";
import { addTextObject } from "#ui/text";
import i18next from "i18next";
diff --git a/src/ui/settings/move-touch-controls-handler.ts b/src/ui/settings/move-touch-controls-handler.ts
index 60572529c89..248ee76a850 100644
--- a/src/ui/settings/move-touch-controls-handler.ts
+++ b/src/ui/settings/move-touch-controls-handler.ts
@@ -9,9 +9,9 @@ export const TOUCH_CONTROL_POSITIONS_PORTRAIT = "touchControlPositionsPortrait";
type ControlPosition = { id: string; x: number; y: number };
type ConfigurationEventListeners = {
- touchstart: EventListener[];
- touchmove: EventListener[];
- touchend: EventListener[];
+ pointerdown: EventListener[];
+ pointermove: EventListener[];
+ pointerup: EventListener[];
};
type ToolbarRefs = {
@@ -39,9 +39,9 @@ export class MoveTouchControlsHandler {
* These are used to remove the event listeners when the configuration mode is disabled.
*/
private configurationEventListeners: ConfigurationEventListeners = {
- touchstart: [],
- touchmove: [],
- touchend: [],
+ pointerdown: [],
+ pointermove: [],
+ pointerup: [],
};
private overlay: Phaser.GameObjects.Container;
@@ -165,34 +165,33 @@ export class MoveTouchControlsHandler {
/**
* Start dragging the given button.
* @param controlGroup The button that is being dragged.
- * @param touch The touch event that started the drag.
+ * @param event The pointer event that started the drag.
*/
private startDrag = (controlGroup: HTMLElement): void => {
this.draggingElement = controlGroup;
};
/**
- * Drags the currently dragged element to the given touch position.
- * @param touch The touch event that is currently happening.
- * @param isLeft Whether the dragged element is a left button.
+ * Drags the currently dragged element to the given pointer position.
+ * @param event The pointer event that is currently happening.
*/
- private drag = (touch: Touch): void => {
+ private drag = (event: PointerEvent): void => {
if (!this.draggingElement) {
return;
}
const rect = this.draggingElement.getBoundingClientRect();
- // Map the touch position to the center of the dragged element.
+ // Map the pointer position to the center of the dragged element.
const xOffset = this.isLeft(this.draggingElement)
- ? touch.clientX - rect.width / 2
- : window.innerWidth - touch.clientX - rect.width / 2;
- const yOffset = window.innerHeight - touch.clientY - rect.height / 2;
+ ? event.clientX - rect.width / 2
+ : window.innerWidth - event.clientX - rect.width / 2;
+ const yOffset = window.innerHeight - event.clientY - rect.height / 2;
this.setPosition(this.draggingElement, xOffset, yOffset);
};
/**
* Stops dragging the currently dragged element.
*/
- private stopDrag = () => {
+ private stopDrag = (): void => {
this.draggingElement = null;
};
@@ -303,19 +302,19 @@ export class MoveTouchControlsHandler {
*/
private createConfigurationEventListeners(controlGroups: HTMLDivElement[]): ConfigurationEventListeners {
return {
- touchstart: controlGroups.map((element: HTMLDivElement) => {
+ pointerdown: controlGroups.map((element: HTMLDivElement) => {
const startDrag = () => this.startDrag(element);
- element.addEventListener("touchstart", startDrag, { passive: true });
+ element.addEventListener("pointerdown", startDrag, { passive: true });
return startDrag;
}),
- touchmove: controlGroups.map(() => {
- const drag = event => this.drag(event.touches[0]);
- window.addEventListener("touchmove", drag, { passive: true });
+ pointermove: controlGroups.map(() => {
+ const drag = (event: PointerEvent) => this.drag(event);
+ window.addEventListener("pointermove", drag, { passive: true });
return drag;
}),
- touchend: controlGroups.map(() => {
+ pointerup: controlGroups.map(() => {
const stopDrag = () => this.stopDrag();
- window.addEventListener("touchend", stopDrag, { passive: true });
+ window.addEventListener("pointerup", stopDrag, { passive: true });
return stopDrag;
}),
};
@@ -373,12 +372,12 @@ export class MoveTouchControlsHandler {
this.draggingElement = null;
// Remove event listeners
- const { touchstart, touchmove, touchend } = this.configurationEventListeners;
+ const { pointerdown, pointermove, pointerup } = this.configurationEventListeners;
this.getControlGroupElements().forEach((element, index) =>
- element.removeEventListener("touchstart", touchstart[index]),
+ element.removeEventListener("pointerdown", pointerdown[index]),
);
- touchmove.forEach(listener => window.removeEventListener("touchmove", listener));
- touchend.forEach(listener => window.removeEventListener("touchend", listener));
+ pointermove.forEach(listener => window.removeEventListener("pointermove", listener));
+ pointerup.forEach(listener => window.removeEventListener("pointerup", listener));
// Remove configuration toolbar
const toolbar = document.querySelector("#touchControls #configToolbar");
diff --git a/src/ui/settings/option-select-ui-handler.ts b/src/ui/settings/option-select-ui-handler.ts
index c989c768244..235f16e7f09 100644
--- a/src/ui/settings/option-select-ui-handler.ts
+++ b/src/ui/settings/option-select-ui-handler.ts
@@ -1,5 +1,5 @@
import { UiMode } from "#enums/ui-mode";
-import { AbstractOptionSelectUiHandler } from "#ui/abstract-option-select-ui-handler";
+import { AbstractOptionSelectUiHandler } from "#ui/handlers/abstract-option-select-ui-handler";
export class OptionSelectUiHandler extends AbstractOptionSelectUiHandler {
constructor(mode: UiMode = UiMode.OPTION_SELECT) {
diff --git a/src/ui/text.ts b/src/ui/text.ts
index 927f9f08bb2..4338a73179d 100644
--- a/src/ui/text.ts
+++ b/src/ui/text.ts
@@ -457,8 +457,8 @@ export function getTextStyleOptions(
if (extraStyleOptions) {
if (extraStyleOptions.fontSize) {
const sizeRatio =
- Number.parseInt(extraStyleOptions.fontSize.toString().slice(0, -2)) /
- Number.parseInt(styleOptions.fontSize?.toString().slice(0, -2) ?? "1");
+ Number.parseInt(extraStyleOptions.fontSize.toString().slice(0, -2))
+ / Number.parseInt(styleOptions.fontSize?.toString().slice(0, -2) ?? "1");
shadowXpos *= sizeRatio;
}
styleOptions = Object.assign(styleOptions, extraStyleOptions);
diff --git a/src/ui/ui-theme.ts b/src/ui/ui-theme.ts
index 9e130417b43..3520447ed1f 100644
--- a/src/ui/ui-theme.ts
+++ b/src/ui/ui-theme.ts
@@ -117,10 +117,8 @@ export function updateWindowType(windowTypeIndex: number): void {
} else if (object.texture?.key === "namebox") {
themedObjects.push(object);
}
- } else if (object instanceof Phaser.GameObjects.Sprite) {
- if (object.texture?.key === "bg") {
- themedObjects.push(object);
- }
+ } else if (object instanceof Phaser.GameObjects.Sprite && object.texture?.key === "bg") {
+ themedObjects.push(object);
}
};
@@ -154,9 +152,9 @@ export function addUiThemeOverrides(): void {
): Phaser.GameObjects.Image {
let legacy = false;
if (
- typeof texture === "string" &&
- globalScene.uiTheme === UiTheme.LEGACY &&
- legacyCompatibleImages.includes(texture)
+ typeof texture === "string"
+ && globalScene.uiTheme === UiTheme.LEGACY
+ && legacyCompatibleImages.includes(texture)
) {
legacy = true;
texture += "_legacy";
@@ -181,9 +179,9 @@ export function addUiThemeOverrides(): void {
): Phaser.GameObjects.Sprite {
let legacy = false;
if (
- typeof texture === "string" &&
- globalScene.uiTheme === UiTheme.LEGACY &&
- legacyCompatibleImages.includes(texture)
+ typeof texture === "string"
+ && globalScene.uiTheme === UiTheme.LEGACY
+ && legacyCompatibleImages.includes(texture)
) {
legacy = true;
texture += "_legacy";
@@ -214,9 +212,9 @@ export function addUiThemeOverrides(): void {
): Phaser.GameObjects.NineSlice {
let legacy = false;
if (
- typeof texture === "string" &&
- globalScene.uiTheme === UiTheme.LEGACY &&
- legacyCompatibleImages.includes(texture)
+ typeof texture === "string"
+ && globalScene.uiTheme === UiTheme.LEGACY
+ && legacyCompatibleImages.includes(texture)
) {
legacy = true;
texture += "_legacy";
diff --git a/src/ui/ui.ts b/src/ui/ui.ts
index e381d205b78..a8e4dbe7318 100644
--- a/src/ui/ui.ts
+++ b/src/ui/ui.ts
@@ -4,63 +4,63 @@ import { Device } from "#enums/devices";
import { PlayerGender } from "#enums/player-gender";
import { TextStyle } from "#enums/text-style";
import { UiMode } from "#enums/ui-mode";
-import { AchvBar } from "#ui/achv-bar";
-import { AchvsUiHandler } from "#ui/achvs-ui-handler";
-import { AdminUiHandler } from "#ui/admin-ui-handler";
-import { AutoCompleteUiHandler } from "#ui/autocomplete-ui-handler";
-import { AwaitableUiHandler } from "#ui/awaitable-ui-handler";
-import { BallUiHandler } from "#ui/ball-ui-handler";
-import { BattleMessageUiHandler } from "#ui/battle-message-ui-handler";
-import type { BgmBar } from "#ui/bgm-bar";
-import { GameChallengesUiHandler } from "#ui/challenges-select-ui-handler";
-import { ChangePasswordFormUiHandler } from "#ui/change-password-form-ui-handler";
-import { CommandUiHandler } from "#ui/command-ui-handler";
-import { ConfirmUiHandler } from "#ui/confirm-ui-handler";
-import { EggGachaUiHandler } from "#ui/egg-gacha-ui-handler";
-import { EggHatchSceneHandler } from "#ui/egg-hatch-scene-handler";
-import { EggListUiHandler } from "#ui/egg-list-ui-handler";
-import { EggSummaryUiHandler } from "#ui/egg-summary-ui-handler";
-import { EvolutionSceneHandler } from "#ui/evolution-scene-handler";
-import { FightUiHandler } from "#ui/fight-ui-handler";
-import { GameStatsUiHandler } from "#ui/game-stats-ui-handler";
+import { AchvBar } from "#ui/containers/achv-bar";
+import type { BgmBar } from "#ui/containers/bgm-bar";
+import { PokedexPageUiHandler } from "#ui/containers/pokedex-page-ui-handler";
+import { SavingIconHandler } from "#ui/containers/saving-icon-handler";
import { GamepadBindingUiHandler } from "#ui/gamepad-binding-ui-handler";
+import { AchvsUiHandler } from "#ui/handlers/achvs-ui-handler";
+import { AutoCompleteUiHandler } from "#ui/handlers/autocomplete-ui-handler";
+import { AwaitableUiHandler } from "#ui/handlers/awaitable-ui-handler";
+import { BallUiHandler } from "#ui/handlers/ball-ui-handler";
+import { BattleMessageUiHandler } from "#ui/handlers/battle-message-ui-handler";
+import { GameChallengesUiHandler } from "#ui/handlers/challenges-select-ui-handler";
+import { ChangePasswordFormUiHandler } from "#ui/handlers/change-password-form-ui-handler";
+import { CommandUiHandler } from "#ui/handlers/command-ui-handler";
+import { ConfirmUiHandler } from "#ui/handlers/confirm-ui-handler";
+import { EggGachaUiHandler } from "#ui/handlers/egg-gacha-ui-handler";
+import { EggHatchSceneHandler } from "#ui/handlers/egg-hatch-scene-handler";
+import { EggListUiHandler } from "#ui/handlers/egg-list-ui-handler";
+import { EggSummaryUiHandler } from "#ui/handlers/egg-summary-ui-handler";
+import { EvolutionSceneHandler } from "#ui/handlers/evolution-scene-handler";
+import { FightUiHandler } from "#ui/handlers/fight-ui-handler";
+import { GameStatsUiHandler } from "#ui/handlers/game-stats-ui-handler";
+import { LoadingModalUiHandler } from "#ui/handlers/loading-modal-ui-handler";
+import { LoginFormUiHandler } from "#ui/handlers/login-form-ui-handler";
+import { MenuUiHandler } from "#ui/handlers/menu-ui-handler";
+import { MessageUiHandler } from "#ui/handlers/message-ui-handler";
+import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler";
+import { MysteryEncounterUiHandler } from "#ui/handlers/mystery-encounter-ui-handler";
+import { PartyUiHandler } from "#ui/handlers/party-ui-handler";
+import { PokedexScanUiHandler } from "#ui/handlers/pokedex-scan-ui-handler";
+import { PokedexUiHandler } from "#ui/handlers/pokedex-ui-handler";
+import { RegistrationFormUiHandler } from "#ui/handlers/registration-form-ui-handler";
+import { RenameFormUiHandler } from "#ui/handlers/rename-form-ui-handler";
+import { RunHistoryUiHandler } from "#ui/handlers/run-history-ui-handler";
+import { RunInfoUiHandler } from "#ui/handlers/run-info-ui-handler";
+import { SaveSlotSelectUiHandler } from "#ui/handlers/save-slot-select-ui-handler";
+import { SessionReloadModalUiHandler } from "#ui/handlers/session-reload-modal-ui-handler";
+import { StarterSelectUiHandler } from "#ui/handlers/starter-select-ui-handler";
+import { SummaryUiHandler } from "#ui/handlers/summary-ui-handler";
+import { TargetSelectUiHandler } from "#ui/handlers/target-select-ui-handler";
+import { TestDialogueUiHandler } from "#ui/handlers/test-dialogue-ui-handler";
+import { TitleUiHandler } from "#ui/handlers/title-ui-handler";
+import type { UiHandler } from "#ui/handlers/ui-handler";
+import { UnavailableModalUiHandler } from "#ui/handlers/unavailable-modal-ui-handler";
import { KeyboardBindingUiHandler } from "#ui/keyboard-binding-ui-handler";
-import { LoadingModalUiHandler } from "#ui/loading-modal-ui-handler";
-import { LoginFormUiHandler } from "#ui/login-form-ui-handler";
-import { MenuUiHandler } from "#ui/menu-ui-handler";
-import { MessageUiHandler } from "#ui/message-ui-handler";
-import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
-import { MysteryEncounterUiHandler } from "#ui/mystery-encounter-ui-handler";
import { NavigationManager } from "#ui/navigation-menu";
import { OptionSelectUiHandler } from "#ui/option-select-ui-handler";
-import { PartyUiHandler } from "#ui/party-ui-handler";
-import { PokedexPageUiHandler } from "#ui/pokedex-page-ui-handler";
-import { PokedexScanUiHandler } from "#ui/pokedex-scan-ui-handler";
-import { PokedexUiHandler } from "#ui/pokedex-ui-handler";
-import { RegistrationFormUiHandler } from "#ui/registration-form-ui-handler";
-import { RenameFormUiHandler } from "#ui/rename-form-ui-handler";
-import { RunHistoryUiHandler } from "#ui/run-history-ui-handler";
-import { RunInfoUiHandler } from "#ui/run-info-ui-handler";
-import { SaveSlotSelectUiHandler } from "#ui/save-slot-select-ui-handler";
-import { SavingIconHandler } from "#ui/saving-icon-handler";
-import { SessionReloadModalUiHandler } from "#ui/session-reload-modal-ui-handler";
import { SettingsAudioUiHandler } from "#ui/settings-audio-ui-handler";
import { SettingsDisplayUiHandler } from "#ui/settings-display-ui-handler";
import { SettingsGamepadUiHandler } from "#ui/settings-gamepad-ui-handler";
import { SettingsKeyboardUiHandler } from "#ui/settings-keyboard-ui-handler";
import { SettingsUiHandler } from "#ui/settings-ui-handler";
-import { StarterSelectUiHandler } from "#ui/starter-select-ui-handler";
-import { SummaryUiHandler } from "#ui/summary-ui-handler";
-import { TargetSelectUiHandler } from "#ui/target-select-ui-handler";
-import { TestDialogueUiHandler } from "#ui/test-dialogue-ui-handler";
import { addTextObject } from "#ui/text";
-import { TitleUiHandler } from "#ui/title-ui-handler";
-import type { UiHandler } from "#ui/ui-handler";
import { addWindow } from "#ui/ui-theme";
-import { UnavailableModalUiHandler } from "#ui/unavailable-modal-ui-handler";
import { executeIf } from "#utils/common";
import i18next from "i18next";
-import { RenameRunFormUiHandler } from "./rename-run-ui-handler";
+import { AdminUiHandler } from "./handlers/admin-ui-handler";
+import { RenameRunFormUiHandler } from "./handlers/rename-run-ui-handler";
const transitionModes = [
UiMode.SAVE_SLOT,
@@ -377,10 +377,12 @@ export class UI extends Phaser.GameObjects.Container {
}
shouldSkipDialogue(i18nKey: string): boolean {
- if (i18next.exists(i18nKey)) {
- if (globalScene.skipSeenDialogues && globalScene.gameData.getSeenDialogues()[i18nKey] === true) {
- return true;
- }
+ if (
+ i18next.exists(i18nKey)
+ && globalScene.skipSeenDialogues
+ && globalScene.gameData.getSeenDialogues()[i18nKey] === true
+ ) {
+ return true;
}
return false;
}
@@ -491,7 +493,7 @@ export class UI extends Phaser.GameObjects.Container {
globalScene.tweens.add({
targets: this.overlay,
alpha: 1,
- duration: duration,
+ duration,
ease: "Sine.easeOut",
onComplete: () => resolve(),
});
@@ -506,7 +508,7 @@ export class UI extends Phaser.GameObjects.Container {
globalScene.tweens.add({
targets: this.overlay,
alpha: 0,
- duration: duration,
+ duration,
ease: "Sine.easeIn",
onComplete: () => {
this.overlay.setVisible(false);
@@ -548,11 +550,11 @@ export class UI extends Phaser.GameObjects.Container {
resolve();
};
if (
- (!chainMode &&
- (transitionModes.indexOf(this.mode) > -1 || transitionModes.indexOf(mode) > -1) &&
- noTransitionModes.indexOf(this.mode) === -1 &&
- noTransitionModes.indexOf(mode) === -1) ||
- (chainMode && noTransitionModes.indexOf(mode) === -1)
+ (!chainMode
+ && (transitionModes.indexOf(this.mode) > -1 || transitionModes.indexOf(mode) > -1)
+ && noTransitionModes.indexOf(this.mode) === -1
+ && noTransitionModes.indexOf(mode) === -1)
+ || (chainMode && noTransitionModes.indexOf(mode) === -1)
) {
this.fadeOut(250).then(() => {
globalScene.time.delayedCall(100, () => {
@@ -593,7 +595,7 @@ export class UI extends Phaser.GameObjects.Container {
revertMode(): Promise {
return new Promise(resolve => {
- if (!this?.modeChain?.length) {
+ if (this?.modeChain?.length === 0) {
return resolve(false);
}
@@ -625,7 +627,7 @@ export class UI extends Phaser.GameObjects.Container {
revertModes(): Promise {
return new Promise(resolve => {
- if (!this?.modeChain?.length) {
+ if (this?.modeChain?.length === 0) {
return resolve();
}
this.revertMode().then(success => executeIf(success, this.revertModes).then(() => resolve()));
diff --git a/src/utils/challenge-utils.ts b/src/utils/challenge-utils.ts
index b0c162a74ed..10f834e24b4 100644
--- a/src/utils/challenge-utils.ts
+++ b/src/utils/challenge-utils.ts
@@ -1,3 +1,5 @@
+// biome-ignore-all lint/style/useUnifiedTypeSignatures: Rule does not allow stuff with JSDoc comments
+
import type { FixedBattleConfig } from "#app/battle";
import { globalScene } from "#app/global-scene";
import { pokemonEvolutions } from "#balance/pokemon-evolutions";
@@ -366,7 +368,7 @@ export function checkStarterValidForChallenge(species: PokemonSpecies, props: De
}
// We check the validity of every evolution and form change, and require that at least one is valid
const speciesToCheck = [species.speciesId];
- while (speciesToCheck.length) {
+ while (speciesToCheck.length > 0) {
const checking = speciesToCheck.pop();
// Linter complains if we don't handle this
if (!checking) {
diff --git a/src/utils/cookies.ts b/src/utils/cookies.ts
index 06391e6f4c7..e82895d1fac 100644
--- a/src/utils/cookies.ts
+++ b/src/utils/cookies.ts
@@ -23,13 +23,11 @@ export function getCookie(cName: string): string {
}
const name = `${cName}=`;
const ca = document.cookie.split(";");
- for (let i = 0; i < ca.length; i++) {
- let c = ca[i];
- while (c.charAt(0) === " ") {
- c = c.substring(1);
- }
- if (c.indexOf(name) === 0) {
- return c.substring(name.length, c.length);
+ // Check all cookies in the document and see if any of them match, grabbing the first one whose value lines up
+ for (const c of ca) {
+ const cTrimmed = c.trim();
+ if (cTrimmed.startsWith(name)) {
+ return c.slice(name.length, c.length);
}
}
return "";
diff --git a/src/utils/data.ts b/src/utils/data.ts
index 75047c38d25..8ff308cde8f 100644
--- a/src/utils/data.ts
+++ b/src/utils/data.ts
@@ -28,9 +28,9 @@ export function deepCopy(values: T): T {
export function deepMergeSpriteData(dest: object, source: object) {
for (const key of Object.keys(source)) {
if (
- !(key in dest) ||
- typeof source[key] !== typeof dest[key] ||
- Array.isArray(source[key]) !== Array.isArray(dest[key])
+ !(key in dest)
+ || typeof source[key] !== typeof dest[key]
+ || Array.isArray(source[key]) !== Array.isArray(dest[key])
) {
continue;
}
diff --git a/src/utils/pokemon-utils.ts b/src/utils/pokemon-utils.ts
index 8de0a3bfcf1..60a4d9e0ef7 100644
--- a/src/utils/pokemon-utils.ts
+++ b/src/utils/pokemon-utils.ts
@@ -80,7 +80,7 @@ export function getFusedSpeciesName(speciesAName: string, speciesBName: string):
let fragA: string;
let fragB: string;
- fragA = splitNameA.length === 1 ? (fragAMatch ? fragAMatch[1] : speciesAName) : splitNameA[splitNameA.length - 1];
+ fragA = splitNameA.length === 1 ? (fragAMatch ? fragAMatch[1] : speciesAName) : splitNameA.at(-1)!;
if (splitNameB.length === 1) {
if (fragBMatch) {
@@ -101,7 +101,7 @@ export function getFusedSpeciesName(speciesAName: string, speciesBName: string):
fragB = speciesBName;
}
} else {
- fragB = splitNameB[splitNameB.length - 1];
+ fragB = splitNameB.at(-1)!;
}
if (splitNameA.length > 1) {
diff --git a/test/@types/vitest.d.ts b/test/@types/vitest.d.ts
index f0bbdf37932..b13d9e53101 100644
--- a/test/@types/vitest.d.ts
+++ b/test/@types/vitest.d.ts
@@ -4,8 +4,6 @@ import type { Phase } from "#app/phase";
import type Overrides from "#app/overrides";
import type { ArenaTag } from "#data/arena-tag";
import type { TerrainType } from "#data/terrain";
-import type { BattlerTag } from "#data/battler-tags";
-import type { PositionalTag } from "#data/positional-tags/positional-tag";
import type { AbilityId } from "#enums/ability-id";
import type { ArenaTagSide } from "#enums/arena-tag-side";
import type { ArenaTagType } from "#enums/arena-tag-type";
@@ -13,12 +11,8 @@ import type { BattlerTagType } from "#enums/battler-tag-type";
import type { MoveId } from "#enums/move-id";
import type { PokemonType } from "#enums/pokemon-type";
import type { PositionalTagType } from "#enums/positional-tag-type";
-import type { BattleStat, EffectiveStat, Stat } from "#enums/stat";
-import type { StatusEffect } from "#enums/status-effect";
+import type { BattleStat, EffectiveStat } from "#enums/stat";
import type { WeatherType } from "#enums/weather-type";
-import type { Arena } from "#field/arena";
-import type { Pokemon } from "#field/pokemon";
-import type { PokemonMove } from "#moves/pokemon-move";
import type { toHaveArenaTagOptions } from "#test/test-utils/matchers/to-have-arena-tag";
import type { toHaveEffectiveStatOptions } from "#test/test-utils/matchers/to-have-effective-stat";
import type { toHavePositionalTagOptions } from "#test/test-utils/matchers/to-have-positional-tag";
@@ -27,9 +21,9 @@ import type { toHaveTypesOptions } from "#test/test-utils/matchers/to-have-types
import type { PhaseString } from "#types/phase-types";
import type { TurnMove } from "#types/turn-move";
import type { AtLeastOne } from "#types/type-helpers";
-import type { toDmgValue } from "utils/common";
+import type { toDmgValue } from "#utils/common";
import type { expect } from "vitest";
-import { toHaveBattlerTagOptions } from "#test/test-utils/matchers/to-have-battler-tag";
+import type { toHaveBattlerTagOptions } from "#test/test-utils/matchers/to-have-battler-tag";
declare module "vitest" {
interface Assertion {
diff --git a/test/abilities/analytic.test.ts b/test/abilities/analytic.test.ts
index cf5a501bbc5..aa9eb3135db 100644
--- a/test/abilities/analytic.test.ts
+++ b/test/abilities/analytic.test.ts
@@ -56,7 +56,7 @@ describe("Abilities - Analytic", () => {
game.override.battleStyle("double");
await game.classicMode.startBattle([SpeciesId.GENGAR, SpeciesId.SHUCKLE]);
- const [enemy] = game.scene.getEnemyField();
+ const enemy = game.field.getEnemyPokemon();
game.move.select(MoveId.TACKLE, 0, BattlerIndex.ENEMY);
game.move.select(MoveId.SPLASH, 1);
diff --git a/test/abilities/arena-trap.test.ts b/test/abilities/arena-trap.test.ts
index 0090487f49c..d43148dce7b 100644
--- a/test/abilities/arena-trap.test.ts
+++ b/test/abilities/arena-trap.test.ts
@@ -6,7 +6,7 @@ import { MoveId } from "#enums/move-id";
import { SpeciesId } from "#enums/species-id";
import { UiMode } from "#enums/ui-mode";
import { GameManager } from "#test/test-utils/game-manager";
-import type { PartyUiHandler } from "#ui/party-ui-handler";
+import type { PartyUiHandler } from "#ui/handlers/party-ui-handler";
import i18next from "i18next";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
diff --git a/test/abilities/cud-chew.test.ts b/test/abilities/cud-chew.test.ts
index f68141096eb..ae3b4ad8765 100644
--- a/test/abilities/cud-chew.test.ts
+++ b/test/abilities/cud-chew.test.ts
@@ -99,7 +99,7 @@ describe("Abilities - Cud Chew", () => {
expect(abDisplaySpy.mock.calls[1][2]).toBe(false);
// should display messgae
- expect(game.textInterceptor.getLatestMessage()).toBe(
+ expect(game.textInterceptor.logs).toContain(
i18next.t("battle:hpIsFull", {
pokemonName: getPokemonNameWithAffix(farigiraf),
}),
diff --git a/test/abilities/friend-guard.test.ts b/test/abilities/friend-guard.test.ts
index 32f4fe06df4..10a9a9c6ee5 100644
--- a/test/abilities/friend-guard.test.ts
+++ b/test/abilities/friend-guard.test.ts
@@ -38,7 +38,12 @@ describe("Moves - Friend Guard", () => {
const [player1, player2] = game.scene.getPlayerField();
const spy = vi.spyOn(player1, "getAttackDamage");
- const enemy1 = game.scene.getEnemyField()[0];
+ const enemy1 = game.field.getEnemyPokemon();
+ const baseDmg = player1.getBaseDamage({
+ source: enemy1,
+ move: allMoves[MoveId.TACKLE],
+ moveCategory: MoveCategory.PHYSICAL,
+ });
game.move.select(MoveId.SPLASH);
game.move.select(MoveId.SPLASH, 1);
@@ -47,12 +52,11 @@ describe("Moves - Friend Guard", () => {
await game.toNextTurn();
// Get the last return value from `getAttackDamage`
- const turn1Damage = spy.mock.results[spy.mock.results.length - 1].value.damage;
// Making sure the test is controlled; turn 1 damage is equal to base damage (after rounding)
- expect(turn1Damage).toBe(
- Math.floor(
- player1.getBaseDamage({ source: enemy1, move: allMoves[MoveId.TACKLE], moveCategory: MoveCategory.PHYSICAL }),
- ),
+ expect(spy).toHaveLastReturnedWith(
+ expect.objectContaining({
+ damage: Math.floor(baseDmg),
+ }),
);
vi.spyOn(player2, "getAbility").mockReturnValue(allAbilities[AbilityId.FRIEND_GUARD]);
@@ -64,14 +68,8 @@ describe("Moves - Friend Guard", () => {
await game.toNextTurn();
// Get the last return value from `getAttackDamage`
- const turn2Damage = spy.mock.results[spy.mock.results.length - 1].value.damage;
// With the ally's Friend Guard, damage should have been reduced from base damage by 25%
- expect(turn2Damage).toBe(
- Math.floor(
- player1.getBaseDamage({ source: enemy1, move: allMoves[MoveId.TACKLE], moveCategory: MoveCategory.PHYSICAL }) *
- 0.75,
- ),
- );
+ expect(spy).toHaveLastReturnedWith(expect.objectContaining({ damage: Math.floor(baseDmg * 0.75) }));
});
it("should NOT reduce damage to pokemon with friend guard", async () => {
@@ -86,7 +84,7 @@ describe("Moves - Friend Guard", () => {
await game.move.selectEnemyMove(MoveId.SPLASH);
await game.toNextTurn();
- const turn1Damage = spy.mock.results[spy.mock.results.length - 1].value.damage;
+ const turn1Damage = spy.mock.results.at(-1)!.value.damage;
vi.spyOn(player2, "getAbility").mockReturnValue(allAbilities[AbilityId.FRIEND_GUARD]);
@@ -96,7 +94,7 @@ describe("Moves - Friend Guard", () => {
await game.move.selectEnemyMove(MoveId.SPLASH);
await game.toNextTurn();
- const turn2Damage = spy.mock.results[spy.mock.results.length - 1].value.damage;
+ const turn2Damage = spy.mock.results.at(-1)!.value.damage;
expect(turn2Damage).toBe(turn1Damage);
});
@@ -112,7 +110,7 @@ describe("Moves - Friend Guard", () => {
await game.move.selectEnemyMove(MoveId.SPLASH);
await game.toNextTurn();
- const turn1Damage = spy.mock.results[spy.mock.results.length - 1].value.damage;
+ const turn1Damage = spy.mock.results.at(-1)!.value.damage;
expect(turn1Damage).toBe(40);
vi.spyOn(player2, "getAbility").mockReturnValue(allAbilities[AbilityId.FRIEND_GUARD]);
@@ -123,7 +121,7 @@ describe("Moves - Friend Guard", () => {
await game.move.selectEnemyMove(MoveId.SPLASH);
await game.toNextTurn();
- const turn2Damage = spy.mock.results[spy.mock.results.length - 1].value.damage;
+ const turn2Damage = spy.mock.results.at(-1)!.value.damage;
expect(turn2Damage).toBe(40);
});
});
diff --git a/test/abilities/power-construct.test.ts b/test/abilities/power-construct.test.ts
index 34e02851daf..6c504359370 100644
--- a/test/abilities/power-construct.test.ts
+++ b/test/abilities/power-construct.test.ts
@@ -33,8 +33,8 @@ describe("Abilities - POWER CONSTRUCT", () => {
});
test("check if fainted 50% Power Construct Pokemon switches to base form on arena reset", async () => {
- const baseForm = 2,
- completeForm = 4;
+ const baseForm = 2;
+ const completeForm = 4;
game.override.startingWave(4).starterForms({
[SpeciesId.ZYGARDE]: completeForm,
});
@@ -59,8 +59,8 @@ describe("Abilities - POWER CONSTRUCT", () => {
});
test("check if fainted 10% Power Construct Pokemon switches to base form on arena reset", async () => {
- const baseForm = 3,
- completeForm = 5;
+ const baseForm = 3;
+ const completeForm = 5;
game.override.startingWave(4).starterForms({
[SpeciesId.ZYGARDE]: completeForm,
});
diff --git a/test/abilities/schooling.test.ts b/test/abilities/schooling.test.ts
index fea919c7c5a..5c908d39866 100644
--- a/test/abilities/schooling.test.ts
+++ b/test/abilities/schooling.test.ts
@@ -29,8 +29,8 @@ describe("Abilities - SCHOOLING", () => {
});
test("check if fainted pokemon switches to base form on arena reset", async () => {
- const soloForm = 0,
- schoolForm = 1;
+ const soloForm = 0;
+ const schoolForm = 1;
game.override.startingWave(4).starterForms({
[SpeciesId.WISHIWASHI]: schoolForm,
});
diff --git a/test/challenges/hardcore.test.ts b/test/challenges/hardcore.test.ts
index 0f4ab1b9f02..a52d7102868 100644
--- a/test/challenges/hardcore.test.ts
+++ b/test/challenges/hardcore.test.ts
@@ -8,7 +8,7 @@ import { SpeciesId } from "#enums/species-id";
import { StatusEffect } from "#enums/status-effect";
import { UiMode } from "#enums/ui-mode";
import { GameManager } from "#test/test-utils/game-manager";
-import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
+import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
diff --git a/test/challenges/limited-support.test.ts b/test/challenges/limited-support.test.ts
index 35413220550..ba8930943dd 100644
--- a/test/challenges/limited-support.test.ts
+++ b/test/challenges/limited-support.test.ts
@@ -5,7 +5,7 @@ import { SpeciesId } from "#enums/species-id";
import { UiMode } from "#enums/ui-mode";
import { ExpBoosterModifier } from "#modifiers/modifier";
import { GameManager } from "#test/test-utils/game-manager";
-import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
+import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
diff --git a/test/daily-mode.test.ts b/test/daily-mode.test.ts
index 34a8da80478..fae12a0b5d7 100644
--- a/test/daily-mode.test.ts
+++ b/test/daily-mode.test.ts
@@ -5,7 +5,7 @@ import { SpeciesId } from "#enums/species-id";
import { UiMode } from "#enums/ui-mode";
import { MapModifier } from "#modifiers/modifier";
import { GameManager } from "#test/test-utils/game-manager";
-import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
+import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
describe("Daily Mode", () => {
diff --git a/test/escape-calculations.test.ts b/test/escape-calculations.test.ts
index f1bb955582a..fb677e81a45 100644
--- a/test/escape-calculations.test.ts
+++ b/test/escape-calculations.test.ts
@@ -76,9 +76,9 @@ describe("Escape chance calculations", () => {
{ pokemonSpeedRatio: 2, escapeAttempts: 3, expectedEscapeChance: 80 },
];
- for (let i = 0; i < escapeChances.length; i++) {
- // sets the number of escape attempts to the required amount
- game.scene.currentBattle.escapeAttempts = escapeChances[i].escapeAttempts;
+ for (const check of escapeChances) {
+ // set the number of escape attempts to the required amount
+ game.scene.currentBattle.escapeAttempts = check.escapeAttempts;
// set playerPokemon's speed to a multiple of the enemySpeed
vi.spyOn(playerPokemon[0], "stats", "get").mockReturnValue([
20,
@@ -86,10 +86,10 @@ describe("Escape chance calculations", () => {
20,
20,
20,
- escapeChances[i].pokemonSpeedRatio * enemySpeed,
+ check.pokemonSpeedRatio * enemySpeed,
]);
const chance = phase.calculateEscapeChance(game.scene.currentBattle.escapeAttempts);
- expect(chance).toBe(escapeChances[i].expectedEscapeChance);
+ expect(chance).toBe(check.expectedEscapeChance);
}
});
@@ -146,9 +146,9 @@ describe("Escape chance calculations", () => {
{ pokemonSpeedRatio: 2, escapeAttempts: 10, expectedEscapeChance: 95 },
];
- for (let i = 0; i < escapeChances.length; i++) {
+ for (const check of escapeChances) {
// sets the number of escape attempts to the required amount
- game.scene.currentBattle.escapeAttempts = escapeChances[i].escapeAttempts;
+ game.scene.currentBattle.escapeAttempts = check.escapeAttempts;
// set the first playerPokemon's speed to a multiple of the enemySpeed
vi.spyOn(playerPokemon[0], "stats", "get").mockReturnValue([
20,
@@ -156,7 +156,7 @@ describe("Escape chance calculations", () => {
20,
20,
20,
- Math.floor(escapeChances[i].pokemonSpeedRatio * totalEnemySpeed * playerASpeedPercentage),
+ Math.floor(check.pokemonSpeedRatio * totalEnemySpeed * playerASpeedPercentage),
]);
// set the second playerPokemon's speed to the remaining value of speed
vi.spyOn(playerPokemon[1], "stats", "get").mockReturnValue([
@@ -165,15 +165,13 @@ describe("Escape chance calculations", () => {
20,
20,
20,
- escapeChances[i].pokemonSpeedRatio * totalEnemySpeed - playerPokemon[0].stats[5],
+ check.pokemonSpeedRatio * totalEnemySpeed - playerPokemon[0].stats[5],
]);
const chance = phase.calculateEscapeChance(game.scene.currentBattle.escapeAttempts);
// checks to make sure the escape values are the same
- expect(chance).toBe(escapeChances[i].expectedEscapeChance);
+ expect(chance).toBe(check.expectedEscapeChance);
// checks to make sure the sum of the player's speed for all pokemon is equal to the appropriate ratio of the total enemy speed
- expect(playerPokemon[0].stats[5] + playerPokemon[1].stats[5]).toBe(
- escapeChances[i].pokemonSpeedRatio * totalEnemySpeed,
- );
+ expect(playerPokemon[0].stats[5] + playerPokemon[1].stats[5]).toBe(check.pokemonSpeedRatio * totalEnemySpeed);
}
});
@@ -238,9 +236,9 @@ describe("Escape chance calculations", () => {
{ pokemonSpeedRatio: 6.1, escapeAttempts: 3, expectedEscapeChance: 25 },
];
- for (let i = 0; i < escapeChances.length; i++) {
+ for (const check of escapeChances) {
// sets the number of escape attempts to the required amount
- game.scene.currentBattle.escapeAttempts = escapeChances[i].escapeAttempts;
+ game.scene.currentBattle.escapeAttempts = check.escapeAttempts;
// set playerPokemon's speed to a multiple of the enemySpeed
vi.spyOn(playerPokemon[0], "stats", "get").mockReturnValue([
20,
@@ -248,10 +246,10 @@ describe("Escape chance calculations", () => {
20,
20,
20,
- escapeChances[i].pokemonSpeedRatio * enemySpeed,
+ check.pokemonSpeedRatio * enemySpeed,
]);
const chance = phase.calculateEscapeChance(game.scene.currentBattle.escapeAttempts);
- expect(chance).toBe(escapeChances[i].expectedEscapeChance);
+ expect(chance).toBe(check.expectedEscapeChance);
}
});
@@ -321,9 +319,9 @@ describe("Escape chance calculations", () => {
{ pokemonSpeedRatio: 5.2, escapeAttempts: 2, expectedEscapeChance: 25 },
];
- for (let i = 0; i < escapeChances.length; i++) {
+ for (const check of escapeChances) {
// sets the number of escape attempts to the required amount
- game.scene.currentBattle.escapeAttempts = escapeChances[i].escapeAttempts;
+ game.scene.currentBattle.escapeAttempts = check.escapeAttempts;
// set the first playerPokemon's speed to a multiple of the enemySpeed
vi.spyOn(playerPokemon[0], "stats", "get").mockReturnValue([
20,
@@ -331,7 +329,7 @@ describe("Escape chance calculations", () => {
20,
20,
20,
- Math.floor(escapeChances[i].pokemonSpeedRatio * totalEnemySpeed * playerASpeedPercentage),
+ Math.floor(check.pokemonSpeedRatio * totalEnemySpeed * playerASpeedPercentage),
]);
// set the second playerPokemon's speed to the remaining value of speed
vi.spyOn(playerPokemon[1], "stats", "get").mockReturnValue([
@@ -340,15 +338,13 @@ describe("Escape chance calculations", () => {
20,
20,
20,
- escapeChances[i].pokemonSpeedRatio * totalEnemySpeed - playerPokemon[0].stats[5],
+ check.pokemonSpeedRatio * totalEnemySpeed - playerPokemon[0].stats[5],
]);
const chance = phase.calculateEscapeChance(game.scene.currentBattle.escapeAttempts);
// checks to make sure the escape values are the same
- expect(chance).toBe(escapeChances[i].expectedEscapeChance);
+ expect(chance).toBe(check.expectedEscapeChance);
// checks to make sure the sum of the player's speed for all pokemon is equal to the appropriate ratio of the total enemy speed
- expect(playerPokemon[0].stats[5] + playerPokemon[1].stats[5]).toBe(
- escapeChances[i].pokemonSpeedRatio * totalEnemySpeed,
- );
+ expect(playerPokemon[0].stats[5] + playerPokemon[1].stats[5]).toBe(check.pokemonSpeedRatio * totalEnemySpeed);
}
});
});
diff --git a/test/imports.test.ts b/test/imports.test.ts
index 04e9462d8d0..aeaa763c05e 100644
--- a/test/imports.test.ts
+++ b/test/imports.test.ts
@@ -1,4 +1,4 @@
-import { initStatsKeys } from "#ui/game-stats-ui-handler";
+import { initStatsKeys } from "#ui/handlers/game-stats-ui-handler";
import { describe, expect, it } from "vitest";
async function importModule() {
diff --git a/test/items/dire-hit.test.ts b/test/items/dire-hit.test.ts
index 6d4bc7524eb..d704a94f3a8 100644
--- a/test/items/dire-hit.test.ts
+++ b/test/items/dire-hit.test.ts
@@ -10,7 +10,7 @@ import { NewBattlePhase } from "#phases/new-battle-phase";
import { TurnEndPhase } from "#phases/turn-end-phase";
import { TurnInitPhase } from "#phases/turn-init-phase";
import { GameManager } from "#test/test-utils/game-manager";
-import type { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
+import type { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
diff --git a/test/items/double-battle-chance-booster.test.ts b/test/items/double-battle-chance-booster.test.ts
index 2c12b34eba3..9985d4b3a55 100644
--- a/test/items/double-battle-chance-booster.test.ts
+++ b/test/items/double-battle-chance-booster.test.ts
@@ -5,7 +5,7 @@ import { SpeciesId } from "#enums/species-id";
import { UiMode } from "#enums/ui-mode";
import { DoubleBattleChanceBoosterModifier } from "#modifiers/modifier";
import { GameManager } from "#test/test-utils/game-manager";
-import type { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
+import type { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
diff --git a/test/items/temp-stat-stage-booster.test.ts b/test/items/temp-stat-stage-booster.test.ts
index 05ea5a03eae..499f1d630b0 100644
--- a/test/items/temp-stat-stage-booster.test.ts
+++ b/test/items/temp-stat-stage-booster.test.ts
@@ -7,7 +7,7 @@ import { BATTLE_STATS, Stat } from "#enums/stat";
import { UiMode } from "#enums/ui-mode";
import { TempStatStageBoosterModifier } from "#modifiers/modifier";
import { GameManager } from "#test/test-utils/game-manager";
-import type { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
+import type { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
diff --git a/test/moves/aurora-veil.test.ts b/test/moves/aurora-veil.test.ts
index 6edc214d580..15aa72d039a 100644
--- a/test/moves/aurora-veil.test.ts
+++ b/test/moves/aurora-veil.test.ts
@@ -139,17 +139,15 @@ const getMockedMoveDamage = (defender: Pokemon, attacker: Pokemon, move: Move) =
const multiplierHolder = new NumberHolder(1);
const side = defender.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
- if (globalScene.arena.getTagOnSide(ArenaTagType.AURORA_VEIL, side)) {
- if (move.getAttrs("CritOnlyAttr").length === 0) {
- globalScene.arena.applyTagsForSide(
- ArenaTagType.AURORA_VEIL,
- side,
- false,
- attacker,
- move.category,
- multiplierHolder,
- );
- }
+ if (globalScene.arena.getTagOnSide(ArenaTagType.AURORA_VEIL, side) && move.getAttrs("CritOnlyAttr").length === 0) {
+ globalScene.arena.applyTagsForSide(
+ ArenaTagType.AURORA_VEIL,
+ side,
+ false,
+ attacker,
+ move.category,
+ multiplierHolder,
+ );
}
return move.power * multiplierHolder.value;
diff --git a/test/moves/delayed-attack.test.ts b/test/moves/delayed-attack.test.ts
index e8cf2871626..420ef6d1f00 100644
--- a/test/moves/delayed-attack.test.ts
+++ b/test/moves/delayed-attack.test.ts
@@ -4,12 +4,15 @@ import { allMoves } from "#data/data-lists";
import { AbilityId } from "#enums/ability-id";
import { BattleType } from "#enums/battle-type";
import { BattlerIndex } from "#enums/battler-index";
+import { Button } from "#enums/buttons";
import { MoveId } from "#enums/move-id";
import { MoveResult } from "#enums/move-result";
+import { PokeballType } from "#enums/pokeball";
import { PokemonType } from "#enums/pokemon-type";
import { PositionalTagType } from "#enums/positional-tag-type";
import { SpeciesId } from "#enums/species-id";
import { Stat } from "#enums/stat";
+import { UiMode } from "#enums/ui-mode";
import { GameManager } from "#test/test-utils/game-manager";
import i18next from "i18next";
import Phaser from "phaser";
@@ -95,7 +98,7 @@ describe("Moves - Delayed Attacks", () => {
expectFutureSightActive(0);
const enemy = game.field.getEnemyPokemon();
- expect(enemy.hp).toBeLessThan(enemy.getMaxHp());
+ expect(enemy).not.toHaveFullHp();
expect(game.textInterceptor.logs).toContain(
i18next.t("moveTriggers:tookMoveAttack", {
pokemonName: getPokemonNameWithAffix(enemy),
@@ -130,12 +133,12 @@ describe("Moves - Delayed Attacks", () => {
expectFutureSightActive();
const enemy = game.field.getEnemyPokemon();
- expect(enemy.hp).toBe(enemy.getMaxHp());
+ expect(enemy).toHaveFullHp();
await passTurns(2);
expectFutureSightActive(0);
- expect(enemy.hp).toBeLessThan(enemy.getMaxHp());
+ expect(enemy).not.toHaveFullHp();
});
it("should work when used against different targets in doubles", async () => {
@@ -149,15 +152,15 @@ describe("Moves - Delayed Attacks", () => {
await game.toEndOfTurn();
expectFutureSightActive(2);
- expect(enemy1.hp).toBe(enemy1.getMaxHp());
- expect(enemy2.hp).toBe(enemy2.getMaxHp());
+ expect(enemy1).toHaveFullHp();
+ expect(enemy2).toHaveFullHp();
expect(karp.getLastXMoves()[0].result).toBe(MoveResult.OTHER);
expect(feebas.getLastXMoves()[0].result).toBe(MoveResult.OTHER);
await passTurns(2);
- expect(enemy1.hp).toBeLessThan(enemy1.getMaxHp());
- expect(enemy2.hp).toBeLessThan(enemy2.getMaxHp());
+ expect(enemy1).not.toHaveFullHp();
+ expect(enemy2).not.toHaveFullHp();
});
it("should trigger multiple pending attacks in order of creation, even if that order changes later on", async () => {
@@ -222,8 +225,8 @@ describe("Moves - Delayed Attacks", () => {
expect(game.scene.getPlayerParty()).toEqual([milotic, karp, feebas]);
- expect(karp.hp).toBe(karp.getMaxHp());
- expect(feebas.hp).toBe(feebas.getMaxHp());
+ expect(karp).toHaveFullHp();
+ expect(feebas).toHaveFullHp();
expect(game.textInterceptor.logs).not.toContain(
i18next.t("moveTriggers:tookMoveAttack", {
pokemonName: getPokemonNameWithAffix(karp),
@@ -245,15 +248,14 @@ describe("Moves - Delayed Attacks", () => {
expect(enemy2.isFainted()).toBe(true);
expectFutureSightActive();
- const attack = game.scene.arena.positionalTagManager.tags.find(
- t => t.tagType === PositionalTagType.DELAYED_ATTACK,
- )!;
- expect(attack).toBeDefined();
- expect(attack.targetIndex).toBe(enemy1.getBattlerIndex());
+ expect(game).toHavePositionalTag({
+ tagType: PositionalTagType.DELAYED_ATTACK,
+ targetIndex: enemy1.getBattlerIndex(),
+ });
await passTurns(2);
- expect(enemy1.hp).toBeLessThan(enemy1.getMaxHp());
+ expect(enemy1).not.toHaveFullHp();
expect(game.textInterceptor.logs).toContain(
i18next.t("moveTriggers:tookMoveAttack", {
pokemonName: getPokemonNameWithAffix(enemy1),
@@ -281,7 +283,7 @@ describe("Moves - Delayed Attacks", () => {
await game.toNextTurn();
expectFutureSightActive(0);
- expect(enemy1.hp).toBe(enemy1.getMaxHp());
+ expect(enemy1).toHaveFullHp();
expect(game.textInterceptor.logs).not.toContain(
i18next.t("moveTriggers:tookMoveAttack", {
pokemonName: getPokemonNameWithAffix(enemy1),
@@ -317,8 +319,8 @@ describe("Moves - Delayed Attacks", () => {
await game.toEndOfTurn();
- expect(enemy1.hp).toBe(enemy1.getMaxHp());
- expect(enemy2.hp).toBeLessThan(enemy2.getMaxHp());
+ expect(enemy1).toHaveFullHp();
+ expect(enemy2).not.toHaveFullHp();
expect(game.textInterceptor.logs).toContain(
i18next.t("moveTriggers:tookMoveAttack", {
pokemonName: getPokemonNameWithAffix(enemy2),
@@ -351,7 +353,7 @@ describe("Moves - Delayed Attacks", () => {
// Player Normalize was not applied due to being off field
const enemy = game.field.getEnemyPokemon();
- expect(enemy.hp).toBeLessThan(enemy.getMaxHp());
+ expect(enemy).not.toHaveFullHp();
expect(game.textInterceptor.logs).toContain(
i18next.t("moveTriggers:tookMoveAttack", {
pokemonName: getPokemonNameWithAffix(enemy),
@@ -384,6 +386,35 @@ describe("Moves - Delayed Attacks", () => {
expect(typeBoostSpy).not.toHaveBeenCalled();
});
+ it("should not crash when catching & releasing a Pokemon on the same turn its delayed attack expires", async () => {
+ game.override.startingModifier([{ name: "MASTER_BALL", count: 1 }]);
+ await game.classicMode.startBattle([
+ SpeciesId.FEEBAS,
+ SpeciesId.FEEBAS,
+ SpeciesId.FEEBAS,
+ SpeciesId.FEEBAS,
+ SpeciesId.FEEBAS,
+ SpeciesId.FEEBAS,
+ ]);
+
+ game.move.use(MoveId.SPLASH);
+ await game.move.forceEnemyMove(MoveId.FUTURE_SIGHT);
+ await game.toNextTurn();
+
+ expectFutureSightActive(1);
+
+ await passTurns(1);
+
+ // Throw master ball and release the enemy
+ game.doThrowPokeball(PokeballType.MASTER_BALL);
+ game.onNextPrompt("AttemptCapturePhase", UiMode.CONFIRM, () => {
+ game.scene.ui.processInput(Button.CANCEL);
+ });
+ await game.toEndOfTurn();
+
+ expectFutureSightActive(0);
+ });
+
// TODO: Implement and move to a power spot's test file
it.todo("Should activate ally's power spot when switched in during single battles");
});
diff --git a/test/moves/focus-punch.test.ts b/test/moves/focus-punch.test.ts
index 9a76dbec0db..d7b40569aaa 100644
--- a/test/moves/focus-punch.test.ts
+++ b/test/moves/focus-punch.test.ts
@@ -9,7 +9,7 @@ import { TurnStartPhase } from "#phases/turn-start-phase";
import { GameManager } from "#test/test-utils/game-manager";
import i18next from "i18next";
import Phaser from "phaser";
-import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
+import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
describe("Moves - Focus Punch", () => {
let phaserGame: Phaser.Game;
@@ -125,8 +125,8 @@ describe("Moves - Focus Punch", () => {
game.move.select(MoveId.FOCUS_PUNCH);
await game.phaseInterceptor.to("MoveEndPhase", true);
await game.phaseInterceptor.to("MessagePhase", false);
- const consoleSpy = vi.spyOn(console, "log");
await game.phaseInterceptor.to("MoveEndPhase", true);
- expect(consoleSpy).nthCalledWith(1, i18next.t("moveTriggers:lostFocus", { pokemonName: "Charizard" }));
+ expect(game.textInterceptor.logs).toContain(i18next.t("moveTriggers:lostFocus", { pokemonName: "Charizard" }));
+ expect(game.textInterceptor.logs).not.toContain(i18next.t("battle:attackFailed"));
});
});
diff --git a/test/moves/light-screen.test.ts b/test/moves/light-screen.test.ts
index b6eb2725346..c715229d4a6 100644
--- a/test/moves/light-screen.test.ts
+++ b/test/moves/light-screen.test.ts
@@ -127,17 +127,15 @@ const getMockedMoveDamage = (defender: Pokemon, attacker: Pokemon, move: Move) =
const multiplierHolder = new NumberHolder(1);
const side = defender.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
- if (globalScene.arena.getTagOnSide(ArenaTagType.LIGHT_SCREEN, side)) {
- if (move.getAttrs("CritOnlyAttr").length === 0) {
- globalScene.arena.applyTagsForSide(
- ArenaTagType.LIGHT_SCREEN,
- side,
- false,
- attacker,
- move.category,
- multiplierHolder,
- );
- }
+ if (globalScene.arena.getTagOnSide(ArenaTagType.LIGHT_SCREEN, side) && move.getAttrs("CritOnlyAttr").length === 0) {
+ globalScene.arena.applyTagsForSide(
+ ArenaTagType.LIGHT_SCREEN,
+ side,
+ false,
+ attacker,
+ move.category,
+ multiplierHolder,
+ );
}
return move.power * multiplierHolder.value;
diff --git a/test/moves/pledge-moves.test.ts b/test/moves/pledge-moves.test.ts
index 7a9c4112d7d..34058829d07 100644
--- a/test/moves/pledge-moves.test.ts
+++ b/test/moves/pledge-moves.test.ts
@@ -126,7 +126,7 @@ describe("Moves - Pledge Moves", () => {
expect(playerPokemon[1].getMoveType).toHaveLastReturnedWith(PokemonType.FIRE);
expect(grassPledge.calculateBattlePower).toHaveLastReturnedWith(150);
- const baseDmg = baseDmgMock.mock.results[baseDmgMock.mock.results.length - 1].value;
+ const baseDmg = baseDmgMock.mock.results.at(-1)!.value;
expect(enemyPokemon[0].getMaxHp() - enemyPokemon[0].hp).toBe(toDmgValue(baseDmg * 1.5));
expect(enemyPokemon[1].hp).toBe(enemyPokemon[1].getMaxHp()); // PLAYER should not have attacked
expect(game.scene.arena.getTagOnSide(ArenaTagType.FIRE_GRASS_PLEDGE, ArenaTagSide.ENEMY)).toBeDefined();
diff --git a/test/moves/poltergeist.test.ts b/test/moves/poltergeist.test.ts
new file mode 100644
index 00000000000..3e603702416
--- /dev/null
+++ b/test/moves/poltergeist.test.ts
@@ -0,0 +1,50 @@
+import { AbilityId } from "#enums/ability-id";
+import { BattlerIndex } from "#enums/battler-index";
+import { MoveId } from "#enums/move-id";
+import { MoveResult } from "#enums/move-result";
+import { SpeciesId } from "#enums/species-id";
+import { GameManager } from "#test/test-utils/game-manager";
+import Phaser from "phaser";
+import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
+
+describe("Move - Poltergeist", () => {
+ let phaserGame: Phaser.Game;
+ let game: GameManager;
+
+ beforeAll(() => {
+ phaserGame = new Phaser.Game({
+ type: Phaser.HEADLESS,
+ });
+ });
+
+ afterEach(() => {
+ game.phaseInterceptor.restoreOg();
+ });
+
+ beforeEach(() => {
+ game = new GameManager(phaserGame);
+ game.override
+ .ability(AbilityId.BALL_FETCH)
+ .battleStyle("single")
+ .criticalHits(false)
+ .enemySpecies(SpeciesId.MAGIKARP)
+ .enemyAbility(AbilityId.BALL_FETCH)
+ .enemyMoveset(MoveId.SPLASH)
+ .startingLevel(100)
+ .enemyLevel(100);
+ });
+
+ it("should not crash when used after both opponents have fainted", async () => {
+ game.override.battleStyle("double").enemyLevel(5);
+ await game.classicMode.startBattle([SpeciesId.STARYU, SpeciesId.SLOWPOKE]);
+
+ game.move.use(MoveId.DAZZLING_GLEAM);
+ game.move.use(MoveId.POLTERGEIST, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY);
+ const [_, poltergeistUser] = game.scene.getPlayerField();
+ await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]);
+ await game.toEndOfTurn();
+ // Expect poltergeist to have failed
+ expect(poltergeistUser).toHaveUsedMove({ move: MoveId.POLTERGEIST, result: MoveResult.FAIL });
+ // If the test makes it to the end of turn, no crash occurred. Nothing to assert
+ });
+});
diff --git a/test/moves/reflect.test.ts b/test/moves/reflect.test.ts
index 426027d3f31..2d1593fb935 100644
--- a/test/moves/reflect.test.ts
+++ b/test/moves/reflect.test.ts
@@ -143,10 +143,8 @@ const getMockedMoveDamage = (defender: Pokemon, attacker: Pokemon, move: Move) =
const multiplierHolder = new NumberHolder(1);
const side = defender.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
- if (globalScene.arena.getTagOnSide(ArenaTagType.REFLECT, side)) {
- if (move.getAttrs("CritOnlyAttr").length === 0) {
- globalScene.arena.applyTagsForSide(ArenaTagType.REFLECT, side, false, attacker, move.category, multiplierHolder);
- }
+ if (globalScene.arena.getTagOnSide(ArenaTagType.REFLECT, side) && move.getAttrs("CritOnlyAttr").length === 0) {
+ globalScene.arena.applyTagsForSide(ArenaTagType.REFLECT, side, false, attacker, move.category, multiplierHolder);
}
return move.power * multiplierHolder.value;
diff --git a/test/mystery-encounter/encounter-test-utils.ts b/test/mystery-encounter/encounter-test-utils.ts
index 7b2dbfc9aeb..fcf27b2c6fb 100644
--- a/test/mystery-encounter/encounter-test-utils.ts
+++ b/test/mystery-encounter/encounter-test-utils.ts
@@ -13,10 +13,10 @@ import {
} from "#phases/mystery-encounter-phases";
import { VictoryPhase } from "#phases/victory-phase";
import type { GameManager } from "#test/test-utils/game-manager";
-import type { MessageUiHandler } from "#ui/message-ui-handler";
-import type { MysteryEncounterUiHandler } from "#ui/mystery-encounter-ui-handler";
+import type { MessageUiHandler } from "#ui/handlers/message-ui-handler";
+import type { MysteryEncounterUiHandler } from "#ui/handlers/mystery-encounter-ui-handler";
+import type { PartyUiHandler } from "#ui/handlers/party-ui-handler";
import type { OptionSelectUiHandler } from "#ui/option-select-ui-handler";
-import type { PartyUiHandler } from "#ui/party-ui-handler";
import { isNullOrUndefined } from "#utils/common";
import { expect, vi } from "vitest";
diff --git a/test/mystery-encounter/encounters/a-trainers-test-encounter.test.ts b/test/mystery-encounter/encounters/a-trainers-test-encounter.test.ts
index b4bd74d44d6..8dc4348adae 100644
--- a/test/mystery-encounter/encounters/a-trainers-test-encounter.test.ts
+++ b/test/mystery-encounter/encounters/a-trainers-test-encounter.test.ts
@@ -135,8 +135,8 @@ describe("A Trainer's Test - Mystery Encounter", () => {
const eggsAfter = scene.gameData.eggs;
expect(eggsAfter).toBeDefined();
expect(eggsBeforeLength + 1).toBe(eggsAfter.length);
- const eggTier = eggsAfter[eggsAfter.length - 1].tier;
- expect(eggTier === EggTier.EPIC || eggTier === EggTier.LEGENDARY).toBeTruthy();
+ const eggTier = eggsAfter.at(-1)?.tier;
+ expect(eggTier).toBeOneOf([EggTier.EPIC, EggTier.LEGENDARY]);
});
});
@@ -183,7 +183,7 @@ describe("A Trainer's Test - Mystery Encounter", () => {
const eggsAfter = scene.gameData.eggs;
expect(eggsAfter).toBeDefined();
expect(eggsBeforeLength + 1).toBe(eggsAfter.length);
- const eggTier = eggsAfter[eggsAfter.length - 1].tier;
+ const eggTier = eggsAfter.at(-1)?.tier;
expect(eggTier).toBe(EggTier.RARE);
});
diff --git a/test/mystery-encounter/encounters/berries-abound-encounter.test.ts b/test/mystery-encounter/encounters/berries-abound-encounter.test.ts
index 5e9dffa1332..44585d4d795 100644
--- a/test/mystery-encounter/encounters/berries-abound-encounter.test.ts
+++ b/test/mystery-encounter/encounters/berries-abound-encounter.test.ts
@@ -17,7 +17,7 @@ import {
} from "#test/mystery-encounter/encounter-test-utils";
import { GameManager } from "#test/test-utils/game-manager";
import { initSceneWithoutEncounterPhase } from "#test/test-utils/game-manager-utils";
-import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
+import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const namespace = "mysteryEncounters/berriesAbound";
diff --git a/test/mystery-encounter/encounters/bug-type-superfan-encounter.test.ts b/test/mystery-encounter/encounters/bug-type-superfan-encounter.test.ts
index 723516174fb..a3357b00b89 100644
--- a/test/mystery-encounter/encounters/bug-type-superfan-encounter.test.ts
+++ b/test/mystery-encounter/encounters/bug-type-superfan-encounter.test.ts
@@ -20,7 +20,7 @@ import {
} from "#test/mystery-encounter/encounter-test-utils";
import { GameManager } from "#test/test-utils/game-manager";
import { initSceneWithoutEncounterPhase } from "#test/test-utils/game-manager-utils";
-import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
+import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const namespace = "mysteryEncounters/bugTypeSuperfan";
diff --git a/test/mystery-encounter/encounters/clowning-around-encounter.test.ts b/test/mystery-encounter/encounters/clowning-around-encounter.test.ts
index e7ec6e43392..d199a331943 100644
--- a/test/mystery-encounter/encounters/clowning-around-encounter.test.ts
+++ b/test/mystery-encounter/encounters/clowning-around-encounter.test.ts
@@ -29,8 +29,8 @@ import {
} from "#test/mystery-encounter/encounter-test-utils";
import { GameManager } from "#test/test-utils/game-manager";
import { initSceneWithoutEncounterPhase } from "#test/test-utils/game-manager-utils";
+import type { PartyUiHandler } from "#ui/handlers/party-ui-handler";
import type { OptionSelectUiHandler } from "#ui/option-select-ui-handler";
-import type { PartyUiHandler } from "#ui/party-ui-handler";
import { getPokemonSpecies } from "#utils/pokemon-utils";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
diff --git a/test/mystery-encounter/encounters/dancing-lessons-encounter.test.ts b/test/mystery-encounter/encounters/dancing-lessons-encounter.test.ts
index 81a2fc7463c..bf42e6d4df3 100644
--- a/test/mystery-encounter/encounters/dancing-lessons-encounter.test.ts
+++ b/test/mystery-encounter/encounters/dancing-lessons-encounter.test.ts
@@ -18,7 +18,7 @@ import {
skipBattleRunMysteryEncounterRewardsPhase,
} from "#test/mystery-encounter/encounter-test-utils";
import { GameManager } from "#test/test-utils/game-manager";
-import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
+import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const namespace = "mysteryEncounters/dancingLessons";
diff --git a/test/mystery-encounter/encounters/department-store-sale-encounter.test.ts b/test/mystery-encounter/encounters/department-store-sale-encounter.test.ts
index 812d6d661ef..d6c566c4de6 100644
--- a/test/mystery-encounter/encounters/department-store-sale-encounter.test.ts
+++ b/test/mystery-encounter/encounters/department-store-sale-encounter.test.ts
@@ -11,7 +11,7 @@ import * as MysteryEncounters from "#mystery-encounters/mystery-encounters";
import { CIVILIZATION_ENCOUNTER_BIOMES } from "#mystery-encounters/mystery-encounters";
import { runMysteryEncounterToEnd } from "#test/mystery-encounter/encounter-test-utils";
import { GameManager } from "#test/test-utils/game-manager";
-import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
+import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const namespace = "mysteryEncounters/departmentStoreSale";
@@ -139,8 +139,8 @@ describe("Department Store Sale - Mystery Encounter", () => {
expect(modifierSelectHandler.options.length).toEqual(3);
for (const option of modifierSelectHandler.options) {
expect(
- option.modifierTypeOption.type.id.includes("PP_UP") ||
- option.modifierTypeOption.type.id.includes("BASE_STAT_BOOSTER"),
+ option.modifierTypeOption.type.id.includes("PP_UP")
+ || option.modifierTypeOption.type.id.includes("BASE_STAT_BOOSTER"),
).toBeTruthy();
}
});
@@ -179,8 +179,8 @@ describe("Department Store Sale - Mystery Encounter", () => {
expect(modifierSelectHandler.options.length).toEqual(5);
for (const option of modifierSelectHandler.options) {
expect(
- option.modifierTypeOption.type.id.includes("DIRE_HIT") ||
- option.modifierTypeOption.type.id.includes("TEMP_STAT_STAGE_BOOSTER"),
+ option.modifierTypeOption.type.id.includes("DIRE_HIT")
+ || option.modifierTypeOption.type.id.includes("TEMP_STAT_STAGE_BOOSTER"),
).toBeTruthy();
}
});
diff --git a/test/mystery-encounter/encounters/field-trip-encounter.test.ts b/test/mystery-encounter/encounters/field-trip-encounter.test.ts
index fd3e20012b1..b8e6e36cf17 100644
--- a/test/mystery-encounter/encounters/field-trip-encounter.test.ts
+++ b/test/mystery-encounter/encounters/field-trip-encounter.test.ts
@@ -12,7 +12,7 @@ import * as MysteryEncounters from "#mystery-encounters/mystery-encounters";
import { SelectModifierPhase } from "#phases/select-modifier-phase";
import { runMysteryEncounterToEnd } from "#test/mystery-encounter/encounter-test-utils";
import { GameManager } from "#test/test-utils/game-manager";
-import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
+import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler";
import i18next from "i18next";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
diff --git a/test/mystery-encounter/encounters/fight-or-flight-encounter.test.ts b/test/mystery-encounter/encounters/fight-or-flight-encounter.test.ts
index 81dbad16e01..34c0f635000 100644
--- a/test/mystery-encounter/encounters/fight-or-flight-encounter.test.ts
+++ b/test/mystery-encounter/encounters/fight-or-flight-encounter.test.ts
@@ -17,7 +17,7 @@ import {
} from "#test/mystery-encounter/encounter-test-utils";
import { GameManager } from "#test/test-utils/game-manager";
import { initSceneWithoutEncounterPhase } from "#test/test-utils/game-manager-utils";
-import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
+import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const namespace = "mysteryEncounters/fightOrFlight";
diff --git a/test/mystery-encounter/encounters/fun-and-games-encounter.test.ts b/test/mystery-encounter/encounters/fun-and-games-encounter.test.ts
index bc1a2893627..8a058bad5fe 100644
--- a/test/mystery-encounter/encounters/fun-and-games-encounter.test.ts
+++ b/test/mystery-encounter/encounters/fun-and-games-encounter.test.ts
@@ -22,7 +22,7 @@ import {
} from "#test/mystery-encounter/encounter-test-utils";
import { GameManager } from "#test/test-utils/game-manager";
import { initSceneWithoutEncounterPhase } from "#test/test-utils/game-manager-utils";
-import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
+import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const namespace = "mysteryEncounters/funAndGames";
diff --git a/test/mystery-encounter/encounters/global-trade-system-encounter.test.ts b/test/mystery-encounter/encounters/global-trade-system-encounter.test.ts
index c8e934168bc..90bc41fde2b 100644
--- a/test/mystery-encounter/encounters/global-trade-system-encounter.test.ts
+++ b/test/mystery-encounter/encounters/global-trade-system-encounter.test.ts
@@ -15,7 +15,7 @@ import * as MysteryEncounters from "#mystery-encounters/mystery-encounters";
import { CIVILIZATION_ENCOUNTER_BIOMES } from "#mystery-encounters/mystery-encounters";
import { runMysteryEncounterToEnd } from "#test/mystery-encounter/encounter-test-utils";
import { GameManager } from "#test/test-utils/game-manager";
-import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
+import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler";
import * as Utils from "#utils/common";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
diff --git a/test/mystery-encounter/encounters/mysterious-challengers-encounter.test.ts b/test/mystery-encounter/encounters/mysterious-challengers-encounter.test.ts
index b937fdcfcf5..ed8b6bffbe9 100644
--- a/test/mystery-encounter/encounters/mysterious-challengers-encounter.test.ts
+++ b/test/mystery-encounter/encounters/mysterious-challengers-encounter.test.ts
@@ -20,7 +20,7 @@ import { GameManager } from "#test/test-utils/game-manager";
import { initSceneWithoutEncounterPhase } from "#test/test-utils/game-manager-utils";
import { TrainerConfig } from "#trainers/trainer-config";
import { TrainerPartyCompoundTemplate, TrainerPartyTemplate } from "#trainers/trainer-party-template";
-import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
+import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const namespace = "mysteryEncounters/mysteriousChallengers";
@@ -213,20 +213,20 @@ describe("Mysterious Challengers - Mystery Encounter", () => {
) as ModifierSelectUiHandler;
expect(modifierSelectHandler.options.length).toEqual(4);
expect(
- modifierSelectHandler.options[0].modifierTypeOption.type.tier -
- modifierSelectHandler.options[0].modifierTypeOption.upgradeCount,
+ modifierSelectHandler.options[0].modifierTypeOption.type.tier
+ - modifierSelectHandler.options[0].modifierTypeOption.upgradeCount,
).toBe(ModifierTier.ULTRA);
expect(
- modifierSelectHandler.options[1].modifierTypeOption.type.tier -
- modifierSelectHandler.options[1].modifierTypeOption.upgradeCount,
+ modifierSelectHandler.options[1].modifierTypeOption.type.tier
+ - modifierSelectHandler.options[1].modifierTypeOption.upgradeCount,
).toBe(ModifierTier.ULTRA);
expect(
- modifierSelectHandler.options[2].modifierTypeOption.type.tier -
- modifierSelectHandler.options[2].modifierTypeOption.upgradeCount,
+ modifierSelectHandler.options[2].modifierTypeOption.type.tier
+ - modifierSelectHandler.options[2].modifierTypeOption.upgradeCount,
).toBe(ModifierTier.GREAT);
expect(
- modifierSelectHandler.options[3].modifierTypeOption.type.tier -
- modifierSelectHandler.options[3].modifierTypeOption.upgradeCount,
+ modifierSelectHandler.options[3].modifierTypeOption.type.tier
+ - modifierSelectHandler.options[3].modifierTypeOption.upgradeCount,
).toBe(ModifierTier.GREAT);
});
});
@@ -269,20 +269,20 @@ describe("Mysterious Challengers - Mystery Encounter", () => {
) as ModifierSelectUiHandler;
expect(modifierSelectHandler.options.length).toEqual(4);
expect(
- modifierSelectHandler.options[0].modifierTypeOption.type.tier -
- modifierSelectHandler.options[0].modifierTypeOption.upgradeCount,
+ modifierSelectHandler.options[0].modifierTypeOption.type.tier
+ - modifierSelectHandler.options[0].modifierTypeOption.upgradeCount,
).toBe(ModifierTier.ROGUE);
expect(
- modifierSelectHandler.options[1].modifierTypeOption.type.tier -
- modifierSelectHandler.options[1].modifierTypeOption.upgradeCount,
+ modifierSelectHandler.options[1].modifierTypeOption.type.tier
+ - modifierSelectHandler.options[1].modifierTypeOption.upgradeCount,
).toBe(ModifierTier.ROGUE);
expect(
- modifierSelectHandler.options[2].modifierTypeOption.type.tier -
- modifierSelectHandler.options[2].modifierTypeOption.upgradeCount,
+ modifierSelectHandler.options[2].modifierTypeOption.type.tier
+ - modifierSelectHandler.options[2].modifierTypeOption.upgradeCount,
).toBe(ModifierTier.ULTRA);
expect(
- modifierSelectHandler.options[3].modifierTypeOption.type.tier -
- modifierSelectHandler.options[3].modifierTypeOption.upgradeCount,
+ modifierSelectHandler.options[3].modifierTypeOption.type.tier
+ - modifierSelectHandler.options[3].modifierTypeOption.upgradeCount,
).toBe(ModifierTier.GREAT);
});
});
diff --git a/test/mystery-encounter/encounters/teleporting-hijinks-encounter.test.ts b/test/mystery-encounter/encounters/teleporting-hijinks-encounter.test.ts
index c88d77a8cf5..a096ea5ff6e 100644
--- a/test/mystery-encounter/encounters/teleporting-hijinks-encounter.test.ts
+++ b/test/mystery-encounter/encounters/teleporting-hijinks-encounter.test.ts
@@ -16,7 +16,7 @@ import {
} from "#test/mystery-encounter/encounter-test-utils";
import { GameManager } from "#test/test-utils/game-manager";
import { initSceneWithoutEncounterPhase } from "#test/test-utils/game-manager-utils";
-import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
+import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler";
import i18next from "i18next";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
diff --git a/test/mystery-encounter/encounters/the-strong-stuff-encounter.test.ts b/test/mystery-encounter/encounters/the-strong-stuff-encounter.test.ts
index 06c4c3c1cee..5df2d2ab358 100644
--- a/test/mystery-encounter/encounters/the-strong-stuff-encounter.test.ts
+++ b/test/mystery-encounter/encounters/the-strong-stuff-encounter.test.ts
@@ -24,7 +24,7 @@ import {
} from "#test/mystery-encounter/encounter-test-utils";
import { GameManager } from "#test/test-utils/game-manager";
import { initSceneWithoutEncounterPhase } from "#test/test-utils/game-manager-utils";
-import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
+import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler";
import { getPokemonSpecies } from "#utils/pokemon-utils";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
diff --git a/test/mystery-encounter/encounters/the-winstrate-challenge-encounter.test.ts b/test/mystery-encounter/encounters/the-winstrate-challenge-encounter.test.ts
index 814e2ee07fb..9b009879522 100644
--- a/test/mystery-encounter/encounters/the-winstrate-challenge-encounter.test.ts
+++ b/test/mystery-encounter/encounters/the-winstrate-challenge-encounter.test.ts
@@ -20,7 +20,7 @@ import { VictoryPhase } from "#phases/victory-phase";
import { runMysteryEncounterToEnd } from "#test/mystery-encounter/encounter-test-utils";
import { GameManager } from "#test/test-utils/game-manager";
import { initSceneWithoutEncounterPhase } from "#test/test-utils/game-manager-utils";
-import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
+import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler";
import { getPokemonSpecies } from "#utils/pokemon-utils";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
diff --git a/test/mystery-encounter/encounters/trash-to-treasure-encounter.test.ts b/test/mystery-encounter/encounters/trash-to-treasure-encounter.test.ts
index fe0139be3a7..6f6c01c7322 100644
--- a/test/mystery-encounter/encounters/trash-to-treasure-encounter.test.ts
+++ b/test/mystery-encounter/encounters/trash-to-treasure-encounter.test.ts
@@ -27,7 +27,7 @@ import {
} from "#test/mystery-encounter/encounter-test-utils";
import { GameManager } from "#test/test-utils/game-manager";
import { initSceneWithoutEncounterPhase } from "#test/test-utils/game-manager-utils";
-import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
+import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler";
import * as Utils from "#utils/common";
import { getPokemonSpecies } from "#utils/pokemon-utils";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
@@ -250,20 +250,20 @@ describe("Trash to Treasure - Mystery Encounter", () => {
) as ModifierSelectUiHandler;
expect(modifierSelectHandler.options.length).toEqual(4);
expect(
- modifierSelectHandler.options[0].modifierTypeOption.type.tier -
- modifierSelectHandler.options[0].modifierTypeOption.upgradeCount,
+ modifierSelectHandler.options[0].modifierTypeOption.type.tier
+ - modifierSelectHandler.options[0].modifierTypeOption.upgradeCount,
).toEqual(ModifierTier.ROGUE);
expect(
- modifierSelectHandler.options[1].modifierTypeOption.type.tier -
- modifierSelectHandler.options[1].modifierTypeOption.upgradeCount,
+ modifierSelectHandler.options[1].modifierTypeOption.type.tier
+ - modifierSelectHandler.options[1].modifierTypeOption.upgradeCount,
).toEqual(ModifierTier.ROGUE);
expect(
- modifierSelectHandler.options[2].modifierTypeOption.type.tier -
- modifierSelectHandler.options[2].modifierTypeOption.upgradeCount,
+ modifierSelectHandler.options[2].modifierTypeOption.type.tier
+ - modifierSelectHandler.options[2].modifierTypeOption.upgradeCount,
).toEqual(ModifierTier.ULTRA);
expect(
- modifierSelectHandler.options[3].modifierTypeOption.type.tier -
- modifierSelectHandler.options[3].modifierTypeOption.upgradeCount,
+ modifierSelectHandler.options[3].modifierTypeOption.type.tier
+ - modifierSelectHandler.options[3].modifierTypeOption.upgradeCount,
).toEqual(ModifierTier.GREAT);
});
});
diff --git a/test/mystery-encounter/encounters/weird-dream-encounter.test.ts b/test/mystery-encounter/encounters/weird-dream-encounter.test.ts
index 9f03b113d27..3640ed3809f 100644
--- a/test/mystery-encounter/encounters/weird-dream-encounter.test.ts
+++ b/test/mystery-encounter/encounters/weird-dream-encounter.test.ts
@@ -16,7 +16,7 @@ import {
} from "#test/mystery-encounter/encounter-test-utils";
import { GameManager } from "#test/test-utils/game-manager";
import { initSceneWithoutEncounterPhase } from "#test/test-utils/game-manager-utils";
-import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
+import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const namespace = "mysteryEncounters/weirdDream";
@@ -204,28 +204,28 @@ describe("Weird Dream - Mystery Encounter", () => {
) as ModifierSelectUiHandler;
expect(modifierSelectHandler.options.length).toEqual(6);
expect(
- modifierSelectHandler.options[0].modifierTypeOption.type.tier -
- modifierSelectHandler.options[0].modifierTypeOption.upgradeCount,
+ modifierSelectHandler.options[0].modifierTypeOption.type.tier
+ - modifierSelectHandler.options[0].modifierTypeOption.upgradeCount,
).toEqual(ModifierTier.ROGUE);
expect(
- modifierSelectHandler.options[1].modifierTypeOption.type.tier -
- modifierSelectHandler.options[1].modifierTypeOption.upgradeCount,
+ modifierSelectHandler.options[1].modifierTypeOption.type.tier
+ - modifierSelectHandler.options[1].modifierTypeOption.upgradeCount,
).toEqual(ModifierTier.ROGUE);
expect(
- modifierSelectHandler.options[2].modifierTypeOption.type.tier -
- modifierSelectHandler.options[2].modifierTypeOption.upgradeCount,
+ modifierSelectHandler.options[2].modifierTypeOption.type.tier
+ - modifierSelectHandler.options[2].modifierTypeOption.upgradeCount,
).toEqual(ModifierTier.ULTRA);
expect(
- modifierSelectHandler.options[3].modifierTypeOption.type.tier -
- modifierSelectHandler.options[3].modifierTypeOption.upgradeCount,
+ modifierSelectHandler.options[3].modifierTypeOption.type.tier
+ - modifierSelectHandler.options[3].modifierTypeOption.upgradeCount,
).toEqual(ModifierTier.ULTRA);
expect(
- modifierSelectHandler.options[4].modifierTypeOption.type.tier -
- modifierSelectHandler.options[4].modifierTypeOption.upgradeCount,
+ modifierSelectHandler.options[4].modifierTypeOption.type.tier
+ - modifierSelectHandler.options[4].modifierTypeOption.upgradeCount,
).toEqual(ModifierTier.GREAT);
expect(
- modifierSelectHandler.options[5].modifierTypeOption.type.tier -
- modifierSelectHandler.options[5].modifierTypeOption.upgradeCount,
+ modifierSelectHandler.options[5].modifierTypeOption.type.tier
+ - modifierSelectHandler.options[5].modifierTypeOption.upgradeCount,
).toEqual(ModifierTier.GREAT);
});
});
diff --git a/test/phases/mystery-encounter-phase.test.ts b/test/phases/mystery-encounter-phase.test.ts
index 30ab977dbc6..8dfbd509a05 100644
--- a/test/phases/mystery-encounter-phase.test.ts
+++ b/test/phases/mystery-encounter-phase.test.ts
@@ -5,8 +5,8 @@ import { SpeciesId } from "#enums/species-id";
import { UiMode } from "#enums/ui-mode";
import { MysteryEncounterOptionSelectedPhase } from "#phases/mystery-encounter-phases";
import { GameManager } from "#test/test-utils/game-manager";
-import type { MessageUiHandler } from "#ui/message-ui-handler";
-import type { MysteryEncounterUiHandler } from "#ui/mystery-encounter-ui-handler";
+import type { MessageUiHandler } from "#ui/handlers/message-ui-handler";
+import type { MysteryEncounterUiHandler } from "#ui/handlers/mystery-encounter-ui-handler";
import i18next from "i18next";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
diff --git a/test/phases/select-modifier-phase.test.ts b/test/phases/select-modifier-phase.test.ts
index b77e31e931f..f6446c6e7be 100644
--- a/test/phases/select-modifier-phase.test.ts
+++ b/test/phases/select-modifier-phase.test.ts
@@ -12,7 +12,7 @@ import { ModifierTypeOption } from "#modifiers/modifier-type";
import { SelectModifierPhase } from "#phases/select-modifier-phase";
import { GameManager } from "#test/test-utils/game-manager";
import { initSceneWithoutEncounterPhase } from "#test/test-utils/game-manager-utils";
-import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
+import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler";
import { shiftCharCodes } from "#utils/common";
import { getPokemonSpecies } from "#utils/pokemon-utils";
import Phaser from "phaser";
@@ -137,16 +137,16 @@ describe("SelectModifierPhase", () => {
expect(modifierSelectHandler.options.length).toEqual(3);
// Reroll with lock can still upgrade
expect(
- modifierSelectHandler.options[0].modifierTypeOption.type.tier -
- modifierSelectHandler.options[0].modifierTypeOption.upgradeCount,
+ modifierSelectHandler.options[0].modifierTypeOption.type.tier
+ - modifierSelectHandler.options[0].modifierTypeOption.upgradeCount,
).toEqual(firstRollTiers[0]);
expect(
- modifierSelectHandler.options[1].modifierTypeOption.type.tier -
- modifierSelectHandler.options[1].modifierTypeOption.upgradeCount,
+ modifierSelectHandler.options[1].modifierTypeOption.type.tier
+ - modifierSelectHandler.options[1].modifierTypeOption.upgradeCount,
).toEqual(firstRollTiers[1]);
expect(
- modifierSelectHandler.options[2].modifierTypeOption.type.tier -
- modifierSelectHandler.options[2].modifierTypeOption.upgradeCount,
+ modifierSelectHandler.options[2].modifierTypeOption.type.tier
+ - modifierSelectHandler.options[2].modifierTypeOption.upgradeCount,
).toEqual(firstRollTiers[2]);
});
@@ -210,24 +210,24 @@ describe("SelectModifierPhase", () => {
) as ModifierSelectUiHandler;
expect(modifierSelectHandler.options.length).toEqual(5);
expect(
- modifierSelectHandler.options[0].modifierTypeOption.type.tier -
- modifierSelectHandler.options[0].modifierTypeOption.upgradeCount,
+ modifierSelectHandler.options[0].modifierTypeOption.type.tier
+ - modifierSelectHandler.options[0].modifierTypeOption.upgradeCount,
).toEqual(ModifierTier.COMMON);
expect(
- modifierSelectHandler.options[1].modifierTypeOption.type.tier -
- modifierSelectHandler.options[1].modifierTypeOption.upgradeCount,
+ modifierSelectHandler.options[1].modifierTypeOption.type.tier
+ - modifierSelectHandler.options[1].modifierTypeOption.upgradeCount,
).toEqual(ModifierTier.GREAT);
expect(
- modifierSelectHandler.options[2].modifierTypeOption.type.tier -
- modifierSelectHandler.options[2].modifierTypeOption.upgradeCount,
+ modifierSelectHandler.options[2].modifierTypeOption.type.tier
+ - modifierSelectHandler.options[2].modifierTypeOption.upgradeCount,
).toEqual(ModifierTier.ULTRA);
expect(
- modifierSelectHandler.options[3].modifierTypeOption.type.tier -
- modifierSelectHandler.options[3].modifierTypeOption.upgradeCount,
+ modifierSelectHandler.options[3].modifierTypeOption.type.tier
+ - modifierSelectHandler.options[3].modifierTypeOption.upgradeCount,
).toEqual(ModifierTier.ROGUE);
expect(
- modifierSelectHandler.options[4].modifierTypeOption.type.tier -
- modifierSelectHandler.options[4].modifierTypeOption.upgradeCount,
+ modifierSelectHandler.options[4].modifierTypeOption.type.tier
+ - modifierSelectHandler.options[4].modifierTypeOption.upgradeCount,
).toEqual(ModifierTier.MASTER);
});
diff --git a/test/plugins/api/pokerogue-daily-api.test.ts b/test/plugins/api/pokerogue-daily-api.test.ts
index ef5dfddada5..b45896e6a2c 100644
--- a/test/plugins/api/pokerogue-daily-api.test.ts
+++ b/test/plugins/api/pokerogue-daily-api.test.ts
@@ -2,7 +2,7 @@ import { PokerogueDailyApi } from "#api/pokerogue-daily-api";
import { initServerForApiTests } from "#test/test-utils/test-file-initialization";
import { getApiBaseUrl } from "#test/test-utils/test-utils";
import type { GetDailyRankingsPageCountRequest, GetDailyRankingsRequest } from "#types/api/pokerogue-daily-api";
-import { type RankingEntry, ScoreboardCategory } from "#ui/daily-run-scoreboard";
+import { type RankingEntry, ScoreboardCategory } from "#ui/containers/daily-run-scoreboard";
import { HttpResponse, http } from "msw";
import type { SetupServerApi } from "msw/node";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
diff --git a/test/setting-menu/helpers/menu-manip.ts b/test/setting-menu/helpers/menu-manip.ts
index 276fef2f973..392425ea6f2 100644
--- a/test/setting-menu/helpers/menu-manip.ts
+++ b/test/setting-menu/helpers/menu-manip.ts
@@ -17,16 +17,12 @@ export class MenuManip {
private config;
private settingName;
private keycode;
- private icon;
private iconDisplayed;
- private specialCaseIcon;
constructor(config) {
this.config = config;
this.settingName = null;
- this.icon = null;
this.iconDisplayed = null;
- this.specialCaseIcon = null;
}
// TODO: Review this
@@ -87,8 +83,8 @@ export class MenuManip {
const icon = getIconWithKeycode(this.config, this.keycode);
const key = getKeyWithKeycode(this.config, this.keycode)!; // TODO: is this bang correct?
const _keys = key.toLowerCase().split("_");
- const iconIdentifier = _keys[_keys.length - 1];
- expect(icon.toLowerCase().includes(iconIdentifier)).toEqual(true);
+ const iconIdentifier = _keys.at(-1);
+ expect(icon.toLowerCase()).toContain(iconIdentifier);
return this;
}
diff --git a/test/sprites/pokemon-sprite.test.ts b/test/sprites/pokemon-sprite.test.ts
index bf945636a71..f3c118921fd 100644
--- a/test/sprites/pokemon-sprite.test.ts
+++ b/test/sprites/pokemon-sprite.test.ts
@@ -148,7 +148,7 @@ describe("check if every variant's sprite are correctly set", () => {
it("check root variant files", () => {
const dirPath = rootDir;
const errors = getMissingFiles(masterlist, dirPath);
- if (errors.length) {
+ if (errors.length > 0) {
console.log("errors", errors);
}
expect(errors).toEqual([]);
@@ -157,7 +157,7 @@ describe("check if every variant's sprite are correctly set", () => {
it("check female variant files", () => {
const dirPath = `${rootDir}female${path.sep}`;
const errors = getMissingFiles(femaleVariant, dirPath);
- if (errors.length) {
+ if (errors.length > 0) {
console.log("errors", errors);
}
expect(errors).toEqual([]);
@@ -166,7 +166,7 @@ describe("check if every variant's sprite are correctly set", () => {
it("check back female variant files", () => {
const dirPath = `${rootDir}back${path.sep}female${path.sep}`;
const errors = getMissingFiles(backVariant.female, dirPath);
- if (errors.length) {
+ if (errors.length > 0) {
console.log("errors", errors);
}
expect(errors).toEqual([]);
@@ -177,7 +177,7 @@ describe("check if every variant's sprite are correctly set", () => {
const backMaleVariant = deepCopy(backVariant);
delete backMaleVariant.female;
const errors = getMissingFiles(backMaleVariant, dirPath);
- if (errors.length) {
+ if (errors.length > 0) {
console.log("errors", errors);
}
expect(errors).toEqual([]);
@@ -186,7 +186,7 @@ describe("check if every variant's sprite are correctly set", () => {
it("check exp back female variant files", () => {
const dirPath = `${rootDir}exp${path.sep}back${path.sep}female${path.sep}`;
const errors = getMissingFiles(expVariant.back.female, dirPath);
- if (errors.length) {
+ if (errors.length > 0) {
console.log("errors", errors);
}
expect(errors.length).toBe(0);
@@ -197,7 +197,7 @@ describe("check if every variant's sprite are correctly set", () => {
const backMaleVariant = deepCopy(expVariant.back);
delete backMaleVariant.female;
const errors = getMissingFiles(backMaleVariant, dirPath);
- if (errors.length) {
+ if (errors.length > 0) {
console.log("errors", errors);
}
expect(errors).toEqual([]);
@@ -206,7 +206,7 @@ describe("check if every variant's sprite are correctly set", () => {
it("check exp female variant files", () => {
const dirPath = `${rootDir}exp${path.sep}female${path.sep}`;
const errors = getMissingFiles(expVariant.female, dirPath);
- if (errors.length) {
+ if (errors.length > 0) {
console.log("errors", errors);
}
expect(errors).toEqual([]);
@@ -218,7 +218,7 @@ describe("check if every variant's sprite are correctly set", () => {
delete expMaleVariant.female;
delete expMaleVariant.back;
const errors = getMissingFiles(expMaleVariant, dirPath);
- if (errors.length) {
+ if (errors.length > 0) {
console.log("errors", errors);
}
expect(errors).toEqual([]);
@@ -229,7 +229,7 @@ describe("check if every variant's sprite are correctly set", () => {
it("look over every file in variant female and check if present in masterlist", () => {
const dirPath = `${rootDir}female${path.sep}`;
const errors = getMissingMasterlist(femaleVariant, dirPath);
- if (errors.length) {
+ if (errors.length > 0) {
console.log("errors for ", dirPath, errors);
}
expect(errors).toEqual([]);
@@ -238,7 +238,7 @@ describe("check if every variant's sprite are correctly set", () => {
it("look over every file in variant back female and check if present in masterlist", () => {
const dirPath = `${rootDir}back${path.sep}female${path.sep}`;
const errors = getMissingMasterlist(backVariant.female, dirPath);
- if (errors.length) {
+ if (errors.length > 0) {
console.log("errors for ", dirPath, errors);
}
expect(errors).toEqual([]);
@@ -248,7 +248,7 @@ describe("check if every variant's sprite are correctly set", () => {
const dirPath = `${rootDir}back${path.sep}`;
const backMaleVariant = deepCopy(backVariant);
const errors = getMissingMasterlist(backMaleVariant, dirPath, ["female"]);
- if (errors.length) {
+ if (errors.length > 0) {
console.log("errors for ", dirPath, errors);
}
expect(errors).toEqual([]);
@@ -257,7 +257,7 @@ describe("check if every variant's sprite are correctly set", () => {
it("look over every file in variant exp back female and check if present in masterlist", () => {
const dirPath = `${rootDir}exp${path.sep}back${path.sep}female${path.sep}`;
const errors = getMissingMasterlist(expVariant.back, dirPath);
- if (errors.length) {
+ if (errors.length > 0) {
console.log("errors for ", dirPath, errors);
}
expect(errors).toEqual([]);
@@ -266,7 +266,7 @@ describe("check if every variant's sprite are correctly set", () => {
it("look over every file in variant exp back male and check if present in masterlist", () => {
const dirPath = `${rootDir}exp${path.sep}back${path.sep}`;
const errors = getMissingMasterlist(expVariant.back, dirPath, ["female"]);
- if (errors.length) {
+ if (errors.length > 0) {
console.log("errors for ", dirPath, errors);
}
expect(errors.length).toBe(0);
@@ -275,7 +275,7 @@ describe("check if every variant's sprite are correctly set", () => {
it("look over every file in variant exp female and check if present in masterlist", () => {
const dirPath = `${rootDir}exp${path.sep}female${path.sep}`;
const errors = getMissingMasterlist(expVariant.female, dirPath);
- if (errors.length) {
+ if (errors.length > 0) {
console.log("errors for ", dirPath, errors);
}
expect(errors).toEqual([]);
@@ -284,7 +284,7 @@ describe("check if every variant's sprite are correctly set", () => {
it("look over every file in variant exp male and check if present in masterlist", () => {
const dirPath = `${rootDir}exp${path.sep}`;
const errors = getMissingMasterlist(expVariant, dirPath, ["back", "female"]);
- if (errors.length) {
+ if (errors.length > 0) {
console.log("errors for ", dirPath, errors);
}
expect(errors).toEqual([]);
@@ -293,7 +293,7 @@ describe("check if every variant's sprite are correctly set", () => {
it("look over every file in variant root and check if present in masterlist", () => {
const dirPath = `${rootDir}`;
const errors = getMissingMasterlist(masterlist, dirPath, ["back", "female", "exp", "icons"]);
- if (errors.length) {
+ if (errors.length > 0) {
console.log("errors for ", dirPath, errors);
}
expect(errors).toEqual([]);
diff --git a/test/test-utils/game-manager-utils.ts b/test/test-utils/game-manager-utils.ts
index 89e352cdbdc..e9c3e9809cc 100644
--- a/test/test-utils/game-manager-utils.ts
+++ b/test/test-utils/game-manager-utils.ts
@@ -9,7 +9,7 @@ import type { MoveId } from "#enums/move-id";
import type { SpeciesId } from "#enums/species-id";
import { PlayerPokemon } from "#field/pokemon";
import type { StarterMoveset } from "#system/game-data";
-import type { Starter } from "#ui/starter-select-ui-handler";
+import type { Starter } from "#ui/handlers/starter-select-ui-handler";
import { getPokemonSpecies, getPokemonSpeciesForm } from "#utils/pokemon-utils";
/** Function to convert Blob to string */
diff --git a/test/test-utils/game-manager.ts b/test/test-utils/game-manager.ts
index 5f56832a6d2..6b7c805df74 100644
--- a/test/test-utils/game-manager.ts
+++ b/test/test-utils/game-manager.ts
@@ -45,13 +45,13 @@ import { MockFetch } from "#test/test-utils/mocks/mock-fetch";
import { PhaseInterceptor } from "#test/test-utils/phase-interceptor";
import { TextInterceptor } from "#test/test-utils/text-interceptor";
import type { PhaseClass, PhaseString } from "#types/phase-types";
-import type { BallUiHandler } from "#ui/ball-ui-handler";
-import type { BattleMessageUiHandler } from "#ui/battle-message-ui-handler";
-import type { CommandUiHandler } from "#ui/command-ui-handler";
-import type { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
-import type { PartyUiHandler } from "#ui/party-ui-handler";
-import type { StarterSelectUiHandler } from "#ui/starter-select-ui-handler";
-import type { TargetSelectUiHandler } from "#ui/target-select-ui-handler";
+import type { BallUiHandler } from "#ui/handlers/ball-ui-handler";
+import type { BattleMessageUiHandler } from "#ui/handlers/battle-message-ui-handler";
+import type { CommandUiHandler } from "#ui/handlers/command-ui-handler";
+import type { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler";
+import type { PartyUiHandler } from "#ui/handlers/party-ui-handler";
+import type { StarterSelectUiHandler } from "#ui/handlers/starter-select-ui-handler";
+import type { TargetSelectUiHandler } from "#ui/handlers/target-select-ui-handler";
import { isNullOrUndefined } from "#utils/common";
import fs from "node:fs";
import { AES, enc } from "crypto-js";
@@ -306,10 +306,10 @@ export class GameManager {
handler.processInput(Button.ACTION);
},
() =>
- this.isCurrentPhase(CommandPhase) ||
- this.isCurrentPhase(MovePhase) ||
- this.isCurrentPhase(TurnStartPhase) ||
- this.isCurrentPhase(TurnEndPhase),
+ this.isCurrentPhase(CommandPhase)
+ || this.isCurrentPhase(MovePhase)
+ || this.isCurrentPhase(TurnStartPhase)
+ || this.isCurrentPhase(TurnEndPhase),
);
}
@@ -331,9 +331,9 @@ export class GameManager {
handler.processInput(Button.CANCEL);
},
() =>
- this.isCurrentPhase(CommandPhase) ||
- this.isCurrentPhase(NewBattlePhase) ||
- this.isCurrentPhase(CheckSwitchPhase),
+ this.isCurrentPhase(CommandPhase)
+ || this.isCurrentPhase(NewBattlePhase)
+ || this.isCurrentPhase(CheckSwitchPhase),
true,
);
@@ -345,9 +345,9 @@ export class GameManager {
handler.processInput(Button.ACTION);
},
() =>
- this.isCurrentPhase(CommandPhase) ||
- this.isCurrentPhase(NewBattlePhase) ||
- this.isCurrentPhase(CheckSwitchPhase),
+ this.isCurrentPhase(CommandPhase)
+ || this.isCurrentPhase(NewBattlePhase)
+ || this.isCurrentPhase(CheckSwitchPhase),
);
}
diff --git a/test/test-utils/game-wrapper.ts b/test/test-utils/game-wrapper.ts
index 1a906bf8492..166f4b8de7a 100644
--- a/test/test-utils/game-wrapper.ts
+++ b/test/test-utils/game-wrapper.ts
@@ -6,17 +6,13 @@ import * as bypassLoginModule from "#app/global-vars/bypass-login";
import { MoveAnim } from "#data/battle-anims";
import { Pokemon } from "#field/pokemon";
import { version } from "#package.json";
-import { blobToString } from "#test/test-utils/game-manager-utils";
import { MockClock } from "#test/test-utils/mocks/mock-clock";
-import { MockFetch } from "#test/test-utils/mocks/mock-fetch";
import { MockGameObjectCreator } from "#test/test-utils/mocks/mock-game-object-creator";
import { MockLoader } from "#test/test-utils/mocks/mock-loader";
import { MockTextureManager } from "#test/test-utils/mocks/mock-texture-manager";
import { MockTimedEventManager } from "#test/test-utils/mocks/mock-timed-event-manager";
import { MockContainer } from "#test/test-utils/mocks/mocks-container/mock-container";
-import { PokedexMonContainer } from "#ui/pokedex-mon-container";
-import { sessionIdKey } from "#utils/common";
-import { setCookie } from "#utils/cookies";
+import { PokedexMonContainer } from "#ui/containers/pokedex-mon-container";
import fs from "node:fs";
import Phaser from "phaser";
import { vi } from "vitest";
@@ -28,20 +24,6 @@ const GamepadPlugin = Phaser.Input.Gamepad.GamepadPlugin;
const EventEmitter = Phaser.Events.EventEmitter;
const UpdateList = Phaser.GameObjects.UpdateList;
-window.URL.createObjectURL = (blob: Blob) => {
- blobToString(blob).then((data: string) => {
- localStorage.setItem("toExport", data);
- });
- return null;
-};
-navigator.getGamepads = () => [];
-global.fetch = vi.fn(MockFetch);
-setCookie(sessionIdKey, "fake_token");
-
-window.matchMedia = () => ({
- matches: false,
-});
-
export class GameWrapper {
public game: Phaser.Game;
public scene: BattleScene;
@@ -99,6 +81,7 @@ export class GameWrapper {
removeAll: () => null,
};
+ // TODO: Can't we just turn on `noAudio` in audio config?
this.scene.sound = {
play: () => null,
pause: () => null,
diff --git a/test/test-utils/helpers/challenge-mode-helper.ts b/test/test-utils/helpers/challenge-mode-helper.ts
index d1a7c8744fd..1b530bb2987 100644
--- a/test/test-utils/helpers/challenge-mode-helper.ts
+++ b/test/test-utils/helpers/challenge-mode-helper.ts
@@ -1,5 +1,6 @@
import overrides from "#app/overrides";
import type { Challenge } from "#data/challenge";
+import { copyChallenge } from "#data/challenge";
import { BattleStyle } from "#enums/battle-style";
import type { Challenges } from "#enums/challenges";
import type { SpeciesId } from "#enums/species-id";
@@ -10,7 +11,6 @@ import { SelectStarterPhase } from "#phases/select-starter-phase";
import { TurnInitPhase } from "#phases/turn-init-phase";
import { generateStarter } from "#test/test-utils/game-manager-utils";
import { GameManagerHelper } from "#test/test-utils/helpers/game-manager-helper";
-import { copyChallenge } from "data/challenge";
type challengeStub = { id: Challenges; value: number; severity: number };
diff --git a/test/test-utils/helpers/classic-mode-helper.ts b/test/test-utils/helpers/classic-mode-helper.ts
index c625ebc911c..f813a8f797e 100644
--- a/test/test-utils/helpers/classic-mode-helper.ts
+++ b/test/test-utils/helpers/classic-mode-helper.ts
@@ -19,8 +19,10 @@ import { GameManagerHelper } from "#test/test-utils/helpers/game-manager-helper"
export class ClassicModeHelper extends GameManagerHelper {
/**
* Runs the classic game to the summon phase.
- * @param species - An array of {@linkcode Species} to summon.
+ * @param species - An array of {@linkcode SpeciesId} to summon.
* @returns A promise that resolves when the summon phase is reached.
+ * @remarks
+ * Do not use this when {@linkcode startBattle} can be used!
*/
async runToSummon(species: SpeciesId[]): Promise;
/**
@@ -30,6 +32,7 @@ export class ClassicModeHelper extends GameManagerHelper {
* @returns A promise that resolves when the summon phase is reached.
* @deprecated - Specifying the starters helps prevent inconsistencies from internal RNG changes.
*/
+ // biome-ignore lint/style/useUnifiedTypeSignatures: Marks the overload for deprecation
async runToSummon(): Promise;
async runToSummon(species: SpeciesId[] | undefined): Promise;
async runToSummon(species?: SpeciesId[]): Promise {
@@ -61,7 +64,7 @@ export class ClassicModeHelper extends GameManagerHelper {
/**
* Transitions to the start of a battle.
- * @param species - An array of {@linkcode Species} to start the battle with.
+ * @param species - An array of {@linkcode SpeciesId} to start the battle with.
* @returns A promise that resolves when the battle is started.
*/
async startBattle(species: SpeciesId[]): Promise;
@@ -72,6 +75,7 @@ export class ClassicModeHelper extends GameManagerHelper {
* @returns A promise that resolves when the battle is started.
* @deprecated - Specifying the starters helps prevent inconsistencies from internal RNG changes.
*/
+ // biome-ignore lint/style/useUnifiedTypeSignatures: Marks the overload for deprecation
async startBattle(): Promise;
async startBattle(species?: SpeciesId[]): Promise {
await this.runToSummon(species);
diff --git a/test/test-utils/helpers/daily-mode-helper.ts b/test/test-utils/helpers/daily-mode-helper.ts
index 94b1e671b4b..4b2ea8c5cf2 100644
--- a/test/test-utils/helpers/daily-mode-helper.ts
+++ b/test/test-utils/helpers/daily-mode-helper.ts
@@ -7,7 +7,7 @@ import { EncounterPhase } from "#phases/encounter-phase";
import { TitlePhase } from "#phases/title-phase";
import { TurnInitPhase } from "#phases/turn-init-phase";
import { GameManagerHelper } from "#test/test-utils/helpers/game-manager-helper";
-import type { SaveSlotSelectUiHandler } from "#ui/save-slot-select-ui-handler";
+import type { SaveSlotSelectUiHandler } from "#ui/handlers/save-slot-select-ui-handler";
/**
* Helper to handle daily mode specifics
diff --git a/test/test-utils/helpers/move-helper.ts b/test/test-utils/helpers/move-helper.ts
index 4afaf03045d..7f642705b5b 100644
--- a/test/test-utils/helpers/move-helper.ts
+++ b/test/test-utils/helpers/move-helper.ts
@@ -67,9 +67,10 @@ export class MoveHelper extends GameManagerHelper {
const movePosition = this.getMovePosition(pkmIndex, move);
if (movePosition === -1) {
expect.fail(
- `MoveHelper.select called with move '${toTitleCase(MoveId[move])}' not in moveset!` +
- `\nBattler Index: ${toTitleCase(BattlerIndex[pkmIndex])}` +
- `\nMoveset: [${this.game.scene
+ // biome-ignore lint/complexity/noUselessStringConcat: Biome does not currently detect this as multiline (BUG)
+ `MoveHelper.select called with move '${toTitleCase(MoveId[move])}' not in moveset!`
+ + `\nBattler Index: ${toTitleCase(BattlerIndex[pkmIndex])}`
+ + `\nMoveset: [${this.game.scene
.getPlayerParty()
[pkmIndex].getMoveset()
.map(pm => toTitleCase(MoveId[pm.moveId]))
@@ -115,9 +116,10 @@ export class MoveHelper extends GameManagerHelper {
const movePosition = this.getMovePosition(pkmIndex, move);
if (movePosition === -1) {
expect.fail(
- `MoveHelper.selectWithTera called with move '${toTitleCase(MoveId[move])}' not in moveset!` +
- `\nBattler Index: ${toTitleCase(BattlerIndex[pkmIndex])}` +
- `\nMoveset: [${this.game.scene
+ // biome-ignore lint/complexity/noUselessStringConcat: Biome does not currently detect this as multiline (BUG)
+ `MoveHelper.selectWithTera called with move '${toTitleCase(MoveId[move])}' not in moveset!`
+ + `\nBattler Index: ${toTitleCase(BattlerIndex[pkmIndex])}`
+ + `\nMoveset: [${this.game.scene
.getPlayerParty()
[pkmIndex].getMoveset()
.map(pm => toTitleCase(MoveId[pm.moveId]))
@@ -231,11 +233,9 @@ export class MoveHelper extends GameManagerHelper {
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([]);
console.warn("Player moveset override disabled due to use of `game.move.changeMoveset`!");
}
- } else {
- if (coerceArray(Overrides.ENEMY_MOVESET_OVERRIDE).length > 0) {
- vi.spyOn(Overrides, "ENEMY_MOVESET_OVERRIDE", "get").mockReturnValue([]);
- console.warn("Enemy moveset override disabled due to use of `game.move.changeMoveset`!");
- }
+ } else if (coerceArray(Overrides.ENEMY_MOVESET_OVERRIDE).length > 0) {
+ vi.spyOn(Overrides, "ENEMY_MOVESET_OVERRIDE", "get").mockReturnValue([]);
+ console.warn("Enemy moveset override disabled due to use of `game.move.changeMoveset`!");
}
moveset = coerceArray(moveset);
expect(moveset.length, "Cannot assign more than 4 moves to a moveset!").toBeLessThanOrEqual(4);
diff --git a/test/test-utils/helpers/overrides-helper.ts b/test/test-utils/helpers/overrides-helper.ts
index 93b89688935..07ea1ea3d09 100644
--- a/test/test-utils/helpers/overrides-helper.ts
+++ b/test/test-utils/helpers/overrides-helper.ts
@@ -1,7 +1,9 @@
/** biome-ignore-start lint/correctness/noUnusedImports: tsdoc imports */
import type { NewArenaEvent } from "#events/battle-scene";
+
/** biome-ignore-end lint/correctness/noUnusedImports: tsdoc imports */
+import { OVERRIDES_COLOR } from "#app/constants/colors";
import type { BattleStyle, RandomTrainerOverride } from "#app/overrides";
import Overrides from "#app/overrides";
import { AbilityId } from "#enums/ability-id";
@@ -19,6 +21,7 @@ import type { ModifierOverride } from "#modifiers/modifier-type";
import type { Variant } from "#sprites/variant";
import { GameManagerHelper } from "#test/test-utils/helpers/game-manager-helper";
import { coerceArray, shiftCharCodes } from "#utils/common";
+import chalk from "chalk";
import { vi } from "vitest";
/**
@@ -665,6 +668,6 @@ export class OverridesHelper extends GameManagerHelper {
}
private log(...params: any[]) {
- console.log("Overrides:", ...params);
+ console.log(chalk.hex(OVERRIDES_COLOR)(...params));
}
}
diff --git a/test/test-utils/helpers/reload-helper.ts b/test/test-utils/helpers/reload-helper.ts
index 7166f1b6cf9..fa627019483 100644
--- a/test/test-utils/helpers/reload-helper.ts
+++ b/test/test-utils/helpers/reload-helper.ts
@@ -48,7 +48,7 @@ export class ReloadHelper extends GameManagerHelper {
// remove all persistent mods before loading
// TODO: Look into why these aren't removed before load
- if (this.game.scene.modifiers.length) {
+ if (this.game.scene.modifiers.length > 0) {
console.log(
"Removing %d modifiers from scene on load...",
this.game.scene.modifiers.length,
diff --git a/test/test-utils/helpers/settings-helper.ts b/test/test-utils/helpers/settings-helper.ts
index a26aa2de33c..46ac74b83dc 100644
--- a/test/test-utils/helpers/settings-helper.ts
+++ b/test/test-utils/helpers/settings-helper.ts
@@ -1,7 +1,9 @@
+import { SETTINGS_COLOR } from "#app/constants/colors";
import { BattleStyle } from "#enums/battle-style";
import { ExpGainsSpeed } from "#enums/exp-gains-speed";
import { PlayerGender } from "#enums/player-gender";
import { GameManagerHelper } from "#test/test-utils/helpers/game-manager-helper";
+import chalk from "chalk";
/**
* Helper to handle settings for tests
@@ -49,6 +51,6 @@ export class SettingsHelper extends GameManagerHelper {
}
private log(...params: any[]) {
- console.log("Settings:", ...params);
+ console.log(chalk.hex(SETTINGS_COLOR)(...params));
}
}
diff --git a/test/test-utils/inputs-handler.ts b/test/test-utils/inputs-handler.ts
index b8b3224c31d..b5638f3694c 100644
--- a/test/test-utils/inputs-handler.ts
+++ b/test/test-utils/inputs-handler.ts
@@ -111,7 +111,7 @@ class FakeMobile {
if (!node) {
return;
}
- const event = new Event("touchstart");
+ const event = new Event("pointerdown");
node.dispatchEvent(event);
}
@@ -120,7 +120,7 @@ class FakeMobile {
if (!node) {
return;
}
- const event = new Event("touchend");
+ const event = new Event("pointerup");
node.dispatchEvent(event);
}
}
diff --git a/test/test-utils/mocks/mock-console-log.ts b/test/test-utils/mocks/mock-console-log.ts
deleted file mode 100644
index f54d41fea3e..00000000000
--- a/test/test-utils/mocks/mock-console-log.ts
+++ /dev/null
@@ -1,80 +0,0 @@
-const originalLog = console.log;
-const originalError = console.error;
-const originalDebug = console.debug;
-const originalWarn = console.warn;
-
-const blacklist = ["Phaser", "variant icon does not exist", 'Texture "%s" not found'];
-const whitelist = ["Phase"];
-
-export class MockConsoleLog {
- constructor(
- private logDisabled = false,
- private phaseText = false,
- ) {}
- private logs: any[] = [];
- private notified: any[] = [];
-
- public log(...args) {
- const argsStr = this.getStr(args);
- this.logs.push(argsStr);
- if (this.logDisabled && !this.phaseText) {
- return;
- }
- if ((this.phaseText && !whitelist.some(b => argsStr.includes(b))) || blacklist.some(b => argsStr.includes(b))) {
- return;
- }
- originalLog(args);
- }
- public error(...args) {
- const argsStr = this.getStr(args);
- this.logs.push(argsStr);
- originalError(args); // Appelle le console.error originel
- }
- public debug(...args) {
- const argsStr = this.getStr(args);
- this.logs.push(argsStr);
- if (this.logDisabled && !this.phaseText) {
- return;
- }
- if (!whitelist.some(b => argsStr.includes(b)) || blacklist.some(b => argsStr.includes(b))) {
- return;
- }
- originalDebug(args);
- }
- warn(...args) {
- const argsStr = this.getStr(args);
- this.logs.push(args);
- if (this.logDisabled && !this.phaseText) {
- return;
- }
- if (!whitelist.some(b => argsStr.includes(b)) || blacklist.some(b => argsStr.includes(b))) {
- return;
- }
- originalWarn(args);
- }
- notify(msg) {
- originalLog(msg);
- this.notified.push(msg);
- }
- getLogs() {
- return this.logs;
- }
- clearLogs() {
- this.logs = [];
- }
- getStr(...args) {
- return args
- .map(arg => {
- if (typeof arg === "object" && arg !== null) {
- // Handle objects including arrays
- return JSON.stringify(arg, (_key, value) => (typeof value === "bigint" ? value.toString() : value));
- }
- if (typeof arg === "bigint") {
- // Handle BigInt values
- return arg.toString();
- }
- return arg.toString();
- })
- .join(";");
- }
-}
diff --git a/test/test-utils/mocks/mock-console/color-map.json b/test/test-utils/mocks/mock-console/color-map.json
new file mode 100644
index 00000000000..ded83e889b0
--- /dev/null
+++ b/test/test-utils/mocks/mock-console/color-map.json
@@ -0,0 +1,150 @@
+{
+ "AliceBlue": "f0f8ff",
+ "AntiqueWhite": "faebd7",
+ "Aqua": "00ffff",
+ "Aquamarine": "7fffd4",
+ "Azure": "f0ffff",
+ "Beige": "f5f5dc",
+ "Bisque": "ffe4c4",
+ "Black": "000000",
+ "BlanchedAlmond": "ffebcd",
+ "Blue": "0000ff",
+ "BlueViolet": "8a2be2",
+ "Brown": "a52a2a",
+ "BurlyWood": "deb887",
+ "CadetBlue": "5f9ea0",
+ "Chartreuse": "7fff00",
+ "Chocolate": "d2691e",
+ "Coral": "ff7f50",
+ "CornflowerBlue": "6495ed",
+ "Cornsilk": "fff8dc",
+ "Crimson": "dc143c",
+ "Cyan": "00ffff",
+ "DarkBlue": "00008b",
+ "DarkCyan": "008b8b",
+ "DarkGoldenRod": "b8860b",
+ "DarkGray": "a9a9a9",
+ "DarkGrey": "a9a9a9",
+ "DarkGreen": "006400",
+ "DarkKhaki": "bdb76b",
+ "DarkMagenta": "8b008b",
+ "DarkOliveGreen": "556b2f",
+ "DarkOrange": "ff8c00",
+ "DarkOrchid": "9932cc",
+ "DarkRed": "8b0000",
+ "DarkSalmon": "e9967a",
+ "DarkSeaGreen": "8fbc8f",
+ "DarkSlateBlue": "483d8b",
+ "DarkSlateGray": "2f4f4f",
+ "DarkSlateGrey": "2f4f4f",
+ "DarkTurquoise": "00ced1",
+ "DarkViolet": "9400d3",
+ "DeepPink": "ff1493",
+ "DeepSkyBlue": "00bfff",
+ "DimGray": "696969",
+ "DimGrey": "696969",
+ "DodgerBlue": "1e90ff",
+ "FireBrick": "b22222",
+ "FloralWhite": "fffaf0",
+ "ForestGreen": "228b22",
+ "Fuchsia": "ff00ff",
+ "Gainsboro": "dcdcdc",
+ "GhostWhite": "f8f8ff",
+ "Gold": "ffd700",
+ "GoldenRod": "daa520",
+ "Gray": "808080",
+ "Grey": "808080",
+ "Green": "008000",
+ "GreenYellow": "adff2f",
+ "HoneyDew": "f0fff0",
+ "HotPink": "ff69b4",
+ "IndianRed": "cd5c5c",
+ "Indigo": "4b0082",
+ "Ivory": "fffff0",
+ "Khaki": "f0e68c",
+ "Lavender": "e6e6fa",
+ "LavenderBlush": "fff0f5",
+ "LawnGreen": "7cfc00",
+ "LemonChiffon": "fffacd",
+ "LightBlue": "add8e6",
+ "LightCoral": "f08080",
+ "LightCyan": "e0ffff",
+ "LightGoldenRodYellow": "fafad2",
+ "LightGray": "d3d3d3",
+ "LightGrey": "d3d3d3",
+ "LightGreen": "90ee90",
+ "LightPink": "ffb6c1",
+ "LightSalmon": "ffa07a",
+ "LightSeaGreen": "20b2aa",
+ "LightSkyBlue": "87cefa",
+ "LightSlateGray": "778899",
+ "LightSlateGrey": "778899",
+ "LightSteelBlue": "b0c4de",
+ "LightYellow": "ffffe0",
+ "Lime": "00ff00",
+ "LimeGreen": "32cd32",
+ "Linen": "faf0e6",
+ "Magenta": "ff00ff",
+ "Maroon": "800000",
+ "MediumAquaMarine": "66cdaa",
+ "MediumBlue": "0000cd",
+ "MediumOrchid": "ba55d3",
+ "MediumPurple": "9370db",
+ "MediumSeaGreen": "3cb371",
+ "MediumSlateBlue": "7b68ee",
+ "MediumSpringGreen": "00fa9a",
+ "MediumTurquoise": "48d1cc",
+ "MediumVioletRed": "c71585",
+ "MidnightBlue": "191970",
+ "MintCream": "f5fffa",
+ "MistyRose": "ffe4e1",
+ "Moccasin": "ffe4b5",
+ "NavajoWhite": "ffdead",
+ "Navy": "000080",
+ "OldLace": "fdf5e6",
+ "Olive": "808000",
+ "OliveDrab": "6b8e23",
+ "Orange": "ffa500",
+ "OrangeRed": "ff4500",
+ "Orchid": "da70d6",
+ "PaleGoldenRod": "eee8aa",
+ "PaleGreen": "98fb98",
+ "PaleTurquoise": "afeeee",
+ "PaleVioletRed": "db7093",
+ "PapayaWhip": "ffefd5",
+ "PeachPuff": "ffdab9",
+ "Peru": "cd853f",
+ "Pink": "ffc0cb",
+ "Plum": "dda0dd",
+ "PowderBlue": "b0e0e6",
+ "Purple": "800080",
+ "RebeccaPurple": "663399",
+ "Red": "ff0000",
+ "RosyBrown": "bc8f8f",
+ "RoyalBlue": "4169e1",
+ "SaddleBrown": "8b4513",
+ "Salmon": "fa8072",
+ "SandyBrown": "f4a460",
+ "SeaGreen": "2e8b57",
+ "SeaShell": "fff5ee",
+ "Sienna": "a0522d",
+ "Silver": "c0c0c0",
+ "SkyBlue": "87ceeb",
+ "SlateBlue": "6a5acd",
+ "SlateGray": "708090",
+ "SlateGrey": "708090",
+ "Snow": "fffafa",
+ "SpringGreen": "00ff7f",
+ "SteelBlue": "4682b4",
+ "Tan": "d2b48c",
+ "Teal": "008080",
+ "Thistle": "d8bfd8",
+ "Tomato": "ff6347",
+ "Turquoise": "40e0d0",
+ "Violet": "ee82ee",
+ "Wheat": "f5deb3",
+ "White": "ffffff",
+ "WhiteSmoke": "f5f5f5",
+ "Yellow": "ffff00",
+ "YellowGreen": "9acd32"
+}
diff --git a/test/test-utils/mocks/mock-console/infer-color.ts b/test/test-utils/mocks/mock-console/infer-color.ts
new file mode 100644
index 00000000000..e01adbc4ad4
--- /dev/null
+++ b/test/test-utils/mocks/mock-console/infer-color.ts
@@ -0,0 +1,61 @@
+import { hslToHex } from "#utils/common";
+import chalk, { type ChalkInstance, type ForegroundColorName, foregroundColorNames } from "chalk";
+import colorMap from "./color-map.json";
+
+export function inferColorFormat(data: [string, ...unknown[]]): ChalkInstance {
+ // Remove all CSS format strings and find the first one containing something vaguely resembling a color
+ data[0] = data[0].replaceAll("%c", "");
+ const args = data.slice(1).filter(t => typeof t === "string");
+ const color = findColorPrefix(args);
+
+ // If the color is within Chalk's native roster, use it directly.
+ if ((foregroundColorNames as string[]).includes(color)) {
+ return chalk[color as ForegroundColorName];
+ }
+
+ // Otherwise, coerce it to hex before feeding it in.
+ return getColor(color);
+}
+
+/**
+ * Find the first string with a "color:" CSS directive in an argument list.
+ * @param args - The arguments containing the color directive
+ * @returns The found color, or `"green"` if none were found
+ */
+function findColorPrefix(args: string[]): string {
+ for (const arg of args) {
+ const match = /color:\s*(.+?)(?:;|$)/g.exec(arg);
+ if (match === null) {
+ continue;
+ }
+
+ return match[1];
+ }
+ return "green";
+}
+
+/**
+ * Coerce an arbitrary CSS color string to a Chalk instance.
+ * @param color - The color to coerce
+ * @returns The Chalk color equivalent.
+ */
+function getColor(color: string): ChalkInstance {
+ if (/^#([a-z0-9]{3,4}|[a-z0-9]{6}|[a-z0-9]{8})$/i.test(color)) {
+ // already in hex
+ return chalk.hex(color);
+ }
+
+ const rgbMatch = /^rgba?\((\d{1,3})%?,\s*(\d{1,3})%?,?\s*(\d{1,3})%?,\s*/i.exec(color);
+ if (rgbMatch) {
+ const [red, green, blue] = rgbMatch;
+ return chalk.rgb(+red, +green, +blue);
+ }
+
+ const hslMatch = /^hslv?\((\d{1,3}),\s*(\d{1,3})%,\s*(\d{1,3})%\)$/i.exec(color);
+ if (hslMatch) {
+ const [hue, saturation, light] = hslMatch;
+ return chalk.hex(hslToHex(+hue, +saturation / 100, +light / 100));
+ }
+
+ return chalk.hex(colorMap[color] ?? "#00ff95ff");
+}
diff --git a/test/test-utils/mocks/mock-console/mock-console.ts b/test/test-utils/mocks/mock-console/mock-console.ts
new file mode 100644
index 00000000000..52ed0af6aa7
--- /dev/null
+++ b/test/test-utils/mocks/mock-console/mock-console.ts
@@ -0,0 +1,211 @@
+import { DEBUG_COLOR, NEW_TURN_COLOR, TRACE_COLOR, UI_MSG_COLOR } from "#app/constants/colors";
+import { inferColorFormat } from "#test/test-utils/mocks/mock-console/infer-color";
+import { coerceArray } from "#utils/common";
+import { type InspectOptions, inspect } from "node:util";
+import chalk, { type ChalkInstance } from "chalk";
+
+// Tell chalk we support truecolor
+chalk.level = 3;
+
+// TODO: Review this
+const blacklist = [
+ "variant icon does not exist", // Repetitive warnings about icons not found
+ 'Texture "%s" not found', // Repetitive warnings about textures not found
+ "type: 'Pokemon',", // Large Pokemon objects
+ "gameVersion: ", // Large session-data and system-data objects
+ "Phaser v", // Phaser version text
+ "Seed:", // Stuff about wave seed (we should really stop logging this shit)
+ "Wave Seed:", // Stuff about wave seed (we should really stop logging this shit)
+] as const;
+const whitelist = ["Start Phase"] as const;
+
+const inspectOptions: InspectOptions = { sorted: true, breakLength: 120, numericSeparator: true };
+
+/**
+ * The {@linkcode MockConsole} is a wrapper around the global {@linkcode console} object.
+ * It automatically colors text and such.
+ */
+export class MockConsole implements Omit {
+ /**
+ * A list of warnings that are queued to be displayed after all tests in the same file are finished.
+ */
+ private static readonly queuedWarnings: unknown[][] = [];
+ /**
+ * The original `Console` object, preserved to avoid overwriting
+ * Vitest's native `console.log` wrapping.
+ */
+ private console = console;
+
+ //#region Static Properties
+
+ /**
+ * Queue a warning to be printed after all tests in the same file are finished.
+ */
+ // TODO: Add some warnings
+ public static queuePostTestWarning(...data: unknown[]): void {
+ MockConsole.queuedWarnings.push(data);
+ }
+
+ /**
+ * Print and reset all post-test warnings.
+ */
+ public static printPostTestWarnings(): void {
+ for (const data of MockConsole.queuedWarnings) {
+ console.warn(...data);
+ }
+ MockConsole.queuedWarnings.splice(0);
+ }
+
+ //#endregion Private Properties
+
+ //#region Utilities
+
+ /**
+ * Check whether a given set of data is in the blacklist to be barred from logging.
+ * @param data - The data being logged
+ * @returns Whether `data` is blacklisted from console logging
+ */
+ private checkBlacklist(data: unknown[]): boolean {
+ const dataStr = this.getStr(data);
+ return !whitelist.some(b => dataStr.includes(b)) && blacklist.some(b => dataStr.includes(b));
+ }
+
+ /**
+ * Returns a human-readable string representation of `data`.
+ */
+ private getStr(data: unknown): string {
+ return inspect(data, inspectOptions);
+ }
+
+ /**
+ * Stringify the given data in a manner fit for logging.
+ * @param color - A Chalk instance or other transformation function used to transform the output,
+ * or `undefined` to not transform it at all.
+ * @param data - The data that the format should be applied to.
+ * @returns A stringified copy of `data` with {@linkcode color} applied to each individual argument.
+ * @todo Do we need to apply color to each entry or just run it through `util.format`?
+ */
+ private format(color: ((s: unknown) => unknown) | undefined, data: unknown | unknown[]): unknown[] {
+ data = coerceArray(data);
+ color ??= a => a;
+ return (data as unknown[]).map(a => color(typeof a === "function" || typeof a === "object" ? this.getStr(a) : a));
+ }
+
+ //#endregion Utilities
+
+ //#region Custom wrappers
+ public info(...data: unknown[]) {
+ return this.log(...data);
+ }
+
+ public trace(...data: unknown[]) {
+ if (this.checkBlacklist(data)) {
+ return;
+ }
+
+ // TODO: Figure out how to add color to the full trace text
+ this.console.trace(...this.format(chalk.hex(TRACE_COLOR), data));
+ }
+
+ public debug(...data: unknown[]) {
+ if (this.checkBlacklist(data)) {
+ return;
+ }
+
+ this.console.debug(...this.format(chalk.hex(DEBUG_COLOR), data));
+ }
+
+ public log(...data: unknown[]): void {
+ if (this.checkBlacklist(data)) {
+ return;
+ }
+
+ let formatter: ChalkInstance | undefined;
+
+ if (data.some(d => typeof d === "string" && d.includes("color:"))) {
+ // Infer the color format from the arguments, then remove everything but the message.
+ formatter = inferColorFormat(data as [string, ...unknown[]]);
+ data.splice(1);
+ } else if (data[0] === "[UI]") {
+ // Cyan for UI debug messages
+ formatter = chalk.hex(UI_MSG_COLOR);
+ } else if (typeof data[0] === "string" && data[0].startsWith("=====")) {
+ // Orange logging for "New Turn"/etc messages
+ formatter = chalk.hex(NEW_TURN_COLOR);
+ }
+
+ this.console.log(...this.format(formatter, data));
+ }
+
+ public warn(...data: unknown[]) {
+ if (this.checkBlacklist(data)) {
+ return;
+ }
+
+ this.console.warn(...this.format(chalk.yellow, data));
+ }
+
+ public error(...data: unknown[]) {
+ if (this.checkBlacklist(data)) {
+ return;
+ }
+
+ this.console.error(...this.format(chalk.redBright, data));
+ }
+
+ //#endregion Custom Wrappers
+
+ //#region Copy-pasted Console code
+ // TODO: Progressively add proper coloration and support for all these methods
+ public dir(...args: Parameters<(typeof console)["dir"]>): ReturnType<(typeof console)["dir"]> {
+ return this.console.dir(...args);
+ }
+ public dirxml(...args: Parameters<(typeof console)["dirxml"]>): ReturnType<(typeof console)["dirxml"]> {
+ return this.console.dirxml(...args);
+ }
+ public table(...args: Parameters<(typeof console)["table"]>): ReturnType<(typeof console)["table"]> {
+ return this.console.table(...args);
+ }
+ public group(...args: Parameters<(typeof console)["group"]>): ReturnType<(typeof console)["group"]> {
+ return this.console.group(...args);
+ }
+ public groupCollapsed(
+ ...args: Parameters<(typeof console)["groupCollapsed"]>
+ ): ReturnType<(typeof console)["groupCollapsed"]> {
+ return this.console.groupCollapsed(...args);
+ }
+ public groupEnd(...args: Parameters<(typeof console)["groupEnd"]>): ReturnType<(typeof console)["groupEnd"]> {
+ return this.console.groupEnd(...args);
+ }
+ public clear(...args: Parameters<(typeof console)["clear"]>): ReturnType<(typeof console)["clear"]> {
+ return this.console.clear(...args);
+ }
+ public count(...args: Parameters<(typeof console)["count"]>): ReturnType<(typeof console)["count"]> {
+ return this.console.count(...args);
+ }
+ public countReset(...args: Parameters<(typeof console)["countReset"]>): ReturnType<(typeof console)["countReset"]> {
+ return this.console.countReset(...args);
+ }
+ public assert(...args: Parameters<(typeof console)["assert"]>): ReturnType<(typeof console)["assert"]> {
+ return this.console.assert(...args);
+ }
+ public profile(...args: Parameters<(typeof console)["profile"]>): ReturnType<(typeof console)["profile"]> {
+ return this.console.profile(...args);
+ }
+ public profileEnd(...args: Parameters<(typeof console)["profileEnd"]>): ReturnType<(typeof console)["profileEnd"]> {
+ return this.console.profileEnd(...args);
+ }
+ public time(...args: Parameters<(typeof console)["time"]>): ReturnType<(typeof console)["time"]> {
+ return this.console.time(...args);
+ }
+ public timeLog(...args: Parameters<(typeof console)["timeLog"]>): ReturnType<(typeof console)["timeLog"]> {
+ return this.console.timeLog(...args);
+ }
+ public timeEnd(...args: Parameters<(typeof console)["timeEnd"]>): ReturnType<(typeof console)["timeEnd"]> {
+ return this.console.timeEnd(...args);
+ }
+ public timeStamp(...args: Parameters<(typeof console)["timeStamp"]>): ReturnType<(typeof console)["timeStamp"]> {
+ return this.console.timeStamp(...args);
+ }
+ //#endregion Copy-pasted Console code
+}
diff --git a/test/test-utils/mocks/mock-timed-event-manager.ts b/test/test-utils/mocks/mock-timed-event-manager.ts
index b6c84876783..4f3de90d9a0 100644
--- a/test/test-utils/mocks/mock-timed-event-manager.ts
+++ b/test/test-utils/mocks/mock-timed-event-manager.ts
@@ -3,8 +3,9 @@ import { CLASSIC_CANDY_FRIENDSHIP_MULTIPLIER } from "#balance/starters";
/** Mock TimedEventManager so that ongoing events don't impact tests */
export class MockTimedEventManager extends TimedEventManager {
- override activeEvent() {
- return undefined;
+ // biome-ignore lint/nursery/noUselessUndefined: Changes return type to void instead of undefined
+ override activeEvent(): undefined {
+ return;
}
override isEventActive(): boolean {
return false;
diff --git a/test/test-utils/mocks/mocks-container/mock-text.ts b/test/test-utils/mocks/mocks-container/mock-text.ts
index ad2fce80972..1216597fbe0 100644
--- a/test/test-utils/mocks/mocks-container/mock-text.ts
+++ b/test/test-utils/mocks/mocks-container/mock-text.ts
@@ -1,4 +1,5 @@
import type { MockGameObject } from "#test/test-utils/mocks/mock-game-object";
+import type { TextInterceptor } from "#test/test-utils/text-interceptor";
import { UI } from "#ui/ui";
export class MockText implements MockGameObject {
@@ -53,13 +54,11 @@ export class MockText implements MockGameObject {
wordWidthWithSpace += whiteSpaceWidth;
}
- if (wordWidthWithSpace > spaceLeft) {
- // Skip printing the newline if it's the first word of the line that is greater
- // than the word wrap width.
- if (j > 0) {
- result += "\n";
- spaceLeft = this.wordWrapWidth;
- }
+ // Skip printing the newline if it's the first word of the line that is greater
+ // than the word wrap width.
+ if (wordWidthWithSpace > spaceLeft && j > 0) {
+ result += "\n";
+ spaceLeft = this.wordWrapWidth;
}
result += word;
@@ -82,13 +81,14 @@ export class MockText implements MockGameObject {
showText(
text: string,
- delay?: number | null,
+ _delay?: number | null,
callback?: Function | null,
- callbackDelay?: number | null,
- prompt?: boolean | null,
- promptDelay?: number | null,
+ _callbackDelay?: number | null,
+ _prompt?: boolean | null,
+ _promptDelay?: number | null,
) {
- this.scene.messageWrapper.showText(text, delay, callback, callbackDelay, prompt, promptDelay);
+ // TODO: this is a very bad way to pass calls around
+ (this.scene.messageWrapper as TextInterceptor).showText(text);
if (callback) {
callback();
}
@@ -96,13 +96,13 @@ export class MockText implements MockGameObject {
showDialogue(
keyOrText: string,
- name: string | undefined,
- delay: number | null = 0,
+ name: string,
+ _delay: number | null,
callback: Function,
- callbackDelay?: number,
- promptDelay?: number,
+ _callbackDelay?: number,
+ _promptDelay?: number,
) {
- this.scene.messageWrapper.showDialogue(keyOrText, name, delay, callback, callbackDelay, promptDelay);
+ (this.scene.messageWrapper as TextInterceptor).showDialogue(keyOrText, name);
if (callback) {
callback();
}
diff --git a/test/test-utils/phase-interceptor.ts b/test/test-utils/phase-interceptor.ts
index cc8d9b8e32a..4ac5e1150e5 100644
--- a/test/test-utils/phase-interceptor.ts
+++ b/test/test-utils/phase-interceptor.ts
@@ -1,6 +1,7 @@
import type { BattleScene } from "#app/battle-scene";
import { Phase } from "#app/phase";
import { UiMode } from "#enums/ui-mode";
+import { AttemptCapturePhase } from "#phases/attempt-capture-phase";
import { AttemptRunPhase } from "#phases/attempt-run-phase";
import { BattleEndPhase } from "#phases/battle-end-phase";
import { BerryPhase } from "#phases/berry-phase";
@@ -66,7 +67,7 @@ import { UnlockPhase } from "#phases/unlock-phase";
import { VictoryPhase } from "#phases/victory-phase";
import { ErrorInterceptor } from "#test/test-utils/error-interceptor";
import type { PhaseClass, PhaseString } from "#types/phase-types";
-import type { AwaitableUiHandler } from "#ui/awaitable-ui-handler";
+import type { AwaitableUiHandler } from "#ui/handlers/awaitable-ui-handler";
import { UI } from "#ui/ui";
export interface PromptHandler {
@@ -183,6 +184,7 @@ export class PhaseInterceptor {
PostGameOverPhase,
RevivalBlessingPhase,
PokemonHealPhase,
+ AttemptCapturePhase,
];
private endBySetMode = [
@@ -235,7 +237,7 @@ export class PhaseInterceptor {
ErrorInterceptor.getInstance().add(this);
const targetName = typeof phaseTo === "string" ? phaseTo : phaseTo.name;
this.intervalRun = setInterval(async () => {
- const currentPhase = this.onHold?.length && this.onHold[0];
+ const currentPhase = this.onHold?.length > 0 && this.onHold[0];
if (!currentPhase) {
// No current phase means the manager either hasn't started yet
// or we were interrupted by prompt; wait for phase to finish
@@ -380,7 +382,7 @@ export class PhaseInterceptor {
*/
startPromptHandler() {
this.promptInterval = setInterval(() => {
- if (this.prompts.length) {
+ if (this.prompts.length > 0) {
const actionForNextPrompt = this.prompts[0];
const expireFn = actionForNextPrompt.expireFn?.();
const currentMode = this.scene.ui.getMode();
@@ -389,11 +391,12 @@ export class PhaseInterceptor {
if (expireFn) {
this.prompts.shift();
} else if (
- currentMode === actionForNextPrompt.mode &&
- currentPhase === actionForNextPrompt.phaseTarget &&
- currentHandler.active &&
- (!actionForNextPrompt.awaitingActionInput ||
- (actionForNextPrompt.awaitingActionInput && (currentHandler as AwaitableUiHandler)["awaitingActionInput"]))
+ currentMode === actionForNextPrompt.mode
+ && currentPhase === actionForNextPrompt.phaseTarget
+ && currentHandler.active
+ && (!actionForNextPrompt.awaitingActionInput
+ || (actionForNextPrompt.awaitingActionInput
+ && (currentHandler as AwaitableUiHandler)["awaitingActionInput"]))
) {
const prompt = this.prompts.shift();
if (prompt?.callback) {
diff --git a/test/test-utils/reporters/custom-default-reporter.ts b/test/test-utils/reporters/custom-default-reporter.ts
new file mode 100644
index 00000000000..15c4881b83c
--- /dev/null
+++ b/test/test-utils/reporters/custom-default-reporter.ts
@@ -0,0 +1,62 @@
+import { relative } from "node:path";
+import { parseStacktrace } from "@vitest/utils/source-map";
+import chalk from "chalk";
+import type { UserConsoleLog } from "vitest";
+import type { TestState } from "vitest/node";
+import { DefaultReporter } from "vitest/reporters";
+
+/**
+ * Custom Vitest reporter to strip the current file names from the output.
+ */
+export default class CustomDefaultReporter extends DefaultReporter {
+ public override onUserConsoleLog(log: UserConsoleLog, taskState?: TestState): void {
+ // This code is more or less copied verbatim from `vitest/reporters` source, with minor tweaks to use
+ // dependencies we actually _have_ (i.e. chalk) rather than ones we don't (i.e. tinyrainbow).
+
+ // SPDX-SnippetBegin
+ // SPDX-SnippetCopyrightText: 2021 VoidZero Inc. and Vitest contributors
+ // SPDX-License-Identifier: MIT
+
+ if (!super.shouldLog(log, taskState)) {
+ return;
+ }
+
+ const output = log.type === "stdout" ? this.ctx.logger.outputStream : this.ctx.logger.errorStream;
+
+ const write = (msg: string) => output.write(msg);
+
+ const task = log.taskId ? this.ctx.state.idMap.get(log.taskId) : undefined;
+
+ write(log.content); // this is about the only changed line (that and us skipping a newline)
+
+ if (!log.origin) {
+ return;
+ }
+
+ // Code for stack trace, ripped directly out of Vitest source code.
+ // I wish they had a helper function to do this so we didn't have to import `@vitest/utils`, but oh well...
+ // browser logs don't have an extra end of line at the end like Node.js does
+ if (log.browser) {
+ write("\n");
+ }
+
+ const project = task ? this.ctx.getProjectByName(task.file.projectName ?? "") : this.ctx.getRootProject();
+
+ const stack = log.browser ? (project.browser?.parseStacktrace(log.origin) ?? []) : parseStacktrace(log.origin);
+
+ const highlight = task && stack.find(i => i.file === task.file.filepath);
+
+ for (const frame of stack) {
+ const color = frame === highlight ? chalk.cyan : chalk.gray;
+ const path = relative(project.config.root, frame.file);
+
+ const positions = [frame.method, `${path}:${chalk.dim(`${frame.line}:${frame.column}`)}`]
+ .filter(Boolean)
+ .join(" ");
+
+ write(color(` ${chalk.dim(">")} ${positions}\n`));
+ }
+
+ // SPDX-SnippetEnd
+ }
+}
diff --git a/test/test-utils/setup/test-end-log.ts b/test/test-utils/setup/test-end-log.ts
new file mode 100644
index 00000000000..9814ba8a45c
--- /dev/null
+++ b/test/test-utils/setup/test-end-log.ts
@@ -0,0 +1,113 @@
+// biome-ignore lint/correctness/noUnusedImports: TSDoc
+import type CustomDefaultReporter from "#test/test-utils/reporters/custom-default-reporter";
+import { basename, join, relative } from "path";
+import chalk from "chalk";
+import type { RunnerTask, RunnerTaskResult, RunnerTestCase } from "vitest";
+
+/**
+ * @module
+ * Code to add markers to the beginning and end of tests.
+ * Intended for use with {@linkcode CustomDefaultReporter}, and placed inside test hooks
+ * (rather than as part of the reporter) to ensure Vitest waits for the log messages to be printed.
+ */
+
+/** A long string of "="s to partition off each test from one another. */
+const TEST_END_BARRIER = chalk.bold.hex("#ff7c7cff")("==================");
+
+// Colors used for Vitest-related test utils
+const TEST_NAME_COLOR = "#008886ff" as const;
+const VITEST_PINK_COLOR = "#c162de" as const;
+
+const testRoot = join(import.meta.dirname, "..", "..", "..");
+
+/**
+ * Log the testfile name and path upon a case starting. \
+ * Used to compensate for us overridding the global Console object and removing Vitest's
+ * test name annotations.
+ * @param test - The {@linkcode RunnerTask} passed from the context
+ */
+export function logTestStart(test: RunnerTask): void {
+ console.log(TEST_END_BARRIER);
+ console.log(
+ `${chalk.dim("> ")}${chalk.hex(VITEST_PINK_COLOR)("Starting test: ")}${chalk.hex(TEST_NAME_COLOR)(getTestName(test))}`,
+ );
+}
+
+/**
+ * Log the testfile name, path and result upon a case ending. \
+ * Used to compensate for us overridding the global Console object and removing Vitest's
+ * test name annotations.
+ * @param task - The {@linkcode RunnerTestCase} passed from the hook
+ */
+export function logTestEnd(task: RunnerTestCase): void {
+ const durationStr = getDurationPrefix(task.result);
+ const resultStr = getResultStr(task.result);
+ console.log(`${chalk.dim("> ")}${chalk.black.bgHex(VITEST_PINK_COLOR)(" Test finished! ")}
+ Name: ${chalk.hex(TEST_NAME_COLOR)(getTestName(task))}
+ Result: ${resultStr}${durationStr}
+ File: ${chalk.hex("#d29b0eff")(
+ getPathFromTest(task.file.filepath) + (task.location ? `:${task.location.line}:${task.location.column}` : ""),
+ )}`);
+}
+
+/**
+ * Get the path of the current test file relative to the `test` directory.
+ * @param abs - The absolute path to the file
+ * @returns The relative path with `test/` appended to it.
+ */
+function getPathFromTest(abs: string): string {
+ return join(basename(testRoot), relative(testRoot, abs));
+}
+
+function getResultStr(result: RunnerTaskResult | undefined): string {
+ if (result?.state !== "pass" && result?.state !== "fail") {
+ return "Unknown";
+ }
+
+ const resultStr =
+ result.state === "pass"
+ ? chalk.green.bold("✔ Passed")
+ : (result?.duration ?? 0) > 2
+ ? chalk.cyan.bold("◴ Timed out")
+ : chalk.red.bold("✗ Failed");
+
+ return resultStr;
+}
+
+/**
+ * Get the text to be displayed for a test's duration.
+ * @param result - The {@linkcode RunnerTaskResult} of the finished test
+ * @returns An appropriately colored suffix for the start time.
+ * Will return an empty string if `result.startTime` is `undefined`
+ */
+function getDurationPrefix(result?: RunnerTaskResult): string {
+ const startTime = result?.startTime;
+ if (!startTime) {
+ return "";
+ }
+ const duration = Math.round(Date.now() - startTime);
+
+ // TODO: Figure out a way to access the current vitest config from a hook
+ const color = duration > 10_000 ? chalk.yellow : chalk.green;
+ return ` ${chalk.dim("in")} ${color(duration)}${chalk.dim("ms")}`;
+}
+
+// Function copied from vitest source to avoid having to import `@vitest/runner/utils` for 1 function
+
+// SPDX-SnippetBegin
+// SPDX-SnippetCopyrightText: 2021 VoidZero Inc. and Vitest contributors
+// SPDX-License-Identifier: MIT
+function getTestName(task: RunnerTask, separator = " > "): string {
+ const names: string[] = [task.name];
+ let current: RunnerTask | undefined = task;
+
+ while ((current = current?.suite)) {
+ if (current?.name) {
+ names.unshift(current.name);
+ }
+ }
+
+ return names.join(separator);
+}
+
+// SPDX-SnippetEnd
diff --git a/test/test-utils/test-file-initialization.ts b/test/test-utils/test-file-initialization.ts
index 631d3f9146b..c172e2d1da8 100644
--- a/test/test-utils/test-file-initialization.ts
+++ b/test/test-utils/test-file-initialization.ts
@@ -3,7 +3,7 @@ import { initializeGame } from "#app/init/init";
import { initI18n } from "#plugins/i18n";
import { blobToString } from "#test/test-utils/game-manager-utils";
import { manageListeners } from "#test/test-utils/listeners-manager";
-import { MockConsoleLog } from "#test/test-utils/mocks/mock-console-log";
+import { MockConsole } from "#test/test-utils/mocks/mock-console/mock-console";
import { mockContext } from "#test/test-utils/mocks/mock-context-canvas";
import { mockLocalStorage } from "#test/test-utils/mocks/mock-local-storage";
import { MockImage } from "#test/test-utils/mocks/mocks-container/mock-image";
@@ -38,14 +38,22 @@ function initTestFile(): void {
/**
* Setup various stubs for testing.
* @todo Move this into a dedicated stub file instead of running it once per test instance
+ * @todo review these to see which are actually necessary
* @todo Investigate why this resets on new test suite start
*/
function setupStubs(): void {
- Object.defineProperty(window, "localStorage", {
- value: mockLocalStorage(),
- });
- Object.defineProperty(window, "console", {
- value: new MockConsoleLog(false),
+ Object.defineProperties(global, {
+ localStorage: {
+ value: mockLocalStorage(),
+ },
+ console: {
+ value: new MockConsole(),
+ },
+ matchMedia: {
+ value: () => ({
+ matches: false,
+ }),
+ },
});
Object.defineProperty(document, "fonts", {
writable: true,
@@ -69,11 +77,6 @@ function setupStubs(): void {
navigator.getGamepads = () => [];
setCookie(SESSION_ID_COOKIE_NAME, "fake_token");
- window.matchMedia = () =>
- ({
- matches: false,
- }) as any;
-
/**
* Sets this object's position relative to another object with a given offset
* @param guideObject - The {@linkcode Phaser.GameObjects.GameObject} to base the position off of
diff --git a/test/test-utils/text-interceptor.ts b/test/test-utils/text-interceptor.ts
index 36a5db4c78d..dfbaf2ff11c 100644
--- a/test/test-utils/text-interceptor.ts
+++ b/test/test-utils/text-interceptor.ts
@@ -1,39 +1,49 @@
+import type { BattleScene } from "#app/battle-scene";
+import chalk from "chalk";
+
/**
- * Class will intercept any text or dialogue message calls and log them for test purposes
+ * The {@linkcode TextInterceptor} is a wrapper class that intercepts and logs any messages
+ * that would be displayed on-screen.
*/
export class TextInterceptor {
- private scene;
- public logs: string[] = [];
- constructor(scene) {
- this.scene = scene;
+ /** A log containing messages having been displayed on screen, sorted in FIFO order. */
+ public readonly logs: string[] = [];
+
+ constructor(scene: BattleScene) {
+ // @ts-expect-error: Find another more sanitary way of doing this
scene.messageWrapper = this;
}
- showText(
- text: string,
- _delay?: number,
- _callback?: Function,
- _callbackDelay?: number,
- _prompt?: boolean,
- _promptDelay?: number,
- ): void {
- console.log(text);
+ /** Clear the current content of the TextInterceptor. */
+ public clearLogs(): void {
+ this.logs.splice(0);
+ }
+
+ showText(text: string): void {
+ // NB: We do not format the raw _logs_ themselves as tests will be actively checking it.
+ console.log(this.formatText(text));
this.logs.push(text);
}
- showDialogue(
- text: string,
- name: string,
- _delay?: number,
- _callback?: Function,
- _callbackDelay?: number,
- _promptDelay?: number,
- ): void {
- console.log(name, text);
+ showDialogue(text: string, name: string): void {
+ console.log(`${name}: \n${this.formatText(text)}`);
this.logs.push(name, text);
}
- getLatestMessage(): string {
- return this.logs.pop() ?? "";
+ /**
+ * Format text to be displayed to the test console, as follows:
+ * 1. Replaces new lines and new text boxes (marked by `$`) with indented new lines.
+ * 2. Removes all `@c{}`, `@d{}`, `@s{}`, and `@f{}` flags from the text.
+ * 3. Makes text blue
+ * @param text - The unformatted text
+ * @returns The formatted text
+ */
+ private formatText(text: string): string {
+ return chalk.blue(
+ text
+ .replace(/\n/g, " ")
+ .replace(/\$/g, "\n ")
+ .replace(/@\w{.*?}/g, ""),
+ );
}
}
diff --git a/test/ui/item-manage-button.test.ts b/test/ui/item-manage-button.test.ts
index c28cd9e802e..b5c24776e7b 100644
--- a/test/ui/item-manage-button.test.ts
+++ b/test/ui/item-manage-button.test.ts
@@ -5,8 +5,8 @@ import { SpeciesId } from "#enums/species-id";
import { UiMode } from "#enums/ui-mode";
import type { Pokemon } from "#field/pokemon";
import { GameManager } from "#test/test-utils/game-manager";
-import type { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
-import { type PartyUiHandler, PartyUiMode } from "#ui/party-ui-handler";
+import type { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler";
+import { type PartyUiHandler, PartyUiMode } from "#ui/handlers/party-ui-handler";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
diff --git a/test/ui/pokedex.test.ts b/test/ui/pokedex.test.ts
index edd9fa879d0..47463fa1aab 100644
--- a/test/ui/pokedex.test.ts
+++ b/test/ui/pokedex.test.ts
@@ -8,9 +8,9 @@ import { SpeciesId } from "#enums/species-id";
import { UiMode } from "#enums/ui-mode";
import type { StarterAttributes } from "#system/game-data";
import { GameManager } from "#test/test-utils/game-manager";
-import { FilterTextRow } from "#ui/filter-text";
-import { PokedexPageUiHandler } from "#ui/pokedex-page-ui-handler";
-import { PokedexUiHandler } from "#ui/pokedex-ui-handler";
+import { FilterTextRow } from "#ui/containers/filter-text";
+import { PokedexPageUiHandler } from "#ui/containers/pokedex-page-ui-handler";
+import { PokedexUiHandler } from "#ui/handlers/pokedex-ui-handler";
import { getPokemonSpecies } from "#utils/pokemon-utils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
@@ -106,8 +106,8 @@ describe("UI - Pokedex", () => {
const speciesSet = new Set();
for (const pkmn of allSpecies) {
if (
- [pkmn.ability1, pkmn.ability2, pkmn.getPassiveAbility(), pkmn.abilityHidden].includes(ability) ||
- pkmn.forms.some(form =>
+ [pkmn.ability1, pkmn.ability2, pkmn.getPassiveAbility(), pkmn.abilityHidden].includes(ability)
+ || pkmn.forms.some(form =>
[form.ability1, form.ability2, form.abilityHidden, form.getPassiveAbility()].includes(ability),
)
) {
diff --git a/test/ui/starter-select.test.ts b/test/ui/starter-select.test.ts
index 397f3d6086f..2f575b72a5c 100644
--- a/test/ui/starter-select.test.ts
+++ b/test/ui/starter-select.test.ts
@@ -8,10 +8,10 @@ import { SpeciesId } from "#enums/species-id";
import { UiMode } from "#enums/ui-mode";
import type { TitlePhase } from "#phases/title-phase";
import { GameManager } from "#test/test-utils/game-manager";
-import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
+import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler";
+import type { SaveSlotSelectUiHandler } from "#ui/handlers/save-slot-select-ui-handler";
+import type { StarterSelectUiHandler } from "#ui/handlers/starter-select-ui-handler";
import type { OptionSelectUiHandler } from "#ui/option-select-ui-handler";
-import type { SaveSlotSelectUiHandler } from "#ui/save-slot-select-ui-handler";
-import type { StarterSelectUiHandler } from "#ui/starter-select-ui-handler";
import i18next from "i18next";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
diff --git a/test/ui/transfer-item-options.test.ts b/test/ui/transfer-item-options.test.ts
index 901aa261f50..7e9c1b5e36b 100644
--- a/test/ui/transfer-item-options.test.ts
+++ b/test/ui/transfer-item-options.test.ts
@@ -4,8 +4,8 @@ import { MoveId } from "#enums/move-id";
import { SpeciesId } from "#enums/species-id";
import { UiMode } from "#enums/ui-mode";
import { GameManager } from "#test/test-utils/game-manager";
-import { type PartyUiHandler, PartyUiMode } from "#ui/party-ui-handler";
-import type { RenameFormUiHandler } from "#ui/rename-form-ui-handler";
+import { type PartyUiHandler, PartyUiMode } from "#ui/handlers/party-ui-handler";
+import type { RenameFormUiHandler } from "#ui/handlers/rename-form-ui-handler";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
diff --git a/test/ui/transfer-item.test.ts b/test/ui/transfer-item.test.ts
index 8e42149acc3..67a21b0656d 100644
--- a/test/ui/transfer-item.test.ts
+++ b/test/ui/transfer-item.test.ts
@@ -4,8 +4,8 @@ import { MoveId } from "#enums/move-id";
import { SpeciesId } from "#enums/species-id";
import { UiMode } from "#enums/ui-mode";
import { GameManager } from "#test/test-utils/game-manager";
-import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
-import { PartyUiHandler, PartyUiMode } from "#ui/party-ui-handler";
+import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler";
+import { PartyUiHandler, PartyUiMode } from "#ui/handlers/party-ui-handler";
import Phaser from "phaser";
import type BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
@@ -70,7 +70,9 @@ describe("UI - Transfer Items", () => {
handler.optionsContainer.list.some(option => (option as BBCodeText).text?.includes("Apicot Berry (2)")),
).toBe(true);
expect(
- handler.optionsContainer.list.some(option => RegExp(/Lum Berry\[color.*(2)/).exec((option as BBCodeText).text)),
+ handler.optionsContainer.list.some(option =>
+ new RegExp(/Lum Berry\[color.*(2)/).exec((option as BBCodeText).text),
+ ),
).toBe(true);
});
diff --git a/test/ui/type-hints.test.ts b/test/ui/type-hints.test.ts
index b5fe0d9585a..56891e22c2a 100644
--- a/test/ui/type-hints.test.ts
+++ b/test/ui/type-hints.test.ts
@@ -4,7 +4,7 @@ import { SpeciesId } from "#enums/species-id";
import { UiMode } from "#enums/ui-mode";
import { GameManager } from "#test/test-utils/game-manager";
import type { MockText } from "#test/test-utils/mocks/mocks-container/mock-text";
-import { FightUiHandler } from "#ui/fight-ui-handler";
+import { FightUiHandler } from "#ui/handlers/fight-ui-handler";
import i18next from "i18next";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
diff --git a/test/vitest.setup.ts b/test/vitest.setup.ts
index be35e18e2e9..23adab01a05 100644
--- a/test/vitest.setup.ts
+++ b/test/vitest.setup.ts
@@ -1,16 +1,21 @@
import "vitest-canvas-mock";
+import { MockConsole } from "#test/test-utils/mocks/mock-console/mock-console";
+import { logTestEnd, logTestStart } from "#test/test-utils/setup/test-end-log";
import { initTests } from "#test/test-utils/test-file-initialization";
-import { afterAll, beforeAll, vi } from "vitest";
+import chalk from "chalk";
+import { afterAll, afterEach, beforeAll, beforeEach, vi } from "vitest";
-/** Set the timezone to UTC for tests. */
+//#region Mocking
-/** Mock the override import to always return default values, ignoring any custom overrides. */
-vi.mock("#app/overrides", async importOriginal => {
- const { defaultOverrides } = await importOriginal();
+// Mock the override import to always return default values, ignoring any custom overrides.
+vi.mock(import("#app/overrides"), async importOriginal => {
+ const { defaultOverrides } = await importOriginal();
return {
default: defaultOverrides,
- defaultOverrides,
+ // Export `defaultOverrides` as a *copy*.
+ // This ensures we can easily reset `overrides` back to its default values after modifying it.
+ defaultOverrides: { ...defaultOverrides },
} satisfies typeof import("#app/overrides");
});
@@ -20,7 +25,7 @@ vi.mock("#app/overrides", async importOriginal => {
* This is necessary because how our code is structured.
* Do NOT try to put any of this code into external functions, it won't work as it's elevated during runtime.
*/
-vi.mock("i18next", async importOriginal => {
+vi.mock(import("i18next"), async importOriginal => {
console.log("Mocking i18next");
const { setupServer } = await import("msw/node");
const { http, HttpResponse } = await import("msw");
@@ -30,8 +35,11 @@ vi.mock("i18next", async importOriginal => {
const filename = req.params[0];
try {
- const json = await import(`../public/locales/en/${req.params[0]}`);
- console.log("Loaded locale", filename);
+ const localeFiles = import.meta.glob("../public/locales/en/**/*.json", { eager: true });
+ const json = localeFiles[`../public/locales/en/${filename}`] || {};
+ if (import.meta.env.VITE_I18N_DEBUG === "1") {
+ console.log("Loaded locale", filename);
+ }
return HttpResponse.json(json);
} catch (err) {
console.log(`Failed to load locale ${filename}!`, err);
@@ -54,7 +62,15 @@ beforeAll(() => {
initTests();
});
+beforeEach(context => {
+ logTestStart(context.task);
+});
+afterEach(context => {
+ logTestEnd(context.task);
+});
+
afterAll(() => {
global.server.close();
- console.log("Closing i18n MSW server!");
+ MockConsole.printPostTestWarnings();
+ console.log(chalk.hex("#dfb8d8")("Closing i18n MSW server!"));
});
diff --git a/tsconfig.json b/tsconfig.json
index 8becb4c00ec..7bf82eaaca0 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -18,47 +18,47 @@
"esModuleInterop": true,
"strictNullChecks": true,
"sourceMap": false,
- "checkJs": true,
"strict": false, // TODO: Enable this eventually
"rootDir": ".",
- "baseUrl": "./src",
- "paths": {
- "#abilities/*": ["./data/abilities/*.ts"],
- "#api/*": ["./plugins/api/*.ts"],
- "#balance/*": ["./data/balance/*.ts"],
- "#enums/*": ["./enums/*.ts"],
- "#events/*": ["./events/*.ts"],
- "#field/*": ["./field/*.ts"],
- "#inputs/*": ["./configs/inputs/*.ts"],
- "#modifiers/*": ["./modifier/*.ts"],
- "#moves/*": ["./data/moves/*.ts"],
- "#mystery-encounters/*": [
- "./data/mystery-encounters/utils/*.ts",
- "./data/mystery-encounters/encounters/*.ts",
- "./data/mystery-encounters/requirements/*.ts",
- "./data/mystery-encounters/*.ts"
- ],
- "#package.json": ["../package.json"],
- "#phases/*": ["./phases/*.ts"],
- "#plugins/*": ["./plugins/vite/*.ts", "./plugins/*.ts"],
- "#sprites/*": ["./sprites/*.ts"],
- "#system/*": [
- "./system/settings/*.ts",
- "./system/version-migration/versions/*.ts",
- "./system/version-migration/*.ts",
- "./system/*.ts"
- ],
- "#trainers/*": ["./data/trainers/*.ts"],
- "#types/*": ["./@types/helpers/*.ts", "./@types/*.ts", "./typings/phaser/*.ts"],
- "#ui/*": ["./ui/battle-info/*.ts", "./ui/settings/*.ts", "./ui/*.ts"],
- "#utils/*": ["./utils/*.ts"],
- "#data/*": ["./data/pokemon-forms/*.ts", "./data/pokemon/*.ts", "./data/*.ts"],
- "#test/*": ["../test/*.ts"],
- "#app/*": ["*.ts"]
- },
"outDir": "./build",
- "noEmit": true
+ "noEmit": true,
+ "paths": {
+ "#abilities/*": ["./src/data/abilities/*.ts"],
+ "#api/*": ["./src/plugins/api/*.ts"],
+ "#balance/*": ["./src/data/balance/*.ts"],
+ "#enums/*": ["./src/enums/*.ts"],
+ "#events/*": ["./src/events/*.ts"],
+ "#field/*": ["./src/field/*.ts"],
+ "#inputs/*": ["./src/configs/inputs/*.ts"],
+ "#modifiers/*": ["./src/modifier/*.ts"],
+ "#moves/*": ["./src/data/moves/*.ts"],
+ "#mystery-encounters/*": [
+ "./src/data/mystery-encounters/utils/*.ts",
+ "./src/data/mystery-encounters/encounters/*.ts",
+ "./src/data/mystery-encounters/requirements/*.ts",
+ "./src/data/mystery-encounters/*.ts"
+ ],
+ "#package.json": ["./package.json"],
+ "#phases/*": ["./src/phases/*.ts"],
+ "#plugins/*": ["./src/plugins/vite/*.ts", "./src/plugins/*.ts"],
+ "#sprites/*": ["./src/sprites/*.ts"],
+ "#system/*": [
+ "./src/system/settings/*.ts",
+ "./src/system/version-migration/versions/*.ts",
+ "./src/system/version-migration/*.ts",
+ "./src/system/*.ts"
+ ],
+ "#trainers/*": ["./src/data/trainers/*.ts"],
+ "#types/*": ["./src/@types/helpers/*.ts", "./src/@types/*.ts", "./src/typings/phaser/*.ts"],
+ "#ui/*": ["./src/ui/battle-info/*.ts", "./src/ui/settings/*.ts", "./src/ui/*.ts"],
+ "#utils/*": ["./src/utils/*.ts"],
+ "#data/*": ["./src/data/pokemon-forms/*.ts", "./src/data/pokemon/*.ts", "./src/data/*.ts"],
+ "#test/*": ["./test/*.ts"],
+ "#app/*": ["./src/*.ts"]
+ }
},
+ // Exclude checking for script JS files as those are covered by the folder's `jsconfig.json`
+ "include": ["**/*.ts", "**/*.d.ts"],
"exclude": [
"node_modules",
"dist",
diff --git a/typedoc-plugins/typedoc-plugin-rename-svg.js b/typedoc-plugins/typedoc-plugin-rename-svg.js
index 5fda4ee3c6d..307206d6006 100644
--- a/typedoc-plugins/typedoc-plugin-rename-svg.js
+++ b/typedoc-plugins/typedoc-plugin-rename-svg.js
@@ -19,15 +19,10 @@ export function load(app) {
app.renderer.on(Renderer.EVENT_END_PAGE, page => {
if (page.pageKind === PageKind.Index && page.contents) {
page.contents = page.contents
- // Replace links to the beta documentation site with the current ref name
+ // Replace the SVG to the beta documentation site with the current ref name
.replace(
- /href="(.*pagefaultgames.github.io\/pokerogue\/).*?"/, // formatting
- `href="$1/${process.env.REF_NAME}"`,
- )
- // Replace the link to Beta's coverage SVG with the SVG file for the branch in question.
- .replace(
- /img src=".*?coverage.svg/, // formatting
- `img src="coverage.svg"`,
+ /^ ({
+export default defineConfig(({ mode }) => ({
...defaultConfig,
test: {
+ reporters: process.env.GITHUB_ACTIONS
+ ? ["github-actions", "./test/test-utils/reporters/custom-default-reporter.ts"]
+ : ["./test/test-utils/reporters/custom-default-reporter.ts"],
env: {
TZ: "UTC",
},
- testTimeout: 20000,
+ testTimeout: 20_000,
+ slowTestThreshold: 10_000,
+ // TODO: Consider enabling
+ // expect: {requireAssertions: true},
setupFiles: ["./test/font-face.setup.ts", "./test/vitest.setup.ts", "./test/matchers.setup.ts"],
sequence: {
sequencer: MySequencer,
},
+ includeTaskLocation: true,
environment: "jsdom" as const,
environmentOptions: {
jsdom: {