Merge branch 'damo-MysteryEncounterCollection' of https://github.com/damocleas/pokerogue into damo-MysteryEncounterCollection

This commit is contained in:
damocleas 2025-04-25 21:10:07 -04:00
commit 813017541e
683 changed files with 10473 additions and 8596 deletions

View File

@ -15,7 +15,7 @@ jobs:
submodules: 'recursive' submodules: 'recursive'
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version: "20" node-version-file: '.nvmrc'
- name: Install dependencies - name: Install dependencies
run: npm ci run: npm ci
- name: Build - name: Build

View File

@ -18,7 +18,7 @@ jobs:
submodules: 'recursive' submodules: 'recursive'
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version: "20" node-version-file: '.nvmrc'
- name: Install dependencies - name: Install dependencies
run: npm ci run: npm ci
- name: Build - name: Build

View File

@ -24,7 +24,7 @@ jobs:
steps: steps:
- name: Checkout repository for Typedoc - name: Checkout repository for Typedoc
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
submodules: 'recursive' submodules: 'recursive'
path: pokerogue_docs path: pokerogue_docs
@ -34,14 +34,14 @@ jobs:
sudo apt update sudo apt update
sudo apt install -y git openssh-client sudo apt install -y git openssh-client
- name: Setup Node 20.13.1 - name: Setup Node 22.14.1
uses: actions/setup-node@v1 uses: actions/setup-node@v4
with: with:
node-version: 20 node-version-file: "pokerogue_docs/.nvmrc"
- name: Checkout repository for Github Pages - name: Checkout repository for Github Pages
if: github.event_name == 'push' if: github.event_name == 'push'
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
path: pokerogue_gh path: pokerogue_gh
ref: gh-pages ref: gh-pages

View File

@ -29,6 +29,7 @@ jobs:
uses: actions/setup-node@v4 # Use the setup-node action version 4 uses: actions/setup-node@v4 # Use the setup-node action version 4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm'
- name: Install Node.js dependencies # Step to install Node.js dependencies - name: Install Node.js dependencies # Step to install Node.js dependencies
run: npm ci # Use 'npm ci' to install dependencies run: npm ci # Use 'npm ci' to install dependencies

View File

@ -19,13 +19,14 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check out Git repository - name: Check out Git repository
uses: actions/checkout@v4 uses: actions/checkout@v4.2.2
with: with:
submodules: 'recursive' submodules: 'recursive'
- name: Set up Node.js - name: Set up Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 20 node-version-file: '.nvmrc'
cache: 'npm'
- name: Install Node.js dependencies - name: Install Node.js dependencies
run: npm ci run: npm ci
- name: Run tests - name: Run tests

View File

@ -7,10 +7,50 @@ on:
branches: branches:
- main # Trigger on push events to the main branch - main # Trigger on push events to the main branch
- beta # Trigger on push events to the beta branch - beta # Trigger on push events to the beta branch
# go upvote https://github.com/actions/runner/issues/1182 and yell at microsoft until they fix this or ditch yml for workflows
paths:
# src and test files
- "src/**"
- "test/**"
- "public/**"
# Workflows that can impact tests
- ".github/workflows/test*.yml"
# top-level files
- "package*.json"
- ".nvrmc" # Updates to node version can break tests
- "vite.*.ts" # vite.config.ts, vite.vitest.config.ts, vitest.workspace.ts
- "tsconfig*.json" # tsconfig.json tweaking can impact compilation
- "global.d.ts"
- ".env.*"
# Blanket negations for files that cannot impact tests
- "!**/*.py" # No .py files
- "!**/*.sh" # No .sh files
- "!**/*.md" # No .md files
- "!**/.git*" # .gitkeep and family
pull_request: pull_request:
branches: branches:
- main # Trigger on pull request events targeting the main branch - main # Trigger on pull request events targeting the main branch
- beta # Trigger on pull request events targeting the beta branch - beta # Trigger on pull request events targeting the beta branch
paths: # go upvote https://github.com/actions/runner/issues/1182 and yell at microsoft because until then we have to duplicate this
# src and test files
- "src/**"
- "test/**"
- "public/**"
# Workflows that can impact tests
- ".github/workflows/test*.yml"
# top-level files
- "package*.json"
- ".nvrmc" # Updates to node version can break tests
- "vite*" # vite.config.ts, vite.vitest.config.ts, vitest.workspace.ts
- "tsconfig*.json" # tsconfig.json tweaking can impact compilation
- "global.d.ts"
- ".env.*"
# Blanket negations for files that cannot impact tests
- "!**/*.py" # No .py files
- "!**/*.sh" # No .sh files
- "!**/*.md" # No .md files
- "!**/.git*" # .gitkeep and family
merge_group: merge_group:
types: [checks_requested] types: [checks_requested]

2
.nvmrc
View File

@ -1 +1 @@
v20.13.1 v22.14.0

View File

@ -12,7 +12,7 @@ If you have the motivation and experience with Typescript/Javascript (or are wil
#### Prerequisites #### Prerequisites
- node: 20.13.1 - node: 22.14.0
- npm: [how to install](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) - npm: [how to install](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)
#### Running Locally #### Running Locally

View File

@ -31,7 +31,7 @@
"src/overrides.ts", "src/overrides.ts",
// TODO: these files are too big and complex, ignore them until their respective refactors // TODO: these files are too big and complex, ignore them until their respective refactors
"src/data/moves/move.ts", "src/data/moves/move.ts",
"src/data/ability.ts", "src/data/abilities/ability.ts",
"src/field/pokemon.ts", "src/field/pokemon.ts",
// this file is just too big: // this file is just too big:
@ -65,7 +65,8 @@
"useDefaultParameterLast": "off", // TODO: Fix spots in the codebase where this flag would be triggered, and then enable "useDefaultParameterLast": "off", // TODO: Fix spots in the codebase where this flag would be triggered, and then enable
"useSingleVarDeclarator": "off", "useSingleVarDeclarator": "off",
"useNodejsImportProtocol": "off", "useNodejsImportProtocol": "off",
"useTemplate": "off" // string concatenation is faster: https://stackoverflow.com/questions/29055518/are-es6-template-literals-faster-than-string-concatenation "useTemplate": "off", // string concatenation is faster: https://stackoverflow.com/questions/29055518/are-es6-template-literals-faster-than-string-concatenation
"noNamespaceImport": "error"
}, },
"suspicious": { "suspicious": {
"noDoubleEquals": "error", "noDoubleEquals": "error",
@ -99,6 +100,9 @@
"rules": { "rules": {
"performance": { "performance": {
"noDelete": "off" "noDelete": "off"
},
"style": {
"noNamespaceImport": "off"
} }
} }
} }

1621
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
{ {
"name": "pokemon-rogue-battle", "name": "pokemon-rogue-battle",
"private": true, "private": true,
"version": "1.7.7", "version": "1.8.4",
"type": "module", "type": "module",
"scripts": { "scripts": {
"start": "vite", "start": "vite",
@ -33,7 +33,7 @@
"@hpcc-js/wasm": "^2.22.4", "@hpcc-js/wasm": "^2.22.4",
"@stylistic/eslint-plugin-ts": "^4.1.0", "@stylistic/eslint-plugin-ts": "^4.1.0",
"@types/jsdom": "^21.1.7", "@types/jsdom": "^21.1.7",
"@types/node": "^20.12.13", "@types/node": "^22.13.14",
"@typescript-eslint/eslint-plugin": "^8.28.0", "@typescript-eslint/eslint-plugin": "^8.28.0",
"@typescript-eslint/parser": "^8.28.0", "@typescript-eslint/parser": "^8.28.0",
"@vitest/coverage-istanbul": "^3.0.9", "@vitest/coverage-istanbul": "^3.0.9",
@ -55,6 +55,7 @@
}, },
"dependencies": { "dependencies": {
"@material/material-color-utilities": "^0.2.7", "@material/material-color-utilities": "^0.2.7",
"compare-versions": "^6.1.1",
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"i18next": "^24.2.2", "i18next": "^24.2.2",
"i18next-browser-languagedetector": "^8.0.4", "i18next-browser-languagedetector": "^8.0.4",
@ -63,9 +64,9 @@
"json-stable-stringify": "^1.2.0", "json-stable-stringify": "^1.2.0",
"jszip": "^3.10.1", "jszip": "^3.10.1",
"phaser": "^3.88.2", "phaser": "^3.88.2",
"phaser3-rex-plugins": "^1.80.14" "phaser3-rex-plugins": "^1.80.15"
}, },
"engines": { "engines": {
"node": ">=20.0.0" "node": ">=22.0.0"
} }
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -0,0 +1,656 @@
{
"3-mega": [0, 2, 2],
"6-mega-x": [0, 2, 2],
"6-mega-y": [0, 2, 2],
"80-mega": [0, 1, 1],
"94-mega": [2, 2, 2],
"127-mega": [0, 1, 1],
"130-mega": [0, 1, 1],
"142-mega": [0, 1, 1],
"150-mega-x": [0, 1, 1],
"150-mega-y": [0, 1, 1],
"181-mega": [0, 1, 2],
"212-mega": [1, 1, 2],
"229-mega": [0, 1, 1],
"248-mega": [0, 1, 1],
"257-mega": [0, 1, 1],
"282-mega": [0, 2, 2],
"302-mega": [0, 1, 1],
"303-mega": [0, 1, 1],
"306-mega": [1, 1, 1],
"308-mega": [0, 1, 1],
"310-mega": [0, 1, 1],
"334-mega": [0, 2, 1],
"354-mega": [0, 1, 1],
"359-mega": [0, 1, 1],
"362-mega": [0, 1, 1],
"373-mega": [0, 1, 1],
"376-mega": [0, 1, 1],
"380-mega": [0, 1, 1],
"381-mega": [0, 1, 1],
"382-primal": [0, 1, 1],
"383-primal": [0, 1, 1],
"384-mega": [0, 2, 1],
"428-mega": [0, 1, 1],
"445-mega": [1, 1, 1],
"448-mega": [1, 1, 1],
"475-mega": [0, 2, 2],
"531-mega": [0, 1, 1],
"653": [0, 1, 1],
"654": [0, 1, 1],
"655": [0, 1, 1],
"656": [0, 1, 1],
"657": [0, 1, 1],
"658": [0, 1, 1],
"658-ash": [0, 1, 1],
"664": [0, 1, 1],
"665": [0, 1, 1],
"666-archipelago": [0, 1, 1],
"666-continental": [0, 1, 1],
"666-elegant": [0, 1, 1],
"666-fancy": [0, 1, 1],
"666-garden": [0, 1, 1],
"666-high-plains": [0, 1, 1],
"666-icy-snow": [0, 1, 1],
"666-jungle": [0, 1, 1],
"666-marine": [0, 1, 1],
"666-meadow": [0, 1, 1],
"666-modern": [0, 1, 1],
"666-monsoon": [0, 1, 1],
"666-ocean": [0, 1, 1],
"666-poke-ball": [0, 1, 1],
"666-polar": [0, 1, 1],
"666-river": [0, 1, 1],
"666-sandstorm": [0, 1, 1],
"666-savanna": [0, 1, 1],
"666-sun": [0, 1, 1],
"666-tundra": [0, 1, 1],
"669-red": [0, 2, 2],
"669-blue": [0, 1, 1],
"669-white": [0, 1, 1],
"669-yellow": [0, 1, 1],
"669-orange": [0, 2, 2],
"670-white": [0, 1, 1],
"670-blue": [0, 1, 1],
"670-orange": [0, 1, 1],
"670-red": [0, 1, 1],
"670-yellow": [0, 1, 1],
"671-red": [0, 1, 2],
"671-blue": [0, 1, 2],
"671-yellow": [0, 1, 1],
"671-white": [0, 1, 2],
"671-orange": [0, 1, 2],
"672": [0, 1, 1],
"673": [0, 1, 1],
"676": [0, 1, 1],
"677": [0, 1, 1],
"678-female": [0, 1, 1],
"678": [0, 1, 1],
"682": [0, 1, 1],
"683": [0, 1, 1],
"684": [0, 1, 1],
"685": [0, 1, 1],
"688": [0, 1, 1],
"689": [0, 1, 1],
"690": [0, 1, 1],
"691": [0, 1, 1],
"696": [0, 1, 1],
"697": [0, 1, 1],
"699": [0, 1, 1],
"700": [0, 1, 1],
"702": [0, 1, 1],
"704": [0, 1, 1],
"705": [0, 1, 1],
"706": [0, 1, 1],
"709": [0, 1, 1],
"710": [0, 1, 1],
"711": [1, 1, 1],
"712": [0, 1, 1],
"713": [0, 1, 1],
"715": [0, 1, 1],
"716-active": [0, 1, 1],
"716-neutral": [0, 1, 1],
"717": [0, 2, 2],
"720-unbound": [1, 1, 1],
"720": [1, 1, 1],
"728": [0, 1, 1],
"729": [0, 1, 1],
"730": [0, 1, 1],
"734": [0, 1, 1],
"735": [0, 1, 1],
"742": [0, 2, 2],
"743": [0, 2, 2],
"747": [0, 2, 2],
"748": [0, 1, 1],
"751": [0, 1, 1],
"752": [0, 1, 1],
"753": [0, 1, 1],
"754": [0, 2, 2],
"755": [0, 1, 1],
"756": [0, 1, 1],
"761": [0, 1, 1],
"762": [0, 1, 1],
"763": [0, 1, 1],
"767": [0, 1, 1],
"768": [0, 1, 1],
"770": [0, 0, 0],
"771": [0, 2, 2],
"772": [0, 1, 1],
"773-fighting": [0, 1, 1],
"773-psychic": [0, 1, 1],
"773-poison": [0, 1, 1],
"773-ground": [0, 1, 1],
"773-ghost": [0, 1, 1],
"773-steel": [0, 1, 1],
"773-rock": [0, 1, 1],
"773-grass": [0, 1, 1],
"773-dragon": [0, 1, 1],
"773-bug": [0, 1, 1],
"773-ice": [0, 1, 1],
"773-dark": [0, 1, 1],
"773": [0, 1, 1],
"773-fairy": [0, 1, 1],
"773-water": [0, 1, 1],
"773-electric": [0, 1, 1],
"773-flying": [0, 1, 1],
"773-fire": [0, 1, 1],
"776": [0, 1, 1],
"777": [0, 1, 1],
"778-busted": [0, 1, 1],
"778-disguised": [0, 1, 1],
"779": [0, 1, 1],
"789": [1, 1, 1],
"790": [0, 1, 1],
"791": [2, 1, 1],
"792": [0, 1, 1],
"793": [0, 2, 2],
"797": [0, 1, 1],
"798": [0, 1, 1],
"800-dawn-wings": [0, 1, 1],
"800-dusk-mane": [0, 1, 1],
"800-ultra": [0, 1, 1],
"800": [0, 1, 1],
"802": [1, 1, 1],
"803": [0, 1, 1],
"804": [0, 1, 1],
"807": [0, 1, 1],
"808": [0, 1, 1],
"809": [0, 1, 1],
"816": [0, 1, 1],
"817": [0, 1, 1],
"818": [1, 1, 1],
"821": [0, 2, 2],
"822": [0, 1, 1],
"823": [0, 1, 1],
"829": [0, 1, 1],
"830": [0, 1, 1],
"835": [0, 1, 1],
"836": [0, 2, 2],
"850": [0, 1, 1],
"851": [0, 1, 1],
"854": [0, 1, 1],
"855": [0, 1, 1],
"856": [0, 1, 1],
"857": [0, 2, 2],
"858": [0, 1, 1],
"859": [0, 1, 1],
"860": [0, 1, 1],
"861": [0, 1, 1],
"862": [0, 1, 1],
"863": [0, 1, 1],
"864": [0, 1, 1],
"867": [0, 1, 1],
"872": [1, 1, 1],
"873": [1, 1, 1],
"876-female": [0, 1, 1],
"876": [0, 1, 1],
"877-hangry": [1, 1, 1],
"877": [1, 1, 1],
"880": [0, 1, 1],
"881": [0, 1, 1],
"882": [0, 2, 1],
"883": [0, 1, 1],
"884": [0, 1, 1],
"885": [1, 1, 1],
"886": [1, 1, 1],
"887": [1, 1, 1],
"888": [0, 1, 1],
"888-crowned": [0, 1, 1],
"889": [0, 1, 1],
"889-crowned": [0, 1, 1],
"890": [0, 2, 1],
"890-eternamax": [0, 1, 1],
"891": [1, 1, 1],
"892-rapid-strike": [1, 1, 1],
"892": [1, 1, 1],
"894": [0, 1, 1],
"895": [0, 1, 1],
"896": [1, 1, 1],
"897": [1, 1, 1],
"898": [1, 1, 1],
"898-ice": [1, 1, 1],
"898-shadow": [1, 1, 1],
"900": [0, 1, 1],
"901": [0, 1, 1],
"903": [0, 1, 1],
"909": [0, 1, 1],
"910": [0, 2, 2],
"911": [0, 2, 2],
"912": [0, 1, 2],
"913": [0, 1, 2],
"914": [0, 2, 1],
"919": [1, 1, 1],
"920": [1, 1, 1],
"924": [1, 1, 1],
"925-four": [1, 2, 2],
"925-three": [1, 2, 2],
"932": [0, 2, 2],
"933": [0, 2, 2],
"934": [0, 1, 1],
"935": [1, 1, 2],
"936": [2, 2, 2],
"937": [2, 2, 2],
"940": [0, 1, 1],
"941": [0, 1, 1],
"944": [0, 1, 1],
"945": [0, 1, 1],
"948": [0, 1, 1],
"949": [0, 1, 1],
"951": [0, 1, 1],
"952": [0, 1, 1],
"953": [0, 1, 1],
"954": [0, 1, 1],
"957": [2, 2, 2],
"958": [2, 2, 2],
"959": [2, 2, 2],
"962": [1, 1, 1],
"967": [0, 1, 1],
"968": [0, 1, 1],
"969": [0, 1, 1],
"970": [0, 1, 1],
"973": [1, 1, 1],
"974": [0, 1, 1],
"975": [0, 1, 1],
"978-curly": [0, 2, 2],
"978-droopy": [0, 2, 2],
"978-stretchy": [0, 2, 2],
"979": [2, 2, 2],
"981": [0, 1, 1],
"982": [0, 1, 1],
"982-three-segment": [0, 1, 1],
"987": [1, 1, 1],
"988": [0, 1, 2],
"993": [0, 1, 1],
"994": [0, 1, 2],
"995": [0, 1, 1],
"996": [0, 1, 1],
"997": [0, 2, 2],
"998": [0, 2, 2],
"999": [2, 1, 1],
"1000": [1, 1, 1],
"1001": [0, 1, 1],
"1003": [0, 1, 1],
"1004": [0, 1, 1],
"1006": [0, 2, 1],
"1007-apex-build": [0, 2, 2],
"1008-ultimate-mode": [1, 1, 1],
"2026": [0, 1, 1],
"2027": [0, 1, 1],
"2028": [0, 1, 1],
"2052": [0, 1, 1],
"2053": [0, 1, 0],
"2103": [0, 1, 1],
"4052": [0, 1, 1],
"4077": [0, 1, 1],
"4078": [0, 1, 1],
"4079": [0, 1, 1],
"4080": [2, 1, 1],
"4144": [0, 1, 1],
"4145": [0, 1, 1],
"4146": [0, 1, 1],
"4199": [2, 1, 1],
"4222": [0, 1, 1],
"4263": [0, 1, 1],
"4264": [0, 1, 1],
"4562": [0, 1, 1],
"6100": [0, 1, 1],
"6101": [0, 1, 1],
"6215": [0, 1, 1],
"6503": [0, 1, 1],
"6549": [0, 1, 1],
"6570": [0, 1, 1],
"6571": [0, 1, 1],
"6705": [0, 1, 1],
"6706": [0, 1, 1],
"6713": [0, 1, 1],
"female": {
"6215": [0, 1, 1]
},
"back": {
"3-mega": [0, 2, 2],
"6-mega-x": [0, 2, 2],
"6-mega-y": [0, 1, 2],
"80-mega": [0, 1, 1],
"94-mega": [1, 1, 1],
"127-mega": [0, 1, 1],
"130-mega": [0, 1, 1],
"142-mega": [0, 1, 1],
"150-mega-x": [0, 1, 1],
"150-mega-y": [0, 1, 1],
"181-mega": [0, 1, 2],
"212-mega": [1, 2, 2],
"229-mega": [0, 1, 1],
"248-mega": [0, 1, 1],
"257-mega": [0, 1, 1],
"282-mega": [0, 1, 1],
"302-mega": [0, 1, 1],
"303-mega": [0, 1, 1],
"306-mega": [1, 1, 1],
"308-mega": [0, 1, 1],
"310-mega": [0, 1, 1],
"334-mega": [0, 1, 1],
"354-mega": [0, 1, 1],
"359-mega": [0, 1, 1],
"362-mega": [0, 1, 1],
"373-mega": [0, 1, 1],
"376-mega": [0, 1, 1],
"380-mega": [0, 1, 1],
"381-mega": [0, 1, 1],
"382-primal": [0, 1, 1],
"383-primal": [0, 1, 1],
"384-mega": [0, 1, 1],
"428-mega": [0, 1, 1],
"445-mega": [1, 1, 1],
"448-mega": [1, 1, 1],
"475-mega": [0, 2, 2],
"531-mega": [0, 1, 1],
"653": [0, 1, 1],
"654": [0, 1, 1],
"655": [0, 1, 1],
"656": [0, 1, 1],
"657": [0, 1, 1],
"658": [0, 1, 1],
"658-ash": [0, 1, 1],
"664": [0, 1, 1],
"665": [0, 1, 1],
"666-archipelago": [0, 1, 1],
"666-continental": [0, 1, 1],
"666-elegant": [0, 1, 1],
"666-fancy": [0, 1, 1],
"666-garden": [0, 1, 1],
"666-high-plains": [0, 1, 1],
"666-icy-snow": [0, 1, 1],
"666-jungle": [0, 1, 1],
"666-marine": [0, 1, 1],
"666-meadow": [0, 1, 1],
"666-modern": [0, 1, 1],
"666-monsoon": [0, 1, 1],
"666-ocean": [0, 1, 1],
"666-poke-ball": [0, 1, 1],
"666-polar": [0, 1, 1],
"666-river": [0, 1, 1],
"666-sandstorm": [0, 1, 1],
"666-savanna": [0, 1, 1],
"666-sun": [0, 1, 1],
"666-tundra": [0, 1, 1],
"669-red": [0, 2, 2],
"669-blue": [0, 2, 2],
"669-white": [0, 2, 2],
"669-yellow": [0, 2, 2],
"669-orange": [0, 2, 2],
"670-white": [0, 1, 1],
"670-blue": [0, 2, 2],
"670-orange": [0, 1, 1],
"670-red": [0, 1, 1],
"670-yellow": [0, 1, 1],
"671-red": [0, 1, 1],
"671-blue": [0, 1, 1],
"671-yellow": [0, 1, 1],
"671-white": [0, 1, 1],
"671-orange": [0, 1, 1],
"672": [0, 1, 1],
"673": [0, 1, 1],
"676": [0, 1, 1],
"677": [0, 1, 1],
"678-female": [0, 1, 1],
"678": [0, 1, 1],
"682": [0, 1, 1],
"683": [0, 1, 1],
"684": [0, 1, 1],
"685": [0, 1, 1],
"688": [0, 1, 1],
"689": [0, 1, 1],
"690": [0, 1, 1],
"691": [0, 1, 1],
"696": [0, 1, 1],
"697": [0, 1, 1],
"699": [0, 2, 2],
"700": [0, 1, 1],
"702": [0, 1, 1],
"704": [0, 1, 1],
"705": [0, 1, 1],
"706": [0, 1, 1],
"709": [0, 1, 1],
"710": [0, 1, 1],
"711": [1, 1, 1],
"712": [0, 1, 1],
"713": [0, 1, 1],
"715": [0, 1, 1],
"716-active": [0, 1, 1],
"716-neutral": [0, 1, 1],
"717": [0, 1, 1],
"720-unbound": [1, 1, 1],
"720": [1, 1, 1],
"728": [0, 1, 1],
"729": [0, 1, 1],
"730": [0, 1, 1],
"734": [0, 1, 1],
"735": [0, 1, 1],
"742": [0, 2, 2],
"743": [0, 2, 2],
"747": [0, 2, 2],
"748": [0, 1, 1],
"751": [0, 1, 1],
"752": [0, 1, 1],
"753": [0, 1, 1],
"754": [0, 2, 2],
"755": [0, 1, 1],
"756": [0, 1, 1],
"761": [0, 1, 1],
"762": [0, 1, 1],
"763": [0, 1, 1],
"767": [0, 1, 1],
"768": [0, 1, 1],
"771": [0, 1, 1],
"772": [0, 1, 1],
"773-fighting": [0, 1, 1],
"773-psychic": [0, 1, 1],
"773-poison": [0, 1, 1],
"773-ground": [0, 1, 1],
"773-ghost": [0, 1, 1],
"773-steel": [0, 1, 1],
"773-rock": [0, 1, 1],
"773-grass": [0, 1, 1],
"773-dragon": [0, 1, 1],
"773-bug": [0, 1, 1],
"773-ice": [0, 1, 1],
"773-dark": [0, 1, 1],
"773": [0, 1, 1],
"773-fairy": [0, 1, 1],
"773-water": [0, 1, 1],
"773-electric": [0, 1, 1],
"773-flying": [0, 1, 1],
"773-fire": [0, 1, 1],
"776": [0, 2, 2],
"777": [0, 1, 1],
"778-busted": [0, 1, 1],
"778-disguised": [0, 1, 1],
"779": [0, 1, 1],
"789": [1, 1, 1],
"790": [0, 1, 1],
"791": [1, 1, 1],
"792": [0, 1, 1],
"793": [0, 1, 1],
"797": [0, 1, 1],
"798": [0, 1, 1],
"800-dawn-wings": [0, 1, 1],
"800-dusk-mane": [0, 1, 1],
"800-ultra": [0, 1, 1],
"800": [0, 1, 1],
"802": [1, 1, 1],
"803": [0, 1, 1],
"804": [0, 1, 1],
"807": [0, 1, 1],
"808": [0, 1, 1],
"809": [0, 1, 1],
"816": [0, 1, 1],
"817": [0, 1, 1],
"818": [0, 1, 1],
"821": [0, 1, 1],
"822": [0, 1, 1],
"823": [0, 1, 1],
"829": [0, 1, 1],
"830": [0, 1, 1],
"835": [0, 1, 1],
"836": [0, 1, 1],
"850": [0, 1, 1],
"851": [0, 1, 1],
"854": [0, 1, 1],
"855": [0, 1, 1],
"856": [0, 1, 1],
"857": [0, 2, 2],
"858": [0, 1, 1],
"859": [0, 1, 1],
"860": [0, 1, 1],
"861": [0, 1, 1],
"862": [0, 1, 1],
"863": [0, 1, 1],
"864": [0, 1, 1],
"867": [0, 1, 1],
"872": [1, 1, 1],
"873": [1, 1, 1],
"876-female": [0, 1, 1],
"876": [0, 1, 1],
"877-hangry": [1, 1, 1],
"877": [1, 1, 1],
"880": [0, 1, 1],
"881": [0, 1, 1],
"882": [0, 1, 1],
"883": [0, 1, 1],
"884": [0, 1, 1],
"885": [1, 1, 1],
"886": [1, 1, 1],
"887": [1, 1, 1],
"888": [0, 1, 1],
"888-crowned": [0, 1, 1],
"889": [0, 1, 1],
"889-crowned": [0, 1, 1],
"890": [0, 1, 1],
"891": [1, 1, 1],
"892-rapid-strike": [1, 1, 1],
"892": [1, 1, 1],
"894": [0, 1, 1],
"895": [0, 1, 1],
"896": [1, 1, 1],
"897": [1, 1, 1],
"898": [1, 1, 1],
"898-ice": [1, 1, 1],
"898-shadow": [1, 1, 1],
"900": [0, 1, 1],
"901": [0, 1, 1],
"903": [0, 1, 1],
"909": [0, 1, 1],
"910": [0, 2, 2],
"911": [0, 1, 1],
"912": [0, 1, 1],
"913": [0, 1, 1],
"914": [0, 2, 2],
"919": [1, 1, 1],
"920": [1, 1, 1],
"924": [1, 1, 1],
"925-four": [1, 2, 2],
"925-three": [1, 2, 2],
"932": [0, 1, 1],
"933": [0, 1, 1],
"934": [0, 1, 1],
"935": [2, 2, 2],
"936": [2, 2, 2],
"937": [2, 2, 2],
"940": [0, 1, 1],
"941": [0, 1, 1],
"944": [0, 1, 1],
"945": [0, 1, 1],
"948": [0, 1, 1],
"949": [0, 1, 1],
"951": [0, 1, 1],
"952": [0, 2, 1],
"953": [0, 1, 1],
"954": [0, 1, 1],
"957": [1, 1, 1],
"958": [1, 1, 1],
"959": [1, 1, 1],
"962": [1, 1, 1],
"967": [0, 1, 1],
"968": [0, 2, 2],
"969": [0, 1, 1],
"970": [0, 1, 1],
"973": [1, 1, 1],
"974": [0, 1, 1],
"975": [0, 1, 1],
"978-curly": [0, 2, 2],
"978-droopy": [0, 2, 2],
"978-stretchy": [0, 1, 1],
"979": [1, 1, 1],
"981": [0, 1, 1],
"982": [0, 1, 1],
"982-three-segment": [0, 1, 1],
"987": [1, 1, 1],
"988": [0, 1, 1],
"993": [0, 1, 1],
"994": [0, 1, 1],
"995": [0, 1, 1],
"996": [0, 1, 1],
"997": [0, 1, 1],
"998": [0, 1, 1],
"999": [1, 1, 1],
"1000": [1, 1, 1],
"1001": [0, 1, 1],
"1003": [0, 1, 1],
"1004": [0, 1, 1],
"1006": [0, 2, 2],
"1007-apex-build": [0, 2, 2],
"1008-ultimate-mode": [1, 1, 1],
"2026": [0, 1, 1],
"2027": [0, 1, 1],
"2028": [0, 1, 1],
"2052": [0, 1, 1],
"2053": [0, 1, 1],
"2103": [0, 1, 1],
"4052": [0, 1, 1],
"4077": [0, 1, 1],
"4078": [0, 1, 1],
"4079": [0, 1, 1],
"4080": [2, 2, 2],
"4144": [0, 1, 1],
"4145": [0, 1, 1],
"4146": [0, 1, 1],
"4199": [2, 1, 1],
"4222": [0, 1, 1],
"4263": [0, 1, 1],
"4264": [0, 1, 1],
"4562": [0, 1, 1],
"6100": [0, 1, 1],
"6101": [0, 1, 1],
"6215": [0, 1, 1],
"6503": [0, 1, 1],
"6549": [0, 1, 1],
"6570": [0, 1, 1],
"6571": [0, 1, 1],
"6705": [0, 1, 1],
"6706": [0, 1, 1],
"6713": [0, 1, 1],
"female": {
"6215": [0, 1, 1]
}
}
}

View File

@ -1813,669 +1813,5 @@
"593": [1, 1, 1], "593": [1, 1, 1],
"6215": [0, 1, 1] "6215": [0, 1, 1]
} }
},
"exp": {
"3-mega": [0, 2, 2],
"6-mega-x": [0, 2, 2],
"6-mega-y": [0, 2, 2],
"80-mega": [0, 1, 1],
"94-mega": [2, 2, 2],
"127-mega": [0, 1, 1],
"130-mega": [0, 1, 1],
"142-mega": [0, 1, 1],
"150-mega-x": [0, 1, 1],
"150-mega-y": [0, 1, 1],
"181-mega": [0, 1, 2],
"212-mega": [1, 1, 2],
"229-mega": [0, 1, 1],
"248-mega": [0, 1, 1],
"257-mega": [0, 1, 1],
"282-mega": [0, 2, 2],
"302-mega": [0, 1, 1],
"303-mega": [0, 1, 1],
"306-mega": [1, 1, 1],
"308-mega": [0, 1, 1],
"310-mega": [0, 1, 1],
"334-mega": [0, 2, 1],
"354-mega": [0, 1, 1],
"359-mega": [0, 1, 1],
"362-mega": [0, 1, 1],
"373-mega": [0, 1, 1],
"376-mega": [0, 1, 1],
"380-mega": [0, 1, 1],
"381-mega": [0, 1, 1],
"382-primal": [0, 1, 1],
"383-primal": [0, 1, 1],
"384-mega": [0, 2, 1],
"428-mega": [0, 1, 1],
"445-mega": [1, 1, 1],
"448-mega": [1, 1, 1],
"475-mega": [0, 2, 2],
"531-mega": [0, 1, 1],
"653": [0, 1, 1],
"654": [0, 1, 1],
"655": [0, 1, 1],
"656": [0, 1, 1],
"657": [0, 1, 1],
"658": [0, 1, 1],
"658-ash": [0, 1, 1],
"664": [0, 1, 1],
"665": [0, 1, 1],
"666-archipelago": [0, 1, 1],
"666-continental": [0, 1, 1],
"666-elegant": [0, 1, 1],
"666-fancy": [0, 1, 1],
"666-garden": [0, 1, 1],
"666-high-plains": [0, 1, 1],
"666-icy-snow": [0, 1, 1],
"666-jungle": [0, 1, 1],
"666-marine": [0, 1, 1],
"666-meadow": [0, 1, 1],
"666-modern": [0, 1, 1],
"666-monsoon": [0, 1, 1],
"666-ocean": [0, 1, 1],
"666-poke-ball": [0, 1, 1],
"666-polar": [0, 1, 1],
"666-river": [0, 1, 1],
"666-sandstorm": [0, 1, 1],
"666-savanna": [0, 1, 1],
"666-sun": [0, 1, 1],
"666-tundra": [0, 1, 1],
"669-red": [0, 2, 2],
"669-blue": [0, 1, 1],
"669-white": [0, 1, 1],
"669-yellow": [0, 1, 1],
"669-orange": [0, 2, 2],
"670-white": [0, 1, 1],
"670-blue": [0, 1, 1],
"670-orange": [0, 1, 1],
"670-red": [0, 1, 1],
"670-yellow": [0, 1, 1],
"671-red": [0, 1, 2],
"671-blue": [0, 1, 2],
"671-yellow": [0, 1, 1],
"671-white": [0, 1, 2],
"671-orange": [0, 1, 2],
"672": [0, 1, 1],
"673": [0, 1, 1],
"676": [0, 1, 1],
"677": [0, 1, 1],
"678-female": [0, 1, 1],
"678": [0, 1, 1],
"682": [0, 1, 1],
"683": [0, 1, 1],
"684": [0, 1, 1],
"685": [0, 1, 1],
"688": [0, 1, 1],
"689": [0, 1, 1],
"690": [0, 1, 1],
"691": [0, 1, 1],
"696": [0, 1, 1],
"697": [0, 1, 1],
"698": [0, 1, 1],
"699": [0, 1, 1],
"700": [0, 1, 1],
"702": [0, 1, 1],
"703": [0, 1, 1],
"704": [0, 1, 1],
"705": [0, 1, 1],
"706": [0, 1, 1],
"708": [0, 1, 1],
"709": [0, 1, 1],
"710": [0, 1, 1],
"711": [1, 1, 1],
"712": [0, 1, 1],
"713": [0, 1, 1],
"714": [0, 1, 1],
"715": [0, 1, 1],
"716-active": [0, 1, 1],
"716-neutral": [0, 1, 1],
"717": [0, 2, 2],
"720-unbound": [1, 1, 1],
"720": [1, 1, 1],
"728": [0, 1, 1],
"729": [0, 1, 1],
"730": [0, 1, 1],
"734": [0, 1, 1],
"735": [0, 1, 1],
"742": [0, 2, 2],
"743": [0, 2, 2],
"747": [0, 2, 2],
"748": [0, 1, 1],
"751": [0, 1, 1],
"752": [0, 1, 1],
"753": [0, 1, 1],
"754": [0, 2, 2],
"755": [0, 1, 1],
"756": [0, 1, 1],
"761": [0, 1, 1],
"762": [0, 1, 1],
"763": [0, 1, 1],
"767": [0, 1, 1],
"768": [0, 1, 1],
"770": [0, 0, 0],
"771": [0, 2, 2],
"772": [0, 1, 1],
"773-fighting": [0, 1, 1],
"773-psychic": [0, 1, 1],
"773-poison": [0, 1, 1],
"773-ground": [0, 1, 1],
"773-ghost": [0, 1, 1],
"773-steel": [0, 1, 1],
"773-rock": [0, 1, 1],
"773-grass": [0, 1, 1],
"773-dragon": [0, 1, 1],
"773-bug": [0, 1, 1],
"773-ice": [0, 1, 1],
"773-dark": [0, 1, 1],
"773": [0, 1, 1],
"773-fairy": [0, 1, 1],
"773-water": [0, 1, 1],
"773-electric": [0, 1, 1],
"773-flying": [0, 1, 1],
"773-fire": [0, 1, 1],
"776": [0, 1, 1],
"777": [0, 1, 1],
"778-busted": [0, 1, 1],
"778-disguised": [0, 1, 1],
"779": [0, 1, 1],
"789": [1, 1, 1],
"790": [0, 1, 1],
"791": [2, 1, 1],
"792": [0, 1, 1],
"793": [0, 2, 2],
"797": [0, 1, 1],
"798": [0, 1, 1],
"800-dawn-wings": [0, 1, 1],
"800-dusk-mane": [0, 1, 1],
"800-ultra": [0, 1, 1],
"800": [0, 1, 1],
"802": [1, 1, 1],
"803": [0, 1, 1],
"804": [0, 1, 1],
"807": [0, 1, 1],
"808": [0, 1, 1],
"809": [0, 1, 1],
"816": [0, 1, 1],
"817": [0, 1, 1],
"818": [1, 1, 1],
"821": [0, 2, 2],
"822": [0, 1, 1],
"823": [0, 1, 1],
"829": [0, 1, 1],
"830": [0, 1, 1],
"835": [0, 1, 1],
"836": [0, 2, 2],
"850": [0, 1, 1],
"851": [0, 1, 1],
"854": [0, 1, 1],
"855": [0, 1, 1],
"856": [0, 1, 1],
"857": [0, 2, 2],
"858": [0, 1, 1],
"859": [0, 1, 1],
"860": [0, 1, 1],
"861": [0, 1, 1],
"862": [0, 1, 1],
"863": [0, 1, 1],
"864": [0, 1, 1],
"867": [0, 1, 1],
"872": [1, 1, 1],
"873": [1, 1, 1],
"876-female": [0, 1, 1],
"876": [0, 1, 1],
"877-hangry": [1, 1, 1],
"877": [1, 1, 1],
"880": [0, 1, 1],
"881": [0, 1, 1],
"882": [0, 2, 1],
"883": [0, 1, 1],
"884": [0, 1, 1],
"885": [1, 1, 1],
"886": [1, 1, 1],
"887": [1, 1, 1],
"888": [0, 1, 1],
"888-crowned": [0, 1, 1],
"889": [0, 1, 1],
"889-crowned": [0, 1, 1],
"890": [0, 2, 1],
"890-eternamax": [0, 1, 1],
"891": [1, 1, 1],
"892-rapid-strike": [1, 1, 1],
"892": [1, 1, 1],
"894": [0, 1, 1],
"895": [0, 1, 1],
"896": [1, 1, 1],
"897": [1, 1, 1],
"898": [1, 1, 1],
"898-ice": [1, 1, 1],
"898-shadow": [1, 1, 1],
"900": [0, 1, 1],
"901": [0, 1, 1],
"903": [0, 1, 1],
"909": [0, 1, 1],
"910": [0, 2, 2],
"911": [0, 2, 2],
"912": [0, 1, 2],
"913": [0, 1, 2],
"914": [0, 2, 1],
"919": [1, 1, 1],
"920": [1, 1, 1],
"924": [1, 1, 1],
"925-four": [1, 2, 2],
"925-three": [1, 2, 2],
"932": [0, 2, 2],
"933": [0, 2, 2],
"934": [0, 1, 1],
"935": [1, 1, 2],
"936": [2, 2, 2],
"937": [2, 2, 2],
"940": [0, 1, 1],
"941": [0, 1, 1],
"944": [0, 1, 1],
"945": [0, 1, 1],
"948": [0, 1, 1],
"949": [0, 1, 1],
"951": [0, 1, 1],
"952": [0, 1, 1],
"953": [0, 1, 1],
"954": [0, 1, 1],
"957": [2, 2, 2],
"958": [2, 2, 2],
"959": [2, 2, 2],
"962": [1, 1, 1],
"967": [0, 1, 1],
"968": [0, 1, 1],
"969": [0, 1, 1],
"970": [0, 1, 1],
"973": [1, 1, 1],
"974": [0, 1, 1],
"975": [0, 1, 1],
"978-curly": [0, 2, 2],
"978-droopy": [0, 2, 2],
"978-stretchy": [0, 2, 2],
"979": [2, 2, 2],
"981": [0, 1, 1],
"982": [0, 1, 1],
"982-three-segment": [0, 1, 1],
"987": [1, 1, 1],
"988": [0, 1, 2],
"993": [0, 1, 1],
"994": [0, 1, 2],
"995": [0, 1, 1],
"996": [0, 1, 1],
"997": [0, 2, 2],
"998": [0, 2, 2],
"999": [2, 1, 1],
"1000": [1, 1, 1],
"1001": [0, 1, 1],
"1003": [0, 1, 1],
"1004": [0, 1, 1],
"1006": [0, 2, 1],
"1007-apex-build": [0, 2, 2],
"1008-ultimate-mode": [1, 1, 1],
"2026": [0, 1, 1],
"2027": [0, 1, 1],
"2028": [0, 1, 1],
"2052": [0, 1, 1],
"2053": [0, 1, 0],
"2103": [0, 1, 1],
"4052": [0, 1, 1],
"4077": [0, 1, 1],
"4078": [0, 1, 1],
"4079": [0, 1, 1],
"4080": [2, 1, 1],
"4144": [0, 1, 1],
"4145": [0, 1, 1],
"4146": [0, 1, 1],
"4199": [2, 1, 1],
"4222": [0, 1, 1],
"4263": [0, 1, 1],
"4264": [0, 1, 1],
"4562": [0, 1, 1],
"6100": [0, 1, 1],
"6101": [0, 1, 1],
"6215": [0, 1, 1],
"6503": [0, 1, 1],
"6549": [0, 1, 1],
"6570": [0, 1, 1],
"6571": [0, 1, 1],
"6705": [0, 1, 1],
"6706": [0, 1, 1],
"6713": [0, 1, 1],
"female": {
"6215": [0, 1, 1]
},
"back": {
"3-mega": [0, 2, 2],
"6-mega-x": [0, 2, 2],
"6-mega-y": [0, 1, 2],
"80-mega": [0, 1, 1],
"94-mega": [1, 1, 1],
"127-mega": [0, 1, 1],
"130-mega": [0, 1, 1],
"142-mega": [0, 1, 1],
"150-mega-x": [0, 1, 1],
"150-mega-y": [0, 1, 1],
"181-mega": [0, 1, 2],
"212-mega": [1, 2, 2],
"229-mega": [0, 1, 1],
"248-mega": [0, 1, 1],
"257-mega": [0, 1, 1],
"282-mega": [0, 1, 1],
"302-mega": [0, 1, 1],
"303-mega": [0, 1, 1],
"306-mega": [1, 1, 1],
"308-mega": [0, 1, 1],
"310-mega": [0, 1, 1],
"334-mega": [0, 1, 1],
"354-mega": [0, 1, 1],
"359-mega": [0, 1, 1],
"362-mega": [0, 1, 1],
"373-mega": [0, 1, 1],
"376-mega": [0, 1, 1],
"380-mega": [0, 1, 1],
"381-mega": [0, 1, 1],
"382-primal": [0, 1, 1],
"383-primal": [0, 1, 1],
"384-mega": [0, 1, 1],
"428-mega": [0, 1, 1],
"445-mega": [1, 1, 1],
"448-mega": [1, 1, 1],
"475-mega": [0, 2, 2],
"531-mega": [0, 1, 1],
"653": [0, 1, 1],
"654": [0, 1, 1],
"655": [0, 1, 1],
"656": [0, 1, 1],
"657": [0, 1, 1],
"658": [0, 1, 1],
"658-ash": [0, 1, 1],
"664": [0, 1, 1],
"665": [0, 1, 1],
"666-archipelago": [0, 1, 1],
"666-continental": [0, 1, 1],
"666-elegant": [0, 1, 1],
"666-fancy": [0, 1, 1],
"666-garden": [0, 1, 1],
"666-high-plains": [0, 1, 1],
"666-icy-snow": [0, 1, 1],
"666-jungle": [0, 1, 1],
"666-marine": [0, 1, 1],
"666-meadow": [0, 1, 1],
"666-modern": [0, 1, 1],
"666-monsoon": [0, 1, 1],
"666-ocean": [0, 1, 1],
"666-poke-ball": [0, 1, 1],
"666-polar": [0, 1, 1],
"666-river": [0, 1, 1],
"666-sandstorm": [0, 1, 1],
"666-savanna": [0, 1, 1],
"666-sun": [0, 1, 1],
"666-tundra": [0, 1, 1],
"669-red": [0, 2, 2],
"669-blue": [0, 2, 2],
"669-white": [0, 2, 2],
"669-yellow": [0, 2, 2],
"669-orange": [0, 2, 2],
"670-white": [0, 1, 1],
"670-blue": [0, 2, 2],
"670-orange": [0, 1, 1],
"670-red": [0, 1, 1],
"670-yellow": [0, 1, 1],
"671-red": [0, 1, 1],
"671-blue": [0, 1, 1],
"671-yellow": [0, 1, 1],
"671-white": [0, 1, 1],
"671-orange": [0, 1, 1],
"672": [0, 1, 1],
"673": [0, 1, 1],
"676": [0, 1, 1],
"677": [0, 1, 1],
"678-female": [0, 1, 1],
"678": [0, 1, 1],
"682": [0, 1, 1],
"683": [0, 1, 1],
"684": [0, 1, 1],
"685": [0, 1, 1],
"688": [0, 1, 1],
"689": [0, 1, 1],
"690": [0, 1, 1],
"691": [0, 1, 1],
"696": [0, 1, 1],
"697": [0, 1, 1],
"698": [0, 1, 1],
"699": [0, 2, 2],
"700": [0, 1, 1],
"702": [0, 1, 1],
"703": [0, 1, 1],
"704": [0, 1, 1],
"705": [0, 1, 1],
"706": [0, 1, 1],
"708": [0, 1, 1],
"709": [0, 1, 1],
"710": [0, 1, 1],
"711": [1, 1, 1],
"712": [0, 1, 1],
"713": [0, 1, 1],
"714": [0, 1, 1],
"715": [0, 1, 1],
"716-active": [0, 1, 1],
"716-neutral": [0, 1, 1],
"717": [0, 1, 1],
"720-unbound": [1, 1, 1],
"720": [1, 1, 1],
"728": [0, 1, 1],
"729": [0, 1, 1],
"730": [0, 1, 1],
"734": [0, 1, 1],
"735": [0, 1, 1],
"742": [0, 2, 2],
"743": [0, 2, 2],
"747": [0, 2, 2],
"748": [0, 1, 1],
"751": [0, 1, 1],
"752": [0, 1, 1],
"753": [0, 1, 1],
"754": [0, 2, 2],
"755": [0, 1, 1],
"756": [0, 1, 1],
"761": [0, 1, 1],
"762": [0, 1, 1],
"763": [0, 1, 1],
"767": [0, 1, 1],
"768": [0, 1, 1],
"771": [0, 1, 1],
"772": [0, 1, 1],
"773-fighting": [0, 1, 1],
"773-psychic": [0, 1, 1],
"773-poison": [0, 1, 1],
"773-ground": [0, 1, 1],
"773-ghost": [0, 1, 1],
"773-steel": [0, 1, 1],
"773-rock": [0, 1, 1],
"773-grass": [0, 1, 1],
"773-dragon": [0, 1, 1],
"773-bug": [0, 1, 1],
"773-ice": [0, 1, 1],
"773-dark": [0, 1, 1],
"773": [0, 1, 1],
"773-fairy": [0, 1, 1],
"773-water": [0, 1, 1],
"773-electric": [0, 1, 1],
"773-flying": [0, 1, 1],
"773-fire": [0, 1, 1],
"776": [0, 2, 2],
"777": [0, 1, 1],
"778-busted": [0, 1, 1],
"778-disguised": [0, 1, 1],
"779": [0, 1, 1],
"789": [1, 1, 1],
"790": [0, 1, 1],
"791": [1, 1, 1],
"792": [0, 1, 1],
"793": [0, 1, 1],
"797": [0, 1, 1],
"798": [0, 1, 1],
"800-dawn-wings": [0, 1, 1],
"800-dusk-mane": [0, 1, 1],
"800-ultra": [0, 1, 1],
"800": [0, 1, 1],
"802": [1, 1, 1],
"803": [0, 1, 1],
"804": [0, 1, 1],
"807": [0, 1, 1],
"808": [0, 1, 1],
"809": [0, 1, 1],
"816": [0, 1, 1],
"817": [0, 1, 1],
"818": [0, 1, 1],
"821": [0, 1, 1],
"822": [0, 1, 1],
"823": [0, 1, 1],
"829": [0, 1, 1],
"830": [0, 1, 1],
"835": [0, 1, 1],
"836": [0, 1, 1],
"850": [0, 1, 1],
"851": [0, 1, 1],
"854": [0, 1, 1],
"855": [0, 1, 1],
"856": [0, 1, 1],
"857": [0, 2, 2],
"858": [0, 1, 1],
"859": [0, 1, 1],
"860": [0, 1, 1],
"861": [0, 1, 1],
"862": [0, 1, 1],
"863": [0, 1, 1],
"864": [0, 1, 1],
"867": [0, 1, 1],
"872": [1, 1, 1],
"873": [1, 1, 1],
"876-female": [0, 1, 1],
"876": [0, 1, 1],
"877-hangry": [1, 1, 1],
"877": [1, 1, 1],
"880": [0, 1, 1],
"881": [0, 1, 1],
"882": [0, 1, 1],
"883": [0, 1, 1],
"884": [0, 1, 1],
"885": [1, 1, 1],
"886": [1, 1, 1],
"887": [1, 1, 1],
"888": [0, 1, 1],
"888-crowned": [0, 1, 1],
"889": [0, 1, 1],
"889-crowned": [0, 1, 1],
"890": [0, 1, 1],
"891": [1, 1, 1],
"892-rapid-strike": [1, 1, 1],
"892": [1, 1, 1],
"894": [0, 1, 1],
"895": [0, 1, 1],
"896": [1, 1, 1],
"897": [1, 1, 1],
"898": [1, 1, 1],
"898-ice": [1, 1, 1],
"898-shadow": [1, 1, 1],
"900": [0, 1, 1],
"901": [0, 1, 1],
"903": [0, 1, 1],
"909": [0, 1, 1],
"910": [0, 2, 2],
"911": [0, 1, 1],
"912": [0, 1, 1],
"913": [0, 1, 1],
"914": [0, 2, 2],
"919": [1, 1, 1],
"920": [1, 1, 1],
"924": [1, 1, 1],
"925-four": [1, 2, 2],
"925-three": [1, 2, 2],
"932": [0, 1, 1],
"933": [0, 1, 1],
"934": [0, 1, 1],
"935": [2, 2, 2],
"936": [2, 2, 2],
"937": [2, 2, 2],
"940": [0, 1, 1],
"941": [0, 1, 1],
"944": [0, 1, 1],
"945": [0, 1, 1],
"948": [0, 1, 1],
"949": [0, 1, 1],
"951": [0, 1, 1],
"952": [0, 2, 1],
"953": [0, 1, 1],
"954": [0, 1, 1],
"957": [1, 1, 1],
"958": [1, 1, 1],
"959": [1, 1, 1],
"962": [1, 1, 1],
"967": [0, 1, 1],
"968": [0, 2, 2],
"969": [0, 1, 1],
"970": [0, 1, 1],
"973": [1, 1, 1],
"974": [0, 1, 1],
"975": [0, 1, 1],
"978-curly": [0, 2, 2],
"978-droopy": [0, 2, 2],
"978-stretchy": [0, 1, 1],
"979": [1, 1, 1],
"981": [0, 1, 1],
"982": [0, 1, 1],
"982-three-segment": [0, 1, 1],
"987": [1, 1, 1],
"988": [0, 1, 1],
"993": [0, 1, 1],
"994": [0, 1, 1],
"995": [0, 1, 1],
"996": [0, 1, 1],
"997": [0, 1, 1],
"998": [0, 1, 1],
"999": [1, 1, 1],
"1000": [1, 1, 1],
"1001": [0, 1, 1],
"1003": [0, 1, 1],
"1004": [0, 1, 1],
"1006": [0, 2, 2],
"1007-apex-build": [0, 2, 2],
"1008-ultimate-mode": [1, 1, 1],
"2026": [0, 1, 1],
"2027": [0, 1, 1],
"2028": [0, 1, 1],
"2052": [0, 1, 1],
"2053": [0, 1, 1],
"2103": [0, 1, 1],
"4052": [0, 1, 1],
"4077": [0, 1, 1],
"4078": [0, 1, 1],
"4079": [0, 1, 1],
"4080": [2, 2, 2],
"4144": [0, 1, 1],
"4145": [0, 1, 1],
"4146": [0, 1, 1],
"4199": [2, 1, 1],
"4222": [0, 1, 1],
"4263": [0, 1, 1],
"4264": [0, 1, 1],
"4562": [0, 1, 1],
"6100": [0, 1, 1],
"6101": [0, 1, 1],
"6215": [0, 1, 1],
"6503": [0, 1, 1],
"6549": [0, 1, 1],
"6570": [0, 1, 1],
"6571": [0, 1, 1],
"6705": [0, 1, 1],
"6706": [0, 1, 1],
"6713": [0, 1, 1],
"female": {
"6215": [0, 1, 1]
}
}
} }
} }

