Merge branch 'beta' into evil-team-monogen

This commit is contained in:
Madmadness65 2024-10-04 00:42:35 -05:00 committed by GitHub
commit 62042bf826
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1430 changed files with 10016 additions and 130920 deletions

View File

@ -1,6 +1,6 @@
VITE_BYPASS_LOGIN=0 VITE_BYPASS_LOGIN=0
VITE_BYPASS_TUTORIAL=0 VITE_BYPASS_TUTORIAL=0
VITE_SERVER_URL=https://api.beta.pokerogue.net VITE_SERVER_URL=https://apibeta.pokerogue.net
VITE_DISCORD_CLIENT_ID=1248062921129459756 VITE_DISCORD_CLIENT_ID=1248062921129459756
VITE_GOOGLE_CLIENT_ID=955345393540-2k6lfftf0fdnb0krqmpthjnqavfvvf73.apps.googleusercontent.com VITE_GOOGLE_CLIENT_ID=955345393540-2k6lfftf0fdnb0krqmpthjnqavfvvf73.apps.googleusercontent.com
VITE_I18N_DEBUG=1 VITE_I18N_DEBUG=0

View File

@ -3,5 +3,5 @@ VITE_BYPASS_TUTORIAL=0
VITE_SERVER_URL=http://localhost:8001 VITE_SERVER_URL=http://localhost:8001
VITE_DISCORD_CLIENT_ID=1234567890 VITE_DISCORD_CLIENT_ID=1234567890
VITE_GOOGLE_CLIENT_ID=1234567890 VITE_GOOGLE_CLIENT_ID=1234567890
VITE_I18N_DEBUG=1 VITE_I18N_DEBUG=0
VITE_PORT=8000 VITE_PORT=8000

38
.github/CODEOWNERS vendored
View File

@ -5,41 +5,3 @@
# github actions/templates etc. - Dev Leads # github actions/templates etc. - Dev Leads
/.github @pagefaultgames/dev-leads /.github @pagefaultgames/dev-leads
# --- Translations ---
# all translations - Translation Leads
/src/locales @pagefaultgames/translation-leads
# Catalan (Spain/Spanish)
/src/locales/ca_ES @pagefaultgames/catalan-translation-team
# German
/src/locales/de @pagefaultgames/german-translation-team
# English
/src/locales/en @pagefaultgames/english-translation-team
# Spanish
/src/locales/es @pagefaultgames/spanish-translation-team
# French
/src/locales/fr @pagefaultgames/french-translation-team
# Italian
/src/locales/it @pagefaultgames/italian-translation-team
# Japenese
/src/locales/ja @pagefaultgames/japanese-translation-team
# Korean
/src/locales/ko @pagefaultgames/korean-translation-team
# Brasilian (Brasil/Portuguese)
/src/locales/pt_BR @pagefaultgames/portuguese_br-translation-team
# Chinese (simplified)
/src/locales/zh_CN @pagefaultgames/chinese_simplified-translation-team
# Chinese (traditional)
/src/locales/zh_TW @pagefaultgames/chinese_traditional-translation-team

2
.github/FUNDING.yml vendored
View File

@ -1 +1 @@
github: patapancakes github: pagefaultgames

View File

@ -11,6 +11,8 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with:
submodules: 'recursive'
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version: "20" node-version: "20"

View File

@ -10,6 +10,8 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with:
submodules: 'recursive'
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version: "20" node-version: "20"

View File

@ -22,6 +22,8 @@ jobs:
steps: steps:
- name: Check out Git repository # Step to check out the repository - name: Check out Git repository # Step to check out the repository
uses: actions/checkout@v4 # Use the checkout action version 4 uses: actions/checkout@v4 # Use the checkout action version 4
with:
submodules: 'recursive'
- name: Set up Node.js # Step to set up Node.js environment - name: Set up Node.js # Step to set up Node.js environment
uses: actions/setup-node@v4 # Use the setup-node action version 4 uses: actions/setup-node@v4 # Use the setup-node action version 4

View File

@ -26,6 +26,7 @@ jobs:
- name: Checkout repository for Typedoc - name: Checkout repository for Typedoc
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
submodules: 'recursive'
path: pokerogue_docs path: pokerogue_docs
- name: Install OS package - name: Install OS package

View File

@ -20,6 +20,8 @@ jobs:
steps: steps:
- name: Check out Git repository - name: Check out Git repository
uses: actions/checkout@v4 uses: actions/checkout@v4
with:
submodules: 'recursive'
- name: Set up Node.js - name: Set up Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:

View File

@ -22,6 +22,7 @@ jobs:
- name: Check out Git repository - name: Check out Git repository
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
submodules: 'recursive'
path: tests-action path: tests-action
- name: Set up Node.js - name: Set up Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "public/locales"]
path = public/locales
url = https://github.com/pagefaultgames/pokerogue-locales

View File

@ -24,6 +24,9 @@ We're using ESLint as our common linter and formatter. It will run automatically
**How do I test a new _______?** **How do I test a new _______?**
- In the `src/overrides.ts` file there are overrides for most values you'll need to change for testing - In the `src/overrides.ts` file there are overrides for most values you'll need to change for testing
**How do I retrieve the translations?**
- The translations were moved to the [dedicated translation repository](https://github.com/pagefaultgames/pokerogue-locales) and are now applied as a submodule in this project.
- The command to retrieve the translations is `git submodule update --init --recursive`. If you still struggle to get it working, please reach out to #dev-corner channel in Discord.
## 🪧 To Do ## 🪧 To Do
Check out [Github Issues](https://github.com/pagefaultgames/pokerogue/issues) to see how can you help us! Check out [Github Issues](https://github.com/pagefaultgames/pokerogue/issues) to see how can you help us!

View File

@ -1,9 +1,7 @@
/** /**
* This script creates a test boilerplate file for a move or ability. * This script creates a test boilerplate file in the appropriate
* @param {string} type - The type of test to create. Either "move", "ability", * directory based on the type selected.
* or "item". * @example npm run create-test
* @param {string} fileName - The name of the file to create.
* @example npm run create-test move tackle
*/ */
import fs from "fs"; import fs from "fs";
@ -34,7 +32,7 @@ async function promptTestType() {
console.log("Exiting..."); console.log("Exiting...");
return process.exit(); return process.exit();
} else if (!typeChoices.includes(typeAnswer.selectedOption)) { } else if (!typeChoices.includes(typeAnswer.selectedOption)) {
console.error('Please provide a valid type ("move", "ability", or "item")!'); console.error(`Please provide a valid type (${typeChoices.join(", ")})!`);
return await promptTestType(); return await promptTestType();
} }
@ -102,7 +100,7 @@ async function runInteractive() {
description = `Mystery Encounter - ${formattedName}`; description = `Mystery Encounter - ${formattedName}`;
break; break;
default: default:
console.error('Invalid type. Please use "move", "ability", or "item".'); console.error(`Invalid type. Please use one of the following: ${typeChoices.join(", ")}.`);
process.exit(1); process.exit(1);
} }

View File

@ -41,6 +41,11 @@ export default [
"keyword-spacing": ["error", { "before": true, "after": true }], // Enforces spacing before and after keywords "keyword-spacing": ["error", { "before": true, "after": true }], // Enforces spacing before and after keywords
"comma-spacing": ["error", { "before": false, "after": true }], // Enforces spacing after comma "comma-spacing": ["error", { "before": false, "after": true }], // Enforces spacing after comma
"import-x/extensions": ["error", "never", { "json": "always" }], // Enforces no extension for imports unless json "import-x/extensions": ["error", "never", { "json": "always" }], // Enforces no extension for imports unless json
"array-bracket-spacing": ["error", "always", { "objectsInArrays": false, "arraysInArrays": false }], // Enforces consistent spacing inside array brackets
"object-curly-spacing": ["error", "always", { "arraysInObjects": false, "objectsInObjects": false }], // Enforces consistent spacing inside braces of object literals, destructuring assignments, and import/export specifiers
"computed-property-spacing": ["error", "never" ], // Enforces consistent spacing inside computed property brackets
"space-infix-ops": ["error", { "int32Hint": false }], // Enforces spacing around infix operators
"no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1, "maxBOF": 0 }], // Disallows multiple empty lines
} }
} }
] ]

View File

@ -14,3 +14,8 @@ pre-push:
eslint: eslint:
glob: "*.{js,ts,jsx,tsx}" glob: "*.{js,ts,jsx,tsx}"
run: npx eslint --fix {push_files} run: npx eslint --fix {push_files}
post-merge:
commands:
update-submodules:
run: git submodule update --init --recursive

51
package-lock.json generated
View File

@ -12,6 +12,7 @@
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"i18next": "^23.11.1", "i18next": "^23.11.1",
"i18next-browser-languagedetector": "^7.2.1", "i18next-browser-languagedetector": "^7.2.1",
"i18next-http-backend": "^2.6.1",
"i18next-korean-postposition-processor": "^1.0.0", "i18next-korean-postposition-processor": "^1.0.0",
"json-stable-stringify": "^1.1.0", "json-stable-stringify": "^1.1.0",
"phaser": "^3.70.0", "phaser": "^3.70.0",
@ -37,7 +38,7 @@
"typedoc": "^0.26.4", "typedoc": "^0.26.4",
"typescript": "^5.5.3", "typescript": "^5.5.3",
"typescript-eslint": "^8.0.0-alpha.54", "typescript-eslint": "^8.0.0-alpha.54",
"vite": "^5.3.5", "vite": "^5.4.8",
"vite-tsconfig-paths": "^4.3.2", "vite-tsconfig-paths": "^4.3.2",
"vitest": "^2.0.4", "vitest": "^2.0.4",
"vitest-canvas-mock": "^0.3.3" "vitest-canvas-mock": "^0.3.3"
@ -3650,7 +3651,6 @@
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true, "dev": true,
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"darwin" "darwin"
@ -4004,9 +4004,10 @@
} }
}, },
"node_modules/i18next-http-backend": { "node_modules/i18next-http-backend": {
"version": "2.5.2", "version": "2.6.1",
"resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.5.2.tgz", "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.6.1.tgz",
"integrity": "sha512-+K8HbDfrvc1/2X8jpb7RLhI9ZxBDpx3xogYkQwGKlWAUXLSEGXzgdt3EcUjLlBCdMwdQY+K+EUF6oh8oB6rwHw==", "integrity": "sha512-rCilMAnlEQNeKOZY1+x8wLM5IpYOj10guGvEpeC59tNjj6MMreLIjIW8D1RclhD3ifLwn6d/Y9HEM1RUE6DSog==",
"license": "MIT",
"dependencies": { "dependencies": {
"cross-fetch": "4.0.0" "cross-fetch": "4.0.0"
} }
@ -5042,7 +5043,6 @@
"url": "https://github.com/sponsors/ai" "url": "https://github.com/sponsors/ai"
} }
], ],
"license": "MIT",
"bin": { "bin": {
"nanoid": "bin/nanoid.cjs" "nanoid": "bin/nanoid.cjs"
}, },
@ -5441,9 +5441,9 @@
} }
}, },
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.4.39", "version": "8.4.47",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
"integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==", "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@ -5459,16 +5459,21 @@
"url": "https://github.com/sponsors/ai" "url": "https://github.com/sponsors/ai"
} }
], ],
"license": "MIT",
"dependencies": { "dependencies": {
"nanoid": "^3.3.7", "nanoid": "^3.3.7",
"picocolors": "^1.0.1", "picocolors": "^1.1.0",
"source-map-js": "^1.2.0" "source-map-js": "^1.2.1"
}, },
"engines": { "engines": {
"node": "^10 || ^12 || >=14" "node": "^10 || ^12 || >=14"
} }
}, },
"node_modules/postcss/node_modules/picocolors": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
"integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==",
"dev": true
},
"node_modules/prelude-ls": { "node_modules/prelude-ls": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@ -5865,11 +5870,10 @@
} }
}, },
"node_modules/source-map-js": { "node_modules/source-map-js": {
"version": "1.2.0", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"dev": true, "dev": true,
"license": "BSD-3-Clause",
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
@ -6469,15 +6473,14 @@
} }
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "5.3.5", "version": "5.4.8",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.3.5.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz",
"integrity": "sha512-MdjglKR6AQXQb9JGiS7Rc2wC6uMjcm7Go/NHNO63EwiJXfuk9PgqiP/n5IDJCziMkfw9n4Ubp7lttNwz+8ZVKA==", "integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"esbuild": "^0.21.3", "esbuild": "^0.21.3",
"postcss": "^8.4.39", "postcss": "^8.4.43",
"rollup": "^4.13.0" "rollup": "^4.20.0"
}, },
"bin": { "bin": {
"vite": "bin/vite.js" "vite": "bin/vite.js"
@ -6496,6 +6499,7 @@
"less": "*", "less": "*",
"lightningcss": "^1.21.0", "lightningcss": "^1.21.0",
"sass": "*", "sass": "*",
"sass-embedded": "*",
"stylus": "*", "stylus": "*",
"sugarss": "*", "sugarss": "*",
"terser": "^5.4.0" "terser": "^5.4.0"
@ -6513,6 +6517,9 @@
"sass": { "sass": {
"optional": true "optional": true
}, },
"sass-embedded": {
"optional": true
},
"stylus": { "stylus": {
"optional": true "optional": true
}, },

View File

@ -19,7 +19,8 @@
"docs": "typedoc", "docs": "typedoc",
"depcruise": "depcruise src", "depcruise": "depcruise src",
"depcruise:graph": "depcruise src --output-type dot | node dependency-graph.js > dependency-graph.svg", "depcruise:graph": "depcruise src --output-type dot | node dependency-graph.js > dependency-graph.svg",
"create-test": "node ./create-test-boilerplate.js" "create-test": "node ./create-test-boilerplate.js",
"postinstall": "npx lefthook install && npx lefthook run post-merge"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.3.0", "@eslint/js": "^9.3.0",
@ -41,7 +42,7 @@
"typedoc": "^0.26.4", "typedoc": "^0.26.4",
"typescript": "^5.5.3", "typescript": "^5.5.3",
"typescript-eslint": "^8.0.0-alpha.54", "typescript-eslint": "^8.0.0-alpha.54",
"vite": "^5.3.5", "vite": "^5.4.8",
"vite-tsconfig-paths": "^4.3.2", "vite-tsconfig-paths": "^4.3.2",
"vitest": "^2.0.4", "vitest": "^2.0.4",
"vitest-canvas-mock": "^0.3.3" "vitest-canvas-mock": "^0.3.3"
@ -51,6 +52,7 @@
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"i18next": "^23.11.1", "i18next": "^23.11.1",
"i18next-browser-languagedetector": "^7.2.1", "i18next-browser-languagedetector": "^7.2.1",
"i18next-http-backend": "^2.6.1",
"i18next-korean-postposition-processor": "^1.0.0", "i18next-korean-postposition-processor": "^1.0.0",
"json-stable-stringify": "^1.1.0", "json-stable-stringify": "^1.1.0",
"phaser": "^3.70.0", "phaser": "^3.70.0",

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

1
public/locales Submodule

@ -0,0 +1 @@
Subproject commit 3ccef8472dd7cc7c362538489954cb8fdad27e5f

View File

@ -1,18 +1,8 @@
import { type enConfig } from "#app/locales/en/config";
import { TOptions } from "i18next"; import { TOptions } from "i18next";
//TODO: this needs to be type properly in the future
// Module declared to make referencing keys in the localization files type-safe. // Module declared to make referencing keys in the localization files type-safe.
declare module "i18next" { declare module "i18next" {
interface CustomTypeOptions { interface TFunction {
defaultNS: "menu", // needed here as well for typedoc (key: string | string[], options?: TOptions & Record<string, unknown>): string;
resources: typeof enConfig
}
interface TFunction {
(
key: string | string[],
options?: TOptions & Record<string, unknown>
): string;
}
} }
}

View File

@ -20,7 +20,7 @@ export function initLoggedInUser(): void {
export function updateUserInfo(): Promise<[boolean, integer]> { export function updateUserInfo(): Promise<[boolean, integer]> {
return new Promise<[boolean, integer]>(resolve => { return new Promise<[boolean, integer]>(resolve => {
if (bypassLogin) { if (bypassLogin) {
loggedInUser = { username: "Guest", lastSessionSlot: -1, discordId: "", googleId: "", hasAdminRole: false}; loggedInUser = { username: "Guest", lastSessionSlot: -1, discordId: "", googleId: "", hasAdminRole: false };
let lastSessionSlot = -1; let lastSessionSlot = -1;
for (let s = 0; s < 5; s++) { for (let s = 0; s < 5; s++) {
if (localStorage.getItem(`sessionData${s ? s : ""}_${loggedInUser.username}`)) { if (localStorage.getItem(`sessionData${s ? s : ""}_${loggedInUser.username}`)) {

View File

@ -25,7 +25,7 @@ import { trainerConfigs, TrainerSlot } from "./data/trainer-config";
import Trainer, { TrainerVariant } from "./field/trainer"; import Trainer, { TrainerVariant } from "./field/trainer";
import TrainerData from "./system/trainer-data"; import TrainerData from "./system/trainer-data";
import SoundFade from "phaser3-rex-plugins/plugins/soundfade"; import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
import { pokemonPrevolutions } from "./data/pokemon-evolutions"; import { pokemonPrevolutions } from "./data/balance/pokemon-evolutions";
import PokeballTray from "./ui/pokeball-tray"; import PokeballTray from "./ui/pokeball-tray";
import InvertPostFX from "./pipelines/invert"; import InvertPostFX from "./pipelines/invert";
import { Achv, achvs, ModifierAchv, MoneyAchv } from "./system/achv"; import { Achv, achvs, ModifierAchv, MoneyAchv } from "./system/achv";
@ -42,7 +42,7 @@ import PokemonSpriteSparkleHandler from "./field/pokemon-sprite-sparkle-handler"
import CharSprite from "./ui/char-sprite"; import CharSprite from "./ui/char-sprite";
import DamageNumberHandler from "./field/damage-number-handler"; import DamageNumberHandler from "./field/damage-number-handler";
import PokemonInfoContainer from "./ui/pokemon-info-container"; import PokemonInfoContainer from "./ui/pokemon-info-container";
import { biomeDepths, getBiomeName } from "./data/biomes"; import { biomeDepths, getBiomeName } from "./data/balance/biomes";
import { SceneBase } from "./scene-base"; import { SceneBase } from "./scene-base";
import CandyBar from "./ui/candy-bar"; import CandyBar from "./ui/candy-bar";
import { Variant, variantData } from "./data/variant"; import { Variant, variantData } from "./data/variant";
@ -1040,10 +1040,6 @@ export default class BattleScene extends SceneBase {
this.gameMode = getGameMode(GameModes.CLASSIC); this.gameMode = getGameMode(GameModes.CLASSIC);
this.setSeed(Overrides.SEED_OVERRIDE || Utils.randomString(24));
console.log("Seed:", this.seed);
this.resetSeed(); // Properly resets RNG after saving and quitting a session
this.disableMenu = false; this.disableMenu = false;
this.score = 0; this.score = 0;
@ -1078,6 +1074,12 @@ export default class BattleScene extends SceneBase {
//@ts-ignore - allowing `null` for currentBattle causes a lot of trouble //@ts-ignore - allowing `null` for currentBattle causes a lot of trouble
this.currentBattle = null; // TODO: resolve ts-ignore this.currentBattle = null; // TODO: resolve ts-ignore
// Reset RNG after end of game or save & quit.
// 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));
console.log("Seed:", this.seed);
this.resetSeed();
this.biomeWaveText.setText(startingWave.toString()); this.biomeWaveText.setText(startingWave.toString());
this.biomeWaveText.setVisible(false); this.biomeWaveText.setVisible(false);
@ -1259,7 +1261,7 @@ export default class BattleScene extends SceneBase {
const isEndlessFifthWave = this.gameMode.hasShortBiomes && (lastBattle.waveIndex % 5) === 0; const isEndlessFifthWave = this.gameMode.hasShortBiomes && (lastBattle.waveIndex % 5) === 0;
const isWaveIndexMultipleOfFiftyMinusOne = (lastBattle.waveIndex % 50) === 49; const isWaveIndexMultipleOfFiftyMinusOne = (lastBattle.waveIndex % 50) === 49;
const isNewBiome = isWaveIndexMultipleOfTen || isEndlessFifthWave || (isEndlessOrDaily && isWaveIndexMultipleOfFiftyMinusOne); const isNewBiome = isWaveIndexMultipleOfTen || isEndlessFifthWave || (isEndlessOrDaily && isWaveIndexMultipleOfFiftyMinusOne);
const resetArenaState = isNewBiome || [BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(this.currentBattle.battleType) || this.currentBattle.battleSpec === BattleSpec.FINAL_BOSS; const resetArenaState = isNewBiome || [ BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER ].includes(this.currentBattle.battleType) || this.currentBattle.battleSpec === BattleSpec.FINAL_BOSS;
this.getEnemyParty().forEach(enemyPokemon => enemyPokemon.destroy()); this.getEnemyParty().forEach(enemyPokemon => enemyPokemon.destroy());
this.trySpreadPokerus(); this.trySpreadPokerus();
if (!isNewBiome && (newWaveIndex % 10) === 5) { if (!isNewBiome && (newWaveIndex % 10) === 5) {
@ -1756,14 +1758,14 @@ export default class BattleScene extends SceneBase {
if (fromArenaPool) { if (fromArenaPool) {
return this.arena.randomSpecies(waveIndex, level, undefined, getPartyLuckValue(this.party)); return this.arena.randomSpecies(waveIndex, level, undefined, getPartyLuckValue(this.party));
} }
const filteredSpecies = speciesFilter ? [...new Set(allSpecies.filter(s => s.isCatchable()).filter(speciesFilter).map(s => { const filteredSpecies = speciesFilter ? [ ...new Set(allSpecies.filter(s => s.isCatchable()).filter(speciesFilter).map(s => {
if (!filterAllEvolutions) { if (!filterAllEvolutions) {
while (pokemonPrevolutions.hasOwnProperty(s.speciesId)) { while (pokemonPrevolutions.hasOwnProperty(s.speciesId)) {
s = getPokemonSpecies(pokemonPrevolutions[s.speciesId]); s = getPokemonSpecies(pokemonPrevolutions[s.speciesId]);
} }
} }
return s; return s;
}))] : allSpecies.filter(s => s.isCatchable()); })) ] : allSpecies.filter(s => s.isCatchable());
return filteredSpecies[Utils.randSeedInt(filteredSpecies.length)]; return filteredSpecies[Utils.randSeedInt(filteredSpecies.length)];
} }
@ -1883,14 +1885,14 @@ export default class BattleScene extends SceneBase {
case "battle_anims": case "battle_anims":
case "cry": case "cry":
if (soundDetails[1].startsWith("PRSFX- ")) { if (soundDetails[1].startsWith("PRSFX- ")) {
sound.setVolume(this.masterVolume*this.fieldVolume*0.5); sound.setVolume(this.masterVolume * this.fieldVolume * 0.5);
} else { } else {
sound.setVolume(this.masterVolume*this.fieldVolume); sound.setVolume(this.masterVolume * this.fieldVolume);
} }
break; break;
case "se": case "se":
case "ui": case "ui":
sound.setVolume(this.masterVolume*this.seVolume); sound.setVolume(this.masterVolume * this.seVolume);
} }
} }
} }
@ -2219,7 +2221,7 @@ export default class BattleScene extends SceneBase {
* *
*/ */
pushConditionalPhase(phase: Phase, condition: () => boolean): void { pushConditionalPhase(phase: Phase, condition: () => boolean): void {
this.conditionalQueue.push([condition, phase]); this.conditionalQueue.push([ condition, phase ]);
} }
/** /**
@ -2443,7 +2445,10 @@ export default class BattleScene extends SceneBase {
} }
if ((modifier as PersistentModifier).add(this.modifiers, !!virtual, this)) { if ((modifier as PersistentModifier).add(this.modifiers, !!virtual, this)) {
if (modifier instanceof PokemonFormChangeItemModifier || modifier instanceof TerastallizeModifier) { if (modifier instanceof PokemonFormChangeItemModifier || modifier instanceof TerastallizeModifier) {
success = modifier.apply([ this.getPokemonById(modifier.pokemonId), true ]); const pokemon = this.getPokemonById(modifier.pokemonId);
if (pokemon) {
success = modifier.apply(pokemon, true);
}
} }
if (playSound && !this.sound.get(soundName)) { if (playSound && !this.sound.get(soundName)) {
this.playSound(soundName); this.playSound(soundName);
@ -2470,7 +2475,7 @@ export default class BattleScene extends SceneBase {
for (const p in this.party) { for (const p in this.party) {
const pokemon = this.party[p]; const pokemon = this.party[p];
const args: any[] = [ pokemon ]; 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.IntegerHolder(1); const hpRestoreMultiplier = new Utils.IntegerHolder(1);
@ -2483,8 +2488,8 @@ export default class BattleScene extends SceneBase {
args.push(this.getPokemonById(modifier.fusePokemonId) as PlayerPokemon); args.push(this.getPokemonById(modifier.fusePokemonId) as PlayerPokemon);
} }
if (modifier.shouldApply(args)) { if (modifier.shouldApply(pokemon, ...args)) {
const result = modifier.apply(args); const result = modifier.apply(pokemon, ...args);
if (result instanceof Promise) { if (result instanceof Promise) {
modifierPromises.push(result.then(s => success ||= s)); modifierPromises.push(result.then(s => success ||= s));
} else { } else {
@ -2493,11 +2498,11 @@ export default class BattleScene extends SceneBase {
} }
} }
return Promise.allSettled([this.party.map(p => p.updateInfo(instant)), ...modifierPromises]).then(() => resolve(success)); return Promise.allSettled([ this.party.map(p => p.updateInfo(instant)), ...modifierPromises ]).then(() => resolve(success));
} else { } else {
const args = [ this ]; const args = [ this ];
if (modifier.shouldApply(args)) { if (modifier.shouldApply(...args)) {
const result = modifier.apply(args); const result = modifier.apply(...args);
if (result instanceof Promise) { if (result instanceof Promise) {
return result.then(success => resolve(success)); return result.then(success => resolve(success));
} else { } else {
@ -2519,7 +2524,10 @@ export default class BattleScene extends SceneBase {
} }
if ((modifier as PersistentModifier).add(this.enemyModifiers, false, this)) { if ((modifier as PersistentModifier).add(this.enemyModifiers, false, this)) {
if (modifier instanceof PokemonFormChangeItemModifier || modifier instanceof TerastallizeModifier) { if (modifier instanceof PokemonFormChangeItemModifier || modifier instanceof TerastallizeModifier) {
modifier.apply([ this.getPokemonById(modifier.pokemonId), true ]); const pokemon = this.getPokemonById(modifier.pokemonId);
if (pokemon) {
modifier.apply(pokemon, true);
}
} }
for (const rm of modifiersToRemove) { for (const rm of modifiersToRemove) {
this.removeModifier(rm, true); this.removeModifier(rm, true);
@ -2753,7 +2761,10 @@ export default class BattleScene extends SceneBase {
if (modifierIndex > -1) { if (modifierIndex > -1) {
modifiers.splice(modifierIndex, 1); modifiers.splice(modifierIndex, 1);
if (modifier instanceof PokemonFormChangeItemModifier || modifier instanceof TerastallizeModifier) { if (modifier instanceof PokemonFormChangeItemModifier || modifier instanceof TerastallizeModifier) {
modifier.apply([ this.getPokemonById(modifier.pokemonId), false ]); const pokemon = this.getPokemonById(modifier.pokemonId);
if (pokemon) {
modifier.apply(pokemon, false);
}
} }
return true; return true;
} }
@ -2771,38 +2782,66 @@ export default class BattleScene extends SceneBase {
return (player ? this.modifiers : this.enemyModifiers).filter((m): m is T => m instanceof modifierType); return (player ? this.modifiers : this.enemyModifiers).filter((m): m is T => m instanceof modifierType);
} }
findModifiers(modifierFilter: ModifierPredicate, player: boolean = true): PersistentModifier[] { /**
return (player ? this.modifiers : this.enemyModifiers).filter(m => (modifierFilter as ModifierPredicate)(m)); * Get all of the modifiers that pass the `modifierFilter` function
* @param modifierFilter The function used to filter a target's modifiers
* @param isPlayer Whether to search the player (`true`) or the enemy (`false`); Defaults to `true`
* @returns the list of all modifiers that passed the `modifierFilter` function
*/
findModifiers(modifierFilter: ModifierPredicate, isPlayer: boolean = true): PersistentModifier[] {
return (isPlayer ? this.modifiers : this.enemyModifiers).filter(modifierFilter);
} }
/**
* Find the first modifier that pass the `modifierFilter` function
* @param modifierFilter The function used to filter a target's modifiers
* @param player Whether to search the player (`true`) or the enemy (`false`); Defaults to `true`
* @returns the first modifier that passed the `modifierFilter` function; `undefined` if none passed
*/
findModifier(modifierFilter: ModifierPredicate, player: boolean = true): PersistentModifier | undefined { findModifier(modifierFilter: ModifierPredicate, player: boolean = true): PersistentModifier | undefined {
return (player ? this.modifiers : this.enemyModifiers).find(m => (modifierFilter as ModifierPredicate)(m)); return (player ? this.modifiers : this.enemyModifiers).find(modifierFilter);
} }
applyShuffledModifiers(scene: BattleScene, modifierType: Constructor<Modifier>, player: boolean = true, ...args: any[]): PersistentModifier[] { /**
let modifiers = (player ? this.modifiers : this.enemyModifiers).filter(m => m instanceof modifierType && m.shouldApply(args)); * Apply all modifiers that match `modifierType` in a random order
* @param scene {@linkcode BattleScene} used to randomize the order of modifiers
* @param modifierType The type of modifier to apply; must extend {@linkcode PersistentModifier}
* @param player Whether to search the player (`true`) or the enemy (`false`); Defaults to `true`
* @param ...args The list of arguments needed to invoke `modifierType.apply`
* @returns the list of all modifiers that matched `modifierType` and were applied.
*/
applyShuffledModifiers<T extends PersistentModifier>(scene: BattleScene, modifierType: Constructor<T>, player: boolean = true, ...args: Parameters<T["apply"]>): T[] {
let modifiers = (player ? this.modifiers : this.enemyModifiers).filter((m): m is T => m instanceof modifierType && m.shouldApply(...args));
scene.executeWithSeedOffset(() => { scene.executeWithSeedOffset(() => {
const shuffleModifiers = mods => { const shuffleModifiers = mods => {
if (mods.length < 1) { if (mods.length < 1) {
return mods; return mods;
} }
const rand = Utils.randSeedInt(mods.length); const rand = Utils.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);
}, scene.currentBattle.turn << 4, scene.waveSeed); }, scene.currentBattle.turn << 4, scene.waveSeed);
return this.applyModifiersInternal(modifiers, player, args); return this.applyModifiersInternal(modifiers, player, args);
} }
applyModifiers(modifierType: Constructor<Modifier>, player: boolean = true, ...args: any[]): PersistentModifier[] { /**
const modifiers = (player ? this.modifiers : this.enemyModifiers).filter(m => m instanceof modifierType && m.shouldApply(args)); * Apply all modifiers that match `modifierType`
* @param modifierType The type of modifier to apply; must extend {@linkcode PersistentModifier}
* @param player Whether to search the player (`true`) or the enemy (`false`); Defaults to `true`
* @param ...args The list of arguments needed to invoke `modifierType.apply`
* @returns the list of all modifiers that matched `modifierType` and were applied.
*/
applyModifiers<T extends PersistentModifier>(modifierType: Constructor<T>, player: boolean = true, ...args: Parameters<T["apply"]>): T[] {
const modifiers = (player ? this.modifiers : this.enemyModifiers).filter((m): m is T => m instanceof modifierType && m.shouldApply(...args));
return this.applyModifiersInternal(modifiers, player, args); return this.applyModifiersInternal(modifiers, player, args);
} }
applyModifiersInternal(modifiers: PersistentModifier[], player: boolean, args: any[]): PersistentModifier[] { /** Helper function to apply all passed modifiers */
const appliedModifiers: PersistentModifier[] = []; applyModifiersInternal<T extends PersistentModifier>(modifiers: T[], player: boolean, args: Parameters<T["apply"]>): T[] {
const appliedModifiers: T[] = [];
for (const modifier of modifiers) { for (const modifier of modifiers) {
if (modifier.apply(args)) { if (modifier.apply(...args)) {
console.log("Applied", modifier.type.name, !player ? "(enemy)" : ""); console.log("Applied", modifier.type.name, !player ? "(enemy)" : "");
appliedModifiers.push(modifier); appliedModifiers.push(modifier);
} }
@ -2811,10 +2850,17 @@ export default class BattleScene extends SceneBase {
return appliedModifiers; return appliedModifiers;
} }
applyModifier(modifierType: Constructor<Modifier>, player: boolean = true, ...args: any[]): PersistentModifier | null { /**
const modifiers = (player ? this.modifiers : this.enemyModifiers).filter(m => m instanceof modifierType && m.shouldApply(args)); * Apply the first modifier that matches `modifierType`
* @param modifierType The type of modifier to apply; must extend {@linkcode PersistentModifier}
* @param player Whether to search the player (`true`) or the enemy (`false`); Defaults to `true`
* @param ...args The list of arguments needed to invoke `modifierType.apply`
* @returns the first modifier that matches `modifierType` and was applied; return `null` if none matched
*/
applyModifier<T extends PersistentModifier>(modifierType: Constructor<T>, player: boolean = true, ...args: Parameters<T["apply"]>): T | null {
const modifiers = (player ? this.modifiers : this.enemyModifiers).filter((m): m is T => m instanceof modifierType && m.shouldApply(...args));
for (const modifier of modifiers) { for (const modifier of modifiers) {
if (modifier.apply(args)) { if (modifier.apply(...args)) {
console.log("Applied", modifier.type.name, !player ? "(enemy)" : ""); console.log("Applied", modifier.type.name, !player ? "(enemy)" : "");
return modifier; return modifier;
} }
@ -2880,7 +2926,7 @@ export default class BattleScene extends SceneBase {
} }
} }
validateAchv(achv: Achv, args?: any[]): boolean { validateAchv(achv: Achv, args?: unknown[]): boolean {
if (!this.gameData.achvUnlocks.hasOwnProperty(achv.id) && achv.validate(this, args)) { if (!this.gameData.achvUnlocks.hasOwnProperty(achv.id) && achv.validate(this, args)) {
this.gameData.achvUnlocks[achv.id] = new Date().getTime(); this.gameData.achvUnlocks[achv.id] = new Date().getTime();
this.ui.achvBar.showAchv(achv); this.ui.achvBar.showAchv(achv);
@ -2893,7 +2939,7 @@ export default class BattleScene extends SceneBase {
return false; return false;
} }
validateVoucher(voucher: Voucher, args?: any[]): boolean { validateVoucher(voucher: Voucher, args?: unknown[]): boolean {
if (!this.gameData.voucherUnlocks.hasOwnProperty(voucher.id) && voucher.validate(this, args)) { if (!this.gameData.voucherUnlocks.hasOwnProperty(voucher.id) && voucher.validate(this, args)) {
this.gameData.voucherUnlocks[voucher.id] = new Date().getTime(); this.gameData.voucherUnlocks[voucher.id] = new Date().getTime();
this.ui.achvBar.showAchv(voucher); this.ui.achvBar.showAchv(voucher);
@ -2932,7 +2978,7 @@ export default class BattleScene extends SceneBase {
keys.push(p.getBattleSpriteKey(true, true)); keys.push(p.getBattleSpriteKey(true, true));
keys.push("cry/" + p.species.getCryKey(p.formIndex)); keys.push("cry/" + p.species.getCryKey(p.formIndex));
if (p.fusionSpecies) { if (p.fusionSpecies) {
keys.push("cry/"+p.fusionSpecies.getCryKey(p.fusionFormIndex)); keys.push("cry/" + p.fusionSpecies.getCryKey(p.fusionFormIndex));
} }
}); });
// enemyParty has to be operated on separately from playerParty because playerPokemon =/= enemyPokemon // enemyParty has to be operated on separately from playerParty because playerPokemon =/= enemyPokemon
@ -2941,7 +2987,7 @@ export default class BattleScene extends SceneBase {
keys.push(p.getSpriteKey(true)); keys.push(p.getSpriteKey(true));
keys.push("cry/" + p.species.getCryKey(p.formIndex)); keys.push("cry/" + p.species.getCryKey(p.formIndex));
if (p.fusionSpecies) { if (p.fusionSpecies) {
keys.push("cry/"+p.fusionSpecies.getCryKey(p.fusionFormIndex)); keys.push("cry/" + p.fusionSpecies.getCryKey(p.fusionFormIndex));
} }
}); });
return keys; return keys;
@ -3089,13 +3135,8 @@ export default class BattleScene extends SceneBase {
* @param sessionDataEncounterType * @param sessionDataEncounterType
*/ */
private isWaveMysteryEncounter(newBattleType: BattleType, waveIndex: number, sessionDataEncounterType?: MysteryEncounterType): boolean { private isWaveMysteryEncounter(newBattleType: BattleType, waveIndex: number, sessionDataEncounterType?: MysteryEncounterType): boolean {
const [lowestMysteryEncounterWave, highestMysteryEncounterWave] = this.gameMode.getMysteryEncounterLegalWaves(); const [ lowestMysteryEncounterWave, highestMysteryEncounterWave ] = this.gameMode.getMysteryEncounterLegalWaves();
if (this.gameMode.hasMysteryEncounters && newBattleType === BattleType.WILD && !this.gameMode.isBoss(waveIndex) && waveIndex < highestMysteryEncounterWave && waveIndex > lowestMysteryEncounterWave) { if (this.gameMode.hasMysteryEncounters && newBattleType === BattleType.WILD && !this.gameMode.isBoss(waveIndex) && waveIndex < highestMysteryEncounterWave && waveIndex > lowestMysteryEncounterWave) {
// If ME type is already defined in session data, no need to roll RNG check
if (!isNullOrUndefined(sessionDataEncounterType)) {
return true;
}
// Base spawn weight is BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT/256, and increases by WEIGHT_INCREMENT_ON_SPAWN_MISS/256 for each missed attempt at spawning an encounter on a valid floor // Base spawn weight is BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT/256, and increases by WEIGHT_INCREMENT_ON_SPAWN_MISS/256 for each missed attempt at spawning an encounter on a valid floor
const sessionEncounterRate = this.mysteryEncounterSaveData.encounterSpawnChance; const sessionEncounterRate = this.mysteryEncounterSaveData.encounterSpawnChance;
const encounteredEvents = this.mysteryEncounterSaveData.encounteredEvents; const encounteredEvents = this.mysteryEncounterSaveData.encounteredEvents;
@ -3160,7 +3201,7 @@ export default class BattleScene extends SceneBase {
} }
// See Enum values for base tier weights // See Enum values for base tier weights
const tierWeights = [MysteryEncounterTier.COMMON, MysteryEncounterTier.GREAT, MysteryEncounterTier.ULTRA, MysteryEncounterTier.ROGUE]; const tierWeights = [ MysteryEncounterTier.COMMON, MysteryEncounterTier.GREAT, MysteryEncounterTier.ULTRA, MysteryEncounterTier.ROGUE ];
// Adjust tier weights by previously encountered events to lower odds of only Common/Great in run // Adjust tier weights by previously encountered events to lower odds of only Common/Great in run
this.mysteryEncounterSaveData.encounteredEvents.forEach(seenEncounterData => { this.mysteryEncounterSaveData.encounteredEvents.forEach(seenEncounterData => {

View File

@ -497,7 +497,7 @@ function getRandomTrainerFunc(trainerPool: (TrainerType | TrainerType[])[], rand
} }
/* 1/3 chance for evil team grunts to be double battles */ /* 1/3 chance for evil team grunts to be double battles */
const evilTeamGrunts = [TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT]; const evilTeamGrunts = [ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT, TrainerType.AETHER_GRUNT, TrainerType.SKULL_GRUNT, TrainerType.MACRO_GRUNT, TrainerType.STAR_GRUNT ];
const isEvilTeamGrunt = evilTeamGrunts.includes(trainerTypes[rand]); const isEvilTeamGrunt = evilTeamGrunts.includes(trainerTypes[rand]);
if (trainerConfigs[trainerTypes[rand]].hasDouble && isEvilTeamGrunt) { if (trainerConfigs[trainerTypes[rand]].hasDouble && isEvilTeamGrunt) {
@ -527,34 +527,34 @@ export const classicFixedBattles: FixedBattleConfigs = {
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)), .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)),
[25]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) [25]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_2, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)) .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_2, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT))
.setCustomModifierRewards({ guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT], allowLuckUpgrades: false }), .setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT ], allowLuckUpgrades: false }),
[35]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) [35]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT, TrainerType.AETHER_GRUNT, TrainerType.SKULL_GRUNT, TrainerType.MACRO_GRUNT, TrainerType.STAR_GRUNT ], true)), .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT, TrainerType.AETHER_GRUNT, TrainerType.SKULL_GRUNT, TrainerType.MACRO_GRUNT, TrainerType.STAR_GRUNT ], true)),
[55]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) [55]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_3, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)) .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_3, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT))
.setCustomModifierRewards({ guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT], allowLuckUpgrades: false }), .setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT ], allowLuckUpgrades: false }),
[62]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35) [62]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT, TrainerType.AETHER_GRUNT, TrainerType.SKULL_GRUNT, TrainerType.MACRO_GRUNT, TrainerType.STAR_GRUNT ], true)), .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT, TrainerType.AETHER_GRUNT, TrainerType.SKULL_GRUNT, TrainerType.MACRO_GRUNT, TrainerType.STAR_GRUNT ], true)),
[64]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35) [64]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT, TrainerType.AETHER_GRUNT, TrainerType.SKULL_GRUNT, TrainerType.MACRO_GRUNT, TrainerType.STAR_GRUNT ], true)), .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT, TrainerType.AETHER_GRUNT, TrainerType.SKULL_GRUNT, TrainerType.MACRO_GRUNT, TrainerType.STAR_GRUNT ], true)),
[66]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35) [66]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
.setGetTrainerFunc(getRandomTrainerFunc([[ TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON, TrainerType.PETREL ], [ TrainerType.TABITHA, TrainerType.COURTNEY ], [ TrainerType.MATT, TrainerType.SHELLY ], [ TrainerType.JUPITER, TrainerType.MARS, TrainerType.SATURN ], [ TrainerType.ZINZOLIN, TrainerType.ROOD ], [ TrainerType.XEROSIC, TrainerType.BRYONY ], TrainerType.FABA, TrainerType.PLUMERIA, TrainerType.OLEANA, [ TrainerType.GIACOMO, TrainerType.MELA, TrainerType.ATTICUS, TrainerType.ORTEGA, TrainerType.ERI ] ], true)), .setGetTrainerFunc(getRandomTrainerFunc([[ TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON, TrainerType.PETREL ], [ TrainerType.TABITHA, TrainerType.COURTNEY ], [ TrainerType.MATT, TrainerType.SHELLY ], [ TrainerType.JUPITER, TrainerType.MARS, TrainerType.SATURN ], [ TrainerType.ZINZOLIN, TrainerType.ROOD ], [ TrainerType.XEROSIC, TrainerType.BRYONY ], TrainerType.FABA, TrainerType.PLUMERIA, TrainerType.OLEANA, [ TrainerType.GIACOMO, TrainerType.MELA, TrainerType.ATTICUS, TrainerType.ORTEGA, TrainerType.ERI ]], true)),
[95]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) [95]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_4, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)) .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_4, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT))
.setCustomModifierRewards({ guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA], allowLuckUpgrades: false }), .setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA ], allowLuckUpgrades: false }),
[112]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35) [112]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT, TrainerType.AETHER_GRUNT, TrainerType.SKULL_GRUNT, TrainerType.MACRO_GRUNT, TrainerType.STAR_GRUNT ], true)), .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT, TrainerType.AETHER_GRUNT, TrainerType.SKULL_GRUNT, TrainerType.MACRO_GRUNT, TrainerType.STAR_GRUNT ], true)),
[114]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35) [114]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
.setGetTrainerFunc(getRandomTrainerFunc([[ TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON, TrainerType.PETREL ], [ TrainerType.TABITHA, TrainerType.COURTNEY ], [ TrainerType.MATT, TrainerType.SHELLY ], [ TrainerType.JUPITER, TrainerType.MARS, TrainerType.SATURN ], [ TrainerType.ZINZOLIN, TrainerType.ROOD ], [ TrainerType.XEROSIC, TrainerType.BRYONY ], TrainerType.FABA, TrainerType.PLUMERIA, TrainerType.OLEANA, [ TrainerType.GIACOMO, TrainerType.MELA, TrainerType.ATTICUS, TrainerType.ORTEGA, TrainerType.ERI ] ], true, 1)), .setGetTrainerFunc(getRandomTrainerFunc([[ TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON, TrainerType.PETREL ], [ TrainerType.TABITHA, TrainerType.COURTNEY ], [ TrainerType.MATT, TrainerType.SHELLY ], [ TrainerType.JUPITER, TrainerType.MARS, TrainerType.SATURN ], [ TrainerType.ZINZOLIN, TrainerType.ROOD ], [ TrainerType.XEROSIC, TrainerType.BRYONY ], TrainerType.FABA, TrainerType.PLUMERIA, TrainerType.OLEANA, [ TrainerType.GIACOMO, TrainerType.MELA, TrainerType.ATTICUS, TrainerType.ORTEGA, TrainerType.ERI ]], true, 1)),
[ClassicFixedBossWaves.EVIL_BOSS_1]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35) [ClassicFixedBossWaves.EVIL_BOSS_1]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_BOSS_GIOVANNI_1, TrainerType.MAXIE, TrainerType.ARCHIE, TrainerType.CYRUS, TrainerType.GHETSIS, TrainerType.LYSANDRE, TrainerType.LUSAMINE, TrainerType.GUZMA, TrainerType.ROSE, TrainerType.PENNY ])) .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_BOSS_GIOVANNI_1, TrainerType.MAXIE, TrainerType.ARCHIE, TrainerType.CYRUS, TrainerType.GHETSIS, TrainerType.LYSANDRE, TrainerType.LUSAMINE, TrainerType.GUZMA, TrainerType.ROSE, TrainerType.PENNY ]))
.setCustomModifierRewards({ guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA], allowLuckUpgrades: false }), .setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA ], allowLuckUpgrades: false }),
[145]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) [145]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_5, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)) .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_5, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT))
.setCustomModifierRewards({ guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.ULTRA], allowLuckUpgrades: false }), .setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.ULTRA ], allowLuckUpgrades: false }),
[ClassicFixedBossWaves.EVIL_BOSS_2]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35) [ClassicFixedBossWaves.EVIL_BOSS_2]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_BOSS_GIOVANNI_2, TrainerType.MAXIE_2, TrainerType.ARCHIE_2, TrainerType.CYRUS_2, TrainerType.GHETSIS_2, TrainerType.LYSANDRE_2, TrainerType.LUSAMINE_2, TrainerType.GUZMA_2, TrainerType.ROSE_2, TrainerType.PENNY_2 ])) .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_BOSS_GIOVANNI_2, TrainerType.MAXIE_2, TrainerType.ARCHIE_2, TrainerType.CYRUS_2, TrainerType.GHETSIS_2, TrainerType.LYSANDRE_2, TrainerType.LUSAMINE_2, TrainerType.GUZMA_2, TrainerType.ROSE_2, TrainerType.PENNY_2 ]))
.setCustomModifierRewards({ guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA], allowLuckUpgrades: false }), .setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA ], allowLuckUpgrades: false }),
[182]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) [182]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.LORELEI, TrainerType.WILL, TrainerType.SIDNEY, TrainerType.AARON, TrainerType.SHAUNTAL, TrainerType.MALVA, [ TrainerType.HALA, TrainerType.MOLAYNE ], TrainerType.MARNIE_ELITE, TrainerType.RIKA, TrainerType.CRISPIN ])), .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.LORELEI, TrainerType.WILL, TrainerType.SIDNEY, TrainerType.AARON, TrainerType.SHAUNTAL, TrainerType.MALVA, [ TrainerType.HALA, TrainerType.MOLAYNE ], TrainerType.MARNIE_ELITE, TrainerType.RIKA, TrainerType.CRISPIN ])),
[184]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182) [184]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182)
@ -567,5 +567,5 @@ export const classicFixedBattles: FixedBattleConfigs = {
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.BLUE, [ TrainerType.RED, TrainerType.LANCE_CHAMPION ], [ TrainerType.STEVEN, TrainerType.WALLACE ], TrainerType.CYNTHIA, [ TrainerType.ALDER, TrainerType.IRIS ], TrainerType.DIANTHA, TrainerType.HAU, TrainerType.LEON, [ TrainerType.GEETA, TrainerType.NEMONA ], TrainerType.KIERAN ])), .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.BLUE, [ TrainerType.RED, TrainerType.LANCE_CHAMPION ], [ TrainerType.STEVEN, TrainerType.WALLACE ], TrainerType.CYNTHIA, [ TrainerType.ALDER, TrainerType.IRIS ], TrainerType.DIANTHA, TrainerType.HAU, TrainerType.LEON, [ TrainerType.GEETA, TrainerType.NEMONA ], TrainerType.KIERAN ])),
[195]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) [195]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_6, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)) .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_6, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT))
.setCustomModifierRewards({ guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT], allowLuckUpgrades: false }) .setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT ], allowLuckUpgrades: false })
}; };

View File

@ -1,5 +1,5 @@
import {Button} from "#enums/buttons"; import { Button } from "#enums/buttons";
import {SettingKeyboard} from "#app/system/settings/settings-keyboard"; import { SettingKeyboard } from "#app/system/settings/settings-keyboard";
const cfg_keyboard_qwerty = { const cfg_keyboard_qwerty = {
padID: "default", padID: "default",

View File

@ -1,4 +1,4 @@
import {Device} from "#enums/devices"; import { Device } from "#enums/devices";
/** /**
* Retrieves the key associated with the specified keycode from the mapping. * Retrieves the key associated with the specified keycode from the mapping.

View File

@ -1,5 +1,5 @@
import {SettingGamepad} from "../../system/settings/settings-gamepad"; import { SettingGamepad } from "../../system/settings/settings-gamepad";
import {Button} from "#enums/buttons"; import { Button } from "#enums/buttons";
/** /**
* Dualshock mapping * Dualshock mapping

View File

@ -1,5 +1,5 @@
import {SettingGamepad} from "../../system/settings/settings-gamepad"; import { SettingGamepad } from "../../system/settings/settings-gamepad";
import {Button} from "#enums/buttons"; import { Button } from "#enums/buttons";
/** /**
* Generic pad mapping * Generic pad mapping

View File

@ -1,5 +1,5 @@
import {SettingGamepad} from "#app/system/settings/settings-gamepad"; import { SettingGamepad } from "#app/system/settings/settings-gamepad";
import {Button} from "#enums/buttons"; import { Button } from "#enums/buttons";
/** /**
* Nintendo Pro Controller mapping * Nintendo Pro Controller mapping

View File

@ -1,5 +1,5 @@
import {SettingGamepad} from "../../system/settings/settings-gamepad"; import { SettingGamepad } from "../../system/settings/settings-gamepad";
import {Button} from "#enums/buttons"; import { Button } from "#enums/buttons";
/** /**
* 081f-e401 - UnlicensedSNES * 081f-e401 - UnlicensedSNES

View File

@ -1,5 +1,5 @@
import {SettingGamepad} from "../../system/settings/settings-gamepad"; import { SettingGamepad } from "../../system/settings/settings-gamepad";
import {Button} from "#enums/buttons"; import { Button } from "#enums/buttons";
/** /**
* Generic pad mapping * Generic pad mapping

View File

@ -4,7 +4,7 @@ import { Constructor } from "#app/utils";
import * as Utils from "../utils"; import * as Utils from "../utils";
import { getPokemonNameWithAffix } from "../messages"; import { getPokemonNameWithAffix } from "../messages";
import { Weather, WeatherType } from "./weather"; import { Weather, WeatherType } from "./weather";
import { BattlerTag, GroundedTag, GulpMissileTag, SemiInvulnerableTag } from "./battler-tags"; import { BattlerTag, GroundedTag } from "./battler-tags";
import { StatusEffect, getNonVolatileStatusEffects, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect"; import { StatusEffect, getNonVolatileStatusEffects, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect";
import { Gender } from "./gender"; import { Gender } from "./gender";
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr, VariableMoveTypeAttr, RandomMovesetMoveAttr, RandomMoveAttr, NaturePowerAttr, CopyMoveAttr, MoveAttr, MultiHitAttr, ChargeAttr, SacrificialAttr, SacrificialAttrOnHit, NeutralDamageAgainstFlyingTypeMultiplierAttr, FixedDamageAttr } from "./move"; import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr, VariableMoveTypeAttr, RandomMovesetMoveAttr, RandomMoveAttr, NaturePowerAttr, CopyMoveAttr, MoveAttr, MultiHitAttr, ChargeAttr, SacrificialAttr, SacrificialAttrOnHit, NeutralDamageAgainstFlyingTypeMultiplierAttr, FixedDamageAttr } from "./move";
@ -123,6 +123,7 @@ export class Ability implements Localizable {
type AbAttrApplyFunc<TAttr extends AbAttr> = (attr: TAttr, passive: boolean) => boolean | Promise<boolean>; type AbAttrApplyFunc<TAttr extends AbAttr> = (attr: TAttr, passive: boolean) => boolean | Promise<boolean>;
type AbAttrCondition = (pokemon: Pokemon) => boolean; type AbAttrCondition = (pokemon: Pokemon) => boolean;
// TODO: Can this be improved?
type PokemonAttackCondition = (user: Pokemon | null, target: Pokemon | null, move: Move) => boolean; type PokemonAttackCondition = (user: Pokemon | null, target: Pokemon | null, move: Move) => boolean;
type PokemonDefendCondition = (target: Pokemon, user: Pokemon, move: Move) => boolean; type PokemonDefendCondition = (target: Pokemon, user: Pokemon, move: Move) => boolean;
type PokemonStatStageChangeCondition = (target: Pokemon, statsChanged: BattleStat[], stages: number) => boolean; type PokemonStatStageChangeCondition = (target: Pokemon, statsChanged: BattleStat[], stages: number) => boolean;
@ -161,7 +162,7 @@ export class BlockRecoilDamageAttr extends AbAttr {
} }
getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]) { getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]) {
return i18next.t("abilityTriggers:blockRecoilDamage", {pokemonName: getPokemonNameWithAffix(pokemon), abilityName: abilityName}); return i18next.t("abilityTriggers:blockRecoilDamage", { pokemonName: getPokemonNameWithAffix(pokemon), abilityName: abilityName });
} }
} }
@ -518,6 +519,7 @@ export class FullHpResistTypeAbAttr extends PreDefendAbAttr {
if (pokemon.isFullHp() && typeMultiplier.value > 0.5) { if (pokemon.isFullHp() && typeMultiplier.value > 0.5) {
typeMultiplier.value = 0.5; typeMultiplier.value = 0.5;
pokemon.turnData.moveEffectiveness = 0.5;
return true; return true;
} }
return false; return false;
@ -536,53 +538,6 @@ export class PostDefendAbAttr extends AbAttr {
} }
} }
/**
* Applies the effects of Gulp Missile when the user is hit by an attack.
* @extends PostDefendAbAttr
*/
export class PostDefendGulpMissileAbAttr extends PostDefendAbAttr {
constructor() {
super(true);
}
/**
* Damages the attacker and triggers the secondary effect based on the form or the BattlerTagType.
* @param {Pokemon} pokemon - The defending Pokemon.
* @param passive - n/a
* @param {Pokemon} attacker - The attacking Pokemon.
* @param {Move} move - The move being used.
* @param {HitResult} hitResult - n/a
* @param {any[]} args - n/a
* @returns Whether the effects of the ability are applied.
*/
applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean | Promise<boolean> {
const battlerTag = pokemon.getTag(GulpMissileTag);
if (!battlerTag || move.category === MoveCategory.STATUS || pokemon.getTag(SemiInvulnerableTag)) {
return false;
}
if (simulated) {
return true;
}
const cancelled = new Utils.BooleanHolder(false);
applyAbAttrs(BlockNonDirectDamageAbAttr, attacker, cancelled);
if (!cancelled.value) {
attacker.damageAndUpdate(Math.max(1, Math.floor(attacker.getMaxHp() / 4)), HitResult.OTHER);
}
if (battlerTag.tagType === BattlerTagType.GULP_MISSILE_ARROKUDA) {
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, attacker.getBattlerIndex(), false, [ Stat.DEF ], -1));
} else {
attacker.trySetStatus(StatusEffect.PARALYSIS, true, pokemon);
}
pokemon.removeTag(battlerTag.tagType);
return true;
}
}
export class FieldPriorityMoveImmunityAbAttr extends PreDefendAbAttr { export class FieldPriorityMoveImmunityAbAttr extends PreDefendAbAttr {
applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean {
const attackPriority = new Utils.IntegerHolder(move.priority); const attackPriority = new Utils.IntegerHolder(move.priority);
@ -1009,7 +964,7 @@ export class PostDefendPerishSongAbAttr extends PostDefendAbAttr {
} }
getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string { getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string {
return i18next.t("abilityTriggers:perishBody", {pokemonName: getPokemonNameWithAffix(pokemon), abilityName: abilityName}); return i18next.t("abilityTriggers:perishBody", { pokemonName: getPokemonNameWithAffix(pokemon), abilityName: abilityName });
} }
} }
@ -1313,7 +1268,7 @@ export class PokemonTypeChangeAbAttr extends PreAttackAbAttr {
if (pokemon.getTypes().some((t) => t !== moveType)) { if (pokemon.getTypes().some((t) => t !== moveType)) {
if (!simulated) { if (!simulated) {
this.moveType = moveType; this.moveType = moveType;
pokemon.summonData.types = [moveType]; pokemon.summonData.types = [ moveType ];
pokemon.updateInfo(); pokemon.updateInfo();
} }
@ -2479,7 +2434,7 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr {
pokemon.setStatStage(s, target.getStatStage(s)); pokemon.setStatStage(s, target.getStatStage(s));
} }
pokemon.summonData.moveset = target.getMoveset().map(m => new PokemonMove(m!.moveId, m!.ppUsed, m!.ppUp)); // TODO: are those bangs correct? pokemon.summonData.moveset = target.getMoveset().map(m => new PokemonMove(m?.moveId ?? Moves.NONE, m?.ppUsed, m?.ppUp));
pokemon.summonData.types = target.getTypes(); pokemon.summonData.types = target.getTypes();
@ -2859,7 +2814,7 @@ export class PreApplyBattlerTagImmunityAbAttr extends PreApplyBattlerTagAbAttr {
constructor(immuneTagTypes: BattlerTagType | BattlerTagType[]) { constructor(immuneTagTypes: BattlerTagType | BattlerTagType[]) {
super(); super();
this.immuneTagTypes = Array.isArray(immuneTagTypes) ? immuneTagTypes : [immuneTagTypes]; this.immuneTagTypes = Array.isArray(immuneTagTypes) ? immuneTagTypes : [ immuneTagTypes ];
} }
applyPreApplyBattlerTag(pokemon: Pokemon, passive: boolean, simulated: boolean, tag: BattlerTag, cancelled: Utils.BooleanHolder, args: any[]): boolean { applyPreApplyBattlerTag(pokemon: Pokemon, passive: boolean, simulated: boolean, tag: BattlerTag, cancelled: Utils.BooleanHolder, args: any[]): boolean {
@ -3144,17 +3099,17 @@ function getAnticipationCondition(): AbAttrCondition {
// edge case for hidden power, type is computed // edge case for hidden power, type is computed
if (move.getMove().id === Moves.HIDDEN_POWER) { if (move.getMove().id === Moves.HIDDEN_POWER) {
const iv_val = Math.floor(((opponent.ivs[Stat.HP] & 1) const iv_val = Math.floor(((opponent.ivs[Stat.HP] & 1)
+(opponent.ivs[Stat.ATK] & 1) * 2 + (opponent.ivs[Stat.ATK] & 1) * 2
+(opponent.ivs[Stat.DEF] & 1) * 4 + (opponent.ivs[Stat.DEF] & 1) * 4
+(opponent.ivs[Stat.SPD] & 1) * 8 + (opponent.ivs[Stat.SPD] & 1) * 8
+(opponent.ivs[Stat.SPATK] & 1) * 16 + (opponent.ivs[Stat.SPATK] & 1) * 16
+(opponent.ivs[Stat.SPDEF] & 1) * 32) * 15/63); + (opponent.ivs[Stat.SPDEF] & 1) * 32) * 15 / 63);
const type = [ const type = [
Type.FIGHTING, Type.FLYING, Type.POISON, Type.GROUND, Type.FIGHTING, Type.FLYING, Type.POISON, Type.GROUND,
Type.ROCK, Type.BUG, Type.GHOST, Type.STEEL, Type.ROCK, Type.BUG, Type.GHOST, Type.STEEL,
Type.FIRE, Type.WATER, Type.GRASS, Type.ELECTRIC, Type.FIRE, Type.WATER, Type.GRASS, Type.ELECTRIC,
Type.PSYCHIC, Type.ICE, Type.DRAGON, Type.DARK][iv_val]; Type.PSYCHIC, Type.ICE, Type.DRAGON, Type.DARK ][iv_val];
if (pokemon.getAttackTypeEffectiveness(type, opponent) >= 2) { if (pokemon.getAttackTypeEffectiveness(type, opponent) >= 2) {
return true; return true;
@ -3199,12 +3154,12 @@ export class ForewarnAbAttr extends PostSummonAbAttr {
} else if (move?.getMove().power === -1) { } else if (move?.getMove().power === -1) {
movePower = 80; movePower = 80;
} else { } else {
movePower = move!.getMove().power; // TODO: is this bang correct? movePower = move?.getMove().power ?? 0;
} }
if (movePower > maxPowerSeen) { if (movePower > maxPowerSeen) {
maxPowerSeen = movePower; maxPowerSeen = movePower;
maxMove = move!.getName(); // TODO: is this bang correct? maxMove = move?.getName() ?? "";
} }
} }
} }
@ -3689,7 +3644,7 @@ export class PostTurnHurtIfSleepingAbAttr extends PostTurnAbAttr {
if ((opp.status?.effect === StatusEffect.SLEEP || opp.hasAbility(Abilities.COMATOSE)) && !opp.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) { if ((opp.status?.effect === StatusEffect.SLEEP || opp.hasAbility(Abilities.COMATOSE)) && !opp.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) {
if (!simulated) { if (!simulated) {
opp.damageAndUpdate(Utils.toDmgValue(opp.getMaxHp() / 8), HitResult.OTHER); opp.damageAndUpdate(Utils.toDmgValue(opp.getMaxHp() / 8), HitResult.OTHER);
pokemon.scene.queueMessage(i18next.t("abilityTriggers:badDreams", {pokemonName: getPokemonNameWithAffix(opp)})); pokemon.scene.queueMessage(i18next.t("abilityTriggers:badDreams", { pokemonName: getPokemonNameWithAffix(opp) }));
} }
hadEffect = true; hadEffect = true;
} }
@ -3800,8 +3755,8 @@ export class PostDancingMoveAbAttr extends PostMoveUsedAbAttr {
*/ */
applyPostMoveUsed(dancer: Pokemon, move: PokemonMove, source: Pokemon, targets: BattlerIndex[], simulated: boolean, args: any[]): boolean | Promise<boolean> { applyPostMoveUsed(dancer: Pokemon, move: PokemonMove, source: Pokemon, targets: BattlerIndex[], simulated: boolean, args: any[]): boolean | Promise<boolean> {
// List of tags that prevent the Dancer from replicating the move // List of tags that prevent the Dancer from replicating the move
const forbiddenTags = [BattlerTagType.FLYING, BattlerTagType.UNDERWATER, const forbiddenTags = [ BattlerTagType.FLYING, BattlerTagType.UNDERWATER,
BattlerTagType.UNDERGROUND, BattlerTagType.HIDDEN]; BattlerTagType.UNDERGROUND, BattlerTagType.HIDDEN ];
// The move to replicate cannot come from the Dancer // The move to replicate cannot come from the Dancer
if (source.getBattlerIndex() !== dancer.getBattlerIndex() if (source.getBattlerIndex() !== dancer.getBattlerIndex()
&& !dancer.summonData.tags.some(tag => forbiddenTags.includes(tag.tagType))) { && !dancer.summonData.tags.some(tag => forbiddenTags.includes(tag.tagType))) {
@ -3812,7 +3767,7 @@ export class PostDancingMoveAbAttr extends PostMoveUsedAbAttr {
dancer.scene.unshiftPhase(new MovePhase(dancer.scene, dancer, target, move, true, true)); dancer.scene.unshiftPhase(new MovePhase(dancer.scene, dancer, target, move, true, true));
} else if (move.getMove() instanceof SelfStatusMove) { } else if (move.getMove() instanceof SelfStatusMove) {
// If the move is a SelfStatusMove (ie. Swords Dance) the Dancer should replicate it on itself // If the move is a SelfStatusMove (ie. Swords Dance) the Dancer should replicate it on itself
dancer.scene.unshiftPhase(new MovePhase(dancer.scene, dancer, [dancer.getBattlerIndex()], move, true, true)); dancer.scene.unshiftPhase(new MovePhase(dancer.scene, dancer, [ dancer.getBattlerIndex() ], move, true, true));
} }
} }
return true; return true;
@ -3829,9 +3784,9 @@ export class PostDancingMoveAbAttr extends PostMoveUsedAbAttr {
*/ */
getTarget(dancer: Pokemon, source: Pokemon, targets: BattlerIndex[]) : BattlerIndex[] { getTarget(dancer: Pokemon, source: Pokemon, targets: BattlerIndex[]) : BattlerIndex[] {
if (dancer.isPlayer()) { if (dancer.isPlayer()) {
return source.isPlayer() ? targets : [source.getBattlerIndex()]; return source.isPlayer() ? targets : [ source.getBattlerIndex() ];
} }
return source.isPlayer() ? [source.getBattlerIndex()] : targets; return source.isPlayer() ? [ source.getBattlerIndex() ] : targets;
} }
} }
@ -4606,7 +4561,7 @@ export class BypassSpeedChanceAbAttr extends AbAttr {
const turnCommand = const turnCommand =
pokemon.scene.currentBattle.turnCommands[pokemon.getBattlerIndex()]; pokemon.scene.currentBattle.turnCommands[pokemon.getBattlerIndex()];
const isCommandFight = turnCommand?.command === Command.FIGHT; const isCommandFight = turnCommand?.command === Command.FIGHT;
const move = turnCommand?.move?.move ?allMoves[turnCommand.move.move] : null; const move = turnCommand?.move?.move ? allMoves[turnCommand.move.move] : null;
const isDamageMove = move?.category === MoveCategory.PHYSICAL || move?.category === MoveCategory.SPECIAL; const isDamageMove = move?.category === MoveCategory.PHYSICAL || move?.category === MoveCategory.SPECIAL;
if (isCommandFight && isDamageMove) { if (isCommandFight && isDamageMove) {
@ -4619,7 +4574,7 @@ export class BypassSpeedChanceAbAttr extends AbAttr {
} }
getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string { getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string {
return i18next.t("abilityTriggers:quickDraw", {pokemonName: getPokemonNameWithAffix(pokemon)}); return i18next.t("abilityTriggers:quickDraw", { pokemonName: getPokemonNameWithAffix(pokemon) });
} }
} }
@ -4667,7 +4622,7 @@ async function applyAbAttrsInternal<TAttr extends AbAttr>(
simulated: boolean = false, simulated: boolean = false,
messages: string[] = [], messages: string[] = [],
) { ) {
for (const passive of [false, true]) { for (const passive of [ false, true ]) {
if (!pokemon?.canApplyAbility(passive)) { if (!pokemon?.canApplyAbility(passive)) {
continue; continue;
} }
@ -4917,7 +4872,7 @@ export function initAbilities() {
.attr(TypeImmunityHealAbAttr, Type.WATER) .attr(TypeImmunityHealAbAttr, Type.WATER)
.ignorable(), .ignorable(),
new Ability(Abilities.OBLIVIOUS, 3) new Ability(Abilities.OBLIVIOUS, 3)
.attr(BattlerTagImmunityAbAttr, [BattlerTagType.INFATUATED, BattlerTagType.TAUNT]) .attr(BattlerTagImmunityAbAttr, [ BattlerTagType.INFATUATED, BattlerTagType.TAUNT ])
.attr(IntimidateImmunityAbAttr) .attr(IntimidateImmunityAbAttr)
.ignorable(), .ignorable(),
new Ability(Abilities.CLOUD_NINE, 3) new Ability(Abilities.CLOUD_NINE, 3)
@ -5062,10 +5017,10 @@ export function initAbilities() {
new Ability(Abilities.CUTE_CHARM, 3) new Ability(Abilities.CUTE_CHARM, 3)
.attr(PostDefendContactApplyTagChanceAbAttr, 30, BattlerTagType.INFATUATED), .attr(PostDefendContactApplyTagChanceAbAttr, 30, BattlerTagType.INFATUATED),
new Ability(Abilities.PLUS, 3) new Ability(Abilities.PLUS, 3)
.conditionalAttr(p => p.scene.currentBattle.double && [Abilities.PLUS, Abilities.MINUS].some(a => p.getAlly().hasAbility(a)), StatMultiplierAbAttr, Stat.SPATK, 1.5) .conditionalAttr(p => p.scene.currentBattle.double && [ Abilities.PLUS, Abilities.MINUS ].some(a => p.getAlly().hasAbility(a)), StatMultiplierAbAttr, Stat.SPATK, 1.5)
.ignorable(), .ignorable(),
new Ability(Abilities.MINUS, 3) new Ability(Abilities.MINUS, 3)
.conditionalAttr(p => p.scene.currentBattle.double && [Abilities.PLUS, Abilities.MINUS].some(a => p.getAlly().hasAbility(a)), StatMultiplierAbAttr, Stat.SPATK, 1.5) .conditionalAttr(p => p.scene.currentBattle.double && [ Abilities.PLUS, Abilities.MINUS ].some(a => p.getAlly().hasAbility(a)), StatMultiplierAbAttr, Stat.SPATK, 1.5)
.ignorable(), .ignorable(),
new Ability(Abilities.FORECAST, 3) new Ability(Abilities.FORECAST, 3)
.attr(UncopiableAbilityAbAttr) .attr(UncopiableAbilityAbAttr)
@ -5183,7 +5138,7 @@ export function initAbilities() {
.conditionalAttr(pokemon => !!pokemon.status || pokemon.hasAbility(Abilities.COMATOSE), StatMultiplierAbAttr, Stat.SPD, 1.5), .conditionalAttr(pokemon => !!pokemon.status || pokemon.hasAbility(Abilities.COMATOSE), StatMultiplierAbAttr, Stat.SPD, 1.5),
new Ability(Abilities.NORMALIZE, 4) new Ability(Abilities.NORMALIZE, 4)
.attr(MoveTypeChangeAbAttr, Type.NORMAL, 1.2, (user, target, move) => { .attr(MoveTypeChangeAbAttr, Type.NORMAL, 1.2, (user, target, move) => {
return ![Moves.HIDDEN_POWER, Moves.WEATHER_BALL, Moves.NATURAL_GIFT, Moves.JUDGMENT, Moves.TECHNO_BLAST].includes(move.id); return ![ Moves.HIDDEN_POWER, Moves.WEATHER_BALL, Moves.NATURAL_GIFT, Moves.JUDGMENT, Moves.TECHNO_BLAST ].includes(move.id);
}), }),
new Ability(Abilities.SNIPER, 4) new Ability(Abilities.SNIPER, 4)
.attr(MultCritAbAttr, 1.5), .attr(MultCritAbAttr, 1.5),
@ -5210,8 +5165,7 @@ export function initAbilities() {
.attr(PostSummonMessageAbAttr, (pokemon: Pokemon) => i18next.t("abilityTriggers:postSummonMoldBreaker", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) })) .attr(PostSummonMessageAbAttr, (pokemon: Pokemon) => i18next.t("abilityTriggers:postSummonMoldBreaker", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }))
.attr(MoveAbilityBypassAbAttr), .attr(MoveAbilityBypassAbAttr),
new Ability(Abilities.SUPER_LUCK, 4) new Ability(Abilities.SUPER_LUCK, 4)
.attr(BonusCritAbAttr) .attr(BonusCritAbAttr),
.partial(),
new Ability(Abilities.AFTERMATH, 4) new Ability(Abilities.AFTERMATH, 4)
.attr(PostFaintContactDamageAbAttr, 4) .attr(PostFaintContactDamageAbAttr, 4)
.bypassFaint(), .bypassFaint(),
@ -5223,15 +5177,14 @@ export function initAbilities() {
.attr(IgnoreOpponentStatStagesAbAttr) .attr(IgnoreOpponentStatStagesAbAttr)
.ignorable(), .ignorable(),
new Ability(Abilities.TINTED_LENS, 4) new Ability(Abilities.TINTED_LENS, 4)
//@ts-ignore .attr(DamageBoostAbAttr, 2, (user, target, move) => (target?.getMoveEffectiveness(user!, move) ?? 1) <= 0.5),
.attr(DamageBoostAbAttr, 2, (user, target, move) => target?.getMoveEffectiveness(user, move) <= 0.5), // TODO: fix TS issues
new Ability(Abilities.FILTER, 4) new Ability(Abilities.FILTER, 4)
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => target.getMoveEffectiveness(user, move) >= 2, 0.75) .attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => target.getMoveEffectiveness(user, move) >= 2, 0.75)
.ignorable(), .ignorable(),
new Ability(Abilities.SLOW_START, 4) new Ability(Abilities.SLOW_START, 4)
.attr(PostSummonAddBattlerTagAbAttr, BattlerTagType.SLOW_START, 5), .attr(PostSummonAddBattlerTagAbAttr, BattlerTagType.SLOW_START, 5),
new Ability(Abilities.SCRAPPY, 4) new Ability(Abilities.SCRAPPY, 4)
.attr(IgnoreTypeImmunityAbAttr, Type.GHOST, [Type.NORMAL, Type.FIGHTING]) .attr(IgnoreTypeImmunityAbAttr, Type.GHOST, [ Type.NORMAL, Type.FIGHTING ])
.attr(IntimidateImmunityAbAttr), .attr(IntimidateImmunityAbAttr),
new Ability(Abilities.STORM_DRAIN, 4) new Ability(Abilities.STORM_DRAIN, 4)
.attr(RedirectTypeMoveAbAttr, Type.WATER) .attr(RedirectTypeMoveAbAttr, Type.WATER)
@ -5272,7 +5225,7 @@ export function initAbilities() {
.attr(PostDefendStealHeldItemAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT)) .attr(PostDefendStealHeldItemAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT))
.condition(getSheerForceHitDisableAbCondition()), .condition(getSheerForceHitDisableAbCondition()),
new Ability(Abilities.SHEER_FORCE, 5) new Ability(Abilities.SHEER_FORCE, 5)
.attr(MovePowerBoostAbAttr, (user, target, move) => move.chance >= 1, 5461/4096) .attr(MovePowerBoostAbAttr, (user, target, move) => move.chance >= 1, 5461 / 4096)
.attr(MoveEffectChanceMultiplierAbAttr, 0) .attr(MoveEffectChanceMultiplierAbAttr, 0)
.partial(), .partial(),
new Ability(Abilities.CONTRARY, 5) new Ability(Abilities.CONTRARY, 5)
@ -5281,7 +5234,7 @@ export function initAbilities() {
new Ability(Abilities.UNNERVE, 5) new Ability(Abilities.UNNERVE, 5)
.attr(PreventBerryUseAbAttr), .attr(PreventBerryUseAbAttr),
new Ability(Abilities.DEFIANT, 5) new Ability(Abilities.DEFIANT, 5)
.attr(PostStatStageChangeStatStageChangeAbAttr, (target, statsChanged, stages) => stages < 0, [Stat.ATK], 2), .attr(PostStatStageChangeStatStageChangeAbAttr, (target, statsChanged, stages) => stages < 0, [ Stat.ATK ], 2),
new Ability(Abilities.DEFEATIST, 5) new Ability(Abilities.DEFEATIST, 5)
.attr(StatMultiplierAbAttr, Stat.ATK, 0.5) .attr(StatMultiplierAbAttr, Stat.ATK, 0.5)
.attr(StatMultiplierAbAttr, Stat.SPATK, 0.5) .attr(StatMultiplierAbAttr, Stat.SPATK, 0.5)
@ -5342,8 +5295,9 @@ export function initAbilities() {
.attr(WonderSkinAbAttr) .attr(WonderSkinAbAttr)
.ignorable(), .ignorable(),
new Ability(Abilities.ANALYTIC, 5) new Ability(Abilities.ANALYTIC, 5)
//@ts-ignore .attr(MovePowerBoostAbAttr, (user, target, move) =>
.attr(MovePowerBoostAbAttr, (user, target, move) => !!target?.getLastXMoves(1).find(m => m.turn === target?.scene.currentBattle.turn) || user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command !== Command.FIGHT, 1.3), // TODO fix TS issues !!target?.getLastXMoves(1).find(m => m.turn === target?.scene.currentBattle.turn)
|| user?.scene.currentBattle.turnCommands[target?.getBattlerIndex() ?? BattlerIndex.ATTACKER]?.command !== Command.FIGHT, 1.3),
new Ability(Abilities.ILLUSION, 5) new Ability(Abilities.ILLUSION, 5)
.attr(UncopiableAbilityAbAttr) .attr(UncopiableAbilityAbAttr)
.attr(UnswappableAbilityAbAttr) .attr(UnswappableAbilityAbAttr)
@ -5366,7 +5320,7 @@ export function initAbilities() {
return move.category !== MoveCategory.STATUS return move.category !== MoveCategory.STATUS
&& (moveType === Type.DARK || moveType === Type.BUG || moveType === Type.GHOST); && (moveType === Type.DARK || moveType === Type.BUG || moveType === Type.GHOST);
}, Stat.SPD, 1) }, Stat.SPD, 1)
.attr(PostIntimidateStatStageChangeAbAttr, [Stat.SPD], 1), .attr(PostIntimidateStatStageChangeAbAttr, [ Stat.SPD ], 1),
new Ability(Abilities.MAGIC_BOUNCE, 5) new Ability(Abilities.MAGIC_BOUNCE, 5)
.ignorable() .ignorable()
.unimplemented(), .unimplemented(),
@ -5403,12 +5357,12 @@ export function initAbilities() {
.attr(PostSummonMessageAbAttr, (pokemon: Pokemon) => i18next.t("abilityTriggers:postSummonTeravolt", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) })) .attr(PostSummonMessageAbAttr, (pokemon: Pokemon) => i18next.t("abilityTriggers:postSummonTeravolt", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }))
.attr(MoveAbilityBypassAbAttr), .attr(MoveAbilityBypassAbAttr),
new Ability(Abilities.AROMA_VEIL, 6) new Ability(Abilities.AROMA_VEIL, 6)
.attr(UserFieldBattlerTagImmunityAbAttr, [BattlerTagType.INFATUATED, BattlerTagType.TAUNT, BattlerTagType.DISABLED, BattlerTagType.TORMENT, BattlerTagType.HEAL_BLOCK]), .attr(UserFieldBattlerTagImmunityAbAttr, [ BattlerTagType.INFATUATED, BattlerTagType.TAUNT, BattlerTagType.DISABLED, BattlerTagType.TORMENT, BattlerTagType.HEAL_BLOCK ]),
new Ability(Abilities.FLOWER_VEIL, 6) new Ability(Abilities.FLOWER_VEIL, 6)
.ignorable() .ignorable()
.unimplemented(), .unimplemented(),
new Ability(Abilities.CHEEK_POUCH, 6) new Ability(Abilities.CHEEK_POUCH, 6)
.attr(HealFromBerryUseAbAttr, 1/3), .attr(HealFromBerryUseAbAttr, 1 / 3),
new Ability(Abilities.PROTEAN, 6) new Ability(Abilities.PROTEAN, 6)
.attr(PokemonTypeChangeAbAttr), .attr(PokemonTypeChangeAbAttr),
//.condition((p) => !p.summonData?.abilitiesApplied.includes(Abilities.PROTEAN)), //Gen 9 Implementation //.condition((p) => !p.summonData?.abilitiesApplied.includes(Abilities.PROTEAN)), //Gen 9 Implementation
@ -5421,7 +5375,7 @@ export function initAbilities() {
.attr(MoveImmunityAbAttr, (pokemon, attacker, move) => pokemon !== attacker && move.hasFlag(MoveFlags.BALLBOMB_MOVE)) .attr(MoveImmunityAbAttr, (pokemon, attacker, move) => pokemon !== attacker && move.hasFlag(MoveFlags.BALLBOMB_MOVE))
.ignorable(), .ignorable(),
new Ability(Abilities.COMPETITIVE, 6) new Ability(Abilities.COMPETITIVE, 6)
.attr(PostStatStageChangeStatStageChangeAbAttr, (target, statsChanged, stages) => stages < 0, [Stat.SPATK], 2), .attr(PostStatStageChangeStatStageChangeAbAttr, (target, statsChanged, stages) => stages < 0, [ Stat.SPATK ], 2),
new Ability(Abilities.STRONG_JAW, 6) new Ability(Abilities.STRONG_JAW, 6)
.attr(MovePowerBoostAbAttr, (user, target, move) => move.hasFlag(MoveFlags.BITING_MOVE), 1.5), .attr(MovePowerBoostAbAttr, (user, target, move) => move.hasFlag(MoveFlags.BITING_MOVE), 1.5),
new Ability(Abilities.REFRIGERATE, 6) new Ability(Abilities.REFRIGERATE, 6)
@ -5508,8 +5462,7 @@ export function initAbilities() {
.bypassFaint() .bypassFaint()
.partial(), .partial(),
new Ability(Abilities.STAKEOUT, 7) new Ability(Abilities.STAKEOUT, 7)
//@ts-ignore .attr(MovePowerBoostAbAttr, (user, target, move) => user?.scene.currentBattle.turnCommands[target?.getBattlerIndex() ?? BattlerIndex.ATTACKER]?.command === Command.POKEMON, 2),
.attr(MovePowerBoostAbAttr, (user, target, move) => user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command === Command.POKEMON, 2), // TODO: fix TS issues
new Ability(Abilities.WATER_BUBBLE, 7) new Ability(Abilities.WATER_BUBBLE, 7)
.attr(ReceivedTypeDamageMultiplierAbAttr, Type.FIRE, 0.5) .attr(ReceivedTypeDamageMultiplierAbAttr, Type.FIRE, 0.5)
.attr(MoveTypePowerBoostAbAttr, Type.WATER, 2) .attr(MoveTypePowerBoostAbAttr, Type.WATER, 2)
@ -5518,7 +5471,7 @@ export function initAbilities() {
new Ability(Abilities.STEELWORKER, 7) new Ability(Abilities.STEELWORKER, 7)
.attr(MoveTypePowerBoostAbAttr, Type.STEEL), .attr(MoveTypePowerBoostAbAttr, Type.STEEL),
new Ability(Abilities.BERSERK, 7) new Ability(Abilities.BERSERK, 7)
.attr(PostDefendHpGatedStatStageChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, 0.5, [Stat.SPATK], 1) .attr(PostDefendHpGatedStatStageChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, 0.5, [ Stat.SPATK ], 1)
.condition(getSheerForceHitDisableAbCondition()), .condition(getSheerForceHitDisableAbCondition()),
new Ability(Abilities.SLUSH_RUSH, 7) new Ability(Abilities.SLUSH_RUSH, 7)
.attr(StatMultiplierAbAttr, Stat.SPD, 2) .attr(StatMultiplierAbAttr, Stat.SPD, 2)
@ -5575,7 +5528,7 @@ export function initAbilities() {
.bypassFaint() .bypassFaint()
.partial(), .partial(),
new Ability(Abilities.CORROSION, 7) // TODO: Test Corrosion against Magic Bounce once it is implemented new Ability(Abilities.CORROSION, 7) // TODO: Test Corrosion against Magic Bounce once it is implemented
.attr(IgnoreTypeStatusEffectImmunityAbAttr, [StatusEffect.POISON, StatusEffect.TOXIC], [Type.STEEL, Type.POISON]) .attr(IgnoreTypeStatusEffectImmunityAbAttr, [ StatusEffect.POISON, StatusEffect.TOXIC ], [ Type.STEEL, Type.POISON ])
.partial(), .partial(),
new Ability(Abilities.COMATOSE, 7) new Ability(Abilities.COMATOSE, 7)
.attr(UncopiableAbilityAbAttr) .attr(UncopiableAbilityAbAttr)
@ -5592,7 +5545,7 @@ export function initAbilities() {
new Ability(Abilities.DANCER, 7) new Ability(Abilities.DANCER, 7)
.attr(PostDancingMoveAbAttr), .attr(PostDancingMoveAbAttr),
new Ability(Abilities.BATTERY, 7) new Ability(Abilities.BATTERY, 7)
.attr(AllyMoveCategoryPowerBoostAbAttr, [MoveCategory.SPECIAL], 1.3), .attr(AllyMoveCategoryPowerBoostAbAttr, [ MoveCategory.SPECIAL ], 1.3),
new Ability(Abilities.FLUFFY, 7) new Ability(Abilities.FLUFFY, 7)
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT), 0.5) .attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT), 0.5)
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => user.getMoveType(move) === Type.FIRE, 2) .attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => user.getMoveType(move) === Type.FIRE, 2)
@ -5647,8 +5600,7 @@ export function initAbilities() {
new Ability(Abilities.PRISM_ARMOR, 7) new Ability(Abilities.PRISM_ARMOR, 7)
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => target.getMoveEffectiveness(user, move) >= 2, 0.75), .attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => target.getMoveEffectiveness(user, move) >= 2, 0.75),
new Ability(Abilities.NEUROFORCE, 7) new Ability(Abilities.NEUROFORCE, 7)
//@ts-ignore .attr(MovePowerBoostAbAttr, (user, target, move) => (target?.getMoveEffectiveness(user!, move) ?? 1) >= 2, 1.25),
.attr(MovePowerBoostAbAttr, (user, target, move) => target?.getMoveEffectiveness(user, move) >= 2, 1.25), // TODO: fix TS issues
new Ability(Abilities.INTREPID_SWORD, 8) new Ability(Abilities.INTREPID_SWORD, 8)
.attr(PostSummonStatStageChangeAbAttr, [ Stat.ATK ], 1, true) .attr(PostSummonStatStageChangeAbAttr, [ Stat.ATK ], 1, true)
.condition(getOncePerBattleCondition(Abilities.INTREPID_SWORD)), .condition(getOncePerBattleCondition(Abilities.INTREPID_SWORD)),
@ -5669,13 +5621,19 @@ export function initAbilities() {
new Ability(Abilities.MIRROR_ARMOR, 8) new Ability(Abilities.MIRROR_ARMOR, 8)
.ignorable() .ignorable()
.unimplemented(), .unimplemented(),
/**
* Right now, the logic is attached to Surf and Dive moves. Ideally, the post-defend/hit should be an
* ability attribute but the current implementation of move effects for BattlerTag does not support this- in the case
* where Cramorant is fainted.
* @see {@linkcode GulpMissileTagAttr} and {@linkcode GulpMissileTag} for Gulp Missile implementation
*/
new Ability(Abilities.GULP_MISSILE, 8) new Ability(Abilities.GULP_MISSILE, 8)
.attr(UnsuppressableAbilityAbAttr) .attr(UnsuppressableAbilityAbAttr)
.attr(NoTransformAbilityAbAttr) .attr(NoTransformAbilityAbAttr)
.attr(NoFusionAbilityAbAttr) .attr(NoFusionAbilityAbAttr)
.attr(UncopiableAbilityAbAttr) .attr(UncopiableAbilityAbAttr)
.attr(UnswappableAbilityAbAttr) .attr(UnswappableAbilityAbAttr)
.attr(PostDefendGulpMissileAbAttr), .bypassFaint(),
new Ability(Abilities.STALWART, 8) new Ability(Abilities.STALWART, 8)
.attr(BlockRedirectAbAttr), .attr(BlockRedirectAbAttr),
new Ability(Abilities.STEAM_ENGINE, 8) new Ability(Abilities.STEAM_ENGINE, 8)
@ -5713,11 +5671,11 @@ export function initAbilities() {
.bypassFaint() .bypassFaint()
.ignorable(), .ignorable(),
new Ability(Abilities.POWER_SPOT, 8) new Ability(Abilities.POWER_SPOT, 8)
.attr(AllyMoveCategoryPowerBoostAbAttr, [MoveCategory.SPECIAL, MoveCategory.PHYSICAL], 1.3), .attr(AllyMoveCategoryPowerBoostAbAttr, [ MoveCategory.SPECIAL, MoveCategory.PHYSICAL ], 1.3),
new Ability(Abilities.MIMICRY, 8) new Ability(Abilities.MIMICRY, 8)
.unimplemented(), .unimplemented(),
new Ability(Abilities.SCREEN_CLEANER, 8) new Ability(Abilities.SCREEN_CLEANER, 8)
.attr(PostSummonRemoveArenaTagAbAttr, [ArenaTagType.AURORA_VEIL, ArenaTagType.LIGHT_SCREEN, ArenaTagType.REFLECT]), .attr(PostSummonRemoveArenaTagAbAttr, [ ArenaTagType.AURORA_VEIL, ArenaTagType.LIGHT_SCREEN, ArenaTagType.REFLECT ]),
new Ability(Abilities.STEELY_SPIRIT, 8) new Ability(Abilities.STEELY_SPIRIT, 8)
.attr(UserFieldMoveTypePowerBoostAbAttr, Type.STEEL), .attr(UserFieldMoveTypePowerBoostAbAttr, Type.STEEL),
new Ability(Abilities.PERISH_BODY, 8) new Ability(Abilities.PERISH_BODY, 8)
@ -5740,10 +5698,8 @@ export function initAbilities() {
.attr(UserFieldStatusEffectImmunityAbAttr, StatusEffect.POISON, StatusEffect.TOXIC) .attr(UserFieldStatusEffectImmunityAbAttr, StatusEffect.POISON, StatusEffect.TOXIC)
.ignorable(), .ignorable(),
new Ability(Abilities.HUNGER_SWITCH, 8) new Ability(Abilities.HUNGER_SWITCH, 8)
//@ts-ignore .attr(PostTurnFormChangeAbAttr, p => p.getFormKey() ? 0 : 1)
.attr(PostTurnFormChangeAbAttr, p => p.getFormKey ? 0 : 1) // TODO: fix ts-ignore .attr(PostTurnFormChangeAbAttr, p => p.getFormKey() ? 1 : 0)
//@ts-ignore
.attr(PostTurnFormChangeAbAttr, p => p.getFormKey ? 1 : 0) // TODO: fix ts-ignore
.attr(UncopiableAbilityAbAttr) .attr(UncopiableAbilityAbAttr)
.attr(UnswappableAbilityAbAttr) .attr(UnswappableAbilityAbAttr)
.attr(NoTransformAbilityAbAttr) .attr(NoTransformAbilityAbAttr)
@ -5802,7 +5758,7 @@ export function initAbilities() {
.attr(PostSummonStatStageChangeOnArenaAbAttr, ArenaTagType.TAILWIND) .attr(PostSummonStatStageChangeOnArenaAbAttr, ArenaTagType.TAILWIND)
.ignorable(), .ignorable(),
new Ability(Abilities.GUARD_DOG, 9) new Ability(Abilities.GUARD_DOG, 9)
.attr(PostIntimidateStatStageChangeAbAttr, [Stat.ATK], 1, true) .attr(PostIntimidateStatStageChangeAbAttr, [ Stat.ATK ], 1, true)
.attr(ForceSwitchOutImmunityAbAttr) .attr(ForceSwitchOutImmunityAbAttr)
.ignorable(), .ignorable(),
new Ability(Abilities.ROCKY_PAYLOAD, 9) new Ability(Abilities.ROCKY_PAYLOAD, 9)
@ -5891,7 +5847,7 @@ export function initAbilities() {
.attr(PreventBypassSpeedChanceAbAttr, (pokemon, move) => move.category === MoveCategory.STATUS) .attr(PreventBypassSpeedChanceAbAttr, (pokemon, move) => move.category === MoveCategory.STATUS)
.attr(MoveAbilityBypassAbAttr, (pokemon, move: Move) => move.category === MoveCategory.STATUS), .attr(MoveAbilityBypassAbAttr, (pokemon, move: Move) => move.category === MoveCategory.STATUS),
new Ability(Abilities.MINDS_EYE, 9) new Ability(Abilities.MINDS_EYE, 9)
.attr(IgnoreTypeImmunityAbAttr, Type.GHOST, [Type.NORMAL, Type.FIGHTING]) .attr(IgnoreTypeImmunityAbAttr, Type.GHOST, [ Type.NORMAL, Type.FIGHTING ])
.attr(ProtectStatAbAttr, Stat.ACC) .attr(ProtectStatAbAttr, Stat.ACC)
.attr(IgnoreOpponentStatStagesAbAttr, [ Stat.EVA ]) .attr(IgnoreOpponentStatStagesAbAttr, [ Stat.EVA ])
.ignorable(), .ignorable(),

View File

@ -135,7 +135,7 @@ export class WeakenMoveScreenTag extends ArenaTag {
*/ */
apply(arena: Arena, args: any[]): boolean { apply(arena: Arena, args: any[]): boolean {
if (this.weakenedCategories.includes((args[0] as MoveCategory))) { if (this.weakenedCategories.includes((args[0] as MoveCategory))) {
(args[2] as Utils.NumberHolder).value = (args[1] as boolean) ? 2732/4096 : 0.5; (args[2] as Utils.NumberHolder).value = (args[1] as boolean) ? 2732 / 4096 : 0.5;
return true; return true;
} }
return false; return false;
@ -148,7 +148,7 @@ export class WeakenMoveScreenTag extends ArenaTag {
*/ */
class ReflectTag extends WeakenMoveScreenTag { class ReflectTag extends WeakenMoveScreenTag {
constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) { constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) {
super(ArenaTagType.REFLECT, turnCount, Moves.REFLECT, sourceId, side, [MoveCategory.PHYSICAL]); super(ArenaTagType.REFLECT, turnCount, Moves.REFLECT, sourceId, side, [ MoveCategory.PHYSICAL ]);
} }
onAdd(arena: Arena, quiet: boolean = false): void { onAdd(arena: Arena, quiet: boolean = false): void {
@ -164,7 +164,7 @@ class ReflectTag extends WeakenMoveScreenTag {
*/ */
class LightScreenTag extends WeakenMoveScreenTag { class LightScreenTag extends WeakenMoveScreenTag {
constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) { constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) {
super(ArenaTagType.LIGHT_SCREEN, turnCount, Moves.LIGHT_SCREEN, sourceId, side, [MoveCategory.SPECIAL]); super(ArenaTagType.LIGHT_SCREEN, turnCount, Moves.LIGHT_SCREEN, sourceId, side, [ MoveCategory.SPECIAL ]);
} }
onAdd(arena: Arena, quiet: boolean = false): void { onAdd(arena: Arena, quiet: boolean = false): void {
@ -180,7 +180,7 @@ class LightScreenTag extends WeakenMoveScreenTag {
*/ */
class AuroraVeilTag extends WeakenMoveScreenTag { class AuroraVeilTag extends WeakenMoveScreenTag {
constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) { constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) {
super(ArenaTagType.AURORA_VEIL, turnCount, Moves.AURORA_VEIL, sourceId, side, [MoveCategory.SPECIAL, MoveCategory.PHYSICAL]); super(ArenaTagType.AURORA_VEIL, turnCount, Moves.AURORA_VEIL, sourceId, side, [ MoveCategory.SPECIAL, MoveCategory.PHYSICAL ]);
} }
onAdd(arena: Arena, quiet: boolean = false): void { onAdd(arena: Arena, quiet: boolean = false): void {
@ -511,6 +511,39 @@ class WaterSportTag extends WeakenMoveTypeTag {
} }
} }
/**
* Arena Tag class for the secondary effect of {@link https://bulbapedia.bulbagarden.net/wiki/Plasma_Fists_(move) | Plasma Fists}.
* Converts Normal-type moves to Electric type for the rest of the turn.
*/
export class PlasmaFistsTag extends ArenaTag {
constructor() {
super(ArenaTagType.PLASMA_FISTS, 1, Moves.PLASMA_FISTS);
}
/** Queues Plasma Fists' on-add message */
onAdd(arena: Arena): void {
arena.scene.queueMessage(i18next.t("arenaTag:plasmaFistsOnAdd"));
}
onRemove(arena: Arena): void { } // Removes default on-remove message
/**
* Converts Normal-type moves to Electric type
* @param arena n/a
* @param args
* - `[0]` {@linkcode Utils.NumberHolder} A container with a move's {@linkcode Type}
* @returns `true` if the given move type changed; `false` otherwise.
*/
apply(arena: Arena, args: any[]): boolean {
const moveType = args[0];
if (moveType instanceof Utils.NumberHolder && moveType.value === Type.NORMAL) {
moveType.value = Type.ELECTRIC;
return true;
}
return false;
}
}
/** /**
* Abstract class to implement arena traps. * Abstract class to implement arena traps.
*/ */
@ -955,7 +988,7 @@ class ImprisonTag extends ArenaTrapTag {
party?.forEach((p: PlayerPokemon | EnemyPokemon ) => { party?.forEach((p: PlayerPokemon | EnemyPokemon ) => {
p.addTag(BattlerTagType.IMPRISON, 1, Moves.IMPRISON, this.sourceId); p.addTag(BattlerTagType.IMPRISON, 1, Moves.IMPRISON, this.sourceId);
}); });
scene.queueMessage(i18next.t("battlerTags:imprisonOnAdd", {pokemonNameWithAffix: getPokemonNameWithAffix(this.source)})); scene.queueMessage(i18next.t("battlerTags:imprisonOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(this.source) }));
} }
} }
@ -1010,6 +1043,8 @@ export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMov
return new MudSportTag(turnCount, sourceId); return new MudSportTag(turnCount, sourceId);
case ArenaTagType.WATER_SPORT: case ArenaTagType.WATER_SPORT:
return new WaterSportTag(turnCount, sourceId); return new WaterSportTag(turnCount, sourceId);
case ArenaTagType.PLASMA_FISTS:
return new PlasmaFistsTag();
case ArenaTagType.SPIKES: case ArenaTagType.SPIKES:
return new SpikesTag(sourceId, side); return new SpikesTag(sourceId, side);
case ArenaTagType.TOXIC_SPIKES: case ArenaTagType.TOXIC_SPIKES:

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
import { allMoves } from "./move"; import { allMoves } from "#app/data/move";
import * as Utils from "../utils"; import * as Utils from "#app/utils";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
@ -81,7 +81,7 @@ export const speciesEggMoves = {
[Species.LEDYBA]: [ Moves.POLLEN_PUFF, Moves.THIEF, Moves.PARTING_SHOT, Moves.SPORE ], [Species.LEDYBA]: [ Moves.POLLEN_PUFF, Moves.THIEF, Moves.PARTING_SHOT, Moves.SPORE ],
[Species.SPINARAK]: [ Moves.PARTING_SHOT, Moves.ATTACK_ORDER, Moves.GASTRO_ACID, Moves.STRENGTH_SAP ], [Species.SPINARAK]: [ Moves.PARTING_SHOT, Moves.ATTACK_ORDER, Moves.GASTRO_ACID, Moves.STRENGTH_SAP ],
[Species.CHINCHOU]: [ Moves.THUNDERCLAP, Moves.BOUNCY_BUBBLE, Moves.THUNDER_CAGE, Moves.TAIL_GLOW ], [Species.CHINCHOU]: [ Moves.THUNDERCLAP, Moves.BOUNCY_BUBBLE, Moves.THUNDER_CAGE, Moves.TAIL_GLOW ],
[Species.PICHU]: [ Moves.MOONBLAST, Moves.WAVE_CRASH, Moves.AIR_SLASH, Moves.AURA_WHEEL ], [Species.PICHU]: [ Moves.MOONBLAST, Moves.TRIPLE_AXEL, Moves.FIERY_DANCE, Moves.AURA_WHEEL ],
[Species.CLEFFA]: [ Moves.CALM_MIND, Moves.EARTH_POWER, Moves.WISH, Moves.LIGHT_OF_RUIN ], [Species.CLEFFA]: [ Moves.CALM_MIND, Moves.EARTH_POWER, Moves.WISH, Moves.LIGHT_OF_RUIN ],
[Species.IGGLYBUFF]: [ Moves.DRAIN_PUNCH, Moves.GRAV_APPLE, Moves.SOFT_BOILED, Moves.EXTREME_SPEED ], [Species.IGGLYBUFF]: [ Moves.DRAIN_PUNCH, Moves.GRAV_APPLE, Moves.SOFT_BOILED, Moves.EXTREME_SPEED ],
[Species.TOGEPI]: [ Moves.SCORCHING_SANDS, Moves.ROOST, Moves.RELIC_SONG, Moves.FIERY_DANCE ], [Species.TOGEPI]: [ Moves.SCORCHING_SANDS, Moves.ROOST, Moves.RELIC_SONG, Moves.FIERY_DANCE ],
@ -195,7 +195,7 @@ export const speciesEggMoves = {
[Species.REGISTEEL]: [ Moves.BODY_PRESS, Moves.SIZZLY_SLIDE, Moves.RECOVER, Moves.GIGATON_HAMMER ], [Species.REGISTEEL]: [ Moves.BODY_PRESS, Moves.SIZZLY_SLIDE, Moves.RECOVER, Moves.GIGATON_HAMMER ],
[Species.LATIAS]: [ Moves.CORE_ENFORCER, Moves.FUSION_FLARE, Moves.SPARKLY_SWIRL, Moves.MYSTICAL_POWER ], [Species.LATIAS]: [ Moves.CORE_ENFORCER, Moves.FUSION_FLARE, Moves.SPARKLY_SWIRL, Moves.MYSTICAL_POWER ],
[Species.LATIOS]: [ Moves.CORE_ENFORCER, Moves.BLUE_FLARE, Moves.NASTY_PLOT, Moves.TACHYON_CUTTER ], [Species.LATIOS]: [ Moves.CORE_ENFORCER, Moves.BLUE_FLARE, Moves.NASTY_PLOT, Moves.TACHYON_CUTTER ],
[Species.KYOGRE]: [ Moves.RECOVER, Moves.HURRICANE, Moves.FLIP_TURN, Moves.WILDBOLT_STORM ], [Species.KYOGRE]: [ Moves.RECOVER, Moves.HURRICANE, Moves.FREEZY_FROST, Moves.WILDBOLT_STORM ],
[Species.GROUDON]: [ Moves.STONE_AXE, Moves.SOLAR_BLADE, Moves.MORNING_SUN, Moves.SACRED_FIRE ], [Species.GROUDON]: [ Moves.STONE_AXE, Moves.SOLAR_BLADE, Moves.MORNING_SUN, Moves.SACRED_FIRE ],
[Species.RAYQUAZA]: [ Moves.V_CREATE, Moves.DRAGON_DARTS, Moves.CORE_ENFORCER, Moves.OBLIVION_WING ], [Species.RAYQUAZA]: [ Moves.V_CREATE, Moves.DRAGON_DARTS, Moves.CORE_ENFORCER, Moves.OBLIVION_WING ],
[Species.JIRACHI]: [ Moves.TACHYON_CUTTER, Moves.TRIPLE_ARROWS, Moves.ROCK_SLIDE, Moves.SHELL_SMASH ], [Species.JIRACHI]: [ Moves.TACHYON_CUTTER, Moves.TRIPLE_ARROWS, Moves.ROCK_SLIDE, Moves.SHELL_SMASH ],

View File

@ -0,0 +1,574 @@
import { Abilities } from "#app/enums/abilities";
import { Species } from "#app/enums/species";
export const starterPassiveAbilities = {
[Species.BULBASAUR]: Abilities.GRASSY_SURGE,
[Species.CHARMANDER]: Abilities.BEAST_BOOST,
[Species.SQUIRTLE]: Abilities.STURDY,
[Species.CATERPIE]: Abilities.MAGICIAN,
[Species.WEEDLE]: Abilities.TINTED_LENS,
[Species.PIDGEY]: Abilities.SHEER_FORCE,
[Species.RATTATA]: Abilities.STRONG_JAW,
[Species.SPEAROW]: Abilities.MOXIE,
[Species.EKANS]: Abilities.REGENERATOR,
[Species.SANDSHREW]: Abilities.TOUGH_CLAWS,
[Species.NIDORAN_F]: Abilities.FLARE_BOOST,
[Species.NIDORAN_M]: Abilities.GUTS,
[Species.VULPIX]: Abilities.FUR_COAT,
[Species.ZUBAT]: Abilities.INTIMIDATE,
[Species.ODDISH]: Abilities.TRIAGE,
[Species.PARAS]: Abilities.TRIAGE,
[Species.VENONAT]: Abilities.SIMPLE,
[Species.DIGLETT]: Abilities.STURDY,
[Species.MEOWTH]: Abilities.TOUGH_CLAWS,
[Species.PSYDUCK]: Abilities.SIMPLE,
[Species.MANKEY]: Abilities.IRON_FIST,
[Species.GROWLITHE]: Abilities.SPEED_BOOST,
[Species.POLIWAG]: Abilities.NO_GUARD,
[Species.ABRA]: Abilities.PSYCHIC_SURGE,
[Species.MACHOP]: Abilities.QUICK_FEET,
[Species.BELLSPROUT]: Abilities.FLOWER_GIFT,
[Species.TENTACOOL]: Abilities.TOXIC_CHAIN,
[Species.GEODUDE]: Abilities.DRY_SKIN,
[Species.PONYTA]: Abilities.MAGIC_GUARD,
[Species.SLOWPOKE]: Abilities.UNAWARE,
[Species.MAGNEMITE]: Abilities.LEVITATE,
[Species.FARFETCHD]: Abilities.SNIPER,
[Species.DODUO]: Abilities.PARENTAL_BOND,
[Species.SEEL]: Abilities.WATER_BUBBLE,
[Species.GRIMER]: Abilities.WATER_ABSORB,
[Species.SHELLDER]: Abilities.ICE_SCALES,
[Species.GASTLY]: Abilities.SHADOW_SHIELD,
[Species.ONIX]: Abilities.ROCKY_PAYLOAD,
[Species.DROWZEE]: Abilities.MAGICIAN,
[Species.KRABBY]: Abilities.THERMAL_EXCHANGE,
[Species.VOLTORB]: Abilities.TRANSISTOR,
[Species.EXEGGCUTE]: Abilities.RIPEN,
[Species.CUBONE]: Abilities.PARENTAL_BOND,
[Species.LICKITUNG]: Abilities.CHEEK_POUCH,
[Species.KOFFING]: Abilities.PARENTAL_BOND,
[Species.RHYHORN]: Abilities.FILTER,
[Species.TANGELA]: Abilities.SEED_SOWER,
[Species.KANGASKHAN]: Abilities.GUTS,
[Species.HORSEA]: Abilities.DRAGONS_MAW,
[Species.GOLDEEN]: Abilities.MULTISCALE,
[Species.STARYU]: Abilities.REGENERATOR,
[Species.SCYTHER]: Abilities.TINTED_LENS,
[Species.PINSIR]: Abilities.TINTED_LENS,
[Species.TAUROS]: Abilities.STAMINA,
[Species.MAGIKARP]: Abilities.MULTISCALE,
[Species.LAPRAS]: Abilities.LIGHTNING_ROD,
[Species.DITTO]: Abilities.ADAPTABILITY,
[Species.EEVEE]: Abilities.PICKUP,
[Species.PORYGON]: Abilities.PROTEAN,
[Species.OMANYTE]: Abilities.STURDY,
[Species.KABUTO]: Abilities.TOUGH_CLAWS,
[Species.AERODACTYL]: Abilities.ORICHALCUM_PULSE,
[Species.ARTICUNO]: Abilities.SNOW_WARNING,
[Species.ZAPDOS]: Abilities.DRIZZLE,
[Species.MOLTRES]: Abilities.DROUGHT,
[Species.DRATINI]: Abilities.AERILATE,
[Species.MEWTWO]: Abilities.NEUROFORCE,
[Species.MEW]: Abilities.PROTEAN,
[Species.CHIKORITA]: Abilities.THICK_FAT,
[Species.CYNDAQUIL]: Abilities.DROUGHT,
[Species.TOTODILE]: Abilities.TOUGH_CLAWS,
[Species.SENTRET]: Abilities.PICKUP,
[Species.HOOTHOOT]: Abilities.AERILATE,
[Species.LEDYBA]: Abilities.PRANKSTER,
[Species.SPINARAK]: Abilities.PRANKSTER,
[Species.CHINCHOU]: Abilities.WATER_BUBBLE,
[Species.PICHU]: Abilities.ELECTRIC_SURGE,
[Species.CLEFFA]: Abilities.ANALYTIC,
[Species.IGGLYBUFF]: Abilities.HUGE_POWER,
[Species.TOGEPI]: Abilities.PIXILATE,
[Species.NATU]: Abilities.TINTED_LENS,
[Species.MAREEP]: Abilities.ELECTROMORPHOSIS,
[Species.HOPPIP]: Abilities.FLUFFY,
[Species.AIPOM]: Abilities.SCRAPPY,
[Species.SUNKERN]: Abilities.DROUGHT,
[Species.YANMA]: Abilities.SHEER_FORCE,
[Species.WOOPER]: Abilities.COMATOSE,
[Species.MURKROW]: Abilities.DARK_AURA,
[Species.MISDREAVUS]: Abilities.BEADS_OF_RUIN,
[Species.UNOWN]: Abilities.PICKUP,
[Species.GIRAFARIG]: Abilities.PARENTAL_BOND,
[Species.PINECO]: Abilities.IRON_BARBS,
[Species.DUNSPARCE]: Abilities.UNAWARE,
[Species.GLIGAR]: Abilities.TOXIC_BOOST,
[Species.SNUBBULL]: Abilities.PIXILATE,
[Species.QWILFISH]: Abilities.TOXIC_DEBRIS,
[Species.SHUCKLE]: Abilities.HARVEST,
[Species.HERACROSS]: Abilities.TECHNICIAN,
[Species.SNEASEL]: Abilities.TOUGH_CLAWS,
[Species.TEDDIURSA]: Abilities.THICK_FAT,
[Species.SLUGMA]: Abilities.DESOLATE_LAND,
[Species.SWINUB]: Abilities.SLUSH_RUSH,
[Species.CORSOLA]: Abilities.STORM_DRAIN,
[Species.REMORAID]: Abilities.SIMPLE,
[Species.DELIBIRD]: Abilities.HUGE_POWER,
[Species.SKARMORY]: Abilities.LIGHTNING_ROD,
[Species.HOUNDOUR]: Abilities.DROUGHT,
[Species.PHANPY]: Abilities.SPEED_BOOST,
[Species.STANTLER]: Abilities.SPEED_BOOST,
[Species.SMEARGLE]: Abilities.PRANKSTER,
[Species.TYROGUE]: Abilities.MOXIE,
[Species.SMOOCHUM]: Abilities.PSYCHIC_SURGE,
[Species.ELEKID]: Abilities.SHEER_FORCE,
[Species.MAGBY]: Abilities.CONTRARY,
[Species.MILTANK]: Abilities.STAMINA,
[Species.RAIKOU]: Abilities.TRANSISTOR,
[Species.ENTEI]: Abilities.MOXIE,
[Species.SUICUNE]: Abilities.UNAWARE,
[Species.LARVITAR]: Abilities.SAND_RUSH,
[Species.LUGIA]: Abilities.DELTA_STREAM,
[Species.HO_OH]: Abilities.MAGIC_GUARD,
[Species.CELEBI]: Abilities.PSYCHIC_SURGE,
[Species.TREECKO]: Abilities.TINTED_LENS,
[Species.TORCHIC]: Abilities.RECKLESS,
[Species.MUDKIP]: Abilities.DRIZZLE,
[Species.POOCHYENA]: Abilities.TOUGH_CLAWS,
[Species.ZIGZAGOON]: Abilities.RUN_AWAY,
[Species.WURMPLE]: Abilities.SIMPLE,
[Species.LOTAD]: Abilities.DRIZZLE,
[Species.SEEDOT]: Abilities.SHARPNESS,
[Species.TAILLOW]: Abilities.AERILATE,
[Species.WINGULL]: Abilities.SWIFT_SWIM,
[Species.RALTS]: Abilities.PSYCHIC_SURGE,
[Species.SURSKIT]: Abilities.WATER_BUBBLE,
[Species.SHROOMISH]: Abilities.GUTS,
[Species.SLAKOTH]: Abilities.GUTS,
[Species.NINCADA]: Abilities.MAGIC_GUARD,
[Species.WHISMUR]: Abilities.PUNK_ROCK,
[Species.MAKUHITA]: Abilities.STAMINA,
[Species.AZURILL]: Abilities.MISTY_SURGE,
[Species.NOSEPASS]: Abilities.LEVITATE,
[Species.SKITTY]: Abilities.SCRAPPY,
[Species.SABLEYE]: Abilities.UNNERVE,
[Species.MAWILE]: Abilities.UNNERVE,
[Species.ARON]: Abilities.EARTH_EATER,
[Species.MEDITITE]: Abilities.MINDS_EYE,
[Species.ELECTRIKE]: Abilities.ELECTRIC_SURGE,
[Species.PLUSLE]: Abilities.POWER_SPOT,
[Species.MINUN]: Abilities.POWER_SPOT,
[Species.VOLBEAT]: Abilities.HONEY_GATHER,
[Species.ILLUMISE]: Abilities.HONEY_GATHER,
[Species.GULPIN]: Abilities.EARTH_EATER,
[Species.CARVANHA]: Abilities.SHEER_FORCE,
[Species.WAILMER]: Abilities.LEVITATE,
[Species.NUMEL]: Abilities.FUR_COAT,
[Species.TORKOAL]: Abilities.ANALYTIC,
[Species.SPOINK]: Abilities.PSYCHIC_SURGE,
[Species.SPINDA]: Abilities.SIMPLE,
[Species.TRAPINCH]: Abilities.ADAPTABILITY,
[Species.CACNEA]: Abilities.SAND_RUSH,
[Species.SWABLU]: Abilities.ADAPTABILITY,
[Species.ZANGOOSE]: Abilities.POISON_HEAL,
[Species.SEVIPER]: Abilities.MULTISCALE,
[Species.LUNATONE]: Abilities.SHADOW_SHIELD,
[Species.SOLROCK]: Abilities.DROUGHT,
[Species.BARBOACH]: Abilities.SIMPLE,
[Species.CORPHISH]: Abilities.TOUGH_CLAWS,
[Species.BALTOY]: Abilities.WELL_BAKED_BODY,
[Species.LILEEP]: Abilities.SEED_SOWER,
[Species.ANORITH]: Abilities.WATER_ABSORB,
[Species.FEEBAS]: Abilities.MAGIC_GUARD,
[Species.CASTFORM]: Abilities.ADAPTABILITY,
[Species.KECLEON]: Abilities.ADAPTABILITY,
[Species.SHUPPET]: Abilities.SHADOW_SHIELD,
[Species.DUSKULL]: Abilities.UNNERVE,
[Species.TROPIUS]: Abilities.RIPEN,
[Species.ABSOL]: Abilities.SHARPNESS,
[Species.WYNAUT]: Abilities.STURDY,
[Species.SNORUNT]: Abilities.SNOW_WARNING,
[Species.SPHEAL]: Abilities.UNAWARE,
[Species.CLAMPERL]: Abilities.DRIZZLE,
[Species.RELICANTH]: Abilities.PRIMORDIAL_SEA,
[Species.LUVDISC]: Abilities.MULTISCALE,
[Species.BAGON]: Abilities.DRAGONS_MAW,
[Species.BELDUM]: Abilities.LEVITATE,
[Species.REGIROCK]: Abilities.SAND_STREAM,
[Species.REGICE]: Abilities.SNOW_WARNING,
[Species.REGISTEEL]: Abilities.FILTER,
[Species.LATIAS]: Abilities.PRISM_ARMOR,
[Species.LATIOS]: Abilities.TINTED_LENS,
[Species.KYOGRE]: Abilities.MOLD_BREAKER,
[Species.GROUDON]: Abilities.TURBOBLAZE,
[Species.RAYQUAZA]: Abilities.UNNERVE,
[Species.JIRACHI]: Abilities.COMATOSE,
[Species.DEOXYS]: Abilities.PROTEAN,
[Species.TURTWIG]: Abilities.THICK_FAT,
[Species.CHIMCHAR]: Abilities.BEAST_BOOST,
[Species.PIPLUP]: Abilities.DRIZZLE,
[Species.STARLY]: Abilities.ROCK_HEAD,
[Species.BIDOOF]: Abilities.SAP_SIPPER,
[Species.KRICKETOT]: Abilities.SHARPNESS,
[Species.SHINX]: Abilities.SPEED_BOOST,
[Species.BUDEW]: Abilities.GRASSY_SURGE,
[Species.CRANIDOS]: Abilities.ROCK_HEAD,
[Species.SHIELDON]: Abilities.EARTH_EATER,
[Species.BURMY]: Abilities.STURDY,
[Species.COMBEE]: Abilities.INTIMIDATE,
[Species.PACHIRISU]: Abilities.HONEY_GATHER,
[Species.BUIZEL]: Abilities.MOXIE,
[Species.CHERUBI]: Abilities.ORICHALCUM_PULSE,
[Species.SHELLOS]: Abilities.REGENERATOR,
[Species.DRIFLOON]: Abilities.MAGIC_GUARD,
[Species.BUNEARY]: Abilities.ADAPTABILITY,
[Species.GLAMEOW]: Abilities.INTIMIDATE,
[Species.CHINGLING]: Abilities.PUNK_ROCK,
[Species.STUNKY]: Abilities.NEUTRALIZING_GAS,
[Species.BRONZOR]: Abilities.BULLETPROOF,
[Species.BONSLY]: Abilities.SAP_SIPPER,
[Species.MIME_JR]: Abilities.OPPORTUNIST,
[Species.HAPPINY]: Abilities.FUR_COAT,
[Species.CHATOT]: Abilities.PUNK_ROCK,
[Species.SPIRITOMB]: Abilities.VESSEL_OF_RUIN,
[Species.GIBLE]: Abilities.SAND_STREAM,
[Species.MUNCHLAX]: Abilities.RIPEN,
[Species.RIOLU]: Abilities.MINDS_EYE,
[Species.HIPPOPOTAS]: Abilities.UNAWARE,
[Species.SKORUPI]: Abilities.SUPER_LUCK,
[Species.CROAGUNK]: Abilities.MOXIE,
[Species.CARNIVINE]: Abilities.ARENA_TRAP,
[Species.FINNEON]: Abilities.WATER_BUBBLE,
[Species.MANTYKE]: Abilities.UNAWARE,
[Species.SNOVER]: Abilities.THICK_FAT,
[Species.ROTOM]: Abilities.HADRON_ENGINE,
[Species.UXIE]: Abilities.UNAWARE,
[Species.MESPRIT]: Abilities.MOODY,
[Species.AZELF]: Abilities.NEUROFORCE,
[Species.DIALGA]: Abilities.LEVITATE,
[Species.PALKIA]: Abilities.SPEED_BOOST,
[Species.HEATRAN]: Abilities.EARTH_EATER,
[Species.REGIGIGAS]: Abilities.SCRAPPY,
[Species.GIRATINA]: Abilities.SHADOW_SHIELD,
[Species.CRESSELIA]: Abilities.SHADOW_SHIELD,
[Species.PHIONE]: Abilities.SIMPLE,
[Species.MANAPHY]: Abilities.PRIMORDIAL_SEA,
[Species.DARKRAI]: Abilities.UNNERVE,
[Species.SHAYMIN]: Abilities.WIND_RIDER,
[Species.ARCEUS]: Abilities.ADAPTABILITY,
[Species.VICTINI]: Abilities.SHEER_FORCE,
[Species.SNIVY]: Abilities.MULTISCALE,
[Species.TEPIG]: Abilities.ROCK_HEAD,
[Species.OSHAWOTT]: Abilities.INTREPID_SWORD,
[Species.PATRAT]: Abilities.NO_GUARD,
[Species.LILLIPUP]: Abilities.FUR_COAT,
[Species.PURRLOIN]: Abilities.PICKUP,
[Species.PANSAGE]: Abilities.WELL_BAKED_BODY,
[Species.PANSEAR]: Abilities.WATER_ABSORB,
[Species.PANPOUR]: Abilities.SAP_SIPPER,
[Species.MUNNA]: Abilities.NEUTRALIZING_GAS,
[Species.PIDOVE]: Abilities.SNIPER,
[Species.BLITZLE]: Abilities.ELECTRIC_SURGE,
[Species.ROGGENROLA]: Abilities.SOLID_ROCK,
[Species.WOOBAT]: Abilities.OPPORTUNIST,
[Species.DRILBUR]: Abilities.SAND_STREAM,
[Species.AUDINO]: Abilities.FRIEND_GUARD,
[Species.TIMBURR]: Abilities.ROCKY_PAYLOAD,
[Species.TYMPOLE]: Abilities.POISON_HEAL,
[Species.THROH]: Abilities.STAMINA,
[Species.SAWK]: Abilities.SCRAPPY,
[Species.SEWADDLE]: Abilities.SHARPNESS,
[Species.VENIPEDE]: Abilities.STAMINA,
[Species.COTTONEE]: Abilities.FLUFFY,
[Species.PETILIL]: Abilities.SIMPLE,
[Species.BASCULIN]: Abilities.SUPREME_OVERLORD,
[Species.SANDILE]: Abilities.TOUGH_CLAWS,
[Species.DARUMAKA]: Abilities.GORILLA_TACTICS,
[Species.MARACTUS]: Abilities.WELL_BAKED_BODY,
[Species.DWEBBLE]: Abilities.ROCKY_PAYLOAD,
[Species.SCRAGGY]: Abilities.PROTEAN,
[Species.SIGILYPH]: Abilities.FLARE_BOOST,
[Species.YAMASK]: Abilities.PURIFYING_SALT,
[Species.TIRTOUGA]: Abilities.WATER_ABSORB,
[Species.ARCHEN]: Abilities.MULTISCALE,
[Species.TRUBBISH]: Abilities.NEUTRALIZING_GAS,
[Species.ZORUA]: Abilities.DARK_AURA,
[Species.MINCCINO]: Abilities.FUR_COAT,
[Species.GOTHITA]: Abilities.UNNERVE,
[Species.SOLOSIS]: Abilities.PSYCHIC_SURGE,
[Species.DUCKLETT]: Abilities.DRIZZLE,
[Species.VANILLITE]: Abilities.SLUSH_RUSH,
[Species.DEERLING]: Abilities.FUR_COAT,
[Species.EMOLGA]: Abilities.TRANSISTOR,
[Species.KARRABLAST]: Abilities.QUICK_DRAW,
[Species.FOONGUS]: Abilities.THICK_FAT,
[Species.FRILLISH]: Abilities.POISON_HEAL,
[Species.ALOMOMOLA]: Abilities.MULTISCALE,
[Species.JOLTIK]: Abilities.TRANSISTOR,
[Species.FERROSEED]: Abilities.ROUGH_SKIN,
[Species.KLINK]: Abilities.STEELY_SPIRIT,
[Species.TYNAMO]: Abilities.POISON_HEAL,
[Species.ELGYEM]: Abilities.PRISM_ARMOR,
[Species.LITWICK]: Abilities.SOUL_HEART,
[Species.AXEW]: Abilities.DRAGONS_MAW,
[Species.CUBCHOO]: Abilities.TOUGH_CLAWS,
[Species.CRYOGONAL]: Abilities.SNOW_WARNING,
[Species.SHELMET]: Abilities.PROTEAN,
[Species.STUNFISK]: Abilities.STORM_DRAIN,
[Species.MIENFOO]: Abilities.NO_GUARD,
[Species.DRUDDIGON]: Abilities.INTIMIDATE,
[Species.GOLETT]: Abilities.SHADOW_SHIELD,
[Species.PAWNIARD]: Abilities.SWORD_OF_RUIN,
[Species.BOUFFALANT]: Abilities.ROCK_HEAD,
[Species.RUFFLET]: Abilities.SPEED_BOOST,
[Species.VULLABY]: Abilities.THICK_FAT,
[Species.HEATMOR]: Abilities.CONTRARY,
[Species.DURANT]: Abilities.COMPOUND_EYES,
[Species.DEINO]: Abilities.PARENTAL_BOND,
[Species.LARVESTA]: Abilities.DROUGHT,
[Species.COBALION]: Abilities.INTREPID_SWORD,
[Species.TERRAKION]: Abilities.ROCKY_PAYLOAD,
[Species.VIRIZION]: Abilities.SHARPNESS,
[Species.TORNADUS]: Abilities.DRIZZLE,
[Species.THUNDURUS]: Abilities.DRIZZLE,
[Species.RESHIRAM]: Abilities.ORICHALCUM_PULSE,
[Species.ZEKROM]: Abilities.HADRON_ENGINE,
[Species.LANDORUS]: Abilities.STORM_DRAIN,
[Species.KYUREM]: Abilities.SNOW_WARNING,
[Species.KELDEO]: Abilities.GRIM_NEIGH,
[Species.MELOETTA]: Abilities.MINDS_EYE,
[Species.GENESECT]: Abilities.PROTEAN,
[Species.CHESPIN]: Abilities.DAUNTLESS_SHIELD,
[Species.FENNEKIN]: Abilities.PSYCHIC_SURGE,
[Species.FROAKIE]: Abilities.STAKEOUT,
[Species.BUNNELBY]: Abilities.GUTS,
[Species.FLETCHLING]: Abilities.MAGIC_GUARD,
[Species.SCATTERBUG]: Abilities.PRANKSTER,
[Species.LITLEO]: Abilities.BEAST_BOOST,
[Species.FLABEBE]: Abilities.GRASSY_SURGE,
[Species.SKIDDO]: Abilities.SEED_SOWER,
[Species.PANCHAM]: Abilities.FUR_COAT,
[Species.FURFROU]: Abilities.FLUFFY,
[Species.ESPURR]: Abilities.FUR_COAT,
[Species.HONEDGE]: Abilities.SHARPNESS,
[Species.SPRITZEE]: Abilities.FUR_COAT,
[Species.SWIRLIX]: Abilities.WELL_BAKED_BODY,
[Species.INKAY]: Abilities.UNNERVE,
[Species.BINACLE]: Abilities.SAP_SIPPER,
[Species.SKRELP]: Abilities.DRAGONS_MAW,
[Species.CLAUNCHER]: Abilities.SWIFT_SWIM,
[Species.HELIOPTILE]: Abilities.PROTEAN,
[Species.TYRUNT]: Abilities.RECKLESS,
[Species.AMAURA]: Abilities.ICE_SCALES,
[Species.HAWLUCHA]: Abilities.MOXIE,
[Species.DEDENNE]: Abilities.PIXILATE,
[Species.CARBINK]: Abilities.SOLID_ROCK,
[Species.GOOMY]: Abilities.REGENERATOR,
[Species.KLEFKI]: Abilities.LEVITATE,
[Species.PHANTUMP]: Abilities.SHADOW_TAG,
[Species.PUMPKABOO]: Abilities.WELL_BAKED_BODY,
[Species.BERGMITE]: Abilities.ICE_SCALES,
[Species.NOIBAT]: Abilities.PUNK_ROCK,
[Species.XERNEAS]: Abilities.HARVEST,
[Species.YVELTAL]: Abilities.SOUL_HEART,
[Species.ZYGARDE]: Abilities.HUGE_POWER,
[Species.DIANCIE]: Abilities.LEVITATE,
[Species.HOOPA]: Abilities.OPPORTUNIST,
[Species.VOLCANION]: Abilities.FILTER,
[Species.ROWLET]: Abilities.SNIPER,
[Species.LITTEN]: Abilities.OPPORTUNIST,
[Species.POPPLIO]: Abilities.PUNK_ROCK,
[Species.PIKIPEK]: Abilities.TECHNICIAN,
[Species.YUNGOOS]: Abilities.TOUGH_CLAWS,
[Species.GRUBBIN]: Abilities.SPEED_BOOST,
[Species.CRABRAWLER]: Abilities.WATER_BUBBLE,
[Species.ORICORIO]: Abilities.ADAPTABILITY,
[Species.CUTIEFLY]: Abilities.TINTED_LENS,
[Species.ROCKRUFF]: Abilities.ROCKY_PAYLOAD,
[Species.WISHIWASHI]: Abilities.REGENERATOR,
[Species.MAREANIE]: Abilities.TOXIC_DEBRIS,
[Species.MUDBRAY]: Abilities.CUD_CHEW,
[Species.DEWPIDER]: Abilities.TINTED_LENS,
[Species.FOMANTIS]: Abilities.SHARPNESS,
[Species.MORELULL]: Abilities.TRIAGE,
[Species.SALANDIT]: Abilities.DRAGONS_MAW,
[Species.STUFFUL]: Abilities.SCRAPPY,
[Species.BOUNSWEET]: Abilities.MOXIE,
[Species.COMFEY]: Abilities.FRIEND_GUARD,
[Species.ORANGURU]: Abilities.POWER_SPOT,
[Species.PASSIMIAN]: Abilities.LIBERO,
[Species.WIMPOD]: Abilities.REGENERATOR,
[Species.SANDYGAST]: Abilities.SAND_SPIT,
[Species.PYUKUMUKU]: Abilities.PURIFYING_SALT,
[Species.TYPE_NULL]: Abilities.ADAPTABILITY,
[Species.MINIOR]: Abilities.STURDY,
[Species.KOMALA]: Abilities.GUTS,
[Species.TURTONATOR]: Abilities.DAUNTLESS_SHIELD,
[Species.TOGEDEMARU]: Abilities.ROUGH_SKIN,
[Species.MIMIKYU]: Abilities.TOUGH_CLAWS,
[Species.BRUXISH]: Abilities.MULTISCALE,
[Species.DRAMPA]: Abilities.THICK_FAT,
[Species.DHELMISE]: Abilities.WATER_BUBBLE,
[Species.JANGMO_O]: Abilities.DAUNTLESS_SHIELD,
[Species.TAPU_KOKO]: Abilities.TRANSISTOR,
[Species.TAPU_LELE]: Abilities.SHEER_FORCE,
[Species.TAPU_BULU]: Abilities.TRIAGE,
[Species.TAPU_FINI]: Abilities.FAIRY_AURA,
[Species.COSMOG]: Abilities.BEAST_BOOST,
[Species.NIHILEGO]: Abilities.LEVITATE,
[Species.BUZZWOLE]: Abilities.MOXIE,
[Species.PHEROMOSA]: Abilities.TINTED_LENS,
[Species.XURKITREE]: Abilities.TRANSISTOR,
[Species.CELESTEELA]: Abilities.HEATPROOF,
[Species.KARTANA]: Abilities.SHARPNESS,
[Species.GUZZLORD]: Abilities.POISON_HEAL,
[Species.NECROZMA]: Abilities.BEAST_BOOST,
[Species.MAGEARNA]: Abilities.STEELY_SPIRIT,
[Species.MARSHADOW]: Abilities.IRON_FIST,
[Species.POIPOLE]: Abilities.SHEER_FORCE,
[Species.STAKATAKA]: Abilities.SOLID_ROCK,
[Species.BLACEPHALON]: Abilities.MAGIC_GUARD,
[Species.ZERAORA]: Abilities.TOUGH_CLAWS,
[Species.MELTAN]: Abilities.STEELY_SPIRIT,
[Species.GROOKEY]: Abilities.GRASS_PELT,
[Species.SCORBUNNY]: Abilities.NO_GUARD,
[Species.SOBBLE]: Abilities.SUPER_LUCK,
[Species.SKWOVET]: Abilities.HARVEST,
[Species.ROOKIDEE]: Abilities.IRON_BARBS,
[Species.BLIPBUG]: Abilities.PSYCHIC_SURGE,
[Species.NICKIT]: Abilities.MAGICIAN,
[Species.GOSSIFLEUR]: Abilities.GRASSY_SURGE,
[Species.WOOLOO]: Abilities.SIMPLE,
[Species.CHEWTLE]: Abilities.ROCKY_PAYLOAD,
[Species.YAMPER]: Abilities.SHEER_FORCE,
[Species.ROLYCOLY]: Abilities.SOLID_ROCK,
[Species.APPLIN]: Abilities.DRAGONS_MAW,
[Species.SILICOBRA]: Abilities.SAND_RUSH,
[Species.CRAMORANT]: Abilities.LIGHTNING_ROD,
[Species.ARROKUDA]: Abilities.INTIMIDATE,
[Species.TOXEL]: Abilities.ELECTRIC_SURGE,
[Species.SIZZLIPEDE]: Abilities.SPEED_BOOST,
[Species.CLOBBOPUS]: Abilities.WATER_BUBBLE,
[Species.SINISTEA]: Abilities.SHADOW_SHIELD,
[Species.HATENNA]: Abilities.FAIRY_AURA,
[Species.IMPIDIMP]: Abilities.FUR_COAT,
[Species.MILCERY]: Abilities.REGENERATOR,
[Species.FALINKS]: Abilities.PARENTAL_BOND,
[Species.PINCURCHIN]: Abilities.ELECTROMORPHOSIS,
[Species.SNOM]: Abilities.SNOW_WARNING,
[Species.STONJOURNER]: Abilities.STURDY,
[Species.EISCUE]: Abilities.ICE_SCALES,
[Species.INDEEDEE]: Abilities.FRIEND_GUARD,
[Species.MORPEKO]: Abilities.MOODY,
[Species.CUFANT]: Abilities.EARTH_EATER,
[Species.DRACOZOLT]: Abilities.NO_GUARD,
[Species.ARCTOZOLT]: Abilities.TRANSISTOR,
[Species.DRACOVISH]: Abilities.SWIFT_SWIM,
[Species.ARCTOVISH]: Abilities.STRONG_JAW,
[Species.DURALUDON]: Abilities.STEELWORKER,
[Species.DREEPY]: Abilities.PARENTAL_BOND,
[Species.ZACIAN]: Abilities.UNNERVE,
[Species.ZAMAZENTA]: Abilities.UNNERVE,
[Species.ETERNATUS]: Abilities.NEUTRALIZING_GAS,
[Species.KUBFU]: Abilities.IRON_FIST,
[Species.ZARUDE]: Abilities.TOUGH_CLAWS,
[Species.REGIELEKI]: Abilities.ELECTRIC_SURGE,
[Species.REGIDRAGO]: Abilities.MULTISCALE,
[Species.GLASTRIER]: Abilities.FILTER,
[Species.SPECTRIER]: Abilities.SHADOW_SHIELD,
[Species.CALYREX]: Abilities.HARVEST,
[Species.ENAMORUS]: Abilities.FAIRY_AURA,
[Species.SPRIGATITO]: Abilities.MAGICIAN,
[Species.FUECOCO]: Abilities.PUNK_ROCK,
[Species.QUAXLY]: Abilities.OPPORTUNIST,
[Species.LECHONK]: Abilities.SIMPLE,
[Species.TAROUNTULA]: Abilities.HONEY_GATHER,
[Species.NYMBLE]: Abilities.GUTS,
[Species.PAWMI]: Abilities.TRANSISTOR,
[Species.TANDEMAUS]: Abilities.SCRAPPY,
[Species.FIDOUGH]: Abilities.WATER_ABSORB,
[Species.SMOLIV]: Abilities.RIPEN,
[Species.SQUAWKABILLY]: Abilities.MOXIE,
[Species.NACLI]: Abilities.SOLID_ROCK,
[Species.CHARCADET]: Abilities.PRISM_ARMOR,
[Species.TADBULB]: Abilities.STAMINA,
[Species.WATTREL]: Abilities.SHEER_FORCE,
[Species.MASCHIFF]: Abilities.STRONG_JAW,
[Species.SHROODLE]: Abilities.CORROSION,
[Species.BRAMBLIN]: Abilities.SHADOW_SHIELD,
[Species.TOEDSCOOL]: Abilities.PRANKSTER,
[Species.KLAWF]: Abilities.WATER_ABSORB,
[Species.CAPSAKID]: Abilities.PARENTAL_BOND,
[Species.RELLOR]: Abilities.PRANKSTER,
[Species.FLITTLE]: Abilities.DAZZLING,
[Species.TINKATINK]: Abilities.STEELWORKER,
[Species.WIGLETT]: Abilities.STURDY,
[Species.BOMBIRDIER]: Abilities.UNBURDEN,
[Species.FINIZEN]: Abilities.IRON_FIST,
[Species.VAROOM]: Abilities.LEVITATE,
[Species.CYCLIZAR]: Abilities.PROTEAN,
[Species.ORTHWORM]: Abilities.REGENERATOR,
[Species.GLIMMET]: Abilities.LEVITATE,
[Species.GREAVARD]: Abilities.FUR_COAT,
[Species.FLAMIGO]: Abilities.MOXIE,
[Species.CETODDLE]: Abilities.ICE_SCALES,
[Species.VELUZA]: Abilities.SUPER_LUCK,
[Species.DONDOZO]: Abilities.PARENTAL_BOND,
[Species.TATSUGIRI]: Abilities.ADAPTABILITY,
[Species.GREAT_TUSK]: Abilities.INTIMIDATE,
[Species.SCREAM_TAIL]: Abilities.UNAWARE,
[Species.BRUTE_BONNET]: Abilities.CHLOROPHYLL,
[Species.FLUTTER_MANE]: Abilities.DAZZLING,
[Species.SLITHER_WING]: Abilities.SCRAPPY,
[Species.SANDY_SHOCKS]: Abilities.EARTH_EATER,
[Species.IRON_TREADS]: Abilities.STEELY_SPIRIT,
[Species.IRON_BUNDLE]: Abilities.SNOW_WARNING,
[Species.IRON_HANDS]: Abilities.IRON_FIST,
[Species.IRON_JUGULIS]: Abilities.LIGHTNING_ROD,
[Species.IRON_MOTH]: Abilities.LEVITATE,
[Species.IRON_THORNS]: Abilities.SAND_STREAM,
[Species.FRIGIBAX]: Abilities.SNOW_WARNING,
[Species.GIMMIGHOUL]: Abilities.HONEY_GATHER,
[Species.WO_CHIEN]: Abilities.VESSEL_OF_RUIN,
[Species.CHIEN_PAO]: Abilities.INTIMIDATE,
[Species.TING_LU]: Abilities.STAMINA,
[Species.CHI_YU]: Abilities.BERSERK,
[Species.ROARING_MOON]: Abilities.TOUGH_CLAWS,
[Species.IRON_VALIANT]: Abilities.ADAPTABILITY,
[Species.KORAIDON]: Abilities.OPPORTUNIST,
[Species.MIRAIDON]: Abilities.OPPORTUNIST,
[Species.WALKING_WAKE]: Abilities.BEAST_BOOST,
[Species.IRON_LEAVES]: Abilities.SHARPNESS,
[Species.POLTCHAGEIST]: Abilities.TRIAGE,
[Species.OKIDOGI]: Abilities.FUR_COAT,
[Species.MUNKIDORI]: Abilities.NEUROFORCE,
[Species.FEZANDIPITI]: Abilities.LEVITATE,
[Species.OGERPON]: Abilities.OPPORTUNIST,
[Species.GOUGING_FIRE]: Abilities.BEAST_BOOST,
[Species.RAGING_BOLT]: Abilities.BEAST_BOOST,
[Species.IRON_BOULDER]: Abilities.SHARPNESS,
[Species.IRON_CROWN]: Abilities.SHARPNESS,
[Species.TERAPAGOS]: Abilities.SOUL_HEART,
[Species.PECHARUNT]: Abilities.TOXIC_CHAIN,
[Species.ALOLA_RATTATA]: Abilities.ADAPTABILITY,
[Species.ALOLA_SANDSHREW]: Abilities.ICE_SCALES,
[Species.ALOLA_VULPIX]: Abilities.SHEER_FORCE,
[Species.ALOLA_DIGLETT]: Abilities.STURDY,
[Species.ALOLA_MEOWTH]: Abilities.DARK_AURA,
[Species.ALOLA_GEODUDE]: Abilities.DRY_SKIN,
[Species.ALOLA_GRIMER]: Abilities.TOXIC_DEBRIS,
[Species.ETERNAL_FLOETTE]: Abilities.MAGIC_GUARD,
[Species.GALAR_MEOWTH]: Abilities.STEELWORKER,
[Species.GALAR_PONYTA]: Abilities.MOXIE,
[Species.GALAR_SLOWPOKE]: Abilities.UNAWARE,
[Species.GALAR_FARFETCHD]: Abilities.INTREPID_SWORD,
[Species.GALAR_ARTICUNO]: Abilities.SERENE_GRACE,
[Species.GALAR_ZAPDOS]: Abilities.TOUGH_CLAWS,
[Species.GALAR_MOLTRES]: Abilities.DARK_AURA,
[Species.GALAR_CORSOLA]: Abilities.SHADOW_SHIELD,
[Species.GALAR_ZIGZAGOON]: Abilities.POISON_HEAL,
[Species.GALAR_DARUMAKA]: Abilities.FLASH_FIRE,
[Species.GALAR_YAMASK]: Abilities.TABLETS_OF_RUIN,
[Species.GALAR_STUNFISK]: Abilities.ARENA_TRAP,
[Species.HISUI_GROWLITHE]: Abilities.RECKLESS,
[Species.HISUI_VOLTORB]: Abilities.TRANSISTOR,
[Species.HISUI_QWILFISH]: Abilities.MERCILESS,
[Species.HISUI_SNEASEL]: Abilities.SCRAPPY,
[Species.HISUI_ZORUA]: Abilities.ADAPTABILITY,
[Species.PALDEA_TAUROS]: Abilities.ADAPTABILITY,
[Species.PALDEA_WOOPER]: Abilities.THICK_FAT,
[Species.BLOODMOON_URSALUNA]: Abilities.BERSERK
};

View File

@ -1,16 +1,18 @@
import { Gender } from "./gender"; import { Gender } from "#app/data/gender";
import { PokeballType } from "./pokeball"; import { PokeballType } from "#app/data/pokeball";
import Pokemon from "../field/pokemon"; import Pokemon from "#app/field/pokemon";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import { Type } from "./type"; import { Type } from "#app/data/type";
import * as Utils from "../utils"; import * as Utils from "#app/utils";
import { SpeciesFormKey } from "./pokemon-species"; import { WeatherType } from "#app/data/weather";
import { WeatherType } from "./weather"; import { Nature } from "#app/data/nature";
import { Nature } from "./nature";
import { Biome } from "#enums/biome"; import { Biome } from "#enums/biome";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import { TimeOfDay } from "#enums/time-of-day"; import { TimeOfDay } from "#enums/time-of-day";
import { DamageMoneyRewardModifier, ExtraModifierModifier, MoneyMultiplierModifier } from "#app/modifier/modifier";
import { SpeciesFormKey } from "#enums/species-form-key";
export enum SpeciesWildEvolutionDelay { export enum SpeciesWildEvolutionDelay {
NONE, NONE,
@ -1647,8 +1649,14 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.FROSMOTH, 1, null, new SpeciesFriendshipEvolutionCondition(90, p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT), SpeciesWildEvolutionDelay.MEDIUM) new SpeciesEvolution(Species.FROSMOTH, 1, null, new SpeciesFriendshipEvolutionCondition(90, p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT), SpeciesWildEvolutionDelay.MEDIUM)
], ],
[Species.GIMMIGHOUL]: [ [Species.GIMMIGHOUL]: [
new SpeciesFormEvolution(Species.GHOLDENGO, "chest", "", 1, null, new SpeciesEvolutionCondition( p => p.evoCounter > 9 ), SpeciesWildEvolutionDelay.VERY_LONG), new SpeciesFormEvolution(Species.GHOLDENGO, "chest", "", 1, null, new SpeciesEvolutionCondition(p => p.evoCounter
new SpeciesFormEvolution(Species.GHOLDENGO, "roaming", "", 1, null, new SpeciesEvolutionCondition( p => p.evoCounter > 9 ), SpeciesWildEvolutionDelay.VERY_LONG) + p.getHeldItems().filter(m => m instanceof DamageMoneyRewardModifier).length
+ p.scene.findModifiers(m => m instanceof MoneyMultiplierModifier
|| m instanceof ExtraModifierModifier).length > 9), SpeciesWildEvolutionDelay.VERY_LONG),
new SpeciesFormEvolution(Species.GHOLDENGO, "roaming", "", 1, null, new SpeciesEvolutionCondition(p => p.evoCounter
+ p.getHeldItems().filter(m => m instanceof DamageMoneyRewardModifier).length
+ p.scene.findModifiers(m => m instanceof MoneyMultiplierModifier
|| m instanceof ExtraModifierModifier).length > 9), SpeciesWildEvolutionDelay.VERY_LONG)
] ]
}; };

53
src/data/balance/rates.ts Normal file
View File

@ -0,0 +1,53 @@
/**
* Rates for shinies and other random properties are defined in this file.
* CHANCE is defined as x/65536
* RATE is defined as 1/x
*/
// #region Encounterable properties
/** `64/65536 -> 1/1024` */
export const BASE_SHINY_CHANCE = 64;
/** `256/65536 -> 1/256` */
export const BASE_HIDDEN_ABILITY_CHANCE = 256;
// #region Egg properties
// Threshold x at which a gacha egg is determined to be a certain tier
// Specifically, the tier is determined by the highest threshold a random value between 0-255 meets or exceeds
// Legendary Up Gacha raises these thresholds by 1, thereby giving Legendary eggs 2/256 chance
export const GACHA_DEFAULT_COMMON_EGG_THRESHOLD = 52; // Default 204/256 chance, 203/256 chance in Legendary Up Gacha
export const GACHA_DEFAULT_RARE_EGG_THRESHOLD = 8; // Default 44/256 chance
export const GACHA_DEFAULT_EPIC_EGG_THRESHOLD = 1; // Default 7/256 chance, leaving Legendary as 1/256 chance
export const GACHA_LEGENDARY_UP_THRESHOLD_OFFSET = 1; // The offset to threshold for Legendary Up gacha eggs. +x/256 Legendary Egg chance, -x/256 Common Egg chance
// The number of eggs without finding a certain tier egg it takes for egg pity to kick in and that tier to be forced
// These numbers are roughly the 80% mark. That is, 80% of the time you'll get an egg before this gets triggered.
export const EGG_PITY_LEGENDARY_THRESHOLD = 412;
export const EGG_PITY_EPIC_THRESHOLD = 59;
export const EGG_PITY_RARE_THRESHOLD = 9;
// Waves to hatch an egg of a given tier
export const HATCH_WAVES_COMMON_EGG = 10;
export const HATCH_WAVES_RARE_EGG = 25;
export const HATCH_WAVES_EPIC_EGG = 50;
export const HATCH_WAVES_LEGENDARY_EGG = 100;
export const HATCH_WAVES_MANAPHY_EGG = 50;
// Rates for specific random properties in 1/x
export const GACHA_DEFAULT_SHINY_RATE = 128;
export const GACHA_SHINY_UP_SHINY_RATE = 64;
export const SAME_SPECIES_EGG_SHINY_RATE = 12;
export const SAME_SPECIES_EGG_HA_RATE = 8;
export const MANAPHY_EGG_MANAPHY_RATE = 8;
export const GACHA_EGG_HA_RATE = 192;
// 1/x for legendary eggs, 1/x*2 for epic eggs, 1/x*4 for rare eggs, and 1/x*8 for common eggs
export const GACHA_DEFAULT_RARE_EGGMOVE_RATE = 6;
export const SAME_SPECIES_EGG_RARE_EGGMOVE_RATE = 3;
export const GACHA_MOVE_UP_RARE_EGGMOVE_RATE = 3;
// #region Variant properties
// The chance x/10 of a shiny being a variant, then of being specifically an epic variant
export const SHINY_VARIANT_CHANCE = 4;
export const SHINY_EPIC_CHANCE = 1;

View File

@ -0,0 +1,671 @@
import { Species } from "#enums/species";
export const POKERUS_STARTER_COUNT = 5;
/**
* Function to get the cumulative friendship threshold at which a candy is earned
* @param starterCost The cost of the starter, found in {@linkcode speciesStarterCosts}
* @returns aforementioned threshold
*/
export function getStarterValueFriendshipCap(starterCost: number): number {
switch (starterCost) {
case 1:
return 20;
case 2:
return 40;
case 3:
return 60;
case 4:
return 100;
case 5:
return 140;
case 6:
return 200;
case 7:
return 280;
case 8:
case 9:
return 450;
default:
return 600;
}
}
export const speciesStarterCosts = {
[Species.BULBASAUR]: 3,
[Species.CHARMANDER]: 3,
[Species.SQUIRTLE]: 3,
[Species.CATERPIE]: 2,
[Species.WEEDLE]: 1,
[Species.PIDGEY]: 1,
[Species.RATTATA]: 1,
[Species.SPEAROW]: 1,
[Species.EKANS]: 2,
[Species.PIKACHU]: 3,
[Species.SANDSHREW]: 2,
[Species.NIDORAN_F]: 3,
[Species.NIDORAN_M]: 3,
[Species.CLEFAIRY]: 3,
[Species.VULPIX]: 3,
[Species.JIGGLYPUFF]: 2,
[Species.ZUBAT]: 3,
[Species.ODDISH]: 3,
[Species.PARAS]: 2,
[Species.VENONAT]: 2,
[Species.DIGLETT]: 2,
[Species.MEOWTH]: 3,
[Species.PSYDUCK]: 2,
[Species.MANKEY]: 4,
[Species.GROWLITHE]: 4,
[Species.POLIWAG]: 2,
[Species.ABRA]: 4,
[Species.MACHOP]: 3,
[Species.BELLSPROUT]: 2,
[Species.TENTACOOL]: 3,
[Species.GEODUDE]: 3,
[Species.PONYTA]: 2,
[Species.SLOWPOKE]: 3,
[Species.MAGNEMITE]: 4,
[Species.FARFETCHD]: 2,
[Species.DODUO]: 3,
[Species.SEEL]: 1,
[Species.GRIMER]: 2,
[Species.SHELLDER]: 5,
[Species.GASTLY]: 4,
[Species.ONIX]: 3,
[Species.DROWZEE]: 2,
[Species.KRABBY]: 3,
[Species.VOLTORB]: 2,
[Species.EXEGGCUTE]: 3,
[Species.CUBONE]: 3,
[Species.HITMONLEE]: 4,
[Species.HITMONCHAN]: 4,
[Species.LICKITUNG]: 3,
[Species.KOFFING]: 2,
[Species.RHYHORN]: 3,
[Species.CHANSEY]: 3,
[Species.TANGELA]: 3,
[Species.KANGASKHAN]: 4,
[Species.HORSEA]: 3,
[Species.GOLDEEN]: 2,
[Species.STARYU]: 3,
[Species.MR_MIME]: 3,
[Species.SCYTHER]: 5,
[Species.JYNX]: 4,
[Species.ELECTABUZZ]: 4,
[Species.MAGMAR]: 4,
[Species.PINSIR]: 4,
[Species.TAUROS]: 4,
[Species.MAGIKARP]: 4,
[Species.LAPRAS]: 4,
[Species.DITTO]: 2,
[Species.EEVEE]: 3,
[Species.PORYGON]: 4,
[Species.OMANYTE]: 3,
[Species.KABUTO]: 3,
[Species.AERODACTYL]: 5,
[Species.SNORLAX]: 5,
[Species.ARTICUNO]: 6,
[Species.ZAPDOS]: 6,
[Species.MOLTRES]: 6,
[Species.DRATINI]: 4,
[Species.MEWTWO]: 8,
[Species.MEW]: 6,
[Species.CHIKORITA]: 2,
[Species.CYNDAQUIL]: 3,
[Species.TOTODILE]: 3,
[Species.SENTRET]: 1,
[Species.HOOTHOOT]: 2,
[Species.LEDYBA]: 1,
[Species.SPINARAK]: 1,
[Species.CHINCHOU]: 2,
[Species.PICHU]: 2,
[Species.CLEFFA]: 2,
[Species.IGGLYBUFF]: 1,
[Species.TOGEPI]: 3,
[Species.NATU]: 2,
[Species.MAREEP]: 2,
[Species.MARILL]: 4,
[Species.SUDOWOODO]: 3,
[Species.HOPPIP]: 2,
[Species.AIPOM]: 2,
[Species.SUNKERN]: 1,
[Species.YANMA]: 3,
[Species.WOOPER]: 2,
[Species.MURKROW]: 3,
[Species.MISDREAVUS]: 2,
[Species.UNOWN]: 1,
[Species.WOBBUFFET]: 2,
[Species.GIRAFARIG]: 3,
[Species.PINECO]: 2,
[Species.DUNSPARCE]: 3,
[Species.GLIGAR]: 3,
[Species.SNUBBULL]: 2,
[Species.QWILFISH]: 3,
[Species.SHUCKLE]: 3,
[Species.HERACROSS]: 5,
[Species.SNEASEL]: 4,
[Species.TEDDIURSA]: 4,
[Species.SLUGMA]: 2,
[Species.SWINUB]: 3,
[Species.CORSOLA]: 2,
[Species.REMORAID]: 2,
[Species.DELIBIRD]: 2,
[Species.MANTINE]: 3,
[Species.SKARMORY]: 4,
[Species.HOUNDOUR]: 3,
[Species.PHANPY]: 3,
[Species.STANTLER]: 3,
[Species.SMEARGLE]: 1,
[Species.TYROGUE]: 3,
[Species.SMOOCHUM]: 3,
[Species.ELEKID]: 3,
[Species.MAGBY]: 3,
[Species.MILTANK]: 4,
[Species.RAIKOU]: 6,
[Species.ENTEI]: 6,
[Species.SUICUNE]: 6,
[Species.LARVITAR]: 4,
[Species.LUGIA]: 8,
[Species.HO_OH]: 8,
[Species.CELEBI]: 6,
[Species.TREECKO]: 3,
[Species.TORCHIC]: 4,
[Species.MUDKIP]: 3,
[Species.POOCHYENA]: 2,
[Species.ZIGZAGOON]: 2,
[Species.WURMPLE]: 1,
[Species.LOTAD]: 3,
[Species.SEEDOT]: 2,
[Species.TAILLOW]: 3,
[Species.WINGULL]: 2,
[Species.RALTS]: 3,
[Species.SURSKIT]: 2,
[Species.SHROOMISH]: 3,
[Species.SLAKOTH]: 4,
[Species.NINCADA]: 4,
[Species.WHISMUR]: 2,
[Species.MAKUHITA]: 3,
[Species.AZURILL]: 4,
[Species.NOSEPASS]: 2,
[Species.SKITTY]: 1,
[Species.SABLEYE]: 2,
[Species.MAWILE]: 3,
[Species.ARON]: 3,
[Species.MEDITITE]: 3,
[Species.ELECTRIKE]: 2,
[Species.PLUSLE]: 2,
[Species.MINUN]: 2,
[Species.VOLBEAT]: 2,
[Species.ILLUMISE]: 2,
[Species.ROSELIA]: 3,
[Species.GULPIN]: 1,
[Species.CARVANHA]: 3,
[Species.WAILMER]: 2,
[Species.NUMEL]: 2,
[Species.TORKOAL]: 3,
[Species.SPOINK]: 2,
[Species.SPINDA]: 1,
[Species.TRAPINCH]: 3,
[Species.CACNEA]: 2,
[Species.SWABLU]: 2,
[Species.ZANGOOSE]: 4,
[Species.SEVIPER]: 3,
[Species.LUNATONE]: 3,
[Species.SOLROCK]: 3,
[Species.BARBOACH]: 2,
[Species.CORPHISH]: 3,
[Species.BALTOY]: 2,
[Species.LILEEP]: 3,
[Species.ANORITH]: 3,
[Species.FEEBAS]: 4,
[Species.CASTFORM]: 1,
[Species.KECLEON]: 2,
[Species.SHUPPET]: 2,
[Species.DUSKULL]: 3,
[Species.TROPIUS]: 3,
[Species.CHIMECHO]: 3,
[Species.ABSOL]: 4,
[Species.WYNAUT]: 2,
[Species.SNORUNT]: 2,
[Species.SPHEAL]: 2,
[Species.CLAMPERL]: 3,
[Species.RELICANTH]: 3,
[Species.LUVDISC]: 1,
[Species.BAGON]: 4,
[Species.BELDUM]: 4,
[Species.REGIROCK]: 6,
[Species.REGICE]: 6,
[Species.REGISTEEL]: 6,
[Species.LATIAS]: 7,
[Species.LATIOS]: 7,
[Species.KYOGRE]: 9,
[Species.GROUDON]: 9,
[Species.RAYQUAZA]: 9,
[Species.JIRACHI]: 7,
[Species.DEOXYS]: 7,
[Species.TURTWIG]: 3,
[Species.CHIMCHAR]: 3,
[Species.PIPLUP]: 3,
[Species.STARLY]: 3,
[Species.BIDOOF]: 2,
[Species.KRICKETOT]: 1,
[Species.SHINX]: 2,
[Species.BUDEW]: 3,
[Species.CRANIDOS]: 3,
[Species.SHIELDON]: 3,
[Species.BURMY]: 2,
[Species.COMBEE]: 2,
[Species.PACHIRISU]: 2,
[Species.BUIZEL]: 2,
[Species.CHERUBI]: 1,
[Species.SHELLOS]: 3,
[Species.DRIFLOON]: 2,
[Species.BUNEARY]: 2,
[Species.GLAMEOW]: 2,
[Species.CHINGLING]: 2,
[Species.STUNKY]: 2,
[Species.BRONZOR]: 3,
[Species.BONSLY]: 2,
[Species.MIME_JR]: 2,
[Species.HAPPINY]: 2,
[Species.CHATOT]: 2,
[Species.SPIRITOMB]: 4,
[Species.GIBLE]: 4,
[Species.MUNCHLAX]: 4,
[Species.RIOLU]: 3,
[Species.HIPPOPOTAS]: 3,
[Species.SKORUPI]: 3,
[Species.CROAGUNK]: 2,
[Species.CARNIVINE]: 2,
[Species.FINNEON]: 1,
[Species.MANTYKE]: 2,
[Species.SNOVER]: 2,
[Species.ROTOM]: 5,
[Species.UXIE]: 6,
[Species.MESPRIT]: 6,
[Species.AZELF]: 6,
[Species.DIALGA]: 8,
[Species.PALKIA]: 8,
[Species.HEATRAN]: 6,
[Species.REGIGIGAS]: 7,
[Species.GIRATINA]: 8,
[Species.CRESSELIA]: 6,
[Species.PHIONE]: 4,
[Species.MANAPHY]: 7,
[Species.DARKRAI]: 7,
[Species.SHAYMIN]: 6,
[Species.ARCEUS]: 9,
[Species.VICTINI]: 7,
[Species.SNIVY]: 3,
[Species.TEPIG]: 3,
[Species.OSHAWOTT]: 3,
[Species.PATRAT]: 1,
[Species.LILLIPUP]: 3,
[Species.PURRLOIN]: 2,
[Species.PANSAGE]: 2,
[Species.PANSEAR]: 2,
[Species.PANPOUR]: 2,
[Species.MUNNA]: 2,
[Species.PIDOVE]: 1,
[Species.BLITZLE]: 2,
[Species.ROGGENROLA]: 3,
[Species.WOOBAT]: 3,
[Species.DRILBUR]: 4,
[Species.AUDINO]: 3,
[Species.TIMBURR]: 4,
[Species.TYMPOLE]: 3,
[Species.THROH]: 4,
[Species.SAWK]: 4,
[Species.SEWADDLE]: 2,
[Species.VENIPEDE]: 3,
[Species.COTTONEE]: 3,
[Species.PETILIL]: 3,
[Species.BASCULIN]: 4,
[Species.SANDILE]: 4,
[Species.DARUMAKA]: 4,
[Species.MARACTUS]: 2,
[Species.DWEBBLE]: 2,
[Species.SCRAGGY]: 3,
[Species.SIGILYPH]: 4,
[Species.YAMASK]: 3,
[Species.TIRTOUGA]: 3,
[Species.ARCHEN]: 3,
[Species.TRUBBISH]: 2,
[Species.ZORUA]: 3,
[Species.MINCCINO]: 3,
[Species.GOTHITA]: 3,
[Species.SOLOSIS]: 3,
[Species.DUCKLETT]: 2,
[Species.VANILLITE]: 3,
[Species.DEERLING]: 2,
[Species.EMOLGA]: 2,
[Species.KARRABLAST]: 3,
[Species.FOONGUS]: 2,
[Species.FRILLISH]: 3,
[Species.ALOMOMOLA]: 4,
[Species.JOLTIK]: 3,
[Species.FERROSEED]: 3,
[Species.KLINK]: 3,
[Species.TYNAMO]: 2,
[Species.ELGYEM]: 2,
[Species.LITWICK]: 3,
[Species.AXEW]: 4,
[Species.CUBCHOO]: 2,
[Species.CRYOGONAL]: 4,
[Species.SHELMET]: 2,
[Species.STUNFISK]: 3,
[Species.MIENFOO]: 3,
[Species.DRUDDIGON]: 4,
[Species.GOLETT]: 3,
[Species.PAWNIARD]: 4,
[Species.BOUFFALANT]: 4,
[Species.RUFFLET]: 3,
[Species.VULLABY]: 3,
[Species.HEATMOR]: 3,
[Species.DURANT]: 4,
[Species.DEINO]: 4,
[Species.LARVESTA]: 4,
[Species.COBALION]: 6,
[Species.TERRAKION]: 6,
[Species.VIRIZION]: 6,
[Species.TORNADUS]: 7,
[Species.THUNDURUS]: 7,
[Species.RESHIRAM]: 8,
[Species.ZEKROM]: 8,
[Species.LANDORUS]: 7,
[Species.KYUREM]: 8,
[Species.KELDEO]: 6,
[Species.MELOETTA]: 7,
[Species.GENESECT]: 6,
[Species.CHESPIN]: 3,
[Species.FENNEKIN]: 3,
[Species.FROAKIE]: 4,
[Species.BUNNELBY]: 3,
[Species.FLETCHLING]: 3,
[Species.SCATTERBUG]: 2,
[Species.LITLEO]: 2,
[Species.FLABEBE]: 3,
[Species.SKIDDO]: 2,
[Species.PANCHAM]: 3,
[Species.FURFROU]: 3,
[Species.ESPURR]: 2,
[Species.HONEDGE]: 4,
[Species.SPRITZEE]: 2,
[Species.SWIRLIX]: 3,
[Species.INKAY]: 3,
[Species.BINACLE]: 3,
[Species.SKRELP]: 2,
[Species.CLAUNCHER]: 3,
[Species.HELIOPTILE]: 3,
[Species.TYRUNT]: 3,
[Species.AMAURA]: 3,
[Species.HAWLUCHA]: 4,
[Species.DEDENNE]: 2,
[Species.CARBINK]: 2,
[Species.GOOMY]: 4,
[Species.KLEFKI]: 3,
[Species.PHANTUMP]: 2,
[Species.PUMPKABOO]: 2,
[Species.BERGMITE]: 3,
[Species.NOIBAT]: 3,
[Species.XERNEAS]: 8,
[Species.YVELTAL]: 8,
[Species.ZYGARDE]: 8,
[Species.DIANCIE]: 7,
[Species.HOOPA]: 7,
[Species.VOLCANION]: 6,
[Species.ETERNAL_FLOETTE]: 4,
[Species.ROWLET]: 3,
[Species.LITTEN]: 3,
[Species.POPPLIO]: 4,
[Species.PIKIPEK]: 2,
[Species.YUNGOOS]: 2,
[Species.GRUBBIN]: 3,
[Species.CRABRAWLER]: 3,
[Species.ORICORIO]: 3,
[Species.CUTIEFLY]: 3,
[Species.ROCKRUFF]: 3,
[Species.WISHIWASHI]: 2,
[Species.MAREANIE]: 2,
[Species.MUDBRAY]: 3,
[Species.DEWPIDER]: 3,
[Species.FOMANTIS]: 2,
[Species.MORELULL]: 2,
[Species.SALANDIT]: 3,
[Species.STUFFUL]: 3,
[Species.BOUNSWEET]: 3,
[Species.COMFEY]: 4,
[Species.ORANGURU]: 4,
[Species.PASSIMIAN]: 4,
[Species.WIMPOD]: 3,
[Species.SANDYGAST]: 3,
[Species.PYUKUMUKU]: 2,
[Species.TYPE_NULL]: 5,
[Species.MINIOR]: 4,
[Species.KOMALA]: 3,
[Species.TURTONATOR]: 4,
[Species.TOGEDEMARU]: 3,
[Species.MIMIKYU]: 4,
[Species.BRUXISH]: 4,
[Species.DRAMPA]: 4,
[Species.DHELMISE]: 4,
[Species.JANGMO_O]: 4,
[Species.TAPU_KOKO]: 6,
[Species.TAPU_LELE]: 6,
[Species.TAPU_BULU]: 6,
[Species.TAPU_FINI]: 6,
[Species.COSMOG]: 7,
[Species.NIHILEGO]: 6,
[Species.BUZZWOLE]: 6,
[Species.PHEROMOSA]: 7,
[Species.XURKITREE]: 6,
[Species.CELESTEELA]: 6,
[Species.KARTANA]: 7,
[Species.GUZZLORD]: 6,
[Species.NECROZMA]: 8,
[Species.MAGEARNA]: 7,
[Species.MARSHADOW]: 7,
[Species.POIPOLE]: 7,
[Species.STAKATAKA]: 6,
[Species.BLACEPHALON]: 7,
[Species.ZERAORA]: 6,
[Species.MELTAN]: 6,
[Species.ALOLA_RATTATA]: 1,
[Species.ALOLA_SANDSHREW]: 2,
[Species.ALOLA_VULPIX]: 3,
[Species.ALOLA_DIGLETT]: 2,
[Species.ALOLA_MEOWTH]: 3,
[Species.ALOLA_GEODUDE]: 3,
[Species.ALOLA_GRIMER]: 3,
[Species.GROOKEY]: 3,
[Species.SCORBUNNY]: 4,
[Species.SOBBLE]: 3,
[Species.SKWOVET]: 2,
[Species.ROOKIDEE]: 3,
[Species.BLIPBUG]: 2,
[Species.NICKIT]: 1,
[Species.GOSSIFLEUR]: 2,
[Species.WOOLOO]: 2,
[Species.CHEWTLE]: 3,
[Species.YAMPER]: 2,
[Species.ROLYCOLY]: 3,
[Species.APPLIN]: 3,
[Species.SILICOBRA]: 3,
[Species.CRAMORANT]: 3,
[Species.ARROKUDA]: 3,
[Species.TOXEL]: 3,
[Species.SIZZLIPEDE]: 3,
[Species.CLOBBOPUS]: 2,
[Species.SINISTEA]: 3,
[Species.HATENNA]: 3,
[Species.IMPIDIMP]: 3,
[Species.MILCERY]: 3,
[Species.FALINKS]: 4,
[Species.PINCURCHIN]: 3,
[Species.SNOM]: 3,
[Species.STONJOURNER]: 3,
[Species.EISCUE]: 3,
[Species.INDEEDEE]: 4,
[Species.MORPEKO]: 3,
[Species.CUFANT]: 3,
[Species.DRACOZOLT]: 5,
[Species.ARCTOZOLT]: 4,
[Species.DRACOVISH]: 5,
[Species.ARCTOVISH]: 4,
[Species.DURALUDON]: 5,
[Species.DREEPY]: 4,
[Species.ZACIAN]: 9,
[Species.ZAMAZENTA]: 8,
[Species.ETERNATUS]: 10,
[Species.KUBFU]: 6,
[Species.ZARUDE]: 6,
[Species.REGIELEKI]: 6,
[Species.REGIDRAGO]: 6,
[Species.GLASTRIER]: 6,
[Species.SPECTRIER]: 7,
[Species.CALYREX]: 8,
[Species.GALAR_MEOWTH]: 3,
[Species.GALAR_PONYTA]: 2,
[Species.GALAR_SLOWPOKE]: 3,
[Species.GALAR_FARFETCHD]: 3,
[Species.GALAR_CORSOLA]: 3,
[Species.GALAR_ZIGZAGOON]: 3,
[Species.GALAR_DARUMAKA]: 4,
[Species.GALAR_YAMASK]: 3,
[Species.GALAR_STUNFISK]: 2,
[Species.GALAR_MR_MIME]: 3,
[Species.GALAR_ARTICUNO]: 6,
[Species.GALAR_ZAPDOS]: 6,
[Species.GALAR_MOLTRES]: 6,
[Species.HISUI_GROWLITHE]: 4,
[Species.HISUI_VOLTORB]: 3,
[Species.HISUI_QWILFISH]: 4,
[Species.HISUI_SNEASEL]: 5,
[Species.HISUI_ZORUA]: 3,
[Species.ENAMORUS]: 7,
[Species.SPRIGATITO]: 4,
[Species.FUECOCO]: 4,
[Species.QUAXLY]: 4,
[Species.LECHONK]: 2,
[Species.TAROUNTULA]: 1,
[Species.NYMBLE]: 3,
[Species.PAWMI]: 3,
[Species.TANDEMAUS]: 4,
[Species.FIDOUGH]: 2,
[Species.SMOLIV]: 3,
[Species.SQUAWKABILLY]: 2,
[Species.NACLI]: 4,
[Species.CHARCADET]: 4,
[Species.TADBULB]: 3,
[Species.WATTREL]: 3,
[Species.MASCHIFF]: 3,
[Species.SHROODLE]: 2,
[Species.BRAMBLIN]: 3,
[Species.TOEDSCOOL]: 3,
[Species.KLAWF]: 3,
[Species.CAPSAKID]: 3,
[Species.RELLOR]: 2,
[Species.FLITTLE]: 3,
[Species.TINKATINK]: 4,
[Species.WIGLETT]: 2,
[Species.BOMBIRDIER]: 3,
[Species.FINIZEN]: 3,
[Species.VAROOM]: 4,
[Species.CYCLIZAR]: 4,
[Species.ORTHWORM]: 4,
[Species.GLIMMET]: 4,
[Species.GREAVARD]: 3,
[Species.FLAMIGO]: 4,
[Species.CETODDLE]: 3,
[Species.VELUZA]: 4,
[Species.DONDOZO]: 4,
[Species.TATSUGIRI]: 4,
[Species.GREAT_TUSK]: 6,
[Species.SCREAM_TAIL]: 6,
[Species.BRUTE_BONNET]: 6,
[Species.FLUTTER_MANE]: 7,
[Species.SLITHER_WING]: 6,
[Species.SANDY_SHOCKS]: 6,
[Species.IRON_TREADS]: 6,
[Species.IRON_BUNDLE]: 6,
[Species.IRON_HANDS]: 6,
[Species.IRON_JUGULIS]: 6,
[Species.IRON_MOTH]: 6,
[Species.IRON_THORNS]: 6,
[Species.FRIGIBAX]: 4,
[Species.GIMMIGHOUL]: 4,
[Species.WO_CHIEN]: 6,
[Species.CHIEN_PAO]: 7,
[Species.TING_LU]: 6,
[Species.CHI_YU]: 7,
[Species.ROARING_MOON]: 6,
[Species.IRON_VALIANT]: 6,
[Species.KORAIDON]: 9,
[Species.MIRAIDON]: 9,
[Species.WALKING_WAKE]: 6,
[Species.IRON_LEAVES]: 6,
[Species.POLTCHAGEIST]: 4,
[Species.OKIDOGI]: 6,
[Species.MUNKIDORI]: 6,
[Species.FEZANDIPITI]: 6,
[Species.OGERPON]: 7,
[Species.GOUGING_FIRE]: 7,
[Species.RAGING_BOLT]: 6,
[Species.IRON_BOULDER]: 7,
[Species.IRON_CROWN]: 6,
[Species.TERAPAGOS]: 8,
[Species.PECHARUNT]: 6,
[Species.PALDEA_TAUROS]: 5,
[Species.PALDEA_WOOPER]: 3,
[Species.BLOODMOON_URSALUNA]: 6,
};
const starterCandyCosts: { passive: number; costReduction: [number, number]; egg: number; }[] = [
{ passive: 40, costReduction: [ 25, 60 ], egg: 30 }, // 1 Cost
{ passive: 40, costReduction: [ 25, 60 ], egg: 30 }, // 2 Cost
{ passive: 35, costReduction: [ 20, 50 ], egg: 25 }, // 3 Cost
{ passive: 30, costReduction: [ 15, 40 ], egg: 20 }, // 4 Cost
{ passive: 25, costReduction: [ 12, 35 ], egg: 18 }, // 5 Cost
{ passive: 20, costReduction: [ 10, 30 ], egg: 15 }, // 6 Cost
{ passive: 15, costReduction: [ 8, 20 ], egg: 12 }, // 7 Cost
{ passive: 10, costReduction: [ 5, 15 ], egg: 10 }, // 8 Cost
{ passive: 10, costReduction: [ 5, 15 ], egg: 10 }, // 9 Cost
{ passive: 10, costReduction: [ 5, 15 ], egg: 10 }, // 10 Cost
];
/**
* Getter for {@linkcode starterCandyCosts} for passive unlock candy cost based on initial point cost
* @param starterCost the default point cost of the starter found in {@linkcode speciesStarterCosts}
* @returns the candy cost for passive unlock
*/
export function getPassiveCandyCount(starterCost: number): number {
return starterCandyCosts[starterCost - 1].passive;
}
/**
* Getter for {@linkcode starterCandyCosts} for value reduction unlock candy cost based on initial point cost
* @param starterCost the default point cost of the starter found in {@linkcode speciesStarterCosts}
* @returns respective candy cost for the two cost reductions as an array 2 numbers
*/
export function getValueReductionCandyCounts(starterCost: number): [number, number] {
return starterCandyCosts[starterCost - 1].costReduction;
}
/**
* Getter for {@linkcode starterCandyCosts} for egg purchase candy cost based on initial point cost
* @param starterCost the default point cost of the starter found in {@linkcode speciesStarterCosts}
* @returns the candy cost for the purchasable egg
*/
export function getSameSpeciesEggCandyCounts(starterCost: number): number {
return starterCandyCosts[starterCost - 1].egg;
}

View File

@ -1,4 +1,4 @@
import { ModifierTier } from "../modifier/modifier-tier"; import { ModifierTier } from "#app/modifier/modifier-tier";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";

View File

@ -556,7 +556,7 @@ function logMissingMoveAnim(move: Moves, ...optionalParams: any[]) {
* @param encounterAnim one or more animations to fetch * @param encounterAnim one or more animations to fetch
*/ */
export async function initEncounterAnims(scene: BattleScene, encounterAnim: EncounterAnim | EncounterAnim[]): Promise<void> { export async function initEncounterAnims(scene: BattleScene, encounterAnim: EncounterAnim | EncounterAnim[]): Promise<void> {
const anims = Array.isArray(encounterAnim) ? encounterAnim : [encounterAnim]; const anims = Array.isArray(encounterAnim) ? encounterAnim : [ encounterAnim ];
const encounterAnimNames = Utils.getEnumKeys(EncounterAnim); const encounterAnimNames = Utils.getEnumKeys(EncounterAnim);
const encounterAnimFetches: Promise<Map<EncounterAnim, AnimConfig>>[] = []; const encounterAnimFetches: Promise<Map<EncounterAnim, AnimConfig>>[] = [];
for (const anim of anims) { for (const anim of anims) {
@ -774,9 +774,9 @@ export abstract class BattleAnim {
private getGraphicFrameData(scene: BattleScene, frames: AnimFrame[], onSubstitute?: boolean): Map<integer, Map<AnimFrameTarget, GraphicFrameData>> { private getGraphicFrameData(scene: BattleScene, frames: AnimFrame[], onSubstitute?: boolean): Map<integer, Map<AnimFrameTarget, GraphicFrameData>> {
const ret: Map<integer, Map<AnimFrameTarget, GraphicFrameData>> = new Map([ const ret: Map<integer, Map<AnimFrameTarget, GraphicFrameData>> = new Map([
[AnimFrameTarget.GRAPHIC, new Map<AnimFrameTarget, GraphicFrameData>() ], [ AnimFrameTarget.GRAPHIC, new Map<AnimFrameTarget, GraphicFrameData>() ],
[AnimFrameTarget.USER, new Map<AnimFrameTarget, GraphicFrameData>() ], [ AnimFrameTarget.USER, new Map<AnimFrameTarget, GraphicFrameData>() ],
[AnimFrameTarget.TARGET, new Map<AnimFrameTarget, GraphicFrameData>() ] [ AnimFrameTarget.TARGET, new Map<AnimFrameTarget, GraphicFrameData>() ]
]); ]);
const isOppAnim = this.isOppAnim(); const isOppAnim = this.isOppAnim();
@ -1093,9 +1093,9 @@ export abstract class BattleAnim {
private getGraphicFrameDataWithoutTarget(frames: AnimFrame[], targetInitialX: number, targetInitialY: number): Map<integer, Map<AnimFrameTarget, GraphicFrameData>> { private getGraphicFrameDataWithoutTarget(frames: AnimFrame[], targetInitialX: number, targetInitialY: number): Map<integer, Map<AnimFrameTarget, GraphicFrameData>> {
const ret: Map<integer, Map<AnimFrameTarget, GraphicFrameData>> = new Map([ const ret: Map<integer, Map<AnimFrameTarget, GraphicFrameData>> = new Map([
[AnimFrameTarget.GRAPHIC, new Map<AnimFrameTarget, GraphicFrameData>() ], [ AnimFrameTarget.GRAPHIC, new Map<AnimFrameTarget, GraphicFrameData>() ],
[AnimFrameTarget.USER, new Map<AnimFrameTarget, GraphicFrameData>() ], [ AnimFrameTarget.USER, new Map<AnimFrameTarget, GraphicFrameData>() ],
[AnimFrameTarget.TARGET, new Map<AnimFrameTarget, GraphicFrameData>() ] [ AnimFrameTarget.TARGET, new Map<AnimFrameTarget, GraphicFrameData>() ]
]); ]);
let g = 0; let g = 0;

View File

@ -363,7 +363,7 @@ export class RechargingTag extends BattlerTag {
super.onAdd(pokemon); super.onAdd(pokemon);
// Queue a placeholder move for the Pokemon to "use" next turn // Queue a placeholder move for the Pokemon to "use" next turn
pokemon.getMoveQueue().push({ move: Moves.NONE, targets: [] }); pokemon.getMoveQueue().push({ move: Moves.NONE, targets: []});
} }
/** Cancels the source's move this turn and queues a "__ must recharge!" message */ /** Cancels the source's move this turn and queues a "__ must recharge!" message */
@ -569,7 +569,7 @@ export class InterruptedTag extends BattlerTag {
super.onAdd(pokemon); super.onAdd(pokemon);
pokemon.getMoveQueue().shift(); pokemon.getMoveQueue().shift();
pokemon.pushMoveHistory({move: Moves.NONE, result: MoveResult.OTHER}); pokemon.pushMoveHistory({ move: Moves.NONE, result: MoveResult.OTHER });
} }
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
@ -1935,10 +1935,10 @@ export class RoostedTag extends BattlerTag {
modifiedTypes = currentTypes.filter(type => type !== Type.NORMAL); modifiedTypes = currentTypes.filter(type => type !== Type.NORMAL);
modifiedTypes.push(Type.FLYING); modifiedTypes.push(Type.FLYING);
} else { } else {
modifiedTypes = [Type.FLYING]; modifiedTypes = [ Type.FLYING ];
} }
} else { } else {
modifiedTypes = [...currentTypes]; modifiedTypes = [ ...currentTypes ];
modifiedTypes.push(Type.FLYING); modifiedTypes.push(Type.FLYING);
} }
pokemon.summonData.types = modifiedTypes; pokemon.summonData.types = modifiedTypes;
@ -1958,10 +1958,10 @@ export class RoostedTag extends BattlerTag {
if (this.isBaseFlying) { if (this.isBaseFlying) {
let modifiedTypes: Type[]; let modifiedTypes: Type[];
if (this.isBasePureFlying && !isCurrentlyDualType) { if (this.isBasePureFlying && !isCurrentlyDualType) {
modifiedTypes = [Type.NORMAL]; modifiedTypes = [ Type.NORMAL ];
} else { } else {
if (!!pokemon.getTag(RemovedTypeTag) && isOriginallyDualType && !isCurrentlyDualType) { if (!!pokemon.getTag(RemovedTypeTag) && isOriginallyDualType && !isCurrentlyDualType) {
modifiedTypes = [Type.UNKNOWN]; modifiedTypes = [ Type.UNKNOWN ];
} else { } else {
modifiedTypes = currentTypes.filter(type => type !== Type.FLYING); modifiedTypes = currentTypes.filter(type => type !== Type.FLYING);
} }
@ -2067,8 +2067,8 @@ export class StockpilingTag extends BattlerTag {
super.loadTag(source); super.loadTag(source);
this.stockpiledCount = source.stockpiledCount || 0; this.stockpiledCount = source.stockpiledCount || 0;
this.statChangeCounts = { this.statChangeCounts = {
[ Stat.DEF ]: source.statChangeCounts?.[ Stat.DEF ] ?? 0, [Stat.DEF]: source.statChangeCounts?.[Stat.DEF] ?? 0,
[ Stat.SPDEF ]: source.statChangeCounts?.[ Stat.SPDEF ] ?? 0, [Stat.SPDEF]: source.statChangeCounts?.[Stat.SPDEF] ?? 0,
}; };
} }
@ -2090,7 +2090,7 @@ export class StockpilingTag extends BattlerTag {
// Attempt to increase DEF and SPDEF by one stage, keeping track of successful changes. // Attempt to increase DEF and SPDEF by one stage, keeping track of successful changes.
pokemon.scene.unshiftPhase(new StatStageChangePhase( pokemon.scene.unshiftPhase(new StatStageChangePhase(
pokemon.scene, pokemon.getBattlerIndex(), true, pokemon.scene, pokemon.getBattlerIndex(), true,
[Stat.SPDEF, Stat.DEF], 1, true, false, true, this.onStatStagesChanged [ Stat.SPDEF, Stat.DEF ], 1, true, false, true, this.onStatStagesChanged
)); ));
} }
} }
@ -2123,7 +2123,36 @@ export class StockpilingTag extends BattlerTag {
*/ */
export class GulpMissileTag extends BattlerTag { export class GulpMissileTag extends BattlerTag {
constructor(tagType: BattlerTagType, sourceMove: Moves) { constructor(tagType: BattlerTagType, sourceMove: Moves) {
super(tagType, BattlerTagLapseType.CUSTOM, 0, sourceMove); super(tagType, BattlerTagLapseType.HIT, 0, sourceMove);
}
override lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
if (pokemon.getTag(BattlerTagType.UNDERWATER)) {
return true;
}
const moveEffectPhase = pokemon.scene.getCurrentPhase();
if (moveEffectPhase instanceof MoveEffectPhase) {
const attacker = moveEffectPhase.getUserPokemon();
if (!attacker) {
return false;
}
const cancelled = new Utils.BooleanHolder(false);
applyAbAttrs(BlockNonDirectDamageAbAttr, attacker, cancelled);
if (!cancelled.value) {
attacker.damageAndUpdate(Math.max(1, Math.floor(attacker.getMaxHp() / 4)), HitResult.OTHER);
}
if (this.tagType === BattlerTagType.GULP_MISSILE_ARROKUDA) {
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, attacker.getBattlerIndex(), false, [ Stat.DEF ], -1));
} else {
attacker.trySetStatus(StatusEffect.PARALYSIS, true, pokemon);
}
}
return false;
} }
/** /**
@ -2238,7 +2267,7 @@ export class HealBlockTag extends MoveRestrictionBattlerTag {
* Uses DisabledTag's selectionDeniedText() message * Uses DisabledTag's selectionDeniedText() message
*/ */
override selectionDeniedText(pokemon: Pokemon, move: Moves): string { override selectionDeniedText(pokemon: Pokemon, move: Moves): string {
return i18next.t("battle:moveDisabled", { moveName: allMoves[move].name }); return i18next.t("battle:moveDisabledHealBlock", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[move].name, healBlockName: allMoves[Moves.HEAL_BLOCK].name });
} }
/** /**
@ -2248,7 +2277,7 @@ export class HealBlockTag extends MoveRestrictionBattlerTag {
* @returns {string} text to display when the move is interrupted * @returns {string} text to display when the move is interrupted
*/ */
override interruptedText(pokemon: Pokemon, move: Moves): string { override interruptedText(pokemon: Pokemon, move: Moves): string {
return i18next.t("battle:disableInterruptedMove", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[move].name }); return i18next.t("battle:moveDisabledHealBlock", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[move].name, healBlockName: allMoves[Moves.HEAL_BLOCK].name });
} }
override onRemove(pokemon: Pokemon): void { override onRemove(pokemon: Pokemon): void {
@ -2325,7 +2354,7 @@ export class SubstituteTag extends BattlerTag {
public sourceInFocus: boolean; public sourceInFocus: boolean;
constructor(sourceMove: Moves, sourceId: integer) { constructor(sourceMove: Moves, sourceId: integer) {
super(BattlerTagType.SUBSTITUTE, [BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.AFTER_MOVE, BattlerTagLapseType.HIT], 0, sourceMove, sourceId, true); super(BattlerTagType.SUBSTITUTE, [ BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.AFTER_MOVE, BattlerTagLapseType.HIT ], 0, sourceMove, sourceId, true);
} }
/** Sets the Substitute's HP and queues an on-add battle animation that initializes the Substitute's sprite. */ /** Sets the Substitute's HP and queues an on-add battle animation that initializes the Substitute's sprite. */
@ -2349,7 +2378,7 @@ export class SubstituteTag extends BattlerTag {
onRemove(pokemon: Pokemon): void { onRemove(pokemon: Pokemon): void {
// Only play the animation if the cause of removal isn't from the source's own move // Only play the animation if the cause of removal isn't from the source's own move
if (!this.sourceInFocus) { if (!this.sourceInFocus) {
pokemon.scene.triggerPokemonBattleAnim(pokemon, PokemonAnimType.SUBSTITUTE_REMOVE, [this.sprite]); pokemon.scene.triggerPokemonBattleAnim(pokemon, PokemonAnimType.SUBSTITUTE_REMOVE, [ this.sprite ]);
} else { } else {
this.sprite.destroy(); this.sprite.destroy();
} }
@ -2373,13 +2402,13 @@ export class SubstituteTag extends BattlerTag {
/** Triggers an animation that brings the Pokemon into focus before it uses a move */ /** Triggers an animation that brings the Pokemon into focus before it uses a move */
onPreMove(pokemon: Pokemon): void { onPreMove(pokemon: Pokemon): void {
pokemon.scene.triggerPokemonBattleAnim(pokemon, PokemonAnimType.SUBSTITUTE_PRE_MOVE, [this.sprite]); pokemon.scene.triggerPokemonBattleAnim(pokemon, PokemonAnimType.SUBSTITUTE_PRE_MOVE, [ this.sprite ]);
this.sourceInFocus = true; this.sourceInFocus = true;
} }
/** Triggers an animation that brings the Pokemon out of focus after it uses a move */ /** Triggers an animation that brings the Pokemon out of focus after it uses a move */
onAfterMove(pokemon: Pokemon): void { onAfterMove(pokemon: Pokemon): void {
pokemon.scene.triggerPokemonBattleAnim(pokemon, PokemonAnimType.SUBSTITUTE_POST_MOVE, [this.sprite]); pokemon.scene.triggerPokemonBattleAnim(pokemon, PokemonAnimType.SUBSTITUTE_POST_MOVE, [ this.sprite ]);
this.sourceInFocus = false; this.sourceInFocus = false;
} }
@ -2501,8 +2530,8 @@ export class TormentTag extends MoveRestrictionBattlerTag {
return false; return false;
} }
override selectionDeniedText(_pokemon: Pokemon, move: Moves): string { override selectionDeniedText(pokemon: Pokemon, _move: Moves): string {
return i18next.t("battle:moveCannotBeSelected", { moveName: allMoves[move].name }); return i18next.t("battle:moveDisabledTorment", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) });
} }
} }
@ -2513,7 +2542,7 @@ export class TormentTag extends MoveRestrictionBattlerTag {
*/ */
export class TauntTag extends MoveRestrictionBattlerTag { export class TauntTag extends MoveRestrictionBattlerTag {
constructor() { constructor() {
super(BattlerTagType.TAUNT, [BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.AFTER_MOVE], 4, Moves.TAUNT); super(BattlerTagType.TAUNT, [ BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.AFTER_MOVE ], 4, Moves.TAUNT);
} }
override onAdd(pokemon: Pokemon) { override onAdd(pokemon: Pokemon) {
@ -2530,12 +2559,12 @@ export class TauntTag extends MoveRestrictionBattlerTag {
return allMoves[move].category === MoveCategory.STATUS; return allMoves[move].category === MoveCategory.STATUS;
} }
override selectionDeniedText(_pokemon: Pokemon, move: Moves): string { override selectionDeniedText(pokemon: Pokemon, move: Moves): string {
return i18next.t("battle:moveCannotBeSelected", { moveName: allMoves[move].name }); return i18next.t("battle:moveDisabledTaunt", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[move].name });
} }
override interruptedText(pokemon: Pokemon, move: Moves): string { override interruptedText(pokemon: Pokemon, move: Moves): string {
return i18next.t("battle:disableInterruptedMove", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[move].name }); return i18next.t("battle:moveDisabledTaunt", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[move].name });
} }
} }
@ -2548,7 +2577,7 @@ export class ImprisonTag extends MoveRestrictionBattlerTag {
private source: Pokemon | null; private source: Pokemon | null;
constructor(sourceId: number) { constructor(sourceId: number) {
super(BattlerTagType.IMPRISON, [BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.AFTER_MOVE], 1, Moves.IMPRISON, sourceId); super(BattlerTagType.IMPRISON, [ BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.AFTER_MOVE ], 1, Moves.IMPRISON, sourceId);
} }
override onAdd(pokemon: Pokemon) { override onAdd(pokemon: Pokemon) {
@ -2580,15 +2609,52 @@ export class ImprisonTag extends MoveRestrictionBattlerTag {
return false; return false;
} }
override selectionDeniedText(_pokemon: Pokemon, move: Moves): string { override selectionDeniedText(pokemon: Pokemon, move: Moves): string {
return i18next.t("battle:moveCannotBeSelected", { moveName: allMoves[move].name }); return i18next.t("battle:moveDisabledImprison", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[move].name });
} }
override interruptedText(pokemon: Pokemon, move: Moves): string { override interruptedText(pokemon: Pokemon, move: Moves): string {
return i18next.t("battle:disableInterruptedMove", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[move].name }); return i18next.t("battle:moveDisabledImprison", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[move].name });
} }
} }
/**
* Battler Tag that applies the effects of Syrup Bomb to the target Pokemon.
* For three turns, starting from the turn of hit, at the end of each turn, the target Pokemon's speed will decrease by 1.
* The tag can also expire by taking the target Pokemon off the field.
*/
export class SyrupBombTag extends BattlerTag {
constructor() {
super(BattlerTagType.SYRUP_BOMB, BattlerTagLapseType.TURN_END, 3, Moves.SYRUP_BOMB);
}
/**
* Adds the Syrup Bomb battler tag to the target Pokemon.
* @param {Pokemon} pokemon the target Pokemon
*/
override onAdd(pokemon: Pokemon) {
super.onAdd(pokemon);
pokemon.scene.queueMessage(i18next.t("battlerTags:syrupBombOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
}
/**
* Applies the single-stage speed down to the target Pokemon and decrements the tag's turn count
* @param {Pokemon} pokemon the target Pokemon
* @param {BattlerTagLapseType} _lapseType
* @returns `true` if the turnCount is still greater than 0 | `false` if the turnCount is 0 or the target Pokemon has been removed from the field
*/
override lapse(pokemon: Pokemon, _lapseType: BattlerTagLapseType): boolean {
if (!pokemon.isActive(true)) {
return false;
}
pokemon.scene.queueMessage(i18next.t("battlerTags:syrupBombLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) })); // Custom message in lieu of an animation in mainline
pokemon.scene.unshiftPhase(new StatStageChangePhase(
pokemon.scene, pokemon.getBattlerIndex(), true,
[ Stat.SPD ], -1, true, false, true
));
return --this.turnCount > 0;
}
}
/** /**
* Retrieves a {@linkcode BattlerTag} based on the provided tag type, turn count, source move, and source ID. * Retrieves a {@linkcode BattlerTag} based on the provided tag type, turn count, source move, and source ID.
@ -2737,9 +2803,9 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source
case BattlerTagType.DISABLED: case BattlerTagType.DISABLED:
return new DisabledTag(sourceId); return new DisabledTag(sourceId);
case BattlerTagType.IGNORE_GHOST: case BattlerTagType.IGNORE_GHOST:
return new ExposedTag(tagType, sourceMove, Type.GHOST, [Type.NORMAL, Type.FIGHTING]); return new ExposedTag(tagType, sourceMove, Type.GHOST, [ Type.NORMAL, Type.FIGHTING ]);
case BattlerTagType.IGNORE_DARK: case BattlerTagType.IGNORE_DARK:
return new ExposedTag(tagType, sourceMove, Type.DARK, [Type.PSYCHIC]); return new ExposedTag(tagType, sourceMove, Type.DARK, [ Type.PSYCHIC ]);
case BattlerTagType.GULP_MISSILE_ARROKUDA: case BattlerTagType.GULP_MISSILE_ARROKUDA:
case BattlerTagType.GULP_MISSILE_PIKACHU: case BattlerTagType.GULP_MISSILE_PIKACHU:
return new GulpMissileTag(tagType, sourceMove); return new GulpMissileTag(tagType, sourceMove);
@ -2763,6 +2829,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source
return new TauntTag(); return new TauntTag();
case BattlerTagType.IMPRISON: case BattlerTagType.IMPRISON:
return new ImprisonTag(sourceId); return new ImprisonTag(sourceId);
case BattlerTagType.SYRUP_BOMB:
return new SyrupBombTag();
case BattlerTagType.NONE: case BattlerTagType.NONE:
default: default:
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId); return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);

View File

@ -1,20 +1,21 @@
import * as Utils from "../utils"; import * as Utils from "#app/utils";
import i18next from "i18next"; import i18next from "i18next";
import { defaultStarterSpecies, DexAttrProps, GameData } from "#app/system/game-data"; import { defaultStarterSpecies, DexAttrProps, GameData } from "#app/system/game-data";
import PokemonSpecies, { getPokemonSpecies, getPokemonSpeciesForm, speciesStarters } from "./pokemon-species"; import PokemonSpecies, { getPokemonSpecies, getPokemonSpeciesForm } from "#app/data/pokemon-species";
import { speciesStarterCosts } from "#app/data/balance/starters";
import Pokemon, { PokemonMove } from "#app/field/pokemon"; import Pokemon, { PokemonMove } from "#app/field/pokemon";
import { BattleType, FixedBattleConfig } from "#app/battle"; import { BattleType, FixedBattleConfig } from "#app/battle";
import Trainer, { TrainerVariant } from "#app/field/trainer"; import Trainer, { TrainerVariant } from "#app/field/trainer";
import { GameMode } from "#app/game-mode"; import { GameMode } from "#app/game-mode";
import { Type } from "./type"; import { Type } from "#app/data/type";
import { Challenges } from "#enums/challenges"; import { Challenges } from "#enums/challenges";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import { TrainerType } from "#enums/trainer-type"; import { TrainerType } from "#enums/trainer-type";
import { Nature } from "./nature"; import { Nature } from "#app/data/nature";
import { Moves } from "#app/enums/moves"; import { Moves } from "#enums/moves";
import { TypeColor, TypeShadow } from "#app/enums/color"; import { TypeColor, TypeShadow } from "#enums/color";
import { pokemonEvolutions } from "./pokemon-evolutions"; import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions";
import { pokemonFormChanges } from "./pokemon-forms"; import { pokemonFormChanges } from "#app/data/pokemon-forms";
import { ModifierTier } from "#app/modifier/modifier-tier"; import { ModifierTier } from "#app/modifier/modifier-tier";
/** A constant for the default max cost of the starting party before a run */ /** A constant for the default max cost of the starting party before a run */
@ -185,7 +186,7 @@ export abstract class Challenge {
*/ */
getDescription(overrideValue?: number): string { getDescription(overrideValue?: number): string {
const value = overrideValue ?? this.value; const value = overrideValue ?? this.value;
return `${i18next.t([`challenges:${this.geti18nKey()}.desc.${value}`, `challenges:${this.geti18nKey()}.desc`])}`; return `${i18next.t([ `challenges:${this.geti18nKey()}.desc.${value}`, `challenges:${this.geti18nKey()}.desc` ])}`;
} }
/** /**
@ -414,9 +415,9 @@ export class SingleGenerationChallenge extends Challenge {
} }
applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean = false): boolean { applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean = false): boolean {
const generations = [pokemon.generation]; const generations = [ pokemon.generation ];
if (soft) { if (soft) {
const speciesToCheck = [pokemon.speciesId]; const speciesToCheck = [ pokemon.speciesId ];
while (speciesToCheck.length) { while (speciesToCheck.length) {
const checking = speciesToCheck.pop(); const checking = speciesToCheck.pop();
if (checking && pokemonEvolutions.hasOwnProperty(checking)) { if (checking && pokemonEvolutions.hasOwnProperty(checking)) {
@ -631,7 +632,7 @@ export class SingleGenerationChallenge extends Challenge {
trainerTypes = [ TrainerType.BRUNO, TrainerType.KOGA, TrainerType.PHOEBE, TrainerType.BERTHA, TrainerType.MARSHAL, TrainerType.SIEBOLD, TrainerType.OLIVIA, TrainerType.NESSA_ELITE, TrainerType.POPPY ]; trainerTypes = [ TrainerType.BRUNO, TrainerType.KOGA, TrainerType.PHOEBE, TrainerType.BERTHA, TrainerType.MARSHAL, TrainerType.SIEBOLD, TrainerType.OLIVIA, TrainerType.NESSA_ELITE, TrainerType.POPPY ];
break; break;
case 186: case 186:
trainerTypes = [ TrainerType.AGATHA, TrainerType.BRUNO, TrainerType.GLACIA, TrainerType.FLINT, TrainerType.GRIMSLEY, TrainerType.WIKSTROM, TrainerType.ACEROLA, Utils.randSeedItem([TrainerType.BEA_ELITE, TrainerType.ALLISTER_ELITE]), TrainerType.LARRY_ELITE ]; trainerTypes = [ TrainerType.AGATHA, TrainerType.BRUNO, TrainerType.GLACIA, TrainerType.FLINT, TrainerType.GRIMSLEY, TrainerType.WIKSTROM, TrainerType.ACEROLA, Utils.randSeedItem([ TrainerType.BEA_ELITE, TrainerType.ALLISTER_ELITE ]), TrainerType.LARRY_ELITE ];
break; break;
case 188: case 188:
trainerTypes = [ TrainerType.LANCE, TrainerType.KAREN, TrainerType.DRAKE, TrainerType.LUCIAN, TrainerType.CAITLIN, TrainerType.DRASNA, TrainerType.KAHILI, TrainerType.RAIHAN_ELITE, TrainerType.HASSEL ]; trainerTypes = [ TrainerType.LANCE, TrainerType.KAREN, TrainerType.DRAKE, TrainerType.LUCIAN, TrainerType.CAITLIN, TrainerType.DRASNA, TrainerType.KAHILI, TrainerType.RAIHAN_ELITE, TrainerType.HASSEL ];
@ -704,10 +705,10 @@ interface monotypeOverride {
*/ */
export class SingleTypeChallenge extends Challenge { export class SingleTypeChallenge extends Challenge {
private static TYPE_OVERRIDES: monotypeOverride[] = [ private static TYPE_OVERRIDES: monotypeOverride[] = [
{species: Species.CASTFORM, type: Type.NORMAL, fusion: false}, { species: Species.CASTFORM, type: Type.NORMAL, fusion: false },
]; ];
// TODO: Find a solution for all Pokemon with this ssui issue, including Basculin and Burmy // TODO: Find a solution for all Pokemon with this ssui issue, including Basculin and Burmy
private static SPECIES_OVERRIDES: Species[] = [Species.MELOETTA]; private static SPECIES_OVERRIDES: Species[] = [ Species.MELOETTA ];
constructor() { constructor() {
super(Challenges.SINGLE_TYPE, 18); super(Challenges.SINGLE_TYPE, 18);
@ -715,9 +716,9 @@ export class SingleTypeChallenge extends Challenge {
override applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean = false): boolean { override applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean = false): 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 (soft && !SingleTypeChallenge.SPECIES_OVERRIDES.includes(pokemon.speciesId)) { if (soft && !SingleTypeChallenge.SPECIES_OVERRIDES.includes(pokemon.speciesId)) {
const speciesToCheck = [pokemon.speciesId]; const speciesToCheck = [ pokemon.speciesId ];
while (speciesToCheck.length) { while (speciesToCheck.length) {
const checking = speciesToCheck.pop(); const checking = speciesToCheck.pop();
if (checking && pokemonEvolutions.hasOwnProperty(checking)) { if (checking && pokemonEvolutions.hasOwnProperty(checking)) {
@ -782,9 +783,9 @@ export class SingleTypeChallenge extends Challenge {
overrideValue = this.value; overrideValue = this.value;
} }
const type = i18next.t(`pokemonInfo:Type.${Type[this.value - 1]}`); const type = i18next.t(`pokemonInfo:Type.${Type[this.value - 1]}`);
const typeColor = `[color=${TypeColor[Type[this.value-1]]}][shadow=${TypeShadow[Type[this.value-1]]}]${type}[/shadow][/color]`; const typeColor = `[color=${TypeColor[Type[this.value - 1]]}][shadow=${TypeShadow[Type[this.value - 1]]}]${type}[/shadow][/color]`;
const defaultDesc = i18next.t("challenges:singleType.desc_default"); const defaultDesc = i18next.t("challenges:singleType.desc_default");
const typeDesc = i18next.t("challenges:singleType.desc", {type: typeColor}); const typeDesc = i18next.t("challenges:singleType.desc", { type: typeColor });
return this.value === 0 ? defaultDesc : typeDesc; return this.value === 0 ? defaultDesc : typeDesc;
} }
@ -814,7 +815,7 @@ export class FreshStartChallenge extends Challenge {
applyStarterCost(species: Species, cost: Utils.NumberHolder): boolean { applyStarterCost(species: Species, cost: Utils.NumberHolder): boolean {
if (defaultStarterSpecies.includes(species)) { if (defaultStarterSpecies.includes(species)) {
cost.value = speciesStarters[species]; cost.value = speciesStarterCosts[species];
return true; return true;
} }
return false; return false;
@ -829,7 +830,7 @@ export class FreshStartChallenge extends Challenge {
pokemon.shiny = false; // Not shiny pokemon.shiny = false; // Not shiny
pokemon.variant = 0; // Not shiny pokemon.variant = 0; // Not shiny
pokemon.formIndex = 0; // Froakie should be base form pokemon.formIndex = 0; // Froakie should be base form
pokemon.ivs = [10, 10, 10, 10, 10, 10]; // Default IVs of 10 for all stats pokemon.ivs = [ 10, 10, 10, 10, 10, 10 ]; // Default IVs of 10 for all stats
return true; return true;
} }
@ -896,7 +897,7 @@ export class LowerStarterMaxCostChallenge extends Challenge {
} }
applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder): boolean { applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder): boolean {
if (speciesStarters[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;
} }

View File

@ -1,10 +1,11 @@
import { PartyMemberStrength } from "#enums/party-member-strength"; import { PartyMemberStrength } from "#enums/party-member-strength";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import BattleScene from "../battle-scene"; import BattleScene from "#app/battle-scene";
import { PlayerPokemon } from "../field/pokemon"; import { PlayerPokemon } from "#app/field/pokemon";
import { Starter } from "../ui/starter-select-ui-handler"; import { Starter } from "#app/ui/starter-select-ui-handler";
import * as Utils from "../utils"; import * as Utils from "#app/utils";
import PokemonSpecies, { PokemonSpeciesForm, getPokemonSpecies, getPokemonSpeciesForm, speciesStarters } from "./pokemon-species"; import PokemonSpecies, { PokemonSpeciesForm, getPokemonSpecies, getPokemonSpeciesForm } from "#app/data/pokemon-species";
import { speciesStarterCosts } from "#app/data/balance/starters";
export interface DailyRunConfig { export interface DailyRunConfig {
seed: integer; seed: integer;
@ -46,9 +47,9 @@ export function getDailyRunStarters(scene: BattleScene, seed: string): Starter[]
for (let c = 0; c < starterCosts.length; c++) { for (let c = 0; c < starterCosts.length; c++) {
const cost = starterCosts[c]; const cost = starterCosts[c];
const costSpecies = Object.keys(speciesStarters) const costSpecies = Object.keys(speciesStarterCosts)
.map(s => parseInt(s) as Species) .map(s => parseInt(s) as Species)
.filter(s => speciesStarters[s] === cost); .filter(s => speciesStarterCosts[s] === cost);
const randPkmSpecies = getPokemonSpecies(Utils.randSeedItem(costSpecies)); const randPkmSpecies = getPokemonSpecies(Utils.randSeedItem(costSpecies));
const starterSpecies = getPokemonSpecies(randPkmSpecies.getTrainerSpeciesForLevel(startingLevel, true, PartyMemberStrength.STRONGER)); const starterSpecies = getPokemonSpecies(randPkmSpecies.getTrainerSpeciesForLevel(startingLevel, true, PartyMemberStrength.STRONGER));
starters.push(getDailyRunStarter(scene, starterSpecies, startingLevel)); starters.push(getDailyRunStarter(scene, starterSpecies, startingLevel));

View File

@ -3123,44 +3123,44 @@ export const trainerTypeDialogue: TrainerTypeDialogue = {
export const doubleBattleDialogue = { export const doubleBattleDialogue = {
"blue_red_double": { "blue_red_double": {
encounter: ["doubleBattleDialogue:blue_red_double.encounter.1"], encounter: [ "doubleBattleDialogue:blue_red_double.encounter.1" ],
victory: ["doubleBattleDialogue:blue_red_double.victory.1"] victory: [ "doubleBattleDialogue:blue_red_double.victory.1" ]
}, },
"red_blue_double": { "red_blue_double": {
encounter: ["doubleBattleDialogue:red_blue_double.encounter.1"], encounter: [ "doubleBattleDialogue:red_blue_double.encounter.1" ],
victory: ["doubleBattleDialogue:red_blue_double.victory.1"] victory: [ "doubleBattleDialogue:red_blue_double.victory.1" ]
}, },
"tate_liza_double": { "tate_liza_double": {
encounter: ["doubleBattleDialogue:tate_liza_double.encounter.1"], encounter: [ "doubleBattleDialogue:tate_liza_double.encounter.1" ],
victory: ["doubleBattleDialogue:tate_liza_double.victory.1"] victory: [ "doubleBattleDialogue:tate_liza_double.victory.1" ]
}, },
"liza_tate_double": { "liza_tate_double": {
encounter: ["doubleBattleDialogue:liza_tate_double.encounter.1"], encounter: [ "doubleBattleDialogue:liza_tate_double.encounter.1" ],
victory: [ "doubleBattleDialogue:liza_tate_double.victory.1"] victory: [ "doubleBattleDialogue:liza_tate_double.victory.1" ]
}, },
"wallace_steven_double": { "wallace_steven_double": {
encounter: [ "doubleBattleDialogue:wallace_steven_double.encounter.1"], encounter: [ "doubleBattleDialogue:wallace_steven_double.encounter.1" ],
victory: [ "doubleBattleDialogue:wallace_steven_double.victory.1"] victory: [ "doubleBattleDialogue:wallace_steven_double.victory.1" ]
}, },
"steven_wallace_double": { "steven_wallace_double": {
encounter: [ "doubleBattleDialogue:steven_wallace_double.encounter.1"], encounter: [ "doubleBattleDialogue:steven_wallace_double.encounter.1" ],
victory: [ "doubleBattleDialogue:steven_wallace_double.victory.1"] victory: [ "doubleBattleDialogue:steven_wallace_double.victory.1" ]
}, },
"alder_iris_double": { "alder_iris_double": {
encounter: [ "doubleBattleDialogue:alder_iris_double.encounter.1"], encounter: [ "doubleBattleDialogue:alder_iris_double.encounter.1" ],
victory: [ "doubleBattleDialogue:alder_iris_double.victory.1"] victory: [ "doubleBattleDialogue:alder_iris_double.victory.1" ]
}, },
"iris_alder_double": { "iris_alder_double": {
encounter: [ "doubleBattleDialogue:iris_alder_double.encounter.1"], encounter: [ "doubleBattleDialogue:iris_alder_double.encounter.1" ],
victory: [ "doubleBattleDialogue:iris_alder_double.victory.1"] victory: [ "doubleBattleDialogue:iris_alder_double.victory.1" ]
}, },
"marnie_piers_double": { "marnie_piers_double": {
encounter: [ "doubleBattleDialogue:marnie_piers_double.encounter.1"], encounter: [ "doubleBattleDialogue:marnie_piers_double.encounter.1" ],
victory: [ "doubleBattleDialogue:marnie_piers_double.victory.1"] victory: [ "doubleBattleDialogue:marnie_piers_double.victory.1" ]
}, },
"piers_marnie_double": { "piers_marnie_double": {
encounter: [ "doubleBattleDialogue:piers_marnie_double.encounter.1"], encounter: [ "doubleBattleDialogue:piers_marnie_double.encounter.1" ],
victory: [ "doubleBattleDialogue:piers_marnie_double.victory.1"] victory: [ "doubleBattleDialogue:piers_marnie_double.victory.1" ]
}, },
@ -3193,7 +3193,7 @@ export function initTrainerTypeDialogue(): void {
const trainerTypes = Object.keys(trainerTypeDialogue).map(t => parseInt(t) as TrainerType); const trainerTypes = Object.keys(trainerTypeDialogue).map(t => parseInt(t) as TrainerType);
for (const trainerType of trainerTypes) { for (const trainerType of trainerTypes) {
const messages = trainerTypeDialogue[trainerType]; const messages = trainerTypeDialogue[trainerType];
const messageTypes = ["encounter", "victory", "defeat"]; const messageTypes = [ "encounter", "victory", "defeat" ];
for (const messageType of messageTypes) { for (const messageType of messageTypes) {
if (Array.isArray(messages)) { if (Array.isArray(messages)) {
if (messages[0][messageType]) { if (messages[0][messageType]) {

View File

@ -48,7 +48,7 @@ export class EggHatchData {
seenCount: currDexEntry.seenCount, seenCount: currDexEntry.seenCount,
caughtCount: currDexEntry.caughtCount, caughtCount: currDexEntry.caughtCount,
hatchedCount: currDexEntry.hatchedCount, hatchedCount: currDexEntry.hatchedCount,
ivs: [...currDexEntry.ivs] ivs: [ ...currDexEntry.ivs ]
}; };
this.starterDataEntryBeforeUpdate = { this.starterDataEntryBeforeUpdate = {
moveset: currStarterDataEntry.moveset, moveset: currStarterDataEntry.moveset,

View File

@ -1,30 +1,19 @@
import BattleScene from "../battle-scene"; import BattleScene from "#app/battle-scene";
import PokemonSpecies, { getPokemonSpecies, speciesStarters } from "./pokemon-species"; import PokemonSpecies, { getPokemonSpecies } from "#app/data/pokemon-species";
import { VariantTier } from "../enums/variant-tier"; import { speciesStarterCosts } from "#app/data/balance/starters";
import * as Utils from "../utils"; import { VariantTier } from "#enums/variant-tier";
import * as Utils from "#app/utils";
import Overrides from "#app/overrides"; import Overrides from "#app/overrides";
import { pokemonPrevolutions } from "./pokemon-evolutions"; import { pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions";
import { PlayerPokemon } from "#app/field/pokemon"; import { PlayerPokemon } from "#app/field/pokemon";
import i18next from "i18next"; import i18next from "i18next";
import { EggTier } from "#enums/egg-type"; import { EggTier } from "#enums/egg-type";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import { EggSourceType } from "#app/enums/egg-source-types"; import { EggSourceType } from "#enums/egg-source-types";
import { MANAPHY_EGG_MANAPHY_RATE, SAME_SPECIES_EGG_HA_RATE, GACHA_EGG_HA_RATE, GACHA_DEFAULT_RARE_EGGMOVE_RATE, SAME_SPECIES_EGG_RARE_EGGMOVE_RATE, GACHA_MOVE_UP_RARE_EGGMOVE_RATE, GACHA_DEFAULT_SHINY_RATE, GACHA_SHINY_UP_SHINY_RATE, SAME_SPECIES_EGG_SHINY_RATE, EGG_PITY_LEGENDARY_THRESHOLD, EGG_PITY_EPIC_THRESHOLD, EGG_PITY_RARE_THRESHOLD, SHINY_VARIANT_CHANCE, SHINY_EPIC_CHANCE, GACHA_DEFAULT_COMMON_EGG_THRESHOLD, GACHA_DEFAULT_RARE_EGG_THRESHOLD, GACHA_DEFAULT_EPIC_EGG_THRESHOLD, GACHA_LEGENDARY_UP_THRESHOLD_OFFSET, HATCH_WAVES_MANAPHY_EGG, HATCH_WAVES_COMMON_EGG, HATCH_WAVES_RARE_EGG, HATCH_WAVES_EPIC_EGG, HATCH_WAVES_LEGENDARY_EGG } from "#app/data/balance/rates";
export const EGG_SEED = 1073741824; export const EGG_SEED = 1073741824;
// Rates for specific random properties in 1/x
const DEFAULT_SHINY_RATE = 128;
const GACHA_SHINY_UP_SHINY_RATE = 64;
const SAME_SPECIES_EGG_SHINY_RATE = 12;
const SAME_SPECIES_EGG_HA_RATE = 8;
const MANAPHY_EGG_MANAPHY_RATE = 8;
const GACHA_EGG_HA_RATE = 192;
// 1/x for legendary eggs, 1/x*2 for epic eggs, 1/x*4 for rare eggs, and 1/x*8 for common eggs
const DEFAULT_RARE_EGGMOVE_RATE = 6;
const SAME_SPECIES_EGG_RARE_EGGMOVE_RATE = 3;
const GACHA_MOVE_UP_RARE_EGGMOVE_RATE = 3;
/** Egg options to override egg properties */ /** Egg options to override egg properties */
export interface IEggOptions { export interface IEggOptions {
/** Id. Used to check if egg type will be manaphy (id % 204 === 0) */ /** Id. Used to check if egg type will be manaphy (id % 204 === 0) */
@ -299,7 +288,7 @@ export class Egg {
public getEggTypeDescriptor(scene: BattleScene): string { public getEggTypeDescriptor(scene: BattleScene): string {
switch (this.sourceType) { switch (this.sourceType) {
case EggSourceType.SAME_SPECIES_EGG: case EggSourceType.SAME_SPECIES_EGG:
return this._eggDescriptor ?? i18next.t("egg:sameSpeciesEgg", { species: getPokemonSpecies(this._species).getName()}); return this._eggDescriptor ?? i18next.t("egg:sameSpeciesEgg", { species: getPokemonSpecies(this._species).getName() });
case EggSourceType.GACHA_LEGENDARY: case EggSourceType.GACHA_LEGENDARY:
return this._eggDescriptor ?? `${i18next.t("egg:gachaTypeLegendary")} (${getPokemonSpecies(getLegendaryGachaSpeciesForTimestamp(scene, this.timestamp)).getName()})`; return this._eggDescriptor ?? `${i18next.t("egg:gachaTypeLegendary")} (${getPokemonSpecies(getLegendaryGachaSpeciesForTimestamp(scene, this.timestamp)).getName()})`;
case EggSourceType.GACHA_SHINY: case EggSourceType.GACHA_SHINY:
@ -323,7 +312,7 @@ export class Egg {
//// ////
private rollEggMoveIndex() { private rollEggMoveIndex() {
let baseChance = DEFAULT_RARE_EGGMOVE_RATE; let baseChance = GACHA_DEFAULT_RARE_EGGMOVE_RATE;
switch (this._sourceType) { switch (this._sourceType) {
case EggSourceType.SAME_SPECIES_EGG: case EggSourceType.SAME_SPECIES_EGG:
baseChance = SAME_SPECIES_EGG_RARE_EGGMOVE_RATE; baseChance = SAME_SPECIES_EGG_RARE_EGGMOVE_RATE;
@ -341,24 +330,24 @@ export class Egg {
private getEggTierDefaultHatchWaves(eggTier?: EggTier): number { private getEggTierDefaultHatchWaves(eggTier?: EggTier): number {
if (this._species === Species.PHIONE || this._species === Species.MANAPHY) { if (this._species === Species.PHIONE || this._species === Species.MANAPHY) {
return 50; return HATCH_WAVES_MANAPHY_EGG;
} }
switch (eggTier ?? this._tier) { switch (eggTier ?? this._tier) {
case EggTier.COMMON: case EggTier.COMMON:
return 10; return HATCH_WAVES_COMMON_EGG;
case EggTier.GREAT: case EggTier.GREAT:
return 25; return HATCH_WAVES_RARE_EGG;
case EggTier.ULTRA: case EggTier.ULTRA:
return 50; return HATCH_WAVES_EPIC_EGG;
} }
return 100; return HATCH_WAVES_LEGENDARY_EGG;
} }
private rollEggTier(): EggTier { private rollEggTier(): EggTier {
const tierValueOffset = this._sourceType === EggSourceType.GACHA_LEGENDARY ? 1 : 0; const tierValueOffset = this._sourceType === EggSourceType.GACHA_LEGENDARY ? GACHA_LEGENDARY_UP_THRESHOLD_OFFSET : 0;
const tierValue = Utils.randInt(256); const tierValue = Utils.randInt(256);
return tierValue >= 52 + tierValueOffset ? EggTier.COMMON : tierValue >= 8 + tierValueOffset ? EggTier.GREAT : tierValue >= 1 + tierValueOffset ? EggTier.ULTRA : EggTier.MASTER; return tierValue >= GACHA_DEFAULT_COMMON_EGG_THRESHOLD + tierValueOffset ? EggTier.COMMON : tierValue >= GACHA_DEFAULT_RARE_EGG_THRESHOLD + tierValueOffset ? EggTier.GREAT : tierValue >= GACHA_DEFAULT_EPIC_EGG_THRESHOLD + tierValueOffset ? EggTier.ULTRA : EggTier.MASTER;
} }
private rollSpecies(scene: BattleScene): Species | null { private rollSpecies(scene: BattleScene): Species | null {
@ -407,10 +396,10 @@ export class Egg {
break; break;
} }
const ignoredSpecies = [Species.PHIONE, Species.MANAPHY, Species.ETERNATUS]; const ignoredSpecies = [ Species.PHIONE, Species.MANAPHY, Species.ETERNATUS ];
let speciesPool = Object.keys(speciesStarters) let speciesPool = Object.keys(speciesStarterCosts)
.filter(s => speciesStarters[s] >= minStarterValue && speciesStarters[s] <= maxStarterValue) .filter(s => speciesStarterCosts[s] >= minStarterValue && speciesStarterCosts[s] <= maxStarterValue)
.map(s => parseInt(s) as Species) .map(s => parseInt(s) as Species)
.filter(s => !pokemonPrevolutions.hasOwnProperty(s) && getPokemonSpecies(s).isObtainable() && ignoredSpecies.indexOf(s) === -1); .filter(s => !pokemonPrevolutions.hasOwnProperty(s) && getPokemonSpecies(s).isObtainable() && ignoredSpecies.indexOf(s) === -1);
@ -441,7 +430,7 @@ export class Egg {
let totalWeight = 0; let totalWeight = 0;
const speciesWeights : number[] = []; const speciesWeights : number[] = [];
for (const speciesId of speciesPool) { for (const speciesId of speciesPool) {
let weight = Math.floor((((maxStarterValue - speciesStarters[speciesId]) / ((maxStarterValue - minStarterValue) + 1)) * 1.5 + 1) * 100); let weight = Math.floor((((maxStarterValue - speciesStarterCosts[speciesId]) / ((maxStarterValue - minStarterValue) + 1)) * 1.5 + 1) * 100);
const species = getPokemonSpecies(speciesId); const species = getPokemonSpecies(speciesId);
if (species.isRegional()) { if (species.isRegional()) {
weight = Math.floor(weight / 2); weight = Math.floor(weight / 2);
@ -475,7 +464,7 @@ export class Egg {
* @returns True if the egg is shiny * @returns True if the egg is shiny
**/ **/
private rollShiny(): boolean { private rollShiny(): boolean {
let shinyChance = DEFAULT_SHINY_RATE; let shinyChance = GACHA_DEFAULT_SHINY_RATE;
switch (this._sourceType) { switch (this._sourceType) {
case EggSourceType.GACHA_SHINY: case EggSourceType.GACHA_SHINY:
shinyChance = GACHA_SHINY_UP_SHINY_RATE; shinyChance = GACHA_SHINY_UP_SHINY_RATE;
@ -498,9 +487,9 @@ export class Egg {
} }
const rand = Utils.randSeedInt(10); const rand = Utils.randSeedInt(10);
if (rand >= 4) { if (rand >= SHINY_VARIANT_CHANCE) {
return VariantTier.STANDARD; // 6/10 return VariantTier.STANDARD; // 6/10
} else if (rand >= 1) { } else if (rand >= SHINY_EPIC_CHANCE) {
return VariantTier.RARE; // 3/10 return VariantTier.RARE; // 3/10
} else { } else {
return VariantTier.EPIC; // 1/10 return VariantTier.EPIC; // 1/10
@ -508,16 +497,16 @@ export class Egg {
} }
private checkForPityTierOverrides(scene: BattleScene): void { private checkForPityTierOverrides(scene: BattleScene): void {
const tierValueOffset = this._sourceType === EggSourceType.GACHA_LEGENDARY ? 1 : 0; const tierValueOffset = this._sourceType === EggSourceType.GACHA_LEGENDARY ? GACHA_LEGENDARY_UP_THRESHOLD_OFFSET : 0;
scene.gameData.eggPity[EggTier.GREAT] += 1; scene.gameData.eggPity[EggTier.GREAT] += 1;
scene.gameData.eggPity[EggTier.ULTRA] += 1; scene.gameData.eggPity[EggTier.ULTRA] += 1;
scene.gameData.eggPity[EggTier.MASTER] += 1 + tierValueOffset; scene.gameData.eggPity[EggTier.MASTER] += 1 + tierValueOffset;
// These numbers are roughly the 80% mark. That is, 80% of the time you'll get an egg before this gets triggered. // These numbers are roughly the 80% mark. That is, 80% of the time you'll get an egg before this gets triggered.
if (scene.gameData.eggPity[EggTier.MASTER] >= 412 && this._tier === EggTier.COMMON) { if (scene.gameData.eggPity[EggTier.MASTER] >= EGG_PITY_LEGENDARY_THRESHOLD && this._tier === EggTier.COMMON) {
this._tier = EggTier.MASTER; this._tier = EggTier.MASTER;
} else if (scene.gameData.eggPity[EggTier.ULTRA] >= 59 && this._tier === EggTier.COMMON) { } else if (scene.gameData.eggPity[EggTier.ULTRA] >= EGG_PITY_EPIC_THRESHOLD && this._tier === EggTier.COMMON) {
this._tier = EggTier.ULTRA; this._tier = EggTier.ULTRA;
} else if (scene.gameData.eggPity[EggTier.GREAT] >= 9 && this._tier === EggTier.COMMON) { } else if (scene.gameData.eggPity[EggTier.GREAT] >= EGG_PITY_RARE_THRESHOLD && this._tier === EggTier.COMMON) {
this._tier = EggTier.GREAT; this._tier = EggTier.GREAT;
} }
scene.gameData.eggPity[this._tier] = 0; scene.gameData.eggPity[this._tier] = 0;
@ -544,7 +533,7 @@ export class Egg {
} }
private getEggTierFromSpeciesStarterValue(): EggTier { private getEggTierFromSpeciesStarterValue(): EggTier {
const speciesStartValue = speciesStarters[this.species]; const speciesStartValue = speciesStarterCosts[this.species];
if (speciesStartValue >= 1 && speciesStartValue <= 3) { if (speciesStartValue >= 1 && speciesStartValue <= 3) {
return EggTier.COMMON; return EggTier.COMMON;
} }
@ -567,7 +556,7 @@ export class Egg {
} }
export function getLegendaryGachaSpeciesForTimestamp(scene: BattleScene, timestamp: number): Species { export function getLegendaryGachaSpeciesForTimestamp(scene: BattleScene, timestamp: number): Species {
const legendarySpecies = Object.entries(speciesStarters) const legendarySpecies = Object.entries(speciesStarterCosts)
.filter(s => s[1] >= 8 && s[1] <= 9) .filter(s => s[1] >= 8 && s[1] <= 9)
.map(s => parseInt(s[0])) .map(s => parseInt(s[0]))
.filter(s => getPokemonSpecies(s).isObtainable()); .filter(s => getPokemonSpecies(s).isObtainable());
@ -594,7 +583,7 @@ export function getLegendaryGachaSpeciesForTimestamp(scene: BattleScene, timesta
* @returns The egg tier of a given pokemon species * @returns The egg tier of a given pokemon species
*/ */
export function getEggTierForSpecies(pokemonSpecies :PokemonSpecies): EggTier { export function getEggTierForSpecies(pokemonSpecies :PokemonSpecies): EggTier {
const speciesBaseValue = speciesStarters[pokemonSpecies.getRootSpeciesId()]; const speciesBaseValue = speciesStarterCosts[pokemonSpecies.getRootSpeciesId()];
if (speciesBaseValue <= 3) { if (speciesBaseValue <= 3) {
return EggTier.COMMON; return EggTier.COMMON;
} else if (speciesBaseValue <= 5) { } else if (speciesBaseValue <= 5) {

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,7 @@ 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/game-mode";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */
const namespace = "mysteryEncounter:aTrainersTest"; const namespace = "mysteryEncounters/aTrainersTest";
/** /**
* A Trainer's Test encounter. * A Trainer's Test encounter.
@ -32,7 +32,7 @@ export const ATrainersTestEncounter: MysteryEncounter =
.withIntroSpriteConfigs([]) // These are set in onInit() .withIntroSpriteConfigs([]) // These are set in onInit()
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
}, },
]) ])
.withAutoHideIntroVisuals(false) .withAutoHideIntroVisuals(false)
@ -76,24 +76,24 @@ export const ATrainersTestEncounter: MysteryEncounter =
encounter.dialogue.intro = [ encounter.dialogue.intro = [
{ {
speaker: `trainerNames:${trainerNameKey}`, speaker: `trainerNames:${trainerNameKey}`,
text: `${namespace}.${trainerNameKey}.intro_dialogue` text: `${namespace}:${trainerNameKey}.intro_dialogue`
} }
]; ];
encounter.options[0].dialogue!.selected = [ encounter.options[0].dialogue!.selected = [
{ {
speaker: `trainerNames:${trainerNameKey}`, speaker: `trainerNames:${trainerNameKey}`,
text: `${namespace}.${trainerNameKey}.accept` text: `${namespace}:${trainerNameKey}.accept`
} }
]; ];
encounter.options[1].dialogue!.selected = [ encounter.options[1].dialogue!.selected = [
{ {
speaker: `trainerNames:${trainerNameKey}`, speaker: `trainerNames:${trainerNameKey}`,
text: `${namespace}.${trainerNameKey}.decline` text: `${namespace}:${trainerNameKey}.decline`
} }
]; ];
encounter.setDialogueToken("statTrainerName", i18next.t(`trainerNames:${trainerNameKey}`)); encounter.setDialogueToken("statTrainerName", i18next.t(`trainerNames:${trainerNameKey}`));
const eggDescription = i18next.t(`${namespace}.title`) + ":\n" + i18next.t(`trainerNames:${trainerNameKey}`); const eggDescription = i18next.t(`${namespace}:title`) + ":\n" + i18next.t(`trainerNames:${trainerNameKey}`);
encounter.misc = { trainerType, trainerNameKey, trainerEggDescription: eggDescription }; encounter.misc = { trainerType, trainerNameKey, trainerEggDescription: eggDescription };
// Trainer config // Trainer config
@ -128,14 +128,14 @@ export const ATrainersTestEncounter: MysteryEncounter =
return true; return true;
}) })
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withIntroDialogue() .withIntroDialogue()
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip` buttonTooltip: `${namespace}:option.1.tooltip`
}, },
async (scene: BattleScene) => { async (scene: BattleScene) => {
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
@ -151,15 +151,15 @@ export const ATrainersTestEncounter: MysteryEncounter =
eggDescriptor: encounter.misc.trainerEggDescription, eggDescriptor: encounter.misc.trainerEggDescription,
tier: EggTier.ULTRA tier: EggTier.ULTRA
}; };
encounter.setDialogueToken("eggType", i18next.t(`${namespace}.eggTypes.epic`)); encounter.setDialogueToken("eggType", i18next.t(`${namespace}:eggTypes.epic`));
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.SACRED_ASH], guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ULTRA], fillRemaining: true }, [eggOptions]); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.SACRED_ASH ], guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ULTRA ], fillRemaining: true }, [ eggOptions ]);
return initBattleWithEnemyConfig(scene, config); return initBattleWithEnemyConfig(scene, config);
} }
) )
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip` buttonTooltip: `${namespace}:option.2.tooltip`
}, },
async (scene: BattleScene) => { async (scene: BattleScene) => {
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
@ -173,14 +173,14 @@ export const ATrainersTestEncounter: MysteryEncounter =
eggDescriptor: encounter.misc.trainerEggDescription, eggDescriptor: encounter.misc.trainerEggDescription,
tier: EggTier.GREAT tier: EggTier.GREAT
}; };
encounter.setDialogueToken("eggType", i18next.t(`${namespace}.eggTypes.rare`)); encounter.setDialogueToken("eggType", i18next.t(`${namespace}:eggTypes.rare`));
setEncounterRewards(scene, { fillRemaining: false, rerollMultiplier: -1 }, [eggOptions]); setEncounterRewards(scene, { fillRemaining: false, rerollMultiplier: -1 }, [ eggOptions ]);
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);
} }
) )
.withOutroDialogue([ .withOutroDialogue([
{ {
text: `${namespace}.outro` text: `${namespace}:outro`
} }
]) ])
.build(); .build();

View File

@ -27,7 +27,7 @@ import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
import i18next from "i18next"; import i18next from "i18next";
/** the i18n namespace for this encounter */ /** the i18n namespace for this encounter */
const namespace = "mysteryEncounter:absoluteAvarice"; const namespace = "mysteryEncounters/absoluteAvarice";
/** /**
* Absolute Avarice encounter. * Absolute Avarice encounter.
@ -163,12 +163,12 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
.withAutoHideIntroVisuals(false) .withAutoHideIntroVisuals(false)
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
} }
]) ])
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
@ -195,7 +195,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
// Can't define stack count on a ModifierType, have to just create separate instances for each stack // Can't define stack count on a ModifierType, have to just create separate instances for each stack
// Overflow berries will be "lost" on the boss, but it's un-catchable anyway // Overflow berries will be "lost" on the boss, but it's un-catchable anyway
for (let i = 0; i < berryMod.stackCount; i++) { for (let i = 0; i < berryMod.stackCount; i++) {
const modifierType = generateModifierType(scene, modifierTypes.BERRY, [berryMod.berryType]) as PokemonHeldItemModifierType; const modifierType = generateModifierType(scene, modifierTypes.BERRY, [ berryMod.berryType ]) as PokemonHeldItemModifierType;
bossModifierConfigs.push({ modifier: modifierType }); bossModifierConfigs.push({ modifier: modifierType });
} }
}); });
@ -204,8 +204,8 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
// SpDef buff below wave 50, +1 to all stats otherwise // SpDef buff below wave 50, +1 to all stats otherwise
const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = scene.currentBattle.waveIndex < 50 ? const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = scene.currentBattle.waveIndex < 50 ?
[Stat.SPDEF] : [ Stat.SPDEF ] :
[Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD]; [ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD ];
// Calculate boss mon // Calculate boss mon
const config: EnemyPartyConfig = { const config: EnemyPartyConfig = {
@ -215,18 +215,18 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
species: getPokemonSpecies(Species.GREEDENT), species: getPokemonSpecies(Species.GREEDENT),
isBoss: true, isBoss: true,
bossSegments: 3, bossSegments: 3,
moveSet: [Moves.THRASH, Moves.BODY_PRESS, Moves.STUFF_CHEEKS, Moves.CRUNCH], moveSet: [ Moves.THRASH, Moves.BODY_PRESS, Moves.STUFF_CHEEKS, Moves.CRUNCH ],
modifierConfigs: bossModifierConfigs, modifierConfigs: bossModifierConfigs,
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON], tags: [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON ],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => { mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
queueEncounterMessage(pokemon.scene, `${namespace}.option.1.boss_enraged`); queueEncounterMessage(pokemon.scene, `${namespace}:option.1.boss_enraged`);
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, statChangesForBattle, 1)); pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, statChangesForBattle, 1));
} }
} }
], ],
}; };
encounter.enemyPartyConfigs = [config]; encounter.enemyPartyConfigs = [ config ];
encounter.setDialogueToken("greedentName", getPokemonSpecies(Species.GREEDENT).getName()); encounter.setDialogueToken("greedentName", getPokemonSpecies(Species.GREEDENT).getName());
return true; return true;
@ -250,11 +250,11 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.1.selected`, text: `${namespace}:option.1.selected`,
}, },
], ],
}) })
@ -274,13 +274,13 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
scene.addModifier(seedModifier, false, false, false, true); scene.addModifier(seedModifier, false, false, false, true);
} }
}); });
queueEncounterMessage(scene, `${namespace}.option.1.food_stash`); queueEncounterMessage(scene, `${namespace}:option.1.food_stash`);
}; };
setEncounterRewards(scene, { fillRemaining: true }, undefined, givePartyPokemonReviverSeeds); setEncounterRewards(scene, { fillRemaining: true }, undefined, givePartyPokemonReviverSeeds);
encounter.startOfBattleEffects.push({ encounter.startOfBattleEffects.push({
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.ENEMY], targets: [ BattlerIndex.ENEMY ],
move: new PokemonMove(Moves.STUFF_CHEEKS), move: new PokemonMove(Moves.STUFF_CHEEKS),
ignorePp: true ignorePp: true
}); });
@ -294,11 +294,11 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.2.selected`, text: `${namespace}:option.2.selected`,
}, },
], ],
}) })
@ -320,7 +320,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
Phaser.Math.RND.shuffle(berryTypesAsArray); Phaser.Math.RND.shuffle(berryTypesAsArray);
const randBerryType = berryTypesAsArray.pop(); const randBerryType = berryTypesAsArray.pop();
const berryModType = generateModifierType(scene, modifierTypes.BERRY, [randBerryType]) as BerryModifierType; const berryModType = generateModifierType(scene, modifierTypes.BERRY, [ randBerryType ]) as BerryModifierType;
applyModifierTypeToPlayerPokemon(scene, pokemon, berryModType); applyModifierTypeToPlayerPokemon(scene, pokemon, berryModType);
} }
} }
@ -336,11 +336,11 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.3.label`, buttonLabel: `${namespace}:option.3.label`,
buttonTooltip: `${namespace}.option.3.tooltip`, buttonTooltip: `${namespace}:option.3.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.3.selected`, text: `${namespace}:option.3.selected`,
}, },
], ],
}) })
@ -355,7 +355,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
// Greedent joins the team, level equal to 2 below highest party member // Greedent joins the team, level equal to 2 below highest party member
const level = getHighestLevelPlayerPokemon(scene, false, true).level - 2; const level = getHighestLevelPlayerPokemon(scene, false, true).level - 2;
const greedent = new EnemyPokemon(scene, getPokemonSpecies(Species.GREEDENT), level, TrainerSlot.NONE, false); const greedent = new EnemyPokemon(scene, getPokemonSpecies(Species.GREEDENT), level, TrainerSlot.NONE, false);
greedent.moveset = [new PokemonMove(Moves.THRASH), new PokemonMove(Moves.BODY_PRESS), new PokemonMove(Moves.STUFF_CHEEKS), new PokemonMove(Moves.SLACK_OFF)]; greedent.moveset = [ new PokemonMove(Moves.THRASH), new PokemonMove(Moves.BODY_PRESS), new PokemonMove(Moves.STUFF_CHEEKS), new PokemonMove(Moves.SLACK_OFF) ];
greedent.passive = true; greedent.passive = true;
transitionMysteryEncounterIntroVisuals(scene, true, true, 500); transitionMysteryEncounterIntroVisuals(scene, true, true, 500);
@ -472,7 +472,7 @@ function doGreedentEatBerries(scene: BattleScene) {
*/ */
function doBerrySpritePile(scene: BattleScene, isEat: boolean = false) { function doBerrySpritePile(scene: BattleScene, isEat: boolean = false) {
const berryAddDelay = 150; const berryAddDelay = 150;
let animationOrder = ["starf", "sitrus", "lansat", "salac", "apicot", "enigma", "liechi", "ganlon", "lum", "petaya", "leppa"]; let animationOrder = [ "starf", "sitrus", "lansat", "salac", "apicot", "enigma", "liechi", "ganlon", "lum", "petaya", "leppa" ];
if (isEat) { if (isEat) {
animationOrder = animationOrder.reverse(); animationOrder = animationOrder.reverse();
} }
@ -496,7 +496,7 @@ function doBerrySpritePile(scene: BattleScene, isEat: boolean = false) {
// Animate Petaya berry falling off the pile // Animate Petaya berry falling off the pile
if (berry === "petaya" && sprite && tintSprite && !isEat) { if (berry === "petaya" && sprite && tintSprite && !isEat) {
scene.time.delayedCall(200, () => { scene.time.delayedCall(200, () => {
doBerryBounce(scene, [sprite, tintSprite], 30, 500); doBerryBounce(scene, [ sprite, tintSprite ], 30, 500);
}); });
} }
}); });

View File

@ -8,14 +8,15 @@ import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/myst
import { AbilityRequirement, CombinationPokemonRequirement, MoveRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements"; import { AbilityRequirement, CombinationPokemonRequirement, MoveRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
import { getHighestStatTotalPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { getHighestStatTotalPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
import { EXTORTION_ABILITIES, EXTORTION_MOVES } from "#app/data/mystery-encounters/requirements/requirement-groups"; import { EXTORTION_ABILITIES, EXTORTION_MOVES } from "#app/data/mystery-encounters/requirements/requirement-groups";
import { getPokemonSpecies, speciesStarters } from "#app/data/pokemon-species"; import { getPokemonSpecies } from "#app/data/pokemon-species";
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/game-mode";
/** the i18n namespace for this encounter */ /** the i18n namespace for this encounter */
const namespace = "mysteryEncounter:offerYouCantRefuse"; const namespace = "mysteryEncounters/anOfferYouCantRefuse";
/** /**
* Money offered starts at base value of Relic Gold, increasing linearly up to 3x Relic Gold based on the starter tier of the Pokemon being purchased * Money offered starts at base value of Relic Gold, increasing linearly up to 3x Relic Gold based on the starter tier of the Pokemon being purchased
@ -56,22 +57,22 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter =
]) ])
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
}, },
{ {
text: `${namespace}.intro_dialogue`, text: `${namespace}:intro_dialogue`,
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
}, },
]) ])
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
const pokemon = getHighestStatTotalPlayerPokemon(scene, true, true); const pokemon = getHighestStatTotalPlayerPokemon(scene, true, true);
const baseSpecies = pokemon.getSpeciesForm().getRootSpeciesId(); const baseSpecies = pokemon.getSpeciesForm().getRootSpeciesId();
const starterValue: number = speciesStarters[baseSpecies] ?? 1; const starterValue: number = speciesStarterCosts[baseSpecies] ?? 1;
const multiplier = Math.max(MONEY_MAXIMUM_MULTIPLIER / 10 * starterValue, MONEY_MINIMUM_MULTIPLIER); const multiplier = Math.max(MONEY_MAXIMUM_MULTIPLIER / 10 * starterValue, MONEY_MINIMUM_MULTIPLIER);
const price = scene.getWaveMoneyAmount(multiplier); const price = scene.getWaveMoneyAmount(multiplier);
@ -104,12 +105,12 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter =
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.1.selected`, text: `${namespace}:option.1.selected`,
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
}, },
], ],
}) })
@ -135,13 +136,13 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter =
new AbilityRequirement(EXTORTION_ABILITIES)) new AbilityRequirement(EXTORTION_ABILITIES))
) )
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
disabledButtonTooltip: `${namespace}.option.2.tooltip_disabled`, disabledButtonTooltip: `${namespace}:option.2.tooltip_disabled`,
selected: [ selected: [
{ {
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
text: `${namespace}.option.2.selected`, text: `${namespace}:option.2.selected`,
}, },
], ],
}) })
@ -159,12 +160,12 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter =
) )
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.3.label`, buttonLabel: `${namespace}:option.3.label`,
buttonTooltip: `${namespace}.option.3.tooltip`, buttonTooltip: `${namespace}:option.3.tooltip`,
selected: [ selected: [
{ {
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
text: `${namespace}.option.3.selected`, text: `${namespace}:option.3.selected`,
}, },
], ],
}, },

View File

@ -33,7 +33,7 @@ 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/game-mode";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */
const namespace = "mysteryEncounter:berriesAbound"; const namespace = "mysteryEncounters/berriesAbound";
/** /**
* Berries Abound encounter. * Berries Abound encounter.
@ -50,7 +50,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
.withIntroSpriteConfigs([]) // Set in onInit() .withIntroSpriteConfigs([]) // Set in onInit()
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
}, },
]) ])
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
@ -69,7 +69,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
isBoss: true isBoss: true
}], }],
}; };
encounter.enemyPartyConfigs = [config]; encounter.enemyPartyConfigs = [ config ];
// Calculate the number of extra berries that player receives // Calculate the number of extra berries that player receives
// 10-40: 2, 40-120: 4, 120-160: 5, 160-180: 7 // 10-40: 2, 40-120: 4, 120-160: 5, 160-180: 7
@ -110,16 +110,16 @@ export const BerriesAboundEncounter: MysteryEncounter =
return true; return true;
}) })
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.1.selected`, text: `${namespace}:option.1.selected`,
}, },
], ],
}, },
@ -129,7 +129,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
const numBerries = encounter.misc.numBerries; const numBerries = encounter.misc.numBerries;
const doBerryRewards = () => { const doBerryRewards = () => {
const berryText = i18next.t(`${namespace}.berries`); const berryText = i18next.t(`${namespace}:berries`);
scene.playSound("item_fanfare"); scene.playSound("item_fanfare");
queueEncounterMessage(scene, i18next.t("battle:rewardGainCount", { modifierName: berryText, count: numBerries })); queueEncounterMessage(scene, i18next.t("battle:rewardGainCount", { modifierName: berryText, count: numBerries }));
@ -157,8 +157,8 @@ export const BerriesAboundEncounter: MysteryEncounter =
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip` buttonTooltip: `${namespace}:option.2.tooltip`
}) })
.withOptionPhase(async (scene: BattleScene) => { .withOptionPhase(async (scene: BattleScene) => {
// Pick race for berries // Pick race for berries
@ -180,7 +180,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
if (speedDiff < 1) { if (speedDiff < 1) {
// Caught and attacked by boss, gets +1 to all stats at start of fight // Caught and attacked by boss, gets +1 to all stats at start of fight
const doBerryRewards = () => { const doBerryRewards = () => {
const berryText = i18next.t(`${namespace}.berries`); const berryText = i18next.t(`${namespace}:berries`);
scene.playSound("item_fanfare"); scene.playSound("item_fanfare");
queueEncounterMessage(scene, i18next.t("battle:rewardGainCount", { modifierName: berryText, count: numBerries })); queueEncounterMessage(scene, i18next.t("battle:rewardGainCount", { modifierName: berryText, count: numBerries }));
@ -193,25 +193,25 @@ export const BerriesAboundEncounter: MysteryEncounter =
// Defense/Spd buffs below wave 50, +1 to all stats otherwise // Defense/Spd buffs below wave 50, +1 to all stats otherwise
const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = scene.currentBattle.waveIndex < 50 ? const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = scene.currentBattle.waveIndex < 50 ?
[Stat.DEF, Stat.SPDEF, Stat.SPD] : [ Stat.DEF, Stat.SPDEF, Stat.SPD ] :
[Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD]; [ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD ];
const config = scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]; const config = scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0];
config.pokemonConfigs![0].tags = [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON]; config.pokemonConfigs![0].tags = [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON ];
config.pokemonConfigs![0].mysteryEncounterBattleEffects = (pokemon: Pokemon) => { config.pokemonConfigs![0].mysteryEncounterBattleEffects = (pokemon: Pokemon) => {
queueEncounterMessage(pokemon.scene, `${namespace}.option.2.boss_enraged`); queueEncounterMessage(pokemon.scene, `${namespace}:option.2.boss_enraged`);
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, statChangesForBattle, 1)); pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, statChangesForBattle, 1));
}; };
setEncounterRewards(scene, { guaranteedModifierTypeOptions: shopOptions, fillRemaining: false }, undefined, doBerryRewards); setEncounterRewards(scene, { guaranteedModifierTypeOptions: shopOptions, fillRemaining: false }, undefined, doBerryRewards);
await showEncounterText(scene, `${namespace}.option.2.selected_bad`); await showEncounterText(scene, `${namespace}:option.2.selected_bad`);
await initBattleWithEnemyConfig(scene, config); await initBattleWithEnemyConfig(scene, config);
return; return;
} else { } else {
// Gains 1 berry for every 10% faster the player's pokemon is than the enemy, up to a max of numBerries, minimum of 2 // Gains 1 berry for every 10% faster the player's pokemon is than the enemy, up to a max of numBerries, minimum of 2
const numBerriesGrabbed = Math.max(Math.min(Math.round((speedDiff - 1)/0.08), numBerries), 2); const numBerriesGrabbed = Math.max(Math.min(Math.round((speedDiff - 1) / 0.08), numBerries), 2);
encounter.setDialogueToken("numBerries", String(numBerriesGrabbed)); encounter.setDialogueToken("numBerries", String(numBerriesGrabbed));
const doFasterBerryRewards = () => { const doFasterBerryRewards = () => {
const berryText = i18next.t(`${namespace}.berries`); const berryText = i18next.t(`${namespace}:berries`);
scene.playSound("item_fanfare"); scene.playSound("item_fanfare");
queueEncounterMessage(scene, i18next.t("battle:rewardGainCount", { modifierName: berryText, count: numBerriesGrabbed })); queueEncounterMessage(scene, i18next.t("battle:rewardGainCount", { modifierName: berryText, count: numBerriesGrabbed }));
@ -224,7 +224,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
setEncounterExp(scene, fastestPokemon.id, encounter.enemyPartyConfigs[0].pokemonConfigs![0].species.baseExp); setEncounterExp(scene, fastestPokemon.id, encounter.enemyPartyConfigs[0].pokemonConfigs![0].species.baseExp);
setEncounterRewards(scene, { guaranteedModifierTypeOptions: shopOptions, fillRemaining: false }, undefined, doFasterBerryRewards); setEncounterRewards(scene, { guaranteedModifierTypeOptions: shopOptions, fillRemaining: false }, undefined, doFasterBerryRewards);
await showEncounterText(scene, `${namespace}.option.2.selected`); await showEncounterText(scene, `${namespace}:option.2.selected`);
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);
} }
}) })
@ -232,11 +232,11 @@ export const BerriesAboundEncounter: MysteryEncounter =
) )
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.3.label`, buttonLabel: `${namespace}:option.3.label`,
buttonTooltip: `${namespace}.option.3.tooltip`, buttonTooltip: `${namespace}:option.3.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.3.selected`, text: `${namespace}:option.3.selected`,
}, },
], ],
}, },
@ -250,7 +250,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
function tryGiveBerry(scene: BattleScene, prioritizedPokemon?: PlayerPokemon) { function tryGiveBerry(scene: BattleScene, prioritizedPokemon?: PlayerPokemon) {
const berryType = randSeedInt(Object.keys(BerryType).filter(s => !isNaN(Number(s))).length) as BerryType; const berryType = randSeedInt(Object.keys(BerryType).filter(s => !isNaN(Number(s))).length) as BerryType;
const berry = generateModifierType(scene, modifierTypes.BERRY, [berryType]) as BerryModifierType; const berry = generateModifierType(scene, modifierTypes.BERRY, [ berryType ]) as BerryModifierType;
const party = scene.getParty(); const party = scene.getParty();

View File

@ -52,7 +52,7 @@ import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
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 */
const namespace = "mysteryEncounter:bugTypeSuperfan"; const namespace = "mysteryEncounters/bugTypeSuperfan";
const POOL_1_POKEMON = [ const POOL_1_POKEMON = [
Species.PARASECT, Species.PARASECT,
@ -181,7 +181,7 @@ const MISC_TUTOR_MOVES = [
/** /**
* Wave breakpoints that determine how strong to make the Bug-Type Superfan's team * Wave breakpoints that determine how strong to make the Bug-Type Superfan's team
*/ */
const WAVE_LEVEL_BREAKPOINTS = [30, 50, 70, 100, 120, 140, 160]; const WAVE_LEVEL_BREAKPOINTS = [ 30, 50, 70, 100, 120, 140, 160 ];
/** /**
* Bug Type Superfan encounter. * Bug Type Superfan encounter.
@ -193,7 +193,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
.withEncounterTier(MysteryEncounterTier.GREAT) .withEncounterTier(MysteryEncounterTier.GREAT)
.withPrimaryPokemonRequirement(new CombinationPokemonRequirement( .withPrimaryPokemonRequirement(new CombinationPokemonRequirement(
// Must have at least 1 Bug type on team, OR have a bug item somewhere on the team // Must have at least 1 Bug type on team, OR have a bug item somewhere on the team
new HeldItemRequirement(["BypassSpeedChanceModifier", "ContactHeldItemTransferChanceModifier"], 1), new HeldItemRequirement([ "BypassSpeedChanceModifier", "ContactHeldItemTransferChanceModifier" ], 1),
new AttackTypeBoosterHeldItemTypeRequirement(Type.BUG, 1), new AttackTypeBoosterHeldItemTypeRequirement(Type.BUG, 1),
new TypeRequirement(Type.BUG, false, 1) new TypeRequirement(Type.BUG, false, 1)
)) ))
@ -203,11 +203,11 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
.withAutoHideIntroVisuals(false) .withAutoHideIntroVisuals(false)
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
}, },
{ {
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
text: `${namespace}.intro_dialogue`, text: `${namespace}:intro_dialogue`,
}, },
]) ])
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
@ -268,7 +268,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
const requiredItems = [ const requiredItems = [
generateModifierType(scene, modifierTypes.QUICK_CLAW), generateModifierType(scene, modifierTypes.QUICK_CLAW),
generateModifierType(scene, modifierTypes.GRIP_CLAW), generateModifierType(scene, modifierTypes.GRIP_CLAW),
generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [Type.BUG]), generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [ Type.BUG ]),
]; ];
const requiredItemString = requiredItems.map(m => m?.name ?? "unknown").join("/"); const requiredItemString = requiredItems.map(m => m?.name ?? "unknown").join("/");
@ -276,17 +276,17 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
return true; return true;
}) })
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [ selected: [
{ {
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
text: `${namespace}.option.1.selected`, text: `${namespace}:option.1.selected`,
}, },
], ],
}, },
@ -317,9 +317,9 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT)
.withPrimaryPokemonRequirement(new TypeRequirement(Type.BUG, false, 1)) // Must have 1 Bug type on team .withPrimaryPokemonRequirement(new TypeRequirement(Type.BUG, false, 1)) // Must have 1 Bug type on team
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
disabledButtonTooltip: `${namespace}.option.2.disabled_tooltip` disabledButtonTooltip: `${namespace}:option.2.disabled_tooltip`
}) })
.withPreOptionPhase(async (scene: BattleScene) => { .withPreOptionPhase(async (scene: BattleScene) => {
// Player shows off their bug types // Player shows off their bug types
@ -327,36 +327,36 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
// Player gets different rewards depending on the number of bug types they have // Player gets different rewards depending on the number of bug types they have
const numBugTypes = scene.getParty().filter(p => p.isOfType(Type.BUG, true)).length; const numBugTypes = scene.getParty().filter(p => p.isOfType(Type.BUG, true)).length;
const numBugTypesText = i18next.t(`${namespace}.numBugTypes`, { count: numBugTypes }); const numBugTypesText = i18next.t(`${namespace}:numBugTypes`, { count: numBugTypes });
encounter.setDialogueToken("numBugTypes", numBugTypesText); encounter.setDialogueToken("numBugTypes", numBugTypesText);
if (numBugTypes < 2) { if (numBugTypes < 2) {
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.SUPER_LURE, modifierTypes.GREAT_BALL], fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.SUPER_LURE, modifierTypes.GREAT_BALL ], fillRemaining: false });
encounter.selectedOption!.dialogue!.selected = [ encounter.selectedOption!.dialogue!.selected = [
{ {
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
text: `${namespace}.option.2.selected_0_to_1`, text: `${namespace}:option.2.selected_0_to_1`,
}, },
]; ];
} else if (numBugTypes < 4) { } else if (numBugTypes < 4) {
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.QUICK_CLAW, modifierTypes.MAX_LURE, modifierTypes.ULTRA_BALL], fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.QUICK_CLAW, modifierTypes.MAX_LURE, modifierTypes.ULTRA_BALL ], fillRemaining: false });
encounter.selectedOption!.dialogue!.selected = [ encounter.selectedOption!.dialogue!.selected = [
{ {
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
text: `${namespace}.option.2.selected_2_to_3`, text: `${namespace}:option.2.selected_2_to_3`,
}, },
]; ];
} else if (numBugTypes < 6) { } else if (numBugTypes < 6) {
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.GRIP_CLAW, modifierTypes.MAX_LURE, modifierTypes.ROGUE_BALL], fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.GRIP_CLAW, modifierTypes.MAX_LURE, modifierTypes.ROGUE_BALL ], fillRemaining: false });
encounter.selectedOption!.dialogue!.selected = [ encounter.selectedOption!.dialogue!.selected = [
{ {
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
text: `${namespace}.option.2.selected_4_to_5`, text: `${namespace}:option.2.selected_4_to_5`,
}, },
]; ];
} else { } else {
// If player has any evolution/form change items that are valid for their party, will spawn one of those items in addition to a Master Ball // If player has any evolution/form change items that are valid for their party, will spawn one of those items in addition to a Master Ball
const modifierOptions: ModifierTypeOption[] = [generateModifierTypeOption(scene, modifierTypes.MASTER_BALL)!, generateModifierTypeOption(scene, modifierTypes.MAX_LURE)!]; const modifierOptions: ModifierTypeOption[] = [ generateModifierTypeOption(scene, modifierTypes.MASTER_BALL)!, generateModifierTypeOption(scene, modifierTypes.MAX_LURE)! ];
const specialOptions: ModifierTypeOption[] = []; const specialOptions: ModifierTypeOption[] = [];
const nonRareEvolutionModifier = generateModifierTypeOption(scene, modifierTypes.EVOLUTION_ITEM); const nonRareEvolutionModifier = generateModifierTypeOption(scene, modifierTypes.EVOLUTION_ITEM);
@ -382,8 +382,8 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
setEncounterRewards(scene, { guaranteedModifierTypeOptions: modifierOptions, fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeOptions: modifierOptions, fillRemaining: false });
encounter.selectedOption!.dialogue!.selected = [ encounter.selectedOption!.dialogue!.selected = [
{ {
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
text: `${namespace}.option.2.selected_6`, text: `${namespace}:option.2.selected_6`,
}, },
]; ];
} }
@ -397,23 +397,23 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT)
.withPrimaryPokemonRequirement(new CombinationPokemonRequirement( .withPrimaryPokemonRequirement(new CombinationPokemonRequirement(
// Meets one or both of the below reqs // Meets one or both of the below reqs
new HeldItemRequirement(["BypassSpeedChanceModifier", "ContactHeldItemTransferChanceModifier"], 1), new HeldItemRequirement([ "BypassSpeedChanceModifier", "ContactHeldItemTransferChanceModifier" ], 1),
new AttackTypeBoosterHeldItemTypeRequirement(Type.BUG, 1) new AttackTypeBoosterHeldItemTypeRequirement(Type.BUG, 1)
)) ))
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.3.label`, buttonLabel: `${namespace}:option.3.label`,
buttonTooltip: `${namespace}.option.3.tooltip`, buttonTooltip: `${namespace}:option.3.tooltip`,
disabledButtonTooltip: `${namespace}.option.3.disabled_tooltip`, disabledButtonTooltip: `${namespace}:option.3.disabled_tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.3.selected`, text: `${namespace}:option.3.selected`,
}, },
{ {
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
text: `${namespace}.option.3.selected_dialogue`, text: `${namespace}:option.3.selected_dialogue`,
}, },
], ],
secondOptionPrompt: `${namespace}.option.3.select_prompt`, secondOptionPrompt: `${namespace}:option.3.select_prompt`,
}) })
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => { .withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
@ -452,7 +452,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
(item instanceof AttackTypeBoosterModifier && (item.type as AttackTypeBoosterModifierType).moveType === Type.BUG); (item instanceof AttackTypeBoosterModifier && (item.type as AttackTypeBoosterModifierType).moveType === Type.BUG);
}); });
if (!hasValidItem) { if (!hasValidItem) {
return getEncounterText(scene, `${namespace}.option.3.invalid_selection`) ?? null; return getEncounterText(scene, `${namespace}:option.3.invalid_selection`) ?? null;
} }
return null; return null;
@ -474,13 +474,13 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
const bugNet = generateModifierTypeOption(scene, modifierTypes.MYSTERY_ENCOUNTER_GOLDEN_BUG_NET)!; const bugNet = generateModifierTypeOption(scene, modifierTypes.MYSTERY_ENCOUNTER_GOLDEN_BUG_NET)!;
bugNet.type.tier = ModifierTier.ROGUE; bugNet.type.tier = ModifierTier.ROGUE;
setEncounterRewards(scene, { guaranteedModifierTypeOptions: [bugNet], guaranteedModifierTypeFuncs: [modifierTypes.REVIVER_SEED], fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeOptions: [ bugNet ], guaranteedModifierTypeFuncs: [ modifierTypes.REVIVER_SEED ], fillRemaining: false });
leaveEncounterWithoutBattle(scene, true); leaveEncounterWithoutBattle(scene, true);
}) })
.build()) .build())
.withOutroDialogue([ .withOutroDialogue([
{ {
text: `${namespace}.outro`, text: `${namespace}:outro`,
}, },
]) ])
.build(); .build();
@ -535,7 +535,7 @@ function getTrainerConfigForWave(waveIndex: number) {
})) }))
.setPartyMemberFunc(2, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true)) .setPartyMemberFunc(2, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true))
.setPartyMemberFunc(3, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true)) .setPartyMemberFunc(3, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([pool3Mon.species], TrainerSlot.TRAINER, true, p => { .setPartyMemberFunc(4, getRandomPartyMemberFunc([ pool3Mon.species ], TrainerSlot.TRAINER, true, p => {
if (!isNullOrUndefined(pool3Mon.formIndex)) { if (!isNullOrUndefined(pool3Mon.formIndex)) {
p.formIndex = pool3Mon.formIndex; p.formIndex = pool3Mon.formIndex;
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
@ -558,14 +558,14 @@ function getTrainerConfigForWave(waveIndex: number) {
p.generateName(); p.generateName();
})) }))
.setPartyMemberFunc(2, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true)) .setPartyMemberFunc(2, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([pool3Mon.species], TrainerSlot.TRAINER, true, p => { .setPartyMemberFunc(3, getRandomPartyMemberFunc([ pool3Mon.species ], TrainerSlot.TRAINER, true, p => {
if (!isNullOrUndefined(pool3Mon.formIndex)) { if (!isNullOrUndefined(pool3Mon.formIndex)) {
p.formIndex = pool3Mon.formIndex; p.formIndex = pool3Mon.formIndex;
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.generateName(); p.generateName();
} }
})) }))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([pool3Mon2.species], TrainerSlot.TRAINER, true, p => { .setPartyMemberFunc(4, getRandomPartyMemberFunc([ pool3Mon2.species ], TrainerSlot.TRAINER, true, p => {
if (!isNullOrUndefined(pool3Mon2.formIndex)) { if (!isNullOrUndefined(pool3Mon2.formIndex)) {
p.formIndex = pool3Mon2.formIndex; p.formIndex = pool3Mon2.formIndex;
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
@ -586,7 +586,7 @@ function getTrainerConfigForWave(waveIndex: number) {
p.generateName(); p.generateName();
})) }))
.setPartyMemberFunc(2, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true)) .setPartyMemberFunc(2, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([pool3Mon.species], TrainerSlot.TRAINER, true, p => { .setPartyMemberFunc(3, getRandomPartyMemberFunc([ pool3Mon.species ], TrainerSlot.TRAINER, true, p => {
if (!isNullOrUndefined(pool3Mon.formIndex)) { if (!isNullOrUndefined(pool3Mon.formIndex)) {
p.formIndex = pool3Mon.formIndex; p.formIndex = pool3Mon.formIndex;
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
@ -611,14 +611,14 @@ function getTrainerConfigForWave(waveIndex: number) {
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.generateName(); p.generateName();
})) }))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([pool3Mon.species], TrainerSlot.TRAINER, true, p => { .setPartyMemberFunc(2, getRandomPartyMemberFunc([ pool3Mon.species ], TrainerSlot.TRAINER, true, p => {
if (!isNullOrUndefined(pool3Mon.formIndex)) { if (!isNullOrUndefined(pool3Mon.formIndex)) {
p.formIndex = pool3Mon.formIndex; p.formIndex = pool3Mon.formIndex;
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.generateName(); p.generateName();
} }
})) }))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([pool3Mon2.species], TrainerSlot.TRAINER, true, p => { .setPartyMemberFunc(3, getRandomPartyMemberFunc([ pool3Mon2.species ], TrainerSlot.TRAINER, true, p => {
if (!isNullOrUndefined(pool3Mon2.formIndex)) { if (!isNullOrUndefined(pool3Mon2.formIndex)) {
p.formIndex = pool3Mon2.formIndex; p.formIndex = pool3Mon2.formIndex;
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
@ -634,7 +634,7 @@ function getTrainerConfigForWave(waveIndex: number) {
function doBugTypeMoveTutor(scene: BattleScene): Promise<void> { function doBugTypeMoveTutor(scene: BattleScene): Promise<void> {
return new Promise<void>(async resolve => { return new Promise<void>(async resolve => {
const moveOptions = scene.currentBattle.mysteryEncounter!.misc.moveTutorOptions; const moveOptions = scene.currentBattle.mysteryEncounter!.misc.moveTutorOptions;
await showEncounterDialogue(scene, `${namespace}.battle_won`, `${namespace}.speaker`); await showEncounterDialogue(scene, `${namespace}:battle_won`, `${namespace}:speaker`);
const overlayScale = 1; const overlayScale = 1;
const moveInfoOverlay = new MoveInfoOverlay(scene, { const moveInfoOverlay = new MoveInfoOverlay(scene, {
@ -669,7 +669,7 @@ function doBugTypeMoveTutor(scene: BattleScene): Promise<void> {
moveInfoOverlay.setVisible(false); moveInfoOverlay.setVisible(false);
}; };
const result = await selectOptionThenPokemon(scene, optionSelectItems, `${namespace}.teach_move_prompt`, undefined, onHoverOverCancel); const result = await selectOptionThenPokemon(scene, optionSelectItems, `${namespace}:teach_move_prompt`, undefined, onHoverOverCancel);
// let forceExit = !!result; // let forceExit = !!result;
if (!result) { if (!result) {
moveInfoOverlay.active = false; moveInfoOverlay.active = false;

View File

@ -34,7 +34,7 @@ import { EncounterAnim } from "#enums/encounter-anims";
import { Challenges } from "#enums/challenges"; import { Challenges } from "#enums/challenges";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */
const namespace = "mysteryEncounter:clowningAround"; const namespace = "mysteryEncounters/clowningAround";
const RANDOM_ABILITY_POOL = [ const RANDOM_ABILITY_POOL = [
Abilities.STURDY, Abilities.STURDY,
@ -98,11 +98,11 @@ export const ClowningAroundEncounter: MysteryEncounter =
]) ])
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
}, },
{ {
text: `${namespace}.intro_dialogue`, text: `${namespace}:intro_dialogue`,
speaker: `${namespace}.speaker` speaker: `${namespace}:speaker`
}, },
]) ])
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
@ -129,38 +129,38 @@ export const ClowningAroundEncounter: MysteryEncounter =
{ {
species: getPokemonSpecies(Species.MR_MIME), species: getPokemonSpecies(Species.MR_MIME),
isBoss: true, isBoss: true,
moveSet: [Moves.TEETER_DANCE, Moves.ALLY_SWITCH, Moves.DAZZLING_GLEAM, Moves.PSYCHIC] moveSet: [ Moves.TEETER_DANCE, Moves.ALLY_SWITCH, Moves.DAZZLING_GLEAM, Moves.PSYCHIC ]
}, },
{ // Blacephalon has the random ability from pool, and 2 entirely random types to fit with the theme of the encounter { // Blacephalon has the random ability from pool, and 2 entirely random types to fit with the theme of the encounter
species: getPokemonSpecies(Species.BLACEPHALON), species: getPokemonSpecies(Species.BLACEPHALON),
mysteryEncounterPokemonData: new MysteryEncounterPokemonData({ ability: ability, types: [randSeedInt(18), randSeedInt(18)] }), mysteryEncounterPokemonData: new MysteryEncounterPokemonData({ ability: ability, types: [ randSeedInt(18), randSeedInt(18) ]}),
isBoss: true, isBoss: true,
moveSet: [Moves.TRICK, Moves.HYPNOSIS, Moves.SHADOW_BALL, Moves.MIND_BLOWN] moveSet: [ Moves.TRICK, Moves.HYPNOSIS, Moves.SHADOW_BALL, Moves.MIND_BLOWN ]
}, },
], ],
doubleBattle: true doubleBattle: true
}); });
// Load animations/sfx for start of fight moves // Load animations/sfx for start of fight moves
loadCustomMovesForEncounter(scene, [Moves.ROLE_PLAY, Moves.TAUNT]); loadCustomMovesForEncounter(scene, [ Moves.ROLE_PLAY, Moves.TAUNT ]);
encounter.setDialogueToken("blacephalonName", getPokemonSpecies(Species.BLACEPHALON).getName()); encounter.setDialogueToken("blacephalonName", getPokemonSpecies(Species.BLACEPHALON).getName());
return true; return true;
}) })
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withOption( .withOption(
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.1.selected`, text: `${namespace}:option.1.selected`,
speaker: `${namespace}.speaker` speaker: `${namespace}:speaker`
}, },
], ],
}) })
@ -175,19 +175,19 @@ export const ClowningAroundEncounter: MysteryEncounter =
encounter.startOfBattleEffects.push( encounter.startOfBattleEffects.push(
{ // Mr. Mime copies the Blacephalon's random ability { // Mr. Mime copies the Blacephalon's random ability
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.ENEMY_2], targets: [ BattlerIndex.ENEMY_2 ],
move: new PokemonMove(Moves.ROLE_PLAY), move: new PokemonMove(Moves.ROLE_PLAY),
ignorePp: true ignorePp: true
}, },
{ {
sourceBattlerIndex: BattlerIndex.ENEMY_2, sourceBattlerIndex: BattlerIndex.ENEMY_2,
targets: [BattlerIndex.PLAYER], targets: [ BattlerIndex.PLAYER ],
move: new PokemonMove(Moves.TAUNT), move: new PokemonMove(Moves.TAUNT),
ignorePp: true ignorePp: true
}, },
{ {
sourceBattlerIndex: BattlerIndex.ENEMY_2, sourceBattlerIndex: BattlerIndex.ENEMY_2,
targets: [BattlerIndex.PLAYER_2], targets: [ BattlerIndex.PLAYER_2 ],
move: new PokemonMove(Moves.TAUNT), move: new PokemonMove(Moves.TAUNT),
ignorePp: true ignorePp: true
}); });
@ -199,7 +199,7 @@ export const ClowningAroundEncounter: MysteryEncounter =
// After the battle, offer the player the opportunity to permanently swap ability // After the battle, offer the player the opportunity to permanently swap ability
const abilityWasSwapped = await handleSwapAbility(scene); const abilityWasSwapped = await handleSwapAbility(scene);
if (abilityWasSwapped) { if (abilityWasSwapped) {
await showEncounterText(scene, `${namespace}.option.1.ability_gained`); await showEncounterText(scene, `${namespace}:option.1.ability_gained`);
} }
// Play animations once ability swap is complete // Play animations once ability swap is complete
@ -222,19 +222,19 @@ export const ClowningAroundEncounter: MysteryEncounter =
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.2.selected`, text: `${namespace}:option.2.selected`,
speaker: `${namespace}.speaker` speaker: `${namespace}:speaker`
}, },
{ {
text: `${namespace}.option.2.selected_2`, text: `${namespace}:option.2.selected_2`,
}, },
{ {
text: `${namespace}.option.2.selected_3`, text: `${namespace}:option.2.selected_3`,
speaker: `${namespace}.speaker` speaker: `${namespace}:speaker`
}, },
], ],
}) })
@ -308,19 +308,19 @@ export const ClowningAroundEncounter: MysteryEncounter =
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.3.label`, buttonLabel: `${namespace}:option.3.label`,
buttonTooltip: `${namespace}.option.3.tooltip`, buttonTooltip: `${namespace}:option.3.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.3.selected`, text: `${namespace}:option.3.selected`,
speaker: `${namespace}.speaker` speaker: `${namespace}:speaker`
}, },
{ {
text: `${namespace}.option.3.selected_2`, text: `${namespace}:option.3.selected_2`,
}, },
{ {
text: `${namespace}.option.3.selected_3`, text: `${namespace}:option.3.selected_3`,
speaker: `${namespace}.speaker` speaker: `${namespace}:speaker`
}, },
], ],
}) })
@ -336,11 +336,11 @@ export const ClowningAroundEncounter: MysteryEncounter =
.filter(move => move && !originalTypes.includes(move.getMove().type) && move.getMove().category !== MoveCategory.STATUS) .filter(move => move && !originalTypes.includes(move.getMove().type) && move.getMove().category !== MoveCategory.STATUS)
.map(move => move!.getMove().type); .map(move => move!.getMove().type);
if (priorityTypes?.length > 0) { if (priorityTypes?.length > 0) {
priorityTypes = [...new Set(priorityTypes)].sort(); priorityTypes = [ ...new Set(priorityTypes) ].sort();
priorityTypes = randSeedShuffle(priorityTypes); priorityTypes = randSeedShuffle(priorityTypes);
} }
const newTypes = [originalTypes[0]]; const newTypes = [ originalTypes[0] ];
let secondType: Type | null = null; let secondType: Type | null = null;
while (secondType === null || secondType === newTypes[0] || originalTypes.includes(secondType)) { while (secondType === null || secondType === newTypes[0] || originalTypes.includes(secondType)) {
if (priorityTypes.length > 0) { if (priorityTypes.length > 0) {
@ -377,15 +377,15 @@ export const ClowningAroundEncounter: MysteryEncounter =
) )
.withOutroDialogue([ .withOutroDialogue([
{ {
text: `${namespace}.outro`, text: `${namespace}:outro`,
}, },
]) ])
.build(); .build();
async function handleSwapAbility(scene: BattleScene) { async function handleSwapAbility(scene: BattleScene) {
return new Promise<boolean>(async resolve => { return new Promise<boolean>(async resolve => {
await showEncounterDialogue(scene, `${namespace}.option.1.apply_ability_dialogue`, `${namespace}.speaker`); await showEncounterDialogue(scene, `${namespace}:option.1.apply_ability_dialogue`, `${namespace}:speaker`);
await showEncounterText(scene, `${namespace}.option.1.apply_ability_message`); await showEncounterText(scene, `${namespace}:option.1.apply_ability_message`);
scene.ui.setMode(Mode.MESSAGE).then(() => { scene.ui.setMode(Mode.MESSAGE).then(() => {
displayYesNoOptions(scene, resolve); displayYesNoOptions(scene, resolve);
@ -394,7 +394,7 @@ async function handleSwapAbility(scene: BattleScene) {
} }
function displayYesNoOptions(scene: BattleScene, resolve) { function displayYesNoOptions(scene: BattleScene, resolve) {
showEncounterText(scene, `${namespace}.option.1.ability_prompt`, null, 500, false); showEncounterText(scene, `${namespace}:option.1.ability_prompt`, null, 500, false);
const fullOptions = [ const fullOptions = [
{ {
label: i18next.t("menu:yes"), label: i18next.t("menu:yes"),
@ -453,37 +453,37 @@ function generateItemsOfTier(scene: BattleScene, pokemon: PlayerPokemon, numItem
// Pools have instances of the modifier type equal to the max stacks that modifier can be applied to any one pokemon // Pools have instances of the modifier type equal to the max stacks that modifier can be applied to any one pokemon
// This is to prevent "over-generating" a random item of a certain type during item swaps // This is to prevent "over-generating" a random item of a certain type during item swaps
const ultraPool = [ const ultraPool = [
[modifierTypes.REVIVER_SEED, 1], [ modifierTypes.REVIVER_SEED, 1 ],
[modifierTypes.GOLDEN_PUNCH, 5], [ modifierTypes.GOLDEN_PUNCH, 5 ],
[modifierTypes.ATTACK_TYPE_BOOSTER, 99], [ modifierTypes.ATTACK_TYPE_BOOSTER, 99 ],
[modifierTypes.QUICK_CLAW, 3], [ modifierTypes.QUICK_CLAW, 3 ],
[modifierTypes.WIDE_LENS, 3] [ modifierTypes.WIDE_LENS, 3 ]
]; ];
const roguePool = [ const roguePool = [
[modifierTypes.LEFTOVERS, 4], [ modifierTypes.LEFTOVERS, 4 ],
[modifierTypes.SHELL_BELL, 4], [ modifierTypes.SHELL_BELL, 4 ],
[modifierTypes.SOUL_DEW, 10], [ modifierTypes.SOUL_DEW, 10 ],
[modifierTypes.SOOTHE_BELL, 3], [ modifierTypes.SOOTHE_BELL, 3 ],
[modifierTypes.SCOPE_LENS, 1], [ modifierTypes.SCOPE_LENS, 1 ],
[modifierTypes.BATON, 1], [ modifierTypes.BATON, 1 ],
[modifierTypes.FOCUS_BAND, 5], [ modifierTypes.FOCUS_BAND, 5 ],
[modifierTypes.KINGS_ROCK, 3], [ modifierTypes.KINGS_ROCK, 3 ],
[modifierTypes.GRIP_CLAW, 5] [ modifierTypes.GRIP_CLAW, 5 ]
]; ];
const berryPool = [ const berryPool = [
[BerryType.APICOT, 3], [ BerryType.APICOT, 3 ],
[BerryType.ENIGMA, 2], [ BerryType.ENIGMA, 2 ],
[BerryType.GANLON, 3], [ BerryType.GANLON, 3 ],
[BerryType.LANSAT, 3], [ BerryType.LANSAT, 3 ],
[BerryType.LEPPA, 2], [ BerryType.LEPPA, 2 ],
[BerryType.LIECHI, 3], [ BerryType.LIECHI, 3 ],
[BerryType.LUM, 2], [ BerryType.LUM, 2 ],
[BerryType.PETAYA, 3], [ BerryType.PETAYA, 3 ],
[BerryType.SALAC, 2], [ BerryType.SALAC, 2 ],
[BerryType.SITRUS, 2], [ BerryType.SITRUS, 2 ],
[BerryType.STARF, 3] [ BerryType.STARF, 3 ]
]; ];
let pool: any[]; let pool: any[];
@ -502,7 +502,7 @@ function generateItemsOfTier(scene: BattleScene, pokemon: PlayerPokemon, numItem
const newItemType = pool[randIndex]; const newItemType = pool[randIndex];
let newMod: PokemonHeldItemModifierType; let newMod: PokemonHeldItemModifierType;
if (tier === "Berries") { if (tier === "Berries") {
newMod = generateModifierType(scene, modifierTypes.BERRY, [newItemType[0]]) as PokemonHeldItemModifierType; newMod = generateModifierType(scene, modifierTypes.BERRY, [ newItemType[0] ]) as PokemonHeldItemModifierType;
} else { } else {
newMod = generateModifierType(scene, newItemType[0]) as PokemonHeldItemModifierType; newMod = generateModifierType(scene, newItemType[0]) as PokemonHeldItemModifierType;
} }

View File

@ -30,7 +30,7 @@ import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
import i18next from "i18next"; import i18next from "i18next";
/** the i18n namespace for this encounter */ /** the i18n namespace for this encounter */
const namespace = "mysteryEncounter:dancingLessons"; const namespace = "mysteryEncounters/dancingLessons";
// Fire form // Fire form
const BAILE_STYLE_BIOMES = [ const BAILE_STYLE_BIOMES = [
@ -99,12 +99,12 @@ export const DancingLessonsEncounter: MysteryEncounter =
}) })
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
} }
]) ])
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
@ -141,7 +141,7 @@ export const DancingLessonsEncounter: MysteryEncounter =
scene.getEnemyParty().forEach(enemyPokemon => { scene.getEnemyParty().forEach(enemyPokemon => {
scene.field.remove(enemyPokemon, true); scene.field.remove(enemyPokemon, true);
}); });
scene.currentBattle.enemyParty = [oricorio]; scene.currentBattle.enemyParty = [ oricorio ];
scene.field.add(oricorio); scene.field.add(oricorio);
// Spawns on offscreen field // Spawns on offscreen field
oricorio.x -= 300; oricorio.x -= 300;
@ -153,14 +153,14 @@ export const DancingLessonsEncounter: MysteryEncounter =
dataSource: oricorioData, dataSource: oricorioData,
isBoss: true, isBoss: true,
// Gets +1 to all stats except SPD on battle start // Gets +1 to all stats except SPD on battle start
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON], tags: [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON ],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => { mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
queueEncounterMessage(pokemon.scene, `${namespace}.option.1.boss_enraged`); queueEncounterMessage(pokemon.scene, `${namespace}:option.1.boss_enraged`);
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF], 1)); pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF ], 1));
} }
}], }],
}; };
encounter.enemyPartyConfigs = [config]; encounter.enemyPartyConfigs = [ config ];
encounter.misc = { encounter.misc = {
oricorioData oricorioData
}; };
@ -173,11 +173,11 @@ export const DancingLessonsEncounter: MysteryEncounter =
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.1.selected`, text: `${namespace}:option.1.selected`,
}, },
], ],
}) })
@ -187,13 +187,13 @@ export const DancingLessonsEncounter: MysteryEncounter =
encounter.startOfBattleEffects.push({ encounter.startOfBattleEffects.push({
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.PLAYER], targets: [ BattlerIndex.PLAYER ],
move: new PokemonMove(Moves.REVELATION_DANCE), move: new PokemonMove(Moves.REVELATION_DANCE),
ignorePp: true ignorePp: true
}); });
await hideOricorioPokemon(scene); await hideOricorioPokemon(scene);
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.BATON], fillRemaining: true }); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.BATON ], fillRemaining: true });
await initBattleWithEnemyConfig(scene, encounter.enemyPartyConfigs[0]); await initBattleWithEnemyConfig(scene, encounter.enemyPartyConfigs[0]);
}) })
.build() .build()
@ -202,11 +202,11 @@ export const DancingLessonsEncounter: MysteryEncounter =
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.2.selected`, text: `${namespace}:option.2.selected`,
}, },
], ],
}) })
@ -237,13 +237,13 @@ export const DancingLessonsEncounter: MysteryEncounter =
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL) .newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)
.withPrimaryPokemonRequirement(new MoveRequirement(DANCING_MOVES)) // Will set option3PrimaryName and option3PrimaryMove dialogue tokens automatically .withPrimaryPokemonRequirement(new MoveRequirement(DANCING_MOVES)) // Will set option3PrimaryName and option3PrimaryMove dialogue tokens automatically
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.3.label`, buttonLabel: `${namespace}:option.3.label`,
buttonTooltip: `${namespace}.option.3.tooltip`, buttonTooltip: `${namespace}:option.3.tooltip`,
disabledButtonTooltip: `${namespace}.option.3.disabled_tooltip`, disabledButtonTooltip: `${namespace}:option.3.disabled_tooltip`,
secondOptionPrompt: `${namespace}.option.3.select_prompt`, secondOptionPrompt: `${namespace}:option.3.select_prompt`,
selected: [ selected: [
{ {
text: `${namespace}.option.3.selected`, text: `${namespace}:option.3.selected`,
}, },
], ],
}) })
@ -278,7 +278,7 @@ export const DancingLessonsEncounter: MysteryEncounter =
} }
const meetsReqs = encounter.options[2].pokemonMeetsPrimaryRequirements(scene, pokemon); const meetsReqs = encounter.options[2].pokemonMeetsPrimaryRequirements(scene, pokemon);
if (!meetsReqs) { if (!meetsReqs) {
return getEncounterText(scene, `${namespace}.invalid_selection`) ?? null; return getEncounterText(scene, `${namespace}:invalid_selection`) ?? null;
} }
return null; return null;

View File

@ -16,7 +16,7 @@ import { PokemonFormChangeItemModifier, PokemonHeldItemModifier } from "#app/mod
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
/** i18n namespace for encounter */ /** i18n namespace for encounter */
const namespace = "mysteryEncounter:darkDeal"; const namespace = "mysteryEncounters/darkDeal";
/** Exclude Ultra Beasts (inludes Cosmog/Solgaleo/Lunala/Necrozma), Paradox (includes Miraidon/Koraidon), Eternatus, and Mythicals */ /** Exclude Ultra Beasts (inludes Cosmog/Solgaleo/Lunala/Necrozma), Paradox (includes Miraidon/Koraidon), Eternatus, and Mythicals */
const excludedBosses = [ const excludedBosses = [
@ -107,32 +107,32 @@ export const DarkDealEncounter: MysteryEncounter =
]) ])
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
}, },
{ {
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
text: `${namespace}.intro_dialogue`, text: `${namespace}:intro_dialogue`,
}, },
]) ])
.withSceneWaveRangeRequirement(30, CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES[1]) .withSceneWaveRangeRequirement(30, CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES[1])
.withScenePartySizeRequirement(2, 6, true) // Must have at least 2 pokemon in party .withScenePartySizeRequirement(2, 6, true) // Must have at least 2 pokemon in party
.withCatchAllowed(true) .withCatchAllowed(true)
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withOption( .withOption(
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [ selected: [
{ {
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
text: `${namespace}.option.1.selected_dialogue`, text: `${namespace}:option.1.selected_dialogue`,
}, },
{ {
text: `${namespace}.option.1.selected_message`, text: `${namespace}:option.1.selected_message`,
}, },
], ],
}) })
@ -164,7 +164,7 @@ export const DarkDealEncounter: MysteryEncounter =
// Starter egg tier, 35/50/10/5 %odds for tiers 6/7/8/9+ // Starter egg tier, 35/50/10/5 %odds for tiers 6/7/8/9+
const roll = randSeedInt(100); const roll = randSeedInt(100);
const starterTier: number | [number, number] = const starterTier: number | [number, number] =
roll >= 65 ? 6 : roll >= 15 ? 7 : roll >= 5 ? 8 : [9, 10]; roll >= 65 ? 6 : roll >= 15 ? 7 : roll >= 5 ? 8 : [ 9, 10 ];
const bossSpecies = getPokemonSpecies(getRandomSpeciesByStarterTier(starterTier, excludedBosses, bossTypes)); const bossSpecies = getPokemonSpecies(getRandomSpeciesByStarterTier(starterTier, excludedBosses, bossTypes));
const pokemonConfig: EnemyPokemonConfig = { const pokemonConfig: EnemyPokemonConfig = {
species: bossSpecies, species: bossSpecies,
@ -179,7 +179,7 @@ export const DarkDealEncounter: MysteryEncounter =
pokemonConfig.formIndex = 0; pokemonConfig.formIndex = 0;
} }
const config: EnemyPartyConfig = { const config: EnemyPartyConfig = {
pokemonConfigs: [pokemonConfig], pokemonConfigs: [ pokemonConfig ],
}; };
return initBattleWithEnemyConfig(scene, config); return initBattleWithEnemyConfig(scene, config);
}) })
@ -187,12 +187,12 @@ export const DarkDealEncounter: MysteryEncounter =
) )
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
selected: [ selected: [
{ {
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
text: `${namespace}.option.2.selected`, text: `${namespace}:option.2.selected`,
}, },
], ],
}, },
@ -204,7 +204,7 @@ export const DarkDealEncounter: MysteryEncounter =
) )
.withOutroDialogue([ .withOutroDialogue([
{ {
text: `${namespace}.outro` text: `${namespace}:outro`
} }
]) ])
.build(); .build();

View File

@ -19,10 +19,10 @@ 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/game-mode";
/** the i18n namespace for this encounter */ /** the i18n namespace for this encounter */
const namespace = "mysteryEncounter:delibirdy"; const namespace = "mysteryEncounters/delibirdy";
/** Berries only */ /** Berries only */
const OPTION_2_ALLOWED_MODIFIERS = ["BerryModifier", "PokemonInstantReviveModifier"]; const OPTION_2_ALLOWED_MODIFIERS = [ "BerryModifier", "PokemonInstantReviveModifier" ];
/** Disallowed items are berries, Reviver Seeds, and Vitamins (form change items and fusion items are not PokemonHeldItemModifiers) */ /** Disallowed items are berries, Reviver Seeds, and Vitamins (form change items and fusion items are not PokemonHeldItemModifiers) */
const OPTION_3_DISALLOWED_MODIFIERS = [ const OPTION_3_DISALLOWED_MODIFIERS = [
@ -81,15 +81,15 @@ export const DelibirdyEncounter: MysteryEncounter =
]) ])
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
} }
]) ])
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withOutroDialogue([ .withOutroDialogue([
{ {
text: `${namespace}.outro`, text: `${namespace}:outro`,
} }
]) ])
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
@ -108,11 +108,11 @@ export const DelibirdyEncounter: MysteryEncounter =
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT)
.withSceneMoneyRequirement(0, DELIBIRDY_MONEY_PRICE_MULTIPLIER) // Must have money to spawn .withSceneMoneyRequirement(0, DELIBIRDY_MONEY_PRICE_MULTIPLIER) // Must have money to spawn
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.1.selected`, text: `${namespace}:option.1.selected`,
}, },
], ],
}) })
@ -145,12 +145,12 @@ export const DelibirdyEncounter: MysteryEncounter =
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT)
.withPrimaryPokemonRequirement(new HeldItemRequirement(OPTION_2_ALLOWED_MODIFIERS)) .withPrimaryPokemonRequirement(new HeldItemRequirement(OPTION_2_ALLOWED_MODIFIERS))
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
secondOptionPrompt: `${namespace}.option.2.select_prompt`, secondOptionPrompt: `${namespace}:option.2.select_prompt`,
selected: [ selected: [
{ {
text: `${namespace}.option.2.selected`, text: `${namespace}:option.2.selected`,
}, },
], ],
}) })
@ -183,7 +183,7 @@ export const DelibirdyEncounter: MysteryEncounter =
// If pokemon has valid item, it can be selected // If pokemon has valid item, it can be selected
const meetsReqs = encounter.options[1].pokemonMeetsPrimaryRequirements(scene, pokemon); const meetsReqs = encounter.options[1].pokemonMeetsPrimaryRequirements(scene, pokemon);
if (!meetsReqs) { if (!meetsReqs) {
return getEncounterText(scene, `${namespace}.invalid_selection`) ?? null; return getEncounterText(scene, `${namespace}:invalid_selection`) ?? null;
} }
return null; return null;
@ -193,7 +193,7 @@ export const DelibirdyEncounter: MysteryEncounter =
}) })
.withOptionPhase(async (scene: BattleScene) => { .withOptionPhase(async (scene: BattleScene) => {
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
const modifier = encounter.misc.chosenModifier; const modifier: BerryModifier | HealingBoosterModifier = encounter.misc.chosenModifier;
// Give the player a Candy Jar if they gave a Berry, and a Healing Charm for Reviver Seed // Give the player a Candy Jar if they gave a Berry, and a Healing Charm for Reviver Seed
if (modifier instanceof BerryModifier) { if (modifier instanceof BerryModifier) {
@ -239,12 +239,12 @@ export const DelibirdyEncounter: MysteryEncounter =
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT)
.withPrimaryPokemonRequirement(new HeldItemRequirement(OPTION_3_DISALLOWED_MODIFIERS, 1, true)) .withPrimaryPokemonRequirement(new HeldItemRequirement(OPTION_3_DISALLOWED_MODIFIERS, 1, true))
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.3.label`, buttonLabel: `${namespace}:option.3.label`,
buttonTooltip: `${namespace}.option.3.tooltip`, buttonTooltip: `${namespace}:option.3.tooltip`,
secondOptionPrompt: `${namespace}.option.3.select_prompt`, secondOptionPrompt: `${namespace}:option.3.select_prompt`,
selected: [ selected: [
{ {
text: `${namespace}.option.3.selected`, text: `${namespace}:option.3.selected`,
}, },
], ],
}) })
@ -277,7 +277,7 @@ export const DelibirdyEncounter: MysteryEncounter =
// If pokemon has valid item, it can be selected // If pokemon has valid item, it can be selected
const meetsReqs = encounter.options[2].pokemonMeetsPrimaryRequirements(scene, pokemon); const meetsReqs = encounter.options[2].pokemonMeetsPrimaryRequirements(scene, pokemon);
if (!meetsReqs) { if (!meetsReqs) {
return getEncounterText(scene, `${namespace}.invalid_selection`) ?? null; return getEncounterText(scene, `${namespace}:invalid_selection`) ?? null;
} }
return null; return null;

View File

@ -14,7 +14,7 @@ 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/game-mode";
/** i18n namespace for encounter */ /** i18n namespace for encounter */
const namespace = "mysteryEncounter:departmentStoreSale"; const namespace = "mysteryEncounters/departmentStoreSale";
/** /**
* Department Store Sale encounter. * Department Store Sale encounter.
@ -43,21 +43,21 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter =
]) ])
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
}, },
{ {
text: `${namespace}.intro_dialogue`, text: `${namespace}:intro_dialogue`,
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
}, },
]) ])
.withAutoHideIntroVisuals(false) .withAutoHideIntroVisuals(false)
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
}, },
async (scene: BattleScene) => { async (scene: BattleScene) => {
// Choose TMs // Choose TMs
@ -82,8 +82,8 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter =
) )
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
}, },
async (scene: BattleScene) => { async (scene: BattleScene) => {
// Choose Vitamins // Choose Vitamins
@ -106,8 +106,8 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter =
) )
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.3.label`, buttonLabel: `${namespace}:option.3.label`,
buttonTooltip: `${namespace}.option.3.tooltip`, buttonTooltip: `${namespace}:option.3.tooltip`,
}, },
async (scene: BattleScene) => { async (scene: BattleScene) => {
// Choose X Items // Choose X Items
@ -130,8 +130,8 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter =
) )
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.4.label`, buttonLabel: `${namespace}:option.4.label`,
buttonTooltip: `${namespace}.option.4.tooltip`, buttonTooltip: `${namespace}:option.4.tooltip`,
}, },
async (scene: BattleScene) => { async (scene: BattleScene) => {
// Choose Pokeballs // Choose Pokeballs
@ -158,7 +158,7 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter =
) )
.withOutroDialogue([ .withOutroDialogue([
{ {
text: `${namespace}.outro`, text: `${namespace}:outro`,
} }
]) ])
.build(); .build();

View File

@ -14,7 +14,7 @@ import i18next from "i18next";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
/** i18n namespace for the encounter */ /** i18n namespace for the encounter */
const namespace = "mysteryEncounter:fieldTrip"; const namespace = "mysteryEncounters/fieldTrip";
/** /**
* Field Trip encounter. * Field Trip encounter.
@ -44,24 +44,24 @@ export const FieldTripEncounter: MysteryEncounter =
]) ])
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
}, },
{ {
text: `${namespace}.intro_dialogue`, text: `${namespace}:intro_dialogue`,
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
}, },
]) ])
.withAutoHideIntroVisuals(false) .withAutoHideIntroVisuals(false)
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withOption( .withOption(
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
secondOptionPrompt: `${namespace}.second_option_prompt`, secondOptionPrompt: `${namespace}:second_option_prompt`,
}) })
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => { .withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
@ -72,7 +72,7 @@ export const FieldTripEncounter: MysteryEncounter =
label: move.getName(), label: move.getName(),
handler: () => { handler: () => {
// Pokemon and move selected // Pokemon and move selected
encounter.setDialogueToken("moveCategory", i18next.t(`${namespace}.physical`)); encounter.setDialogueToken("moveCategory", i18next.t(`${namespace}:physical`));
pokemonAndMoveChosen(scene, pokemon, move, MoveCategory.PHYSICAL); pokemonAndMoveChosen(scene, pokemon, move, MoveCategory.PHYSICAL);
return true; return true;
}, },
@ -87,9 +87,9 @@ export const FieldTripEncounter: MysteryEncounter =
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
if (encounter.misc.correctMove) { if (encounter.misc.correctMove) {
const modifiers = [ const modifiers = [
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [Stat.ATK])!, generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.ATK ])!,
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [Stat.DEF])!, generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.DEF ])!,
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [Stat.SPD])!, generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.SPD ])!,
generateModifierTypeOption(scene, modifierTypes.DIRE_HIT)!, generateModifierTypeOption(scene, modifierTypes.DIRE_HIT)!,
generateModifierTypeOption(scene, modifierTypes.RARER_CANDY)!, generateModifierTypeOption(scene, modifierTypes.RARER_CANDY)!,
]; ];
@ -105,9 +105,9 @@ export const FieldTripEncounter: MysteryEncounter =
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
secondOptionPrompt: `${namespace}.second_option_prompt`, secondOptionPrompt: `${namespace}:second_option_prompt`,
}) })
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => { .withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
@ -118,7 +118,7 @@ export const FieldTripEncounter: MysteryEncounter =
label: move.getName(), label: move.getName(),
handler: () => { handler: () => {
// Pokemon and move selected // Pokemon and move selected
encounter.setDialogueToken("moveCategory", i18next.t(`${namespace}.special`)); encounter.setDialogueToken("moveCategory", i18next.t(`${namespace}:special`));
pokemonAndMoveChosen(scene, pokemon, move, MoveCategory.SPECIAL); pokemonAndMoveChosen(scene, pokemon, move, MoveCategory.SPECIAL);
return true; return true;
}, },
@ -133,9 +133,9 @@ export const FieldTripEncounter: MysteryEncounter =
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
if (encounter.misc.correctMove) { if (encounter.misc.correctMove) {
const modifiers = [ const modifiers = [
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [Stat.SPATK])!, generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.SPATK ])!,
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [Stat.SPDEF])!, generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.SPDEF ])!,
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [Stat.SPD])!, generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.SPD ])!,
generateModifierTypeOption(scene, modifierTypes.DIRE_HIT)!, generateModifierTypeOption(scene, modifierTypes.DIRE_HIT)!,
generateModifierTypeOption(scene, modifierTypes.RARER_CANDY)!, generateModifierTypeOption(scene, modifierTypes.RARER_CANDY)!,
]; ];
@ -151,9 +151,9 @@ export const FieldTripEncounter: MysteryEncounter =
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.3.label`, buttonLabel: `${namespace}:option.3.label`,
buttonTooltip: `${namespace}.option.3.tooltip`, buttonTooltip: `${namespace}:option.3.tooltip`,
secondOptionPrompt: `${namespace}.second_option_prompt`, secondOptionPrompt: `${namespace}:second_option_prompt`,
}) })
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => { .withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
@ -164,7 +164,7 @@ export const FieldTripEncounter: MysteryEncounter =
label: move.getName(), label: move.getName(),
handler: () => { handler: () => {
// Pokemon and move selected // Pokemon and move selected
encounter.setDialogueToken("moveCategory", i18next.t(`${namespace}.status`)); encounter.setDialogueToken("moveCategory", i18next.t(`${namespace}:status`));
pokemonAndMoveChosen(scene, pokemon, move, MoveCategory.STATUS); pokemonAndMoveChosen(scene, pokemon, move, MoveCategory.STATUS);
return true; return true;
}, },
@ -179,8 +179,8 @@ export const FieldTripEncounter: MysteryEncounter =
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
if (encounter.misc.correctMove) { if (encounter.misc.correctMove) {
const modifiers = [ const modifiers = [
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [Stat.ACC])!, generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.ACC ])!,
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [Stat.SPD])!, generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.SPD ])!,
generateModifierTypeOption(scene, modifierTypes.GREAT_BALL)!, generateModifierTypeOption(scene, modifierTypes.GREAT_BALL)!,
generateModifierTypeOption(scene, modifierTypes.IV_SCANNER)!, generateModifierTypeOption(scene, modifierTypes.IV_SCANNER)!,
generateModifierTypeOption(scene, modifierTypes.RARER_CANDY)!, generateModifierTypeOption(scene, modifierTypes.RARER_CANDY)!,
@ -203,31 +203,31 @@ function pokemonAndMoveChosen(scene: BattleScene, pokemon: PlayerPokemon, move:
if (!correctMove) { if (!correctMove) {
encounter.selectedOption!.dialogue!.selected = [ encounter.selectedOption!.dialogue!.selected = [
{ {
text: `${namespace}.option.selected`, text: `${namespace}:option.selected`,
}, },
{ {
text: `${namespace}.incorrect`, text: `${namespace}:incorrect`,
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
}, },
{ {
text: `${namespace}.incorrect_exp`, text: `${namespace}:incorrect_exp`,
}, },
]; ];
setEncounterExp(scene, scene.getParty().map((p) => p.id), 50); setEncounterExp(scene, scene.getParty().map((p) => p.id), 50);
} else { } else {
encounter.selectedOption!.dialogue!.selected = [ encounter.selectedOption!.dialogue!.selected = [
{ {
text: `${namespace}.option.selected`, text: `${namespace}:option.selected`,
}, },
{ {
text: `${namespace}.correct`, text: `${namespace}:correct`,
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
}, },
{ {
text: `${namespace}.correct_exp`, text: `${namespace}:correct_exp`,
}, },
]; ];
setEncounterExp(scene, [pokemon.id], 100); setEncounterExp(scene, [ pokemon.id ], 100);
} }
encounter.misc = { encounter.misc = {
correctMove: correctMove, correctMove: correctMove,

View File

@ -24,7 +24,7 @@ import { EncounterAnim } from "#enums/encounter-anims";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */
const namespace = "mysteryEncounter:fieryFallout"; const namespace = "mysteryEncounters/fieryFallout";
/** /**
* Damage percentage taken when suffering the heat. * Damage percentage taken when suffering the heat.
@ -49,7 +49,7 @@ export const FieryFalloutEncounter: MysteryEncounter =
.withFleeAllowed(false) .withFleeAllowed(false)
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
}, },
]) ])
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
@ -73,7 +73,7 @@ export const FieryFalloutEncounter: MysteryEncounter =
doubleBattle: true, doubleBattle: true,
disableSwitch: true disableSwitch: true
}; };
encounter.enemyPartyConfigs = [config]; encounter.enemyPartyConfigs = [ config ];
// Load hidden Volcarona sprites // Load hidden Volcarona sprites
encounter.spriteConfigs = [ encounter.spriteConfigs = [
@ -99,7 +99,7 @@ export const FieryFalloutEncounter: MysteryEncounter =
]; ];
// Load animations/sfx for Volcarona moves // Load animations/sfx for Volcarona moves
loadCustomMovesForEncounter(scene, [Moves.FIRE_SPIN, Moves.QUIVER_DANCE]); loadCustomMovesForEncounter(scene, [ Moves.FIRE_SPIN, Moves.QUIVER_DANCE ]);
scene.arena.trySetWeather(WeatherType.SUNNY, true); scene.arena.trySetWeather(WeatherType.SUNNY, true);
@ -122,16 +122,16 @@ export const FieryFalloutEncounter: MysteryEncounter =
return true; return true;
}) })
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.1.selected`, text: `${namespace}:option.1.selected`,
}, },
], ],
}, },
@ -143,25 +143,25 @@ export const FieryFalloutEncounter: MysteryEncounter =
encounter.startOfBattleEffects.push( encounter.startOfBattleEffects.push(
{ {
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.PLAYER], targets: [ BattlerIndex.PLAYER ],
move: new PokemonMove(Moves.FIRE_SPIN), move: new PokemonMove(Moves.FIRE_SPIN),
ignorePp: true ignorePp: true
}, },
{ {
sourceBattlerIndex: BattlerIndex.ENEMY_2, sourceBattlerIndex: BattlerIndex.ENEMY_2,
targets: [BattlerIndex.PLAYER_2], targets: [ BattlerIndex.PLAYER_2 ],
move: new PokemonMove(Moves.FIRE_SPIN), move: new PokemonMove(Moves.FIRE_SPIN),
ignorePp: true ignorePp: true
}, },
{ {
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.ENEMY], targets: [ BattlerIndex.ENEMY ],
move: new PokemonMove(Moves.QUIVER_DANCE), move: new PokemonMove(Moves.QUIVER_DANCE),
ignorePp: true ignorePp: true
}, },
{ {
sourceBattlerIndex: BattlerIndex.ENEMY_2, sourceBattlerIndex: BattlerIndex.ENEMY_2,
targets: [BattlerIndex.ENEMY_2], targets: [ BattlerIndex.ENEMY_2 ],
move: new PokemonMove(Moves.QUIVER_DANCE), move: new PokemonMove(Moves.QUIVER_DANCE),
ignorePp: true ignorePp: true
}); });
@ -170,11 +170,11 @@ export const FieryFalloutEncounter: MysteryEncounter =
) )
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.2.selected`, text: `${namespace}:option.2.selected`,
}, },
], ],
}, },
@ -197,7 +197,7 @@ export const FieryFalloutEncounter: MysteryEncounter =
if (chosenPokemon.trySetStatus(StatusEffect.BURN)) { if (chosenPokemon.trySetStatus(StatusEffect.BURN)) {
// Burn applied // Burn applied
encounter.setDialogueToken("burnedPokemon", chosenPokemon.getNameToRender()); encounter.setDialogueToken("burnedPokemon", chosenPokemon.getNameToRender());
queueEncounterMessage(scene, `${namespace}.option.2.target_burned`); queueEncounterMessage(scene, `${namespace}:option.2.target_burned`);
} }
} }
@ -211,12 +211,12 @@ export const FieryFalloutEncounter: MysteryEncounter =
.withPrimaryPokemonRequirement(new TypeRequirement(Type.FIRE, true, 1)) // Will set option3PrimaryName dialogue token automatically .withPrimaryPokemonRequirement(new TypeRequirement(Type.FIRE, true, 1)) // Will set option3PrimaryName dialogue token automatically
.withSecondaryPokemonRequirement(new TypeRequirement(Type.FIRE, true, 1)) // Will set option3SecondaryName dialogue token automatically .withSecondaryPokemonRequirement(new TypeRequirement(Type.FIRE, true, 1)) // Will set option3SecondaryName dialogue token automatically
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.3.label`, buttonLabel: `${namespace}:option.3.label`,
buttonTooltip: `${namespace}.option.3.tooltip`, buttonTooltip: `${namespace}:option.3.tooltip`,
disabledButtonTooltip: `${namespace}.option.3.disabled_tooltip`, disabledButtonTooltip: `${namespace}:option.3.disabled_tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.3.selected`, text: `${namespace}:option.3.selected`,
}, },
], ],
}) })
@ -237,7 +237,7 @@ export const FieryFalloutEncounter: MysteryEncounter =
const primary = encounter.options[2].primaryPokemon!; const primary = encounter.options[2].primaryPokemon!;
const secondary = encounter.options[2].secondaryPokemon![0]; const secondary = encounter.options[2].secondaryPokemon![0];
setEncounterExp(scene, [primary.id, secondary.id], getPokemonSpecies(Species.VOLCARONA).baseExp * 2); setEncounterExp(scene, [ primary.id, secondary.id ], getPokemonSpecies(Species.VOLCARONA).baseExp * 2);
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);
}) })
.build() .build()
@ -248,9 +248,9 @@ function giveLeadPokemonCharcoal(scene: BattleScene) {
// Give first party pokemon Charcoal for free at end of battle // Give first party pokemon Charcoal for free at end of battle
const leadPokemon = scene.getParty()?.[0]; const leadPokemon = scene.getParty()?.[0];
if (leadPokemon) { if (leadPokemon) {
const charcoal = generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [Type.FIRE]) as AttackTypeBoosterModifierType; const charcoal = generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [ Type.FIRE ]) as AttackTypeBoosterModifierType;
applyModifierTypeToPlayerPokemon(scene, leadPokemon, charcoal); applyModifierTypeToPlayerPokemon(scene, leadPokemon, charcoal);
scene.currentBattle.mysteryEncounter!.setDialogueToken("leadPokemon", leadPokemon.getNameToRender()); scene.currentBattle.mysteryEncounter!.setDialogueToken("leadPokemon", leadPokemon.getNameToRender());
queueEncounterMessage(scene, `${namespace}.found_charcoal`); queueEncounterMessage(scene, `${namespace}:found_charcoal`);
} }
} }

View File

@ -31,7 +31,7 @@ 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/game-mode";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */
const namespace = "mysteryEncounter:fightOrFlight"; const namespace = "mysteryEncounters/fightOrFlight";
/** /**
* Fight or Flight encounter. * Fight or Flight encounter.
@ -48,7 +48,7 @@ export const FightOrFlightEncounter: MysteryEncounter =
.withIntroSpriteConfigs([]) // Set in onInit() .withIntroSpriteConfigs([]) // Set in onInit()
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
}, },
]) ])
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
@ -65,16 +65,16 @@ export const FightOrFlightEncounter: MysteryEncounter =
species: bossSpecies, species: bossSpecies,
dataSource: new PokemonData(bossPokemon), dataSource: new PokemonData(bossPokemon),
isBoss: true, isBoss: true,
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON], tags: [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON ],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => { mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
queueEncounterMessage(pokemon.scene, `${namespace}.option.1.stat_boost`); queueEncounterMessage(pokemon.scene, `${namespace}:option.1.stat_boost`);
// Randomly boost 1 stat 2 stages // Randomly boost 1 stat 2 stages
// Cannot boost Spd, Acc, or Evasion // Cannot boost Spd, Acc, or Evasion
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [randSeedInt(4, 1)], 2)); pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ randSeedInt(4, 1) ], 2));
} }
}], }],
}; };
encounter.enemyPartyConfigs = [config]; encounter.enemyPartyConfigs = [ config ];
// Calculate item // Calculate item
// Waves 10-40 GREAT, 60-120 ULTRA, 120-160 ROGUE, 160-180 MASTER // Waves 10-40 GREAT, 60-120 ULTRA, 120-160 ROGUE, 160-180 MASTER
@ -90,7 +90,7 @@ export const FightOrFlightEncounter: MysteryEncounter =
let item: ModifierTypeOption | null = null; let item: ModifierTypeOption | null = null;
// TMs and Candy Jar excluded from possible rewards as they're too swingy in value for a singular item reward // TMs and Candy Jar excluded from possible rewards as they're too swingy in value for a singular item reward
while (!item || item.type.id.includes("TM_") || item.type.id === "CANDY_JAR") { while (!item || item.type.id.includes("TM_") || item.type.id === "CANDY_JAR") {
item = getPlayerModifierTypeOptions(1, scene.getParty(), [], { guaranteedModifierTiers: [tier], allowLuckUpgrades: false })[0]; item = getPlayerModifierTypeOptions(1, scene.getParty(), [], { guaranteedModifierTiers: [ tier ], allowLuckUpgrades: false })[0];
} }
encounter.setDialogueToken("itemName", item.type.name); encounter.setDialogueToken("itemName", item.type.name);
encounter.misc = item; encounter.misc = item;
@ -120,16 +120,16 @@ export const FightOrFlightEncounter: MysteryEncounter =
return true; return true;
}) })
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.1.selected`, text: `${namespace}:option.1.selected`,
}, },
], ],
}, },
@ -137,7 +137,7 @@ export const FightOrFlightEncounter: MysteryEncounter =
// Pick battle // Pick battle
// Pokemon will randomly boost 1 stat by 2 stages // Pokemon will randomly boost 1 stat by 2 stages
const item = scene.currentBattle.mysteryEncounter!.misc as ModifierTypeOption; const item = scene.currentBattle.mysteryEncounter!.misc as ModifierTypeOption;
setEncounterRewards(scene, { guaranteedModifierTypeOptions: [item], fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeOptions: [ item ], fillRemaining: false });
await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]); await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]);
} }
) )
@ -146,12 +146,12 @@ export const FightOrFlightEncounter: MysteryEncounter =
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL) .newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)
.withPrimaryPokemonRequirement(new MoveRequirement(STEALING_MOVES)) // Will set option2PrimaryName and option2PrimaryMove dialogue tokens automatically .withPrimaryPokemonRequirement(new MoveRequirement(STEALING_MOVES)) // Will set option2PrimaryName and option2PrimaryMove dialogue tokens automatically
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
disabledButtonTooltip: `${namespace}.option.2.disabled_tooltip`, disabledButtonTooltip: `${namespace}:option.2.disabled_tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.2.selected` text: `${namespace}:option.2.selected`
} }
] ]
}) })
@ -159,7 +159,7 @@ export const FightOrFlightEncounter: MysteryEncounter =
// Pick steal // Pick steal
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
const item = scene.currentBattle.mysteryEncounter!.misc as ModifierTypeOption; const item = scene.currentBattle.mysteryEncounter!.misc as ModifierTypeOption;
setEncounterRewards(scene, { guaranteedModifierTypeOptions: [item], fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeOptions: [ item ], fillRemaining: false });
// Use primaryPokemon to execute the thievery // Use primaryPokemon to execute the thievery
const primaryPokemon = encounter.options[1].primaryPokemon!; const primaryPokemon = encounter.options[1].primaryPokemon!;
@ -170,11 +170,11 @@ export const FightOrFlightEncounter: MysteryEncounter =
) )
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.3.label`, buttonLabel: `${namespace}:option.3.label`,
buttonTooltip: `${namespace}.option.3.tooltip`, buttonTooltip: `${namespace}:option.3.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.3.selected`, text: `${namespace}:option.3.selected`,
}, },
], ],
}, },

View File

@ -25,7 +25,7 @@ import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
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 */
const namespace = "mysteryEncounter:funAndGames"; const namespace = "mysteryEncounters/funAndGames";
/** /**
* Fun and Games! encounter. * Fun and Games! encounter.
@ -72,13 +72,13 @@ export const FunAndGamesEncounter: MysteryEncounter =
]) ])
.withIntroDialogue([ .withIntroDialogue([
{ {
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
text: `${namespace}.intro_dialogue`, text: `${namespace}:intro_dialogue`,
}, },
]) ])
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
scene.loadBgm("mystery_encounter_fun_and_games", "mystery_encounter_fun_and_games.mp3"); scene.loadBgm("mystery_encounter_fun_and_games", "mystery_encounter_fun_and_games.mp3");
@ -93,11 +93,11 @@ export const FunAndGamesEncounter: MysteryEncounter =
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT)
.withSceneRequirement(new MoneyRequirement(0, 1.5)) // Cost equal to 1 Max Potion .withSceneRequirement(new MoneyRequirement(0, 1.5)) // Cost equal to 1 Max Potion
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.1.selected`, text: `${namespace}:option.1.selected`,
}, },
], ],
}) })
@ -112,7 +112,7 @@ export const FunAndGamesEncounter: MysteryEncounter =
// Only Pokemon that are not KOed/legal can be selected // Only Pokemon that are not KOed/legal can be selected
const selectableFilter = (pokemon: Pokemon) => { const selectableFilter = (pokemon: Pokemon) => {
return isPokemonValidForEncounterOptionSelection(pokemon, scene, `${namespace}.invalid_selection`); return isPokemonValidForEncounterOptionSelection(pokemon, scene, `${namespace}:invalid_selection`);
}; };
return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter); return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter);
@ -141,11 +141,11 @@ export const FunAndGamesEncounter: MysteryEncounter =
) )
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.2.selected`, text: `${namespace}:option.2.selected`,
}, },
], ],
}, },
@ -197,7 +197,7 @@ async function summonPlayerPokemon(scene: BattleScene) {
const enemySpecies = getPokemonSpecies(Species.WOBBUFFET); const enemySpecies = getPokemonSpecies(Species.WOBBUFFET);
scene.currentBattle.enemyParty = []; scene.currentBattle.enemyParty = [];
const wobbuffet = scene.addEnemyPokemon(enemySpecies, encounter.misc.playerPokemon.level, TrainerSlot.NONE, false); const wobbuffet = scene.addEnemyPokemon(enemySpecies, encounter.misc.playerPokemon.level, TrainerSlot.NONE, false);
wobbuffet.ivs = [0, 0, 0, 0, 0, 0]; wobbuffet.ivs = [ 0, 0, 0, 0, 0, 0 ];
wobbuffet.setNature(Nature.MILD); wobbuffet.setNature(Nature.MILD);
wobbuffet.setAlpha(0); wobbuffet.setAlpha(0);
wobbuffet.setVisible(false); wobbuffet.setVisible(false);
@ -231,7 +231,7 @@ function handleLoseMinigame(scene: BattleScene) {
scene.currentBattle.enemyParty = []; scene.currentBattle.enemyParty = [];
scene.currentBattle.mysteryEncounter!.doContinueEncounter = undefined; scene.currentBattle.mysteryEncounter!.doContinueEncounter = undefined;
leaveEncounterWithoutBattle(scene, true); leaveEncounterWithoutBattle(scene, true);
await showEncounterText(scene, `${namespace}.ko`); await showEncounterText(scene, `${namespace}:ko`);
const reviveCost = scene.getWaveMoneyAmount(1.5); const reviveCost = scene.getWaveMoneyAmount(1.5);
updatePlayerMoney(scene, -reviveCost, true, false); updatePlayerMoney(scene, -reviveCost, true, false);
} }
@ -256,20 +256,20 @@ function handleNextTurn(scene: BattleScene) {
let isHealPhase = false; let isHealPhase = false;
if (healthRatio < 0.03) { if (healthRatio < 0.03) {
// Grand prize // Grand prize
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.MULTI_LENS], fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.MULTI_LENS ], fillRemaining: false });
resultMessageKey = `${namespace}.best_result`; resultMessageKey = `${namespace}:best_result`;
} else if (healthRatio < 0.15) { } else if (healthRatio < 0.15) {
// 2nd prize // 2nd prize
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.SCOPE_LENS], fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.SCOPE_LENS ], fillRemaining: false });
resultMessageKey = `${namespace}.great_result`; resultMessageKey = `${namespace}:great_result`;
} else if (healthRatio < 0.33) { } else if (healthRatio < 0.33) {
// 3rd prize // 3rd prize
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.WIDE_LENS], fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.WIDE_LENS ], fillRemaining: false });
resultMessageKey = `${namespace}.good_result`; resultMessageKey = `${namespace}:good_result`;
} else { } else {
// No prize // No prize
isHealPhase = true; isHealPhase = true;
resultMessageKey = `${namespace}.bad_result`; resultMessageKey = `${namespace}:bad_result`;
} }
// End the battle // End the battle
@ -279,7 +279,7 @@ function handleNextTurn(scene: BattleScene) {
scene.currentBattle.mysteryEncounter!.doContinueEncounter = undefined; scene.currentBattle.mysteryEncounter!.doContinueEncounter = undefined;
leaveEncounterWithoutBattle(scene, isHealPhase); leaveEncounterWithoutBattle(scene, isHealPhase);
// Must end the TurnInit phase prematurely so battle phases aren't added to queue // Must end the TurnInit phase prematurely so battle phases aren't added to queue
queueEncounterMessage(scene, `${namespace}.end_game`); queueEncounterMessage(scene, `${namespace}:end_game`);
queueEncounterMessage(scene, resultMessageKey); queueEncounterMessage(scene, resultMessageKey);
// Skip remainder of TurnInitPhase // Skip remainder of TurnInitPhase
@ -287,9 +287,9 @@ function handleNextTurn(scene: BattleScene) {
} else { } else {
if (encounter.misc.turnsRemaining < 3) { if (encounter.misc.turnsRemaining < 3) {
// Display charging messages on turns that aren't the initial turn // Display charging messages on turns that aren't the initial turn
queueEncounterMessage(scene, `${namespace}.charging_continue`); queueEncounterMessage(scene, `${namespace}:charging_continue`);
} }
queueEncounterMessage(scene, `${namespace}.turn_remaining_${encounter.misc.turnsRemaining}`); queueEncounterMessage(scene, `${namespace}:turn_remaining_${encounter.misc.turnsRemaining}`);
encounter.misc.turnsRemaining--; encounter.misc.turnsRemaining--;
} }
@ -411,7 +411,7 @@ function hideShowmanIntroSprite(scene: BattleScene) {
// Slide the Wobbuffet and Game over slightly // Slide the Wobbuffet and Game over slightly
scene.tweens.add({ scene.tweens.add({
targets: [wobbuffet, carnivalGame], targets: [ wobbuffet, carnivalGame ],
x: "+=16", x: "+=16",
ease: "Sine.easeInOut", ease: "Sine.easeInOut",
duration: 750 duration: 750

View File

@ -27,7 +27,7 @@ import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
import { addPokemonDataToDexAndValidateAchievements } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { addPokemonDataToDexAndValidateAchievements } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */
const namespace = "mysteryEncounter:globalTradeSystem"; const namespace = "mysteryEncounters/globalTradeSystem";
/** Base shiny chance of 512/65536 -> 1/128 odds, affected by events and Shiny Charms. Cannot exceed 1/16 odds. */ /** Base shiny chance of 512/65536 -> 1/128 odds, affected by events and Shiny Charms. Cannot exceed 1/16 odds. */
const WONDER_TRADE_SHINY_CHANCE = 512; const WONDER_TRADE_SHINY_CHANCE = 512;
@ -35,15 +35,15 @@ const WONDER_TRADE_SHINY_CHANCE = 512;
const MAX_WONDER_TRADE_SHINY_CHANCE = 4096; const MAX_WONDER_TRADE_SHINY_CHANCE = 4096;
const LEGENDARY_TRADE_POOLS = { const LEGENDARY_TRADE_POOLS = {
1: [Species.RATTATA, Species.PIDGEY, Species.WEEDLE], 1: [ Species.RATTATA, Species.PIDGEY, Species.WEEDLE ],
2: [Species.SENTRET, Species.HOOTHOOT, Species.LEDYBA], 2: [ Species.SENTRET, Species.HOOTHOOT, Species.LEDYBA ],
3: [Species.POOCHYENA, Species.ZIGZAGOON, Species.TAILLOW], 3: [ Species.POOCHYENA, Species.ZIGZAGOON, Species.TAILLOW ],
4: [Species.BIDOOF, Species.STARLY, Species.KRICKETOT], 4: [ Species.BIDOOF, Species.STARLY, Species.KRICKETOT ],
5: [Species.PATRAT, Species.PURRLOIN, Species.PIDOVE], 5: [ Species.PATRAT, Species.PURRLOIN, Species.PIDOVE ],
6: [Species.BUNNELBY, Species.LITLEO, Species.SCATTERBUG], 6: [ Species.BUNNELBY, Species.LITLEO, Species.SCATTERBUG ],
7: [Species.PIKIPEK, Species.YUNGOOS, Species.ROCKRUFF], 7: [ Species.PIKIPEK, Species.YUNGOOS, Species.ROCKRUFF ],
8: [Species.SKWOVET, Species.WOOLOO, Species.ROOKIDEE], 8: [ Species.SKWOVET, Species.WOOLOO, Species.ROOKIDEE ],
9: [Species.LECHONK, Species.FIDOUGH, Species.TAROUNTULA] 9: [ Species.LECHONK, Species.FIDOUGH, Species.TAROUNTULA ]
}; };
/** Exclude Paradox mons as they aren't considered legendary/mythical */ /** Exclude Paradox mons as they aren't considered legendary/mythical */
@ -93,12 +93,12 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
]) ])
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
} }
]) ])
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
@ -133,9 +133,9 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withHasDexProgress(true) .withHasDexProgress(true)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
secondOptionPrompt: `${namespace}.option.1.trade_options_prompt`, secondOptionPrompt: `${namespace}:option.1.trade_options_prompt`,
}) })
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => { .withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
@ -159,7 +159,7 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
return true; return true;
}, },
onHover: () => { onHover: () => {
const formName = tradePokemon.species.forms && tradePokemon.species.forms.length > tradePokemon.formIndex ? tradePokemon.species.forms[pokemon.formIndex].formName : null; const formName = tradePokemon.species.forms && tradePokemon.species.forms.length > tradePokemon.formIndex ? tradePokemon.species.forms[tradePokemon.formIndex].formName : null;
const line1 = i18next.t("pokemonInfoContainer:ability") + " " + tradePokemon.getAbility().name + (tradePokemon.getGender() !== Gender.GENDERLESS ? " | " + i18next.t("pokemonInfoContainer:gender") + " " + getGenderSymbol(tradePokemon.getGender()) : ""); const line1 = i18next.t("pokemonInfoContainer:ability") + " " + tradePokemon.getAbility().name + (tradePokemon.getGender() !== Gender.GENDERLESS ? " | " + i18next.t("pokemonInfoContainer:gender") + " " + getGenderSymbol(tradePokemon.getGender()) : "");
const line2 = i18next.t("pokemonInfoContainer:nature") + " " + getNatureName(tradePokemon.getNature()) + (formName ? " | " + i18next.t("pokemonInfoContainer:form") + " " + formName : ""); const line2 = i18next.t("pokemonInfoContainer:nature") + " " + getNatureName(tradePokemon.getNature()) + (formName ? " | " + i18next.t("pokemonInfoContainer:form") + " " + formName : "");
showEncounterText(scene, `${line1}\n${line2}`, 0, 0, false); showEncounterText(scene, `${line1}\n${line2}`, 0, 0, false);
@ -201,7 +201,7 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
// Show the trade animation // Show the trade animation
await showTradeBackground(scene); await showTradeBackground(scene);
await doPokemonTradeSequence(scene, tradedPokemon, newPlayerPokemon); await doPokemonTradeSequence(scene, tradedPokemon, newPlayerPokemon);
await showEncounterText(scene, `${namespace}.trade_received`, null, 0, true, 4000); await showEncounterText(scene, `${namespace}:trade_received`, null, 0, true, 4000);
scene.playBgm(encounter.misc.bgmKey); scene.playBgm(encounter.misc.bgmKey);
await addPokemonDataToDexAndValidateAchievements(scene, newPlayerPokemon); await addPokemonDataToDexAndValidateAchievements(scene, newPlayerPokemon);
await hideTradeBackground(scene); await hideTradeBackground(scene);
@ -216,8 +216,8 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withHasDexProgress(true) .withHasDexProgress(true)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
}) })
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => { .withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
@ -309,7 +309,7 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
// Show the trade animation // Show the trade animation
await showTradeBackground(scene); await showTradeBackground(scene);
await doPokemonTradeSequence(scene, tradedPokemon, newPlayerPokemon); await doPokemonTradeSequence(scene, tradedPokemon, newPlayerPokemon);
await showEncounterText(scene, `${namespace}.trade_received`, null, 0, true, 4000); await showEncounterText(scene, `${namespace}:trade_received`, null, 0, true, 4000);
scene.playBgm(encounter.misc.bgmKey); scene.playBgm(encounter.misc.bgmKey);
await addPokemonDataToDexAndValidateAchievements(scene, newPlayerPokemon); await addPokemonDataToDexAndValidateAchievements(scene, newPlayerPokemon);
await hideTradeBackground(scene); await hideTradeBackground(scene);
@ -323,9 +323,9 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.3.label`, buttonLabel: `${namespace}:option.3.label`,
buttonTooltip: `${namespace}.option.3.tooltip`, buttonTooltip: `${namespace}:option.3.tooltip`,
secondOptionPrompt: `${namespace}.option.3.trade_options_prompt`, secondOptionPrompt: `${namespace}:option.3.trade_options_prompt`,
}) })
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => { .withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
@ -355,7 +355,7 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
return it.isTransferable; return it.isTransferable;
}).length > 0; }).length > 0;
if (!meetsReqs) { if (!meetsReqs) {
return getEncounterText(scene, `${namespace}.option.3.invalid_selection`) ?? null; return getEncounterText(scene, `${namespace}:option.3.invalid_selection`) ?? null;
} }
return null; return null;
@ -387,11 +387,11 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
let item: ModifierTypeOption | null = null; let item: ModifierTypeOption | null = null;
// TMs excluded from possible rewards // TMs excluded from possible rewards
while (!item || item.type.id.includes("TM_")) { while (!item || item.type.id.includes("TM_")) {
item = getPlayerModifierTypeOptions(1, scene.getParty(), [], { guaranteedModifierTiers: [tier], allowLuckUpgrades: false })[0]; item = getPlayerModifierTypeOptions(1, scene.getParty(), [], { guaranteedModifierTiers: [ tier ], allowLuckUpgrades: false })[0];
} }
encounter.setDialogueToken("itemName", item.type.name); encounter.setDialogueToken("itemName", item.type.name);
setEncounterRewards(scene, { guaranteedModifierTypeOptions: [item], fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeOptions: [ item ], fillRemaining: false });
// Remove the chosen modifier if its stacks go to 0 // Remove the chosen modifier if its stacks go to 0
modifier.stackCount -= 1; modifier.stackCount -= 1;
@ -403,18 +403,18 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
// Generate a trainer name // Generate a trainer name
const traderName = generateRandomTraderName(); const traderName = generateRandomTraderName();
encounter.setDialogueToken("tradeTrainerName", traderName.trim()); encounter.setDialogueToken("tradeTrainerName", traderName.trim());
await showEncounterText(scene, `${namespace}.item_trade_selected`); await showEncounterText(scene, `${namespace}:item_trade_selected`);
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);
}) })
.build() .build()
) )
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.4.label`, buttonLabel: `${namespace}:option.4.label`,
buttonTooltip: `${namespace}.option.4.tooltip`, buttonTooltip: `${namespace}:option.4.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.4.selected`, text: `${namespace}:option.4.selected`,
}, },
], ],
}, },
@ -628,10 +628,10 @@ function doPokemonTradeSequence(scene: BattleScene, tradedPokemon: PlayerPokemon
duration: 500, duration: 500,
onComplete: async () => { onComplete: async () => {
scene.fadeOutBgm(1000, false); scene.fadeOutBgm(1000, false);
await showEncounterText(scene, `${namespace}.pokemon_trade_selected`); await showEncounterText(scene, `${namespace}:pokemon_trade_selected`);
tradedPokemon.cry(); tradedPokemon.cry();
scene.playBgm("evolution"); scene.playBgm("evolution");
await showEncounterText(scene, `${namespace}.pokemon_trade_goodbye`); await showEncounterText(scene, `${namespace}:pokemon_trade_goodbye`);
tradedPokeball.setAlpha(0); tradedPokeball.setAlpha(0);
tradedPokeball.setVisible(true); tradedPokeball.setVisible(true);
@ -650,7 +650,7 @@ function doPokemonTradeSequence(scene: BattleScene, tradedPokemon: PlayerPokemon
// addPokeballOpenParticles(scene, tradedPokemon.x, tradedPokemon.y, tradedPokemon.pokeball); // addPokeballOpenParticles(scene, tradedPokemon.x, tradedPokemon.y, tradedPokemon.pokeball);
scene.tweens.add({ scene.tweens.add({
targets: [tradedPokemonTintSprite, tradedPokemonSprite], targets: [ tradedPokemonTintSprite, tradedPokemonSprite ],
duration: 500, duration: 500,
ease: "Sine.easeIn", ease: "Sine.easeIn",
scale: 0.25, scale: 0.25,
@ -726,7 +726,7 @@ function doPokemonTradeFlyBySequence(scene: BattleScene, tradedPokemonSprite: Ph
duration: FADE_DELAY, duration: FADE_DELAY,
onComplete: () => { onComplete: () => {
scene.tweens.add({ scene.tweens.add({
targets: [receivedPokemonSprite, tradedPokemonSprite], targets: [ receivedPokemonSprite, tradedPokemonSprite ],
y: tradeBaseBg.displayWidth / 2 - 100, y: tradeBaseBg.displayWidth / 2 - 100,
ease: "Cubic.easeInOut", ease: "Cubic.easeInOut",
duration: BASE_ANIM_DURATION * 3, duration: BASE_ANIM_DURATION * 3,

View File

@ -10,7 +10,7 @@ import { applyDamageToPokemon } from "#app/data/mystery-encounters/utils/encount
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/game-mode";
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;
const OPTION_2_REQUIRED_MOVE = Moves.FLY; const OPTION_2_REQUIRED_MOVE = Moves.FLY;
@ -21,7 +21,7 @@ const OPTION_2_REQUIRED_MOVE = Moves.FLY;
*/ */
const DAMAGE_PERCENTAGE: number = 25; const DAMAGE_PERCENTAGE: number = 25;
/** The i18n namespace for the encounter */ /** The i18n namespace for the encounter */
const namespace = "mysteryEncounter:lostAtSea"; const namespace = "mysteryEncounters/lostAtSea";
/** /**
* Lost at sea encounter. * Lost at sea encounter.
@ -40,7 +40,7 @@ export const LostAtSeaEncounter: MysteryEncounter = MysteryEncounterBuilder.with
y: 3, y: 3,
}, },
]) ])
.withIntroDialogue([{ text: `${namespace}.intro` }]) .withIntroDialogue([{ text: `${namespace}:intro` }])
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
@ -50,22 +50,22 @@ export const LostAtSeaEncounter: MysteryEncounter = MysteryEncounterBuilder.with
return true; return true;
}) })
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withOption( .withOption(
// Option 1: Use a (non fainted) pokemon that can learn Surf to guide you back/ // Option 1: Use a (non fainted) pokemon that can learn Surf to guide you back/
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT)
.withPokemonCanLearnMoveRequirement(OPTION_1_REQUIRED_MOVE) .withPokemonCanLearnMoveRequirement(OPTION_1_REQUIRED_MOVE)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
disabledButtonLabel: `${namespace}.option.1.label_disabled`, disabledButtonLabel: `${namespace}:option.1.label_disabled`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
disabledButtonTooltip: `${namespace}.option.1.tooltip_disabled`, disabledButtonTooltip: `${namespace}:option.1.tooltip_disabled`,
selected: [ selected: [
{ {
text: `${namespace}.option.1.selected`, text: `${namespace}:option.1.selected`,
}, },
], ],
}) })
@ -78,13 +78,13 @@ export const LostAtSeaEncounter: MysteryEncounter = MysteryEncounterBuilder.with
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT)
.withPokemonCanLearnMoveRequirement(OPTION_2_REQUIRED_MOVE) .withPokemonCanLearnMoveRequirement(OPTION_2_REQUIRED_MOVE)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
disabledButtonLabel: `${namespace}.option.2.label_disabled`, disabledButtonLabel: `${namespace}:option.2.label_disabled`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
disabledButtonTooltip: `${namespace}.option.2.tooltip_disabled`, disabledButtonTooltip: `${namespace}:option.2.tooltip_disabled`,
selected: [ selected: [
{ {
text: `${namespace}.option.2.selected`, text: `${namespace}:option.2.selected`,
}, },
], ],
}) })
@ -94,11 +94,11 @@ export const LostAtSeaEncounter: MysteryEncounter = MysteryEncounterBuilder.with
.withSimpleOption( .withSimpleOption(
// Option 3: Wander aimlessly // Option 3: Wander aimlessly
{ {
buttonLabel: `${namespace}.option.3.label`, buttonLabel: `${namespace}:option.3.label`,
buttonTooltip: `${namespace}.option.3.tooltip`, buttonTooltip: `${namespace}:option.3.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.3.selected`, text: `${namespace}:option.3.selected`,
}, },
], ],
}, },
@ -118,7 +118,7 @@ export const LostAtSeaEncounter: MysteryEncounter = MysteryEncounterBuilder.with
) )
.withOutroDialogue([ .withOutroDialogue([
{ {
text: `${namespace}.outro`, text: `${namespace}:outro`,
}, },
]) ])
.build(); .build();

View File

@ -20,7 +20,7 @@ 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/game-mode";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */
const namespace = "mysteryEncounter:mysteriousChallengers"; const namespace = "mysteryEncounters/mysteriousChallengers";
/** /**
* Mysterious Challengers encounter. * Mysterious Challengers encounter.
@ -34,7 +34,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter =
.withIntroSpriteConfigs([]) // These are set in onInit() .withIntroSpriteConfigs([]) // These are set in onInit()
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
}, },
]) ])
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
@ -125,16 +125,16 @@ export const MysteriousChallengersEncounter: MysteryEncounter =
return true; return true;
}) })
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.selected`, text: `${namespace}:option.selected`,
}, },
], ],
}, },
@ -143,7 +143,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter =
// Spawn standard trainer battle with memory mushroom reward // Spawn standard trainer battle with memory mushroom reward
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0]; const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0];
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.TM_COMMON, modifierTypes.TM_GREAT, modifierTypes.MEMORY_MUSHROOM], fillRemaining: true }); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.TM_COMMON, modifierTypes.TM_GREAT, modifierTypes.MEMORY_MUSHROOM ], fillRemaining: true });
// Seed offsets to remove possibility of different trainers having exact same teams // Seed offsets to remove possibility of different trainers having exact same teams
let ret; let ret;
@ -155,11 +155,11 @@ export const MysteriousChallengersEncounter: MysteryEncounter =
) )
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.selected`, text: `${namespace}:option.selected`,
}, },
], ],
}, },
@ -168,7 +168,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter =
// Spawn hard fight // Spawn hard fight
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[1]; const config: EnemyPartyConfig = encounter.enemyPartyConfigs[1];
setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT], fillRemaining: true }); setEncounterRewards(scene, { guaranteedModifierTiers: [ ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT ], fillRemaining: true });
// Seed offsets to remove possibility of different trainers having exact same teams // Seed offsets to remove possibility of different trainers having exact same teams
let ret; let ret;
@ -180,11 +180,11 @@ export const MysteriousChallengersEncounter: MysteryEncounter =
) )
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.3.label`, buttonLabel: `${namespace}:option.3.label`,
buttonTooltip: `${namespace}.option.3.tooltip`, buttonTooltip: `${namespace}:option.3.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.selected`, text: `${namespace}:option.selected`,
}, },
], ],
}, },
@ -196,7 +196,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter =
// To avoid player level snowballing from picking this option // To avoid player level snowballing from picking this option
encounter.expMultiplier = 0.9; encounter.expMultiplier = 0.9;
setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.GREAT], fillRemaining: true }); setEncounterRewards(scene, { guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.GREAT ], fillRemaining: true });
// Seed offsets to remove possibility of different trainers having exact same teams // Seed offsets to remove possibility of different trainers having exact same teams
let ret; let ret;
@ -208,7 +208,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter =
) )
.withOutroDialogue([ .withOutroDialogue([
{ {
text: `${namespace}.outro`, text: `${namespace}:outro`,
}, },
]) ])
.build(); .build();

View File

@ -16,7 +16,7 @@ import { GameOverPhase } from "#app/phases/game-over-phase";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
/** i18n namespace for encounter */ /** i18n namespace for encounter */
const namespace = "mysteryEncounter:mysteriousChest"; const namespace = "mysteryEncounters/mysteriousChest";
const RAND_LENGTH = 100; const RAND_LENGTH = 100;
const TRAP_PERCENT = 35; const TRAP_PERCENT = 35;
@ -58,12 +58,12 @@ export const MysteriousChestEncounter: MysteryEncounter =
]) ])
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
} }
]) ])
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
@ -76,12 +76,12 @@ export const MysteriousChestEncounter: MysteryEncounter =
species: getPokemonSpecies(Species.GIMMIGHOUL), species: getPokemonSpecies(Species.GIMMIGHOUL),
formIndex: 0, formIndex: 0,
isBoss: true, isBoss: true,
moveSet: [Moves.NASTY_PLOT, Moves.SHADOW_BALL, Moves.POWER_GEM, Moves.THIEF] moveSet: [ Moves.NASTY_PLOT, Moves.SHADOW_BALL, Moves.POWER_GEM, Moves.THIEF ]
} }
], ],
}; };
encounter.enemyPartyConfigs = [config]; encounter.enemyPartyConfigs = [ config ];
encounter.setDialogueToken("gimmighoulName", getPokemonSpecies(Species.GIMMIGHOUL).getName()); encounter.setDialogueToken("gimmighoulName", getPokemonSpecies(Species.GIMMIGHOUL).getName());
encounter.setDialogueToken("trapPercent", TRAP_PERCENT.toString()); encounter.setDialogueToken("trapPercent", TRAP_PERCENT.toString());
@ -96,11 +96,11 @@ export const MysteriousChestEncounter: MysteryEncounter =
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.1.selected`, text: `${namespace}:option.1.selected`,
}, },
], ],
}) })
@ -141,7 +141,7 @@ export const MysteriousChestEncounter: MysteryEncounter =
], ],
}); });
// Display result message then proceed to rewards // Display result message then proceed to rewards
queueEncounterMessage(scene, `${namespace}.option.1.normal`); queueEncounterMessage(scene, `${namespace}:option.1.normal`);
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);
} else if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT - ULTRA_REWARDS_PERCENT) { } else if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT - ULTRA_REWARDS_PERCENT) {
// Choose between 3 ULTRA tier items (30%) // Choose between 3 ULTRA tier items (30%)
@ -153,19 +153,19 @@ export const MysteriousChestEncounter: MysteryEncounter =
], ],
}); });
// Display result message then proceed to rewards // Display result message then proceed to rewards
queueEncounterMessage(scene, `${namespace}.option.1.good`); queueEncounterMessage(scene, `${namespace}:option.1.good`);
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);
} else if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT - ULTRA_REWARDS_PERCENT - ROGUE_REWARDS_PERCENT) { } else if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT - ULTRA_REWARDS_PERCENT - ROGUE_REWARDS_PERCENT) {
// Choose between 2 ROGUE tier items (10%) // Choose between 2 ROGUE tier items (10%)
setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ROGUE] }); setEncounterRewards(scene, { guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE ]});
// Display result message then proceed to rewards // Display result message then proceed to rewards
queueEncounterMessage(scene, `${namespace}.option.1.great`); queueEncounterMessage(scene, `${namespace}:option.1.great`);
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);
} else if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT - ULTRA_REWARDS_PERCENT - ROGUE_REWARDS_PERCENT - MASTER_REWARDS_PERCENT) { } else if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT - ULTRA_REWARDS_PERCENT - ROGUE_REWARDS_PERCENT - MASTER_REWARDS_PERCENT) {
// Choose 1 MASTER tier item (5%) // Choose 1 MASTER tier item (5%)
setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.MASTER] }); setEncounterRewards(scene, { guaranteedModifierTiers: [ ModifierTier.MASTER ]});
// Display result message then proceed to rewards // Display result message then proceed to rewards
queueEncounterMessage(scene, `${namespace}.option.1.amazing`); queueEncounterMessage(scene, `${namespace}:option.1.amazing`);
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);
} else { } else {
// Your highest level unfainted Pokemon gets OHKO. Start battle against a Gimmighoul (35%) // Your highest level unfainted Pokemon gets OHKO. Start battle against a Gimmighoul (35%)
@ -173,7 +173,7 @@ export const MysteriousChestEncounter: MysteryEncounter =
koPlayerPokemon(scene, highestLevelPokemon); koPlayerPokemon(scene, highestLevelPokemon);
encounter.setDialogueToken("pokeName", highestLevelPokemon.getNameToRender()); encounter.setDialogueToken("pokeName", highestLevelPokemon.getNameToRender());
await showEncounterText(scene, `${namespace}.option.1.bad`); await showEncounterText(scene, `${namespace}:option.1.bad`);
// Handle game over edge case // Handle game over edge case
const allowedPokemon = scene.getParty().filter(p => p.isAllowedInBattle()); const allowedPokemon = scene.getParty().filter(p => p.isAllowedInBattle());
@ -193,11 +193,11 @@ export const MysteriousChestEncounter: MysteryEncounter =
) )
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.2.selected`, text: `${namespace}:option.2.selected`,
}, },
], ],
}, },

View File

@ -15,7 +15,7 @@ import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
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 */
const namespace = "mysteryEncounter:partTimer"; const namespace = "mysteryEncounters/partTimer";
/** /**
* Part Timer encounter. * Part Timer encounter.
@ -45,11 +45,11 @@ export const PartTimerEncounter: MysteryEncounter =
.withAutoHideIntroVisuals(false) .withAutoHideIntroVisuals(false)
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
}, },
{ {
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
text: `${namespace}.intro_dialogue`, text: `${namespace}:intro_dialogue`,
}, },
]) ])
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
@ -69,17 +69,17 @@ export const PartTimerEncounter: MysteryEncounter =
return true; return true;
}) })
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withOption(MysteryEncounterOptionBuilder .withOption(MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.1.selected` text: `${namespace}:option.1.selected`
} }
] ]
}) })
@ -94,7 +94,7 @@ export const PartTimerEncounter: MysteryEncounter =
// Calculation from Pokemon.calculateStats // Calculation from Pokemon.calculateStats
const baselineValue = Math.floor(((2 * 90 + 16) * pokemon.level) * 0.01) + 5; const baselineValue = Math.floor(((2 * 90 + 16) * pokemon.level) * 0.01) + 5;
const percentDiff = (pokemon.getStat(Stat.SPD) - baselineValue) / baselineValue; const percentDiff = (pokemon.getStat(Stat.SPD) - baselineValue) / baselineValue;
const moneyMultiplier = Math.min(Math.max(2.5 * (1+ percentDiff), 1), 4); const moneyMultiplier = Math.min(Math.max(2.5 * (1 + percentDiff), 1), 4);
encounter.misc = { encounter.misc = {
moneyMultiplier moneyMultiplier
@ -118,7 +118,7 @@ export const PartTimerEncounter: MysteryEncounter =
// Only Pokemon non-KOd pokemon can be selected // Only Pokemon non-KOd pokemon can be selected
const selectableFilter = (pokemon: Pokemon) => { const selectableFilter = (pokemon: Pokemon) => {
return isPokemonValidForEncounterOptionSelection(pokemon, scene, `${namespace}.invalid_selection`); return isPokemonValidForEncounterOptionSelection(pokemon, scene, `${namespace}:invalid_selection`);
}; };
return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter); return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter);
@ -132,14 +132,14 @@ export const PartTimerEncounter: MysteryEncounter =
// Give money and do dialogue // Give money and do dialogue
if (moneyMultiplier > 2.5) { if (moneyMultiplier > 2.5) {
await showEncounterDialogue(scene, `${namespace}.job_complete_good`, `${namespace}.speaker`); await showEncounterDialogue(scene, `${namespace}:job_complete_good`, `${namespace}:speaker`);
} else { } else {
await showEncounterDialogue(scene, `${namespace}.job_complete_bad`, `${namespace}.speaker`); await showEncounterDialogue(scene, `${namespace}:job_complete_bad`, `${namespace}:speaker`);
} }
const moneyChange = scene.getWaveMoneyAmount(moneyMultiplier); const moneyChange = scene.getWaveMoneyAmount(moneyMultiplier);
updatePlayerMoney(scene, moneyChange, true, false); updatePlayerMoney(scene, moneyChange, true, false);
await showEncounterText(scene, i18next.t("mysteryEncounterMessages:receive_money", { amount: moneyChange })); await showEncounterText(scene, i18next.t("mysteryEncounterMessages:receive_money", { amount: moneyChange }));
await showEncounterText(scene, `${namespace}.pokemon_tired`); await showEncounterText(scene, `${namespace}:pokemon_tired`);
setEncounterRewards(scene, { fillRemaining: true }); setEncounterRewards(scene, { fillRemaining: true });
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);
@ -149,11 +149,11 @@ export const PartTimerEncounter: MysteryEncounter =
.withOption(MysteryEncounterOptionBuilder .withOption(MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.2.selected` text: `${namespace}:option.2.selected`
} }
] ]
}) })
@ -195,7 +195,7 @@ export const PartTimerEncounter: MysteryEncounter =
// Only Pokemon non-KOd pokemon can be selected // Only Pokemon non-KOd pokemon can be selected
const selectableFilter = (pokemon: Pokemon) => { const selectableFilter = (pokemon: Pokemon) => {
return isPokemonValidForEncounterOptionSelection(pokemon, scene, `${namespace}.invalid_selection`); return isPokemonValidForEncounterOptionSelection(pokemon, scene, `${namespace}:invalid_selection`);
}; };
return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter); return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter);
@ -209,14 +209,14 @@ export const PartTimerEncounter: MysteryEncounter =
// Give money and do dialogue // Give money and do dialogue
if (moneyMultiplier > 2.5) { if (moneyMultiplier > 2.5) {
await showEncounterDialogue(scene, `${namespace}.job_complete_good`, `${namespace}.speaker`); await showEncounterDialogue(scene, `${namespace}:job_complete_good`, `${namespace}:speaker`);
} else { } else {
await showEncounterDialogue(scene, `${namespace}.job_complete_bad`, `${namespace}.speaker`); await showEncounterDialogue(scene, `${namespace}:job_complete_bad`, `${namespace}:speaker`);
} }
const moneyChange = scene.getWaveMoneyAmount(moneyMultiplier); const moneyChange = scene.getWaveMoneyAmount(moneyMultiplier);
updatePlayerMoney(scene, moneyChange, true, false); updatePlayerMoney(scene, moneyChange, true, false);
await showEncounterText(scene, i18next.t("mysteryEncounterMessages:receive_money", { amount: moneyChange })); await showEncounterText(scene, i18next.t("mysteryEncounterMessages:receive_money", { amount: moneyChange }));
await showEncounterText(scene, `${namespace}.pokemon_tired`); await showEncounterText(scene, `${namespace}:pokemon_tired`);
setEncounterRewards(scene, { fillRemaining: true }); setEncounterRewards(scene, { fillRemaining: true });
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);
@ -228,12 +228,12 @@ export const PartTimerEncounter: MysteryEncounter =
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL) .newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)
.withPrimaryPokemonRequirement(new MoveRequirement(CHARMING_MOVES)) // Will set option3PrimaryName and option3PrimaryMove dialogue tokens automatically .withPrimaryPokemonRequirement(new MoveRequirement(CHARMING_MOVES)) // Will set option3PrimaryName and option3PrimaryMove dialogue tokens automatically
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.3.label`, buttonLabel: `${namespace}:option.3.label`,
buttonTooltip: `${namespace}.option.3.tooltip`, buttonTooltip: `${namespace}:option.3.tooltip`,
disabledButtonTooltip: `${namespace}.option.3.disabled_tooltip`, disabledButtonTooltip: `${namespace}:option.3.disabled_tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.3.selected`, text: `${namespace}:option.3.selected`,
}, },
], ],
}) })
@ -264,11 +264,11 @@ export const PartTimerEncounter: MysteryEncounter =
await transitionMysteryEncounterIntroVisuals(scene, false, false); await transitionMysteryEncounterIntroVisuals(scene, false, false);
// Give money and do dialogue // Give money and do dialogue
await showEncounterDialogue(scene, `${namespace}.job_complete_good`, `${namespace}.speaker`); await showEncounterDialogue(scene, `${namespace}:job_complete_good`, `${namespace}:speaker`);
const moneyChange = scene.getWaveMoneyAmount(2.5); const moneyChange = scene.getWaveMoneyAmount(2.5);
updatePlayerMoney(scene, moneyChange, true, false); updatePlayerMoney(scene, moneyChange, true, false);
await showEncounterText(scene, i18next.t("mysteryEncounterMessages:receive_money", { amount: moneyChange })); await showEncounterText(scene, i18next.t("mysteryEncounterMessages:receive_money", { amount: moneyChange }));
await showEncounterText(scene, `${namespace}.pokemon_tired`); await showEncounterText(scene, `${namespace}:pokemon_tired`);
setEncounterRewards(scene, { fillRemaining: true }); setEncounterRewards(scene, { fillRemaining: true });
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);
@ -277,8 +277,8 @@ export const PartTimerEncounter: MysteryEncounter =
) )
.withOutroDialogue([ .withOutroDialogue([
{ {
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
text: `${namespace}.outro`, text: `${namespace}:outro`,
} }
]) ])
.build(); .build();

View File

@ -21,9 +21,9 @@ 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/game-mode";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */
const namespace = "mysteryEncounter:safariZone"; const namespace = "mysteryEncounters/safariZone";
const TRAINER_THROW_ANIMATION_TIMES = [512, 184, 768]; const TRAINER_THROW_ANIMATION_TIMES = [ 512, 184, 768 ];
const SAFARI_MONEY_MULTIPLIER = 2; const SAFARI_MONEY_MULTIPLIER = 2;
@ -51,12 +51,12 @@ export const SafariZoneEncounter: MysteryEncounter =
]) ])
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
}, },
]) ])
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
scene.currentBattle.mysteryEncounter?.setDialogueToken("numEncounters", NUM_SAFARI_ENCOUNTERS.toString()); scene.currentBattle.mysteryEncounter?.setDialogueToken("numEncounters", NUM_SAFARI_ENCOUNTERS.toString());
return true; return true;
@ -65,11 +65,11 @@ export const SafariZoneEncounter: MysteryEncounter =
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT)
.withSceneRequirement(new MoneyRequirement(0, SAFARI_MONEY_MULTIPLIER)) // Cost equal to 1 Max Revive .withSceneRequirement(new MoneyRequirement(0, SAFARI_MONEY_MULTIPLIER)) // Cost equal to 1 Max Revive
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.1.selected`, text: `${namespace}:option.1.selected`,
}, },
], ],
}) })
@ -98,11 +98,11 @@ export const SafariZoneEncounter: MysteryEncounter =
) )
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.2.selected`, text: `${namespace}:option.2.selected`,
}, },
], ],
}, },
@ -133,11 +133,11 @@ const safariZoneGameOptions: MysteryEncounterOption[] = [
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.safari.1.label`, buttonLabel: `${namespace}:safari.1.label`,
buttonTooltip: `${namespace}.safari.1.tooltip`, buttonTooltip: `${namespace}:safari.1.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.safari.1.selected`, text: `${namespace}:safari.1.selected`,
} }
], ],
}) })
@ -168,11 +168,11 @@ const safariZoneGameOptions: MysteryEncounterOption[] = [
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.safari.2.label`, buttonLabel: `${namespace}:safari.2.label`,
buttonTooltip: `${namespace}.safari.2.tooltip`, buttonTooltip: `${namespace}:safari.2.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.safari.2.selected`, text: `${namespace}:safari.2.selected`,
}, },
], ],
}) })
@ -186,9 +186,9 @@ const safariZoneGameOptions: MysteryEncounterOption[] = [
// 80% chance to increase flee stage +1 // 80% chance to increase flee stage +1
const fleeChangeResult = tryChangeFleeStage(scene, 1, 8); const fleeChangeResult = tryChangeFleeStage(scene, 1, 8);
if (!fleeChangeResult) { if (!fleeChangeResult) {
await showEncounterText(scene, getEncounterText(scene, `${namespace}.safari.busy_eating`) ?? "", null, 1000, false ); await showEncounterText(scene, getEncounterText(scene, `${namespace}:safari.busy_eating`) ?? "", null, 1000, false );
} else { } else {
await showEncounterText(scene, getEncounterText(scene, `${namespace}.safari.eating`) ?? "", null, 1000, false); await showEncounterText(scene, getEncounterText(scene, `${namespace}:safari.eating`) ?? "", null, 1000, false);
} }
await doEndTurn(scene, 1); await doEndTurn(scene, 1);
@ -198,11 +198,11 @@ const safariZoneGameOptions: MysteryEncounterOption[] = [
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.safari.3.label`, buttonLabel: `${namespace}:safari.3.label`,
buttonTooltip: `${namespace}.safari.3.tooltip`, buttonTooltip: `${namespace}:safari.3.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.safari.3.selected`, text: `${namespace}:safari.3.selected`,
}, },
], ],
}) })
@ -215,9 +215,9 @@ const safariZoneGameOptions: MysteryEncounterOption[] = [
// 80% chance to decrease catch stage -1 // 80% chance to decrease catch stage -1
const catchChangeResult = tryChangeCatchStage(scene, -1, 8); const catchChangeResult = tryChangeCatchStage(scene, -1, 8);
if (!catchChangeResult) { if (!catchChangeResult) {
await showEncounterText(scene, getEncounterText(scene, `${namespace}.safari.beside_itself_angry`) ?? "", null, 1000, false ); await showEncounterText(scene, getEncounterText(scene, `${namespace}:safari.beside_itself_angry`) ?? "", null, 1000, false );
} else { } else {
await showEncounterText(scene, getEncounterText(scene, `${namespace}.safari.angry`) ?? "", null, 1000, false ); await showEncounterText(scene, getEncounterText(scene, `${namespace}:safari.angry`) ?? "", null, 1000, false );
} }
await doEndTurn(scene, 2); await doEndTurn(scene, 2);
@ -227,8 +227,8 @@ const safariZoneGameOptions: MysteryEncounterOption[] = [
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.safari.4.label`, buttonLabel: `${namespace}:safari.4.label`,
buttonTooltip: `${namespace}.safari.4.tooltip`, buttonTooltip: `${namespace}:safari.4.tooltip`,
}) })
.withOptionPhase(async (scene: BattleScene) => { .withOptionPhase(async (scene: BattleScene) => {
// Flee option // Flee option
@ -253,14 +253,14 @@ async function summonSafariPokemon(scene: BattleScene) {
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
// Message pokemon remaining // Message pokemon remaining
encounter.setDialogueToken("remainingCount", encounter.misc.safariPokemonRemaining); encounter.setDialogueToken("remainingCount", encounter.misc.safariPokemonRemaining);
scene.queueMessage(getEncounterText(scene, `${namespace}.safari.remaining_count`) ?? "", null, true); scene.queueMessage(getEncounterText(scene, `${namespace}:safari.remaining_count`) ?? "", null, true);
// Generate pokemon using safariPokemonRemaining so they are always the same pokemon no matter how many turns are taken // Generate pokemon using safariPokemonRemaining so they are always the same pokemon no matter how many turns are taken
// Safari pokemon roll twice on shiny and HA chances, but are otherwise normal // Safari pokemon roll twice on shiny and HA chances, but are otherwise normal
let enemySpecies; let enemySpecies;
let pokemon; let pokemon;
scene.executeWithSeedOffset(() => { scene.executeWithSeedOffset(() => {
enemySpecies = getPokemonSpecies(getRandomSpeciesByStarterTier([0, 5], undefined, undefined, false, false, false)); enemySpecies = getPokemonSpecies(getRandomSpeciesByStarterTier([ 0, 5 ], undefined, undefined, false, false, false));
const level = scene.currentBattle.getLevelForWave(); const level = scene.currentBattle.getLevelForWave();
enemySpecies = getPokemonSpecies(enemySpecies.getWildSpeciesForLevel(level, true, false, scene.gameMode)); enemySpecies = getPokemonSpecies(enemySpecies.getWildSpeciesForLevel(level, true, false, scene.gameMode));
pokemon = scene.addEnemyPokemon(enemySpecies, level, TrainerSlot.NONE, false); pokemon = scene.addEnemyPokemon(enemySpecies, level, TrainerSlot.NONE, false);
@ -518,7 +518,7 @@ async function doEndTurn(scene: BattleScene, cursorIndex: number) {
leaveEncounterWithoutBattle(scene, true); leaveEncounterWithoutBattle(scene, true);
} }
} else { } else {
scene.queueMessage(getEncounterText(scene, `${namespace}.safari.watching`) ?? "", 0, null, 1000); scene.queueMessage(getEncounterText(scene, `${namespace}:safari.watching`) ?? "", 0, null, 1000);
initSubsequentOptionSelect(scene, { overrideOptions: safariZoneGameOptions, startingCursorIndex: cursorIndex, hideDescription: true }); initSubsequentOptionSelect(scene, { overrideOptions: safariZoneGameOptions, startingCursorIndex: cursorIndex, hideDescription: true });
} }
} }

View File

@ -18,7 +18,7 @@ import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
import i18next from "i18next"; import i18next from "i18next";
/** the i18n namespace for this encounter */ /** the i18n namespace for this encounter */
const namespace = "mysteryEncounter:shadyVitaminDealer"; const namespace = "mysteryEncounters/shadyVitaminDealer";
const VITAMIN_DEALER_CHEAP_PRICE_MULTIPLIER = 1.5; const VITAMIN_DEALER_CHEAP_PRICE_MULTIPLIER = 1.5;
const VITAMIN_DEALER_EXPENSIVE_PRICE_MULTIPLIER = 3.5; const VITAMIN_DEALER_EXPENSIVE_PRICE_MULTIPLIER = 3.5;
@ -33,7 +33,7 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter =
.withEncounterTier(MysteryEncounterTier.COMMON) .withEncounterTier(MysteryEncounterTier.COMMON)
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES) .withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
.withSceneRequirement(new MoneyRequirement(0, VITAMIN_DEALER_CHEAP_PRICE_MULTIPLIER)) // Must have the money for at least the cheap deal .withSceneRequirement(new MoneyRequirement(0, VITAMIN_DEALER_CHEAP_PRICE_MULTIPLIER)) // Must have the money for at least the cheap deal
.withPrimaryPokemonHealthRatioRequirement([0.51, 1]) // At least 1 Pokemon must have above half HP .withPrimaryPokemonHealthRatioRequirement([ 0.51, 1 ]) // At least 1 Pokemon must have above half HP
.withIntroSpriteConfigs([ .withIntroSpriteConfigs([
{ {
spriteKey: Species.KROOKODILE.toString(), spriteKey: Species.KROOKODILE.toString(),
@ -55,26 +55,26 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter =
]) ])
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
}, },
{ {
text: `${namespace}.intro_dialogue`, text: `${namespace}:intro_dialogue`,
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
}, },
]) ])
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withOption( .withOption(
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT)
.withSceneMoneyRequirement(0, VITAMIN_DEALER_CHEAP_PRICE_MULTIPLIER) .withSceneMoneyRequirement(0, VITAMIN_DEALER_CHEAP_PRICE_MULTIPLIER)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.selected`, text: `${namespace}:option.selected`,
}, },
], ],
}) })
@ -103,7 +103,7 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter =
return i18next.t("partyUiHandler:cantBeUsed", { pokemonName: pokemon.getNameToRender() }) ?? null; return i18next.t("partyUiHandler:cantBeUsed", { pokemonName: pokemon.getNameToRender() }) ?? null;
} }
if (!encounter.pokemonMeetsPrimaryRequirements(scene, pokemon)) { if (!encounter.pokemonMeetsPrimaryRequirements(scene, pokemon)) {
return getEncounterText(scene, `${namespace}.invalid_selection`) ?? null; return getEncounterText(scene, `${namespace}:invalid_selection`) ?? null;
} }
return null; return null;
@ -139,8 +139,8 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter =
chosenPokemon.nature = newNature; chosenPokemon.nature = newNature;
encounter.setDialogueToken("newNature", getNatureName(newNature)); encounter.setDialogueToken("newNature", getNatureName(newNature));
queueEncounterMessage(scene, `${namespace}.cheap_side_effects`); queueEncounterMessage(scene, `${namespace}:cheap_side_effects`);
setEncounterExp(scene, [chosenPokemon.id], 100); setEncounterExp(scene, [ chosenPokemon.id ], 100);
chosenPokemon.updateInfo(); chosenPokemon.updateInfo();
}) })
.build() .build()
@ -150,11 +150,11 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter =
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT)
.withSceneMoneyRequirement(0, VITAMIN_DEALER_EXPENSIVE_PRICE_MULTIPLIER) .withSceneMoneyRequirement(0, VITAMIN_DEALER_EXPENSIVE_PRICE_MULTIPLIER)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.selected`, text: `${namespace}:option.selected`,
}, },
], ],
}) })
@ -178,7 +178,7 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter =
// Only Pokemon that can gain benefits are unfainted // Only Pokemon that can gain benefits are unfainted
const selectableFilter = (pokemon: Pokemon) => { const selectableFilter = (pokemon: Pokemon) => {
return isPokemonValidForEncounterOptionSelection(pokemon, scene, `${namespace}.invalid_selection`); return isPokemonValidForEncounterOptionSelection(pokemon, scene, `${namespace}:invalid_selection`);
}; };
return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter); return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter);
@ -200,8 +200,8 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter =
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
const chosenPokemon = encounter.misc.chosenPokemon; const chosenPokemon = encounter.misc.chosenPokemon;
queueEncounterMessage(scene, `${namespace}.no_bad_effects`); queueEncounterMessage(scene, `${namespace}:no_bad_effects`);
setEncounterExp(scene, [chosenPokemon.id], 100); setEncounterExp(scene, [ chosenPokemon.id ], 100);
chosenPokemon.updateInfo(); chosenPokemon.updateInfo();
}) })
@ -209,12 +209,12 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter =
) )
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.3.label`, buttonLabel: `${namespace}:option.3.label`,
buttonTooltip: `${namespace}.option.3.tooltip`, buttonTooltip: `${namespace}:option.3.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.3.selected`, text: `${namespace}:option.3.selected`,
speaker: `${namespace}.speaker` speaker: `${namespace}:speaker`
} }
] ]
}, },

View File

@ -21,7 +21,7 @@ import { BerryType } from "#enums/berry-type";
import { MysteryEncounterPokemonData } from "#app/data/mystery-encounters/mystery-encounter-pokemon-data"; import { MysteryEncounterPokemonData } from "#app/data/mystery-encounters/mystery-encounter-pokemon-data";
/** i18n namespace for the encounter */ /** i18n namespace for the encounter */
const namespace = "mysteryEncounter:slumberingSnorlax"; const namespace = "mysteryEncounters/slumberingSnorlax";
/** /**
* Sleeping Snorlax encounter. * Sleeping Snorlax encounter.
@ -48,7 +48,7 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter =
]) ])
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
}, },
]) ])
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
@ -60,15 +60,15 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter =
const pokemonConfig: EnemyPokemonConfig = { const pokemonConfig: EnemyPokemonConfig = {
species: bossSpecies, species: bossSpecies,
isBoss: true, isBoss: true,
status: [StatusEffect.SLEEP, 5], // Extra turns on timer for Snorlax's start of fight moves status: [ StatusEffect.SLEEP, 5 ], // Extra turns on timer for Snorlax's start of fight moves
moveSet: [Moves.REST, Moves.SLEEP_TALK, Moves.CRUNCH, Moves.GIGA_IMPACT], moveSet: [ Moves.REST, Moves.SLEEP_TALK, Moves.CRUNCH, Moves.GIGA_IMPACT ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.SITRUS]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.SITRUS ]) as PokemonHeldItemModifierType,
stackCount: 2 stackCount: 2
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.ENIGMA]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.ENIGMA ]) as PokemonHeldItemModifierType,
stackCount: 2 stackCount: 2
}, },
], ],
@ -77,44 +77,44 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter =
}; };
const config: EnemyPartyConfig = { const config: EnemyPartyConfig = {
levelAdditiveModifier: 0.5, levelAdditiveModifier: 0.5,
pokemonConfigs: [pokemonConfig], pokemonConfigs: [ pokemonConfig ],
}; };
encounter.enemyPartyConfigs = [config]; encounter.enemyPartyConfigs = [ config ];
// Load animations/sfx for Snorlax fight start moves // Load animations/sfx for Snorlax fight start moves
loadCustomMovesForEncounter(scene, [Moves.SNORE]); loadCustomMovesForEncounter(scene, [ Moves.SNORE ]);
encounter.setDialogueToken("snorlaxName", getPokemonSpecies(Species.SNORLAX).getName()); encounter.setDialogueToken("snorlaxName", getPokemonSpecies(Species.SNORLAX).getName());
return true; return true;
}) })
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.1.selected`, text: `${namespace}:option.1.selected`,
}, },
], ],
}, },
async (scene: BattleScene) => { async (scene: BattleScene) => {
// Pick battle // Pick battle
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.LEFTOVERS], fillRemaining: true}); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.LEFTOVERS ], fillRemaining: true });
encounter.startOfBattleEffects.push( encounter.startOfBattleEffects.push(
{ {
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.PLAYER], targets: [ BattlerIndex.PLAYER ],
move: new PokemonMove(Moves.SNORE), move: new PokemonMove(Moves.SNORE),
ignorePp: true ignorePp: true
}, },
{ {
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.PLAYER], targets: [ BattlerIndex.PLAYER ],
move: new PokemonMove(Moves.SNORE), move: new PokemonMove(Moves.SNORE),
ignorePp: true ignorePp: true
}); });
@ -123,11 +123,11 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter =
) )
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.2.selected`, text: `${namespace}:option.2.selected`,
}, },
], ],
}, },
@ -135,7 +135,7 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter =
// Fall asleep waiting for Snorlax // Fall asleep waiting for Snorlax
// Full heal party // Full heal party
scene.unshiftPhase(new PartyHealPhase(scene, true)); scene.unshiftPhase(new PartyHealPhase(scene, true));
queueEncounterMessage(scene, `${namespace}.option.2.rest_result`); queueEncounterMessage(scene, `${namespace}:option.2.rest_result`);
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);
} }
) )
@ -144,19 +144,19 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter =
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL) .newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)
.withPrimaryPokemonRequirement(new MoveRequirement(STEALING_MOVES)) .withPrimaryPokemonRequirement(new MoveRequirement(STEALING_MOVES))
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.3.label`, buttonLabel: `${namespace}:option.3.label`,
buttonTooltip: `${namespace}.option.3.tooltip`, buttonTooltip: `${namespace}:option.3.tooltip`,
disabledButtonTooltip: `${namespace}.option.3.disabled_tooltip`, disabledButtonTooltip: `${namespace}:option.3.disabled_tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.3.selected` text: `${namespace}:option.3.selected`
} }
] ]
}) })
.withOptionPhase(async (scene: BattleScene) => { .withOptionPhase(async (scene: BattleScene) => {
// Steal the Snorlax's Leftovers // Steal the Snorlax's Leftovers
const instance = scene.currentBattle.mysteryEncounter!; const instance = scene.currentBattle.mysteryEncounter!;
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.LEFTOVERS], fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.LEFTOVERS ], fillRemaining: false });
// Snorlax exp to Pokemon that did the stealing // Snorlax exp to Pokemon that did the stealing
setEncounterExp(scene, instance.primaryPokemon!.id, getPokemonSpecies(Species.SNORLAX).baseExp); setEncounterExp(scene, instance.primaryPokemon!.id, getPokemonSpecies(Species.SNORLAX).baseExp);
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);

View File

@ -23,11 +23,11 @@ import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
import { getEncounterPokemonLevelForWave, STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { getEncounterPokemonLevelForWave, STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
/** the i18n namespace for this encounter */ /** the i18n namespace for this encounter */
const namespace = "mysteryEncounter:teleportingHijinks"; const namespace = "mysteryEncounters/teleportingHijinks";
const MONEY_COST_MULTIPLIER = 1.75; const MONEY_COST_MULTIPLIER = 1.75;
const BIOME_CANDIDATES = [Biome.SPACE, Biome.FAIRY_CAVE, Biome.LABORATORY, Biome.ISLAND, Biome.WASTELAND, Biome.DOJO]; const BIOME_CANDIDATES = [ Biome.SPACE, Biome.FAIRY_CAVE, Biome.LABORATORY, Biome.ISLAND, Biome.WASTELAND, Biome.DOJO ];
const MACHINE_INTERFACING_TYPES = [Type.ELECTRIC, Type.STEEL]; const MACHINE_INTERFACING_TYPES = [ Type.ELECTRIC, Type.STEEL ];
/** /**
* Teleporting Hijinks encounter. * Teleporting Hijinks encounter.
@ -38,7 +38,7 @@ export const TeleportingHijinksEncounter: MysteryEncounter =
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.TELEPORTING_HIJINKS) MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.TELEPORTING_HIJINKS)
.withEncounterTier(MysteryEncounterTier.COMMON) .withEncounterTier(MysteryEncounterTier.COMMON)
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES) .withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
.withSceneRequirement(new WaveModulusRequirement([1, 2, 3], 10)) // Must be in first 3 waves after boss wave .withSceneRequirement(new WaveModulusRequirement([ 1, 2, 3 ], 10)) // Must be in first 3 waves after boss wave
.withSceneRequirement(new MoneyRequirement(0, MONEY_COST_MULTIPLIER)) // Must be able to pay teleport cost .withSceneRequirement(new MoneyRequirement(0, MONEY_COST_MULTIPLIER)) // Must be able to pay teleport cost
.withAutoHideIntroVisuals(false) .withAutoHideIntroVisuals(false)
.withCatchAllowed(true) .withCatchAllowed(true)
@ -55,12 +55,12 @@ export const TeleportingHijinksEncounter: MysteryEncounter =
]) ])
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
} }
]) ])
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
const price = scene.getWaveMoneyAmount(MONEY_COST_MULTIPLIER); const price = scene.getWaveMoneyAmount(MONEY_COST_MULTIPLIER);
@ -76,11 +76,11 @@ export const TeleportingHijinksEncounter: MysteryEncounter =
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT)
.withSceneMoneyRequirement(0, MONEY_COST_MULTIPLIER) // Must be able to pay teleport cost .withSceneMoneyRequirement(0, MONEY_COST_MULTIPLIER) // Must be able to pay teleport cost
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.1.selected`, text: `${namespace}:option.1.selected`,
} }
], ],
}) })
@ -100,12 +100,12 @@ export const TeleportingHijinksEncounter: MysteryEncounter =
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL) .newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)
.withPokemonTypeRequirement(MACHINE_INTERFACING_TYPES, true, 1) // Must have Steel or Electric type .withPokemonTypeRequirement(MACHINE_INTERFACING_TYPES, true, 1) // Must have Steel or Electric type
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
disabledButtonTooltip: `${namespace}.option.2.disabled_tooltip`, disabledButtonTooltip: `${namespace}:option.2.disabled_tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.2.selected`, text: `${namespace}:option.2.selected`,
} }
], ],
}) })
@ -119,11 +119,11 @@ export const TeleportingHijinksEncounter: MysteryEncounter =
) )
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.3.label`, buttonLabel: `${namespace}:option.3.label`,
buttonTooltip: `${namespace}.option.3.tooltip`, buttonTooltip: `${namespace}:option.3.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.3.selected`, text: `${namespace}:option.3.selected`,
}, },
], ],
}, },
@ -145,9 +145,9 @@ export const TeleportingHijinksEncounter: MysteryEncounter =
}], }],
}; };
const magnet = generateModifierTypeOption(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [Type.STEEL])!; const magnet = generateModifierTypeOption(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [ Type.STEEL ])!;
const metalCoat = generateModifierTypeOption(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [Type.ELECTRIC])!; const metalCoat = generateModifierTypeOption(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [ Type.ELECTRIC ])!;
setEncounterRewards(scene, { guaranteedModifierTypeOptions: [magnet, metalCoat], fillRemaining: true }); setEncounterRewards(scene, { guaranteedModifierTypeOptions: [ magnet, metalCoat ], fillRemaining: true });
transitionMysteryEncounterIntroVisuals(scene, true, true); transitionMysteryEncounterIntroVisuals(scene, true, true);
await initBattleWithEnemyConfig(scene, config); await initBattleWithEnemyConfig(scene, config);
} }
@ -162,10 +162,10 @@ async function doBiomeTransitionDialogueAndBattleInit(scene: BattleScene) {
const newBiome = filteredBiomes[randSeedInt(filteredBiomes.length)]; const newBiome = filteredBiomes[randSeedInt(filteredBiomes.length)];
// Show dialogue and transition biome // Show dialogue and transition biome
await showEncounterText(scene, `${namespace}.transport`); await showEncounterText(scene, `${namespace}:transport`);
await Promise.all([animateBiomeChange(scene, newBiome), transitionMysteryEncounterIntroVisuals(scene)]); await Promise.all([ animateBiomeChange(scene, newBiome), transitionMysteryEncounterIntroVisuals(scene) ]);
scene.playBgm(); scene.playBgm();
await showEncounterText(scene, `${namespace}.attacked`); await showEncounterText(scene, `${namespace}:attacked`);
// Init enemy // Init enemy
const level = getEncounterPokemonLevelForWave(scene, STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER); const level = getEncounterPokemonLevelForWave(scene, STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER);
@ -175,8 +175,8 @@ async function doBiomeTransitionDialogueAndBattleInit(scene: BattleScene) {
// Defense/Spd buffs below wave 50, +1 to all stats otherwise // Defense/Spd buffs below wave 50, +1 to all stats otherwise
const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = scene.currentBattle.waveIndex < 50 ? const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = scene.currentBattle.waveIndex < 50 ?
[Stat.DEF, Stat.SPDEF, Stat.SPD] : [ Stat.DEF, Stat.SPDEF, Stat.SPD ] :
[Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD]; [ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD ];
const config: EnemyPartyConfig = { const config: EnemyPartyConfig = {
pokemonConfigs: [{ pokemonConfigs: [{
@ -184,9 +184,9 @@ async function doBiomeTransitionDialogueAndBattleInit(scene: BattleScene) {
species: bossSpecies, species: bossSpecies,
dataSource: new PokemonData(bossPokemon), dataSource: new PokemonData(bossPokemon),
isBoss: true, isBoss: true,
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON], tags: [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON ],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => { mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
queueEncounterMessage(pokemon.scene, `${namespace}.boss_enraged`); queueEncounterMessage(pokemon.scene, `${namespace}:boss_enraged`);
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, statChangesForBattle, 1)); pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, statChangesForBattle, 1));
} }
}], }],
@ -198,7 +198,7 @@ async function doBiomeTransitionDialogueAndBattleInit(scene: BattleScene) {
async function animateBiomeChange(scene: BattleScene, nextBiome: Biome) { async function animateBiomeChange(scene: BattleScene, nextBiome: Biome) {
return new Promise<void>(resolve => { return new Promise<void>(resolve => {
scene.tweens.add({ scene.tweens.add({
targets: [scene.arenaEnemy, scene.lastEnemyTrainer], targets: [ scene.arenaEnemy, scene.lastEnemyTrainer ],
x: "+=300", x: "+=300",
duration: 2000, duration: 2000,
onComplete: () => { onComplete: () => {
@ -214,7 +214,7 @@ async function animateBiomeChange(scene: BattleScene, nextBiome: Biome) {
scene.arenaPlayerTransition.setVisible(true); scene.arenaPlayerTransition.setVisible(true);
scene.tweens.add({ scene.tweens.add({
targets: [scene.arenaPlayer, scene.arenaBgTransition, scene.arenaPlayerTransition], targets: [ scene.arenaPlayer, scene.arenaBgTransition, scene.arenaPlayerTransition ],
duration: 1000, duration: 1000,
ease: "Sine.easeInOut", ease: "Sine.easeInOut",
alpha: (target: any) => target === scene.arenaPlayer ? 0 : 1, alpha: (target: any) => target === scene.arenaPlayer ? 0 : 1,

View File

@ -10,7 +10,8 @@ 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";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import { getPokemonSpecies, speciesStarters } from "#app/data/pokemon-species"; import { getPokemonSpecies } from "#app/data/pokemon-species";
import { speciesStarterCosts } from "#app/data/balance/starters";
import { Nature } from "#enums/nature"; import { Nature } from "#enums/nature";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { PlayerPokemon } from "#app/field/pokemon"; import { PlayerPokemon } from "#app/field/pokemon";
@ -26,7 +27,7 @@ import { Type } from "#app/data/type";
import { getPokeballTintColor } from "#app/data/pokeball"; import { getPokeballTintColor } from "#app/data/pokeball";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */
const namespace = "mysteryEncounter:expertPokemonBreeder"; const namespace = "mysteryEncounters/theExpertPokemonBreeder";
const trainerNameKey = "trainerNames:expert_pokemon_breeder"; const trainerNameKey = "trainerNames:expert_pokemon_breeder";
@ -47,29 +48,29 @@ class BreederSpeciesEvolution {
} }
const POOL_1_POKEMON: (Species | BreederSpeciesEvolution)[][] = [ const POOL_1_POKEMON: (Species | BreederSpeciesEvolution)[][] = [
[Species.MUNCHLAX, new BreederSpeciesEvolution(Species.SNORLAX, SECOND_STAGE_EVOLUTION_WAVE)], [ Species.MUNCHLAX, new BreederSpeciesEvolution(Species.SNORLAX, SECOND_STAGE_EVOLUTION_WAVE) ],
[Species.HAPPINY, new BreederSpeciesEvolution(Species.CHANSEY, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.BLISSEY, FINAL_STAGE_EVOLUTION_WAVE)], [ Species.HAPPINY, new BreederSpeciesEvolution(Species.CHANSEY, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.BLISSEY, FINAL_STAGE_EVOLUTION_WAVE) ],
[Species.MAGBY, new BreederSpeciesEvolution(Species.MAGMAR, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.MAGMORTAR, FINAL_STAGE_EVOLUTION_WAVE)], [ Species.MAGBY, new BreederSpeciesEvolution(Species.MAGMAR, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.MAGMORTAR, FINAL_STAGE_EVOLUTION_WAVE) ],
[Species.ELEKID, new BreederSpeciesEvolution(Species.ELECTABUZZ, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.ELECTIVIRE, FINAL_STAGE_EVOLUTION_WAVE)], [ Species.ELEKID, new BreederSpeciesEvolution(Species.ELECTABUZZ, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.ELECTIVIRE, FINAL_STAGE_EVOLUTION_WAVE) ],
[Species.RIOLU, new BreederSpeciesEvolution(Species.LUCARIO, SECOND_STAGE_EVOLUTION_WAVE)], [ Species.RIOLU, new BreederSpeciesEvolution(Species.LUCARIO, SECOND_STAGE_EVOLUTION_WAVE) ],
[Species.BUDEW, new BreederSpeciesEvolution(Species.ROSELIA, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.ROSERADE, FINAL_STAGE_EVOLUTION_WAVE)], [ Species.BUDEW, new BreederSpeciesEvolution(Species.ROSELIA, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.ROSERADE, FINAL_STAGE_EVOLUTION_WAVE) ],
[Species.TOXEL, new BreederSpeciesEvolution(Species.TOXTRICITY, SECOND_STAGE_EVOLUTION_WAVE)], [ Species.TOXEL, new BreederSpeciesEvolution(Species.TOXTRICITY, SECOND_STAGE_EVOLUTION_WAVE) ],
[Species.MIME_JR, new BreederSpeciesEvolution(Species.GALAR_MR_MIME, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.MR_RIME, FINAL_STAGE_EVOLUTION_WAVE)] [ Species.MIME_JR, new BreederSpeciesEvolution(Species.GALAR_MR_MIME, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.MR_RIME, FINAL_STAGE_EVOLUTION_WAVE) ]
]; ];
const POOL_2_POKEMON: (Species | BreederSpeciesEvolution)[][] = [ const POOL_2_POKEMON: (Species | BreederSpeciesEvolution)[][] = [
[Species.PICHU, new BreederSpeciesEvolution(Species.PIKACHU, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.RAICHU, FINAL_STAGE_EVOLUTION_WAVE)], [ Species.PICHU, new BreederSpeciesEvolution(Species.PIKACHU, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.RAICHU, FINAL_STAGE_EVOLUTION_WAVE) ],
[Species.PICHU, new BreederSpeciesEvolution(Species.PIKACHU, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.ALOLA_RAICHU, FINAL_STAGE_EVOLUTION_WAVE)], [ Species.PICHU, new BreederSpeciesEvolution(Species.PIKACHU, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.ALOLA_RAICHU, FINAL_STAGE_EVOLUTION_WAVE) ],
[Species.JYNX], [ Species.JYNX ],
[Species.TYROGUE, new BreederSpeciesEvolution(Species.HITMONLEE, SECOND_STAGE_EVOLUTION_WAVE)], [ Species.TYROGUE, new BreederSpeciesEvolution(Species.HITMONLEE, SECOND_STAGE_EVOLUTION_WAVE) ],
[Species.TYROGUE, new BreederSpeciesEvolution(Species.HITMONCHAN, SECOND_STAGE_EVOLUTION_WAVE)], [ Species.TYROGUE, new BreederSpeciesEvolution(Species.HITMONCHAN, SECOND_STAGE_EVOLUTION_WAVE) ],
[Species.TYROGUE, new BreederSpeciesEvolution(Species.HITMONTOP, SECOND_STAGE_EVOLUTION_WAVE)], [ Species.TYROGUE, new BreederSpeciesEvolution(Species.HITMONTOP, SECOND_STAGE_EVOLUTION_WAVE) ],
[Species.IGGLYBUFF, new BreederSpeciesEvolution(Species.JIGGLYPUFF, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.WIGGLYTUFF, FINAL_STAGE_EVOLUTION_WAVE)], [ Species.IGGLYBUFF, new BreederSpeciesEvolution(Species.JIGGLYPUFF, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.WIGGLYTUFF, FINAL_STAGE_EVOLUTION_WAVE) ],
[Species.AZURILL, new BreederSpeciesEvolution(Species.MARILL, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.AZUMARILL, FINAL_STAGE_EVOLUTION_WAVE)], [ Species.AZURILL, new BreederSpeciesEvolution(Species.MARILL, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.AZUMARILL, FINAL_STAGE_EVOLUTION_WAVE) ],
[Species.WYNAUT, new BreederSpeciesEvolution(Species.WOBBUFFET, SECOND_STAGE_EVOLUTION_WAVE)], [ Species.WYNAUT, new BreederSpeciesEvolution(Species.WOBBUFFET, SECOND_STAGE_EVOLUTION_WAVE) ],
[Species.CHINGLING, new BreederSpeciesEvolution(Species.CHIMECHO, SECOND_STAGE_EVOLUTION_WAVE)], [ Species.CHINGLING, new BreederSpeciesEvolution(Species.CHIMECHO, SECOND_STAGE_EVOLUTION_WAVE) ],
[Species.BONSLY, new BreederSpeciesEvolution(Species.SUDOWOODO, SECOND_STAGE_EVOLUTION_WAVE)], [ Species.BONSLY, new BreederSpeciesEvolution(Species.SUDOWOODO, SECOND_STAGE_EVOLUTION_WAVE) ],
[Species.MANTYKE, new BreederSpeciesEvolution(Species.MANTINE, SECOND_STAGE_EVOLUTION_WAVE)] [ Species.MANTYKE, new BreederSpeciesEvolution(Species.MANTINE, SECOND_STAGE_EVOLUTION_WAVE) ]
]; ];
/** /**
@ -85,11 +86,11 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter =
.withIntroSpriteConfigs([]) // These are set in onInit() .withIntroSpriteConfigs([]) // These are set in onInit()
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
}, },
{ {
speaker: trainerNameKey, speaker: trainerNameKey,
text: `${namespace}.intro_dialogue`, text: `${namespace}:intro_dialogue`,
}, },
]) ])
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
@ -137,46 +138,46 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter =
encounter.setDialogueToken("pokemon3Name", pokemon3.getNameToRender()); encounter.setDialogueToken("pokemon3Name", pokemon3.getNameToRender());
// Dialogue and egg calcs for Pokemon 1 // Dialogue and egg calcs for Pokemon 1
const [pokemon1CommonEggs, pokemon1RareEggs] = calculateEggRewardsForPokemon(pokemon1); const [ pokemon1CommonEggs, pokemon1RareEggs ] = calculateEggRewardsForPokemon(pokemon1);
let pokemon1Tooltip = getEncounterText(scene, `${namespace}.option.1.tooltip_base`)!; let pokemon1Tooltip = getEncounterText(scene, `${namespace}:option.1.tooltip_base`)!;
if (pokemon1RareEggs > 0) { if (pokemon1RareEggs > 0) {
const eggsText = i18next.t(`${namespace}.numEggs`, { count: pokemon1RareEggs, rarity: i18next.t("egg:greatTier") }); const eggsText = i18next.t(`${namespace}:numEggs`, { count: pokemon1RareEggs, rarity: i18next.t("egg:greatTier") });
pokemon1Tooltip += i18next.t(`${namespace}.eggs_tooltip`, { eggs: eggsText }); pokemon1Tooltip += i18next.t(`${namespace}:eggs_tooltip`, { eggs: eggsText });
encounter.setDialogueToken("pokemon1RareEggs", eggsText); encounter.setDialogueToken("pokemon1RareEggs", eggsText);
} }
if (pokemon1CommonEggs > 0) { if (pokemon1CommonEggs > 0) {
const eggsText = i18next.t(`${namespace}.numEggs`, { count: pokemon1CommonEggs, rarity: i18next.t("egg:defaultTier") }); const eggsText = i18next.t(`${namespace}:numEggs`, { count: pokemon1CommonEggs, rarity: i18next.t("egg:defaultTier") });
pokemon1Tooltip += i18next.t(`${namespace}.eggs_tooltip`, { eggs: eggsText }); pokemon1Tooltip += i18next.t(`${namespace}:eggs_tooltip`, { eggs: eggsText });
encounter.setDialogueToken("pokemon1CommonEggs", eggsText); encounter.setDialogueToken("pokemon1CommonEggs", eggsText);
} }
encounter.options[0].dialogue!.buttonTooltip = pokemon1Tooltip; encounter.options[0].dialogue!.buttonTooltip = pokemon1Tooltip;
// Dialogue and egg calcs for Pokemon 2 // Dialogue and egg calcs for Pokemon 2
const [pokemon2CommonEggs, pokemon2RareEggs] = calculateEggRewardsForPokemon(pokemon2); const [ pokemon2CommonEggs, pokemon2RareEggs ] = calculateEggRewardsForPokemon(pokemon2);
let pokemon2Tooltip = getEncounterText(scene, `${namespace}.option.2.tooltip_base`)!; let pokemon2Tooltip = getEncounterText(scene, `${namespace}:option.2.tooltip_base`)!;
if (pokemon2RareEggs > 0) { if (pokemon2RareEggs > 0) {
const eggsText = i18next.t(`${namespace}.numEggs`, { count: pokemon2RareEggs, rarity: i18next.t("egg:greatTier") }); const eggsText = i18next.t(`${namespace}:numEggs`, { count: pokemon2RareEggs, rarity: i18next.t("egg:greatTier") });
pokemon2Tooltip += i18next.t(`${namespace}.eggs_tooltip`, { eggs: eggsText }); pokemon2Tooltip += i18next.t(`${namespace}:eggs_tooltip`, { eggs: eggsText });
encounter.setDialogueToken("pokemon2RareEggs", eggsText); encounter.setDialogueToken("pokemon2RareEggs", eggsText);
} }
if (pokemon2CommonEggs > 0) { if (pokemon2CommonEggs > 0) {
const eggsText = i18next.t(`${namespace}.numEggs`, { count: pokemon2CommonEggs, rarity: i18next.t("egg:defaultTier") }); const eggsText = i18next.t(`${namespace}:numEggs`, { count: pokemon2CommonEggs, rarity: i18next.t("egg:defaultTier") });
pokemon2Tooltip += i18next.t(`${namespace}.eggs_tooltip`, { eggs: eggsText }); pokemon2Tooltip += i18next.t(`${namespace}:eggs_tooltip`, { eggs: eggsText });
encounter.setDialogueToken("pokemon1CommonEggs", eggsText); encounter.setDialogueToken("pokemon1CommonEggs", eggsText);
} }
encounter.options[1].dialogue!.buttonTooltip = pokemon2Tooltip; encounter.options[1].dialogue!.buttonTooltip = pokemon2Tooltip;
// Dialogue and egg calcs for Pokemon 3 // Dialogue and egg calcs for Pokemon 3
const [pokemon3CommonEggs, pokemon3RareEggs] = calculateEggRewardsForPokemon(pokemon3); const [ pokemon3CommonEggs, pokemon3RareEggs ] = calculateEggRewardsForPokemon(pokemon3);
let pokemon3Tooltip = getEncounterText(scene, `${namespace}.option.3.tooltip_base`)!; let pokemon3Tooltip = getEncounterText(scene, `${namespace}:option.3.tooltip_base`)!;
if (pokemon3RareEggs > 0) { if (pokemon3RareEggs > 0) {
const eggsText = i18next.t(`${namespace}.numEggs`, { count: pokemon3RareEggs, rarity: i18next.t("egg:greatTier") }); const eggsText = i18next.t(`${namespace}:numEggs`, { count: pokemon3RareEggs, rarity: i18next.t("egg:greatTier") });
pokemon3Tooltip += i18next.t(`${namespace}.eggs_tooltip`, { eggs: eggsText }); pokemon3Tooltip += i18next.t(`${namespace}:eggs_tooltip`, { eggs: eggsText });
encounter.setDialogueToken("pokemon3RareEggs", eggsText); encounter.setDialogueToken("pokemon3RareEggs", eggsText);
} }
if (pokemon3CommonEggs > 0) { if (pokemon3CommonEggs > 0) {
const eggsText = i18next.t(`${namespace}.numEggs`, { count: pokemon3CommonEggs, rarity: i18next.t("egg:defaultTier") }); const eggsText = i18next.t(`${namespace}:numEggs`, { count: pokemon3CommonEggs, rarity: i18next.t("egg:defaultTier") });
pokemon3Tooltip += i18next.t(`${namespace}.eggs_tooltip`, { eggs: eggsText }); pokemon3Tooltip += i18next.t(`${namespace}:eggs_tooltip`, { eggs: eggsText });
encounter.setDialogueToken("pokemon3CommonEggs", eggsText); encounter.setDialogueToken("pokemon3CommonEggs", eggsText);
} }
encounter.options[2].dialogue!.buttonTooltip = pokemon3Tooltip; encounter.options[2].dialogue!.buttonTooltip = pokemon3Tooltip;
@ -195,18 +196,18 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter =
return true; return true;
}) })
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withOption( .withOption(
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
selected: [ selected: [
{ {
speaker: trainerNameKey, speaker: trainerNameKey,
text: `${namespace}.option.selected`, text: `${namespace}:option.selected`,
}, },
], ],
}) })
@ -228,17 +229,17 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter =
encounter.dialogue.outro = [ encounter.dialogue.outro = [
{ {
speaker: trainerNameKey, speaker: trainerNameKey,
text: `${namespace}.outro`, text: `${namespace}:outro`,
}, },
]; ];
if (encounter.dialogueTokens.hasOwnProperty("pokemon1CommonEggs")) { if (encounter.dialogueTokens.hasOwnProperty("pokemon1CommonEggs")) {
encounter.dialogue.outro.push({ encounter.dialogue.outro.push({
text: i18next.t(`${namespace}.gained_eggs`, { numEggs: encounter.dialogueTokens["pokemon1CommonEggs"] }), text: i18next.t(`${namespace}:gained_eggs`, { numEggs: encounter.dialogueTokens["pokemon1CommonEggs"] }),
}); });
} }
if (encounter.dialogueTokens.hasOwnProperty("pokemon1RareEggs")) { if (encounter.dialogueTokens.hasOwnProperty("pokemon1RareEggs")) {
encounter.dialogue.outro.push({ encounter.dialogue.outro.push({
text: i18next.t(`${namespace}.gained_eggs`, { numEggs: encounter.dialogueTokens["pokemon1RareEggs"] }), text: i18next.t(`${namespace}:gained_eggs`, { numEggs: encounter.dialogueTokens["pokemon1RareEggs"] }),
}); });
} }
@ -254,11 +255,11 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter =
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
selected: [ selected: [
{ {
speaker: trainerNameKey, speaker: trainerNameKey,
text: `${namespace}.option.selected`, text: `${namespace}:option.selected`,
}, },
], ],
}) })
@ -280,17 +281,17 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter =
encounter.dialogue.outro = [ encounter.dialogue.outro = [
{ {
speaker: trainerNameKey, speaker: trainerNameKey,
text: `${namespace}.outro`, text: `${namespace}:outro`,
}, },
]; ];
if (encounter.dialogueTokens.hasOwnProperty("pokemon2CommonEggs")) { if (encounter.dialogueTokens.hasOwnProperty("pokemon2CommonEggs")) {
encounter.dialogue.outro.push({ encounter.dialogue.outro.push({
text: i18next.t(`${namespace}.gained_eggs`, { numEggs: encounter.dialogueTokens["pokemon2CommonEggs"] }), text: i18next.t(`${namespace}:gained_eggs`, { numEggs: encounter.dialogueTokens["pokemon2CommonEggs"] }),
}); });
} }
if (encounter.dialogueTokens.hasOwnProperty("pokemon2RareEggs")) { if (encounter.dialogueTokens.hasOwnProperty("pokemon2RareEggs")) {
encounter.dialogue.outro.push({ encounter.dialogue.outro.push({
text: i18next.t(`${namespace}.gained_eggs`, { numEggs: encounter.dialogueTokens["pokemon2RareEggs"] }), text: i18next.t(`${namespace}:gained_eggs`, { numEggs: encounter.dialogueTokens["pokemon2RareEggs"] }),
}); });
} }
@ -306,11 +307,11 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter =
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.3.label`, buttonLabel: `${namespace}:option.3.label`,
selected: [ selected: [
{ {
speaker: trainerNameKey, speaker: trainerNameKey,
text: `${namespace}.option.selected`, text: `${namespace}:option.selected`,
}, },
], ],
}) })
@ -332,17 +333,17 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter =
encounter.dialogue.outro = [ encounter.dialogue.outro = [
{ {
speaker: trainerNameKey, speaker: trainerNameKey,
text: `${namespace}.outro`, text: `${namespace}:outro`,
}, },
]; ];
if (encounter.dialogueTokens.hasOwnProperty("pokemon3CommonEggs")) { if (encounter.dialogueTokens.hasOwnProperty("pokemon3CommonEggs")) {
encounter.dialogue.outro.push({ encounter.dialogue.outro.push({
text: i18next.t(`${namespace}.gained_eggs`, { numEggs: encounter.dialogueTokens["pokemon3CommonEggs"] }), text: i18next.t(`${namespace}:gained_eggs`, { numEggs: encounter.dialogueTokens["pokemon3CommonEggs"] }),
}); });
} }
if (encounter.dialogueTokens.hasOwnProperty("pokemon3RareEggs")) { if (encounter.dialogueTokens.hasOwnProperty("pokemon3RareEggs")) {
encounter.dialogue.outro.push({ encounter.dialogue.outro.push({
text: i18next.t(`${namespace}.gained_eggs`, { numEggs: encounter.dialogueTokens["pokemon3RareEggs"] }), text: i18next.t(`${namespace}:gained_eggs`, { numEggs: encounter.dialogueTokens["pokemon3RareEggs"] }),
}); });
} }
@ -357,7 +358,7 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter =
.withOutroDialogue([ .withOutroDialogue([
{ {
speaker: trainerNameKey, speaker: trainerNameKey,
text: `${namespace}.outro`, text: `${namespace}:outro`,
}, },
]) ])
.build(); .build();
@ -374,17 +375,17 @@ function getPartyConfig(scene: BattleScene): EnemyPartyConfig {
trainerType: TrainerType.EXPERT_POKEMON_BREEDER, trainerType: TrainerType.EXPERT_POKEMON_BREEDER,
pokemonConfigs: [ pokemonConfigs: [
{ {
nickname: i18next.t(`${namespace}.cleffa_1_nickname`, { speciesName: getPokemonSpecies(cleffaSpecies).getName() }), nickname: i18next.t(`${namespace}:cleffa_1_nickname`, { speciesName: getPokemonSpecies(cleffaSpecies).getName() }),
species: getPokemonSpecies(cleffaSpecies), species: getPokemonSpecies(cleffaSpecies),
isBoss: false, isBoss: false,
abilityIndex: 1, // Magic Guard abilityIndex: 1, // Magic Guard
shiny: false, shiny: false,
nature: Nature.ADAMANT, nature: Nature.ADAMANT,
moveSet: [Moves.METEOR_MASH, Moves.FIRE_PUNCH, Moves.ICE_PUNCH, Moves.THUNDER_PUNCH], moveSet: [ Moves.METEOR_MASH, Moves.FIRE_PUNCH, Moves.ICE_PUNCH, Moves.THUNDER_PUNCH ],
ivs: [31, 31, 31, 31, 31, 31], ivs: [ 31, 31, 31, 31, 31, 31 ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.TERA_SHARD, [Type.STEEL]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.TERA_SHARD, [ Type.STEEL ]) as PokemonHeldItemModifierType,
} }
] ]
} }
@ -394,26 +395,26 @@ function getPartyConfig(scene: BattleScene): EnemyPartyConfig {
if (scene.arena.biomeType === Biome.SPACE) { if (scene.arena.biomeType === Biome.SPACE) {
// All 3 members always Cleffa line, but different configs // All 3 members always Cleffa line, but different configs
baseConfig.pokemonConfigs!.push({ baseConfig.pokemonConfigs!.push({
nickname: i18next.t(`${namespace}.cleffa_2_nickname`, { speciesName: getPokemonSpecies(cleffaSpecies).getName() }), nickname: i18next.t(`${namespace}:cleffa_2_nickname`, { speciesName: getPokemonSpecies(cleffaSpecies).getName() }),
species: getPokemonSpecies(cleffaSpecies), species: getPokemonSpecies(cleffaSpecies),
isBoss: false, isBoss: false,
abilityIndex: 1, // Magic Guard abilityIndex: 1, // Magic Guard
shiny: true, shiny: true,
variant: 1, variant: 1,
nature: Nature.MODEST, nature: Nature.MODEST,
moveSet: [Moves.MOONBLAST, Moves.MYSTICAL_FIRE, Moves.ICE_BEAM, Moves.THUNDERBOLT], moveSet: [ Moves.MOONBLAST, Moves.MYSTICAL_FIRE, Moves.ICE_BEAM, Moves.THUNDERBOLT ],
ivs: [31, 31, 31, 31, 31, 31] ivs: [ 31, 31, 31, 31, 31, 31 ]
}, },
{ {
nickname: i18next.t(`${namespace}.cleffa_3_nickname`, { speciesName: getPokemonSpecies(cleffaSpecies).getName() }), nickname: i18next.t(`${namespace}:cleffa_3_nickname`, { speciesName: getPokemonSpecies(cleffaSpecies).getName() }),
species: getPokemonSpecies(cleffaSpecies), species: getPokemonSpecies(cleffaSpecies),
isBoss: false, isBoss: false,
abilityIndex: 2, // Friend Guard / Unaware abilityIndex: 2, // Friend Guard / Unaware
shiny: true, shiny: true,
variant: 2, variant: 2,
nature: Nature.BOLD, nature: Nature.BOLD,
moveSet: [Moves.TRI_ATTACK, Moves.STORED_POWER, Moves.TAKE_HEART, Moves.MOONLIGHT], moveSet: [ Moves.TRI_ATTACK, Moves.STORED_POWER, Moves.TAKE_HEART, Moves.MOONLIGHT ],
ivs: [31, 31, 31, 31, 31, 31] ivs: [ 31, 31, 31, 31, 31, 31 ]
}); });
} else { } else {
// Second member from pool 1 // Second member from pool 1
@ -424,12 +425,12 @@ function getPartyConfig(scene: BattleScene): EnemyPartyConfig {
baseConfig.pokemonConfigs!.push({ baseConfig.pokemonConfigs!.push({
species: getPokemonSpecies(pool1Species), species: getPokemonSpecies(pool1Species),
isBoss: false, isBoss: false,
ivs: [31, 31, 31, 31, 31, 31] ivs: [ 31, 31, 31, 31, 31, 31 ]
}, },
{ {
species: getPokemonSpecies(pool2Species), species: getPokemonSpecies(pool2Species),
isBoss: false, isBoss: false,
ivs: [31, 31, 31, 31, 31, 31] ivs: [ 31, 31, 31, 31, 31, 31 ]
}); });
} }
@ -454,8 +455,8 @@ function calculateEggRewardsForPokemon(pokemon: PlayerPokemon): [number, number]
const rootSpecies = pokemon.species.getRootSpeciesId(); const rootSpecies = pokemon.species.getRootSpeciesId();
let pointsFromStarterTier = 0; let pointsFromStarterTier = 0;
// 2 points for every 1 below 7 that the pokemon's starter tier is (max 12, min 0) // 2 points for every 1 below 7 that the pokemon's starter tier is (max 12, min 0)
if (speciesStarters.hasOwnProperty(rootSpecies)) { if (speciesStarterCosts.hasOwnProperty(rootSpecies)) {
const starterTier = speciesStarters[rootSpecies]; const starterTier = speciesStarterCosts[rootSpecies];
pointsFromStarterTier = Math.min(Math.max(Math.floor(7 - starterTier) * 2, 0), 12); pointsFromStarterTier = Math.min(Math.max(Math.floor(7 - starterTier) * 2, 0), 12);
} }
@ -467,11 +468,11 @@ function calculateEggRewardsForPokemon(pokemon: PlayerPokemon): [number, number]
// 1 Common egg for every point leftover // 1 Common egg for every point leftover
const numCommons = totalPoints % 6; const numCommons = totalPoints % 6;
return [numCommons, numRares]; return [ numCommons, numRares ];
} }
function getEggOptions(scene: BattleScene, commonEggs: number, rareEggs: number) { function getEggOptions(scene: BattleScene, commonEggs: number, rareEggs: number) {
const eggDescription = i18next.t(`${namespace}.title`) + ":\n" + i18next.t(trainerNameKey); const eggDescription = i18next.t(`${namespace}:title`) + ":\n" + i18next.t(trainerNameKey);
const eggOptions: IEggOptions[] = []; const eggOptions: IEggOptions[] = [];
if (commonEggs > 0) { if (commonEggs > 0) {
@ -540,7 +541,7 @@ function onGameOver(scene: BattleScene) {
encounter.dialogue.outro = [ encounter.dialogue.outro = [
{ {
speaker: trainerNameKey, speaker: trainerNameKey,
text: `${namespace}.outro_failed`, text: `${namespace}:outro_failed`,
}, },
]; ];
@ -558,6 +559,10 @@ function onGameOver(scene: BattleScene) {
// Revert BGM // Revert BGM
scene.playBgm(scene.arena.bgm); scene.playBgm(scene.arena.bgm);
// Clear any leftover battle phases
scene.clearPhaseQueue();
scene.clearPhaseQueueSplice();
// Return enemy Pokemon // Return enemy Pokemon
const pokemon = scene.getEnemyPokemon(); const pokemon = scene.getEnemyPokemon();
if (pokemon) { if (pokemon) {

View File

@ -5,7 +5,8 @@ import BattleScene from "#app/battle-scene";
import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter"; import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
import { MoneyRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements"; import { MoneyRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
import { catchPokemon, getRandomSpeciesByStarterTier, getSpriteKeysFromPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { catchPokemon, getRandomSpeciesByStarterTier, getSpriteKeysFromPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
import { getPokemonSpecies, speciesStarters } from "#app/data/pokemon-species"; import { getPokemonSpecies } from "#app/data/pokemon-species";
import { speciesStarterCosts } from "#app/data/balance/starters";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import { PokeballType } from "#app/data/pokeball"; import { PokeballType } from "#app/data/pokeball";
import { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon"; import { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon";
@ -18,7 +19,7 @@ import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
/** the i18n namespace for this encounter */ /** the i18n namespace for this encounter */
const namespace = "mysteryEncounter:pokemonSalesman"; const namespace = "mysteryEncounters/thePokemonSalesman";
const MAX_POKEMON_PRICE_MULTIPLIER = 4; const MAX_POKEMON_PRICE_MULTIPLIER = 4;
@ -45,25 +46,25 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter =
]) ])
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
}, },
{ {
text: `${namespace}.intro_dialogue`, text: `${namespace}:intro_dialogue`,
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
}, },
]) ])
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
let species = getPokemonSpecies(getRandomSpeciesByStarterTier([0, 5], undefined, undefined, false, false, false)); let species = getPokemonSpecies(getRandomSpeciesByStarterTier([ 0, 5 ], undefined, undefined, false, false, false));
let tries = 0; let tries = 0;
// Reroll any species that don't have HAs // Reroll any species that don't have HAs
while ((isNullOrUndefined(species.abilityHidden) || species.abilityHidden === Abilities.NONE) && tries < 5) { while ((isNullOrUndefined(species.abilityHidden) || species.abilityHidden === Abilities.NONE) && tries < 5) {
species = getPokemonSpecies(getRandomSpeciesByStarterTier([0, 5], undefined, undefined, false, false, false)); species = getPokemonSpecies(getRandomSpeciesByStarterTier([ 0, 5 ], undefined, undefined, false, false, false));
tries++; tries++;
} }
@ -88,15 +89,15 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter =
isPokemon: true isPokemon: true
}); });
const starterTier = speciesStarters[species.speciesId]; const starterTier = speciesStarterCosts[species.speciesId];
// Prices decrease by starter tier less than 5, but only reduces cost by half at max // Prices decrease by starter tier less than 5, but only reduces cost by half at max
let priceMultiplier = MAX_POKEMON_PRICE_MULTIPLIER * (Math.max(starterTier, 2.5) / 5); let priceMultiplier = MAX_POKEMON_PRICE_MULTIPLIER * (Math.max(starterTier, 2.5) / 5);
if (pokemon.shiny) { if (pokemon.shiny) {
// Always max price for shiny (flip HA back to normal), and add special messaging // Always max price for shiny (flip HA back to normal), and add special messaging
priceMultiplier = MAX_POKEMON_PRICE_MULTIPLIER; priceMultiplier = MAX_POKEMON_PRICE_MULTIPLIER;
pokemon.abilityIndex = 0; pokemon.abilityIndex = 0;
encounter.dialogue.encounterOptionsDialogue!.description = `${namespace}.description_shiny`; encounter.dialogue.encounterOptionsDialogue!.description = `${namespace}:description_shiny`;
encounter.options[0].dialogue!.buttonTooltip = `${namespace}.option.1.tooltip_shiny`; encounter.options[0].dialogue!.buttonTooltip = `${namespace}:option.1.tooltip_shiny`;
} }
const price = scene.getWaveMoneyAmount(priceMultiplier); const price = scene.getWaveMoneyAmount(priceMultiplier);
encounter.setDialogueToken("purchasePokemon", pokemon.getNameToRender()); encounter.setDialogueToken("purchasePokemon", pokemon.getNameToRender());
@ -116,11 +117,11 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter =
.withHasDexProgress(true) .withHasDexProgress(true)
.withSceneMoneyRequirement(0, MAX_POKEMON_PRICE_MULTIPLIER) // Wave scaling money multiplier of 2 .withSceneMoneyRequirement(0, MAX_POKEMON_PRICE_MULTIPLIER) // Wave scaling money multiplier of 2
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.1.selected_message`, text: `${namespace}:option.1.selected_message`,
} }
], ],
}) })
@ -133,7 +134,7 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter =
updatePlayerMoney(scene, -price, true, false); updatePlayerMoney(scene, -price, true, false);
// Show dialogue // Show dialogue
await showEncounterDialogue(scene, `${namespace}.option.1.selected_dialogue`, `${namespace}.speaker`); await showEncounterDialogue(scene, `${namespace}:option.1.selected_dialogue`, `${namespace}:speaker`);
await transitionMysteryEncounterIntroVisuals(scene); await transitionMysteryEncounterIntroVisuals(scene);
// "Catch" purchased pokemon // "Catch" purchased pokemon
@ -147,11 +148,11 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter =
) )
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.2.selected`, text: `${namespace}:option.2.selected`,
}, },
], ],
}, },

View File

@ -20,7 +20,7 @@ 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/game-mode";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */
const namespace = "mysteryEncounter:theStrongStuff"; const namespace = "mysteryEncounters/theStrongStuff";
// Halved for HP stat // Halved for HP stat
const HIGH_BST_REDUCTION_VALUE = 15; const HIGH_BST_REDUCTION_VALUE = 15;
@ -64,7 +64,7 @@ export const TheStrongStuffEncounter: MysteryEncounter =
]) // Set in onInit() ]) // Set in onInit()
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
}, },
]) ])
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
@ -81,52 +81,52 @@ export const TheStrongStuffEncounter: MysteryEncounter =
bossSegments: 5, bossSegments: 5,
mysteryEncounterPokemonData: new MysteryEncounterPokemonData({ spriteScale: 1.25 }), mysteryEncounterPokemonData: new MysteryEncounterPokemonData({ spriteScale: 1.25 }),
nature: Nature.BOLD, nature: Nature.BOLD,
moveSet: [Moves.INFESTATION, Moves.SALT_CURE, Moves.GASTRO_ACID, Moves.HEAL_ORDER], moveSet: [ Moves.INFESTATION, Moves.SALT_CURE, Moves.GASTRO_ACID, Moves.HEAL_ORDER ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.SITRUS]) as PokemonHeldItemModifierType modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.SITRUS ]) as PokemonHeldItemModifierType
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.ENIGMA]) as PokemonHeldItemModifierType modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.ENIGMA ]) as PokemonHeldItemModifierType
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.APICOT]) as PokemonHeldItemModifierType modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.APICOT ]) as PokemonHeldItemModifierType
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.GANLON]) as PokemonHeldItemModifierType modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.GANLON ]) as PokemonHeldItemModifierType
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.LUM]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.LUM ]) as PokemonHeldItemModifierType,
stackCount: 2 stackCount: 2
} }
], ],
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON], tags: [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON ],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => { mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
queueEncounterMessage(pokemon.scene, `${namespace}.option.2.stat_boost`); queueEncounterMessage(pokemon.scene, `${namespace}:option.2.stat_boost`);
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [Stat.DEF, Stat.SPDEF], 2)); pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ Stat.DEF, Stat.SPDEF ], 2));
} }
} }
], ],
}; };
encounter.enemyPartyConfigs = [config]; encounter.enemyPartyConfigs = [ config ];
loadCustomMovesForEncounter(scene, [Moves.GASTRO_ACID, Moves.STEALTH_ROCK]); loadCustomMovesForEncounter(scene, [ Moves.GASTRO_ACID, Moves.STEALTH_ROCK ]);
encounter.setDialogueToken("shuckleName", getPokemonSpecies(Species.SHUCKLE).getName()); encounter.setDialogueToken("shuckleName", getPokemonSpecies(Species.SHUCKLE).getName());
return true; return true;
}) })
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.1.selected` text: `${namespace}:option.1.selected`
} }
] ]
}, },
@ -159,11 +159,11 @@ export const TheStrongStuffEncounter: MysteryEncounter =
encounter.setDialogueToken("reductionValue", HIGH_BST_REDUCTION_VALUE.toString()); encounter.setDialogueToken("reductionValue", HIGH_BST_REDUCTION_VALUE.toString());
encounter.setDialogueToken("increaseValue", BST_INCREASE_VALUE.toString()); encounter.setDialogueToken("increaseValue", BST_INCREASE_VALUE.toString());
await showEncounterText(scene, `${namespace}.option.1.selected_2`, null, undefined, true); await showEncounterText(scene, `${namespace}:option.1.selected_2`, null, undefined, true);
encounter.dialogue.outro = [ encounter.dialogue.outro = [
{ {
text: `${namespace}.outro`, text: `${namespace}:outro`,
} }
]; ];
setEncounterRewards(scene, { fillRemaining: true }); setEncounterRewards(scene, { fillRemaining: true });
@ -173,28 +173,28 @@ export const TheStrongStuffEncounter: MysteryEncounter =
) )
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.2.selected`, text: `${namespace}:option.2.selected`,
}, },
], ],
}, },
async (scene: BattleScene) => { async (scene: BattleScene) => {
// Pick battle // Pick battle
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.SOUL_DEW], fillRemaining: true }); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.SOUL_DEW ], fillRemaining: true });
encounter.startOfBattleEffects.push( encounter.startOfBattleEffects.push(
{ {
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.PLAYER], targets: [ BattlerIndex.PLAYER ],
move: new PokemonMove(Moves.GASTRO_ACID), move: new PokemonMove(Moves.GASTRO_ACID),
ignorePp: true ignorePp: true
}, },
{ {
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.PLAYER], targets: [ BattlerIndex.PLAYER ],
move: new PokemonMove(Moves.STEALTH_ROCK), move: new PokemonMove(Moves.STEALTH_ROCK),
ignorePp: true ignorePp: true
}); });

View File

@ -25,7 +25,7 @@ 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/game-mode";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */
const namespace = "mysteryEncounter:theWinstrateChallenge"; const namespace = "mysteryEncounters/theWinstrateChallenge";
/** /**
* The Winstrate Challenge encounter. * The Winstrate Challenge encounter.
@ -74,11 +74,11 @@ export const TheWinstrateChallengeEncounter: MysteryEncounter =
]) ])
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
}, },
{ {
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
text: `${namespace}.intro_dialogue`, text: `${namespace}:intro_dialogue`,
}, },
]) ])
.withAutoHideIntroVisuals(false) .withAutoHideIntroVisuals(false)
@ -94,17 +94,17 @@ export const TheWinstrateChallengeEncounter: MysteryEncounter =
return true; return true;
}) })
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [ selected: [
{ {
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
text: `${namespace}.option.1.selected`, text: `${namespace}:option.1.selected`,
}, },
], ],
}, },
@ -119,19 +119,19 @@ export const TheWinstrateChallengeEncounter: MysteryEncounter =
) )
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
selected: [ selected: [
{ {
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
text: `${namespace}.option.2.selected`, text: `${namespace}:option.2.selected`,
}, },
], ],
}, },
async (scene: BattleScene) => { async (scene: BattleScene) => {
// Refuse the challenge, they full heal the party and give the player a Rarer Candy // Refuse the challenge, they full heal the party and give the player a Rarer Candy
scene.unshiftPhase(new PartyHealPhase(scene, true)); scene.unshiftPhase(new PartyHealPhase(scene, true));
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.RARER_CANDY], fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.RARER_CANDY ], fillRemaining: false });
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);
} }
) )
@ -142,7 +142,7 @@ async function spawnNextTrainerOrEndEncounter(scene: BattleScene) {
const nextConfig = encounter.enemyPartyConfigs.pop(); const nextConfig = encounter.enemyPartyConfigs.pop();
if (!nextConfig) { if (!nextConfig) {
await transitionMysteryEncounterIntroVisuals(scene, false, false); await transitionMysteryEncounterIntroVisuals(scene, false, false);
await showEncounterDialogue(scene, `${namespace}.victory`, `${namespace}.speaker`); await showEncounterDialogue(scene, `${namespace}:victory`, `${namespace}:speaker`);
// Give 10x Voucher // Give 10x Voucher
const newModifier = modifierTypes.VOUCHER_PREMIUM().newModifier(); const newModifier = modifierTypes.VOUCHER_PREMIUM().newModifier();
@ -150,11 +150,11 @@ async function spawnNextTrainerOrEndEncounter(scene: BattleScene) {
scene.playSound("item_fanfare"); scene.playSound("item_fanfare");
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: newModifier?.type.name })); await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: newModifier?.type.name }));
await showEncounterDialogue(scene, `${namespace}.victory_2`, `${namespace}.speaker`); await showEncounterDialogue(scene, `${namespace}:victory_2`, `${namespace}:speaker`);
scene.ui.clearText(); // Clears "Winstrate" title from screen as rewards get animated in scene.ui.clearText(); // Clears "Winstrate" title from screen as rewards get animated in
const machoBrace = generateModifierTypeOption(scene, modifierTypes.MYSTERY_ENCOUNTER_MACHO_BRACE)!; const machoBrace = generateModifierTypeOption(scene, modifierTypes.MYSTERY_ENCOUNTER_MACHO_BRACE)!;
machoBrace.type.tier = ModifierTier.MASTER; machoBrace.type.tier = ModifierTier.MASTER;
setEncounterRewards(scene, { guaranteedModifierTypeOptions: [machoBrace], fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeOptions: [ machoBrace ], fillRemaining: false });
encounter.doContinueEncounter = undefined; encounter.doContinueEncounter = undefined;
leaveEncounterWithoutBattle(scene, false, MysteryEncounterMode.NO_BATTLE); leaveEncounterWithoutBattle(scene, false, MysteryEncounterMode.NO_BATTLE);
} else { } else {
@ -232,7 +232,7 @@ function getVictorTrainerConfig(scene: BattleScene): EnemyPartyConfig {
isBoss: false, isBoss: false,
abilityIndex: 0, // Guts abilityIndex: 0, // Guts
nature: Nature.ADAMANT, nature: Nature.ADAMANT,
moveSet: [Moves.FACADE, Moves.BRAVE_BIRD, Moves.PROTECT, Moves.QUICK_ATTACK], moveSet: [ Moves.FACADE, Moves.BRAVE_BIRD, Moves.PROTECT, Moves.QUICK_ATTACK ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.FLAME_ORB) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.FLAME_ORB) as PokemonHeldItemModifierType,
@ -250,7 +250,7 @@ function getVictorTrainerConfig(scene: BattleScene): EnemyPartyConfig {
isBoss: false, isBoss: false,
abilityIndex: 1, // Guts abilityIndex: 1, // Guts
nature: Nature.ADAMANT, nature: Nature.ADAMANT,
moveSet: [Moves.FACADE, Moves.OBSTRUCT, Moves.NIGHT_SLASH, Moves.FIRE_PUNCH], moveSet: [ Moves.FACADE, Moves.OBSTRUCT, Moves.NIGHT_SLASH, Moves.FIRE_PUNCH ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.FLAME_ORB) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.FLAME_ORB) as PokemonHeldItemModifierType,
@ -276,7 +276,7 @@ function getVictoriaTrainerConfig(scene: BattleScene): EnemyPartyConfig {
isBoss: false, isBoss: false,
abilityIndex: 0, // Natural Cure abilityIndex: 0, // Natural Cure
nature: Nature.CALM, nature: Nature.CALM,
moveSet: [Moves.SYNTHESIS, Moves.SLUDGE_BOMB, Moves.GIGA_DRAIN, Moves.SLEEP_POWDER], moveSet: [ Moves.SYNTHESIS, Moves.SLUDGE_BOMB, Moves.GIGA_DRAIN, Moves.SLEEP_POWDER ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.SOUL_DEW) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.SOUL_DEW) as PokemonHeldItemModifierType,
@ -294,15 +294,15 @@ function getVictoriaTrainerConfig(scene: BattleScene): EnemyPartyConfig {
isBoss: false, isBoss: false,
formIndex: 1, formIndex: 1,
nature: Nature.TIMID, nature: Nature.TIMID,
moveSet: [Moves.PSYSHOCK, Moves.MOONBLAST, Moves.SHADOW_BALL, Moves.WILL_O_WISP], moveSet: [ Moves.PSYSHOCK, Moves.MOONBLAST, Moves.SHADOW_BALL, Moves.WILL_O_WISP ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [Type.PSYCHIC]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [ Type.PSYCHIC ]) as PokemonHeldItemModifierType,
stackCount: 1, stackCount: 1,
isTransferable: false isTransferable: false
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [Type.FAIRY]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [ Type.FAIRY ]) as PokemonHeldItemModifierType,
stackCount: 1, stackCount: 1,
isTransferable: false isTransferable: false
} }
@ -321,15 +321,15 @@ function getViviTrainerConfig(scene: BattleScene): EnemyPartyConfig {
isBoss: false, isBoss: false,
abilityIndex: 3, // Lightning Rod abilityIndex: 3, // Lightning Rod
nature: Nature.ADAMANT, nature: Nature.ADAMANT,
moveSet: [Moves.WATERFALL, Moves.MEGAHORN, Moves.KNOCK_OFF, Moves.REST], moveSet: [ Moves.WATERFALL, Moves.MEGAHORN, Moves.KNOCK_OFF, Moves.REST ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.LUM]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.LUM ]) as PokemonHeldItemModifierType,
stackCount: 2, stackCount: 2,
isTransferable: false isTransferable: false
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER, [Stat.HP]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER, [ Stat.HP ]) as PokemonHeldItemModifierType,
stackCount: 4, stackCount: 4,
isTransferable: false isTransferable: false
} }
@ -340,10 +340,10 @@ function getViviTrainerConfig(scene: BattleScene): EnemyPartyConfig {
isBoss: false, isBoss: false,
abilityIndex: 1, // Poison Heal abilityIndex: 1, // Poison Heal
nature: Nature.JOLLY, nature: Nature.JOLLY,
moveSet: [Moves.SPORE, Moves.SWORDS_DANCE, Moves.SEED_BOMB, Moves.DRAIN_PUNCH], moveSet: [ Moves.SPORE, Moves.SWORDS_DANCE, Moves.SEED_BOMB, Moves.DRAIN_PUNCH ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER, [Stat.HP]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER, [ Stat.HP ]) as PokemonHeldItemModifierType,
stackCount: 4, stackCount: 4,
isTransferable: false isTransferable: false
}, },
@ -358,7 +358,7 @@ function getViviTrainerConfig(scene: BattleScene): EnemyPartyConfig {
isBoss: false, isBoss: false,
formIndex: 1, formIndex: 1,
nature: Nature.CALM, nature: Nature.CALM,
moveSet: [Moves.EARTH_POWER, Moves.FIRE_BLAST, Moves.YAWN, Moves.PROTECT], moveSet: [ Moves.EARTH_POWER, Moves.FIRE_BLAST, Moves.YAWN, Moves.PROTECT ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.QUICK_CLAW) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.QUICK_CLAW) as PokemonHeldItemModifierType,
@ -380,7 +380,7 @@ function getVickyTrainerConfig(scene: BattleScene): EnemyPartyConfig {
isBoss: false, isBoss: false,
formIndex: 1, formIndex: 1,
nature: Nature.IMPISH, nature: Nature.IMPISH,
moveSet: [Moves.AXE_KICK, Moves.ICE_PUNCH, Moves.ZEN_HEADBUTT, Moves.BULLET_PUNCH], moveSet: [ Moves.AXE_KICK, Moves.ICE_PUNCH, Moves.ZEN_HEADBUTT, Moves.BULLET_PUNCH ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType,
@ -401,10 +401,10 @@ function getVitoTrainerConfig(scene: BattleScene): EnemyPartyConfig {
isBoss: false, isBoss: false,
abilityIndex: 0, // Soundproof abilityIndex: 0, // Soundproof
nature: Nature.MODEST, nature: Nature.MODEST,
moveSet: [Moves.THUNDERBOLT, Moves.GIGA_DRAIN, Moves.FOUL_PLAY, Moves.THUNDER_WAVE], moveSet: [ Moves.THUNDERBOLT, Moves.GIGA_DRAIN, Moves.FOUL_PLAY, Moves.THUNDER_WAVE ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER, [Stat.SPD]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER, [ Stat.SPD ]) as PokemonHeldItemModifierType,
stackCount: 2, stackCount: 2,
isTransferable: false isTransferable: false
} }
@ -415,50 +415,50 @@ function getVitoTrainerConfig(scene: BattleScene): EnemyPartyConfig {
isBoss: false, isBoss: false,
abilityIndex: 2, // Gluttony abilityIndex: 2, // Gluttony
nature: Nature.QUIET, nature: Nature.QUIET,
moveSet: [Moves.SLUDGE_BOMB, Moves.GIGA_DRAIN, Moves.ICE_BEAM, Moves.EARTHQUAKE], moveSet: [ Moves.SLUDGE_BOMB, Moves.GIGA_DRAIN, Moves.ICE_BEAM, Moves.EARTHQUAKE ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.SITRUS]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.SITRUS ]) as PokemonHeldItemModifierType,
stackCount: 2, stackCount: 2,
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.APICOT]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.APICOT ]) as PokemonHeldItemModifierType,
stackCount: 2, stackCount: 2,
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.GANLON]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.GANLON ]) as PokemonHeldItemModifierType,
stackCount: 2, stackCount: 2,
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.STARF]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.STARF ]) as PokemonHeldItemModifierType,
stackCount: 2, stackCount: 2,
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.SALAC]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.SALAC ]) as PokemonHeldItemModifierType,
stackCount: 2, stackCount: 2,
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.LUM]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.LUM ]) as PokemonHeldItemModifierType,
stackCount: 2, stackCount: 2,
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.LANSAT]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.LANSAT ]) as PokemonHeldItemModifierType,
stackCount: 2, stackCount: 2,
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.LIECHI]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.LIECHI ]) as PokemonHeldItemModifierType,
stackCount: 2, stackCount: 2,
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.PETAYA]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.PETAYA ]) as PokemonHeldItemModifierType,
stackCount: 2, stackCount: 2,
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.ENIGMA]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.ENIGMA ]) as PokemonHeldItemModifierType,
stackCount: 2, stackCount: 2,
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.LEPPA]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.LEPPA ]) as PokemonHeldItemModifierType,
stackCount: 2, stackCount: 2,
} }
] ]
@ -468,7 +468,7 @@ function getVitoTrainerConfig(scene: BattleScene): EnemyPartyConfig {
isBoss: false, isBoss: false,
abilityIndex: 2, // Tangled Feet abilityIndex: 2, // Tangled Feet
nature: Nature.JOLLY, nature: Nature.JOLLY,
moveSet: [Moves.DRILL_PECK, Moves.QUICK_ATTACK, Moves.THRASH, Moves.KNOCK_OFF], moveSet: [ Moves.DRILL_PECK, Moves.QUICK_ATTACK, Moves.THRASH, Moves.KNOCK_OFF ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.KINGS_ROCK) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.KINGS_ROCK) as PokemonHeldItemModifierType,
@ -482,7 +482,7 @@ function getVitoTrainerConfig(scene: BattleScene): EnemyPartyConfig {
isBoss: false, isBoss: false,
formIndex: 1, formIndex: 1,
nature: Nature.BOLD, nature: Nature.BOLD,
moveSet: [Moves.PSYCHIC, Moves.SHADOW_BALL, Moves.FOCUS_BLAST, Moves.THUNDERBOLT], moveSet: [ Moves.PSYCHIC, Moves.SHADOW_BALL, Moves.FOCUS_BLAST, Moves.THUNDERBOLT ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.WIDE_LENS) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.WIDE_LENS) as PokemonHeldItemModifierType,
@ -496,7 +496,7 @@ function getVitoTrainerConfig(scene: BattleScene): EnemyPartyConfig {
isBoss: false, isBoss: false,
abilityIndex: 0, // Sheer Force abilityIndex: 0, // Sheer Force
nature: Nature.IMPISH, nature: Nature.IMPISH,
moveSet: [Moves.EARTHQUAKE, Moves.U_TURN, Moves.FLARE_BLITZ, Moves.ROCK_SLIDE], moveSet: [ Moves.EARTHQUAKE, Moves.U_TURN, Moves.FLARE_BLITZ, Moves.ROCK_SLIDE ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.QUICK_CLAW) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.QUICK_CLAW) as PokemonHeldItemModifierType,

View File

@ -1,7 +1,7 @@
import { Ability, allAbilities } from "#app/data/ability"; import { Ability, allAbilities } from "#app/data/ability";
import { EnemyPartyConfig, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, selectPokemonForOption, setEncounterRewards, } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import { EnemyPartyConfig, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, selectPokemonForOption, setEncounterRewards, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { getNatureName, Nature } from "#app/data/nature"; import { getNatureName, Nature } from "#app/data/nature";
import { speciesStarters } from "#app/data/pokemon-species"; import { speciesStarterCosts } from "#app/data/balance/starters";
import Pokemon, { PlayerPokemon } from "#app/field/pokemon"; import Pokemon, { PlayerPokemon } from "#app/field/pokemon";
import { PokemonHeldItemModifier } from "#app/modifier/modifier"; import { PokemonHeldItemModifier } from "#app/modifier/modifier";
import { AbilityAttr } from "#app/system/game-data"; import { AbilityAttr } from "#app/system/game-data";
@ -23,7 +23,7 @@ import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
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 */
const namespace = "mysteryEncounter:trainingSession"; const namespace = "mysteryEncounters/trainingSession";
/** /**
* Training Session encounter. * Training Session encounter.
@ -49,22 +49,22 @@ export const TrainingSessionEncounter: MysteryEncounter =
]) ])
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
} }
]) ])
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withOption( .withOption(
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withHasDexProgress(true) .withHasDexProgress(true)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.selected`, text: `${namespace}:option.selected`,
}, },
], ],
}) })
@ -78,7 +78,7 @@ export const TrainingSessionEncounter: MysteryEncounter =
// Only Pokemon that are not KOed/legal can be trained // Only Pokemon that are not KOed/legal can be trained
const selectableFilter = (pokemon: Pokemon) => { const selectableFilter = (pokemon: Pokemon) => {
return isPokemonValidForEncounterOptionSelection(pokemon, scene, `${namespace}.invalid_selection`); return isPokemonValidForEncounterOptionSelection(pokemon, scene, `${namespace}:invalid_selection`);
}; };
return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter); return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter);
@ -156,7 +156,7 @@ export const TrainingSessionEncounter: MysteryEncounter =
scene.addModifier(mod, true, false, false, true); scene.addModifier(mod, true, false, false, true);
} }
scene.updateModifiers(true); scene.updateModifiers(true);
queueEncounterMessage(scene, `${namespace}.option.1.finished`); queueEncounterMessage(scene, `${namespace}:option.1.finished`);
}; };
setEncounterRewards(scene, { fillRemaining: true }, undefined, onBeforeRewardsPhase); setEncounterRewards(scene, { fillRemaining: true }, undefined, onBeforeRewardsPhase);
@ -170,12 +170,12 @@ export const TrainingSessionEncounter: MysteryEncounter =
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withHasDexProgress(true) .withHasDexProgress(true)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
secondOptionPrompt: `${namespace}.option.2.select_prompt`, secondOptionPrompt: `${namespace}:option.2.select_prompt`,
selected: [ selected: [
{ {
text: `${namespace}.option.selected`, text: `${namespace}:option.selected`,
}, },
], ],
}) })
@ -204,7 +204,7 @@ export const TrainingSessionEncounter: MysteryEncounter =
// Only Pokemon that are not KOed/legal can be trained // Only Pokemon that are not KOed/legal can be trained
const selectableFilter = (pokemon: Pokemon) => { const selectableFilter = (pokemon: Pokemon) => {
return isPokemonValidForEncounterOptionSelection(pokemon, scene, `${namespace}.invalid_selection`); return isPokemonValidForEncounterOptionSelection(pokemon, scene, `${namespace}:invalid_selection`);
}; };
return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter); return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter);
@ -221,7 +221,7 @@ export const TrainingSessionEncounter: MysteryEncounter =
scene.removePokemonFromPlayerParty(playerPokemon, false); scene.removePokemonFromPlayerParty(playerPokemon, false);
const onBeforeRewardsPhase = () => { const onBeforeRewardsPhase = () => {
queueEncounterMessage(scene, `${namespace}.option.2.finished`); queueEncounterMessage(scene, `${namespace}:option.2.finished`);
// Add the pokemon back to party with Nature change // Add the pokemon back to party with Nature change
playerPokemon.setNature(encounter.misc.chosenNature); playerPokemon.setNature(encounter.misc.chosenNature);
scene.gameData.setPokemonCaught(playerPokemon, false); scene.gameData.setPokemonCaught(playerPokemon, false);
@ -246,12 +246,12 @@ export const TrainingSessionEncounter: MysteryEncounter =
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withHasDexProgress(true) .withHasDexProgress(true)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.3.label`, buttonLabel: `${namespace}:option.3.label`,
buttonTooltip: `${namespace}.option.3.tooltip`, buttonTooltip: `${namespace}:option.3.tooltip`,
secondOptionPrompt: `${namespace}.option.3.select_prompt`, secondOptionPrompt: `${namespace}:option.3.select_prompt`,
selected: [ selected: [
{ {
text: `${namespace}.option.selected`, text: `${namespace}:option.selected`,
}, },
], ],
}) })
@ -295,7 +295,7 @@ export const TrainingSessionEncounter: MysteryEncounter =
// Only Pokemon that are not KOed/legal can be trained // Only Pokemon that are not KOed/legal can be trained
const selectableFilter = (pokemon: Pokemon) => { const selectableFilter = (pokemon: Pokemon) => {
return isPokemonValidForEncounterOptionSelection(pokemon, scene, `${namespace}.invalid_selection`); return isPokemonValidForEncounterOptionSelection(pokemon, scene, `${namespace}:invalid_selection`);
}; };
return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter); return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter);
@ -316,7 +316,7 @@ export const TrainingSessionEncounter: MysteryEncounter =
scene.removePokemonFromPlayerParty(playerPokemon, false); scene.removePokemonFromPlayerParty(playerPokemon, false);
const onBeforeRewardsPhase = () => { const onBeforeRewardsPhase = () => {
queueEncounterMessage(scene, `${namespace}.option.3.finished`); queueEncounterMessage(scene, `${namespace}:option.3.finished`);
// Add the pokemon back to party with ability change // Add the pokemon back to party with ability change
const abilityIndex = encounter.misc.abilityIndex; const abilityIndex = encounter.misc.abilityIndex;
@ -326,7 +326,7 @@ export const TrainingSessionEncounter: MysteryEncounter =
// Only update the fusion's dex data if the Pokemon is already caught in dex (ignore rentals) // Only update the fusion's dex data if the Pokemon is already caught in dex (ignore rentals)
const rootFusionSpecies = playerPokemon.fusionSpecies?.getRootSpeciesId(); const rootFusionSpecies = playerPokemon.fusionSpecies?.getRootSpeciesId();
if (!isNullOrUndefined(rootFusionSpecies) if (!isNullOrUndefined(rootFusionSpecies)
&& speciesStarters.hasOwnProperty(rootFusionSpecies) && speciesStarterCosts.hasOwnProperty(rootFusionSpecies)
&& !!scene.gameData.dexData[rootFusionSpecies].caughtAttr) { && !!scene.gameData.dexData[rootFusionSpecies].caughtAttr) {
scene.gameData.starterData[rootFusionSpecies].abilityAttr |= playerPokemon.fusionAbilityIndex !== 1 || playerPokemon.fusionSpecies?.ability2 scene.gameData.starterData[rootFusionSpecies].abilityAttr |= playerPokemon.fusionAbilityIndex !== 1 || playerPokemon.fusionSpecies?.ability2
? 1 << playerPokemon.fusionAbilityIndex ? 1 << playerPokemon.fusionAbilityIndex
@ -356,11 +356,11 @@ export const TrainingSessionEncounter: MysteryEncounter =
) )
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.4.label`, buttonLabel: `${namespace}:option.4.label`,
buttonTooltip: `${namespace}.option.4.tooltip`, buttonTooltip: `${namespace}:option.4.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.4.selected`, text: `${namespace}:option.4.selected`,
}, },
], ],
}, },

View File

@ -19,7 +19,7 @@ import { PokemonMove } from "#app/field/pokemon";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
/** the i18n namespace for this encounter */ /** the i18n namespace for this encounter */
const namespace = "mysteryEncounter:trashToTreasure"; const namespace = "mysteryEncounters/trashToTreasure";
const SOUND_EFFECT_WAIT_TIME = 700; const SOUND_EFFECT_WAIT_TIME = 700;
@ -51,12 +51,12 @@ export const TrashToTreasureEncounter: MysteryEncounter =
.withAutoHideIntroVisuals(false) .withAutoHideIntroVisuals(false)
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
}, },
]) ])
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
@ -67,17 +67,17 @@ export const TrashToTreasureEncounter: MysteryEncounter =
isBoss: true, isBoss: true,
formIndex: 1, // Gmax formIndex: 1, // Gmax
bossSegmentModifier: 1, // +1 Segment from normal bossSegmentModifier: 1, // +1 Segment from normal
moveSet: [Moves.PAYBACK, Moves.GUNK_SHOT, Moves.STOMPING_TANTRUM, Moves.DRAIN_PUNCH] moveSet: [ Moves.PAYBACK, Moves.GUNK_SHOT, Moves.STOMPING_TANTRUM, Moves.DRAIN_PUNCH ]
}; };
const config: EnemyPartyConfig = { const config: EnemyPartyConfig = {
levelAdditiveModifier: 1, levelAdditiveModifier: 1,
pokemonConfigs: [pokemonConfig], pokemonConfigs: [ pokemonConfig ],
disableSwitch: true disableSwitch: true
}; };
encounter.enemyPartyConfigs = [config]; encounter.enemyPartyConfigs = [ config ];
// Load animations/sfx for Garbodor fight start moves // Load animations/sfx for Garbodor fight start moves
loadCustomMovesForEncounter(scene, [Moves.TOXIC, Moves.AMNESIA]); loadCustomMovesForEncounter(scene, [ Moves.TOXIC, Moves.AMNESIA ]);
scene.loadSe("PRSFX- Dig2", "battle_anims", "PRSFX- Dig2.wav"); scene.loadSe("PRSFX- Dig2", "battle_anims", "PRSFX- Dig2.wav");
scene.loadSe("PRSFX- Venom Drench", "battle_anims", "PRSFX- Venom Drench.wav"); scene.loadSe("PRSFX- Venom Drench", "battle_anims", "PRSFX- Venom Drench.wav");
@ -90,11 +90,11 @@ export const TrashToTreasureEncounter: MysteryEncounter =
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.1.selected`, text: `${namespace}:option.1.selected`,
}, },
], ],
}) })
@ -107,7 +107,7 @@ export const TrashToTreasureEncounter: MysteryEncounter =
transitionMysteryEncounterIntroVisuals(scene); transitionMysteryEncounterIntroVisuals(scene);
await tryApplyDigRewardItems(scene); await tryApplyDigRewardItems(scene);
const blackSludge = generateModifierType(scene, modifierTypes.MYSTERY_ENCOUNTER_BLACK_SLUDGE, [SHOP_ITEM_COST_MULTIPLIER]); const blackSludge = generateModifierType(scene, modifierTypes.MYSTERY_ENCOUNTER_BLACK_SLUDGE, [ SHOP_ITEM_COST_MULTIPLIER ]);
const modifier = blackSludge?.newModifier(); const modifier = blackSludge?.newModifier();
if (modifier) { if (modifier) {
await scene.addModifier(modifier, false, false, false, true); await scene.addModifier(modifier, false, false, false, true);
@ -123,33 +123,33 @@ export const TrashToTreasureEncounter: MysteryEncounter =
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.2.selected`, text: `${namespace}:option.2.selected`,
}, },
], ],
}) })
.withOptionPhase(async (scene: BattleScene) => { .withOptionPhase(async (scene: BattleScene) => {
// Investigate garbage, battle Gmax Garbodor // Investigate garbage, battle Gmax Garbodor
scene.setFieldScale(0.75); scene.setFieldScale(0.75);
await showEncounterText(scene, `${namespace}.option.2.selected_2`); await showEncounterText(scene, `${namespace}:option.2.selected_2`);
transitionMysteryEncounterIntroVisuals(scene); transitionMysteryEncounterIntroVisuals(scene);
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.GREAT], fillRemaining: true }); setEncounterRewards(scene, { guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.GREAT ], fillRemaining: true });
encounter.startOfBattleEffects.push( encounter.startOfBattleEffects.push(
{ {
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.PLAYER], targets: [ BattlerIndex.PLAYER ],
move: new PokemonMove(Moves.TOXIC), move: new PokemonMove(Moves.TOXIC),
ignorePp: true ignorePp: true
}, },
{ {
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.ENEMY], targets: [ BattlerIndex.ENEMY ],
move: new PokemonMove(Moves.AMNESIA), move: new PokemonMove(Moves.AMNESIA),
ignorePp: true ignorePp: true
}); });

View File

@ -25,7 +25,7 @@ import { Stat } from "#enums/stat";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */
const namespace = "mysteryEncounter:uncommonBreed"; const namespace = "mysteryEncounters/uncommonBreed";
/** /**
* Uncommon Breed encounter. * Uncommon Breed encounter.
@ -42,7 +42,7 @@ export const UncommonBreedEncounter: MysteryEncounter =
.withIntroSpriteConfigs([]) // Set in onInit() .withIntroSpriteConfigs([]) // Set in onInit()
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
}, },
]) ])
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
@ -74,8 +74,8 @@ export const UncommonBreedEncounter: MysteryEncounter =
// Defense/Spd buffs below wave 50, +1 to all stats otherwise // Defense/Spd buffs below wave 50, +1 to all stats otherwise
const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = scene.currentBattle.waveIndex < 50 ? const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = scene.currentBattle.waveIndex < 50 ?
[Stat.DEF, Stat.SPDEF, Stat.SPD] : [ Stat.DEF, Stat.SPDEF, Stat.SPD ] :
[Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD]; [ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD ];
const config: EnemyPartyConfig = { const config: EnemyPartyConfig = {
pokemonConfigs: [{ pokemonConfigs: [{
@ -83,14 +83,14 @@ export const UncommonBreedEncounter: MysteryEncounter =
species: species, species: species,
dataSource: new PokemonData(pokemon), dataSource: new PokemonData(pokemon),
isBoss: false, isBoss: false,
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON], tags: [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON ],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => { mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
queueEncounterMessage(pokemon.scene, `${namespace}.option.1.stat_boost`); queueEncounterMessage(pokemon.scene, `${namespace}:option.1.stat_boost`);
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, statChangesForBattle, 1)); pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, statChangesForBattle, 1));
} }
}], }],
}; };
encounter.enemyPartyConfigs = [config]; encounter.enemyPartyConfigs = [ config ];
const { spriteKey, fileRoot } = getSpriteKeysFromPokemon(pokemon); const { spriteKey, fileRoot } = getSpriteKeysFromPokemon(pokemon);
encounter.spriteConfigs = [ encounter.spriteConfigs = [
@ -125,16 +125,16 @@ export const UncommonBreedEncounter: MysteryEncounter =
scene.time.delayedCall(500, () => scene.playSound("battle_anims/PRSFX- Spotlight2")); scene.time.delayedCall(500, () => scene.playSound("battle_anims/PRSFX- Spotlight2"));
return true; return true;
}) })
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.1.selected`, text: `${namespace}:option.1.selected`,
}, },
], ],
}, },
@ -152,7 +152,7 @@ export const UncommonBreedEncounter: MysteryEncounter =
encounter.startOfBattleEffects.push( encounter.startOfBattleEffects.push(
{ {
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [target], targets: [ target ],
move: pokemonMove, move: pokemonMove,
ignorePp: true ignorePp: true
}); });
@ -167,12 +167,12 @@ export const UncommonBreedEncounter: MysteryEncounter =
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL) .newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)
.withSceneRequirement(new PersistentModifierRequirement("BerryModifier", 4)) // Will set option2PrimaryName and option2PrimaryMove dialogue tokens automatically .withSceneRequirement(new PersistentModifierRequirement("BerryModifier", 4)) // Will set option2PrimaryName and option2PrimaryMove dialogue tokens automatically
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
disabledButtonTooltip: `${namespace}.option.2.disabled_tooltip`, disabledButtonTooltip: `${namespace}:option.2.disabled_tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.2.selected` text: `${namespace}:option.2.selected`
} }
] ]
}) })
@ -181,7 +181,7 @@ export const UncommonBreedEncounter: MysteryEncounter =
// Remove 4 random berries from player's party // Remove 4 random berries from player's party
// Get all player berry items, remove from party, and store reference // Get all player berry items, remove from party, and store reference
const berryItems: BerryModifier[]= scene.findModifiers(m => m instanceof BerryModifier) as BerryModifier[]; const berryItems: BerryModifier[] = scene.findModifiers(m => m instanceof BerryModifier) as BerryModifier[];
for (let i = 0; i < 4; i++) { for (let i = 0; i < 4; i++) {
const index = randSeedInt(berryItems.length); const index = randSeedInt(berryItems.length);
const randBerry = berryItems[index]; const randBerry = berryItems[index];
@ -211,12 +211,12 @@ export const UncommonBreedEncounter: MysteryEncounter =
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL) .newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)
.withPrimaryPokemonRequirement(new MoveRequirement(CHARMING_MOVES)) // Will set option2PrimaryName and option2PrimaryMove dialogue tokens automatically .withPrimaryPokemonRequirement(new MoveRequirement(CHARMING_MOVES)) // Will set option2PrimaryName and option2PrimaryMove dialogue tokens automatically
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.3.label`, buttonLabel: `${namespace}:option.3.label`,
buttonTooltip: `${namespace}.option.3.tooltip`, buttonTooltip: `${namespace}:option.3.tooltip`,
disabledButtonTooltip: `${namespace}.option.3.disabled_tooltip`, disabledButtonTooltip: `${namespace}:option.3.disabled_tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.3.selected` text: `${namespace}:option.3.selected`
} }
] ]
}) })

View File

@ -23,7 +23,7 @@ import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
import { Challenges } from "#enums/challenges"; import { Challenges } from "#enums/challenges";
/** i18n namespace for encounter */ /** i18n namespace for encounter */
const namespace = "mysteryEncounter:weirdDream"; const namespace = "mysteryEncounters/weirdDream";
/** Exclude Ultra Beasts, Paradox, Eternatus, and all legendary/mythical/trio pokemon that are below 570 BST */ /** Exclude Ultra Beasts, Paradox, Eternatus, and all legendary/mythical/trio pokemon that are below 570 BST */
const EXCLUDED_TRANSFORMATION_SPECIES = [ const EXCLUDED_TRANSFORMATION_SPECIES = [
@ -89,12 +89,12 @@ const PERCENT_LEVEL_LOSS_ON_REFUSE = 12.5;
* Value ranges of the resulting species BST transformations after adding values to original species * Value ranges of the resulting species BST transformations after adding values to original species
* 2 Pokemon in the party use this range * 2 Pokemon in the party use this range
*/ */
const HIGH_BST_TRANSFORM_BASE_VALUES: [number, number] = [90, 110]; const HIGH_BST_TRANSFORM_BASE_VALUES: [number, number] = [ 90, 110 ];
/** /**
* Value ranges of the resulting species BST transformations after adding values to original species * Value ranges of the resulting species BST transformations after adding values to original species
* All remaining Pokemon in the party use this range * All remaining Pokemon in the party use this range
*/ */
const STANDARD_BST_TRANSFORM_BASE_VALUES: [number, number] = [40, 50]; const STANDARD_BST_TRANSFORM_BASE_VALUES: [number, number] = [ 40, 50 ];
/** /**
* Weird Dream encounter. * Weird Dream encounter.
@ -118,16 +118,16 @@ export const WeirdDreamEncounter: MysteryEncounter =
]) ])
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}.intro`, text: `${namespace}:intro`,
}, },
{ {
speaker: `${namespace}.speaker`, speaker: `${namespace}:speaker`,
text: `${namespace}.intro_dialogue`, text: `${namespace}:intro_dialogue`,
}, },
]) ])
.withTitle(`${namespace}.title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}.description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}.query`) .withQuery(`${namespace}:query`)
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
scene.loadBgm("mystery_encounter_weird_dream", "mystery_encounter_weird_dream.mp3"); scene.loadBgm("mystery_encounter_weird_dream", "mystery_encounter_weird_dream.mp3");
return true; return true;
@ -141,11 +141,11 @@ export const WeirdDreamEncounter: MysteryEncounter =
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withHasDexProgress(true) .withHasDexProgress(true)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}.option.1.label`, buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`, buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.1.selected`, text: `${namespace}:option.1.selected`,
} }
], ],
}) })
@ -165,7 +165,7 @@ export const WeirdDreamEncounter: MysteryEncounter =
}) })
.withOptionPhase(async (scene: BattleScene) => { .withOptionPhase(async (scene: BattleScene) => {
// Starts cutscene dialogue, but does not await so that cutscene plays as player goes through dialogue // Starts cutscene dialogue, but does not await so that cutscene plays as player goes through dialogue
const cutsceneDialoguePromise = showEncounterText(scene, `${namespace}.option.1.cutscene`); const cutsceneDialoguePromise = showEncounterText(scene, `${namespace}:option.1.cutscene`);
// Change the entire player's party // Change the entire player's party
// Wait for all new Pokemon assets to be loaded before showing transformation animations // Wait for all new Pokemon assets to be loaded before showing transformation animations
@ -189,21 +189,21 @@ export const WeirdDreamEncounter: MysteryEncounter =
await cutsceneDialoguePromise; await cutsceneDialoguePromise;
doHideDreamBackground(scene); doHideDreamBackground(scene);
await showEncounterText(scene, `${namespace}.option.1.dream_complete`); await showEncounterText(scene, `${namespace}:option.1.dream_complete`);
await doNewTeamPostProcess(scene, transformations); await doNewTeamPostProcess(scene, transformations);
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.MEMORY_MUSHROOM, modifierTypes.ROGUE_BALL, modifierTypes.MINT, modifierTypes.MINT]}); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.MEMORY_MUSHROOM, modifierTypes.ROGUE_BALL, modifierTypes.MINT, modifierTypes.MINT ]});
leaveEncounterWithoutBattle(scene, true); leaveEncounterWithoutBattle(scene, true);
}) })
.build() .build()
) )
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}.option.2.label`, buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`, buttonTooltip: `${namespace}:option.2.tooltip`,
selected: [ selected: [
{ {
text: `${namespace}.option.2.selected`, text: `${namespace}:option.2.selected`,
}, },
], ],
}, },
@ -372,7 +372,7 @@ async function doNewTeamPostProcess(scene: BattleScene, transformations: Pokemon
// Randomize the second type of the pokemon // Randomize the second type of the pokemon
// If the pokemon does not normally have a second type, it will gain 1 // If the pokemon does not normally have a second type, it will gain 1
const newTypes = [newPokemon.getTypes()[0]]; const newTypes = [ newPokemon.getTypes()[0] ];
let newType = randSeedInt(18) as Type; let newType = randSeedInt(18) as Type;
while (newType === newTypes[0]) { while (newType === newTypes[0]) {
newType = randSeedInt(18) as Type; newType = randSeedInt(18) as Type;
@ -390,14 +390,14 @@ async function doNewTeamPostProcess(scene: BattleScene, transformations: Pokemon
// Any pokemon that is at or below 450 BST gets +20 permanent BST to 3 stats: HP (halved, +10), lowest of Atk/SpAtk, and lowest of Def/SpDef // Any pokemon that is at or below 450 BST gets +20 permanent BST to 3 stats: HP (halved, +10), lowest of Atk/SpAtk, and lowest of Def/SpDef
if (newPokemon.getSpeciesForm().getBaseStatTotal() <= GAIN_OLD_GATEAU_ITEM_BST_THRESHOLD) { if (newPokemon.getSpeciesForm().getBaseStatTotal() <= GAIN_OLD_GATEAU_ITEM_BST_THRESHOLD) {
const stats: Stat[] = [Stat.HP]; const stats: Stat[] = [ Stat.HP ];
const baseStats = newPokemon.getSpeciesForm().baseStats.slice(0); const baseStats = newPokemon.getSpeciesForm().baseStats.slice(0);
// Attack or SpAtk // Attack or SpAtk
stats.push(baseStats[Stat.ATK] < baseStats[Stat.SPATK] ? Stat.ATK : Stat.SPATK); stats.push(baseStats[Stat.ATK] < baseStats[Stat.SPATK] ? Stat.ATK : Stat.SPATK);
// Def or SpDef // Def or SpDef
stats.push(baseStats[Stat.DEF] < baseStats[Stat.SPDEF] ? Stat.DEF : Stat.SPDEF); stats.push(baseStats[Stat.DEF] < baseStats[Stat.SPDEF] ? Stat.DEF : Stat.SPDEF);
const modType = modifierTypes.MYSTERY_ENCOUNTER_OLD_GATEAU() const modType = modifierTypes.MYSTERY_ENCOUNTER_OLD_GATEAU()
.generateType(scene.getParty(), [20, stats]) .generateType(scene.getParty(), [ 20, stats ])
?.withIdFromFunc(modifierTypes.MYSTERY_ENCOUNTER_OLD_GATEAU); ?.withIdFromFunc(modifierTypes.MYSTERY_ENCOUNTER_OLD_GATEAU);
const modifier = modType?.newModifier(newPokemon); const modifier = modType?.newModifier(newPokemon);
if (modifier) { if (modifier) {
@ -553,7 +553,7 @@ async function addEggMoveToNewPokemonMoveset(scene: BattleScene, newPokemon: Pla
let eggMoveIndex: null | number = null; let eggMoveIndex: null | number = null;
const eggMoves = newPokemon.getEggMoves()?.slice(0); const eggMoves = newPokemon.getEggMoves()?.slice(0);
if (eggMoves) { if (eggMoves) {
const eggMoveIndices = randSeedShuffle([0, 1, 2, 3]); const eggMoveIndices = randSeedShuffle([ 0, 1, 2, 3 ]);
let randomEggMoveIndex = eggMoveIndices.pop(); let randomEggMoveIndex = eggMoveIndices.pop();
let randomEggMove = !isNullOrUndefined(randomEggMoveIndex) ? eggMoves[randomEggMoveIndex] : null; let randomEggMove = !isNullOrUndefined(randomEggMoveIndex) ? eggMoves[randomEggMoveIndex] : null;
let retries = 0; let retries = 0;

View File

@ -5,16 +5,16 @@ import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import { TimeOfDay } from "#enums/time-of-day"; import { TimeOfDay } from "#enums/time-of-day";
import { Nature } from "../nature"; import { Nature } from "#app/data/nature";
import { EvolutionItem, pokemonEvolutions } from "../pokemon-evolutions"; import { EvolutionItem, pokemonEvolutions } from "#app/data/balance/pokemon-evolutions";
import { FormChangeItem, pokemonFormChanges, SpeciesFormChangeItemTrigger } from "../pokemon-forms"; import { FormChangeItem, pokemonFormChanges, SpeciesFormChangeItemTrigger } from "#app/data/pokemon-forms";
import { SpeciesFormKey } from "../pokemon-species"; import { StatusEffect } from "#app/data/status-effect";
import { StatusEffect } from "../status-effect"; import { Type } from "#app/data/type";
import { Type } from "../type"; import { WeatherType } from "#app/data/weather";
import { WeatherType } from "../weather";
import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { AttackTypeBoosterModifier } from "#app/modifier/modifier"; import { AttackTypeBoosterModifier } from "#app/modifier/modifier";
import { AttackTypeBoosterModifierType } from "#app/modifier/modifier-type"; import { AttackTypeBoosterModifierType } from "#app/modifier/modifier-type";
import { SpeciesFormKey } from "#enums/species-form-key";
export interface EncounterRequirement { export interface EncounterRequirement {
meetsRequirement(scene: BattleScene): boolean; // Boolean to see if a requirement is met meetsRequirement(scene: BattleScene): boolean; // Boolean to see if a requirement is met
@ -147,7 +147,7 @@ export class PreviousEncounterRequirement extends EncounterSceneRequirement {
} }
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
return ["previousEncounter", scene.mysteryEncounterSaveData.encounteredEvents.find(e => e.type === this.previousEncounterRequirement)?.[0].toString() ?? ""]; return [ "previousEncounter", scene.mysteryEncounterSaveData.encounteredEvents.find(e => e.type === this.previousEncounterRequirement)?.[0].toString() ?? "" ];
} }
} }
@ -175,7 +175,7 @@ export class WaveRangeRequirement extends EncounterSceneRequirement {
} }
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
return ["waveIndex", scene.currentBattle.waveIndex.toString()]; return [ "waveIndex", scene.currentBattle.waveIndex.toString() ];
} }
} }
@ -204,7 +204,7 @@ export class WaveModulusRequirement extends EncounterSceneRequirement {
} }
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
return ["waveIndex", scene.currentBattle.waveIndex.toString()]; return [ "waveIndex", scene.currentBattle.waveIndex.toString() ];
} }
} }
@ -213,7 +213,7 @@ export class TimeOfDayRequirement extends EncounterSceneRequirement {
constructor(timeOfDay: TimeOfDay | TimeOfDay[]) { constructor(timeOfDay: TimeOfDay | TimeOfDay[]) {
super(); super();
this.requiredTimeOfDay = Array.isArray(timeOfDay) ? timeOfDay : [timeOfDay]; this.requiredTimeOfDay = Array.isArray(timeOfDay) ? timeOfDay : [ timeOfDay ];
} }
override meetsRequirement(scene: BattleScene): boolean { override meetsRequirement(scene: BattleScene): boolean {
@ -226,7 +226,7 @@ export class TimeOfDayRequirement extends EncounterSceneRequirement {
} }
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
return ["timeOfDay", TimeOfDay[scene.arena.getTimeOfDay()].toLocaleLowerCase()]; return [ "timeOfDay", TimeOfDay[scene.arena.getTimeOfDay()].toLocaleLowerCase() ];
} }
} }
@ -235,7 +235,7 @@ export class WeatherRequirement extends EncounterSceneRequirement {
constructor(weather: WeatherType | WeatherType[]) { constructor(weather: WeatherType | WeatherType[]) {
super(); super();
this.requiredWeather = Array.isArray(weather) ? weather : [weather]; this.requiredWeather = Array.isArray(weather) ? weather : [ weather ];
} }
override meetsRequirement(scene: BattleScene): boolean { override meetsRequirement(scene: BattleScene): boolean {
@ -253,7 +253,7 @@ export class WeatherRequirement extends EncounterSceneRequirement {
if (!isNullOrUndefined(currentWeather)) { if (!isNullOrUndefined(currentWeather)) {
token = WeatherType[currentWeather].replace("_", " ").toLocaleLowerCase(); token = WeatherType[currentWeather].replace("_", " ").toLocaleLowerCase();
} }
return ["weather", token]; return [ "weather", token ];
} }
} }
@ -285,7 +285,7 @@ export class PartySizeRequirement extends EncounterSceneRequirement {
} }
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
return ["partySize", scene.getParty().length.toString()]; return [ "partySize", scene.getParty().length.toString() ];
} }
} }
@ -296,7 +296,7 @@ export class PersistentModifierRequirement extends EncounterSceneRequirement {
constructor(heldItem: string | string[], minNumberOfItems: number = 1) { constructor(heldItem: string | string[], minNumberOfItems: number = 1) {
super(); super();
this.minNumberOfItems = minNumberOfItems; this.minNumberOfItems = minNumberOfItems;
this.requiredHeldItemModifiers = Array.isArray(heldItem) ? heldItem : [heldItem]; this.requiredHeldItemModifiers = Array.isArray(heldItem) ? heldItem : [ heldItem ];
} }
override meetsRequirement(scene: BattleScene): boolean { override meetsRequirement(scene: BattleScene): boolean {
@ -318,7 +318,7 @@ export class PersistentModifierRequirement extends EncounterSceneRequirement {
} }
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
return ["requiredItem", this.requiredHeldItemModifiers[0]]; return [ "requiredItem", this.requiredHeldItemModifiers[0] ];
} }
} }
@ -346,7 +346,7 @@ export class MoneyRequirement extends EncounterSceneRequirement {
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
const value = this.scalingMultiplier > 0 ? scene.getWaveMoneyAmount(this.scalingMultiplier).toString() : this.requiredMoney.toString(); const value = this.scalingMultiplier > 0 ? scene.getWaveMoneyAmount(this.scalingMultiplier).toString() : this.requiredMoney.toString();
return ["money", value]; return [ "money", value ];
} }
} }
@ -359,7 +359,7 @@ export class SpeciesRequirement extends EncounterPokemonRequirement {
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredSpecies = Array.isArray(species) ? species : [species]; this.requiredSpecies = Array.isArray(species) ? species : [ species ];
} }
override meetsRequirement(scene: BattleScene): boolean { override meetsRequirement(scene: BattleScene): boolean {
@ -381,9 +381,9 @@ export class SpeciesRequirement extends EncounterPokemonRequirement {
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
if (pokemon?.species.speciesId && this.requiredSpecies.includes(pokemon.species.speciesId)) { if (pokemon?.species.speciesId && this.requiredSpecies.includes(pokemon.species.speciesId)) {
return ["species", Species[pokemon.species.speciesId]]; return [ "species", Species[pokemon.species.speciesId] ];
} }
return ["species", ""]; return [ "species", "" ];
} }
} }
@ -397,7 +397,7 @@ export class NatureRequirement extends EncounterPokemonRequirement {
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredNature = Array.isArray(nature) ? nature : [nature]; this.requiredNature = Array.isArray(nature) ? nature : [ nature ];
} }
override meetsRequirement(scene: BattleScene): boolean { override meetsRequirement(scene: BattleScene): boolean {
@ -419,9 +419,9 @@ export class NatureRequirement extends EncounterPokemonRequirement {
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
if (!isNullOrUndefined(pokemon?.nature) && this.requiredNature.includes(pokemon.nature)) { if (!isNullOrUndefined(pokemon?.nature) && this.requiredNature.includes(pokemon.nature)) {
return ["nature", Nature[pokemon.nature]]; return [ "nature", Nature[pokemon.nature] ];
} }
return ["nature", ""]; return [ "nature", "" ];
} }
} }
@ -436,7 +436,7 @@ export class TypeRequirement extends EncounterPokemonRequirement {
this.excludeFainted = excludeFainted; this.excludeFainted = excludeFainted;
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredType = Array.isArray(type) ? type : [type]; this.requiredType = Array.isArray(type) ? type : [ type ];
} }
override meetsRequirement(scene: BattleScene): boolean { override meetsRequirement(scene: BattleScene): boolean {
@ -465,9 +465,9 @@ export class TypeRequirement extends EncounterPokemonRequirement {
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
const includedTypes = this.requiredType.filter((ty) => pokemon?.getTypes().includes(ty)); const includedTypes = this.requiredType.filter((ty) => pokemon?.getTypes().includes(ty));
if (includedTypes.length > 0) { if (includedTypes.length > 0) {
return ["type", Type[includedTypes[0]]]; return [ "type", Type[includedTypes[0]] ];
} }
return ["type", ""]; return [ "type", "" ];
} }
} }
@ -481,7 +481,7 @@ export class MoveRequirement extends EncounterPokemonRequirement {
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredMoves = Array.isArray(moves) ? moves : [moves]; this.requiredMoves = Array.isArray(moves) ? moves : [ moves ];
} }
override meetsRequirement(scene: BattleScene): boolean { override meetsRequirement(scene: BattleScene): boolean {
@ -504,9 +504,9 @@ export class MoveRequirement extends EncounterPokemonRequirement {
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
const includedMoves = pokemon?.moveset.filter((move) => move?.moveId && this.requiredMoves.includes(move.moveId)); const includedMoves = pokemon?.moveset.filter((move) => move?.moveId && this.requiredMoves.includes(move.moveId));
if (includedMoves && includedMoves.length > 0 && includedMoves[0]) { if (includedMoves && includedMoves.length > 0 && includedMoves[0]) {
return ["move", includedMoves[0].getName()]; return [ "move", includedMoves[0].getName() ];
} }
return ["move", ""]; return [ "move", "" ];
} }
} }
@ -525,7 +525,7 @@ export class CompatibleMoveRequirement extends EncounterPokemonRequirement {
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredMoves = Array.isArray(learnableMove) ? learnableMove : [learnableMove]; this.requiredMoves = Array.isArray(learnableMove) ? learnableMove : [ learnableMove ];
} }
override meetsRequirement(scene: BattleScene): boolean { override meetsRequirement(scene: BattleScene): boolean {
@ -548,9 +548,9 @@ export class CompatibleMoveRequirement extends EncounterPokemonRequirement {
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
const includedCompatMoves = this.requiredMoves.filter((reqMove) => pokemon?.compatibleTms.filter((tm) => !pokemon.moveset.find(m => m?.moveId === tm)).includes(reqMove)); const includedCompatMoves = this.requiredMoves.filter((reqMove) => pokemon?.compatibleTms.filter((tm) => !pokemon.moveset.find(m => m?.moveId === tm)).includes(reqMove));
if (includedCompatMoves.length > 0) { if (includedCompatMoves.length > 0) {
return ["compatibleMove", Moves[includedCompatMoves[0]]]; return [ "compatibleMove", Moves[includedCompatMoves[0]] ];
} }
return ["compatibleMove", ""]; return [ "compatibleMove", "" ];
} }
} }
@ -564,7 +564,7 @@ export class AbilityRequirement extends EncounterPokemonRequirement {
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredAbilities = Array.isArray(abilities) ? abilities : [abilities]; this.requiredAbilities = Array.isArray(abilities) ? abilities : [ abilities ];
} }
override meetsRequirement(scene: BattleScene): boolean { override meetsRequirement(scene: BattleScene): boolean {
@ -586,9 +586,9 @@ export class AbilityRequirement extends EncounterPokemonRequirement {
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
if (pokemon?.getAbility().id && this.requiredAbilities.some(a => pokemon.getAbility().id === a)) { if (pokemon?.getAbility().id && this.requiredAbilities.some(a => pokemon.getAbility().id === a)) {
return ["ability", pokemon.getAbility().name]; return [ "ability", pokemon.getAbility().name ];
} }
return ["ability", ""]; return [ "ability", "" ];
} }
} }
@ -601,7 +601,7 @@ export class StatusEffectRequirement extends EncounterPokemonRequirement {
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredStatusEffect = Array.isArray(statusEffect) ? statusEffect : [statusEffect]; this.requiredStatusEffect = Array.isArray(statusEffect) ? statusEffect : [ statusEffect ];
} }
override meetsRequirement(scene: BattleScene): boolean { override meetsRequirement(scene: BattleScene): boolean {
@ -649,9 +649,9 @@ export class StatusEffectRequirement extends EncounterPokemonRequirement {
return pokemon!.status?.effect === a; return pokemon!.status?.effect === a;
}); });
if (reqStatus.length > 0) { if (reqStatus.length > 0) {
return ["status", StatusEffect[reqStatus[0]]]; return [ "status", StatusEffect[reqStatus[0]] ];
} }
return ["status", ""]; return [ "status", "" ];
} }
} }
@ -670,7 +670,7 @@ export class CanFormChangeWithItemRequirement extends EncounterPokemonRequiremen
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredFormChangeItem = Array.isArray(formChangeItem) ? formChangeItem : [formChangeItem]; this.requiredFormChangeItem = Array.isArray(formChangeItem) ? formChangeItem : [ formChangeItem ];
} }
override meetsRequirement(scene: BattleScene): boolean { override meetsRequirement(scene: BattleScene): boolean {
@ -706,9 +706,9 @@ export class CanFormChangeWithItemRequirement extends EncounterPokemonRequiremen
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
const requiredItems = this.requiredFormChangeItem.filter((formChangeItem) => this.filterByForm(pokemon, formChangeItem)); const requiredItems = this.requiredFormChangeItem.filter((formChangeItem) => this.filterByForm(pokemon, formChangeItem));
if (requiredItems.length > 0) { if (requiredItems.length > 0) {
return ["formChangeItem", FormChangeItem[requiredItems[0]]]; return [ "formChangeItem", FormChangeItem[requiredItems[0]] ];
} }
return ["formChangeItem", ""]; return [ "formChangeItem", "" ];
} }
} }
@ -722,7 +722,7 @@ export class CanEvolveWithItemRequirement extends EncounterPokemonRequirement {
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredEvolutionItem = Array.isArray(evolutionItems) ? evolutionItems : [evolutionItems]; this.requiredEvolutionItem = Array.isArray(evolutionItems) ? evolutionItems : [ evolutionItems ];
} }
override meetsRequirement(scene: BattleScene): boolean { override meetsRequirement(scene: BattleScene): boolean {
@ -756,9 +756,9 @@ export class CanEvolveWithItemRequirement extends EncounterPokemonRequirement {
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
const requiredItems = this.requiredEvolutionItem.filter((evoItem) => this.filterByEvo(pokemon, evoItem)); const requiredItems = this.requiredEvolutionItem.filter((evoItem) => this.filterByEvo(pokemon, evoItem));
if (requiredItems.length > 0) { if (requiredItems.length > 0) {
return ["evolutionItem", EvolutionItem[requiredItems[0]]]; return [ "evolutionItem", EvolutionItem[requiredItems[0]] ];
} }
return ["evolutionItem", ""]; return [ "evolutionItem", "" ];
} }
} }
@ -772,7 +772,7 @@ export class HeldItemRequirement extends EncounterPokemonRequirement {
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredHeldItemModifiers = Array.isArray(heldItem) ? heldItem : [heldItem]; this.requiredHeldItemModifiers = Array.isArray(heldItem) ? heldItem : [ heldItem ];
this.requireTransferable = requireTransferable; this.requireTransferable = requireTransferable;
} }
@ -807,9 +807,9 @@ export class HeldItemRequirement extends EncounterPokemonRequirement {
&& (!this.requireTransferable || it.isTransferable); && (!this.requireTransferable || it.isTransferable);
}); });
if (requiredItems && requiredItems.length > 0) { if (requiredItems && requiredItems.length > 0) {
return ["heldItem", requiredItems[0].type.name]; return [ "heldItem", requiredItems[0].type.name ];
} }
return ["heldItem", ""]; return [ "heldItem", "" ];
} }
} }
@ -823,7 +823,7 @@ export class AttackTypeBoosterHeldItemTypeRequirement extends EncounterPokemonRe
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredHeldItemTypes = Array.isArray(heldItemTypes) ? heldItemTypes : [heldItemTypes]; this.requiredHeldItemTypes = Array.isArray(heldItemTypes) ? heldItemTypes : [ heldItemTypes ];
this.requireTransferable = requireTransferable; this.requireTransferable = requireTransferable;
} }
@ -864,9 +864,9 @@ export class AttackTypeBoosterHeldItemTypeRequirement extends EncounterPokemonRe
&& (!this.requireTransferable || it.isTransferable); && (!this.requireTransferable || it.isTransferable);
}); });
if (requiredItems && requiredItems.length > 0) { if (requiredItems && requiredItems.length > 0) {
return ["heldItem", requiredItems[0].type.name]; return [ "heldItem", requiredItems[0].type.name ];
} }
return ["heldItem", ""]; return [ "heldItem", "" ];
} }
} }
@ -904,7 +904,7 @@ export class LevelRequirement extends EncounterPokemonRequirement {
} }
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
return ["level", pokemon?.level.toString() ?? ""]; return [ "level", pokemon?.level.toString() ?? "" ];
} }
} }
@ -942,7 +942,7 @@ export class FriendshipRequirement extends EncounterPokemonRequirement {
} }
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
return ["friendship", pokemon?.friendship.toString() ?? ""]; return [ "friendship", pokemon?.friendship.toString() ?? "" ];
} }
} }
@ -989,9 +989,9 @@ export class HealthRatioRequirement extends EncounterPokemonRequirement {
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
const hpRatio = pokemon?.getHpRatio(); const hpRatio = pokemon?.getHpRatio();
if (!isNullOrUndefined(hpRatio)) { if (!isNullOrUndefined(hpRatio)) {
return ["healthRatio", Math.floor(hpRatio * 100).toString() + "%"]; return [ "healthRatio", Math.floor(hpRatio * 100).toString() + "%" ];
} }
return ["healthRatio", ""]; return [ "healthRatio", "" ];
} }
} }
@ -1029,8 +1029,7 @@ export class WeightRequirement extends EncounterPokemonRequirement {
} }
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
return ["weight", pokemon?.getWeight().toString() ?? ""]; return [ "weight", pokemon?.getWeight().toString() ?? "" ];
} }
} }

View File

@ -265,7 +265,7 @@ export default class MysteryEncounter implements IMysteryEncounter {
} }
this.encounterTier = this.encounterTier ?? MysteryEncounterTier.COMMON; this.encounterTier = this.encounterTier ?? MysteryEncounterTier.COMMON;
this.dialogue = this.dialogue ?? {}; this.dialogue = this.dialogue ?? {};
this.spriteConfigs = this.spriteConfigs ? [...this.spriteConfigs] : []; this.spriteConfigs = this.spriteConfigs ? [ ...this.spriteConfigs ] : [];
// Default max is 1 for ROGUE encounters, 2 for others // Default max is 1 for ROGUE encounters, 2 for others
this.maxAllowedEncounters = this.maxAllowedEncounters ?? this.encounterTier === MysteryEncounterTier.ROGUE ? DEFAULT_MAX_ALLOWED_ROGUE_ENCOUNTERS : DEFAULT_MAX_ALLOWED_ENCOUNTERS; this.maxAllowedEncounters = this.maxAllowedEncounters ?? this.encounterTier === MysteryEncounterTier.ROGUE ? DEFAULT_MAX_ALLOWED_ROGUE_ENCOUNTERS : DEFAULT_MAX_ALLOWED_ENCOUNTERS;
this.encounterMode = MysteryEncounterMode.DEFAULT; this.encounterMode = MysteryEncounterMode.DEFAULT;
@ -573,7 +573,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
*/ */
withOption(option: MysteryEncounterOption): this & Pick<IMysteryEncounter, "options"> { withOption(option: MysteryEncounterOption): this & Pick<IMysteryEncounter, "options"> {
if (!this.options) { if (!this.options) {
const options = [option]; const options = [ option ];
return Object.assign(this, { options }); return Object.assign(this, { options });
} else { } else {
this.options.push(option); this.options.push(option);
@ -624,11 +624,11 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
} }
withIntroDialogue(dialogue: MysteryEncounterDialogue["intro"] = []): this { withIntroDialogue(dialogue: MysteryEncounterDialogue["intro"] = []): this {
this.dialogue = {...this.dialogue, intro: dialogue }; this.dialogue = { ...this.dialogue, intro: dialogue };
return this; return this;
} }
withIntro({spriteConfigs, dialogue} : {spriteConfigs: MysteryEncounterSpriteConfig[], dialogue?: MysteryEncounterDialogue["intro"]}) { withIntro({ spriteConfigs, dialogue } : {spriteConfigs: MysteryEncounterSpriteConfig[], dialogue?: MysteryEncounterDialogue["intro"]}) {
return this.withIntroSpriteConfigs(spriteConfigs).withIntroDialogue(dialogue); return this.withIntroSpriteConfigs(spriteConfigs).withIntroDialogue(dialogue);
} }
@ -660,7 +660,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
* @returns * @returns
*/ */
withAnimations(...encounterAnimations: EncounterAnim[]): this & Required<Pick<IMysteryEncounter, "encounterAnimations">> { withAnimations(...encounterAnimations: EncounterAnim[]): this & Required<Pick<IMysteryEncounter, "encounterAnimations">> {
const animations = Array.isArray(encounterAnimations) ? encounterAnimations : [encounterAnimations]; const animations = Array.isArray(encounterAnimations) ? encounterAnimations : [ encounterAnimations ];
return Object.assign(this, { encounterAnimations: animations }); return Object.assign(this, { encounterAnimations: animations });
} }
@ -670,7 +670,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
* @param disallowedGameModes * @param disallowedGameModes
*/ */
withDisallowedGameModes(...disallowedGameModes: GameModes[]): this & Required<Pick<IMysteryEncounter, "disallowedGameModes">> { withDisallowedGameModes(...disallowedGameModes: GameModes[]): this & Required<Pick<IMysteryEncounter, "disallowedGameModes">> {
const gameModes = Array.isArray(disallowedGameModes) ? disallowedGameModes : [disallowedGameModes]; const gameModes = Array.isArray(disallowedGameModes) ? disallowedGameModes : [ disallowedGameModes ];
return Object.assign(this, { disallowedGameModes: gameModes }); return Object.assign(this, { disallowedGameModes: gameModes });
} }
@ -680,7 +680,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
* @param disallowedChallenges * @param disallowedChallenges
*/ */
withDisallowedChallenges(...disallowedChallenges: Challenges[]): this & Required<Pick<IMysteryEncounter, "disallowedChallenges">> { withDisallowedChallenges(...disallowedChallenges: Challenges[]): this & Required<Pick<IMysteryEncounter, "disallowedChallenges">> {
const challenges = Array.isArray(disallowedChallenges) ? disallowedChallenges : [disallowedChallenges]; const challenges = Array.isArray(disallowedChallenges) ? disallowedChallenges : [ disallowedChallenges ];
return Object.assign(this, { disallowedChallenges: challenges }); return Object.assign(this, { disallowedChallenges: challenges });
} }
@ -755,7 +755,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
* @returns * @returns
*/ */
withSceneWaveRangeRequirement(min: number, max?: number): this & Required<Pick<IMysteryEncounter, "requirements">> { withSceneWaveRangeRequirement(min: number, max?: number): this & Required<Pick<IMysteryEncounter, "requirements">> {
return this.withSceneRequirement(new WaveRangeRequirement([min, max ?? min])); return this.withSceneRequirement(new WaveRangeRequirement([ min, max ?? min ]));
} }
/** /**
@ -767,7 +767,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
* @returns * @returns
*/ */
withScenePartySizeRequirement(min: number, max?: number, excludeDisallowedPokemon: boolean = false): this & Required<Pick<IMysteryEncounter, "requirements">> { withScenePartySizeRequirement(min: number, max?: number, excludeDisallowedPokemon: boolean = false): this & Required<Pick<IMysteryEncounter, "requirements">> {
return this.withSceneRequirement(new PartySizeRequirement([min, max ?? min], excludeDisallowedPokemon)); return this.withSceneRequirement(new PartySizeRequirement([ min, max ?? min ], excludeDisallowedPokemon));
} }
/** /**
@ -982,7 +982,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
* @returns * @returns
*/ */
withOutroDialogue(dialogue: MysteryEncounterDialogue["outro"] = []): this { withOutroDialogue(dialogue: MysteryEncounterDialogue["outro"] = []): this {
this.dialogue = {...this.dialogue, outro: dialogue }; this.dialogue = { ...this.dialogue, outro: dialogue };
return this; return this;
} }

View File

@ -32,7 +32,7 @@ import { FunAndGamesEncounter } from "#app/data/mystery-encounters/encounters/fu
import { UncommonBreedEncounter } from "#app/data/mystery-encounters/encounters/uncommon-breed-encounter"; import { UncommonBreedEncounter } from "#app/data/mystery-encounters/encounters/uncommon-breed-encounter";
import { GlobalTradeSystemEncounter } from "#app/data/mystery-encounters/encounters/global-trade-system-encounter"; import { GlobalTradeSystemEncounter } from "#app/data/mystery-encounters/encounters/global-trade-system-encounter";
import { TheExpertPokemonBreederEncounter } from "#app/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter"; import { TheExpertPokemonBreederEncounter } from "#app/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter";
import { getBiomeName } from "#app/data/biomes"; import { getBiomeName } from "#app/data/balance/biomes";
/** /**
* Spawn chance: (BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT + WIGHT_INCREMENT_ON_SPAWN_MISS * <number of missed spawns>) / MYSTERY_ENCOUNTER_SPAWN_MAX_WEIGHT * Spawn chance: (BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT + WIGHT_INCREMENT_ON_SPAWN_MISS * <number of missed spawns>) / MYSTERY_ENCOUNTER_SPAWN_MAX_WEIGHT
@ -224,72 +224,72 @@ const anyBiomeEncounters: MysteryEncounterType[] = [
* that biome groups do not cover * that biome groups do not cover
*/ */
export const mysteryEncountersByBiome = new Map<Biome, MysteryEncounterType[]>([ export const mysteryEncountersByBiome = new Map<Biome, MysteryEncounterType[]>([
[Biome.TOWN, []], [ Biome.TOWN, []],
[Biome.PLAINS, [ [ Biome.PLAINS, [
MysteryEncounterType.SLUMBERING_SNORLAX, MysteryEncounterType.SLUMBERING_SNORLAX,
MysteryEncounterType.ABSOLUTE_AVARICE MysteryEncounterType.ABSOLUTE_AVARICE
]], ]],
[Biome.GRASS, [ [ Biome.GRASS, [
MysteryEncounterType.SLUMBERING_SNORLAX, MysteryEncounterType.SLUMBERING_SNORLAX,
MysteryEncounterType.ABSOLUTE_AVARICE MysteryEncounterType.ABSOLUTE_AVARICE
]], ]],
[Biome.TALL_GRASS, [ [ Biome.TALL_GRASS, [
MysteryEncounterType.ABSOLUTE_AVARICE MysteryEncounterType.ABSOLUTE_AVARICE
]], ]],
[Biome.METROPOLIS, []], [ Biome.METROPOLIS, []],
[Biome.FOREST, [ [ Biome.FOREST, [
MysteryEncounterType.SAFARI_ZONE, MysteryEncounterType.SAFARI_ZONE,
MysteryEncounterType.ABSOLUTE_AVARICE MysteryEncounterType.ABSOLUTE_AVARICE
]], ]],
[Biome.SEA, [ [ Biome.SEA, [
MysteryEncounterType.LOST_AT_SEA MysteryEncounterType.LOST_AT_SEA
]], ]],
[Biome.SWAMP, [ [ Biome.SWAMP, [
MysteryEncounterType.SAFARI_ZONE MysteryEncounterType.SAFARI_ZONE
]], ]],
[Biome.BEACH, []], [ Biome.BEACH, []],
[Biome.LAKE, []], [ Biome.LAKE, []],
[Biome.SEABED, []], [ Biome.SEABED, []],
[Biome.MOUNTAIN, []], [ Biome.MOUNTAIN, []],
[Biome.BADLANDS, [ [ Biome.BADLANDS, [
MysteryEncounterType.DANCING_LESSONS MysteryEncounterType.DANCING_LESSONS
]], ]],
[Biome.CAVE, [ [ Biome.CAVE, [
MysteryEncounterType.THE_STRONG_STUFF MysteryEncounterType.THE_STRONG_STUFF
]], ]],
[Biome.DESERT, [ [ Biome.DESERT, [
MysteryEncounterType.DANCING_LESSONS MysteryEncounterType.DANCING_LESSONS
]], ]],
[Biome.ICE_CAVE, []], [ Biome.ICE_CAVE, []],
[Biome.MEADOW, []], [ Biome.MEADOW, []],
[Biome.POWER_PLANT, []], [ Biome.POWER_PLANT, []],
[Biome.VOLCANO, [ [ Biome.VOLCANO, [
MysteryEncounterType.FIERY_FALLOUT, MysteryEncounterType.FIERY_FALLOUT,
MysteryEncounterType.DANCING_LESSONS MysteryEncounterType.DANCING_LESSONS
]], ]],
[Biome.GRAVEYARD, []], [ Biome.GRAVEYARD, []],
[Biome.DOJO, []], [ Biome.DOJO, []],
[Biome.FACTORY, []], [ Biome.FACTORY, []],
[Biome.RUINS, []], [ Biome.RUINS, []],
[Biome.WASTELAND, [ [ Biome.WASTELAND, [
MysteryEncounterType.DANCING_LESSONS MysteryEncounterType.DANCING_LESSONS
]], ]],
[Biome.ABYSS, [ [ Biome.ABYSS, [
MysteryEncounterType.DANCING_LESSONS MysteryEncounterType.DANCING_LESSONS
]], ]],
[Biome.SPACE, [ [ Biome.SPACE, [
MysteryEncounterType.THE_EXPERT_POKEMON_BREEDER MysteryEncounterType.THE_EXPERT_POKEMON_BREEDER
]], ]],
[Biome.CONSTRUCTION_SITE, []], [ Biome.CONSTRUCTION_SITE, []],
[Biome.JUNGLE, [ [ Biome.JUNGLE, [
MysteryEncounterType.SAFARI_ZONE MysteryEncounterType.SAFARI_ZONE
]], ]],
[Biome.FAIRY_CAVE, []], [ Biome.FAIRY_CAVE, []],
[Biome.TEMPLE, []], [ Biome.TEMPLE, []],
[Biome.SLUM, []], [ Biome.SLUM, []],
[Biome.SNOWY_FOREST, []], [ Biome.SNOWY_FOREST, []],
[Biome.ISLAND, []], [ Biome.ISLAND, []],
[Biome.LABORATORY, []] [ Biome.LABORATORY, []]
]); ]);
export function initMysteryEncounters() { export function initMysteryEncounters() {
@ -363,6 +363,7 @@ export function initMysteryEncounters() {
}); });
// Add ANY biome encounters to biome map // Add ANY biome encounters to biome map
// eslint-disable-next-line
let encounterBiomeTableLog = ""; let encounterBiomeTableLog = "";
mysteryEncountersByBiome.forEach((biomeEncounters, biome) => { mysteryEncountersByBiome.forEach((biomeEncounters, biome) => {
anyBiomeEncounters.forEach(encounter => { anyBiomeEncounters.forEach(encounter => {
@ -374,5 +375,5 @@ export function initMysteryEncounters() {
encounterBiomeTableLog += `${getBiomeName(biome).toUpperCase()}: [${biomeEncounters.map(type => MysteryEncounterType[type].toString().toLowerCase()).sort().join(", ")}]\n`; encounterBiomeTableLog += `${getBiomeName(biome).toUpperCase()}: [${biomeEncounters.map(type => MysteryEncounterType[type].toString().toLowerCase()).sort().join(", ")}]\n`;
}); });
console.debug("All Mystery Encounters by Biome:\n" + encounterBiomeTableLog); //console.debug("All Mystery Encounters by Biome:\n" + encounterBiomeTableLog);
} }

View File

@ -28,7 +28,7 @@ export class CanLearnMoveRequirement extends EncounterPokemonRequirement {
constructor(requiredMoves: Moves | Moves[], options: CanLearnMoveRequirementOptions = {}) { constructor(requiredMoves: Moves | Moves[], options: CanLearnMoveRequirementOptions = {}) {
super(); super();
this.requiredMoves = Array.isArray(requiredMoves) ? requiredMoves : [requiredMoves]; this.requiredMoves = Array.isArray(requiredMoves) ? requiredMoves : [ requiredMoves ];
this.excludeLevelMoves = options.excludeLevelMoves ?? false; this.excludeLevelMoves = options.excludeLevelMoves ?? false;
this.excludeTmMoves = options.excludeTmMoves ?? false; this.excludeTmMoves = options.excludeTmMoves ?? false;
@ -64,11 +64,11 @@ export class CanLearnMoveRequirement extends EncounterPokemonRequirement {
} }
override getDialogueToken(_scene: BattleScene, _pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(_scene: BattleScene, _pokemon?: PlayerPokemon): [string, string] {
return ["requiredMoves", this.requiredMoves.map(m => new PokemonMove(m).getName()).join(", ")]; return [ "requiredMoves", this.requiredMoves.map(m => new PokemonMove(m).getName()).join(", ") ];
} }
private getPokemonLevelMoves(pkm: PlayerPokemon): Moves[] { private getPokemonLevelMoves(pkm: PlayerPokemon): Moves[] {
return pkm.getLevelMoves().map(([_level, move]) => move); return pkm.getLevelMoves().map(([ _level, move ]) => move);
} }
private getAllPokemonMoves(pkm: PlayerPokemon): Moves[] { private getAllPokemonMoves(pkm: PlayerPokemon): Moves[] {

View File

@ -1,5 +1,5 @@
import Battle, { BattlerIndex, BattleType } from "#app/battle"; import Battle, { BattlerIndex, BattleType } from "#app/battle";
import { biomeLinks, BiomePoolTier } from "#app/data/biomes"; import { biomeLinks, BiomePoolTier } from "#app/data/balance/biomes";
import MysteryEncounterOption from "#app/data/mystery-encounters/mystery-encounter-option"; import MysteryEncounterOption from "#app/data/mystery-encounters/mystery-encounter-option";
import { AVERAGE_ENCOUNTERS_PER_RUN_TARGET, WEIGHT_INCREMENT_ON_SPAWN_MISS } from "#app/data/mystery-encounters/mystery-encounters"; import { AVERAGE_ENCOUNTERS_PER_RUN_TARGET, WEIGHT_INCREMENT_ON_SPAWN_MISS } from "#app/data/mystery-encounters/mystery-encounters";
import { showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
@ -373,7 +373,7 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig:
* @param moves * @param moves
*/ */
export function loadCustomMovesForEncounter(scene: BattleScene, moves: Moves | Moves[]) { export function loadCustomMovesForEncounter(scene: BattleScene, moves: Moves | Moves[]) {
moves = Array.isArray(moves) ? moves : [moves]; moves = Array.isArray(moves) ? moves : [ moves ];
return Promise.all(moves.map(move => initMoveAnim(scene, move))) return Promise.all(moves.map(move => initMoveAnim(scene, move)))
.then(() => loadMoveAnimAssets(scene, moves)); .then(() => loadMoveAnimAssets(scene, moves));
} }
@ -663,7 +663,7 @@ export function setEncounterRewards(scene: BattleScene, customShopRewards?: Cust
* @param useWaveIndex - set to false when directly passing the the full exp value instead of baseExpValue * @param useWaveIndex - set to false when directly passing the the full exp value instead of baseExpValue
*/ */
export function setEncounterExp(scene: BattleScene, participantId: number | number[], baseExpValue: number, useWaveIndex: boolean = true) { export function setEncounterExp(scene: BattleScene, participantId: number | number[], baseExpValue: number, useWaveIndex: boolean = true) {
const participantIds = Array.isArray(participantId) ? participantId : [participantId]; const participantIds = Array.isArray(participantId) ? participantId : [ participantId ];
scene.currentBattle.mysteryEncounter!.doEncounterExp = (scene: BattleScene) => { scene.currentBattle.mysteryEncounter!.doEncounterExp = (scene: BattleScene) => {
scene.unshiftPhase(new PartyExpPhase(scene, baseExpValue, useWaveIndex, new Set(participantIds))); scene.unshiftPhase(new PartyExpPhase(scene, baseExpValue, useWaveIndex, new Set(participantIds)));
@ -800,8 +800,8 @@ export function transitionMysteryEncounterIntroVisuals(scene: BattleScene, hide:
// Transition // Transition
scene.tweens.add({ scene.tweens.add({
targets: [introVisuals, enemyPokemon], targets: [ introVisuals, enemyPokemon ],
x: `${hide? "+" : "-"}=16`, x: `${hide ? "+" : "-"}=16`,
y: `${hide ? "-" : "+"}=16`, y: `${hide ? "-" : "+"}=16`,
alpha: hide ? 0 : 1, alpha: hide ? 0 : 1,
ease: "Sine.easeInOut", ease: "Sine.easeInOut",
@ -888,14 +888,14 @@ export function calculateMEAggregateStats(scene: BattleScene, baseSpawnWeight: n
const numRuns = 1000; const numRuns = 1000;
let run = 0; let run = 0;
const biomes = Object.keys(Biome).filter(key => isNaN(Number(key))); const biomes = Object.keys(Biome).filter(key => isNaN(Number(key)));
const alwaysPickTheseBiomes = [Biome.ISLAND, Biome.ABYSS, Biome.WASTELAND, Biome.FAIRY_CAVE, Biome.TEMPLE, Biome.LABORATORY, Biome.SPACE, Biome.WASTELAND]; const alwaysPickTheseBiomes = [ Biome.ISLAND, Biome.ABYSS, Biome.WASTELAND, Biome.FAIRY_CAVE, Biome.TEMPLE, Biome.LABORATORY, Biome.SPACE, Biome.WASTELAND ];
const calculateNumEncounters = (): any[] => { const calculateNumEncounters = (): any[] => {
let encounterRate = baseSpawnWeight; // BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT let encounterRate = baseSpawnWeight; // BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT
const numEncounters = [0, 0, 0, 0]; const numEncounters = [ 0, 0, 0, 0 ];
let mostRecentEncounterWave = 0; let mostRecentEncounterWave = 0;
const encountersByBiome = new Map<string, number>(biomes.map(b => [b, 0])); const encountersByBiome = new Map<string, number>(biomes.map(b => [ b, 0 ]));
const validMEfloorsByBiome = new Map<string, number>(biomes.map(b => [b, 0])); const validMEfloorsByBiome = new Map<string, number>(biomes.map(b => [ b, 0 ]));
let currentBiome = Biome.TOWN; let currentBiome = Biome.TOWN;
let currentArena = scene.newArena(currentBiome); let currentArena = scene.newArena(currentBiome);
scene.setSeed(Utils.randomString(24)); scene.setSeed(Utils.randomString(24));
@ -968,7 +968,7 @@ export function calculateMEAggregateStats(scene: BattleScene, baseSpawnWeight: n
// Calculate encounter rarity // Calculate encounter rarity
// Common / Uncommon / Rare / Super Rare (base is out of 128) // Common / Uncommon / Rare / Super Rare (base is out of 128)
const tierWeights = [66, 40, 19, 3]; const tierWeights = [ 66, 40, 19, 3 ];
// Adjust tier weights by currently encountered events (pity system that lowers odds of multiple Common/Great) // Adjust tier weights by currently encountered events (pity system that lowers odds of multiple Common/Great)
tierWeights[0] = tierWeights[0] - 6 * numEncounters[0]; tierWeights[0] = tierWeights[0] - 6 * numEncounters[0];
@ -987,7 +987,7 @@ export function calculateMEAggregateStats(scene: BattleScene, baseSpawnWeight: n
} }
} }
return [numEncounters, encountersByBiome, validMEfloorsByBiome]; return [ numEncounters, encountersByBiome, validMEfloorsByBiome ];
}; };
const encounterRuns: number[][] = []; const encounterRuns: number[][] = [];
@ -995,7 +995,7 @@ export function calculateMEAggregateStats(scene: BattleScene, baseSpawnWeight: n
const validFloorsByBiome: Map<string, number>[] = []; const validFloorsByBiome: Map<string, number>[] = [];
while (run < numRuns) { while (run < numRuns) {
scene.executeWithSeedOffset(() => { scene.executeWithSeedOffset(() => {
const [numEncounters, encountersByBiome, validMEfloorsByBiome] = calculateNumEncounters(); const [ numEncounters, encountersByBiome, validMEfloorsByBiome ] = calculateNumEncounters();
encounterRuns.push(numEncounters); encounterRuns.push(numEncounters);
encountersByBiomeRuns.push(encountersByBiome); encountersByBiomeRuns.push(encountersByBiome);
validFloorsByBiome.push(validMEfloorsByBiome); validFloorsByBiome.push(validMEfloorsByBiome);
@ -1036,7 +1036,7 @@ export function calculateMEAggregateStats(scene: BattleScene, baseSpawnWeight: n
let stats = `Starting weight: ${baseSpawnWeight}\nAverage MEs per run: ${totalMean}\nStandard Deviation: ${totalStd}\nAvg Commons: ${commonMean}\nAvg Greats: ${uncommonMean}\nAvg Ultras: ${rareMean}\nAvg Rogues: ${superRareMean}\n`; let stats = `Starting weight: ${baseSpawnWeight}\nAverage MEs per run: ${totalMean}\nStandard Deviation: ${totalStd}\nAvg Commons: ${commonMean}\nAvg Greats: ${uncommonMean}\nAvg Ultras: ${rareMean}\nAvg Rogues: ${superRareMean}\n`;
const meanEncountersPerRunPerBiomeSorted = [...meanEncountersPerRunPerBiome.entries()].sort((e1, e2) => e2[1] - e1[1]); const meanEncountersPerRunPerBiomeSorted = [ ...meanEncountersPerRunPerBiome.entries() ].sort((e1, e2) => e2[1] - e1[1]);
meanEncountersPerRunPerBiomeSorted.forEach(value => stats = stats + `${value[0]}: avg valid floors ${meanMEFloorsPerRunPerBiome.get(value[0])}, avg MEs ${value[1]},\n`); meanEncountersPerRunPerBiomeSorted.forEach(value => stats = stats + `${value[0]}: avg valid floors ${meanMEFloorsPerRunPerBiome.get(value[0])}, avg MEs ${value[1]},\n`);
console.log(stats); console.log(stats);
@ -1054,7 +1054,7 @@ export function calculateRareSpawnAggregateStats(scene: BattleScene, luckValue:
let run = 0; let run = 0;
const calculateNumRareEncounters = (): any[] => { const calculateNumRareEncounters = (): any[] => {
const bossEncountersByRarity = [0, 0, 0, 0]; const bossEncountersByRarity = [ 0, 0, 0, 0 ];
scene.setSeed(Utils.randomString(24)); scene.setSeed(Utils.randomString(24));
scene.resetSeed(); scene.resetSeed();
// There are 12 wild boss floors // There are 12 wild boss floors

View File

@ -12,7 +12,8 @@ import { Mode } from "#app/ui/ui";
import { PartyOption, PartyUiMode } from "#app/ui/party-ui-handler"; import { PartyOption, PartyUiMode } from "#app/ui/party-ui-handler";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import { Type } from "#app/data/type"; import { Type } from "#app/data/type";
import PokemonSpecies, { getPokemonSpecies, speciesStarters } from "#app/data/pokemon-species"; import PokemonSpecies, { getPokemonSpecies } from "#app/data/pokemon-species";
import { speciesStarterCosts } from "#app/data/balance/starters";
import { getEncounterText, queueEncounterMessage, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { getEncounterText, queueEncounterMessage, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import { modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type"; import { modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
@ -206,8 +207,8 @@ export function getRandomSpeciesByStarterTier(starterTiers: number | [number, nu
let min = Array.isArray(starterTiers) ? starterTiers[0] : starterTiers; let min = Array.isArray(starterTiers) ? starterTiers[0] : starterTiers;
let max = Array.isArray(starterTiers) ? starterTiers[1] : starterTiers; let max = Array.isArray(starterTiers) ? starterTiers[1] : starterTiers;
let filteredSpecies: [PokemonSpecies, number][] = Object.keys(speciesStarters) let filteredSpecies: [PokemonSpecies, number][] = Object.keys(speciesStarterCosts)
.map(s => [parseInt(s) as Species, speciesStarters[s] as number]) .map(s => [ parseInt(s) as Species, speciesStarterCosts[s] as number ])
.filter(s => { .filter(s => {
const pokemonSpecies = getPokemonSpecies(s[0]); const pokemonSpecies = getPokemonSpecies(s[0]);
return pokemonSpecies && (!excludedSpecies || !excludedSpecies.includes(s[0])) return pokemonSpecies && (!excludedSpecies || !excludedSpecies.includes(s[0]))
@ -215,7 +216,7 @@ export function getRandomSpeciesByStarterTier(starterTiers: number | [number, nu
&& (allowLegendary || !pokemonSpecies.legendary) && (allowLegendary || !pokemonSpecies.legendary)
&& (allowMythical || !pokemonSpecies.mythical); && (allowMythical || !pokemonSpecies.mythical);
}) })
.map(s => [getPokemonSpecies(s[0]), s[1]]); .map(s => [ getPokemonSpecies(s[0]), s[1] ]);
if (types && types.length > 0) { if (types && types.length > 0) {
filteredSpecies = filteredSpecies.filter(s => types.includes(s[0].type1) || (!isNullOrUndefined(s[0].type2) && types.includes(s[0].type2))); filteredSpecies = filteredSpecies.filter(s => types.includes(s[0].type1) || (!isNullOrUndefined(s[0].type2) && types.includes(s[0].type2)));
@ -224,7 +225,7 @@ export function getRandomSpeciesByStarterTier(starterTiers: number | [number, nu
// If no filtered mons exist at specified starter tiers, will expand starter search range until there are // If no filtered mons exist at specified starter tiers, will expand starter search range until there are
// Starts by decrementing starter tier min until it is 0, then increments tier max up to 10 // Starts by decrementing starter tier min until it is 0, then increments tier max up to 10
let tryFilterStarterTiers: [PokemonSpecies, number][] = filteredSpecies.filter(s => (s[1] >= min && s[1] <= max)); let tryFilterStarterTiers: [PokemonSpecies, number][] = filteredSpecies.filter(s => (s[1] >= min && s[1] <= max));
while (tryFilterStarterTiers.length === 0 && (min !== 0 && max !== 10)) { while (tryFilterStarterTiers.length === 0 && !(min === 0 && max === 10)) {
if (min > 0) { if (min > 0) {
min--; min--;
} else { } else {
@ -312,7 +313,7 @@ export function applyHealToPokemon(scene: BattleScene, pokemon: PlayerPokemon, h
*/ */
export async function modifyPlayerPokemonBST(pokemon: PlayerPokemon, value: number) { export async function modifyPlayerPokemonBST(pokemon: PlayerPokemon, value: number) {
const modType = modifierTypes.MYSTERY_ENCOUNTER_SHUCKLE_JUICE() const modType = modifierTypes.MYSTERY_ENCOUNTER_SHUCKLE_JUICE()
.generateType(pokemon.scene.getParty(), [value]) .generateType(pokemon.scene.getParty(), [ value ])
?.withIdFromFunc(modifierTypes.MYSTERY_ENCOUNTER_SHUCKLE_JUICE); ?.withIdFromFunc(modifierTypes.MYSTERY_ENCOUNTER_SHUCKLE_JUICE);
const modifier = modType?.newModifier(pokemon); const modifier = modType?.newModifier(pokemon);
if (modifier) { if (modifier) {
@ -601,7 +602,7 @@ export async function catchPokemon(scene: BattleScene, pokemon: EnemyPokemon, po
} }
}); });
}; };
Promise.all([pokemon.hideInfo(), scene.gameData.setPokemonCaught(pokemon)]).then(() => { Promise.all([ pokemon.hideInfo(), scene.gameData.setPokemonCaught(pokemon) ]).then(() => {
if (scene.getParty().length === 6) { if (scene.getParty().length === 6) {
const promptRelease = () => { const promptRelease = () => {
scene.ui.showText(i18next.t("battle:partyFull", { pokemonName: pokemon.getNameToRender() }), null, () => { scene.ui.showText(i18next.t("battle:partyFull", { pokemonName: pokemon.getNameToRender() }), null, () => {
@ -727,33 +728,33 @@ export function doPlayerFlee(scene: BattleScene, pokemon: EnemyPokemon): Promise
* Bug Species and their corresponding weights * Bug Species and their corresponding weights
*/ */
const GOLDEN_BUG_NET_SPECIES_POOL: [Species, number][] = [ const GOLDEN_BUG_NET_SPECIES_POOL: [Species, number][] = [
[Species.SCYTHER, 40], [ Species.SCYTHER, 40 ],
[Species.SCIZOR, 40], [ Species.SCIZOR, 40 ],
[Species.KLEAVOR, 40], [ Species.KLEAVOR, 40 ],
[Species.PINSIR, 40], [ Species.PINSIR, 40 ],
[Species.HERACROSS, 40], [ Species.HERACROSS, 40 ],
[Species.YANMA, 40], [ Species.YANMA, 40 ],
[Species.YANMEGA, 40], [ Species.YANMEGA, 40 ],
[Species.SHUCKLE, 40], [ Species.SHUCKLE, 40 ],
[Species.ANORITH, 40], [ Species.ANORITH, 40 ],
[Species.ARMALDO, 40], [ Species.ARMALDO, 40 ],
[Species.ESCAVALIER, 40], [ Species.ESCAVALIER, 40 ],
[Species.ACCELGOR, 40], [ Species.ACCELGOR, 40 ],
[Species.JOLTIK, 40], [ Species.JOLTIK, 40 ],
[Species.GALVANTULA, 40], [ Species.GALVANTULA, 40 ],
[Species.DURANT, 40], [ Species.DURANT, 40 ],
[Species.LARVESTA, 40], [ Species.LARVESTA, 40 ],
[Species.VOLCARONA, 40], [ Species.VOLCARONA, 40 ],
[Species.DEWPIDER, 40], [ Species.DEWPIDER, 40 ],
[Species.ARAQUANID, 40], [ Species.ARAQUANID, 40 ],
[Species.WIMPOD, 40], [ Species.WIMPOD, 40 ],
[Species.GOLISOPOD, 40], [ Species.GOLISOPOD, 40 ],
[Species.SIZZLIPEDE, 40], [ Species.SIZZLIPEDE, 40 ],
[Species.CENTISKORCH, 40], [ Species.CENTISKORCH, 40 ],
[Species.NYMBLE, 40], [ Species.NYMBLE, 40 ],
[Species.LOKIX, 40], [ Species.LOKIX, 40 ],
[Species.BUZZWOLE, 1], [ Species.BUZZWOLE, 1 ],
[Species.PHEROMOSA, 1], [ Species.PHEROMOSA, 1 ],
]; ];
/** /**

View File

@ -1,10 +1,9 @@
import { PokemonFormChangeItemModifier, TerastallizeModifier } from "../modifier/modifier"; import { PokemonFormChangeItemModifier, TerastallizeModifier } from "../modifier/modifier";
import Pokemon from "../field/pokemon"; import Pokemon from "../field/pokemon";
import { SpeciesFormKey } from "./pokemon-species";
import { StatusEffect } from "./status-effect"; import { StatusEffect } from "./status-effect";
import { MoveCategory, allMoves } from "./move"; import { MoveCategory, allMoves } from "./move";
import { Type } from "./type"; import { Type } from "./type";
import { Constructor } from "#app/utils"; import { Constructor, nil } from "#app/utils";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
@ -13,6 +12,7 @@ import { getPokemonNameWithAffix } from "#app/messages";
import i18next from "i18next"; import i18next from "i18next";
import { WeatherType } from "./weather"; import { WeatherType } from "./weather";
import { Challenges } from "#app/enums/challenges"; import { Challenges } from "#app/enums/challenges";
import { SpeciesFormKey } from "#enums/species-form-key";
export enum FormChangeItem { export enum FormChangeItem {
NONE, NONE,
@ -185,7 +185,7 @@ export class SpeciesFormChange {
return true; return true;
} }
findTrigger(triggerType: Constructor<SpeciesFormChangeTrigger>): SpeciesFormChangeTrigger | null { findTrigger(triggerType: Constructor<SpeciesFormChangeTrigger>): SpeciesFormChangeTrigger | nil {
if (!this.trigger.hasTriggerType(triggerType)) { if (!this.trigger.hasTriggerType(triggerType)) {
return null; return null;
} }
@ -193,7 +193,7 @@ export class SpeciesFormChange {
const trigger = this.trigger; const trigger = this.trigger;
if (trigger instanceof SpeciesFormChangeCompoundTrigger) { if (trigger instanceof SpeciesFormChangeCompoundTrigger) {
return trigger.triggers.find(t => t.hasTriggerType(triggerType))!; // TODO: is this bang correct? return trigger.triggers.find(t => t.hasTriggerType(triggerType));
} }
return trigger; return trigger;
@ -202,11 +202,11 @@ export class SpeciesFormChange {
export class SpeciesFormChangeCondition { export class SpeciesFormChangeCondition {
public predicate: SpeciesFormChangeConditionPredicate; public predicate: SpeciesFormChangeConditionPredicate;
public enforceFunc: SpeciesFormChangeConditionEnforceFunc | null; public enforceFunc: SpeciesFormChangeConditionEnforceFunc | nil;
constructor(predicate: SpeciesFormChangeConditionPredicate, enforceFunc?: SpeciesFormChangeConditionEnforceFunc) { constructor(predicate: SpeciesFormChangeConditionPredicate, enforceFunc?: SpeciesFormChangeConditionEnforceFunc) {
this.predicate = predicate; this.predicate = predicate;
this.enforceFunc = enforceFunc!; // TODO: is this bang correct? this.enforceFunc = enforceFunc;
} }
} }
@ -640,18 +640,18 @@ export const pokemonFormChanges: PokemonFormChanges = {
new SpeciesFormChange(Species.ALTARIA, "", SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.ALTARIANITE)) new SpeciesFormChange(Species.ALTARIA, "", SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.ALTARIANITE))
], ],
[Species.CASTFORM]: [ [Species.CASTFORM]: [
new SpeciesFormChange(Species.CASTFORM, "", "sunny", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [WeatherType.SUNNY, WeatherType.HARSH_SUN]), true), new SpeciesFormChange(Species.CASTFORM, "", "sunny", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [ WeatherType.SUNNY, WeatherType.HARSH_SUN ]), true),
new SpeciesFormChange(Species.CASTFORM, "rainy", "sunny", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [WeatherType.SUNNY, WeatherType.HARSH_SUN]), true), new SpeciesFormChange(Species.CASTFORM, "rainy", "sunny", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [ WeatherType.SUNNY, WeatherType.HARSH_SUN ]), true),
new SpeciesFormChange(Species.CASTFORM, "snowy", "sunny", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [WeatherType.SUNNY, WeatherType.HARSH_SUN]), true), new SpeciesFormChange(Species.CASTFORM, "snowy", "sunny", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [ WeatherType.SUNNY, WeatherType.HARSH_SUN ]), true),
new SpeciesFormChange(Species.CASTFORM, "", "rainy", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [WeatherType.RAIN, WeatherType.HEAVY_RAIN]), true), new SpeciesFormChange(Species.CASTFORM, "", "rainy", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [ WeatherType.RAIN, WeatherType.HEAVY_RAIN ]), true),
new SpeciesFormChange(Species.CASTFORM, "sunny", "rainy", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [WeatherType.RAIN, WeatherType.HEAVY_RAIN]), true), new SpeciesFormChange(Species.CASTFORM, "sunny", "rainy", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [ WeatherType.RAIN, WeatherType.HEAVY_RAIN ]), true),
new SpeciesFormChange(Species.CASTFORM, "snowy", "rainy", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [WeatherType.RAIN, WeatherType.HEAVY_RAIN]), true), new SpeciesFormChange(Species.CASTFORM, "snowy", "rainy", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [ WeatherType.RAIN, WeatherType.HEAVY_RAIN ]), true),
new SpeciesFormChange(Species.CASTFORM, "", "snowy", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [WeatherType.HAIL, WeatherType.SNOW]), true), new SpeciesFormChange(Species.CASTFORM, "", "snowy", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [ WeatherType.HAIL, WeatherType.SNOW ]), true),
new SpeciesFormChange(Species.CASTFORM, "sunny", "snowy", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [WeatherType.HAIL, WeatherType.SNOW]), true), new SpeciesFormChange(Species.CASTFORM, "sunny", "snowy", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [ WeatherType.HAIL, WeatherType.SNOW ]), true),
new SpeciesFormChange(Species.CASTFORM, "rainy", "snowy", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [WeatherType.HAIL, WeatherType.SNOW]), true), new SpeciesFormChange(Species.CASTFORM, "rainy", "snowy", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [ WeatherType.HAIL, WeatherType.SNOW ]), true),
new SpeciesFormChange(Species.CASTFORM, "sunny", "", new SpeciesFormChangeRevertWeatherFormTrigger(Abilities.FORECAST, [WeatherType.NONE, WeatherType.SANDSTORM, WeatherType.STRONG_WINDS, WeatherType.FOG]), true), new SpeciesFormChange(Species.CASTFORM, "sunny", "", new SpeciesFormChangeRevertWeatherFormTrigger(Abilities.FORECAST, [ WeatherType.NONE, WeatherType.SANDSTORM, WeatherType.STRONG_WINDS, WeatherType.FOG ]), true),
new SpeciesFormChange(Species.CASTFORM, "rainy", "", new SpeciesFormChangeRevertWeatherFormTrigger(Abilities.FORECAST, [WeatherType.NONE, WeatherType.SANDSTORM, WeatherType.STRONG_WINDS, WeatherType.FOG]), true), new SpeciesFormChange(Species.CASTFORM, "rainy", "", new SpeciesFormChangeRevertWeatherFormTrigger(Abilities.FORECAST, [ WeatherType.NONE, WeatherType.SANDSTORM, WeatherType.STRONG_WINDS, WeatherType.FOG ]), true),
new SpeciesFormChange(Species.CASTFORM, "snowy", "", new SpeciesFormChangeRevertWeatherFormTrigger(Abilities.FORECAST, [WeatherType.NONE, WeatherType.SANDSTORM, WeatherType.STRONG_WINDS, WeatherType.FOG]), true), new SpeciesFormChange(Species.CASTFORM, "snowy", "", new SpeciesFormChangeRevertWeatherFormTrigger(Abilities.FORECAST, [ WeatherType.NONE, WeatherType.SANDSTORM, WeatherType.STRONG_WINDS, WeatherType.FOG ]), true),
new SpeciesFormChange(Species.CASTFORM, "sunny", "", new SpeciesFormChangeActiveTrigger(), true), new SpeciesFormChange(Species.CASTFORM, "sunny", "", new SpeciesFormChangeActiveTrigger(), true),
new SpeciesFormChange(Species.CASTFORM, "rainy", "", new SpeciesFormChangeActiveTrigger(), true), new SpeciesFormChange(Species.CASTFORM, "rainy", "", new SpeciesFormChangeActiveTrigger(), true),
new SpeciesFormChange(Species.CASTFORM, "snowy", "", new SpeciesFormChangeActiveTrigger(), true) new SpeciesFormChange(Species.CASTFORM, "snowy", "", new SpeciesFormChangeActiveTrigger(), true)

File diff suppressed because it is too large Load Diff

View File

@ -185,26 +185,26 @@ const seasonalSplashMessages: Season[] = [
name: "Halloween", name: "Halloween",
start: "09-15", start: "09-15",
end: "10-31", end: "10-31",
messages: ["halloween.pumpkabooAbout", "halloween.mayContainSpiders", "halloween.spookyScarySkeledirge", "halloween.gourgeistUsedTrickOrTreat", "halloween.letsSnuggleForever"], messages: [ "halloween.pumpkabooAbout", "halloween.mayContainSpiders", "halloween.spookyScarySkeledirge", "halloween.gourgeistUsedTrickOrTreat", "halloween.letsSnuggleForever" ],
}, },
{ {
name: "XMAS", name: "XMAS",
start: "12-01", start: "12-01",
end: "12-26", end: "12-26",
messages: ["xmas.happyHolidays", "xmas.unaffilicatedWithDelibirdServices", "xmas.delibirdSeason", "xmas.diamondsFromTheSky", "xmas.holidayStylePikachuNotIncluded"], messages: [ "xmas.happyHolidays", "xmas.unaffilicatedWithDelibirdServices", "xmas.delibirdSeason", "xmas.diamondsFromTheSky", "xmas.holidayStylePikachuNotIncluded" ],
}, },
{ {
name: "New Year's", name: "New Year's",
start: "01-01", start: "01-01",
end: "01-31", end: "01-31",
messages: ["newYears.happyNewYear"], messages: [ "newYears.happyNewYear" ],
}, },
]; ];
//#endregion //#endregion
export function getSplashMessages(): string[] { export function getSplashMessages(): string[] {
const splashMessages: string[] = [...commonSplashMessages]; const splashMessages: string[] = [ ...commonSplashMessages ];
console.log("use seasonal splash messages", USE_SEASONAL_SPLASH_MESSAGES); console.log("use seasonal splash messages", USE_SEASONAL_SPLASH_MESSAGES);
if (USE_SEASONAL_SPLASH_MESSAGES) { if (USE_SEASONAL_SPLASH_MESSAGES) {
// add seasonal splash messages if the season is active // add seasonal splash messages if the season is active

File diff suppressed because it is too large Load Diff

View File

@ -75,56 +75,56 @@ const trainerNameConfigs: TrainerNameConfigs = {
}; };
export const trainerNamePools = { export const trainerNamePools = {
[TrainerType.ACE_TRAINER]: [["Aaron", "Allen", "Blake", "Brian", "Gaven", "Jake", "Kevin", "Mike", "Nick", "Paul", "Ryan", "Sean", "Darin", "Albert", "Berke", "Clyde", "Edgar", "George", "Leroy", "Owen", "Parker", "Randall", "Ruben", "Samuel", "Vincent", "Warren", "Wilton", "Zane", "Alfred", "Braxton", "Felix", "Gerald", "Jonathan", "Leonel", "Marcel", "Mitchell", "Quincy", "Roderick", "Colby", "Rolando", "Yuji", "Abel", "Anton", "Arthur", "Cesar", "Dalton", "Dennis", "Ernest", "Garrett", "Graham", "Henry", "Isaiah", "Jonah", "Jose", "Keenan", "Micah", "Omar", "Quinn", "Rodolfo", "Saul", "Sergio", "Skylar", "Stefan", "Zachery", "Alton", "Arabella", "Bonita", "Cal", "Cody", "French", "Kobe", "Paulo", "Shaye", "Austin", "Beckett", "Charlie", "Corky", "David", "Dwayne", "Elmer", "Jesse", "Jared", "Johan", "Jordan", "Kipp", "Lou", "Terry", "Tom", "Webster", "Billy", "Doyle", "Enzio", "Geoff", "Grant", "Kelsey", "Miguel", "Pierce", "Ray", "Santino", "Shel", "Adelbert", "Bence", "Emil", "Evan", "Mathis", "Maxim", "Neil", "Rico", "Robbie", "Theo", "Viktor", "Benedict", "Cornelius", "Hisato", "Leopold", "Neville", "Vito", "Chase", "Cole", "Hiroshi", "Jackson", "Jim", "Kekoa", "Makana", "Yuki", "Elwood", "Seth", "Alvin", "Arjun", "Arnold", "Cameron", "Carl", "Carlton", "Christopher", "Dave", "Dax", "Dominic", "Edmund", "Finn", "Fred", "Garret", "Grayson", "Jace", "Jaxson", "Jay", "Jirard", "Johnson", "Kayden", "Kite", "Louis", "Mac", "Marty", "Percy", "Raymond", "Ronnie", "Satch", "Tim", "Zach", "Conner", "Vince", "Bedro", "Boda", "Botan", "Daras", "Dury", "Herton", "Rewn", "Stum", "Tock", "Trilo", "Berki", "Cruik", "Dazon", "Desid", "Dillot", "Farfin", "Forgon", "Hebel", "Morfon", "Moril", "Shadd", "Vanhub", "Bardo", "Carben", "Degin", "Gorps", "Klept", "Lask", "Malex", "Mopar", "Niled", "Noxon", "Teslor", "Tetil"], ["Beth", "Carol", "Cybil", "Emma", "Fran", "Gwen", "Irene", "Jenn", "Joyce", "Kate", "Kelly", "Lois", "Lola", "Megan", "Quinn", "Reena", "Cara", "Alexa", "Brooke", "Caroline", "Elaine", "Hope", "Jennifer", "Jody", "Julie", "Lori", "Mary", "Michelle", "Shannon", "Wendy", "Alexia", "Alicia", "Athena", "Carolina", "Cristin", "Darcy", "Dianne", "Halle", "Jazmyn", "Katelynn", "Keira", "Marley", "Allyson", "Kathleen", "Naomi", "Alyssa", "Ariana", "Brandi", "Breanna", "Brenda", "Brenna", "Catherine", "Clarice", "Dana", "Deanna", "Destiny", "Jamie", "Jasmin", "Kassandra", "Laura", "Maria", "Mariah", "Maya", "Meagan", "Mikayla", "Monique", "Natasha", "Olivia", "Sandra", "Savannah", "Sydney", "Moira", "Piper", "Salma", "Allison", "Beverly", "Cathy", "Cheyenne", "Clara", "Dara", "Eileen", "Glinda", "Junko", "Lena", "Lucille", "Mariana", "Olwen", "Shanta", "Stella", "Angi", "Belle", "Chandra", "Cora", "Eve", "Jacqueline", "Jeanne", "Juliet", "Kathrine", "Layla", "Lucca", "Melina", "Miki", "Nina", "Sable", "Shelly", "Summer", "Trish", "Vicki", "Alanza", "Cordelia", "Hilde", "Imelda", "Michele", "Mireille", "Claudia", "Constance", "Harriet", "Honor", "Melba", "Portia", "Alexis", "Angela", "Karla", "Lindsey", "Tori", "Sheri", "Jada", "Kailee", "Amanda", "Annie", "Kindra", "Kyla", "Sofia", "Yvette", "Becky", "Flora", "Gloria", "Buna", "Ferda", "Lehan", "Liqui", "Lomen", "Neira", "Atilo", "Detta", "Gilly", "Gosney", "Levens", "Moden", "Rask", "Rateis", "Rosno", "Tynan", "Veron", "Zoel", "Cida", "Dibsin", "Dodin", "Ebson", "Equin", "Flostin", "Gabsen", "Halsion", "Hileon", "Quelor", "Rapeel", "Roze", "Tensin"]], [TrainerType.ACE_TRAINER]: [[ "Aaron", "Allen", "Blake", "Brian", "Gaven", "Jake", "Kevin", "Mike", "Nick", "Paul", "Ryan", "Sean", "Darin", "Albert", "Berke", "Clyde", "Edgar", "George", "Leroy", "Owen", "Parker", "Randall", "Ruben", "Samuel", "Vincent", "Warren", "Wilton", "Zane", "Alfred", "Braxton", "Felix", "Gerald", "Jonathan", "Leonel", "Marcel", "Mitchell", "Quincy", "Roderick", "Colby", "Rolando", "Yuji", "Abel", "Anton", "Arthur", "Cesar", "Dalton", "Dennis", "Ernest", "Garrett", "Graham", "Henry", "Isaiah", "Jonah", "Jose", "Keenan", "Micah", "Omar", "Quinn", "Rodolfo", "Saul", "Sergio", "Skylar", "Stefan", "Zachery", "Alton", "Arabella", "Bonita", "Cal", "Cody", "French", "Kobe", "Paulo", "Shaye", "Austin", "Beckett", "Charlie", "Corky", "David", "Dwayne", "Elmer", "Jesse", "Jared", "Johan", "Jordan", "Kipp", "Lou", "Terry", "Tom", "Webster", "Billy", "Doyle", "Enzio", "Geoff", "Grant", "Kelsey", "Miguel", "Pierce", "Ray", "Santino", "Shel", "Adelbert", "Bence", "Emil", "Evan", "Mathis", "Maxim", "Neil", "Rico", "Robbie", "Theo", "Viktor", "Benedict", "Cornelius", "Hisato", "Leopold", "Neville", "Vito", "Chase", "Cole", "Hiroshi", "Jackson", "Jim", "Kekoa", "Makana", "Yuki", "Elwood", "Seth", "Alvin", "Arjun", "Arnold", "Cameron", "Carl", "Carlton", "Christopher", "Dave", "Dax", "Dominic", "Edmund", "Finn", "Fred", "Garret", "Grayson", "Jace", "Jaxson", "Jay", "Jirard", "Johnson", "Kayden", "Kite", "Louis", "Mac", "Marty", "Percy", "Raymond", "Ronnie", "Satch", "Tim", "Zach", "Conner", "Vince", "Bedro", "Boda", "Botan", "Daras", "Dury", "Herton", "Rewn", "Stum", "Tock", "Trilo", "Berki", "Cruik", "Dazon", "Desid", "Dillot", "Farfin", "Forgon", "Hebel", "Morfon", "Moril", "Shadd", "Vanhub", "Bardo", "Carben", "Degin", "Gorps", "Klept", "Lask", "Malex", "Mopar", "Niled", "Noxon", "Teslor", "Tetil" ], [ "Beth", "Carol", "Cybil", "Emma", "Fran", "Gwen", "Irene", "Jenn", "Joyce", "Kate", "Kelly", "Lois", "Lola", "Megan", "Quinn", "Reena", "Cara", "Alexa", "Brooke", "Caroline", "Elaine", "Hope", "Jennifer", "Jody", "Julie", "Lori", "Mary", "Michelle", "Shannon", "Wendy", "Alexia", "Alicia", "Athena", "Carolina", "Cristin", "Darcy", "Dianne", "Halle", "Jazmyn", "Katelynn", "Keira", "Marley", "Allyson", "Kathleen", "Naomi", "Alyssa", "Ariana", "Brandi", "Breanna", "Brenda", "Brenna", "Catherine", "Clarice", "Dana", "Deanna", "Destiny", "Jamie", "Jasmin", "Kassandra", "Laura", "Maria", "Mariah", "Maya", "Meagan", "Mikayla", "Monique", "Natasha", "Olivia", "Sandra", "Savannah", "Sydney", "Moira", "Piper", "Salma", "Allison", "Beverly", "Cathy", "Cheyenne", "Clara", "Dara", "Eileen", "Glinda", "Junko", "Lena", "Lucille", "Mariana", "Olwen", "Shanta", "Stella", "Angi", "Belle", "Chandra", "Cora", "Eve", "Jacqueline", "Jeanne", "Juliet", "Kathrine", "Layla", "Lucca", "Melina", "Miki", "Nina", "Sable", "Shelly", "Summer", "Trish", "Vicki", "Alanza", "Cordelia", "Hilde", "Imelda", "Michele", "Mireille", "Claudia", "Constance", "Harriet", "Honor", "Melba", "Portia", "Alexis", "Angela", "Karla", "Lindsey", "Tori", "Sheri", "Jada", "Kailee", "Amanda", "Annie", "Kindra", "Kyla", "Sofia", "Yvette", "Becky", "Flora", "Gloria", "Buna", "Ferda", "Lehan", "Liqui", "Lomen", "Neira", "Atilo", "Detta", "Gilly", "Gosney", "Levens", "Moden", "Rask", "Rateis", "Rosno", "Tynan", "Veron", "Zoel", "Cida", "Dibsin", "Dodin", "Ebson", "Equin", "Flostin", "Gabsen", "Halsion", "Hileon", "Quelor", "Rapeel", "Roze", "Tensin" ]],
[TrainerType.ARTIST]: [["Ismael", "William", "Horton", "Pierre", "Zach", "Gough", "Salvador", "Vincent", "Duncan"], ["Georgia"]], [TrainerType.ARTIST]: [[ "Ismael", "William", "Horton", "Pierre", "Zach", "Gough", "Salvador", "Vincent", "Duncan" ], [ "Georgia" ]],
[TrainerType.BACKERS]: [["Alf & Fred", "Hawk & Dar", "Joe & Ross", "Les & Web", "Masa & Yas", "Stu & Art"], ["Ai & Ciel", "Ami & Eira", "Cam & Abby", "Fey & Sue", "Kat & Phae", "Kay & Ali", "Ava & Aya", "Cleo & Rio", "May & Mal"]], [TrainerType.BACKERS]: [[ "Alf & Fred", "Hawk & Dar", "Joe & Ross", "Les & Web", "Masa & Yas", "Stu & Art" ], [ "Ai & Ciel", "Ami & Eira", "Cam & Abby", "Fey & Sue", "Kat & Phae", "Kay & Ali", "Ava & Aya", "Cleo & Rio", "May & Mal" ]],
[TrainerType.BACKPACKER]: [["Alexander", "Carlos", "Herman", "Jerome", "Keane", "Kelsey", "Kiyo", "Michael", "Nate", "Peter", "Sam", "Stephen", "Talon", "Terrance", "Toru", "Waylon", "Boone", "Clifford", "Ivan", "Kendall", "Lowell", "Randall", "Reece", "Roland", "Shane", "Walt", "Farid", "Heike", "Joren", "Lane", "Roderick", "Darnell", "Deon", "Emory", "Graeme", "Grayson", "Aitor", "Alex", "Arturo", "Asier", "Jaime", "Jonathan", "Julio", "Kevin", "Kosuke", "Lander", "Markel", "Mateo", "Nil", "Pau", "Samuel"], ["Anna", "Corin", "Elaine", "Emi", "Jill", "Kumiko", "Liz", "Lois", "Lora", "Molly", "Patty", "Ruth", "Vicki", "Annie", "Blossom", "Clara", "Eileen", "Mae", "Myra", "Rachel", "Tami", "Ashley", "Mikiko", "Kiana", "Perdy", "Maria", "Yuho", "Peren", "Barbara", "Diane"]], [TrainerType.BACKPACKER]: [[ "Alexander", "Carlos", "Herman", "Jerome", "Keane", "Kelsey", "Kiyo", "Michael", "Nate", "Peter", "Sam", "Stephen", "Talon", "Terrance", "Toru", "Waylon", "Boone", "Clifford", "Ivan", "Kendall", "Lowell", "Randall", "Reece", "Roland", "Shane", "Walt", "Farid", "Heike", "Joren", "Lane", "Roderick", "Darnell", "Deon", "Emory", "Graeme", "Grayson", "Aitor", "Alex", "Arturo", "Asier", "Jaime", "Jonathan", "Julio", "Kevin", "Kosuke", "Lander", "Markel", "Mateo", "Nil", "Pau", "Samuel" ], [ "Anna", "Corin", "Elaine", "Emi", "Jill", "Kumiko", "Liz", "Lois", "Lora", "Molly", "Patty", "Ruth", "Vicki", "Annie", "Blossom", "Clara", "Eileen", "Mae", "Myra", "Rachel", "Tami", "Ashley", "Mikiko", "Kiana", "Perdy", "Maria", "Yuho", "Peren", "Barbara", "Diane" ]],
[TrainerType.BAKER]: ["Chris", "Jenn", "Lilly"], [TrainerType.BAKER]: [ "Chris", "Jenn", "Lilly" ],
[TrainerType.BEAUTY]: ["Cassie", "Julia", "Olivia", "Samantha", "Valerie", "Victoria", "Bridget", "Connie", "Jessica", "Johanna", "Melissa", "Sheila", "Shirley", "Tiffany", "Namiko", "Thalia", "Grace", "Lola", "Lori", "Maura", "Tamia", "Cyndy", "Devon", "Gabriella", "Harley", "Lindsay", "Nicola", "Callie", "Charlotte", "Kassandra", "December", "Fleming", "Nikola", "Aimee", "Anais", "Brigitte", "Cassandra", "Andrea", "Brittney", "Carolyn", "Krystal", "Alexis", "Alice", "Aina", "Anya", "Arianna", "Aubrey", "Beverly", "Camille", "Beauty", "Evette", "Hansol", "Haruka", "Jill", "Jo", "Lana", "Lois", "Lucy", "Mai", "Nickie", "Nicole", "Prita", "Rose", "Shelly", "Suzy", "Tessa", "Anita", "Alissa", "Rita", "Cudsy", "Eloff", "Miru", "Minot", "Nevah", "Niven", "Ogoin"], [TrainerType.BEAUTY]: [ "Cassie", "Julia", "Olivia", "Samantha", "Valerie", "Victoria", "Bridget", "Connie", "Jessica", "Johanna", "Melissa", "Sheila", "Shirley", "Tiffany", "Namiko", "Thalia", "Grace", "Lola", "Lori", "Maura", "Tamia", "Cyndy", "Devon", "Gabriella", "Harley", "Lindsay", "Nicola", "Callie", "Charlotte", "Kassandra", "December", "Fleming", "Nikola", "Aimee", "Anais", "Brigitte", "Cassandra", "Andrea", "Brittney", "Carolyn", "Krystal", "Alexis", "Alice", "Aina", "Anya", "Arianna", "Aubrey", "Beverly", "Camille", "Beauty", "Evette", "Hansol", "Haruka", "Jill", "Jo", "Lana", "Lois", "Lucy", "Mai", "Nickie", "Nicole", "Prita", "Rose", "Shelly", "Suzy", "Tessa", "Anita", "Alissa", "Rita", "Cudsy", "Eloff", "Miru", "Minot", "Nevah", "Niven", "Ogoin" ],
[TrainerType.BIKER]: ["Charles", "Dwayne", "Glenn", "Harris", "Joel", "Riley", "Zeke", "Alex", "Billy", "Ernest", "Gerald", "Hideo", "Isaac", "Jared", "Jaren", "Jaxon", "Jordy", "Lao", "Lukas", "Malik", "Nikolas", "Ricardo", "Ruben", "Virgil", "William", "Aiden", "Dale", "Dan", "Jacob", "Markey", "Reese", "Teddy", "Theron", "Jeremy", "Morgann", "Phillip", "Philip", "Stanley", "Dillon"], [TrainerType.BIKER]: [ "Charles", "Dwayne", "Glenn", "Harris", "Joel", "Riley", "Zeke", "Alex", "Billy", "Ernest", "Gerald", "Hideo", "Isaac", "Jared", "Jaren", "Jaxon", "Jordy", "Lao", "Lukas", "Malik", "Nikolas", "Ricardo", "Ruben", "Virgil", "William", "Aiden", "Dale", "Dan", "Jacob", "Markey", "Reese", "Teddy", "Theron", "Jeremy", "Morgann", "Phillip", "Philip", "Stanley", "Dillon" ],
[TrainerType.BLACK_BELT]: [["Kenji", "Lao", "Lung", "Nob", "Wai", "Yoshi", "Atsushi", "Daisuke", "Hideki", "Hitoshi", "Kiyo", "Koichi", "Koji", "Yuji", "Cristian", "Rhett", "Takao", "Theodore", "Zander", "Aaron", "Hugh", "Mike", "Nicolas", "Shea", "Takashi", "Adam", "Carl", "Colby", "Darren", "David", "Davon", "Derek", "Eddie", "Gregory", "Griffin", "Jarrett", "Jeffery", "Kendal", "Kyle", "Luke", "Miles", "Nathaniel", "Philip", "Rafael", "Ray", "Ricky", "Sean", "Willie", "Ander", "Manford", "Benjamin", "Corey", "Edward", "Grant", "Jay", "Kendrew", "Kentaro", "Ryder", "Teppei", "Thomas", "Tyrone", "Andrey", "Donny", "Drago", "Gordon", "Grigor", "Jeriel", "Kenneth", "Martell", "Mathis", "Rich", "Rocky", "Rodrigo", "Wesley", "Zachery", "Alonzo", "Cadoc", "Gunnar", "Igor", "Killian", "Markus", "Ricardo", "Yanis", "Banting", "Clayton", "Duane", "Earl", "Greg", "Roy", "Terry", "Tracy", "Walter", "Alvaro", "Curtis", "Francis", "Ross", "Brice", "Cheng", "Dudley", "Eric", "Kano", "Masahiro", "Randy", "Ryuji", "Steve", "Tadashi", "Wong", "Yuen", "Brian", "Carter", "Reece", "Nick", "Yang"], ["Cora", "Cyndy", "Jill", "Laura", "Sadie", "Tessa", "Vivian", "Aisha", "Callie", "Danielle", "Helene", "Jocelyn", "Lilith", "Paula", "Reyna", "Helen", "Kelsey", "Tyler", "Amy", "Chandra", "Hillary", "Janie", "Lee", "Maggie", "Mikiko", "Miriam", "Sharon", "Susie", "Xiao", "Alize", "Azra", "Brenda", "Chalina", "Chan", "Glinda", "Maki", "Tia", "Tiffany", "Wendy", "Andrea", "Gabrielle", "Gerardine", "Hailey", "Hedvig", "Justine", "Kinsey", "Sigrid", "Veronique", "Tess"]], [TrainerType.BLACK_BELT]: [[ "Kenji", "Lao", "Lung", "Nob", "Wai", "Yoshi", "Atsushi", "Daisuke", "Hideki", "Hitoshi", "Kiyo", "Koichi", "Koji", "Yuji", "Cristian", "Rhett", "Takao", "Theodore", "Zander", "Aaron", "Hugh", "Mike", "Nicolas", "Shea", "Takashi", "Adam", "Carl", "Colby", "Darren", "David", "Davon", "Derek", "Eddie", "Gregory", "Griffin", "Jarrett", "Jeffery", "Kendal", "Kyle", "Luke", "Miles", "Nathaniel", "Philip", "Rafael", "Ray", "Ricky", "Sean", "Willie", "Ander", "Manford", "Benjamin", "Corey", "Edward", "Grant", "Jay", "Kendrew", "Kentaro", "Ryder", "Teppei", "Thomas", "Tyrone", "Andrey", "Donny", "Drago", "Gordon", "Grigor", "Jeriel", "Kenneth", "Martell", "Mathis", "Rich", "Rocky", "Rodrigo", "Wesley", "Zachery", "Alonzo", "Cadoc", "Gunnar", "Igor", "Killian", "Markus", "Ricardo", "Yanis", "Banting", "Clayton", "Duane", "Earl", "Greg", "Roy", "Terry", "Tracy", "Walter", "Alvaro", "Curtis", "Francis", "Ross", "Brice", "Cheng", "Dudley", "Eric", "Kano", "Masahiro", "Randy", "Ryuji", "Steve", "Tadashi", "Wong", "Yuen", "Brian", "Carter", "Reece", "Nick", "Yang" ], [ "Cora", "Cyndy", "Jill", "Laura", "Sadie", "Tessa", "Vivian", "Aisha", "Callie", "Danielle", "Helene", "Jocelyn", "Lilith", "Paula", "Reyna", "Helen", "Kelsey", "Tyler", "Amy", "Chandra", "Hillary", "Janie", "Lee", "Maggie", "Mikiko", "Miriam", "Sharon", "Susie", "Xiao", "Alize", "Azra", "Brenda", "Chalina", "Chan", "Glinda", "Maki", "Tia", "Tiffany", "Wendy", "Andrea", "Gabrielle", "Gerardine", "Hailey", "Hedvig", "Justine", "Kinsey", "Sigrid", "Veronique", "Tess" ]],
[TrainerType.BREEDER]: [["Isaac", "Myles", "Salvadore", "Albert", "Kahlil", "Eustace", "Galen", "Owen", "Addison", "Marcus", "Foster", "Cory", "Glenn", "Jay", "Wesley", "William", "Adrian", "Bradley", "Jaime"], ["Allison", "Alize", "Bethany", "Lily", "Lydia", "Gabrielle", "Jayden", "Pat", "Veronica", "Amber", "Jennifer", "Kaylee", "Adelaide", "Brooke", "Ethel", "April", "Irene", "Magnolia", "Amala", "Mercy", "Amanda", "Ikue", "Savannah", "Yuka", "Chloe", "Debra", "Denise", "Elena"]], [TrainerType.BREEDER]: [[ "Isaac", "Myles", "Salvadore", "Albert", "Kahlil", "Eustace", "Galen", "Owen", "Addison", "Marcus", "Foster", "Cory", "Glenn", "Jay", "Wesley", "William", "Adrian", "Bradley", "Jaime" ], [ "Allison", "Alize", "Bethany", "Lily", "Lydia", "Gabrielle", "Jayden", "Pat", "Veronica", "Amber", "Jennifer", "Kaylee", "Adelaide", "Brooke", "Ethel", "April", "Irene", "Magnolia", "Amala", "Mercy", "Amanda", "Ikue", "Savannah", "Yuka", "Chloe", "Debra", "Denise", "Elena" ]],
[TrainerType.CLERK]: [["Chaz", "Clemens", "Doug", "Fredric", "Ivan", "Isaac", "Nelson", "Wade", "Warren", "Augustin", "Gilligan", "Cody", "Jeremy", "Shane", "Dugal", "Royce", "Ronald"], ["Alberta", "Ingrid", "Katie", "Piper", "Trisha", "Wren", "Britney", "Lana", "Jessica", "Kristen", "Michelle", "Gabrielle"]], [TrainerType.CLERK]: [[ "Chaz", "Clemens", "Doug", "Fredric", "Ivan", "Isaac", "Nelson", "Wade", "Warren", "Augustin", "Gilligan", "Cody", "Jeremy", "Shane", "Dugal", "Royce", "Ronald" ], [ "Alberta", "Ingrid", "Katie", "Piper", "Trisha", "Wren", "Britney", "Lana", "Jessica", "Kristen", "Michelle", "Gabrielle" ]],
[TrainerType.CYCLIST]: [["Axel", "James", "John", "Ryan", "Hector", "Jeremiah"], ["Kayla", "Megan", "Nicole", "Rachel", "Krissa", "Adelaide"]], [TrainerType.CYCLIST]: [[ "Axel", "James", "John", "Ryan", "Hector", "Jeremiah" ], [ "Kayla", "Megan", "Nicole", "Rachel", "Krissa", "Adelaide" ]],
[TrainerType.DANCER]: ["Brian", "Davey", "Dirk", "Edmond", "Mickey", "Raymond", "Cara", "Julia", "Maika", "Mireille", "Ronda", "Zoe"], [TrainerType.DANCER]: [ "Brian", "Davey", "Dirk", "Edmond", "Mickey", "Raymond", "Cara", "Julia", "Maika", "Mireille", "Ronda", "Zoe" ],
[TrainerType.DEPOT_AGENT]: ["Josh", "Hank", "Vincent"], [TrainerType.DEPOT_AGENT]: [ "Josh", "Hank", "Vincent" ],
[TrainerType.DOCTOR]: [["Hank", "Jerry", "Jules", "Logan", "Wayne", "Braid", "Derek", "Heath", "Julius", "Kit", "Graham"], ["Kirsten", "Sachiko", "Shery", "Carol", "Dixie", "Mariah"]], [TrainerType.DOCTOR]: [[ "Hank", "Jerry", "Jules", "Logan", "Wayne", "Braid", "Derek", "Heath", "Julius", "Kit", "Graham" ], [ "Kirsten", "Sachiko", "Shery", "Carol", "Dixie", "Mariah" ]],
[TrainerType.FIREBREATHER]: ["Bill", "Burt", "Cliff", "Dick", "Lyle", "Ned", "Otis", "Ray", "Richard", "Walt"], [TrainerType.FIREBREATHER]: [ "Bill", "Burt", "Cliff", "Dick", "Lyle", "Ned", "Otis", "Ray", "Richard", "Walt" ],
[TrainerType.FISHERMAN]: ["Andre", "Arnold", "Barney", "Chris", "Edgar", "Henry", "Jonah", "Justin", "Kyle", "Martin", "Marvin", "Ralph", "Raymond", "Scott", "Stephen", "Wilton", "Tully", "Andrew", "Barny", "Carter", "Claude", "Dale", "Elliot", "Eugene", "Ivan", "Ned", "Nolan", "Roger", "Ronald", "Wade", "Wayne", "Darian", "Kai", "Chip", "Hank", "Kaden", "Tommy", "Tylor", "Alec", "Brett", "Cameron", "Cody", "Cole", "Cory", "Erick", "George", "Joseph", "Juan", "Kenneth", "Luc", "Miguel", "Travis", "Walter", "Zachary", "Josh", "Gideon", "Kyler", "Liam", "Murphy", "Bruce", "Damon", "Devon", "Hubert", "Jones", "Lydon", "Mick", "Pete", "Sean", "Sid", "Vince", "Bucky", "Dean", "Eustace", "Kenzo", "Leroy", "Mack", "Ryder", "Ewan", "Finn", "Murray", "Seward", "Shad", "Wharton", "Finley", "Fisher", "Fisk", "River", "Sheaffer", "Timin", "Carl", "Ernest", "Hal", "Herbert", "Hisato", "Mike", "Vernon", "Harriet", "Marina", "Chase"], [TrainerType.FISHERMAN]: [ "Andre", "Arnold", "Barney", "Chris", "Edgar", "Henry", "Jonah", "Justin", "Kyle", "Martin", "Marvin", "Ralph", "Raymond", "Scott", "Stephen", "Wilton", "Tully", "Andrew", "Barny", "Carter", "Claude", "Dale", "Elliot", "Eugene", "Ivan", "Ned", "Nolan", "Roger", "Ronald", "Wade", "Wayne", "Darian", "Kai", "Chip", "Hank", "Kaden", "Tommy", "Tylor", "Alec", "Brett", "Cameron", "Cody", "Cole", "Cory", "Erick", "George", "Joseph", "Juan", "Kenneth", "Luc", "Miguel", "Travis", "Walter", "Zachary", "Josh", "Gideon", "Kyler", "Liam", "Murphy", "Bruce", "Damon", "Devon", "Hubert", "Jones", "Lydon", "Mick", "Pete", "Sean", "Sid", "Vince", "Bucky", "Dean", "Eustace", "Kenzo", "Leroy", "Mack", "Ryder", "Ewan", "Finn", "Murray", "Seward", "Shad", "Wharton", "Finley", "Fisher", "Fisk", "River", "Sheaffer", "Timin", "Carl", "Ernest", "Hal", "Herbert", "Hisato", "Mike", "Vernon", "Harriet", "Marina", "Chase" ],
[TrainerType.GUITARIST]: ["Anna", "Beverly", "January", "Tina", "Alicia", "Claudia", "Julia", "Lidia", "Mireia", "Noelia", "Sara", "Sheila", "Tatiana"], [TrainerType.GUITARIST]: [ "Anna", "Beverly", "January", "Tina", "Alicia", "Claudia", "Julia", "Lidia", "Mireia", "Noelia", "Sara", "Sheila", "Tatiana" ],
[TrainerType.HARLEQUIN]: ["Charley", "Ian", "Jack", "Kerry", "Louis", "Pat", "Paul", "Rick", "Anders", "Clarence", "Gary"], [TrainerType.HARLEQUIN]: [ "Charley", "Ian", "Jack", "Kerry", "Louis", "Pat", "Paul", "Rick", "Anders", "Clarence", "Gary" ],
[TrainerType.HIKER]: ["Anthony", "Bailey", "Benjamin", "Daniel", "Erik", "Jim", "Kenny", "Leonard", "Michael", "Parry", "Phillip", "Russell", "Sidney", "Tim", "Timothy", "Alan", "Brice", "Clark", "Eric", "Lenny", "Lucas", "Mike", "Trent", "Devan", "Eli", "Marc", "Sawyer", "Allen", "Daryl", "Dudley", "Earl", "Franklin", "Jeremy", "Marcos", "Nob", "Oliver", "Wayne", "Alexander", "Damon", "Jonathan", "Justin", "Kevin", "Lorenzo", "Louis", "Maurice", "Nicholas", "Reginald", "Robert", "Theodore", "Bruce", "Clarke", "Devin", "Dwight", "Edwin", "Eoin", "Noland", "Russel", "Andy", "Bret", "Darrell", "Gene", "Hardy", "Hugh", "Jebediah", "Jeremiah", "Kit", "Neil", "Terrell", "Don", "Doug", "Hunter", "Jared", "Jerome", "Keith", "Manuel", "Markus", "Otto", "Shelby", "Stephen", "Teppei", "Tobias", "Wade", "Zaiem", "Aaron", "Alain", "Bergin", "Bernard", "Brent", "Corwin", "Craig", "Delmon", "Dunstan", "Orestes", "Ross", "Davian", "Calhoun", "David", "Gabriel", "Ryan", "Thomas", "Travis", "Zachary", "Anuhea", "Barnaby", "Claus", "Collin", "Colson", "Dexter", "Dillan", "Eugine", "Farkas", "Hisato", "Julius", "Kenji", "Irwin", "Lionel", "Paul", "Richter", "Valentino", "Donald", "Douglas", "Kevyn", "Chester"], //["Angela","Carla","Celia","Daniela","Estela","Fatima","Helena","Leire","Lucia","Luna","Manuela","Mar","Marina","Miyu","Nancy","Nerea","Paula","Rocio","Yanira"] [TrainerType.HIKER]: [ "Anthony", "Bailey", "Benjamin", "Daniel", "Erik", "Jim", "Kenny", "Leonard", "Michael", "Parry", "Phillip", "Russell", "Sidney", "Tim", "Timothy", "Alan", "Brice", "Clark", "Eric", "Lenny", "Lucas", "Mike", "Trent", "Devan", "Eli", "Marc", "Sawyer", "Allen", "Daryl", "Dudley", "Earl", "Franklin", "Jeremy", "Marcos", "Nob", "Oliver", "Wayne", "Alexander", "Damon", "Jonathan", "Justin", "Kevin", "Lorenzo", "Louis", "Maurice", "Nicholas", "Reginald", "Robert", "Theodore", "Bruce", "Clarke", "Devin", "Dwight", "Edwin", "Eoin", "Noland", "Russel", "Andy", "Bret", "Darrell", "Gene", "Hardy", "Hugh", "Jebediah", "Jeremiah", "Kit", "Neil", "Terrell", "Don", "Doug", "Hunter", "Jared", "Jerome", "Keith", "Manuel", "Markus", "Otto", "Shelby", "Stephen", "Teppei", "Tobias", "Wade", "Zaiem", "Aaron", "Alain", "Bergin", "Bernard", "Brent", "Corwin", "Craig", "Delmon", "Dunstan", "Orestes", "Ross", "Davian", "Calhoun", "David", "Gabriel", "Ryan", "Thomas", "Travis", "Zachary", "Anuhea", "Barnaby", "Claus", "Collin", "Colson", "Dexter", "Dillan", "Eugine", "Farkas", "Hisato", "Julius", "Kenji", "Irwin", "Lionel", "Paul", "Richter", "Valentino", "Donald", "Douglas", "Kevyn", "Chester" ], //["Angela","Carla","Celia","Daniela","Estela","Fatima","Helena","Leire","Lucia","Luna","Manuela","Mar","Marina","Miyu","Nancy","Nerea","Paula","Rocio","Yanira"]
[TrainerType.HOOLIGANS]: ["Jim & Cas", "Rob & Sal"], [TrainerType.HOOLIGANS]: [ "Jim & Cas", "Rob & Sal" ],
[TrainerType.HOOPSTER]: ["Bobby", "John", "Lamarcus", "Derrick", "Nicolas"], [TrainerType.HOOPSTER]: [ "Bobby", "John", "Lamarcus", "Derrick", "Nicolas" ],
[TrainerType.INFIELDER]: ["Alex", "Connor", "Todd"], [TrainerType.INFIELDER]: [ "Alex", "Connor", "Todd" ],
[TrainerType.JANITOR]: ["Caleb", "Geoff", "Brady", "Felix", "Orville", "Melvin", "Shawn"], [TrainerType.JANITOR]: [ "Caleb", "Geoff", "Brady", "Felix", "Orville", "Melvin", "Shawn" ],
[TrainerType.LINEBACKER]: ["Bob", "Dan", "Jonah"], [TrainerType.LINEBACKER]: [ "Bob", "Dan", "Jonah" ],
[TrainerType.MAID]: ["Belinda", "Sophie", "Emily", "Elena", "Clare", "Alica", "Tanya", "Tammy"], [TrainerType.MAID]: [ "Belinda", "Sophie", "Emily", "Elena", "Clare", "Alica", "Tanya", "Tammy" ],
[TrainerType.MUSICIAN]: ["Boris", "Preston", "Charles", "Clyde", "Vincent", "Dalton", "Kirk", "Shawn", "Fabian", "Fernando", "Joseph", "Marcos", "Arturo", "Jerry", "Lonnie", "Tony"], [TrainerType.MUSICIAN]: [ "Boris", "Preston", "Charles", "Clyde", "Vincent", "Dalton", "Kirk", "Shawn", "Fabian", "Fernando", "Joseph", "Marcos", "Arturo", "Jerry", "Lonnie", "Tony" ],
[TrainerType.NURSERY_AIDE]: ["Autumn", "Briana", "Leah", "Miho", "Ethel", "Hollie", "Ilse", "June", "Kimya", "Rosalyn"], [TrainerType.NURSERY_AIDE]: [ "Autumn", "Briana", "Leah", "Miho", "Ethel", "Hollie", "Ilse", "June", "Kimya", "Rosalyn" ],
[TrainerType.OFFICER]: ["Dirk", "Keith", "Alex", "Bobby", "Caleb", "Danny", "Dylan", "Thomas", "Daniel", "Jeff", "Braven", "Dell", "Neagle", "Haruki", "Mitchell", "Raymond"], [TrainerType.OFFICER]: [ "Dirk", "Keith", "Alex", "Bobby", "Caleb", "Danny", "Dylan", "Thomas", "Daniel", "Jeff", "Braven", "Dell", "Neagle", "Haruki", "Mitchell", "Raymond" ],
[TrainerType.PARASOL_LADY]: ["Angelica", "Clarissa", "Madeline", "Akari", "Annabell", "Kayley", "Rachel", "Alexa", "Sabrina", "April", "Gwyneth", "Laura", "Lumi", "Mariah", "Melita", "Nicole", "Tihana", "Ingrid", "Tyra"], [TrainerType.PARASOL_LADY]: [ "Angelica", "Clarissa", "Madeline", "Akari", "Annabell", "Kayley", "Rachel", "Alexa", "Sabrina", "April", "Gwyneth", "Laura", "Lumi", "Mariah", "Melita", "Nicole", "Tihana", "Ingrid", "Tyra" ],
[TrainerType.PILOT]: ["Chase", "Leonard", "Ted", "Elron", "Ewing", "Flynn", "Winslow"], [TrainerType.PILOT]: [ "Chase", "Leonard", "Ted", "Elron", "Ewing", "Flynn", "Winslow" ],
[TrainerType.POKEFAN]: [["Alex", "Allan", "Brandon", "Carter", "Colin", "Derek", "Jeremy", "Joshua", "Rex", "Robert", "Trevor", "William", "Colton", "Miguel", "Francisco", "Kaleb", "Leonard", "Boone", "Elliot", "Jude", "Norbert", "Corey", "Gabe", "Baxter"], ["Beverly", "Georgia", "Jaime", "Ruth", "Isabel", "Marissa", "Vanessa", "Annika", "Bethany", "Kimberly", "Meredith", "Rebekah", "Eleanor", "Darcy", "Lydia", "Sachiko", "Abigail", "Agnes", "Lydie", "Roisin", "Tara", "Carmen", "Janet"]], [TrainerType.POKEFAN]: [[ "Alex", "Allan", "Brandon", "Carter", "Colin", "Derek", "Jeremy", "Joshua", "Rex", "Robert", "Trevor", "William", "Colton", "Miguel", "Francisco", "Kaleb", "Leonard", "Boone", "Elliot", "Jude", "Norbert", "Corey", "Gabe", "Baxter" ], [ "Beverly", "Georgia", "Jaime", "Ruth", "Isabel", "Marissa", "Vanessa", "Annika", "Bethany", "Kimberly", "Meredith", "Rebekah", "Eleanor", "Darcy", "Lydia", "Sachiko", "Abigail", "Agnes", "Lydie", "Roisin", "Tara", "Carmen", "Janet" ]],
[TrainerType.PRESCHOOLER]: [["Billy", "Doyle", "Evan", "Homer", "Tully", "Albert", "Buster", "Greg", "Ike", "Jojo", "Tyrone", "Adrian", "Oliver", "Hayden", "Hunter", "Kaleb", "Liam", "Dylan"], ["Juliet", "Mia", "Sarah", "Wendy", "Winter", "Chrissy", "Eva", "Lin", "Samantha", "Ella", "Lily", "Natalie", "Ailey", "Hannah", "Malia", "Kindra", "Nancy"]], [TrainerType.PRESCHOOLER]: [[ "Billy", "Doyle", "Evan", "Homer", "Tully", "Albert", "Buster", "Greg", "Ike", "Jojo", "Tyrone", "Adrian", "Oliver", "Hayden", "Hunter", "Kaleb", "Liam", "Dylan" ], [ "Juliet", "Mia", "Sarah", "Wendy", "Winter", "Chrissy", "Eva", "Lin", "Samantha", "Ella", "Lily", "Natalie", "Ailey", "Hannah", "Malia", "Kindra", "Nancy" ]],
[TrainerType.PSYCHIC]: [["Fidel", "Franklin", "Gilbert", "Greg", "Herman", "Jared", "Mark", "Nathan", "Norman", "Phil", "Richard", "Rodney", "Cameron", "Edward", "Fritz", "Joshua", "Preston", "Virgil", "William", "Alvaro", "Blake", "Cedric", "Keenan", "Nicholas", "Dario", "Johan", "Lorenzo", "Tyron", "Bryce", "Corbin", "Deandre", "Elijah", "Kody", "Landon", "Maxwell", "Mitchell", "Sterling", "Eli", "Nelson", "Vernon", "Gaven", "Gerard", "Low", "Micki", "Perry", "Rudolf", "Tommy", "Al", "Nandor", "Tully", "Arthur", "Emanuel", "Franz", "Harry", "Paschal", "Robert", "Sayid", "Angelo", "Anton", "Arin", "Avery", "Danny", "Frasier", "Harrison", "Jaime", "Ross", "Rui", "Vlad", "Mason"], ["Alexis", "Hannah", "Jacki", "Jaclyn", "Kayla", "Maura", "Samantha", "Alix", "Brandi", "Edie", "Macey", "Mariella", "Marlene", "Laura", "Rodette", "Abigail", "Brittney", "Chelsey", "Daisy", "Desiree", "Kendra", "Lindsey", "Rachael", "Valencia", "Belle", "Cybil", "Doreen", "Dua", "Future", "Lin", "Madhu", "Alia", "Ena", "Joyce", "Lynette", "Olesia", "Sarah"]], [TrainerType.PSYCHIC]: [[ "Fidel", "Franklin", "Gilbert", "Greg", "Herman", "Jared", "Mark", "Nathan", "Norman", "Phil", "Richard", "Rodney", "Cameron", "Edward", "Fritz", "Joshua", "Preston", "Virgil", "William", "Alvaro", "Blake", "Cedric", "Keenan", "Nicholas", "Dario", "Johan", "Lorenzo", "Tyron", "Bryce", "Corbin", "Deandre", "Elijah", "Kody", "Landon", "Maxwell", "Mitchell", "Sterling", "Eli", "Nelson", "Vernon", "Gaven", "Gerard", "Low", "Micki", "Perry", "Rudolf", "Tommy", "Al", "Nandor", "Tully", "Arthur", "Emanuel", "Franz", "Harry", "Paschal", "Robert", "Sayid", "Angelo", "Anton", "Arin", "Avery", "Danny", "Frasier", "Harrison", "Jaime", "Ross", "Rui", "Vlad", "Mason" ], [ "Alexis", "Hannah", "Jacki", "Jaclyn", "Kayla", "Maura", "Samantha", "Alix", "Brandi", "Edie", "Macey", "Mariella", "Marlene", "Laura", "Rodette", "Abigail", "Brittney", "Chelsey", "Daisy", "Desiree", "Kendra", "Lindsey", "Rachael", "Valencia", "Belle", "Cybil", "Doreen", "Dua", "Future", "Lin", "Madhu", "Alia", "Ena", "Joyce", "Lynette", "Olesia", "Sarah" ]],
[TrainerType.RANGER]: [["Carlos", "Jackson", "Sebastian", "Gav", "Lorenzo", "Logan", "Nicolas", "Trenton", "Deshawn", "Dwayne", "Jeffery", "Kyler", "Taylor", "Alain", "Claude", "Crofton", "Forrest", "Harry", "Jaden", "Keith", "Lewis", "Miguel", "Pedro", "Ralph", "Richard", "Bret", "Daryl", "Eddie", "Johan", "Leaf", "Louis", "Maxwell", "Parker", "Rick", "Steve", "Bjorn", "Chaise", "Dean", "Lee", "Maurice", "Nash", "Ralf", "Reed", "Shinobu", "Silas"], ["Catherine", "Jenna", "Sophia", "Merdith", "Nora", "Beth", "Chelsea", "Katelyn", "Madeline", "Allison", "Ashlee", "Felicia", "Krista", "Annie", "Audra", "Brenda", "Chloris", "Eliza", "Heidi", "Irene", "Mary", "Mylene", "Shanti", "Shelly", "Thalia", "Anja", "Briana", "Dianna", "Elaine", "Elle", "Hillary", "Katie", "Lena", "Lois", "Malory", "Melita", "Mikiko", "Naoko", "Serenity", "Ambre", "Brooke", "Clementine", "Melina", "Petra", "Twiggy"]], [TrainerType.RANGER]: [[ "Carlos", "Jackson", "Sebastian", "Gav", "Lorenzo", "Logan", "Nicolas", "Trenton", "Deshawn", "Dwayne", "Jeffery", "Kyler", "Taylor", "Alain", "Claude", "Crofton", "Forrest", "Harry", "Jaden", "Keith", "Lewis", "Miguel", "Pedro", "Ralph", "Richard", "Bret", "Daryl", "Eddie", "Johan", "Leaf", "Louis", "Maxwell", "Parker", "Rick", "Steve", "Bjorn", "Chaise", "Dean", "Lee", "Maurice", "Nash", "Ralf", "Reed", "Shinobu", "Silas" ], [ "Catherine", "Jenna", "Sophia", "Merdith", "Nora", "Beth", "Chelsea", "Katelyn", "Madeline", "Allison", "Ashlee", "Felicia", "Krista", "Annie", "Audra", "Brenda", "Chloris", "Eliza", "Heidi", "Irene", "Mary", "Mylene", "Shanti", "Shelly", "Thalia", "Anja", "Briana", "Dianna", "Elaine", "Elle", "Hillary", "Katie", "Lena", "Lois", "Malory", "Melita", "Mikiko", "Naoko", "Serenity", "Ambre", "Brooke", "Clementine", "Melina", "Petra", "Twiggy" ]],
[TrainerType.RICH]: [["Alfred", "Edward", "Gregory", "Preston", "Thomas", "Tucker", "Walter", "Clifford", "Everett", "Micah", "Nate", "Pierre", "Terrance", "Arthur", "Brooks", "Emanuel", "Lamar", "Jeremy", "Leonardo", "Milton", "Frederic", "Renaud", "Robert", "Yan", "Daniel", "Sheldon", "Stonewall", "Gerald", "Ronald", "Smith", "Stanley", "Reginald", "Orson", "Wilco", "Caden", "Glenn"], ["Rebecca", "Reina", "Cassandra", "Emilia", "Grace", "Marian", "Elizabeth", "Kathleen", "Sayuri", "Caroline", "Judy"]], [TrainerType.RICH]: [[ "Alfred", "Edward", "Gregory", "Preston", "Thomas", "Tucker", "Walter", "Clifford", "Everett", "Micah", "Nate", "Pierre", "Terrance", "Arthur", "Brooks", "Emanuel", "Lamar", "Jeremy", "Leonardo", "Milton", "Frederic", "Renaud", "Robert", "Yan", "Daniel", "Sheldon", "Stonewall", "Gerald", "Ronald", "Smith", "Stanley", "Reginald", "Orson", "Wilco", "Caden", "Glenn" ], [ "Rebecca", "Reina", "Cassandra", "Emilia", "Grace", "Marian", "Elizabeth", "Kathleen", "Sayuri", "Caroline", "Judy" ]],
[TrainerType.RICH_KID]: [["Garret", "Winston", "Dawson", "Enrique", "Jason", "Roman", "Trey", "Liam", "Anthony", "Brad", "Cody", "Manuel", "Martin", "Pierce", "Rolan", "Keenan", "Filbert", "Antoin", "Cyus", "Diek", "Dugo", "Flitz", "Jurek", "Lond", "Perd", "Quint", "Basto", "Benit", "Brot", "Denc", "Guyit", "Marcon", "Perc", "Puros", "Roex", "Sainz", "Symin", "Tark", "Venak"], ["Anette", "Brianna", "Cindy", "Colleen", "Daphne", "Elizabeth", "Naomi", "Sarah", "Charlotte", "Gillian", "Jacki", "Lady", "Melissa", "Celeste", "Colette", "Elizandra", "Isabel", "Lynette", "Magnolia", "Sophie", "Lina", "Dulcie", "Auro", "Brin", "Caril", "Eloos", "Gwin", "Illa", "Kowly", "Rima", "Ristin", "Vesey", "Brena", "Deasy", "Denslon", "Kylet", "Nemi", "Rene", "Sanol", "Stouner", "Sturk", "Talmen", "Zoila"]], [TrainerType.RICH_KID]: [[ "Garret", "Winston", "Dawson", "Enrique", "Jason", "Roman", "Trey", "Liam", "Anthony", "Brad", "Cody", "Manuel", "Martin", "Pierce", "Rolan", "Keenan", "Filbert", "Antoin", "Cyus", "Diek", "Dugo", "Flitz", "Jurek", "Lond", "Perd", "Quint", "Basto", "Benit", "Brot", "Denc", "Guyit", "Marcon", "Perc", "Puros", "Roex", "Sainz", "Symin", "Tark", "Venak" ], [ "Anette", "Brianna", "Cindy", "Colleen", "Daphne", "Elizabeth", "Naomi", "Sarah", "Charlotte", "Gillian", "Jacki", "Lady", "Melissa", "Celeste", "Colette", "Elizandra", "Isabel", "Lynette", "Magnolia", "Sophie", "Lina", "Dulcie", "Auro", "Brin", "Caril", "Eloos", "Gwin", "Illa", "Kowly", "Rima", "Ristin", "Vesey", "Brena", "Deasy", "Denslon", "Kylet", "Nemi", "Rene", "Sanol", "Stouner", "Sturk", "Talmen", "Zoila" ]],
[TrainerType.ROUGHNECK]: ["Camron", "Corey", "Gabriel", "Isaiah", "Jamal", "Koji", "Luke", "Paxton", "Raul", "Zeek", "Kirby", "Chance", "Dave", "Fletcher", "Johnny", "Reese", "Joey", "Ricky", "Silvester", "Martin"], [TrainerType.ROUGHNECK]: [ "Camron", "Corey", "Gabriel", "Isaiah", "Jamal", "Koji", "Luke", "Paxton", "Raul", "Zeek", "Kirby", "Chance", "Dave", "Fletcher", "Johnny", "Reese", "Joey", "Ricky", "Silvester", "Martin" ],
[TrainerType.SAILOR]: ["Alberto", "Bost", "Brennan", "Brenden", "Claude", "Cory", "Damian", "Dirk", "Duncan", "Dwayne", "Dylan", "Eddie", "Edmond", "Elijah", "Ernest", "Eugene", "Garrett", "Golos", "Gratin", "Grestly", "Harry", "Hols", "Hudson", "Huey", "Jebol", "Jeff", "Leonald", "Luther", "Kelvin", "Kenneth", "Kent", "Knook", "Marc", "Mifis", "Monar", "Morkor", "Ordes", "Oxlin", "Parker", "Paul", "Philip", "Roberto", "Samson", "Skyler", "Stanly", "Tebu", "Terrell", "Trevor", "Yasu", "Zachariah"], [TrainerType.SAILOR]: [ "Alberto", "Bost", "Brennan", "Brenden", "Claude", "Cory", "Damian", "Dirk", "Duncan", "Dwayne", "Dylan", "Eddie", "Edmond", "Elijah", "Ernest", "Eugene", "Garrett", "Golos", "Gratin", "Grestly", "Harry", "Hols", "Hudson", "Huey", "Jebol", "Jeff", "Leonald", "Luther", "Kelvin", "Kenneth", "Kent", "Knook", "Marc", "Mifis", "Monar", "Morkor", "Ordes", "Oxlin", "Parker", "Paul", "Philip", "Roberto", "Samson", "Skyler", "Stanly", "Tebu", "Terrell", "Trevor", "Yasu", "Zachariah" ],
[TrainerType.SCIENTIST]: [["Jed", "Marc", "Mitch", "Rich", "Ross", "Beau", "Braydon", "Connor", "Ed", "Ivan", "Jerry", "Jose", "Joshua", "Parker", "Rodney", "Taylor", "Ted", "Travis", "Zackery", "Darrius", "Emilio", "Fredrick", "Shaun", "Stefano", "Travon", "Daniel", "Garett", "Gregg", "Linden", "Lowell", "Trenton", "Dudley", "Luke", "Markus", "Nathan", "Orville", "Randall", "Ron", "Ronald", "Simon", "Steve", "William", "Franklin", "Clarke", "Jacques", "Terrance", "Ernst", "Justus", "Ikaika", "Jayson", "Kyle", "Reid", "Tyrone", "Adam", "Albert", "Alphonse", "Cory", "Donnie", "Elton", "Francis", "Gordon", "Herbert", "Humphrey", "Jordan", "Julian", "Keaton", "Levi", "Melvin", "Murray", "West", "Craig", "Coren", "Dubik", "Kotan", "Lethco", "Mante", "Mort", "Myron", "Odlow", "Ribek", "Roeck", "Vogi", "Vonder", "Zogo", "Doimo", "Doton", "Durel", "Hildon", "Kukla", "Messa", "Nanot", "Platen", "Raburn", "Reman", "Acrod", "Coffy", "Elrok", "Foss", "Hardig", "Hombol", "Hospel", "Kaller", "Klots", "Krilok", "Limar", "Loket", "Mesak", "Morbit", "Newin", "Orill", "Tabor", "Tekot"], ["Blythe", "Chan", "Kathrine", "Marie", "Maria", "Naoko", "Samantha", "Satomi", "Shannon", "Athena", "Caroline", "Lumi", "Lumina", "Marissa", "Sonia"]], [TrainerType.SCIENTIST]: [[ "Jed", "Marc", "Mitch", "Rich", "Ross", "Beau", "Braydon", "Connor", "Ed", "Ivan", "Jerry", "Jose", "Joshua", "Parker", "Rodney", "Taylor", "Ted", "Travis", "Zackery", "Darrius", "Emilio", "Fredrick", "Shaun", "Stefano", "Travon", "Daniel", "Garett", "Gregg", "Linden", "Lowell", "Trenton", "Dudley", "Luke", "Markus", "Nathan", "Orville", "Randall", "Ron", "Ronald", "Simon", "Steve", "William", "Franklin", "Clarke", "Jacques", "Terrance", "Ernst", "Justus", "Ikaika", "Jayson", "Kyle", "Reid", "Tyrone", "Adam", "Albert", "Alphonse", "Cory", "Donnie", "Elton", "Francis", "Gordon", "Herbert", "Humphrey", "Jordan", "Julian", "Keaton", "Levi", "Melvin", "Murray", "West", "Craig", "Coren", "Dubik", "Kotan", "Lethco", "Mante", "Mort", "Myron", "Odlow", "Ribek", "Roeck", "Vogi", "Vonder", "Zogo", "Doimo", "Doton", "Durel", "Hildon", "Kukla", "Messa", "Nanot", "Platen", "Raburn", "Reman", "Acrod", "Coffy", "Elrok", "Foss", "Hardig", "Hombol", "Hospel", "Kaller", "Klots", "Krilok", "Limar", "Loket", "Mesak", "Morbit", "Newin", "Orill", "Tabor", "Tekot" ], [ "Blythe", "Chan", "Kathrine", "Marie", "Maria", "Naoko", "Samantha", "Satomi", "Shannon", "Athena", "Caroline", "Lumi", "Lumina", "Marissa", "Sonia" ]],
[TrainerType.SMASHER]: ["Aspen", "Elena", "Mari", "Amy", "Lizzy"], [TrainerType.SMASHER]: [ "Aspen", "Elena", "Mari", "Amy", "Lizzy" ],
[TrainerType.SNOW_WORKER]: [["Braden", "Brendon", "Colin", "Conrad", "Dillan", "Gary", "Gerardo", "Holden", "Jackson", "Mason", "Quentin", "Willy", "Noel", "Arnold", "Brady", "Brand", "Cairn", "Cliff", "Don", "Eddie", "Felix", "Filipe", "Glenn", "Gus", "Heath", "Matthew", "Patton", "Rich", "Rob", "Ryan", "Scott", "Shelby", "Sterling", "Tyler", "Victor", "Zack", "Friedrich", "Herman", "Isaac", "Leo", "Maynard", "Mitchell", "Morgann", "Nathan", "Niel", "Pasqual", "Paul", "Tavarius", "Tibor", "Dimitri", "Narek", "Yusif", "Frank", "Jeff", "Vaclav", "Ovid", "Francis", "Keith", "Russel", "Sangon", "Toway", "Bomber", "Chean", "Demit", "Hubor", "Kebile", "Laber", "Ordo", "Retay", "Ronix", "Wagel", "Dobit", "Kaster", "Lobel", "Releo", "Saken", "Rustix"], ["Georgia", "Sandra", "Yvonne"]], [TrainerType.SNOW_WORKER]: [[ "Braden", "Brendon", "Colin", "Conrad", "Dillan", "Gary", "Gerardo", "Holden", "Jackson", "Mason", "Quentin", "Willy", "Noel", "Arnold", "Brady", "Brand", "Cairn", "Cliff", "Don", "Eddie", "Felix", "Filipe", "Glenn", "Gus", "Heath", "Matthew", "Patton", "Rich", "Rob", "Ryan", "Scott", "Shelby", "Sterling", "Tyler", "Victor", "Zack", "Friedrich", "Herman", "Isaac", "Leo", "Maynard", "Mitchell", "Morgann", "Nathan", "Niel", "Pasqual", "Paul", "Tavarius", "Tibor", "Dimitri", "Narek", "Yusif", "Frank", "Jeff", "Vaclav", "Ovid", "Francis", "Keith", "Russel", "Sangon", "Toway", "Bomber", "Chean", "Demit", "Hubor", "Kebile", "Laber", "Ordo", "Retay", "Ronix", "Wagel", "Dobit", "Kaster", "Lobel", "Releo", "Saken", "Rustix" ], [ "Georgia", "Sandra", "Yvonne" ]],
[TrainerType.STRIKER]: ["Marco", "Roberto", "Tony"], [TrainerType.STRIKER]: [ "Marco", "Roberto", "Tony" ],
[TrainerType.SCHOOL_KID]: [["Alan", "Billy", "Chad", "Danny", "Dudley", "Jack", "Joe", "Johnny", "Kipp", "Nate", "Ricky", "Tommy", "Jerry", "Paul", "Ted", "Chance", "Esteban", "Forrest", "Harrison", "Connor", "Sherman", "Torin", "Travis", "Al", "Carter", "Edgar", "Jem", "Sammy", "Shane", "Shayne", "Alvin", "Keston", "Neil", "Seymour", "William", "Carson", "Clark", "Nolan"], ["Georgia", "Karen", "Meiko", "Christine", "Mackenzie", "Tiera", "Ann", "Gina", "Lydia", "Marsha", "Millie", "Sally", "Serena", "Silvia", "Alberta", "Cassie", "Mara", "Rita", "Georgie", "Meena", "Nitzel"]], [TrainerType.SCHOOL_KID]: [[ "Alan", "Billy", "Chad", "Danny", "Dudley", "Jack", "Joe", "Johnny", "Kipp", "Nate", "Ricky", "Tommy", "Jerry", "Paul", "Ted", "Chance", "Esteban", "Forrest", "Harrison", "Connor", "Sherman", "Torin", "Travis", "Al", "Carter", "Edgar", "Jem", "Sammy", "Shane", "Shayne", "Alvin", "Keston", "Neil", "Seymour", "William", "Carson", "Clark", "Nolan" ], [ "Georgia", "Karen", "Meiko", "Christine", "Mackenzie", "Tiera", "Ann", "Gina", "Lydia", "Marsha", "Millie", "Sally", "Serena", "Silvia", "Alberta", "Cassie", "Mara", "Rita", "Georgie", "Meena", "Nitzel" ]],
[TrainerType.SWIMMER]: [["Berke", "Cameron", "Charlie", "George", "Harold", "Jerome", "Kirk", "Mathew", "Parker", "Randall", "Seth", "Simon", "Tucker", "Austin", "Barry", "Chad", "Cody", "Darrin", "David", "Dean", "Douglas", "Franklin", "Gilbert", "Herman", "Jack", "Luis", "Matthew", "Reed", "Richard", "Rodney", "Roland", "Spencer", "Stan", "Tony", "Clarence", "Declan", "Dominik", "Harrison", "Kevin", "Leonardo", "Nolen", "Pete", "Santiago", "Axle", "Braden", "Finn", "Garrett", "Mymo", "Reece", "Samir", "Toby", "Adrian", "Colton", "Dillon", "Erik", "Evan", "Francisco", "Glenn", "Kurt", "Oscar", "Ricardo", "Sam", "Sheltin", "Troy", "Vincent", "Wade", "Wesley", "Duane", "Elmo", "Esteban", "Frankie", "Ronald", "Tyson", "Bart", "Matt", "Tim", "Wright", "Jeffery", "Kyle", "Alessandro", "Estaban", "Kieran", "Ramses", "Casey", "Dakota", "Jared", "Kalani", "Keoni", "Lawrence", "Logan", "Robert", "Roddy", "Yasu", "Derek", "Jacob", "Bruce", "Clayton"], ["Briana", "Dawn", "Denise", "Diana", "Elaine", "Kara", "Kaylee", "Lori", "Nicole", "Nikki", "Paula", "Susie", "Wendy", "Alice", "Beth", "Beverly", "Brenda", "Dana", "Debra", "Grace", "Jenny", "Katie", "Laurel", "Linda", "Missy", "Sharon", "Tanya", "Tara", "Tisha", "Carlee", "Imani", "Isabelle", "Kyla", "Sienna", "Abigail", "Amara", "Anya", "Connie", "Maria", "Melissa", "Nora", "Shirley", "Shania", "Tiffany", "Aubree", "Cassandra", "Claire", "Crystal", "Erica", "Gabrielle", "Haley", "Jessica", "Joanna", "Lydia", "Mallory", "Mary", "Miranda", "Paige", "Sophia", "Vanessa", "Chelan", "Debbie", "Joy", "Kendra", "Leona", "Mina", "Caroline", "Joyce", "Larissa", "Rebecca", "Tyra", "Dara", "Desiree", "Kaoru", "Ruth", "Coral", "Genevieve", "Isla", "Marissa", "Romy", "Sheryl", "Alexandria", "Alicia", "Chelsea", "Jade", "Kelsie", "Laura", "Portia", "Shelby", "Sara", "Tiare", "Kyra", "Natasha", "Layla", "Scarlett", "Cora"]], [TrainerType.SWIMMER]: [[ "Berke", "Cameron", "Charlie", "George", "Harold", "Jerome", "Kirk", "Mathew", "Parker", "Randall", "Seth", "Simon", "Tucker", "Austin", "Barry", "Chad", "Cody", "Darrin", "David", "Dean", "Douglas", "Franklin", "Gilbert", "Herman", "Jack", "Luis", "Matthew", "Reed", "Richard", "Rodney", "Roland", "Spencer", "Stan", "Tony", "Clarence", "Declan", "Dominik", "Harrison", "Kevin", "Leonardo", "Nolen", "Pete", "Santiago", "Axle", "Braden", "Finn", "Garrett", "Mymo", "Reece", "Samir", "Toby", "Adrian", "Colton", "Dillon", "Erik", "Evan", "Francisco", "Glenn", "Kurt", "Oscar", "Ricardo", "Sam", "Sheltin", "Troy", "Vincent", "Wade", "Wesley", "Duane", "Elmo", "Esteban", "Frankie", "Ronald", "Tyson", "Bart", "Matt", "Tim", "Wright", "Jeffery", "Kyle", "Alessandro", "Estaban", "Kieran", "Ramses", "Casey", "Dakota", "Jared", "Kalani", "Keoni", "Lawrence", "Logan", "Robert", "Roddy", "Yasu", "Derek", "Jacob", "Bruce", "Clayton" ], [ "Briana", "Dawn", "Denise", "Diana", "Elaine", "Kara", "Kaylee", "Lori", "Nicole", "Nikki", "Paula", "Susie", "Wendy", "Alice", "Beth", "Beverly", "Brenda", "Dana", "Debra", "Grace", "Jenny", "Katie", "Laurel", "Linda", "Missy", "Sharon", "Tanya", "Tara", "Tisha", "Carlee", "Imani", "Isabelle", "Kyla", "Sienna", "Abigail", "Amara", "Anya", "Connie", "Maria", "Melissa", "Nora", "Shirley", "Shania", "Tiffany", "Aubree", "Cassandra", "Claire", "Crystal", "Erica", "Gabrielle", "Haley", "Jessica", "Joanna", "Lydia", "Mallory", "Mary", "Miranda", "Paige", "Sophia", "Vanessa", "Chelan", "Debbie", "Joy", "Kendra", "Leona", "Mina", "Caroline", "Joyce", "Larissa", "Rebecca", "Tyra", "Dara", "Desiree", "Kaoru", "Ruth", "Coral", "Genevieve", "Isla", "Marissa", "Romy", "Sheryl", "Alexandria", "Alicia", "Chelsea", "Jade", "Kelsie", "Laura", "Portia", "Shelby", "Sara", "Tiare", "Kyra", "Natasha", "Layla", "Scarlett", "Cora" ]],
[TrainerType.TWINS]: ["Amy & May", "Jo & Zoe", "Meg & Peg", "Ann & Anne", "Lea & Pia", "Amy & Liv", "Gina & Mia", "Miu & Yuki", "Tori & Tia", "Eli & Anne", "Jen & Kira", "Joy & Meg", "Kiri & Jan", "Miu & Mia", "Emma & Lil", "Liv & Liz", "Teri & Tia", "Amy & Mimi", "Clea & Gil", "Day & Dani", "Kay & Tia", "Tori & Til", "Saya & Aya", "Emy & Lin", "Kumi & Amy", "Mayo & May", "Ally & Amy", "Lia & Lily", "Rae & Ula", "Sola & Ana", "Tara & Val", "Faith & Joy", "Nana & Nina"], [TrainerType.TWINS]: [ "Amy & May", "Jo & Zoe", "Meg & Peg", "Ann & Anne", "Lea & Pia", "Amy & Liv", "Gina & Mia", "Miu & Yuki", "Tori & Tia", "Eli & Anne", "Jen & Kira", "Joy & Meg", "Kiri & Jan", "Miu & Mia", "Emma & Lil", "Liv & Liz", "Teri & Tia", "Amy & Mimi", "Clea & Gil", "Day & Dani", "Kay & Tia", "Tori & Til", "Saya & Aya", "Emy & Lin", "Kumi & Amy", "Mayo & May", "Ally & Amy", "Lia & Lily", "Rae & Ula", "Sola & Ana", "Tara & Val", "Faith & Joy", "Nana & Nina" ],
[TrainerType.VETERAN]: [["Armando", "Brenden", "Brian", "Clayton", "Edgar", "Emanuel", "Grant", "Harlan", "Terrell", "Arlen", "Chester", "Hugo", "Martell", "Ray", "Shaun", "Abraham", "Carter", "Claude", "Jerry", "Lucius", "Murphy", "Rayne", "Ron", "Sinan", "Sterling", "Vincent", "Zach", "Gerard", "Gilles", "Louis", "Timeo", "Akira", "Don", "Eric", "Harry", "Leon", "Roger", "Angus", "Aristo", "Brone", "Johnny"], ["Julia", "Karla", "Kim", "Sayuri", "Tiffany", "Cathy", "Cecile", "Chloris", "Denae", "Gina", "Maya", "Oriana", "Portia", "Rhona", "Rosaline", "Catrina", "Inga", "Trisha", "Heather", "Lynn", "Sheri", "Alonsa", "Ella", "Leticia", "Kiara"]], [TrainerType.VETERAN]: [[ "Armando", "Brenden", "Brian", "Clayton", "Edgar", "Emanuel", "Grant", "Harlan", "Terrell", "Arlen", "Chester", "Hugo", "Martell", "Ray", "Shaun", "Abraham", "Carter", "Claude", "Jerry", "Lucius", "Murphy", "Rayne", "Ron", "Sinan", "Sterling", "Vincent", "Zach", "Gerard", "Gilles", "Louis", "Timeo", "Akira", "Don", "Eric", "Harry", "Leon", "Roger", "Angus", "Aristo", "Brone", "Johnny" ], [ "Julia", "Karla", "Kim", "Sayuri", "Tiffany", "Cathy", "Cecile", "Chloris", "Denae", "Gina", "Maya", "Oriana", "Portia", "Rhona", "Rosaline", "Catrina", "Inga", "Trisha", "Heather", "Lynn", "Sheri", "Alonsa", "Ella", "Leticia", "Kiara" ]],
[TrainerType.WAITER]: [["Bert", "Clint", "Maxwell", "Lou"], ["Kati", "Aurora", "Bonita", "Flo", "Tia", "Jan", "Olwen", "Paget", "Paula", "Talia"]], [TrainerType.WAITER]: [[ "Bert", "Clint", "Maxwell", "Lou" ], [ "Kati", "Aurora", "Bonita", "Flo", "Tia", "Jan", "Olwen", "Paget", "Paula", "Talia" ]],
[TrainerType.WORKER]: [["Braden", "Brendon", "Colin", "Conrad", "Dillan", "Gary", "Gerardo", "Holden", "Jackson", "Mason", "Quentin", "Willy", "Noel", "Arnold", "Brady", "Brand", "Cairn", "Cliff", "Don", "Eddie", "Felix", "Filipe", "Glenn", "Gus", "Heath", "Matthew", "Patton", "Rich", "Rob", "Ryan", "Scott", "Shelby", "Sterling", "Tyler", "Victor", "Zack", "Friedrich", "Herman", "Isaac", "Leo", "Maynard", "Mitchell", "Morgann", "Nathan", "Niel", "Pasqual", "Paul", "Tavarius", "Tibor", "Dimitri", "Narek", "Yusif", "Frank", "Jeff", "Vaclav", "Ovid", "Francis", "Keith", "Russel", "Sangon", "Toway", "Bomber", "Chean", "Demit", "Hubor", "Kebile", "Laber", "Ordo", "Retay", "Ronix", "Wagel", "Dobit", "Kaster", "Lobel", "Releo", "Saken", "Rustix"], ["Georgia", "Sandra", "Yvonne"]], [TrainerType.WORKER]: [[ "Braden", "Brendon", "Colin", "Conrad", "Dillan", "Gary", "Gerardo", "Holden", "Jackson", "Mason", "Quentin", "Willy", "Noel", "Arnold", "Brady", "Brand", "Cairn", "Cliff", "Don", "Eddie", "Felix", "Filipe", "Glenn", "Gus", "Heath", "Matthew", "Patton", "Rich", "Rob", "Ryan", "Scott", "Shelby", "Sterling", "Tyler", "Victor", "Zack", "Friedrich", "Herman", "Isaac", "Leo", "Maynard", "Mitchell", "Morgann", "Nathan", "Niel", "Pasqual", "Paul", "Tavarius", "Tibor", "Dimitri", "Narek", "Yusif", "Frank", "Jeff", "Vaclav", "Ovid", "Francis", "Keith", "Russel", "Sangon", "Toway", "Bomber", "Chean", "Demit", "Hubor", "Kebile", "Laber", "Ordo", "Retay", "Ronix", "Wagel", "Dobit", "Kaster", "Lobel", "Releo", "Saken", "Rustix" ], [ "Georgia", "Sandra", "Yvonne" ]],
[TrainerType.YOUNGSTER]: [["Albert", "Gordon", "Ian", "Jason", "Jimmy", "Mikey", "Owen", "Samuel", "Warren", "Allen", "Ben", "Billy", "Calvin", "Dillion", "Eddie", "Joey", "Josh", "Neal", "Timmy", "Tommy", "Breyden", "Deandre", "Demetrius", "Dillon", "Jaylen", "Johnson", "Shigenobu", "Chad", "Cole", "Cordell", "Dan", "Dave", "Destin", "Nash", "Tyler", "Yasu", "Austin", "Dallas", "Darius", "Donny", "Jonathon", "Logan", "Michael", "Oliver", "Sebastian", "Tristan", "Wayne", "Norman", "Roland", "Regis", "Abe", "Astor", "Keita", "Kenneth", "Kevin", "Kyle", "Lester", "Masao", "Nicholas", "Parker", "Wes", "Zachary", "Cody", "Henley", "Jaye", "Karl", "Kenny", "Masahiro", "Pedro", "Petey", "Sinclair", "Terrell", "Waylon", "Aidan", "Anthony", "David", "Jacob", "Jayden", "Cutler", "Ham", "Caleb", "Kai", "Honus", "Kenway", "Bret", "Chris", "Cid", "Dennis", "Easton", "Ken", "Robby", "Ronny", "Shawn", "Benjamin", "Jake", "Travis", "Adan", "Aday", "Beltran", "Elian", "Hernan", "Julen", "Luka", "Roi", "Bernie", "Dustin", "Jonathan", "Wyatt"], ["Alice", "Bridget", "Carrie", "Connie", "Dana", "Ellen", "Krise", "Laura", "Linda", "Michelle", "Shannon", "Andrea", "Crissy", "Janice", "Robin", "Sally", "Tiana", "Haley", "Ali", "Ann", "Dalia", "Dawn", "Iris", "Joana", "Julia", "Kay", "Lisa", "Megan", "Mikaela", "Miriam", "Paige", "Reli", "Blythe", "Briana", "Caroline", "Cassidy", "Kaitlin", "Madeline", "Molly", "Natalie", "Samantha", "Sarah", "Cathy", "Dye", "Eri", "Eva", "Fey", "Kara", "Lurleen", "Maki", "Mali", "Maya", "Miki", "Sibyl", "Daya", "Diana", "Flo", "Helia", "Henrietta", "Isabel", "Mai", "Persephone", "Serena", "Anna", "Charlotte", "Elin", "Elsa", "Lise", "Sara", "Suzette", "Audrey", "Emmy", "Isabella", "Madison", "Rika", "Rylee", "Salla", "Ellie", "Alexandra", "Amy", "Lass", "Brittany", "Chel", "Cindy", "Dianne", "Emily", "Emma", "Evelyn", "Hana", "Harleen", "Hazel", "Jocelyn", "Katrina", "Kimberly", "Lina", "Marge", "Mila", "Mizuki", "Rena", "Sal", "Satoko", "Summer", "Tomoe", "Vicky", "Yue", "Yumi", "Lauren", "Rei", "Riley", "Lois", "Nancy", "Tammy", "Terry"]], [TrainerType.YOUNGSTER]: [[ "Albert", "Gordon", "Ian", "Jason", "Jimmy", "Mikey", "Owen", "Samuel", "Warren", "Allen", "Ben", "Billy", "Calvin", "Dillion", "Eddie", "Joey", "Josh", "Neal", "Timmy", "Tommy", "Breyden", "Deandre", "Demetrius", "Dillon", "Jaylen", "Johnson", "Shigenobu", "Chad", "Cole", "Cordell", "Dan", "Dave", "Destin", "Nash", "Tyler", "Yasu", "Austin", "Dallas", "Darius", "Donny", "Jonathon", "Logan", "Michael", "Oliver", "Sebastian", "Tristan", "Wayne", "Norman", "Roland", "Regis", "Abe", "Astor", "Keita", "Kenneth", "Kevin", "Kyle", "Lester", "Masao", "Nicholas", "Parker", "Wes", "Zachary", "Cody", "Henley", "Jaye", "Karl", "Kenny", "Masahiro", "Pedro", "Petey", "Sinclair", "Terrell", "Waylon", "Aidan", "Anthony", "David", "Jacob", "Jayden", "Cutler", "Ham", "Caleb", "Kai", "Honus", "Kenway", "Bret", "Chris", "Cid", "Dennis", "Easton", "Ken", "Robby", "Ronny", "Shawn", "Benjamin", "Jake", "Travis", "Adan", "Aday", "Beltran", "Elian", "Hernan", "Julen", "Luka", "Roi", "Bernie", "Dustin", "Jonathan", "Wyatt" ], [ "Alice", "Bridget", "Carrie", "Connie", "Dana", "Ellen", "Krise", "Laura", "Linda", "Michelle", "Shannon", "Andrea", "Crissy", "Janice", "Robin", "Sally", "Tiana", "Haley", "Ali", "Ann", "Dalia", "Dawn", "Iris", "Joana", "Julia", "Kay", "Lisa", "Megan", "Mikaela", "Miriam", "Paige", "Reli", "Blythe", "Briana", "Caroline", "Cassidy", "Kaitlin", "Madeline", "Molly", "Natalie", "Samantha", "Sarah", "Cathy", "Dye", "Eri", "Eva", "Fey", "Kara", "Lurleen", "Maki", "Mali", "Maya", "Miki", "Sibyl", "Daya", "Diana", "Flo", "Helia", "Henrietta", "Isabel", "Mai", "Persephone", "Serena", "Anna", "Charlotte", "Elin", "Elsa", "Lise", "Sara", "Suzette", "Audrey", "Emmy", "Isabella", "Madison", "Rika", "Rylee", "Salla", "Ellie", "Alexandra", "Amy", "Lass", "Brittany", "Chel", "Cindy", "Dianne", "Emily", "Emma", "Evelyn", "Hana", "Harleen", "Hazel", "Jocelyn", "Katrina", "Kimberly", "Lina", "Marge", "Mila", "Mizuki", "Rena", "Sal", "Satoko", "Summer", "Tomoe", "Vicky", "Yue", "Yumi", "Lauren", "Rei", "Riley", "Lois", "Nancy", "Tammy", "Terry" ]],
[TrainerType.HEX_MANIAC]: ["Kindra", "Patricia", "Tammy", "Tasha", "Valerie", "Alaina", "Kathleen", "Leah", "Makie", "Sylvia", "Anina", "Arachna", "Carrie", "Desdemona", "Josette", "Luna", "Melanie", "Osanna", "Raziah"], [TrainerType.HEX_MANIAC]: [ "Kindra", "Patricia", "Tammy", "Tasha", "Valerie", "Alaina", "Kathleen", "Leah", "Makie", "Sylvia", "Anina", "Arachna", "Carrie", "Desdemona", "Josette", "Luna", "Melanie", "Osanna", "Raziah" ],
}; };
// function used in a commented code // function used in a commented code
@ -140,7 +140,7 @@ function fetchAndPopulateTrainerNames(url: string, parser: DOMParser, trainerNam
if (!trainerListHeader) { if (!trainerListHeader) {
return []; return [];
} }
const elements = [...(trainerListHeader?.parentElement?.childNodes ?? [])]; const elements = [ ...(trainerListHeader?.parentElement?.childNodes ?? []) ];
const startChildIndex = elements.indexOf(trainerListHeader); const startChildIndex = elements.indexOf(trainerListHeader);
const endChildIndex = elements.findIndex(h => h.nodeName === "H2" && elements.indexOf(h) > startChildIndex); const endChildIndex = elements.findIndex(h => h.nodeName === "H2" && elements.indexOf(h) > startChildIndex);
const tables = elements.filter(t => { const tables = elements.filter(t => {
@ -152,7 +152,7 @@ function fetchAndPopulateTrainerNames(url: string, parser: DOMParser, trainerNam
}).map(t => t as Element); }).map(t => t as Element);
console.log(url, tables); console.log(url, tables);
for (const table of tables) { for (const table of tables) {
const trainerRows = [...table.querySelectorAll("tr:not(:first-child)")].filter(r => r.children.length === 9); const trainerRows = [ ...table.querySelectorAll("tr:not(:first-child)") ].filter(r => r.children.length === 9);
for (const row of trainerRows) { for (const row of trainerRows) {
const nameCell = row.firstElementChild; const nameCell = row.firstElementChild;
if (!nameCell) { if (!nameCell) {

View File

@ -171,9 +171,9 @@ export function getWeatherLapseMessage(weatherType: WeatherType): string | null
export function getWeatherDamageMessage(weatherType: WeatherType, pokemon: Pokemon): string | null { export function getWeatherDamageMessage(weatherType: WeatherType, pokemon: Pokemon): string | null {
switch (weatherType) { switch (weatherType) {
case WeatherType.SANDSTORM: case WeatherType.SANDSTORM:
return i18next.t("weather:sandstormDamageMessage", {pokemonNameWithAffix: getPokemonNameWithAffix(pokemon)}); return i18next.t("weather:sandstormDamageMessage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) });
case WeatherType.HAIL: case WeatherType.HAIL:
return i18next.t("weather:hailDamageMessage", {pokemonNameWithAffix: getPokemonNameWithAffix(pokemon)}); return i18next.t("weather:hailDamageMessage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) });
} }
return null; return null;
@ -238,9 +238,9 @@ export function getTerrainClearMessage(terrainType: TerrainType): string | null
export function getTerrainBlockMessage(pokemon: Pokemon, terrainType: TerrainType): string { export function getTerrainBlockMessage(pokemon: Pokemon, terrainType: TerrainType): string {
if (terrainType === TerrainType.MISTY) { if (terrainType === TerrainType.MISTY) {
return i18next.t("terrain:mistyBlockMessage", {pokemonNameWithAffix: getPokemonNameWithAffix(pokemon)}); return i18next.t("terrain:mistyBlockMessage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) });
} }
return i18next.t("terrain:defaultBlockMessage", {pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), terrainName: getTerrainName(terrainType)}); return i18next.t("terrain:defaultBlockMessage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), terrainName: getTerrainName(terrainType) });
} }
interface WeatherPoolEntry { interface WeatherPoolEntry {

View File

@ -1,4 +1,3 @@
export enum ArenaTagType { export enum ArenaTagType {
NONE = "NONE", NONE = "NONE",
MUD_SPORT = "MUD_SPORT", MUD_SPORT = "MUD_SPORT",
@ -25,4 +24,5 @@ export enum ArenaTagType {
SAFEGUARD = "SAFEGUARD", SAFEGUARD = "SAFEGUARD",
NO_CRIT = "NO_CRIT", NO_CRIT = "NO_CRIT",
IMPRISON = "IMPRISON", IMPRISON = "IMPRISON",
PLASMA_FISTS = "PLASMA_FISTS",
} }

View File

@ -1,4 +1,3 @@
export enum BattlerTagType { export enum BattlerTagType {
NONE = "NONE", NONE = "NONE",
RECHARGING = "RECHARGING", RECHARGING = "RECHARGING",
@ -85,4 +84,5 @@ export enum BattlerTagType {
TORMENT = "TORMENT", TORMENT = "TORMENT",
TAUNT = "TAUNT", TAUNT = "TAUNT",
IMPRISON = "IMPRISON", IMPRISON = "IMPRISON",
SYRUP_BOMB = "SYRUP_BOMB",
} }

View File

@ -1,4 +1,3 @@
export enum BerryType { export enum BerryType {
SITRUS, SITRUS,
LUM, LUM,

View File

@ -1,4 +1,3 @@
export enum Biome { export enum Biome {
TOWN, TOWN,
PLAINS, PLAINS,

View File

@ -0,0 +1,13 @@
export enum SpeciesFormKey {
MEGA = "mega",
MEGA_X = "mega-x",
MEGA_Y = "mega-y",
PRIMAL = "primal",
ORIGIN = "origin",
INCARNATE = "incarnate",
THERIAN = "therian",
GIGANTAMAX = "gigantamax",
GIGANTAMAX_SINGLE = "gigantamax-single",
GIGANTAMAX_RAPID = "gigantamax-rapid",
ETERNAMAX = "eternamax",
}

View File

@ -1,4 +1,3 @@
export enum TimeOfDay { export enum TimeOfDay {
ALL = -1, ALL = -1,
DAWN, DAWN,

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