mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-09-23 15:03:24 +02:00
Merge branch 'beta' into no-dummy-RELEASE
This commit is contained in:
commit
0d814f8ce2
@ -5,9 +5,7 @@ module.exports = {
|
|||||||
name: "no-non-type-@type-exports",
|
name: "no-non-type-@type-exports",
|
||||||
severity: "error",
|
severity: "error",
|
||||||
comment:
|
comment:
|
||||||
"Files in @types should not export anything but types and interfaces. " +
|
"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.",
|
||||||
"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: {},
|
from: {},
|
||||||
to: {
|
to: {
|
||||||
path: "(^|/)src/@types",
|
path: "(^|/)src/@types",
|
||||||
@ -29,8 +27,7 @@ module.exports = {
|
|||||||
name: "no-circular-at-runtime",
|
name: "no-circular-at-runtime",
|
||||||
severity: "error",
|
severity: "error",
|
||||||
comment:
|
comment:
|
||||||
"This dependency is part of a circular relationship. You might want to revise " +
|
"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) ",
|
||||||
"your solution (i.e. use dependency inversion, make sure the modules have a single responsibility) ",
|
|
||||||
from: {},
|
from: {},
|
||||||
to: {
|
to: {
|
||||||
circular: true,
|
circular: true,
|
||||||
@ -42,11 +39,7 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
name: "no-orphans",
|
name: "no-orphans",
|
||||||
comment:
|
comment:
|
||||||
"This is an orphan module - it's likely not used (anymore?). Either use it or " +
|
"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.",
|
||||||
"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",
|
severity: "error",
|
||||||
from: {
|
from: {
|
||||||
orphan: true,
|
orphan: true,
|
||||||
@ -63,8 +56,7 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
name: "no-deprecated-core",
|
name: "no-deprecated-core",
|
||||||
comment:
|
comment:
|
||||||
"A module depends on a node core module that has been deprecated. Find an alternative - these are " +
|
"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.",
|
||||||
"bound to exist - node doesn't deprecate lightly.",
|
|
||||||
severity: "error",
|
severity: "error",
|
||||||
from: {},
|
from: {},
|
||||||
to: {
|
to: {
|
||||||
@ -96,8 +88,7 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
name: "not-to-deprecated",
|
name: "not-to-deprecated",
|
||||||
comment:
|
comment:
|
||||||
"This module uses a (version of an) npm module that has been deprecated. Either upgrade to a later " +
|
"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.",
|
||||||
"version of that module, or find an alternative. Deprecated modules are a security risk.",
|
|
||||||
severity: "error",
|
severity: "error",
|
||||||
from: {},
|
from: {},
|
||||||
to: {
|
to: {
|
||||||
@ -108,10 +99,7 @@ module.exports = {
|
|||||||
name: "no-non-package-json",
|
name: "no-non-package-json",
|
||||||
severity: "error",
|
severity: "error",
|
||||||
comment:
|
comment:
|
||||||
"This module depends on an npm package that isn't in the 'dependencies' section of 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.",
|
||||||
"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: {},
|
from: {},
|
||||||
to: {
|
to: {
|
||||||
dependencyTypes: ["npm-no-pkg", "npm-unknown"],
|
dependencyTypes: ["npm-no-pkg", "npm-unknown"],
|
||||||
@ -120,8 +108,7 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
name: "not-to-unresolvable",
|
name: "not-to-unresolvable",
|
||||||
comment:
|
comment:
|
||||||
"This module depends on a module that cannot be found ('resolved to disk'). If it's an npm " +
|
"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.",
|
||||||
"module: add it to your package.json. In all other cases you likely already know what to do.",
|
|
||||||
severity: "error",
|
severity: "error",
|
||||||
from: {},
|
from: {},
|
||||||
to: {
|
to: {
|
||||||
@ -131,9 +118,7 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
name: "no-duplicate-dep-types",
|
name: "no-duplicate-dep-types",
|
||||||
comment:
|
comment:
|
||||||
"Likely this module depends on an external ('npm') package that occurs more than once " +
|
"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.",
|
||||||
"in your package.json i.e. bot as a devDependencies and in dependencies. This will cause " +
|
|
||||||
"maintenance problems later on.",
|
|
||||||
severity: "error",
|
severity: "error",
|
||||||
from: {},
|
from: {},
|
||||||
to: {
|
to: {
|
||||||
@ -150,9 +135,7 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
name: "not-to-spec",
|
name: "not-to-spec",
|
||||||
comment:
|
comment:
|
||||||
"This module depends on a spec (test) file. The sole responsibility of a spec file is to test code. " +
|
"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.",
|
||||||
"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",
|
severity: "error",
|
||||||
from: {},
|
from: {},
|
||||||
to: {
|
to: {
|
||||||
@ -163,11 +146,7 @@ module.exports = {
|
|||||||
name: "not-to-dev-dep",
|
name: "not-to-dev-dep",
|
||||||
severity: "error",
|
severity: "error",
|
||||||
comment:
|
comment:
|
||||||
"This module depends on an npm package from the 'devDependencies' section of your " +
|
"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",
|
||||||
"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: {
|
from: {
|
||||||
path: "^(src)",
|
path: "^(src)",
|
||||||
pathNot: ["[.](?:spec|test|setup|script)[.](?:js|mjs|cjs|jsx|ts|mts|cts|tsx)$", "./test"],
|
pathNot: ["[.](?:spec|test|setup|script)[.](?:js|mjs|cjs|jsx|ts|mts|cts|tsx)$", "./test"],
|
||||||
@ -184,10 +163,7 @@ module.exports = {
|
|||||||
name: "optional-deps-used",
|
name: "optional-deps-used",
|
||||||
severity: "info",
|
severity: "info",
|
||||||
comment:
|
comment:
|
||||||
"This module depends on an npm package that is declared as an optional dependency " +
|
"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.",
|
||||||
"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.",
|
|
||||||
from: {},
|
from: {},
|
||||||
to: {
|
to: {
|
||||||
dependencyTypes: ["npm-optional"],
|
dependencyTypes: ["npm-optional"],
|
||||||
@ -196,10 +172,7 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
name: "peer-deps-used",
|
name: "peer-deps-used",
|
||||||
comment:
|
comment:
|
||||||
"This module depends on an npm package that is declared as a peer dependency " +
|
"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.",
|
||||||
"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",
|
severity: "error",
|
||||||
from: {},
|
from: {},
|
||||||
to: {
|
to: {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
# top-most EditorConfig file
|
# top-most EditorConfig file
|
||||||
root = true
|
root = true
|
||||||
|
|
||||||
[src/*.{js,ts}]
|
[**/*.{js,ts,json,jsonc}]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
end_of_line = lf
|
end_of_line = lf
|
||||||
|
16
.github/workflows/github-pages.yml
vendored
16
.github/workflows/github-pages.yml
vendored
@ -27,20 +27,18 @@ jobs:
|
|||||||
# Only push docs when running on pushes to main/beta
|
# Only push docs when running on pushes to main/beta
|
||||||
DRY_RUN: ${{github.event_name != 'push' || (github.ref_name != 'beta' && github.ref_name != 'main')}}
|
DRY_RUN: ${{github.event_name != 'push' || (github.ref_name != 'beta' && github.ref_name != 'main')}}
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository for Typedoc
|
- name: Checkout repository for Typedoc
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: 'recursive'
|
|
||||||
path: pokerogue_docs
|
path: pokerogue_docs
|
||||||
|
sparse-checkout: |
|
||||||
- name: Install OS package
|
/*
|
||||||
run: |
|
!/public/
|
||||||
sudo apt update
|
/public/images/pokemon/variant/_exp_masterlist.json
|
||||||
sudo apt install -y git openssh-client
|
/public/images/pokemon/variant/_masterlist.json
|
||||||
|
/public/images/logo.png
|
||||||
|
sparse-checkout-cone-mode: false
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v4
|
uses: pnpm/action-setup@v4
|
||||||
|
79
.github/workflows/linting.yml
vendored
79
.github/workflows/linting.yml
vendored
@ -18,7 +18,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
run-linters:
|
run-linters:
|
||||||
name: Run linters
|
name: Run all linters
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
@ -26,27 +26,86 @@ jobs:
|
|||||||
- name: Check out Git repository
|
- name: Check out Git repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: 'recursive'
|
submodules: "recursive"
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v4
|
uses: pnpm/action-setup@v4
|
||||||
with:
|
with:
|
||||||
version: 10
|
version: 10
|
||||||
|
|
||||||
- name: Set up Node.js
|
- name: Set up Node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: ".nvmrc"
|
||||||
cache: 'pnpm'
|
cache: "pnpm"
|
||||||
|
|
||||||
- name: Install Node.js dependencies
|
- name: Install Node modules
|
||||||
run: pnpm i
|
run: pnpm i
|
||||||
|
|
||||||
- name: Lint with Biome
|
# Lint files with Biome-Lint - https://biomejs.dev/linter/
|
||||||
|
- name: Run Biome-Lint
|
||||||
run: pnpm biome-ci
|
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
|
run: pnpm depcruise
|
||||||
|
id: depcruise
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
- name: Lint with ls-lint
|
# Validate types with tsc - https://www.typescriptlang.org/docs/handbook/compiler-options.html#using-the-cli
|
||||||
run: pnpm ls-lint
|
- 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"
|
||||||
|
4
.github/workflows/tests.yml
vendored
4
.github/workflows/tests.yml
vendored
@ -28,6 +28,10 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
sparse-checkout: |
|
||||||
|
.github/test-filters.yml
|
||||||
|
sparse-checkout-cone-mode: false
|
||||||
|
|
||||||
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36
|
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36
|
||||||
id: filter
|
id: filter
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -11,6 +11,7 @@ node_modules
|
|||||||
dist
|
dist
|
||||||
dist-ssr
|
dist-ssr
|
||||||
*.local
|
*.local
|
||||||
|
build
|
||||||
|
|
||||||
# Editor directories and files (excluding `extensions.json` for devcontainer)
|
# Editor directories and files (excluding `extensions.json` for devcontainer)
|
||||||
*.code-workspace
|
*.code-workspace
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<picture><img src="./public/images/logo.png" width="300" alt="PokéRogue"></picture>
|
<div align="center"><picture><img src="./public/images/logo.png" width="300" alt="PokéRogue"></picture>
|
||||||
|
|
||||||
[](https://discord.gg/pokerogue)
|
[](https://discord.gg/pokerogue)
|
||||||
[](https://pagefaultgames.github.io/pokerogue/beta)
|
[](https://pagefaultgames.github.io/pokerogue/beta)
|
||||||
[](https://github.com/pagefaultgames/pokerogue/actions/workflows/tests.yml)
|
[](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)</div>
|
||||||
|
|
||||||
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!
|
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!
|
||||||
|
|
||||||
|
161
biome.jsonc
161
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": {
|
"vcs": {
|
||||||
"enabled": false,
|
"enabled": true,
|
||||||
"clientKind": "git",
|
"clientKind": "git",
|
||||||
"useIgnoreFile": true,
|
"useIgnoreFile": true,
|
||||||
"defaultBranch": "beta"
|
"defaultBranch": "beta"
|
||||||
@ -10,7 +10,7 @@
|
|||||||
"enabled": true,
|
"enabled": true,
|
||||||
"useEditorconfig": true,
|
"useEditorconfig": true,
|
||||||
"indentStyle": "space",
|
"indentStyle": "space",
|
||||||
"includes": ["**", "!**/src/enums/**/*", "!**/src/data/balance/**/*"],
|
"includes": ["**", "!**/src/data/balance/**"],
|
||||||
"lineWidth": 120
|
"lineWidth": 120
|
||||||
},
|
},
|
||||||
"files": {
|
"files": {
|
||||||
@ -19,14 +19,12 @@
|
|||||||
// and having to verify whether each individual file is ignored
|
// and having to verify whether each individual file is ignored
|
||||||
"includes": [
|
"includes": [
|
||||||
"**",
|
"**",
|
||||||
"!**/dist/**/*",
|
"!**/dist",
|
||||||
"!**/build/**/*",
|
"!**/coverage",
|
||||||
"!**/coverage/**/*",
|
"!**/public",
|
||||||
"!**/public/**/*",
|
"!**/.github",
|
||||||
"!**/.github/**/*",
|
"!**/node_modules",
|
||||||
"!**/node_modules/**/*",
|
"!**/typedoc",
|
||||||
"!**/.vscode/**/*",
|
|
||||||
"!**/typedoc/**/*",
|
|
||||||
// TODO: lint css and html?
|
// TODO: lint css and html?
|
||||||
"!**/*.css",
|
"!**/*.css",
|
||||||
"!**/*.html",
|
"!**/*.html",
|
||||||
@ -48,28 +46,75 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// TODO: Remove unneeded `options` blocks once biome's JSON schema is fixed to not require them
|
||||||
"linter": {
|
"linter": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"rules": {
|
"rules": {
|
||||||
"recommended": true,
|
"recommended": true,
|
||||||
"correctness": {
|
"correctness": {
|
||||||
"noUndeclaredVariables": "off",
|
"noUndeclaredVariables": "error",
|
||||||
"noUnusedVariables": "error",
|
"noUnusedVariables": "error",
|
||||||
"noSwitchDeclarations": "error",
|
"noSwitchDeclarations": "error",
|
||||||
"noVoidTypeReturn": "error",
|
"noVoidTypeReturn": "error",
|
||||||
"noUnusedImports": {
|
"noUnusedImports": {
|
||||||
"level": "error",
|
"level": "error",
|
||||||
"fix": "safe"
|
"fix": "safe",
|
||||||
|
"options": {}
|
||||||
},
|
},
|
||||||
"noUnusedFunctionParameters": "error",
|
"noUnusedFunctionParameters": "error",
|
||||||
"noUnusedLabels": "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": {
|
"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": {
|
"useBlockStatements": {
|
||||||
"level": "error",
|
"level": "error",
|
||||||
"fix": "safe"
|
"fix": "safe",
|
||||||
|
"options": {}
|
||||||
},
|
},
|
||||||
"useConst": "error",
|
"useConst": "error",
|
||||||
"useImportType": "error",
|
"useImportType": "error",
|
||||||
@ -80,9 +125,14 @@
|
|||||||
// TODO: Fix spots in the codebase where this flag would be triggered
|
// TODO: Fix spots in the codebase where this flag would be triggered
|
||||||
// and then set to "error" and re-enable the fixer
|
// and then set to "error" and re-enable the fixer
|
||||||
"level": "warn",
|
"level": "warn",
|
||||||
"fix": "none"
|
"fix": "none",
|
||||||
|
"options": {}
|
||||||
|
},
|
||||||
|
"useSingleVarDeclarator": {
|
||||||
|
"level": "error",
|
||||||
|
"fix": "safe",
|
||||||
|
"options": {}
|
||||||
},
|
},
|
||||||
"useSingleVarDeclarator": "off",
|
|
||||||
"useNodejsImportProtocol": "off",
|
"useNodejsImportProtocol": "off",
|
||||||
"useTemplate": "off", // string concatenation is faster: https://stackoverflow.com/questions/29055518/are-es6-template-literals-faster-than-string-concatenation
|
"useTemplate": "off", // string concatenation is faster: https://stackoverflow.com/questions/29055518/are-es6-template-literals-faster-than-string-concatenation
|
||||||
"useAsConstAssertion": "error",
|
"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": {
|
"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",
|
"noDoubleEquals": "error",
|
||||||
// While this would be a nice rule to enable, the current structure of the codebase makes this infeasible
|
// 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.
|
// 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.
|
// This can likely be enabled for all non-utils files once these are eventually reworked, but until then we leave it off.
|
||||||
"noExplicitAny": "off",
|
"noExplicitAny": "off",
|
||||||
"noAssignInExpressions": "off",
|
"noAssignInExpressions": "off",
|
||||||
"noPrototypeBuiltins": "off",
|
"noPrototypeBuiltins": "off", // TODO: enable this
|
||||||
"noFallthroughSwitchClause": "error", // Prevents accidental automatic fallthroughs in switch cases (use disable comment if needed)
|
"noFallthroughSwitchClause": "error", // Prevents accidental automatic fallthroughs in switch cases (use disable comment if needed)
|
||||||
"noImplicitAnyLet": "warn", // TODO: Refactor and make this an error
|
"noImplicitAnyLet": "warn", // TODO: Refactor and make this an error
|
||||||
"noRedeclare": "info", // TODO: Refactor and make this an error
|
"noRedeclare": "info", // TODO: Refactor and make this an error
|
||||||
"noGlobalIsNan": "off",
|
"noGlobalIsNan": "error",
|
||||||
"noAsyncPromiseExecutor": "warn", // TODO: Refactor and make this an error
|
"noAsyncPromiseExecutor": "warn", // TODO: Refactor and make this an error
|
||||||
"noVar": "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": {
|
"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
|
"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.
|
"noForEach": "off", // Foreach vs for of is not that simple.
|
||||||
"noUselessSwitchCase": "off", // Explicit > Implicit
|
"noUselessSwitchCase": "off", // Explicit > Implicit
|
||||||
"noUselessConstructor": "error",
|
"noUselessConstructor": "error",
|
||||||
"noBannedTypes": "warn", // TODO: Refactor and make this an error
|
"noBannedTypes": "warn", // TODO: Refactor and make this an error
|
||||||
"noThisInStatic": "error",
|
"noThisInStatic": "error",
|
||||||
"noUselessThisAlias": "error",
|
"noUselessThisAlias": "error",
|
||||||
"noUselessTernary": "error"
|
"noUselessTernary": "error",
|
||||||
|
"useIndexOf": "error"
|
||||||
},
|
},
|
||||||
"performance": {
|
"performance": {
|
||||||
"noNamespaceImport": "error",
|
"noNamespaceImport": "error",
|
||||||
"noDelete": "error"
|
"noDelete": "error",
|
||||||
|
"noBarrelFile": "error"
|
||||||
},
|
},
|
||||||
"nursery": {
|
"nursery": {
|
||||||
"useAdjacentGetterSetter": "error",
|
"noUselessUndefined": "error",
|
||||||
"noConstantBinaryExpression": "error",
|
"useMaxParams": {
|
||||||
"noTsIgnore": "error",
|
"level": "warn", // TODO: Change to "error"... eventually...
|
||||||
"noAwaitInLoop": "off",
|
"options": { "max": 4 } // A lot of stuff has a few params, but
|
||||||
"useJsonImportAttribute": "off", // "Import attributes are only supported when the '--module' option is set to 'esnext', 'node18', 'nodenext', or 'preserve'. ts(2823)"
|
},
|
||||||
"useIndexOf": "error",
|
"noShadow": "warn", // TODO: refactor and make "error"
|
||||||
"useObjectSpread": "error",
|
"noNonNullAssertedOptionalChain": "warn" // TODO: refactor and make "error"
|
||||||
"useNumericSeparators": "off", // TODO: enable?
|
|
||||||
"useIterableCallbackReturn": "warn", // TODO: refactor and make "error"
|
|
||||||
"noShadow": "warn" // TODO: refactor and make "error"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"javascript": {
|
"javascript": {
|
||||||
"formatter": {
|
"formatter": {
|
||||||
"quoteStyle": "double",
|
"quoteStyle": "double",
|
||||||
"arrowParentheses": "asNeeded"
|
"arrowParentheses": "asNeeded",
|
||||||
|
"operatorLinebreak": "before"
|
||||||
},
|
},
|
||||||
|
"globals": ["Phaser"],
|
||||||
"parser": {
|
"parser": {
|
||||||
"jsxEverywhere": false
|
"jsxEverywhere": false
|
||||||
}
|
}
|
||||||
@ -166,7 +238,7 @@
|
|||||||
"noNamespaceImport": "off" // this is required for `vi.spyOn` to work in some tests
|
"noNamespaceImport": "off" // this is required for `vi.spyOn` to work in some tests
|
||||||
},
|
},
|
||||||
"style": {
|
"style": {
|
||||||
"noNonNullAssertion": "off"
|
"noNonNullAssertion": "off" // tedious in some tests
|
||||||
},
|
},
|
||||||
"nursery": {
|
"nursery": {
|
||||||
"noFloatingPromises": "error"
|
"noFloatingPromises": "error"
|
||||||
@ -175,10 +247,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Overrides to prevent unused import removal inside `overrides.ts` and enums files (for TSDoc linkcodes),
|
// Overrides to prevent unused import removal inside `overrides.ts`, enums & `.d.ts` files (for TSDoc linkcodes),
|
||||||
// as well as in all TS files in `scripts/` (which are assumed to be boilerplate templates).
|
// 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": {
|
"linter": {
|
||||||
"rules": {
|
"rules": {
|
||||||
"correctness": {
|
"correctness": {
|
||||||
@ -188,7 +267,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"includes": ["**/src/overrides.ts", "**/scripts/**/*.ts"],
|
"includes": ["**/src/overrides.ts"],
|
||||||
"linter": {
|
"linter": {
|
||||||
"rules": {
|
"rules": {
|
||||||
"style": {
|
"style": {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
# Linting & Formatting
|
# 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.
|
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
|
### 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
|
# Using Biome
|
||||||
|
|
||||||
@ -15,34 +15,43 @@ On the other hand, if Biome complains about a piece of code, **there's probably
|
|||||||
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.
|
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
|
## 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.
|
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.
|
||||||
You will **not** be able to push code with `error`-level linting problems - fix them beforehand.
|
|
||||||
|
|
||||||
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
|
## 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)
|
||||||
|
|
||||||
|
2. Execute the Biome executable manually from the command line like so:
|
||||||
```sh
|
```sh
|
||||||
pnpm exec biome check --[flags]
|
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:
|
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).
|
- `--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 only perform checks on all changed or staged files respectively. Biome sources this info from the relevant version control system (in this case Git).
|
- `--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.
|
- `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
|
## 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:
|
Some things to consider:
|
||||||
|
|
||||||
- We have disabled rules that prioritize style over performance, such as `useTemplate`.
|
- 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.
|
- 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).
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# Localization 101
|
# 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.
|
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.
|
This document aims to cover everything you need to know to help keep the integration process for localization smooth and simple.
|
||||||
@ -24,6 +24,7 @@ The parent repo (the "superproject") houses a cloned version of the 2nd reposito
|
|||||||
|
|
||||||
>[!TIP]
|
>[!TIP]
|
||||||
> Many popular IDEs have integrated `git` support with special handling around submodules:
|
> 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:
|
The following command will initialize your branch's locales repository and update its HEAD:
|
||||||
```bash
|
```bash
|
||||||
git submodule update --init --recursive
|
pnpm update-locales
|
||||||
```
|
```
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> This command is run _automatically_ after cloning, merging or changing branches, so you should rarely have to run it manually.
|
> This command is run _automatically_ after cloning, merging or changing branches, so you should rarely have to run it manually.
|
||||||
|
|
||||||
> [!IMPORTANT]
|
> [!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?
|
## How Are Translations Integrated?
|
||||||
|
|
||||||
@ -65,7 +66,7 @@ The basic process for fetching translated text goes roughly as follows:
|
|||||||
```
|
```
|
||||||
|
|
||||||
# Submitting Locales Changes
|
# 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.
|
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]
|
> [!CAUTION]
|
||||||
@ -73,21 +74,21 @@ Since these two PRs aren't _technically_ linked, it's important to coordinate wi
|
|||||||
|
|
||||||
## Making Changes
|
## 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.
|
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]
|
> [!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`.
|
> 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
|
## 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.
|
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.
|
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.
|
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].
|
- 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.
|
- 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.
|
[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 should also [notify the current Head of Translation](#notifying-translation) to ensure a fast response.
|
||||||
3. Your locales should use the following format:
|
3. Your locales should use the following format:
|
||||||
@ -95,7 +96,7 @@ If this feature requires new text, the text should be integrated into the code w
|
|||||||
- Key names should be in `camelCase`. Example: `aceTrainer`
|
- 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`
|
- 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).
|
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.
|
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).
|
[^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:
|
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.
|
- 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.
|
- 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`.
|
- 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
|
## Documenting Locales Changes
|
||||||
|
@ -4,7 +4,9 @@ pre-commit:
|
|||||||
- rebase
|
- rebase
|
||||||
commands:
|
commands:
|
||||||
biome-lint:
|
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
|
stage_fixed: true
|
||||||
ls-lint:
|
ls-lint:
|
||||||
run: pnpm exec ls-lint
|
run: pnpm exec ls-lint
|
||||||
@ -12,11 +14,11 @@ pre-commit:
|
|||||||
post-merge:
|
post-merge:
|
||||||
commands:
|
commands:
|
||||||
update-submodules:
|
update-submodules:
|
||||||
run: git submodule update --init --recursive
|
run: pnpm update-locales
|
||||||
|
|
||||||
post-checkout:
|
post-checkout:
|
||||||
commands:
|
commands:
|
||||||
update-submodules:
|
update-submodules:
|
||||||
# cf https://git-scm.com/docs/githooks#_post_checkout:
|
# cf https://git-scm.com/docs/githooks#_post_checkout:
|
||||||
# The 3rd argument is 1 for branch checkouts and 0 for file checkouts.
|
# 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
|
run: if test {3} -eq "1"; then pnpm update-locales; fi
|
11
package.json
11
package.json
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "pokemon-rogue-battle",
|
"name": "pokemon-rogue-battle",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.10.6",
|
"version": "1.10.7",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start:prod": "vite --mode production",
|
"start:prod": "vite --mode production",
|
||||||
@ -15,25 +15,30 @@
|
|||||||
"test:watch": "vitest watch --coverage --no-isolate",
|
"test:watch": "vitest watch --coverage --no-isolate",
|
||||||
"test:silent": "vitest run --silent='passed-only' --no-isolate",
|
"test:silent": "vitest run --silent='passed-only' --no-isolate",
|
||||||
"test:create": "node scripts/create-test/create-test.js",
|
"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",
|
"scrape-trainers": "node scripts/scrape-trainer-names/main.js",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
|
"typecheck:scripts": "tsc -p scripts/jsconfig.json",
|
||||||
"biome": "biome check --write --changed --no-errors-on-unmatched --diagnostic-level=error",
|
"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",
|
"biome-ci": "biome ci --diagnostic-level=error --reporter=github --no-errors-on-unmatched",
|
||||||
"typedoc": "typedoc",
|
"typedoc": "typedoc",
|
||||||
"depcruise": "depcruise src test",
|
"depcruise": "depcruise src test",
|
||||||
"postinstall": "lefthook install; git submodule update --init --recursive",
|
"postinstall": "lefthook install; git submodule update --init --recursive",
|
||||||
"update-version:patch": "pnpm version patch --force --no-git-tag-version",
|
"update-version:patch": "pnpm version patch --force --no-git-tag-version",
|
||||||
"update-version:minor": "pnpm version minor --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"
|
"update-locales:remote": "git submodule update --progress --init --recursive --force --remote"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "2.0.0",
|
"@biomejs/biome": "2.2.3",
|
||||||
"@ls-lint/ls-lint": "2.3.1",
|
"@ls-lint/ls-lint": "2.3.1",
|
||||||
"@types/crypto-js": "^4.2.0",
|
"@types/crypto-js": "^4.2.0",
|
||||||
"@types/jsdom": "^21.1.7",
|
"@types/jsdom": "^21.1.7",
|
||||||
"@types/node": "^22.16.5",
|
"@types/node": "^22.16.5",
|
||||||
"@vitest/coverage-istanbul": "^3.2.4",
|
"@vitest/coverage-istanbul": "^3.2.4",
|
||||||
"@vitest/expect": "^3.2.4",
|
"@vitest/expect": "^3.2.4",
|
||||||
|
"@vitest/utils": "^3.2.4",
|
||||||
"chalk": "^5.4.1",
|
"chalk": "^5.4.1",
|
||||||
"dependency-cruiser": "^16.10.4",
|
"dependency-cruiser": "^16.10.4",
|
||||||
"inquirer": "^12.8.2",
|
"inquirer": "^12.8.2",
|
||||||
@ -41,7 +46,7 @@
|
|||||||
"lefthook": "^1.12.2",
|
"lefthook": "^1.12.2",
|
||||||
"msw": "^2.10.4",
|
"msw": "^2.10.4",
|
||||||
"phaser3spectorjs": "^0.0.8",
|
"phaser3spectorjs": "^0.0.8",
|
||||||
"typedoc": "^0.28.8",
|
"typedoc": "^0.28.12",
|
||||||
"typedoc-github-theme": "^0.3.1",
|
"typedoc-github-theme": "^0.3.1",
|
||||||
"typedoc-plugin-coverage": "^4.0.1",
|
"typedoc-plugin-coverage": "^4.0.1",
|
||||||
"typedoc-plugin-mdn-links": "^5.0.9",
|
"typedoc-plugin-mdn-links": "^5.0.9",
|
||||||
|
203
pnpm-lock.yaml
203
pnpm-lock.yaml
@ -43,8 +43,8 @@ importers:
|
|||||||
version: 1.80.16(graphology-types@0.24.8)
|
version: 1.80.16(graphology-types@0.24.8)
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@biomejs/biome':
|
'@biomejs/biome':
|
||||||
specifier: 2.0.0
|
specifier: 2.2.3
|
||||||
version: 2.0.0
|
version: 2.2.3
|
||||||
'@ls-lint/ls-lint':
|
'@ls-lint/ls-lint':
|
||||||
specifier: 2.3.1
|
specifier: 2.3.1
|
||||||
version: 2.3.1
|
version: 2.3.1
|
||||||
@ -59,10 +59,13 @@ importers:
|
|||||||
version: 22.16.5
|
version: 22.16.5
|
||||||
'@vitest/coverage-istanbul':
|
'@vitest/coverage-istanbul':
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.4
|
||||||
version: 3.2.4(vitest@3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.0))
|
version: 3.2.4(vitest@3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.1))
|
||||||
'@vitest/expect':
|
'@vitest/expect':
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.4
|
||||||
version: 3.2.4
|
version: 3.2.4
|
||||||
|
'@vitest/utils':
|
||||||
|
specifier: ^3.2.4
|
||||||
|
version: 3.2.4
|
||||||
chalk:
|
chalk:
|
||||||
specifier: ^5.4.1
|
specifier: ^5.4.1
|
||||||
version: 5.4.1
|
version: 5.4.1
|
||||||
@ -85,32 +88,32 @@ importers:
|
|||||||
specifier: ^0.0.8
|
specifier: ^0.0.8
|
||||||
version: 0.0.8
|
version: 0.0.8
|
||||||
typedoc:
|
typedoc:
|
||||||
specifier: ^0.28.8
|
specifier: ^0.28.12
|
||||||
version: 0.28.8(typescript@5.8.3)
|
version: 0.28.12(typescript@5.8.3)
|
||||||
typedoc-github-theme:
|
typedoc-github-theme:
|
||||||
specifier: ^0.3.1
|
specifier: ^0.3.1
|
||||||
version: 0.3.1(typedoc@0.28.8(typescript@5.8.3))
|
version: 0.3.1(typedoc@0.28.12(typescript@5.8.3))
|
||||||
typedoc-plugin-coverage:
|
typedoc-plugin-coverage:
|
||||||
specifier: ^4.0.1
|
specifier: ^4.0.1
|
||||||
version: 4.0.1(typedoc@0.28.8(typescript@5.8.3))
|
version: 4.0.1(typedoc@0.28.12(typescript@5.8.3))
|
||||||
typedoc-plugin-mdn-links:
|
typedoc-plugin-mdn-links:
|
||||||
specifier: ^5.0.9
|
specifier: ^5.0.9
|
||||||
version: 5.0.9(typedoc@0.28.8(typescript@5.8.3))
|
version: 5.0.9(typedoc@0.28.12(typescript@5.8.3))
|
||||||
typescript:
|
typescript:
|
||||||
specifier: ^5.8.3
|
specifier: ^5.8.3
|
||||||
version: 5.8.3
|
version: 5.8.3
|
||||||
vite:
|
vite:
|
||||||
specifier: ^7.0.6
|
specifier: ^7.0.6
|
||||||
version: 7.0.6(@types/node@22.16.5)(yaml@2.8.0)
|
version: 7.0.6(@types/node@22.16.5)(yaml@2.8.1)
|
||||||
vite-tsconfig-paths:
|
vite-tsconfig-paths:
|
||||||
specifier: ^5.1.4
|
specifier: ^5.1.4
|
||||||
version: 5.1.4(typescript@5.8.3)(vite@7.0.6(@types/node@22.16.5)(yaml@2.8.0))
|
version: 5.1.4(typescript@5.8.3)(vite@7.0.6(@types/node@22.16.5)(yaml@2.8.1))
|
||||||
vitest:
|
vitest:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.4
|
||||||
version: 3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.0)
|
version: 3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.1)
|
||||||
vitest-canvas-mock:
|
vitest-canvas-mock:
|
||||||
specifier: ^0.3.3
|
specifier: ^0.3.3
|
||||||
version: 0.3.3(vitest@3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.0))
|
version: 0.3.3(vitest@3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.1))
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
@ -192,55 +195,55 @@ packages:
|
|||||||
resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==}
|
resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
'@biomejs/biome@2.0.0':
|
'@biomejs/biome@2.2.3':
|
||||||
resolution: {integrity: sha512-BlUoXEOI/UQTDEj/pVfnkMo8SrZw3oOWBDrXYFT43V7HTkIUDkBRY53IC5Jx1QkZbaB+0ai1wJIfYwp9+qaJTQ==}
|
resolution: {integrity: sha512-9w0uMTvPrIdvUrxazZ42Ib7t8Y2yoGLKLdNne93RLICmaHw7mcLv4PPb5LvZLJF3141gQHiCColOh/v6VWlWmg==}
|
||||||
engines: {node: '>=14.21.3'}
|
engines: {node: '>=14.21.3'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
'@biomejs/cli-darwin-arm64@2.0.0':
|
'@biomejs/cli-darwin-arm64@2.2.3':
|
||||||
resolution: {integrity: sha512-QvqWYtFFhhxdf8jMAdJzXW+Frc7X8XsnHQLY+TBM1fnT1TfeV/v9vsFI5L2J7GH6qN1+QEEJ19jHibCY2Ypplw==}
|
resolution: {integrity: sha512-OrqQVBpadB5eqzinXN4+Q6honBz+tTlKVCsbEuEpljK8ASSItzIRZUA02mTikl3H/1nO2BMPFiJ0nkEZNy3B1w==}
|
||||||
engines: {node: '>=14.21.3'}
|
engines: {node: '>=14.21.3'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
'@biomejs/cli-darwin-x64@2.0.0':
|
'@biomejs/cli-darwin-x64@2.2.3':
|
||||||
resolution: {integrity: sha512-5JFhls1EfmuIH4QGFPlNpxJQFC6ic3X1ltcoLN+eSRRIPr6H/lUS1ttuD0Fj7rPgPhZqopK/jfH8UVj/1hIsQw==}
|
resolution: {integrity: sha512-OCdBpb1TmyfsTgBAM1kPMXyYKTohQ48WpiN9tkt9xvU6gKVKHY4oVwteBebiOqyfyzCNaSiuKIPjmHjUZ2ZNMg==}
|
||||||
engines: {node: '>=14.21.3'}
|
engines: {node: '>=14.21.3'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
'@biomejs/cli-linux-arm64-musl@2.0.0':
|
'@biomejs/cli-linux-arm64-musl@2.2.3':
|
||||||
resolution: {integrity: sha512-Bxsz8ki8+b3PytMnS5SgrGV+mbAWwIxI3ydChb/d1rURlJTMdxTTq5LTebUnlsUWAX6OvJuFeiVq9Gjn1YbCyA==}
|
resolution: {integrity: sha512-q3w9jJ6JFPZPeqyvwwPeaiS/6NEszZ+pXKF+IczNo8Xj6fsii45a4gEEicKyKIytalV+s829ACZujQlXAiVLBQ==}
|
||||||
engines: {node: '>=14.21.3'}
|
engines: {node: '>=14.21.3'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@biomejs/cli-linux-arm64@2.0.0':
|
'@biomejs/cli-linux-arm64@2.2.3':
|
||||||
resolution: {integrity: sha512-BAH4QVi06TzAbVchXdJPsL0Z/P87jOfes15rI+p3EX9/EGTfIjaQ9lBVlHunxcmoptaA5y1Hdb9UYojIhmnjIw==}
|
resolution: {integrity: sha512-g/Uta2DqYpECxG+vUmTAmUKlVhnGEcY7DXWgKP8ruLRa8Si1QHsWknPY3B/wCo0KgYiFIOAZ9hjsHfNb9L85+g==}
|
||||||
engines: {node: '>=14.21.3'}
|
engines: {node: '>=14.21.3'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@biomejs/cli-linux-x64-musl@2.0.0':
|
'@biomejs/cli-linux-x64-musl@2.2.3':
|
||||||
resolution: {integrity: sha512-tiQ0ABxMJb9I6GlfNp0ulrTiQSFacJRJO8245FFwE3ty3bfsfxlU/miblzDIi+qNrgGsLq5wIZcVYGp4c+HXZA==}
|
resolution: {integrity: sha512-y76Dn4vkP1sMRGPFlNc+OTETBhGPJ90jY3il6jAfur8XWrYBQV3swZ1Jo0R2g+JpOeeoA0cOwM7mJG6svDz79w==}
|
||||||
engines: {node: '>=14.21.3'}
|
engines: {node: '>=14.21.3'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@biomejs/cli-linux-x64@2.0.0':
|
'@biomejs/cli-linux-x64@2.2.3':
|
||||||
resolution: {integrity: sha512-09PcOGYTtkopWRm6mZ/B6Mr6UHdkniUgIG/jLBv+2J8Z61ezRE+xQmpi3yNgUrFIAU4lPA9atg7mhvE/5Bo7Wg==}
|
resolution: {integrity: sha512-LEtyYL1fJsvw35CxrbQ0gZoxOG3oZsAjzfRdvRBRHxOpQ91Q5doRVjvWW/wepgSdgk5hlaNzfeqpyGmfSD0Eyw==}
|
||||||
engines: {node: '>=14.21.3'}
|
engines: {node: '>=14.21.3'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@biomejs/cli-win32-arm64@2.0.0':
|
'@biomejs/cli-win32-arm64@2.2.3':
|
||||||
resolution: {integrity: sha512-vrTtuGu91xNTEQ5ZcMJBZuDlqr32DWU1r14UfePIGndF//s2WUAmer4FmgoPgruo76rprk37e8S2A2c0psXdxw==}
|
resolution: {integrity: sha512-Ms9zFYzjcJK7LV+AOMYnjN3pV3xL8Prxf9aWdDVL74onLn5kcvZ1ZMQswE5XHtnd/r/0bnUd928Rpbs14BzVmA==}
|
||||||
engines: {node: '>=14.21.3'}
|
engines: {node: '>=14.21.3'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
'@biomejs/cli-win32-x64@2.0.0':
|
'@biomejs/cli-win32-x64@2.2.3':
|
||||||
resolution: {integrity: sha512-2USVQ0hklNsph/KIR72ZdeptyXNnQ3JdzPn3NbjI4Sna34CnxeiYAaZcZzXPDl5PYNFBivV4xmvT3Z3rTmyDBg==}
|
resolution: {integrity: sha512-gvCpewE7mBwBIpqk1YrUqNR4mCiyJm6UI3YWQQXkedSSEwzRdodRpaKhbdbHw1/hmTWOVXQ+Eih5Qctf4TCVOQ==}
|
||||||
engines: {node: '>=14.21.3'}
|
engines: {node: '>=14.21.3'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
@ -438,8 +441,8 @@ packages:
|
|||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
'@gerrit0/mini-shiki@3.8.1':
|
'@gerrit0/mini-shiki@3.12.2':
|
||||||
resolution: {integrity: sha512-HVZW+8pxoOExr5ZMPK15U79jQAZTO/S6i5byQyyZGjtNj+qaYd82cizTncwFzTQgiLo8uUBym6vh+/1tfJklTw==}
|
resolution: {integrity: sha512-HKZPmO8OSSAAo20H2B3xgJdxZaLTwtlMwxg0967scnrDlPwe6j5+ULGHyIqwgTbFCn9yv/ff8CmfWZLE9YKBzA==}
|
||||||
|
|
||||||
'@inquirer/checkbox@4.2.0':
|
'@inquirer/checkbox@4.2.0':
|
||||||
resolution: {integrity: sha512-fdSw07FLJEU5vbpOPzXo5c6xmMGDzbZE2+niuDHX5N6mc6V0Ebso/q3xiHra4D73+PMsC8MJmcaZKuAAoaQsSA==}
|
resolution: {integrity: sha512-fdSw07FLJEU5vbpOPzXo5c6xmMGDzbZE2+niuDHX5N6mc6V0Ebso/q3xiHra4D73+PMsC8MJmcaZKuAAoaQsSA==}
|
||||||
@ -709,17 +712,17 @@ packages:
|
|||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
'@shikijs/engine-oniguruma@3.8.1':
|
'@shikijs/engine-oniguruma@3.12.2':
|
||||||
resolution: {integrity: sha512-KGQJZHlNY7c656qPFEQpIoqOuC4LrxjyNndRdzk5WKB/Ie87+NJCF1xo9KkOUxwxylk7rT6nhlZyTGTC4fCe1g==}
|
resolution: {integrity: sha512-hozwnFHsLvujK4/CPVHNo3Bcg2EsnG8krI/ZQ2FlBlCRpPZW4XAEQmEwqegJsypsTAN9ehu2tEYe30lYKSZW/w==}
|
||||||
|
|
||||||
'@shikijs/langs@3.8.1':
|
'@shikijs/langs@3.12.2':
|
||||||
resolution: {integrity: sha512-TjOFg2Wp1w07oKnXjs0AUMb4kJvujML+fJ1C5cmEj45lhjbUXtziT1x2bPQb9Db6kmPhkG5NI2tgYW1/DzhUuQ==}
|
resolution: {integrity: sha512-bVx5PfuZHDSHoBal+KzJZGheFuyH4qwwcwG/n+MsWno5cTlKmaNtTsGzJpHYQ8YPbB5BdEdKU1rga5/6JGY8ww==}
|
||||||
|
|
||||||
'@shikijs/themes@3.8.1':
|
'@shikijs/themes@3.12.2':
|
||||||
resolution: {integrity: sha512-Vu3t3BBLifc0GB0UPg2Pox1naTemrrvyZv2lkiSw3QayVV60me1ujFQwPZGgUTmwXl1yhCPW8Lieesm0CYruLQ==}
|
resolution: {integrity: sha512-fTR3QAgnwYpfGczpIbzPjlRnxyONJOerguQv1iwpyQZ9QXX4qy/XFQqXlf17XTsorxnHoJGbH/LXBvwtqDsF5A==}
|
||||||
|
|
||||||
'@shikijs/types@3.8.1':
|
'@shikijs/types@3.12.2':
|
||||||
resolution: {integrity: sha512-5C39Q8/8r1I26suLh+5TPk1DTrbY/kn3IdWA5HdizR0FhlhD05zx5nKCqhzSfDHH3p4S0ZefxWd77DLV+8FhGg==}
|
resolution: {integrity: sha512-K5UIBzxCyv0YoxN3LMrKB9zuhp1bV+LgewxuVwHdl4Gz5oePoUFrr9EfgJlGlDeXCU1b/yhdnXeuRvAnz8HN8Q==}
|
||||||
|
|
||||||
'@shikijs/vscode-textmate@10.0.2':
|
'@shikijs/vscode-textmate@10.0.2':
|
||||||
resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==}
|
resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==}
|
||||||
@ -1815,12 +1818,12 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
typedoc: 0.27.x || 0.28.x
|
typedoc: 0.27.x || 0.28.x
|
||||||
|
|
||||||
typedoc@0.28.8:
|
typedoc@0.28.12:
|
||||||
resolution: {integrity: sha512-16GfLopc8icHfdvqZDqdGBoS2AieIRP2rpf9mU+MgN+gGLyEQvAO0QgOa6NJ5QNmQi0LFrDY9in4F2fUNKgJKA==}
|
resolution: {integrity: sha512-H5ODu4f7N+myG4MfuSp2Vh6wV+WLoZaEYxKPt2y8hmmqNEMVrH69DAjjdmYivF4tP/C2jrIZCZhPalZlTU/ipA==}
|
||||||
engines: {node: '>= 18', pnpm: '>= 10'}
|
engines: {node: '>= 18', pnpm: '>= 10'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
typescript: 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x
|
typescript: 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x
|
||||||
|
|
||||||
typescript@5.8.3:
|
typescript@5.8.3:
|
||||||
resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==}
|
resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==}
|
||||||
@ -2017,8 +2020,8 @@ packages:
|
|||||||
yallist@3.1.1:
|
yallist@3.1.1:
|
||||||
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
|
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
|
||||||
|
|
||||||
yaml@2.8.0:
|
yaml@2.8.1:
|
||||||
resolution: {integrity: sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==}
|
resolution: {integrity: sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==}
|
||||||
engines: {node: '>= 14.6'}
|
engines: {node: '>= 14.6'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
@ -2151,39 +2154,39 @@ snapshots:
|
|||||||
'@babel/helper-string-parser': 7.27.1
|
'@babel/helper-string-parser': 7.27.1
|
||||||
'@babel/helper-validator-identifier': 7.27.1
|
'@babel/helper-validator-identifier': 7.27.1
|
||||||
|
|
||||||
'@biomejs/biome@2.0.0':
|
'@biomejs/biome@2.2.3':
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@biomejs/cli-darwin-arm64': 2.0.0
|
'@biomejs/cli-darwin-arm64': 2.2.3
|
||||||
'@biomejs/cli-darwin-x64': 2.0.0
|
'@biomejs/cli-darwin-x64': 2.2.3
|
||||||
'@biomejs/cli-linux-arm64': 2.0.0
|
'@biomejs/cli-linux-arm64': 2.2.3
|
||||||
'@biomejs/cli-linux-arm64-musl': 2.0.0
|
'@biomejs/cli-linux-arm64-musl': 2.2.3
|
||||||
'@biomejs/cli-linux-x64': 2.0.0
|
'@biomejs/cli-linux-x64': 2.2.3
|
||||||
'@biomejs/cli-linux-x64-musl': 2.0.0
|
'@biomejs/cli-linux-x64-musl': 2.2.3
|
||||||
'@biomejs/cli-win32-arm64': 2.0.0
|
'@biomejs/cli-win32-arm64': 2.2.3
|
||||||
'@biomejs/cli-win32-x64': 2.0.0
|
'@biomejs/cli-win32-x64': 2.2.3
|
||||||
|
|
||||||
'@biomejs/cli-darwin-arm64@2.0.0':
|
'@biomejs/cli-darwin-arm64@2.2.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@biomejs/cli-darwin-x64@2.0.0':
|
'@biomejs/cli-darwin-x64@2.2.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@biomejs/cli-linux-arm64-musl@2.0.0':
|
'@biomejs/cli-linux-arm64-musl@2.2.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@biomejs/cli-linux-arm64@2.0.0':
|
'@biomejs/cli-linux-arm64@2.2.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@biomejs/cli-linux-x64-musl@2.0.0':
|
'@biomejs/cli-linux-x64-musl@2.2.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@biomejs/cli-linux-x64@2.0.0':
|
'@biomejs/cli-linux-x64@2.2.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@biomejs/cli-win32-arm64@2.0.0':
|
'@biomejs/cli-win32-arm64@2.2.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@biomejs/cli-win32-x64@2.0.0':
|
'@biomejs/cli-win32-x64@2.2.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@bundled-es-modules/cookie@2.0.1':
|
'@bundled-es-modules/cookie@2.0.1':
|
||||||
@ -2297,12 +2300,12 @@ snapshots:
|
|||||||
'@esbuild/win32-x64@0.25.8':
|
'@esbuild/win32-x64@0.25.8':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@gerrit0/mini-shiki@3.8.1':
|
'@gerrit0/mini-shiki@3.12.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@shikijs/engine-oniguruma': 3.8.1
|
'@shikijs/engine-oniguruma': 3.12.2
|
||||||
'@shikijs/langs': 3.8.1
|
'@shikijs/langs': 3.12.2
|
||||||
'@shikijs/themes': 3.8.1
|
'@shikijs/themes': 3.12.2
|
||||||
'@shikijs/types': 3.8.1
|
'@shikijs/types': 3.12.2
|
||||||
'@shikijs/vscode-textmate': 10.0.2
|
'@shikijs/vscode-textmate': 10.0.2
|
||||||
|
|
||||||
'@inquirer/checkbox@4.2.0(@types/node@22.16.5)':
|
'@inquirer/checkbox@4.2.0(@types/node@22.16.5)':
|
||||||
@ -2531,20 +2534,20 @@ snapshots:
|
|||||||
'@rollup/rollup-win32-x64-msvc@4.46.1':
|
'@rollup/rollup-win32-x64-msvc@4.46.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@shikijs/engine-oniguruma@3.8.1':
|
'@shikijs/engine-oniguruma@3.12.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@shikijs/types': 3.8.1
|
'@shikijs/types': 3.12.2
|
||||||
'@shikijs/vscode-textmate': 10.0.2
|
'@shikijs/vscode-textmate': 10.0.2
|
||||||
|
|
||||||
'@shikijs/langs@3.8.1':
|
'@shikijs/langs@3.12.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@shikijs/types': 3.8.1
|
'@shikijs/types': 3.12.2
|
||||||
|
|
||||||
'@shikijs/themes@3.8.1':
|
'@shikijs/themes@3.12.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@shikijs/types': 3.8.1
|
'@shikijs/types': 3.12.2
|
||||||
|
|
||||||
'@shikijs/types@3.8.1':
|
'@shikijs/types@3.12.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@shikijs/vscode-textmate': 10.0.2
|
'@shikijs/vscode-textmate': 10.0.2
|
||||||
'@types/hast': 3.0.4
|
'@types/hast': 3.0.4
|
||||||
@ -2583,7 +2586,7 @@ snapshots:
|
|||||||
|
|
||||||
'@types/unist@3.0.3': {}
|
'@types/unist@3.0.3': {}
|
||||||
|
|
||||||
'@vitest/coverage-istanbul@3.2.4(vitest@3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.0))':
|
'@vitest/coverage-istanbul@3.2.4(vitest@3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.1))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@istanbuljs/schema': 0.1.3
|
'@istanbuljs/schema': 0.1.3
|
||||||
debug: 4.4.1
|
debug: 4.4.1
|
||||||
@ -2595,7 +2598,7 @@ snapshots:
|
|||||||
magicast: 0.3.5
|
magicast: 0.3.5
|
||||||
test-exclude: 7.0.1
|
test-exclude: 7.0.1
|
||||||
tinyrainbow: 2.0.0
|
tinyrainbow: 2.0.0
|
||||||
vitest: 3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.0)
|
vitest: 3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.1)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
@ -2607,14 +2610,14 @@ snapshots:
|
|||||||
chai: 5.2.1
|
chai: 5.2.1
|
||||||
tinyrainbow: 2.0.0
|
tinyrainbow: 2.0.0
|
||||||
|
|
||||||
'@vitest/mocker@3.2.4(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(vite@7.0.6(@types/node@22.16.5)(yaml@2.8.0))':
|
'@vitest/mocker@3.2.4(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(vite@7.0.6(@types/node@22.16.5)(yaml@2.8.1))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vitest/spy': 3.2.4
|
'@vitest/spy': 3.2.4
|
||||||
estree-walker: 3.0.3
|
estree-walker: 3.0.3
|
||||||
magic-string: 0.30.17
|
magic-string: 0.30.17
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
msw: 2.10.4(@types/node@22.16.5)(typescript@5.8.3)
|
msw: 2.10.4(@types/node@22.16.5)(typescript@5.8.3)
|
||||||
vite: 7.0.6(@types/node@22.16.5)(yaml@2.8.0)
|
vite: 7.0.6(@types/node@22.16.5)(yaml@2.8.1)
|
||||||
|
|
||||||
'@vitest/pretty-format@3.2.4':
|
'@vitest/pretty-format@3.2.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -3660,26 +3663,26 @@ snapshots:
|
|||||||
|
|
||||||
type-fest@4.41.0: {}
|
type-fest@4.41.0: {}
|
||||||
|
|
||||||
typedoc-github-theme@0.3.1(typedoc@0.28.8(typescript@5.8.3)):
|
typedoc-github-theme@0.3.1(typedoc@0.28.12(typescript@5.8.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
typedoc: 0.28.8(typescript@5.8.3)
|
typedoc: 0.28.12(typescript@5.8.3)
|
||||||
|
|
||||||
typedoc-plugin-coverage@4.0.1(typedoc@0.28.8(typescript@5.8.3)):
|
typedoc-plugin-coverage@4.0.1(typedoc@0.28.12(typescript@5.8.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
typedoc: 0.28.8(typescript@5.8.3)
|
typedoc: 0.28.12(typescript@5.8.3)
|
||||||
|
|
||||||
typedoc-plugin-mdn-links@5.0.9(typedoc@0.28.8(typescript@5.8.3)):
|
typedoc-plugin-mdn-links@5.0.9(typedoc@0.28.12(typescript@5.8.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
typedoc: 0.28.8(typescript@5.8.3)
|
typedoc: 0.28.12(typescript@5.8.3)
|
||||||
|
|
||||||
typedoc@0.28.8(typescript@5.8.3):
|
typedoc@0.28.12(typescript@5.8.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@gerrit0/mini-shiki': 3.8.1
|
'@gerrit0/mini-shiki': 3.12.2
|
||||||
lunr: 2.3.9
|
lunr: 2.3.9
|
||||||
markdown-it: 14.1.0
|
markdown-it: 14.1.0
|
||||||
minimatch: 9.0.5
|
minimatch: 9.0.5
|
||||||
typescript: 5.8.3
|
typescript: 5.8.3
|
||||||
yaml: 2.8.0
|
yaml: 2.8.1
|
||||||
|
|
||||||
typescript@5.8.3: {}
|
typescript@5.8.3: {}
|
||||||
|
|
||||||
@ -3702,13 +3705,13 @@ snapshots:
|
|||||||
|
|
||||||
util-deprecate@1.0.2: {}
|
util-deprecate@1.0.2: {}
|
||||||
|
|
||||||
vite-node@3.2.4(@types/node@22.16.5)(yaml@2.8.0):
|
vite-node@3.2.4(@types/node@22.16.5)(yaml@2.8.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
cac: 6.7.14
|
cac: 6.7.14
|
||||||
debug: 4.4.1
|
debug: 4.4.1
|
||||||
es-module-lexer: 1.7.0
|
es-module-lexer: 1.7.0
|
||||||
pathe: 2.0.3
|
pathe: 2.0.3
|
||||||
vite: 7.0.6(@types/node@22.16.5)(yaml@2.8.0)
|
vite: 7.0.6(@types/node@22.16.5)(yaml@2.8.1)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@types/node'
|
- '@types/node'
|
||||||
- jiti
|
- jiti
|
||||||
@ -3723,18 +3726,18 @@ snapshots:
|
|||||||
- tsx
|
- tsx
|
||||||
- yaml
|
- yaml
|
||||||
|
|
||||||
vite-tsconfig-paths@5.1.4(typescript@5.8.3)(vite@7.0.6(@types/node@22.16.5)(yaml@2.8.0)):
|
vite-tsconfig-paths@5.1.4(typescript@5.8.3)(vite@7.0.6(@types/node@22.16.5)(yaml@2.8.1)):
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.4.1
|
debug: 4.4.1
|
||||||
globrex: 0.1.2
|
globrex: 0.1.2
|
||||||
tsconfck: 3.1.6(typescript@5.8.3)
|
tsconfck: 3.1.6(typescript@5.8.3)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vite: 7.0.6(@types/node@22.16.5)(yaml@2.8.0)
|
vite: 7.0.6(@types/node@22.16.5)(yaml@2.8.1)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
- typescript
|
- typescript
|
||||||
|
|
||||||
vite@7.0.6(@types/node@22.16.5)(yaml@2.8.0):
|
vite@7.0.6(@types/node@22.16.5)(yaml@2.8.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.25.8
|
esbuild: 0.25.8
|
||||||
fdir: 6.4.6(picomatch@4.0.3)
|
fdir: 6.4.6(picomatch@4.0.3)
|
||||||
@ -3745,18 +3748,18 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/node': 22.16.5
|
'@types/node': 22.16.5
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
yaml: 2.8.0
|
yaml: 2.8.1
|
||||||
|
|
||||||
vitest-canvas-mock@0.3.3(vitest@3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.0)):
|
vitest-canvas-mock@0.3.3(vitest@3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.1)):
|
||||||
dependencies:
|
dependencies:
|
||||||
jest-canvas-mock: 2.5.2
|
jest-canvas-mock: 2.5.2
|
||||||
vitest: 3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.0)
|
vitest: 3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.1)
|
||||||
|
|
||||||
vitest@3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.0):
|
vitest@3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/chai': 5.2.2
|
'@types/chai': 5.2.2
|
||||||
'@vitest/expect': 3.2.4
|
'@vitest/expect': 3.2.4
|
||||||
'@vitest/mocker': 3.2.4(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(vite@7.0.6(@types/node@22.16.5)(yaml@2.8.0))
|
'@vitest/mocker': 3.2.4(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(vite@7.0.6(@types/node@22.16.5)(yaml@2.8.1))
|
||||||
'@vitest/pretty-format': 3.2.4
|
'@vitest/pretty-format': 3.2.4
|
||||||
'@vitest/runner': 3.2.4
|
'@vitest/runner': 3.2.4
|
||||||
'@vitest/snapshot': 3.2.4
|
'@vitest/snapshot': 3.2.4
|
||||||
@ -3774,8 +3777,8 @@ snapshots:
|
|||||||
tinyglobby: 0.2.14
|
tinyglobby: 0.2.14
|
||||||
tinypool: 1.1.1
|
tinypool: 1.1.1
|
||||||
tinyrainbow: 2.0.0
|
tinyrainbow: 2.0.0
|
||||||
vite: 7.0.6(@types/node@22.16.5)(yaml@2.8.0)
|
vite: 7.0.6(@types/node@22.16.5)(yaml@2.8.1)
|
||||||
vite-node: 3.2.4(@types/node@22.16.5)(yaml@2.8.0)
|
vite-node: 3.2.4(@types/node@22.16.5)(yaml@2.8.1)
|
||||||
why-is-node-running: 2.3.0
|
why-is-node-running: 2.3.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/node': 22.16.5
|
'@types/node': 22.16.5
|
||||||
@ -3859,7 +3862,7 @@ snapshots:
|
|||||||
|
|
||||||
yallist@3.1.1: {}
|
yallist@3.1.1: {}
|
||||||
|
|
||||||
yaml@2.8.0: {}
|
yaml@2.8.1: {}
|
||||||
|
|
||||||
yargs-parser@21.1.1: {}
|
yargs-parser@21.1.1: {}
|
||||||
|
|
||||||
|
BIN
public/images/ui/language_icon.png
Normal file
BIN
public/images/ui/language_icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 294 B |
BIN
public/images/ui/legacy/language_icon.png
Normal file
BIN
public/images/ui/legacy/language_icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 294 B |
@ -1 +1 @@
|
|||||||
Subproject commit 2686cd3edc0bd2c7a7f12cc54c00c109e51a48d7
|
Subproject commit 090bfefaf7e9d4efcbca61fa78a9cdf5d701830b
|
@ -1,7 +1,10 @@
|
|||||||
import { AbilityId } from "#enums/ability-id";
|
import { AbilityId } from "#enums/ability-id";
|
||||||
|
import { BattlerIndex } from "#enums/battler-index";
|
||||||
import { MoveId } from "#enums/move-id";
|
import { MoveId } from "#enums/move-id";
|
||||||
|
import { MoveResult } from "#enums/move-result";
|
||||||
import { SpeciesId } from "#enums/species-id";
|
import { SpeciesId } from "#enums/species-id";
|
||||||
import { GameManager } from "#test/test-utils/game-manager";
|
import { GameManager } from "#test/test-utils/game-manager";
|
||||||
|
import i18next from "i18next";
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
@ -32,12 +35,18 @@ describe("{{description}}", () => {
|
|||||||
.enemyLevel(100);
|
.enemyLevel(100);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Find more awesome utility functions inside `#test/test-utils`!
|
||||||
it("should do XYZ", async () => {
|
it("should do XYZ", async () => {
|
||||||
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||||
|
|
||||||
|
const feebas = game.field.getPlayerPokemon();
|
||||||
|
|
||||||
game.move.use(MoveId.SPLASH);
|
game.move.use(MoveId.SPLASH);
|
||||||
|
await game.move.forceEnemyMove(MoveId.CELEBRATE);
|
||||||
|
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
||||||
await game.toEndOfTurn();
|
await game.toEndOfTurn();
|
||||||
|
|
||||||
expect(true).toBe(true);
|
expect(feebas).toHaveUsedMove({ move: MoveId.SPLASH, result: MoveResult.SUCCESS });
|
||||||
|
expect(game.textInterceptor.logs).toContain(i18next.t("moveTriggers:splash"));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -156,7 +156,7 @@ async function runInteractive() {
|
|||||||
console.log(chalk.green.bold(`✔ File created at: test/${localDir}/${fileName}.test.ts\n`));
|
console.log(chalk.green.bold(`✔ File created at: test/${localDir}/${fileName}.test.ts\n`));
|
||||||
console.groupEnd();
|
console.groupEnd();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(chalk.red("✗ Error: ", err.message));
|
console.error(chalk.red("✗ Error: ", err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// Usage: node decrypt-save.js <encrypted-file> [save-file]
|
// Usage: node decrypt-save.js <encrypted-file> [save-file]
|
||||||
|
|
||||||
// biome-ignore lint/performance/noNamespaceImport: This is how you import fs from node
|
import fs from "node:fs";
|
||||||
import * as fs from "node:fs";
|
|
||||||
import crypto_js from "crypto-js";
|
import crypto_js from "crypto-js";
|
||||||
|
|
||||||
const { AES, enc } = crypto_js;
|
const { AES, enc } = crypto_js;
|
||||||
@ -60,6 +59,11 @@ function decryptSave(path) {
|
|||||||
try {
|
try {
|
||||||
fileData = fs.readFileSync(path, "utf8");
|
fileData = fs.readFileSync(path, "utf8");
|
||||||
} catch (e) {
|
} 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) {
|
switch (e.code) {
|
||||||
case "ENOENT":
|
case "ENOENT":
|
||||||
console.error(`File not found: ${path}`);
|
console.error(`File not found: ${path}`);
|
||||||
@ -104,6 +108,13 @@ function writeToFile(filePath, data) {
|
|||||||
try {
|
try {
|
||||||
fs.writeFileSync(filePath, data);
|
fs.writeFileSync(filePath, data);
|
||||||
} catch (e) {
|
} 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) {
|
switch (e.code) {
|
||||||
case "EACCES":
|
case "EACCES":
|
||||||
console.error(`Could not open ${filePath}: Permission denied`);
|
console.error(`Could not open ${filePath}: Permission denied`);
|
||||||
@ -114,7 +125,8 @@ function writeToFile(filePath, data) {
|
|||||||
default:
|
default:
|
||||||
console.error(`Error writing file: ${e.message}`);
|
console.error(`Error writing file: ${e.message}`);
|
||||||
}
|
}
|
||||||
process.exit(1);
|
process.exitCode = 1;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
17
scripts/jsconfig.json
Normal file
17
scripts/jsconfig.json
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
10
scripts/parse-egg-moves/egg-move-template.boilerplate.ts
Normal file
10
scripts/parse-egg-moves/egg-move-template.boilerplate.ts
Normal file
@ -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}}";
|
17
scripts/parse-egg-moves/help-message.js
Normal file
17
scripts/parse-egg-moves/help-message.js
Normal file
@ -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)
|
||||||
|
`);
|
||||||
|
}
|
108
scripts/parse-egg-moves/interactive.js
Normal file
108
scripts/parse-egg-moves/interactive.js
Normal file
@ -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<Option>} 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<string>} 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<string>} 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<string>} 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);
|
||||||
|
}
|
168
scripts/parse-egg-moves/main.js
Normal file
168
scripts/parse-egg-moves/main.js
Normal file
@ -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<void>}
|
||||||
|
*/
|
||||||
|
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<void>}
|
||||||
|
*/
|
||||||
|
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();
|
79
scripts/parse-egg-moves/parse.js
Normal file
79
scripts/parse-egg-moves/parse.js
Normal file
@ -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<Record<SpeciesId, [MoveId, MoveId, MoveId, MoveId]>>";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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("_");
|
||||||
|
}
|
@ -31,11 +31,11 @@ export function fetchNames(trainerListHeader, knownFemale = false) {
|
|||||||
|
|
||||||
// Grab all the trainer name tables sorted by generation
|
// Grab all the trainer name tables sorted by generation
|
||||||
const tables = elements.slice(startChildIndex, endChildIndex).filter(
|
const tables = elements.slice(startChildIndex, endChildIndex).filter(
|
||||||
/** @type {(t: ChildNode) => t is Element} */
|
/** @type {(t: ChildNode) => t is HTMLTableElement} */
|
||||||
(
|
(
|
||||||
t =>
|
t =>
|
||||||
// Only grab expandable tables within the header block
|
// 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.
|
* 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 {boolean} isFemale - Whether the trainer is known to be female or not
|
||||||
* @param {Set<string>} trainerNames A Set containing the male trainer names
|
* @param {Set<string>} trainerNames A Set containing the male trainer names
|
||||||
* @param {Set<string>} femaleTrainerNames - A Set containing the female trainer names
|
* @param {Set<string>} femaleTrainerNames - A Set containing the female trainer names
|
||||||
@ -56,7 +56,7 @@ export function fetchNames(trainerListHeader, knownFemale = false) {
|
|||||||
function parseTable(tables, isFemale, trainerNames, femaleTrainerNames) {
|
function parseTable(tables, isFemale, trainerNames, femaleTrainerNames) {
|
||||||
for (const table of tables) {
|
for (const table of tables) {
|
||||||
// Grab all rows past the first header with exactly 9 children in them (Name, Battle, Winnings, 6 party slots)
|
// 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) {
|
for (const row of trainerRows) {
|
||||||
const content = row.firstElementChild?.innerHTML;
|
const content = row.firstElementChild?.innerHTML;
|
||||||
// Skip empty elements & ones without anchors
|
// Skip empty elements & ones without anchors
|
||||||
|
@ -129,7 +129,7 @@ async function scrapeTrainerNames(classes) {
|
|||||||
reason = `Server produced error code of ${+errCode}`;
|
reason = `Server produced error code of ${+errCode}`;
|
||||||
}
|
}
|
||||||
throw new Error(
|
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 [female, counterpartURLs] = checkGenderAndType(document);
|
||||||
const names = fetchNames(trainerListHeader, female);
|
const names = fetchNames(trainerListHeader, female);
|
||||||
if (names === INVALID_URL) {
|
if (names === INVALID_URL) {
|
||||||
return Promise.reject(
|
return Promise.reject(new Error(chalk.red.bold(`URL "${classURL}" did not correspond to a valid trainer class!`)));
|
||||||
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
|
// Recurse into all unseen gender counterparts' URLs, using the first male name we find
|
||||||
@ -285,7 +283,7 @@ async function promptExisting(outFile) {
|
|||||||
{
|
{
|
||||||
type: "confirm",
|
type: "confirm",
|
||||||
name: "continue",
|
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,
|
default: false,
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { ScoreboardCategory } from "#ui/daily-run-scoreboard";
|
import type { ScoreboardCategory } from "#ui/containers/daily-run-scoreboard";
|
||||||
|
|
||||||
export interface GetDailyRankingsRequest {
|
export interface GetDailyRankingsRequest {
|
||||||
category: ScoreboardCategory;
|
category: ScoreboardCategory;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { SessionSaveData, SystemSaveData } from "#system/game-data";
|
import type { SessionSaveData, SystemSaveData } from "#types/save-data";
|
||||||
|
|
||||||
export interface UpdateAllSavedataRequest {
|
export interface UpdateAllSavedataRequest {
|
||||||
system: SystemSaveData;
|
system: SystemSaveData;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { SystemSaveData } from "#system/game-data";
|
import type { SystemSaveData } from "#types/save-data";
|
||||||
|
|
||||||
export interface GetSystemSavedataRequest {
|
export interface GetSystemSavedataRequest {
|
||||||
clientSessionId: string;
|
clientSessionId: string;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import type { ArenaTagTypeMap } from "#data/arena-tag";
|
import type { ArenaTagTypeMap } from "#data/arena-tag";
|
||||||
import type { ArenaTagType } from "#enums/arena-tag-type";
|
import type { ArenaTagType } from "#enums/arena-tag-type";
|
||||||
// biome-ignore lint/correctness/noUnusedImports: TSDocs
|
// biome-ignore lint/correctness/noUnusedImports: TSDocs
|
||||||
import type { SessionSaveData } from "#system/game-data";
|
import type { SessionSaveData } from "#types/save-data";
|
||||||
import type { ObjectValues } from "#types/type-helpers";
|
import type { ObjectValues } from "#types/type-helpers";
|
||||||
|
|
||||||
/** Subset of {@linkcode ArenaTagType}s that apply some negative effect to pokemon that switch in ({@link https://bulbapedia.bulbagarden.net/wiki/List_of_moves_that_cause_entry_hazards#List_of_traps | entry hazards} and Imprison. */
|
/** Subset of {@linkcode ArenaTagType}s that apply some negative effect to pokemon that switch in ({@link https://bulbapedia.bulbagarden.net/wiki/List_of_moves_that_cause_entry_hazards#List_of_traps | entry hazards} and Imprison. */
|
||||||
@ -38,6 +38,7 @@ type SerializableArenaTagTypeMap = Pick<ArenaTagTypeMap, SerializableArenaTagTyp
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Type mapping all `ArenaTag`s to type-safe representations of their serialized forms.
|
* Type mapping all `ArenaTag`s to type-safe representations of their serialized forms.
|
||||||
|
*
|
||||||
* @interface
|
* @interface
|
||||||
*/
|
*/
|
||||||
export type ArenaTagDataMap = {
|
export type ArenaTagDataMap = {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// biome-ignore-start lint/correctness/noUnusedImports: Used in a TSDoc comment
|
// biome-ignore-start lint/correctness/noUnusedImports: Used in a TSDoc comment
|
||||||
import type { AbilityBattlerTag, BattlerTagTypeMap, SerializableBattlerTag, TypeBoostTag } from "#data/battler-tags";
|
import type { AbilityBattlerTag, BattlerTagTypeMap, SerializableBattlerTag, TypeBoostTag } from "#data/battler-tags";
|
||||||
import type { AbilityId } from "#enums/ability-id";
|
import type { AbilityId } from "#enums/ability-id";
|
||||||
import type { SessionSaveData } from "#system/game-data";
|
import type { SessionSaveData } from "#types/save-data";
|
||||||
// biome-ignore-end lint/correctness/noUnusedImports: Used in a TSDoc comment
|
// biome-ignore-end lint/correctness/noUnusedImports: Used in a TSDoc comment
|
||||||
|
|
||||||
import type { BattlerTagType } from "#enums/battler-tag-type";
|
import type { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
|
143
src/@types/save-data.ts
Normal file
143
src/@types/save-data.ts
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
import type { PokeballCounts } from "#app/battle-scene";
|
||||||
|
import type { Tutorial } from "#app/tutorial";
|
||||||
|
import type { BattleType } from "#enums/battle-type";
|
||||||
|
import type { GameModes } from "#enums/game-modes";
|
||||||
|
import type { MoveId } from "#enums/move-id";
|
||||||
|
import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
|
import type { PlayerGender } from "#enums/player-gender";
|
||||||
|
import type { PokemonType } from "#enums/pokemon-type";
|
||||||
|
import type { MysteryEncounterSaveData } from "#mystery-encounters/mystery-encounter-save-data";
|
||||||
|
import type { Variant } from "#sprites/variant";
|
||||||
|
import type { ArenaData } from "#system/arena-data";
|
||||||
|
import type { ChallengeData } from "#system/challenge-data";
|
||||||
|
import type { EggData } from "#system/egg-data";
|
||||||
|
import type { GameStats } from "#system/game-stats";
|
||||||
|
import type { ModifierData } from "#system/modifier-data";
|
||||||
|
import type { PokemonData } from "#system/pokemon-data";
|
||||||
|
import type { TrainerData } from "#system/trainer-data";
|
||||||
|
import type { DexData } from "./dex-data";
|
||||||
|
|
||||||
|
export interface SystemSaveData {
|
||||||
|
trainerId: number;
|
||||||
|
secretId: number;
|
||||||
|
gender: PlayerGender;
|
||||||
|
dexData: DexData;
|
||||||
|
starterData: StarterData;
|
||||||
|
gameStats: GameStats;
|
||||||
|
unlocks: Unlocks;
|
||||||
|
achvUnlocks: AchvUnlocks;
|
||||||
|
voucherUnlocks: VoucherUnlocks;
|
||||||
|
voucherCounts: VoucherCounts;
|
||||||
|
eggs: EggData[];
|
||||||
|
gameVersion: string;
|
||||||
|
timestamp: number;
|
||||||
|
eggPity: number[];
|
||||||
|
unlockPity: number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SessionSaveData {
|
||||||
|
seed: string;
|
||||||
|
playTime: number;
|
||||||
|
gameMode: GameModes;
|
||||||
|
party: PokemonData[];
|
||||||
|
enemyParty: PokemonData[];
|
||||||
|
modifiers: ModifierData[];
|
||||||
|
enemyModifiers: ModifierData[];
|
||||||
|
arena: ArenaData;
|
||||||
|
pokeballCounts: PokeballCounts;
|
||||||
|
money: number;
|
||||||
|
score: number;
|
||||||
|
waveIndex: number;
|
||||||
|
battleType: BattleType;
|
||||||
|
trainer: TrainerData;
|
||||||
|
gameVersion: string;
|
||||||
|
/** The player-chosen name of the run */
|
||||||
|
name: string;
|
||||||
|
timestamp: number;
|
||||||
|
challenges: ChallengeData[];
|
||||||
|
mysteryEncounterType: MysteryEncounterType | -1; // Only defined when current wave is ME,
|
||||||
|
mysteryEncounterSaveData: MysteryEncounterSaveData;
|
||||||
|
/**
|
||||||
|
* Counts the amount of pokemon fainted in your party during the current arena encounter.
|
||||||
|
*/
|
||||||
|
playerFaints: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Unlocks {
|
||||||
|
[key: number]: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AchvUnlocks {
|
||||||
|
[key: string]: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VoucherUnlocks {
|
||||||
|
[key: string]: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VoucherCounts {
|
||||||
|
[type: string]: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type StarterMoveset = [MoveId] | [MoveId, MoveId] | [MoveId, MoveId, MoveId] | [MoveId, MoveId, MoveId, MoveId];
|
||||||
|
|
||||||
|
export interface StarterFormMoveData {
|
||||||
|
[key: number]: StarterMoveset;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StarterMoveData {
|
||||||
|
[key: number]: StarterMoveset | StarterFormMoveData;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StarterAttributes {
|
||||||
|
nature?: number;
|
||||||
|
ability?: number;
|
||||||
|
variant?: number;
|
||||||
|
form?: number;
|
||||||
|
female?: boolean;
|
||||||
|
shiny?: boolean;
|
||||||
|
favorite?: boolean;
|
||||||
|
nickname?: string;
|
||||||
|
tera?: PokemonType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DexAttrProps {
|
||||||
|
shiny: boolean;
|
||||||
|
female: boolean;
|
||||||
|
variant: Variant;
|
||||||
|
formIndex: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RunHistoryData = Record<number, RunEntry>;
|
||||||
|
|
||||||
|
export interface RunEntry {
|
||||||
|
entry: SessionSaveData;
|
||||||
|
isVictory: boolean;
|
||||||
|
/*Automatically set to false at the moment - implementation TBD*/
|
||||||
|
isFavorite: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StarterDataEntry {
|
||||||
|
moveset: StarterMoveset | StarterFormMoveData | null;
|
||||||
|
eggMoves: number;
|
||||||
|
candyCount: number;
|
||||||
|
friendship: number;
|
||||||
|
abilityAttr: number;
|
||||||
|
passiveAttr: number;
|
||||||
|
valueReduction: number;
|
||||||
|
classicWinCount: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StarterData {
|
||||||
|
[key: number]: StarterDataEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Rework into a bitmask
|
||||||
|
export type TutorialFlags = {
|
||||||
|
[key in Tutorial]: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Rework into a bitmask
|
||||||
|
export interface SeenDialogues {
|
||||||
|
[key: string]: boolean;
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import type { SessionSaveData } from "#system/game-data";
|
import type { SessionSaveData } from "./save-data";
|
||||||
|
|
||||||
export interface SessionSaveMigrator {
|
export interface SessionSaveMigrator {
|
||||||
version: string;
|
version: string;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { SystemSaveData } from "#system/game-data";
|
import type { SystemSaveData } from "./save-data";
|
||||||
|
|
||||||
export interface SystemSaveMigrator {
|
export interface SystemSaveMigrator {
|
||||||
version: string;
|
version: string;
|
||||||
|
@ -121,13 +121,13 @@ import { vouchers } from "#system/voucher";
|
|||||||
import { trainerConfigs } from "#trainers/trainer-config";
|
import { trainerConfigs } from "#trainers/trainer-config";
|
||||||
import type { HeldModifierConfig } from "#types/held-modifier-config";
|
import type { HeldModifierConfig } from "#types/held-modifier-config";
|
||||||
import type { Localizable } from "#types/locales";
|
import type { Localizable } from "#types/locales";
|
||||||
import { AbilityBar } from "#ui/ability-bar";
|
import { AbilityBar } from "#ui/containers/ability-bar";
|
||||||
import { ArenaFlyout } from "#ui/arena-flyout";
|
import { ArenaFlyout } from "#ui/containers/arena-flyout";
|
||||||
import { CandyBar } from "#ui/candy-bar";
|
import { CandyBar } from "#ui/containers/candy-bar";
|
||||||
import { CharSprite } from "#ui/char-sprite";
|
import { CharSprite } from "#ui/containers/char-sprite";
|
||||||
import { PartyExpBar } from "#ui/party-exp-bar";
|
import { PartyExpBar } from "#ui/containers/party-exp-bar";
|
||||||
import { PokeballTray } from "#ui/pokeball-tray";
|
import { PokeballTray } from "#ui/containers/pokeball-tray";
|
||||||
import { PokemonInfoContainer } from "#ui/pokemon-info-container";
|
import { PokemonInfoContainer } from "#ui/containers/pokemon-info-container";
|
||||||
import { addTextObject, getTextColor } from "#ui/text";
|
import { addTextObject, getTextColor } from "#ui/text";
|
||||||
import { UI } from "#ui/ui";
|
import { UI } from "#ui/ui";
|
||||||
import { addUiThemeOverrides } from "#ui/ui-theme";
|
import { addUiThemeOverrides } from "#ui/ui-theme";
|
||||||
@ -804,7 +804,7 @@ export class BattleScene extends SceneBase {
|
|||||||
* @returns An array of {@linkcode Pokemon}, as described above.
|
* @returns An array of {@linkcode Pokemon}, as described above.
|
||||||
*/
|
*/
|
||||||
public getField(activeOnly = false): Pokemon[] {
|
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 playerField = this.getPlayerField();
|
||||||
const enemyField = this.getEnemyField();
|
const enemyField = this.getEnemyField();
|
||||||
ret.splice(0, playerField.length, ...playerField);
|
ret.splice(0, playerField.length, ...playerField);
|
||||||
@ -827,10 +827,10 @@ export class BattleScene extends SceneBase {
|
|||||||
do {
|
do {
|
||||||
targetingMovePhase = this.phaseManager.findPhase(
|
targetingMovePhase = this.phaseManager.findPhase(
|
||||||
mp =>
|
mp =>
|
||||||
mp.is("MovePhase") &&
|
mp.is("MovePhase")
|
||||||
mp.targets.length === 1 &&
|
&& mp.targets.length === 1
|
||||||
mp.targets[0] === removedPokemon.getBattlerIndex() &&
|
&& mp.targets[0] === removedPokemon.getBattlerIndex()
|
||||||
mp.pokemon.isPlayer() !== allyPokemon.isPlayer(),
|
&& mp.pokemon.isPlayer() !== allyPokemon.isPlayer(),
|
||||||
) as MovePhase;
|
) as MovePhase;
|
||||||
if (targetingMovePhase && targetingMovePhase.targets[0] !== allyPokemon.getBattlerIndex()) {
|
if (targetingMovePhase && targetingMovePhase.targets[0] !== allyPokemon.getBattlerIndex()) {
|
||||||
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.
|
* @param pokemonId - The ID whose Pokemon will be retrieved.
|
||||||
* @returns The {@linkcode Pokemon} associated with the given id.
|
* @returns The {@linkcode Pokemon} associated with the given id.
|
||||||
* Returns `null` if the ID is `undefined` or not present in either party.
|
* 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 {
|
getPokemonById(pokemonId: number | undefined): Pokemon | null {
|
||||||
if (isNullOrUndefined(pokemonId)) {
|
if (isNullOrUndefined(pokemonId)) {
|
||||||
@ -1315,16 +1317,16 @@ export class BattleScene extends SceneBase {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (
|
if (
|
||||||
!this.gameMode.hasTrainers ||
|
!this.gameMode.hasTrainers
|
||||||
Overrides.BATTLE_TYPE_OVERRIDE === BattleType.WILD ||
|
|| Overrides.BATTLE_TYPE_OVERRIDE === BattleType.WILD
|
||||||
(Overrides.DISABLE_STANDARD_TRAINERS_OVERRIDE && isNullOrUndefined(trainerData))
|
|| (Overrides.DISABLE_STANDARD_TRAINERS_OVERRIDE && isNullOrUndefined(trainerData))
|
||||||
) {
|
) {
|
||||||
newBattleType = BattleType.WILD;
|
newBattleType = BattleType.WILD;
|
||||||
} else {
|
} else {
|
||||||
newBattleType =
|
newBattleType =
|
||||||
Overrides.BATTLE_TYPE_OVERRIDE ??
|
Overrides.BATTLE_TYPE_OVERRIDE
|
||||||
battleType ??
|
?? battleType
|
||||||
(this.gameMode.isWaveTrainer(newWaveIndex, this.arena) ? BattleType.TRAINER : BattleType.WILD);
|
?? (this.gameMode.isWaveTrainer(newWaveIndex, this.arena) ? BattleType.TRAINER : BattleType.WILD);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newBattleType === BattleType.TRAINER) {
|
if (newBattleType === BattleType.TRAINER) {
|
||||||
@ -1335,12 +1337,12 @@ export class BattleScene extends SceneBase {
|
|||||||
doubleTrainer = true;
|
doubleTrainer = true;
|
||||||
} else if (trainerConfigs[trainerType].hasDouble) {
|
} else if (trainerConfigs[trainerType].hasDouble) {
|
||||||
doubleTrainer =
|
doubleTrainer =
|
||||||
Overrides.RANDOM_TRAINER_OVERRIDE?.alwaysDouble ||
|
Overrides.RANDOM_TRAINER_OVERRIDE?.alwaysDouble
|
||||||
!randSeedInt(this.getDoubleBattleChance(newWaveIndex, playerField));
|
|| !randSeedInt(this.getDoubleBattleChance(newWaveIndex, playerField));
|
||||||
// Add a check that special trainers can't be double except for tate and liza - they should use the normal double chance
|
// Add a check that special trainers can't be double except for tate and liza - they should use the normal double chance
|
||||||
if (
|
if (
|
||||||
trainerConfigs[trainerType].trainerTypeDouble &&
|
trainerConfigs[trainerType].trainerTypeDouble
|
||||||
![TrainerType.TATE, TrainerType.LIZA].includes(trainerType)
|
&& ![TrainerType.TATE, TrainerType.LIZA].includes(trainerType)
|
||||||
) {
|
) {
|
||||||
doubleTrainer = false;
|
doubleTrainer = false;
|
||||||
}
|
}
|
||||||
@ -1357,8 +1359,8 @@ export class BattleScene extends SceneBase {
|
|||||||
// Check for mystery encounter
|
// Check for mystery encounter
|
||||||
// Can only occur in place of a standard (non-boss) wild battle, waves 10-180
|
// Can only occur in place of a standard (non-boss) wild battle, waves 10-180
|
||||||
if (
|
if (
|
||||||
!Overrides.BATTLE_TYPE_OVERRIDE &&
|
!Overrides.BATTLE_TYPE_OVERRIDE
|
||||||
(this.isWaveMysteryEncounter(newBattleType, newWaveIndex) || newBattleType === BattleType.MYSTERY_ENCOUNTER)
|
&& (this.isWaveMysteryEncounter(newBattleType, newWaveIndex) || newBattleType === BattleType.MYSTERY_ENCOUNTER)
|
||||||
) {
|
) {
|
||||||
newBattleType = BattleType.MYSTERY_ENCOUNTER;
|
newBattleType = BattleType.MYSTERY_ENCOUNTER;
|
||||||
// Reset to base spawn weight
|
// Reset to base spawn weight
|
||||||
@ -1448,9 +1450,9 @@ export class BattleScene extends SceneBase {
|
|||||||
const isNewBiome = this.isNewBiome(lastBattle);
|
const isNewBiome = this.isNewBiome(lastBattle);
|
||||||
/** Whether to reset and recall pokemon */
|
/** Whether to reset and recall pokemon */
|
||||||
const resetArenaState =
|
const resetArenaState =
|
||||||
isNewBiome ||
|
isNewBiome
|
||||||
[BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(this.currentBattle.battleType) ||
|
|| [BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(this.currentBattle.battleType)
|
||||||
this.currentBattle.battleSpec === BattleSpec.FINAL_BOSS;
|
|| this.currentBattle.battleSpec === BattleSpec.FINAL_BOSS;
|
||||||
|
|
||||||
for (const enemyPokemon of this.getEnemyParty()) {
|
for (const enemyPokemon of this.getEnemyParty()) {
|
||||||
enemyPokemon.destroy();
|
enemyPokemon.destroy();
|
||||||
@ -1476,6 +1478,7 @@ export class BattleScene extends SceneBase {
|
|||||||
pokemon.resetBattleAndWaveData();
|
pokemon.resetBattleAndWaveData();
|
||||||
pokemon.resetTera();
|
pokemon.resetTera();
|
||||||
applyAbAttrs("PostBattleInitAbAttr", { pokemon });
|
applyAbAttrs("PostBattleInitAbAttr", { pokemon });
|
||||||
|
// Terapagos resets tera on each fight
|
||||||
if (pokemon.hasSpecies(SpeciesId.TERAPAGOS)) {
|
if (pokemon.hasSpecies(SpeciesId.TERAPAGOS)) {
|
||||||
this.arena.playerTerasUsed = 0;
|
this.arena.playerTerasUsed = 0;
|
||||||
}
|
}
|
||||||
@ -1521,8 +1524,8 @@ export class BattleScene extends SceneBase {
|
|||||||
const fieldScale =
|
const fieldScale =
|
||||||
Math.floor(
|
Math.floor(
|
||||||
Math.pow(
|
Math.pow(
|
||||||
1 /
|
1
|
||||||
this.getField(true)
|
/ this.getField(true)
|
||||||
.map(p => p.getSpriteScale())
|
.map(p => p.getSpriteScale())
|
||||||
.reduce((highestScale: number, scale: number) => (highestScale = Math.max(scale, highestScale)), 0),
|
.reduce((highestScale: number, scale: number) => (highestScale = Math.max(scale, highestScale)), 0),
|
||||||
0.7,
|
0.7,
|
||||||
@ -1546,10 +1549,10 @@ export class BattleScene extends SceneBase {
|
|||||||
|
|
||||||
this.tweens.add({
|
this.tweens.add({
|
||||||
targets: this.field,
|
targets: this.field,
|
||||||
scale: scale,
|
scale,
|
||||||
x: (defaultWidth - scaledWidth) / 2,
|
x: (defaultWidth - scaledWidth) / 2,
|
||||||
y: defaultHeight - scaledHeight,
|
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",
|
ease: "Sine.easeInOut",
|
||||||
onComplete: () => resolve(),
|
onComplete: () => resolve(),
|
||||||
});
|
});
|
||||||
@ -1557,20 +1560,20 @@ export class BattleScene extends SceneBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getSpeciesFormIndex(species: PokemonSpecies, gender?: Gender, nature?: Nature, ignoreArena?: boolean): number {
|
getSpeciesFormIndex(species: PokemonSpecies, gender?: Gender, nature?: Nature, ignoreArena?: boolean): number {
|
||||||
if (!species.forms?.length) {
|
if (species.forms?.length === 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isEggPhase =
|
const isEggPhase =
|
||||||
this.phaseManager.getCurrentPhase().is("EggLapsePhase") ||
|
this.phaseManager.getCurrentPhase().is("EggLapsePhase")
|
||||||
this.phaseManager.getCurrentPhase().is("EggHatchPhase");
|
|| this.phaseManager.getCurrentPhase().is("EggHatchPhase");
|
||||||
|
|
||||||
if (
|
if (
|
||||||
// Give trainers with specialty types an appropriately-typed form for Wormadam, Rotom, Arceus, Oricorio, Silvally, or Paldean Tauros.
|
// Give trainers with specialty types an appropriately-typed form for Wormadam, Rotom, Arceus, Oricorio, Silvally, or Paldean Tauros.
|
||||||
!isEggPhase &&
|
!isEggPhase
|
||||||
this.currentBattle?.battleType === BattleType.TRAINER &&
|
&& this.currentBattle?.battleType === BattleType.TRAINER
|
||||||
!isNullOrUndefined(this.currentBattle.trainer) &&
|
&& !isNullOrUndefined(this.currentBattle.trainer)
|
||||||
this.currentBattle.trainer.config.hasSpecialtyType()
|
&& this.currentBattle.trainer.config.hasSpecialtyType()
|
||||||
) {
|
) {
|
||||||
if (species.speciesId === SpeciesId.WORMADAM) {
|
if (species.speciesId === SpeciesId.WORMADAM) {
|
||||||
switch (this.currentBattle.trainer.config.specialtyType) {
|
switch (this.currentBattle.trainer.config.specialtyType) {
|
||||||
@ -1662,9 +1665,9 @@ export class BattleScene extends SceneBase {
|
|||||||
return randSeedInt(8);
|
return randSeedInt(8);
|
||||||
case SpeciesId.EEVEE:
|
case SpeciesId.EEVEE:
|
||||||
if (
|
if (
|
||||||
this.currentBattle?.battleType === BattleType.TRAINER &&
|
this.currentBattle?.battleType === BattleType.TRAINER
|
||||||
this.currentBattle?.waveIndex < 30 &&
|
&& this.currentBattle?.waveIndex < 30
|
||||||
!isEggPhase
|
&& !isEggPhase
|
||||||
) {
|
) {
|
||||||
return 0; // No Partner Eevee for Wave 12 Preschoolers
|
return 0; // No Partner Eevee for Wave 12 Preschoolers
|
||||||
}
|
}
|
||||||
@ -1774,9 +1777,9 @@ export class BattleScene extends SceneBase {
|
|||||||
} else {
|
} else {
|
||||||
this.executeWithSeedOffset(() => {
|
this.executeWithSeedOffset(() => {
|
||||||
isBoss =
|
isBoss =
|
||||||
waveIndex % 10 === 0 ||
|
waveIndex % 10 === 0
|
||||||
(this.gameMode.hasRandomBosses &&
|
|| (this.gameMode.hasRandomBosses
|
||||||
randSeedInt(100) < Math.min(Math.max(Math.ceil((waveIndex - 250) / 50), 0) * 2, 30));
|
&& randSeedInt(100) < Math.min(Math.max(Math.ceil((waveIndex - 250) / 50), 0) * 2, 30));
|
||||||
}, waveIndex << 2);
|
}, waveIndex << 2);
|
||||||
}
|
}
|
||||||
if (!isBoss) {
|
if (!isBoss) {
|
||||||
@ -1788,11 +1791,9 @@ export class BattleScene extends SceneBase {
|
|||||||
if (level >= 100) {
|
if (level >= 100) {
|
||||||
ret++;
|
ret++;
|
||||||
}
|
}
|
||||||
if (species) {
|
if (species && species.baseTotal >= 670) {
|
||||||
if (species.baseTotal >= 670) {
|
|
||||||
ret++;
|
ret++;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
ret += Math.floor(waveIndex / 250);
|
ret += Math.floor(waveIndex / 250);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -1835,12 +1836,7 @@ export class BattleScene extends SceneBase {
|
|||||||
this.rngCounter = 0;
|
this.rngCounter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
executeWithSeedOffset(
|
executeWithSeedOffset(func: () => void, offset: number, seedOverride?: string): void {
|
||||||
// biome-ignore lint/complexity/noBannedTypes: Refactor to not use Function
|
|
||||||
func: Function,
|
|
||||||
offset: number,
|
|
||||||
seedOverride?: string,
|
|
||||||
): void {
|
|
||||||
if (!func) {
|
if (!func) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1897,8 +1893,8 @@ export class BattleScene extends SceneBase {
|
|||||||
): Phaser.GameObjects.Sprite {
|
): Phaser.GameObjects.Sprite {
|
||||||
sprite.setPipeline(this.spritePipeline, {
|
sprite.setPipeline(this.spritePipeline, {
|
||||||
tone: [0.0, 0.0, 0.0, 0.0],
|
tone: [0.0, 0.0, 0.0, 0.0],
|
||||||
hasShadow: hasShadow,
|
hasShadow,
|
||||||
ignoreOverride: ignoreOverride,
|
ignoreOverride,
|
||||||
teraColor: pokemon ? getTypeRgb(pokemon.getTeraType()) : undefined,
|
teraColor: pokemon ? getTypeRgb(pokemon.getTeraType()) : undefined,
|
||||||
isTerastallized: pokemon ? pokemon.isTerastallized : false,
|
isTerastallized: pokemon ? pokemon.isTerastallized : false,
|
||||||
});
|
});
|
||||||
@ -1919,7 +1915,7 @@ export class BattleScene extends SceneBase {
|
|||||||
targets: this.fieldOverlay,
|
targets: this.fieldOverlay,
|
||||||
alpha: 0.5,
|
alpha: 0.5,
|
||||||
ease: "Sine.easeOut",
|
ease: "Sine.easeOut",
|
||||||
duration: duration,
|
duration,
|
||||||
onComplete: () => resolve(),
|
onComplete: () => resolve(),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -1930,7 +1926,7 @@ export class BattleScene extends SceneBase {
|
|||||||
this.tweens.add({
|
this.tweens.add({
|
||||||
targets: this.fieldOverlay,
|
targets: this.fieldOverlay,
|
||||||
alpha: 0,
|
alpha: 0,
|
||||||
duration: duration,
|
duration,
|
||||||
ease: "Cubic.easeIn",
|
ease: "Cubic.easeIn",
|
||||||
onComplete: () => resolve(),
|
onComplete: () => resolve(),
|
||||||
});
|
});
|
||||||
@ -1964,7 +1960,7 @@ export class BattleScene extends SceneBase {
|
|||||||
this.tweens.add({
|
this.tweens.add({
|
||||||
targets: this.shopOverlay,
|
targets: this.shopOverlay,
|
||||||
alpha: 0,
|
alpha: 0,
|
||||||
duration: duration,
|
duration,
|
||||||
ease: "Cubic.easeIn",
|
ease: "Cubic.easeIn",
|
||||||
onComplete: () => resolve(),
|
onComplete: () => resolve(),
|
||||||
});
|
});
|
||||||
@ -2041,7 +2037,7 @@ export class BattleScene extends SceneBase {
|
|||||||
this.luckLabelText.setX(this.scaledCanvas.width - 2 - (this.luckText.displayWidth + 2));
|
this.luckLabelText.setX(this.scaledCanvas.width - 2 - (this.luckText.displayWidth + 2));
|
||||||
this.tweens.add({
|
this.tweens.add({
|
||||||
targets: labels,
|
targets: labels,
|
||||||
duration: duration,
|
duration,
|
||||||
alpha: 1,
|
alpha: 1,
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
for (const label of labels) {
|
for (const label of labels) {
|
||||||
@ -2058,7 +2054,7 @@ export class BattleScene extends SceneBase {
|
|||||||
const labels = [this.luckLabelText, this.luckText];
|
const labels = [this.luckLabelText, this.luckText];
|
||||||
this.tweens.add({
|
this.tweens.add({
|
||||||
targets: labels,
|
targets: labels,
|
||||||
duration: duration,
|
duration,
|
||||||
alpha: 0,
|
alpha: 0,
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
for (const label of labels) {
|
for (const label of labels) {
|
||||||
@ -2072,9 +2068,9 @@ export class BattleScene extends SceneBase {
|
|||||||
const enemyModifierCount = this.enemyModifiers.filter(m => m.isIconVisible()).length;
|
const enemyModifierCount = this.enemyModifiers.filter(m => m.isIconVisible()).length;
|
||||||
const biomeWaveTextHeight = this.biomeWaveText.getBottomLeft().y - this.biomeWaveText.getTopLeft().y;
|
const biomeWaveTextHeight = this.biomeWaveText.getBottomLeft().y - this.biomeWaveText.getTopLeft().y;
|
||||||
this.biomeWaveText.setY(
|
this.biomeWaveText.setY(
|
||||||
-this.scaledCanvas.height +
|
-this.scaledCanvas.height
|
||||||
(enemyModifierCount ? (enemyModifierCount <= 12 ? 15 : 24) : 0) +
|
+ (enemyModifierCount ? (enemyModifierCount <= 12 ? 15 : 24) : 0)
|
||||||
biomeWaveTextHeight / 2,
|
+ biomeWaveTextHeight / 2,
|
||||||
);
|
);
|
||||||
this.moneyText.setY(this.biomeWaveText.y + 10);
|
this.moneyText.setY(this.biomeWaveText.y + 10);
|
||||||
this.scoreText.setY(this.moneyText.y + 10);
|
this.scoreText.setY(this.moneyText.y + 10);
|
||||||
@ -2098,9 +2094,9 @@ export class BattleScene extends SceneBase {
|
|||||||
|
|
||||||
addFaintedEnemyScore(enemy: EnemyPokemon): void {
|
addFaintedEnemyScore(enemy: EnemyPokemon): void {
|
||||||
let scoreIncrease =
|
let scoreIncrease =
|
||||||
enemy.getSpeciesForm().getBaseExp() *
|
enemy.getSpeciesForm().getBaseExp()
|
||||||
(enemy.level / this.getMaxExpLevel()) *
|
* (enemy.level / this.getMaxExpLevel())
|
||||||
((enemy.ivs.reduce((iv: number, total: number) => (total += iv), 0) / 93) * 0.2 + 0.8);
|
* ((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(
|
this.findModifiers(m => m instanceof PokemonHeldItemModifier && m.pokemonId === enemy.id, false).map(
|
||||||
m => (scoreIncrease *= (m as PokemonHeldItemModifier).getScoreMultiplier()),
|
m => (scoreIncrease *= (m as PokemonHeldItemModifier).getScoreMultiplier()),
|
||||||
);
|
);
|
||||||
@ -2621,8 +2617,8 @@ export class BattleScene extends SceneBase {
|
|||||||
const waveIndex = this.currentBattle.waveIndex;
|
const waveIndex = this.currentBattle.waveIndex;
|
||||||
const waveSetIndex = Math.ceil(waveIndex / 10) - 1;
|
const waveSetIndex = Math.ceil(waveIndex / 10) - 1;
|
||||||
const moneyValue =
|
const moneyValue =
|
||||||
Math.pow((waveSetIndex + 1 + (0.75 + (((waveIndex - 1) % 10) + 1) / 10)) * 100, 1 + 0.005 * waveSetIndex) *
|
Math.pow((waveSetIndex + 1 + (0.75 + (((waveIndex - 1) % 10) + 1) / 10)) * 100, 1 + 0.005 * waveSetIndex)
|
||||||
moneyMultiplier;
|
* moneyMultiplier;
|
||||||
return Math.floor(moneyValue / 10) * 10;
|
return Math.floor(moneyValue / 10) * 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2736,10 +2732,8 @@ export class BattleScene extends SceneBase {
|
|||||||
}
|
}
|
||||||
if (!ignoreUpdate) {
|
if (!ignoreUpdate) {
|
||||||
this.updateModifiers(false, instant);
|
this.updateModifiers(false, instant);
|
||||||
resolve();
|
|
||||||
} else {
|
|
||||||
resolve();
|
|
||||||
}
|
}
|
||||||
|
resolve();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2936,8 +2930,8 @@ export class BattleScene extends SceneBase {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const isBoss =
|
const isBoss =
|
||||||
enemyPokemon.isBoss() ||
|
enemyPokemon.isBoss()
|
||||||
(this.currentBattle.battleType === BattleType.TRAINER && !!this.currentBattle.trainer?.config.isBoss);
|
|| (this.currentBattle.battleType === BattleType.TRAINER && !!this.currentBattle.trainer?.config.isBoss);
|
||||||
let upgradeChance = 32;
|
let upgradeChance = 32;
|
||||||
if (isBoss) {
|
if (isBoss) {
|
||||||
upgradeChance /= 2;
|
upgradeChance /= 2;
|
||||||
@ -3006,15 +3000,15 @@ export class BattleScene extends SceneBase {
|
|||||||
for (let m = 0; m < modifiers.length; m++) {
|
for (let m = 0; m < modifiers.length; m++) {
|
||||||
const modifier = modifiers[m];
|
const modifier = modifiers[m];
|
||||||
if (
|
if (
|
||||||
modifier instanceof PokemonHeldItemModifier &&
|
modifier instanceof PokemonHeldItemModifier
|
||||||
!this.getPokemonById((modifier as PokemonHeldItemModifier).pokemonId)
|
&& !this.getPokemonById((modifier as PokemonHeldItemModifier).pokemonId)
|
||||||
) {
|
) {
|
||||||
modifiers.splice(m--, 1);
|
modifiers.splice(m--, 1);
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
modifier instanceof PokemonHeldItemModifier &&
|
modifier instanceof PokemonHeldItemModifier
|
||||||
!isNullOrUndefined(modifier.getSpecies()) &&
|
&& !isNullOrUndefined(modifier.getSpecies())
|
||||||
!this.getPokemonById(modifier.pokemonId)?.hasSpecies(modifier.getSpecies()!)
|
&& !this.getPokemonById(modifier.pokemonId)?.hasSpecies(modifier.getSpecies()!)
|
||||||
) {
|
) {
|
||||||
modifiers.splice(m--, 1);
|
modifiers.splice(m--, 1);
|
||||||
}
|
}
|
||||||
@ -3114,7 +3108,7 @@ export class BattleScene extends SceneBase {
|
|||||||
* Apply all modifiers that match `modifierType` in a random order
|
* Apply all modifiers that match `modifierType` in a random order
|
||||||
* @param modifierType The type of modifier to apply; must extend {@linkcode PersistentModifier}
|
* @param modifierType The type of modifier to apply; must extend {@linkcode PersistentModifier}
|
||||||
* @param player Whether to search the player (`true`) or the enemy (`false`); Defaults to `true`
|
* @param player Whether to search the player (`true`) or the enemy (`false`); Defaults to `true`
|
||||||
* @param ...args The list of arguments needed to invoke `modifierType.apply`
|
* @param args The list of arguments needed to invoke `modifierType.apply`
|
||||||
* @returns the list of all modifiers that matched `modifierType` and were applied.
|
* @returns the list of all modifiers that matched `modifierType` and were applied.
|
||||||
*/
|
*/
|
||||||
applyShuffledModifiers<T extends PersistentModifier>(
|
applyShuffledModifiers<T extends PersistentModifier>(
|
||||||
@ -3128,7 +3122,7 @@ export class BattleScene extends SceneBase {
|
|||||||
this.executeWithSeedOffset(
|
this.executeWithSeedOffset(
|
||||||
() => {
|
() => {
|
||||||
const shuffleModifiers = mods => {
|
const shuffleModifiers = mods => {
|
||||||
if (mods.length < 1) {
|
if (mods.length === 0) {
|
||||||
return mods;
|
return mods;
|
||||||
}
|
}
|
||||||
const rand = randSeedInt(mods.length);
|
const rand = randSeedInt(mods.length);
|
||||||
@ -3146,7 +3140,7 @@ export class BattleScene extends SceneBase {
|
|||||||
* Apply all modifiers that match `modifierType`
|
* Apply all modifiers that match `modifierType`
|
||||||
* @param modifierType The type of modifier to apply; must extend {@linkcode PersistentModifier}
|
* @param modifierType The type of modifier to apply; must extend {@linkcode PersistentModifier}
|
||||||
* @param player Whether to search the player (`true`) or the enemy (`false`); Defaults to `true`
|
* @param player Whether to search the player (`true`) or the enemy (`false`); Defaults to `true`
|
||||||
* @param ...args The list of arguments needed to invoke `modifierType.apply`
|
* @param args The list of arguments needed to invoke `modifierType.apply`
|
||||||
* @returns the list of all modifiers that matched `modifierType` and were applied.
|
* @returns the list of all modifiers that matched `modifierType` and were applied.
|
||||||
*/
|
*/
|
||||||
applyModifiers<T extends PersistentModifier>(
|
applyModifiers<T extends PersistentModifier>(
|
||||||
@ -3181,7 +3175,7 @@ export class BattleScene extends SceneBase {
|
|||||||
* Apply the first modifier that matches `modifierType`
|
* Apply the first modifier that matches `modifierType`
|
||||||
* @param modifierType The type of modifier to apply; must extend {@linkcode PersistentModifier}
|
* @param modifierType The type of modifier to apply; must extend {@linkcode PersistentModifier}
|
||||||
* @param player Whether to search the player (`true`) or the enemy (`false`); Defaults to `true`
|
* @param player Whether to search the player (`true`) or the enemy (`false`); Defaults to `true`
|
||||||
* @param ...args The list of arguments needed to invoke `modifierType.apply`
|
* @param args The list of arguments needed to invoke `modifierType.apply`
|
||||||
* @returns the first modifier that matches `modifierType` and was applied; return `null` if none matched
|
* @returns the first modifier that matches `modifierType` and was applied; return `null` if none matched
|
||||||
*/
|
*/
|
||||||
applyModifier<T extends PersistentModifier>(
|
applyModifier<T extends PersistentModifier>(
|
||||||
@ -3278,8 +3272,8 @@ export class BattleScene extends SceneBase {
|
|||||||
|
|
||||||
validateAchv(achv: Achv, args?: unknown[]): boolean {
|
validateAchv(achv: Achv, args?: unknown[]): boolean {
|
||||||
if (
|
if (
|
||||||
(!this.gameData.achvUnlocks.hasOwnProperty(achv.id) || Overrides.ACHIEVEMENTS_REUNLOCK_OVERRIDE) &&
|
(!this.gameData.achvUnlocks.hasOwnProperty(achv.id) || Overrides.ACHIEVEMENTS_REUNLOCK_OVERRIDE)
|
||||||
achv.validate(args)
|
&& achv.validate(args)
|
||||||
) {
|
) {
|
||||||
this.gameData.achvUnlocks[achv.id] = Date.now();
|
this.gameData.achvUnlocks[achv.id] = Date.now();
|
||||||
this.ui.achvBar.showAchv(achv);
|
this.ui.achvBar.showAchv(achv);
|
||||||
@ -3329,7 +3323,7 @@ export class BattleScene extends SceneBase {
|
|||||||
/**
|
/**
|
||||||
* This function retrieves the sprite and audio keys for active Pokemon.
|
* This function retrieves the sprite and audio keys for active Pokemon.
|
||||||
* Active Pokemon include both enemy and player Pokemon of the current wave.
|
* Active Pokemon include both enemy and player Pokemon of the current wave.
|
||||||
* Note: Questions on garbage collection go to @frutescens
|
* Note: Questions on garbage collection go to `@frutescens`
|
||||||
* @returns a string array of active sprite and audio keys that should not be deleted
|
* @returns a string array of active sprite and audio keys that should not be deleted
|
||||||
*/
|
*/
|
||||||
getActiveKeys(): string[] {
|
getActiveKeys(): string[] {
|
||||||
@ -3417,8 +3411,8 @@ export class BattleScene extends SceneBase {
|
|||||||
|
|
||||||
if (participantIds.size > 0) {
|
if (participantIds.size > 0) {
|
||||||
if (
|
if (
|
||||||
this.currentBattle.battleType === BattleType.TRAINER ||
|
this.currentBattle.battleType === BattleType.TRAINER
|
||||||
this.currentBattle.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE
|
|| this.currentBattle.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE
|
||||||
) {
|
) {
|
||||||
expValue = Math.floor(expValue * 1.5);
|
expValue = Math.floor(expValue * 1.5);
|
||||||
} else if (this.currentBattle.isBattleMysteryEncounter() && this.currentBattle.mysteryEncounter) {
|
} else if (this.currentBattle.isBattleMysteryEncounter() && this.currentBattle.mysteryEncounter) {
|
||||||
@ -3514,12 +3508,12 @@ export class BattleScene extends SceneBase {
|
|||||||
isMysteryEncounterValidForWave(battleType: BattleType, waveIndex: number): boolean {
|
isMysteryEncounterValidForWave(battleType: BattleType, waveIndex: number): boolean {
|
||||||
const [lowestMysteryEncounterWave, highestMysteryEncounterWave] = this.gameMode.getMysteryEncounterLegalWaves();
|
const [lowestMysteryEncounterWave, highestMysteryEncounterWave] = this.gameMode.getMysteryEncounterLegalWaves();
|
||||||
return (
|
return (
|
||||||
this.gameMode.hasMysteryEncounters &&
|
this.gameMode.hasMysteryEncounters
|
||||||
battleType === BattleType.WILD &&
|
&& battleType === BattleType.WILD
|
||||||
!this.gameMode.isBoss(waveIndex) &&
|
&& !this.gameMode.isBoss(waveIndex)
|
||||||
waveIndex % 10 !== 1 &&
|
&& waveIndex % 10 !== 1
|
||||||
waveIndex < highestMysteryEncounterWave &&
|
&& waveIndex < highestMysteryEncounterWave
|
||||||
waveIndex > lowestMysteryEncounterWave
|
&& 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
|
// 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
|
// 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 =
|
const expectedEncountersByFloor =
|
||||||
(AVERAGE_ENCOUNTERS_PER_RUN_TARGET / (highestMysteryEncounterWave - lowestMysteryEncounterWave)) *
|
(AVERAGE_ENCOUNTERS_PER_RUN_TARGET / (highestMysteryEncounterWave - lowestMysteryEncounterWave))
|
||||||
(waveIndex - lowestMysteryEncounterWave);
|
* (waveIndex - lowestMysteryEncounterWave);
|
||||||
const currentRunDiffFromAvg = expectedEncountersByFloor - encounteredEvents.length;
|
const currentRunDiffFromAvg = expectedEncountersByFloor - encounteredEvents.length;
|
||||||
const favoredEncounterRate =
|
const favoredEncounterRate =
|
||||||
sessionEncounterRate +
|
sessionEncounterRate
|
||||||
Math.min(currentRunDiffFromAvg * ANTI_VARIANCE_WEIGHT_MODIFIER, MYSTERY_ENCOUNTER_SPAWN_MAX_WEIGHT / 2);
|
+ Math.min(currentRunDiffFromAvg * ANTI_VARIANCE_WEIGHT_MODIFIER, MYSTERY_ENCOUNTER_SPAWN_MAX_WEIGHT / 2);
|
||||||
|
|
||||||
const successRate = Overrides.MYSTERY_ENCOUNTER_RATE_OVERRIDE ?? favoredEncounterRate;
|
const successRate = Overrides.MYSTERY_ENCOUNTER_RATE_OVERRIDE ?? favoredEncounterRate;
|
||||||
|
|
||||||
// MEs can only spawn 3 or more waves after the previous ME, barring overrides
|
// MEs can only spawn 3 or more waves after the previous ME, barring overrides
|
||||||
const canSpawn =
|
const canSpawn = encounteredEvents.length === 0 || waveIndex - encounteredEvents.at(-1)!.waveIndex > 3;
|
||||||
encounteredEvents.length === 0 || waveIndex - encounteredEvents[encounteredEvents.length - 1].waveIndex > 3;
|
|
||||||
|
|
||||||
if (canSpawn || Overrides.MYSTERY_ENCOUNTER_RATE_OVERRIDE !== null) {
|
if (canSpawn || Overrides.MYSTERY_ENCOUNTER_RATE_OVERRIDE !== null) {
|
||||||
let roll = MYSTERY_ENCOUNTER_SPAWN_MAX_WEIGHT;
|
let roll = MYSTERY_ENCOUNTER_SPAWN_MAX_WEIGHT;
|
||||||
@ -3580,8 +3573,8 @@ export class BattleScene extends SceneBase {
|
|||||||
// Loading override or session encounter
|
// Loading override or session encounter
|
||||||
let encounter: MysteryEncounter | null;
|
let encounter: MysteryEncounter | null;
|
||||||
if (
|
if (
|
||||||
!isNullOrUndefined(Overrides.MYSTERY_ENCOUNTER_OVERRIDE) &&
|
!isNullOrUndefined(Overrides.MYSTERY_ENCOUNTER_OVERRIDE)
|
||||||
allMysteryEncounters.hasOwnProperty(Overrides.MYSTERY_ENCOUNTER_OVERRIDE)
|
&& allMysteryEncounters.hasOwnProperty(Overrides.MYSTERY_ENCOUNTER_OVERRIDE)
|
||||||
) {
|
) {
|
||||||
encounter = allMysteryEncounters[Overrides.MYSTERY_ENCOUNTER_OVERRIDE];
|
encounter = allMysteryEncounters[Overrides.MYSTERY_ENCOUNTER_OVERRIDE];
|
||||||
if (canBypass) {
|
if (canBypass) {
|
||||||
@ -3596,9 +3589,9 @@ export class BattleScene extends SceneBase {
|
|||||||
|
|
||||||
// Check for queued encounters first
|
// Check for queued encounters first
|
||||||
if (
|
if (
|
||||||
!encounter &&
|
!encounter
|
||||||
this.mysteryEncounterSaveData?.queuedEncounters &&
|
&& this.mysteryEncounterSaveData?.queuedEncounters
|
||||||
this.mysteryEncounterSaveData.queuedEncounters.length > 0
|
&& this.mysteryEncounterSaveData.queuedEncounters.length > 0
|
||||||
) {
|
) {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
while (i < this.mysteryEncounterSaveData.queuedEncounters.length && !!encounter) {
|
while (i < this.mysteryEncounterSaveData.queuedEncounters.length && !!encounter) {
|
||||||
@ -3655,11 +3648,7 @@ export class BattleScene extends SceneBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let availableEncounters: MysteryEncounter[] = [];
|
let availableEncounters: MysteryEncounter[] = [];
|
||||||
const previousEncounter =
|
const previousEncounter = this.mysteryEncounterSaveData.encounteredEvents.at(-1)?.type ?? null; // TODO: This being `null` is a bit weird
|
||||||
this.mysteryEncounterSaveData.encounteredEvents.length > 0
|
|
||||||
? this.mysteryEncounterSaveData.encounteredEvents[this.mysteryEncounterSaveData.encounteredEvents.length - 1]
|
|
||||||
.type
|
|
||||||
: null;
|
|
||||||
const disabledEncounters = this.eventManager.getEventMysteryEncountersDisabled();
|
const disabledEncounters = this.eventManager.getEventMysteryEncountersDisabled();
|
||||||
const biomeMysteryEncounters =
|
const biomeMysteryEncounters =
|
||||||
mysteryEncountersByBiome.get(this.arena.biomeType)?.filter(enc => !disabledEncounters.includes(enc)) ?? [];
|
mysteryEncountersByBiome.get(this.arena.biomeType)?.filter(enc => !disabledEncounters.includes(enc)) ?? [];
|
||||||
@ -3678,9 +3667,9 @@ export class BattleScene extends SceneBase {
|
|||||||
}
|
}
|
||||||
const disallowedGameModes = encounterCandidate.disallowedGameModes;
|
const disallowedGameModes = encounterCandidate.disallowedGameModes;
|
||||||
if (
|
if (
|
||||||
disallowedGameModes &&
|
disallowedGameModes
|
||||||
disallowedGameModes.length > 0 &&
|
&& disallowedGameModes.length > 0
|
||||||
disallowedGameModes.includes(this.gameMode.modeId)
|
&& disallowedGameModes.includes(this.gameMode.modeId)
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -3694,11 +3683,11 @@ export class BattleScene extends SceneBase {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return !(
|
return !(
|
||||||
this.mysteryEncounterSaveData.encounteredEvents.length > 0 &&
|
this.mysteryEncounterSaveData.encounteredEvents.length > 0
|
||||||
encounterCandidate.maxAllowedEncounters &&
|
&& encounterCandidate.maxAllowedEncounters
|
||||||
encounterCandidate.maxAllowedEncounters > 0 &&
|
&& encounterCandidate.maxAllowedEncounters > 0
|
||||||
this.mysteryEncounterSaveData.encounteredEvents.filter(e => e.type === encounterType).length >=
|
&& this.mysteryEncounterSaveData.encounteredEvents.filter(e => e.type === encounterType).length
|
||||||
encounterCandidate.maxAllowedEncounters
|
>= encounterCandidate.maxAllowedEncounters
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.map(m => allMysteryEncounters[m]);
|
.map(m => allMysteryEncounters[m]);
|
||||||
|
@ -237,11 +237,11 @@ export class Battle {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
this.battleType === BattleType.TRAINER ||
|
this.battleType === BattleType.TRAINER
|
||||||
this.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE
|
|| this.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE
|
||||||
) {
|
) {
|
||||||
if (!this.started && this.trainer?.config.encounterBgm && this.trainer?.getEncounterMessages()?.length) {
|
if (!this.started && this.trainer?.config.encounterBgm && this.trainer.getEncounterMessages().length > 0) {
|
||||||
return `encounter_${this.trainer?.getEncounterBgm()}`;
|
return `encounter_${this.trainer.getEncounterBgm()}`;
|
||||||
}
|
}
|
||||||
if (globalScene.musicPreference === MusicPreference.GENFIVE) {
|
if (globalScene.musicPreference === MusicPreference.GENFIVE) {
|
||||||
return this.trainer?.getBattleBgm() ?? null;
|
return this.trainer?.getBattleBgm() ?? null;
|
||||||
|
@ -116,8 +116,8 @@ export function getIconForLatestInput(configs, source, devices, settingName) {
|
|||||||
export function assign(config, settingNameTarget, keycode): boolean {
|
export function assign(config, settingNameTarget, keycode): boolean {
|
||||||
// first, we need to check if this keycode is already used on another settingName
|
// first, we need to check if this keycode is already used on another settingName
|
||||||
if (
|
if (
|
||||||
!canIAssignThisKey(config, getKeyWithKeycode(config, keycode)) ||
|
!canIAssignThisKey(config, getKeyWithKeycode(config, keycode))
|
||||||
!canIOverrideThisSetting(config, settingNameTarget)
|
|| !canIOverrideThisSetting(config, settingNameTarget)
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
25
src/constants/colors.ts
Normal file
25
src/constants/colors.ts
Normal file
@ -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 <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;
|
File diff suppressed because it is too large
Load Diff
@ -572,10 +572,10 @@ class MatBlockTag extends ConditionalProtectTag {
|
|||||||
const CraftyShieldConditionFunc: ProtectConditionFunc = (_arena, moveId) => {
|
const CraftyShieldConditionFunc: ProtectConditionFunc = (_arena, moveId) => {
|
||||||
const move = allMoves[moveId];
|
const move = allMoves[moveId];
|
||||||
return (
|
return (
|
||||||
move.category === MoveCategory.STATUS &&
|
move.category === MoveCategory.STATUS
|
||||||
move.moveTarget !== MoveTarget.ENEMY_SIDE &&
|
&& move.moveTarget !== MoveTarget.ENEMY_SIDE
|
||||||
move.moveTarget !== MoveTarget.BOTH_SIDES &&
|
&& move.moveTarget !== MoveTarget.BOTH_SIDES
|
||||||
move.moveTarget !== MoveTarget.ALL
|
&& move.moveTarget !== MoveTarget.ALL
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -765,9 +765,10 @@ export abstract class EntryHazardTag extends SerializableArenaTag {
|
|||||||
const source = this.getSourcePokemon();
|
const source = this.getSourcePokemon();
|
||||||
if (!source) {
|
if (!source) {
|
||||||
console.warn(
|
console.warn(
|
||||||
"Failed to get source Pokemon for AernaTrapTag on add message!" +
|
// biome-ignore lint/complexity/noUselessStringConcat: Rule bugs out with operator linebreaks set to `before`
|
||||||
`\nTag type: ${this.tagType}` +
|
"Failed to get source Pokemon for AernaTrapTag on add message!"
|
||||||
`\nPID: ${this.sourceId}`,
|
+ `\nTag type: ${this.tagType}`
|
||||||
|
+ `\nPID: ${this.sourceId}`,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1131,7 +1132,7 @@ class ImprisonTag extends EntryHazardTag {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This applies the effects of Imprison to any opposing Pokemon that switch into the field while the source Pokemon is still active
|
* This applies the effects of Imprison to any opposing Pokemon that switch into the field while the source Pokemon is still active
|
||||||
* @param {Pokemon} pokemon the Pokemon Imprison is applied to
|
* @param pokemon the Pokemon Imprison is applied to
|
||||||
* @returns `true`
|
* @returns `true`
|
||||||
*/
|
*/
|
||||||
override activateTrap(pokemon: Pokemon): boolean {
|
override activateTrap(pokemon: Pokemon): boolean {
|
||||||
|
@ -7649,7 +7649,7 @@ export function initBiomes() {
|
|||||||
? pokemonEvolutions[speciesId]
|
? 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);
|
uncatchableSpecies.push(speciesId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 { MoveId } from "#enums/move-id";
|
||||||
import { SpeciesId } from "#enums/species-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 = {
|
export const speciesEggMoves = {
|
||||||
[SpeciesId.BULBASAUR]: [ MoveId.SAPPY_SEED, MoveId.MALIGNANT_CHAIN, MoveId.EARTH_POWER, MoveId.MATCHA_GOTCHA ],
|
[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 ],
|
[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_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.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 ]
|
[SpeciesId.BLOODMOON_URSALUNA]: [ MoveId.NASTY_PLOT, MoveId.ROCK_POLISH, MoveId.SANDSEAR_STORM, MoveId.BOOMBURST ]
|
||||||
};
|
} satisfies Partial<Record<SpeciesId, [MoveId, MoveId, MoveId, MoveId]>>;
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -78,7 +78,7 @@ export enum EvolutionItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const tyrogueMoves = [MoveId.LOW_SWEEP, MoveId.MACH_PUNCH, MoveId.RAPID_SPIN] as const;
|
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:
|
* Pokemon Evolution tuple type consisting of:
|
||||||
@ -136,7 +136,7 @@ export class SpeciesEvolutionCondition {
|
|||||||
case EvoCondKey.FRIENDSHIP:
|
case EvoCondKey.FRIENDSHIP:
|
||||||
return i18next.t("pokemonEvolutions:friendship");
|
return i18next.t("pokemonEvolutions:friendship");
|
||||||
case EvoCondKey.TIME:
|
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:
|
case EvoCondKey.MOVE_TYPE:
|
||||||
return i18next.t("pokemonEvolutions:moveType", {type: i18next.t(`pokemonInfo:type.${toCamelCase(PokemonType[cond.pkmnType])}`)});
|
return i18next.t("pokemonEvolutions:moveType", {type: i18next.t(`pokemonInfo:type.${toCamelCase(PokemonType[cond.pkmnType])}`)});
|
||||||
case EvoCondKey.PARTY_TYPE:
|
case EvoCondKey.PARTY_TYPE:
|
||||||
@ -193,7 +193,10 @@ export class SpeciesEvolutionCondition {
|
|||||||
case EvoCondKey.WEATHER:
|
case EvoCondKey.WEATHER:
|
||||||
return cond.weather.includes(globalScene.arena.getWeatherType());
|
return cond.weather.includes(globalScene.arena.getWeatherType());
|
||||||
case EvoCondKey.TYROGUE:
|
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:
|
case EvoCondKey.NATURE:
|
||||||
return cond.nature.includes(pokemon.getNature());
|
return cond.nature.includes(pokemon.getNature());
|
||||||
case EvoCondKey.RANDOM_FORM: {
|
case EvoCondKey.RANDOM_FORM: {
|
||||||
@ -656,18 +659,10 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||||||
new SpeciesEvolution(SpeciesId.GARDEVOIR, 30, null, null),
|
new SpeciesEvolution(SpeciesId.GARDEVOIR, 30, null, null),
|
||||||
new SpeciesEvolution(SpeciesId.GALLADE, 1, EvolutionItem.DAWN_STONE, {key: EvoCondKey.GENDER, gender: Gender.MALE}, SpeciesWildEvolutionDelay.LONG),
|
new SpeciesEvolution(SpeciesId.GALLADE, 1, EvolutionItem.DAWN_STONE, {key: EvoCondKey.GENDER, gender: Gender.MALE}, SpeciesWildEvolutionDelay.LONG),
|
||||||
],
|
],
|
||||||
[SpeciesId.SURSKIT]: [
|
[SpeciesId.SURSKIT]: [new SpeciesEvolution(SpeciesId.MASQUERAIN, 22, null, null)],
|
||||||
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.SHROOMISH]: [
|
[SpeciesId.VIGOROTH]: [new SpeciesEvolution(SpeciesId.SLAKING, 36, null, null)],
|
||||||
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]: [
|
[SpeciesId.NINCADA]: [
|
||||||
new SpeciesEvolution(SpeciesId.NINJASK, 20, null, null),
|
new SpeciesEvolution(SpeciesId.NINJASK, 20, null, null),
|
||||||
new SpeciesEvolution(SpeciesId.SHEDINJA, 20, null, {key: EvoCondKey.SHEDINJA})
|
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.GLALIE, 42, null, null),
|
||||||
new SpeciesEvolution(SpeciesId.FROSLASS, 1, EvolutionItem.DAWN_STONE, {key: EvoCondKey.GENDER, gender: Gender.FEMALE}, SpeciesWildEvolutionDelay.LONG),
|
new SpeciesEvolution(SpeciesId.FROSLASS, 1, EvolutionItem.DAWN_STONE, {key: EvoCondKey.GENDER, gender: Gender.FEMALE}, SpeciesWildEvolutionDelay.LONG),
|
||||||
],
|
],
|
||||||
[SpeciesId.SPHEAL]: [
|
[SpeciesId.SPHEAL]: [new SpeciesEvolution(SpeciesId.SEALEO, 32, null, null)],
|
||||||
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.SEALEO]: [
|
[SpeciesId.SHELGON]: [new SpeciesEvolution(SpeciesId.SALAMENCE, 50, null, null)],
|
||||||
new SpeciesEvolution(SpeciesId.WALREIN, 44, null, null)
|
[SpeciesId.BELDUM]: [new SpeciesEvolution(SpeciesId.METANG, 20, null, null)],
|
||||||
],
|
[SpeciesId.METANG]: [new SpeciesEvolution(SpeciesId.METAGROSS, 45, null, null)],
|
||||||
[SpeciesId.BAGON]: [
|
[SpeciesId.TURTWIG]: [new SpeciesEvolution(SpeciesId.GROTLE, 18, null, null)],
|
||||||
new SpeciesEvolution(SpeciesId.SHELGON, 30, null, null)
|
[SpeciesId.GROTLE]: [new SpeciesEvolution(SpeciesId.TORTERRA, 32, null, null)],
|
||||||
],
|
[SpeciesId.CHIMCHAR]: [new SpeciesEvolution(SpeciesId.MONFERNO, 14, null, null)],
|
||||||
[SpeciesId.SHELGON]: [
|
[SpeciesId.MONFERNO]: [new SpeciesEvolution(SpeciesId.INFERNAPE, 36, null, null)],
|
||||||
new SpeciesEvolution(SpeciesId.SALAMENCE, 50, null, null)
|
[SpeciesId.PIPLUP]: [new SpeciesEvolution(SpeciesId.PRINPLUP, 16, null, null)],
|
||||||
],
|
[SpeciesId.PRINPLUP]: [new SpeciesEvolution(SpeciesId.EMPOLEON, 36, null, null)],
|
||||||
[SpeciesId.BELDUM]: [
|
[SpeciesId.STARLY]: [new SpeciesEvolution(SpeciesId.STARAVIA, 14, null, null)],
|
||||||
new SpeciesEvolution(SpeciesId.METANG, 20, null, null)
|
[SpeciesId.STARAVIA]: [new SpeciesEvolution(SpeciesId.STARAPTOR, 34, null, null)],
|
||||||
],
|
[SpeciesId.BIDOOF]: [new SpeciesEvolution(SpeciesId.BIBAREL, 15, null, null)],
|
||||||
[SpeciesId.METANG]: [
|
[SpeciesId.KRICKETOT]: [new SpeciesEvolution(SpeciesId.KRICKETUNE, 10, null, null)],
|
||||||
new SpeciesEvolution(SpeciesId.METAGROSS, 45, null, null)
|
[SpeciesId.SHINX]: [new SpeciesEvolution(SpeciesId.LUXIO, 15, null, null)],
|
||||||
],
|
[SpeciesId.LUXIO]: [new SpeciesEvolution(SpeciesId.LUXRAY, 30, null, null)],
|
||||||
[SpeciesId.TURTWIG]: [
|
[SpeciesId.CRANIDOS]: [new SpeciesEvolution(SpeciesId.RAMPARDOS, 30, null, null)],
|
||||||
new SpeciesEvolution(SpeciesId.GROTLE, 18, null, null)
|
[SpeciesId.SHIELDON]: [new SpeciesEvolution(SpeciesId.BASTIODON, 30, 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]: [
|
[SpeciesId.BURMY]: [
|
||||||
new SpeciesEvolution(SpeciesId.MOTHIM, 20, null, {key: EvoCondKey.GENDER, gender: Gender.MALE}),
|
new SpeciesEvolution(SpeciesId.MOTHIM, 20, null, {key: EvoCondKey.GENDER, gender: Gender.MALE}),
|
||||||
new SpeciesEvolution(SpeciesId.WORMADAM, 20, null, {key: EvoCondKey.GENDER, gender: Gender.FEMALE})
|
new SpeciesEvolution(SpeciesId.WORMADAM, 20, null, {key: EvoCondKey.GENDER, gender: Gender.FEMALE})
|
||||||
|
@ -139,8 +139,8 @@ class AnimFrame {
|
|||||||
focus: AnimFocus,
|
focus: AnimFocus,
|
||||||
init?: boolean,
|
init?: boolean,
|
||||||
) {
|
) {
|
||||||
this.x = !init ? ((x || 0) - 128) * 0.5 : x;
|
this.x = init ? x : ((x || 0) - 128) * 0.5;
|
||||||
this.y = !init ? ((y || 0) - 224) * 0.5 : y;
|
this.y = init ? y : ((y || 0) - 224) * 0.5;
|
||||||
if (zoomX) {
|
if (zoomX) {
|
||||||
this.zoomX = zoomX;
|
this.zoomX = zoomX;
|
||||||
} else if (init) {
|
} else if (init) {
|
||||||
@ -360,7 +360,7 @@ class AnimTimedUpdateBgEvent extends AnimTimedBgEvent {
|
|||||||
if (this.opacity !== undefined) {
|
if (this.opacity !== undefined) {
|
||||||
tweenProps["alpha"] = (this.opacity || 0) / 255;
|
tweenProps["alpha"] = (this.opacity || 0) / 255;
|
||||||
}
|
}
|
||||||
if (Object.keys(tweenProps).length) {
|
if (Object.keys(tweenProps).length > 0) {
|
||||||
globalScene.tweens.add({
|
globalScene.tweens.add({
|
||||||
targets: moveAnim.bgSprite,
|
targets: moveAnim.bgSprite,
|
||||||
duration: getFrameMs(this.duration * 3),
|
duration: getFrameMs(this.duration * 3),
|
||||||
@ -625,7 +625,7 @@ function loadAnimAssets(anims: AnimConfig[], startLoad?: boolean): Promise<void>
|
|||||||
const backgrounds = new Set<string>();
|
const backgrounds = new Set<string>();
|
||||||
const sounds = new Set<string>();
|
const sounds = new Set<string>();
|
||||||
for (const a of anims) {
|
for (const a of anims) {
|
||||||
if (!a.frames?.length) {
|
if (a.frames?.length === 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const animSounds = a.getSoundResourceNames();
|
const animSounds = a.getSoundResourceNames();
|
||||||
@ -816,8 +816,8 @@ export abstract class BattleAnim {
|
|||||||
x = point[0];
|
x = point[0];
|
||||||
y = point[1];
|
y = point[1];
|
||||||
if (
|
if (
|
||||||
frame.target === AnimFrameTarget.GRAPHIC &&
|
frame.target === AnimFrameTarget.GRAPHIC
|
||||||
isReversed(this.srcLine[0], this.srcLine[2], this.dstLine[0], this.dstLine[2])
|
&& isReversed(this.srcLine[0], this.srcLine[2], this.dstLine[0], this.dstLine[2])
|
||||||
) {
|
) {
|
||||||
scaleX = scaleX * -1;
|
scaleX = scaleX * -1;
|
||||||
}
|
}
|
||||||
@ -826,7 +826,7 @@ export abstract class BattleAnim {
|
|||||||
}
|
}
|
||||||
const angle = -frame.angle;
|
const angle = -frame.angle;
|
||||||
const key = frame.target === AnimFrameTarget.GRAPHIC ? g++ : frame.target === AnimFrameTarget.USER ? u++ : t++;
|
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;
|
return ret;
|
||||||
@ -835,8 +835,8 @@ export abstract class BattleAnim {
|
|||||||
// biome-ignore lint/complexity/noBannedTypes: callback is used liberally
|
// biome-ignore lint/complexity/noBannedTypes: callback is used liberally
|
||||||
play(onSubstitute?: boolean, callback?: Function) {
|
play(onSubstitute?: boolean, callback?: Function) {
|
||||||
const isOppAnim = this.isOppAnim();
|
const isOppAnim = this.isOppAnim();
|
||||||
const user = !isOppAnim ? this.user! : this.target!; // TODO: are those bangs correct?
|
const user = isOppAnim ? this.target! : this.user!;
|
||||||
const target = !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 (!target?.isOnField() && !this.playRegardlessOfIssues) {
|
||||||
if (callback) {
|
if (callback) {
|
||||||
@ -888,8 +888,8 @@ export abstract class BattleAnim {
|
|||||||
* and `this.target` prevent the target's Substitute doll from disappearing
|
* and `this.target` prevent the target's Substitute doll from disappearing
|
||||||
* after being the target of an animation.
|
* after being the target of an animation.
|
||||||
*/
|
*/
|
||||||
const userSpriteToShow = !isOppAnim ? userSprite : targetSprite;
|
const userSpriteToShow = isOppAnim ? targetSprite : userSprite;
|
||||||
const targetSpriteToShow = !isOppAnim ? targetSprite : userSprite;
|
const targetSpriteToShow = isOppAnim ? userSprite : targetSprite;
|
||||||
if (!this.isHideUser() && userSpriteToShow) {
|
if (!this.isHideUser() && userSpriteToShow) {
|
||||||
userSpriteToShow.setVisible(true);
|
userSpriteToShow.setVisible(true);
|
||||||
}
|
}
|
||||||
@ -1142,18 +1142,18 @@ export abstract class BattleAnim {
|
|||||||
|
|
||||||
for (const frame of frames) {
|
for (const frame of frames) {
|
||||||
let { x, y } = frame;
|
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;
|
const scaleY = frame.zoomY / 100;
|
||||||
x += targetInitialX;
|
x += targetInitialX;
|
||||||
y += targetInitialY;
|
y += targetInitialY;
|
||||||
const angle = -frame.angle;
|
const angle = -frame.angle;
|
||||||
const key = frame.target === AnimFrameTarget.GRAPHIC ? g++ : frame.target === AnimFrameTarget.USER ? u++ : t++;
|
const key = frame.target === AnimFrameTarget.GRAPHIC ? g++ : frame.target === AnimFrameTarget.USER ? u++ : t++;
|
||||||
ret.get(frame.target)?.set(key, {
|
ret.get(frame.target)?.set(key, {
|
||||||
x: x,
|
x,
|
||||||
y: y,
|
y,
|
||||||
scaleX: scaleX,
|
scaleX,
|
||||||
scaleY: scaleY,
|
scaleY,
|
||||||
angle: angle,
|
angle,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1135,8 +1135,8 @@ export class PowderTag extends BattlerTag {
|
|||||||
const move = movePhase.move.getMove();
|
const move = movePhase.move.getMove();
|
||||||
const weather = globalScene.arena.weather;
|
const weather = globalScene.arena.weather;
|
||||||
if (
|
if (
|
||||||
pokemon.getMoveType(move) !== PokemonType.FIRE ||
|
pokemon.getMoveType(move) !== PokemonType.FIRE
|
||||||
(weather?.weatherType === WeatherType.HEAVY_RAIN && !weather.isEffectSuppressed()) // Heavy rain takes priority over powder
|
|| (weather?.weatherType === WeatherType.HEAVY_RAIN && !weather.isEffectSuppressed()) // Heavy rain takes priority over powder
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1793,9 +1793,9 @@ export abstract class ContactProtectedTag extends ProtectedTag {
|
|||||||
|
|
||||||
const moveData = getMoveEffectPhaseData(pokemon);
|
const moveData = getMoveEffectPhaseData(pokemon);
|
||||||
if (
|
if (
|
||||||
lapseType === BattlerTagLapseType.CUSTOM &&
|
lapseType === BattlerTagLapseType.CUSTOM
|
||||||
moveData &&
|
&& moveData
|
||||||
moveData.move.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user: moveData.attacker, target: pokemon })
|
&& moveData.move.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user: moveData.attacker, target: pokemon })
|
||||||
) {
|
) {
|
||||||
this.onContact(moveData.attacker, pokemon);
|
this.onContact(moveData.attacker, pokemon);
|
||||||
}
|
}
|
||||||
@ -2159,7 +2159,7 @@ export class HighestStatBoostTag extends AbilityBattlerTag {
|
|||||||
null,
|
null,
|
||||||
false,
|
false,
|
||||||
null,
|
null,
|
||||||
true,
|
false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2474,10 +2474,7 @@ export class RemovedTypeTag extends SerializableBattlerTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Battler tag for effects that ground the source, allowing Ground-type moves to hit them. */
|
||||||
* Battler tag for effects that ground the source, allowing Ground-type moves to hit them.
|
|
||||||
* @description `IGNORE_FLYING`: Persistent grounding effects (i.e. from Smack Down and Thousand Waves)
|
|
||||||
*/
|
|
||||||
export class GroundedTag extends SerializableBattlerTag {
|
export class GroundedTag extends SerializableBattlerTag {
|
||||||
public override readonly tagType = BattlerTagType.IGNORE_FLYING;
|
public override readonly tagType = BattlerTagType.IGNORE_FLYING;
|
||||||
constructor(tagType: BattlerTagType.IGNORE_FLYING, lapseType: BattlerTagLapseType, sourceMove: MoveId) {
|
constructor(tagType: BattlerTagType.IGNORE_FLYING, lapseType: BattlerTagLapseType, sourceMove: MoveId) {
|
||||||
@ -2485,11 +2482,7 @@ export class GroundedTag extends SerializableBattlerTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Removes flying type from a pokemon for a single turn */
|
||||||
* @description `ROOSTED`: Tag for temporary grounding if only source of ungrounding is flying and pokemon uses Roost.
|
|
||||||
* Roost removes flying type from a pokemon for a single turn.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export class RoostedTag extends BattlerTag {
|
export class RoostedTag extends BattlerTag {
|
||||||
private isBaseFlying: boolean;
|
private isBaseFlying: boolean;
|
||||||
private isBasePureFlying: boolean;
|
private isBasePureFlying: boolean;
|
||||||
@ -2538,13 +2531,11 @@ export class RoostedTag extends BattlerTag {
|
|||||||
let modifiedTypes: PokemonType[];
|
let modifiedTypes: PokemonType[];
|
||||||
if (this.isBasePureFlying && !isCurrentlyDualType) {
|
if (this.isBasePureFlying && !isCurrentlyDualType) {
|
||||||
modifiedTypes = [PokemonType.NORMAL];
|
modifiedTypes = [PokemonType.NORMAL];
|
||||||
} else {
|
} else if (!!pokemon.getTag(RemovedTypeTag) && isOriginallyDualType && !isCurrentlyDualType) {
|
||||||
if (!!pokemon.getTag(RemovedTypeTag) && isOriginallyDualType && !isCurrentlyDualType) {
|
|
||||||
modifiedTypes = [PokemonType.UNKNOWN];
|
modifiedTypes = [PokemonType.UNKNOWN];
|
||||||
} else {
|
} else {
|
||||||
modifiedTypes = currentTypes.filter(type => type !== PokemonType.FLYING);
|
modifiedTypes = currentTypes.filter(type => type !== PokemonType.FLYING);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
pokemon.summonData.types = modifiedTypes;
|
pokemon.summonData.types = modifiedTypes;
|
||||||
pokemon.updateInfo();
|
pokemon.updateInfo();
|
||||||
}
|
}
|
||||||
@ -2570,7 +2561,7 @@ export class FormBlockDamageTag extends SerializableBattlerTag {
|
|||||||
/**
|
/**
|
||||||
* Applies the tag to the Pokémon.
|
* Applies the tag to the Pokémon.
|
||||||
* Triggers a form change if the Pokémon is not in its defense form.
|
* Triggers a form change if the Pokémon is not in its defense form.
|
||||||
* @param {Pokemon} pokemon The Pokémon to which the tag is added.
|
* @param pokemon The Pokémon to which the tag is added.
|
||||||
*/
|
*/
|
||||||
onAdd(pokemon: Pokemon): void {
|
onAdd(pokemon: Pokemon): void {
|
||||||
super.onAdd(pokemon);
|
super.onAdd(pokemon);
|
||||||
@ -2819,9 +2810,9 @@ export class GulpMissileTag extends SerializableBattlerTag {
|
|||||||
// Bang here is OK as if sourceMove was undefined, this would just evaluate to false
|
// 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 isSurfOrDive = [MoveId.SURF, MoveId.DIVE].includes(this.sourceMove!);
|
||||||
const isNormalForm =
|
const isNormalForm =
|
||||||
pokemon.formIndex === 0 &&
|
pokemon.formIndex === 0
|
||||||
!pokemon.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA) &&
|
&& !pokemon.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)
|
||||||
!pokemon.getTag(BattlerTagType.GULP_MISSILE_PIKACHU);
|
&& !pokemon.getTag(BattlerTagType.GULP_MISSILE_PIKACHU);
|
||||||
const isCramorant = pokemon.species.speciesId === SpeciesId.CRAMORANT;
|
const isCramorant = pokemon.species.speciesId === SpeciesId.CRAMORANT;
|
||||||
|
|
||||||
return isSurfOrDive && isNormalForm && isCramorant;
|
return isSurfOrDive && isNormalForm && isCramorant;
|
||||||
@ -3862,7 +3853,7 @@ function getMoveEffectPhaseData(_pokemon: Pokemon): { phase: MoveEffectPhase; at
|
|||||||
const phase = globalScene.phaseManager.getCurrentPhase();
|
const phase = globalScene.phaseManager.getCurrentPhase();
|
||||||
if (phase?.is("MoveEffectPhase")) {
|
if (phase?.is("MoveEffectPhase")) {
|
||||||
return {
|
return {
|
||||||
phase: phase,
|
phase,
|
||||||
attacker: phase.getPokemon(),
|
attacker: phase.getPokemon(),
|
||||||
move: phase.move,
|
move: phase.move,
|
||||||
};
|
};
|
||||||
|
@ -28,7 +28,7 @@ export function getBerryPredicate(berryType: BerryType): BerryPredicate {
|
|||||||
return (pokemon: Pokemon) => !!pokemon.status || !!pokemon.getTag(BattlerTagType.CONFUSED);
|
return (pokemon: Pokemon) => !!pokemon.status || !!pokemon.getTag(BattlerTagType.CONFUSED);
|
||||||
case BerryType.ENIGMA:
|
case BerryType.ENIGMA:
|
||||||
return (pokemon: Pokemon) =>
|
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.LIECHI:
|
||||||
case BerryType.GANLON:
|
case BerryType.GANLON:
|
||||||
case BerryType.PETAYA:
|
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
|
// Pick the first move completely out of PP, or else the first one that has any PP missing
|
||||||
const ppRestoreMove =
|
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) {
|
if (ppRestoreMove) {
|
||||||
ppRestoreMove.ppUsed = Math.max(ppRestoreMove.ppUsed - 10, 0);
|
ppRestoreMove.ppUsed = Math.max(ppRestoreMove.ppUsed - 10, 0);
|
||||||
globalScene.phaseManager.queueMessage(
|
globalScene.phaseManager.queueMessage(
|
||||||
|
@ -21,9 +21,10 @@ import type { EnemyPokemon, PlayerPokemon, Pokemon } from "#field/pokemon";
|
|||||||
import { Trainer } from "#field/trainer";
|
import { Trainer } from "#field/trainer";
|
||||||
import type { ModifierTypeOption } from "#modifiers/modifier-type";
|
import type { ModifierTypeOption } from "#modifiers/modifier-type";
|
||||||
import { PokemonMove } from "#moves/pokemon-move";
|
import { PokemonMove } from "#moves/pokemon-move";
|
||||||
import type { DexAttrProps, GameData, StarterDataEntry } from "#system/game-data";
|
import type { GameData } from "#system/game-data";
|
||||||
import { RibbonData, type RibbonFlag } from "#system/ribbons/ribbon-data";
|
import { RibbonData, type RibbonFlag } from "#system/ribbons/ribbon-data";
|
||||||
import type { DexEntry } from "#types/dex-data";
|
import type { DexEntry } from "#types/dex-data";
|
||||||
|
import type { DexAttrProps, StarterDataEntry } from "#types/save-data";
|
||||||
import { type BooleanHolder, isBetween, type NumberHolder, randSeedItem } from "#utils/common";
|
import { type BooleanHolder, isBetween, type NumberHolder, randSeedItem } from "#utils/common";
|
||||||
import { deepCopy } from "#utils/data";
|
import { deepCopy } from "#utils/data";
|
||||||
import { getPokemonSpecies, getPokemonSpeciesForm } from "#utils/pokemon-utils";
|
import { getPokemonSpecies, getPokemonSpeciesForm } from "#utils/pokemon-utils";
|
||||||
@ -56,7 +57,7 @@ export abstract class Challenge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param id {@link Challenges} The enum value for the challenge
|
* @param id - The enum value for the challenge
|
||||||
*/
|
*/
|
||||||
constructor(id: Challenges, maxValue: number = Number.MAX_SAFE_INTEGER) {
|
constructor(id: Challenges, maxValue: number = Number.MAX_SAFE_INTEGER) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
@ -85,9 +86,9 @@ export abstract class Challenge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used for unlockable challenges to check if they're unlocked.
|
* Check if an unlockable challenge is unlocked
|
||||||
* @param data {@link GameData} The save data.
|
* @param data - The save data
|
||||||
* @returns {@link boolean} Whether this challenge is unlocked.
|
* @returns Whether this challenge is unlocked
|
||||||
*/
|
*/
|
||||||
isUnlocked(data: GameData): boolean {
|
isUnlocked(data: GameData): boolean {
|
||||||
return this.conditions.every(f => f(data));
|
return this.conditions.every(f => f(data));
|
||||||
@ -95,8 +96,8 @@ export abstract class Challenge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an unlock condition to this challenge.
|
* Adds an unlock condition to this challenge.
|
||||||
* @param condition {@link ChallengeCondition} The condition to add.
|
* @param condition - The condition to add
|
||||||
* @returns {@link Challenge} This challenge
|
* @returns This challenge
|
||||||
*/
|
*/
|
||||||
condition(condition: ChallengeCondition): Challenge {
|
condition(condition: ChallengeCondition): Challenge {
|
||||||
this.conditions.push(condition);
|
this.conditions.push(condition);
|
||||||
@ -105,7 +106,7 @@ export abstract class Challenge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {@link string} The localised name of this challenge.
|
* @returns The localised name of this challenge.
|
||||||
*/
|
*/
|
||||||
getName(): string {
|
getName(): string {
|
||||||
return i18next.t(`challenges:${this.geti18nKey()}.name`);
|
return i18next.t(`challenges:${this.geti18nKey()}.name`);
|
||||||
@ -132,7 +133,7 @@ export abstract class Challenge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Increase the value of the challenge
|
* Increase the value of the challenge
|
||||||
* @returns {@link boolean} Returns true if the value changed
|
* @returns Returns true if the value changed
|
||||||
*/
|
*/
|
||||||
increaseValue(): boolean {
|
increaseValue(): boolean {
|
||||||
if (this.value < this.maxValue) {
|
if (this.value < this.maxValue) {
|
||||||
@ -144,7 +145,7 @@ export abstract class Challenge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Decrease the value of the challenge
|
* Decrease the value of the challenge
|
||||||
* @returns {@link boolean} Returns true if the value changed
|
* @returns Returns true if the value changed
|
||||||
*/
|
*/
|
||||||
decreaseValue(): boolean {
|
decreaseValue(): boolean {
|
||||||
if (this.value > 0) {
|
if (this.value > 0) {
|
||||||
@ -163,7 +164,7 @@ export abstract class Challenge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Decrease the severity of the challenge
|
* Decrease the severity of the challenge
|
||||||
* @returns {@link boolean} Returns true if the value changed
|
* @returns Returns true if the value changed
|
||||||
*/
|
*/
|
||||||
decreaseSeverity(): boolean {
|
decreaseSeverity(): boolean {
|
||||||
if (this.severity > 0) {
|
if (this.severity > 0) {
|
||||||
@ -175,7 +176,7 @@ export abstract class Challenge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Increase the severity of the challenge
|
* Increase the severity of the challenge
|
||||||
* @returns {@link boolean} Returns true if the value changed
|
* @returns Returns true if the value changed
|
||||||
*/
|
*/
|
||||||
increaseSeverity(): boolean {
|
increaseSeverity(): boolean {
|
||||||
if (this.severity < this.maxSeverity) {
|
if (this.severity < this.maxSeverity) {
|
||||||
@ -187,7 +188,7 @@ export abstract class Challenge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the "difficulty" value of this challenge.
|
* Gets the "difficulty" value of this challenge.
|
||||||
* @returns {@link integer} The difficulty value.
|
* @returns The difficulty value.
|
||||||
*/
|
*/
|
||||||
getDifficulty(): number {
|
getDifficulty(): number {
|
||||||
return this.value;
|
return this.value;
|
||||||
@ -195,7 +196,7 @@ export abstract class Challenge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the minimum difficulty added by this challenge.
|
* Gets the minimum difficulty added by this challenge.
|
||||||
* @returns {@link integer} The difficulty value.
|
* @returns The difficulty value.
|
||||||
*/
|
*/
|
||||||
getMinDifficulty(): number {
|
getMinDifficulty(): number {
|
||||||
return 0;
|
return 0;
|
||||||
@ -203,7 +204,7 @@ export abstract class Challenge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Clones a challenge, either from another challenge or json. Chainable.
|
* Clones a challenge, either from another challenge or json. Chainable.
|
||||||
* @param source The source challenge or json.
|
* @param _source - The source challenge or json.
|
||||||
* @returns This challenge.
|
* @returns This challenge.
|
||||||
*/
|
*/
|
||||||
static loadChallenge(_source: Challenge | any): Challenge {
|
static loadChallenge(_source: Challenge | any): Challenge {
|
||||||
@ -212,10 +213,10 @@ export abstract class Challenge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An apply function for STARTER_CHOICE challenges. Derived classes should alter this.
|
* An apply function for STARTER_CHOICE challenges. Derived classes should alter this.
|
||||||
* @param _pokemon {@link PokemonSpecies} The pokemon to check the validity of.
|
* @param _pokemon - The Pokémon to check the validity of
|
||||||
* @param _valid {@link BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed.
|
* @param _valid - Holder for whether the Pokémon is valid or not
|
||||||
* @param _dexAttr {@link DexAttrProps} The dex attributes of the pokemon.
|
* @param _dexAttr - The dex attributes of the Pokémon
|
||||||
* @returns {@link boolean} Whether this function did anything.
|
* @returns Whether this function did anything.
|
||||||
*/
|
*/
|
||||||
applyStarterChoice(_pokemon: PokemonSpecies, _valid: BooleanHolder, _dexAttr: DexAttrProps): boolean {
|
applyStarterChoice(_pokemon: PokemonSpecies, _valid: BooleanHolder, _dexAttr: DexAttrProps): boolean {
|
||||||
return false;
|
return false;
|
||||||
@ -223,8 +224,8 @@ export abstract class Challenge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An apply function for STARTER_POINTS challenges. Derived classes should alter this.
|
* An apply function for STARTER_POINTS challenges. Derived classes should alter this.
|
||||||
* @param _points {@link NumberHolder} The amount of points you have available.
|
* @param _points - Holder for amount of starter points the user has to spend
|
||||||
* @returns {@link boolean} Whether this function did anything.
|
* @returns Whether this function did anything
|
||||||
*/
|
*/
|
||||||
applyStarterPoints(_points: NumberHolder): boolean {
|
applyStarterPoints(_points: NumberHolder): boolean {
|
||||||
return false;
|
return false;
|
||||||
@ -232,9 +233,9 @@ export abstract class Challenge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An apply function for STARTER_COST challenges. Derived classes should alter this.
|
* An apply function for STARTER_COST challenges. Derived classes should alter this.
|
||||||
* @param _species {@link SpeciesId} The pokemon to change the cost of.
|
* @param _species - The pokémon to change the cost of
|
||||||
* @param _cost {@link NumberHolder} The cost of the starter.
|
* @param _cost - Holder for the cost of the starter Pokémon
|
||||||
* @returns {@link boolean} Whether this function did anything.
|
* @returns Whether this function did anything.
|
||||||
*/
|
*/
|
||||||
applyStarterCost(_species: SpeciesId, _cost: NumberHolder): boolean {
|
applyStarterCost(_species: SpeciesId, _cost: NumberHolder): boolean {
|
||||||
return false;
|
return false;
|
||||||
@ -242,8 +243,8 @@ export abstract class Challenge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An apply function for STARTER_SELECT_MODIFY challenges. Derived classes should alter this.
|
* An apply function for STARTER_SELECT_MODIFY challenges. Derived classes should alter this.
|
||||||
* @param _pokemon {@link Pokemon} The starter pokemon to modify.
|
* @param _pokemon - The starter Pokémon to modify.
|
||||||
* @returns {@link boolean} Whether this function did anything.
|
* @returns Whether this function did anything.
|
||||||
*/
|
*/
|
||||||
applyStarterSelectModify(_speciesId: SpeciesId, _dexEntry: DexEntry, _starterDataEntry: StarterDataEntry): boolean {
|
applyStarterSelectModify(_speciesId: SpeciesId, _dexEntry: DexEntry, _starterDataEntry: StarterDataEntry): boolean {
|
||||||
return false;
|
return false;
|
||||||
@ -251,8 +252,8 @@ export abstract class Challenge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An apply function for STARTER_MODIFY challenges. Derived classes should alter this.
|
* An apply function for STARTER_MODIFY challenges. Derived classes should alter this.
|
||||||
* @param _pokemon {@link Pokemon} The starter pokemon to modify.
|
* @param _pokemon - The starter Pokémon to modify.
|
||||||
* @returns {@link boolean} Whether this function did anything.
|
* @returns Whether this function did anything.
|
||||||
*/
|
*/
|
||||||
applyStarterModify(_pokemon: Pokemon): boolean {
|
applyStarterModify(_pokemon: Pokemon): boolean {
|
||||||
return false;
|
return false;
|
||||||
@ -260,9 +261,9 @@ export abstract class Challenge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An apply function for POKEMON_IN_BATTLE challenges. Derived classes should alter this.
|
* An apply function for POKEMON_IN_BATTLE challenges. Derived classes should alter this.
|
||||||
* @param _pokemon {@link Pokemon} The pokemon to check the validity of.
|
* @param _pokemon - The Pokémon to check the validity of
|
||||||
* @param _valid {@link BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed.
|
* @param _valid - Holds a boolean that will be set to false if the Pokémon isn't allowed
|
||||||
* @returns {@link boolean} Whether this function did anything.
|
* @returns Whether this function did anything
|
||||||
*/
|
*/
|
||||||
applyPokemonInBattle(_pokemon: Pokemon, _valid: BooleanHolder): boolean {
|
applyPokemonInBattle(_pokemon: Pokemon, _valid: BooleanHolder): boolean {
|
||||||
return false;
|
return false;
|
||||||
@ -270,9 +271,9 @@ export abstract class Challenge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An apply function for FIXED_BATTLE challenges. Derived classes should alter this.
|
* An apply function for FIXED_BATTLE challenges. Derived classes should alter this.
|
||||||
* @param _waveIndex {@link Number} The current wave index.
|
* @param _waveIndex The current wave index
|
||||||
* @param _battleConfig {@link FixedBattleConfig} The battle config to modify.
|
* @param _battleConfig - The battle config to modify
|
||||||
* @returns {@link boolean} Whether this function did anything.
|
* @returns Whether this function did anything
|
||||||
*/
|
*/
|
||||||
applyFixedBattle(_waveIndex: number, _battleConfig: FixedBattleConfig): boolean {
|
applyFixedBattle(_waveIndex: number, _battleConfig: FixedBattleConfig): boolean {
|
||||||
return false;
|
return false;
|
||||||
@ -280,8 +281,8 @@ export abstract class Challenge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An apply function for TYPE_EFFECTIVENESS challenges. Derived classes should alter this.
|
* An apply function for TYPE_EFFECTIVENESS challenges. Derived classes should alter this.
|
||||||
* @param _effectiveness {@linkcode NumberHolder} The current effectiveness of the move.
|
* @param _effectiveness - The current effectiveness of the move
|
||||||
* @returns Whether this function did anything.
|
* @returns Whether this function did anything
|
||||||
*/
|
*/
|
||||||
applyTypeEffectiveness(_effectiveness: NumberHolder): boolean {
|
applyTypeEffectiveness(_effectiveness: NumberHolder): boolean {
|
||||||
return false;
|
return false;
|
||||||
@ -289,11 +290,11 @@ export abstract class Challenge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An apply function for AI_LEVEL challenges. Derived classes should alter this.
|
* An apply function for AI_LEVEL challenges. Derived classes should alter this.
|
||||||
* @param _level {@link NumberHolder} The generated level.
|
* @param _level - The generated level.
|
||||||
* @param _levelCap {@link Number} The current level cap.
|
* @param _levelCap - The current level cap.
|
||||||
* @param _isTrainer {@link Boolean} Whether this is a trainer pokemon.
|
* @param _isTrainer - Whether this is a trainer Pokémon
|
||||||
* @param _isBoss {@link Boolean} Whether this is a non-trainer boss pokemon.
|
* @param _isBoss - Whether this is a non-trainer boss Pokémon
|
||||||
* @returns {@link boolean} Whether this function did anything.
|
* @returns - Whether this function did anything
|
||||||
*/
|
*/
|
||||||
applyLevelChange(_level: NumberHolder, _levelCap: number, _isTrainer: boolean, _isBoss: boolean): boolean {
|
applyLevelChange(_level: NumberHolder, _levelCap: number, _isTrainer: boolean, _isBoss: boolean): boolean {
|
||||||
return false;
|
return false;
|
||||||
@ -301,9 +302,9 @@ export abstract class Challenge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An apply function for AI_MOVE_SLOTS challenges. Derived classes should alter this.
|
* An apply function for AI_MOVE_SLOTS challenges. Derived classes should alter this.
|
||||||
* @param pokemon {@link Pokemon} The pokemon that is being considered.
|
* @param _pokemon - The Pokémon that is being considered
|
||||||
* @param moveSlots {@link NumberHolder} The amount of move slots.
|
* @param _moveSlots - The amount of move slots
|
||||||
* @returns {@link boolean} Whether this function did anything.
|
* @returns Whether this function did anything
|
||||||
*/
|
*/
|
||||||
applyMoveSlot(_pokemon: Pokemon, _moveSlots: NumberHolder): boolean {
|
applyMoveSlot(_pokemon: Pokemon, _moveSlots: NumberHolder): boolean {
|
||||||
return false;
|
return false;
|
||||||
@ -311,9 +312,9 @@ export abstract class Challenge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An apply function for PASSIVE_ACCESS challenges. Derived classes should alter this.
|
* An apply function for PASSIVE_ACCESS challenges. Derived classes should alter this.
|
||||||
* @param pokemon {@link Pokemon} The pokemon to change.
|
* @param _pokemon - The Pokémon to change
|
||||||
* @param hasPassive {@link BooleanHolder} Whether it should have its passive.
|
* @param _hasPassive - Whether it should have its passive
|
||||||
* @returns {@link boolean} Whether this function did anything.
|
* @returns Whether this function did anything
|
||||||
*/
|
*/
|
||||||
applyPassiveAccess(_pokemon: Pokemon, _hasPassive: BooleanHolder): boolean {
|
applyPassiveAccess(_pokemon: Pokemon, _hasPassive: BooleanHolder): boolean {
|
||||||
return false;
|
return false;
|
||||||
@ -321,7 +322,7 @@ export abstract class Challenge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An apply function for GAME_MODE_MODIFY challenges. Derived classes should alter this.
|
* An apply function for GAME_MODE_MODIFY challenges. Derived classes should alter this.
|
||||||
* @returns {@link boolean} Whether this function did anything.
|
* @returns Whether this function did anything
|
||||||
*/
|
*/
|
||||||
applyGameModeModify(): boolean {
|
applyGameModeModify(): boolean {
|
||||||
return false;
|
return false;
|
||||||
@ -329,11 +330,11 @@ export abstract class Challenge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An apply function for MOVE_ACCESS. Derived classes should alter this.
|
* An apply function for MOVE_ACCESS. Derived classes should alter this.
|
||||||
* @param _pokemon {@link Pokemon} What pokemon would learn the move.
|
* @param _pokemon - What Pokémon would learn the move
|
||||||
* @param _moveSource {@link MoveSourceType} What source the pokemon would get the move from.
|
* @param _moveSource - What source the Pokémon would get the move from
|
||||||
* @param _move {@link MoveId} The move in question.
|
* @param _move - The move in question
|
||||||
* @param _level {@link NumberHolder} The level threshold for access.
|
* @param _level - The level threshold for access
|
||||||
* @returns {@link boolean} Whether this function did anything.
|
* @returns Whether this function did anything
|
||||||
*/
|
*/
|
||||||
applyMoveAccessLevel(_pokemon: Pokemon, _moveSource: MoveSourceType, _move: MoveId, _level: NumberHolder): boolean {
|
applyMoveAccessLevel(_pokemon: Pokemon, _moveSource: MoveSourceType, _move: MoveId, _level: NumberHolder): boolean {
|
||||||
return false;
|
return false;
|
||||||
@ -341,21 +342,21 @@ export abstract class Challenge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An apply function for MOVE_WEIGHT. Derived classes should alter this.
|
* An apply function for MOVE_WEIGHT. Derived classes should alter this.
|
||||||
* @param _pokemon {@link Pokemon} What pokemon would learn the move.
|
* @param _pokemon - What Pokémon would learn the move
|
||||||
* @param _moveSource {@link MoveSourceType} What source the pokemon would get the move from.
|
* @param _moveSource - What source the Pokémon would get the move from
|
||||||
* @param _move {@link MoveId} The move in question.
|
* @param _move - The move in question.
|
||||||
* @param _weight {@link NumberHolder} The base weight of the move
|
* @param _weight - The base weight of the move
|
||||||
* @returns {@link boolean} Whether this function did anything.
|
* @returns Whether this function did anything
|
||||||
*/
|
*/
|
||||||
applyMoveWeight(_pokemon: Pokemon, _moveSource: MoveSourceType, _move: MoveId, _level: NumberHolder): boolean {
|
applyMoveWeight(_pokemon: Pokemon, _moveSource: MoveSourceType, _move: MoveId, _weight: NumberHolder): boolean {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An apply function for FlipStats. Derived classes should alter this.
|
* An apply function for FlipStats. Derived classes should alter this.
|
||||||
* @param _pokemon {@link Pokemon} What pokemon would learn the move.
|
* @param _pokemon - What Pokémon would learn the move
|
||||||
* @param _baseStats What are the stats to flip.
|
* @param _baseStats What are the stats to flip
|
||||||
* @returns {@link boolean} Whether this function did anything.
|
* @returns Whether this function did anything
|
||||||
*/
|
*/
|
||||||
applyFlipStat(_pokemon: Pokemon, _baseStats: number[]) {
|
applyFlipStat(_pokemon: Pokemon, _baseStats: number[]) {
|
||||||
return false;
|
return false;
|
||||||
@ -381,9 +382,9 @@ export abstract class Challenge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An apply function for POKEMON_ADD_TO_PARTY. Derived classes should alter this.
|
* An apply function for POKEMON_ADD_TO_PARTY. Derived classes should alter this.
|
||||||
* @param _pokemon - The pokemon being caught
|
* @param _pokemon - The Pokémon being caught
|
||||||
* @param _status - Whether the pokemon can be added to the party or not
|
* @param _status - Whether the Pokémon can be added to the party or not
|
||||||
* @return Whether this function did anything
|
* @returns Whether this function did anything
|
||||||
*/
|
*/
|
||||||
applyPokemonAddToParty(_pokemon: EnemyPokemon, _status: BooleanHolder): boolean {
|
applyPokemonAddToParty(_pokemon: EnemyPokemon, _status: BooleanHolder): boolean {
|
||||||
return false;
|
return false;
|
||||||
@ -391,8 +392,8 @@ export abstract class Challenge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An apply function for POKEMON_FUSION. Derived classes should alter this.
|
* An apply function for POKEMON_FUSION. Derived classes should alter this.
|
||||||
* @param _pokemon - The pokemon being checked
|
* @param _pokemon - The Pokémon being checked
|
||||||
* @param _status - Whether the selected pokemon is allowed to fuse or not
|
* @param _status - Whether the selected Pokémon is allowed to fuse or not
|
||||||
* @returns Whether this function did anything
|
* @returns Whether this function did anything
|
||||||
*/
|
*/
|
||||||
applyPokemonFusion(_pokemon: PlayerPokemon, _status: BooleanHolder): boolean {
|
applyPokemonFusion(_pokemon: PlayerPokemon, _status: BooleanHolder): boolean {
|
||||||
@ -467,8 +468,8 @@ export class SingleGenerationChallenge extends Challenge {
|
|||||||
const baseGeneration = getPokemonSpecies(pokemon.species.speciesId).generation;
|
const baseGeneration = getPokemonSpecies(pokemon.species.speciesId).generation;
|
||||||
const fusionGeneration = pokemon.isFusion() ? getPokemonSpecies(pokemon.fusionSpecies!.speciesId).generation : 0;
|
const fusionGeneration = pokemon.isFusion() ? getPokemonSpecies(pokemon.fusionSpecies!.speciesId).generation : 0;
|
||||||
if (
|
if (
|
||||||
pokemon.isPlayer() &&
|
pokemon.isPlayer()
|
||||||
(baseGeneration !== this.value || (pokemon.isFusion() && fusionGeneration !== this.value))
|
&& (baseGeneration !== this.value || (pokemon.isFusion() && fusionGeneration !== this.value))
|
||||||
) {
|
) {
|
||||||
valid.value = false;
|
valid.value = false;
|
||||||
return true;
|
return true;
|
||||||
@ -670,10 +671,7 @@ export class SingleGenerationChallenge extends Challenge {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
override getDifficulty(): number {
|
||||||
* @overrides
|
|
||||||
*/
|
|
||||||
getDifficulty(): number {
|
|
||||||
return this.value > 0 ? 1 : 0;
|
return this.value > 0 ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -741,12 +739,12 @@ export class SingleTypeChallenge extends Challenge {
|
|||||||
|
|
||||||
applyPokemonInBattle(pokemon: Pokemon, valid: BooleanHolder): boolean {
|
applyPokemonInBattle(pokemon: Pokemon, valid: BooleanHolder): boolean {
|
||||||
if (
|
if (
|
||||||
pokemon.isPlayer() &&
|
pokemon.isPlayer()
|
||||||
!pokemon.isOfType(this.value - 1, false, false, true) &&
|
&& !pokemon.isOfType(this.value - 1, false, false, true)
|
||||||
!SingleTypeChallenge.TYPE_OVERRIDES.some(
|
&& !SingleTypeChallenge.TYPE_OVERRIDES.some(
|
||||||
o =>
|
o =>
|
||||||
o.type === this.value - 1 &&
|
o.type === this.value - 1
|
||||||
(pokemon.isFusion() && o.fusion ? pokemon.fusionSpecies! : pokemon.species).speciesId === o.species,
|
&& (pokemon.isFusion() && o.fusion ? pokemon.fusionSpecies! : pokemon.species).speciesId === o.species,
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
// TODO: is the bang on fusionSpecies correct?
|
// TODO: is the bang on fusionSpecies correct?
|
||||||
@ -756,15 +754,12 @@ export class SingleTypeChallenge extends Challenge {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
override getDifficulty(): number {
|
||||||
* @overrides
|
|
||||||
*/
|
|
||||||
getDifficulty(): number {
|
|
||||||
return this.value > 0 ? 1 : 0;
|
return this.value > 0 ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
getValue(overrideValue: number = this.value): string {
|
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 {
|
getDescription(overrideValue: number = this.value): string {
|
||||||
@ -823,11 +818,11 @@ export class FreshStartChallenge extends Challenge {
|
|||||||
|
|
||||||
// Remove natures except for the default ones
|
// Remove natures except for the default ones
|
||||||
const neutralNaturesAttr =
|
const neutralNaturesAttr =
|
||||||
(1 << (Nature.HARDY + 1)) |
|
(1 << (Nature.HARDY + 1))
|
||||||
(1 << (Nature.DOCILE + 1)) |
|
| (1 << (Nature.DOCILE + 1))
|
||||||
(1 << (Nature.SERIOUS + 1)) |
|
| (1 << (Nature.SERIOUS + 1))
|
||||||
(1 << (Nature.BASHFUL + 1)) |
|
| (1 << (Nature.BASHFUL + 1))
|
||||||
(1 << (Nature.QUIRKY + 1));
|
| (1 << (Nature.QUIRKY + 1));
|
||||||
dexEntry.natureAttr &= neutralNaturesAttr;
|
dexEntry.natureAttr &= neutralNaturesAttr;
|
||||||
|
|
||||||
// Cap all ivs at 15
|
// Cap all ivs at 15
|
||||||
@ -882,8 +877,8 @@ export class FreshStartChallenge extends Challenge {
|
|||||||
if (pokemon.species.speciesId === SpeciesId.ZYGARDE && pokemon.formIndex >= 2) {
|
if (pokemon.species.speciesId === SpeciesId.ZYGARDE && pokemon.formIndex >= 2) {
|
||||||
pokemon.formIndex -= 2; // Sets 10%-PC to 10%-AB and 50%-PC to 50%-AB
|
pokemon.formIndex -= 2; // Sets 10%-PC to 10%-AB and 50%-PC to 50%-AB
|
||||||
} else if (
|
} else if (
|
||||||
pokemon.formIndex > 0 &&
|
pokemon.formIndex > 0
|
||||||
[
|
&& [
|
||||||
SpeciesId.PIKACHU,
|
SpeciesId.PIKACHU,
|
||||||
SpeciesId.EEVEE,
|
SpeciesId.EEVEE,
|
||||||
SpeciesId.PICHU,
|
SpeciesId.PICHU,
|
||||||
|
@ -6,7 +6,7 @@ import { PokemonSpecies } from "#data/pokemon-species";
|
|||||||
import { BiomeId } from "#enums/biome-id";
|
import { BiomeId } from "#enums/biome-id";
|
||||||
import { PartyMemberStrength } from "#enums/party-member-strength";
|
import { PartyMemberStrength } from "#enums/party-member-strength";
|
||||||
import { SpeciesId } from "#enums/species-id";
|
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 { isNullOrUndefined, randSeedGauss, randSeedInt, randSeedItem } from "#utils/common";
|
||||||
import { getEnumValues } from "#utils/enums";
|
import { getEnumValues } from "#utils/enums";
|
||||||
import { getPokemonSpecies, getPokemonSpeciesForm } from "#utils/pokemon-utils";
|
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(randSeedInt(9 - starterCosts[0], 1));
|
||||||
starterCosts.push(10 - (starterCosts[0] + starterCosts[1]));
|
starterCosts.push(10 - (starterCosts[0] + starterCosts[1]));
|
||||||
|
|
||||||
for (let c = 0; c < starterCosts.length; c++) {
|
for (const cost of starterCosts) {
|
||||||
const cost = starterCosts[c];
|
|
||||||
const costSpecies = Object.keys(speciesStarterCosts)
|
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);
|
.filter(s => speciesStarterCosts[s] === cost);
|
||||||
const randPkmSpecies = getPokemonSpecies(randSeedItem(costSpecies));
|
const randPkmSpecies = getPokemonSpecies(randSeedItem(costSpecies));
|
||||||
const starterSpecies = getPokemonSpecies(
|
const starterSpecies = getPokemonSpecies(
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import type { PlayerPokemon } from "#field/pokemon";
|
import type { PlayerPokemon } from "#field/pokemon";
|
||||||
import type { StarterDataEntry } from "#system/game-data";
|
|
||||||
import type { DexEntry } from "#types/dex-data";
|
import type { DexEntry } from "#types/dex-data";
|
||||||
|
import type { StarterDataEntry } from "#types/save-data";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores data associated with a specific egg and the hatched pokemon
|
* Stores data associated with a specific egg and the hatched pokemon
|
||||||
|
@ -220,9 +220,9 @@ export class Egg {
|
|||||||
|
|
||||||
public isManaphyEgg(): boolean {
|
public isManaphyEgg(): boolean {
|
||||||
return (
|
return (
|
||||||
this._species === SpeciesId.PHIONE ||
|
this._species === SpeciesId.PHIONE
|
||||||
this._species === SpeciesId.MANAPHY ||
|
|| this._species === SpeciesId.MANAPHY
|
||||||
(this._tier === EggTier.COMMON && !(this._id % 204) && !this._species)
|
|| (this._tier === EggTier.COMMON && !(this._id % 204) && !this._species)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,15 +324,15 @@ export class Egg {
|
|||||||
switch (this.sourceType) {
|
switch (this.sourceType) {
|
||||||
case EggSourceType.SAME_SPECIES_EGG:
|
case EggSourceType.SAME_SPECIES_EGG:
|
||||||
return (
|
return (
|
||||||
this._eggDescriptor ??
|
this._eggDescriptor
|
||||||
i18next.t("egg:sameSpeciesEgg", {
|
?? i18next.t("egg:sameSpeciesEgg", {
|
||||||
species: getPokemonSpecies(this._species).getName(),
|
species: getPokemonSpecies(this._species).getName(),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
case EggSourceType.GACHA_LEGENDARY:
|
case EggSourceType.GACHA_LEGENDARY:
|
||||||
return (
|
return (
|
||||||
this._eggDescriptor ??
|
this._eggDescriptor
|
||||||
`${i18next.t("egg:gachaTypeLegendary")} (${getPokemonSpecies(getLegendaryGachaSpeciesForTimestamp(this.timestamp)).getName()})`
|
?? `${i18next.t("egg:gachaTypeLegendary")} (${getPokemonSpecies(getLegendaryGachaSpeciesForTimestamp(this.timestamp)).getName()})`
|
||||||
);
|
);
|
||||||
case EggSourceType.GACHA_SHINY:
|
case EggSourceType.GACHA_SHINY:
|
||||||
return this._eggDescriptor ?? i18next.t("egg:gachaTypeShiny");
|
return this._eggDescriptor ?? i18next.t("egg:gachaTypeShiny");
|
||||||
@ -419,11 +419,9 @@ export class Egg {
|
|||||||
const rand = randSeedInt(MANAPHY_EGG_MANAPHY_RATE) !== 1;
|
const rand = randSeedInt(MANAPHY_EGG_MANAPHY_RATE) !== 1;
|
||||||
return rand ? SpeciesId.PHIONE : SpeciesId.MANAPHY;
|
return rand ? SpeciesId.PHIONE : SpeciesId.MANAPHY;
|
||||||
}
|
}
|
||||||
if (this.tier === EggTier.LEGENDARY && this._sourceType === EggSourceType.GACHA_LEGENDARY) {
|
if (this.tier === EggTier.LEGENDARY && this._sourceType === EggSourceType.GACHA_LEGENDARY && !randSeedInt(2)) {
|
||||||
if (!randSeedInt(2)) {
|
|
||||||
return getLegendaryGachaSpeciesForTimestamp(this.timestamp);
|
return getLegendaryGachaSpeciesForTimestamp(this.timestamp);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let minStarterValue: number;
|
let minStarterValue: number;
|
||||||
let maxStarterValue: number;
|
let maxStarterValue: number;
|
||||||
@ -454,9 +452,9 @@ export class Egg {
|
|||||||
.map(s => Number.parseInt(s) as SpeciesId)
|
.map(s => Number.parseInt(s) as SpeciesId)
|
||||||
.filter(
|
.filter(
|
||||||
s =>
|
s =>
|
||||||
!pokemonPrevolutions.hasOwnProperty(s) &&
|
!pokemonPrevolutions.hasOwnProperty(s)
|
||||||
getPokemonSpecies(s).isObtainable() &&
|
&& getPokemonSpecies(s).isObtainable()
|
||||||
ignoredSpecies.indexOf(s) === -1,
|
&& ignoredSpecies.indexOf(s) === -1,
|
||||||
);
|
);
|
||||||
|
|
||||||
// If this is the 10th egg without unlocking something new, attempt to force it.
|
// 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(
|
const lockedPool = speciesPool.filter(
|
||||||
s => !globalScene.gameData.dexData[s].caughtAttr && !globalScene.gameData.eggs.some(e => e.species === s),
|
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
|
// Skip this if everything is unlocked
|
||||||
speciesPool = lockedPool;
|
speciesPool = lockedPool;
|
||||||
}
|
}
|
||||||
@ -510,8 +508,8 @@ export class Egg {
|
|||||||
species = species!; // tell TS compiled it's defined now!
|
species = species!; // tell TS compiled it's defined now!
|
||||||
|
|
||||||
if (
|
if (
|
||||||
globalScene.gameData.dexData[species].caughtAttr ||
|
globalScene.gameData.dexData[species].caughtAttr
|
||||||
globalScene.gameData.eggs.some(e => e.species === species)
|
|| globalScene.gameData.eggs.some(e => e.species === species)
|
||||||
) {
|
) {
|
||||||
globalScene.gameData.unlockPity[this.tier] = Math.min(globalScene.gameData.unlockPity[this.tier] + 1, 10);
|
globalScene.gameData.unlockPity[this.tier] = Math.min(globalScene.gameData.unlockPity[this.tier] + 1, 10);
|
||||||
} else {
|
} else {
|
||||||
@ -567,8 +565,8 @@ export class Egg {
|
|||||||
globalScene.gameData.eggPity[EggTier.LEGENDARY] += 1 + tierValueOffset;
|
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.
|
// These numbers are roughly the 80% mark. That is, 80% of the time you'll get an egg before this gets triggered.
|
||||||
if (
|
if (
|
||||||
globalScene.gameData.eggPity[EggTier.LEGENDARY] >= EGG_PITY_LEGENDARY_THRESHOLD &&
|
globalScene.gameData.eggPity[EggTier.LEGENDARY] >= EGG_PITY_LEGENDARY_THRESHOLD
|
||||||
this._tier === EggTier.COMMON
|
&& this._tier === EggTier.COMMON
|
||||||
) {
|
) {
|
||||||
this._tier = EggTier.LEGENDARY;
|
this._tier = EggTier.LEGENDARY;
|
||||||
} else if (globalScene.gameData.eggPity[EggTier.EPIC] >= EGG_PITY_EPIC_THRESHOLD && this._tier === EggTier.COMMON) {
|
} else if (globalScene.gameData.eggPity[EggTier.EPIC] >= EGG_PITY_EPIC_THRESHOLD && this._tier === EggTier.COMMON) {
|
||||||
|
@ -126,7 +126,7 @@ export function getMoveTargets(user: Pokemon, move: MoveId, replaceTarget?: Move
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const frenzyMissFunc: UserMoveConditionFunc = (user: Pokemon, move: 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.getMoveQueue().shift();
|
||||||
}
|
}
|
||||||
user.removeTag(BattlerTagType.FRENZY); // FRENZY tag should be disrupted on miss/no effect
|
user.removeTag(BattlerTagType.FRENZY); // FRENZY tag should be disrupted on miss/no effect
|
||||||
|
@ -643,9 +643,9 @@ export abstract class Move implements Localizable {
|
|||||||
* will not consider {@linkcode AbilityId.WIND_RIDER | Wind Rider }.
|
* will not consider {@linkcode AbilityId.WIND_RIDER | Wind Rider }.
|
||||||
*
|
*
|
||||||
* To simply check whether the move has a flag, use {@linkcode hasFlag}.
|
* To simply check whether the move has a flag, use {@linkcode hasFlag}.
|
||||||
* @param flag {@linkcode MoveFlags} MoveFlag to check on user and/or target
|
* @param flag - MoveFlag to check on user and/or target
|
||||||
* @param user {@linkcode Pokemon} the Pokemon using the move
|
* @param user - the Pokemon using the move
|
||||||
* @param target {@linkcode Pokemon} the Pokemon receiving the move
|
* @param target - the Pokemon receiving the move
|
||||||
* @param isFollowUp (defaults to `false`) `true` if the move was used as a follow up
|
* @param isFollowUp (defaults to `false`) `true` if the move was used as a follow up
|
||||||
* @returns boolean
|
* @returns boolean
|
||||||
* @see {@linkcode hasFlag}
|
* @see {@linkcode hasFlag}
|
||||||
@ -1143,11 +1143,7 @@ function ChargeMove<TBase extends SubMove>(Base: TBase, nameAppend: string) {
|
|||||||
export class ChargingAttackMove extends ChargeMove(AttackMove, "ChargingAttackMove") {}
|
export class ChargingAttackMove extends ChargeMove(AttackMove, "ChargingAttackMove") {}
|
||||||
export class ChargingSelfStatusMove extends ChargeMove(SelfStatusMove, "ChargingSelfStatusMove") {}
|
export class ChargingSelfStatusMove extends ChargeMove(SelfStatusMove, "ChargingSelfStatusMove") {}
|
||||||
|
|
||||||
/**
|
/** Base class defining all {@linkcode Move} Attributes */
|
||||||
* Base class defining all {@linkcode Move} Attributes
|
|
||||||
* @abstract
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
*/
|
|
||||||
export abstract class MoveAttr {
|
export abstract class MoveAttr {
|
||||||
/** Should this {@linkcode Move} target the user? */
|
/** Should this {@linkcode Move} target the user? */
|
||||||
public selfTarget: boolean;
|
public selfTarget: boolean;
|
||||||
@ -1243,8 +1239,6 @@ interface MoveEffectAttrOptions {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class defining all Move Effect Attributes
|
* Base class defining all Move Effect Attributes
|
||||||
* @extends MoveAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
*/
|
*/
|
||||||
export class MoveEffectAttr extends MoveAttr {
|
export class MoveEffectAttr extends MoveAttr {
|
||||||
/**
|
/**
|
||||||
@ -1460,7 +1454,6 @@ export class PreMoveMessageAttr extends MoveAttr {
|
|||||||
* Attribute for moves that can be conditionally interrupted to be considered to
|
* Attribute for moves that can be conditionally interrupted to be considered to
|
||||||
* have failed before their "useMove" message is displayed. Currently used by
|
* have failed before their "useMove" message is displayed. Currently used by
|
||||||
* Focus Punch.
|
* Focus Punch.
|
||||||
* @extends MoveAttr
|
|
||||||
*/
|
*/
|
||||||
export class PreUseInterruptAttr extends MoveAttr {
|
export class PreUseInterruptAttr extends MoveAttr {
|
||||||
protected message: string | MoveMessageFunc;
|
protected message: string | MoveMessageFunc;
|
||||||
@ -1504,7 +1497,6 @@ export class PreUseInterruptAttr extends MoveAttr {
|
|||||||
/**
|
/**
|
||||||
* Attribute for Status moves that take attack type effectiveness
|
* Attribute for Status moves that take attack type effectiveness
|
||||||
* into consideration (i.e. {@linkcode https://bulbapedia.bulbagarden.net/wiki/Thunder_Wave_(move) | Thunder Wave})
|
* into consideration (i.e. {@linkcode https://bulbapedia.bulbagarden.net/wiki/Thunder_Wave_(move) | Thunder Wave})
|
||||||
* @extends MoveAttr
|
|
||||||
*/
|
*/
|
||||||
export class RespectAttackTypeImmunityAttr extends MoveAttr { }
|
export class RespectAttackTypeImmunityAttr extends MoveAttr { }
|
||||||
|
|
||||||
@ -1788,9 +1780,7 @@ export class RecoilAttr extends MoveEffectAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Attribute used for moves which self KO the user regardless if the move hits a target
|
* Attribute used for moves which self KO the user regardless if the move hits a target
|
||||||
* @extends MoveEffectAttr
|
*/
|
||||||
* @see {@linkcode apply}
|
|
||||||
**/
|
|
||||||
export class SacrificialAttr extends MoveEffectAttr {
|
export class SacrificialAttr extends MoveEffectAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(true, { trigger: MoveEffectTrigger.POST_TARGET });
|
super(true, { trigger: MoveEffectTrigger.POST_TARGET });
|
||||||
@ -1821,9 +1811,7 @@ export class SacrificialAttr extends MoveEffectAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Attribute used for moves which self KO the user but only if the move hits a target
|
* Attribute used for moves which self KO the user but only if the move hits a target
|
||||||
* @extends MoveEffectAttr
|
*/
|
||||||
* @see {@linkcode apply}
|
|
||||||
**/
|
|
||||||
export class SacrificialAttrOnHit extends MoveEffectAttr {
|
export class SacrificialAttrOnHit extends MoveEffectAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(true);
|
super(true);
|
||||||
@ -1860,8 +1848,6 @@ export class SacrificialAttrOnHit extends MoveEffectAttr {
|
|||||||
/**
|
/**
|
||||||
* Attribute used for moves which cut the user's Max HP in half.
|
* Attribute used for moves which cut the user's Max HP in half.
|
||||||
* Triggers using {@linkcode MoveEffectTrigger.POST_TARGET}.
|
* Triggers using {@linkcode MoveEffectTrigger.POST_TARGET}.
|
||||||
* @extends MoveEffectAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
*/
|
*/
|
||||||
export class HalfSacrificialAttr extends MoveEffectAttr {
|
export class HalfSacrificialAttr extends MoveEffectAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -1961,8 +1947,6 @@ export class AddSubstituteAttr extends MoveEffectAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Heals the user or target by {@linkcode healRatio} depending on the value of {@linkcode selfTarget}
|
* Heals the user or target by {@linkcode healRatio} depending on the value of {@linkcode selfTarget}
|
||||||
* @extends MoveEffectAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
*/
|
*/
|
||||||
export class HealAttr extends MoveEffectAttr {
|
export class HealAttr extends MoveEffectAttr {
|
||||||
constructor(
|
constructor(
|
||||||
@ -2051,8 +2035,6 @@ export class RestAttr extends HealAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Cures the user's party of non-volatile status conditions, ie. Heal Bell, Aromatherapy
|
* Cures the user's party of non-volatile status conditions, ie. Heal Bell, Aromatherapy
|
||||||
* @extends MoveEffectAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
*/
|
*/
|
||||||
export class PartyStatusCureAttr extends MoveEffectAttr {
|
export class PartyStatusCureAttr extends MoveEffectAttr {
|
||||||
/** Message to display after using move */
|
/** Message to display after using move */
|
||||||
@ -2111,7 +2093,6 @@ export class PartyStatusCureAttr extends MoveEffectAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies damage to the target's ally equal to 1/16 of that ally's max HP.
|
* Applies damage to the target's ally equal to 1/16 of that ally's max HP.
|
||||||
* @extends MoveEffectAttr
|
|
||||||
*/
|
*/
|
||||||
export class FlameBurstAttr extends MoveEffectAttr {
|
export class FlameBurstAttr extends MoveEffectAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -2200,8 +2181,6 @@ export class SacrificialFullRestoreAttr extends SacrificialAttr {
|
|||||||
/**
|
/**
|
||||||
* Attribute used for moves which ignore type-based debuffs from weather, namely Hydro Steam.
|
* Attribute used for moves which ignore type-based debuffs from weather, namely Hydro Steam.
|
||||||
* Called during damage calculation after getting said debuff from getAttackTypeMultiplier in the Pokemon class.
|
* Called during damage calculation after getting said debuff from getAttackTypeMultiplier in the Pokemon class.
|
||||||
* @extends MoveAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
*/
|
*/
|
||||||
export class IgnoreWeatherTypeDebuffAttr extends MoveAttr {
|
export class IgnoreWeatherTypeDebuffAttr extends MoveAttr {
|
||||||
/** The {@linkcode WeatherType} this move ignores */
|
/** The {@linkcode WeatherType} this move ignores */
|
||||||
@ -2280,8 +2259,6 @@ export class SandHealAttr extends WeatherHealAttr {
|
|||||||
/**
|
/**
|
||||||
* Heals the target or the user by either {@linkcode normalHealRatio} or {@linkcode boostedHealRatio}
|
* Heals the target or the user by either {@linkcode normalHealRatio} or {@linkcode boostedHealRatio}
|
||||||
* depending on the evaluation of {@linkcode condition}
|
* depending on the evaluation of {@linkcode condition}
|
||||||
* @extends HealAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
*/
|
*/
|
||||||
export class BoostHealAttr extends HealAttr {
|
export class BoostHealAttr extends HealAttr {
|
||||||
/** Healing received when {@linkcode condition} is false */
|
/** Healing received when {@linkcode condition} is false */
|
||||||
@ -2314,8 +2291,6 @@ export class BoostHealAttr extends HealAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Heals the target only if it is the ally
|
* Heals the target only if it is the ally
|
||||||
* @extends HealAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
*/
|
*/
|
||||||
export class HealOnAllyAttr extends HealAttr {
|
export class HealOnAllyAttr extends HealAttr {
|
||||||
override canApply(user: Pokemon, target: Pokemon, _move: Move, _args?: any[]): boolean {
|
override canApply(user: Pokemon, target: Pokemon, _move: Move, _args?: any[]): boolean {
|
||||||
@ -2334,9 +2309,6 @@ export class HealOnAllyAttr extends HealAttr {
|
|||||||
/**
|
/**
|
||||||
* Heals user as a side effect of a move that hits a target.
|
* Heals user as a side effect of a move that hits a target.
|
||||||
* Healing is based on {@linkcode healRatio} * the amount of damage dealt or a stat of the target.
|
* Healing is based on {@linkcode healRatio} * the amount of damage dealt or a stat of the target.
|
||||||
* @extends MoveEffectAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
* @see {@linkcode getUserBenefitScore}
|
|
||||||
*/
|
*/
|
||||||
// TODO: Make Strength Sap its own attribute that extends off of this one
|
// TODO: Make Strength Sap its own attribute that extends off of this one
|
||||||
export class HitHealAttr extends MoveEffectAttr {
|
export class HitHealAttr extends MoveEffectAttr {
|
||||||
@ -2406,8 +2378,6 @@ export class HitHealAttr extends MoveEffectAttr {
|
|||||||
* Attribute used for moves that change priority in a turn given a condition,
|
* Attribute used for moves that change priority in a turn given a condition,
|
||||||
* e.g. Grassy Glide
|
* e.g. Grassy Glide
|
||||||
* Called when move order is calculated in {@linkcode TurnStartPhase}.
|
* Called when move order is calculated in {@linkcode TurnStartPhase}.
|
||||||
* @extends MoveAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
*/
|
*/
|
||||||
export class IncrementMovePriorityAttr extends MoveAttr {
|
export class IncrementMovePriorityAttr extends MoveAttr {
|
||||||
/** The condition for a move's priority being incremented */
|
/** The condition for a move's priority being incremented */
|
||||||
@ -2443,10 +2413,8 @@ export class IncrementMovePriorityAttr extends MoveAttr {
|
|||||||
/**
|
/**
|
||||||
* Attribute used for attack moves that hit multiple times per use, e.g. Bullet Seed.
|
* Attribute used for attack moves that hit multiple times per use, e.g. Bullet Seed.
|
||||||
*
|
*
|
||||||
|
* @remarks
|
||||||
* Applied at the beginning of {@linkcode MoveEffectPhase}.
|
* Applied at the beginning of {@linkcode MoveEffectPhase}.
|
||||||
*
|
|
||||||
* @extends MoveAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
*/
|
*/
|
||||||
export class MultiHitAttr extends MoveAttr {
|
export class MultiHitAttr extends MoveAttr {
|
||||||
/** This move's intrinsic multi-hit type. It should never be modified. */
|
/** This move's intrinsic multi-hit type. It should never be modified. */
|
||||||
@ -2956,8 +2924,6 @@ export class StealEatBerryAttr extends EatBerryAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Move attribute that signals that the move should cure a status effect
|
* Move attribute that signals that the move should cure a status effect
|
||||||
* @extends MoveEffectAttr
|
|
||||||
* @see {@linkcode apply()}
|
|
||||||
*/
|
*/
|
||||||
export class HealStatusEffectAttr extends MoveEffectAttr {
|
export class HealStatusEffectAttr extends MoveEffectAttr {
|
||||||
/** List of Status Effects to cure */
|
/** List of Status Effects to cure */
|
||||||
@ -3040,8 +3006,6 @@ export class BypassSleepAttr extends MoveAttr {
|
|||||||
/**
|
/**
|
||||||
* Attribute used for moves that bypass the burn damage reduction of physical moves, currently only facade
|
* Attribute used for moves that bypass the burn damage reduction of physical moves, currently only facade
|
||||||
* Called during damage calculation
|
* Called during damage calculation
|
||||||
* @extends MoveAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
*/
|
*/
|
||||||
export class BypassBurnDamageReductionAttr extends MoveAttr {
|
export class BypassBurnDamageReductionAttr extends MoveAttr {
|
||||||
/** Prevents the move's damage from being reduced by burn
|
/** Prevents the move's damage from being reduced by burn
|
||||||
@ -3150,7 +3114,6 @@ export class OneHitKOAttr extends MoveAttr {
|
|||||||
/**
|
/**
|
||||||
* Attribute that allows charge moves to resolve in 1 turn under a given condition.
|
* Attribute that allows charge moves to resolve in 1 turn under a given condition.
|
||||||
* Should only be used for {@linkcode ChargingMove | ChargingMoves} as a `chargeAttr`.
|
* Should only be used for {@linkcode ChargingMove | ChargingMoves} as a `chargeAttr`.
|
||||||
* @extends MoveAttr
|
|
||||||
*/
|
*/
|
||||||
export class InstantChargeAttr extends MoveAttr {
|
export class InstantChargeAttr extends MoveAttr {
|
||||||
/** The condition in which the move with this attribute instantly charges */
|
/** The condition in which the move with this attribute instantly charges */
|
||||||
@ -3187,7 +3150,6 @@ export class InstantChargeAttr extends MoveAttr {
|
|||||||
/**
|
/**
|
||||||
* Attribute that allows charge moves to resolve in 1 turn while specific {@linkcode WeatherType | Weather}
|
* Attribute that allows charge moves to resolve in 1 turn while specific {@linkcode WeatherType | Weather}
|
||||||
* is active. Should only be used for {@linkcode ChargingMove | ChargingMoves} as a `chargeAttr`.
|
* is active. Should only be used for {@linkcode ChargingMove | ChargingMoves} as a `chargeAttr`.
|
||||||
* @extends InstantChargeAttr
|
|
||||||
*/
|
*/
|
||||||
export class WeatherInstantChargeAttr extends InstantChargeAttr {
|
export class WeatherInstantChargeAttr extends InstantChargeAttr {
|
||||||
constructor(weatherTypes: WeatherType[]) {
|
constructor(weatherTypes: WeatherType[]) {
|
||||||
@ -3317,7 +3279,6 @@ export class WishAttr extends MoveEffectAttr {
|
|||||||
/**
|
/**
|
||||||
* Attribute that cancels the associated move's effects when set to be combined with the user's ally's
|
* Attribute that cancels the associated move's effects when set to be combined with the user's ally's
|
||||||
* subsequent move this turn. Used for Grass Pledge, Water Pledge, and Fire Pledge.
|
* subsequent move this turn. Used for Grass Pledge, Water Pledge, and Fire Pledge.
|
||||||
* @extends OverrideMoveEffectAttr
|
|
||||||
*/
|
*/
|
||||||
export class AwaitCombinedPledgeAttr extends OverrideMoveEffectAttr {
|
export class AwaitCombinedPledgeAttr extends OverrideMoveEffectAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -3372,7 +3333,6 @@ export class AwaitCombinedPledgeAttr extends OverrideMoveEffectAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set of optional parameters that may be applied to stat stage changing effects
|
* Set of optional parameters that may be applied to stat stage changing effects
|
||||||
* @extends MoveEffectAttrOptions
|
|
||||||
* @see {@linkcode StatStageChangeAttr}
|
* @see {@linkcode StatStageChangeAttr}
|
||||||
*/
|
*/
|
||||||
interface StatStageChangeAttrOptions extends MoveEffectAttrOptions {
|
interface StatStageChangeAttrOptions extends MoveEffectAttrOptions {
|
||||||
@ -3389,9 +3349,6 @@ interface StatStageChangeAttrOptions extends MoveEffectAttrOptions {
|
|||||||
* @param stages How many stages to change the stat(s) by, [-6, 6]
|
* @param stages How many stages to change the stat(s) by, [-6, 6]
|
||||||
* @param selfTarget `true` if the move is self-targetting
|
* @param selfTarget `true` if the move is self-targetting
|
||||||
* @param options {@linkcode StatStageChangeAttrOptions} Container for any optional parameters for this attribute.
|
* @param options {@linkcode StatStageChangeAttrOptions} Container for any optional parameters for this attribute.
|
||||||
*
|
|
||||||
* @extends MoveEffectAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
*/
|
*/
|
||||||
export class StatStageChangeAttr extends MoveEffectAttr {
|
export class StatStageChangeAttr extends MoveEffectAttr {
|
||||||
public stats: BattleStat[];
|
public stats: BattleStat[];
|
||||||
@ -3822,8 +3779,6 @@ export class ResetStatsAttr extends MoveEffectAttr {
|
|||||||
/**
|
/**
|
||||||
* Attribute used for status moves, specifically Heart, Guard, and Power Swap,
|
* Attribute used for status moves, specifically Heart, Guard, and Power Swap,
|
||||||
* that swaps the user's and target's corresponding stat stages.
|
* that swaps the user's and target's corresponding stat stages.
|
||||||
* @extends MoveEffectAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
*/
|
*/
|
||||||
export class SwapStatStagesAttr extends MoveEffectAttr {
|
export class SwapStatStagesAttr extends MoveEffectAttr {
|
||||||
/** The stat stages to be swapped between the user and the target */
|
/** The stat stages to be swapped between the user and the target */
|
||||||
@ -4111,8 +4066,6 @@ export class WeightPowerAttr extends VariablePowerAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Attribute used for Electro Ball move.
|
* Attribute used for Electro Ball move.
|
||||||
* @extends VariablePowerAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
**/
|
**/
|
||||||
export class ElectroBallPowerAttr extends VariablePowerAttr {
|
export class ElectroBallPowerAttr extends VariablePowerAttr {
|
||||||
/**
|
/**
|
||||||
@ -4146,8 +4099,6 @@ export class ElectroBallPowerAttr extends VariablePowerAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Attribute used for Gyro Ball move.
|
* Attribute used for Gyro Ball move.
|
||||||
* @extends VariablePowerAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
**/
|
**/
|
||||||
export class GyroBallPowerAttr extends VariablePowerAttr {
|
export class GyroBallPowerAttr extends VariablePowerAttr {
|
||||||
/**
|
/**
|
||||||
@ -4403,11 +4354,11 @@ const countPositiveStatStages = (pokemon: Pokemon): number => {
|
|||||||
export class PositiveStatStagePowerAttr extends VariablePowerAttr {
|
export class PositiveStatStagePowerAttr extends VariablePowerAttr {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Pokemon} user The pokemon that is being used to calculate the amount of positive stats
|
* @param user The pokemon that is being used to calculate the amount of positive stats
|
||||||
* @param {Pokemon} target N/A
|
* @param target N/A
|
||||||
* @param {Move} move N/A
|
* @param move N/A
|
||||||
* @param {any[]} args The argument for VariablePowerAttr, accumulates and sets the amount of power multiplied by stats
|
* @param args The argument for VariablePowerAttr, accumulates and sets the amount of power multiplied by stats
|
||||||
* @returns {boolean} Returns true if attribute is applied
|
* @returns Returns true if attribute is applied
|
||||||
*/
|
*/
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
const positiveStatStages: number = countPositiveStatStages(user);
|
const positiveStatStages: number = countPositiveStatStages(user);
|
||||||
@ -4427,10 +4378,10 @@ export class PunishmentPowerAttr extends VariablePowerAttr {
|
|||||||
private PUNISHMENT_MAX_BASE_POWER = 200;
|
private PUNISHMENT_MAX_BASE_POWER = 200;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Pokemon} user N/A
|
* @param user N/A
|
||||||
* @param {Pokemon} target The pokemon that the move is being used against, as well as calculating the stats for the min/max base power
|
* @param target The pokemon that the move is being used against, as well as calculating the stats for the min/max base power
|
||||||
* @param {Move} move N/A
|
* @param move N/A
|
||||||
* @param {any[]} args The value that is being changed due to VariablePowerAttr
|
* @param args The value that is being changed due to VariablePowerAttr
|
||||||
* @returns Returns true if attribute is applied
|
* @returns Returns true if attribute is applied
|
||||||
*/
|
*/
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
@ -4546,8 +4497,6 @@ const hasStockpileStacksCondition: MoveConditionFunc = (user) => {
|
|||||||
/**
|
/**
|
||||||
* Attribute used for multi-hit moves that increase power in increments of the
|
* Attribute used for multi-hit moves that increase power in increments of the
|
||||||
* move's base power for each hit, namely Triple Kick and Triple Axel.
|
* move's base power for each hit, namely Triple Kick and Triple Axel.
|
||||||
* @extends VariablePowerAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
*/
|
*/
|
||||||
export class MultiHitPowerIncrementAttr extends VariablePowerAttr {
|
export class MultiHitPowerIncrementAttr extends VariablePowerAttr {
|
||||||
/** The max number of base power increments allowed for this move */
|
/** The max number of base power increments allowed for this move */
|
||||||
@ -4584,8 +4533,6 @@ export class MultiHitPowerIncrementAttr extends VariablePowerAttr {
|
|||||||
* Attribute used for moves that double in power if the given move immediately
|
* Attribute used for moves that double in power if the given move immediately
|
||||||
* preceded the move applying the attribute, namely Fusion Flare and
|
* preceded the move applying the attribute, namely Fusion Flare and
|
||||||
* Fusion Bolt.
|
* Fusion Bolt.
|
||||||
* @extends VariablePowerAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
*/
|
*/
|
||||||
export class LastMoveDoublePowerAttr extends VariablePowerAttr {
|
export class LastMoveDoublePowerAttr extends VariablePowerAttr {
|
||||||
/** The move that must precede the current move */
|
/** The move that must precede the current move */
|
||||||
@ -4688,7 +4635,6 @@ export class CombinedPledgeStabBoostAttr extends MoveAttr {
|
|||||||
/**
|
/**
|
||||||
* Variable Power attribute for {@link https://bulbapedia.bulbagarden.net/wiki/Round_(move) | Round}.
|
* Variable Power attribute for {@link https://bulbapedia.bulbagarden.net/wiki/Round_(move) | Round}.
|
||||||
* Doubles power if another Pokemon has previously selected Round this turn.
|
* Doubles power if another Pokemon has previously selected Round this turn.
|
||||||
* @extends VariablePowerAttr
|
|
||||||
*/
|
*/
|
||||||
export class RoundPowerAttr extends VariablePowerAttr {
|
export class RoundPowerAttr extends VariablePowerAttr {
|
||||||
override apply(user: Pokemon, target: Pokemon, move: Move, args: [NumberHolder]): boolean {
|
override apply(user: Pokemon, target: Pokemon, move: Move, args: [NumberHolder]): boolean {
|
||||||
@ -4706,8 +4652,6 @@ export class RoundPowerAttr extends VariablePowerAttr {
|
|||||||
* Attribute for the "combo" effect of {@link https://bulbapedia.bulbagarden.net/wiki/Round_(move) | Round}.
|
* Attribute for the "combo" effect of {@link https://bulbapedia.bulbagarden.net/wiki/Round_(move) | Round}.
|
||||||
* Preempts the next move in the turn order with the first instance of any Pokemon
|
* Preempts the next move in the turn order with the first instance of any Pokemon
|
||||||
* using Round. Also marks the Pokemon using the cued Round to double the move's power.
|
* using Round. Also marks the Pokemon using the cued Round to double the move's power.
|
||||||
* @extends MoveEffectAttr
|
|
||||||
* @see {@linkcode RoundPowerAttr}
|
|
||||||
*/
|
*/
|
||||||
export class CueNextRoundAttr extends MoveEffectAttr {
|
export class CueNextRoundAttr extends MoveEffectAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -4909,8 +4853,6 @@ export class StormAccuracyAttr extends VariableAccuracyAttr {
|
|||||||
/**
|
/**
|
||||||
* Attribute used for moves which never miss
|
* Attribute used for moves which never miss
|
||||||
* against Pokemon with the {@linkcode BattlerTagType.MINIMIZED}
|
* against Pokemon with the {@linkcode BattlerTagType.MINIMIZED}
|
||||||
* @extends VariableAccuracyAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
*/
|
*/
|
||||||
export class AlwaysHitMinimizeAttr extends VariableAccuracyAttr {
|
export class AlwaysHitMinimizeAttr extends VariableAccuracyAttr {
|
||||||
/**
|
/**
|
||||||
@ -4983,9 +4925,8 @@ export class PhotonGeyserCategoryAttr extends VariableMoveCategoryAttr {
|
|||||||
* Attribute used for tera moves that change category based on the user's Atk and SpAtk stats
|
* Attribute used for tera moves that change category based on the user's Atk and SpAtk stats
|
||||||
* Note: Currently, `getEffectiveStat` does not ignore all abilities that affect stats except those
|
* Note: Currently, `getEffectiveStat` does not ignore all abilities that affect stats except those
|
||||||
* with the attribute of `StatMultiplierAbAttr`
|
* with the attribute of `StatMultiplierAbAttr`
|
||||||
* TODO: Remove the `.partial()` tag from Tera Blast and Tera Starstorm when the above issue is resolved
|
|
||||||
* @extends VariableMoveCategoryAttr
|
|
||||||
*/
|
*/
|
||||||
|
// TODO: Remove the `.partial()` tag from Tera Blast and Tera Starstorm when the above issue is resolved
|
||||||
export class TeraMoveCategoryAttr extends VariableMoveCategoryAttr {
|
export class TeraMoveCategoryAttr extends VariableMoveCategoryAttr {
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
const category = (args[0] as NumberHolder);
|
const category = (args[0] as NumberHolder);
|
||||||
@ -5002,7 +4943,6 @@ export class TeraMoveCategoryAttr extends VariableMoveCategoryAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Increases the power of Tera Blast if the user is Terastallized into Stellar type
|
* Increases the power of Tera Blast if the user is Terastallized into Stellar type
|
||||||
* @extends VariablePowerAttr
|
|
||||||
*/
|
*/
|
||||||
export class TeraBlastPowerAttr extends VariablePowerAttr {
|
export class TeraBlastPowerAttr extends VariablePowerAttr {
|
||||||
/**
|
/**
|
||||||
@ -5029,8 +4969,6 @@ export class TeraBlastPowerAttr extends VariablePowerAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the move category to status when used on the ally
|
* Change the move category to status when used on the ally
|
||||||
* @extends VariableMoveCategoryAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
*/
|
*/
|
||||||
export class StatusCategoryOnAllyAttr extends VariableMoveCategoryAttr {
|
export class StatusCategoryOnAllyAttr extends VariableMoveCategoryAttr {
|
||||||
/**
|
/**
|
||||||
@ -5262,8 +5200,6 @@ export class WeatherBallTypeAttr extends VariableMoveTypeAttr {
|
|||||||
/**
|
/**
|
||||||
* Changes the move's type to match the current terrain.
|
* Changes the move's type to match the current terrain.
|
||||||
* Has no effect if the user is not grounded.
|
* Has no effect if the user is not grounded.
|
||||||
* @extends VariableMoveTypeAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
*/
|
*/
|
||||||
export class TerrainPulseTypeAttr extends VariableMoveTypeAttr {
|
export class TerrainPulseTypeAttr extends VariableMoveTypeAttr {
|
||||||
/**
|
/**
|
||||||
@ -5311,7 +5247,6 @@ export class TerrainPulseTypeAttr extends VariableMoveTypeAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes type based on the user's IVs
|
* Changes type based on the user's IVs
|
||||||
* @extends VariableMoveTypeAttr
|
|
||||||
*/
|
*/
|
||||||
export class HiddenPowerTypeAttr extends VariableMoveTypeAttr {
|
export class HiddenPowerTypeAttr extends VariableMoveTypeAttr {
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
@ -5339,7 +5274,6 @@ export class HiddenPowerTypeAttr extends VariableMoveTypeAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the type of Tera Blast to match the user's tera type
|
* Changes the type of Tera Blast to match the user's tera type
|
||||||
* @extends VariableMoveTypeAttr
|
|
||||||
*/
|
*/
|
||||||
export class TeraBlastTypeAttr extends VariableMoveTypeAttr {
|
export class TeraBlastTypeAttr extends VariableMoveTypeAttr {
|
||||||
/**
|
/**
|
||||||
@ -5366,7 +5300,6 @@ export class TeraBlastTypeAttr extends VariableMoveTypeAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Attribute used for Tera Starstorm that changes the move type to Stellar
|
* Attribute used for Tera Starstorm that changes the move type to Stellar
|
||||||
* @extends VariableMoveTypeAttr
|
|
||||||
*/
|
*/
|
||||||
export class TeraStarstormTypeAttr extends VariableMoveTypeAttr {
|
export class TeraStarstormTypeAttr extends VariableMoveTypeAttr {
|
||||||
/**
|
/**
|
||||||
@ -5412,7 +5345,6 @@ export class MatchUserTypeAttr extends VariableMoveTypeAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the type of a Pledge move based on the Pledge move combined with it.
|
* Changes the type of a Pledge move based on the Pledge move combined with it.
|
||||||
* @extends VariableMoveTypeAttr
|
|
||||||
*/
|
*/
|
||||||
export class CombinedPledgeTypeAttr extends VariableMoveTypeAttr {
|
export class CombinedPledgeTypeAttr extends VariableMoveTypeAttr {
|
||||||
override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
@ -5550,10 +5482,10 @@ export class SheerColdAccuracyAttr extends OneHitKOAccuracyAttr {
|
|||||||
/**
|
/**
|
||||||
* Changes the normal One Hit KO Accuracy Attr to implement the Gen VII changes,
|
* Changes the normal One Hit KO Accuracy Attr to implement the Gen VII changes,
|
||||||
* where if the user is Ice-Type, it has more accuracy.
|
* where if the user is Ice-Type, it has more accuracy.
|
||||||
* @param {Pokemon} user Pokemon that is using the move; checks the Pokemon's level.
|
* @param user Pokemon that is using the move; checks the Pokemon's level.
|
||||||
* @param {Pokemon} target Pokemon that is receiving the move; checks the Pokemon's level.
|
* @param target Pokemon that is receiving the move; checks the Pokemon's level.
|
||||||
* @param {Move} move N/A
|
* @param move N/A
|
||||||
* @param {any[]} args Uses the accuracy argument, allowing to change it from either 0 if it doesn't pass
|
* @param args Uses the accuracy argument, allowing to change it from either 0 if it doesn't pass
|
||||||
* the first if/else, or 30/20 depending on the type of the user Pokemon.
|
* the first if/else, or 30/20 depending on the type of the user Pokemon.
|
||||||
* @returns Returns true if move is successful, false if misses.
|
* @returns Returns true if move is successful, false if misses.
|
||||||
*/
|
*/
|
||||||
@ -5668,7 +5600,6 @@ export class FrenzyAttr extends MoveEffectAttr {
|
|||||||
/**
|
/**
|
||||||
* Attribute that grants {@link https://bulbapedia.bulbagarden.net/wiki/Semi-invulnerable_turn | semi-invulnerability} to the user during
|
* Attribute that grants {@link https://bulbapedia.bulbagarden.net/wiki/Semi-invulnerable_turn | semi-invulnerability} to the user during
|
||||||
* the associated move's charging phase. Should only be used for {@linkcode ChargingMove | ChargingMoves} as a `chargeAttr`.
|
* the associated move's charging phase. Should only be used for {@linkcode ChargingMove | ChargingMoves} as a `chargeAttr`.
|
||||||
* @extends MoveEffectAttr
|
|
||||||
*/
|
*/
|
||||||
export class SemiInvulnerableAttr extends MoveEffectAttr {
|
export class SemiInvulnerableAttr extends MoveEffectAttr {
|
||||||
/** The type of {@linkcode SemiInvulnerableTag} to grant to the user */
|
/** The type of {@linkcode SemiInvulnerableTag} to grant to the user */
|
||||||
@ -5794,7 +5725,6 @@ export class AddBattlerTagAttr extends MoveEffectAttr {
|
|||||||
/**
|
/**
|
||||||
* Adds a {@link https://bulbapedia.bulbagarden.net/wiki/Seeding | Seeding} effect to the target
|
* Adds a {@link https://bulbapedia.bulbagarden.net/wiki/Seeding | Seeding} effect to the target
|
||||||
* as seen with Leech Seed and Sappy Seed.
|
* as seen with Leech Seed and Sappy Seed.
|
||||||
* @extends AddBattlerTagAttr
|
|
||||||
*/
|
*/
|
||||||
export class LeechSeedAttr extends AddBattlerTagAttr {
|
export class LeechSeedAttr extends AddBattlerTagAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -5804,7 +5734,6 @@ export class LeechSeedAttr extends AddBattlerTagAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the appropriate battler tag for Smack Down and Thousand arrows
|
* Adds the appropriate battler tag for Smack Down and Thousand arrows
|
||||||
* @extends AddBattlerTagAttr
|
|
||||||
*/
|
*/
|
||||||
export class FallDownAttr extends AddBattlerTagAttr {
|
export class FallDownAttr extends AddBattlerTagAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -5829,7 +5758,6 @@ export class FallDownAttr extends AddBattlerTagAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the appropriate battler tag for Gulp Missile when Surf or Dive is used.
|
* Adds the appropriate battler tag for Gulp Missile when Surf or Dive is used.
|
||||||
* @extends MoveEffectAttr
|
|
||||||
*/
|
*/
|
||||||
export class GulpMissileTagAttr extends MoveEffectAttr {
|
export class GulpMissileTagAttr extends MoveEffectAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -5869,7 +5797,6 @@ export class GulpMissileTagAttr extends MoveEffectAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Attribute to implement Jaw Lock's linked trapping effect between the user and target
|
* Attribute to implement Jaw Lock's linked trapping effect between the user and target
|
||||||
* @extends AddBattlerTagAttr
|
|
||||||
*/
|
*/
|
||||||
export class JawLockAttr extends AddBattlerTagAttr {
|
export class JawLockAttr extends AddBattlerTagAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -6035,7 +5962,6 @@ export class ProtectAttr extends AddBattlerTagAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Attribute to remove all Substitutes from the field.
|
* Attribute to remove all Substitutes from the field.
|
||||||
* @extends MoveEffectAttr
|
|
||||||
* @see {@link https://bulbapedia.bulbagarden.net/wiki/Tidy_Up_(move) | Tidy Up}
|
* @see {@link https://bulbapedia.bulbagarden.net/wiki/Tidy_Up_(move) | Tidy Up}
|
||||||
* @see {@linkcode SubstituteTag}
|
* @see {@linkcode SubstituteTag}
|
||||||
*/
|
*/
|
||||||
@ -6067,7 +5993,6 @@ export class RemoveAllSubstitutesAttr extends MoveEffectAttr {
|
|||||||
* Attribute used when a move can deal damage to {@linkcode BattlerTagType}
|
* Attribute used when a move can deal damage to {@linkcode BattlerTagType}
|
||||||
* Moves that always hit but do not deal double damage: Thunder, Fissure, Sky Uppercut,
|
* Moves that always hit but do not deal double damage: Thunder, Fissure, Sky Uppercut,
|
||||||
* Smack Down, Hurricane, Thousand Arrows
|
* Smack Down, Hurricane, Thousand Arrows
|
||||||
* @extends MoveAttr
|
|
||||||
*/
|
*/
|
||||||
export class HitsTagAttr extends MoveAttr {
|
export class HitsTagAttr extends MoveAttr {
|
||||||
/** The {@linkcode BattlerTagType} this move hits */
|
/** The {@linkcode BattlerTagType} this move hits */
|
||||||
@ -6181,8 +6106,6 @@ export class AddArenaTrapTagAttr extends AddArenaTagAttr {
|
|||||||
/**
|
/**
|
||||||
* Attribute used for Stone Axe and Ceaseless Edge.
|
* Attribute used for Stone Axe and Ceaseless Edge.
|
||||||
* Applies the given ArenaTrapTag when move is used.
|
* Applies the given ArenaTrapTag when move is used.
|
||||||
* @extends AddArenaTagAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
*/
|
*/
|
||||||
export class AddArenaTrapTagHitAttr extends AddArenaTagAttr {
|
export class AddArenaTrapTagHitAttr extends AddArenaTagAttr {
|
||||||
/**
|
/**
|
||||||
@ -6275,10 +6198,7 @@ export class RemoveScreensAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*Swaps arena effects between the player and enemy side
|
/** Swaps arena effects between the player and enemy side */
|
||||||
* @extends MoveEffectAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
*/
|
|
||||||
export class SwapArenaTagsAttr extends MoveEffectAttr {
|
export class SwapArenaTagsAttr extends MoveEffectAttr {
|
||||||
public SwapTags: ArenaTagType[];
|
public SwapTags: ArenaTagType[];
|
||||||
|
|
||||||
@ -6344,8 +6264,6 @@ export class AddPledgeEffectAttr extends AddArenaTagAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Attribute used for Revival Blessing.
|
* Attribute used for Revival Blessing.
|
||||||
* @extends MoveEffectAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
*/
|
*/
|
||||||
export class RevivalBlessingAttr extends MoveEffectAttr {
|
export class RevivalBlessingAttr extends MoveEffectAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -6410,7 +6328,6 @@ export class RevivalBlessingAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export class ForceSwitchOutAttr extends MoveEffectAttr {
|
export class ForceSwitchOutAttr extends MoveEffectAttr {
|
||||||
constructor(
|
constructor(
|
||||||
private selfSwitch: boolean = false,
|
private selfSwitch: boolean = false,
|
||||||
@ -6769,7 +6686,7 @@ export class CopyBiomeTypeAttr extends MoveEffectAttr {
|
|||||||
/**
|
/**
|
||||||
* Retrieves a type from the current terrain
|
* Retrieves a type from the current terrain
|
||||||
* @param terrainType {@linkcode TerrainType}
|
* @param terrainType {@linkcode TerrainType}
|
||||||
* @returns {@linkcode Type}
|
* @returns
|
||||||
*/
|
*/
|
||||||
private getTypeForTerrain(terrainType: TerrainType): PokemonType {
|
private getTypeForTerrain(terrainType: TerrainType): PokemonType {
|
||||||
switch (terrainType) {
|
switch (terrainType) {
|
||||||
@ -6790,7 +6707,7 @@ export class CopyBiomeTypeAttr extends MoveEffectAttr {
|
|||||||
/**
|
/**
|
||||||
* Retrieves a type from the current biome
|
* Retrieves a type from the current biome
|
||||||
* @param biomeType {@linkcode BiomeId}
|
* @param biomeType {@linkcode BiomeId}
|
||||||
* @returns {@linkcode Type}
|
* @returns
|
||||||
*/
|
*/
|
||||||
private getTypeForBiome(biomeType: BiomeId): PokemonType {
|
private getTypeForBiome(biomeType: BiomeId): PokemonType {
|
||||||
switch (biomeType) {
|
switch (biomeType) {
|
||||||
@ -6923,8 +6840,6 @@ export class FirstMoveTypeAttr extends MoveEffectAttr {
|
|||||||
/**
|
/**
|
||||||
* Attribute used to call a move.
|
* Attribute used to call a move.
|
||||||
* Used by other move attributes: {@linkcode RandomMoveAttr}, {@linkcode RandomMovesetMoveAttr}, {@linkcode CopyMoveAttr}
|
* Used by other move attributes: {@linkcode RandomMoveAttr}, {@linkcode RandomMovesetMoveAttr}, {@linkcode CopyMoveAttr}
|
||||||
* @see {@linkcode apply} for move call
|
|
||||||
* @extends OverrideMoveEffectAttr
|
|
||||||
*/
|
*/
|
||||||
class CallMoveAttr extends OverrideMoveEffectAttr {
|
class CallMoveAttr extends OverrideMoveEffectAttr {
|
||||||
protected invalidMoves: ReadonlySet<MoveId>;
|
protected invalidMoves: ReadonlySet<MoveId>;
|
||||||
@ -6956,8 +6871,6 @@ class CallMoveAttr extends OverrideMoveEffectAttr {
|
|||||||
/**
|
/**
|
||||||
* Attribute used to call a random move.
|
* Attribute used to call a random move.
|
||||||
* Used for {@linkcode MoveId.METRONOME}
|
* Used for {@linkcode MoveId.METRONOME}
|
||||||
* @see {@linkcode apply} for move selection and move call
|
|
||||||
* @extends CallMoveAttr to call a selected move
|
|
||||||
*/
|
*/
|
||||||
export class RandomMoveAttr extends CallMoveAttr {
|
export class RandomMoveAttr extends CallMoveAttr {
|
||||||
constructor(invalidMoves: ReadonlySet<MoveId>) {
|
constructor(invalidMoves: ReadonlySet<MoveId>) {
|
||||||
@ -7005,8 +6918,6 @@ export class RandomMoveAttr extends CallMoveAttr {
|
|||||||
* Fails if the user has no callable moves.
|
* Fails if the user has no callable moves.
|
||||||
*
|
*
|
||||||
* Invalid moves are indicated by what is passed in to invalidMoves: {@linkcode invalidAssistMoves} or {@linkcode invalidSleepTalkMoves}
|
* Invalid moves are indicated by what is passed in to invalidMoves: {@linkcode invalidAssistMoves} or {@linkcode invalidSleepTalkMoves}
|
||||||
* @extends RandomMoveAttr to use the callMove function on a moveId
|
|
||||||
* @see {@linkcode getCondition} for move selection
|
|
||||||
*/
|
*/
|
||||||
export class RandomMovesetMoveAttr extends CallMoveAttr {
|
export class RandomMovesetMoveAttr extends CallMoveAttr {
|
||||||
private includeParty: boolean;
|
private includeParty: boolean;
|
||||||
@ -7192,8 +7103,6 @@ export class NaturePowerAttr extends OverrideMoveEffectAttr {
|
|||||||
/**
|
/**
|
||||||
* Attribute used to copy a previously-used move.
|
* Attribute used to copy a previously-used move.
|
||||||
* Used for {@linkcode MoveId.COPYCAT} and {@linkcode MoveId.MIRROR_MOVE}
|
* Used for {@linkcode MoveId.COPYCAT} and {@linkcode MoveId.MIRROR_MOVE}
|
||||||
* @see {@linkcode apply} for move selection and move call
|
|
||||||
* @extends CallMoveAttr to call a selected move
|
|
||||||
*/
|
*/
|
||||||
export class CopyMoveAttr extends CallMoveAttr {
|
export class CopyMoveAttr extends CallMoveAttr {
|
||||||
private mirrorMove: boolean;
|
private mirrorMove: boolean;
|
||||||
@ -7529,11 +7438,11 @@ export class SketchAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* User copies the opponent's last used move, if possible
|
* User copies the opponent's last used move, if possible
|
||||||
* @param {Pokemon} user Pokemon that used the move and will replace Sketch with the copied move
|
* @param user Pokemon that used the move and will replace Sketch with the copied move
|
||||||
* @param {Pokemon} target Pokemon that the user wants to copy a move from
|
* @param target Pokemon that the user wants to copy a move from
|
||||||
* @param {Move} move Move being used
|
* @param move Move being used
|
||||||
* @param {any[]} args Unused
|
* @param args Unused
|
||||||
* @returns {boolean} true if the function succeeds, otherwise false
|
* @returns true if the function succeeds, otherwise false
|
||||||
*/
|
*/
|
||||||
|
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
@ -7696,10 +7605,6 @@ export class SwitchAbilitiesAttr extends MoveEffectAttr {
|
|||||||
/**
|
/**
|
||||||
* Attribute used for moves that suppress abilities like {@linkcode MoveId.GASTRO_ACID}.
|
* Attribute used for moves that suppress abilities like {@linkcode MoveId.GASTRO_ACID}.
|
||||||
* A suppressed ability cannot be activated.
|
* A suppressed ability cannot be activated.
|
||||||
*
|
|
||||||
* @extends MoveEffectAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
* @see {@linkcode getCondition}
|
|
||||||
*/
|
*/
|
||||||
export class SuppressAbilitiesAttr extends MoveEffectAttr {
|
export class SuppressAbilitiesAttr extends MoveEffectAttr {
|
||||||
/** Sets ability suppression for the target pokemon and displays a message. */
|
/** Sets ability suppression for the target pokemon and displays a message. */
|
||||||
@ -7725,8 +7630,7 @@ export class SuppressAbilitiesAttr extends MoveEffectAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies the effects of {@linkcode SuppressAbilitiesAttr} if the target has already moved this turn.
|
* Applies the effects of {@linkcode SuppressAbilitiesAttr} if the target has already moved this turn.
|
||||||
* @extends MoveEffectAttr
|
* @see {@linkcode MoveId.CORE_ENFORCER}
|
||||||
* @see {@linkcode MoveId.CORE_ENFORCER} (the move which uses this effect)
|
|
||||||
*/
|
*/
|
||||||
export class SuppressAbilitiesIfActedAttr extends MoveEffectAttr {
|
export class SuppressAbilitiesIfActedAttr extends MoveEffectAttr {
|
||||||
/**
|
/**
|
||||||
@ -7775,8 +7679,6 @@ export class TransformAttr extends MoveEffectAttr {
|
|||||||
/**
|
/**
|
||||||
* Attribute used for status moves, namely Speed Swap,
|
* Attribute used for status moves, namely Speed Swap,
|
||||||
* that swaps the user's and target's corresponding stats.
|
* that swaps the user's and target's corresponding stats.
|
||||||
* @extends MoveEffectAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
*/
|
*/
|
||||||
export class SwapStatAttr extends MoveEffectAttr {
|
export class SwapStatAttr extends MoveEffectAttr {
|
||||||
/** The stat to be swapped between the user and the target */
|
/** The stat to be swapped between the user and the target */
|
||||||
@ -7817,7 +7719,6 @@ export class SwapStatAttr extends MoveEffectAttr {
|
|||||||
/**
|
/**
|
||||||
* Attribute used to switch the user's own stats.
|
* Attribute used to switch the user's own stats.
|
||||||
* Used by Power Shift.
|
* Used by Power Shift.
|
||||||
* @extends MoveEffectAttr
|
|
||||||
*/
|
*/
|
||||||
export class ShiftStatAttr extends MoveEffectAttr {
|
export class ShiftStatAttr extends MoveEffectAttr {
|
||||||
private statToSwitch: EffectiveStat;
|
private statToSwitch: EffectiveStat;
|
||||||
@ -7832,7 +7733,7 @@ export class ShiftStatAttr extends MoveEffectAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Switches the user's stats based on the {@linkcode statToSwitch} and {@linkcode statToSwitchWith} attributes.
|
* Switches the user's stats based on the {@linkcode statToSwitch} and {@linkcode statToSwitchWith} attributes.
|
||||||
* @param {Pokemon} user the {@linkcode Pokemon} that used the move
|
* @param user the {@linkcode Pokemon} that used the move
|
||||||
* @param target n/a
|
* @param target n/a
|
||||||
* @param move n/a
|
* @param move n/a
|
||||||
* @param args n/a
|
* @param args n/a
|
||||||
@ -7860,7 +7761,7 @@ export class ShiftStatAttr extends MoveEffectAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Encourages the user to use the move if the stat to switch with is greater than the stat to switch.
|
* Encourages the user to use the move if the stat to switch with is greater than the stat to switch.
|
||||||
* @param {Pokemon} user the {@linkcode Pokemon} that used the move
|
* @param user the {@linkcode Pokemon} that used the move
|
||||||
* @param target n/a
|
* @param target n/a
|
||||||
* @param move n/a
|
* @param move n/a
|
||||||
* @returns number of points to add to the user's benefit score
|
* @returns number of points to add to the user's benefit score
|
||||||
@ -7874,8 +7775,6 @@ export class ShiftStatAttr extends MoveEffectAttr {
|
|||||||
* Attribute used for status moves, namely Power Split and Guard Split,
|
* Attribute used for status moves, namely Power Split and Guard Split,
|
||||||
* that take the average of a user's and target's corresponding
|
* that take the average of a user's and target's corresponding
|
||||||
* stats and assign that average back to each corresponding stat.
|
* stats and assign that average back to each corresponding stat.
|
||||||
* @extends MoveEffectAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
*/
|
*/
|
||||||
export class AverageStatsAttr extends MoveEffectAttr {
|
export class AverageStatsAttr extends MoveEffectAttr {
|
||||||
/** The stats to be averaged individually between the user and the target */
|
/** The stats to be averaged individually between the user and the target */
|
||||||
@ -7928,11 +7827,7 @@ export class MoneyAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Applies {@linkcode BattlerTagType.DESTINY_BOND} to the user */
|
||||||
* Applies {@linkcode BattlerTagType.DESTINY_BOND} to the user.
|
|
||||||
*
|
|
||||||
* @extends MoveEffectAttr
|
|
||||||
*/
|
|
||||||
export class DestinyBondAttr extends MoveEffectAttr {
|
export class DestinyBondAttr extends MoveEffectAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(true, { trigger: MoveEffectTrigger.PRE_APPLY });
|
super(true, { trigger: MoveEffectTrigger.PRE_APPLY });
|
||||||
@ -7943,7 +7838,7 @@ export class DestinyBondAttr extends MoveEffectAttr {
|
|||||||
* @param user {@linkcode Pokemon} that is having the tag applied to.
|
* @param user {@linkcode Pokemon} that is having the tag applied to.
|
||||||
* @param target {@linkcode Pokemon} N/A
|
* @param target {@linkcode Pokemon} N/A
|
||||||
* @param move {@linkcode Move} {@linkcode Move.DESTINY_BOND}
|
* @param move {@linkcode Move} {@linkcode Move.DESTINY_BOND}
|
||||||
* @param {any[]} args N/A
|
* @param args N/A
|
||||||
* @returns true
|
* @returns true
|
||||||
*/
|
*/
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
@ -7953,10 +7848,7 @@ export class DestinyBondAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Attribute to apply a battler tag to the target if they have had their stats boosted this turn */
|
||||||
* Attribute to apply a battler tag to the target if they have had their stats boosted this turn.
|
|
||||||
* @extends AddBattlerTagAttr
|
|
||||||
*/
|
|
||||||
export class AddBattlerTagIfBoostedAttr extends AddBattlerTagAttr {
|
export class AddBattlerTagIfBoostedAttr extends AddBattlerTagAttr {
|
||||||
constructor(tag: BattlerTagType) {
|
constructor(tag: BattlerTagType) {
|
||||||
super(tag, false, false, 2, 5);
|
super(tag, false, false, 2, 5);
|
||||||
@ -7966,7 +7858,7 @@ export class AddBattlerTagIfBoostedAttr extends AddBattlerTagAttr {
|
|||||||
* @param user {@linkcode Pokemon} using this move
|
* @param user {@linkcode Pokemon} using this move
|
||||||
* @param target {@linkcode Pokemon} target of this move
|
* @param target {@linkcode Pokemon} target of this move
|
||||||
* @param move {@linkcode Move} being used
|
* @param move {@linkcode Move} being used
|
||||||
* @param {any[]} args N/A
|
* @param args N/A
|
||||||
* @returns true
|
* @returns true
|
||||||
*/
|
*/
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
@ -7979,7 +7871,6 @@ export class AddBattlerTagIfBoostedAttr extends AddBattlerTagAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Attribute to apply a status effect to the target if they have had their stats boosted this turn.
|
* Attribute to apply a status effect to the target if they have had their stats boosted this turn.
|
||||||
* @extends MoveEffectAttr
|
|
||||||
*/
|
*/
|
||||||
export class StatusIfBoostedAttr extends MoveEffectAttr {
|
export class StatusIfBoostedAttr extends MoveEffectAttr {
|
||||||
public effect: StatusEffect;
|
public effect: StatusEffect;
|
||||||
@ -7993,7 +7884,7 @@ export class StatusIfBoostedAttr extends MoveEffectAttr {
|
|||||||
* @param user {@linkcode Pokemon} using this move
|
* @param user {@linkcode Pokemon} using this move
|
||||||
* @param target {@linkcode Pokemon} target of this move
|
* @param target {@linkcode Pokemon} target of this move
|
||||||
* @param move {@linkcode Move} N/A
|
* @param move {@linkcode Move} N/A
|
||||||
* @param {any[]} args N/A
|
* @param args N/A
|
||||||
* @returns true
|
* @returns true
|
||||||
*/
|
*/
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
@ -8075,7 +7966,6 @@ export class AfterYouAttr extends MoveEffectAttr {
|
|||||||
/**
|
/**
|
||||||
* Move effect to force the target to move last, ignoring priority.
|
* Move effect to force the target to move last, ignoring priority.
|
||||||
* If applied to multiple targets, they move in speed order after all other moves.
|
* If applied to multiple targets, they move in speed order after all other moves.
|
||||||
* @extends MoveEffectAttr
|
|
||||||
*/
|
*/
|
||||||
export class ForceLastAttr extends MoveEffectAttr {
|
export class ForceLastAttr extends MoveEffectAttr {
|
||||||
/**
|
/**
|
||||||
@ -8137,9 +8027,12 @@ const failIfSingleBattle: MoveConditionFunc = (user, target, move) => globalScen
|
|||||||
|
|
||||||
const failIfDampCondition: MoveConditionFunc = (user, target, move) => {
|
const failIfDampCondition: MoveConditionFunc = (user, target, move) => {
|
||||||
const cancelled = new BooleanHolder(false);
|
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
|
// 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 }));
|
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:cannotUseMove", { pokemonName: getPokemonNameWithAffix(user), moveName: move.name }));
|
||||||
}
|
}
|
||||||
return !cancelled.value;
|
return !cancelled.value;
|
||||||
@ -8161,6 +8054,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 failIfNoTargetHeldItemsCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => target.getHeldItems().filter(i => i.isTransferable)?.length > 0;
|
||||||
|
|
||||||
const attackedByItemMessageFunc = (user: Pokemon, target: Pokemon, move: Move) => {
|
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);
|
const heldItems = target.getHeldItems().filter(i => i.isTransferable);
|
||||||
if (heldItems.length === 0) {
|
if (heldItems.length === 0) {
|
||||||
return "";
|
return "";
|
||||||
@ -8248,11 +8144,11 @@ export class ResistLastMoveTypeAttr extends MoveEffectAttr {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* User changes its type to a random type that resists the target's last used move
|
* User changes its type to a random type that resists the target's last used move
|
||||||
* @param {Pokemon} user Pokemon that used the move and will change types
|
* @param user Pokemon that used the move and will change types
|
||||||
* @param {Pokemon} target Opposing pokemon that recently used a move
|
* @param target Opposing pokemon that recently used a move
|
||||||
* @param {Move} move Move being used
|
* @param move Move being used
|
||||||
* @param {any[]} args Unused
|
* @param args Unused
|
||||||
* @returns {boolean} true if the function succeeds
|
* @returns true if the function succeeds
|
||||||
*/
|
*/
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
if (!super.apply(user, target, move, args)) {
|
if (!super.apply(user, target, move, args)) {
|
||||||
@ -8313,9 +8209,6 @@ export class ResistLastMoveTypeAttr extends MoveEffectAttr {
|
|||||||
* Drops the target's immunity to types it is immune to
|
* Drops the target's immunity to types it is immune to
|
||||||
* and makes its evasiveness be ignored during accuracy
|
* and makes its evasiveness be ignored during accuracy
|
||||||
* checks. Used by: {@linkcode MoveId.ODOR_SLEUTH | Odor Sleuth}, {@linkcode MoveId.MIRACLE_EYE | Miracle Eye} and {@linkcode MoveId.FORESIGHT | Foresight}
|
* checks. Used by: {@linkcode MoveId.ODOR_SLEUTH | Odor Sleuth}, {@linkcode MoveId.MIRACLE_EYE | Miracle Eye} and {@linkcode MoveId.FORESIGHT | Foresight}
|
||||||
*
|
|
||||||
* @extends AddBattlerTagAttr
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
*/
|
*/
|
||||||
export class ExposedMoveAttr extends AddBattlerTagAttr {
|
export class ExposedMoveAttr extends AddBattlerTagAttr {
|
||||||
constructor(tagType: BattlerTagType) {
|
constructor(tagType: BattlerTagType) {
|
||||||
|
@ -50,10 +50,9 @@ export class PokemonMove {
|
|||||||
const move = this.getMove();
|
const move = this.getMove();
|
||||||
// TODO: Add Sky Drop's 1 turn stall
|
// TODO: Add Sky Drop's 1 turn stall
|
||||||
const usability = new BooleanHolder(
|
const usability = new BooleanHolder(
|
||||||
!move.name.endsWith(" (N)") &&
|
!move.name.endsWith(" (N)")
|
||||||
(ignorePp || this.ppUsed < this.getMovePp() || move.pp === -1) &&
|
&& (ignorePp || this.ppUsed < this.getMovePp() || move.pp === -1) // TODO: Review if the `MoveId.NONE` check is even necessary anymore
|
||||||
// TODO: Review if the `MoveId.NONE` check is even necessary anymore
|
&& !(this.moveId !== MoveId.NONE && !ignoreRestrictionTags && pokemon.isMoveRestricted(this.moveId, pokemon)),
|
||||||
!(this.moveId !== MoveId.NONE && !ignoreRestrictionTags && pokemon.isMoveRestricted(this.moveId, pokemon)),
|
|
||||||
);
|
);
|
||||||
if (pokemon.isPlayer()) {
|
if (pokemon.isPlayer()) {
|
||||||
applyChallenges(ChallengeType.POKEMON_MOVE, move.id, usability);
|
applyChallenges(ChallengeType.POKEMON_MOVE, move.id, usability);
|
||||||
|
@ -111,7 +111,7 @@ export const ATrainersTestEncounter: MysteryEncounter = MysteryEncounterBuilder.
|
|||||||
const trainerSpriteKey = trainerConfig.getSpriteKey();
|
const trainerSpriteKey = trainerConfig.getSpriteKey();
|
||||||
encounter.enemyPartyConfigs.push({
|
encounter.enemyPartyConfigs.push({
|
||||||
levelAdditiveModifier: 1,
|
levelAdditiveModifier: 1,
|
||||||
trainerConfig: trainerConfig,
|
trainerConfig,
|
||||||
});
|
});
|
||||||
|
|
||||||
encounter.spriteConfigs = [
|
encounter.spriteConfigs = [
|
||||||
|
@ -527,7 +527,8 @@ function doBerrySpritePile(isEat = false) {
|
|||||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||||
animationOrder.forEach((berry, i) => {
|
animationOrder.forEach((berry, i) => {
|
||||||
const introVisualsIndex = encounter.spriteConfigs.findIndex(config => config.spriteKey?.includes(berry));
|
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);
|
const sprites = encounter.introVisuals?.getSpriteAtIndex(introVisualsIndex);
|
||||||
if (sprites) {
|
if (sprites) {
|
||||||
sprite = sprites[0];
|
sprite = sprites[0];
|
||||||
|
@ -93,8 +93,8 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter = MysteryEncounterB
|
|||||||
|
|
||||||
// Store pokemon and price
|
// Store pokemon and price
|
||||||
encounter.misc = {
|
encounter.misc = {
|
||||||
pokemon: pokemon,
|
pokemon,
|
||||||
price: price,
|
price,
|
||||||
};
|
};
|
||||||
|
|
||||||
// If player meets the combo OR requirements for option 2, populate the token
|
// If player meets the combo OR requirements for option 2, populate the token
|
||||||
|
@ -71,7 +71,7 @@ export const BerriesAboundEncounter: MysteryEncounter = MysteryEncounterBuilder.
|
|||||||
const config: EnemyPartyConfig = {
|
const config: EnemyPartyConfig = {
|
||||||
pokemonConfigs: [
|
pokemonConfigs: [
|
||||||
{
|
{
|
||||||
level: level,
|
level,
|
||||||
species: bossPokemon.species,
|
species: bossPokemon.species,
|
||||||
dataSource: new PokemonData(bossPokemon),
|
dataSource: new PokemonData(bossPokemon),
|
||||||
isBoss: true,
|
isBoss: true,
|
||||||
@ -105,8 +105,8 @@ export const BerriesAboundEncounter: MysteryEncounter = MysteryEncounterBuilder.
|
|||||||
hasShadow: true,
|
hasShadow: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
spriteKey: spriteKey,
|
spriteKey,
|
||||||
fileRoot: fileRoot,
|
fileRoot,
|
||||||
hasShadow: true,
|
hasShadow: true,
|
||||||
tint: 0.25,
|
tint: 0.25,
|
||||||
x: -5,
|
x: -5,
|
||||||
@ -320,9 +320,9 @@ function tryGiveBerry(prioritizedPokemon?: PlayerPokemon) {
|
|||||||
if (prioritizedPokemon) {
|
if (prioritizedPokemon) {
|
||||||
const heldBerriesOfType = globalScene.findModifier(
|
const heldBerriesOfType = globalScene.findModifier(
|
||||||
m =>
|
m =>
|
||||||
m instanceof BerryModifier &&
|
m instanceof BerryModifier
|
||||||
m.pokemonId === prioritizedPokemon.id &&
|
&& m.pokemonId === prioritizedPokemon.id
|
||||||
(m as BerryModifier).berryType === berryType,
|
&& (m as BerryModifier).berryType === berryType,
|
||||||
true,
|
true,
|
||||||
) as BerryModifier;
|
) as BerryModifier;
|
||||||
|
|
||||||
|
@ -46,8 +46,8 @@ import {
|
|||||||
} from "#mystery-encounters/mystery-encounter-requirements";
|
} from "#mystery-encounters/mystery-encounter-requirements";
|
||||||
import { getRandomPartyMemberFunc, trainerConfigs } from "#trainers/trainer-config";
|
import { getRandomPartyMemberFunc, trainerConfigs } from "#trainers/trainer-config";
|
||||||
import { TrainerPartyCompoundTemplate, TrainerPartyTemplate } from "#trainers/trainer-party-template";
|
import { TrainerPartyCompoundTemplate, TrainerPartyTemplate } from "#trainers/trainer-party-template";
|
||||||
import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
|
import { MoveInfoOverlay } from "#ui/containers/move-info-overlay";
|
||||||
import { MoveInfoOverlay } from "#ui/move-info-overlay";
|
import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler";
|
||||||
import { isNullOrUndefined, randSeedInt, randSeedShuffle } from "#utils/common";
|
import { isNullOrUndefined, randSeedInt, randSeedShuffle } from "#utils/common";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
|
||||||
@ -213,7 +213,8 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
female: true,
|
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]) {
|
if (globalScene.currentBattle.waveIndex < WAVE_LEVEL_BREAKPOINTS[3]) {
|
||||||
beedrillKeys = getSpriteKeysFromSpecies(SpeciesId.BEEDRILL, false);
|
beedrillKeys = getSpriteKeysFromSpecies(SpeciesId.BEEDRILL, false);
|
||||||
butterfreeKeys = getSpriteKeysFromSpecies(SpeciesId.BUTTERFREE, false);
|
butterfreeKeys = getSpriteKeysFromSpecies(SpeciesId.BUTTERFREE, false);
|
||||||
@ -247,7 +248,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
yShadow: -4,
|
yShadow: -4,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
spriteKey: spriteKey,
|
spriteKey,
|
||||||
fileRoot: "trainer",
|
fileRoot: "trainer",
|
||||||
hasShadow: true,
|
hasShadow: true,
|
||||||
x: 4,
|
x: 4,
|
||||||
@ -440,11 +441,11 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
// Get Pokemon held items and filter for valid ones
|
// Get Pokemon held items and filter for valid ones
|
||||||
const validItems = pokemon.getHeldItems().filter(item => {
|
const validItems = pokemon.getHeldItems().filter(item => {
|
||||||
return (
|
return (
|
||||||
(item instanceof BypassSpeedChanceModifier ||
|
(item instanceof BypassSpeedChanceModifier
|
||||||
item instanceof ContactHeldItemTransferChanceModifier ||
|
|| item instanceof ContactHeldItemTransferChanceModifier
|
||||||
(item instanceof AttackTypeBoosterModifier &&
|
|| (item instanceof AttackTypeBoosterModifier
|
||||||
(item.type as AttackTypeBoosterModifierType).moveType === PokemonType.BUG)) &&
|
&& (item.type as AttackTypeBoosterModifierType).moveType === PokemonType.BUG))
|
||||||
item.isTransferable
|
&& item.isTransferable
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -469,10 +470,10 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
// If pokemon has valid item, it can be selected
|
// If pokemon has valid item, it can be selected
|
||||||
const hasValidItem = pokemon.getHeldItems().some(item => {
|
const hasValidItem = pokemon.getHeldItems().some(item => {
|
||||||
return (
|
return (
|
||||||
item instanceof BypassSpeedChanceModifier ||
|
item instanceof BypassSpeedChanceModifier
|
||||||
item instanceof ContactHeldItemTransferChanceModifier ||
|
|| item instanceof ContactHeldItemTransferChanceModifier
|
||||||
(item instanceof AttackTypeBoosterModifier &&
|
|| (item instanceof AttackTypeBoosterModifier
|
||||||
(item.type as AttackTypeBoosterModifierType).moveType === PokemonType.BUG)
|
&& (item.type as AttackTypeBoosterModifierType).moveType === PokemonType.BUG)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
if (!hasValidItem) {
|
if (!hasValidItem) {
|
||||||
|
@ -45,7 +45,7 @@ import { MysteryEncounterBuilder } from "#mystery-encounters/mystery-encounter";
|
|||||||
import { MysteryEncounterOptionBuilder } from "#mystery-encounters/mystery-encounter-option";
|
import { MysteryEncounterOptionBuilder } from "#mystery-encounters/mystery-encounter-option";
|
||||||
import { trainerConfigs } from "#trainers/trainer-config";
|
import { trainerConfigs } from "#trainers/trainer-config";
|
||||||
import { TrainerPartyCompoundTemplate, TrainerPartyTemplate } from "#trainers/trainer-party-template";
|
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 { randSeedInt, randSeedShuffle } from "#utils/common";
|
||||||
import { getPokemonSpecies } from "#utils/pokemon-utils";
|
import { getPokemonSpecies } from "#utils/pokemon-utils";
|
||||||
import i18next from "i18next";
|
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
|
// Blacephalon has the random ability from pool, and 2 entirely random types to fit with the theme of the encounter
|
||||||
species: getPokemonSpecies(SpeciesId.BLACEPHALON),
|
species: getPokemonSpecies(SpeciesId.BLACEPHALON),
|
||||||
customPokemonData: new CustomPokemonData({
|
customPokemonData: new CustomPokemonData({
|
||||||
ability: ability,
|
ability,
|
||||||
types: [firstType, secondType],
|
types: [firstType, secondType],
|
||||||
}),
|
}),
|
||||||
isBoss: true,
|
isBoss: true,
|
||||||
|
@ -37,7 +37,7 @@ import { MysteryEncounterOptionBuilder } from "#mystery-encounters/mystery-encou
|
|||||||
import { MoveRequirement } from "#mystery-encounters/mystery-encounter-requirements";
|
import { MoveRequirement } from "#mystery-encounters/mystery-encounter-requirements";
|
||||||
import { DANCING_MOVES } from "#mystery-encounters/requirement-groups";
|
import { DANCING_MOVES } from "#mystery-encounters/requirement-groups";
|
||||||
import { PokemonData } from "#system/pokemon-data";
|
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 { getPokemonSpecies } from "#utils/pokemon-utils";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
|
||||||
@ -168,7 +168,7 @@ export const DancingLessonsEncounter: MysteryEncounter = MysteryEncounterBuilder
|
|||||||
const config: EnemyPartyConfig = {
|
const config: EnemyPartyConfig = {
|
||||||
pokemonConfigs: [
|
pokemonConfigs: [
|
||||||
{
|
{
|
||||||
species: species,
|
species,
|
||||||
dataSource: oricorioData,
|
dataSource: oricorioData,
|
||||||
isBoss: true,
|
isBoss: true,
|
||||||
// Gets +1 to all stats except SPD on battle start
|
// Gets +1 to all stats except SPD on battle start
|
||||||
|
@ -33,7 +33,7 @@ import {
|
|||||||
MoneyRequirement,
|
MoneyRequirement,
|
||||||
} from "#mystery-encounters/mystery-encounter-requirements";
|
} from "#mystery-encounters/mystery-encounter-requirements";
|
||||||
import i18next from "#plugins/i18n";
|
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 { randSeedItem } from "#utils/common";
|
||||||
import { getPokemonSpecies } from "#utils/pokemon-utils";
|
import { getPokemonSpecies } from "#utils/pokemon-utils";
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ import {
|
|||||||
import type { MysteryEncounter } from "#mystery-encounters/mystery-encounter";
|
import type { MysteryEncounter } from "#mystery-encounters/mystery-encounter";
|
||||||
import { MysteryEncounterBuilder } from "#mystery-encounters/mystery-encounter";
|
import { MysteryEncounterBuilder } from "#mystery-encounters/mystery-encounter";
|
||||||
import { MysteryEncounterOptionBuilder } from "#mystery-encounters/mystery-encounter-option";
|
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";
|
import i18next from "i18next";
|
||||||
|
|
||||||
/** i18n namespace for the encounter */
|
/** i18n namespace for the encounter */
|
||||||
@ -249,6 +249,6 @@ function pokemonAndMoveChosen(pokemon: PlayerPokemon, move: PokemonMove, correct
|
|||||||
setEncounterExp([pokemon.id], 100);
|
setEncounterExp([pokemon.id], 100);
|
||||||
}
|
}
|
||||||
encounter.misc = {
|
encounter.misc = {
|
||||||
correctMove: correctMove,
|
correctMove,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ export const FightOrFlightEncounter: MysteryEncounter = MysteryEncounterBuilder.
|
|||||||
const config: EnemyPartyConfig = {
|
const config: EnemyPartyConfig = {
|
||||||
pokemonConfigs: [
|
pokemonConfigs: [
|
||||||
{
|
{
|
||||||
level: level,
|
level,
|
||||||
species: bossPokemon.species,
|
species: bossPokemon.species,
|
||||||
dataSource: new PokemonData(bossPokemon),
|
dataSource: new PokemonData(bossPokemon),
|
||||||
isBoss: true,
|
isBoss: true,
|
||||||
@ -120,8 +120,8 @@ export const FightOrFlightEncounter: MysteryEncounter = MysteryEncounterBuilder.
|
|||||||
disableAnimation: true,
|
disableAnimation: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
spriteKey: spriteKey,
|
spriteKey,
|
||||||
fileRoot: fileRoot,
|
fileRoot,
|
||||||
hasShadow: true,
|
hasShadow: true,
|
||||||
tint: 0.25,
|
tint: 0.25,
|
||||||
x: -5,
|
x: -5,
|
||||||
|
@ -42,7 +42,7 @@ import { MysteryEncounterOptionBuilder } from "#mystery-encounters/mystery-encou
|
|||||||
import { PartySizeRequirement } from "#mystery-encounters/mystery-encounter-requirements";
|
import { PartySizeRequirement } from "#mystery-encounters/mystery-encounter-requirements";
|
||||||
import { PokemonData } from "#system/pokemon-data";
|
import { PokemonData } from "#system/pokemon-data";
|
||||||
import { MusicPreference } from "#system/settings";
|
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 { isNullOrUndefined, NumberHolder, randInt, randSeedInt, randSeedItem, randSeedShuffle } from "#utils/common";
|
||||||
import { getEnumKeys } from "#utils/enums";
|
import { getEnumKeys } from "#utils/enums";
|
||||||
import { getRandomLocaleEntry } from "#utils/i18n";
|
import { getRandomLocaleEntry } from "#utils/i18n";
|
||||||
@ -195,10 +195,10 @@ export const GlobalTradeSystemEncounter: MysteryEncounter = MysteryEncounterBuil
|
|||||||
: ""
|
: ""
|
||||||
}`;
|
}`;
|
||||||
const line2 =
|
const line2 =
|
||||||
i18next.t("pokemonInfoContainer:nature") +
|
i18next.t("pokemonInfoContainer:nature")
|
||||||
" " +
|
+ " "
|
||||||
getNatureName(tradePokemon.getNature()) +
|
+ getNatureName(tradePokemon.getNature())
|
||||||
(formName ? ` | ${i18next.t("pokemonInfoContainer:form")} ${formName}` : "");
|
+ (formName ? ` | ${i18next.t("pokemonInfoContainer:form")} ${formName}` : "");
|
||||||
showEncounterText(`${line1}\n${line2}`, 0, 0, false);
|
showEncounterText(`${line1}\n${line2}`, 0, 0, false);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -292,8 +292,7 @@ export const GlobalTradeSystemEncounter: MysteryEncounter = MysteryEncounterBuil
|
|||||||
|
|
||||||
// Extra HA roll at base 1/64 odds (boosted by events and charms)
|
// Extra HA roll at base 1/64 odds (boosted by events and charms)
|
||||||
const hiddenIndex = tradePokemon.species.ability2 ? 2 : 1;
|
const hiddenIndex = tradePokemon.species.ability2 ? 2 : 1;
|
||||||
if (tradePokemon.species.abilityHidden) {
|
if (tradePokemon.species.abilityHidden && tradePokemon.abilityIndex < hiddenIndex) {
|
||||||
if (tradePokemon.abilityIndex < hiddenIndex) {
|
|
||||||
const hiddenAbilityChance = new NumberHolder(64);
|
const hiddenAbilityChance = new NumberHolder(64);
|
||||||
globalScene.applyModifiers(HiddenAbilityRateBoosterModifier, true, hiddenAbilityChance);
|
globalScene.applyModifiers(HiddenAbilityRateBoosterModifier, true, hiddenAbilityChance);
|
||||||
|
|
||||||
@ -303,7 +302,6 @@ export const GlobalTradeSystemEncounter: MysteryEncounter = MysteryEncounterBuil
|
|||||||
tradePokemon.abilityIndex = hiddenIndex;
|
tradePokemon.abilityIndex = hiddenIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// If Pokemon is still not shiny or with HA, give the Pokemon a random Common egg move in its moveset
|
// If Pokemon is still not shiny or with HA, give the Pokemon a random Common egg move in its moveset
|
||||||
if (!tradePokemon.shiny && (!tradePokemon.species.abilityHidden || tradePokemon.abilityIndex < hiddenIndex)) {
|
if (!tradePokemon.shiny && (!tradePokemon.species.abilityHidden || tradePokemon.abilityIndex < hiddenIndex)) {
|
||||||
|
@ -50,7 +50,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = MysteryEncounter
|
|||||||
const normalSpriteKey = normalConfig.getSpriteKey(female, normalConfig.doubleOnly);
|
const normalSpriteKey = normalConfig.getSpriteKey(female, normalConfig.doubleOnly);
|
||||||
encounter.enemyPartyConfigs.push({
|
encounter.enemyPartyConfigs.push({
|
||||||
trainerConfig: normalConfig,
|
trainerConfig: normalConfig,
|
||||||
female: female,
|
female,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Hard difficulty trainer is another random trainer, but with AVERAGE_BALANCED config
|
// Hard difficulty trainer is another random trainer, but with AVERAGE_BALANCED config
|
||||||
@ -81,7 +81,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = MysteryEncounter
|
|||||||
encounter.enemyPartyConfigs.push({
|
encounter.enemyPartyConfigs.push({
|
||||||
trainerConfig: hardConfig,
|
trainerConfig: hardConfig,
|
||||||
levelAdditiveModifier: 1,
|
levelAdditiveModifier: 1,
|
||||||
female: female,
|
female,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Brutal trainer is pulled from pool of boss trainers (gym leaders) for the biome
|
// 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({
|
encounter.enemyPartyConfigs.push({
|
||||||
trainerConfig: brutalConfig,
|
trainerConfig: brutalConfig,
|
||||||
levelAdditiveModifier: 1.5,
|
levelAdditiveModifier: 1.5,
|
||||||
female: female,
|
female,
|
||||||
});
|
});
|
||||||
|
|
||||||
encounter.spriteConfigs = [
|
encounter.spriteConfigs = [
|
||||||
|
@ -163,8 +163,12 @@ export const MysteriousChestEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
queueEncounterMessage(`${namespace}:option.1.great`);
|
queueEncounterMessage(`${namespace}:option.1.great`);
|
||||||
leaveEncounterWithoutBattle();
|
leaveEncounterWithoutBattle();
|
||||||
} else if (
|
} else if (
|
||||||
roll >=
|
roll
|
||||||
RAND_LENGTH - COMMON_REWARDS_PERCENT - ULTRA_REWARDS_PERCENT - ROGUE_REWARDS_PERCENT - MASTER_REWARDS_PERCENT
|
>= RAND_LENGTH
|
||||||
|
- COMMON_REWARDS_PERCENT
|
||||||
|
- ULTRA_REWARDS_PERCENT
|
||||||
|
- ROGUE_REWARDS_PERCENT
|
||||||
|
- MASTER_REWARDS_PERCENT
|
||||||
) {
|
) {
|
||||||
// Choose 1 MASTER tier item (5%)
|
// Choose 1 MASTER tier item (5%)
|
||||||
setEncounterRewards({
|
setEncounterRewards({
|
||||||
|
@ -104,7 +104,7 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter = MysteryEncounterBui
|
|||||||
encounter.setDialogueToken("boost2", modifiers[1].name);
|
encounter.setDialogueToken("boost2", modifiers[1].name);
|
||||||
encounter.misc = {
|
encounter.misc = {
|
||||||
chosenPokemon: pokemon,
|
chosenPokemon: pokemon,
|
||||||
modifiers: modifiers,
|
modifiers,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -187,7 +187,7 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter = MysteryEncounterBui
|
|||||||
encounter.setDialogueToken("boost2", modifiers[1].name);
|
encounter.setDialogueToken("boost2", modifiers[1].name);
|
||||||
encounter.misc = {
|
encounter.misc = {
|
||||||
chosenPokemon: pokemon,
|
chosenPokemon: pokemon,
|
||||||
modifiers: modifiers,
|
modifiers,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ export const TeleportingHijinksEncounter: MysteryEncounter = MysteryEncounterBui
|
|||||||
const config: EnemyPartyConfig = {
|
const config: EnemyPartyConfig = {
|
||||||
pokemonConfigs: [
|
pokemonConfigs: [
|
||||||
{
|
{
|
||||||
level: level,
|
level,
|
||||||
species: bossSpecies,
|
species: bossSpecies,
|
||||||
dataSource: new PokemonData(bossPokemon),
|
dataSource: new PokemonData(bossPokemon),
|
||||||
isBoss: true,
|
isBoss: true,
|
||||||
@ -221,7 +221,7 @@ async function doBiomeTransitionDialogueAndBattleInit() {
|
|||||||
const config: EnemyPartyConfig = {
|
const config: EnemyPartyConfig = {
|
||||||
pokemonConfigs: [
|
pokemonConfigs: [
|
||||||
{
|
{
|
||||||
level: level,
|
level,
|
||||||
species: bossSpecies,
|
species: bossSpecies,
|
||||||
dataSource: new PokemonData(bossPokemon),
|
dataSource: new PokemonData(bossPokemon),
|
||||||
isBoss: true,
|
isBoss: true,
|
||||||
|
@ -92,11 +92,11 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter = MysteryEncounterBui
|
|||||||
.getEventEncounters()
|
.getEventEncounters()
|
||||||
.filter(
|
.filter(
|
||||||
s =>
|
s =>
|
||||||
!getPokemonSpecies(s.species).legendary &&
|
!getPokemonSpecies(s.species).legendary
|
||||||
!getPokemonSpecies(s.species).subLegendary &&
|
&& !getPokemonSpecies(s.species).subLegendary
|
||||||
!getPokemonSpecies(s.species).mythical &&
|
&& !getPokemonSpecies(s.species).mythical
|
||||||
!NON_LEGEND_PARADOX_POKEMON.includes(s.species) &&
|
&& !NON_LEGEND_PARADOX_POKEMON.includes(s.species)
|
||||||
!NON_LEGEND_ULTRA_BEASTS.includes(s.species),
|
&& !NON_LEGEND_ULTRA_BEASTS.includes(s.species),
|
||||||
);
|
);
|
||||||
|
|
||||||
let pokemon: PlayerPokemon;
|
let pokemon: PlayerPokemon;
|
||||||
@ -109,16 +109,16 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter = MysteryEncounterBui
|
|||||||
* Mons rolled from the event encounter pool get 3 extra shiny rolls
|
* Mons rolled from the event encounter pool get 3 extra shiny rolls
|
||||||
*/
|
*/
|
||||||
if (
|
if (
|
||||||
r === 0 ||
|
r === 0
|
||||||
((isNullOrUndefined(species.abilityHidden) || species.abilityHidden === AbilityId.NONE) &&
|
|| ((isNullOrUndefined(species.abilityHidden) || species.abilityHidden === AbilityId.NONE)
|
||||||
validEventEncounters.length === 0)
|
&& validEventEncounters.length === 0)
|
||||||
) {
|
) {
|
||||||
// If you roll 1%, give shiny Magikarp with random variant
|
// If you roll 1%, give shiny Magikarp with random variant
|
||||||
species = getPokemonSpecies(SpeciesId.MAGIKARP);
|
species = getPokemonSpecies(SpeciesId.MAGIKARP);
|
||||||
pokemon = new PlayerPokemon(species, 5, 2, undefined, undefined, true);
|
pokemon = new PlayerPokemon(species, 5, 2, undefined, undefined, true);
|
||||||
} else if (
|
} else if (
|
||||||
validEventEncounters.length > 0 &&
|
validEventEncounters.length > 0
|
||||||
(r <= EVENT_THRESHOLD || isNullOrUndefined(species.abilityHidden) || species.abilityHidden === AbilityId.NONE)
|
&& (r <= EVENT_THRESHOLD || isNullOrUndefined(species.abilityHidden) || species.abilityHidden === AbilityId.NONE)
|
||||||
) {
|
) {
|
||||||
tries = 0;
|
tries = 0;
|
||||||
do {
|
do {
|
||||||
@ -162,8 +162,8 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter = MysteryEncounterBui
|
|||||||
|
|
||||||
const { spriteKey, fileRoot } = getSpriteKeysFromPokemon(pokemon);
|
const { spriteKey, fileRoot } = getSpriteKeysFromPokemon(pokemon);
|
||||||
encounter.spriteConfigs.push({
|
encounter.spriteConfigs.push({
|
||||||
spriteKey: spriteKey,
|
spriteKey,
|
||||||
fileRoot: fileRoot,
|
fileRoot,
|
||||||
hasShadow: true,
|
hasShadow: true,
|
||||||
repeat: true,
|
repeat: true,
|
||||||
isPokemon: true,
|
isPokemon: true,
|
||||||
@ -185,8 +185,8 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter = MysteryEncounterBui
|
|||||||
encounter.setDialogueToken("purchasePokemon", pokemon.getNameToRender());
|
encounter.setDialogueToken("purchasePokemon", pokemon.getNameToRender());
|
||||||
encounter.setDialogueToken("price", price.toString());
|
encounter.setDialogueToken("price", price.toString());
|
||||||
encounter.misc = {
|
encounter.misc = {
|
||||||
price: price,
|
price,
|
||||||
pokemon: pokemon,
|
pokemon,
|
||||||
};
|
};
|
||||||
|
|
||||||
pokemon.calculateStats();
|
pokemon.calculateStats();
|
||||||
|
@ -212,9 +212,9 @@ function endTrainerBattleAndShowDialogue(): Promise<void> {
|
|||||||
// Only trigger form change when Eiscue is in Noice form
|
// Only trigger form change when Eiscue is in Noice form
|
||||||
// Hardcoded Eiscue for now in case it is fused with another pokemon
|
// Hardcoded Eiscue for now in case it is fused with another pokemon
|
||||||
if (
|
if (
|
||||||
pokemon.species.speciesId === SpeciesId.EISCUE &&
|
pokemon.species.speciesId === SpeciesId.EISCUE
|
||||||
pokemon.hasAbility(AbilityId.ICE_FACE) &&
|
&& pokemon.hasAbility(AbilityId.ICE_FACE)
|
||||||
pokemon.formIndex === 1
|
&& pokemon.formIndex === 1
|
||||||
) {
|
) {
|
||||||
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeAbilityTrigger);
|
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeAbilityTrigger);
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ import { MysteryEncounterBuilder } from "#mystery-encounters/mystery-encounter";
|
|||||||
import { MysteryEncounterOptionBuilder } from "#mystery-encounters/mystery-encounter-option";
|
import { MysteryEncounterOptionBuilder } from "#mystery-encounters/mystery-encounter-option";
|
||||||
import { PokemonData } from "#system/pokemon-data";
|
import { PokemonData } from "#system/pokemon-data";
|
||||||
import type { HeldModifierConfig } from "#types/held-modifier-config";
|
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 { isNullOrUndefined, randSeedShuffle } from "#utils/common";
|
||||||
import { getEnumValues } from "#utils/enums";
|
import { getEnumValues } from "#utils/enums";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
@ -113,7 +113,7 @@ export const TrainingSessionEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
let ivIndexes: any[] = [];
|
let ivIndexes: any[] = [];
|
||||||
playerPokemon.ivs.forEach((iv, index) => {
|
playerPokemon.ivs.forEach((iv, index) => {
|
||||||
if (iv < 31) {
|
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)
|
// Only update the fusion's dex data if the Pokemon is already caught in dex (ignore rentals)
|
||||||
const rootFusionSpecies = playerPokemon.fusionSpecies?.getRootSpeciesId();
|
const rootFusionSpecies = playerPokemon.fusionSpecies?.getRootSpeciesId();
|
||||||
if (
|
if (
|
||||||
!isNullOrUndefined(rootFusionSpecies) &&
|
!isNullOrUndefined(rootFusionSpecies)
|
||||||
speciesStarterCosts.hasOwnProperty(rootFusionSpecies) &&
|
&& speciesStarterCosts.hasOwnProperty(rootFusionSpecies)
|
||||||
!!globalScene.gameData.dexData[rootFusionSpecies].caughtAttr
|
&& !!globalScene.gameData.dexData[rootFusionSpecies].caughtAttr
|
||||||
) {
|
) {
|
||||||
globalScene.gameData.starterData[rootFusionSpecies].abilityAttr |=
|
globalScene.gameData.starterData[rootFusionSpecies].abilityAttr |=
|
||||||
playerPokemon.fusionAbilityIndex !== 1 || playerPokemon.fusionSpecies?.ability2
|
playerPokemon.fusionAbilityIndex !== 1 || playerPokemon.fusionSpecies?.ability2
|
||||||
@ -396,7 +396,7 @@ function getEnemyConfig(playerPokemon: PlayerPokemon, segments: number, modifier
|
|||||||
formIndex: playerPokemon.formIndex,
|
formIndex: playerPokemon.formIndex,
|
||||||
level: playerPokemon.level,
|
level: playerPokemon.level,
|
||||||
dataSource: data,
|
dataSource: data,
|
||||||
modifierConfigs: modifierConfigs,
|
modifierConfigs,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
@ -71,7 +71,7 @@ export const UncommonBreedEncounter: MysteryEncounter = MysteryEncounterBuilder.
|
|||||||
const randomEggMove: MoveId = eggMoves[eggMoveIndex];
|
const randomEggMove: MoveId = eggMoves[eggMoveIndex];
|
||||||
encounter.misc = {
|
encounter.misc = {
|
||||||
eggMove: randomEggMove,
|
eggMove: randomEggMove,
|
||||||
pokemon: pokemon,
|
pokemon,
|
||||||
};
|
};
|
||||||
if (pokemon.moveset.length < 4) {
|
if (pokemon.moveset.length < 4) {
|
||||||
pokemon.moveset.push(new PokemonMove(randomEggMove));
|
pokemon.moveset.push(new PokemonMove(randomEggMove));
|
||||||
@ -91,7 +91,7 @@ export const UncommonBreedEncounter: MysteryEncounter = MysteryEncounterBuilder.
|
|||||||
const config: EnemyPartyConfig = {
|
const config: EnemyPartyConfig = {
|
||||||
pokemonConfigs: [
|
pokemonConfigs: [
|
||||||
{
|
{
|
||||||
level: level,
|
level,
|
||||||
species: pokemon.species,
|
species: pokemon.species,
|
||||||
dataSource: new PokemonData(pokemon),
|
dataSource: new PokemonData(pokemon),
|
||||||
isBoss: false,
|
isBoss: false,
|
||||||
@ -114,8 +114,8 @@ export const UncommonBreedEncounter: MysteryEncounter = MysteryEncounterBuilder.
|
|||||||
const { spriteKey, fileRoot } = getSpriteKeysFromPokemon(pokemon);
|
const { spriteKey, fileRoot } = getSpriteKeysFromPokemon(pokemon);
|
||||||
encounter.spriteConfigs = [
|
encounter.spriteConfigs = [
|
||||||
{
|
{
|
||||||
spriteKey: spriteKey,
|
spriteKey,
|
||||||
fileRoot: fileRoot,
|
fileRoot,
|
||||||
hasShadow: true,
|
hasShadow: true,
|
||||||
x: -5,
|
x: -5,
|
||||||
repeat: true,
|
repeat: true,
|
||||||
|
@ -285,7 +285,7 @@ export const WeirdDreamEncounter: MysteryEncounter = MysteryEncounterBuilder.wit
|
|||||||
species: transformation.newSpecies,
|
species: transformation.newSpecies,
|
||||||
isBoss: newPokemon.getSpeciesForm().getBaseStatTotal() > NON_LEGENDARY_BST_THRESHOLD,
|
isBoss: newPokemon.getSpeciesForm().getBaseStatTotal() > NON_LEGENDARY_BST_THRESHOLD,
|
||||||
level: previousPokemon.level,
|
level: previousPokemon.level,
|
||||||
dataSource: dataSource,
|
dataSource,
|
||||||
modifierConfigs: newPokemonHeldItemConfigs,
|
modifierConfigs: newPokemonHeldItemConfigs,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -299,7 +299,7 @@ export const WeirdDreamEncounter: MysteryEncounter = MysteryEncounterBuilder.wit
|
|||||||
].clone();
|
].clone();
|
||||||
trainerConfig.setPartyTemplates(new TrainerPartyTemplate(transformations.length, PartyMemberStrength.STRONG));
|
trainerConfig.setPartyTemplates(new TrainerPartyTemplate(transformations.length, PartyMemberStrength.STRONG));
|
||||||
const enemyPartyConfig: EnemyPartyConfig = {
|
const enemyPartyConfig: EnemyPartyConfig = {
|
||||||
trainerConfig: trainerConfig,
|
trainerConfig,
|
||||||
pokemonConfigs: enemyPokemonConfigs,
|
pokemonConfigs: enemyPokemonConfigs,
|
||||||
female: genderIndex === PlayerGender.FEMALE,
|
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
|
// For pokemon at/below 570 BST or any shiny pokemon, unlock it permanently as if you had caught it
|
||||||
if (
|
if (
|
||||||
!forBattle &&
|
!forBattle
|
||||||
(newPokemon.getSpeciesForm().getBaseStatTotal() <= NON_LEGENDARY_BST_THRESHOLD || newPokemon.isShiny())
|
&& (newPokemon.getSpeciesForm().getBaseStatTotal() <= NON_LEGENDARY_BST_THRESHOLD || newPokemon.isShiny())
|
||||||
) {
|
) {
|
||||||
if (
|
if (
|
||||||
newPokemon.getSpeciesForm().abilityHidden &&
|
newPokemon.getSpeciesForm().abilityHidden
|
||||||
newPokemon.abilityIndex === newPokemon.getSpeciesForm().getAbilityCount() - 1
|
&& newPokemon.abilityIndex === newPokemon.getSpeciesForm().getAbilityCount() - 1
|
||||||
) {
|
) {
|
||||||
globalScene.validateAchv(achvs.HIDDEN_ABILITY);
|
globalScene.validateAchv(achvs.HIDDEN_ABILITY);
|
||||||
}
|
}
|
||||||
@ -644,10 +644,10 @@ function getTransformedSpecies(
|
|||||||
const bstInRange = speciesBst >= bstMin && speciesBst <= bstCap;
|
const bstInRange = speciesBst >= bstMin && speciesBst <= bstCap;
|
||||||
// Checks that a Pokemon has not already been added in the +600 or 570-600 slots;
|
// Checks that a Pokemon has not already been added in the +600 or 570-600 slots;
|
||||||
const validBst =
|
const validBst =
|
||||||
(!hasPokemonBstBetween570And600 ||
|
(!hasPokemonBstBetween570And600
|
||||||
speciesBst < NON_LEGENDARY_BST_THRESHOLD ||
|
|| speciesBst < NON_LEGENDARY_BST_THRESHOLD
|
||||||
speciesBst > SUPER_LEGENDARY_BST_THRESHOLD) &&
|
|| speciesBst > SUPER_LEGENDARY_BST_THRESHOLD)
|
||||||
(!hasPokemonBstHigherThan600 || speciesBst <= SUPER_LEGENDARY_BST_THRESHOLD);
|
&& (!hasPokemonBstHigherThan600 || speciesBst <= SUPER_LEGENDARY_BST_THRESHOLD);
|
||||||
return bstInRange && validBst && !EXCLUDED_TRANSFORMATION_SPECIES.includes(s.speciesId);
|
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
|
// For pokemon that the player owns (including ones just caught), unlock the egg move
|
||||||
if (
|
if (
|
||||||
!forBattle &&
|
!forBattle
|
||||||
!isNullOrUndefined(randomEggMoveIndex) &&
|
&& !isNullOrUndefined(randomEggMoveIndex)
|
||||||
!!globalScene.gameData.dexData[speciesRootForm].caughtAttr
|
&& !!globalScene.gameData.dexData[speciesRootForm].caughtAttr
|
||||||
) {
|
) {
|
||||||
await globalScene.gameData.setEggMoveUnlocked(getPokemonSpecies(speciesRootForm), randomEggMoveIndex, true);
|
await globalScene.gameData.setEggMoveUnlocked(getPokemonSpecies(speciesRootForm), randomEggMoveIndex, true);
|
||||||
}
|
}
|
||||||
|
@ -76,9 +76,9 @@ export class MysteryEncounterOption implements IMysteryEncounterOption {
|
|||||||
*/
|
*/
|
||||||
hasRequirements(): boolean {
|
hasRequirements(): boolean {
|
||||||
return (
|
return (
|
||||||
this.requirements.length > 0 ||
|
this.requirements.length > 0
|
||||||
this.primaryPokemonRequirements.length > 0 ||
|
|| this.primaryPokemonRequirements.length > 0
|
||||||
this.secondaryPokemonRequirements.length > 0
|
|| this.secondaryPokemonRequirements.length > 0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,9 +87,9 @@ export class MysteryEncounterOption implements IMysteryEncounterOption {
|
|||||||
*/
|
*/
|
||||||
meetsRequirements(): boolean {
|
meetsRequirements(): boolean {
|
||||||
return (
|
return (
|
||||||
!this.requirements.some(requirement => !requirement.meetsRequirement()) &&
|
!this.requirements.some(requirement => !requirement.meetsRequirement())
|
||||||
this.meetsSupportingRequirementAndSupportingPokemonSelected() &&
|
&& this.meetsSupportingRequirementAndSupportingPokemonSelected()
|
||||||
this.meetsPrimaryRequirementAndPrimaryPokemonSelected()
|
&& this.meetsPrimaryRequirementAndPrimaryPokemonSelected()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,7 +209,7 @@ export class MysteryEncounterOptionBuilder implements Partial<IMysteryEncounterO
|
|||||||
}
|
}
|
||||||
|
|
||||||
withHasDexProgress(hasDexProgress: boolean): this & Required<Pick<IMysteryEncounterOption, "hasDexProgress">> {
|
withHasDexProgress(hasDexProgress: boolean): this & Required<Pick<IMysteryEncounterOption, "hasDexProgress">> {
|
||||||
return Object.assign(this, { hasDexProgress: hasDexProgress });
|
return Object.assign(this, { hasDexProgress });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -220,7 +220,7 @@ export class MysteryEncounterOptionBuilder implements Partial<IMysteryEncounterO
|
|||||||
requirement: EncounterSceneRequirement,
|
requirement: EncounterSceneRequirement,
|
||||||
): this & Required<Pick<IMysteryEncounterOption, "requirements">> {
|
): this & Required<Pick<IMysteryEncounterOption, "requirements">> {
|
||||||
if (requirement instanceof EncounterPokemonRequirement) {
|
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);
|
this.requirements.push(requirement);
|
||||||
@ -240,7 +240,7 @@ export class MysteryEncounterOptionBuilder implements Partial<IMysteryEncounterO
|
|||||||
withPreOptionPhase(
|
withPreOptionPhase(
|
||||||
onPreOptionPhase: OptionPhaseCallback,
|
onPreOptionPhase: OptionPhaseCallback,
|
||||||
): this & Required<Pick<IMysteryEncounterOption, "onPreOptionPhase">> {
|
): this & Required<Pick<IMysteryEncounterOption, "onPreOptionPhase">> {
|
||||||
return Object.assign(this, { onPreOptionPhase: onPreOptionPhase });
|
return Object.assign(this, { onPreOptionPhase });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -248,13 +248,13 @@ export class MysteryEncounterOptionBuilder implements Partial<IMysteryEncounterO
|
|||||||
* @param onOptionPhase
|
* @param onOptionPhase
|
||||||
*/
|
*/
|
||||||
withOptionPhase(onOptionPhase: OptionPhaseCallback): this & Required<Pick<IMysteryEncounterOption, "onOptionPhase">> {
|
withOptionPhase(onOptionPhase: OptionPhaseCallback): this & Required<Pick<IMysteryEncounterOption, "onOptionPhase">> {
|
||||||
return Object.assign(this, { onOptionPhase: onOptionPhase });
|
return Object.assign(this, { onOptionPhase });
|
||||||
}
|
}
|
||||||
|
|
||||||
withPostOptionPhase(
|
withPostOptionPhase(
|
||||||
onPostOptionPhase: OptionPhaseCallback,
|
onPostOptionPhase: OptionPhaseCallback,
|
||||||
): this & Required<Pick<IMysteryEncounterOption, "onPostOptionPhase">> {
|
): this & Required<Pick<IMysteryEncounterOption, "onPostOptionPhase">> {
|
||||||
return Object.assign(this, { onPostOptionPhase: onPostOptionPhase });
|
return Object.assign(this, { onPostOptionPhase });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -265,7 +265,7 @@ export class MysteryEncounterOptionBuilder implements Partial<IMysteryEncounterO
|
|||||||
requirement: EncounterPokemonRequirement,
|
requirement: EncounterPokemonRequirement,
|
||||||
): this & Required<Pick<IMysteryEncounterOption, "primaryPokemonRequirements">> {
|
): this & Required<Pick<IMysteryEncounterOption, "primaryPokemonRequirements">> {
|
||||||
if (requirement instanceof EncounterSceneRequirement) {
|
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);
|
this.primaryPokemonRequirements.push(requirement);
|
||||||
@ -315,7 +315,7 @@ export class MysteryEncounterOptionBuilder implements Partial<IMysteryEncounterO
|
|||||||
excludePrimaryFromSecondaryRequirements = true,
|
excludePrimaryFromSecondaryRequirements = true,
|
||||||
): this & Required<Pick<IMysteryEncounterOption, "secondaryPokemonRequirements">> {
|
): this & Required<Pick<IMysteryEncounterOption, "secondaryPokemonRequirements">> {
|
||||||
if (requirement instanceof EncounterSceneRequirement) {
|
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);
|
this.secondaryPokemonRequirements.push(requirement);
|
||||||
|
@ -222,8 +222,8 @@ export class WaveRangeRequirement extends EncounterSceneRequirement {
|
|||||||
if (!isNullOrUndefined(this.waveRange) && this.waveRange[0] <= this.waveRange[1]) {
|
if (!isNullOrUndefined(this.waveRange) && this.waveRange[0] <= this.waveRange[1]) {
|
||||||
const waveIndex = globalScene.currentBattle.waveIndex;
|
const waveIndex = globalScene.currentBattle.waveIndex;
|
||||||
if (
|
if (
|
||||||
(waveIndex >= 0 && this.waveRange[0] >= 0 && this.waveRange[0] > waveIndex) ||
|
(waveIndex >= 0 && this.waveRange[0] >= 0 && this.waveRange[0] > waveIndex)
|
||||||
(this.waveRange[1] >= 0 && this.waveRange[1] < waveIndex)
|
|| (this.waveRange[1] >= 0 && this.waveRange[1] < waveIndex)
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -276,9 +276,9 @@ export class TimeOfDayRequirement extends EncounterSceneRequirement {
|
|||||||
override meetsRequirement(): boolean {
|
override meetsRequirement(): boolean {
|
||||||
const timeOfDay = globalScene.arena?.getTimeOfDay();
|
const timeOfDay = globalScene.arena?.getTimeOfDay();
|
||||||
return !(
|
return !(
|
||||||
!isNullOrUndefined(timeOfDay) &&
|
!isNullOrUndefined(timeOfDay)
|
||||||
this.requiredTimeOfDay?.length > 0 &&
|
&& this.requiredTimeOfDay?.length > 0
|
||||||
!this.requiredTimeOfDay.includes(timeOfDay)
|
&& !this.requiredTimeOfDay.includes(timeOfDay)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,9 +298,9 @@ export class WeatherRequirement extends EncounterSceneRequirement {
|
|||||||
override meetsRequirement(): boolean {
|
override meetsRequirement(): boolean {
|
||||||
const currentWeather = globalScene.arena.weather?.weatherType;
|
const currentWeather = globalScene.arena.weather?.weatherType;
|
||||||
return !(
|
return !(
|
||||||
!isNullOrUndefined(currentWeather) &&
|
!isNullOrUndefined(currentWeather)
|
||||||
this.requiredWeather?.length > 0 &&
|
&& this.requiredWeather?.length > 0
|
||||||
!this.requiredWeather.includes(currentWeather!)
|
&& !this.requiredWeather.includes(currentWeather!)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,8 +336,8 @@ export class PartySizeRequirement extends EncounterSceneRequirement {
|
|||||||
? globalScene.getPokemonAllowedInBattle().length
|
? globalScene.getPokemonAllowedInBattle().length
|
||||||
: globalScene.getPlayerParty().length;
|
: globalScene.getPlayerParty().length;
|
||||||
if (
|
if (
|
||||||
(partySize >= 0 && this.partySizeRange[0] >= 0 && this.partySizeRange[0] > partySize) ||
|
(partySize >= 0 && this.partySizeRange[0] >= 0 && this.partySizeRange[0] > partySize)
|
||||||
(this.partySizeRange[1] >= 0 && this.partySizeRange[1] < partySize)
|
|| (this.partySizeRange[1] >= 0 && this.partySizeRange[1] < partySize)
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -572,15 +572,15 @@ export class MoveRequirement extends EncounterPokemonRequirement {
|
|||||||
// get the Pokemon with at least one move in the required moves list
|
// get the Pokemon with at least one move in the required moves list
|
||||||
return partyPokemon.filter(
|
return partyPokemon.filter(
|
||||||
pokemon =>
|
pokemon =>
|
||||||
(!this.excludeDisallowedPokemon || pokemon.isAllowedInBattle()) &&
|
(!this.excludeDisallowedPokemon || pokemon.isAllowedInBattle())
|
||||||
pokemon.moveset.some(move => move.moveId && this.requiredMoves.includes(move.moveId)),
|
&& 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
|
// for an inverted query, we only want to get the pokemon that don't have ANY of the listed moves
|
||||||
return partyPokemon.filter(
|
return partyPokemon.filter(
|
||||||
pokemon =>
|
pokemon =>
|
||||||
(!this.excludeDisallowedPokemon || pokemon.isAllowedInBattle()) &&
|
(!this.excludeDisallowedPokemon || pokemon.isAllowedInBattle())
|
||||||
!pokemon.moveset.some(move => move.moveId && this.requiredMoves.includes(move.moveId)),
|
&& !pokemon.moveset.some(move => move.moveId && this.requiredMoves.includes(move.moveId)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -678,15 +678,15 @@ export class AbilityRequirement extends EncounterPokemonRequirement {
|
|||||||
if (!this.invertQuery) {
|
if (!this.invertQuery) {
|
||||||
return partyPokemon.filter(
|
return partyPokemon.filter(
|
||||||
pokemon =>
|
pokemon =>
|
||||||
(!this.excludeDisallowedPokemon || pokemon.isAllowedInBattle()) &&
|
(!this.excludeDisallowedPokemon || pokemon.isAllowedInBattle())
|
||||||
this.requiredAbilities.some(ability => pokemon.hasAbility(ability, false)),
|
&& 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
|
// for an inverted query, we only want to get the pokemon that don't have ANY of the listed abilities
|
||||||
return partyPokemon.filter(
|
return partyPokemon.filter(
|
||||||
pokemon =>
|
pokemon =>
|
||||||
(!this.excludeDisallowedPokemon || pokemon.isAllowedInBattle()) &&
|
(!this.excludeDisallowedPokemon || pokemon.isAllowedInBattle())
|
||||||
this.requiredAbilities.filter(ability => pokemon.hasAbility(ability, false)).length === 0,
|
&& this.requiredAbilities.filter(ability => pokemon.hasAbility(ability, false)).length === 0,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -728,9 +728,9 @@ export class StatusEffectRequirement extends EncounterPokemonRequirement {
|
|||||||
if (statusEffect === StatusEffect.NONE) {
|
if (statusEffect === StatusEffect.NONE) {
|
||||||
// StatusEffect.NONE also checks for null or undefined status
|
// StatusEffect.NONE also checks for null or undefined status
|
||||||
return (
|
return (
|
||||||
isNullOrUndefined(pokemon.status) ||
|
isNullOrUndefined(pokemon.status)
|
||||||
isNullOrUndefined(pokemon.status.effect) ||
|
|| isNullOrUndefined(pokemon.status.effect)
|
||||||
pokemon.status.effect === statusEffect
|
|| pokemon.status.effect === statusEffect
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return pokemon.status?.effect === statusEffect;
|
return pokemon.status?.effect === statusEffect;
|
||||||
@ -743,9 +743,9 @@ export class StatusEffectRequirement extends EncounterPokemonRequirement {
|
|||||||
if (statusEffect === StatusEffect.NONE) {
|
if (statusEffect === StatusEffect.NONE) {
|
||||||
// StatusEffect.NONE also checks for null or undefined status
|
// StatusEffect.NONE also checks for null or undefined status
|
||||||
return (
|
return (
|
||||||
isNullOrUndefined(pokemon.status) ||
|
isNullOrUndefined(pokemon.status)
|
||||||
isNullOrUndefined(pokemon.status.effect) ||
|
|| isNullOrUndefined(pokemon.status.effect)
|
||||||
pokemon.status.effect === statusEffect
|
|| pokemon.status.effect === statusEffect
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return pokemon.status?.effect === statusEffect;
|
return pokemon.status?.effect === statusEffect;
|
||||||
@ -796,9 +796,8 @@ export class CanFormChangeWithItemRequirement extends EncounterPokemonRequiremen
|
|||||||
|
|
||||||
filterByForm(pokemon, formChangeItem) {
|
filterByForm(pokemon, formChangeItem) {
|
||||||
return (
|
return (
|
||||||
pokemonFormChanges.hasOwnProperty(pokemon.species.speciesId) &&
|
pokemonFormChanges.hasOwnProperty(pokemon.species.speciesId) // Get all form changes for this species with an item trigger, including any compound triggers
|
||||||
// Get all form changes for this species with an item trigger, including any compound triggers
|
&& pokemonFormChanges[pokemon.species.speciesId]
|
||||||
pokemonFormChanges[pokemon.species.speciesId]
|
|
||||||
.filter(fc => fc.trigger.hasTriggerType(SpeciesFormChangeItemTrigger))
|
.filter(fc => fc.trigger.hasTriggerType(SpeciesFormChangeItemTrigger))
|
||||||
// Returns true if any form changes match this item
|
// Returns true if any form changes match this item
|
||||||
.flatMap(fc => fc.findTrigger(SpeciesFormChangeItemTrigger) as SpeciesFormChangeItemTrigger)
|
.flatMap(fc => fc.findTrigger(SpeciesFormChangeItemTrigger) as SpeciesFormChangeItemTrigger)
|
||||||
@ -870,8 +869,8 @@ export class HeldItemRequirement extends EncounterPokemonRequirement {
|
|||||||
pokemon =>
|
pokemon =>
|
||||||
pokemon.getHeldItems().filter(it => {
|
pokemon.getHeldItems().filter(it => {
|
||||||
return (
|
return (
|
||||||
!this.requiredHeldItemModifiers.some(heldItem => it.constructor.name === heldItem) &&
|
!this.requiredHeldItemModifiers.some(heldItem => it.constructor.name === heldItem)
|
||||||
(!this.requireTransferable || it.isTransferable)
|
&& (!this.requireTransferable || it.isTransferable)
|
||||||
);
|
);
|
||||||
}).length > 0,
|
}).length > 0,
|
||||||
);
|
);
|
||||||
@ -880,8 +879,8 @@ export class HeldItemRequirement extends EncounterPokemonRequirement {
|
|||||||
override getDialogueToken(pokemon?: PlayerPokemon): [string, string] {
|
override getDialogueToken(pokemon?: PlayerPokemon): [string, string] {
|
||||||
const requiredItems = pokemon?.getHeldItems().filter(it => {
|
const requiredItems = pokemon?.getHeldItems().filter(it => {
|
||||||
return (
|
return (
|
||||||
this.requiredHeldItemModifiers.some(heldItem => it.constructor.name === heldItem) &&
|
this.requiredHeldItemModifiers.some(heldItem => it.constructor.name === heldItem)
|
||||||
(!this.requireTransferable || it.isTransferable)
|
&& (!this.requireTransferable || it.isTransferable)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
if (requiredItems && requiredItems.length > 0) {
|
if (requiredItems && requiredItems.length > 0) {
|
||||||
@ -924,9 +923,9 @@ export class AttackTypeBoosterHeldItemTypeRequirement extends EncounterPokemonRe
|
|||||||
this.requiredHeldItemTypes.some(heldItemType => {
|
this.requiredHeldItemTypes.some(heldItemType => {
|
||||||
return pokemon.getHeldItems().some(it => {
|
return pokemon.getHeldItems().some(it => {
|
||||||
return (
|
return (
|
||||||
it instanceof AttackTypeBoosterModifier &&
|
it instanceof AttackTypeBoosterModifier
|
||||||
(it.type as AttackTypeBoosterModifierType).moveType === heldItemType &&
|
&& (it.type as AttackTypeBoosterModifierType).moveType === heldItemType
|
||||||
(!this.requireTransferable || it.isTransferable)
|
&& (!this.requireTransferable || it.isTransferable)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
@ -939,9 +938,9 @@ export class AttackTypeBoosterHeldItemTypeRequirement extends EncounterPokemonRe
|
|||||||
pokemon.getHeldItems().filter(it => {
|
pokemon.getHeldItems().filter(it => {
|
||||||
return !this.requiredHeldItemTypes.some(
|
return !this.requiredHeldItemTypes.some(
|
||||||
heldItemType =>
|
heldItemType =>
|
||||||
it instanceof AttackTypeBoosterModifier &&
|
it instanceof AttackTypeBoosterModifier
|
||||||
(it.type as AttackTypeBoosterModifierType).moveType === heldItemType &&
|
&& (it.type as AttackTypeBoosterModifierType).moveType === heldItemType
|
||||||
(!this.requireTransferable || it.isTransferable),
|
&& (!this.requireTransferable || it.isTransferable),
|
||||||
);
|
);
|
||||||
}).length > 0,
|
}).length > 0,
|
||||||
);
|
);
|
||||||
@ -952,10 +951,10 @@ export class AttackTypeBoosterHeldItemTypeRequirement extends EncounterPokemonRe
|
|||||||
return (
|
return (
|
||||||
this.requiredHeldItemTypes.some(
|
this.requiredHeldItemTypes.some(
|
||||||
heldItemType =>
|
heldItemType =>
|
||||||
it instanceof AttackTypeBoosterModifier &&
|
it instanceof AttackTypeBoosterModifier
|
||||||
(it.type as AttackTypeBoosterModifierType).moveType === heldItemType,
|
&& (it.type as AttackTypeBoosterModifierType).moveType === heldItemType,
|
||||||
) &&
|
)
|
||||||
(!this.requireTransferable || it.isTransferable)
|
&& (!this.requireTransferable || it.isTransferable)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
if (requiredItems && requiredItems.length > 0) {
|
if (requiredItems && requiredItems.length > 0) {
|
||||||
@ -1021,8 +1020,8 @@ export class FriendshipRequirement extends EncounterPokemonRequirement {
|
|||||||
override meetsRequirement(): boolean {
|
override meetsRequirement(): boolean {
|
||||||
// Party Pokemon inside required friendship range
|
// Party Pokemon inside required friendship range
|
||||||
if (
|
if (
|
||||||
!isNullOrUndefined(this.requiredFriendshipRange) &&
|
!isNullOrUndefined(this.requiredFriendshipRange)
|
||||||
this.requiredFriendshipRange[0] <= this.requiredFriendshipRange[1]
|
&& this.requiredFriendshipRange[0] <= this.requiredFriendshipRange[1]
|
||||||
) {
|
) {
|
||||||
const partyPokemon = globalScene.getPlayerParty();
|
const partyPokemon = globalScene.getPlayerParty();
|
||||||
const pokemonInRange = this.queryParty(partyPokemon);
|
const pokemonInRange = this.queryParty(partyPokemon);
|
||||||
@ -1037,8 +1036,8 @@ export class FriendshipRequirement extends EncounterPokemonRequirement {
|
|||||||
if (!this.invertQuery) {
|
if (!this.invertQuery) {
|
||||||
return partyPokemon.filter(
|
return partyPokemon.filter(
|
||||||
pokemon =>
|
pokemon =>
|
||||||
pokemon.friendship >= this.requiredFriendshipRange[0] &&
|
pokemon.friendship >= this.requiredFriendshipRange[0]
|
||||||
pokemon.friendship <= this.requiredFriendshipRange[1],
|
&& 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
|
// for an inverted query, we only want to get the pokemon that don't have ANY of the listed requiredFriendshipRanges
|
||||||
|
@ -576,10 +576,9 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @static Defines the type of encounter which is used as an identifier, should be tied to a unique MysteryEncounterType
|
* Defines the type of encounter which is used as an identifier, should be tied to a unique MysteryEncounterType
|
||||||
* NOTE: if new functions are added to {@linkcode MysteryEncounter} class
|
|
||||||
* @param encounterType
|
* @param encounterType
|
||||||
* @returns this
|
* @returns a new instance of MysteryEncounterBuilder with encounterType set
|
||||||
*/
|
*/
|
||||||
static withEncounterType(
|
static withEncounterType(
|
||||||
encounterType: MysteryEncounterType,
|
encounterType: MysteryEncounterType,
|
||||||
@ -658,7 +657,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
|||||||
withIntroSpriteConfigs(
|
withIntroSpriteConfigs(
|
||||||
spriteConfigs: MysteryEncounterSpriteConfig[],
|
spriteConfigs: MysteryEncounterSpriteConfig[],
|
||||||
): this & Pick<IMysteryEncounter, "spriteConfigs"> {
|
): this & Pick<IMysteryEncounter, "spriteConfigs"> {
|
||||||
return Object.assign(this, { spriteConfigs: spriteConfigs });
|
return Object.assign(this, { spriteConfigs });
|
||||||
}
|
}
|
||||||
|
|
||||||
withIntroDialogue(dialogue: MysteryEncounterDialogue["intro"] = []): this {
|
withIntroDialogue(dialogue: MysteryEncounterDialogue["intro"] = []): this {
|
||||||
@ -703,7 +702,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
withEncounterTier(encounterTier: MysteryEncounterTier): this & Pick<IMysteryEncounter, "encounterTier"> {
|
withEncounterTier(encounterTier: MysteryEncounterTier): this & Pick<IMysteryEncounter, "encounterTier"> {
|
||||||
return Object.assign(this, { encounterTier: encounterTier });
|
return Object.assign(this, { encounterTier });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -753,7 +752,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
|||||||
withContinuousEncounter(
|
withContinuousEncounter(
|
||||||
continuousEncounter: boolean,
|
continuousEncounter: boolean,
|
||||||
): this & Required<Pick<IMysteryEncounter, "continuousEncounter">> {
|
): this & Required<Pick<IMysteryEncounter, "continuousEncounter">> {
|
||||||
return Object.assign(this, { continuousEncounter: continuousEncounter });
|
return Object.assign(this, { continuousEncounter });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -807,7 +806,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
|||||||
withMaxAllowedEncounters(
|
withMaxAllowedEncounters(
|
||||||
maxAllowedEncounters: number,
|
maxAllowedEncounters: number,
|
||||||
): this & Required<Pick<IMysteryEncounter, "maxAllowedEncounters">> {
|
): this & Required<Pick<IMysteryEncounter, "maxAllowedEncounters">> {
|
||||||
return Object.assign(this, { maxAllowedEncounters: maxAllowedEncounters });
|
return Object.assign(this, { maxAllowedEncounters });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -821,7 +820,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
|||||||
requirement: EncounterSceneRequirement,
|
requirement: EncounterSceneRequirement,
|
||||||
): this & Required<Pick<IMysteryEncounter, "requirements">> {
|
): this & Required<Pick<IMysteryEncounter, "requirements">> {
|
||||||
if (requirement instanceof EncounterPokemonRequirement) {
|
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);
|
this.requirements.push(requirement);
|
||||||
return this;
|
return this;
|
||||||
@ -864,7 +863,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
|||||||
requirement: EncounterPokemonRequirement,
|
requirement: EncounterPokemonRequirement,
|
||||||
): this & Required<Pick<IMysteryEncounter, "primaryPokemonRequirements">> {
|
): this & Required<Pick<IMysteryEncounter, "primaryPokemonRequirements">> {
|
||||||
if (requirement instanceof EncounterSceneRequirement) {
|
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);
|
this.primaryPokemonRequirements.push(requirement);
|
||||||
@ -917,7 +916,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
|||||||
excludePrimaryFromSecondaryRequirements = false,
|
excludePrimaryFromSecondaryRequirements = false,
|
||||||
): this & Required<Pick<IMysteryEncounter, "secondaryPokemonRequirements">> {
|
): this & Required<Pick<IMysteryEncounter, "secondaryPokemonRequirements">> {
|
||||||
if (requirement instanceof EncounterSceneRequirement) {
|
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);
|
this.secondaryPokemonRequirements.push(requirement);
|
||||||
@ -939,7 +938,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
withRewards(doEncounterRewards: () => boolean): this & Required<Pick<IMysteryEncounter, "doEncounterRewards">> {
|
withRewards(doEncounterRewards: () => boolean): this & Required<Pick<IMysteryEncounter, "doEncounterRewards">> {
|
||||||
return Object.assign(this, { doEncounterRewards: doEncounterRewards });
|
return Object.assign(this, { doEncounterRewards });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -953,7 +952,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
withExp(doEncounterExp: () => boolean): this & Required<Pick<IMysteryEncounter, "doEncounterExp">> {
|
withExp(doEncounterExp: () => boolean): this & Required<Pick<IMysteryEncounter, "doEncounterExp">> {
|
||||||
return Object.assign(this, { doEncounterExp: doEncounterExp });
|
return Object.assign(this, { doEncounterExp });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -974,7 +973,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
withOnVisualsStart(onVisualsStart: () => boolean): this & Required<Pick<IMysteryEncounter, "onVisualsStart">> {
|
withOnVisualsStart(onVisualsStart: () => boolean): this & Required<Pick<IMysteryEncounter, "onVisualsStart">> {
|
||||||
return Object.assign(this, { onVisualsStart: onVisualsStart });
|
return Object.assign(this, { onVisualsStart });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -984,7 +983,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
withCatchAllowed(catchAllowed: boolean): this & Required<Pick<IMysteryEncounter, "catchAllowed">> {
|
withCatchAllowed(catchAllowed: boolean): this & Required<Pick<IMysteryEncounter, "catchAllowed">> {
|
||||||
return Object.assign(this, { catchAllowed: catchAllowed });
|
return Object.assign(this, { catchAllowed });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1004,7 +1003,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
|||||||
hideBattleIntroMessage: boolean,
|
hideBattleIntroMessage: boolean,
|
||||||
): this & Required<Pick<IMysteryEncounter, "hideBattleIntroMessage">> {
|
): this & Required<Pick<IMysteryEncounter, "hideBattleIntroMessage">> {
|
||||||
return Object.assign(this, {
|
return Object.assign(this, {
|
||||||
hideBattleIntroMessage: hideBattleIntroMessage,
|
hideBattleIntroMessage,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1015,7 +1014,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
|||||||
withAutoHideIntroVisuals(
|
withAutoHideIntroVisuals(
|
||||||
autoHideIntroVisuals: boolean,
|
autoHideIntroVisuals: boolean,
|
||||||
): this & Required<Pick<IMysteryEncounter, "autoHideIntroVisuals">> {
|
): this & Required<Pick<IMysteryEncounter, "autoHideIntroVisuals">> {
|
||||||
return Object.assign(this, { autoHideIntroVisuals: autoHideIntroVisuals });
|
return Object.assign(this, { autoHideIntroVisuals });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1027,7 +1026,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
|||||||
enterIntroVisualsFromRight: boolean,
|
enterIntroVisualsFromRight: boolean,
|
||||||
): this & Required<Pick<IMysteryEncounter, "enterIntroVisualsFromRight">> {
|
): this & Required<Pick<IMysteryEncounter, "enterIntroVisualsFromRight">> {
|
||||||
return Object.assign(this, {
|
return Object.assign(this, {
|
||||||
enterIntroVisualsFromRight: enterIntroVisualsFromRight,
|
enterIntroVisualsFromRight,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,9 +46,9 @@ import type { PokemonData } from "#system/pokemon-data";
|
|||||||
import type { TrainerConfig } from "#trainers/trainer-config";
|
import type { TrainerConfig } from "#trainers/trainer-config";
|
||||||
import { trainerConfigs } from "#trainers/trainer-config";
|
import { trainerConfigs } from "#trainers/trainer-config";
|
||||||
import type { HeldModifierConfig } from "#types/held-modifier-config";
|
import type { HeldModifierConfig } from "#types/held-modifier-config";
|
||||||
import type { OptionSelectConfig, OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
|
import type { OptionSelectConfig, OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler";
|
||||||
import type { PartyOption, PokemonSelectFilter } from "#ui/party-ui-handler";
|
import type { PartyOption, PokemonSelectFilter } from "#ui/handlers/party-ui-handler";
|
||||||
import { PartyUiMode } from "#ui/party-ui-handler";
|
import { PartyUiMode } from "#ui/handlers/party-ui-handler";
|
||||||
import { coerceArray, isNullOrUndefined, randomString, randSeedInt, randSeedItem } from "#utils/common";
|
import { coerceArray, isNullOrUndefined, randomString, randSeedInt, randSeedItem } from "#utils/common";
|
||||||
import { getPokemonSpecies } from "#utils/pokemon-utils";
|
import { getPokemonSpecies } from "#utils/pokemon-utils";
|
||||||
import i18next from "i18next";
|
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
|
// 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.
|
// levelAdditiveModifier value of 0.5 will halve the modifier scaling, 2 will double it, etc.
|
||||||
// Leaving null/undefined will disable level scaling
|
// 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);
|
const additive = Math.max(Math.round((globalScene.currentBattle.waveIndex / 10) * mult), 0);
|
||||||
battle.enemyLevels = battle.enemyLevels.map(level => level + additive);
|
battle.enemyLevels = battle.enemyLevels.map(level => level + additive);
|
||||||
|
|
||||||
@ -297,9 +297,9 @@ export async function initBattleWithEnemyConfig(partyConfig: EnemyPartyConfig):
|
|||||||
|
|
||||||
// Set Boss
|
// Set Boss
|
||||||
if (config.isBoss) {
|
if (config.isBoss) {
|
||||||
let segments = !isNullOrUndefined(config.bossSegments)
|
let segments =
|
||||||
? config.bossSegments!
|
config.bossSegments
|
||||||
: globalScene.getEncounterBossSegments(globalScene.currentBattle.waveIndex, level, enemySpecies, true);
|
?? globalScene.getEncounterBossSegments(globalScene.currentBattle.waveIndex, level, enemySpecies, true);
|
||||||
if (!isNullOrUndefined(config.bossSegmentModifier)) {
|
if (!isNullOrUndefined(config.bossSegmentModifier)) {
|
||||||
segments += config.bossSegmentModifier;
|
segments += config.bossSegmentModifier;
|
||||||
}
|
}
|
||||||
@ -545,22 +545,25 @@ export function selectPokemonForOption(
|
|||||||
UiMode.PARTY,
|
UiMode.PARTY,
|
||||||
PartyUiMode.SELECT,
|
PartyUiMode.SELECT,
|
||||||
-1,
|
-1,
|
||||||
(slotIndex: number, _option: PartyOption) => {
|
async (slotIndex: number, _option: PartyOption) => {
|
||||||
if (slotIndex < globalScene.getPlayerParty().length) {
|
await globalScene.ui.setMode(modeToSetOnExit);
|
||||||
globalScene.ui.setMode(modeToSetOnExit).then(() => {
|
if (slotIndex >= globalScene.getPlayerParty().length) {
|
||||||
|
onPokemonNotSelected?.();
|
||||||
|
resolve(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const pokemon = globalScene.getPlayerParty()[slotIndex];
|
const pokemon = globalScene.getPlayerParty()[slotIndex];
|
||||||
const secondaryOptions = onPokemonSelected(pokemon);
|
const secondaryOptions = onPokemonSelected(pokemon);
|
||||||
if (!secondaryOptions) {
|
if (!secondaryOptions) {
|
||||||
globalScene.currentBattle.mysteryEncounter!.setDialogueToken(
|
globalScene.currentBattle.mysteryEncounter!.setDialogueToken("selectedPokemon", pokemon.getNameToRender());
|
||||||
"selectedPokemon",
|
|
||||||
pokemon.getNameToRender(),
|
|
||||||
);
|
|
||||||
resolve(true);
|
resolve(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// There is a second option to choose after selecting the Pokemon
|
// There is a second option to choose after selecting the Pokemon
|
||||||
globalScene.ui.setMode(UiMode.MESSAGE).then(() => {
|
await globalScene.ui.setMode(UiMode.MESSAGE);
|
||||||
|
// TODO: fix this
|
||||||
const displayOptions = () => {
|
const displayOptions = () => {
|
||||||
// Always appends a cancel option to bottom of options
|
// Always appends a cancel option to bottom of options
|
||||||
const fullOptions = secondaryOptions
|
const fullOptions = secondaryOptions
|
||||||
@ -599,29 +602,17 @@ export function selectPokemonForOption(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Do hover over the starting selection option
|
// Do hover over the starting selection option
|
||||||
if (fullOptions[0].onHover) {
|
if (fullOptions[0]?.onHover) {
|
||||||
fullOptions[0].onHover();
|
fullOptions[0].onHover();
|
||||||
}
|
}
|
||||||
globalScene.ui.setModeWithoutClear(UiMode.OPTION_SELECT, config, null, true);
|
globalScene.ui.setModeWithoutClear(UiMode.OPTION_SELECT, config, null, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const textPromptKey =
|
const textPromptKey = globalScene.currentBattle.mysteryEncounter?.selectedOption?.dialogue?.secondOptionPrompt;
|
||||||
globalScene.currentBattle.mysteryEncounter?.selectedOption?.dialogue?.secondOptionPrompt;
|
if (textPromptKey) {
|
||||||
if (!textPromptKey) {
|
await showEncounterText(textPromptKey);
|
||||||
|
}
|
||||||
displayOptions();
|
displayOptions();
|
||||||
} else {
|
|
||||||
showEncounterText(textPromptKey).then(() => displayOptions());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
globalScene.ui.setMode(modeToSetOnExit).then(() => {
|
|
||||||
if (onPokemonNotSelected) {
|
|
||||||
onPokemonNotSelected();
|
|
||||||
}
|
|
||||||
resolve(false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
selectablePokemonFilter,
|
selectablePokemonFilter,
|
||||||
);
|
);
|
||||||
@ -651,24 +642,16 @@ export function selectOptionThenPokemon(
|
|||||||
return new Promise<PokemonAndOptionSelected | null>(resolve => {
|
return new Promise<PokemonAndOptionSelected | null>(resolve => {
|
||||||
const modeToSetOnExit = globalScene.ui.getMode();
|
const modeToSetOnExit = globalScene.ui.getMode();
|
||||||
|
|
||||||
const displayOptions = (config: OptionSelectConfig) => {
|
const displayOptions = async (config: OptionSelectConfig) => {
|
||||||
globalScene.ui.setMode(UiMode.MESSAGE).then(() => {
|
await globalScene.ui.setMode(UiMode.MESSAGE);
|
||||||
if (!optionSelectPromptKey) {
|
if (optionSelectPromptKey) {
|
||||||
|
showEncounterText(optionSelectPromptKey);
|
||||||
|
}
|
||||||
// Do hover over the starting selection option
|
// Do hover over the starting selection option
|
||||||
if (fullOptions[0].onHover) {
|
if (fullOptions[0]?.onHover) {
|
||||||
fullOptions[0].onHover();
|
fullOptions[0].onHover();
|
||||||
}
|
}
|
||||||
globalScene.ui.setMode(UiMode.OPTION_SELECT, config);
|
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 selectPokemonAfterOption = (selectedOptionIndex: number) => {
|
const selectPokemonAfterOption = (selectedOptionIndex: number) => {
|
||||||
@ -683,7 +666,7 @@ export function selectOptionThenPokemon(
|
|||||||
globalScene.ui.setMode(modeToSetOnExit).then(() => {
|
globalScene.ui.setMode(modeToSetOnExit).then(() => {
|
||||||
const result: PokemonAndOptionSelected = {
|
const result: PokemonAndOptionSelected = {
|
||||||
selectedPokemonIndex: slotIndex,
|
selectedPokemonIndex: slotIndex,
|
||||||
selectedOptionIndex: selectedOptionIndex,
|
selectedOptionIndex,
|
||||||
};
|
};
|
||||||
resolve(result);
|
resolve(result);
|
||||||
});
|
});
|
||||||
@ -965,10 +948,10 @@ export function transitionMysteryEncounterIntroVisuals(hide = true, destroy = tr
|
|||||||
export function handleMysteryEncounterBattleStartEffects() {
|
export function handleMysteryEncounterBattleStartEffects() {
|
||||||
const encounter = globalScene.currentBattle.mysteryEncounter;
|
const encounter = globalScene.currentBattle.mysteryEncounter;
|
||||||
if (
|
if (
|
||||||
globalScene.currentBattle.isBattleMysteryEncounter() &&
|
globalScene.currentBattle.isBattleMysteryEncounter()
|
||||||
encounter &&
|
&& encounter
|
||||||
encounter.encounterMode !== MysteryEncounterMode.NO_BATTLE &&
|
&& encounter.encounterMode !== MysteryEncounterMode.NO_BATTLE
|
||||||
!encounter.startOfBattleEffectsComplete
|
&& !encounter.startOfBattleEffectsComplete
|
||||||
) {
|
) {
|
||||||
const effects = encounter.startOfBattleEffects;
|
const effects = encounter.startOfBattleEffects;
|
||||||
effects.forEach(effect => {
|
effects.forEach(effect => {
|
||||||
@ -986,7 +969,7 @@ export function handleMysteryEncounterBattleStartEffects() {
|
|||||||
/**
|
/**
|
||||||
* Can queue extra phases or logic during {@linkcode TurnInitPhase}
|
* Can queue extra phases or logic during {@linkcode TurnInitPhase}
|
||||||
* Should mostly just be used for injecting custom phases into the battle system on turn start
|
* Should mostly just be used for injecting custom phases into the battle system on turn start
|
||||||
* @return boolean - if true, will skip the remainder of the {@linkcode TurnInitPhase}
|
* @returns boolean - if true, will skip the remainder of the {@linkcode TurnInitPhase}
|
||||||
*/
|
*/
|
||||||
export function handleMysteryEncounterTurnStartEffects(): boolean {
|
export function handleMysteryEncounterTurnStartEffects(): boolean {
|
||||||
const encounter = globalScene.currentBattle.mysteryEncounter;
|
const encounter = globalScene.currentBattle.mysteryEncounter;
|
||||||
@ -1003,7 +986,7 @@ export function handleMysteryEncounterTurnStartEffects(): boolean {
|
|||||||
* @param level the level of the mon, which differs between MEs
|
* @param level the level of the mon, which differs between MEs
|
||||||
* @param isBoss whether the mon should be a Boss
|
* @param isBoss whether the mon should be a Boss
|
||||||
* @param rerollHidden whether the mon should get an extra roll for Hidden Ability
|
* @param rerollHidden whether the mon should get an extra roll for Hidden Ability
|
||||||
* @returns {@linkcode EnemyPokemon} for the requested encounter
|
* @returns for the requested encounter
|
||||||
*/
|
*/
|
||||||
export function getRandomEncounterSpecies(level: number, isBoss = false, rerollHidden = false): EnemyPokemon {
|
export function getRandomEncounterSpecies(level: number, isBoss = false, rerollHidden = false): EnemyPokemon {
|
||||||
let bossSpecies: PokemonSpecies;
|
let bossSpecies: PokemonSpecies;
|
||||||
@ -1093,7 +1076,7 @@ export function calculateMEAggregateStats(baseSpawnWeight: number) {
|
|||||||
.filter(b => {
|
.filter(b => {
|
||||||
return !Array.isArray(b) || !randSeedInt(b[1]);
|
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);
|
}, i * 100);
|
||||||
if (biomes! && biomes.length > 0) {
|
if (biomes! && biomes.length > 0) {
|
||||||
const specialBiomes = biomes.filter(b => alwaysPickTheseBiomes.includes(b));
|
const specialBiomes = biomes.filter(b => alwaysPickTheseBiomes.includes(b));
|
||||||
@ -1107,13 +1090,11 @@ export function calculateMEAggregateStats(baseSpawnWeight: number) {
|
|||||||
}
|
}
|
||||||
} else if (biomeLinks.hasOwnProperty(currentBiome)) {
|
} else if (biomeLinks.hasOwnProperty(currentBiome)) {
|
||||||
currentBiome = biomeLinks[currentBiome] as BiomeId;
|
currentBiome = biomeLinks[currentBiome] as BiomeId;
|
||||||
} else {
|
} else if (i % 50 === 0) {
|
||||||
if (!(i % 50)) {
|
|
||||||
currentBiome = BiomeId.END;
|
currentBiome = BiomeId.END;
|
||||||
} else {
|
} else {
|
||||||
currentBiome = globalScene.generateRandomBiome(i);
|
currentBiome = globalScene.generateRandomBiome(i);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
currentArena = globalScene.newArena(currentBiome);
|
currentArena = globalScene.newArena(currentBiome);
|
||||||
}
|
}
|
||||||
|
@ -31,9 +31,9 @@ import {
|
|||||||
showEncounterText,
|
showEncounterText,
|
||||||
} from "#mystery-encounters/encounter-dialogue-utils";
|
} from "#mystery-encounters/encounter-dialogue-utils";
|
||||||
import { achvs } from "#system/achv";
|
import { achvs } from "#system/achv";
|
||||||
import type { PartyOption } from "#ui/party-ui-handler";
|
import type { PartyOption } from "#ui/handlers/party-ui-handler";
|
||||||
import { PartyUiMode } from "#ui/party-ui-handler";
|
import { PartyUiMode } from "#ui/handlers/party-ui-handler";
|
||||||
import { SummaryUiMode } from "#ui/summary-ui-handler";
|
import { SummaryUiMode } from "#ui/handlers/summary-ui-handler";
|
||||||
import { applyChallenges } from "#utils/challenge-utils";
|
import { applyChallenges } from "#utils/challenge-utils";
|
||||||
import { BooleanHolder, isNullOrUndefined, randSeedInt } from "#utils/common";
|
import { BooleanHolder, isNullOrUndefined, randSeedInt } from "#utils/common";
|
||||||
import { getPokemonSpecies } from "#utils/pokemon-utils";
|
import { getPokemonSpecies } from "#utils/pokemon-utils";
|
||||||
@ -265,11 +265,11 @@ export function getRandomSpeciesByStarterCost(
|
|||||||
.filter(s => {
|
.filter(s => {
|
||||||
const pokemonSpecies = getPokemonSpecies(s[0]);
|
const pokemonSpecies = getPokemonSpecies(s[0]);
|
||||||
return (
|
return (
|
||||||
pokemonSpecies &&
|
pokemonSpecies
|
||||||
(!excludedSpecies || !excludedSpecies.includes(s[0])) &&
|
&& (!excludedSpecies || !excludedSpecies.includes(s[0]))
|
||||||
(allowSubLegendary || !pokemonSpecies.subLegendary) &&
|
&& (allowSubLegendary || !pokemonSpecies.subLegendary)
|
||||||
(allowLegendary || !pokemonSpecies.legendary) &&
|
&& (allowLegendary || !pokemonSpecies.legendary)
|
||||||
(allowMythical || !pokemonSpecies.mythical)
|
&& (allowMythical || !pokemonSpecies.mythical)
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.map(s => [getPokemonSpecies(s[0]), s[1]]);
|
.map(s => [getPokemonSpecies(s[0]), s[1]]);
|
||||||
@ -409,10 +409,10 @@ export async function applyModifierTypeToPlayerPokemon(
|
|||||||
const modifier = modType.newModifier(pokemon);
|
const modifier = modType.newModifier(pokemon);
|
||||||
const existing = globalScene.findModifier(
|
const existing = globalScene.findModifier(
|
||||||
(m): m is PokemonHeldItemModifier =>
|
(m): m is PokemonHeldItemModifier =>
|
||||||
m instanceof PokemonHeldItemModifier &&
|
m instanceof PokemonHeldItemModifier
|
||||||
m.type.id === modType.id &&
|
&& m.type.id === modType.id
|
||||||
m.pokemonId === pokemon.id &&
|
&& m.pokemonId === pokemon.id
|
||||||
m.matchType(modifier),
|
&& m.matchType(modifier),
|
||||||
) as PokemonHeldItemModifier | undefined;
|
) as PokemonHeldItemModifier | undefined;
|
||||||
|
|
||||||
// At max stacks
|
// At max stacks
|
||||||
@ -650,8 +650,8 @@ export async function catchPokemon(
|
|||||||
const speciesForm = !pokemon.fusionSpecies ? pokemon.getSpeciesForm() : pokemon.getFusionSpeciesForm();
|
const speciesForm = !pokemon.fusionSpecies ? pokemon.getSpeciesForm() : pokemon.getFusionSpeciesForm();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
speciesForm.abilityHidden &&
|
speciesForm.abilityHidden
|
||||||
(pokemon.fusionSpecies ? pokemon.fusionAbilityIndex : pokemon.abilityIndex) === speciesForm.getAbilityCount() - 1
|
&& (pokemon.fusionSpecies ? pokemon.fusionAbilityIndex : pokemon.abilityIndex) === speciesForm.getAbilityCount() - 1
|
||||||
) {
|
) {
|
||||||
globalScene.validateAchv(achvs.HIDDEN_ABILITY);
|
globalScene.validateAchv(achvs.HIDDEN_ABILITY);
|
||||||
}
|
}
|
||||||
@ -988,8 +988,8 @@ export async function addPokemonDataToDexAndValidateAchievements(pokemon: Player
|
|||||||
const speciesForm = !pokemon.fusionSpecies ? pokemon.getSpeciesForm() : pokemon.getFusionSpeciesForm();
|
const speciesForm = !pokemon.fusionSpecies ? pokemon.getSpeciesForm() : pokemon.getFusionSpeciesForm();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
speciesForm.abilityHidden &&
|
speciesForm.abilityHidden
|
||||||
(pokemon.fusionSpecies ? pokemon.fusionAbilityIndex : pokemon.abilityIndex) === speciesForm.getAbilityCount() - 1
|
&& (pokemon.fusionSpecies ? pokemon.fusionAbilityIndex : pokemon.abilityIndex) === speciesForm.getAbilityCount() - 1
|
||||||
) {
|
) {
|
||||||
globalScene.validateAchv(achvs.HIDDEN_ABILITY);
|
globalScene.validateAchv(achvs.HIDDEN_ABILITY);
|
||||||
}
|
}
|
||||||
|
@ -86,8 +86,8 @@ export class PostSummonPhasePriorityQueue extends PhasePriorityQueue {
|
|||||||
this.queue.sort((phaseA: PostSummonPhase, phaseB: PostSummonPhase) => {
|
this.queue.sort((phaseA: PostSummonPhase, phaseB: PostSummonPhase) => {
|
||||||
if (phaseA.getPriority() === phaseB.getPriority()) {
|
if (phaseA.getPriority() === phaseB.getPriority()) {
|
||||||
return (
|
return (
|
||||||
(phaseB.getPokemon().getEffectiveStat(Stat.SPD) - phaseA.getPokemon().getEffectiveStat(Stat.SPD)) *
|
(phaseB.getPokemon().getEffectiveStat(Stat.SPD) - phaseA.getPokemon().getEffectiveStat(Stat.SPD))
|
||||||
(isTrickRoom() ? -1 : 1)
|
* (isTrickRoom() ? -1 : 1)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ export class SpeciesFormChange {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pokemon.species.forms.length) {
|
if (pokemon.species.forms.length === 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,10 +82,10 @@ export class SpeciesFormChangeItemTrigger extends SpeciesFormChangeTrigger {
|
|||||||
// Assume that if m has the `formChangeItem` property, then it is a PokemonFormChangeItemModifier
|
// Assume that if m has the `formChangeItem` property, then it is a PokemonFormChangeItemModifier
|
||||||
const m = r as PokemonFormChangeItemModifier;
|
const m = r as PokemonFormChangeItemModifier;
|
||||||
return (
|
return (
|
||||||
"formChangeItem" in m &&
|
"formChangeItem" in m
|
||||||
m.pokemonId === pokemon.id &&
|
&& m.pokemonId === pokemon.id
|
||||||
m.formChangeItem === this.item &&
|
&& m.formChangeItem === this.item
|
||||||
m.active === this.active
|
&& m.active === this.active
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -155,7 +155,7 @@ export class SpeciesFormChangeMoveLearnedTrigger extends SpeciesFormChangeTrigge
|
|||||||
}
|
}
|
||||||
|
|
||||||
canChange(pokemon: Pokemon): boolean {
|
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");
|
description = i18next.t("pokemonEvolutions:forms.postMove");
|
||||||
canChange(pokemon: Pokemon): boolean {
|
canChange(pokemon: Pokemon): boolean {
|
||||||
return (
|
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 {
|
canChange(pokemon: Pokemon): boolean {
|
||||||
return (
|
return (
|
||||||
this.formKey ===
|
this.formKey
|
||||||
pokemon.species.forms[globalScene.getSpeciesFormIndex(pokemon.species, pokemon.gender, pokemon.getNature(), true)]
|
=== pokemon.species.forms[
|
||||||
.formKey
|
globalScene.getSpeciesFormIndex(pokemon.species, pokemon.gender, pokemon.getNature(), true)
|
||||||
|
].formKey
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -259,10 +260,10 @@ export class SpeciesFormChangeWeatherTrigger extends SpeciesFormChangeTrigger {
|
|||||||
const isAbilitySuppressed = pokemon.summonData.abilitySuppressed;
|
const isAbilitySuppressed = pokemon.summonData.abilitySuppressed;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
!isAbilitySuppressed &&
|
!isAbilitySuppressed
|
||||||
!isWeatherSuppressed &&
|
&& !isWeatherSuppressed
|
||||||
pokemon.hasAbility(this.ability) &&
|
&& pokemon.hasAbility(this.ability)
|
||||||
this.weathers.includes(currentWeather)
|
&& this.weathers.includes(currentWeather)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -288,7 +289,7 @@ export class SpeciesFormChangeRevertWeatherFormTrigger extends SpeciesFormChange
|
|||||||
/**
|
/**
|
||||||
* Checks if the Pokemon has the required ability and the weather is one that will revert
|
* Checks if the Pokemon has the required ability and the weather is one that will revert
|
||||||
* the Pokemon to its original form or the weather or ability is suppressed
|
* the Pokemon to its original form or the weather or ability is suppressed
|
||||||
* @param {Pokemon} pokemon the pokemon that is trying to do the form change
|
* @param pokemon the pokemon that is trying to do the form change
|
||||||
* @returns `true` if the Pokemon will revert to its original form, `false` otherwise
|
* @returns `true` if the Pokemon will revert to its original form, `false` otherwise
|
||||||
*/
|
*/
|
||||||
canChange(pokemon: Pokemon): boolean {
|
canChange(pokemon: Pokemon): boolean {
|
||||||
|
@ -26,8 +26,8 @@ import { loadPokemonVariantAssets } from "#sprites/pokemon-sprite";
|
|||||||
import { hasExpSprite } from "#sprites/sprite-utils";
|
import { hasExpSprite } from "#sprites/sprite-utils";
|
||||||
import type { Variant, VariantSet } from "#sprites/variant";
|
import type { Variant, VariantSet } from "#sprites/variant";
|
||||||
import { populateVariantColorCache, variantColorCache, variantData } from "#sprites/variant";
|
import { populateVariantColorCache, variantColorCache, variantData } from "#sprites/variant";
|
||||||
import type { StarterMoveset } from "#system/game-data";
|
|
||||||
import type { Localizable } from "#types/locales";
|
import type { Localizable } from "#types/locales";
|
||||||
|
import type { StarterMoveset } from "#types/save-data";
|
||||||
import { isNullOrUndefined, randSeedFloat, randSeedGauss, randSeedInt } from "#utils/common";
|
import { isNullOrUndefined, randSeedFloat, randSeedGauss, randSeedInt } from "#utils/common";
|
||||||
import { getPokemonSpecies } from "#utils/pokemon-utils";
|
import { getPokemonSpecies } from "#utils/pokemon-utils";
|
||||||
import { toCamelCase, toPascalCase } from "#utils/strings";
|
import { toCamelCase, toPascalCase } from "#utils/strings";
|
||||||
@ -202,8 +202,8 @@ export abstract class PokemonSpeciesForm {
|
|||||||
}
|
}
|
||||||
let starterSpeciesId = this.speciesId;
|
let starterSpeciesId = this.speciesId;
|
||||||
while (
|
while (
|
||||||
!(starterSpeciesId in starterPassiveAbilities) ||
|
!(starterSpeciesId in starterPassiveAbilities)
|
||||||
!(formIndex in starterPassiveAbilities[starterSpeciesId])
|
|| !(formIndex in starterPassiveAbilities[starterSpeciesId])
|
||||||
) {
|
) {
|
||||||
if (pokemonPrevolutions.hasOwnProperty(starterSpeciesId)) {
|
if (pokemonPrevolutions.hasOwnProperty(starterSpeciesId)) {
|
||||||
starterSpeciesId = pokemonPrevolutions[starterSpeciesId];
|
starterSpeciesId = pokemonPrevolutions[starterSpeciesId];
|
||||||
@ -221,8 +221,8 @@ export abstract class PokemonSpeciesForm {
|
|||||||
|
|
||||||
getLevelMoves(): LevelMoves {
|
getLevelMoves(): LevelMoves {
|
||||||
if (
|
if (
|
||||||
pokemonSpeciesFormLevelMoves.hasOwnProperty(this.speciesId) &&
|
pokemonSpeciesFormLevelMoves.hasOwnProperty(this.speciesId)
|
||||||
pokemonSpeciesFormLevelMoves[this.speciesId].hasOwnProperty(this.formIndex)
|
&& pokemonSpeciesFormLevelMoves[this.speciesId].hasOwnProperty(this.formIndex)
|
||||||
) {
|
) {
|
||||||
return pokemonSpeciesFormLevelMoves[this.speciesId][this.formIndex].slice(0);
|
return pokemonSpeciesFormLevelMoves[this.speciesId][this.formIndex].slice(0);
|
||||||
}
|
}
|
||||||
@ -302,9 +302,9 @@ export abstract class PokemonSpeciesForm {
|
|||||||
|
|
||||||
const formSpriteKey = this.getFormSpriteKey(formIndex);
|
const formSpriteKey = this.getFormSpriteKey(formIndex);
|
||||||
const showGenderDiffs =
|
const showGenderDiffs =
|
||||||
this.genderDiffs &&
|
this.genderDiffs
|
||||||
female &&
|
&& female
|
||||||
![SpeciesFormKey.MEGA, SpeciesFormKey.GIGANTAMAX].includes(formSpriteKey as SpeciesFormKey);
|
&& ![SpeciesFormKey.MEGA, SpeciesFormKey.GIGANTAMAX].includes(formSpriteKey as SpeciesFormKey);
|
||||||
|
|
||||||
return `${showGenderDiffs ? "female__" : ""}${this.speciesId}${formSpriteKey ? `-${formSpriteKey}` : ""}`;
|
return `${showGenderDiffs ? "female__" : ""}${this.speciesId}${formSpriteKey ? `-${formSpriteKey}` : ""}`;
|
||||||
}
|
}
|
||||||
@ -425,7 +425,7 @@ export abstract class PokemonSpeciesForm {
|
|||||||
}
|
}
|
||||||
let ret = speciesId.toString();
|
let ret = speciesId.toString();
|
||||||
const forms = getPokemonSpecies(speciesId).forms;
|
const forms = getPokemonSpecies(speciesId).forms;
|
||||||
if (forms.length) {
|
if (forms.length > 0) {
|
||||||
if (formIndex !== undefined && formIndex >= forms.length) {
|
if (formIndex !== undefined && formIndex >= forms.length) {
|
||||||
console.warn(
|
console.warn(
|
||||||
`Attempted accessing form with index ${formIndex} of species ${getPokemonSpecies(speciesId).getName()} with only ${forms.length || 0} forms`,
|
`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 (
|
if (
|
||||||
pokemonFormLevelMoves.hasOwnProperty(this.speciesId) &&
|
pokemonFormLevelMoves.hasOwnProperty(this.speciesId)
|
||||||
pokemonFormLevelMoves[this.speciesId].hasOwnProperty(this.formIndex)
|
&& pokemonFormLevelMoves[this.speciesId].hasOwnProperty(this.formIndex)
|
||||||
) {
|
) {
|
||||||
if (!pokemonFormLevelMoves[this.speciesId][this.formIndex].find(lm => lm[0] <= 5 && lm[1] === moveId)) {
|
if (!pokemonFormLevelMoves[this.speciesId][this.formIndex].find(lm => lm[0] <= 5 && lm[1] === moveId)) {
|
||||||
return false;
|
return false;
|
||||||
@ -758,7 +758,7 @@ export class PokemonSpecies extends PokemonSpeciesForm implements Localizable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getName(formIndex?: number): string {
|
getName(formIndex?: number): string {
|
||||||
if (formIndex !== undefined && this.forms.length) {
|
if (formIndex !== undefined && this.forms.length > 0) {
|
||||||
const form = this.forms[formIndex];
|
const form = this.forms[formIndex];
|
||||||
let key: string | null;
|
let key: string | null;
|
||||||
switch (form.formKey) {
|
switch (form.formKey) {
|
||||||
@ -846,9 +846,9 @@ export class PokemonSpecies extends PokemonSpeciesForm implements Localizable {
|
|||||||
? i18next.t(`battlePokemonForm:${toCamelCase(formKey)}`, { pokemonName: this.name })
|
? i18next.t(`battlePokemonForm:${toCamelCase(formKey)}`, { pokemonName: this.name })
|
||||||
: i18next.t(`pokemonForm:battleForm.${toCamelCase(formKey)}`);
|
: i18next.t(`pokemonForm:battleForm.${toCamelCase(formKey)}`);
|
||||||
} else if (
|
} else if (
|
||||||
region === Region.NORMAL ||
|
region === Region.NORMAL
|
||||||
(this.speciesId === SpeciesId.GALAR_DARMANITAN && formIndex > 0) ||
|
|| (this.speciesId === SpeciesId.GALAR_DARMANITAN && formIndex > 0)
|
||||||
this.speciesId === SpeciesId.PALDEA_TAUROS
|
|| this.speciesId === SpeciesId.PALDEA_TAUROS
|
||||||
) {
|
) {
|
||||||
// More special cases can be added here
|
// More special cases can be added here
|
||||||
const i18key = `pokemonForm:${speciesName}${formText}`;
|
const i18key = `pokemonForm:${speciesName}${formText}`;
|
||||||
@ -919,7 +919,7 @@ export class PokemonSpecies extends PokemonSpeciesForm implements Localizable {
|
|||||||
* The calculation with evolution delay is a weighted average of the easeIn and easeOut functions where preferredMinLevel is the denominator.
|
* The calculation with evolution delay is a weighted average of the easeIn and easeOut functions where preferredMinLevel is the denominator.
|
||||||
* This also means a lower value of x will lead to a higher evolution chance.
|
* This also means a lower value of x will lead to a higher evolution chance.
|
||||||
* @param strength {@linkcode PartyMemberStrength} The strength of the party member in question
|
* @param strength {@linkcode PartyMemberStrength} The strength of the party member in question
|
||||||
* @returns {@linkcode number} The level difference from expected evolution level tolerated for a mon to be unevolved. Lower value = higher evolution chance.
|
* @returns The level difference from expected evolution level tolerated for a mon to be unevolved. Lower value = higher evolution chance.
|
||||||
*/
|
*/
|
||||||
private getStrengthLevelDiff(strength: PartyMemberStrength): number {
|
private getStrengthLevelDiff(strength: PartyMemberStrength): number {
|
||||||
switch (Math.min(strength, PartyMemberStrength.STRONGER)) {
|
switch (Math.min(strength, PartyMemberStrength.STRONGER)) {
|
||||||
@ -947,7 +947,7 @@ export class PokemonSpecies extends PokemonSpeciesForm implements Localizable {
|
|||||||
): SpeciesId {
|
): SpeciesId {
|
||||||
const prevolutionLevels = this.getPrevolutionLevels();
|
const prevolutionLevels = this.getPrevolutionLevels();
|
||||||
|
|
||||||
if (prevolutionLevels.length) {
|
if (prevolutionLevels.length > 0) {
|
||||||
for (let pl = prevolutionLevels.length - 1; pl >= 0; pl--) {
|
for (let pl = prevolutionLevels.length - 1; pl >= 0; pl--) {
|
||||||
const prevolutionLevel = prevolutionLevels[pl];
|
const prevolutionLevel = prevolutionLevels[pl];
|
||||||
if (level < prevolutionLevel[1]) {
|
if (level < prevolutionLevel[1]) {
|
||||||
@ -958,11 +958,11 @@ export class PokemonSpecies extends PokemonSpeciesForm implements Localizable {
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
// If evolutions shouldn't happen, add more cases here :)
|
// If evolutions shouldn't happen, add more cases here :)
|
||||||
!allowEvolving ||
|
!allowEvolving
|
||||||
!pokemonEvolutions.hasOwnProperty(this.speciesId) ||
|
|| !pokemonEvolutions.hasOwnProperty(this.speciesId)
|
||||||
(globalScene.currentBattle?.waveIndex === 20 &&
|
|| (globalScene.currentBattle?.waveIndex === 20
|
||||||
globalScene.gameMode.isClassic &&
|
&& globalScene.gameMode.isClassic
|
||||||
globalScene.currentBattle.trainer)
|
&& globalScene.currentBattle.trainer)
|
||||||
) {
|
) {
|
||||||
return this.speciesId;
|
return this.speciesId;
|
||||||
}
|
}
|
||||||
@ -988,8 +988,7 @@ export class PokemonSpecies extends PokemonSpeciesForm implements Localizable {
|
|||||||
|
|
||||||
if (!forTrainer && isRegionalEvolution) {
|
if (!forTrainer && isRegionalEvolution) {
|
||||||
evolutionChance = 0;
|
evolutionChance = 0;
|
||||||
} else {
|
} else if (ev.wildDelay === SpeciesWildEvolutionDelay.NONE) {
|
||||||
if (ev.wildDelay === SpeciesWildEvolutionDelay.NONE) {
|
|
||||||
if (strength === PartyMemberStrength.STRONGER) {
|
if (strength === PartyMemberStrength.STRONGER) {
|
||||||
evolutionChance = 1;
|
evolutionChance = 1;
|
||||||
} else {
|
} else {
|
||||||
@ -1015,15 +1014,14 @@ export class PokemonSpecies extends PokemonSpeciesForm implements Localizable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
evolutionChance = Math.min(
|
evolutionChance = Math.min(
|
||||||
0.65 * easeInFunc(Math.min(Math.max(level - evolutionLevel, 0), preferredMinLevel) / preferredMinLevel) +
|
0.65 * easeInFunc(Math.min(Math.max(level - evolutionLevel, 0), preferredMinLevel) / preferredMinLevel)
|
||||||
0.35 *
|
+ 0.35
|
||||||
easeOutFunc(
|
* easeOutFunc(
|
||||||
Math.min(Math.max(level - evolutionLevel, 0), preferredMinLevel * 2.5) / (preferredMinLevel * 2.5),
|
Math.min(Math.max(level - evolutionLevel, 0), preferredMinLevel * 2.5) / (preferredMinLevel * 2.5),
|
||||||
),
|
),
|
||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: Adjust templates and delays so we don't have to hardcode it
|
//TODO: Adjust templates and delays so we don't have to hardcode it
|
||||||
/* TEMPORARY! (Most) Trainers shouldn't be using unevolved Pokemon by the third gym leader / wave 80. Exceptions to this include Breeders, whose large teams are balanced by the use of weaker pokemon */
|
/* TEMPORARY! (Most) Trainers shouldn't be using unevolved Pokemon by the third gym leader / wave 80. Exceptions to this include Breeders, whose large teams are balanced by the use of weaker pokemon */
|
||||||
@ -1097,9 +1095,9 @@ export class PokemonSpecies extends PokemonSpeciesForm implements Localizable {
|
|||||||
for (const p of allEvolvingPokemon) {
|
for (const p of allEvolvingPokemon) {
|
||||||
for (const e of pokemonEvolutions[p]) {
|
for (const e of pokemonEvolutions[p]) {
|
||||||
if (
|
if (
|
||||||
e.speciesId === this.speciesId &&
|
e.speciesId === this.speciesId
|
||||||
(!this.forms.length || !e.evoFormKey || e.evoFormKey === this.forms[this.formIndex].formKey) &&
|
&& (this.forms.length === 0 || !e.evoFormKey || e.evoFormKey === this.forms[this.formIndex].formKey)
|
||||||
prevolutionLevels.every(pe => pe[0] !== Number.parseInt(p))
|
&& prevolutionLevels.every(pe => pe[0] !== Number.parseInt(p))
|
||||||
) {
|
) {
|
||||||
const speciesId = Number.parseInt(p) as SpeciesId;
|
const speciesId = Number.parseInt(p) as SpeciesId;
|
||||||
const level = e.level;
|
const level = e.level;
|
||||||
@ -1135,9 +1133,9 @@ export class PokemonSpecies extends PokemonSpeciesForm implements Localizable {
|
|||||||
prevolutionLevels[l][0],
|
prevolutionLevels[l][0],
|
||||||
Math.min(
|
Math.min(
|
||||||
Math.max(
|
Math.max(
|
||||||
evolution?.level! +
|
evolution?.level!
|
||||||
Math.round(randSeedGauss(0.5, 1 + levelDiff * 0.2) * Math.max(evolution?.wildDelay!, 0.5) * 5) -
|
+ Math.round(randSeedGauss(0.5, 1 + levelDiff * 0.2) * Math.max(evolution?.wildDelay!, 0.5) * 5)
|
||||||
1,
|
- 1,
|
||||||
2,
|
2,
|
||||||
evolution?.level!,
|
evolution?.level!,
|
||||||
),
|
),
|
||||||
@ -1146,15 +1144,13 @@ export class PokemonSpecies extends PokemonSpeciesForm implements Localizable {
|
|||||||
]); // TODO: are those bangs correct?
|
]); // TODO: are those bangs correct?
|
||||||
}
|
}
|
||||||
const lastPrevolutionLevel = ret[prevolutionLevels.length - 1][1];
|
const lastPrevolutionLevel = ret[prevolutionLevels.length - 1][1];
|
||||||
const evolution = pokemonEvolutions[prevolutionLevels[prevolutionLevels.length - 1][0]].find(
|
const evolution = pokemonEvolutions[prevolutionLevels.at(-1)![0]].find(e => e.speciesId === this.speciesId);
|
||||||
e => e.speciesId === this.speciesId,
|
|
||||||
);
|
|
||||||
ret.push([
|
ret.push([
|
||||||
this.speciesId,
|
this.speciesId,
|
||||||
Math.min(
|
Math.min(
|
||||||
Math.max(
|
Math.max(
|
||||||
lastPrevolutionLevel +
|
lastPrevolutionLevel
|
||||||
Math.round(randSeedGauss(0.5, 1 + levelDiff * 0.2) * Math.max(evolution?.wildDelay!, 0.5) * 5),
|
+ Math.round(randSeedGauss(0.5, 1 + levelDiff * 0.2) * Math.max(evolution?.wildDelay!, 0.5) * 5),
|
||||||
lastPrevolutionLevel + 1,
|
lastPrevolutionLevel + 1,
|
||||||
evolution?.level!,
|
evolution?.level!,
|
||||||
),
|
),
|
||||||
@ -1176,16 +1172,16 @@ export class PokemonSpecies extends PokemonSpeciesForm implements Localizable {
|
|||||||
const mythical = this.mythical;
|
const mythical = this.mythical;
|
||||||
return species => {
|
return species => {
|
||||||
return (
|
return (
|
||||||
(subLegendary ||
|
(subLegendary
|
||||||
legendary ||
|
|| legendary
|
||||||
mythical ||
|
|| mythical
|
||||||
(pokemonEvolutions.hasOwnProperty(species.speciesId) === hasEvolution &&
|
|| (pokemonEvolutions.hasOwnProperty(species.speciesId) === hasEvolution
|
||||||
pokemonPrevolutions.hasOwnProperty(species.speciesId) === hasPrevolution)) &&
|
&& pokemonPrevolutions.hasOwnProperty(species.speciesId) === hasPrevolution))
|
||||||
species.subLegendary === subLegendary &&
|
&& species.subLegendary === subLegendary
|
||||||
species.legendary === legendary &&
|
&& species.legendary === legendary
|
||||||
species.mythical === mythical &&
|
&& species.mythical === mythical
|
||||||
(this.isTrainerForbidden() || !species.isTrainerForbidden()) &&
|
&& (this.isTrainerForbidden() || !species.isTrainerForbidden())
|
||||||
species.speciesId !== SpeciesId.DITTO
|
&& species.speciesId !== SpeciesId.DITTO
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1202,19 +1198,19 @@ export class PokemonSpecies extends PokemonSpeciesForm implements Localizable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getFormSpriteKey(formIndex?: number) {
|
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(
|
console.warn(
|
||||||
`Attempted accessing form with index ${formIndex} of species ${this.getName()} with only ${this.forms.length || 0} forms`,
|
`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);
|
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.
|
* 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 {
|
getFullUnlocksData(): bigint {
|
||||||
let caughtAttr = 0n;
|
let caughtAttr = 0n;
|
||||||
|
@ -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
|
// Silently disappear if either source or target are missing or happen to be the same pokemon
|
||||||
// (i.e. targeting oneself)
|
// (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
|
// 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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,8 +53,8 @@ const SEASONAL_WEIGHT_MULTIPLIER = 15;
|
|||||||
//#region Common Messages
|
//#region Common Messages
|
||||||
|
|
||||||
const commonSplashMessages = [
|
const commonSplashMessages = [
|
||||||
...Array(BATTLES_WON_WEIGHT_MULTIPLIER).fill("battlesWon"),
|
...new Array(BATTLES_WON_WEIGHT_MULTIPLIER).fill("battlesWon"),
|
||||||
...Array(POKEMON_NAMES_WEIGHT_MULTIPLIER).fill("underratedPokemon"),
|
...new Array(POKEMON_NAMES_WEIGHT_MULTIPLIER).fill("underratedPokemon"),
|
||||||
"joinTheDiscord",
|
"joinTheDiscord",
|
||||||
"infiniteLevels",
|
"infiniteLevels",
|
||||||
"everythingIsStackable",
|
"everythingIsStackable",
|
||||||
@ -333,7 +333,7 @@ export function getSplashMessages(): string[] {
|
|||||||
if (now >= startDate && now <= endDate) {
|
if (now >= startDate && now <= endDate) {
|
||||||
console.log(`Adding ${messages.length} ${name} splash messages (weight: x${SEASONAL_WEIGHT_MULTIPLIER})`);
|
console.log(`Adding ${messages.length} ${name} splash messages (weight: x${SEASONAL_WEIGHT_MULTIPLIER})`);
|
||||||
for (const message of messages) {
|
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);
|
splashMessages.push(...weightedMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,12 +59,12 @@ export function getStatusEffectObtainText(
|
|||||||
|
|
||||||
if (!sourceText) {
|
if (!sourceText) {
|
||||||
const i18nKey = `${getStatusEffectMessageKey(statusEffect)}.obtain` as ParseKeys;
|
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;
|
const i18nKey = `${getStatusEffectMessageKey(statusEffect)}.obtainSource` as ParseKeys;
|
||||||
return i18next.t(i18nKey, {
|
return i18next.t(i18nKey, {
|
||||||
pokemonNameWithAffix: pokemonNameWithAffix,
|
pokemonNameWithAffix,
|
||||||
sourceText: sourceText,
|
sourceText,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ export function getStatusEffectActivationText(statusEffect: StatusEffect, pokemo
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
const i18nKey = `${getStatusEffectMessageKey(statusEffect)}.activation` as ParseKeys;
|
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 {
|
export function getStatusEffectOverlapText(statusEffect: StatusEffect, pokemonNameWithAffix: string): string {
|
||||||
@ -81,7 +81,7 @@ export function getStatusEffectOverlapText(statusEffect: StatusEffect, pokemonNa
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
const i18nKey = `${getStatusEffectMessageKey(statusEffect)}.overlap` as ParseKeys;
|
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 {
|
export function getStatusEffectHealText(statusEffect: StatusEffect, pokemonNameWithAffix: string): string {
|
||||||
@ -89,7 +89,7 @@ export function getStatusEffectHealText(statusEffect: StatusEffect, pokemonNameW
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
const i18nKey = `${getStatusEffectMessageKey(statusEffect)}.heal` as ParseKeys;
|
const i18nKey = `${getStatusEffectMessageKey(statusEffect)}.heal` as ParseKeys;
|
||||||
return i18next.t(i18nKey, { pokemonNameWithAffix: pokemonNameWithAffix });
|
return i18next.t(i18nKey, { pokemonNameWithAffix });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getStatusEffectDescriptor(statusEffect: StatusEffect): string {
|
export function getStatusEffectDescriptor(statusEffect: StatusEffect): string {
|
||||||
|
@ -65,14 +65,10 @@ export class Terrain {
|
|||||||
// Psychic terrain will only cancel a move if it:
|
// Psychic terrain will only cancel a move if it:
|
||||||
return (
|
return (
|
||||||
// ... is neither spread nor field-targeted,
|
// ... is neither spread nor field-targeted,
|
||||||
!isFieldTargeted(move) &&
|
!isFieldTargeted(move)
|
||||||
!isSpreadMove(move) &&
|
&& !isSpreadMove(move) // .. has positive final priority,
|
||||||
// .. has positive final priority,
|
&& move.getPriority(user) > 0 // ...and is targeting at least 1 grounded opponent
|
||||||
move.getPriority(user) > 0 &&
|
&& user.getOpponents(true).some(o => targets.includes(o.getBattlerIndex()) && o.isGrounded())
|
||||||
// ...and is targeting at least 1 grounded opponent
|
|
||||||
user
|
|
||||||
.getOpponents(true)
|
|
||||||
.some(o => targets.includes(o.getBattlerIndex()) && o.isGrounded())
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,8 +140,8 @@ export class TrainerConfig {
|
|||||||
this.victoryBgm = "victory_trainer";
|
this.victoryBgm = "victory_trainer";
|
||||||
this.partyTemplates = [trainerPartyTemplates.TWO_AVG];
|
this.partyTemplates = [trainerPartyTemplates.TWO_AVG];
|
||||||
this.speciesFilter = species =>
|
this.speciesFilter = species =>
|
||||||
(allowLegendaries || (!species.legendary && !species.subLegendary && !species.mythical)) &&
|
(allowLegendaries || (!species.legendary && !species.subLegendary && !species.mythical))
|
||||||
!species.isTrainerForbidden();
|
&& !species.isTrainerForbidden();
|
||||||
}
|
}
|
||||||
|
|
||||||
getKey(): string {
|
getKey(): string {
|
||||||
@ -204,7 +204,7 @@ export class TrainerConfig {
|
|||||||
/**
|
/**
|
||||||
* Returns the derived trainer type for a given trainer type.
|
* Returns the derived trainer type for a given trainer type.
|
||||||
* @param trainerTypeToDeriveFrom - The trainer type to derive from. (If null, the this.trainerType property will be used.)
|
* @param trainerTypeToDeriveFrom - The trainer type to derive from. (If null, the this.trainerType property will be used.)
|
||||||
* @returns {TrainerType} - The derived trainer type.
|
* @returns - The derived trainer type.
|
||||||
*/
|
*/
|
||||||
getDerivedType(trainerTypeToDeriveFrom: TrainerType | null = null): TrainerType {
|
getDerivedType(trainerTypeToDeriveFrom: TrainerType | null = null): TrainerType {
|
||||||
let trainerType = trainerTypeToDeriveFrom ? trainerTypeToDeriveFrom : this.trainerType;
|
let trainerType = trainerTypeToDeriveFrom ? trainerTypeToDeriveFrom : this.trainerType;
|
||||||
@ -274,9 +274,9 @@ export class TrainerConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the configuration for trainers with genders, including the female name and encounter background music (BGM).
|
* Sets the configuration for trainers with genders, including the female name and encounter background music (BGM).
|
||||||
* @param {string} [nameFemale] The name of the female trainer. If 'Ivy', a localized name will be assigned.
|
* @param [nameFemale] The name of the female trainer. If 'Ivy', a localized name will be assigned.
|
||||||
* @param {TrainerType | string} [femaleEncounterBgm] The encounter BGM for the female trainer, which can be a TrainerType or a string.
|
* @param [femaleEncounterBgm] The encounter BGM for the female trainer, which can be a TrainerType or a string.
|
||||||
* @returns {TrainerConfig} The updated TrainerConfig instance.
|
* @returns The updated TrainerConfig instance.
|
||||||
*/
|
*/
|
||||||
setHasGenders(nameFemale?: string, femaleEncounterBgm?: TrainerType | string): TrainerConfig {
|
setHasGenders(nameFemale?: string, femaleEncounterBgm?: TrainerType | string): TrainerConfig {
|
||||||
// If the female name is 'Ivy' (the rival), assign a localized name.
|
// If the female name is 'Ivy' (the rival), assign a localized name.
|
||||||
@ -314,7 +314,7 @@ export class TrainerConfig {
|
|||||||
* Sets the configuration for trainers with double battles, including the name of the double trainer and the encounter BGM.
|
* Sets the configuration for trainers with double battles, including the name of the double trainer and the encounter BGM.
|
||||||
* @param nameDouble The name of the double trainer (e.g., "Ace Duo" for Trainer Class Doubles or "red_blue_double" for NAMED trainer doubles).
|
* @param nameDouble The name of the double trainer (e.g., "Ace Duo" for Trainer Class Doubles or "red_blue_double" for NAMED trainer doubles).
|
||||||
* @param doubleEncounterBgm The encounter BGM for the double trainer, which can be a TrainerType or a string.
|
* @param doubleEncounterBgm The encounter BGM for the double trainer, which can be a TrainerType or a string.
|
||||||
* @returns {TrainerConfig} The updated TrainerConfig instance.
|
* @returns The updated TrainerConfig instance.
|
||||||
*/
|
*/
|
||||||
setHasDouble(nameDouble: string, doubleEncounterBgm?: TrainerType | string): TrainerConfig {
|
setHasDouble(nameDouble: string, doubleEncounterBgm?: TrainerType | string): TrainerConfig {
|
||||||
this.hasDouble = true;
|
this.hasDouble = true;
|
||||||
@ -331,7 +331,7 @@ export class TrainerConfig {
|
|||||||
/**
|
/**
|
||||||
* Sets the trainer type for double battles.
|
* Sets the trainer type for double battles.
|
||||||
* @param trainerTypeDouble The TrainerType of the partner in a double battle.
|
* @param trainerTypeDouble The TrainerType of the partner in a double battle.
|
||||||
* @returns {TrainerConfig} The updated TrainerConfig instance.
|
* @returns The updated TrainerConfig instance.
|
||||||
*/
|
*/
|
||||||
setDoubleTrainerType(trainerTypeDouble: TrainerType): TrainerConfig {
|
setDoubleTrainerType(trainerTypeDouble: TrainerType): TrainerConfig {
|
||||||
this.trainerTypeDouble = trainerTypeDouble;
|
this.trainerTypeDouble = trainerTypeDouble;
|
||||||
@ -356,7 +356,7 @@ export class TrainerConfig {
|
|||||||
/**
|
/**
|
||||||
* Sets the title for double trainers
|
* Sets the title for double trainers
|
||||||
* @param titleDouble The key for the title in the i18n file. (e.g., "champion_double").
|
* @param titleDouble The key for the title in the i18n file. (e.g., "champion_double").
|
||||||
* @returns {TrainerConfig} The updated TrainerConfig instance.
|
* @returns The updated TrainerConfig instance.
|
||||||
*/
|
*/
|
||||||
setDoubleTitle(titleDouble: string): TrainerConfig {
|
setDoubleTitle(titleDouble: string): TrainerConfig {
|
||||||
// First check if i18n is initialized
|
// First check if i18n is initialized
|
||||||
@ -523,9 +523,9 @@ export class TrainerConfig {
|
|||||||
* Initializes the trainer configuration for an evil team admin.
|
* Initializes the trainer configuration for an evil team admin.
|
||||||
* @param title The title of the evil team admin.
|
* @param title The title of the evil team admin.
|
||||||
* @param poolName The evil team the admin belongs to.
|
* @param poolName The evil team the admin belongs to.
|
||||||
* @param {SpeciesId | SpeciesId[]} signatureSpecies The signature species for the evil team leader.
|
* @param signatureSpecies The signature species for the evil team leader.
|
||||||
* @param specialtyType The specialty Type of the admin, if they have one
|
* @param specialtyType The specialty Type of the admin, if they have one
|
||||||
* @returns {TrainerConfig} The updated TrainerConfig instance.
|
* @returns The updated TrainerConfig instance.
|
||||||
*/
|
*/
|
||||||
initForEvilTeamAdmin(
|
initForEvilTeamAdmin(
|
||||||
title: string,
|
title: string,
|
||||||
@ -566,7 +566,7 @@ export class TrainerConfig {
|
|||||||
/**
|
/**
|
||||||
* Initializes the trainer configuration for a Stat Trainer, as part of the Trainer's Test Mystery Encounter.
|
* Initializes the trainer configuration for a Stat Trainer, as part of the Trainer's Test Mystery Encounter.
|
||||||
* @param _isMale Whether the stat trainer is Male or Female (for localization of the title).
|
* @param _isMale Whether the stat trainer is Male or Female (for localization of the title).
|
||||||
* @returns {TrainerConfig} The updated TrainerConfig instance.
|
* @returns The updated TrainerConfig instance.
|
||||||
*/
|
*/
|
||||||
initForStatTrainer(_isMale = false): TrainerConfig {
|
initForStatTrainer(_isMale = false): TrainerConfig {
|
||||||
if (!getIsInitialized()) {
|
if (!getIsInitialized()) {
|
||||||
@ -590,10 +590,10 @@ export class TrainerConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the trainer configuration for an evil team leader. Temporarily hardcoding evil leader teams though.
|
* Initializes the trainer configuration for an evil team leader. Temporarily hardcoding evil leader teams though.
|
||||||
* @param {SpeciesId | SpeciesId[]} signatureSpecies The signature species for the evil team leader.
|
* @param signatureSpecies The signature species for the evil team leader.
|
||||||
* @param {PokemonType} specialtyType The specialty type for the evil team Leader.
|
* @param specialtyType The specialty type for the evil team Leader.
|
||||||
* @param boolean Whether or not this is the rematch fight
|
* @param boolean Whether or not this is the rematch fight
|
||||||
* @returns {TrainerConfig} The updated TrainerConfig instance.
|
* @returns The updated TrainerConfig instance.
|
||||||
*/
|
*/
|
||||||
initForEvilTeamLeader(
|
initForEvilTeamLeader(
|
||||||
title: string,
|
title: string,
|
||||||
@ -631,12 +631,12 @@ export class TrainerConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the trainer configuration for a Gym Leader.
|
* Initializes the trainer configuration for a Gym Leader.
|
||||||
* @param {SpeciesId | SpeciesId[]} signatureSpecies The signature species for the Gym Leader. Added to party in reverse order.
|
* @param signatureSpecies The signature species for the Gym Leader. Added to party in reverse order.
|
||||||
* @param isMale Whether the Gym Leader is Male or Not (for localization of the title).
|
* @param isMale Whether the Gym Leader is Male or Not (for localization of the title).
|
||||||
* @param {PokemonType} specialtyType The specialty type for the Gym Leader.
|
* @param specialtyType The specialty type for the Gym Leader.
|
||||||
* @param ignoreMinTeraWave Whether the Gym Leader always uses Tera (true), or only Teras after {@linkcode GYM_LEADER_TERA_WAVE} (false). Defaults to false.
|
* @param ignoreMinTeraWave Whether the Gym Leader always uses Tera (true), or only Teras after {@linkcode GYM_LEADER_TERA_WAVE} (false). Defaults to false.
|
||||||
* @param teraSlot Optional, sets the party member in this slot to Terastallize. Wraps based on party size.
|
* @param teraSlot Optional, sets the party member in this slot to Terastallize. Wraps based on party size.
|
||||||
* @returns {TrainerConfig} The updated TrainerConfig instance.
|
* @returns The updated TrainerConfig instance.
|
||||||
*/
|
*/
|
||||||
initForGymLeader(
|
initForGymLeader(
|
||||||
signatureSpecies: (SpeciesId | SpeciesId[])[],
|
signatureSpecies: (SpeciesId | SpeciesId[])[],
|
||||||
@ -748,9 +748,9 @@ export class TrainerConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the trainer configuration for a Champion.
|
* Initializes the trainer configuration for a Champion.
|
||||||
* @param {SpeciesId | SpeciesId[]} signatureSpecies The signature species for the Champion.
|
* @param signatureSpecies The signature species for the Champion.
|
||||||
* @param isMale Whether the Champion is Male or Female (for localization of the title).
|
* @param isMale Whether the Champion is Male or Female (for localization of the title).
|
||||||
* @returns {TrainerConfig} The updated TrainerConfig instance.
|
* @returns The updated TrainerConfig instance.
|
||||||
*/
|
*/
|
||||||
initForChampion(isMale: boolean): TrainerConfig {
|
initForChampion(isMale: boolean): TrainerConfig {
|
||||||
// Check if the internationalization (i18n) system is initialized.
|
// Check if the internationalization (i18n) system is initialized.
|
||||||
@ -785,7 +785,7 @@ export class TrainerConfig {
|
|||||||
/**
|
/**
|
||||||
* Sets a localized name for the trainer. This should only be used for trainers that dont use a "initFor" function and are considered "named" trainers
|
* Sets a localized name for the trainer. This should only be used for trainers that dont use a "initFor" function and are considered "named" trainers
|
||||||
* @param name - The name of the trainer.
|
* @param name - The name of the trainer.
|
||||||
* @returns {TrainerConfig} The updated TrainerConfig instance.
|
* @returns The updated TrainerConfig instance.
|
||||||
*/
|
*/
|
||||||
setLocalizedName(name: string): TrainerConfig {
|
setLocalizedName(name: string): TrainerConfig {
|
||||||
// Check if the internationalization (i18n) system is initialized.
|
// Check if the internationalization (i18n) system is initialized.
|
||||||
@ -798,9 +798,9 @@ export class TrainerConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the title for the trainer based on the provided trainer slot and variant.
|
* Retrieves the title for the trainer based on the provided trainer slot and variant.
|
||||||
* @param {TrainerSlot} trainerSlot - The slot to determine which title to use. Defaults to TrainerSlot.NONE.
|
* @param trainerSlot - The slot to determine which title to use. Defaults to TrainerSlot.NONE.
|
||||||
* @param {TrainerVariant} variant - The variant of the trainer to determine the specific title.
|
* @param variant - The variant of the trainer to determine the specific title.
|
||||||
* @returns {string} - The title of the trainer.
|
* @returns - The title of the trainer.
|
||||||
*/
|
*/
|
||||||
getTitle(trainerSlot: TrainerSlot = TrainerSlot.NONE, variant: TrainerVariant): string {
|
getTitle(trainerSlot: TrainerSlot = TrainerSlot.NONE, variant: TrainerVariant): string {
|
||||||
const ret = this.name;
|
const ret = this.name;
|
||||||
@ -816,8 +816,8 @@ export class TrainerConfig {
|
|||||||
if (this.nameFemale) {
|
if (this.nameFemale) {
|
||||||
// Check if the variant is either female or this is for the partner in a double battle
|
// Check if the variant is either female or this is for the partner in a double battle
|
||||||
if (
|
if (
|
||||||
variant === TrainerVariant.FEMALE ||
|
variant === TrainerVariant.FEMALE
|
||||||
(variant === TrainerVariant.DOUBLE && trainerSlot === TrainerSlot.TRAINER_PARTNER)
|
|| (variant === TrainerVariant.DOUBLE && trainerSlot === TrainerSlot.TRAINER_PARTNER)
|
||||||
) {
|
) {
|
||||||
return this.nameFemale;
|
return this.nameFemale;
|
||||||
}
|
}
|
||||||
@ -1088,8 +1088,8 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
s =>
|
s =>
|
||||||
[s.ability1, s.ability2, s.abilityHidden].some(
|
[s.ability1, s.ability2, s.abilityHidden].some(
|
||||||
a =>
|
a =>
|
||||||
!!a &&
|
!!a
|
||||||
[
|
&& [
|
||||||
AbilityId.WHITE_SMOKE,
|
AbilityId.WHITE_SMOKE,
|
||||||
AbilityId.GLUTTONY,
|
AbilityId.GLUTTONY,
|
||||||
AbilityId.HONEY_GATHER,
|
AbilityId.HONEY_GATHER,
|
||||||
@ -1102,8 +1102,8 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
AbilityId.SUPERSWEET_SYRUP,
|
AbilityId.SUPERSWEET_SYRUP,
|
||||||
AbilityId.HOSPITALITY,
|
AbilityId.HOSPITALITY,
|
||||||
].includes(a),
|
].includes(a),
|
||||||
) ||
|
)
|
||||||
s
|
|| s
|
||||||
.getLevelMoves()
|
.getLevelMoves()
|
||||||
.some(plm =>
|
.some(plm =>
|
||||||
[MoveId.SOFT_BOILED, MoveId.SPORE, MoveId.MILK_DRINK, MoveId.OVERHEAT, MoveId.TEATIME].includes(plm[1]),
|
[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 =>
|
||||||
[s.ability1, s.ability2, s.abilityHidden].some(
|
[s.ability1, s.ability2, s.abilityHidden].some(
|
||||||
a =>
|
a =>
|
||||||
!!a &&
|
!!a
|
||||||
[
|
&& [
|
||||||
AbilityId.DRIZZLE,
|
AbilityId.DRIZZLE,
|
||||||
AbilityId.SWIFT_SWIM,
|
AbilityId.SWIFT_SWIM,
|
||||||
AbilityId.HYDRATION,
|
AbilityId.HYDRATION,
|
||||||
@ -4642,9 +4642,9 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
2,
|
2,
|
||||||
getSpeciesFilterRandomPartyMemberFunc(
|
getSpeciesFilterRandomPartyMemberFunc(
|
||||||
(species: PokemonSpecies) =>
|
(species: PokemonSpecies) =>
|
||||||
!pokemonEvolutions.hasOwnProperty(species.speciesId) &&
|
!pokemonEvolutions.hasOwnProperty(species.speciesId)
|
||||||
!pokemonPrevolutions.hasOwnProperty(species.speciesId) &&
|
&& !pokemonPrevolutions.hasOwnProperty(species.speciesId)
|
||||||
species.baseTotal >= 450,
|
&& species.baseTotal >= 450,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
[TrainerType.RIVAL_3]: new TrainerConfig(++t)
|
[TrainerType.RIVAL_3]: new TrainerConfig(++t)
|
||||||
@ -4717,9 +4717,9 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
2,
|
2,
|
||||||
getSpeciesFilterRandomPartyMemberFunc(
|
getSpeciesFilterRandomPartyMemberFunc(
|
||||||
(species: PokemonSpecies) =>
|
(species: PokemonSpecies) =>
|
||||||
!pokemonEvolutions.hasOwnProperty(species.speciesId) &&
|
!pokemonEvolutions.hasOwnProperty(species.speciesId)
|
||||||
!pokemonPrevolutions.hasOwnProperty(species.speciesId) &&
|
&& !pokemonPrevolutions.hasOwnProperty(species.speciesId)
|
||||||
species.baseTotal >= 450,
|
&& species.baseTotal >= 450,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.setSpeciesFilter(species => species.baseTotal >= 540),
|
.setSpeciesFilter(species => species.baseTotal >= 540),
|
||||||
@ -4798,9 +4798,9 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
2,
|
2,
|
||||||
getSpeciesFilterRandomPartyMemberFunc(
|
getSpeciesFilterRandomPartyMemberFunc(
|
||||||
(species: PokemonSpecies) =>
|
(species: PokemonSpecies) =>
|
||||||
!pokemonEvolutions.hasOwnProperty(species.speciesId) &&
|
!pokemonEvolutions.hasOwnProperty(species.speciesId)
|
||||||
!pokemonPrevolutions.hasOwnProperty(species.speciesId) &&
|
&& !pokemonPrevolutions.hasOwnProperty(species.speciesId)
|
||||||
species.baseTotal >= 450,
|
&& species.baseTotal >= 450,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.setSpeciesFilter(species => species.baseTotal >= 540)
|
.setSpeciesFilter(species => species.baseTotal >= 540)
|
||||||
@ -4880,9 +4880,9 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
2,
|
2,
|
||||||
getSpeciesFilterRandomPartyMemberFunc(
|
getSpeciesFilterRandomPartyMemberFunc(
|
||||||
(species: PokemonSpecies) =>
|
(species: PokemonSpecies) =>
|
||||||
!pokemonEvolutions.hasOwnProperty(species.speciesId) &&
|
!pokemonEvolutions.hasOwnProperty(species.speciesId)
|
||||||
!pokemonPrevolutions.hasOwnProperty(species.speciesId) &&
|
&& !pokemonPrevolutions.hasOwnProperty(species.speciesId)
|
||||||
species.baseTotal >= 450,
|
&& species.baseTotal >= 450,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.setSpeciesFilter(species => species.baseTotal >= 540)
|
.setSpeciesFilter(species => species.baseTotal >= 540)
|
||||||
@ -4976,9 +4976,9 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
2,
|
2,
|
||||||
getSpeciesFilterRandomPartyMemberFunc(
|
getSpeciesFilterRandomPartyMemberFunc(
|
||||||
(species: PokemonSpecies) =>
|
(species: PokemonSpecies) =>
|
||||||
!pokemonEvolutions.hasOwnProperty(species.speciesId) &&
|
!pokemonEvolutions.hasOwnProperty(species.speciesId)
|
||||||
!pokemonPrevolutions.hasOwnProperty(species.speciesId) &&
|
&& !pokemonPrevolutions.hasOwnProperty(species.speciesId)
|
||||||
species.baseTotal >= 450,
|
&& species.baseTotal >= 450,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.setSpeciesFilter(species => species.baseTotal >= 540)
|
.setSpeciesFilter(species => species.baseTotal >= 540)
|
||||||
|
@ -286,7 +286,7 @@ export function getTypeDamageMultiplierColor(
|
|||||||
case 0.5:
|
case 0.5:
|
||||||
return "#FE8E00";
|
return "#FE8E00";
|
||||||
case 1:
|
case 1:
|
||||||
return undefined;
|
return;
|
||||||
case 2:
|
case 2:
|
||||||
return "#4AA500";
|
return "#4AA500";
|
||||||
case 4:
|
case 4:
|
||||||
@ -306,7 +306,7 @@ export function getTypeDamageMultiplierColor(
|
|||||||
case 0.5:
|
case 0.5:
|
||||||
return "#0093FF";
|
return "#0093FF";
|
||||||
case 1:
|
case 1:
|
||||||
return undefined;
|
return;
|
||||||
case 2:
|
case 2:
|
||||||
return "#FE8E00";
|
return "#FE8E00";
|
||||||
case 4:
|
case 4:
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export enum AiType {
|
export enum AiType {
|
||||||
RANDOM,
|
RANDOM,
|
||||||
SMART_RANDOM,
|
SMART_RANDOM,
|
||||||
SMART
|
SMART,
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export enum ArenaTagSide {
|
export enum ArenaTagSide {
|
||||||
BOTH,
|
BOTH,
|
||||||
PLAYER,
|
PLAYER,
|
||||||
ENEMY
|
ENEMY,
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
import type { ArenaTagTypeMap } from "#data/arena-tag";
|
|
||||||
import type { NonSerializableArenaTagType, SerializableArenaTagType } from "#types/arena-tags";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enum representing all different types of {@linkcode ArenaTag}s.
|
* Enum representing all different types of {@linkcode ArenaTag}s.
|
||||||
* @privateRemarks
|
* @privateRemarks
|
||||||
@ -36,5 +33,5 @@ export enum ArenaTagType {
|
|||||||
WATER_FIRE_PLEDGE = "WATER_FIRE_PLEDGE",
|
WATER_FIRE_PLEDGE = "WATER_FIRE_PLEDGE",
|
||||||
GRASS_WATER_PLEDGE = "GRASS_WATER_PLEDGE",
|
GRASS_WATER_PLEDGE = "GRASS_WATER_PLEDGE",
|
||||||
FAIRY_LOCK = "FAIRY_LOCK",
|
FAIRY_LOCK = "FAIRY_LOCK",
|
||||||
NEUTRALIZING_GAS = "NEUTRALIZING_GAS"
|
NEUTRALIZING_GAS = "NEUTRALIZING_GAS",
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export enum BattleSpec {
|
export enum BattleSpec {
|
||||||
DEFAULT,
|
DEFAULT,
|
||||||
FINAL_BOSS
|
FINAL_BOSS,
|
||||||
}
|
}
|
||||||
|
@ -3,5 +3,5 @@ export enum BattleStyle {
|
|||||||
/** Display option to switch active pokemon at battle start. */
|
/** Display option to switch active pokemon at battle start. */
|
||||||
SWITCH,
|
SWITCH,
|
||||||
/** Hide option to switch active pokemon at battle start. */
|
/** Hide option to switch active pokemon at battle start. */
|
||||||
SET
|
SET,
|
||||||
}
|
}
|
||||||
|
@ -2,5 +2,5 @@ export enum BattleType {
|
|||||||
WILD,
|
WILD,
|
||||||
TRAINER,
|
TRAINER,
|
||||||
CLEAR,
|
CLEAR,
|
||||||
MYSTERY_ENCOUNTER
|
MYSTERY_ENCOUNTER,
|
||||||
}
|
}
|
||||||
|
@ -7,5 +7,5 @@ export enum BattlerIndex {
|
|||||||
PLAYER,
|
PLAYER,
|
||||||
PLAYER_2,
|
PLAYER_2,
|
||||||
ENEMY,
|
ENEMY,
|
||||||
ENEMY_2
|
ENEMY_2,
|
||||||
}
|
}
|
||||||
|
@ -9,5 +9,5 @@ export enum BerryType {
|
|||||||
SALAC,
|
SALAC,
|
||||||
LANSAT,
|
LANSAT,
|
||||||
STARF,
|
STARF,
|
||||||
LEPPA
|
LEPPA,
|
||||||
}
|
}
|
||||||
|
@ -34,5 +34,5 @@ export enum BiomeId {
|
|||||||
SNOWY_FOREST,
|
SNOWY_FOREST,
|
||||||
ISLAND = 40,
|
ISLAND = 40,
|
||||||
LABORATORY,
|
LABORATORY,
|
||||||
END = 50
|
END = 50,
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ export enum Color {
|
|||||||
ULTRA = "#f8d038",
|
ULTRA = "#f8d038",
|
||||||
ROGUE = "#d52929",
|
ROGUE = "#d52929",
|
||||||
MASTER = "#e020c0",
|
MASTER = "#e020c0",
|
||||||
LUXURY = "#e64a18"
|
LUXURY = "#e64a18",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum TypeColor {
|
export enum TypeColor {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user