View File

@ -1,48 +0,0 @@
{
"1": {
"cbaa84": "44827c",
"b3747e": "4b7465",
"eeffbf": "cdffb5",
"dcffb2": "8eeab9",
"ffbfca": "43bf8d",
"b7ffb2": "72d8ce",
"fff2b2": "9bffa9",
"85b4cc": "cf755d",
"a6e1ff": "efab87",
"101010": "101010",
"cacaca": "cacaca",
"537180": "b04f4b",
"2eaeec": "4dc796",
"1f75a0": "29988e",
"fdfdfd": "fdfdfd",
"d197a1": "d197a1",
"ffdce6": "ffdce6",
"217aa6": "7f99e1",
"30b2f2": "b5dcff",
"f9f9f9": "e6e3b4",
"c0c0c0": "d7cca0"
},
"2": {
"cbaa84": "cc78db",
"b3747e": "c452a6",
"eeffbf": "ed9ff2",
"dcffb2": "d7bbf4",
"ffbfca": "faccff",
"b7ffb2": "dceeff",
"fff2b2": "eb88b9",
"85b4cc": "654a8a",
"a6e1ff": "936daa",
"101010": "101010",
"cacaca": "cacaca",
"537180": "392d65",
"2eaeec": "ad4e6e",
"1f75a0": "8d2656",
"fdfdfd": "fdfdfd",
"d197a1": "d197a1",
"ffdce6": "ffdce6",
"217aa6": "efaa51",
"30b2f2": "ffd169",
"f9f9f9": "373453",
"c0c0c0": "282747"
}
}

View File

@ -1,32 +0,0 @@
{
"1": {
"535763": "292638",
"306090": "c35b2a",
"c3c7d3": "68638e",
"88aacc": "e67c37",
"fefefe": "fefefe",
"a3a7b3": "4d496b",
"737783": "37344e",
"101010": "101010",
"bbddff": "ffa633",
"1fbfdf": "ff9b44",
"5f6060": "e6ac60",
"fcfefe": "ffeed6",
"bfbbbb": "ffd3a1"
},
"2": {
"535763": "976ba9",
"306090": "a03c69",
"c3c7d3": "faecff",
"88aacc": "e25493",
"fefefe": "ffe2ee",
"a3a7b3": "e4cdf9",
"737783": "cca1db",
"101010": "101010",
"bbddff": "f591bd",
"1fbfdf": "de5f8e",
"5f6060": "5a3d84",
"fcfefe": "a473bf",
"bfbbbb": "8359a7"
}
}

View File

@ -1,28 +0,0 @@
{
"1": {
"101010": "101010",
"2b2a3a": "722023",
"603d2b": "36384f",
"215738": "4d362e",
"48484a": "a14743",
"c18760": "7c808c",
"3fa76c": "907f76",
"915e45": "575a6a",
"0b0c0b": "0b0c0b",
"da585b": "5996d2",
"ff8c8f": "87d1ff"
},
"2": {
"101010": "101010",
"2b2a3a": "6f5f80",
"603d2b": "31161d",
"215738": "a94079",
"48484a": "9c92a4",
"c18760": "7e5658",
"3fa76c": "da7ea8",
"915e45": "56323a",
"0b0c0b": "0b0c0b",
"da585b": "e18933",
"ff8c8f": "ffc875"
}
}

View File

@ -1,32 +0,0 @@
{
"1": {
"6a3f73": "731338",
"bd70cc": "a42c54",
"101010": "101010",
"bfacbf": "7047ba",
"8e5499": "8e1d4b",
"f2daf2": "8d7be3",
"404040": "202558",
"665c66": "2f386b",
"ccb43d": "ff8a58",
"f8f8f8": "8d7be3",
"595959": "2f386b",
"ffe14c": "ffc182",
"000000": "101010"
},
"2": {
"6a3f73": "5f151c",
"bd70cc": "c24430",
"101010": "101010",
"bfacbf": "f9e8dd",
"8e5499": "882c27",
"f2daf2": "f8f8f8",
"404040": "5b1922",
"665c66": "7c2928",
"ccb43d": "33d8d0",
"f8f8f8": "f8f8f8",
"595959": "7c2928",
"ffe14c": "49ffcd",
"000000": "101010"
}
}

View File

@ -1,38 +0,0 @@
{
"1": {
"b3747e": "4b7465",
"ffbfca": "43bf8d",
"fff2b2": "9bffa9",
"537180": "b04f4b",
"a6e1ff": "efab87",
"101010": "101010",
"85b4cc": "cf755d",
"217aa6": "7f99e1",
"30b2f2": "b5dcff",
"fdfdfd": "fdfdfd",
"c0c0c0": "d7cca0",
"cacaca": "cacaca",
"cbaa84": "44827c",
"dcffb2": "8eeab9",
"eeffbf": "cdffb5",
"b7ffb2": "72d8ce"
},
"2": {
"b3747e": "c452a6",
"ffbfca": "faccff",
"fff2b2": "eb88b9",
"537180": "392d65",
"a6e1ff": "936daa",
"101010": "101010",
"85b4cc": "654a8a",
"217aa6": "efaa51",
"30b2f2": "ffd169",
"fdfdfd": "fdfdfd",
"c0c0c0": "282747",
"cacaca": "cacaca",
"cbaa84": "cc78db",
"dcffb2": "d7bbf4",
"eeffbf": "ed9ff2",
"b7ffb2": "dceeff"
}
}

View File

@ -1,28 +0,0 @@
{
"1": {
"306090": "c35b2a",
"88aacc": "e67c37",
"fefefe": "fefefe",
"535763": "292638",
"a3a7b3": "4d496b",
"737783": "37344e",
"bbddff": "ffa633",
"101010": "101010",
"5f6060": "e6ac60",
"bfbbbb": "ffd3a1",
"fcfefe": "ffeed6"
},
"2": {
"306090": "a03c69",
"88aacc": "e25493",
"fefefe": "ffe2ee",
"535763": "976ba9",
"a3a7b3": "e4cdf9",
"737783": "cca1db",
"bbddff": "f591bd",
"101010": "101010",
"5f6060": "5a3d84",
"bfbbbb": "8359a7",
"fcfefe": "a473bf"
}
}

View File

@ -1,40 +0,0 @@
{
"1": {
"1a1a1c": "1a1a1c",
"686665": "646085",
"103222": "802c26",
"221b17": "221b17",
"090606": "090606",
"4ab38e": "a14743",
"38956f": "a14743",
"ab9074": "7c808c",
"4e4e4e": "494e5b",
"917860": "7c808c",
"424244": "2b303c",
"78604c": "575a6a",
"6b5442": "40435a",
"5f4939": "36384f",
"4f2a09": "292929",
"6c4513": "36384f",
"353638": "353638"
},
"2": {
"1a1a1c": "1a1a1c",
"686665": "ccc3cf",
"103222": "a94079",
"221b17": "221b17",
"090606": "090606",
"4ab38e": "da7ea8",
"38956f": "da7ea8",
"ab9074": "7e5658",
"4e4e4e": "9c92a4",
"917860": "7e5658",
"424244": "6f5f80",
"78604c": "56323a",
"6b5442": "47232b",
"5f4939": "31161d",
"4f2a09": "250e14",
"6c4513": "31161d",
"353638": "57496b"
}
}

View File

@ -1,24 +0,0 @@
{
"1": {
"101010": "101010",
"6a3f73": "500a25",
"bd70cc": "a42c54",
"8e5499": "8e1d4b",
"404040": "202558",
"595959": "2f386b",
"bfacbf": "8d7be3",
"665c66": "2f386b",
"f2daf2": "8d7be3"
},
"2": {
"101010": "101010",
"6a3f73": "5f151c",
"bd70cc": "c24430",
"8e5499": "882c27",
"404040": "5b1922",
"595959": "7c2928",
"bfacbf": "f9e8dd",
"665c66": "7c2928",
"f2daf2": "f9e8dd"
}
}

@ -1 +1 @@
Subproject commit e599780a369f87a96ab0469a8908cea86628145f Subproject commit 18c1963ef309612a5a7fef76f9879709a7202189

View File

@ -22,6 +22,9 @@ from typing import Literal as L
MASTERLIST_PATH = os.path.join( MASTERLIST_PATH = os.path.join(
os.path.dirname(os.path.dirname(__file__)), "public", "images", "pokemon", "variant", "_masterlist.json" os.path.dirname(os.path.dirname(__file__)), "public", "images", "pokemon", "variant", "_masterlist.json"
) )
EXP_MASTERLIST_PATH = os.path.join(
os.path.dirname(os.path.dirname(__file__)), "public", "images", "pokemon", "variant", "_exp_masterlist.json"
)
DEFAULT_OUTPUT_PATH = "sprite-mismatches.csv" DEFAULT_OUTPUT_PATH = "sprite-mismatches.csv"
@ -93,6 +96,7 @@ if __name__ == "__main__":
help=f"The path to a file to save the output file. If not specified, will write to {DEFAULT_OUTPUT_PATH}.", help=f"The path to a file to save the output file. If not specified, will write to {DEFAULT_OUTPUT_PATH}.",
) )
p.add_argument("--masterlist", default=MASTERLIST_PATH, help=f"The path to the masterlist file to validate. Defaults to {MASTERLIST_PATH}.") p.add_argument("--masterlist", default=MASTERLIST_PATH, help=f"The path to the masterlist file to validate. Defaults to {MASTERLIST_PATH}.")
p.add_argument("--exp-masterlist", default=EXP_MASTERLIST_PATH, help=f"The path to the exp masterlist file to validate against. Defaults to {EXP_MASTERLIST_PATH}.")
args = p.parse_args() args = p.parse_args()
mismatches = make_mismatch_sprite_list(args.masterlist) mismatches = make_mismatch_sprite_list(args.masterlist)
write_mismatch_csv(args.output, mismatches) write_mismatch_csv(args.output, mismatches)

View File

@ -0,0 +1,6 @@
import type { SessionSaveData } from "#app/system/game-data";
export interface SessionSaveMigrator {
version: string;
migrate: (data: SessionSaveData) => void;
}

View File

@ -0,0 +1,5 @@
export interface SettingsSaveMigrator {
version: string;
// biome-ignore lint/complexity/noBannedTypes: TODO - refactor settings
migrate: (data: Object) => void;
}

View File

@ -0,0 +1,6 @@
import type { SystemSaveData } from "#app/system/game-data";
export interface SystemSaveMigrator {
version: string;
migrate: (data: SystemSaveData) => void;
}

View File

@ -0,0 +1,11 @@
import type { AbAttr } from "#app/data/abilities/ab-attrs/ab-attr";
import type Move from "#app/data/moves/move";
import type Pokemon from "#app/field/pokemon";
import type { BattleStat } from "#enums/stat";
export type AbAttrApplyFunc<TAttr extends AbAttr> = (attr: TAttr, passive: boolean) => void;
export type AbAttrSuccessFunc<TAttr extends AbAttr> = (attr: TAttr, passive: boolean) => boolean;
export type AbAttrCondition = (pokemon: Pokemon) => boolean;
export type PokemonAttackCondition = (user: Pokemon | null, target: Pokemon | null, move: Move) => boolean;
export type PokemonDefendCondition = (target: Pokemon, user: Pokemon, move: Move) => boolean;
export type PokemonStatStageChangeCondition = (target: Pokemon, statsChanged: BattleStat[], stages: number) => boolean;

View File

@ -1,11 +1,11 @@
import { pokerogueApi } from "#app/plugins/api/pokerogue-api"; import { pokerogueApi } from "#app/plugins/api/pokerogue-api";
import type { UserInfo } from "#app/@types/UserInfo"; import type { UserInfo } from "#app/@types/UserInfo";
import { bypassLogin } from "./battle-scene"; import { bypassLogin } from "./global-vars/bypass-login";
import * as Utils from "./utils"; import { randomString } from "#app/utils/common";
export let loggedInUser: UserInfo | null = null; export let loggedInUser: UserInfo | null = null;
// This is a random string that is used to identify the client session - unique per session (tab or window) so that the game will only save on the one that the server is expecting // This is a random string that is used to identify the client session - unique per session (tab or window) so that the game will only save on the one that the server is expecting
export const clientSessionId = Utils.randomString(32); export const clientSessionId = randomString(32);
export function initLoggedInUser(): void { export function initLoggedInUser(): void {
loggedInUser = { loggedInUser = {

View File

@ -5,9 +5,20 @@ import { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon";
import type { PokemonSpeciesFilter } from "#app/data/pokemon-species"; import type { PokemonSpeciesFilter } from "#app/data/pokemon-species";
import type PokemonSpecies from "#app/data/pokemon-species"; import type PokemonSpecies from "#app/data/pokemon-species";
import { allSpecies, getPokemonSpecies } from "#app/data/pokemon-species"; import { allSpecies, getPokemonSpecies } from "#app/data/pokemon-species";
import type { Constructor } from "#app/utils"; import {
import { isNullOrUndefined, randSeedInt } from "#app/utils"; fixedInt,
import * as Utils from "#app/utils"; deepMergeObjects,
getIvsFromId,
randSeedInt,
getEnumValues,
randomString,
NumberHolder,
shiftCharCodes,
formatMoney,
isNullOrUndefined,
BooleanHolder,
type Constructor,
} from "#app/utils/common";
import type { Modifier, ModifierPredicate, TurnHeldItemTransferModifier } from "./modifier/modifier"; import type { Modifier, ModifierPredicate, TurnHeldItemTransferModifier } from "./modifier/modifier";
import { import {
ConsumableModifier, ConsumableModifier,
@ -56,7 +67,6 @@ import {
} from "#app/modifier/modifier-type"; } from "#app/modifier/modifier-type";
import AbilityBar from "#app/ui/ability-bar"; import AbilityBar from "#app/ui/ability-bar";
import { import {
allAbilities,
applyAbAttrs, applyAbAttrs,
applyPostBattleInitAbAttrs, applyPostBattleInitAbAttrs,
applyPostItemLostAbAttrs, applyPostItemLostAbAttrs,
@ -64,9 +74,11 @@ import {
DoubleBattleChanceAbAttr, DoubleBattleChanceAbAttr,
PostBattleInitAbAttr, PostBattleInitAbAttr,
PostItemLostAbAttr, PostItemLostAbAttr,
} from "#app/data/ability"; } from "#app/data/abilities/ability";
import { allAbilities } from "./data/data-lists";
import type { FixedBattleConfig } from "#app/battle"; import type { FixedBattleConfig } from "#app/battle";
import Battle, { BattleType } from "#app/battle"; import Battle from "#app/battle";
import { BattleType } from "#enums/battle-type";
import type { GameMode } from "#app/game-mode"; import type { GameMode } from "#app/game-mode";
import { GameModes, getGameMode } from "#app/game-mode"; import { GameModes, getGameMode } from "#app/game-mode";
import FieldSpritePipeline from "#app/pipelines/field-sprite"; import FieldSpritePipeline from "#app/pipelines/field-sprite";
@ -106,8 +118,8 @@ import PokemonInfoContainer from "#app/ui/pokemon-info-container";
import { biomeDepths, getBiomeName } from "#app/data/balance/biomes"; import { biomeDepths, getBiomeName } from "#app/data/balance/biomes";
import { SceneBase } from "#app/scene-base"; import { SceneBase } from "#app/scene-base";
import CandyBar from "#app/ui/candy-bar"; import CandyBar from "#app/ui/candy-bar";
import type { Variant, VariantSet } from "#app/data/variant"; import type { Variant } from "#app/sprites/variant";
import { variantColorCache, variantData } from "#app/data/variant"; import { variantData, clearVariantData } from "#app/sprites/variant";
import type { Localizable } from "#app/interfaces/locales"; import type { Localizable } from "#app/interfaces/locales";
import Overrides from "#app/overrides"; import Overrides from "#app/overrides";
import { InputsController } from "#app/inputs-controller"; import { InputsController } from "#app/inputs-controller";
@ -139,7 +151,6 @@ import { NextEncounterPhase } from "#app/phases/next-encounter-phase";
import { PokemonAnimPhase } from "#app/phases/pokemon-anim-phase"; import { PokemonAnimPhase } from "#app/phases/pokemon-anim-phase";
import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase"; import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase";
import { ReturnPhase } from "#app/phases/return-phase"; import { ReturnPhase } from "#app/phases/return-phase";
import { SelectBiomePhase } from "#app/phases/select-biome-phase";
import { ShowTrainerPhase } from "#app/phases/show-trainer-phase"; import { ShowTrainerPhase } from "#app/phases/show-trainer-phase";
import { SummonPhase } from "#app/phases/summon-phase"; import { SummonPhase } from "#app/phases/summon-phase";
import { SwitchPhase } from "#app/phases/switch-phase"; import { SwitchPhase } from "#app/phases/switch-phase";
@ -170,8 +181,11 @@ import { StatusEffect } from "#enums/status-effect";
import { initGlobalScene } from "#app/global-scene"; import { initGlobalScene } from "#app/global-scene";
import { ShowAbilityPhase } from "#app/phases/show-ability-phase"; import { ShowAbilityPhase } from "#app/phases/show-ability-phase";
import { HideAbilityPhase } from "#app/phases/hide-ability-phase"; import { HideAbilityPhase } from "#app/phases/hide-ability-phase";
import { expSpriteKeys } from "./sprites/sprite-keys";
export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1"; import { hasExpSprite } from "./sprites/sprite-utils";
import { timedEventManager } from "./global-event-manager";
import { starterColors } from "./global-vars/starter-colors";
import { startingWave } from "./starting-wave";
const DEBUG_RNG = false; const DEBUG_RNG = false;
@ -179,15 +193,6 @@ const OPP_IVS_OVERRIDE_VALIDATED: number[] = (
Array.isArray(Overrides.OPP_IVS_OVERRIDE) ? Overrides.OPP_IVS_OVERRIDE : new Array(6).fill(Overrides.OPP_IVS_OVERRIDE) Array.isArray(Overrides.OPP_IVS_OVERRIDE) ? Overrides.OPP_IVS_OVERRIDE : new Array(6).fill(Overrides.OPP_IVS_OVERRIDE)
).map(iv => (Number.isNaN(iv) || iv === null || iv > 31 ? -1 : iv)); ).map(iv => (Number.isNaN(iv) || iv === null || iv > 31 ? -1 : iv));
export const startingWave = Overrides.STARTING_WAVE_OVERRIDE || 1;
const expSpriteKeys: string[] = [];
export let starterColors: StarterColors;
interface StarterColors {
[key: string]: [string, string];
}
export interface PokeballCounts { export interface PokeballCounts {
[pb: string]: number; [pb: string]: number;
} }
@ -408,7 +413,7 @@ export default class BattleScene extends SceneBase {
} }
const variant = atlasPath.includes("variant/") || /_[0-3]$/.test(atlasPath); const variant = atlasPath.includes("variant/") || /_[0-3]$/.test(atlasPath);
if (experimental) { if (experimental) {
experimental = this.hasExpSprite(key); experimental = hasExpSprite(key);
} }
if (variant) { if (variant) {
atlasPath = atlasPath.replace("variant/", ""); atlasPath = atlasPath.replace("variant/", "");
@ -420,35 +425,6 @@ export default class BattleScene extends SceneBase {
); );
} }
/**
* Load the variant assets for the given sprite and stores them in {@linkcode variantColorCache}
*/
public async loadPokemonVariantAssets(spriteKey: string, fileRoot: string, variant?: Variant): Promise<void> {
const useExpSprite = this.experimentalSprites && this.hasExpSprite(spriteKey);
if (useExpSprite) {
fileRoot = `exp/${fileRoot}`;
}
let variantConfig = variantData;
fileRoot.split("/").map(p => (variantConfig ? (variantConfig = variantConfig[p]) : null));
const variantSet = variantConfig as VariantSet;
return new Promise<void>(resolve => {
if (variantSet && variant !== undefined && variantSet[variant] === 1) {
if (variantColorCache.hasOwnProperty(spriteKey)) {
return resolve();
}
this.cachedFetch(`./images/pokemon/variant/${fileRoot}.json`)
.then(res => res.json())
.then(c => {
variantColorCache[spriteKey] = c;
resolve();
});
} else {
resolve();
}
});
}
async preload() { async preload() {
if (DEBUG_RNG) { if (DEBUG_RNG) {
const originalRealInRange = Phaser.Math.RND.realInRange; const originalRealInRange = Phaser.Math.RND.realInRange;
@ -761,7 +737,7 @@ export default class BattleScene extends SceneBase {
} }
this.playTimeTimer = this.time.addEvent({ this.playTimeTimer = this.time.addEvent({
delay: Utils.fixedInt(1000), delay: fixedInt(1000),
repeat: -1, repeat: -1,
callback: () => { callback: () => {
if (this.gameData) { if (this.gameData) {
@ -782,53 +758,36 @@ export default class BattleScene extends SceneBase {
} }
async initExpSprites(): Promise<void> { async initExpSprites(): Promise<void> {
if (expSpriteKeys.length) { if (expSpriteKeys.size > 0) {
return; return;
} }
this.cachedFetch("./exp-sprites.json") this.cachedFetch("./exp-sprites.json")
.then(res => res.json()) .then(res => res.json())
.then(keys => { .then(keys => {
if (Array.isArray(keys)) { if (Array.isArray(keys)) {
expSpriteKeys.push(...keys); for (const key of keys) {
expSpriteKeys.add(key);
}
} }
Promise.resolve(); Promise.resolve();
}); });
} }
/**
* Initialize the variant data.
* If experimental sprites are enabled, their entries are replaced via this method.
*/
async initVariantData(): Promise<void> { async initVariantData(): Promise<void> {
for (const key of Object.keys(variantData)) { clearVariantData();
delete variantData[key]; const otherVariantData = await this.cachedFetch("./images/pokemon/variant/_masterlist.json").then(r => r.json());
for (const k of Object.keys(otherVariantData)) {
variantData[k] = otherVariantData[k];
} }
await this.cachedFetch("./images/pokemon/variant/_masterlist.json") if (!this.experimentalSprites) {
.then(res => res.json()) return;
.then(v => {
for (const k of Object.keys(v)) {
variantData[k] = v[k];
} }
if (this.experimentalSprites) { const expVariantData = await this.cachedFetch("./images/pokemon/variant/_exp_masterlist.json").then(r => r.json());
const expVariantData = variantData["exp"]; deepMergeObjects(variantData, expVariantData);
const traverseVariantData = (keys: string[]) => {
let variantTree = variantData;
let expTree = expVariantData;
keys.map((k: string, i: number) => {
if (i < keys.length - 1) {
variantTree = variantTree[k];
expTree = expTree[k];
} else if (variantTree.hasOwnProperty(k) && expTree.hasOwnProperty(k)) {
if (["back", "female"].includes(k)) {
traverseVariantData(keys.concat(k));
} else {
variantTree[k] = expTree[k];
}
}
});
};
for (const ek of Object.keys(expVariantData)) {
traverseVariantData([ek]);
}
}
Promise.resolve();
});
} }
cachedFetch(url: string, init?: RequestInit): Promise<Response> { cachedFetch(url: string, init?: RequestInit): Promise<Response> {
@ -842,48 +801,15 @@ export default class BattleScene extends SceneBase {
return fetch(url, init); return fetch(url, init);
} }
initStarterColors(): Promise<void> { async initStarterColors(): Promise<void> {
return new Promise(resolve => { if (Object.keys(starterColors).length > 0) {
if (starterColors) { // already initialized
return resolve(); return;
} }
const sc = await this.cachedFetch("./starter-colors.json").then(res => res.json());
this.cachedFetch("./starter-colors.json")
.then(res => res.json())
.then(sc => {
starterColors = {};
for (const key of Object.keys(sc)) { for (const key of Object.keys(sc)) {
starterColors[key] = sc[key]; starterColors[key] = sc[key];
} }
resolve();
});
});
}
hasExpSprite(key: string): boolean {
const keyMatch = /^pkmn__?(back__)?(shiny__)?(female__)?(\d+)(\-.*?)?(?:_[1-3])?$/g.exec(key);
if (!keyMatch) {
return false;
}
let k = keyMatch[4]!;
if (keyMatch[2]) {
k += "s";
}
if (keyMatch[1]) {
k += "b";
}
if (keyMatch[3]) {
k += "f";
}
if (keyMatch[5]) {
k += keyMatch[5];
}
if (!expSpriteKeys.includes(k)) {
return false;
}
return true;
} }
public getPlayerParty(): PlayerPokemon[] { public getPlayerParty(): PlayerPokemon[] {
@ -1066,7 +992,7 @@ export default class BattleScene extends SceneBase {
} }
if (boss && !dataSource) { if (boss && !dataSource) {
const secondaryIvs = Utils.getIvsFromId(Utils.randSeedInt(4294967296)); const secondaryIvs = getIvsFromId(randSeedInt(4294967296));
for (let s = 0; s < pokemon.ivs.length; s++) { for (let s = 0; s < pokemon.ivs.length; s++) {
pokemon.ivs[s] = Math.round( pokemon.ivs[s] = Math.round(
@ -1139,7 +1065,7 @@ export default class BattleScene extends SceneBase {
container.add(icon); container.add(icon);
if (pokemon.isFusion()) { if (pokemon.isFusion(true)) {
const fusionIcon = this.add.sprite(0, 0, pokemon.getFusionIconAtlasKey(ignoreOverride)); const fusionIcon = this.add.sprite(0, 0, pokemon.getFusionIconAtlasKey(ignoreOverride));
fusionIcon.setName("sprite-fusion-icon"); fusionIcon.setName("sprite-fusion-icon");
fusionIcon.setOrigin(0.5, 0); fusionIcon.setOrigin(0.5, 0);
@ -1225,7 +1151,7 @@ export default class BattleScene extends SceneBase {
* Generates a random number using the current battle's seed * Generates a random number using the current battle's seed
* *
* This calls {@linkcode Battle.randSeedInt}({@linkcode range}, {@linkcode min}) in `src/battle.ts` * This calls {@linkcode Battle.randSeedInt}({@linkcode range}, {@linkcode min}) in `src/battle.ts`
* which calls {@linkcode Utils.randSeedInt randSeedInt}({@linkcode range}, {@linkcode min}) in `src/utils.ts` * which calls {@linkcode randSeedInt randSeedInt}({@linkcode range}, {@linkcode min}) in `src/utils.ts`
* *
* @param range How large of a range of random numbers to choose from. If {@linkcode range} <= 1, returns {@linkcode min} * @param range How large of a range of random numbers to choose from. If {@linkcode range} <= 1, returns {@linkcode min}
* @param min The minimum integer to pick, default `0` * @param min The minimum integer to pick, default `0`
@ -1250,7 +1176,7 @@ export default class BattleScene extends SceneBase {
this.lockModifierTiers = false; this.lockModifierTiers = false;
this.pokeballCounts = Object.fromEntries( this.pokeballCounts = Object.fromEntries(
Utils.getEnumValues(PokeballType) getEnumValues(PokeballType)
.filter(p => p <= PokeballType.MASTER_BALL) .filter(p => p <= PokeballType.MASTER_BALL)
.map(t => [t, 0]), .map(t => [t, 0]),
); );
@ -1282,7 +1208,7 @@ export default class BattleScene extends SceneBase {
// Reset RNG after end of game or save & quit. // Reset RNG after end of game or save & quit.
// This needs to happen after clearing this.currentBattle or the seed will be affected by the last wave played // This needs to happen after clearing this.currentBattle or the seed will be affected by the last wave played
this.setSeed(Overrides.SEED_OVERRIDE || Utils.randomString(24)); this.setSeed(Overrides.SEED_OVERRIDE || randomString(24));
console.log("Seed:", this.seed); console.log("Seed:", this.seed);
this.resetSeed(); this.resetSeed();
@ -1323,7 +1249,7 @@ export default class BattleScene extends SceneBase {
...allSpecies, ...allSpecies,
...allMoves, ...allMoves,
...allAbilities, ...allAbilities,
...Utils.getEnumValues(ModifierPoolType) ...getEnumValues(ModifierPoolType)
.map(mpt => getModifierPoolForType(mpt)) .map(mpt => getModifierPoolForType(mpt))
.flatMap(mp => .flatMap(mp =>
Object.values(mp) Object.values(mp)
@ -1363,7 +1289,7 @@ export default class BattleScene extends SceneBase {
} }
getDoubleBattleChance(newWaveIndex: number, playerField: PlayerPokemon[]) { getDoubleBattleChance(newWaveIndex: number, playerField: PlayerPokemon[]) {
const doubleChance = new Utils.NumberHolder(newWaveIndex % 10 === 0 ? 32 : 8); const doubleChance = new NumberHolder(newWaveIndex % 10 === 0 ? 32 : 8);
this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance); this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance);
for (const p of playerField) { for (const p of playerField) {
applyAbAttrs(DoubleBattleChanceAbAttr, p, null, false, doubleChance); applyAbAttrs(DoubleBattleChanceAbAttr, p, null, false, doubleChance);
@ -1371,6 +1297,16 @@ export default class BattleScene extends SceneBase {
return Math.max(doubleChance.value, 1); return Math.max(doubleChance.value, 1);
} }
isNewBiome(currentBattle = this.currentBattle) {
const isWaveIndexMultipleOfTen = !(currentBattle.waveIndex % 10);
const isEndlessOrDaily = this.gameMode.hasShortBiomes || this.gameMode.isDaily;
const isEndlessFifthWave = this.gameMode.hasShortBiomes && currentBattle.waveIndex % 5 === 0;
const isWaveIndexMultipleOfFiftyMinusOne = currentBattle.waveIndex % 50 === 49;
const isNewBiome =
isWaveIndexMultipleOfTen || isEndlessFifthWave || (isEndlessOrDaily && isWaveIndexMultipleOfFiftyMinusOne);
return isNewBiome;
}
// TODO: ...this never actually returns `null`, right? // TODO: ...this never actually returns `null`, right?
newBattle( newBattle(
waveIndex?: number, waveIndex?: number,
@ -1405,22 +1341,27 @@ export default class BattleScene extends SceneBase {
} else { } else {
if ( if (
!this.gameMode.hasTrainers || !this.gameMode.hasTrainers ||
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 if (battleType === undefined) {
newBattleType = this.gameMode.isWaveTrainer(newWaveIndex, this.arena) ? BattleType.TRAINER : BattleType.WILD;
} else { } else {
newBattleType = battleType; newBattleType =
Overrides.BATTLE_TYPE_OVERRIDE ??
battleType ??
(this.gameMode.isWaveTrainer(newWaveIndex, this.arena) ? BattleType.TRAINER : BattleType.WILD);
} }
if (newBattleType === BattleType.TRAINER) { if (newBattleType === BattleType.TRAINER) {
const trainerType = this.arena.randomTrainerType(newWaveIndex); const trainerType =
Overrides.RANDOM_TRAINER_OVERRIDE?.trainerType ?? this.arena.randomTrainerType(newWaveIndex);
let doubleTrainer = false; let doubleTrainer = false;
if (trainerConfigs[trainerType].doubleOnly) { if (trainerConfigs[trainerType].doubleOnly) {
doubleTrainer = true; doubleTrainer = true;
} else if (trainerConfigs[trainerType].hasDouble) { } else if (trainerConfigs[trainerType].hasDouble) {
doubleTrainer = !Utils.randSeedInt(this.getDoubleBattleChance(newWaveIndex, playerField)); doubleTrainer =
Overrides.RANDOM_TRAINER_OVERRIDE?.alwaysDouble ||
!randSeedInt(this.getDoubleBattleChance(newWaveIndex, playerField));
// Add a check that special trainers can't be double except for tate and liza - they should use the normal double chance // 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 &&
@ -1431,7 +1372,7 @@ export default class BattleScene extends SceneBase {
} }
const variant = doubleTrainer const variant = doubleTrainer
? TrainerVariant.DOUBLE ? TrainerVariant.DOUBLE
: Utils.randSeedInt(2) : randSeedInt(2)
? TrainerVariant.FEMALE ? TrainerVariant.FEMALE
: TrainerVariant.DEFAULT; : TrainerVariant.DEFAULT;
newTrainer = trainerData !== undefined ? trainerData.toTrainer() : new Trainer(trainerType, variant); newTrainer = trainerData !== undefined ? trainerData.toTrainer() : new Trainer(trainerType, variant);
@ -1440,7 +1381,10 @@ export default 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 (this.isWaveMysteryEncounter(newBattleType, newWaveIndex) || newBattleType === BattleType.MYSTERY_ENCOUNTER) { if (
!Overrides.BATTLE_TYPE_OVERRIDE &&
(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
this.mysteryEncounterSaveData.encounterSpawnChance = BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT; this.mysteryEncounterSaveData.encounterSpawnChance = BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT;
@ -1449,7 +1393,7 @@ export default class BattleScene extends SceneBase {
if (double === undefined && newWaveIndex > 1) { if (double === undefined && newWaveIndex > 1) {
if (newBattleType === BattleType.WILD && !this.gameMode.isWaveFinal(newWaveIndex)) { if (newBattleType === BattleType.WILD && !this.gameMode.isWaveFinal(newWaveIndex)) {
newDouble = !Utils.randSeedInt(this.getDoubleBattleChance(newWaveIndex, playerField)); newDouble = !randSeedInt(this.getDoubleBattleChance(newWaveIndex, playerField));
} else if (newBattleType === BattleType.TRAINER) { } else if (newBattleType === BattleType.TRAINER) {
newDouble = newTrainer?.variant === TrainerVariant.DOUBLE; newDouble = newTrainer?.variant === TrainerVariant.DOUBLE;
} }
@ -1462,10 +1406,10 @@ export default class BattleScene extends SceneBase {
newDouble = false; newDouble = false;
} }
if (!isNullOrUndefined(Overrides.BATTLE_TYPE_OVERRIDE)) { if (!isNullOrUndefined(Overrides.BATTLE_STYLE_OVERRIDE)) {
let doubleOverrideForWave: "single" | "double" | null = null; let doubleOverrideForWave: "single" | "double" | null = null;
switch (Overrides.BATTLE_TYPE_OVERRIDE) { switch (Overrides.BATTLE_STYLE_OVERRIDE) {
case "double": case "double":
doubleOverrideForWave = "double"; doubleOverrideForWave = "double";
break; break;
@ -1485,7 +1429,7 @@ export default class BattleScene extends SceneBase {
} }
/** /**
* Override battles into single only if not fighting with trainers. * Override battles into single only if not fighting with trainers.
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/1948 | GitHub Issue #1948} * @see {@link https://github.com/pagefaultgames/pokerogue/issues/1948 GitHub Issue #1948}
*/ */
if (newBattleType !== BattleType.TRAINER && doubleOverrideForWave === "single") { if (newBattleType !== BattleType.TRAINER && doubleOverrideForWave === "single") {
newDouble = false; newDouble = false;
@ -1525,15 +1469,8 @@ export default class BattleScene extends SceneBase {
this.currentBattle.mysteryEncounterType = mysteryEncounterType; this.currentBattle.mysteryEncounterType = mysteryEncounterType;
} }
//this.pushPhase(new TrainerMessageTestPhase(this, TrainerType.RIVAL, TrainerType.RIVAL_2, TrainerType.RIVAL_3, TrainerType.RIVAL_4, TrainerType.RIVAL_5, TrainerType.RIVAL_6));
if (!waveIndex && lastBattle) { if (!waveIndex && lastBattle) {
const isWaveIndexMultipleOfTen = !(lastBattle.waveIndex % 10); const isNewBiome = this.isNewBiome(lastBattle);
const isEndlessOrDaily = this.gameMode.hasShortBiomes || this.gameMode.isDaily;
const isEndlessFifthWave = this.gameMode.hasShortBiomes && lastBattle.waveIndex % 5 === 0;
const isWaveIndexMultipleOfFiftyMinusOne = lastBattle.waveIndex % 50 === 49;
const isNewBiome =
isWaveIndexMultipleOfTen || isEndlessFifthWave || (isEndlessOrDaily && isWaveIndexMultipleOfFiftyMinusOne);
const resetArenaState = const resetArenaState =
isNewBiome || isNewBiome ||
[BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(this.currentBattle.battleType) || [BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(this.currentBattle.battleType) ||
@ -1582,7 +1519,6 @@ export default class BattleScene extends SceneBase {
if (!this.gameMode.hasRandomBiomes && !isNewBiome) { if (!this.gameMode.hasRandomBiomes && !isNewBiome) {
this.pushPhase(new NextEncounterPhase()); this.pushPhase(new NextEncounterPhase());
} else { } else {
this.pushPhase(new SelectBiomePhase());
this.pushPhase(new NewBiomeEncounterPhase()); this.pushPhase(new NewBiomeEncounterPhase());
const newMaxExpLevel = this.getMaxExpLevel(); const newMaxExpLevel = this.getMaxExpLevel();
@ -1639,7 +1575,7 @@ export default class BattleScene extends SceneBase {
scale: scale, scale: scale,
x: (defaultWidth - scaledWidth) / 2, x: (defaultWidth - scaledWidth) / 2,
y: defaultHeight - scaledHeight, y: defaultHeight - scaledHeight,
duration: !instant ? Utils.fixedInt(Math.abs(this.field.scale - scale) * 200) : 0, duration: !instant ? fixedInt(Math.abs(this.field.scale - scale) * 200) : 0,
ease: "Sine.easeInOut", ease: "Sine.easeInOut",
onComplete: () => resolve(), onComplete: () => resolve(),
}); });
@ -1736,12 +1672,12 @@ export default class BattleScene extends SceneBase {
case Species.SQUAWKABILLY: case Species.SQUAWKABILLY:
case Species.TATSUGIRI: case Species.TATSUGIRI:
case Species.PALDEA_TAUROS: case Species.PALDEA_TAUROS:
return Utils.randSeedInt(species.forms.length); return randSeedInt(species.forms.length);
case Species.PIKACHU: case Species.PIKACHU:
if (this.currentBattle?.battleType === BattleType.TRAINER && this.currentBattle?.waveIndex < 30) { if (this.currentBattle?.battleType === BattleType.TRAINER && this.currentBattle?.waveIndex < 30) {
return 0; // Ban Cosplay and Partner Pika from Trainers before wave 30 return 0; // Ban Cosplay and Partner Pika from Trainers before wave 30
} }
return Utils.randSeedInt(8); return randSeedInt(8);
case Species.EEVEE: case Species.EEVEE:
if ( if (
this.currentBattle?.battleType === BattleType.TRAINER && this.currentBattle?.battleType === BattleType.TRAINER &&
@ -1750,22 +1686,22 @@ export default class BattleScene extends SceneBase {
) { ) {
return 0; // No Partner Eevee for Wave 12 Preschoolers return 0; // No Partner Eevee for Wave 12 Preschoolers
} }
return Utils.randSeedInt(2); return randSeedInt(2);
case Species.FROAKIE: case Species.FROAKIE:
case Species.FROGADIER: case Species.FROGADIER:
case Species.GRENINJA: case Species.GRENINJA:
if (this.currentBattle?.battleType === BattleType.TRAINER && !isEggPhase) { if (this.currentBattle?.battleType === BattleType.TRAINER && !isEggPhase) {
return 0; // Don't give trainers Battle Bond Greninja, Froakie or Frogadier return 0; // Don't give trainers Battle Bond Greninja, Froakie or Frogadier
} }
return Utils.randSeedInt(2); return randSeedInt(2);
case Species.URSHIFU: case Species.URSHIFU:
return Utils.randSeedInt(2); return randSeedInt(2);
case Species.ZYGARDE: case Species.ZYGARDE:
return Utils.randSeedInt(4); return randSeedInt(4);
case Species.MINIOR: case Species.MINIOR:
return Utils.randSeedInt(7); return randSeedInt(7);
case Species.ALCREMIE: case Species.ALCREMIE:
return Utils.randSeedInt(9); return randSeedInt(9);
case Species.MEOWSTIC: case Species.MEOWSTIC:
case Species.INDEEDEE: case Species.INDEEDEE:
case Species.BASCULEGION: case Species.BASCULEGION:
@ -1796,7 +1732,7 @@ export default class BattleScene extends SceneBase {
if (this.gameMode.hasMysteryEncounters && !isEggPhase) { if (this.gameMode.hasMysteryEncounters && !isEggPhase) {
return 1; // Wandering form return 1; // Wandering form
} }
return Utils.randSeedInt(species.forms.length); return randSeedInt(species.forms.length);
} }
if (ignoreArena) { if (ignoreArena) {
@ -1805,7 +1741,7 @@ export default class BattleScene extends SceneBase {
case Species.WORMADAM: case Species.WORMADAM:
case Species.ROTOM: case Species.ROTOM:
case Species.LYCANROC: case Species.LYCANROC:
return Utils.randSeedInt(species.forms.length); return randSeedInt(species.forms.length);
} }
return 0; return 0;
} }
@ -1817,7 +1753,7 @@ export default class BattleScene extends SceneBase {
let ret = false; let ret = false;
this.executeWithSeedOffset( this.executeWithSeedOffset(
() => { () => {
ret = !Utils.randSeedInt(2); ret = !randSeedInt(2);
}, },
0, 0,
this.seed.toString(), this.seed.toString(),
@ -1829,7 +1765,7 @@ export default class BattleScene extends SceneBase {
let ret = 0; let ret = 0;
this.executeWithSeedOffset( this.executeWithSeedOffset(
() => { () => {
ret = Utils.randSeedInt(8) * 5; ret = randSeedInt(8) * 5;
}, },
0, 0,
this.seed.toString(), this.seed.toString(),
@ -1858,7 +1794,7 @@ export default class BattleScene extends SceneBase {
isBoss = isBoss =
waveIndex % 10 === 0 || waveIndex % 10 === 0 ||
(this.gameMode.hasRandomBosses && (this.gameMode.hasRandomBosses &&
Utils.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) {
@ -1885,7 +1821,7 @@ export default class BattleScene extends SceneBase {
const infectedIndexes: number[] = []; const infectedIndexes: number[] = [];
const spread = (index: number, spreadTo: number) => { const spread = (index: number, spreadTo: number) => {
const partyMember = party[index + spreadTo]; const partyMember = party[index + spreadTo];
if (!partyMember.pokerus && !Utils.randSeedInt(10)) { if (!partyMember.pokerus && !randSeedInt(10)) {
partyMember.pokerus = true; partyMember.pokerus = true;
infectedIndexes.push(index + spreadTo); infectedIndexes.push(index + spreadTo);
} }
@ -1911,7 +1847,7 @@ export default class BattleScene extends SceneBase {
resetSeed(waveIndex?: number): void { resetSeed(waveIndex?: number): void {
const wave = waveIndex || this.currentBattle?.waveIndex || 0; const wave = waveIndex || this.currentBattle?.waveIndex || 0;
this.waveSeed = Utils.shiftCharCodes(this.seed, wave); this.waveSeed = shiftCharCodes(this.seed, wave);
Phaser.Math.RND.sow([this.waveSeed]); Phaser.Math.RND.sow([this.waveSeed]);
console.log("Wave Seed:", this.waveSeed, wave); console.log("Wave Seed:", this.waveSeed, wave);
this.rngCounter = 0; this.rngCounter = 0;
@ -1930,7 +1866,7 @@ export default class BattleScene extends SceneBase {
const tempRngOffset = this.rngOffset; const tempRngOffset = this.rngOffset;
const tempRngSeedOverride = this.rngSeedOverride; const tempRngSeedOverride = this.rngSeedOverride;
const state = Phaser.Math.RND.state(); const state = Phaser.Math.RND.state();
Phaser.Math.RND.sow([Utils.shiftCharCodes(seedOverride || this.seed, offset)]); Phaser.Math.RND.sow([shiftCharCodes(seedOverride || this.seed, offset)]);
this.rngCounter = 0; this.rngCounter = 0;
this.rngOffset = offset; this.rngOffset = offset;
this.rngSeedOverride = seedOverride || ""; this.rngSeedOverride = seedOverride || "";
@ -2075,7 +2011,7 @@ export default class BattleScene extends SceneBase {
if (this.money === undefined) { if (this.money === undefined) {
return; return;
} }
const formattedMoney = Utils.formatMoney(this.moneyFormat, this.money); const formattedMoney = formatMoney(this.moneyFormat, this.money);
this.moneyText.setText(i18next.t("battleScene:moneyOwned", { formattedMoney })); this.moneyText.setText(i18next.t("battleScene:moneyOwned", { formattedMoney }));
this.fieldUI.moveAbove(this.moneyText, this.luckText); this.fieldUI.moveAbove(this.moneyText, this.luckText);
if (forceVisible) { if (forceVisible) {
@ -2232,12 +2168,12 @@ export default class BattleScene extends SceneBase {
), ),
] ]
: allSpecies.filter(s => s.isCatchable()); : allSpecies.filter(s => s.isCatchable());
return filteredSpecies[Utils.randSeedInt(filteredSpecies.length)]; return filteredSpecies[randSeedInt(filteredSpecies.length)];
} }
generateRandomBiome(waveIndex: number): Biome { generateRandomBiome(waveIndex: number): Biome {
const relWave = waveIndex % 250; const relWave = waveIndex % 250;
const biomes = Utils.getEnumValues(Biome).filter(b => b !== Biome.TOWN && b !== Biome.END); const biomes = getEnumValues(Biome).filter(b => b !== Biome.TOWN && b !== Biome.END);
const maxDepth = biomeDepths[Biome.END][0] - 2; const maxDepth = biomeDepths[Biome.END][0] - 2;
const depthWeights = new Array(maxDepth + 1) const depthWeights = new Array(maxDepth + 1)
.fill(null) .fill(null)
@ -2249,7 +2185,7 @@ export default class BattleScene extends SceneBase {
biomeThresholds.push(totalWeight); biomeThresholds.push(totalWeight);
} }
const randInt = Utils.randSeedInt(totalWeight); const randInt = randSeedInt(totalWeight);
for (let i = 0; i < biomes.length; i++) { for (let i = 0; i < biomes.length; i++) {
if (randInt < biomeThresholds[i]) { if (randInt < biomeThresholds[i]) {
@ -2257,7 +2193,7 @@ export default class BattleScene extends SceneBase {
} }
} }
return biomes[Utils.randSeedInt(biomes.length)]; return biomes[randSeedInt(biomes.length)];
} }
isBgmPlaying(): boolean { isBgmPlaying(): boolean {
@ -2268,6 +2204,9 @@ export default class BattleScene extends SceneBase {
if (bgmName === undefined) { if (bgmName === undefined) {
bgmName = this.currentBattle?.getBgmOverride() || this.arena?.bgm; bgmName = this.currentBattle?.getBgmOverride() || this.arena?.bgm;
} }
bgmName = timedEventManager.getEventBgmReplacement(bgmName);
if (this.bgm && bgmName === this.bgm.key) { if (this.bgm && bgmName === this.bgm.key) {
if (!this.bgm.isPlaying) { if (!this.bgm.isPlaying) {
this.bgm.play({ this.bgm.play({
@ -2439,7 +2378,7 @@ export default class BattleScene extends SceneBase {
this.bgmResumeTimer.destroy(); this.bgmResumeTimer.destroy();
} }
if (resumeBgm) { if (resumeBgm) {
this.bgmResumeTimer = this.time.delayedCall(pauseDuration || Utils.fixedInt(sound.totalDuration * 1000), () => { this.bgmResumeTimer = this.time.delayedCall(pauseDuration || fixedInt(sound.totalDuration * 1000), () => {
this.resumeBgm(); this.resumeBgm();
this.bgmResumeTimer = null; this.bgmResumeTimer = null;
}); });
@ -2660,6 +2599,10 @@ export default class BattleScene extends SceneBase {
return 41.42; return 41.42;
case "mystery_encounter_delibirdy": // Firel Delibirdy case "mystery_encounter_delibirdy": // Firel Delibirdy
return 82.28; return 82.28;
case "title_afd": // Andr06 - PokéRogue Title Remix (AFD)
return 47.66;
case "battle_rival_3_afd": // Andr06 - Final N Battle Remix (AFD)
return 49.147;
} }
return 0; return 0;
@ -2929,14 +2872,19 @@ export default class BattleScene extends SceneBase {
* @param show Whether to show or hide the bar * @param show Whether to show or hide the bar
*/ */
public queueAbilityDisplay(pokemon: Pokemon, passive: boolean, show: boolean): void { public queueAbilityDisplay(pokemon: Pokemon, passive: boolean, show: boolean): void {
this.unshiftPhase( this.unshiftPhase(show ? new ShowAbilityPhase(pokemon.getBattlerIndex(), passive) : new HideAbilityPhase());
show
? new ShowAbilityPhase(pokemon.getBattlerIndex(), passive)
: new HideAbilityPhase(pokemon.getBattlerIndex(), passive),
);
this.clearPhaseQueueSplice(); this.clearPhaseQueueSplice();
} }
/**
* Hides the ability bar if it is currently visible
*/
public hideAbilityBar(): void {
if (this.abilityBar.isVisible()) {
this.unshiftPhase(new HideAbilityPhase());
}
}
/** /**
* Moves everything from nextCommandPhaseQueue to phaseQueue (keeping order) * Moves everything from nextCommandPhaseQueue to phaseQueue (keeping order)
*/ */
@ -3023,7 +2971,7 @@ export default class BattleScene extends SceneBase {
const args: unknown[] = []; const args: unknown[] = [];
if (modifier instanceof PokemonHpRestoreModifier) { if (modifier instanceof PokemonHpRestoreModifier) {
if (!(modifier as PokemonHpRestoreModifier).fainted) { if (!(modifier as PokemonHpRestoreModifier).fainted) {
const hpRestoreMultiplier = new Utils.NumberHolder(1); const hpRestoreMultiplier = new NumberHolder(1);
this.applyModifiers(HealingBoosterModifier, true, hpRestoreMultiplier); this.applyModifiers(HealingBoosterModifier, true, hpRestoreMultiplier);
args.push(hpRestoreMultiplier.value); args.push(hpRestoreMultiplier.value);
} else { } else {
@ -3031,7 +2979,7 @@ export default class BattleScene extends SceneBase {
} }
} else if (modifier instanceof FusePokemonModifier) { } else if (modifier instanceof FusePokemonModifier) {
args.push(this.getPokemonById(modifier.fusePokemonId) as PlayerPokemon); args.push(this.getPokemonById(modifier.fusePokemonId) as PlayerPokemon);
} else if (modifier instanceof RememberMoveModifier && !Utils.isNullOrUndefined(cost)) { } else if (modifier instanceof RememberMoveModifier && !isNullOrUndefined(cost)) {
args.push(cost); args.push(cost);
} }
@ -3100,7 +3048,7 @@ export default class BattleScene extends SceneBase {
itemLost = true, itemLost = true,
): boolean { ): boolean {
const source = itemModifier.pokemonId ? itemModifier.getPokemon() : null; const source = itemModifier.pokemonId ? itemModifier.getPokemon() : null;
const cancelled = new Utils.BooleanHolder(false); const cancelled = new BooleanHolder(false);
if (source && source.isPlayer() !== target.isPlayer()) { if (source && source.isPlayer() !== target.isPlayer()) {
applyAbAttrs(BlockItemTheftAbAttr, source, cancelled); applyAbAttrs(BlockItemTheftAbAttr, source, cancelled);
@ -3169,7 +3117,7 @@ export default class BattleScene extends SceneBase {
canTransferHeldItemModifier(itemModifier: PokemonHeldItemModifier, target: Pokemon, transferQuantity = 1): boolean { canTransferHeldItemModifier(itemModifier: PokemonHeldItemModifier, target: Pokemon, transferQuantity = 1): boolean {
const mod = itemModifier.clone() as PokemonHeldItemModifier; const mod = itemModifier.clone() as PokemonHeldItemModifier;
const source = mod.pokemonId ? mod.getPokemon() : null; const source = mod.pokemonId ? mod.getPokemon() : null;
const cancelled = new Utils.BooleanHolder(false); const cancelled = new BooleanHolder(false);
if (source && source.isPlayer() !== target.isPlayer()) { if (source && source.isPlayer() !== target.isPlayer()) {
applyAbAttrs(BlockItemTheftAbAttr, source, cancelled); applyAbAttrs(BlockItemTheftAbAttr, source, cancelled);
@ -3263,7 +3211,7 @@ export default class BattleScene extends SceneBase {
} }
let count = 0; let count = 0;
for (let c = 0; c < chances; c++) { for (let c = 0; c < chances; c++) {
if (!Utils.randSeedInt(this.gameMode.getEnemyModifierChance(isBoss))) { if (!randSeedInt(this.gameMode.getEnemyModifierChance(isBoss))) {
count++; count++;
} }
} }
@ -3439,7 +3387,7 @@ export default class BattleScene extends SceneBase {
if (mods.length < 1) { if (mods.length < 1) {
return mods; return mods;
} }
const rand = Utils.randSeedInt(mods.length); const rand = randSeedInt(mods.length);
return [mods[rand], ...shuffleModifiers(mods.filter((_, i) => i !== rand))]; return [mods[rand], ...shuffleModifiers(mods.filter((_, i) => i !== rand))];
}; };
modifiers = shuffleModifiers(modifiers); modifiers = shuffleModifiers(modifiers);
@ -3665,7 +3613,7 @@ export default class BattleScene extends SceneBase {
*/ */
initFinalBossPhaseTwo(pokemon: Pokemon): void { initFinalBossPhaseTwo(pokemon: Pokemon): void {
if (pokemon instanceof EnemyPokemon && pokemon.isBoss() && !pokemon.formIndex && pokemon.bossSegmentIndex < 1) { if (pokemon instanceof EnemyPokemon && pokemon.isBoss() && !pokemon.formIndex && pokemon.bossSegmentIndex < 1) {
this.fadeOutBgm(Utils.fixedInt(2000), false); this.fadeOutBgm(fixedInt(2000), false);
this.ui.showDialogue( this.ui.showDialogue(
battleSpecDialogue[BattleSpec.FINAL_BOSS].firstStageWin, battleSpecDialogue[BattleSpec.FINAL_BOSS].firstStageWin,
pokemon.species.name, pokemon.species.name,
@ -3768,7 +3716,7 @@ export default class BattleScene extends SceneBase {
if (Overrides.XP_MULTIPLIER_OVERRIDE !== null) { if (Overrides.XP_MULTIPLIER_OVERRIDE !== null) {
expMultiplier = Overrides.XP_MULTIPLIER_OVERRIDE; expMultiplier = Overrides.XP_MULTIPLIER_OVERRIDE;
} }
const pokemonExp = new Utils.NumberHolder(expValue * expMultiplier); const pokemonExp = new NumberHolder(expValue * expMultiplier);
this.applyModifiers(PokemonExpBoosterModifier, true, partyMember, pokemonExp); this.applyModifiers(PokemonExpBoosterModifier, true, partyMember, pokemonExp);
partyMemberExp.push(Math.floor(pokemonExp.value)); partyMemberExp.push(Math.floor(pokemonExp.value));
} }
@ -3917,7 +3865,7 @@ export default class BattleScene extends SceneBase {
while (i < this.mysteryEncounterSaveData.queuedEncounters.length && !!encounter) { while (i < this.mysteryEncounterSaveData.queuedEncounters.length && !!encounter) {
const candidate = this.mysteryEncounterSaveData.queuedEncounters[i]; const candidate = this.mysteryEncounterSaveData.queuedEncounters[i];
const forcedChance = candidate.spawnPercent; const forcedChance = candidate.spawnPercent;
if (Utils.randSeedInt(100) < forcedChance) { if (randSeedInt(100) < forcedChance) {
encounter = allMysteryEncounters[candidate.type]; encounter = allMysteryEncounters[candidate.type];
} }
@ -3950,7 +3898,7 @@ export default class BattleScene extends SceneBase {
} }
const totalWeight = tierWeights.reduce((a, b) => a + b); const totalWeight = tierWeights.reduce((a, b) => a + b);
const tierValue = Utils.randSeedInt(totalWeight); const tierValue = randSeedInt(totalWeight);
const commonThreshold = totalWeight - tierWeights[0]; const commonThreshold = totalWeight - tierWeights[0];
const greatThreshold = totalWeight - tierWeights[0] - tierWeights[1]; const greatThreshold = totalWeight - tierWeights[0] - tierWeights[1];
const ultraThreshold = totalWeight - tierWeights[0] - tierWeights[1] - tierWeights[2]; const ultraThreshold = totalWeight - tierWeights[0] - tierWeights[1] - tierWeights[2];
@ -4042,7 +3990,7 @@ export default class BattleScene extends SceneBase {
console.log("No Mystery Encounters found, falling back to Mysterious Challengers."); console.log("No Mystery Encounters found, falling back to Mysterious Challengers.");
return allMysteryEncounters[MysteryEncounterType.MYSTERIOUS_CHALLENGERS]; return allMysteryEncounters[MysteryEncounterType.MYSTERIOUS_CHALLENGERS];
} }
encounter = availableEncounters[Utils.randSeedInt(availableEncounters.length)]; encounter = availableEncounters[randSeedInt(availableEncounters.length)];
// New encounter object to not dirty flags // New encounter object to not dirty flags
encounter = new MysteryEncounter(encounter); encounter = new MysteryEncounter(encounter);
encounter.populateDialogueTokensFromRequirements(); encounter.populateDialogueTokensFromRequirements();

View File

@ -1,6 +1,14 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import type { Command } from "./ui/command-ui-handler"; import type { Command } from "./ui/command-ui-handler";
import * as Utils from "./utils"; import {
randomString,
getEnumValues,
NumberHolder,
randSeedInt,
shiftCharCodes,
randSeedItem,
randInt,
} from "#app/utils/common";
import Trainer, { TrainerVariant } from "./field/trainer"; import Trainer, { TrainerVariant } from "./field/trainer";
import type { GameMode } from "./game-mode"; import type { GameMode } from "./game-mode";
import { MoneyMultiplierModifier, PokemonHeldItemModifier } from "./modifier/modifier"; import { MoneyMultiplierModifier, PokemonHeldItemModifier } from "./modifier/modifier";
@ -22,36 +30,8 @@ import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
import type { CustomModifierSettings } from "#app/modifier/modifier-type"; import type { CustomModifierSettings } from "#app/modifier/modifier-type";
import { ModifierTier } from "#app/modifier/modifier-tier"; import { ModifierTier } from "#app/modifier/modifier-tier";
import type { MysteryEncounterType } from "#enums/mystery-encounter-type"; import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { BattleType } from "#enums/battle-type";
export enum ClassicFixedBossWaves { import { ClassicFixedBossWaves } from "#enums/fixed-boss-waves";
TOWN_YOUNGSTER = 5,
RIVAL_1 = 8,
RIVAL_2 = 25,
EVIL_GRUNT_1 = 35,
RIVAL_3 = 55,
EVIL_GRUNT_2 = 62,
EVIL_GRUNT_3 = 64,
EVIL_ADMIN_1 = 66,
RIVAL_4 = 95,
EVIL_GRUNT_4 = 112,
EVIL_ADMIN_2 = 114,
EVIL_BOSS_1 = 115,
RIVAL_5 = 145,
EVIL_BOSS_2 = 165,
ELITE_FOUR_1 = 182,
ELITE_FOUR_2 = 184,
ELITE_FOUR_3 = 186,
ELITE_FOUR_4 = 188,
CHAMPION = 190,
RIVAL_6 = 195,
}
export enum BattleType {
WILD,
TRAINER,
CLEAR,
MYSTERY_ENCOUNTER,
}
export enum BattlerIndex { export enum BattlerIndex {
ATTACKER = -1, ATTACKER = -1,
@ -99,7 +79,7 @@ export default class Battle {
public postBattleLoot: PokemonHeldItemModifier[] = []; public postBattleLoot: PokemonHeldItemModifier[] = [];
public escapeAttempts = 0; public escapeAttempts = 0;
public lastMove: Moves; public lastMove: Moves;
public battleSeed: string = Utils.randomString(16, true); public battleSeed: string = randomString(16, true);
private battleSeedState: string | null = null; private battleSeedState: string | null = null;
public moneyScattered = 0; public moneyScattered = 0;
/** Primarily for double battles, keeps track of last enemy and player pokemon that triggered its ability or used a move */ /** Primarily for double battles, keeps track of last enemy and player pokemon that triggered its ability or used a move */
@ -181,8 +161,8 @@ export default class Battle {
incrementTurn(): void { incrementTurn(): void {
this.turn++; this.turn++;
this.turnCommands = Object.fromEntries(Utils.getEnumValues(BattlerIndex).map(bt => [bt, null])); this.turnCommands = Object.fromEntries(getEnumValues(BattlerIndex).map(bt => [bt, null]));
this.preTurnCommands = Object.fromEntries(Utils.getEnumValues(BattlerIndex).map(bt => [bt, null])); this.preTurnCommands = Object.fromEntries(getEnumValues(BattlerIndex).map(bt => [bt, null]));
this.battleSeedState = null; this.battleSeedState = null;
} }
@ -211,7 +191,7 @@ export default class Battle {
} }
pickUpScatteredMoney(): void { pickUpScatteredMoney(): void {
const moneyAmount = new Utils.NumberHolder(globalScene.currentBattle.moneyScattered); const moneyAmount = new NumberHolder(globalScene.currentBattle.moneyScattered);
globalScene.applyModifiers(MoneyMultiplierModifier, true, moneyAmount); globalScene.applyModifiers(MoneyMultiplierModifier, true, moneyAmount);
if (globalScene.arena.getTag(ArenaTagType.HAPPY_HOUR)) { if (globalScene.arena.getTag(ArenaTagType.HAPPY_HOUR)) {
@ -448,7 +428,7 @@ export default class Battle {
} }
/** /**
* Generates a random number using the current battle's seed. Calls {@linkcode Utils.randSeedInt} * Generates a random number using the current battle's seed. Calls {@linkcode randSeedInt}
* @param range How large of a range of random numbers to choose from. If {@linkcode range} <= 1, returns {@linkcode min} * @param range How large of a range of random numbers to choose from. If {@linkcode range} <= 1, returns {@linkcode min}
* @param min The minimum integer to pick, default `0` * @param min The minimum integer to pick, default `0`
* @returns A random integer between {@linkcode min} and ({@linkcode min} + {@linkcode range} - 1) * @returns A random integer between {@linkcode min} and ({@linkcode min} + {@linkcode range} - 1)
@ -463,12 +443,12 @@ export default class Battle {
if (this.battleSeedState) { if (this.battleSeedState) {
Phaser.Math.RND.state(this.battleSeedState); Phaser.Math.RND.state(this.battleSeedState);
} else { } else {
Phaser.Math.RND.sow([Utils.shiftCharCodes(this.battleSeed, this.turn << 6)]); Phaser.Math.RND.sow([shiftCharCodes(this.battleSeed, this.turn << 6)]);
console.log("Battle Seed:", this.battleSeed); console.log("Battle Seed:", this.battleSeed);
} }
globalScene.rngCounter = this.rngCounter++; globalScene.rngCounter = this.rngCounter++;
globalScene.rngSeedOverride = this.battleSeed; globalScene.rngSeedOverride = this.battleSeed;
const ret = Utils.randSeedInt(range, min); const ret = randSeedInt(range, min);
this.battleSeedState = Phaser.Math.RND.state(); this.battleSeedState = Phaser.Math.RND.state();
Phaser.Math.RND.state(state); Phaser.Math.RND.state(state);
globalScene.rngCounter = tempRngCounter; globalScene.rngCounter = tempRngCounter;
@ -554,19 +534,19 @@ export function getRandomTrainerFunc(
seedOffset = 0, seedOffset = 0,
): GetTrainerFunc { ): GetTrainerFunc {
return () => { return () => {
const rand = Utils.randSeedInt(trainerPool.length); const rand = randSeedInt(trainerPool.length);
const trainerTypes: TrainerType[] = []; const trainerTypes: TrainerType[] = [];
globalScene.executeWithSeedOffset(() => { globalScene.executeWithSeedOffset(() => {
for (const trainerPoolEntry of trainerPool) { for (const trainerPoolEntry of trainerPool) {
const trainerType = Array.isArray(trainerPoolEntry) ? Utils.randSeedItem(trainerPoolEntry) : trainerPoolEntry; const trainerType = Array.isArray(trainerPoolEntry) ? randSeedItem(trainerPoolEntry) : trainerPoolEntry;
trainerTypes.push(trainerType); trainerTypes.push(trainerType);
} }
}, seedOffset); }, seedOffset);
let trainerGender = TrainerVariant.DEFAULT; let trainerGender = TrainerVariant.DEFAULT;
if (randomGender) { if (randomGender) {
trainerGender = Utils.randInt(2) === 0 ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT; trainerGender = randInt(2) === 0 ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT;
} }
/* 1/3 chance for evil team grunts to be double battles */ /* 1/3 chance for evil team grunts to be double battles */
@ -585,7 +565,7 @@ export function getRandomTrainerFunc(
const isEvilTeamGrunt = evilTeamGrunts.includes(trainerTypes[rand]); const isEvilTeamGrunt = evilTeamGrunts.includes(trainerTypes[rand]);
if (trainerConfigs[trainerTypes[rand]].hasDouble && isEvilTeamGrunt) { if (trainerConfigs[trainerTypes[rand]].hasDouble && isEvilTeamGrunt) {
return new Trainer(trainerTypes[rand], Utils.randInt(3) === 0 ? TrainerVariant.DOUBLE : trainerGender); return new Trainer(trainerTypes[rand], randInt(3) === 0 ? TrainerVariant.DOUBLE : trainerGender);
} }
return new Trainer(trainerTypes[rand], trainerGender); return new Trainer(trainerTypes[rand], trainerGender);
@ -608,7 +588,7 @@ export const classicFixedBattles: FixedBattleConfigs = {
[ClassicFixedBossWaves.TOWN_YOUNGSTER]: new FixedBattleConfig() [ClassicFixedBossWaves.TOWN_YOUNGSTER]: new FixedBattleConfig()
.setBattleType(BattleType.TRAINER) .setBattleType(BattleType.TRAINER)
.setGetTrainerFunc( .setGetTrainerFunc(
() => new Trainer(TrainerType.YOUNGSTER, Utils.randSeedInt(2) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT), () => new Trainer(TrainerType.YOUNGSTER, randSeedInt(2) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT),
), ),
[ClassicFixedBossWaves.RIVAL_1]: new FixedBattleConfig() [ClassicFixedBossWaves.RIVAL_1]: new FixedBattleConfig()
.setBattleType(BattleType.TRAINER) .setBattleType(BattleType.TRAINER)

View File

@ -2,10 +2,15 @@
export const PLAYER_PARTY_MAX_SIZE: number = 6; export const PLAYER_PARTY_MAX_SIZE: number = 6;
/** Whether to use seasonal splash messages in general */ /** Whether to use seasonal splash messages in general */
export const USE_SEASONAL_SPLASH_MESSAGES: boolean = false; export const USE_SEASONAL_SPLASH_MESSAGES: boolean = true;
/** Name of the session ID cookie */ /** Name of the session ID cookie */
export const SESSION_ID_COOKIE_NAME: string = "pokerogue_sessionId"; export const SESSION_ID_COOKIE_NAME: string = "pokerogue_sessionId";
/** Max value for an integer attribute in {@linkcode SystemSaveData} */ /** Max value for an integer attribute in {@linkcode SystemSaveData} */
export const MAX_INT_ATTR_VALUE = 0x80000000; export const MAX_INT_ATTR_VALUE = 0x80000000;
/** The min and max waves for mystery encounters to spawn in classic mode */
export const CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES: [number, number] = [10, 180] as const;
/** The min and max waves for mystery encounters to spawn in challenge mode */
export const CHALLENGE_MODE_MYSTERY_ENCOUNTER_WAVES: [number, number] = [10, 180] as const;

View File

@ -0,0 +1,54 @@
import type { AbAttrCondition } from "#app/@types/ability-types";
import type Pokemon from "#app/field/pokemon";
import type { BooleanHolder } from "#app/utils/common";
export abstract class AbAttr {
public showAbility: boolean;
private extraCondition: AbAttrCondition;
constructor(showAbility = true) {
this.showAbility = showAbility;
}
/**
* Applies ability effects without checking conditions
* @param _pokemon - The pokemon to apply this ability to
* @param _passive - Whether or not the ability is a passive
* @param _simulated - Whether the call is simulated
* @param _args - Extra args passed to the function. Handled by child classes.
* @see {@linkcode canApply}
*/
apply(
_pokemon: Pokemon,
_passive: boolean,
_simulated: boolean,
_cancelled: BooleanHolder | null,
_args: any[],
): void {}
getTriggerMessage(_pokemon: Pokemon, _abilityName: string, ..._args: any[]): string | null {
return null;
}
getCondition(): AbAttrCondition | null {
return this.extraCondition || null;
}
addCondition(condition: AbAttrCondition): AbAttr {
this.extraCondition = condition;
return this;
}
/**
* Returns a boolean describing whether the ability can be applied under current conditions
* @param _pokemon - The pokemon to apply this ability to
* @param _passive - Whether or not the ability is a passive
* @param _simulated - Whether the call is simulated
* @param _args - Extra args passed to the function. Handled by child classes.
* @returns `true` if the ability can be applied, `false` otherwise
* @see {@linkcode apply}
*/
canApply(_pokemon: Pokemon, _passive: boolean, _simulated: boolean, _args: any[]): boolean {
return true;
}
}

View File

@ -0,0 +1,137 @@
import { Abilities } from "#enums/abilities";
import type { AbAttrCondition } from "#app/@types/ability-types";
import type { AbAttr } from "#app/data/abilities/ab-attrs/ab-attr";
import i18next from "i18next";
import type { Localizable } from "#app/interfaces/locales";
import type { Constructor } from "#app/utils/common";
export class Ability implements Localizable {
public id: Abilities;
private nameAppend: string;
public name: string;
public description: string;
public generation: number;
public isBypassFaint: boolean;
public isIgnorable: boolean;
public isSuppressable = true;
public isCopiable = true;
public isReplaceable = true;
public attrs: AbAttr[];
public conditions: AbAttrCondition[];
constructor(id: Abilities, generation: number) {
this.id = id;
this.nameAppend = "";
this.generation = generation;
this.attrs = [];
this.conditions = [];
this.isSuppressable = true;
this.isCopiable = true;
this.isReplaceable = true;
this.localize();
}
public get isSwappable(): boolean {
return this.isCopiable && this.isReplaceable;
}
localize(): void {
const i18nKey = Abilities[this.id]
.split("_")
.filter(f => f)
.map((f, i) => (i ? `${f[0]}${f.slice(1).toLowerCase()}` : f.toLowerCase()))
.join("") as string;
this.name = this.id ? `${i18next.t(`ability:${i18nKey}.name`) as string}${this.nameAppend}` : "";
this.description = this.id ? (i18next.t(`ability:${i18nKey}.description`) as string) : "";
}
/**
* Get all ability attributes that match `attrType`
* @param attrType any attribute that extends {@linkcode AbAttr}
* @returns Array of attributes that match `attrType`, Empty Array if none match.
*/
getAttrs<T extends AbAttr>(attrType: Constructor<T>): T[] {
return this.attrs.filter((a): a is T => a instanceof attrType);
}
/**
* Check if an ability has an attribute that matches `attrType`
* @param attrType any attribute that extends {@linkcode AbAttr}
* @returns true if the ability has attribute `attrType`
*/
hasAttr<T extends AbAttr>(attrType: Constructor<T>): boolean {
return this.attrs.some(attr => attr instanceof attrType);
}
attr<T extends Constructor<AbAttr>>(AttrType: T, ...args: ConstructorParameters<T>): Ability {
const attr = new AttrType(...args);
this.attrs.push(attr);
return this;
}
conditionalAttr<T extends Constructor<AbAttr>>(
condition: AbAttrCondition,
AttrType: T,
...args: ConstructorParameters<T>
): Ability {
const attr = new AttrType(...args);
attr.addCondition(condition);
this.attrs.push(attr);
return this;
}
bypassFaint(): Ability {
this.isBypassFaint = true;
return this;
}
ignorable(): Ability {
this.isIgnorable = true;
return this;
}
unsuppressable(): Ability {
this.isSuppressable = false;
return this;
}
uncopiable(): Ability {
this.isCopiable = false;
return this;
}
unreplaceable(): Ability {
this.isReplaceable = false;
return this;
}
condition(condition: AbAttrCondition): Ability {
this.conditions.push(condition);
return this;
}
partial(): this {
this.nameAppend += " (P)";
return this;
}
unimplemented(): this {
this.nameAppend += " (N)";
return this;
}
/**
* Internal flag used for developers to document edge cases. When using this, please be sure to document the edge case.
* @returns the ability
*/
edgeCase(): this {
return this;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,13 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import type { Arena } from "#app/field/arena"; import type { Arena } from "#app/field/arena";
import { PokemonType } from "#enums/pokemon-type"; import { PokemonType } from "#enums/pokemon-type";
import { BooleanHolder, NumberHolder, toDmgValue } from "#app/utils"; import { BooleanHolder, NumberHolder, toDmgValue } from "#app/utils/common";
import { allMoves } from "#app/data/moves/move"; import { allMoves } from "#app/data/moves/move";
import { MoveTarget } from "#enums/MoveTarget"; import { MoveTarget } from "#enums/MoveTarget";
import { MoveCategory } from "#enums/MoveCategory"; import { MoveCategory } from "#enums/MoveCategory";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { HitResult, PokemonMove } from "#app/field/pokemon"; import { HitResult } from "#app/field/pokemon";
import { StatusEffect } from "#enums/status-effect"; import { StatusEffect } from "#enums/status-effect";
import type { BattlerIndex } from "#app/battle"; import type { BattlerIndex } from "#app/battle";
import { import {
@ -18,7 +18,7 @@ import {
applyAbAttrs, applyAbAttrs,
applyOnGainAbAttrs, applyOnGainAbAttrs,
applyOnLoseAbAttrs, applyOnLoseAbAttrs,
} from "#app/data/ability"; } from "#app/data/abilities/ability";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import { CommonAnim, CommonBattleAnim } from "#app/data/battle-anims"; import { CommonAnim, CommonBattleAnim } from "#app/data/battle-anims";
import i18next from "i18next"; import i18next from "i18next";
@ -28,7 +28,6 @@ import { BattlerTagType } from "#enums/battler-tag-type";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import { MoveEffectPhase } from "#app/phases/move-effect-phase";
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase"; import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
import { ShowAbilityPhase } from "#app/phases/show-ability-phase";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { CommonAnimPhase } from "#app/phases/common-anim-phase"; import { CommonAnimPhase } from "#app/phases/common-anim-phase";
@ -336,7 +335,7 @@ export class ConditionalProtectTag extends ArenaTag {
* @param arena the {@linkcode Arena} containing this tag * @param arena the {@linkcode Arena} containing this tag
* @param simulated `true` if the tag is applied quietly; `false` otherwise. * @param simulated `true` if the tag is applied quietly; `false` otherwise.
* @param isProtected a {@linkcode BooleanHolder} used to flag if the move is protected against * @param isProtected a {@linkcode BooleanHolder} used to flag if the move is protected against
* @param attacker the attacking {@linkcode Pokemon} * @param _attacker the attacking {@linkcode Pokemon}
* @param defender the defending {@linkcode Pokemon} * @param defender the defending {@linkcode Pokemon}
* @param moveId the {@linkcode Moves | identifier} for the move being used * @param moveId the {@linkcode Moves | identifier} for the move being used
* @param ignoresProtectBypass a {@linkcode BooleanHolder} used to flag if a protection effect supercedes effects that ignore protection * @param ignoresProtectBypass a {@linkcode BooleanHolder} used to flag if a protection effect supercedes effects that ignore protection
@ -346,7 +345,7 @@ export class ConditionalProtectTag extends ArenaTag {
arena: Arena, arena: Arena,
simulated: boolean, simulated: boolean,
isProtected: BooleanHolder, isProtected: BooleanHolder,
attacker: Pokemon, _attacker: Pokemon,
defender: Pokemon, defender: Pokemon,
moveId: Moves, moveId: Moves,
ignoresProtectBypass: BooleanHolder, ignoresProtectBypass: BooleanHolder,
@ -355,8 +354,6 @@ export class ConditionalProtectTag extends ArenaTag {
if (!isProtected.value) { if (!isProtected.value) {
isProtected.value = true; isProtected.value = true;
if (!simulated) { if (!simulated) {
attacker.stopMultiHit(defender);
new CommonBattleAnim(CommonAnim.PROTECT, defender).play(); new CommonBattleAnim(CommonAnim.PROTECT, defender).play();
globalScene.queueMessage( globalScene.queueMessage(
i18next.t("arenaTag:conditionalProtectApply", { i18next.t("arenaTag:conditionalProtectApply", {
@ -900,7 +897,7 @@ export class DelayedAttackTag extends ArenaTag {
if (!ret) { if (!ret) {
globalScene.unshiftPhase( globalScene.unshiftPhase(
new MoveEffectPhase(this.sourceId!, [this.targetIndex], new PokemonMove(this.sourceMove!, 0, 0, true)), new MoveEffectPhase(this.sourceId!, [this.targetIndex], allMoves[this.sourceMove!], false, true),
); // TODO: are those bangs correct? ); // TODO: are those bangs correct?
} }
@ -1160,9 +1157,11 @@ class TailwindTag extends ArenaTag {
); );
} }
// Raise attack by one stage if party member has WIND_RIDER ability // Raise attack by one stage if party member has WIND_RIDER ability
// TODO: Ability displays should be handled by the ability
if (pokemon.hasAbility(Abilities.WIND_RIDER)) { if (pokemon.hasAbility(Abilities.WIND_RIDER)) {
globalScene.unshiftPhase(new ShowAbilityPhase(pokemon.getBattlerIndex())); globalScene.queueAbilityDisplay(pokemon, false, true);
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [Stat.ATK], 1, true)); globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [Stat.ATK], 1, true));
globalScene.queueAbilityDisplay(pokemon, false, false);
} }
} }
} }

View File

@ -1,5 +1,5 @@
import { PokemonType } from "#enums/pokemon-type"; import { PokemonType } from "#enums/pokemon-type";
import * as Utils from "#app/utils"; import { randSeedInt, getEnumValues } from "#app/utils/common";
import type { SpeciesFormEvolution } from "#app/data/balance/pokemon-evolutions"; import type { SpeciesFormEvolution } from "#app/data/balance/pokemon-evolutions";
import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions"; import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions";
import i18next from "i18next"; import i18next from "i18next";
@ -7710,7 +7710,7 @@ export function initBiomes() {
if (biome === Biome.END) { if (biome === Biome.END) {
const biomeList = Object.keys(Biome).filter(key => !Number.isNaN(Number(key))); const biomeList = Object.keys(Biome).filter(key => !Number.isNaN(Number(key)));
biomeList.pop(); // Removes Biome.END from the list biomeList.pop(); // Removes Biome.END from the list
const randIndex = Utils.randSeedInt(biomeList.length, 1); // Will never be Biome.TOWN const randIndex = randSeedInt(biomeList.length, 1); // Will never be Biome.TOWN
biome = Biome[biomeList[randIndex]]; biome = Biome[biomeList[randIndex]];
} }
const linkedBiomes: (Biome | [ Biome, number ])[] = Array.isArray(biomeLinks[biome]) const linkedBiomes: (Biome | [ Biome, number ])[] = Array.isArray(biomeLinks[biome])
@ -7733,15 +7733,15 @@ export function initBiomes() {
traverseBiome(Biome.TOWN, 0); traverseBiome(Biome.TOWN, 0);
biomeDepths[Biome.END] = [ Object.values(biomeDepths).map(d => d[0]).reduce((max: number, value: number) => Math.max(max, value), 0) + 1, 1 ]; biomeDepths[Biome.END] = [ Object.values(biomeDepths).map(d => d[0]).reduce((max: number, value: number) => Math.max(max, value), 0) + 1, 1 ];
for (const biome of Utils.getEnumValues(Biome)) { for (const biome of getEnumValues(Biome)) {
biomePokemonPools[biome] = {}; biomePokemonPools[biome] = {};
biomeTrainerPools[biome] = {}; biomeTrainerPools[biome] = {};
for (const tier of Utils.getEnumValues(BiomePoolTier)) { for (const tier of getEnumValues(BiomePoolTier)) {
biomePokemonPools[biome][tier] = {}; biomePokemonPools[biome][tier] = {};
biomeTrainerPools[biome][tier] = []; biomeTrainerPools[biome][tier] = [];
for (const tod of Utils.getEnumValues(TimeOfDay)) { for (const tod of getEnumValues(TimeOfDay)) {
biomePokemonPools[biome][tier][tod] = []; biomePokemonPools[biome][tier][tod] = [];
} }
} }

View File

@ -1,5 +1,5 @@
import { allMoves } from "#app/data/moves/move"; import { allMoves } from "#app/data/moves/move";
import * as Utils from "#app/utils"; import { getEnumKeys, getEnumValues } from "#app/utils/common";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
@ -587,8 +587,8 @@ export const speciesEggMoves = {
function parseEggMoves(content: string): void { function parseEggMoves(content: string): void {
let output = ""; let output = "";
const speciesNames = Utils.getEnumKeys(Species); const speciesNames = getEnumKeys(Species);
const speciesValues = Utils.getEnumValues(Species); const speciesValues = getEnumValues(Species);
const lines = content.split(/\n/g); const lines = content.split(/\n/g);
for (const line of lines) { for (const line of lines) {

View File

@ -15,7 +15,7 @@ export const starterPassiveAbilities: StarterPassiveAbilities = {
[Species.VENUSAUR]: { 0: Abilities.GRASSY_SURGE, 1: Abilities.SEED_SOWER, 2: Abilities.FLOWER_VEIL }, [Species.VENUSAUR]: { 0: Abilities.GRASSY_SURGE, 1: Abilities.SEED_SOWER, 2: Abilities.FLOWER_VEIL },
[Species.CHARMANDER]: { 0: Abilities.SHEER_FORCE }, [Species.CHARMANDER]: { 0: Abilities.SHEER_FORCE },
[Species.CHARMELEON]: { 0: Abilities.BEAST_BOOST }, [Species.CHARMELEON]: { 0: Abilities.BEAST_BOOST },
[Species.CHARIZARD]: { 0: Abilities.BEAST_BOOST, 1: Abilities.LEVITATE, 2: Abilities.INTIMIDATE, 3: Abilities.UNNERVE }, [Species.CHARIZARD]: { 0: Abilities.BEAST_BOOST, 1: Abilities.LEVITATE, 2: Abilities.TURBOBLAZE, 3: Abilities.UNNERVE },
[Species.SQUIRTLE]: { 0: Abilities.DAUNTLESS_SHIELD }, [Species.SQUIRTLE]: { 0: Abilities.DAUNTLESS_SHIELD },
[Species.WARTORTLE]: { 0: Abilities.DAUNTLESS_SHIELD }, [Species.WARTORTLE]: { 0: Abilities.DAUNTLESS_SHIELD },
[Species.BLASTOISE]: { 0: Abilities.DAUNTLESS_SHIELD, 1: Abilities.BULLETPROOF, 2: Abilities.BULLETPROOF }, [Species.BLASTOISE]: { 0: Abilities.DAUNTLESS_SHIELD, 1: Abilities.BULLETPROOF, 2: Abilities.BULLETPROOF },
@ -154,14 +154,14 @@ export const starterPassiveAbilities: StarterPassiveAbilities = {
[Species.LEAFEON]: { 0: Abilities.GRASSY_SURGE }, [Species.LEAFEON]: { 0: Abilities.GRASSY_SURGE },
[Species.GLACEON]: { 0: Abilities.SNOW_WARNING }, [Species.GLACEON]: { 0: Abilities.SNOW_WARNING },
[Species.SYLVEON]: { 0: Abilities.COMPETITIVE }, [Species.SYLVEON]: { 0: Abilities.COMPETITIVE },
[Species.PORYGON]: { 0: Abilities.LEVITATE }, [Species.PORYGON]: { 0: Abilities.TRANSISTOR },
[Species.PORYGON2]: { 0: Abilities.LEVITATE }, [Species.PORYGON2]: { 0: Abilities.TRANSISTOR },
[Species.PORYGON_Z]: { 0: Abilities.PROTEAN }, [Species.PORYGON_Z]: { 0: Abilities.PROTEAN },
[Species.OMANYTE]: { 0: Abilities.STURDY }, [Species.OMANYTE]: { 0: Abilities.STURDY },
[Species.OMASTAR]: { 0: Abilities.STURDY }, [Species.OMASTAR]: { 0: Abilities.STURDY },
[Species.KABUTO]: { 0: Abilities.TOUGH_CLAWS }, [Species.KABUTO]: { 0: Abilities.TOUGH_CLAWS },
[Species.KABUTOPS]: { 0: Abilities.TOUGH_CLAWS }, [Species.KABUTOPS]: { 0: Abilities.TOUGH_CLAWS },
[Species.AERODACTYL]: { 0: Abilities.INTIMIDATE, 1: Abilities.DELTA_STREAM }, [Species.AERODACTYL]: { 0: Abilities.INTIMIDATE, 1: Abilities.INTIMIDATE },
[Species.ARTICUNO]: { 0: Abilities.SNOW_WARNING }, [Species.ARTICUNO]: { 0: Abilities.SNOW_WARNING },
[Species.ZAPDOS]: { 0: Abilities.DRIZZLE }, [Species.ZAPDOS]: { 0: Abilities.DRIZZLE },
[Species.MOLTRES]: { 0: Abilities.DROUGHT }, [Species.MOLTRES]: { 0: Abilities.DROUGHT },
@ -309,7 +309,7 @@ export const starterPassiveAbilities: StarterPassiveAbilities = {
[Species.SHIFTRY]: { 0: Abilities.SHARPNESS }, [Species.SHIFTRY]: { 0: Abilities.SHARPNESS },
[Species.TAILLOW]: { 0: Abilities.AERILATE }, [Species.TAILLOW]: { 0: Abilities.AERILATE },
[Species.SWELLOW]: { 0: Abilities.AERILATE }, [Species.SWELLOW]: { 0: Abilities.AERILATE },
[Species.WINGULL]: { 0: Abilities.DRIZZLE }, [Species.WINGULL]: { 0: Abilities.WATER_ABSORB },
[Species.PELIPPER]: { 0: Abilities.SWIFT_SWIM }, [Species.PELIPPER]: { 0: Abilities.SWIFT_SWIM },
[Species.RALTS]: { 0: Abilities.NEUROFORCE }, [Species.RALTS]: { 0: Abilities.NEUROFORCE },
[Species.KIRLIA]: { 0: Abilities.NEUROFORCE }, [Species.KIRLIA]: { 0: Abilities.NEUROFORCE },
@ -612,8 +612,8 @@ export const starterPassiveAbilities: StarterPassiveAbilities = {
[Species.REUNICLUS]: { 0: Abilities.PSYCHIC_SURGE }, [Species.REUNICLUS]: { 0: Abilities.PSYCHIC_SURGE },
[Species.DUCKLETT]: { 0: Abilities.DRIZZLE }, [Species.DUCKLETT]: { 0: Abilities.DRIZZLE },
[Species.SWANNA]: { 0: Abilities.DRIZZLE }, [Species.SWANNA]: { 0: Abilities.DRIZZLE },
[Species.VANILLITE]: { 0: Abilities.SNOW_WARNING }, [Species.VANILLITE]: { 0: Abilities.REFRIGERATE },
[Species.VANILLISH]: { 0: Abilities.SNOW_WARNING }, [Species.VANILLISH]: { 0: Abilities.REFRIGERATE },
[Species.VANILLUXE]: { 0: Abilities.SLUSH_RUSH }, [Species.VANILLUXE]: { 0: Abilities.SLUSH_RUSH },
[Species.DEERLING]: { 0: Abilities.FLOWER_VEIL, 1: Abilities.CUD_CHEW, 2: Abilities.HARVEST, 3: Abilities.FUR_COAT }, [Species.DEERLING]: { 0: Abilities.FLOWER_VEIL, 1: Abilities.CUD_CHEW, 2: Abilities.HARVEST, 3: Abilities.FUR_COAT },
[Species.SAWSBUCK]: { 0: Abilities.FLOWER_VEIL, 1: Abilities.CUD_CHEW, 2: Abilities.HARVEST, 3: Abilities.FUR_COAT }, [Species.SAWSBUCK]: { 0: Abilities.FLOWER_VEIL, 1: Abilities.CUD_CHEW, 2: Abilities.HARVEST, 3: Abilities.FUR_COAT },
@ -838,7 +838,7 @@ export const starterPassiveAbilities: StarterPassiveAbilities = {
[Species.CELESTEELA]: { 0: Abilities.HEATPROOF }, [Species.CELESTEELA]: { 0: Abilities.HEATPROOF },
[Species.KARTANA]: { 0: Abilities.TECHNICIAN }, [Species.KARTANA]: { 0: Abilities.TECHNICIAN },
[Species.GUZZLORD]: { 0: Abilities.POISON_HEAL }, [Species.GUZZLORD]: { 0: Abilities.POISON_HEAL },
[Species.NECROZMA]: { 0: Abilities.BEAST_BOOST, 1: Abilities.FULL_METAL_BODY, 2: Abilities.SHADOW_SHIELD, 3: Abilities.PRISM_ARMOR }, [Species.NECROZMA]: { 0: Abilities.BEAST_BOOST, 1: Abilities.FULL_METAL_BODY, 2: Abilities.SHADOW_SHIELD, 3: Abilities.UNNERVE },
[Species.MAGEARNA]: { 0: Abilities.STEELY_SPIRIT, 1: Abilities.STEELY_SPIRIT }, [Species.MAGEARNA]: { 0: Abilities.STEELY_SPIRIT, 1: Abilities.STEELY_SPIRIT },
[Species.MARSHADOW]: { 0: Abilities.IRON_FIST }, [Species.MARSHADOW]: { 0: Abilities.IRON_FIST },
[Species.POIPOLE]: { 0: Abilities.LEVITATE }, [Species.POIPOLE]: { 0: Abilities.LEVITATE },

View File

@ -3,7 +3,7 @@ import { Gender } from "#app/data/gender";
import { PokeballType } from "#enums/pokeball"; import { PokeballType } from "#enums/pokeball";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { PokemonType } from "#enums/pokemon-type"; import { PokemonType } from "#enums/pokemon-type";
import * as Utils from "#app/utils"; import { randSeedInt } from "#app/utils/common";
import { WeatherType } from "#enums/weather-type"; import { WeatherType } from "#enums/weather-type";
import { Nature } from "#enums/nature"; import { Nature } from "#enums/nature";
import { Biome } from "#enums/biome"; import { Biome } from "#enums/biome";
@ -14,6 +14,7 @@ import { DamageMoneyRewardModifier, ExtraModifierModifier, MoneyMultiplierModifi
import { SpeciesFormKey } from "#enums/species-form-key"; import { SpeciesFormKey } from "#enums/species-form-key";
import { speciesStarterCosts } from "./starters"; import { speciesStarterCosts } from "./starters";
import i18next from "i18next"; import i18next from "i18next";
import { initI18n } from "#app/plugins/i18n";
export enum SpeciesWildEvolutionDelay { export enum SpeciesWildEvolutionDelay {
@ -95,6 +96,9 @@ export class SpeciesFormEvolution {
public description = ""; public description = "";
constructor(speciesId: Species, preFormKey: string | null, evoFormKey: string | null, level: number, item: EvolutionItem | null, condition: SpeciesEvolutionCondition | null, wildDelay?: SpeciesWildEvolutionDelay) { constructor(speciesId: Species, preFormKey: string | null, evoFormKey: string | null, level: number, item: EvolutionItem | null, condition: SpeciesEvolutionCondition | null, wildDelay?: SpeciesWildEvolutionDelay) {
if (!i18next.isInitialized) {
initI18n();
}
this.speciesId = speciesId; this.speciesId = speciesId;
this.preFormKey = preFormKey; this.preFormKey = preFormKey;
this.evoFormKey = evoFormKey; this.evoFormKey = evoFormKey;
@ -333,7 +337,7 @@ class DunsparceEvolutionCondition extends SpeciesEvolutionCondition {
super(p => { super(p => {
let ret = false; let ret = false;
if (p.moveset.filter(m => m.moveId === Moves.HYPER_DRILL).length > 0) { if (p.moveset.filter(m => m.moveId === Moves.HYPER_DRILL).length > 0) {
globalScene.executeWithSeedOffset(() => ret = !Utils.randSeedInt(4), p.id); globalScene.executeWithSeedOffset(() => ret = !randSeedInt(4), p.id);
} }
return ret; return ret;
}); });
@ -346,7 +350,7 @@ class TandemausEvolutionCondition extends SpeciesEvolutionCondition {
constructor() { constructor() {
super(p => { super(p => {
let ret = false; let ret = false;
globalScene.executeWithSeedOffset(() => ret = !Utils.randSeedInt(4), p.id); globalScene.executeWithSeedOffset(() => ret = !randSeedInt(4), p.id);
return ret; return ret;
}); });
} }

View File

@ -11,87 +11,87 @@ export type SignatureSpecies = {
*/ */
export const signatureSpecies: SignatureSpecies = { export const signatureSpecies: SignatureSpecies = {
// Gym Leaders- Kanto // Gym Leaders- Kanto
BROCK: [Species.GEODUDE, Species.ONIX], BROCK: [Species.ONIX, Species.GEODUDE, [Species.OMANYTE, Species.KABUTO], Species.AERODACTYL],
MISTY: [Species.STARYU, Species.PSYDUCK], MISTY: [Species.STARYU, Species.PSYDUCK, Species.WOOPER, Species.LAPRAS],
LT_SURGE: [Species.VOLTORB, Species.PIKACHU, Species.ELECTABUZZ], LT_SURGE: [Species.PICHU, Species.VOLTORB, Species.ELEKID, Species.JOLTEON],
ERIKA: [Species.ODDISH, Species.BELLSPROUT, Species.TANGELA, Species.HOPPIP], ERIKA: [Species.ODDISH, Species.BELLSPROUT, Species.TANGELA, Species.HOPPIP],
JANINE: [Species.VENONAT, Species.SPINARAK, Species.ZUBAT], JANINE: [Species.VENONAT, Species.SPINARAK, Species.ZUBAT, Species.KOFFING],
SABRINA: [Species.ABRA, Species.MR_MIME, Species.ESPEON], SABRINA: [Species.ABRA, Species.MR_MIME, Species.SMOOCHUM, Species.ESPEON],
BLAINE: [Species.GROWLITHE, Species.PONYTA, Species.MAGMAR], BLAINE: [Species.GROWLITHE, Species.PONYTA, Species.MAGBY, Species.VULPIX],
GIOVANNI: [Species.SANDILE, Species.MURKROW, Species.NIDORAN_M, Species.NIDORAN_F], GIOVANNI: [Species.RHYHORN, Species.MEOWTH, [Species.NIDORAN_F, Species.NIDORAN_M], Species.DIGLETT], // Tera Ground Meowth
// Gym Leaders- Johto // Gym Leaders- Johto
FALKNER: [Species.PIDGEY, Species.HOOTHOOT, Species.DODUO], FALKNER: [Species.PIDGEY, Species.HOOTHOOT, Species.NATU, Species.MURKROW],
BUGSY: [Species.SCYTHER, Species.HERACROSS, Species.SHUCKLE, Species.PINSIR], BUGSY: [Species.SCYTHER, Species.SHUCKLE, Species.YANMA, [Species.PINSIR, Species.HERACROSS]],
WHITNEY: [Species.JIGGLYPUFF, Species.MILTANK, Species.AIPOM, Species.GIRAFARIG], WHITNEY: [Species.MILTANK, Species.AIPOM, Species.IGGLYBUFF, [Species.GIRAFARIG, Species.STANTLER]],
MORTY: [Species.GASTLY, Species.MISDREAVUS, Species.SABLEYE], MORTY: [Species.GASTLY, Species.MISDREAVUS, Species.DUSKULL, Species.SABLEYE],
CHUCK: [Species.POLIWRATH, Species.MANKEY], CHUCK: [Species.POLIWRATH, Species.MANKEY, Species.TYROGUE, Species.MACHOP],
JASMINE: [Species.MAGNEMITE, Species.STEELIX], JASMINE: [Species.STEELIX, Species.MAGNEMITE, Species.PINECO, Species.SKARMORY],
PRYCE: [Species.SEEL, Species.SWINUB], PRYCE: [Species.SWINUB, Species.SEEL, Species.SHELLDER, Species.SNEASEL],
CLAIR: [Species.DRATINI, Species.HORSEA, Species.GYARADOS], CLAIR: [Species.HORSEA, Species.DRATINI, Species.MAGIKARP, Species.DRUDDIGON], // Tera Dragon Magikarp
// Gym Leaders- Hoenn // Gym Leaders- Hoenn
ROXANNE: [Species.GEODUDE, Species.NOSEPASS], ROXANNE: [Species.NOSEPASS, Species.GEODUDE, [Species.LILEEP, Species.ANORITH], Species.ARON],
BRAWLY: [Species.MACHOP, Species.MAKUHITA], BRAWLY: [Species.MAKUHITA, Species.MACHOP, Species.MEDITITE, Species.SHROOMISH],
WATTSON: [Species.MAGNEMITE, Species.VOLTORB, Species.ELECTRIKE], WATTSON: [Species.ELECTRIKE, Species.VOLTORB, Species.MAGNEMITE, [Species.PLUSLE, Species.MINUN]],
FLANNERY: [Species.SLUGMA, Species.TORKOAL, Species.NUMEL], FLANNERY: [Species.TORKOAL, Species.SLUGMA, Species.NUMEL, Species.HOUNDOUR],
NORMAN: [Species.SLAKOTH, Species.SPINDA, Species.ZIGZAGOON, Species.KECLEON], NORMAN: [Species.SLAKOTH, Species.KECLEON, Species.WHISMUR, Species.ZANGOOSE],
WINONA: [Species.SWABLU, Species.WINGULL, Species.TROPIUS, Species.SKARMORY], WINONA: [Species.SWABLU, Species.WINGULL, Species.TROPIUS, Species.SKARMORY],
TATE: [Species.SOLROCK, Species.NATU, Species.CHIMECHO, Species.GALLADE], TATE: [Species.SOLROCK, Species.NATU, Species.CHINGLING, Species.GALLADE],
LIZA: [Species.LUNATONE, Species.SPOINK, Species.BALTOY, Species.GARDEVOIR], LIZA: [Species.LUNATONE, Species.BALTOY, Species.SPOINK, Species.GARDEVOIR],
JUAN: [Species.HORSEA, Species.BARBOACH, Species.SPHEAL, Species.RELICANTH], JUAN: [Species.HORSEA, Species.SPHEAL, Species.BARBOACH, Species.CORPHISH],
// Gym Leaders- Sinnoh // Gym Leaders- Sinnoh
ROARK: [Species.CRANIDOS, Species.LARVITAR, Species.GEODUDE], ROARK: [Species.CRANIDOS, Species.GEODUDE, Species.NOSEPASS, Species.LARVITAR],
GARDENIA: [Species.ROSELIA, Species.TANGELA, Species.TURTWIG], GARDENIA: [Species.BUDEW, Species.CHERUBI, Species.TURTWIG, Species.LEAFEON],
MAYLENE: [Species.LUCARIO, Species.MEDITITE, Species.CHIMCHAR], MAYLENE: [Species.RIOLU, Species.MEDITITE, Species.CHIMCHAR, Species.CROAGUNK],
CRASHER_WAKE: [Species.BUIZEL, Species.WOOPER, Species.PIPLUP, Species.MAGIKARP], CRASHER_WAKE: [Species.BUIZEL, Species.WOOPER, Species.PIPLUP, Species.MAGIKARP],
FANTINA: [Species.MISDREAVUS, Species.DRIFLOON, Species.SPIRITOMB], FANTINA: [Species.MISDREAVUS, Species.DRIFLOON, Species.DUSKULL, Species.SPIRITOMB],
BYRON: [Species.SHIELDON, Species.BRONZOR, Species.AGGRON], BYRON: [Species.SHIELDON, Species.BRONZOR, Species.ARON, Species.SKARMORY],
CANDICE: [Species.SNEASEL, Species.SNOVER, Species.SNORUNT], CANDICE: [Species.FROSLASS, Species.SNOVER, Species.SNEASEL, Species.GLACEON],
VOLKNER: [Species.SHINX, Species.CHINCHOU, Species.ROTOM], VOLKNER: [Species.ELEKID, Species.SHINX, Species.CHINCHOU, Species.ROTOM],
// Gym Leaders- Unova // Gym Leaders- Unova
CILAN: [Species.PANSAGE, Species.FOONGUS, Species.PETILIL], CILAN: [Species.PANSAGE, Species.SNIVY, Species.MARACTUS, Species.FERROSEED],
CHILI: [Species.PANSEAR, Species.DARUMAKA, Species.NUMEL], CHILI: [Species.PANSEAR, Species.TEPIG, Species.HEATMOR, Species.DARUMAKA],
CRESS: [Species.PANPOUR, Species.TYMPOLE, Species.SLOWPOKE], CRESS: [Species.PANPOUR, Species.OSHAWOTT, Species.BASCULIN, Species.TYMPOLE],
CHEREN: [Species.LILLIPUP, Species.MINCCINO, Species.PIDOVE], CHEREN: [Species.LILLIPUP, Species.MINCCINO, Species.PIDOVE, Species.BOUFFALANT],
LENORA: [Species.PATRAT, Species.DEERLING, Species.AUDINO], LENORA: [Species.PATRAT, Species.DEERLING, Species.AUDINO, Species.BRAVIARY],
ROXIE: [Species.VENIPEDE, Species.TRUBBISH, Species.SKORUPI], ROXIE: [Species.VENIPEDE, Species.KOFFING, Species.TRUBBISH, Species.TOXEL],
BURGH: [Species.SEWADDLE, Species.SHELMET, Species.KARRABLAST], BURGH: [Species.SEWADDLE, Species.DWEBBLE, [Species.KARRABLAST, Species.SHELMET], Species.DURANT],
ELESA: [Species.EMOLGA, Species.BLITZLE, Species.JOLTIK], ELESA: [Species.BLITZLE, Species.EMOLGA, Species.JOLTIK, Species.TYNAMO],
CLAY: [Species.DRILBUR, Species.SANDILE, Species.GOLETT], CLAY: [Species.DRILBUR, Species.SANDILE, Species.TYMPOLE, Species.GOLETT],
SKYLA: [Species.DUCKLETT, Species.WOOBAT, Species.RUFFLET], SKYLA: [Species.DUCKLETT, Species.WOOBAT, [Species.RUFFLET, Species.VULLABY], Species.ARCHEN],
BRYCEN: [Species.CRYOGONAL, Species.VANILLITE, Species.CUBCHOO], BRYCEN: [Species.CRYOGONAL, Species.VANILLITE, Species.CUBCHOO, Species.GALAR_DARUMAKA],
DRAYDEN: [Species.DRUDDIGON, Species.AXEW, Species.DEINO], DRAYDEN: [Species.AXEW, Species.DRUDDIGON, Species.TRAPINCH, Species.DEINO],
MARLON: [Species.WAILMER, Species.FRILLISH, Species.TIRTOUGA], MARLON: [Species.FRILLISH, Species.TIRTOUGA, Species.WAILMER, Species.MANTYKE],
// Gym Leaders- Kalos // Gym Leaders- Kalos
VIOLA: [Species.SURSKIT, Species.SCATTERBUG], VIOLA: [Species.SCATTERBUG, Species.SURSKIT, Species.CUTIEFLY, Species.BLIPBUG],
GRANT: [Species.AMAURA, Species.TYRUNT], GRANT: [Species.TYRUNT, Species.AMAURA, Species.BINACLE, Species.DWEBBLE],
KORRINA: [Species.HAWLUCHA, Species.LUCARIO, Species.MIENFOO], KORRINA: [Species.RIOLU, Species.MIENFOO, Species.HAWLUCHA, Species.PANCHAM],
RAMOS: [Species.SKIDDO, Species.HOPPIP, Species.BELLSPROUT], RAMOS: [Species.SKIDDO, Species.HOPPIP, Species.BELLSPROUT, [Species.PHANTUMP, Species.PUMPKABOO]],
CLEMONT: [Species.HELIOPTILE, Species.MAGNEMITE, Species.EMOLGA], CLEMONT: [Species.HELIOPTILE, Species.MAGNEMITE, Species.DEDENNE, Species.ROTOM],
VALERIE: [Species.SYLVEON, Species.MAWILE, Species.MR_MIME], VALERIE: [Species.SYLVEON, Species.MAWILE, Species.MR_MIME, [Species.SPRITZEE, Species.SWIRLIX]],
OLYMPIA: [Species.ESPURR, Species.SIGILYPH, Species.SLOWKING], OLYMPIA: [Species.ESPURR, Species.SIGILYPH, Species.INKAY, Species.SLOWKING],
WULFRIC: [Species.BERGMITE, Species.SNOVER, Species.CRYOGONAL], WULFRIC: [Species.BERGMITE, Species.SNOVER, Species.CRYOGONAL, Species.SWINUB],
// Gym Leaders- Galar // Gym Leaders- Galar
MILO: [Species.GOSSIFLEUR, Species.APPLIN, Species.BOUNSWEET], MILO: [Species.GOSSIFLEUR, Species.SEEDOT, Species.APPLIN, Species.LOTAD],
NESSA: [Species.CHEWTLE, Species.ARROKUDA, Species.WIMPOD], NESSA: [Species.CHEWTLE, Species.WIMPOD, Species.ARROKUDA, Species.MAREANIE],
KABU: [Species.SIZZLIPEDE, Species.VULPIX, Species.TORKOAL], KABU: [Species.SIZZLIPEDE, Species.VULPIX, Species.GROWLITHE, Species.TORKOAL],
BEA: [Species.GALAR_FARFETCHD, Species.MACHOP, Species.CLOBBOPUS], BEA: [Species.MACHOP, Species.GALAR_FARFETCHD, Species.CLOBBOPUS, Species.FALINKS],
ALLISTER: [Species.GALAR_YAMASK, Species.GALAR_CORSOLA, Species.GASTLY], ALLISTER: [Species.GASTLY, Species.GALAR_YAMASK, Species.GALAR_CORSOLA, Species.SINISTEA],
OPAL: [Species.MILCERY, Species.TOGETIC, Species.GALAR_WEEZING], OPAL: [Species.MILCERY, Species.GALAR_WEEZING, Species.TOGEPI, Species.MAWILE],
BEDE: [Species.HATENNA, Species.GALAR_PONYTA, Species.GARDEVOIR], BEDE: [Species.HATENNA, Species.GALAR_PONYTA, Species.GARDEVOIR, Species.SYLVEON],
GORDIE: [Species.ROLYCOLY, Species.STONJOURNER, Species.BINACLE], GORDIE: [Species.ROLYCOLY, [Species.SHUCKLE, Species.BINACLE], Species.STONJOURNER, Species.LARVITAR],
MELONY: [Species.SNOM, Species.GALAR_DARUMAKA, Species.GALAR_MR_MIME], MELONY: [Species.LAPRAS, Species.SNOM, Species.EISCUE, [Species.GALAR_MR_MIME, Species.GALAR_DARUMAKA]],
PIERS: [Species.GALAR_ZIGZAGOON, Species.SCRAGGY, Species.INKAY], PIERS: [Species.GALAR_ZIGZAGOON, Species.SCRAGGY, Species.TOXEL, Species.INKAY], // Tera Dark Toxel
MARNIE: [Species.IMPIDIMP, Species.PURRLOIN, Species.MORPEKO], MARNIE: [Species.IMPIDIMP, Species.MORPEKO, Species.PURRLOIN, Species.CROAGUNK], // Tera Dark Croagunk
RAIHAN: [Species.DURALUDON, Species.TURTONATOR, Species.GOOMY], RAIHAN: [Species.DURALUDON, Species.TRAPINCH, Species.GOOMY, Species.TURTONATOR],
// Gym Leaders- Paldea; First slot is Tera // Gym Leaders- Paldea; First slot is Tera
KATY: [Species.TEDDIURSA, Species.NYMBLE, Species.TAROUNTULA], // Tera Bug Teddiursa KATY: [Species.TEDDIURSA, Species.NYMBLE, Species.TAROUNTULA, Species.RELLOR], // Tera Bug Teddiursa
BRASSIUS: [Species.SUDOWOODO, Species.BRAMBLIN, Species.SMOLIV], // Tera Grass Sudowoodo BRASSIUS: [Species.BONSLY, Species.SMOLIV, Species.BRAMBLIN, Species.SUNKERN], // Tera Grass Bonsly
IONO: [Species.MISDREAVUS, Species.TADBULB, Species.WATTREL], // Tera Ghost Misdreavus IONO: [Species.MISDREAVUS, Species.TADBULB, Species.WATTREL, Species.MAGNEMITE], // Tera Ghost Misdreavus
KOFU: [Species.CRABRAWLER, Species.VELUZA, Species.WIGLETT, Species.WINGULL], // Tera Water Crabrawler KOFU: [Species.CRABRAWLER, Species.VELUZA, Species.WIGLETT, Species.WINGULL], // Tera Water Crabrawler
LARRY: [Species.STARLY, Species.DUNSPARCE, Species.LECHONK, Species.KOMALA], // Tera Normal Starly LARRY: [Species.STARLY, Species.DUNSPARCE, Species.LECHONK, Species.KOMALA], // Tera Normal Starly
RYME: [Species.TOXEL, Species.GREAVARD, Species.SHUPPET, Species.MIMIKYU], // Tera Ghost Toxel RYME: [Species.TOXEL, Species.GREAVARD, Species.SHUPPET, Species.MIMIKYU], // Tera Ghost Toxel
TULIP: [Species.FLABEBE, Species.FLITTLE, Species.RALTS, Species.GIRAFARIG], // Tera Psychic Flabebe TULIP: [Species.FLABEBE, Species.FLITTLE, Species.RALTS, Species.GIRAFARIG], // Tera Psychic Flabebe
GRUSHA: [Species.SWABLU, Species.CETODDLE, Species.CUBCHOO, Species.ALOLA_VULPIX], // Tera Ice Swablu GRUSHA: [Species.SWABLU, Species.CETODDLE, Species.SNOM, Species.CUBCHOO], // Tera Ice Swablu
// Elite Four- Kanto // Elite Four- Kanto
LORELEI: [ LORELEI: [

View File

@ -19126,6 +19126,8 @@ export const tmSpecies: TmSpecies = {
Species.KROOKODILE, Species.KROOKODILE,
Species.SCRAGGY, Species.SCRAGGY,
Species.SCRAFTY, Species.SCRAFTY,
Species.YAMASK,
Species.COFAGRIGUS,
Species.SAWSBUCK, Species.SAWSBUCK,
Species.LITWICK, Species.LITWICK,
Species.LAMPENT, Species.LAMPENT,
@ -19163,6 +19165,7 @@ export const tmSpecies: TmSpecies = {
Species.SINISTEA, Species.SINISTEA,
Species.POLTEAGEIST, Species.POLTEAGEIST,
Species.PERRSERKER, Species.PERRSERKER,
Species.RUNERIGUS,
Species.PINCURCHIN, Species.PINCURCHIN,
Species.STONJOURNER, Species.STONJOURNER,
Species.CUFANT, Species.CUFANT,
@ -19228,6 +19231,7 @@ export const tmSpecies: TmSpecies = {
Species.GALAR_SLOWBRO, Species.GALAR_SLOWBRO,
Species.GALAR_WEEZING, Species.GALAR_WEEZING,
Species.GALAR_SLOWKING, Species.GALAR_SLOWKING,
Species.GALAR_YAMASK,
Species.HISUI_ELECTRODE, Species.HISUI_ELECTRODE,
Species.HISUI_TYPHLOSION, Species.HISUI_TYPHLOSION,
Species.HISUI_QWILFISH, Species.HISUI_QWILFISH,
@ -30922,6 +30926,7 @@ export const tmSpecies: TmSpecies = {
Species.MURKROW, Species.MURKROW,
Species.SLOWKING, Species.SLOWKING,
Species.MISDREAVUS, Species.MISDREAVUS,
Species.UNOWN,
Species.GIRAFARIG, Species.GIRAFARIG,
Species.PINECO, Species.PINECO,
Species.FORRETRESS, Species.FORRETRESS,
@ -40134,6 +40139,8 @@ export const tmSpecies: TmSpecies = {
Species.MEOWSTIC, Species.MEOWSTIC,
Species.SPRITZEE, Species.SPRITZEE,
Species.AROMATISSE, Species.AROMATISSE,
Species.INKAY,
Species.MALAMAR,
Species.SYLVEON, Species.SYLVEON,
Species.CARBINK, Species.CARBINK,
Species.PHANTUMP, Species.PHANTUMP,
@ -49173,6 +49180,7 @@ export const tmSpecies: TmSpecies = {
Species.KANGASKHAN, Species.KANGASKHAN,
Species.GOLDEEN, Species.GOLDEEN,
Species.SEAKING, Species.SEAKING,
Species.GYARADOS,
Species.LAPRAS, Species.LAPRAS,
Species.VAPOREON, Species.VAPOREON,
Species.KABUTOPS, Species.KABUTOPS,
@ -52587,6 +52595,7 @@ export const tmSpecies: TmSpecies = {
Species.SNORLAX, Species.SNORLAX,
Species.MEWTWO, Species.MEWTWO,
Species.MEW, Species.MEW,
Species.MEGANIUM,
Species.CYNDAQUIL, Species.CYNDAQUIL,
Species.QUILAVA, Species.QUILAVA,
Species.TYPHLOSION, Species.TYPHLOSION,
@ -66205,7 +66214,11 @@ export const tmSpecies: TmSpecies = {
Species.SQUIRTLE, Species.SQUIRTLE,
Species.WARTORTLE, Species.WARTORTLE,
Species.BLASTOISE, Species.BLASTOISE,
Species.CATERPIE,
Species.METAPOD,
Species.BUTTERFREE, Species.BUTTERFREE,
Species.WEEDLE,
Species.KAKUNA,
Species.BEEDRILL, Species.BEEDRILL,
Species.PIDGEY, Species.PIDGEY,
Species.PIDGEOTTO, Species.PIDGEOTTO,
@ -66451,7 +66464,10 @@ export const tmSpecies: TmSpecies = {
Species.MIGHTYENA, Species.MIGHTYENA,
Species.ZIGZAGOON, Species.ZIGZAGOON,
Species.LINOONE, Species.LINOONE,
Species.WURMPLE,
Species.SILCOON,
Species.BEAUTIFLY, Species.BEAUTIFLY,
Species.CASCOON,
Species.DUSTOX, Species.DUSTOX,
Species.LOTAD, Species.LOTAD,
Species.LOMBRE, Species.LOMBRE,
@ -66987,6 +67003,8 @@ export const tmSpecies: TmSpecies = {
Species.STAKATAKA, Species.STAKATAKA,
Species.BLACEPHALON, Species.BLACEPHALON,
Species.ZERAORA, Species.ZERAORA,
Species.MELTAN,
Species.MELMETAL,
Species.ALOLA_RATTATA, Species.ALOLA_RATTATA,
Species.ALOLA_RATICATE, Species.ALOLA_RATICATE,
Species.ALOLA_RAICHU, Species.ALOLA_RAICHU,
@ -67020,8 +67038,19 @@ export const tmSpecies: TmSpecies = {
Species.ROOKIDEE, Species.ROOKIDEE,
Species.CORVISQUIRE, Species.CORVISQUIRE,
Species.CORVIKNIGHT, Species.CORVIKNIGHT,
Species.BLIPBUG,
Species.DOTTLER,
Species.ORBEETLE,
Species.NICKIT,
Species.THIEVUL,
Species.GOSSIFLEUR,
Species.ELDEGOSS,
Species.WOOLOO,
Species.DUBWOOL,
Species.CHEWTLE, Species.CHEWTLE,
Species.DREDNAW, Species.DREDNAW,
Species.YAMPER,
Species.BOLTUND,
Species.ROLYCOLY, Species.ROLYCOLY,
Species.CARKOL, Species.CARKOL,
Species.COALOSSAL, Species.COALOSSAL,
@ -67035,6 +67064,10 @@ export const tmSpecies: TmSpecies = {
Species.BARRASKEWDA, Species.BARRASKEWDA,
Species.TOXEL, Species.TOXEL,
Species.TOXTRICITY, Species.TOXTRICITY,
Species.SIZZLIPEDE,
Species.CENTISKORCH,
Species.CLOBBOPUS,
Species.GRAPPLOCT,
Species.SINISTEA, Species.SINISTEA,
Species.POLTEAGEIST, Species.POLTEAGEIST,
Species.HATENNA, Species.HATENNA,
@ -67043,7 +67076,14 @@ export const tmSpecies: TmSpecies = {
Species.IMPIDIMP, Species.IMPIDIMP,
Species.MORGREM, Species.MORGREM,
Species.GRIMMSNARL, Species.GRIMMSNARL,
Species.OBSTAGOON,
Species.PERRSERKER, Species.PERRSERKER,
Species.CURSOLA,
Species.SIRFETCHD,
Species.MR_RIME,
Species.RUNERIGUS,
Species.MILCERY,
Species.ALCREMIE,
Species.FALINKS, Species.FALINKS,
Species.PINCURCHIN, Species.PINCURCHIN,
Species.SNOM, Species.SNOM,
@ -67054,6 +67094,11 @@ export const tmSpecies: TmSpecies = {
Species.MORPEKO, Species.MORPEKO,
Species.CUFANT, Species.CUFANT,
Species.COPPERAJAH, Species.COPPERAJAH,
Species.DRACOZOLT,
Species.ARCTOZOLT,
Species.DRACOVISH,
Species.ARCTOVISH,
Species.DURALUDON,
Species.DREEPY, Species.DREEPY,
Species.DRAKLOAK, Species.DRAKLOAK,
Species.DRAGAPULT, Species.DRAGAPULT,
@ -67195,13 +67240,24 @@ export const tmSpecies: TmSpecies = {
Species.IRON_CROWN, Species.IRON_CROWN,
Species.PECHARUNT, Species.PECHARUNT,
Species.GALAR_MEOWTH, Species.GALAR_MEOWTH,
Species.GALAR_PONYTA,
Species.GALAR_RAPIDASH,
Species.GALAR_SLOWPOKE, Species.GALAR_SLOWPOKE,
Species.GALAR_SLOWBRO, Species.GALAR_SLOWBRO,
Species.GALAR_FARFETCHD,
Species.GALAR_WEEZING, Species.GALAR_WEEZING,
Species.GALAR_MR_MIME,
Species.GALAR_ARTICUNO, Species.GALAR_ARTICUNO,
Species.GALAR_ZAPDOS, Species.GALAR_ZAPDOS,
Species.GALAR_MOLTRES, Species.GALAR_MOLTRES,
Species.GALAR_SLOWKING, Species.GALAR_SLOWKING,
Species.GALAR_CORSOLA,
Species.GALAR_ZIGZAGOON,
Species.GALAR_LINOONE,
Species.GALAR_DARUMAKA,
Species.GALAR_DARMANITAN,
Species.GALAR_YAMASK,
Species.GALAR_STUNFISK,
Species.HISUI_GROWLITHE, Species.HISUI_GROWLITHE,
Species.HISUI_ARCANINE, Species.HISUI_ARCANINE,
Species.HISUI_VOLTORB, Species.HISUI_VOLTORB,

View File

@ -2,11 +2,11 @@ import { globalScene } from "#app/global-scene";
import { AttackMove, BeakBlastHeaderAttr, DelayedAttackAttr, SelfStatusMove, allMoves } from "./moves/move"; import { AttackMove, BeakBlastHeaderAttr, DelayedAttackAttr, SelfStatusMove, allMoves } from "./moves/move";
import { MoveFlags } from "#enums/MoveFlags"; import { MoveFlags } from "#enums/MoveFlags";
import type Pokemon from "../field/pokemon"; import type Pokemon from "../field/pokemon";
import { type nil, getFrameMs, getEnumKeys, getEnumValues, animationFileName } from "../utils"; import { type nil, getFrameMs, getEnumKeys, getEnumValues, animationFileName } from "../utils/common";
import type { BattlerIndex } from "../battle"; import type { BattlerIndex } from "../battle";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { SubstituteTag } from "./battler-tags"; import { SubstituteTag } from "./battler-tags";
import { isNullOrUndefined } from "../utils"; import { isNullOrUndefined } from "../utils/common";
import Phaser from "phaser"; import Phaser from "phaser";
import { EncounterAnim } from "#enums/encounter-anims"; import { EncounterAnim } from "#enums/encounter-anims";
@ -1428,7 +1428,8 @@ export class MoveAnim extends BattleAnim {
public move: Moves; public move: Moves;
constructor(move: Moves, user: Pokemon, target: BattlerIndex, playOnEmptyField = false) { constructor(move: Moves, user: Pokemon, target: BattlerIndex, playOnEmptyField = false) {
super(user, globalScene.getField()[target], playOnEmptyField); // Set target to the user pokemon if no target is found to avoid crashes
super(user, globalScene.getField()[target] ?? user, playOnEmptyField);
this.move = move; this.move = move;
} }

View File

@ -1,13 +1,13 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { import {
allAbilities,
applyAbAttrs, applyAbAttrs,
BlockNonDirectDamageAbAttr, BlockNonDirectDamageAbAttr,
FlinchEffectAbAttr, FlinchEffectAbAttr,
ProtectStatAbAttr, ProtectStatAbAttr,
ConditionalUserFieldProtectStatAbAttr, ConditionalUserFieldProtectStatAbAttr,
ReverseDrainAbAttr, ReverseDrainAbAttr,
} from "#app/data/ability"; } from "#app/data/abilities/ability";
import { allAbilities } from "./data-lists";
import { ChargeAnim, CommonAnim, CommonBattleAnim, MoveChargeAnim } from "#app/data/battle-anims"; import { ChargeAnim, CommonAnim, CommonBattleAnim, MoveChargeAnim } from "#app/data/battle-anims";
import type Move from "#app/data/moves/move"; import type Move from "#app/data/moves/move";
import { import {
@ -30,11 +30,10 @@ import { CommonAnimPhase } from "#app/phases/common-anim-phase";
import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import { MoveEffectPhase } from "#app/phases/move-effect-phase";
import { MovePhase } from "#app/phases/move-phase"; import { MovePhase } from "#app/phases/move-phase";
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase"; import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
import { ShowAbilityPhase } from "#app/phases/show-ability-phase";
import type { StatStageChangeCallback } from "#app/phases/stat-stage-change-phase"; import type { StatStageChangeCallback } from "#app/phases/stat-stage-change-phase";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import i18next from "#app/plugins/i18n"; import i18next from "#app/plugins/i18n";
import { BooleanHolder, getFrameMs, NumberHolder, toDmgValue } from "#app/utils"; import { BooleanHolder, getFrameMs, NumberHolder, toDmgValue } from "#app/utils/common";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
@ -43,7 +42,7 @@ import { Species } from "#enums/species";
import { EFFECTIVE_STATS, getStatKey, Stat, type BattleStat, type EffectiveStat } from "#enums/stat"; import { EFFECTIVE_STATS, getStatKey, Stat, type BattleStat, type EffectiveStat } from "#enums/stat";
import { StatusEffect } from "#enums/status-effect"; import { StatusEffect } from "#enums/status-effect";
import { WeatherType } from "#enums/weather-type"; import { WeatherType } from "#enums/weather-type";
import * as Utils from "../utils"; import { isNullOrUndefined } from "#app/utils/common";
export enum BattlerTagLapseType { export enum BattlerTagLapseType {
FAINT, FAINT,
@ -53,6 +52,7 @@ export enum BattlerTagLapseType {
MOVE_EFFECT, MOVE_EFFECT,
TURN_END, TURN_END,
HIT, HIT,
/** Tag lapses AFTER_HIT, applying its effects even if the user faints */
AFTER_HIT, AFTER_HIT,
CUSTOM, CUSTOM,
} }
@ -303,7 +303,7 @@ export class DisabledTag extends MoveRestrictionBattlerTag {
super.onAdd(pokemon); super.onAdd(pokemon);
const move = pokemon.getLastXMoves(-1).find(m => !m.virtual); const move = pokemon.getLastXMoves(-1).find(m => !m.virtual);
if (Utils.isNullOrUndefined(move) || move.move === Moves.STRUGGLE || move.move === Moves.NONE) { if (isNullOrUndefined(move) || move.move === Moves.STRUGGLE || move.move === Moves.NONE) {
return; return;
} }
@ -499,7 +499,13 @@ export class BeakBlastChargingTag extends BattlerTag {
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
if (lapseType === BattlerTagLapseType.AFTER_HIT) { if (lapseType === BattlerTagLapseType.AFTER_HIT) {
const phaseData = getMoveEffectPhaseData(pokemon); const phaseData = getMoveEffectPhaseData(pokemon);
if (phaseData?.move.hasFlag(MoveFlags.MAKES_CONTACT)) { if (
phaseData?.move.doesFlagEffectApply({
flag: MoveFlags.MAKES_CONTACT,
user: phaseData.attacker,
target: pokemon,
})
) {
phaseData.attacker.trySetStatus(StatusEffect.BURN, true, pokemon); phaseData.attacker.trySetStatus(StatusEffect.BURN, true, pokemon);
} }
return true; return true;
@ -1612,19 +1618,50 @@ export class ProtectedTag extends BattlerTag {
} }
} }
/** Base class for `BattlerTag`s that block damaging moves but not status moves */ /** Class for `BattlerTag`s that apply some effect when hit by a contact move */
export class DamageProtectedTag extends ProtectedTag {} export class ContactProtectedTag extends ProtectedTag {
/**
* Function to call when a contact move hits the pokemon with this tag.
* @param _attacker - The pokemon using the contact move
* @param _user - The pokemon that is being attacked and has the tag
* @param _move - The move used by the attacker
*/
onContact(_attacker: Pokemon, _user: Pokemon) {}
/**
* Lapse the tag and apply `onContact` if the move makes contact and
* `lapseType` is custom, respecting the move's flags and the pokemon's
* abilities, and whether the lapseType is custom.
*
* @param pokemon - The pokemon with the tag
* @param lapseType - The type of lapse to apply. If this is not {@linkcode BattlerTagLapseType.CUSTOM CUSTOM}, no effect will be applied.
* @returns Whether the tag continues to exist after the lapse.
*/
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
const ret = super.lapse(pokemon, lapseType);
const moveData = getMoveEffectPhaseData(pokemon);
if (
lapseType === BattlerTagLapseType.CUSTOM &&
moveData &&
moveData.move.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user: moveData.attacker, target: pokemon })
) {
this.onContact(moveData.attacker, pokemon);
}
return ret;
}
}
/** /**
* `BattlerTag` class for moves that block damaging moves damage the enemy if the enemy's move makes contact * `BattlerTag` class for moves that block damaging moves damage the enemy if the enemy's move makes contact
* Used by {@linkcode Moves.SPIKY_SHIELD} * Used by {@linkcode Moves.SPIKY_SHIELD}
*/ */
export class ContactDamageProtectedTag extends ProtectedTag { export class ContactDamageProtectedTag extends ContactProtectedTag {
private damageRatio: number; private damageRatio: number;
constructor(sourceMove: Moves, damageRatio: number) { constructor(sourceMove: Moves, damageRatio: number) {
super(sourceMove, BattlerTagType.SPIKY_SHIELD); super(sourceMove, BattlerTagType.SPIKY_SHIELD);
this.damageRatio = damageRatio; this.damageRatio = damageRatio;
} }
@ -1637,14 +1674,15 @@ export class ContactDamageProtectedTag extends ProtectedTag {
this.damageRatio = source.damageRatio; this.damageRatio = source.damageRatio;
} }
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { /**
const ret = super.lapse(pokemon, lapseType); * Damage the attacker by `this.damageRatio` of the target's max HP
* @param attacker - The pokemon using the contact move
if (lapseType === BattlerTagLapseType.CUSTOM) { * @param user - The pokemon that is being attacked and has the tag
const effectPhase = globalScene.getCurrentPhase(); */
if (effectPhase instanceof MoveEffectPhase && effectPhase.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) { override onContact(attacker: Pokemon, user: Pokemon): void {
const attacker = effectPhase.getPokemon(); const cancelled = new BooleanHolder(false);
if (!attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) { applyAbAttrs(BlockNonDirectDamageAbAttr, user, cancelled);
if (!cancelled.value) {
attacker.damageAndUpdate(toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)), { attacker.damageAndUpdate(toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)), {
result: HitResult.INDIRECT, result: HitResult.INDIRECT,
}); });
@ -1652,7 +1690,30 @@ export class ContactDamageProtectedTag extends ProtectedTag {
} }
} }
return ret; /** Base class for `BattlerTag`s that block damaging moves but not status moves */
export class DamageProtectedTag extends ContactProtectedTag {}
export class ContactSetStatusProtectedTag extends DamageProtectedTag {
/**
* @param sourceMove The move that caused the tag to be applied
* @param tagType The type of the tag
* @param statusEffect The status effect to apply to the attacker
*/
constructor(
sourceMove: Moves,
tagType: BattlerTagType,
private statusEffect: StatusEffect,
) {
super(sourceMove, tagType);
}
/**
* Set the status effect on the attacker
* @param attacker - The pokemon using the contact move
* @param user - The pokemon that is being attacked and has the tag
*/
override onContact(attacker: Pokemon, user: Pokemon): void {
attacker.trySetStatus(this.statusEffect, true, user);
} }
} }
@ -1675,68 +1736,19 @@ export class ContactStatStageChangeProtectedTag extends DamageProtectedTag {
* When given a battler tag or json representing one, load the data for it. * When given a battler tag or json representing one, load the data for it.
* @param {BattlerTag | any} source A battler tag * @param {BattlerTag | any} source A battler tag
*/ */
loadTag(source: BattlerTag | any): void { override loadTag(source: BattlerTag | any): void {
super.loadTag(source); super.loadTag(source);
this.stat = source.stat; this.stat = source.stat;
this.levels = source.levels; this.levels = source.levels;
} }
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
const ret = super.lapse(pokemon, lapseType);
if (lapseType === BattlerTagLapseType.CUSTOM) {
const effectPhase = globalScene.getCurrentPhase();
if (effectPhase instanceof MoveEffectPhase && effectPhase.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) {
const attacker = effectPhase.getPokemon();
globalScene.unshiftPhase(new StatStageChangePhase(attacker.getBattlerIndex(), false, [this.stat], this.levels));
}
}
return ret;
}
}
export class ContactPoisonProtectedTag extends ProtectedTag {
constructor(sourceMove: Moves) {
super(sourceMove, BattlerTagType.BANEFUL_BUNKER);
}
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
const ret = super.lapse(pokemon, lapseType);
if (lapseType === BattlerTagLapseType.CUSTOM) {
const effectPhase = globalScene.getCurrentPhase();
if (effectPhase instanceof MoveEffectPhase && effectPhase.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) {
const attacker = effectPhase.getPokemon();
attacker.trySetStatus(StatusEffect.POISON, true, pokemon);
}
}
return ret;
}
}
/** /**
* `BattlerTag` class for moves that block damaging moves and burn the enemy if the enemy's move makes contact * Initiate the stat stage change on the attacker
* Used by {@linkcode Moves.BURNING_BULWARK} * @param attacker - The pokemon using the contact move
* @param user - The pokemon that is being attacked and has the tag
*/ */
export class ContactBurnProtectedTag extends DamageProtectedTag { override onContact(attacker: Pokemon, _user: Pokemon): void {
constructor(sourceMove: Moves) { globalScene.unshiftPhase(new StatStageChangePhase(attacker.getBattlerIndex(), false, [this.stat], this.levels));
super(sourceMove, BattlerTagType.BURNING_BULWARK);
}
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
const ret = super.lapse(pokemon, lapseType);
if (lapseType === BattlerTagLapseType.CUSTOM) {
const effectPhase = globalScene.getCurrentPhase();
if (effectPhase instanceof MoveEffectPhase && effectPhase.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) {
const attacker = effectPhase.getPokemon();
attacker.trySetStatus(StatusEffect.BURN, true);
}
}
return ret;
} }
} }
@ -1901,12 +1913,14 @@ export class TruantTag extends AbilityBattlerTag {
if (lastMove && lastMove.move !== Moves.NONE) { if (lastMove && lastMove.move !== Moves.NONE) {
(globalScene.getCurrentPhase() as MovePhase).cancel(); (globalScene.getCurrentPhase() as MovePhase).cancel();
globalScene.unshiftPhase(new ShowAbilityPhase(pokemon.id, passive)); // TODO: Ability displays should be handled by the ability
globalScene.queueAbilityDisplay(pokemon, passive, true);
globalScene.queueMessage( globalScene.queueMessage(
i18next.t("battlerTags:truantLapse", { i18next.t("battlerTags:truantLapse", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}), }),
); );
globalScene.queueAbilityDisplay(pokemon, passive, false);
} }
return true; return true;
@ -2623,7 +2637,7 @@ export class GulpMissileTag extends BattlerTag {
return false; return false;
} }
if (moveEffectPhase.move.getMove().hitsSubstitute(attacker, pokemon)) { if (moveEffectPhase.move.hitsSubstitute(attacker, pokemon)) {
return true; return true;
} }
@ -2979,7 +2993,7 @@ export class SubstituteTag extends BattlerTag {
if (!attacker) { if (!attacker) {
return; return;
} }
const move = moveEffectPhase.move.getMove(); const move = moveEffectPhase.move;
const firstHit = attacker.turnData.hitCount === attacker.turnData.hitsLeft; const firstHit = attacker.turnData.hitCount === attacker.turnData.hitsLeft;
if (firstHit && move.hitsSubstitute(attacker, pokemon)) { if (firstHit && move.hitsSubstitute(attacker, pokemon)) {
@ -3517,9 +3531,9 @@ export function getBattlerTag(
case BattlerTagType.SILK_TRAP: case BattlerTagType.SILK_TRAP:
return new ContactStatStageChangeProtectedTag(sourceMove, tagType, Stat.SPD, -1); return new ContactStatStageChangeProtectedTag(sourceMove, tagType, Stat.SPD, -1);
case BattlerTagType.BANEFUL_BUNKER: case BattlerTagType.BANEFUL_BUNKER:
return new ContactPoisonProtectedTag(sourceMove); return new ContactSetStatusProtectedTag(sourceMove, tagType, StatusEffect.POISON);
case BattlerTagType.BURNING_BULWARK: case BattlerTagType.BURNING_BULWARK:
return new ContactBurnProtectedTag(sourceMove); return new ContactSetStatusProtectedTag(sourceMove, tagType, StatusEffect.BURN);
case BattlerTagType.ENDURING: case BattlerTagType.ENDURING:
return new EnduringTag(tagType, BattlerTagLapseType.TURN_END, sourceMove); return new EnduringTag(tagType, BattlerTagLapseType.TURN_END, sourceMove);
case BattlerTagType.ENDURE_TOKEN: case BattlerTagType.ENDURE_TOKEN:
@ -3667,7 +3681,7 @@ function getMoveEffectPhaseData(_pokemon: Pokemon): { phase: MoveEffectPhase; at
return { return {
phase: phase, phase: phase,
attacker: phase.getPokemon(), attacker: phase.getPokemon(),
move: phase.move.getMove(), move: phase.move,
}; };
} }
return null; return null;

View File

@ -2,14 +2,14 @@ import { getPokemonNameWithAffix } from "../messages";
import type Pokemon from "../field/pokemon"; import type Pokemon from "../field/pokemon";
import { HitResult } from "../field/pokemon"; import { HitResult } from "../field/pokemon";
import { getStatusEffectHealText } from "./status-effect"; import { getStatusEffectHealText } from "./status-effect";
import * as Utils from "../utils"; import { NumberHolder, toDmgValue, randSeedInt } from "#app/utils/common";
import { import {
DoubleBerryEffectAbAttr, DoubleBerryEffectAbAttr,
PostItemLostAbAttr, PostItemLostAbAttr,
ReduceBerryUseThresholdAbAttr, ReduceBerryUseThresholdAbAttr,
applyAbAttrs, applyAbAttrs,
applyPostItemLostAbAttrs, applyPostItemLostAbAttrs,
} from "./ability"; } from "./abilities/ability";
import i18next from "i18next"; import i18next from "i18next";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { BerryType } from "#enums/berry-type"; import { BerryType } from "#enums/berry-type";
@ -43,7 +43,7 @@ export function getBerryPredicate(berryType: BerryType): BerryPredicate {
case BerryType.APICOT: case BerryType.APICOT:
case BerryType.SALAC: case BerryType.SALAC:
return (pokemon: Pokemon) => { return (pokemon: Pokemon) => {
const threshold = new Utils.NumberHolder(0.25); const threshold = new NumberHolder(0.25);
// Offset BerryType such that LIECHI -> Stat.ATK = 1, GANLON -> Stat.DEF = 2, so on and so forth // Offset BerryType such that LIECHI -> Stat.ATK = 1, GANLON -> Stat.DEF = 2, so on and so forth
const stat: BattleStat = berryType - BerryType.ENIGMA; const stat: BattleStat = berryType - BerryType.ENIGMA;
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold); applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold);
@ -51,19 +51,19 @@ export function getBerryPredicate(berryType: BerryType): BerryPredicate {
}; };
case BerryType.LANSAT: case BerryType.LANSAT:
return (pokemon: Pokemon) => { return (pokemon: Pokemon) => {
const threshold = new Utils.NumberHolder(0.25); const threshold = new NumberHolder(0.25);
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold); applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold);
return pokemon.getHpRatio() < 0.25 && !pokemon.getTag(BattlerTagType.CRIT_BOOST); return pokemon.getHpRatio() < 0.25 && !pokemon.getTag(BattlerTagType.CRIT_BOOST);
}; };
case BerryType.STARF: case BerryType.STARF:
return (pokemon: Pokemon) => { return (pokemon: Pokemon) => {
const threshold = new Utils.NumberHolder(0.25); const threshold = new NumberHolder(0.25);
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold); applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold);
return pokemon.getHpRatio() < 0.25; return pokemon.getHpRatio() < 0.25;
}; };
case BerryType.LEPPA: case BerryType.LEPPA:
return (pokemon: Pokemon) => { return (pokemon: Pokemon) => {
const threshold = new Utils.NumberHolder(0.25); const threshold = new NumberHolder(0.25);
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold); applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold);
return !!pokemon.getMoveset().find(m => !m.getPpRatio()); return !!pokemon.getMoveset().find(m => !m.getPpRatio());
}; };
@ -80,7 +80,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
if (pokemon.battleData) { if (pokemon.battleData) {
pokemon.battleData.berriesEaten.push(berryType); pokemon.battleData.berriesEaten.push(berryType);
} }
const hpHealed = new Utils.NumberHolder(Utils.toDmgValue(pokemon.getMaxHp() / 4)); const hpHealed = new NumberHolder(toDmgValue(pokemon.getMaxHp() / 4));
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, hpHealed); applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, hpHealed);
globalScene.unshiftPhase( globalScene.unshiftPhase(
new PokemonHealPhase( new PokemonHealPhase(
@ -118,7 +118,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
} }
// Offset BerryType such that LIECHI -> Stat.ATK = 1, GANLON -> Stat.DEF = 2, so on and so forth // Offset BerryType such that LIECHI -> Stat.ATK = 1, GANLON -> Stat.DEF = 2, so on and so forth
const stat: BattleStat = berryType - BerryType.ENIGMA; const stat: BattleStat = berryType - BerryType.ENIGMA;
const statStages = new Utils.NumberHolder(1); const statStages = new NumberHolder(1);
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, statStages); applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, statStages);
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [stat], statStages.value)); globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [stat], statStages.value));
applyPostItemLostAbAttrs(PostItemLostAbAttr, berryOwner ?? pokemon, false); applyPostItemLostAbAttrs(PostItemLostAbAttr, berryOwner ?? pokemon, false);
@ -136,8 +136,8 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
if (pokemon.battleData) { if (pokemon.battleData) {
pokemon.battleData.berriesEaten.push(berryType); pokemon.battleData.berriesEaten.push(berryType);
} }
const randStat = Utils.randSeedInt(Stat.SPD, Stat.ATK); const randStat = randSeedInt(Stat.SPD, Stat.ATK);
const stages = new Utils.NumberHolder(2); const stages = new NumberHolder(2);
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, stages); applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, stages);
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [randStat], stages.value)); globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [randStat], stages.value));
applyPostItemLostAbAttrs(PostItemLostAbAttr, berryOwner ?? pokemon, false); applyPostItemLostAbAttrs(PostItemLostAbAttr, berryOwner ?? pokemon, false);

View File

@ -1,4 +1,4 @@
import * as Utils from "#app/utils"; import { BooleanHolder, type NumberHolder, randSeedItem, deepCopy } from "#app/utils/common";
import i18next from "i18next"; import i18next from "i18next";
import type { DexAttrProps, GameData } from "#app/system/game-data"; import type { DexAttrProps, GameData } from "#app/system/game-data";
import { defaultStarterSpecies } from "#app/system/game-data"; import { defaultStarterSpecies } from "#app/system/game-data";
@ -8,7 +8,9 @@ import { speciesStarterCosts } from "#app/data/balance/starters";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { PokemonMove } from "#app/field/pokemon"; import { PokemonMove } from "#app/field/pokemon";
import type { FixedBattleConfig } from "#app/battle"; import type { FixedBattleConfig } from "#app/battle";
import { ClassicFixedBossWaves, BattleType, getRandomTrainerFunc } from "#app/battle"; import { getRandomTrainerFunc } from "#app/battle";
import { ClassicFixedBossWaves } from "#enums/fixed-boss-waves";
import { BattleType } from "#enums/battle-type";
import Trainer, { TrainerVariant } from "#app/field/trainer"; import Trainer, { TrainerVariant } from "#app/field/trainer";
import { PokemonType } from "#enums/pokemon-type"; import { PokemonType } from "#enums/pokemon-type";
import { Challenges } from "#enums/challenges"; import { Challenges } from "#enums/challenges";
@ -283,30 +285,30 @@ 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 {@link PokemonSpecies} The pokemon to check the validity of.
* @param _valid {@link Utils.BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed. * @param _valid {@link BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed.
* @param _dexAttr {@link DexAttrProps} The dex attributes of the pokemon. * @param _dexAttr {@link DexAttrProps} The dex attributes of the pokemon.
* @returns {@link boolean} Whether this function did anything. * @returns {@link boolean} Whether this function did anything.
*/ */
applyStarterChoice(_pokemon: PokemonSpecies, _valid: Utils.BooleanHolder, _dexAttr: DexAttrProps): boolean { applyStarterChoice(_pokemon: PokemonSpecies, _valid: BooleanHolder, _dexAttr: DexAttrProps): boolean {
return false; return false;
} }
/** /**
* 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 Utils.NumberHolder} The amount of points you have available. * @param _points {@link NumberHolder} The amount of points you have available.
* @returns {@link boolean} Whether this function did anything. * @returns {@link boolean} Whether this function did anything.
*/ */
applyStarterPoints(_points: Utils.NumberHolder): boolean { applyStarterPoints(_points: NumberHolder): boolean {
return false; return false;
} }
/** /**
* 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 Species} The pokemon to change the cost of. * @param _species {@link Species} The pokemon to change the cost of.
* @param _cost {@link Utils.NumberHolder} The cost of the starter. * @param _cost {@link NumberHolder} The cost of the starter.
* @returns {@link boolean} Whether this function did anything. * @returns {@link boolean} Whether this function did anything.
*/ */
applyStarterCost(_species: Species, _cost: Utils.NumberHolder): boolean { applyStarterCost(_species: Species, _cost: NumberHolder): boolean {
return false; return false;
} }
@ -322,10 +324,10 @@ 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 {@link Pokemon} The pokemon to check the validity of.
* @param _valid {@link Utils.BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed. * @param _valid {@link BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed.
* @returns {@link boolean} Whether this function did anything. * @returns {@link boolean} Whether this function did anything.
*/ */
applyPokemonInBattle(_pokemon: Pokemon, _valid: Utils.BooleanHolder): boolean { applyPokemonInBattle(_pokemon: Pokemon, _valid: BooleanHolder): boolean {
return false; return false;
} }
@ -341,42 +343,42 @@ 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 Utils.NumberHolder} The current effectiveness of the move. * @param _effectiveness {@linkcode NumberHolder} The current effectiveness of the move.
* @returns Whether this function did anything. * @returns Whether this function did anything.
*/ */
applyTypeEffectiveness(_effectiveness: Utils.NumberHolder): boolean { applyTypeEffectiveness(_effectiveness: NumberHolder): boolean {
return false; return false;
} }
/** /**
* 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 Utils.NumberHolder} The generated level. * @param _level {@link NumberHolder} The generated level.
* @param _levelCap {@link Number} The current level cap. * @param _levelCap {@link Number} The current level cap.
* @param _isTrainer {@link Boolean} Whether this is a trainer pokemon. * @param _isTrainer {@link Boolean} Whether this is a trainer pokemon.
* @param _isBoss {@link Boolean} Whether this is a non-trainer boss pokemon. * @param _isBoss {@link Boolean} Whether this is a non-trainer boss pokemon.
* @returns {@link boolean} Whether this function did anything. * @returns {@link boolean} Whether this function did anything.
*/ */
applyLevelChange(_level: Utils.NumberHolder, _levelCap: number, _isTrainer: boolean, _isBoss: boolean): boolean { applyLevelChange(_level: NumberHolder, _levelCap: number, _isTrainer: boolean, _isBoss: boolean): boolean {
return false; return false;
} }
/** /**
* 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 {@link Pokemon} The pokemon that is being considered.
* @param moveSlots {@link Utils.NumberHolder} The amount of move slots. * @param moveSlots {@link NumberHolder} The amount of move slots.
* @returns {@link boolean} Whether this function did anything. * @returns {@link boolean} Whether this function did anything.
*/ */
applyMoveSlot(_pokemon: Pokemon, _moveSlots: Utils.NumberHolder): boolean { applyMoveSlot(_pokemon: Pokemon, _moveSlots: NumberHolder): boolean {
return false; return false;
} }
/** /**
* 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 {@link Pokemon} The pokemon to change.
* @param hasPassive {@link Utils.BooleanHolder} Whether it should have its passive. * @param hasPassive {@link BooleanHolder} Whether it should have its passive.
* @returns {@link boolean} Whether this function did anything. * @returns {@link boolean} Whether this function did anything.
*/ */
applyPassiveAccess(_pokemon: Pokemon, _hasPassive: Utils.BooleanHolder): boolean { applyPassiveAccess(_pokemon: Pokemon, _hasPassive: BooleanHolder): boolean {
return false; return false;
} }
@ -393,15 +395,10 @@ export abstract class Challenge {
* @param _pokemon {@link Pokemon} What pokemon would learn the move. * @param _pokemon {@link Pokemon} What pokemon would learn the move.
* @param _moveSource {@link MoveSourceType} What source the pokemon would get the move from. * @param _moveSource {@link MoveSourceType} What source the pokemon would get the move from.
* @param _move {@link Moves} The move in question. * @param _move {@link Moves} The move in question.
* @param _level {@link Utils.NumberHolder} The level threshold for access. * @param _level {@link NumberHolder} The level threshold for access.
* @returns {@link boolean} Whether this function did anything. * @returns {@link boolean} Whether this function did anything.
*/ */
applyMoveAccessLevel( applyMoveAccessLevel(_pokemon: Pokemon, _moveSource: MoveSourceType, _move: Moves, _level: NumberHolder): boolean {
_pokemon: Pokemon,
_moveSource: MoveSourceType,
_move: Moves,
_level: Utils.NumberHolder,
): boolean {
return false; return false;
} }
@ -410,10 +407,10 @@ export abstract class Challenge {
* @param _pokemon {@link Pokemon} What pokemon would learn the move. * @param _pokemon {@link Pokemon} What pokemon would learn the move.
* @param _moveSource {@link MoveSourceType} What source the pokemon would get the move from. * @param _moveSource {@link MoveSourceType} What source the pokemon would get the move from.
* @param _move {@link Moves} The move in question. * @param _move {@link Moves} The move in question.
* @param _weight {@link Utils.NumberHolder} The base weight of the move * @param _weight {@link NumberHolder} The base weight of the move
* @returns {@link boolean} Whether this function did anything. * @returns {@link boolean} Whether this function did anything.
*/ */
applyMoveWeight(_pokemon: Pokemon, _moveSource: MoveSourceType, _move: Moves, _level: Utils.NumberHolder): boolean { applyMoveWeight(_pokemon: Pokemon, _moveSource: MoveSourceType, _move: Moves, _level: NumberHolder): boolean {
return false; return false;
} }
@ -438,7 +435,7 @@ export class SingleGenerationChallenge extends Challenge {
super(Challenges.SINGLE_GENERATION, 9); super(Challenges.SINGLE_GENERATION, 9);
} }
applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder): boolean { applyStarterChoice(pokemon: PokemonSpecies, valid: BooleanHolder): boolean {
if (pokemon.generation !== this.value) { if (pokemon.generation !== this.value) {
valid.value = false; valid.value = false;
return true; return true;
@ -446,7 +443,7 @@ export class SingleGenerationChallenge extends Challenge {
return false; return false;
} }
applyPokemonInBattle(pokemon: Pokemon, valid: Utils.BooleanHolder): boolean { applyPokemonInBattle(pokemon: Pokemon, valid: BooleanHolder): boolean {
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 (
@ -575,7 +572,7 @@ export class SingleGenerationChallenge extends Challenge {
TrainerType.AARON, TrainerType.AARON,
TrainerType.SHAUNTAL, TrainerType.SHAUNTAL,
TrainerType.MALVA, TrainerType.MALVA,
Utils.randSeedItem([TrainerType.HALA, TrainerType.MOLAYNE]), randSeedItem([TrainerType.HALA, TrainerType.MOLAYNE]),
TrainerType.MARNIE_ELITE, TrainerType.MARNIE_ELITE,
TrainerType.RIKA, TrainerType.RIKA,
]; ];
@ -602,7 +599,7 @@ export class SingleGenerationChallenge extends Challenge {
TrainerType.GRIMSLEY, TrainerType.GRIMSLEY,
TrainerType.WIKSTROM, TrainerType.WIKSTROM,
TrainerType.ACEROLA, TrainerType.ACEROLA,
Utils.randSeedItem([TrainerType.BEA_ELITE, TrainerType.ALLISTER_ELITE]), randSeedItem([TrainerType.BEA_ELITE, TrainerType.ALLISTER_ELITE]),
TrainerType.LARRY_ELITE, TrainerType.LARRY_ELITE,
]; ];
break; break;
@ -622,14 +619,14 @@ export class SingleGenerationChallenge extends Challenge {
case ClassicFixedBossWaves.CHAMPION: case ClassicFixedBossWaves.CHAMPION:
trainerTypes = [ trainerTypes = [
TrainerType.BLUE, TrainerType.BLUE,
Utils.randSeedItem([TrainerType.RED, TrainerType.LANCE_CHAMPION]), randSeedItem([TrainerType.RED, TrainerType.LANCE_CHAMPION]),
Utils.randSeedItem([TrainerType.STEVEN, TrainerType.WALLACE]), randSeedItem([TrainerType.STEVEN, TrainerType.WALLACE]),
TrainerType.CYNTHIA, TrainerType.CYNTHIA,
Utils.randSeedItem([TrainerType.ALDER, TrainerType.IRIS]), randSeedItem([TrainerType.ALDER, TrainerType.IRIS]),
TrainerType.DIANTHA, TrainerType.DIANTHA,
Utils.randSeedItem([TrainerType.KUKUI, TrainerType.HAU]), randSeedItem([TrainerType.KUKUI, TrainerType.HAU]),
Utils.randSeedItem([TrainerType.LEON, TrainerType.MUSTARD]), randSeedItem([TrainerType.LEON, TrainerType.MUSTARD]),
Utils.randSeedItem([TrainerType.GEETA, TrainerType.NEMONA]), randSeedItem([TrainerType.GEETA, TrainerType.NEMONA]),
]; ];
break; break;
} }
@ -718,7 +715,7 @@ export class SingleTypeChallenge extends Challenge {
super(Challenges.SINGLE_TYPE, 18); super(Challenges.SINGLE_TYPE, 18);
} }
override applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps): boolean { override applyStarterChoice(pokemon: PokemonSpecies, valid: BooleanHolder, dexAttr: DexAttrProps): boolean {
const speciesForm = getPokemonSpeciesForm(pokemon.speciesId, dexAttr.formIndex); const speciesForm = getPokemonSpeciesForm(pokemon.speciesId, dexAttr.formIndex);
const types = [speciesForm.type1, speciesForm.type2]; const types = [speciesForm.type1, speciesForm.type2];
if (!types.includes(this.value - 1)) { if (!types.includes(this.value - 1)) {
@ -728,7 +725,7 @@ export class SingleTypeChallenge extends Challenge {
return false; return false;
} }
applyPokemonInBattle(pokemon: Pokemon, valid: Utils.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) &&
@ -798,7 +795,7 @@ export class FreshStartChallenge extends Challenge {
super(Challenges.FRESH_START, 1); super(Challenges.FRESH_START, 1);
} }
applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder): boolean { applyStarterChoice(pokemon: PokemonSpecies, valid: BooleanHolder): boolean {
if (!defaultStarterSpecies.includes(pokemon.speciesId)) { if (!defaultStarterSpecies.includes(pokemon.speciesId)) {
valid.value = false; valid.value = false;
return true; return true;
@ -806,7 +803,7 @@ export class FreshStartChallenge extends Challenge {
return false; return false;
} }
applyStarterCost(species: Species, cost: Utils.NumberHolder): boolean { applyStarterCost(species: Species, cost: NumberHolder): boolean {
if (defaultStarterSpecies.includes(species)) { if (defaultStarterSpecies.includes(species)) {
cost.value = speciesStarterCosts[species]; cost.value = speciesStarterCosts[species];
return true; return true;
@ -864,7 +861,7 @@ export class InverseBattleChallenge extends Challenge {
return 0; return 0;
} }
applyTypeEffectiveness(effectiveness: Utils.NumberHolder): boolean { applyTypeEffectiveness(effectiveness: NumberHolder): boolean {
if (effectiveness.value < 1) { if (effectiveness.value < 1) {
effectiveness.value = 2; effectiveness.value = 2;
return true; return true;
@ -887,7 +884,7 @@ export class FlipStatChallenge extends Challenge {
} }
override applyFlipStat(_pokemon: Pokemon, baseStats: number[]) { override applyFlipStat(_pokemon: Pokemon, baseStats: number[]) {
const origStats = Utils.deepCopy(baseStats); const origStats = deepCopy(baseStats);
baseStats[0] = origStats[5]; baseStats[0] = origStats[5];
baseStats[1] = origStats[4]; baseStats[1] = origStats[4];
baseStats[2] = origStats[3]; baseStats[2] = origStats[3];
@ -923,7 +920,7 @@ export class LowerStarterMaxCostChallenge extends Challenge {
return (DEFAULT_PARTY_MAX_COST - overrideValue).toString(); return (DEFAULT_PARTY_MAX_COST - overrideValue).toString();
} }
applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder): boolean { applyStarterChoice(pokemon: PokemonSpecies, valid: BooleanHolder): boolean {
if (speciesStarterCosts[pokemon.speciesId] > DEFAULT_PARTY_MAX_COST - this.value) { if (speciesStarterCosts[pokemon.speciesId] > DEFAULT_PARTY_MAX_COST - this.value) {
valid.value = false; valid.value = false;
return true; return true;
@ -957,7 +954,7 @@ export class LowerStarterPointsChallenge extends Challenge {
return (DEFAULT_PARTY_MAX_COST - overrideValue).toString(); return (DEFAULT_PARTY_MAX_COST - overrideValue).toString();
} }
applyStarterPoints(points: Utils.NumberHolder): boolean { applyStarterPoints(points: NumberHolder): boolean {
points.value -= this.value; points.value -= this.value;
return true; return true;
} }
@ -974,34 +971,34 @@ export class LowerStarterPointsChallenge extends Challenge {
* Apply all challenges that modify starter choice. * Apply all challenges that modify starter choice.
* @param challengeType {@link ChallengeType} ChallengeType.STARTER_CHOICE * @param challengeType {@link ChallengeType} ChallengeType.STARTER_CHOICE
* @param pokemon {@link PokemonSpecies} The pokemon to check the validity of. * @param pokemon {@link PokemonSpecies} The pokemon to check the validity of.
* @param valid {@link Utils.BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed. * @param valid {@link BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed.
* @param dexAttr {@link DexAttrProps} The dex attributes of the pokemon. * @param dexAttr {@link DexAttrProps} The dex attributes of the pokemon.
* @returns True if any challenge was successfully applied. * @returns True if any challenge was successfully applied.
*/ */
export function applyChallenges( export function applyChallenges(
challengeType: ChallengeType.STARTER_CHOICE, challengeType: ChallengeType.STARTER_CHOICE,
pokemon: PokemonSpecies, pokemon: PokemonSpecies,
valid: Utils.BooleanHolder, valid: BooleanHolder,
dexAttr: DexAttrProps, dexAttr: DexAttrProps,
): boolean; ): boolean;
/** /**
* Apply all challenges that modify available total starter points. * Apply all challenges that modify available total starter points.
* @param challengeType {@link ChallengeType} ChallengeType.STARTER_POINTS * @param challengeType {@link ChallengeType} ChallengeType.STARTER_POINTS
* @param points {@link Utils.NumberHolder} The amount of points you have available. * @param points {@link NumberHolder} The amount of points you have available.
* @returns True if any challenge was successfully applied. * @returns True if any challenge was successfully applied.
*/ */
export function applyChallenges(challengeType: ChallengeType.STARTER_POINTS, points: Utils.NumberHolder): boolean; export function applyChallenges(challengeType: ChallengeType.STARTER_POINTS, points: NumberHolder): boolean;
/** /**
* Apply all challenges that modify the cost of a starter. * Apply all challenges that modify the cost of a starter.
* @param challengeType {@link ChallengeType} ChallengeType.STARTER_COST * @param challengeType {@link ChallengeType} ChallengeType.STARTER_COST
* @param species {@link Species} The pokemon to change the cost of. * @param species {@link Species} The pokemon to change the cost of.
* @param points {@link Utils.NumberHolder} The cost of the pokemon. * @param points {@link NumberHolder} The cost of the pokemon.
* @returns True if any challenge was successfully applied. * @returns True if any challenge was successfully applied.
*/ */
export function applyChallenges( export function applyChallenges(
challengeType: ChallengeType.STARTER_COST, challengeType: ChallengeType.STARTER_COST,
species: Species, species: Species,
cost: Utils.NumberHolder, cost: NumberHolder,
): boolean; ): boolean;
/** /**
* Apply all challenges that modify a starter after selection. * Apply all challenges that modify a starter after selection.
@ -1014,13 +1011,13 @@ export function applyChallenges(challengeType: ChallengeType.STARTER_MODIFY, pok
* Apply all challenges that what pokemon you can have in battle. * Apply all challenges that what pokemon you can have in battle.
* @param challengeType {@link ChallengeType} ChallengeType.POKEMON_IN_BATTLE * @param challengeType {@link ChallengeType} ChallengeType.POKEMON_IN_BATTLE
* @param pokemon {@link Pokemon} The pokemon to check the validity of. * @param pokemon {@link Pokemon} The pokemon to check the validity of.
* @param valid {@link Utils.BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed. * @param valid {@link BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed.
* @returns True if any challenge was successfully applied. * @returns True if any challenge was successfully applied.
*/ */
export function applyChallenges( export function applyChallenges(
challengeType: ChallengeType.POKEMON_IN_BATTLE, challengeType: ChallengeType.POKEMON_IN_BATTLE,
pokemon: Pokemon, pokemon: Pokemon,
valid: Utils.BooleanHolder, valid: BooleanHolder,
): boolean; ): boolean;
/** /**
* Apply all challenges that modify what fixed battles there are. * Apply all challenges that modify what fixed battles there are.
@ -1037,17 +1034,14 @@ export function applyChallenges(
/** /**
* Apply all challenges that modify type effectiveness. * Apply all challenges that modify type effectiveness.
* @param challengeType {@linkcode ChallengeType} ChallengeType.TYPE_EFFECTIVENESS * @param challengeType {@linkcode ChallengeType} ChallengeType.TYPE_EFFECTIVENESS
* @param effectiveness {@linkcode Utils.NumberHolder} The current effectiveness of the move. * @param effectiveness {@linkcode NumberHolder} The current effectiveness of the move.
* @returns True if any challenge was successfully applied. * @returns True if any challenge was successfully applied.
*/ */
export function applyChallenges( export function applyChallenges(challengeType: ChallengeType.TYPE_EFFECTIVENESS, effectiveness: NumberHolder): boolean;
challengeType: ChallengeType.TYPE_EFFECTIVENESS,
effectiveness: Utils.NumberHolder,
): boolean;
/** /**
* Apply all challenges that modify what level AI are. * Apply all challenges that modify what level AI are.
* @param challengeType {@link ChallengeType} ChallengeType.AI_LEVEL * @param challengeType {@link ChallengeType} ChallengeType.AI_LEVEL
* @param level {@link Utils.NumberHolder} The generated level of the pokemon. * @param level {@link NumberHolder} The generated level of the pokemon.
* @param levelCap {@link Number} The maximum level cap for the current wave. * @param levelCap {@link Number} The maximum level cap for the current wave.
* @param isTrainer {@link Boolean} Whether this is a trainer pokemon. * @param isTrainer {@link Boolean} Whether this is a trainer pokemon.
* @param isBoss {@link Boolean} Whether this is a non-trainer boss pokemon. * @param isBoss {@link Boolean} Whether this is a non-trainer boss pokemon.
@ -1055,7 +1049,7 @@ export function applyChallenges(
*/ */
export function applyChallenges( export function applyChallenges(
challengeType: ChallengeType.AI_LEVEL, challengeType: ChallengeType.AI_LEVEL,
level: Utils.NumberHolder, level: NumberHolder,
levelCap: number, levelCap: number,
isTrainer: boolean, isTrainer: boolean,
isBoss: boolean, isBoss: boolean,
@ -1064,25 +1058,25 @@ export function applyChallenges(
* Apply all challenges that modify how many move slots the AI has. * Apply all challenges that modify how many move slots the AI has.
* @param challengeType {@link ChallengeType} ChallengeType.AI_MOVE_SLOTS * @param challengeType {@link ChallengeType} ChallengeType.AI_MOVE_SLOTS
* @param pokemon {@link Pokemon} The pokemon being considered. * @param pokemon {@link Pokemon} The pokemon being considered.
* @param moveSlots {@link Utils.NumberHolder} The amount of move slots. * @param moveSlots {@link NumberHolder} The amount of move slots.
* @returns True if any challenge was successfully applied. * @returns True if any challenge was successfully applied.
*/ */
export function applyChallenges( export function applyChallenges(
challengeType: ChallengeType.AI_MOVE_SLOTS, challengeType: ChallengeType.AI_MOVE_SLOTS,
pokemon: Pokemon, pokemon: Pokemon,
moveSlots: Utils.NumberHolder, moveSlots: NumberHolder,
): boolean; ): boolean;
/** /**
* Apply all challenges that modify whether a pokemon has its passive. * Apply all challenges that modify whether a pokemon has its passive.
* @param challengeType {@link ChallengeType} ChallengeType.PASSIVE_ACCESS * @param challengeType {@link ChallengeType} ChallengeType.PASSIVE_ACCESS
* @param pokemon {@link Pokemon} The pokemon to modify. * @param pokemon {@link Pokemon} The pokemon to modify.
* @param hasPassive {@link Utils.BooleanHolder} Whether it has its passive. * @param hasPassive {@link BooleanHolder} Whether it has its passive.
* @returns True if any challenge was successfully applied. * @returns True if any challenge was successfully applied.
*/ */
export function applyChallenges( export function applyChallenges(
challengeType: ChallengeType.PASSIVE_ACCESS, challengeType: ChallengeType.PASSIVE_ACCESS,
pokemon: Pokemon, pokemon: Pokemon,
hasPassive: Utils.BooleanHolder, hasPassive: BooleanHolder,
): boolean; ): boolean;
/** /**
* Apply all challenges that modify the game modes settings. * Apply all challenges that modify the game modes settings.
@ -1096,7 +1090,7 @@ export function applyChallenges(challengeType: ChallengeType.GAME_MODE_MODIFY):
* @param pokemon {@link Pokemon} What pokemon would learn the move. * @param pokemon {@link Pokemon} What pokemon would learn the move.
* @param moveSource {@link MoveSourceType} What source the pokemon would get the move from. * @param moveSource {@link MoveSourceType} What source the pokemon would get the move from.
* @param move {@link Moves} The move in question. * @param move {@link Moves} The move in question.
* @param level {@link Utils.NumberHolder} The level threshold for access. * @param level {@link NumberHolder} The level threshold for access.
* @returns True if any challenge was successfully applied. * @returns True if any challenge was successfully applied.
*/ */
export function applyChallenges( export function applyChallenges(
@ -1104,7 +1098,7 @@ export function applyChallenges(
pokemon: Pokemon, pokemon: Pokemon,
moveSource: MoveSourceType, moveSource: MoveSourceType,
move: Moves, move: Moves,
level: Utils.NumberHolder, level: NumberHolder,
): boolean; ): boolean;
/** /**
* Apply all challenges that modify what weight a pokemon gives to move generation * Apply all challenges that modify what weight a pokemon gives to move generation
@ -1112,7 +1106,7 @@ export function applyChallenges(
* @param pokemon {@link Pokemon} What pokemon would learn the move. * @param pokemon {@link Pokemon} What pokemon would learn the move.
* @param moveSource {@link MoveSourceType} What source the pokemon would get the move from. * @param moveSource {@link MoveSourceType} What source the pokemon would get the move from.
* @param move {@link Moves} The move in question. * @param move {@link Moves} The move in question.
* @param weight {@link Utils.NumberHolder} The weight of the move. * @param weight {@link NumberHolder} The weight of the move.
* @returns True if any challenge was successfully applied. * @returns True if any challenge was successfully applied.
*/ */
export function applyChallenges( export function applyChallenges(
@ -1120,7 +1114,7 @@ export function applyChallenges(
pokemon: Pokemon, pokemon: Pokemon,
moveSource: MoveSourceType, moveSource: MoveSourceType,
move: Moves, move: Moves,
weight: Utils.NumberHolder, weight: NumberHolder,
): boolean; ): boolean;
export function applyChallenges(challengeType: ChallengeType.FLIP_STAT, pokemon: Pokemon, baseStats: number[]): boolean; export function applyChallenges(challengeType: ChallengeType.FLIP_STAT, pokemon: Pokemon, baseStats: number[]): boolean;
@ -1225,7 +1219,7 @@ export function initChallenges() {
*/ */
export function checkStarterValidForChallenge(species: PokemonSpecies, props: DexAttrProps, soft: boolean) { export function checkStarterValidForChallenge(species: PokemonSpecies, props: DexAttrProps, soft: boolean) {
if (!soft) { if (!soft) {
const isValidForChallenge = new Utils.BooleanHolder(true); const isValidForChallenge = new BooleanHolder(true);
applyChallenges(ChallengeType.STARTER_CHOICE, species, isValidForChallenge, props); applyChallenges(ChallengeType.STARTER_CHOICE, species, isValidForChallenge, props);
return isValidForChallenge.value; return isValidForChallenge.value;
} }
@ -1263,7 +1257,7 @@ export function checkStarterValidForChallenge(species: PokemonSpecies, props: De
* @returns `true` if the species is considered valid. * @returns `true` if the species is considered valid.
*/ */
function checkSpeciesValidForChallenge(species: PokemonSpecies, props: DexAttrProps, soft: boolean) { function checkSpeciesValidForChallenge(species: PokemonSpecies, props: DexAttrProps, soft: boolean) {
const isValidForChallenge = new Utils.BooleanHolder(true); const isValidForChallenge = new BooleanHolder(true);
applyChallenges(ChallengeType.STARTER_CHOICE, species, isValidForChallenge, props); applyChallenges(ChallengeType.STARTER_CHOICE, species, isValidForChallenge, props);
if (!soft || !pokemonFormChanges.hasOwnProperty(species.speciesId)) { if (!soft || !pokemonFormChanges.hasOwnProperty(species.speciesId)) {
return isValidForChallenge.value; return isValidForChallenge.value;
@ -1272,23 +1266,22 @@ function checkSpeciesValidForChallenge(species: PokemonSpecies, props: DexAttrPr
if (soft && isValidForChallenge.value) { if (soft && isValidForChallenge.value) {
return true; return true;
} }
pokemonFormChanges[species.speciesId].forEach(f1 => {
// Exclude form changes that require the mon to be on the field to begin with, const result = pokemonFormChanges[species.speciesId].some(f1 => {
// such as Castform // Exclude form changes that require the mon to be on the field to begin with
if (!("item" in f1)) { if (!("item" in f1.trigger)) {
return;
}
species.forms.forEach((f2, formIndex) => {
if (f1.formKey === f2.formKey) {
const formProps = { ...props };
formProps.formIndex = formIndex;
const isFormValidForChallenge = new Utils.BooleanHolder(true);
applyChallenges(ChallengeType.STARTER_CHOICE, species, isFormValidForChallenge, formProps);
if (isFormValidForChallenge.value) {
return true;
}
}
});
});
return false; return false;
} }
return species.forms.some((f2, formIndex) => {
if (f1.formKey === f2.formKey) {
const formProps = { ...props, formIndex };
const isFormValidForChallenge = new BooleanHolder(true);
applyChallenges(ChallengeType.STARTER_CHOICE, species, isFormValidForChallenge, formProps);
return isFormValidForChallenge.value;
}
return false;
});
});
return result;
}

View File

@ -1,6 +1,6 @@
import type { Abilities } from "#enums/abilities"; import type { Abilities } from "#enums/abilities";
import type { PokemonType } from "#enums/pokemon-type"; import type { PokemonType } from "#enums/pokemon-type";
import { isNullOrUndefined } from "#app/utils"; import { isNullOrUndefined } from "#app/utils/common";
import type { Nature } from "#enums/nature"; import type { Nature } from "#enums/nature";
/** /**

View File

@ -3,7 +3,7 @@ import type { Species } from "#enums/species";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { PlayerPokemon } from "#app/field/pokemon"; import { PlayerPokemon } from "#app/field/pokemon";
import type { Starter } from "#app/ui/starter-select-ui-handler"; import type { Starter } from "#app/ui/starter-select-ui-handler";
import * as Utils from "#app/utils"; import { randSeedGauss, randSeedInt, randSeedItem, getEnumValues } from "#app/utils/common";
import type { PokemonSpeciesForm } from "#app/data/pokemon-species"; import type { PokemonSpeciesForm } from "#app/data/pokemon-species";
import PokemonSpecies, { getPokemonSpecies, getPokemonSpeciesForm } from "#app/data/pokemon-species"; import PokemonSpecies, { getPokemonSpecies, getPokemonSpeciesForm } from "#app/data/pokemon-species";
import { speciesStarterCosts } from "#app/data/balance/starters"; import { speciesStarterCosts } from "#app/data/balance/starters";
@ -43,8 +43,8 @@ export function getDailyRunStarters(seed: string): Starter[] {
} }
const starterCosts: number[] = []; const starterCosts: number[] = [];
starterCosts.push(Math.min(Math.round(3.5 + Math.abs(Utils.randSeedGauss(1))), 8)); starterCosts.push(Math.min(Math.round(3.5 + Math.abs(randSeedGauss(1))), 8));
starterCosts.push(Utils.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 (let c = 0; c < starterCosts.length; c++) {
@ -52,7 +52,7 @@ export function getDailyRunStarters(seed: string): Starter[] {
const costSpecies = Object.keys(speciesStarterCosts) const costSpecies = Object.keys(speciesStarterCosts)
.map(s => Number.parseInt(s) as Species) .map(s => Number.parseInt(s) as Species)
.filter(s => speciesStarterCosts[s] === cost); .filter(s => speciesStarterCosts[s] === cost);
const randPkmSpecies = getPokemonSpecies(Utils.randSeedItem(costSpecies)); const randPkmSpecies = getPokemonSpecies(randSeedItem(costSpecies));
const starterSpecies = getPokemonSpecies( const starterSpecies = getPokemonSpecies(
randPkmSpecies.getTrainerSpeciesForLevel(startingLevel, true, PartyMemberStrength.STRONGER), randPkmSpecies.getTrainerSpeciesForLevel(startingLevel, true, PartyMemberStrength.STRONGER),
); );
@ -143,7 +143,7 @@ const dailyBiomeWeights: BiomeWeights = {
}; };
export function getDailyStartingBiome(): Biome { export function getDailyStartingBiome(): Biome {
const biomes = Utils.getEnumValues(Biome).filter(b => b !== Biome.TOWN && b !== Biome.END); const biomes = getEnumValues(Biome).filter(b => b !== Biome.TOWN && b !== Biome.END);
let totalWeight = 0; let totalWeight = 0;
const biomeThresholds: number[] = []; const biomeThresholds: number[] = [];
@ -155,7 +155,7 @@ export function getDailyStartingBiome(): Biome {
biomeThresholds.push(totalWeight); biomeThresholds.push(totalWeight);
} }
const randInt = Utils.randSeedInt(totalWeight); const randInt = randSeedInt(totalWeight);
for (let i = 0; i < biomes.length; i++) { for (let i = 0; i < biomes.length; i++) {
if (randInt < biomeThresholds[i]) { if (randInt < biomeThresholds[i]) {
@ -164,5 +164,5 @@ export function getDailyStartingBiome(): Biome {
} }
// Fallback in case something went wrong // Fallback in case something went wrong
return biomes[Utils.randSeedInt(biomes.length)]; return biomes[randSeedInt(biomes.length)];
} }

3
src/data/data-lists.ts Normal file
View File

@ -0,0 +1,3 @@
import type { Ability } from "./abilities/ability-class";
export const allAbilities: Ability[] = [];

View File

@ -4,7 +4,7 @@ import type PokemonSpecies from "#app/data/pokemon-species";
import { getPokemonSpecies } from "#app/data/pokemon-species"; import { getPokemonSpecies } from "#app/data/pokemon-species";
import { speciesStarterCosts } from "#app/data/balance/starters"; import { speciesStarterCosts } from "#app/data/balance/starters";
import { VariantTier } from "#enums/variant-tier"; import { VariantTier } from "#enums/variant-tier";
import * as Utils from "#app/utils"; import { randInt, randomString, randSeedInt, getIvsFromId } from "#app/utils/common";
import Overrides from "#app/overrides"; import Overrides from "#app/overrides";
import { pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions"; import { pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions";
import type { PlayerPokemon } from "#app/field/pokemon"; import type { PlayerPokemon } from "#app/field/pokemon";
@ -171,7 +171,7 @@ export class Egg {
this.checkForPityTierOverrides(); this.checkForPityTierOverrides();
} }
this._id = eggOptions?.id ?? Utils.randInt(EGG_SEED, EGG_SEED * this._tier); this._id = eggOptions?.id ?? randInt(EGG_SEED, EGG_SEED * this._tier);
this._sourceType = eggOptions?.sourceType ?? undefined; this._sourceType = eggOptions?.sourceType ?? undefined;
this._hatchWaves = eggOptions?.hatchWaves ?? this.getEggTierDefaultHatchWaves(); this._hatchWaves = eggOptions?.hatchWaves ?? this.getEggTierDefaultHatchWaves();
@ -203,7 +203,7 @@ export class Egg {
} }
}; };
const seedOverride = Utils.randomString(24); const seedOverride = randomString(24);
globalScene.executeWithSeedOffset( globalScene.executeWithSeedOffset(
() => { () => {
generateEggProperties(eggOptions); generateEggProperties(eggOptions);
@ -248,18 +248,15 @@ export class Egg {
let pokemonSpecies = getPokemonSpecies(this._species); let pokemonSpecies = getPokemonSpecies(this._species);
// Special condition to have Phione eggs also have a chance of generating Manaphy // Special condition to have Phione eggs also have a chance of generating Manaphy
if (this._species === Species.PHIONE && this._sourceType === EggSourceType.SAME_SPECIES_EGG) { if (this._species === Species.PHIONE && this._sourceType === EggSourceType.SAME_SPECIES_EGG) {
pokemonSpecies = getPokemonSpecies( pokemonSpecies = getPokemonSpecies(randSeedInt(MANAPHY_EGG_MANAPHY_RATE) ? Species.PHIONE : Species.MANAPHY);
Utils.randSeedInt(MANAPHY_EGG_MANAPHY_RATE) ? Species.PHIONE : Species.MANAPHY,
);
} }
// Sets the hidden ability if a hidden ability exists and // Sets the hidden ability if a hidden ability exists and
// the override is set or the egg hits the chance // the override is set or the egg hits the chance
let abilityIndex: number | undefined = undefined; let abilityIndex: number | undefined = undefined;
const sameSpeciesEggHACheck = const sameSpeciesEggHACheck =
this._sourceType === EggSourceType.SAME_SPECIES_EGG && !Utils.randSeedInt(SAME_SPECIES_EGG_HA_RATE); this._sourceType === EggSourceType.SAME_SPECIES_EGG && !randSeedInt(SAME_SPECIES_EGG_HA_RATE);
const gachaEggHACheck = const gachaEggHACheck = !(this._sourceType === EggSourceType.SAME_SPECIES_EGG) && !randSeedInt(GACHA_EGG_HA_RATE);
!(this._sourceType === EggSourceType.SAME_SPECIES_EGG) && !Utils.randSeedInt(GACHA_EGG_HA_RATE);
if (pokemonSpecies.abilityHidden && (this._overrideHiddenAbility || sameSpeciesEggHACheck || gachaEggHACheck)) { if (pokemonSpecies.abilityHidden && (this._overrideHiddenAbility || sameSpeciesEggHACheck || gachaEggHACheck)) {
abilityIndex = 2; abilityIndex = 2;
} }
@ -269,7 +266,7 @@ export class Egg {
ret.shiny = this._isShiny; ret.shiny = this._isShiny;
ret.variant = this._variantTier; ret.variant = this._variantTier;
const secondaryIvs = Utils.getIvsFromId(Utils.randSeedInt(4294967295)); const secondaryIvs = getIvsFromId(randSeedInt(4294967295));
for (let s = 0; s < ret.ivs.length; s++) { for (let s = 0; s < ret.ivs.length; s++) {
ret.ivs[s] = Math.max(ret.ivs[s], secondaryIvs[s]); ret.ivs[s] = Math.max(ret.ivs[s], secondaryIvs[s]);
@ -370,7 +367,7 @@ export class Egg {
} }
const tierMultiplier = this.isManaphyEgg() ? 2 : Math.pow(2, 3 - this.tier); const tierMultiplier = this.isManaphyEgg() ? 2 : Math.pow(2, 3 - this.tier);
return Utils.randSeedInt(baseChance * tierMultiplier) ? Utils.randSeedInt(3) : 3; return randSeedInt(baseChance * tierMultiplier) ? randSeedInt(3) : 3;
} }
private getEggTierDefaultHatchWaves(eggTier?: EggTier): number { private getEggTierDefaultHatchWaves(eggTier?: EggTier): number {
@ -392,7 +389,7 @@ export class Egg {
private rollEggTier(): EggTier { private rollEggTier(): EggTier {
const tierValueOffset = const tierValueOffset =
this._sourceType === EggSourceType.GACHA_LEGENDARY ? GACHA_LEGENDARY_UP_THRESHOLD_OFFSET : 0; this._sourceType === EggSourceType.GACHA_LEGENDARY ? GACHA_LEGENDARY_UP_THRESHOLD_OFFSET : 0;
const tierValue = Utils.randInt(256); const tierValue = randInt(256);
return tierValue >= GACHA_DEFAULT_COMMON_EGG_THRESHOLD + tierValueOffset return tierValue >= GACHA_DEFAULT_COMMON_EGG_THRESHOLD + tierValueOffset
? EggTier.COMMON ? EggTier.COMMON
: tierValue >= GACHA_DEFAULT_RARE_EGG_THRESHOLD + tierValueOffset : tierValue >= GACHA_DEFAULT_RARE_EGG_THRESHOLD + tierValueOffset
@ -417,11 +414,11 @@ export class Egg {
* when Utils.randSeedInt(8) = 1, and by making the generatePlayerPokemon() species * when Utils.randSeedInt(8) = 1, and by making the generatePlayerPokemon() species
* check pass when Utils.randSeedInt(8) = 0, we can tell them apart during tests. * check pass when Utils.randSeedInt(8) = 0, we can tell them apart during tests.
*/ */
const rand = Utils.randSeedInt(MANAPHY_EGG_MANAPHY_RATE) !== 1; const rand = randSeedInt(MANAPHY_EGG_MANAPHY_RATE) !== 1;
return rand ? Species.PHIONE : Species.MANAPHY; return rand ? Species.PHIONE : Species.MANAPHY;
} }
if (this.tier === EggTier.LEGENDARY && this._sourceType === EggSourceType.GACHA_LEGENDARY) { if (this.tier === EggTier.LEGENDARY && this._sourceType === EggSourceType.GACHA_LEGENDARY) {
if (!Utils.randSeedInt(2)) { if (!randSeedInt(2)) {
return getLegendaryGachaSpeciesForTimestamp(this.timestamp); return getLegendaryGachaSpeciesForTimestamp(this.timestamp);
} }
} }
@ -501,7 +498,7 @@ export class Egg {
let species: Species; let species: Species;
const rand = Utils.randSeedInt(totalWeight); const rand = randSeedInt(totalWeight);
for (let s = 0; s < speciesWeights.length; s++) { for (let s = 0; s < speciesWeights.length; s++) {
if (rand < speciesWeights[s]) { if (rand < speciesWeights[s]) {
species = speciesPool[s]; species = speciesPool[s];
@ -539,7 +536,7 @@ export class Egg {
break; break;
} }
return !Utils.randSeedInt(shinyChance); return !randSeedInt(shinyChance);
} }
// Uses the same logic as pokemon.generateVariant(). I would like to only have this logic in one // Uses the same logic as pokemon.generateVariant(). I would like to only have this logic in one
@ -550,7 +547,7 @@ export class Egg {
return VariantTier.STANDARD; return VariantTier.STANDARD;
} }
const rand = Utils.randSeedInt(10); const rand = randSeedInt(10);
if (rand >= SHINY_VARIANT_CHANCE) { if (rand >= SHINY_VARIANT_CHANCE) {
return VariantTier.STANDARD; // 6/10 return VariantTier.STANDARD; // 6/10
} }

View File

@ -0,0 +1,20 @@
import { MoveTarget } from "#enums/MoveTarget";
import type Move from "./move";
/**
* Return whether the move targets the field
*
* Examples include
* - Hazard moves like spikes
* - Weather moves like rain dance
* - User side moves like reflect and safeguard
*/
export function isFieldTargeted(move: Move): boolean {
switch (move.moveTarget) {
case MoveTarget.BOTH_SIDES:
case MoveTarget.USER_SIDE:
case MoveTarget.ENEMY_SIDE:
return true;
}
return false;
}

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,7 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { TrainerType } from "#enums/trainer-type"; import { TrainerType } from "#enums/trainer-type";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import { getSpriteKeysFromSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { getSpriteKeysFromSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
import { randSeedInt } from "#app/utils"; import { randSeedInt } from "#app/utils/common";
import i18next from "i18next"; import i18next from "i18next";
import type { IEggOptions } from "#app/data/egg"; import type { IEggOptions } from "#app/data/egg";
import { EggSourceType } from "#enums/egg-source-types"; import { EggSourceType } from "#enums/egg-source-types";
@ -22,7 +22,7 @@ import { EggTier } from "#enums/egg-type";
import { PartyHealPhase } from "#app/phases/party-heal-phase"; import { PartyHealPhase } from "#app/phases/party-heal-phase";
import { ModifierTier } from "#app/modifier/modifier-tier"; import { ModifierTier } from "#app/modifier/modifier-tier";
import { modifierTypes } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */
const namespace = "mysteryEncounters/aTrainersTest"; const namespace = "mysteryEncounters/aTrainersTest";

View File

@ -24,7 +24,7 @@ import { BerryModifier, PokemonInstantReviveModifier } from "#app/modifier/modif
import { getPokemonSpecies } from "#app/data/pokemon-species"; import { getPokemonSpecies } from "#app/data/pokemon-species";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { randInt } from "#app/utils"; import { randInt } from "#app/utils/common";
import { BattlerIndex } from "#app/battle"; import { BattlerIndex } from "#app/battle";
import { import {
applyModifierTypeToPlayerPokemon, applyModifierTypeToPlayerPokemon,
@ -37,7 +37,7 @@ import type HeldModifierConfig from "#app/interfaces/held-modifier-config";
import type { BerryType } from "#enums/berry-type"; import type { BerryType } from "#enums/berry-type";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import i18next from "i18next"; import i18next from "i18next";
/** the i18n namespace for this encounter */ /** the i18n namespace for this encounter */

View File

@ -23,7 +23,7 @@ import { speciesStarterCosts } from "#app/data/balance/starters";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase"; import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import i18next from "i18next"; import i18next from "i18next";
/** the i18n namespace for this encounter */ /** the i18n namespace for this encounter */

View File

@ -13,7 +13,7 @@ import type { PlayerPokemon } from "#app/field/pokemon";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import type { BerryModifierType, ModifierTypeOption } from "#app/modifier/modifier-type"; import type { BerryModifierType, ModifierTypeOption } from "#app/modifier/modifier-type";
import { ModifierPoolType, modifierTypes, regenerateModifierPoolThresholds } from "#app/modifier/modifier-type"; import { ModifierPoolType, modifierTypes, regenerateModifierPoolThresholds } from "#app/modifier/modifier-type";
import { randSeedInt } from "#app/utils"; import { randSeedInt } from "#app/utils/common";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
@ -36,7 +36,7 @@ import i18next from "#app/plugins/i18n";
import { BerryType } from "#enums/berry-type"; import { BerryType } from "#enums/berry-type";
import { PERMANENT_STATS, Stat } from "#enums/stat"; import { PERMANENT_STATS, Stat } from "#enums/stat";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */
const namespace = "mysteryEncounters/berriesAbound"; const namespace = "mysteryEncounters/berriesAbound";

View File

@ -16,7 +16,7 @@ import { TrainerSlot } from "#enums/trainer-slot";
import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { PartyMemberStrength } from "#enums/party-member-strength"; import { PartyMemberStrength } from "#enums/party-member-strength";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { isNullOrUndefined, randSeedInt, randSeedShuffle } from "#app/utils"; import { isNullOrUndefined, randSeedInt, randSeedShuffle } from "#app/utils/common";
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter"; import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
@ -52,7 +52,7 @@ import i18next from "i18next";
import MoveInfoOverlay from "#app/ui/move-info-overlay"; import MoveInfoOverlay from "#app/ui/move-info-overlay";
import { allMoves } from "#app/data/moves/move"; import { allMoves } from "#app/data/moves/move";
import { ModifierTier } from "#app/modifier/modifier-tier"; import { ModifierTier } from "#app/modifier/modifier-tier";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { getSpriteKeysFromSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { getSpriteKeysFromSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */

View File

@ -31,14 +31,14 @@ import {
import { PokemonType } from "#enums/pokemon-type"; import { PokemonType } from "#enums/pokemon-type";
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option"; import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { randSeedInt, randSeedShuffle } from "#app/utils"; import { randSeedInt, randSeedShuffle } from "#app/utils/common";
import { showEncounterDialogue, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { showEncounterDialogue, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import { Mode } from "#app/ui/ui"; import { UiMode } from "#enums/ui-mode";
import i18next from "i18next"; import i18next from "i18next";
import type { OptionSelectConfig } from "#app/ui/abstact-option-select-ui-handler"; import type { OptionSelectConfig } from "#app/ui/abstact-option-select-ui-handler";
import type { PlayerPokemon } from "#app/field/pokemon"; import type { PlayerPokemon } from "#app/field/pokemon";
import { PokemonMove } from "#app/field/pokemon"; import { PokemonMove } from "#app/field/pokemon";
import { Ability } from "#app/data/ability"; import { Ability } from "#app/data/abilities/ability-class";
import { BerryModifier } from "#app/modifier/modifier"; import { BerryModifier } from "#app/modifier/modifier";
import { BerryType } from "#enums/berry-type"; import { BerryType } from "#enums/berry-type";
import { BattlerIndex } from "#app/battle"; import { BattlerIndex } from "#app/battle";
@ -46,7 +46,7 @@ import { Moves } from "#enums/moves";
import { EncounterBattleAnim } from "#app/data/battle-anims"; import { EncounterBattleAnim } from "#app/data/battle-anims";
import { MoveCategory } from "#enums/MoveCategory"; import { MoveCategory } from "#enums/MoveCategory";
import { CustomPokemonData } from "#app/data/custom-pokemon-data"; import { CustomPokemonData } from "#app/data/custom-pokemon-data";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { EncounterAnim } from "#enums/encounter-anims"; import { EncounterAnim } from "#enums/encounter-anims";
import { Challenges } from "#enums/challenges"; import { Challenges } from "#enums/challenges";
@ -437,7 +437,7 @@ async function handleSwapAbility() {
await showEncounterDialogue(`${namespace}:option.1.apply_ability_dialogue`, `${namespace}:speaker`); await showEncounterDialogue(`${namespace}:option.1.apply_ability_dialogue`, `${namespace}:speaker`);
await showEncounterText(`${namespace}:option.1.apply_ability_message`); await showEncounterText(`${namespace}:option.1.apply_ability_message`);
globalScene.ui.setMode(Mode.MESSAGE).then(() => { globalScene.ui.setMode(UiMode.MESSAGE).then(() => {
displayYesNoOptions(resolve); displayYesNoOptions(resolve);
}); });
}); });
@ -467,7 +467,7 @@ function displayYesNoOptions(resolve) {
maxOptions: 7, maxOptions: 7,
yOffset: 0, yOffset: 0,
}; };
globalScene.ui.setModeWithoutClear(Mode.OPTION_SELECT, config, null, true); globalScene.ui.setModeWithoutClear(UiMode.OPTION_SELECT, config, null, true);
} }
function onYesAbilitySwap(resolve) { function onYesAbilitySwap(resolve) {
@ -477,11 +477,11 @@ function onYesAbilitySwap(resolve) {
applyAbilityOverrideToPokemon(pokemon, encounter.misc.ability); applyAbilityOverrideToPokemon(pokemon, encounter.misc.ability);
encounter.setDialogueToken("chosenPokemon", pokemon.getNameToRender()); encounter.setDialogueToken("chosenPokemon", pokemon.getNameToRender());
globalScene.ui.setMode(Mode.MESSAGE).then(() => resolve(true)); globalScene.ui.setMode(UiMode.MESSAGE).then(() => resolve(true));
}; };
const onPokemonNotSelected = () => { const onPokemonNotSelected = () => {
globalScene.ui.setMode(Mode.MESSAGE).then(() => { globalScene.ui.setMode(UiMode.MESSAGE).then(() => {
displayYesNoOptions(resolve); displayYesNoOptions(resolve);
}); });
}; };

View File

@ -24,7 +24,7 @@ import { TrainerSlot } from "#enums/trainer-slot";
import type { PlayerPokemon } from "#app/field/pokemon"; import type { PlayerPokemon } from "#app/field/pokemon";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { EnemyPokemon, PokemonMove } from "#app/field/pokemon"; import { EnemyPokemon, PokemonMove } from "#app/field/pokemon";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { modifierTypes } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type";
import { LearnMovePhase } from "#app/phases/learn-move-phase"; import { LearnMovePhase } from "#app/phases/learn-move-phase";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";

View File

@ -1,5 +1,5 @@
import type { PokemonType } from "#enums/pokemon-type"; import type { PokemonType } from "#enums/pokemon-type";
import { isNullOrUndefined, randSeedInt } from "#app/utils"; import { isNullOrUndefined, randSeedInt } from "#app/utils/common";
import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
@ -19,7 +19,7 @@ import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode
import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase"; import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase";
import type { PokemonHeldItemModifier } from "#app/modifier/modifier"; import type { PokemonHeldItemModifier } from "#app/modifier/modifier";
import { PokemonFormChangeItemModifier } from "#app/modifier/modifier"; import { PokemonFormChangeItemModifier } from "#app/modifier/modifier";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { Challenges } from "#enums/challenges"; import { Challenges } from "#enums/challenges";
/** i18n namespace for encounter */ /** i18n namespace for encounter */

View File

@ -18,7 +18,7 @@ import { applyModifierTypeToPlayerPokemon } from "#app/data/mystery-encounters/u
import { getPokemonSpecies } from "#app/data/pokemon-species"; import { getPokemonSpecies } from "#app/data/pokemon-species";
import type { PlayerPokemon } from "#app/field/pokemon"; import type { PlayerPokemon } from "#app/field/pokemon";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import type { PokemonHeldItemModifier, PokemonInstantReviveModifier } from "#app/modifier/modifier"; import type { PokemonHeldItemModifier, PokemonInstantReviveModifier } from "#app/modifier/modifier";
import { import {
BerryModifier, BerryModifier,
@ -32,11 +32,12 @@ import { modifierTypes } from "#app/modifier/modifier-type";
import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase"; import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase";
import i18next from "#app/plugins/i18n"; import i18next from "#app/plugins/i18n";
import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler"; import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
import { randSeedItem } from "#app/utils"; import { randSeedItem } from "#app/utils/common";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import { timedEventManager } from "#app/global-event-manager";
/** the i18n namespace for this encounter */ /** the i18n namespace for this encounter */
const namespace = "mysteryEncounters/delibirdy"; const namespace = "mysteryEncounters/delibirdy";
@ -56,7 +57,7 @@ const OPTION_3_DISALLOWED_MODIFIERS = [
const DELIBIRDY_MONEY_PRICE_MULTIPLIER = 2; const DELIBIRDY_MONEY_PRICE_MULTIPLIER = 2;
const doEventReward = () => { const doEventReward = () => {
const event_buff = globalScene.eventManager.getDelibirdyBuff(); const event_buff = timedEventManager.getDelibirdyBuff();
if (event_buff.length > 0) { if (event_buff.length > 0) {
const candidates = event_buff.filter(c => { const candidates = event_buff.filter(c => {
const mtype = generateModifierType(modifierTypes[c]); const mtype = generateModifierType(modifierTypes[c]);

View File

@ -4,13 +4,13 @@ import {
} from "#app/data/mystery-encounters/utils/encounter-phase-utils"; } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import type { ModifierTypeFunc } from "#app/modifier/modifier-type"; import type { ModifierTypeFunc } from "#app/modifier/modifier-type";
import { modifierTypes } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type";
import { randSeedInt } from "#app/utils"; import { randSeedInt } from "#app/utils/common";
import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter"; import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
/** i18n namespace for encounter */ /** i18n namespace for encounter */
const namespace = "mysteryEncounters/departmentStoreSale"; const namespace = "mysteryEncounters/departmentStoreSale";

View File

@ -18,7 +18,7 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import i18next from "i18next"; import i18next from "i18next";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
/** i18n namespace for the encounter */ /** i18n namespace for the encounter */
const namespace = "mysteryEncounters/fieldTrip"; const namespace = "mysteryEncounters/fieldTrip";

View File

@ -30,7 +30,7 @@ import { PokemonMove } from "#app/field/pokemon";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { EncounterBattleAnim } from "#app/data/battle-anims"; import { EncounterBattleAnim } from "#app/data/battle-anims";
import { WeatherType } from "#enums/weather-type"; import { WeatherType } from "#enums/weather-type";
import { isNullOrUndefined, randSeedInt } from "#app/utils"; import { isNullOrUndefined, randSeedInt } from "#app/utils/common";
import { StatusEffect } from "#enums/status-effect"; import { StatusEffect } from "#enums/status-effect";
import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import { import {
@ -41,12 +41,12 @@ import {
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { EncounterAnim } from "#enums/encounter-anims"; import { EncounterAnim } from "#enums/encounter-anims";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import { Ability } from "#app/data/ability"; import { Ability } from "#app/data/abilities/ability-class";
import { FIRE_RESISTANT_ABILITIES } from "#app/data/mystery-encounters/requirements/requirement-groups"; import { FIRE_RESISTANT_ABILITIES } from "#app/data/mystery-encounters/requirements/requirement-groups";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */

View File

@ -31,9 +31,9 @@ import {
import PokemonData from "#app/system/pokemon-data"; import PokemonData from "#app/system/pokemon-data";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import { randSeedInt } from "#app/utils"; import { randSeedInt } from "#app/utils/common";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */
const namespace = "mysteryEncounters/fightOrFlight"; const namespace = "mysteryEncounters/fightOrFlight";

View File

@ -30,7 +30,7 @@ import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms";
import { PostSummonPhase } from "#app/phases/post-summon-phase"; import { PostSummonPhase } from "#app/phases/post-summon-phase";
import { modifierTypes } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type";
import { Nature } from "#enums/nature"; import { Nature } from "#enums/nature";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { isPokemonValidForEncounterOptionSelection } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { isPokemonValidForEncounterOptionSelection } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */

View File

@ -23,7 +23,14 @@ import { allSpecies, getPokemonSpecies } from "#app/data/pokemon-species";
import { getTypeRgb } from "#app/data/type"; import { getTypeRgb } from "#app/data/type";
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option"; import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { NumberHolder, isNullOrUndefined, randInt, randSeedInt, randSeedShuffle, randSeedItem } from "#app/utils"; import {
NumberHolder,
isNullOrUndefined,
randInt,
randSeedInt,
randSeedShuffle,
randSeedItem,
} from "#app/utils/common";
import type { PlayerPokemon } from "#app/field/pokemon"; import type { PlayerPokemon } from "#app/field/pokemon";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { EnemyPokemon, PokemonMove } from "#app/field/pokemon"; import { EnemyPokemon, PokemonMove } from "#app/field/pokemon";
@ -41,11 +48,12 @@ import { Gender, getGenderSymbol } from "#app/data/gender";
import { getNatureName } from "#app/data/nature"; import { getNatureName } from "#app/data/nature";
import { getPokeballAtlasKey, getPokeballTintColor } from "#app/data/pokeball"; import { getPokeballAtlasKey, getPokeballTintColor } from "#app/data/pokeball";
import { getEncounterText, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { getEncounterText, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { addPokemonDataToDexAndValidateAchievements } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { addPokemonDataToDexAndValidateAchievements } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
import type { PokeballType } from "#enums/pokeball"; import type { PokeballType } from "#enums/pokeball";
import { doShinySparkleAnim } from "#app/field/anims"; import { doShinySparkleAnim } from "#app/field/anims";
import { TrainerType } from "#enums/trainer-type"; import { TrainerType } from "#enums/trainer-type";
import { timedEventManager } from "#app/global-event-manager";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */
const namespace = "mysteryEncounters/globalTradeSystem"; const namespace = "mysteryEncounters/globalTradeSystem";
@ -273,8 +281,8 @@ export const GlobalTradeSystemEncounter: MysteryEncounter = MysteryEncounterBuil
// Extra shiny roll at 1/128 odds (boosted by events and charms) // Extra shiny roll at 1/128 odds (boosted by events and charms)
if (!tradePokemon.shiny) { if (!tradePokemon.shiny) {
const shinyThreshold = new NumberHolder(WONDER_TRADE_SHINY_CHANCE); const shinyThreshold = new NumberHolder(WONDER_TRADE_SHINY_CHANCE);
if (globalScene.eventManager.isEventActive()) { if (timedEventManager.isEventActive()) {
shinyThreshold.value *= globalScene.eventManager.getShinyMultiplier(); shinyThreshold.value *= timedEventManager.getShinyMultiplier();
} }
globalScene.applyModifiers(ShinyRateBoosterModifier, true, shinyThreshold); globalScene.applyModifiers(ShinyRateBoosterModifier, true, shinyThreshold);
@ -984,12 +992,11 @@ function doTradeReceivedSequence(
function generateRandomTraderName() { function generateRandomTraderName() {
const length = TrainerType.YOUNGSTER - TrainerType.ACE_TRAINER + 1; const length = TrainerType.YOUNGSTER - TrainerType.ACE_TRAINER + 1;
// +1 avoids TrainerType.UNKNOWN // +1 avoids TrainerType.UNKNOWN
const trainerTypePool = i18next.t("trainersCommon:" + TrainerType[randInt(length) + 1], { returnObjects: true }); const classKey = `trainersCommon:${TrainerType[randInt(length) + 1]}`;
// Some trainers have 2 gendered pools, some do not // Some trainers have 2 gendered pools, some do not
const gender = randInt(2) === 0 ? "MALE" : "FEMALE"; const genderKey = i18next.exists(`${classKey}.MALE`) ? (randInt(2) === 0 ? ".MALE" : ".FEMALE") : "";
const trainerNameString = randSeedItem( const trainerNameKey = randSeedItem(Object.keys(i18next.t(`${classKey}${genderKey}`, { returnObjects: true })));
Object.values(trainerTypePool.hasOwnProperty(gender) ? trainerTypePool[gender] : trainerTypePool), const trainerNameString = i18next.t(`${classKey}${genderKey}.${trainerNameKey}`);
) as string;
// Some names have an '&' symbol and need to be trimmed to a single name instead of a double name // Some names have an '&' symbol and need to be trimmed to a single name instead of a double name
const trainerNames = trainerNameString.split(" & "); const trainerNames = trainerNameString.split(" & ");
return trainerNames[randInt(trainerNames.length)]; return trainerNames[randInt(trainerNames.length)];

View File

@ -10,7 +10,7 @@ import { leaveEncounterWithoutBattle, setEncounterExp } from "../utils/encounter
import { applyDamageToPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { applyDamageToPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { PokemonMove } from "#app/field/pokemon"; import { PokemonMove } from "#app/field/pokemon";
const OPTION_1_REQUIRED_MOVE = Moves.SURF; const OPTION_1_REQUIRED_MOVE = Moves.SURF;

View File

@ -12,11 +12,11 @@ import { modifierTypes } from "#app/modifier/modifier-type";
import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { PartyMemberStrength } from "#enums/party-member-strength"; import { PartyMemberStrength } from "#enums/party-member-strength";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import * as Utils from "#app/utils"; import { randSeedInt } from "#app/utils/common";
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter"; import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */
const namespace = "mysteryEncounters/mysteriousChallengers"; const namespace = "mysteryEncounters/mysteriousChallengers";
@ -46,7 +46,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = MysteryEncounter
const normalConfig = trainerConfigs[normalTrainerType].clone(); const normalConfig = trainerConfigs[normalTrainerType].clone();
let female = false; let female = false;
if (normalConfig.hasGenders) { if (normalConfig.hasGenders) {
female = !!Utils.randSeedInt(2); female = !!randSeedInt(2);
} }
const normalSpriteKey = normalConfig.getSpriteKey(female, normalConfig.doubleOnly); const normalSpriteKey = normalConfig.getSpriteKey(female, normalConfig.doubleOnly);
encounter.enemyPartyConfigs.push({ encounter.enemyPartyConfigs.push({
@ -76,7 +76,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = MysteryEncounter
hardConfig.setPartyTemplates(hardTemplate); hardConfig.setPartyTemplates(hardTemplate);
female = false; female = false;
if (hardConfig.hasGenders) { if (hardConfig.hasGenders) {
female = !!Utils.randSeedInt(2); female = !!randSeedInt(2);
} }
const hardSpriteKey = hardConfig.getSpriteKey(female, hardConfig.doubleOnly); const hardSpriteKey = hardConfig.getSpriteKey(female, hardConfig.doubleOnly);
encounter.enemyPartyConfigs.push({ encounter.enemyPartyConfigs.push({
@ -96,7 +96,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = MysteryEncounter
brutalConfig.partyTemplateFunc = null; // Overrides gym leader party template func brutalConfig.partyTemplateFunc = null; // Overrides gym leader party template func
female = false; female = false;
if (brutalConfig.hasGenders) { if (brutalConfig.hasGenders) {
female = !!Utils.randSeedInt(2); female = !!randSeedInt(2);
} }
const brutalSpriteKey = brutalConfig.getSpriteKey(female, brutalConfig.doubleOnly); const brutalSpriteKey = brutalConfig.getSpriteKey(female, brutalConfig.doubleOnly);
encounter.enemyPartyConfigs.push({ encounter.enemyPartyConfigs.push({

View File

@ -15,10 +15,10 @@ import {
koPlayerPokemon, koPlayerPokemon,
} from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
import { getPokemonSpecies } from "#app/data/pokemon-species"; import { getPokemonSpecies } from "#app/data/pokemon-species";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { ModifierTier } from "#app/modifier/modifier-tier"; import { ModifierTier } from "#app/modifier/modifier-tier";
import { GameOverPhase } from "#app/phases/game-over-phase"; import { GameOverPhase } from "#app/phases/game-over-phase";
import { randSeedInt } from "#app/utils"; import { randSeedInt } from "#app/utils/common";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";

View File

@ -20,7 +20,7 @@ import { showEncounterDialogue, showEncounterText } from "#app/data/mystery-enco
import i18next from "i18next"; import i18next from "i18next";
import type { PlayerPokemon } from "#app/field/pokemon"; import type { PlayerPokemon } from "#app/field/pokemon";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { isPokemonValidForEncounterOptionSelection } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { isPokemonValidForEncounterOptionSelection } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */

View File

@ -15,7 +15,7 @@ import { HiddenAbilityRateBoosterModifier, IvScannerModifier } from "#app/modifi
import type { EnemyPokemon } from "#app/field/pokemon"; import type { EnemyPokemon } from "#app/field/pokemon";
import { PokeballType } from "#enums/pokeball"; import { PokeballType } from "#enums/pokeball";
import { PlayerGender } from "#enums/player-gender"; import { PlayerGender } from "#enums/player-gender";
import { NumberHolder, randSeedInt } from "#app/utils"; import { NumberHolder, randSeedInt } from "#app/utils/common";
import type PokemonSpecies from "#app/data/pokemon-species"; import type PokemonSpecies from "#app/data/pokemon-species";
import { getPokemonSpecies } from "#app/data/pokemon-species"; import { getPokemonSpecies } from "#app/data/pokemon-species";
import { MoneyRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements"; import { MoneyRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
@ -31,7 +31,7 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { ScanIvsPhase } from "#app/phases/scan-ivs-phase"; import { ScanIvsPhase } from "#app/phases/scan-ivs-phase";
import { SummonPhase } from "#app/phases/summon-phase"; import { SummonPhase } from "#app/phases/summon-phase";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { NON_LEGEND_PARADOX_POKEMON } from "#app/data/balance/special-species-groups"; import { NON_LEGEND_PARADOX_POKEMON } from "#app/data/balance/special-species-groups";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */

View File

@ -8,7 +8,7 @@ import {
import type { PlayerPokemon } from "#app/field/pokemon"; import type { PlayerPokemon } from "#app/field/pokemon";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { modifierTypes } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type";
import { randSeedInt } from "#app/utils"; import { randSeedInt } from "#app/utils/common";
import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
@ -26,7 +26,7 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import type { Nature } from "#enums/nature"; import type { Nature } from "#enums/nature";
import { getNatureName } from "#app/data/nature"; import { getNatureName } from "#app/data/nature";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import i18next from "i18next"; import i18next from "i18next";
/** the i18n namespace for this encounter */ /** the i18n namespace for this encounter */

View File

@ -26,7 +26,7 @@ import { getPokemonSpecies } from "#app/data/pokemon-species";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { PartyHealPhase } from "#app/phases/party-heal-phase"; import { PartyHealPhase } from "#app/phases/party-heal-phase";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { BerryType } from "#enums/berry-type"; import { BerryType } from "#enums/berry-type";
import { CustomPokemonData } from "#app/data/custom-pokemon-data"; import { CustomPokemonData } from "#app/data/custom-pokemon-data";
@ -42,7 +42,7 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter = MysteryEncounterBuil
MysteryEncounterType.SLUMBERING_SNORLAX, MysteryEncounterType.SLUMBERING_SNORLAX,
) )
.withEncounterTier(MysteryEncounterTier.GREAT) .withEncounterTier(MysteryEncounterTier.GREAT)
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES) .withSceneWaveRangeRequirement(15, 150)
.withCatchAllowed(true) .withCatchAllowed(true)
.withHideWildIntroMessage(true) .withHideWildIntroMessage(true)
.withFleeAllowed(false) .withFleeAllowed(false)
@ -72,16 +72,25 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter = MysteryEncounterBuil
species: bossSpecies, species: bossSpecies,
isBoss: true, isBoss: true,
shiny: false, // Shiny lock because shiny is rolled only if the battle option is picked shiny: false, // Shiny lock because shiny is rolled only if the battle option is picked
status: [StatusEffect.SLEEP, 5], // Extra turns on timer for Snorlax's start of fight moves status: [StatusEffect.SLEEP, 6], // Extra turns on timer for Snorlax's start of fight moves
moveSet: [Moves.REST, Moves.SLEEP_TALK, Moves.CRUNCH, Moves.GIGA_IMPACT], moveSet: [Moves.BODY_SLAM, Moves.CRUNCH, Moves.SLEEP_TALK, Moves.REST],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(modifierTypes.BERRY, [BerryType.SITRUS]) as PokemonHeldItemModifierType, modifier: generateModifierType(modifierTypes.BERRY, [BerryType.SITRUS]) as PokemonHeldItemModifierType,
stackCount: 2,
}, },
{ {
modifier: generateModifierType(modifierTypes.BERRY, [BerryType.ENIGMA]) as PokemonHeldItemModifierType, modifier: generateModifierType(modifierTypes.BERRY, [BerryType.ENIGMA]) as PokemonHeldItemModifierType,
stackCount: 2, },
{
modifier: generateModifierType(modifierTypes.BASE_STAT_BOOSTER, [Stat.HP]) as PokemonHeldItemModifierType,
},
{
modifier: generateModifierType(modifierTypes.SOOTHE_BELL) as PokemonHeldItemModifierType,
stackCount: randSeedInt(2, 0),
},
{
modifier: generateModifierType(modifierTypes.LUCKY_EGG) as PokemonHeldItemModifierType,
stackCount: randSeedInt(2, 0),
}, },
], ],
customPokemonData: new CustomPokemonData({ spriteScale: 1.25 }), customPokemonData: new CustomPokemonData({ spriteScale: 1.25 }),
@ -128,12 +137,6 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter = MysteryEncounterBuil
move: new PokemonMove(Moves.SNORE), move: new PokemonMove(Moves.SNORE),
ignorePp: true, ignorePp: true,
}, },
{
sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.PLAYER],
move: new PokemonMove(Moves.SNORE),
ignorePp: true,
},
); );
await initBattleWithEnemyConfig(encounter.enemyPartyConfigs[0]); await initBattleWithEnemyConfig(encounter.enemyPartyConfigs[0]);
}, },

View File

@ -7,7 +7,7 @@ import {
transitionMysteryEncounterIntroVisuals, transitionMysteryEncounterIntroVisuals,
updatePlayerMoney, updatePlayerMoney,
} from "#app/data/mystery-encounters/utils/encounter-phase-utils"; } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { randSeedInt } from "#app/utils"; import { randSeedInt } from "#app/utils/common";
import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
@ -29,7 +29,7 @@ import { BattlerTagType } from "#enums/battler-tag-type";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { import {
getEncounterPokemonLevelForWave, getEncounterPokemonLevelForWave,
STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER, STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER,

View File

@ -7,11 +7,11 @@ import {
import { trainerConfigs } from "#app/data/trainers/trainer-config"; import { trainerConfigs } from "#app/data/trainers/trainer-config";
import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { randSeedShuffle } from "#app/utils"; import { randSeedShuffle } from "#app/utils/common";
import type MysteryEncounter from "../mystery-encounter"; import type MysteryEncounter from "../mystery-encounter";
import { MysteryEncounterBuilder } from "../mystery-encounter"; import { MysteryEncounterBuilder } from "../mystery-encounter";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { Biome } from "#enums/biome"; import { Biome } from "#enums/biome";
import { TrainerType } from "#enums/trainer-type"; import { TrainerType } from "#enums/trainer-type";
import i18next from "i18next"; import i18next from "i18next";

View File

@ -3,7 +3,7 @@ import {
transitionMysteryEncounterIntroVisuals, transitionMysteryEncounterIntroVisuals,
updatePlayerMoney, updatePlayerMoney,
} from "#app/data/mystery-encounters/utils/encounter-phase-utils"; } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { isNullOrUndefined, randSeedInt } from "#app/utils"; import { isNullOrUndefined, NumberHolder, randSeedInt, randSeedItem } from "#app/utils/common";
import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
@ -26,9 +26,10 @@ import { showEncounterDialogue } from "#app/data/mystery-encounters/utils/encoun
import PokemonData from "#app/system/pokemon-data"; import PokemonData from "#app/system/pokemon-data";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { NON_LEGEND_PARADOX_POKEMON } from "#app/data/balance/special-species-groups"; import { NON_LEGEND_PARADOX_POKEMON, NON_LEGEND_ULTRA_BEASTS } from "#app/data/balance/special-species-groups";
import { timedEventManager } from "#app/global-event-manager";
/** the i18n namespace for this encounter */ /** the i18n namespace for this encounter */
const namespace = "mysteryEncounters/thePokemonSalesman"; const namespace = "mysteryEncounters/thePokemonSalesman";
@ -38,6 +39,9 @@ const MAX_POKEMON_PRICE_MULTIPLIER = 4;
/** Odds of shiny magikarp will be 1/value */ /** Odds of shiny magikarp will be 1/value */
const SHINY_MAGIKARP_WEIGHT = 100; const SHINY_MAGIKARP_WEIGHT = 100;
/** Odds of event sale will be value/100 */
const EVENT_THRESHOLD = 50;
/** /**
* Pokemon Salesman encounter. * Pokemon Salesman encounter.
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3799 | GitHub Issue #3799} * @see {@link https://github.com/pagefaultgames/pokerogue/issues/3799 | GitHub Issue #3799}
@ -82,15 +86,46 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter = MysteryEncounterBui
tries++; tries++;
} }
const r = randSeedInt(SHINY_MAGIKARP_WEIGHT);
const validEventEncounters = timedEventManager
.getEventEncounters()
.filter(
s =>
!getPokemonSpecies(s.species).legendary &&
!getPokemonSpecies(s.species).subLegendary &&
!getPokemonSpecies(s.species).mythical &&
!NON_LEGEND_PARADOX_POKEMON.includes(s.species) &&
!NON_LEGEND_ULTRA_BEASTS.includes(s.species),
);
let pokemon: PlayerPokemon; let pokemon: PlayerPokemon;
/**
* Mon is determined as follows:
* If you roll the 1% for Shiny Magikarp, you get Magikarp with a random variant
* If an event with more than 1 valid event encounter species is active, you have 20% chance to get one of those
* If the rolled species has no HA, and there are valid event encounters, you will get one of those
* If the rolled species has no HA and there are no valid event encounters, you will get Shiny Magikarp
* Mons rolled from the event encounter pool get 2 extra shiny rolls
*/
if ( if (
randSeedInt(SHINY_MAGIKARP_WEIGHT) === 0 || r === 0 ||
isNullOrUndefined(species.abilityHidden) || ((isNullOrUndefined(species.abilityHidden) || species.abilityHidden === Abilities.NONE) &&
species.abilityHidden === Abilities.NONE (validEventEncounters.length === 0))
) { ) {
// If no HA mon found or you roll 1%, give shiny Magikarp with random variant // If you roll 1%, give shiny Magikarp with random variant
species = getPokemonSpecies(Species.MAGIKARP); species = getPokemonSpecies(Species.MAGIKARP);
pokemon = new PlayerPokemon(species, 5, 2, species.formIndex, undefined, true); pokemon = new PlayerPokemon(species, 5, 2, undefined, undefined, true);
} else if (
(validEventEncounters.length > 0 && (r <= EVENT_THRESHOLD ||
(isNullOrUndefined(species.abilityHidden) || species.abilityHidden === Abilities.NONE)))
) {
// If you roll 20%, give event encounter with 2 extra shiny rolls and its HA, if it has one
const enc = randSeedItem(validEventEncounters);
species = getPokemonSpecies(enc.species);
pokemon = new PlayerPokemon(species, 5, species.abilityHidden === Abilities.NONE ? undefined : 2, enc.formIndex);
pokemon.trySetShinySeed();
pokemon.trySetShinySeed();
} else { } else {
pokemon = new PlayerPokemon(species, 5, 2, species.formIndex); pokemon = new PlayerPokemon(species, 5, 2, species.formIndex);
} }

View File

@ -28,7 +28,7 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { CustomPokemonData } from "#app/data/custom-pokemon-data"; import { CustomPokemonData } from "#app/data/custom-pokemon-data";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */
const namespace = "mysteryEncounters/theStrongStuff"; const namespace = "mysteryEncounters/theStrongStuff";

View File

@ -24,7 +24,7 @@ import { PokemonType } from "#enums/pokemon-type";
import { BerryType } from "#enums/berry-type"; import { BerryType } from "#enums/berry-type";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import { SpeciesFormChangeAbilityTrigger } from "#app/data/pokemon-forms"; import { SpeciesFormChangeAbilityTrigger } from "#app/data/pokemon-forms";
import { applyPostBattleInitAbAttrs, PostBattleInitAbAttr } from "#app/data/ability"; import { applyPostBattleInitAbAttrs, PostBattleInitAbAttr } from "#app/data/abilities/ability";
import { showEncounterDialogue, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { showEncounterDialogue, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
import { PartyHealPhase } from "#app/phases/party-heal-phase"; import { PartyHealPhase } from "#app/phases/party-heal-phase";
@ -32,7 +32,7 @@ import { ShowTrainerPhase } from "#app/phases/show-trainer-phase";
import { ReturnPhase } from "#app/phases/return-phase"; import { ReturnPhase } from "#app/phases/return-phase";
import i18next from "i18next"; import i18next from "i18next";
import { ModifierTier } from "#app/modifier/modifier-tier"; import { ModifierTier } from "#app/modifier/modifier-tier";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */

View File

@ -1,5 +1,5 @@
import type { Ability } from "#app/data/ability"; import type { Ability } from "#app/data/abilities/ability-class";
import { allAbilities } from "#app/data/ability"; import { allAbilities } from "#app/data/data-lists";
import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { import {
initBattleWithEnemyConfig, initBattleWithEnemyConfig,
@ -15,7 +15,7 @@ import type { PokemonHeldItemModifier } from "#app/modifier/modifier";
import { AbilityAttr } from "#app/system/game-data"; import { AbilityAttr } from "#app/system/game-data";
import PokemonData from "#app/system/pokemon-data"; import PokemonData from "#app/system/pokemon-data";
import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler"; import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
import { isNullOrUndefined, randSeedShuffle } from "#app/utils"; import { isNullOrUndefined, randSeedShuffle } from "#app/utils/common";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
@ -28,7 +28,7 @@ import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode
import type HeldModifierConfig from "#app/interfaces/held-modifier-config"; import type HeldModifierConfig from "#app/interfaces/held-modifier-config";
import i18next from "i18next"; import i18next from "i18next";
import { getStatKey } from "#enums/stat"; import { getStatKey } from "#enums/stat";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { isPokemonValidForEncounterOptionSelection } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { isPokemonValidForEncounterOptionSelection } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
import type { Nature } from "#enums/nature"; import type { Nature } from "#enums/nature";

View File

@ -26,8 +26,8 @@ import { getPokemonSpecies } from "#app/data/pokemon-species";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { BattlerIndex } from "#app/battle"; import { BattlerIndex } from "#app/battle";
import { PokemonMove } from "#app/field/pokemon"; import { PokemonMove } from "#app/field/pokemon";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { randSeedInt } from "#app/utils"; import { randSeedInt } from "#app/utils/common";
/** the i18n namespace for this encounter */ /** the i18n namespace for this encounter */
const namespace = "mysteryEncounters/trashToTreasure"; const namespace = "mysteryEncounters/trashToTreasure";

View File

@ -27,7 +27,7 @@ import {
getSpriteKeysFromPokemon, getSpriteKeysFromPokemon,
} from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
import PokemonData from "#app/system/pokemon-data"; import PokemonData from "#app/system/pokemon-data";
import { isNullOrUndefined, randSeedInt } from "#app/utils"; import { isNullOrUndefined, randSeedInt } from "#app/utils/common";
import type { Moves } from "#enums/moves"; import type { Moves } from "#enums/moves";
import { BattlerIndex } from "#app/battle"; import { BattlerIndex } from "#app/battle";
import { SelfStatusMove } from "#app/data/moves/move"; import { SelfStatusMove } from "#app/data/moves/move";
@ -37,7 +37,7 @@ import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encoun
import { BerryModifier } from "#app/modifier/modifier"; import { BerryModifier } from "#app/modifier/modifier";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */
const namespace = "mysteryEncounters/uncommonBreed"; const namespace = "mysteryEncounters/uncommonBreed";

View File

@ -17,7 +17,7 @@ import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode
import type { PlayerPokemon } from "#app/field/pokemon"; import type { PlayerPokemon } from "#app/field/pokemon";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { PokemonMove } from "#app/field/pokemon"; import { PokemonMove } from "#app/field/pokemon";
import { NumberHolder, isNullOrUndefined, randSeedInt, randSeedShuffle } from "#app/utils"; import { NumberHolder, isNullOrUndefined, randSeedInt, randSeedShuffle } from "#app/utils/common";
import type PokemonSpecies from "#app/data/pokemon-species"; import type PokemonSpecies from "#app/data/pokemon-species";
import { allSpecies, getPokemonSpecies } from "#app/data/pokemon-species"; import { allSpecies, getPokemonSpecies } from "#app/data/pokemon-species";
import type { PokemonHeldItemModifier } from "#app/modifier/modifier"; import type { PokemonHeldItemModifier } from "#app/modifier/modifier";

View File

@ -12,7 +12,7 @@ import {
} from "#app/data/mystery-encounters/mystery-encounter-requirements"; } from "#app/data/mystery-encounters/mystery-encounter-requirements";
import type { CanLearnMoveRequirementOptions } from "./requirements/can-learn-move-requirement"; import type { CanLearnMoveRequirementOptions } from "./requirements/can-learn-move-requirement";
import { CanLearnMoveRequirement } from "./requirements/can-learn-move-requirement"; import { CanLearnMoveRequirement } from "./requirements/can-learn-move-requirement";
import { isNullOrUndefined, randSeedInt } from "#app/utils"; import { isNullOrUndefined, randSeedInt } from "#app/utils/common";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
// biome-ignore lint/suspicious/noConfusingVoidType: void unions in callbacks are OK // biome-ignore lint/suspicious/noConfusingVoidType: void unions in callbacks are OK

View File

@ -1,5 +1,5 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { allAbilities } from "#app/data/ability"; import { allAbilities } from "../data-lists";
import { EvolutionItem, pokemonEvolutions } from "#app/data/balance/pokemon-evolutions"; import { EvolutionItem, pokemonEvolutions } from "#app/data/balance/pokemon-evolutions";
import { Nature } from "#enums/nature"; import { Nature } from "#enums/nature";
import { FormChangeItem, pokemonFormChanges, SpeciesFormChangeItemTrigger } from "#app/data/pokemon-forms"; import { FormChangeItem, pokemonFormChanges, SpeciesFormChangeItemTrigger } from "#app/data/pokemon-forms";
@ -9,7 +9,7 @@ import { WeatherType } from "#enums/weather-type";
import type { PlayerPokemon } from "#app/field/pokemon"; import type { PlayerPokemon } from "#app/field/pokemon";
import { AttackTypeBoosterModifier } from "#app/modifier/modifier"; import { AttackTypeBoosterModifier } from "#app/modifier/modifier";
import type { AttackTypeBoosterModifierType } from "#app/modifier/modifier-type"; import type { AttackTypeBoosterModifierType } from "#app/modifier/modifier-type";
import { isNullOrUndefined } from "#app/utils"; import { isNullOrUndefined } from "#app/utils/common";
import type { Abilities } from "#enums/abilities"; import type { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import type { MysteryEncounterType } from "#enums/mystery-encounter-type"; import type { MysteryEncounterType } from "#enums/mystery-encounter-type";

View File

@ -1,6 +1,6 @@
import type { MysteryEncounterType } from "#enums/mystery-encounter-type"; import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT } from "#app/data/mystery-encounters/mystery-encounters"; import { BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT } from "#app/data/mystery-encounters/mystery-encounters";
import { isNullOrUndefined } from "#app/utils"; import { isNullOrUndefined } from "#app/utils/common";
import type { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import type { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
export class SeenEncounterData { export class SeenEncounterData {

View File

@ -1,11 +1,11 @@
import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import type { PlayerPokemon, PokemonMove } from "#app/field/pokemon"; import type { PlayerPokemon, PokemonMove } from "#app/field/pokemon";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { capitalizeFirstLetter, isNullOrUndefined } from "#app/utils"; import { capitalizeFirstLetter, isNullOrUndefined } from "#app/utils/common";
import type { MysteryEncounterType } from "#enums/mystery-encounter-type"; import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
import type { MysteryEncounterSpriteConfig } from "#app/field/mystery-encounter-intro"; import type { MysteryEncounterSpriteConfig } from "#app/field/mystery-encounter-intro";
import MysteryEncounterIntroVisuals from "#app/field/mystery-encounter-intro"; import MysteryEncounterIntroVisuals from "#app/field/mystery-encounter-intro";
import * as Utils from "#app/utils"; import { randSeedInt } from "#app/utils/common";
import type { StatusEffect } from "#enums/status-effect"; import type { StatusEffect } from "#enums/status-effect";
import type { OptionTextDisplay } from "./mystery-encounter-dialogue"; import type { OptionTextDisplay } from "./mystery-encounter-dialogue";
import type MysteryEncounterDialogue from "./mystery-encounter-dialogue"; import type MysteryEncounterDialogue from "./mystery-encounter-dialogue";
@ -378,13 +378,13 @@ export default class MysteryEncounter implements IMysteryEncounter {
} }
if (truePrimaryPool.length > 0) { if (truePrimaryPool.length > 0) {
// Always choose from the non-overlapping pokemon first // Always choose from the non-overlapping pokemon first
this.primaryPokemon = truePrimaryPool[Utils.randSeedInt(truePrimaryPool.length, 0)]; this.primaryPokemon = truePrimaryPool[randSeedInt(truePrimaryPool.length, 0)];
return true; return true;
} }
// If there are multiple overlapping pokemon, we're okay - just choose one and take it out of the primary pokemon pool // If there are multiple overlapping pokemon, we're okay - just choose one and take it out of the primary pokemon pool
if (overlap.length > 1 || this.secondaryPokemon.length - overlap.length >= 1) { if (overlap.length > 1 || this.secondaryPokemon.length - overlap.length >= 1) {
// is this working? // is this working?
this.primaryPokemon = overlap[Utils.randSeedInt(overlap.length, 0)]; this.primaryPokemon = overlap[randSeedInt(overlap.length, 0)];
this.secondaryPokemon = this.secondaryPokemon.filter(supp => supp !== this.primaryPokemon); this.secondaryPokemon = this.secondaryPokemon.filter(supp => supp !== this.primaryPokemon);
return true; return true;
} }
@ -394,7 +394,7 @@ export default class MysteryEncounter implements IMysteryEncounter {
return false; return false;
} }
// this means we CAN have the same pokemon be a primary and secondary pokemon, so just choose any qualifying one randomly. // this means we CAN have the same pokemon be a primary and secondary pokemon, so just choose any qualifying one randomly.
this.primaryPokemon = qualified[Utils.randSeedInt(qualified.length, 0)]; this.primaryPokemon = qualified[randSeedInt(qualified.length, 0)];
return true; return true;
} }

View File

@ -226,9 +226,9 @@ const anyBiomeEncounters: MysteryEncounterType[] = [
*/ */
export const mysteryEncountersByBiome = new Map<Biome, MysteryEncounterType[]>([ export const mysteryEncountersByBiome = new Map<Biome, MysteryEncounterType[]>([
[Biome.TOWN, []], [Biome.TOWN, []],
[Biome.PLAINS, [MysteryEncounterType.SLUMBERING_SNORLAX, MysteryEncounterType.ABSOLUTE_AVARICE]], [Biome.PLAINS, [MysteryEncounterType.SLUMBERING_SNORLAX]],
[Biome.GRASS, [MysteryEncounterType.SLUMBERING_SNORLAX, MysteryEncounterType.ABSOLUTE_AVARICE]], [Biome.GRASS, [MysteryEncounterType.SLUMBERING_SNORLAX, MysteryEncounterType.ABSOLUTE_AVARICE]],
[Biome.TALL_GRASS, [MysteryEncounterType.ABSOLUTE_AVARICE]], [Biome.TALL_GRASS, [MysteryEncounterType.SLUMBERING_SNORLAX, MysteryEncounterType.ABSOLUTE_AVARICE]],
[Biome.METROPOLIS, []], [Biome.METROPOLIS, []],
[Biome.FOREST, [MysteryEncounterType.SAFARI_ZONE, MysteryEncounterType.ABSOLUTE_AVARICE]], [Biome.FOREST, [MysteryEncounterType.SAFARI_ZONE, MysteryEncounterType.ABSOLUTE_AVARICE]],
[Biome.SEA, [MysteryEncounterType.LOST_AT_SEA]], [Biome.SEA, [MysteryEncounterType.LOST_AT_SEA]],

View File

@ -1,7 +1,7 @@
import type { Moves } from "#app/enums/moves"; import type { Moves } from "#app/enums/moves";
import type { PlayerPokemon } from "#app/field/pokemon"; import type { PlayerPokemon } from "#app/field/pokemon";
import { PokemonMove } from "#app/field/pokemon"; import { PokemonMove } from "#app/field/pokemon";
import { isNullOrUndefined } from "#app/utils"; import { isNullOrUndefined } from "#app/utils/common";
import { EncounterPokemonRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements"; import { EncounterPokemonRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";

Some files were not shown because too many files have changed in this diff Show More