Merge branch 'beta' into ability-refactoring

This commit is contained in:
Wlowscha 2025-01-31 00:51:27 +01:00 committed by GitHub
commit 2ff1966e06
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
113 changed files with 4530 additions and 10627 deletions

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "pokemon-rogue-battle",
"version": "1.4.3",
"version": "1.5.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "pokemon-rogue-battle",
"version": "1.4.3",
"version": "1.5.2",
"hasInstallScript": true,
"dependencies": {
"@material/material-color-utilities": "^0.2.7",

View File

@ -1,7 +1,7 @@
{
"name": "pokemon-rogue-battle",
"private": true,
"version": "1.4.3",
"version": "1.5.2",
"type": "module",
"scripts": {
"start": "vite",
@ -20,7 +20,9 @@
"depcruise": "depcruise src",
"depcruise:graph": "depcruise src --output-type dot | node dependency-graph.js > dependency-graph.svg",
"create-test": "node ./create-test-boilerplate.js",
"postinstall": "npx lefthook install && npx lefthook run post-merge"
"postinstall": "npx lefthook install && npx lefthook run post-merge",
"update-version:patch": "npm version patch --force --no-git-tag-version",
"update-version:minor": "npm version minor --force --no-git-tag-version"
},
"devDependencies": {
"@eslint/js": "^9.3.0",

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 34 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 712 B

After

Width:  |  Height:  |  Size: 748 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 29 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 713 B

After

Width:  |  Height:  |  Size: 748 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -4,6 +4,8 @@
"ffee52": "37d6de",
"debd29": "078a8f",
"833100": "002112",
"830009": "23033b",
"189d87": "c2247b",
"ff7b73": "712f8f",
"de4141": "3f1375",
"ffbdbd": "a266b0",
@ -11,6 +13,7 @@
"107b6a": "9e1976",
"105241": "4f2800",
"83de7b": "a37707",
"2e5529": "38001c",
"5a9c39": "705207",
"20b49c": "de3592",
"fdfdfd": "fdfdfd",
@ -21,14 +24,17 @@
"ffee52": "f75ea8",
"debd29": "a30a66",
"833100": "0b2e01",
"830009": "154205",
"189d87": "f17f05",
"ff7b73": "9db042",
"de4141": "3c8227",
"ffbdbd": "e7e385",
"101010": "101010",
"107b6a": "d44300",
"105241": "030129",
"83de7b": "433d99",
"5a9c39": "19164f",
"105241": "381601",
"83de7b": "80ced9",
"2e5519": "011c38",
"5a9c39": "446b94",
"20b49c": "fa8405",
"fdfdfd": "fdfdfd",
"5ad5c5": "faa405"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -1,6 +1,7 @@
{
"1": {
"843100": "033b22",
"830009": "23033b",
"ff7b73": "712f8f",
"ffbdbd": "a266b0",
"debd29": "078a8f",
@ -13,11 +14,13 @@
"5a9c3a": "b34952",
"84de7b": "ff745e",
"5ad6c5": "f062a4",
"2e5519": "38001c",
"21b59c": "de3592",
"ffffff": "ffffff"
},
"2": {
"843100": "420514",
"830009": "154205",
"ff7b73": "9db042",
"ffbdbd": "e7e385",
"debd29": "a30a66",
@ -30,6 +33,7 @@
"5a9c3a": "446b94",
"84de7b": "80ced9",
"5ad6c5": "faa405",
"2e5519": "011c38",
"21b59c": "fa8405",
"ffffff": "ffffff"
}

View File

@ -835,7 +835,7 @@
"6713": [0, 1, 1],
"8901": [1, 1, 1],
"female": {
"3": [0, 2, 1],
"3": [0, 1, 1],
"19": [0, 1, 1],
"20": [0, 1, 1],
"25": [0, 1, 1],
@ -869,6 +869,7 @@
"198": [0, 1, 1],
"203": [0, 1, 1],
"207": [0, 1, 1],
"212": [1, 1, 1],
"215": [0, 1, 1],
"217": [1, 1, 1],
"229": [0, 1, 1],
@ -1778,6 +1779,7 @@
"198": [0, 1, 1],
"203": [0, 1, 1],
"207": [0, 1, 1],
"212": [1, 1, 1],
"215": [0, 1, 1],
"217": [1, 1, 1],
"229": [0, 1, 1],

View File

@ -1,6 +1,7 @@
{
"1": {
"833100": "180136",
"830009": "23033b",
"bd6a31": "012729",
"ffee52": "37d6de",
"debd29": "078a8f",
@ -8,15 +9,18 @@
"de4141": "3f1375",
"ff7b73": "712f8f",
"ffbdbd": "a266b0",
"5a9c39": "705207",
"105241": "4f2800",
"83de7b": "a37707",
"e8a3a3": "91579e",
"5a9c39": "b34952",
"105241": "190038",
"2e5519": "38001c",
"83de7b": "ff745e",
"107b6a": "b80479",
"20b49c": "de3592",
"fdfdfd": "fdfdfd"
},
"2": {
"833100": "0b2e01",
"830009": "154205",
"bd6a31": "420514",
"ffee52": "f75ea8",
"debd29": "a30a66",
@ -24,9 +28,11 @@
"de4141": "3c8227",
"ff7b73": "9db042",
"ffbdbd": "e7e385",
"5a9c39": "19164f",
"105241": "030129",
"83de7b": "433d99",
"e8a3a3": "ced76f",
"5a9c39": "446b94",
"105241": "381601",
"2e5519": "011c38",
"83de7b": "80ced9",
"107b6a": "d15d04",
"20b49c": "fa8405",
"fdfdfd": "fdfdfd"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -1,6 +1,7 @@
{
"1": {
"843100": "033b22",
"830009": "23033b",
"ffbdbd": "a266b0",
"ff7b73": "712f8f",
"debd29": "078a8f",
@ -11,6 +12,7 @@
"105242": "190038",
"107b6b": "c21f7e",
"5a9c3a": "b34952",
"2e5519": "38001c",
"5ad6c5": "f062a4",
"21b59c": "de3592",
"84de7b": "ff745e",
@ -18,6 +20,7 @@
},
"2": {
"843100": "420514",
"830009": "154205",
"ffbdbd": "e7e385",
"ff7b73": "9db042",
"debd29": "a30a66",
@ -25,7 +28,8 @@
"de4242": "3c8227",
"101010": "101010",
"ffef52": "f75ea8",
"105242": "001a33",
"105242": "381601",
"2e5519": "011c38",
"107b6b": "d15d04",
"5a9c3a": "446b94",
"5ad6c5": "faa405",

View File

@ -9,7 +9,7 @@
"de62a4": "ffc668",
"4a83a4": "387fa7",
"314a62": "244260",
"70bbb4": "f8d371",
"548e88": "2d60bb",
"a4295a": "cc762f"
},
"1": {
@ -22,7 +22,7 @@
"de62a4": "ffdf90",
"4a83a4": "a1c8db",
"314a62": "7396b4",
"70bbb4": "70bbb4",
"548e88": "a9c0c6",
"a4295a": "e28c27"
},
"2": {
@ -35,7 +35,7 @@
"de62a4": "e25038",
"4a83a4": "e6aa47",
"314a62": "b56f2a",
"70bbb4": "f8d371",
"548e88": "e0b544",
"a4295a": "a62a21"
}
}

View File

@ -0,0 +1,41 @@
{
"0": {
"632929": "215a2d",
"f76b6b": "8cce73",
"a52929": "2f794e",
"101010": "101010",
"d63a3a": "4a9c53",
"9494a5": "9494a5",
"ffffff": "ffffff",
"b5b5ce": "b5b5ce",
"3a3a4a": "3a3a4a",
"9c6b21": "9c6b21",
"dec510": "dec510"
},
"1": {
"632929": "2f2962",
"f76b6b": "639cf7",
"a52929": "29429c",
"101010": "101010",
"d63a3a": "4263ef",
"9494a5": "6262a4",
"ffffff": "ffffff",
"b5b5ce": "b5b5ce",
"3a3a4a": "3c3c50",
"9c6b21": "131387",
"dec510": "10bdde"
},
"2": {
"632929": "645117",
"f76b6b": "c59f29",
"a52929": "b88619",
"101010": "101010",
"d63a3a": "ffca2a",
"9494a5": "3c4543",
"ffffff": "ffffff",
"b5b5ce": "b5b5ce",
"3a3a4a": "282d2c",
"9c6b21": "9c6b21",
"dec510": "dec510"
}
}

View File

@ -1,6 +1,7 @@
{
"1": {
"843100": "033b22",
"830009": "23033b",
"ffbdbd": "a266b0",
"ffef52": "37d6de",
"debd29": "078a8f",
@ -10,6 +11,7 @@
"101010": "101010",
"105242": "190038",
"107b6b": "9e1976",
"2e5519": "38001c",
"5a9c3a": "b34952",
"5ad6c5": "f062a4",
"21b59c": "de3592",
@ -18,6 +20,7 @@
},
"2": {
"843100": "420514",
"830009": "154205",
"ffbdbd": "e7e385",
"ffef52": "f75ea8",
"debd29": "a30a66",
@ -27,6 +30,7 @@
"101010": "101010",
"105242": "381601",
"107b6b": "d15d04",
"2e5519": "011c38",
"5a9c3a": "446b94",
"5ad6c5": "faa405",
"21b59c": "fa8405",

View File

@ -8,7 +8,7 @@
"0f0f0f": "0f0f0f",
"314a62": "244260",
"621841": "71370f",
"70bbb4": "f8d371",
"548e88": "2d60bb",
"de62a4": "ffc668",
"a4295a": "cc762f"
},
@ -21,7 +21,7 @@
"0f0f0f": "0f0f0f",
"314a62": "7396b4",
"621841": "7b3c08",
"70bbb4": "70bbb4",
"548e88": "a9c0c6",
"de62a4": "ffdf90",
"a4295a": "e28c27"
},
@ -34,7 +34,7 @@
"0f0f0f": "0f0f0f",
"314a62": "b56f2a",
"621841": "5a0a05",
"70bbb4": "f8d371",
"548e88": "e0b544",
"de62a4": "e25038",
"a4295a": "a62a21"
}

View File

@ -0,0 +1,41 @@
{
"0": {
"632929": "215a2d",
"f76b6b": "8cce73",
"101010": "101010",
"3a3a4a": "3a3a4a",
"ffffff": "ffffff",
"d63a3a": "4a9c53",
"b5b5ce": "b5b5ce",
"9494a5": "9494a5",
"a52929": "2f794e",
"dec510": "dec510",
"9c6b21": "9c6b21"
},
"1": {
"632929": "2f2962",
"f76b6b": "639cf7",
"101010": "101010",
"3a3a4a": "3c3c50",
"ffffff": "ffffff",
"d63a3a": "4263ef",
"b5b5ce": "b5b5ce",
"9494a5": "6262a4",
"a52929": "29429c",
"dec510": "10bdde",
"9c6b21": "131387"
},
"2": {
"632929": "645117",
"f76b6b": "c59f29",
"101010": "101010",
"3a3a4a": "282d2c",
"ffffff": "ffffff",
"d63a3a": "ffca2a",
"b5b5ce": "b5b5ce",
"9494a5": "3c4543",
"a52929": "b88619",
"dec510": "dec510",
"9c6b21": "9c6b21"
}
}

View File

@ -1,19 +1,41 @@
{
"1": {
"843100": "033b22",
"830009": "23033b",
"ffbdbd": "a266b0",
"ffef52": "37d6de",
"debd29": "078a8f",
"ff7b73": "712f8f",
"bd6b31": "168a69",
"de4242": "3f1375",
"101010": "101010",
"105242": "190038",
"107b6b": "9e1976",
"2e5519": "38001c",
"5a9c3a": "b34952",
"5ad6c5": "f062a4",
"21b59c": "de3592",
"84de7b": "ff745e",
"ffffff": "ffffff"
},
"2": {
"843100": "420514",
"ff7b73": "9db042",
"830009": "154205",
"ffbdbd": "e7e385",
"ffef52": "f75ea8",
"debd29": "a30a66",
"ff7b73": "9db042",
"bd6b31": "852a41",
"de4242": "3c8227",
"101010": "101010",
"105242": "381601",
"107b6b": "d44300",
"107b6b": "d15d04",
"2e5519": "011c38",
"5a9c3a": "446b94",
"84de7b": "80ced9",
"5ad6c5": "faa405",
"21b59c": "fa8405",
"ffffff": "ffffff"
"84de7b": "80ced9",
"ffffff": "ffffff",
"2f561a": "011b34"
}
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 865 B

After

Width:  |  Height:  |  Size: 985 B

@ -1 +1 @@
Subproject commit acad8499a4ca488a9871902de140f635235f309a
Subproject commit 5ef993b95fa8248adc0fb7d9489baccf546bf8e3

View File

@ -112,7 +112,7 @@ import { ExpGainsSpeed } from "#enums/exp-gains-speed";
import { BattlerTagType } from "#enums/battler-tag-type";
import { FRIENDSHIP_GAIN_FROM_BATTLE } from "#app/data/balance/starters";
import { StatusEffect } from "#enums/status-effect";
import { globalScene, initGlobalScene } from "#app/global-scene";
import { initGlobalScene } from "#app/global-scene";
export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1";
@ -363,28 +363,30 @@ export default class BattleScene extends SceneBase {
/**
* Load the variant assets for the given sprite and stores them in {@linkcode variantColorCache}
*/
loadPokemonVariantAssets(spriteKey: string, fileRoot: string, variant?: Variant) {
public async loadPokemonVariantAssets(spriteKey: string, fileRoot: string, variant?: Variant): Promise<void> {
const useExpSprite = this.experimentalSprites && this.hasExpSprite(spriteKey);
if (useExpSprite) {
fileRoot = `exp/${fileRoot}`;
}
let variantConfig = variantData;
fileRoot.split("/").map(p => variantConfig ? variantConfig = variantConfig[p] : null);
fileRoot.split("/").map((p) => (variantConfig ? (variantConfig = variantConfig[p]) : null));
const variantSet = variantConfig as VariantSet;
if (variantSet && (variant !== undefined && variantSet[variant] === 1)) {
const populateVariantColors = (key: string): Promise<void> => {
return new Promise(resolve => {
if (variantColorCache.hasOwnProperty(key)) {
return resolve();
}
this.cachedFetch(`./images/pokemon/variant/${fileRoot}.json`).then(res => res.json()).then(c => {
variantColorCache[key] = c;
return new Promise<void>((resolve) => {
if (variantSet && variant !== undefined && variantSet[variant] === 1) {
if (variantColorCache.hasOwnProperty(spriteKey)) {
return resolve();
}
this.cachedFetch(`./images/pokemon/variant/${fileRoot}.json`)
.then((res) => res.json())
.then((c) => {
variantColorCache[spriteKey] = c;
resolve();
});
});
};
populateVariantColors(spriteKey);
}
} else {
resolve();
}
});
}
async preload() {
@ -392,10 +394,10 @@ export default class BattleScene extends SceneBase {
const originalRealInRange = Phaser.Math.RND.realInRange;
Phaser.Math.RND.realInRange = function (min: number, max: number): number {
const ret = originalRealInRange.apply(this, [ min, max ]);
const args = [ "RNG", ++globalScene.rngCounter, ret / (max - min), `min: ${min} / max: ${max}` ];
args.push(`seed: ${globalScene.rngSeedOverride || globalScene.waveSeed || globalScene.seed}`);
if (globalScene.rngOffset) {
args.push(`offset: ${globalScene.rngOffset}`);
const args = [ "RNG", ++this.rngCounter, ret / (max - min), `min: ${min} / max: ${max}` ];
args.push(`seed: ${this.rngSeedOverride || this.waveSeed || this.seed}`);
if (this.rngOffset) {
args.push(`offset: ${this.rngOffset}`);
}
console.log(...args);
return ret;
@ -408,7 +410,7 @@ export default class BattleScene extends SceneBase {
}
create() {
globalScene.scene.remove(LoadingScene.KEY);
this.scene.remove(LoadingScene.KEY);
initGameSpeed.apply(this);
this.inputController = new InputsController();
this.uiInputs = new UiInputs(this.inputController);
@ -867,6 +869,12 @@ export default class BattleScene extends SceneBase {
return party.slice(0, Math.min(party.length, this.currentBattle?.double ? 2 : 1));
}
/**
* Returns an array of Pokemon on both sides of the battle - player first, then enemy.
* Does not actually check if the pokemon are on the field or not, and always has length 4 regardless of battle type.
* @param activeOnly Whether to consider only active pokemon
* @returns array of {@linkcode Pokemon}
*/
public getField(activeOnly: boolean = false): Pokemon[] {
const ret = new Array(4).fill(null);
const playerField = this.getPlayerField();
@ -1482,6 +1490,8 @@ export default class BattleScene extends SceneBase {
return 0; // Don't give trainers Battle Bond Greninja
}
return Utils.randSeedInt(2);
case Species.URSHIFU:
return Utils.randSeedInt(2);
case Species.ZYGARDE:
return Utils.randSeedInt(4);
case Species.MINIOR:
@ -1841,8 +1851,10 @@ export default class BattleScene extends SceneBase {
this.currentBattle.battleScore += Math.ceil(scoreIncrease);
}
getMaxExpLevel(ignoreLevelCap?: boolean): integer {
if (ignoreLevelCap) {
getMaxExpLevel(ignoreLevelCap: boolean = false): integer {
if (Overrides.LEVEL_CAP_OVERRIDE > 0) {
return Overrides.LEVEL_CAP_OVERRIDE;
} else if (ignoreLevelCap || Overrides.LEVEL_CAP_OVERRIDE < 0) {
return Number.MAX_SAFE_INTEGER;
}
const waveIndex = Math.ceil((this.currentBattle?.waveIndex || 1) / 10) * 10;
@ -2080,8 +2092,11 @@ export default class BattleScene extends SceneBase {
return sound;
}
/** The loop point of any given battle, mystery encounter, or title track, read as seconds and milliseconds. */
getBgmLoopPoint(bgmName: string): number {
switch (bgmName) {
case "title": //Firel PokéRogue Title
return 46.500;
case "battle_kanto_champion": //B2W2 Kanto Champion Battle
return 13.950;
case "battle_johto_champion": //B2W2 Johto Champion Battle
@ -2952,7 +2967,7 @@ export default class BattleScene extends SceneBase {
*/
applyShuffledModifiers<T extends PersistentModifier>(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));
globalScene.executeWithSeedOffset(() => {
this.executeWithSeedOffset(() => {
const shuffleModifiers = mods => {
if (mods.length < 1) {
return mods;
@ -2961,7 +2976,7 @@ export default class BattleScene extends SceneBase {
return [ mods[rand], ...shuffleModifiers(mods.filter((_, i) => i !== rand)) ];
};
modifiers = shuffleModifiers(modifiers);
}, globalScene.currentBattle.turn << 4, globalScene.waveSeed);
}, this.currentBattle.turn << 4, this.waveSeed);
return this.applyModifiersInternal(modifiers, player, args);
}
@ -3386,7 +3401,8 @@ export default class BattleScene extends SceneBase {
const previousEncounter = this.mysteryEncounterSaveData.encounteredEvents.length > 0 ?
this.mysteryEncounterSaveData.encounteredEvents[this.mysteryEncounterSaveData.encounteredEvents.length - 1].type
: null;
const biomeMysteryEncounters = mysteryEncountersByBiome.get(this.arena.biomeType) ?? [];
const disabledEncounters = this.eventManager.getEventMysteryEncountersDisabled();
const biomeMysteryEncounters = mysteryEncountersByBiome.get(this.arena.biomeType)?.filter(enc => !disabledEncounters.includes(enc)) ?? [];
// If no valid encounters exist at tier, checks next tier down, continuing until there are some encounters available
while (availableEncounters.length === 0 && tier !== null) {
availableEncounters = biomeMysteryEncounters
@ -3395,7 +3411,7 @@ export default class BattleScene extends SceneBase {
if (!encounterCandidate) {
return false;
}
if (encounterCandidate.encounterTier !== tier) {
if (this.eventManager.getMysteryEncounterTierForEvent(encounterType, encounterCandidate.encounterTier) !== tier) {
return false;
}
const disallowedGameModes = encounterCandidate.disallowedGameModes;

View File

@ -24,9 +24,26 @@ import { ModifierTier } from "#app/modifier/modifier-tier";
import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
export enum ClassicFixedBossWaves {
// TODO: other fixed wave battles should be added here
TOWN_YOUNGSTER = 5,
RIVAL_1 = 8,
RIVAL_2 = 25,
EVIL_GRUNT_1 = 35,
RIVAL_3 = 55,
EVIL_GRUNT_2 = 62,
EVIL_GRUNT_3 = 64,
EVIL_ADMIN_1 = 66,
RIVAL_4 = 95,
EVIL_GRUNT_4 = 112,
EVIL_ADMIN_2 = 114,
EVIL_BOSS_1 = 115,
RIVAL_5 = 145,
EVIL_BOSS_2 = 165,
ELITE_FOUR_1 = 182,
ELITE_FOUR_2 = 184,
ELITE_FOUR_3 = 186,
ELITE_FOUR_4 = 188,
CHAMPION = 190,
RIVAL_6 = 195,
}
export enum BattleType {
@ -500,7 +517,7 @@ export class FixedBattleConfig {
* @param seedOffset the seed offset to use for the random generation of the trainer
* @returns the generated trainer
*/
function getRandomTrainerFunc(trainerPool: (TrainerType | TrainerType[])[], randomGender: boolean = false, seedOffset: number = 0): GetTrainerFunc {
export function getRandomTrainerFunc(trainerPool: (TrainerType | TrainerType[])[], randomGender: boolean = false, seedOffset: number = 0): GetTrainerFunc {
return () => {
const rand = Utils.randSeedInt(trainerPool.length);
const trainerTypes: TrainerType[] = [];
@ -544,51 +561,51 @@ export interface FixedBattleConfigs {
* Champion on 190
*/
export const classicFixedBattles: FixedBattleConfigs = {
[5]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
[ClassicFixedBossWaves.TOWN_YOUNGSTER]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
.setGetTrainerFunc(() => new Trainer(TrainerType.YOUNGSTER, Utils.randSeedInt(2) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)),
[8]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
[ClassicFixedBossWaves.RIVAL_1]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
.setGetTrainerFunc(() => new Trainer(TrainerType.RIVAL, globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)),
[25]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
[ClassicFixedBossWaves.RIVAL_2]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
.setGetTrainerFunc(() => new Trainer(TrainerType.RIVAL_2, globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT))
.setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT ], allowLuckUpgrades: false }),
[35]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
[ClassicFixedBossWaves.EVIL_GRUNT_1]: 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)),
[55]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
[ClassicFixedBossWaves.RIVAL_3]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
.setGetTrainerFunc(() => new Trainer(TrainerType.RIVAL_3, globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT))
.setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT ], allowLuckUpgrades: false }),
[62]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
[ClassicFixedBossWaves.EVIL_GRUNT_2]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1)
.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)
[ClassicFixedBossWaves.EVIL_GRUNT_3]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1)
.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)
[ClassicFixedBossWaves.EVIL_ADMIN_1]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_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)),
[95]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
[ClassicFixedBossWaves.RIVAL_4]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
.setGetTrainerFunc(() => new Trainer(TrainerType.RIVAL_4, globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT))
.setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA ], allowLuckUpgrades: false }),
[112]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
[ClassicFixedBossWaves.EVIL_GRUNT_4]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1)
.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)
[ClassicFixedBossWaves.EVIL_ADMIN_2]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_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(ClassicFixedBossWaves.EVIL_GRUNT_1)
.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 }),
[145]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
[ClassicFixedBossWaves.RIVAL_5]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
.setGetTrainerFunc(() => new Trainer(TrainerType.RIVAL_5, globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT))
.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(ClassicFixedBossWaves.EVIL_GRUNT_1)
.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 }),
[182]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
[ClassicFixedBossWaves.ELITE_FOUR_1]: 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 ])),
[184]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182)
[ClassicFixedBossWaves.ELITE_FOUR_2]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(ClassicFixedBossWaves.ELITE_FOUR_1)
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.BRUNO, TrainerType.KOGA, TrainerType.PHOEBE, TrainerType.BERTHA, TrainerType.MARSHAL, TrainerType.SIEBOLD, TrainerType.OLIVIA, TrainerType.NESSA_ELITE, TrainerType.POPPY, TrainerType.AMARYS ])),
[186]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182)
[ClassicFixedBossWaves.ELITE_FOUR_3]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(ClassicFixedBossWaves.ELITE_FOUR_1)
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.AGATHA, TrainerType.BRUNO, TrainerType.GLACIA, TrainerType.FLINT, TrainerType.GRIMSLEY, TrainerType.WIKSTROM, TrainerType.ACEROLA, [ TrainerType.BEA_ELITE, TrainerType.ALLISTER_ELITE ], TrainerType.LARRY_ELITE, TrainerType.LACEY ])),
[188]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182)
[ClassicFixedBossWaves.ELITE_FOUR_4]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(ClassicFixedBossWaves.ELITE_FOUR_1)
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.LANCE, TrainerType.KAREN, TrainerType.DRAKE, TrainerType.LUCIAN, TrainerType.CAITLIN, TrainerType.DRASNA, TrainerType.KAHILI, TrainerType.RAIHAN_ELITE, TrainerType.HASSEL, TrainerType.DRAYTON ])),
[190]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182)
[ClassicFixedBossWaves.CHAMPION]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(ClassicFixedBossWaves.ELITE_FOUR_1)
.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)
[ClassicFixedBossWaves.RIVAL_6]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
.setGetTrainerFunc(() => new Trainer(TrainerType.RIVAL_6, globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT))
.setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT ], allowLuckUpgrades: false })
};

View File

@ -16,7 +16,7 @@ import type { ArenaTrapTag } from "./arena-tag";
import { ArenaTagSide } from "./arena-tag";
import { BerryModifier, HitHealModifier, PokemonHeldItemModifier } from "../modifier/modifier";
import { TerrainType } from "./terrain";
import { SpeciesFormChangeManualTrigger, SpeciesFormChangeRevertWeatherFormTrigger, SpeciesFormChangeWeatherTrigger } from "./pokemon-forms";
import { SpeciesFormChangeAbilityTrigger, SpeciesFormChangeRevertWeatherFormTrigger, SpeciesFormChangeWeatherTrigger } from "./pokemon-forms";
import i18next from "i18next";
import type { Localizable } from "#app/interfaces/locales";
import { Command } from "../ui/command-ui-handler";
@ -232,7 +232,7 @@ export class PostBattleInitFormChangeAbAttr extends PostBattleInitAbAttr {
applyPostBattleInit(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean {
const formIndex = this.formFunc(pokemon);
if (formIndex !== pokemon.formIndex && !simulated) {
return globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false);
return globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeAbilityTrigger, false);
}
return false;
@ -1875,7 +1875,7 @@ export class PostVictoryFormChangeAbAttr extends PostVictoryAbAttr {
const formIndex = this.formFunc(pokemon);
if (formIndex !== pokemon.formIndex) {
if (!simulated) {
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false);
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeAbilityTrigger, false);
}
return true;
}
@ -2306,7 +2306,7 @@ export class PostSummonFormChangeAbAttr extends PostSummonAbAttr {
applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean {
const formIndex = this.formFunc(pokemon);
if (formIndex !== pokemon.formIndex) {
return simulated || globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false);
return simulated || globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeAbilityTrigger, false);
}
return false;
@ -2685,7 +2685,7 @@ export class PreSwitchOutFormChangeAbAttr extends PreSwitchOutAbAttr {
const formIndex = this.formFunc(pokemon);
if (formIndex !== pokemon.formIndex) {
if (!simulated) {
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false);
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeAbilityTrigger, false);
}
return true;
}
@ -3716,7 +3716,7 @@ export class PostTurnFormChangeAbAttr extends PostTurnAbAttr {
const formIndex = this.formFunc(pokemon);
if (formIndex !== pokemon.formIndex) {
if (!simulated) {
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false);
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeAbilityTrigger, false);
}
return true;
@ -5960,12 +5960,14 @@ export function initAbilities() {
.attr(PostBattleInitFormChangeAbAttr, () => 0)
.attr(PostSummonFormChangeAbAttr, p => p.formIndex % 7 + (p.getHpRatio() <= 0.5 ? 7 : 0))
.attr(PostTurnFormChangeAbAttr, p => p.formIndex % 7 + (p.getHpRatio() <= 0.5 ? 7 : 0))
.conditionalAttr(p => p.formIndex !== 7, StatusEffectImmunityAbAttr)
.conditionalAttr(p => p.formIndex !== 7, BattlerTagImmunityAbAttr, BattlerTagType.DROWSY)
.attr(UncopiableAbilityAbAttr)
.attr(UnswappableAbilityAbAttr)
.attr(UnsuppressableAbilityAbAttr)
.attr(NoFusionAbilityAbAttr)
.bypassFaint()
.partial(), // Meteor form should protect against status effects and yawn
.attr(NoTransformAbilityAbAttr)
.bypassFaint(),
new Ability(Abilities.STAKEOUT, 7)
.attr(MovePowerBoostAbAttr, (user, target, move) => !!target?.turnData.switchedInThisTurn, 2),
new Ability(Abilities.WATER_BUBBLE, 7)

File diff suppressed because it is too large Load Diff

View File

@ -12,6 +12,8 @@ import { Species } from "#enums/species";
import { TimeOfDay } from "#enums/time-of-day";
import { DamageMoneyRewardModifier, ExtraModifierModifier, MoneyMultiplierModifier, TempExtraModifierModifier } from "#app/modifier/modifier";
import { SpeciesFormKey } from "#enums/species-form-key";
import { speciesStarterCosts } from "./starters";
import i18next from "i18next";
export enum SpeciesWildEvolutionDelay {
@ -120,17 +122,214 @@ export class FusionSpeciesFormEvolution extends SpeciesFormEvolution {
export class SpeciesEvolutionCondition {
public predicate: EvolutionConditionPredicate;
public enforceFunc: EvolutionConditionEnforceFunc | undefined;
public enforceFunc?: EvolutionConditionEnforceFunc;
public description: string;
constructor(predicate: EvolutionConditionPredicate, enforceFunc?: EvolutionConditionEnforceFunc) {
this.predicate = predicate;
this.enforceFunc = enforceFunc;
this.description = "";
}
}
export class SpeciesFriendshipEvolutionCondition extends SpeciesEvolutionCondition {
constructor(friendshipAmount: integer, predicate?: EvolutionConditionPredicate, enforceFunc?: EvolutionConditionEnforceFunc) {
super(p => p.friendship >= friendshipAmount && (!predicate || predicate(p)), enforceFunc);
class GenderEvolutionCondition extends SpeciesEvolutionCondition {
public gender: Gender;
constructor(gender: Gender) {
super(p => p.gender === gender, p => p.gender = gender);
this.gender = gender;
this.description = i18next.t("pokemonEvolutions:gender", { gender: i18next.t(`pokemonEvolutions:${Gender[gender]}`) });
}
}
class TimeOfDayEvolutionCondition extends SpeciesEvolutionCondition {
public timesOfDay: TimeOfDay[];
constructor(tod: "day" | "night") {
if (tod === "day") {
super(() => globalScene.arena.getTimeOfDay() === TimeOfDay.DAWN || globalScene.arena.getTimeOfDay() === TimeOfDay.DAY);
this.timesOfDay = [ TimeOfDay.DAWN, TimeOfDay.DAY ];
} else if (tod === "night") {
super(() => globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT);
this.timesOfDay = [ TimeOfDay.DUSK, TimeOfDay.NIGHT ];
} else {
super(() => false);
this.timesOfDay = [];
}
this.description = i18next.t("pokemonEvolutions:timeOfDay", { tod: i18next.t(`pokemonEvolutions:${tod}`) });
}
}
class MoveEvolutionCondition extends SpeciesEvolutionCondition {
public move: Moves;
constructor(move: Moves) {
super(p => p.moveset.filter(m => m?.moveId === move).length > 0);
this.move = move;
const moveKey = Moves[this.move].split("_").filter(f => f).map((f, i) => i ? `${f[0]}${f.slice(1).toLowerCase()}` : f.toLowerCase()).join("");
this.description = i18next.t("pokemonEvolutions:move", { move: i18next.t(`move:${moveKey}.name`) });
}
}
class FriendshipEvolutionCondition extends SpeciesEvolutionCondition {
public amount: integer;
constructor(amount: number) {
super(p => p.friendship >= amount);
this.amount = amount;
this.description = i18next.t("pokemonEvolutions:friendship");
}
}
class FriendshipTimeOfDayEvolutionCondition extends SpeciesEvolutionCondition {
public amount: integer;
public timesOfDay: TimeOfDay[];
constructor(amount: number, tod: "day" | "night") {
if (tod === "day") {
super(p => p.friendship >= amount && (globalScene.arena.getTimeOfDay() === TimeOfDay.DAWN || globalScene.arena.getTimeOfDay() === TimeOfDay.DAY));
this.timesOfDay = [ TimeOfDay.DAWN, TimeOfDay.DAY ];
} else if (tod === "night") {
super(p => p.friendship >= amount && (globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT));
this.timesOfDay = [ TimeOfDay.DUSK, TimeOfDay.NIGHT ];
} else {
super(p => false);
this.timesOfDay = [];
}
this.amount = amount;
this.description = i18next.t("pokemonEvolutions:friendshipTimeOfDay", { tod: i18next.t(`pokemonEvolutions:${tod}`) });
}
}
class FriendshipMoveTypeEvolutionCondition extends SpeciesEvolutionCondition {
public amount: integer;
public type: Type;
constructor(amount: number, type: Type) {
super(p => p.friendship >= amount && !!p.getMoveset().find(m => m?.getMove().type === type));
this.amount = amount;
this.type = type;
this.description = i18next.t("pokemonEvolutions:friendshipMoveType", { type: i18next.t(`pokemonInfo:Type.${Type[this.type]}`) });
}
}
class ShedinjaEvolutionCondition extends SpeciesEvolutionCondition {
constructor() {
super(() => globalScene.getPlayerParty().length < 6 && globalScene.pokeballCounts[PokeballType.POKEBALL] > 0);
this.description = i18next.t("pokemonEvolutions:shedinja");
}
}
class PartyTypeEvolutionCondition extends SpeciesEvolutionCondition {
public type: Type;
constructor(type: Type) {
super(() => !!globalScene.getPlayerParty().find(p => p.getTypes(false, false, true).indexOf(type) > -1));
this.type = type;
this.description = i18next.t("pokemonEvolutions:partyType", { type: i18next.t(`pokemonInfo:Type.${Type[this.type]}`) });
}
}
class CaughtEvolutionCondition extends SpeciesEvolutionCondition {
public species: Species;
constructor(species: Species) {
super(() => !!globalScene.gameData.dexData[species].caughtAttr);
this.species = species;
this.description = i18next.t("pokemonEvolutions:caught", { species: i18next.t(`pokemon:${Species[this.species].toLowerCase()}`) });
}
}
class WeatherEvolutionCondition extends SpeciesEvolutionCondition {
public weatherTypes: WeatherType[];
constructor(weatherTypes: WeatherType[]) {
super(() => weatherTypes.indexOf(globalScene.arena.weather?.weatherType || WeatherType.NONE) > -1);
this.weatherTypes = weatherTypes;
}
}
class MoveTypeEvolutionCondition extends SpeciesEvolutionCondition {
public type: Type;
constructor(type: Type) {
super(p => p.moveset.filter(m => m?.getMove().type === type).length > 0);
this.type = type;
this.description = i18next.t("pokemonEvolutions:moveType", { type: i18next.t(`pokemonInfo:Type.${Type[this.type]}`) });
}
}
class TreasureEvolutionCondition extends SpeciesEvolutionCondition {
constructor() {
super(p => p.evoCounter
+ p.getHeldItems().filter(m => m instanceof DamageMoneyRewardModifier).length
+ globalScene.findModifiers(m => m instanceof MoneyMultiplierModifier
|| m instanceof ExtraModifierModifier || m instanceof TempExtraModifierModifier).length > 9);
this.description = i18next.t("pokemonEvolutions:treasure");
}
}
class TyrogueEvolutionCondition extends SpeciesEvolutionCondition {
public move: Moves;
constructor(move: Moves) {
super(p =>
p.getMoveset(true).find(m => m && [ Moves.LOW_SWEEP, Moves.MACH_PUNCH, Moves.RAPID_SPIN ].includes(m?.moveId))?.moveId === move);
this.move = move;
const moveKey = Moves[this.move].split("_").filter(f => f).map((f, i) => i ? `${f[0]}${f.slice(1).toLowerCase()}` : f.toLowerCase()).join("");
this.description = i18next.t("pokemonEvolutions:move", { move: i18next.t(`move:${moveKey}.name`) });
}
}
class NatureEvolutionCondition extends SpeciesEvolutionCondition {
public natures: Nature[];
constructor(natures: Nature[]) {
super(p => natures.indexOf(p.getNature()) > -1);
this.natures = natures;
this.description = i18next.t("pokemonEvolutions:nature");
}
}
class MoveTimeOfDayEvolutionCondition extends SpeciesEvolutionCondition {
public move: Moves;
public timesOfDay: TimeOfDay[];
constructor(move: Moves, tod: "day" | "night") {
if (tod === "day") {
super(p => p.moveset.filter(m => m?.moveId === move).length > 0 && (globalScene.arena.getTimeOfDay() === TimeOfDay.DAWN || globalScene.arena.getTimeOfDay() === TimeOfDay.DAY));
this.move = move;
this.timesOfDay = [ TimeOfDay.DAWN, TimeOfDay.DAY ];
} else if (tod === "night") {
super(p => p.moveset.filter(m => m?.moveId === move).length > 0 && (globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT));
this.move = move;
this.timesOfDay = [ TimeOfDay.DUSK, TimeOfDay.NIGHT ];
} else {
super(() => false);
this.timesOfDay = [];
}
const moveKey = Moves[this.move].split("_").filter(f => f).map((f, i) => i ? `${f[0]}${f.slice(1).toLowerCase()}` : f.toLowerCase()).join("");
this.description = i18next.t("pokemonEvolutions:moveTimeOfDay", { move: i18next.t(`move:${moveKey}.name`), tod: i18next.t(`pokemonEvolutions:${tod}`) });
}
}
class BiomeEvolutionCondition extends SpeciesEvolutionCondition {
public biomes: Biome[];
constructor(biomes: Biome[]) {
super(() => biomes.filter(b => b === globalScene.arena.biomeType).length > 0);
this.biomes = biomes;
this.description = i18next.t("pokemonEvolutions:biome");
}
}
class DunsparceEvolutionCondition extends SpeciesEvolutionCondition {
constructor() {
super(p => {
let ret = false;
if (p.moveset.filter(m => m?.moveId === Moves.HYPER_DRILL).length > 0) {
globalScene.executeWithSeedOffset(() => ret = !Utils.randSeedInt(4), p.id);
}
return ret;
});
const moveKey = Moves[Moves.HYPER_DRILL].split("_").filter(f => f).map((f, i) => i ? `${f[0]}${f.slice(1).toLowerCase()}` : f.toLowerCase()).join("");
this.description = i18next.t("pokemonEvolutions:move", { move: i18next.t(`move:${moveKey}.name`) });
}
}
class TandemausEvolutionCondition extends SpeciesEvolutionCondition {
constructor() {
super(p => {
let ret = false;
globalScene.executeWithSeedOffset(() => ret = !Utils.randSeedInt(4), p.id);
return ret;
});
}
}
@ -267,8 +466,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.ELECTRODE, 30, null, null)
],
[Species.CUBONE]: [
new SpeciesEvolution(Species.ALOLA_MAROWAK, 28, null, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT)),
new SpeciesEvolution(Species.MAROWAK, 28, null, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DAWN || globalScene.arena.getTimeOfDay() === TimeOfDay.DAY))
new SpeciesEvolution(Species.ALOLA_MAROWAK, 28, null, new TimeOfDayEvolutionCondition("night")),
new SpeciesEvolution(Species.MAROWAK, 28, null, new TimeOfDayEvolutionCondition("day"))
],
[Species.TYROGUE]: [
/**
@ -277,19 +476,13 @@ export const pokemonEvolutions: PokemonEvolutions = {
* If Tyrogue knows multiple of these moves, its evolution is based on
* the first qualifying move in its moveset.
*/
new SpeciesEvolution(Species.HITMONLEE, 20, null, new SpeciesEvolutionCondition(p =>
p.getMoveset(true).find(move => move && [ Moves.LOW_SWEEP, Moves.MACH_PUNCH, Moves.RAPID_SPIN ].includes(move?.moveId))?.moveId === Moves.LOW_SWEEP
)),
new SpeciesEvolution(Species.HITMONCHAN, 20, null, new SpeciesEvolutionCondition(p =>
p.getMoveset(true).find(move => move && [ Moves.LOW_SWEEP, Moves.MACH_PUNCH, Moves.RAPID_SPIN ].includes(move?.moveId))?.moveId === Moves.MACH_PUNCH
)),
new SpeciesEvolution(Species.HITMONTOP, 20, null, new SpeciesEvolutionCondition(p =>
p.getMoveset(true).find(move => move && [ Moves.LOW_SWEEP, Moves.MACH_PUNCH, Moves.RAPID_SPIN ].includes(move?.moveId))?.moveId === Moves.RAPID_SPIN
)),
new SpeciesEvolution(Species.HITMONLEE, 20, null, new TyrogueEvolutionCondition(Moves.LOW_SWEEP)),
new SpeciesEvolution(Species.HITMONCHAN, 20, null, new TyrogueEvolutionCondition(Moves.MACH_PUNCH)),
new SpeciesEvolution(Species.HITMONTOP, 20, null, new TyrogueEvolutionCondition(Moves.RAPID_SPIN)),
],
[Species.KOFFING]: [
new SpeciesEvolution(Species.GALAR_WEEZING, 35, null, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT)),
new SpeciesEvolution(Species.WEEZING, 35, null, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DAWN || globalScene.arena.getTimeOfDay() === TimeOfDay.DAY))
new SpeciesEvolution(Species.GALAR_WEEZING, 35, null, new TimeOfDayEvolutionCondition("night")),
new SpeciesEvolution(Species.WEEZING, 35, null, new TimeOfDayEvolutionCondition("day"))
],
[Species.RHYHORN]: [
new SpeciesEvolution(Species.RHYDON, 42, null, null)
@ -334,8 +527,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.QUILAVA, 14, null, null)
],
[Species.QUILAVA]: [
new SpeciesEvolution(Species.HISUI_TYPHLOSION, 36, null, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT)),
new SpeciesEvolution(Species.TYPHLOSION, 36, null, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DAWN || globalScene.arena.getTimeOfDay() === TimeOfDay.DAY))
new SpeciesEvolution(Species.HISUI_TYPHLOSION, 36, null, new TimeOfDayEvolutionCondition("night")),
new SpeciesEvolution(Species.TYPHLOSION, 36, null, new TimeOfDayEvolutionCondition("day"))
],
[Species.TOTODILE]: [
new SpeciesEvolution(Species.CROCONAW, 18, null, null)
@ -437,8 +630,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.LINOONE, 20, null, null)
],
[Species.WURMPLE]: [
new SpeciesEvolution(Species.SILCOON, 7, null, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DAWN || globalScene.arena.getTimeOfDay() === TimeOfDay.DAY)),
new SpeciesEvolution(Species.CASCOON, 7, null, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT))
new SpeciesEvolution(Species.SILCOON, 7, null, new TimeOfDayEvolutionCondition("day")),
new SpeciesEvolution(Species.CASCOON, 7, null, new TimeOfDayEvolutionCondition("night"))
],
[Species.SILCOON]: [
new SpeciesEvolution(Species.BEAUTIFLY, 10, null, null)
@ -462,8 +655,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.KIRLIA, 20, null, null)
],
[Species.KIRLIA]: [
new SpeciesEvolution(Species.GARDEVOIR, 30, null, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE)),
new SpeciesEvolution(Species.GALLADE, 30, null, new SpeciesEvolutionCondition(p => p.gender === Gender.MALE, p => p.gender = Gender.MALE))
new SpeciesEvolution(Species.GARDEVOIR, 30, null, new GenderEvolutionCondition(Gender.FEMALE)),
new SpeciesEvolution(Species.GALLADE, 30, null, new GenderEvolutionCondition(Gender.MALE))
],
[Species.SURSKIT]: [
new SpeciesEvolution(Species.MASQUERAIN, 22, null, null)
@ -479,7 +672,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
],
[Species.NINCADA]: [
new SpeciesEvolution(Species.NINJASK, 20, null, null),
new SpeciesEvolution(Species.SHEDINJA, 20, null, new SpeciesEvolutionCondition(p => globalScene.getPlayerParty().length < 6 && globalScene.pokeballCounts[PokeballType.POKEBALL] > 0))
new SpeciesEvolution(Species.SHEDINJA, 20, null, new ShedinjaEvolutionCondition())
],
[Species.WHISMUR]: [
new SpeciesEvolution(Species.LOUDRED, 20, null, null)
@ -551,8 +744,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.DUSCLOPS, 37, null, null)
],
[Species.SNORUNT]: [
new SpeciesEvolution(Species.GLALIE, 42, null, new SpeciesEvolutionCondition(p => p.gender === Gender.MALE, p => p.gender = Gender.MALE)),
new SpeciesEvolution(Species.FROSLASS, 42, null, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE))
new SpeciesEvolution(Species.GLALIE, 42, null, new GenderEvolutionCondition(Gender.MALE)),
new SpeciesEvolution(Species.FROSLASS, 42, null, new GenderEvolutionCondition(Gender.FEMALE))
],
[Species.SPHEAL]: [
new SpeciesEvolution(Species.SEALEO, 32, null, null)
@ -615,11 +808,11 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.BASTIODON, 30, null, null)
],
[Species.BURMY]: [
new SpeciesEvolution(Species.MOTHIM, 20, null, new SpeciesEvolutionCondition(p => p.gender === Gender.MALE, p => p.gender = Gender.MALE)),
new SpeciesEvolution(Species.WORMADAM, 20, null, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE))
new SpeciesEvolution(Species.MOTHIM, 20, null, new GenderEvolutionCondition(Gender.MALE)),
new SpeciesEvolution(Species.WORMADAM, 20, null, new GenderEvolutionCondition(Gender.FEMALE))
],
[Species.COMBEE]: [
new SpeciesEvolution(Species.VESPIQUEN, 21, null, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE))
new SpeciesEvolution(Species.VESPIQUEN, 21, null, new GenderEvolutionCondition(Gender.FEMALE))
],
[Species.BUIZEL]: [
new SpeciesEvolution(Species.FLOATZEL, 26, null, null)
@ -661,7 +854,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.LUMINEON, 31, null, null)
],
[Species.MANTYKE]: [
new SpeciesEvolution(Species.MANTINE, 32, null, new SpeciesEvolutionCondition(p => !!globalScene.gameData.dexData[Species.REMORAID].caughtAttr), SpeciesWildEvolutionDelay.MEDIUM)
new SpeciesEvolution(Species.MANTINE, 32, null, new CaughtEvolutionCondition(Species.REMORAID), SpeciesWildEvolutionDelay.MEDIUM)
],
[Species.SNOVER]: [
new SpeciesEvolution(Species.ABOMASNOW, 40, null, null)
@ -682,8 +875,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.DEWOTT, 17, null, null)
],
[Species.DEWOTT]: [
new SpeciesEvolution(Species.HISUI_SAMUROTT, 36, null, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT)),
new SpeciesEvolution(Species.SAMUROTT, 36, null, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DAWN || globalScene.arena.getTimeOfDay() === TimeOfDay.DAY))
new SpeciesEvolution(Species.HISUI_SAMUROTT, 36, null, new TimeOfDayEvolutionCondition("night")),
new SpeciesEvolution(Species.SAMUROTT, 36, null, new TimeOfDayEvolutionCondition("day"))
],
[Species.PATRAT]: [
new SpeciesEvolution(Species.WATCHOG, 20, null, null)
@ -833,8 +1026,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.KINGAMBIT, 1, EvolutionItem.LEADERS_CREST, null, SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.RUFFLET]: [
new SpeciesEvolution(Species.HISUI_BRAVIARY, 54, null, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT)),
new SpeciesEvolution(Species.BRAVIARY, 54, null, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DAWN || globalScene.arena.getTimeOfDay() === TimeOfDay.DAY))
new SpeciesEvolution(Species.HISUI_BRAVIARY, 54, null, new TimeOfDayEvolutionCondition("night")),
new SpeciesEvolution(Species.BRAVIARY, 54, null, new TimeOfDayEvolutionCondition("day"))
],
[Species.VULLABY]: [
new SpeciesEvolution(Species.MANDIBUZZ, 54, null, null)
@ -891,11 +1084,11 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.GOGOAT, 32, null, null)
],
[Species.PANCHAM]: [
new SpeciesEvolution(Species.PANGORO, 32, null, new SpeciesEvolutionCondition(p => !!globalScene.getPlayerParty().find(p => p.getTypes(false, false, true).indexOf(Type.DARK) > -1)), SpeciesWildEvolutionDelay.MEDIUM)
new SpeciesEvolution(Species.PANGORO, 32, null, new PartyTypeEvolutionCondition(Type.DARK), SpeciesWildEvolutionDelay.MEDIUM)
],
[Species.ESPURR]: [
new SpeciesFormEvolution(Species.MEOWSTIC, "", "female", 25, null, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE)),
new SpeciesFormEvolution(Species.MEOWSTIC, "", "", 25, null, new SpeciesEvolutionCondition(p => p.gender === Gender.MALE, p => p.gender = Gender.MALE))
new SpeciesFormEvolution(Species.MEOWSTIC, "", "female", 25, null, new GenderEvolutionCondition(Gender.FEMALE)),
new SpeciesFormEvolution(Species.MEOWSTIC, "", "", 25, null, new GenderEvolutionCondition(Gender.MALE))
],
[Species.HONEDGE]: [
new SpeciesEvolution(Species.DOUBLADE, 35, null, null)
@ -913,21 +1106,21 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.CLAWITZER, 37, null, null)
],
[Species.TYRUNT]: [
new SpeciesEvolution(Species.TYRANTRUM, 39, null, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DAWN || globalScene.arena.getTimeOfDay() === TimeOfDay.DAY))
new SpeciesEvolution(Species.TYRANTRUM, 39, null, new TimeOfDayEvolutionCondition("day"))
],
[Species.AMAURA]: [
new SpeciesEvolution(Species.AURORUS, 39, null, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT))
new SpeciesEvolution(Species.AURORUS, 39, null, new TimeOfDayEvolutionCondition("night"))
],
[Species.GOOMY]: [
new SpeciesEvolution(Species.HISUI_SLIGGOO, 40, null, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT)),
new SpeciesEvolution(Species.SLIGGOO, 40, null, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DAWN || globalScene.arena.getTimeOfDay() === TimeOfDay.DAY))
new SpeciesEvolution(Species.HISUI_SLIGGOO, 40, null, new TimeOfDayEvolutionCondition("night")),
new SpeciesEvolution(Species.SLIGGOO, 40, null, new TimeOfDayEvolutionCondition("day"))
],
[Species.SLIGGOO]: [
new SpeciesEvolution(Species.GOODRA, 50, null, new SpeciesEvolutionCondition(p => [ WeatherType.RAIN, WeatherType.FOG, WeatherType.HEAVY_RAIN ].indexOf(globalScene.arena.weather?.weatherType || WeatherType.NONE) > -1), SpeciesWildEvolutionDelay.LONG)
new SpeciesEvolution(Species.GOODRA, 50, null, new WeatherEvolutionCondition([ WeatherType.RAIN, WeatherType.FOG, WeatherType.HEAVY_RAIN ]), SpeciesWildEvolutionDelay.LONG)
],
[Species.BERGMITE]: [
new SpeciesEvolution(Species.HISUI_AVALUGG, 37, null, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT)),
new SpeciesEvolution(Species.AVALUGG, 37, null, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DAWN || globalScene.arena.getTimeOfDay() === TimeOfDay.DAY))
new SpeciesEvolution(Species.HISUI_AVALUGG, 37, null, new TimeOfDayEvolutionCondition("night")),
new SpeciesEvolution(Species.AVALUGG, 37, null, new TimeOfDayEvolutionCondition("day"))
],
[Species.NOIBAT]: [
new SpeciesEvolution(Species.NOIVERN, 48, null, null)
@ -936,8 +1129,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.DARTRIX, 17, null, null)
],
[Species.DARTRIX]: [
new SpeciesEvolution(Species.HISUI_DECIDUEYE, 36, null, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT)),
new SpeciesEvolution(Species.DECIDUEYE, 34, null, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DAWN || globalScene.arena.getTimeOfDay() === TimeOfDay.DAY))
new SpeciesEvolution(Species.HISUI_DECIDUEYE, 36, null, new TimeOfDayEvolutionCondition("night")),
new SpeciesEvolution(Species.DECIDUEYE, 34, null, new TimeOfDayEvolutionCondition("day"))
],
[Species.LITTEN]: [
new SpeciesEvolution(Species.TORRACAT, 17, null, null)
@ -958,7 +1151,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.TOUCANNON, 28, null, null)
],
[Species.YUNGOOS]: [
new SpeciesEvolution(Species.GUMSHOOS, 20, null, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DAWN || globalScene.arena.getTimeOfDay() === TimeOfDay.DAY))
new SpeciesEvolution(Species.GUMSHOOS, 20, null, new TimeOfDayEvolutionCondition("day"))
],
[Species.GRUBBIN]: [
new SpeciesEvolution(Species.CHARJABUG, 20, null, null)
@ -976,13 +1169,13 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.ARAQUANID, 22, null, null)
],
[Species.FOMANTIS]: [
new SpeciesEvolution(Species.LURANTIS, 34, null, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DAWN || globalScene.arena.getTimeOfDay() === TimeOfDay.DAY))
new SpeciesEvolution(Species.LURANTIS, 34, null, new TimeOfDayEvolutionCondition("day"))
],
[Species.MORELULL]: [
new SpeciesEvolution(Species.SHIINOTIC, 24, null, null)
],
[Species.SALANDIT]: [
new SpeciesEvolution(Species.SALAZZLE, 33, null, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE))
new SpeciesEvolution(Species.SALAZZLE, 33, null, new GenderEvolutionCondition(Gender.FEMALE))
],
[Species.STUFFUL]: [
new SpeciesEvolution(Species.BEWEAR, 27, null, null)
@ -1013,7 +1206,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.MELMETAL, 48, null, null)
],
[Species.ALOLA_RATTATA]: [
new SpeciesEvolution(Species.ALOLA_RATICATE, 20, null, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT))
new SpeciesEvolution(Species.ALOLA_RATICATE, 20, null, new TimeOfDayEvolutionCondition("night"))
],
[Species.ALOLA_DIGLETT]: [
new SpeciesEvolution(Species.ALOLA_DUGTRIO, 26, null, null)
@ -1086,7 +1279,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
],
[Species.TOXEL]: [
new SpeciesFormEvolution(Species.TOXTRICITY, "", "lowkey", 30, null,
new SpeciesEvolutionCondition(p => [ Nature.LONELY, Nature.BOLD, Nature.RELAXED, Nature.TIMID, Nature.SERIOUS, Nature.MODEST, Nature.MILD, Nature.QUIET, Nature.BASHFUL, Nature.CALM, Nature.GENTLE, Nature.CAREFUL ].indexOf(p.getNature()) > -1)),
new NatureEvolutionCondition([ Nature.LONELY, Nature.BOLD, Nature.RELAXED, Nature.TIMID, Nature.SERIOUS, Nature.MODEST, Nature.MILD, Nature.QUIET, Nature.BASHFUL, Nature.CALM, Nature.GENTLE, Nature.CAREFUL ])
),
new SpeciesFormEvolution(Species.TOXTRICITY, "", "amped", 30, null, null)
],
[Species.SIZZLIPEDE]: [
@ -1136,7 +1330,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.GALAR_LINOONE, 20, null, null)
],
[Species.GALAR_LINOONE]: [
new SpeciesEvolution(Species.OBSTAGOON, 35, null, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT))
new SpeciesEvolution(Species.OBSTAGOON, 35, null, new TimeOfDayEvolutionCondition("night"))
],
[Species.GALAR_YAMASK]: [
new SpeciesEvolution(Species.RUNERIGUS, 34, null, null)
@ -1145,7 +1339,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.HISUI_ZOROARK, 30, null, null)
],
[Species.HISUI_SLIGGOO]: [
new SpeciesEvolution(Species.HISUI_GOODRA, 50, null, new SpeciesEvolutionCondition(p => [ WeatherType.RAIN, WeatherType.FOG, WeatherType.HEAVY_RAIN ].indexOf(globalScene.arena.weather?.weatherType || WeatherType.NONE) > -1), SpeciesWildEvolutionDelay.LONG)
new SpeciesEvolution(Species.HISUI_GOODRA, 50, null, new WeatherEvolutionCondition([ WeatherType.RAIN, WeatherType.FOG, WeatherType.HEAVY_RAIN ]), SpeciesWildEvolutionDelay.LONG)
],
[Species.SPRIGATITO]: [
new SpeciesEvolution(Species.FLORAGATO, 16, null, null)
@ -1166,8 +1360,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.QUAQUAVAL, 36, null, null)
],
[Species.LECHONK]: [
new SpeciesFormEvolution(Species.OINKOLOGNE, "", "female", 18, null, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE)),
new SpeciesFormEvolution(Species.OINKOLOGNE, "", "", 18, null, new SpeciesEvolutionCondition(p => p.gender === Gender.MALE, p => p.gender = Gender.MALE))
new SpeciesFormEvolution(Species.OINKOLOGNE, "", "female", 18, null, new GenderEvolutionCondition(Gender.FEMALE)),
new SpeciesFormEvolution(Species.OINKOLOGNE, "", "", 18, null, new GenderEvolutionCondition(Gender.MALE))
],
[Species.TAROUNTULA]: [
new SpeciesEvolution(Species.SPIDOPS, 15, null, null)
@ -1182,11 +1376,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.PAWMOT, 32, null, null)
],
[Species.TANDEMAUS]: [
new SpeciesFormEvolution(Species.MAUSHOLD, "", "three", 25, null, new SpeciesEvolutionCondition(p => {
let ret = false;
globalScene.executeWithSeedOffset(() => ret = !Utils.randSeedInt(4), p.id);
return ret;
})),
new SpeciesFormEvolution(Species.MAUSHOLD, "", "three", 25, null, new TandemausEvolutionCondition()),
new SpeciesEvolution(Species.MAUSHOLD, 25, null, null)
],
[Species.FIDOUGH]: [
@ -1244,7 +1434,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.GLIMMORA, 35, null, null)
],
[Species.GREAVARD]: [
new SpeciesEvolution(Species.HOUNDSTONE, 30, null, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT))
new SpeciesEvolution(Species.HOUNDSTONE, 30, null, new TimeOfDayEvolutionCondition("night"))
],
[Species.FRIGIBAX]: [
new SpeciesEvolution(Species.ARCTIBAX, 35, null, null)
@ -1301,21 +1491,21 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.EXEGGUTOR, 1, EvolutionItem.LEAF_STONE, null, SpeciesWildEvolutionDelay.LONG)
],
[Species.TANGELA]: [
new SpeciesEvolution(Species.TANGROWTH, 34, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.ANCIENT_POWER).length > 0), SpeciesWildEvolutionDelay.LONG)
new SpeciesEvolution(Species.TANGROWTH, 34, null, new MoveEvolutionCondition(Moves.ANCIENT_POWER), SpeciesWildEvolutionDelay.LONG)
],
[Species.LICKITUNG]: [
new SpeciesEvolution(Species.LICKILICKY, 32, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.ROLLOUT).length > 0), SpeciesWildEvolutionDelay.LONG)
new SpeciesEvolution(Species.LICKILICKY, 32, null, new MoveEvolutionCondition(Moves.ROLLOUT), SpeciesWildEvolutionDelay.LONG)
],
[Species.STARYU]: [
new SpeciesEvolution(Species.STARMIE, 1, EvolutionItem.WATER_STONE, null, SpeciesWildEvolutionDelay.LONG)
],
[Species.EEVEE]: [
new SpeciesFormEvolution(Species.SYLVEON, "", "", 1, null, new SpeciesFriendshipEvolutionCondition(120, p => !!p.getMoveset().find(m => m?.getMove().type === Type.FAIRY)), SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.SYLVEON, "partner", "", 1, null, new SpeciesFriendshipEvolutionCondition(120, p => !!p.getMoveset().find(m => m?.getMove().type === Type.FAIRY)), SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.ESPEON, "", "", 1, null, new SpeciesFriendshipEvolutionCondition(120, p => globalScene.arena.getTimeOfDay() === TimeOfDay.DAY), SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.ESPEON, "partner", "", 1, null, new SpeciesFriendshipEvolutionCondition(120, p => globalScene.arena.getTimeOfDay() === TimeOfDay.DAY), SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.UMBREON, "", "", 1, null, new SpeciesFriendshipEvolutionCondition(120, p => globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT), SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.UMBREON, "partner", "", 1, null, new SpeciesFriendshipEvolutionCondition(120, p => globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT), SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.SYLVEON, "", "", 1, null, new FriendshipMoveTypeEvolutionCondition(120, Type.FAIRY), SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.SYLVEON, "partner", "", 1, null, new FriendshipMoveTypeEvolutionCondition(120, Type.FAIRY), SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.ESPEON, "", "", 1, null, new FriendshipTimeOfDayEvolutionCondition(120, "day"), SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.ESPEON, "partner", "", 1, null, new FriendshipTimeOfDayEvolutionCondition(120, "day"), SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.UMBREON, "", "", 1, null, new FriendshipTimeOfDayEvolutionCondition(120, "night"), SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.UMBREON, "partner", "", 1, null, new FriendshipTimeOfDayEvolutionCondition(120, "night"), SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.VAPOREON, "", "", 1, EvolutionItem.WATER_STONE, null, SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.VAPOREON, "partner", "", 1, EvolutionItem.WATER_STONE, null, SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.JOLTEON, "", "", 1, EvolutionItem.THUNDER_STONE, null, SpeciesWildEvolutionDelay.LONG),
@ -1331,13 +1521,13 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.TOGEKISS, 1, EvolutionItem.SHINY_STONE, null, SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.AIPOM]: [
new SpeciesEvolution(Species.AMBIPOM, 32, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.DOUBLE_HIT).length > 0), SpeciesWildEvolutionDelay.LONG)
new SpeciesEvolution(Species.AMBIPOM, 32, null, new MoveEvolutionCondition(Moves.DOUBLE_HIT), SpeciesWildEvolutionDelay.LONG)
],
[Species.SUNKERN]: [
new SpeciesEvolution(Species.SUNFLORA, 1, EvolutionItem.SUN_STONE, null, SpeciesWildEvolutionDelay.LONG)
],
[Species.YANMA]: [
new SpeciesEvolution(Species.YANMEGA, 33, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.ANCIENT_POWER).length > 0), SpeciesWildEvolutionDelay.LONG)
new SpeciesEvolution(Species.YANMEGA, 33, null, new MoveEvolutionCondition(Moves.ANCIENT_POWER), SpeciesWildEvolutionDelay.LONG)
],
[Species.MURKROW]: [
new SpeciesEvolution(Species.HONCHKROW, 1, EvolutionItem.DUSK_STONE, null, SpeciesWildEvolutionDelay.VERY_LONG)
@ -1346,32 +1536,26 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.MISMAGIUS, 1, EvolutionItem.DUSK_STONE, null, SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.GIRAFARIG]: [
new SpeciesEvolution(Species.FARIGIRAF, 32, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.TWIN_BEAM).length > 0), SpeciesWildEvolutionDelay.LONG)
new SpeciesEvolution(Species.FARIGIRAF, 32, null, new MoveEvolutionCondition(Moves.TWIN_BEAM), SpeciesWildEvolutionDelay.LONG)
],
[Species.DUNSPARCE]: [
new SpeciesFormEvolution(Species.DUDUNSPARCE, "", "three-segment", 32, null, new SpeciesEvolutionCondition(p => {
let ret = false;
if (p.moveset.filter(m => m?.moveId === Moves.HYPER_DRILL).length > 0) {
globalScene.executeWithSeedOffset(() => ret = !Utils.randSeedInt(4), p.id);
}
return ret;
}), SpeciesWildEvolutionDelay.LONG),
new SpeciesEvolution(Species.DUDUNSPARCE, 32, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.HYPER_DRILL).length > 0), SpeciesWildEvolutionDelay.LONG)
new SpeciesFormEvolution(Species.DUDUNSPARCE, "", "three-segment", 32, null, new DunsparceEvolutionCondition(), SpeciesWildEvolutionDelay.LONG),
new SpeciesEvolution(Species.DUDUNSPARCE, 32, null, new MoveEvolutionCondition(Moves.HYPER_DRILL), SpeciesWildEvolutionDelay.LONG)
],
[Species.GLIGAR]: [
new SpeciesEvolution(Species.GLISCOR, 1, EvolutionItem.RAZOR_FANG, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT /* Razor fang at night*/), SpeciesWildEvolutionDelay.VERY_LONG)
new SpeciesEvolution(Species.GLISCOR, 1, EvolutionItem.RAZOR_FANG, new TimeOfDayEvolutionCondition("night") /* Razor fang at night*/, SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.SNEASEL]: [
new SpeciesEvolution(Species.WEAVILE, 1, EvolutionItem.RAZOR_CLAW, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT /* Razor claw at night*/), SpeciesWildEvolutionDelay.VERY_LONG)
new SpeciesEvolution(Species.WEAVILE, 1, EvolutionItem.RAZOR_CLAW, new TimeOfDayEvolutionCondition("night") /* Razor claw at night*/, SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.URSARING]: [
new SpeciesEvolution(Species.URSALUNA, 1, EvolutionItem.PEAT_BLOCK, null, SpeciesWildEvolutionDelay.VERY_LONG) //Ursaring does not evolve into Bloodmoon Ursaluna
],
[Species.PILOSWINE]: [
new SpeciesEvolution(Species.MAMOSWINE, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.ANCIENT_POWER).length > 0), SpeciesWildEvolutionDelay.VERY_LONG)
new SpeciesEvolution(Species.MAMOSWINE, 1, null, new MoveEvolutionCondition(Moves.ANCIENT_POWER), SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.STANTLER]: [
new SpeciesEvolution(Species.WYRDEER, 25, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.PSYSHIELD_BASH).length > 0), SpeciesWildEvolutionDelay.VERY_LONG)
new SpeciesEvolution(Species.WYRDEER, 25, null, new MoveEvolutionCondition(Moves.PSYSHIELD_BASH), SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.LOMBRE]: [
new SpeciesEvolution(Species.LUDICOLO, 1, EvolutionItem.WATER_STONE, null, SpeciesWildEvolutionDelay.LONG)
@ -1389,11 +1573,11 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.ROSERADE, 1, EvolutionItem.SHINY_STONE, null, SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.BONSLY]: [
new SpeciesEvolution(Species.SUDOWOODO, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.MIMIC).length > 0), SpeciesWildEvolutionDelay.MEDIUM)
new SpeciesEvolution(Species.SUDOWOODO, 1, null, new MoveEvolutionCondition(Moves.MIMIC), SpeciesWildEvolutionDelay.MEDIUM)
],
[Species.MIME_JR]: [
new SpeciesEvolution(Species.GALAR_MR_MIME, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.MIMIC).length > 0 && (globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT)), SpeciesWildEvolutionDelay.MEDIUM),
new SpeciesEvolution(Species.MR_MIME, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.MIMIC).length > 0 && (globalScene.arena.getTimeOfDay() === TimeOfDay.DAWN || globalScene.arena.getTimeOfDay() === TimeOfDay.DAY)), SpeciesWildEvolutionDelay.MEDIUM)
new SpeciesEvolution(Species.GALAR_MR_MIME, 1, null, new MoveTimeOfDayEvolutionCondition(Moves.MIMIC, "night"), SpeciesWildEvolutionDelay.MEDIUM),
new SpeciesEvolution(Species.MR_MIME, 1, null, new MoveTimeOfDayEvolutionCondition(Moves.MIMIC, "day"), SpeciesWildEvolutionDelay.MEDIUM)
],
[Species.PANSAGE]: [
new SpeciesEvolution(Species.SIMISAGE, 1, EvolutionItem.LEAF_STONE, null, SpeciesWildEvolutionDelay.LONG)
@ -1415,8 +1599,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.LILLIGANT, 1, EvolutionItem.SUN_STONE, null, SpeciesWildEvolutionDelay.LONG)
],
[Species.BASCULIN]: [
new SpeciesFormEvolution(Species.BASCULEGION, "white-striped", "female", 40, null, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE), SpeciesWildEvolutionDelay.VERY_LONG),
new SpeciesFormEvolution(Species.BASCULEGION, "white-striped", "male", 40, null, new SpeciesEvolutionCondition(p => p.gender === Gender.MALE, p => p.gender = Gender.MALE), SpeciesWildEvolutionDelay.VERY_LONG)
new SpeciesFormEvolution(Species.BASCULEGION, "white-striped", "female", 40, null, new GenderEvolutionCondition(Gender.FEMALE), SpeciesWildEvolutionDelay.VERY_LONG),
new SpeciesFormEvolution(Species.BASCULEGION, "white-striped", "male", 40, null, new GenderEvolutionCondition(Gender.MALE), SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.MINCCINO]: [
new SpeciesEvolution(Species.CINCCINO, 1, EvolutionItem.SHINY_STONE, null, SpeciesWildEvolutionDelay.LONG)
@ -1443,15 +1627,15 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.CRABOMINABLE, 1, EvolutionItem.ICE_STONE, null, SpeciesWildEvolutionDelay.LONG)
],
[Species.ROCKRUFF]: [
new SpeciesFormEvolution(Species.LYCANROC, "", "midday", 25, null, new SpeciesEvolutionCondition(p => (globalScene.arena.getTimeOfDay() === TimeOfDay.DAWN || globalScene.arena.getTimeOfDay() === TimeOfDay.DAY) && (p.formIndex === 0))),
new SpeciesFormEvolution(Species.LYCANROC, "own-tempo", "dusk", 25, null, new SpeciesEvolutionCondition(p => p.formIndex === 1)),
new SpeciesFormEvolution(Species.LYCANROC, "", "midnight", 25, null, new SpeciesEvolutionCondition(p => (globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT) && (p.formIndex === 0)))
new SpeciesFormEvolution(Species.LYCANROC, "own-tempo", "dusk", 25, null, null),
new SpeciesFormEvolution(Species.LYCANROC, "", "midday", 25, null, new TimeOfDayEvolutionCondition("day")),
new SpeciesFormEvolution(Species.LYCANROC, "", "midnight", 25, null, new TimeOfDayEvolutionCondition("night"))
],
[Species.STEENEE]: [
new SpeciesEvolution(Species.TSAREENA, 28, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.STOMP).length > 0), SpeciesWildEvolutionDelay.LONG)
new SpeciesEvolution(Species.TSAREENA, 28, null, new MoveEvolutionCondition(Moves.STOMP), SpeciesWildEvolutionDelay.LONG)
],
[Species.POIPOLE]: [
new SpeciesEvolution(Species.NAGANADEL, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.DRAGON_PULSE).length > 0), SpeciesWildEvolutionDelay.LONG)
new SpeciesEvolution(Species.NAGANADEL, 1, null, new MoveEvolutionCondition(Moves.DRAGON_PULSE), SpeciesWildEvolutionDelay.LONG)
],
[Species.ALOLA_SANDSHREW]: [
new SpeciesEvolution(Species.ALOLA_SANDSLASH, 1, EvolutionItem.ICE_STONE, null, SpeciesWildEvolutionDelay.LONG)
@ -1465,22 +1649,40 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.APPLETUN, 1, EvolutionItem.SWEET_APPLE, null, SpeciesWildEvolutionDelay.LONG)
],
[Species.CLOBBOPUS]: [
new SpeciesEvolution(Species.GRAPPLOCT, 35, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.TAUNT).length > 0)/*Once Taunt is implemented, change evo level to 1 and delay to LONG*/)
new SpeciesEvolution(Species.GRAPPLOCT, 35, null, new MoveEvolutionCondition(Moves.TAUNT)/*Once Taunt is implemented, change evo level to 1 and delay to LONG*/)
],
[Species.SINISTEA]: [
new SpeciesFormEvolution(Species.POLTEAGEIST, "phony", "phony", 1, EvolutionItem.CRACKED_POT, null, SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.POLTEAGEIST, "antique", "antique", 1, EvolutionItem.CHIPPED_POT, null, SpeciesWildEvolutionDelay.LONG)
],
[Species.MILCERY]: [
new SpeciesFormEvolution(Species.ALCREMIE, "", "vanilla-cream", 1, EvolutionItem.STRAWBERRY_SWEET, new SpeciesEvolutionCondition(p => globalScene.arena.biomeType === Biome.TOWN || globalScene.arena.biomeType === Biome.PLAINS || globalScene.arena.biomeType === Biome.GRASS || globalScene.arena.biomeType === Biome.TALL_GRASS || globalScene.arena.biomeType === Biome.METROPOLIS), SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.ALCREMIE, "", "ruby-cream", 1, EvolutionItem.STRAWBERRY_SWEET, new SpeciesEvolutionCondition(p => globalScene.arena.biomeType === Biome.BADLANDS || globalScene.arena.biomeType === Biome.VOLCANO || globalScene.arena.biomeType === Biome.GRAVEYARD || globalScene.arena.biomeType === Biome.FACTORY || globalScene.arena.biomeType === Biome.SLUM), SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.ALCREMIE, "", "matcha-cream", 1, EvolutionItem.STRAWBERRY_SWEET, new SpeciesEvolutionCondition(p => globalScene.arena.biomeType === Biome.FOREST || globalScene.arena.biomeType === Biome.SWAMP || globalScene.arena.biomeType === Biome.MEADOW || globalScene.arena.biomeType === Biome.JUNGLE), SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.ALCREMIE, "", "mint-cream", 1, EvolutionItem.STRAWBERRY_SWEET, new SpeciesEvolutionCondition(p => globalScene.arena.biomeType === Biome.SEA || globalScene.arena.biomeType === Biome.BEACH || globalScene.arena.biomeType === Biome.LAKE || globalScene.arena.biomeType === Biome.SEABED), SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.ALCREMIE, "", "lemon-cream", 1, EvolutionItem.STRAWBERRY_SWEET, new SpeciesEvolutionCondition(p => globalScene.arena.biomeType === Biome.DESERT || globalScene.arena.biomeType === Biome.POWER_PLANT || globalScene.arena.biomeType === Biome.DOJO || globalScene.arena.biomeType === Biome.RUINS || globalScene.arena.biomeType === Biome.CONSTRUCTION_SITE), SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.ALCREMIE, "", "salted-cream", 1, EvolutionItem.STRAWBERRY_SWEET, new SpeciesEvolutionCondition(p => globalScene.arena.biomeType === Biome.MOUNTAIN || globalScene.arena.biomeType === Biome.CAVE || globalScene.arena.biomeType === Biome.ICE_CAVE || globalScene.arena.biomeType === Biome.FAIRY_CAVE || globalScene.arena.biomeType === Biome.SNOWY_FOREST), SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.ALCREMIE, "", "ruby-swirl", 1, EvolutionItem.STRAWBERRY_SWEET, new SpeciesEvolutionCondition(p => globalScene.arena.biomeType === Biome.WASTELAND || globalScene.arena.biomeType === Biome.LABORATORY), SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.ALCREMIE, "", "caramel-swirl", 1, EvolutionItem.STRAWBERRY_SWEET, new SpeciesEvolutionCondition(p => globalScene.arena.biomeType === Biome.TEMPLE || globalScene.arena.biomeType === Biome.ISLAND), SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.ALCREMIE, "", "rainbow-swirl", 1, EvolutionItem.STRAWBERRY_SWEET, new SpeciesEvolutionCondition(p => globalScene.arena.biomeType === Biome.ABYSS || globalScene.arena.biomeType === Biome.SPACE || globalScene.arena.biomeType === Biome.END), SpeciesWildEvolutionDelay.LONG)
new SpeciesFormEvolution(Species.ALCREMIE, "", "vanilla-cream", 1, EvolutionItem.STRAWBERRY_SWEET,
new BiomeEvolutionCondition([ Biome.TOWN, Biome.PLAINS, Biome.GRASS, Biome.TALL_GRASS, Biome.METROPOLIS ]),
SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.ALCREMIE, "", "ruby-cream", 1, EvolutionItem.STRAWBERRY_SWEET,
new BiomeEvolutionCondition([ Biome.BADLANDS, Biome.VOLCANO, Biome.GRAVEYARD, Biome.FACTORY, Biome.SLUM ]),
SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.ALCREMIE, "", "matcha-cream", 1, EvolutionItem.STRAWBERRY_SWEET,
new BiomeEvolutionCondition([ Biome.FOREST, Biome.SWAMP, Biome.MEADOW, Biome.JUNGLE ]),
SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.ALCREMIE, "", "mint-cream", 1, EvolutionItem.STRAWBERRY_SWEET,
new BiomeEvolutionCondition([ Biome.SEA, Biome.BEACH, Biome.LAKE, Biome.SEABED ]),
SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.ALCREMIE, "", "lemon-cream", 1, EvolutionItem.STRAWBERRY_SWEET,
new BiomeEvolutionCondition([ Biome.DESERT, Biome.POWER_PLANT, Biome.DOJO, Biome.RUINS, Biome.CONSTRUCTION_SITE ]),
SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.ALCREMIE, "", "salted-cream", 1, EvolutionItem.STRAWBERRY_SWEET,
new BiomeEvolutionCondition([ Biome.MOUNTAIN, Biome.CAVE, Biome.ICE_CAVE, Biome.FAIRY_CAVE, Biome.SNOWY_FOREST ]),
SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.ALCREMIE, "", "ruby-swirl", 1, EvolutionItem.STRAWBERRY_SWEET,
new BiomeEvolutionCondition([ Biome.WASTELAND, Biome.LABORATORY ]),
SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.ALCREMIE, "", "caramel-swirl", 1, EvolutionItem.STRAWBERRY_SWEET,
new BiomeEvolutionCondition([ Biome.TEMPLE, Biome.ISLAND ]),
SpeciesWildEvolutionDelay.LONG),
new SpeciesFormEvolution(Species.ALCREMIE, "", "rainbow-swirl", 1, EvolutionItem.STRAWBERRY_SWEET,
new BiomeEvolutionCondition([ Biome.ABYSS, Biome.SPACE, Biome.END ]),
SpeciesWildEvolutionDelay.LONG)
],
[Species.DURALUDON]: [
new SpeciesFormEvolution(Species.ARCHALUDON, "", "", 1, EvolutionItem.METAL_ALLOY, null, SpeciesWildEvolutionDelay.VERY_LONG)
@ -1499,10 +1701,10 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.HISUI_ELECTRODE, 1, EvolutionItem.LEAF_STONE, null, SpeciesWildEvolutionDelay.LONG)
],
[Species.HISUI_QWILFISH]: [
new SpeciesEvolution(Species.OVERQWIL, 28, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.BARB_BARRAGE).length > 0), SpeciesWildEvolutionDelay.LONG)
new SpeciesEvolution(Species.OVERQWIL, 28, null, new MoveEvolutionCondition(Moves.BARB_BARRAGE), SpeciesWildEvolutionDelay.LONG)
],
[Species.HISUI_SNEASEL]: [
new SpeciesEvolution(Species.SNEASLER, 1, EvolutionItem.RAZOR_CLAW, new SpeciesEvolutionCondition(p => globalScene.arena.getTimeOfDay() === TimeOfDay.DAWN || globalScene.arena.getTimeOfDay() === TimeOfDay.DAY /* Razor claw at day*/), SpeciesWildEvolutionDelay.VERY_LONG)
new SpeciesEvolution(Species.SNEASLER, 1, EvolutionItem.RAZOR_CLAW, new TimeOfDayEvolutionCondition("day") /* Razor claw at day*/, SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.CHARCADET]: [
new SpeciesEvolution(Species.ARMAROUGE, 1, EvolutionItem.AUSPICIOUS_ARMOR, null, SpeciesWildEvolutionDelay.LONG),
@ -1522,7 +1724,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesFormEvolution(Species.SINISTCHA, "artisan", "masterpiece", 1, EvolutionItem.MASTERPIECE_TEACUP, null, SpeciesWildEvolutionDelay.LONG)
],
[Species.DIPPLIN]: [
new SpeciesEvolution(Species.HYDRAPPLE, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.DRAGON_CHEER).length > 0), SpeciesWildEvolutionDelay.VERY_LONG)
new SpeciesEvolution(Species.HYDRAPPLE, 1, null, new MoveEvolutionCondition(Moves.DRAGON_CHEER), SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.KADABRA]: [
new SpeciesEvolution(Species.ALAKAZAM, 1, EvolutionItem.LINKING_CORD, null, SpeciesWildEvolutionDelay.VERY_LONG)
@ -1537,9 +1739,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.GENGAR, 1, EvolutionItem.LINKING_CORD, null, SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.ONIX]: [
new SpeciesEvolution(Species.STEELIX, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(
p => p.moveset.filter(m => m?.getMove().type === Type.STEEL).length > 0),
SpeciesWildEvolutionDelay.VERY_LONG)
new SpeciesEvolution(Species.STEELIX, 1, EvolutionItem.LINKING_CORD, new MoveTypeEvolutionCondition(Type.STEEL), SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.RHYDON]: [
new SpeciesEvolution(Species.RHYPERIOR, 1, EvolutionItem.PROTECTOR, null, SpeciesWildEvolutionDelay.VERY_LONG)
@ -1548,9 +1748,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.KINGDRA, 1, EvolutionItem.DRAGON_SCALE, null, SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.SCYTHER]: [
new SpeciesEvolution(Species.SCIZOR, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(
p => p.moveset.filter(m => m?.getMove().type === Type.STEEL).length > 0),
SpeciesWildEvolutionDelay.VERY_LONG),
new SpeciesEvolution(Species.SCIZOR, 1, EvolutionItem.LINKING_CORD, new MoveTypeEvolutionCondition(Type.STEEL), SpeciesWildEvolutionDelay.VERY_LONG),
new SpeciesEvolution(Species.KLEAVOR, 1, EvolutionItem.BLACK_AUGURITE, null, SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.ELECTABUZZ]: [
@ -1572,8 +1770,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.DUSKNOIR, 1, EvolutionItem.REAPER_CLOTH, null, SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.CLAMPERL]: [
new SpeciesEvolution(Species.HUNTAIL, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(p => p.gender === Gender.MALE, p => p.gender = Gender.MALE /* Deep Sea Tooth */), SpeciesWildEvolutionDelay.VERY_LONG),
new SpeciesEvolution(Species.GOREBYSS, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE /* Deep Sea Scale */), SpeciesWildEvolutionDelay.VERY_LONG)
new SpeciesEvolution(Species.HUNTAIL, 1, EvolutionItem.LINKING_CORD, new GenderEvolutionCondition(Gender.MALE /* Deep Sea Tooth */), SpeciesWildEvolutionDelay.VERY_LONG),
new SpeciesEvolution(Species.GOREBYSS, 1, EvolutionItem.LINKING_CORD, new GenderEvolutionCondition(Gender.FEMALE /* Deep Sea Scale */), SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.BOLDORE]: [
new SpeciesEvolution(Species.GIGALITH, 1, EvolutionItem.LINKING_CORD, null, SpeciesWildEvolutionDelay.VERY_LONG)
@ -1582,10 +1780,10 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.CONKELDURR, 1, EvolutionItem.LINKING_CORD, null, SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.KARRABLAST]: [
new SpeciesEvolution(Species.ESCAVALIER, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(p => !!globalScene.gameData.dexData[Species.SHELMET].caughtAttr), SpeciesWildEvolutionDelay.VERY_LONG)
new SpeciesEvolution(Species.ESCAVALIER, 1, EvolutionItem.LINKING_CORD, new CaughtEvolutionCondition(Species.SHELMET), SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.SHELMET]: [
new SpeciesEvolution(Species.ACCELGOR, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(p => !!globalScene.gameData.dexData[Species.KARRABLAST].caughtAttr), SpeciesWildEvolutionDelay.VERY_LONG)
new SpeciesEvolution(Species.ACCELGOR, 1, EvolutionItem.LINKING_CORD, new CaughtEvolutionCondition(Species.KARRABLAST), SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.SPRITZEE]: [
new SpeciesEvolution(Species.AROMATISSE, 1, EvolutionItem.SACHET, null, SpeciesWildEvolutionDelay.VERY_LONG)
@ -1603,72 +1801,66 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.ALOLA_GOLEM, 1, EvolutionItem.LINKING_CORD, null, SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.PRIMEAPE]: [
new SpeciesEvolution(Species.ANNIHILAPE, 35, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.RAGE_FIST).length > 0), SpeciesWildEvolutionDelay.VERY_LONG)
new SpeciesEvolution(Species.ANNIHILAPE, 35, null, new MoveEvolutionCondition(Moves.RAGE_FIST), SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.GOLBAT]: [
new SpeciesEvolution(Species.CROBAT, 1, null, new SpeciesFriendshipEvolutionCondition(120), SpeciesWildEvolutionDelay.VERY_LONG)
new SpeciesEvolution(Species.CROBAT, 1, null, new FriendshipEvolutionCondition(120), SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.CHANSEY]: [
new SpeciesEvolution(Species.BLISSEY, 1, null, new SpeciesFriendshipEvolutionCondition(200), SpeciesWildEvolutionDelay.LONG)
new SpeciesEvolution(Species.BLISSEY, 1, null, new FriendshipEvolutionCondition(200), SpeciesWildEvolutionDelay.LONG)
],
[Species.PICHU]: [
new SpeciesFormEvolution(Species.PIKACHU, "spiky", "partner", 1, null, new SpeciesFriendshipEvolutionCondition(90), SpeciesWildEvolutionDelay.SHORT),
new SpeciesFormEvolution(Species.PIKACHU, "", "", 1, null, new SpeciesFriendshipEvolutionCondition(90), SpeciesWildEvolutionDelay.SHORT),
new SpeciesFormEvolution(Species.PIKACHU, "spiky", "partner", 1, null, new FriendshipEvolutionCondition(90), SpeciesWildEvolutionDelay.SHORT),
new SpeciesFormEvolution(Species.PIKACHU, "", "", 1, null, new FriendshipEvolutionCondition(90), SpeciesWildEvolutionDelay.SHORT),
],
[Species.CLEFFA]: [
new SpeciesEvolution(Species.CLEFAIRY, 1, null, new SpeciesFriendshipEvolutionCondition(160), SpeciesWildEvolutionDelay.SHORT)
new SpeciesEvolution(Species.CLEFAIRY, 1, null, new FriendshipEvolutionCondition(160), SpeciesWildEvolutionDelay.SHORT)
],
[Species.IGGLYBUFF]: [
new SpeciesEvolution(Species.JIGGLYPUFF, 1, null, new SpeciesFriendshipEvolutionCondition(70), SpeciesWildEvolutionDelay.SHORT)
new SpeciesEvolution(Species.JIGGLYPUFF, 1, null, new FriendshipEvolutionCondition(70), SpeciesWildEvolutionDelay.SHORT)
],
[Species.TOGEPI]: [
new SpeciesEvolution(Species.TOGETIC, 1, null, new SpeciesFriendshipEvolutionCondition(70), SpeciesWildEvolutionDelay.SHORT)
new SpeciesEvolution(Species.TOGETIC, 1, null, new FriendshipEvolutionCondition(70), SpeciesWildEvolutionDelay.SHORT)
],
[Species.AZURILL]: [
new SpeciesEvolution(Species.MARILL, 1, null, new SpeciesFriendshipEvolutionCondition(70), SpeciesWildEvolutionDelay.SHORT)
new SpeciesEvolution(Species.MARILL, 1, null, new FriendshipEvolutionCondition(70), SpeciesWildEvolutionDelay.SHORT)
],
[Species.BUDEW]: [
new SpeciesEvolution(Species.ROSELIA, 1, null, new SpeciesFriendshipEvolutionCondition(70, p => globalScene.arena.getTimeOfDay() === TimeOfDay.DAWN || globalScene.arena.getTimeOfDay() === TimeOfDay.DAY), SpeciesWildEvolutionDelay.SHORT)
new SpeciesEvolution(Species.ROSELIA, 1, null, new FriendshipTimeOfDayEvolutionCondition(70, "day"), SpeciesWildEvolutionDelay.SHORT)
],
[Species.BUNEARY]: [
new SpeciesEvolution(Species.LOPUNNY, 1, null, new SpeciesFriendshipEvolutionCondition(70), SpeciesWildEvolutionDelay.MEDIUM)
new SpeciesEvolution(Species.LOPUNNY, 1, null, new FriendshipEvolutionCondition(70), SpeciesWildEvolutionDelay.MEDIUM)
],
[Species.CHINGLING]: [
new SpeciesEvolution(Species.CHIMECHO, 1, null, new SpeciesFriendshipEvolutionCondition(90, p => globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT), SpeciesWildEvolutionDelay.MEDIUM)
new SpeciesEvolution(Species.CHIMECHO, 1, null, new FriendshipTimeOfDayEvolutionCondition(90, "night"), SpeciesWildEvolutionDelay.MEDIUM)
],
[Species.HAPPINY]: [
new SpeciesEvolution(Species.CHANSEY, 1, null, new SpeciesFriendshipEvolutionCondition(160), SpeciesWildEvolutionDelay.SHORT)
new SpeciesEvolution(Species.CHANSEY, 1, null, new FriendshipEvolutionCondition(160), SpeciesWildEvolutionDelay.SHORT)
],
[Species.MUNCHLAX]: [
new SpeciesEvolution(Species.SNORLAX, 1, null, new SpeciesFriendshipEvolutionCondition(120), SpeciesWildEvolutionDelay.LONG)
new SpeciesEvolution(Species.SNORLAX, 1, null, new FriendshipEvolutionCondition(120), SpeciesWildEvolutionDelay.LONG)
],
[Species.RIOLU]: [
new SpeciesEvolution(Species.LUCARIO, 1, null, new SpeciesFriendshipEvolutionCondition(120, p => globalScene.arena.getTimeOfDay() === TimeOfDay.DAWN || globalScene.arena.getTimeOfDay() === TimeOfDay.DAY), SpeciesWildEvolutionDelay.LONG)
new SpeciesEvolution(Species.LUCARIO, 1, null, new FriendshipTimeOfDayEvolutionCondition(120, "day"), SpeciesWildEvolutionDelay.LONG)
],
[Species.WOOBAT]: [
new SpeciesEvolution(Species.SWOOBAT, 1, null, new SpeciesFriendshipEvolutionCondition(90), SpeciesWildEvolutionDelay.MEDIUM)
new SpeciesEvolution(Species.SWOOBAT, 1, null, new FriendshipEvolutionCondition(90), SpeciesWildEvolutionDelay.MEDIUM)
],
[Species.SWADLOON]: [
new SpeciesEvolution(Species.LEAVANNY, 1, null, new SpeciesFriendshipEvolutionCondition(120), SpeciesWildEvolutionDelay.LONG)
new SpeciesEvolution(Species.LEAVANNY, 1, null, new FriendshipEvolutionCondition(120), SpeciesWildEvolutionDelay.LONG)
],
[Species.TYPE_NULL]: [
new SpeciesEvolution(Species.SILVALLY, 1, null, new SpeciesFriendshipEvolutionCondition(100), SpeciesWildEvolutionDelay.LONG)
new SpeciesEvolution(Species.SILVALLY, 1, null, new FriendshipEvolutionCondition(100), SpeciesWildEvolutionDelay.LONG)
],
[Species.ALOLA_MEOWTH]: [
new SpeciesEvolution(Species.ALOLA_PERSIAN, 1, null, new SpeciesFriendshipEvolutionCondition(120), SpeciesWildEvolutionDelay.LONG)
new SpeciesEvolution(Species.ALOLA_PERSIAN, 1, null, new FriendshipEvolutionCondition(120), SpeciesWildEvolutionDelay.LONG)
],
[Species.SNOM]: [
new SpeciesEvolution(Species.FROSMOTH, 1, null, new SpeciesFriendshipEvolutionCondition(90, p => globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT), SpeciesWildEvolutionDelay.MEDIUM)
new SpeciesEvolution(Species.FROSMOTH, 1, null, new FriendshipTimeOfDayEvolutionCondition(90, "night"), SpeciesWildEvolutionDelay.MEDIUM)
],
[Species.GIMMIGHOUL]: [
new SpeciesFormEvolution(Species.GHOLDENGO, "chest", "", 1, null, new SpeciesEvolutionCondition(p => p.evoCounter
+ p.getHeldItems().filter(m => m instanceof DamageMoneyRewardModifier).length
+ globalScene.findModifiers(m => m instanceof MoneyMultiplierModifier
|| m instanceof ExtraModifierModifier || m instanceof TempExtraModifierModifier).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
+ globalScene.findModifiers(m => m instanceof MoneyMultiplierModifier
|| m instanceof ExtraModifierModifier || m instanceof TempExtraModifierModifier).length > 9), SpeciesWildEvolutionDelay.VERY_LONG)
new SpeciesFormEvolution(Species.GHOLDENGO, "chest", "", 1, null, new TreasureEvolutionCondition(), SpeciesWildEvolutionDelay.VERY_LONG),
new SpeciesFormEvolution(Species.GHOLDENGO, "roaming", "", 1, null, new TreasureEvolutionCondition(), SpeciesWildEvolutionDelay.VERY_LONG)
]
};
@ -1691,3 +1883,19 @@ export function initPokemonPrevolutions(): void {
}
});
}
// TODO: This may cause funny business for double starters such as Pichu/Pikachu
export const pokemonStarters: PokemonPrevolutions = {};
export function initPokemonStarters(): void {
const starterKeys = Object.keys(pokemonPrevolutions);
starterKeys.forEach(pk => {
const prevolution = pokemonPrevolutions[pk];
if (speciesStarterCosts.hasOwnProperty(prevolution)) {
pokemonStarters[pk] = prevolution;
} else {
pokemonStarters[pk] = pokemonPrevolutions[prevolution];
}
});
}

View File

@ -19718,6 +19718,44 @@ export const pokemonFormLevelMoves: PokemonSpeciesFormLevelMoves = {
[ 48, Moves.CLOSE_COMBAT ],
[ 52, Moves.FOCUS_PUNCH ],
],
2: [
[ EVOLVE_MOVE, Moves.WICKED_BLOW ],
[ 1, Moves.LEER ],
[ 1, Moves.FOCUS_ENERGY ],
[ 1, Moves.ENDURE ],
[ 1, Moves.ROCK_SMASH ],
[ 1, Moves.SUCKER_PUNCH ],
[ 12, Moves.AERIAL_ACE ],
[ 16, Moves.SCARY_FACE ],
[ 20, Moves.HEADBUTT ],
[ 24, Moves.BRICK_BREAK ],
[ 28, Moves.DETECT ],
[ 32, Moves.BULK_UP ],
[ 36, Moves.IRON_HEAD ],
[ 40, Moves.DYNAMIC_PUNCH ],
[ 44, Moves.COUNTER ],
[ 48, Moves.CLOSE_COMBAT ],
[ 52, Moves.FOCUS_PUNCH ],
],
3: [
[ EVOLVE_MOVE, Moves.SURGING_STRIKES ],
[ 1, Moves.LEER ],
[ 1, Moves.FOCUS_ENERGY ],
[ 1, Moves.ENDURE ],
[ 1, Moves.ROCK_SMASH ],
[ 1, Moves.AQUA_JET ],
[ 12, Moves.AERIAL_ACE ],
[ 16, Moves.SCARY_FACE ],
[ 20, Moves.HEADBUTT ],
[ 24, Moves.BRICK_BREAK ],
[ 28, Moves.DETECT ],
[ 32, Moves.BULK_UP ],
[ 36, Moves.IRON_HEAD ],
[ 40, Moves.DYNAMIC_PUNCH ],
[ 44, Moves.COUNTER ],
[ 48, Moves.CLOSE_COMBAT ],
[ 52, Moves.FOCUS_PUNCH ],
],
},
[Species.CALYREX]: {
1: [

View File

@ -51,9 +51,7 @@ export const speciesStarterCosts = {
[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,
@ -84,22 +82,15 @@ export const speciesStarterCosts = {
[Species.VOLTORB]: 2,
[Species.EXEGGCUTE]: 3,
[Species.CUBONE]: 3,
[Species.HITMONLEE]: 4,
[Species.HITMONCHAN]: 4,
[Species.LICKITUNG]: 3,
[Species.KOFFING]: 2,
[Species.RHYHORN]: 4,
[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,
@ -110,7 +101,6 @@ export const speciesStarterCosts = {
[Species.OMANYTE]: 3,
[Species.KABUTO]: 3,
[Species.AERODACTYL]: 5,
[Species.SNORLAX]: 5,
[Species.ARTICUNO]: 5,
[Species.ZAPDOS]: 6,
[Species.MOLTRES]: 6,
@ -132,8 +122,6 @@ export const speciesStarterCosts = {
[Species.TOGEPI]: 3,
[Species.NATU]: 2,
[Species.MAREEP]: 2,
[Species.MARILL]: 4,
[Species.SUDOWOODO]: 3,
[Species.HOPPIP]: 2,
[Species.AIPOM]: 2,
[Species.SUNKERN]: 1,
@ -142,7 +130,6 @@ export const speciesStarterCosts = {
[Species.MURKROW]: 3,
[Species.MISDREAVUS]: 2,
[Species.UNOWN]: 1,
[Species.WOBBUFFET]: 2,
[Species.GIRAFARIG]: 3,
[Species.PINECO]: 2,
[Species.DUNSPARCE]: 3,
@ -158,7 +145,6 @@ export const speciesStarterCosts = {
[Species.CORSOLA]: 2,
[Species.REMORAID]: 2,
[Species.DELIBIRD]: 2,
[Species.MANTINE]: 3,
[Species.SKARMORY]: 4,
[Species.HOUNDOUR]: 3,
[Species.PHANPY]: 3,
@ -206,7 +192,6 @@ export const speciesStarterCosts = {
[Species.MINUN]: 2,
[Species.VOLBEAT]: 2,
[Species.ILLUMISE]: 2,
[Species.ROSELIA]: 3,
[Species.GULPIN]: 1,
[Species.CARVANHA]: 3,
[Species.WAILMER]: 2,
@ -232,7 +217,6 @@ export const speciesStarterCosts = {
[Species.SHUPPET]: 2,
[Species.DUSKULL]: 3,
[Species.TROPIUS]: 3,
[Species.CHIMECHO]: 3,
[Species.ABSOL]: 4,
[Species.WYNAUT]: 2,
[Species.SNORUNT]: 2,
@ -543,7 +527,6 @@ export const speciesStarterCosts = {
[Species.GALAR_PONYTA]: 2,
[Species.GALAR_SLOWPOKE]: 3,
[Species.GALAR_FARFETCHD]: 3,
[Species.GALAR_MR_MIME]: 3,
[Species.GALAR_ARTICUNO]: 6,
[Species.GALAR_ZAPDOS]: 6,
[Species.GALAR_MOLTRES]: 6,

View File

@ -18,7 +18,7 @@ import {
MoveFlags,
StatusCategoryOnAllyAttr
} from "#app/data/move";
import { SpeciesFormChangeManualTrigger } from "#app/data/pokemon-forms";
import { SpeciesFormChangeAbilityTrigger } from "#app/data/pokemon-forms";
import { getStatusEffectHealText } from "#app/data/status-effect";
import { TerrainType } from "#app/data/terrain";
import { Type } from "#enums/type";
@ -2149,7 +2149,7 @@ export class FormBlockDamageTag extends BattlerTag {
super.onAdd(pokemon);
if (pokemon.formIndex !== 0) {
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger);
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeAbilityTrigger);
}
}
@ -2161,7 +2161,7 @@ export class FormBlockDamageTag extends BattlerTag {
onRemove(pokemon: Pokemon): void {
super.onRemove(pokemon);
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger);
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeAbilityTrigger);
}
}
/** Provides the additional weather-based effects of the Ice Face ability */
@ -2361,12 +2361,12 @@ export class GulpMissileTag extends BattlerTag {
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger);
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeAbilityTrigger);
}
onRemove(pokemon: Pokemon): void {
super.onRemove(pokemon);
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger);
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeAbilityTrigger);
}
}

View File

@ -8,7 +8,7 @@ import { speciesStarterCosts } from "#app/data/balance/starters";
import type Pokemon from "#app/field/pokemon";
import { PokemonMove } from "#app/field/pokemon";
import type { FixedBattleConfig } from "#app/battle";
import { BattleType } from "#app/battle";
import { ClassicFixedBossWaves, BattleType, getRandomTrainerFunc } from "#app/battle";
import Trainer, { TrainerVariant } from "#app/field/trainer";
import type { GameMode } from "#app/game-mode";
import { Type } from "#enums/type";
@ -20,6 +20,7 @@ import type { Moves } from "#enums/moves";
import { TypeColor, TypeShadow } from "#enums/color";
import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions";
import { pokemonFormChanges } from "#app/data/pokemon-forms";
import { ModifierTier } from "#app/modifier/modifier-tier";
/** A constant for the default max cost of the starting party before a run */
const DEFAULT_PARTY_MAX_COST = 10;
@ -464,30 +465,64 @@ export class SingleGenerationChallenge extends Challenge {
return false;
}
applyFixedBattle(waveIndex: Number, battleConfig: FixedBattleConfig): boolean {
let trainerTypes: TrainerType[] = [];
applyFixedBattle(waveIndex: number, battleConfig: FixedBattleConfig): boolean {
let trainerTypes: (TrainerType | TrainerType[])[] = [];
const evilTeamWaves: number[] = [ ClassicFixedBossWaves.EVIL_GRUNT_1, ClassicFixedBossWaves.EVIL_GRUNT_2, ClassicFixedBossWaves.EVIL_GRUNT_3, ClassicFixedBossWaves.EVIL_ADMIN_1, ClassicFixedBossWaves.EVIL_GRUNT_4, ClassicFixedBossWaves.EVIL_ADMIN_2, ClassicFixedBossWaves.EVIL_BOSS_1, ClassicFixedBossWaves.EVIL_BOSS_2 ];
const evilTeamGrunts = [[ TrainerType.ROCKET_GRUNT ], [ 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 evilTeamAdmins = [[ TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON, TrainerType.PETREL ], [ 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 ]];
const evilTeamBosses = [[ TrainerType.ROCKET_BOSS_GIOVANNI_1 ], [ TrainerType.ROCKET_BOSS_GIOVANNI_1 ], [ TrainerType.MAXIE, TrainerType.ARCHIE ], [ TrainerType.CYRUS ], [ TrainerType.GHETSIS ], [ TrainerType.LYSANDRE ], [ TrainerType.LUSAMINE, TrainerType.GUZMA ], [ TrainerType.ROSE ], [ TrainerType.PENNY ]];
const evilTeamBossRematches = [[ TrainerType.ROCKET_BOSS_GIOVANNI_2 ], [ 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 ]];
switch (waveIndex) {
case 182:
case ClassicFixedBossWaves.EVIL_GRUNT_1:
trainerTypes = evilTeamGrunts[this.value - 1];
battleConfig.setBattleType(BattleType.TRAINER).setGetTrainerFunc(getRandomTrainerFunc(trainerTypes, true));
return true;
case ClassicFixedBossWaves.EVIL_GRUNT_2:
case ClassicFixedBossWaves.EVIL_GRUNT_3:
case ClassicFixedBossWaves.EVIL_GRUNT_4:
trainerTypes = evilTeamGrunts[this.value - 1];
break;
case ClassicFixedBossWaves.EVIL_ADMIN_1:
case ClassicFixedBossWaves.EVIL_ADMIN_2:
trainerTypes = evilTeamAdmins[this.value - 1];
break;
case ClassicFixedBossWaves.EVIL_BOSS_1:
trainerTypes = evilTeamBosses[this.value - 1];
battleConfig.setBattleType(BattleType.TRAINER).setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1).setGetTrainerFunc(getRandomTrainerFunc(trainerTypes, true))
.setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA ], allowLuckUpgrades: false });
return true;
case ClassicFixedBossWaves.EVIL_BOSS_2:
trainerTypes = evilTeamBossRematches[this.value - 1];
battleConfig.setBattleType(BattleType.TRAINER).setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1).setGetTrainerFunc(getRandomTrainerFunc(trainerTypes, true))
.setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA ], allowLuckUpgrades: false });
return true;
case ClassicFixedBossWaves.ELITE_FOUR_1:
trainerTypes = [ TrainerType.LORELEI, TrainerType.WILL, TrainerType.SIDNEY, TrainerType.AARON, TrainerType.SHAUNTAL, TrainerType.MALVA, Utils.randSeedItem([ TrainerType.HALA, TrainerType.MOLAYNE ]), TrainerType.MARNIE_ELITE, TrainerType.RIKA ];
break;
case 184:
case ClassicFixedBossWaves.ELITE_FOUR_2:
trainerTypes = [ TrainerType.BRUNO, TrainerType.KOGA, TrainerType.PHOEBE, TrainerType.BERTHA, TrainerType.MARSHAL, TrainerType.SIEBOLD, TrainerType.OLIVIA, TrainerType.NESSA_ELITE, TrainerType.POPPY ];
break;
case 186:
case ClassicFixedBossWaves.ELITE_FOUR_3:
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;
case 188:
case ClassicFixedBossWaves.ELITE_FOUR_4:
trainerTypes = [ TrainerType.LANCE, TrainerType.KAREN, TrainerType.DRAKE, TrainerType.LUCIAN, TrainerType.CAITLIN, TrainerType.DRASNA, TrainerType.KAHILI, TrainerType.RAIHAN_ELITE, TrainerType.HASSEL ];
break;
case 190:
case ClassicFixedBossWaves.CHAMPION:
trainerTypes = [ TrainerType.BLUE, Utils.randSeedItem([ TrainerType.RED, TrainerType.LANCE_CHAMPION ]), Utils.randSeedItem([ TrainerType.STEVEN, TrainerType.WALLACE ]), TrainerType.CYNTHIA, Utils.randSeedItem([ TrainerType.ALDER, TrainerType.IRIS ]), TrainerType.DIANTHA, TrainerType.HAU, TrainerType.LEON, Utils.randSeedItem([ TrainerType.GEETA, TrainerType.NEMONA ]) ];
break;
}
if (trainerTypes.length === 0) {
return false;
} else {
battleConfig.setBattleType(BattleType.TRAINER).setGetTrainerFunc(() => new Trainer(trainerTypes[this.value - 1], TrainerVariant.DEFAULT));
} else if (evilTeamWaves.includes(waveIndex)) {
battleConfig.setBattleType(BattleType.TRAINER).setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1).setGetTrainerFunc(getRandomTrainerFunc(trainerTypes, true));
return true;
} else if (waveIndex >= ClassicFixedBossWaves.ELITE_FOUR_1 && waveIndex <= ClassicFixedBossWaves.CHAMPION) {
const ttypes = trainerTypes as TrainerType[];
battleConfig.setBattleType(BattleType.TRAINER).setGetTrainerFunc(() => new Trainer(ttypes[this.value - 1], TrainerVariant.DEFAULT));
return true;
} else {
return false;
}
}

View File

@ -5,7 +5,8 @@ import type { Nature } from "#enums/nature";
/**
* Data that can customize a Pokemon in non-standard ways from its Species
* Currently only used by Mystery Encounters and Mints.
* Used by Mystery Encounters and Mints
* Also used as a counter how often a Pokemon got hit until new arena encounter
*/
export class CustomPokemonData {
public spriteScale: number;
@ -13,6 +14,8 @@ export class CustomPokemonData {
public passive: Abilities | -1;
public nature: Nature | -1;
public types: Type[];
/** `hitsReceivedCount` aka `hitsRecCount` saves how often the pokemon got hit until a new arena encounter (used for Rage Fist) */
public hitsRecCount: number;
constructor(data?: CustomPokemonData | Partial<CustomPokemonData>) {
if (!isNullOrUndefined(data)) {
@ -24,5 +27,10 @@ export class CustomPokemonData {
this.passive = this.passive ?? -1;
this.nature = this.nature ?? -1;
this.types = this.types ?? [];
this.hitsRecCount = this.hitsRecCount ?? 0;
}
resetHitReceivedCount(): void {
this.hitsRecCount = 0;
}
}

View File

@ -1380,8 +1380,10 @@ export class UserHpDamageAttr extends FixedDamageAttr {
}
export class TargetHalfHpDamageAttr extends FixedDamageAttr {
// the initial amount of hp the target had before the first hit
// used for multi lens
/**
* The initial amount of hp the target had before the first hit.
* Used for calculating multi lens damage.
*/
private initialHp: number;
constructor() {
super(0);
@ -1405,12 +1407,10 @@ export class TargetHalfHpDamageAttr extends FixedDamageAttr {
// multi lens added hit; use initialHp tracker to ensure correct damage
(args[0] as Utils.NumberHolder).value = Utils.toDmgValue(this.initialHp / 2);
return true;
break;
case lensCount + 1:
// parental bond added hit; calc damage as normal
(args[0] as Utils.NumberHolder).value = Utils.toDmgValue(target.hp / 2);
return true;
break;
}
}
@ -1892,7 +1892,8 @@ export class SacrificialFullRestoreAttr extends SacrificialAttr {
}
// We don't know which party member will be chosen, so pick the highest max HP in the party
const maxPartyMemberHp = globalScene.getPlayerParty().map(p => p.getMaxHp()).reduce((maxHp: integer, hp: integer) => Math.max(hp, maxHp), 0);
const party = user.isPlayer() ? globalScene.getPlayerParty() : globalScene.getEnemyParty();
const maxPartyMemberHp = party.map(p => p.getMaxHp()).reduce((maxHp: integer, hp: integer) => Math.max(hp, maxHp), 0);
globalScene.pushPhase(
new PokemonHealPhase(
@ -3993,12 +3994,32 @@ export class FriendshipPowerAttr extends VariablePowerAttr {
}
}
export class HitCountPowerAttr extends VariablePowerAttr {
/**
* This Attribute calculates the current power of {@linkcode Moves.RAGE_FIST}.
* The counter for power calculation does not reset on every wave but on every new arena encounter
*/
export class RageFistPowerAttr extends VariablePowerAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
(args[0] as Utils.NumberHolder).value += Math.min(user.battleData.hitCount, 6) * 50;
const { hitCount, prevHitCount } = user.battleData;
const basePower: Utils.NumberHolder = args[0];
this.updateHitReceivedCount(user, hitCount, prevHitCount);
basePower.value = 50 + (Math.min(user.customPokemonData.hitsRecCount, 6) * 50);
return true;
}
/**
* Updates the number of hits the Pokemon has taken in battle
* @param user Pokemon calling Rage Fist
* @param hitCount The number of received hits this battle
* @param previousHitCount The number of received hits this battle since last time Rage Fist was used
*/
protected updateHitReceivedCount(user: Pokemon, hitCount: number, previousHitCount: number): void {
user.customPokemonData.hitsRecCount += (hitCount - previousHitCount);
user.battleData.prevHitCount = hitCount;
}
}
/**
@ -6109,7 +6130,7 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
return false;
}
// Don't allow wild mons to flee with U-turn et al
// Don't allow wild mons to flee with U-turn et al.
if (this.selfSwitch && !user.isPlayer() && move.category !== MoveCategory.STATUS) {
return false;
}
@ -7064,7 +7085,25 @@ export class RepeatMoveAttr extends MoveEffectAttr {
// get the last move used (excluding status based failures) as well as the corresponding moveset slot
const lastMove = target.getLastXMoves(-1).find(m => m.move !== Moves.NONE)!;
const movesetMove = target.getMoveset().find(m => m?.moveId === lastMove.move)!;
const moveTargets = lastMove.targets ?? [];
// If the last move used can hit more than one target or has variable targets,
// re-compute the targets for the attack
// (mainly for alternating double/single battle shenanigans)
// Rampaging moves (e.g. Outrage) are not included due to being incompatible with Instruct
// TODO: Fix this once dragon darts gets smart targeting
let moveTargets = movesetMove.getMove().isMultiTarget() ? getMoveTargets(target, lastMove.move).targets : lastMove.targets;
/** In the event the instructed move's only target is a fainted opponent, redirect it to an alive ally if possible
Normally, all yet-unexecuted move phases would swap over when the enemy in question faints
(see `redirectPokemonMoves` in `battle-scene.ts`),
but since instruct adds a new move phase pre-emptively, we need to handle this interaction manually.
*/
const firstTarget = globalScene.getField()[moveTargets[0]];
if (globalScene.currentBattle.double && moveTargets.length === 1 && firstTarget.isFainted() && firstTarget !== target.getAlly()) {
const ally = firstTarget.getAlly();
if (ally.isActive()) { // ally exists, is not dead and can sponge the blast
moveTargets = [ ally.getBattlerIndex() ];
}
}
globalScene.queueMessage(i18next.t("moveTriggers:instructingMove", {
userPokemonName: getPokemonNameWithAffix(user),
@ -7078,12 +7117,9 @@ export class RepeatMoveAttr extends MoveEffectAttr {
getCondition(): MoveConditionFunc {
return (user, target, move) => {
// TODO: Confirm behavior of instructing move known by target but called by another move
const lastMove = target.getLastXMoves(-1).find(m => m.move !== Moves.NONE);
const movesetMove = target.getMoveset().find(m => m?.moveId === lastMove?.move);
const moveTargets = lastMove?.targets ?? [];
// TODO: Add a way of adding moves to list procedurally rather than a pre-defined blacklist
const unrepeatablemoves = [
const uninstructableMoves = [
// Locking/Continually Executed moves
Moves.OUTRAGE,
Moves.RAGING_FURY,
@ -7138,11 +7174,11 @@ export class RepeatMoveAttr extends MoveEffectAttr {
// TODO: Add Max/G-Move blockage if or when they are implemented
];
if (!movesetMove // called move not in target's moveset (dancer, forgetting the move, etc.)
if (!lastMove?.move // no move to instruct
|| !movesetMove // called move not in target's moveset (forgetting the move, etc.)
|| movesetMove.ppUsed === movesetMove.getMovePp() // move out of pp
|| allMoves[lastMove?.move ?? Moves.NONE].isChargingMove() // called move is a charging/recharging move
|| !moveTargets.length // called move has no targets
|| unrepeatablemoves.includes(lastMove?.move ?? Moves.NONE)) { // called move is explicitly in the banlist
|| allMoves[lastMove.move].isChargingMove() // called move is a charging/recharging move
|| uninstructableMoves.includes(lastMove.move)) { // called move is in the banlist
return false;
}
return true;
@ -7150,7 +7186,7 @@ export class RepeatMoveAttr extends MoveEffectAttr {
}
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer {
// TODO: Make the AI acutally use instruct
// TODO: Make the AI actually use instruct
/* Ideally, the AI would score instruct based on the scorings of the on-field pokemons'
* last used moves at the time of using Instruct (by the time the instructor gets to act)
* with respect to the user's side.
@ -10259,7 +10295,10 @@ export function initMoves() {
new StatusMove(Moves.INSTRUCT, Type.PSYCHIC, -1, 15, -1, 0, 7)
.ignoresSubstitute()
.attr(RepeatMoveAttr)
.edgeCase(), // incorrect interactions with Gigaton Hammer, Blood Moon & Torment
// incorrect interactions with Gigaton Hammer, Blood Moon & Torment
// Also has incorrect interactions with Dancer due to the latter
// erroneously adding copied moves to move history.
.edgeCase(),
new AttackMove(Moves.BEAK_BLAST, Type.FLYING, MoveCategory.PHYSICAL, 100, 100, 15, -1, -3, 7)
.attr(BeakBlastHeaderAttr)
.ballBombMove()
@ -10991,8 +11030,8 @@ export function initMoves() {
new AttackMove(Moves.TWIN_BEAM, Type.PSYCHIC, MoveCategory.SPECIAL, 40, 100, 10, -1, 0, 9)
.attr(MultiHitAttr, MultiHitType._2),
new AttackMove(Moves.RAGE_FIST, Type.GHOST, MoveCategory.PHYSICAL, 50, 100, 10, -1, 0, 9)
.partial() // Counter resets every wave instead of on arena reset
.attr(HitCountPowerAttr)
.edgeCase() // Counter incorrectly increases on confusion self-hits
.attr(RageFistPowerAttr)
.punchingMove(),
new AttackMove(Moves.ARMOR_CANNON, Type.FIRE, MoveCategory.SPECIAL, 120, 100, 5, -1, 0, 9)
.attr(StatStageChangeAttr, [ Stat.DEF, Stat.SPDEF ], -1, true),

View File

@ -4,6 +4,7 @@ import type {
import {
generateModifierType,
generateModifierTypeOption,
getRandomEncounterSpecies,
initBattleWithEnemyConfig,
leaveEncounterWithoutBattle,
setEncounterExp,
@ -11,17 +12,15 @@ import {
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import type { PlayerPokemon } from "#app/field/pokemon";
import type Pokemon from "#app/field/pokemon";
import { EnemyPokemon } from "#app/field/pokemon";
import type {
BerryModifierType,
ModifierTypeOption } from "#app/modifier/modifier-type";
import {
getPartyLuckValue,
ModifierPoolType,
modifierTypes,
regenerateModifierPoolThresholds,
} from "#app/modifier/modifier-type";
import { randSeedInt, randSeedItem } from "#app/utils";
import { randSeedInt } from "#app/utils";
import { BattlerTagType } from "#enums/battler-tag-type";
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { globalScene } from "#app/global-scene";
@ -31,7 +30,6 @@ import { queueEncounterMessage, showEncounterText } from "#app/data/mystery-enco
import { getPokemonNameWithAffix } from "#app/messages";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { TrainerSlot } from "#app/data/trainer-config";
import { applyModifierTypeToPlayerPokemon, getEncounterPokemonLevelForWave, getHighestStatPlayerPokemon, getSpriteKeysFromPokemon, STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
import PokemonData from "#app/system/pokemon-data";
import { BerryModifier } from "#app/modifier/modifier";
@ -40,8 +38,6 @@ import { BerryType } from "#enums/berry-type";
import { PERMANENT_STATS, Stat } from "#enums/stat";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
import type PokemonSpecies from "#app/data/pokemon-species";
import { getPokemonSpecies } from "#app/data/pokemon-species";
/** the i18n namespace for the encounter */
const namespace = "mysteryEncounters/berriesAbound";
@ -69,20 +65,12 @@ export const BerriesAboundEncounter: MysteryEncounter =
// Calculate boss mon
const level = getEncounterPokemonLevelForWave(STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER);
let bossSpecies: PokemonSpecies;
if (globalScene.eventManager.isEventActive() && globalScene.eventManager.activeEvent()?.uncommonBreedEncounters && randSeedInt(2) === 1) {
const eventEncounter = randSeedItem(globalScene.eventManager.activeEvent()!.uncommonBreedEncounters!);
const levelSpecies = getPokemonSpecies(eventEncounter.species).getWildSpeciesForLevel(level, eventEncounter.allowEvolution ?? false, true, globalScene.gameMode);
bossSpecies = getPokemonSpecies( levelSpecies );
} else {
bossSpecies = globalScene.arena.randomSpecies(globalScene.currentBattle.waveIndex, level, 0, getPartyLuckValue(globalScene.getPlayerParty()), true);
}
const bossPokemon = new EnemyPokemon(bossSpecies, level, TrainerSlot.NONE, true);
const bossPokemon = getRandomEncounterSpecies(level, true);
encounter.setDialogueToken("enemyPokemon", getPokemonNameWithAffix(bossPokemon));
const config: EnemyPartyConfig = {
pokemonConfigs: [{
level: level,
species: bossSpecies,
species: bossPokemon.species,
dataSource: new PokemonData(bossPokemon),
isBoss: true
}],

View File

@ -41,7 +41,7 @@ const OPTION_3_DISALLOWED_MODIFIERS = [
const DELIBIRDY_MONEY_PRICE_MULTIPLIER = 2;
const doEventReward = () => {
const event_buff = globalScene.eventManager.activeEvent()?.delibirdyBuff ?? [];
const event_buff = globalScene.eventManager.getDelibirdyBuff();
if (event_buff.length > 0) {
const candidates = event_buff.filter((c => {
const mtype = generateModifierType(modifierTypes[c]);

View File

@ -2,6 +2,7 @@ import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/myst
import type {
EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import {
getRandomEncounterSpecies,
initBattleWithEnemyConfig,
leaveEncounterWithoutBattle,
setEncounterExp,
@ -9,12 +10,10 @@ import {
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { STEALING_MOVES } from "#app/data/mystery-encounters/requirements/requirement-groups";
import type Pokemon from "#app/field/pokemon";
import { EnemyPokemon } from "#app/field/pokemon";
import { ModifierTier } from "#app/modifier/modifier-tier";
import type {
ModifierTypeOption } from "#app/modifier/modifier-type";
import {
getPartyLuckValue,
getPlayerModifierTypeOptions,
ModifierPoolType,
regenerateModifierPoolThresholds,
@ -26,16 +25,13 @@ import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-en
import { MoveRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { TrainerSlot } from "#app/data/trainer-config";
import { getEncounterPokemonLevelForWave, getSpriteKeysFromPokemon, STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
import PokemonData from "#app/system/pokemon-data";
import { BattlerTagType } from "#enums/battler-tag-type";
import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import { randSeedInt, randSeedItem } from "#app/utils";
import { randSeedInt } from "#app/utils";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
import type PokemonSpecies from "#app/data/pokemon-species";
import { getPokemonSpecies } from "#app/data/pokemon-species";
/** the i18n namespace for the encounter */
const namespace = "mysteryEncounters/fightOrFlight";
@ -63,20 +59,12 @@ export const FightOrFlightEncounter: MysteryEncounter =
// Calculate boss mon
const level = getEncounterPokemonLevelForWave(STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER);
let bossSpecies: PokemonSpecies;
if (globalScene.eventManager.isEventActive() && globalScene.eventManager.activeEvent()?.uncommonBreedEncounters && randSeedInt(2) === 1) {
const eventEncounter = randSeedItem(globalScene.eventManager.activeEvent()!.uncommonBreedEncounters!);
const levelSpecies = getPokemonSpecies(eventEncounter.species).getWildSpeciesForLevel(level, eventEncounter.allowEvolution ?? false, true, globalScene.gameMode);
bossSpecies = getPokemonSpecies( levelSpecies );
} else {
bossSpecies = globalScene.arena.randomSpecies(globalScene.currentBattle.waveIndex, level, 0, getPartyLuckValue(globalScene.getPlayerParty()), true);
}
const bossPokemon = new EnemyPokemon(bossSpecies, level, TrainerSlot.NONE, true);
const bossPokemon = getRandomEncounterSpecies(level, true);
encounter.setDialogueToken("enemyPokemon", bossPokemon.getNameToRender());
const config: EnemyPartyConfig = {
pokemonConfigs: [{
level: level,
species: bossSpecies,
species: bossPokemon.species,
dataSource: new PokemonData(bossPokemon),
isBoss: true,
tags: [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON ],

View File

@ -449,7 +449,7 @@ function getPokemonTradeOptions(): Map<number, EnemyPokemon[]> {
});
tradeOptionsMap.set(pokemon.id, tradeOptions);
} else {
const originalBst = pokemon.calculateBaseStats().reduce((a, b) => a + b, 0);
const originalBst = pokemon.getSpeciesForm().getBaseStatTotal();
const tradeOptions: PokemonSpecies[] = [];
for (let i = 0; i < 3; i++) {

View File

@ -452,7 +452,7 @@ function getSpeciesFromPool(speciesPool: (Species | BreederSpeciesEvolution)[][]
}
function calculateEggRewardsForPokemon(pokemon: PlayerPokemon): [number, number] {
const bst = pokemon.calculateBaseStats().reduce((a, b) => a + b, 0);
const bst = pokemon.getSpeciesForm().getBaseStatTotal();
// 1 point for every 20 points below 680 BST the pokemon is, (max 18, min 1)
const pointsFromBst = Math.min(Math.max(Math.floor((680 - bst) / 20), 1), 18);

View File

@ -147,8 +147,8 @@ export const TheStrongStuffEncounter: MysteryEncounter =
// Sort party by bst
const sortedParty = globalScene.getPlayerParty().slice(0)
.sort((pokemon1, pokemon2) => {
const pokemon1Bst = pokemon1.calculateBaseStats().reduce((a, b) => a + b, 0);
const pokemon2Bst = pokemon2.calculateBaseStats().reduce((a, b) => a + b, 0);
const pokemon1Bst = pokemon1.getSpeciesForm().getBaseStatTotal();
const pokemon2Bst = pokemon2.getSpeciesForm().getBaseStatTotal();
return pokemon2Bst - pokemon1Bst;
});

View File

@ -16,7 +16,7 @@ import { Nature } from "#enums/nature";
import { Type } from "#enums/type";
import { BerryType } from "#enums/berry-type";
import { Stat } from "#enums/stat";
import { SpeciesFormChangeManualTrigger } from "#app/data/pokemon-forms";
import { SpeciesFormChangeAbilityTrigger } from "#app/data/pokemon-forms";
import { applyPostBattleInitAbAttrs, PostBattleInitAbAttr } from "#app/data/ability";
import { showEncounterDialogue, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
@ -198,7 +198,7 @@ function endTrainerBattleAndShowDialogue(): Promise<void> {
// Only trigger form change when Eiscue is in Noice form
// Hardcoded Eiscue for now in case it is fused with another pokemon
if (pokemon.species.speciesId === Species.EISCUE && pokemon.hasAbility(Abilities.ICE_FACE) && pokemon.formIndex === 1) {
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger);
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeAbilityTrigger);
}
pokemon.resetBattleData();

View File

@ -1,10 +1,10 @@
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { initBattleWithEnemyConfig, leaveEncounterWithoutBattle, setEncounterExp, setEncounterRewards } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { getRandomEncounterSpecies, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, setEncounterExp, setEncounterRewards } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { CHARMING_MOVES } from "#app/data/mystery-encounters/requirements/requirement-groups";
import type Pokemon from "#app/field/pokemon";
import { EnemyPokemon, PokemonMove } from "#app/field/pokemon";
import { getPartyLuckValue } from "#app/modifier/modifier-type";
import type { EnemyPokemon } from "#app/field/pokemon";
import { PokemonMove } from "#app/field/pokemon";
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { globalScene } from "#app/global-scene";
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
@ -12,10 +12,9 @@ import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-en
import { MoveRequirement, PersistentModifierRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { TrainerSlot } from "#app/data/trainer-config";
import { catchPokemon, getHighestLevelPlayerPokemon, getSpriteKeysFromPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
import PokemonData from "#app/system/pokemon-data";
import { isNullOrUndefined, randSeedInt, randSeedItem } from "#app/utils";
import { isNullOrUndefined, randSeedInt } from "#app/utils";
import type { Moves } from "#enums/moves";
import { BattlerIndex } from "#app/battle";
import { SelfStatusMove } from "#app/data/move";
@ -26,8 +25,6 @@ import { BerryModifier } from "#app/modifier/modifier";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { Stat } from "#enums/stat";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
import type PokemonSpecies from "#app/data/pokemon-species";
import { getPokemonSpecies } from "#app/data/pokemon-species";
/** the i18n namespace for the encounter */
const namespace = "mysteryEncounters/uncommonBreed";
@ -56,15 +53,7 @@ export const UncommonBreedEncounter: MysteryEncounter =
// Calculate boss mon
// Level equal to 2 below highest party member
const level = getHighestLevelPlayerPokemon(false, true).level - 2;
let species: PokemonSpecies;
if (globalScene.eventManager.isEventActive() && globalScene.eventManager.activeEvent()?.uncommonBreedEncounters && randSeedInt(2) === 1) {
const eventEncounter = randSeedItem(globalScene.eventManager.activeEvent()!.uncommonBreedEncounters!);
const levelSpecies = getPokemonSpecies(eventEncounter.species).getWildSpeciesForLevel(level, eventEncounter.allowEvolution ?? false, true, globalScene.gameMode);
species = getPokemonSpecies( levelSpecies );
} else {
species = globalScene.arena.randomSpecies(globalScene.currentBattle.waveIndex, level, 0, getPartyLuckValue(globalScene.getPlayerParty()), true);
}
const pokemon = new EnemyPokemon(species, level, TrainerSlot.NONE, true);
const pokemon = getRandomEncounterSpecies(level, true, true);
// Pokemon will always have one of its egg moves in its moveset
const eggMoves = pokemon.getEggMoves();
@ -92,7 +81,7 @@ export const UncommonBreedEncounter: MysteryEncounter =
const config: EnemyPartyConfig = {
pokemonConfigs: [{
level: level,
species: species,
species: pokemon.species,
dataSource: new PokemonData(pokemon),
isBoss: false,
tags: [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON ],

View File

@ -360,7 +360,7 @@ function getTeamTransformations(): PokemonTransformation[] {
const index = pokemonTransformations.findIndex(p => p.previousPokemon.id === removed.id);
pokemonTransformations[index].heldItems = removed.getHeldItems().filter(m => !(m instanceof PokemonFormChangeItemModifier));
const bst = removed.calculateBaseStats().reduce((a, b) => a + b, 0);
const bst = removed.getSpeciesForm().getBaseStatTotal();
let newBstRange: [number, number];
if (i < 2) {
newBstRange = HIGH_BST_TRANSFORM_BASE_VALUES;

View File

@ -6,9 +6,9 @@ import { AVERAGE_ENCOUNTERS_PER_RUN_TARGET, WEIGHT_INCREMENT_ON_SPAWN_MISS } fro
import { showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import type { AiType, PlayerPokemon } from "#app/field/pokemon";
import type Pokemon from "#app/field/pokemon";
import { FieldPosition, PokemonMove, PokemonSummonData } from "#app/field/pokemon";
import { EnemyPokemon, FieldPosition, PokemonMove, PokemonSummonData } from "#app/field/pokemon";
import type { CustomModifierSettings, ModifierType } from "#app/modifier/modifier-type";
import { ModifierPoolType, ModifierTypeGenerator, ModifierTypeOption, modifierTypes, regenerateModifierPoolThresholds } from "#app/modifier/modifier-type";
import { getPartyLuckValue, ModifierPoolType, ModifierTypeGenerator, ModifierTypeOption, modifierTypes, regenerateModifierPoolThresholds } from "#app/modifier/modifier-type";
import { MysteryEncounterBattlePhase, MysteryEncounterBattleStartCleanupPhase, MysteryEncounterPhase, MysteryEncounterRewardsPhase } from "#app/phases/mystery-encounter-phases";
import type PokemonData from "#app/system/pokemon-data";
import type { OptionSelectConfig, OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
@ -16,7 +16,7 @@ import type { PartyOption, PokemonSelectFilter } from "#app/ui/party-ui-handler"
import { PartyUiMode } from "#app/ui/party-ui-handler";
import { Mode } from "#app/ui/ui";
import * as Utils from "#app/utils";
import { isNullOrUndefined } from "#app/utils";
import { isNullOrUndefined, randSeedInt, randSeedItem } from "#app/utils";
import type { BattlerTagType } from "#enums/battler-tag-type";
import { Biome } from "#enums/biome";
import type { TrainerType } from "#enums/trainer-type";
@ -45,6 +45,7 @@ import { PartyExpPhase } from "#app/phases/party-exp-phase";
import type { Variant } from "#app/data/variant";
import { StatusEffect } from "#enums/status-effect";
import { globalScene } from "#app/global-scene";
import { getPokemonSpecies } from "#app/data/pokemon-species";
/**
* Animates exclamation sprite over trainer's head at start of encounter
@ -874,6 +875,41 @@ export function handleMysteryEncounterTurnStartEffects(): boolean {
return false;
}
/**
* Helper function for encounters such as {@linkcode UncommonBreedEncounter} which call for a random species including event encounters.
* If the mon is from the event encounter list, it will do an extra shiny roll.
* @param level the level of the mon, which differs between MEs
* @param isBoss whether the mon should be a Boss
* @param rerollHidden whether the mon should get an extra roll for Hidden Ability
* @returns {@linkcode EnemyPokemon} for the requested encounter
*/
export function getRandomEncounterSpecies(level: number, isBoss: boolean = false, rerollHidden: boolean = false): EnemyPokemon {
let bossSpecies: PokemonSpecies;
let isEventEncounter = false;
const eventEncounters = globalScene.eventManager.getEventEncounters();
if (eventEncounters.length > 0 && randSeedInt(2) === 1) {
const eventEncounter = randSeedItem(eventEncounters);
const levelSpecies = getPokemonSpecies(eventEncounter.species).getWildSpeciesForLevel(level, !eventEncounter.blockEvolution, isBoss, globalScene.gameMode);
isEventEncounter = true;
bossSpecies = getPokemonSpecies(levelSpecies);
} else {
bossSpecies = globalScene.arena.randomSpecies(globalScene.currentBattle.waveIndex, level, 0, getPartyLuckValue(globalScene.getPlayerParty()), isBoss);
}
const ret = new EnemyPokemon(bossSpecies, level, TrainerSlot.NONE, isBoss);
//Reroll shiny for event encounters
if (isEventEncounter && !ret.shiny) {
ret.trySetShinySeed();
}
//Reroll hidden ability
if (rerollHidden && ret.abilityIndex !== 2 && ret.species.abilityHidden) {
ret.tryRerollHiddenAbilitySeed();
}
return ret;
}
/**
* TODO: remove once encounter spawn rate is finalized
* Just a helper function to calculate aggregate stats for MEs in a Classic run

View File

@ -212,6 +212,8 @@ export class SpeciesFormChangeCondition {
}
export abstract class SpeciesFormChangeTrigger {
public description: string = "";
canChange(pokemon: Pokemon): boolean {
return true;
}
@ -222,16 +224,19 @@ export abstract class SpeciesFormChangeTrigger {
}
export class SpeciesFormChangeManualTrigger extends SpeciesFormChangeTrigger {
canChange(pokemon: Pokemon): boolean {
return true;
}
}
export class SpeciesFormChangeAbilityTrigger extends SpeciesFormChangeTrigger {
public description: string = i18next.t("pokemonEvolutions:Forms.ability");
}
export class SpeciesFormChangeCompoundTrigger {
public description: string = "";
public triggers: SpeciesFormChangeTrigger[];
constructor(...triggers: SpeciesFormChangeTrigger[]) {
this.triggers = triggers;
this.description = this.triggers.filter(trigger => trigger?.description?.length > 0).map(trigger => trigger.description).join(", ");
}
canChange(pokemon: Pokemon): boolean {
@ -257,6 +262,9 @@ export class SpeciesFormChangeItemTrigger extends SpeciesFormChangeTrigger {
super();
this.item = item;
this.active = active;
this.description = this.active ?
i18next.t("pokemonEvolutions:Forms.item", { item: i18next.t(`modifierType:FormChangeItem.${FormChangeItem[this.item]}`) }) :
i18next.t("pokemonEvolutions:Forms.deactivateItem", { item: i18next.t(`modifierType:FormChangeItem.${FormChangeItem[this.item]}`) });
}
canChange(pokemon: Pokemon): boolean {
@ -270,6 +278,7 @@ export class SpeciesFormChangeTimeOfDayTrigger extends SpeciesFormChangeTrigger
constructor(...timesOfDay: TimeOfDay[]) {
super();
this.timesOfDay = timesOfDay;
this.description = i18next.t("pokemonEvolutions:Forms.timeOfDay");
}
canChange(pokemon: Pokemon): boolean {
@ -283,6 +292,7 @@ export class SpeciesFormChangeActiveTrigger extends SpeciesFormChangeTrigger {
constructor(active: boolean = false) {
super();
this.active = active;
this.description = this.active ? i18next.t("pokemonEvolutions:Forms.enter") : i18next.t("pokemonEvolutions:Forms.leave");
}
canChange(pokemon: Pokemon): boolean {
@ -301,6 +311,7 @@ export class SpeciesFormChangeStatusEffectTrigger extends SpeciesFormChangeTrigg
}
this.statusEffects = statusEffects;
this.invert = invert;
this.description = i18next.t("pokemonEvolutions:Forms.statusEffect");
}
canChange(pokemon: Pokemon): boolean {
@ -316,6 +327,8 @@ export class SpeciesFormChangeMoveLearnedTrigger extends SpeciesFormChangeTrigge
super();
this.move = move;
this.known = known;
const moveKey = Moves[this.move].split("_").filter(f => f).map((f, i) => i ? `${f[0]}${f.slice(1).toLowerCase()}` : f.toLowerCase()).join("") as unknown as string;
this.description = i18next.t("pokemonEvolutions:Forms.moveLearned", { move: i18next.t(`move:${moveKey}.name`) });
}
canChange(pokemon: Pokemon): boolean {
@ -335,6 +348,8 @@ export abstract class SpeciesFormChangeMoveTrigger extends SpeciesFormChangeTrig
}
export class SpeciesFormChangePreMoveTrigger extends SpeciesFormChangeMoveTrigger {
description = i18next.t("pokemonEvolutions:Forms.preMove");
canChange(pokemon: Pokemon): boolean {
const command = globalScene.currentBattle.turnCommands[pokemon.getBattlerIndex()];
return !!command?.move && this.movePredicate(command.move.move) === this.used;
@ -342,6 +357,8 @@ export class SpeciesFormChangePreMoveTrigger extends SpeciesFormChangeMoveTrigge
}
export class SpeciesFormChangePostMoveTrigger extends SpeciesFormChangeMoveTrigger {
description = i18next.t("pokemonEvolutions:Forms.postMove");
canChange(pokemon: Pokemon): boolean {
return pokemon.summonData && !!pokemon.getLastXMoves(1).filter(m => this.movePredicate(m.move)).length === this.used;
}
@ -367,6 +384,7 @@ export class SpeciesDefaultFormMatchTrigger extends SpeciesFormChangeTrigger {
constructor(formKey: string) {
super();
this.formKey = formKey;
this.description = "";
}
canChange(pokemon: Pokemon): boolean {
@ -386,6 +404,7 @@ export class SpeciesFormChangeTeraTrigger extends SpeciesFormChangeTrigger {
constructor(teraType: Type) {
super();
this.teraType = teraType;
this.description = i18next.t("pokemonEvolutions:Forms.tera", { teraType: i18next.t(`pokemonInfo:Type.${Type[this.teraType]}`) });
}
/**
@ -404,6 +423,8 @@ export class SpeciesFormChangeTeraTrigger extends SpeciesFormChangeTrigger {
* @extends SpeciesFormChangeTrigger
*/
export class SpeciesFormChangeLapseTeraTrigger extends SpeciesFormChangeTrigger {
description = i18next.t("pokemonEvolutions:Forms.teraLapse");
canChange(pokemon: Pokemon): boolean {
return !!globalScene.findModifier(m => m instanceof TerastallizeModifier && m.pokemonId === pokemon.id);
}
@ -424,6 +445,7 @@ export class SpeciesFormChangeWeatherTrigger extends SpeciesFormChangeTrigger {
super();
this.ability = ability;
this.weathers = weathers;
this.description = i18next.t("pokemonEvolutions:Forms.weather");
}
/**
@ -457,6 +479,7 @@ export class SpeciesFormChangeRevertWeatherFormTrigger extends SpeciesFormChange
super();
this.ability = ability;
this.weathers = weathers;
this.description = i18next.t("pokemonEvolutions:Forms.weatherRevert");
}
/**
@ -751,8 +774,8 @@ export const pokemonFormChanges: PokemonFormChanges = {
new SpeciesFormChange(Species.ARCEUS, "normal", "fairy", new SpeciesFormChangeItemTrigger(FormChangeItem.PIXIE_PLATE))
],
[Species.DARMANITAN]: [
new SpeciesFormChange(Species.DARMANITAN, "", "zen", new SpeciesFormChangeManualTrigger(), true),
new SpeciesFormChange(Species.DARMANITAN, "zen", "", new SpeciesFormChangeManualTrigger(), true)
new SpeciesFormChange(Species.DARMANITAN, "", "zen", new SpeciesFormChangeAbilityTrigger(), true),
new SpeciesFormChange(Species.DARMANITAN, "zen", "", new SpeciesFormChangeAbilityTrigger(), true)
],
[Species.GARBODOR]: [
new SpeciesFormChange(Species.GARBODOR, "", SpeciesFormKey.GIGANTAMAX, new SpeciesFormChangeItemTrigger(FormChangeItem.MAX_MUSHROOMS))
@ -785,12 +808,12 @@ export const pokemonFormChanges: PokemonFormChanges = {
new SpeciesFormChange(Species.GENESECT, "", "douse", new SpeciesFormChangeItemTrigger(FormChangeItem.DOUSE_DRIVE))
],
[Species.GRENINJA]: [
new SpeciesFormChange(Species.GRENINJA, "battle-bond", "ash", new SpeciesFormChangeManualTrigger(), true),
new SpeciesFormChange(Species.GRENINJA, "ash", "battle-bond", new SpeciesFormChangeManualTrigger(), true)
new SpeciesFormChange(Species.GRENINJA, "battle-bond", "ash", new SpeciesFormChangeAbilityTrigger(), true),
new SpeciesFormChange(Species.GRENINJA, "ash", "battle-bond", new SpeciesFormChangeAbilityTrigger(), true)
],
[Species.PALAFIN] : [
new SpeciesFormChange(Species.PALAFIN, "zero", "hero", new SpeciesFormChangeManualTrigger(), true),
new SpeciesFormChange(Species.PALAFIN, "hero", "zero", new SpeciesFormChangeManualTrigger(), true)
new SpeciesFormChange(Species.PALAFIN, "zero", "hero", new SpeciesFormChangeAbilityTrigger(), true),
new SpeciesFormChange(Species.PALAFIN, "hero", "zero", new SpeciesFormChangeAbilityTrigger(), true)
],
[Species.AEGISLASH]: [
new SpeciesFormChange(Species.AEGISLASH, "blade", "shield", new SpeciesFormChangePreMoveTrigger(Moves.KINGS_SHIELD), true, new SpeciesFormChangeCondition(p => p.hasAbility(Abilities.STANCE_CHANGE))),
@ -802,10 +825,10 @@ export const pokemonFormChanges: PokemonFormChanges = {
new SpeciesFormChange(Species.XERNEAS, "active", "neutral", new SpeciesFormChangeActiveTrigger(false), true)
],
[Species.ZYGARDE]: [
new SpeciesFormChange(Species.ZYGARDE, "50-pc", "complete", new SpeciesFormChangeManualTrigger(), true),
new SpeciesFormChange(Species.ZYGARDE, "complete", "50-pc", new SpeciesFormChangeManualTrigger(), true),
new SpeciesFormChange(Species.ZYGARDE, "10-pc", "10-complete", new SpeciesFormChangeManualTrigger(), true),
new SpeciesFormChange(Species.ZYGARDE, "10-complete", "10-pc", new SpeciesFormChangeManualTrigger(), true)
new SpeciesFormChange(Species.ZYGARDE, "50-pc", "complete", new SpeciesFormChangeAbilityTrigger(), true),
new SpeciesFormChange(Species.ZYGARDE, "complete", "50-pc", new SpeciesFormChangeAbilityTrigger(), true),
new SpeciesFormChange(Species.ZYGARDE, "10-pc", "10-complete", new SpeciesFormChangeAbilityTrigger(), true),
new SpeciesFormChange(Species.ZYGARDE, "10-complete", "10-pc", new SpeciesFormChangeAbilityTrigger(), true)
],
[Species.DIANCIE]: [
new SpeciesFormChange(Species.DIANCIE, "", SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.DIANCITE))
@ -814,8 +837,8 @@ export const pokemonFormChanges: PokemonFormChanges = {
new SpeciesFormChange(Species.HOOPA, "", "unbound", new SpeciesFormChangeItemTrigger(FormChangeItem.PRISON_BOTTLE))
],
[Species.WISHIWASHI]: [
new SpeciesFormChange(Species.WISHIWASHI, "", "school", new SpeciesFormChangeManualTrigger(), true),
new SpeciesFormChange(Species.WISHIWASHI, "school", "", new SpeciesFormChangeManualTrigger(), true)
new SpeciesFormChange(Species.WISHIWASHI, "", "school", new SpeciesFormChangeAbilityTrigger(), true),
new SpeciesFormChange(Species.WISHIWASHI, "school", "", new SpeciesFormChangeAbilityTrigger(), true)
],
[Species.SILVALLY]: [
new SpeciesFormChange(Species.SILVALLY, "normal", "fighting", new SpeciesFormChangeItemTrigger(FormChangeItem.FIGHTING_MEMORY)),
@ -837,24 +860,24 @@ export const pokemonFormChanges: PokemonFormChanges = {
new SpeciesFormChange(Species.SILVALLY, "normal", "fairy", new SpeciesFormChangeItemTrigger(FormChangeItem.FAIRY_MEMORY))
],
[Species.MINIOR]: [
new SpeciesFormChange(Species.MINIOR, "red-meteor", "red", new SpeciesFormChangeManualTrigger(), true),
new SpeciesFormChange(Species.MINIOR, "red", "red-meteor", new SpeciesFormChangeManualTrigger(), true),
new SpeciesFormChange(Species.MINIOR, "orange-meteor", "orange", new SpeciesFormChangeManualTrigger(), true),
new SpeciesFormChange(Species.MINIOR, "orange", "orange-meteor", new SpeciesFormChangeManualTrigger(), true),
new SpeciesFormChange(Species.MINIOR, "yellow-meteor", "yellow", new SpeciesFormChangeManualTrigger(), true),
new SpeciesFormChange(Species.MINIOR, "yellow", "yellow-meteor", new SpeciesFormChangeManualTrigger(), true),
new SpeciesFormChange(Species.MINIOR, "green-meteor", "green", new SpeciesFormChangeManualTrigger(), true),
new SpeciesFormChange(Species.MINIOR, "green", "green-meteor", new SpeciesFormChangeManualTrigger(), true),
new SpeciesFormChange(Species.MINIOR, "blue-meteor", "blue", new SpeciesFormChangeManualTrigger(), true),
new SpeciesFormChange(Species.MINIOR, "blue", "blue-meteor", new SpeciesFormChangeManualTrigger(), true),
new SpeciesFormChange(Species.MINIOR, "indigo-meteor", "indigo", new SpeciesFormChangeManualTrigger(), true),
new SpeciesFormChange(Species.MINIOR, "indigo", "indigo-meteor", new SpeciesFormChangeManualTrigger(), true),
new SpeciesFormChange(Species.MINIOR, "violet-meteor", "violet", new SpeciesFormChangeManualTrigger(), true),
new SpeciesFormChange(Species.MINIOR, "violet", "violet-meteor", new SpeciesFormChangeManualTrigger(), true)
new SpeciesFormChange(Species.MINIOR, "red-meteor", "red", new SpeciesFormChangeAbilityTrigger(), true),
new SpeciesFormChange(Species.MINIOR, "red", "red-meteor", new SpeciesFormChangeAbilityTrigger(), true),
new SpeciesFormChange(Species.MINIOR, "orange-meteor", "orange", new SpeciesFormChangeAbilityTrigger(), true),
new SpeciesFormChange(Species.MINIOR, "orange", "orange-meteor", new SpeciesFormChangeAbilityTrigger(), true),
new SpeciesFormChange(Species.MINIOR, "yellow-meteor", "yellow", new SpeciesFormChangeAbilityTrigger(), true),
new SpeciesFormChange(Species.MINIOR, "yellow", "yellow-meteor", new SpeciesFormChangeAbilityTrigger(), true),
new SpeciesFormChange(Species.MINIOR, "green-meteor", "green", new SpeciesFormChangeAbilityTrigger(), true),
new SpeciesFormChange(Species.MINIOR, "green", "green-meteor", new SpeciesFormChangeAbilityTrigger(), true),
new SpeciesFormChange(Species.MINIOR, "blue-meteor", "blue", new SpeciesFormChangeAbilityTrigger(), true),
new SpeciesFormChange(Species.MINIOR, "blue", "blue-meteor", new SpeciesFormChangeAbilityTrigger(), true),
new SpeciesFormChange(Species.MINIOR, "indigo-meteor", "indigo", new SpeciesFormChangeAbilityTrigger(), true),
new SpeciesFormChange(Species.MINIOR, "indigo", "indigo-meteor", new SpeciesFormChangeAbilityTrigger(), true),
new SpeciesFormChange(Species.MINIOR, "violet-meteor", "violet", new SpeciesFormChangeAbilityTrigger(), true),
new SpeciesFormChange(Species.MINIOR, "violet", "violet-meteor", new SpeciesFormChangeAbilityTrigger(), true)
],
[Species.MIMIKYU]: [
new SpeciesFormChange(Species.MIMIKYU, "disguised", "busted", new SpeciesFormChangeManualTrigger(), true),
new SpeciesFormChange(Species.MIMIKYU, "busted", "disguised", new SpeciesFormChangeManualTrigger(), true)
new SpeciesFormChange(Species.MIMIKYU, "disguised", "busted", new SpeciesFormChangeAbilityTrigger(), true),
new SpeciesFormChange(Species.MIMIKYU, "busted", "disguised", new SpeciesFormChangeAbilityTrigger(), true)
],
[Species.NECROZMA]: [
new SpeciesFormChange(Species.NECROZMA, "", "dawn-wings", new SpeciesFormChangeItemTrigger(FormChangeItem.N_LUNARIZER), false, getSpeciesDependentFormChangeCondition(Species.LUNALA)),
@ -896,10 +919,10 @@ export const pokemonFormChanges: PokemonFormChanges = {
new SpeciesFormChange(Species.SANDACONDA, "", SpeciesFormKey.GIGANTAMAX, new SpeciesFormChangeItemTrigger(FormChangeItem.MAX_MUSHROOMS))
],
[Species.CRAMORANT]: [
new SpeciesFormChange(Species.CRAMORANT, "", "gulping", new SpeciesFormChangeManualTrigger, true, new SpeciesFormChangeCondition(p => p.getHpRatio() >= .5)),
new SpeciesFormChange(Species.CRAMORANT, "", "gorging", new SpeciesFormChangeManualTrigger, true, new SpeciesFormChangeCondition(p => p.getHpRatio() < .5)),
new SpeciesFormChange(Species.CRAMORANT, "gulping", "", new SpeciesFormChangeManualTrigger, true),
new SpeciesFormChange(Species.CRAMORANT, "gorging", "", new SpeciesFormChangeManualTrigger, true),
new SpeciesFormChange(Species.CRAMORANT, "", "gulping", new SpeciesFormChangeAbilityTrigger, true, new SpeciesFormChangeCondition(p => p.getHpRatio() >= .5)),
new SpeciesFormChange(Species.CRAMORANT, "", "gorging", new SpeciesFormChangeAbilityTrigger, true, new SpeciesFormChangeCondition(p => p.getHpRatio() < .5)),
new SpeciesFormChange(Species.CRAMORANT, "gulping", "", new SpeciesFormChangeAbilityTrigger, true),
new SpeciesFormChange(Species.CRAMORANT, "gorging", "", new SpeciesFormChangeAbilityTrigger, true),
new SpeciesFormChange(Species.CRAMORANT, "gulping", "", new SpeciesFormChangeActiveTrigger(false), true),
new SpeciesFormChange(Species.CRAMORANT, "gorging", "", new SpeciesFormChangeActiveTrigger(false), true)
],
@ -930,12 +953,12 @@ export const pokemonFormChanges: PokemonFormChanges = {
new SpeciesFormChange(Species.ALCREMIE, "rainbow-swirl", SpeciesFormKey.GIGANTAMAX, new SpeciesFormChangeItemTrigger(FormChangeItem.MAX_MUSHROOMS))
],
[Species.EISCUE]: [
new SpeciesFormChange(Species.EISCUE, "", "no-ice", new SpeciesFormChangeManualTrigger(), true),
new SpeciesFormChange(Species.EISCUE, "no-ice", "", new SpeciesFormChangeManualTrigger(), true)
new SpeciesFormChange(Species.EISCUE, "", "no-ice", new SpeciesFormChangeAbilityTrigger(), true),
new SpeciesFormChange(Species.EISCUE, "no-ice", "", new SpeciesFormChangeAbilityTrigger(), true)
],
[Species.MORPEKO]: [
new SpeciesFormChange(Species.MORPEKO, "full-belly", "hangry", new SpeciesFormChangeManualTrigger(), true),
new SpeciesFormChange(Species.MORPEKO, "hangry", "full-belly", new SpeciesFormChangeManualTrigger(), true)
new SpeciesFormChange(Species.MORPEKO, "full-belly", "hangry", new SpeciesFormChangeAbilityTrigger(), true),
new SpeciesFormChange(Species.MORPEKO, "hangry", "full-belly", new SpeciesFormChangeAbilityTrigger(), true)
],
[Species.COPPERAJAH]: [
new SpeciesFormChange(Species.COPPERAJAH, "", SpeciesFormKey.GIGANTAMAX, new SpeciesFormChangeItemTrigger(FormChangeItem.MAX_MUSHROOMS))
@ -978,13 +1001,13 @@ export const pokemonFormChanges: PokemonFormChanges = {
new SpeciesFormChange(Species.OGERPON, "cornerstone-mask-tera", "cornerstone-mask", new SpeciesFormChangeLapseTeraTrigger(), true, new SpeciesFormChangeCondition(p => p.getTeraType() !== Type.ROCK))
],
[Species.TERAPAGOS]: [
new SpeciesFormChange(Species.TERAPAGOS, "", "terastal", new SpeciesFormChangeManualTrigger(), true),
new SpeciesFormChange(Species.TERAPAGOS, "", "terastal", new SpeciesFormChangeAbilityTrigger(), true),
new SpeciesFormChange(Species.TERAPAGOS, "terastal", "stellar", new SpeciesFormChangeTeraTrigger(Type.STELLAR)),
new SpeciesFormChange(Species.TERAPAGOS, "stellar", "terastal", new SpeciesFormChangeLapseTeraTrigger(), true, new SpeciesFormChangeCondition(p => p.getTeraType() !== Type.STELLAR))
],
[Species.GALAR_DARMANITAN]: [
new SpeciesFormChange(Species.GALAR_DARMANITAN, "", "zen", new SpeciesFormChangeManualTrigger(), true),
new SpeciesFormChange(Species.GALAR_DARMANITAN, "zen", "", new SpeciesFormChangeManualTrigger(), true)
new SpeciesFormChange(Species.GALAR_DARMANITAN, "", "zen", new SpeciesFormChangeAbilityTrigger(), true),
new SpeciesFormChange(Species.GALAR_DARMANITAN, "zen", "", new SpeciesFormChangeAbilityTrigger(), true)
],
};
@ -1002,3 +1025,4 @@ export function initPokemonForms() {
formChanges.push(...newFormChanges);
});
}

View File

@ -22,6 +22,7 @@ import type { Variant, VariantSet } from "#app/data/variant";
import { variantData } from "#app/data/variant";
import { speciesStarterCosts, POKERUS_STARTER_COUNT } from "#app/data/balance/starters";
import { SpeciesFormKey } from "#enums/species-form-key";
import { starterPassiveAbilities } from "#app/data/balance/passives";
export enum Region {
NORMAL,
@ -230,6 +231,31 @@ export abstract class PokemonSpeciesForm {
return ret;
}
/**
* Method to get the passive ability of a Pokemon species
* @param formIndex The form index to use, defaults to form for this species instance
* @returns The id of the ability
*/
getPassiveAbility(formIndex?: number): Abilities {
if (Utils.isNullOrUndefined(formIndex)) {
formIndex = this.formIndex;
}
let starterSpeciesId = this.speciesId;
while (!(starterSpeciesId in starterPassiveAbilities) || !(formIndex in starterPassiveAbilities[starterSpeciesId])) {
if (pokemonPrevolutions.hasOwnProperty(starterSpeciesId)) {
starterSpeciesId = pokemonPrevolutions[starterSpeciesId];
} else { // If we've reached the base species and still haven't found a matching ability, use form 0 if possible
if (0 in starterPassiveAbilities[starterSpeciesId]) {
return starterPassiveAbilities[starterSpeciesId][0];
} else {
console.log("No passive ability found for %s, using run away", this.speciesId);
return Abilities.RUN_AWAY;
}
}
}
return starterPassiveAbilities[starterSpeciesId][formIndex];
}
getLevelMoves(): LevelMoves {
if (pokemonSpeciesFormLevelMoves.hasOwnProperty(this.speciesId) && pokemonSpeciesFormLevelMoves[this.speciesId].hasOwnProperty(this.formIndex)) {
return pokemonSpeciesFormLevelMoves[this.speciesId][this.formIndex].slice(0);
@ -516,8 +542,7 @@ export abstract class PokemonSpeciesForm {
globalScene.anims.get(spriteKey).frameRate = 10;
}
const spritePath = this.getSpriteAtlasPath(female, formIndex, shiny, variant).replace("variant/", "").replace(/_[1-3]$/, "");
globalScene.loadPokemonVariantAssets(spriteKey, spritePath, variant);
resolve();
globalScene.loadPokemonVariantAssets(spriteKey, spritePath, variant).then(() => resolve());
});
if (startLoad) {
if (!globalScene.load.isLoading()) {
@ -2639,17 +2664,9 @@ export function initSpecies() {
new PokemonSpecies(Species.IRON_VALIANT, 9, false, false, false, "Paradox Pokémon", Type.FAIRY, Type.FIGHTING, 1.4, 35, Abilities.QUARK_DRIVE, Abilities.NONE, Abilities.NONE, 590, 74, 130, 90, 120, 60, 116, 10, 0, 295, GrowthRate.SLOW, null, false),
new PokemonSpecies(Species.KORAIDON, 9, false, true, false, "Paradox Pokémon", Type.FIGHTING, Type.DRAGON, 2.5, 303, Abilities.ORICHALCUM_PULSE, Abilities.NONE, Abilities.NONE, 670, 100, 135, 115, 85, 100, 135, 3, 0, 335, GrowthRate.SLOW, null, false, false,
new PokemonForm("Apex Build", "apex-build", Type.FIGHTING, Type.DRAGON, 2.5, 303, Abilities.ORICHALCUM_PULSE, Abilities.NONE, Abilities.NONE, 670, 100, 135, 115, 85, 100, 135, 3, 0, 335, false, null, true),
new PokemonForm("Limited Build", "limited-build", Type.FIGHTING, Type.DRAGON, 3.5, 303, Abilities.ORICHALCUM_PULSE, Abilities.NONE, Abilities.NONE, 670, 100, 135, 115, 85, 100, 135, 3, 0, 335, false, null, true),
new PokemonForm("Sprinting Build", "sprinting-build", Type.FIGHTING, Type.DRAGON, 3.5, 303, Abilities.ORICHALCUM_PULSE, Abilities.NONE, Abilities.NONE, 670, 100, 135, 115, 85, 100, 135, 3, 0, 335, false, null, true),
new PokemonForm("Swimming Build", "swimming-build", Type.FIGHTING, Type.DRAGON, 3.5, 303, Abilities.ORICHALCUM_PULSE, Abilities.NONE, Abilities.NONE, 670, 100, 135, 115, 85, 100, 135, 3, 0, 335, false, null, true),
new PokemonForm("Gliding Build", "gliding-build", Type.FIGHTING, Type.DRAGON, 3.5, 303, Abilities.ORICHALCUM_PULSE, Abilities.NONE, Abilities.NONE, 670, 100, 135, 115, 85, 100, 135, 3, 0, 335, false, null, true),
),
new PokemonSpecies(Species.MIRAIDON, 9, false, true, false, "Paradox Pokémon", Type.ELECTRIC, Type.DRAGON, 3.5, 240, Abilities.HADRON_ENGINE, Abilities.NONE, Abilities.NONE, 670, 100, 85, 100, 135, 115, 135, 3, 0, 335, GrowthRate.SLOW, null, false, false,
new PokemonForm("Ultimate Mode", "ultimate-mode", Type.ELECTRIC, Type.DRAGON, 3.5, 240, Abilities.HADRON_ENGINE, Abilities.NONE, Abilities.NONE, 670, 100, 85, 100, 135, 115, 135, 3, 0, 335, false, null, true),
new PokemonForm("Low-Power Mode", "low-power-mode", Type.ELECTRIC, Type.DRAGON, 2.8, 240, Abilities.HADRON_ENGINE, Abilities.NONE, Abilities.NONE, 670, 100, 85, 100, 135, 115, 135, 3, 0, 335, false, null, true),
new PokemonForm("Drive Mode", "drive-mode", Type.ELECTRIC, Type.DRAGON, 2.8, 240, Abilities.HADRON_ENGINE, Abilities.NONE, Abilities.NONE, 670, 100, 85, 100, 135, 115, 135, 3, 0, 335, false, null, true),
new PokemonForm("Aquatic Mode", "aquatic-mode", Type.ELECTRIC, Type.DRAGON, 2.8, 240, Abilities.HADRON_ENGINE, Abilities.NONE, Abilities.NONE, 670, 100, 85, 100, 135, 115, 135, 3, 0, 335, false, null, true),
new PokemonForm("Glide Mode", "glide-mode", Type.ELECTRIC, Type.DRAGON, 2.8, 240, Abilities.HADRON_ENGINE, Abilities.NONE, Abilities.NONE, 670, 100, 85, 100, 135, 115, 135, 3, 0, 335, false, null, true),
),
new PokemonSpecies(Species.WALKING_WAKE, 9, false, false, false, "Paradox Pokémon", Type.WATER, Type.DRAGON, 3.5, 280, Abilities.PROTOSYNTHESIS, Abilities.NONE, Abilities.NONE, 590, 99, 83, 91, 125, 83, 109, 10, 0, 295, GrowthRate.SLOW, null, false), //Custom Catchrate, matching Gouging Fire and Raging Bolt
new PokemonSpecies(Species.IRON_LEAVES, 9, false, false, false, "Paradox Pokémon", Type.GRASS, Type.PSYCHIC, 1.5, 125, Abilities.QUARK_DRIVE, Abilities.NONE, Abilities.NONE, 590, 90, 130, 88, 70, 108, 104, 10, 0, 295, GrowthRate.SLOW, null, false), //Custom Catchrate, matching Iron Boulder and Iron Crown

View File

@ -162,7 +162,7 @@ export function getNonVolatileStatusEffects():Array<StatusEffect> {
}
/**
* Returns whether a statuss effect is non volatile.
* Returns whether a status effect is non volatile.
* Non-volatile status condition is a status that remains after being switched out.
* @param status The status to check
*/

View File

@ -25,8 +25,6 @@ import { Gender } from "#app/data/gender";
/** Minimum BST for Pokemon generated onto the Elite Four's teams */
const ELITE_FOUR_MINIMUM_BST = 460;
/** Minimum BST for Pokemon generated onto the E4 Champion's team */
const CHAMPION_MINIMUM_BST = 508;
export enum TrainerPoolTier {
COMMON,
@ -164,7 +162,7 @@ export const trainerPartyTemplates = {
ELITE_FOUR: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(3, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER)),
CHAMPION: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER), new TrainerPartyTemplate(5, PartyMemberStrength.STRONG, false, true)),
CHAMPION: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(4, PartyMemberStrength.STRONG), new TrainerPartyTemplate(2, PartyMemberStrength.STRONGER, false, true)),
RIVAL: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE)),
RIVAL_2: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.WEAK, false, true)),
@ -905,7 +903,7 @@ export class TrainerConfig {
this.setHasVoucher(true);
this.setBattleBgm("battle_unova_elite");
this.setVictoryBgm("victory_gym");
this.setGenModifiersFunc(party => getRandomTeraModifiers(party, 2, specialtyTypes.length ? specialtyTypes : undefined));
this.setGenModifiersFunc(party => getRandomTeraModifiers(party, 1, specialtyTypes.length ? specialtyTypes : undefined));
return this;
}
@ -916,7 +914,7 @@ export class TrainerConfig {
* @param isMale Whether the Champion is Male or Female (for localization of the title).
* @returns {TrainerConfig} The updated TrainerConfig instance.
**/
initForChampion(signatureSpecies: (Species | Species[])[], isMale: boolean): TrainerConfig {
initForChampion(isMale: boolean): TrainerConfig {
// Check if the internationalization (i18n) system is initialized.
if (!getIsInitialized()) {
initI18n();
@ -925,18 +923,6 @@ export class TrainerConfig {
// Set the party templates for the Champion.
this.setPartyTemplates(trainerPartyTemplates.CHAMPION);
// Set up party members with their corresponding species.
signatureSpecies.forEach((speciesPool, s) => {
// Ensure speciesPool is an array.
if (!Array.isArray(speciesPool)) {
speciesPool = [ speciesPool ];
}
// Set a function to get a random party member from the species pool.
this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool));
});
this.setSpeciesFilter(p => p.baseTotal >= CHAMPION_MINIMUM_BST);
// Localize the trainer's name by converting it to lowercase and replacing spaces with underscores.
const nameForCall = this.name.toLowerCase().replace(/\s/g, "_");
this.name = i18next.t(`trainerNames:${nameForCall}`);
@ -955,7 +941,6 @@ export class TrainerConfig {
this.setHasVoucher(true);
this.setBattleBgm("battle_champion_alder");
this.setVictoryBgm("victory_champion");
this.setGenModifiersFunc(party => getRandomTeraModifiers(party, 3));
return this;
}
@ -1341,20 +1326,6 @@ export const signatureSpecies: SignatureSpecies = {
AMARYS: [ Species.SKARMORY, Species.EMPOLEON, Species.SCIZOR, Species.METAGROSS ],
LACEY: [ Species.EXCADRILL, Species.PRIMARINA, [ Species.ALCREMIE, Species.GRANBULL ], Species.WHIMSICOTT ],
DRAYTON: [ Species.DRAGONITE, Species.ARCHALUDON, Species.HAXORUS, Species.SCEPTILE ],
BLUE: [[ Species.GYARADOS, Species.EXEGGUTOR, Species.ARCANINE ], Species.HO_OH, [ Species.RHYPERIOR, Species.MAGNEZONE ]], // Alakazam lead, Mega Pidgeot
RED: [ Species.LUGIA, Species.SNORLAX, [ Species.ESPEON, Species.UMBREON, Species.SYLVEON ]], // GMax Pikachu lead, Mega gen 1 starter
LANCE_CHAMPION: [ Species.DRAGONITE, Species.KINGDRA, Species.ALOLA_EXEGGUTOR ], // Aerodactyl lead, Mega Latias/Latios
STEVEN: [ Species.AGGRON, [ Species.ARMALDO, Species.CRADILY ], Species.DIALGA ], // Skarmory lead, Mega Metagross
WALLACE: [ Species.MILOTIC, Species.PALKIA, Species.LUDICOLO ], // Pelipper lead, Mega Swampert
CYNTHIA: [ Species.GIRATINA, Species.LUCARIO, Species.TOGEKISS ], // Spiritomb lead, Mega Garchomp
ALDER: [ Species.VOLCARONA, Species.ZEKROM, [ Species.ACCELGOR, Species.ESCAVALIER ], Species.KELDEO ], // Bouffalant/Braviary lead
IRIS: [ Species.HAXORUS, Species.RESHIRAM, Species.ARCHEOPS ], // Druddigon lead, Gmax Lapras
DIANTHA: [ Species.HAWLUCHA, Species.XERNEAS, Species.GOODRA ], // Gourgeist lead, Mega Gardevoir
HAU: [[ Species.SOLGALEO, Species.LUNALA ], Species.NOIVERN, [ Species.DECIDUEYE, Species.INCINEROAR, Species.PRIMARINA ], [ Species.TAPU_BULU, Species.TAPU_FINI, Species.TAPU_KOKO, Species.TAPU_LELE ]], // Alola Raichu lead
LEON: [ Species.DRAGAPULT, Species.ZACIAN, Species.AEGISLASH ], // Rillaboom/Cinderace/Inteleon lead, GMax Charizard
GEETA: [ Species.MIRAIDON, [ Species.ESPATHRA, Species.VELUZA ], [ Species.AVALUGG, Species.HISUI_AVALUGG ], Species.KINGAMBIT ], // Glimmora lead
NEMONA: [ Species.KORAIDON, Species.PAWMOT, [ Species.DUDUNSPARCE, Species.ORTHWORM ], [ Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL ]], // Lycanroc lead
KIERAN: [[ Species.GRIMMSNARL, Species.INCINEROAR, Species.PORYGON_Z ], Species.OGERPON, Species.TERAPAGOS, Species.HYDRAPPLE ], // Poliwrath/Politoed lead
};
export const trainerConfigs: TrainerConfigs = {
@ -1751,111 +1722,357 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerType.LACEY]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["LACEY"], false, Type.FAIRY).setMixedBattleBgm("battle_bb_elite"),
[TrainerType.DRAYTON]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["DRAYTON"], true, Type.DRAGON).setMixedBattleBgm("battle_bb_elite"),
[TrainerType.BLUE]: new TrainerConfig((t = TrainerType.BLUE)).initForChampion(signatureSpecies["BLUE"], true).setBattleBgm("battle_kanto_champion").setMixedBattleBgm("battle_kanto_champion").setHasDouble("blue_red_double").setDoubleTrainerType(TrainerType.RED).setDoubleTitle("champion_double")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.ALAKAZAM ], TrainerSlot.TRAINER, true, p => {
[TrainerType.BLUE]: new TrainerConfig((t = TrainerType.BLUE)).initForChampion(true).setBattleBgm("battle_kanto_champion").setMixedBattleBgm("battle_kanto_champion").setHasDouble("blue_red_double").setDoubleTrainerType(TrainerType.RED).setDoubleTitle("champion_double")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.ALAKAZAM ]))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.MACHAMP ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.HO_OH ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.MASTER_BALL;
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.PIDGEOT ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.RHYPERIOR, Species.ELECTIVIRE, Species.MAGMORTAR ]))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.ARCANINE, Species.EXEGGUTOR, Species.GYARADOS ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.setBoss(true, 2);
}))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.PIDGEOT ], TrainerSlot.TRAINER, true, p => {
p.formIndex = 1; // Mega Pidgeot
p.generateAndPopulateMoveset();
p.generateName();
})),
[TrainerType.RED]: new TrainerConfig(++t).initForChampion(signatureSpecies["RED"], true).setBattleBgm("battle_johto_champion").setMixedBattleBgm("battle_johto_champion").setHasDouble("red_blue_double").setDoubleTrainerType(TrainerType.BLUE).setDoubleTitle("champion_double")
p.gender = Gender.MALE;
}))
.setGenModifiersFunc(party => {
const teraPokemon = party[3];
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ];
}),
[TrainerType.RED]: new TrainerConfig(++t).initForChampion(true).setBattleBgm("battle_johto_champion").setMixedBattleBgm("battle_johto_champion").setHasDouble("red_blue_double").setDoubleTrainerType(TrainerType.BLUE).setDoubleTitle("champion_double")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.PIKACHU ], TrainerSlot.TRAINER, true, p => {
p.formIndex = 8; // G-Max Pikachu
p.generateAndPopulateMoveset();
p.generateName();
p.gender = Gender.MALE;
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.ESPEON, Species.UMBREON, Species.SYLVEON ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.LUGIA ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.MASTER_BALL;
}))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.MEGANIUM, Species.TYPHLOSION, Species.FERALIGATR ]))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.SNORLAX ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.setBoss(true, 2);
}))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE ], TrainerSlot.TRAINER, true, p => {
p.formIndex = 1; // Mega Venusaur, Mega Charizard X, or Mega Blastoise
p.generateAndPopulateMoveset();
p.generateName();
})),
[TrainerType.LANCE_CHAMPION]: new TrainerConfig(++t).setName("Lance").initForChampion(signatureSpecies["LANCE_CHAMPION"], true).setBattleBgm("battle_johto_champion").setMixedBattleBgm("battle_johto_champion")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.AERODACTYL ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.gender = Gender.MALE;
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.LATIAS, Species.LATIOS ], TrainerSlot.TRAINER, true, p => {
p.formIndex = 1; // Mega Latias or Mega Latios
.setGenModifiersFunc(party => {
const teraPokemon = party[3];
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ];
}),
[TrainerType.LANCE_CHAMPION]: new TrainerConfig(++t).setName("Lance").initForChampion(true).setBattleBgm("battle_johto_champion").setMixedBattleBgm("battle_johto_champion")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.GYARADOS, Species.KINGDRA ]))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.AERODACTYL ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SALAMENCE ], TrainerSlot.TRAINER, true, p => {
p.formIndex = 1; // Mega Salamence
p.generateAndPopulateMoveset();
p.generateName();
})),
[TrainerType.STEVEN]: new TrainerConfig(++t).initForChampion(signatureSpecies["STEVEN"], true).setBattleBgm("battle_hoenn_champion_g5").setMixedBattleBgm("battle_hoenn_champion_g6").setHasDouble("steven_wallace_double").setDoubleTrainerType(TrainerType.WALLACE).setDoubleTitle("champion_double")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SKARMORY ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.METAGROSS ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.CHARIZARD ]))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.TYRANITAR, Species.GARCHOMP, Species.KOMMO_O ]))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.DRAGONITE ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.gender = Gender.MALE;
p.setBoss(true, 2);
}))
.setGenModifiersFunc(party => {
const teraPokemon = party[4];
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ];
}),
[TrainerType.STEVEN]: new TrainerConfig(++t).initForChampion(true).setBattleBgm("battle_hoenn_champion_g5").setMixedBattleBgm("battle_hoenn_champion_g6").setHasDouble("steven_wallace_double").setDoubleTrainerType(TrainerType.WALLACE).setDoubleTitle("champion_double")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SKARMORY ]))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.CRADILY, Species.ARMALDO ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.AGGRON ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.setBoss(true, 2);
}))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.GOLURK, Species.RUNERIGUS ]))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.REGIROCK, Species.REGICE, Species.REGISTEEL ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL;
}))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.METAGROSS ], TrainerSlot.TRAINER, true, p => {
p.formIndex = 1; // Mega Metagross
p.generateAndPopulateMoveset();
p.generateName();
})),
[TrainerType.WALLACE]: new TrainerConfig(++t).initForChampion(signatureSpecies["WALLACE"], true).setBattleBgm("battle_hoenn_champion_g5").setMixedBattleBgm("battle_hoenn_champion_g6").setHasDouble("wallace_steven_double").setDoubleTrainerType(TrainerType.STEVEN).setDoubleTitle("champion_double")
}))
.setGenModifiersFunc(party => {
const teraPokemon = party[4];
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ];
}),
[TrainerType.WALLACE]: new TrainerConfig(++t).initForChampion(true).setBattleBgm("battle_hoenn_champion_g5").setMixedBattleBgm("battle_hoenn_champion_g6").setHasDouble("wallace_steven_double").setDoubleTrainerType(TrainerType.STEVEN).setDoubleTitle("champion_double")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.PELIPPER ], TrainerSlot.TRAINER, true, p => {
p.abilityIndex = 1; // Drizzle
p.generateAndPopulateMoveset();
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.SWAMPERT ], TrainerSlot.TRAINER, true, p => {
p.formIndex = 1; // Mega Swampert
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.LUDICOLO ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.LATIAS, Species.LATIOS ], TrainerSlot.TRAINER, true, p => {
p.formIndex = 1; // Mega Latios or Mega Latias
p.generateAndPopulateMoveset();
p.generateName();
})),
[TrainerType.CYNTHIA]: new TrainerConfig(++t).initForChampion(signatureSpecies["CYNTHIA"], false).setBattleBgm("battle_sinnoh_champion").setMixedBattleBgm("battle_sinnoh_champion")
p.pokeball = PokeballType.MASTER_BALL;
}))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.SWAMPERT, Species.GASTRODON, Species.SEISMITOAD ]))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.REGIELEKI, Species.REGIDRAGO ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL;
}))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.MILOTIC ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.gender = Gender.FEMALE;
p.setBoss(true, 2);
}))
.setGenModifiersFunc(party => {
const teraPokemon = party[4];
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ];
}),
[TrainerType.CYNTHIA]: new TrainerConfig(++t).initForChampion(false).setBattleBgm("battle_sinnoh_champion").setMixedBattleBgm("battle_sinnoh_champion")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SPIRITOMB ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.GARCHOMP ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.LUCARIO ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.GIRATINA ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.MASTER_BALL;
}))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.MILOTIC, Species.ROSERADE, Species.HISUI_ARCANINE ]))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.TOGEKISS ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.setBoss(true, 2);
}))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.GARCHOMP ], TrainerSlot.TRAINER, true, p => {
p.formIndex = 1; // Mega Garchomp
p.generateAndPopulateMoveset();
p.generateName();
})),
[TrainerType.ALDER]: new TrainerConfig(++t).initForChampion(signatureSpecies["ALDER"], true).setHasDouble("alder_iris_double").setDoubleTrainerType(TrainerType.IRIS).setDoubleTitle("champion_double").setBattleBgm("battle_champion_alder").setMixedBattleBgm("battle_champion_alder")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BOUFFALANT, Species.BRAVIARY ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
})),
[TrainerType.IRIS]: new TrainerConfig(++t).initForChampion(signatureSpecies["IRIS"], false).setBattleBgm("battle_champion_iris").setMixedBattleBgm("battle_champion_iris").setHasDouble("iris_alder_double").setDoubleTrainerType(TrainerType.ALDER).setDoubleTitle("champion_double")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.DRUDDIGON ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.gender = Gender.FEMALE;
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.LAPRAS ], TrainerSlot.TRAINER, true, p => {
.setGenModifiersFunc(party => {
const teraPokemon = party[3];
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ];
}),
[TrainerType.ALDER]: new TrainerConfig(++t).initForChampion(true).setHasDouble("alder_iris_double").setDoubleTrainerType(TrainerType.IRIS).setDoubleTitle("champion_double").setBattleBgm("battle_champion_alder").setMixedBattleBgm("battle_champion_alder")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BOUFFALANT, Species.BRAVIARY ]))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.HISUI_LILLIGANT, Species.HISUI_ZOROARK, Species.BASCULEGION ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ROGUE_BALL;
}))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.ZEKROM ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.MASTER_BALL;
}))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.KELDEO ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL;
}))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.CHANDELURE, Species.KROOKODILE, Species.REUNICLUS, Species.CONKELDURR ]))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.VOLCARONA ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.gender = Gender.MALE;
p.setBoss(true, 2);
}))
.setGenModifiersFunc(party => {
const pokemon = party[4];
return [ modifierTypes.TERA_SHARD().generateType([], [ pokemon.species.speciesId === Species.KROOKODILE ? pokemon.species.type2 : pokemon.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(pokemon) as PersistentModifier ];
}),
[TrainerType.IRIS]: new TrainerConfig(++t).initForChampion(false).setBattleBgm("battle_champion_iris").setMixedBattleBgm("battle_champion_iris").setHasDouble("iris_alder_double").setDoubleTrainerType(TrainerType.ALDER).setDoubleTitle("champion_double")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.DRUDDIGON ]))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.ARCHEOPS ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.RESHIRAM ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.MASTER_BALL;
}))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.SALAMENCE, Species.HYDREIGON, Species.ARCHALUDON ]))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.LAPRAS ], TrainerSlot.TRAINER, true, p => {
p.formIndex = 1; // G-Max Lapras
p.generateAndPopulateMoveset();
p.generateName();
})),
[TrainerType.DIANTHA]: new TrainerConfig(++t).initForChampion(signatureSpecies["DIANTHA"], false).setMixedBattleBgm("battle_kalos_champion")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.GOURGEIST ], TrainerSlot.TRAINER, true, p => {
}))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.HAXORUS ], TrainerSlot.TRAINER, true, p => {
p.abilityIndex = 1; // Mold Breaker
p.generateAndPopulateMoveset();
p.gender = Gender.FEMALE;
p.setBoss(true, 2);
}))
.setGenModifiersFunc(party => {
const teraPokemon = party[3];
return [ modifierTypes.TERA_SHARD().generateType([], [ Type.DRAGON ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ];
}),
[TrainerType.DIANTHA]: new TrainerConfig(++t).initForChampion(false).setMixedBattleBgm("battle_kalos_champion")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.HAWLUCHA ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.GARDEVOIR ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.TREVENANT, Species.GOURGEIST ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.XERNEAS ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.MASTER_BALL;
}))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.TYRANTRUM, Species.AURORUS ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.abilityIndex = 2; // Rock Head Tyrantrum, Snow Warning Aurorus
}))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.GOODRA ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.setBoss(true, 2);
}))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.GARDEVOIR ], TrainerSlot.TRAINER, true, p => {
p.formIndex = 1; // Mega Gardevoir
p.generateAndPopulateMoveset();
p.generateName();
})),
[TrainerType.HAU]: new TrainerConfig(++t).initForChampion(signatureSpecies["HAU"], true).setMixedBattleBgm("battle_alola_champion")
p.gender = Gender.FEMALE;
}))
.setGenModifiersFunc(party => {
const teraPokemon = party[3];
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type2 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ];
}),
[TrainerType.HAU]: new TrainerConfig(++t).initForChampion(true).setMixedBattleBgm("battle_alola_champion")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.ALOLA_RAICHU ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
})),
[TrainerType.LEON]: new TrainerConfig(++t).initForChampion(signatureSpecies["LEON"], true).setMixedBattleBgm("battle_galar_champion")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.RILLABOOM, Species.CINDERACE, Species.INTELEON ], TrainerSlot.TRAINER, true, p => {
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.NOIVERN ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SOLGALEO ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.MASTER_BALL;
}))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.TAPU_KOKO, Species.TAPU_LELE, Species.TAPU_BULU, Species.TAPU_FINI ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL;
}))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.ZYGARDE ], TrainerSlot.TRAINER, true, p => {
p.formIndex = 1; // Zygarde 10% forme, Aura Break
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ROGUE_BALL;
}))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.DECIDUEYE, Species.INCINEROAR, Species.PRIMARINA ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.setBoss(true, 2);
p.gender = p.species.speciesId === Species.PRIMARINA ? Gender.FEMALE : Gender.MALE;
}))
.setGenModifiersFunc(party => {
const teraPokemon = party[3];
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ];
}),
[TrainerType.LEON]: new TrainerConfig(++t).initForChampion(true).setMixedBattleBgm("battle_galar_champion")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.AEGISLASH ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.CHARIZARD ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.RHYPERIOR, Species.SEISMITOAD, Species.MR_RIME ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.ZACIAN ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.MASTER_BALL;
}))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.DRAGAPULT ]))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.RILLABOOM, Species.CINDERACE, Species.INTELEON ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.setBoss(true, 2);
}))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.CHARIZARD ], TrainerSlot.TRAINER, true, p => {
p.formIndex = 3; // G-Max Charizard
p.generateAndPopulateMoveset();
p.generateName();
})),
[TrainerType.GEETA]: new TrainerConfig(++t).initForChampion(signatureSpecies["GEETA"], false).setMixedBattleBgm("battle_champion_geeta")
p.gender = Gender.MALE;
}))
.setGenModifiersFunc(party => {
const teraPokemon = party[3];
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ];
}),
[TrainerType.GEETA]: new TrainerConfig(++t).initForChampion(false).setMixedBattleBgm("battle_champion_geeta")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.GLIMMORA ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
})),
[TrainerType.NEMONA]: new TrainerConfig(++t).initForChampion(signatureSpecies["NEMONA"], false).setMixedBattleBgm("battle_champion_nemona")
p.gender = Gender.MALE;
p.setBoss(true, 2);
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.ESPATHRA, Species.VELUZA ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.MIRAIDON ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.MASTER_BALL;
}))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.BAXCALIBUR ]))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.CHESNAUGHT, Species.DELPHOX, Species.GRENINJA ]))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.KINGAMBIT ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.abilityIndex = 1; // Supreme Overlord
}))
.setGenModifiersFunc(party => {
const teraPokemon = party[5];
return [ modifierTypes.TERA_SHARD().generateType([], [ Type.FLYING ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ];
}),
[TrainerType.NEMONA]: new TrainerConfig(++t).initForChampion(false).setMixedBattleBgm("battle_champion_nemona")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.LYCANROC ], TrainerSlot.TRAINER, true, p => {
p.formIndex = 0; // Midday form
p.generateAndPopulateMoveset();
})),
[TrainerType.KIERAN]: new TrainerConfig(++t).initForChampion(signatureSpecies["KIERAN"], true).setMixedBattleBgm("battle_champion_kieran")
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.PAWMOT ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.KORAIDON ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.MASTER_BALL;
}))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.GHOLDENGO ]))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.ARMAROUGE, Species.CERULEDGE ]))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.gender = Gender.MALE;
p.setBoss(true, 2);
}))
.setGenModifiersFunc(party => {
const teraPokemon = party[4];
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type2 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ];
}),
[TrainerType.KIERAN]: new TrainerConfig(++t).initForChampion(true).setMixedBattleBgm("battle_champion_kieran")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.POLIWRATH, Species.POLITOED ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
})),
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.INCINEROAR, Species.GRIMMSNARL ], TrainerSlot.TRAINER, true, p => {
// Intimidate Incineroar, Prankster Grimmsnarl
p.generateAndPopulateMoveset();
if (p.species.speciesId === Species.INCINEROAR) {
p.abilityIndex = 2;
} else if (p.species.speciesId === Species.GRIMMSNARL) {
p.abilityIndex = 0;
}
}))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.TERAPAGOS ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.MASTER_BALL;
}))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.URSALUNA, Species.BLOODMOON_URSALUNA ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL;
}))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.OGERPON ], TrainerSlot.TRAINER, true, p => {
p.formIndex = Utils.randSeedInt(4, 4); // Random Ogerpon Tera Mask
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL;
if (!p.moveset.some(move => !Utils.isNullOrUndefined(move) && move.moveId === Moves.IVY_CUDGEL)) { // Check if Ivy Cudgel is in the moveset, if not, replace the first move with Ivy Cudgel.
p.moveset[0] = new PokemonMove(Moves.IVY_CUDGEL);
}
}))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.HYDRAPPLE ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.gender = Gender.MALE;
p.setBoss(true, 2);
}))
.setGenModifiersFunc(party => {
const starter = party[4];
let teraShardType: Type;
const pokemonType2 = starter.species.forms[starter.formIndex].type2;
if (starter.formIndex === 4 || Utils.isNullOrUndefined(pokemonType2)) {
teraShardType = starter.species.type1;
} else {
teraShardType = pokemonType2;
}
return [ modifierTypes.TERA_SHARD().generateType([], [ teraShardType ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier ];
}),
[TrainerType.RIVAL]: new TrainerConfig((t = TrainerType.RIVAL)).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setStaticParty().setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival").setMixedBattleBgm("battle_rival").setPartyTemplates(trainerPartyTemplates.RIVAL)
.setModifierRewardFuncs(() => modifierTypes.SUPER_EXP_CHARM, () => modifierTypes.EXP_SHARE)
@ -1934,13 +2151,13 @@ export const trainerConfigs: TrainerConfigs = {
}),
[TrainerType.ROCKET_BOSS_GIOVANNI_1]: new TrainerConfig(t = TrainerType.ROCKET_BOSS_GIOVANNI_1).setName("Giovanni").initForEvilTeamLeader("Rocket Boss", []).setMixedBattleBgm("battle_rocket_boss").setVictoryBgm("victory_team_plasma")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.PERSIAN, Species.ALOLA_PERSIAN ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.PERSIAN ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.gender = Gender.MALE;
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.DUGTRIO, Species.ALOLA_DUGTRIO ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.HONCHKROW ]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.NIDOKING, Species.NIDOQUEEN ]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.NIDOQUEEN, Species.NIDOKING ]))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.RHYPERIOR ]))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.KANGASKHAN ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
@ -1956,33 +2173,35 @@ export const trainerConfigs: TrainerConfigs = {
p.pokeball = PokeballType.ULTRA_BALL;
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.HIPPOWDON ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.EXCADRILL, Species.GARCHOMP ]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.KANGASKHAN ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.GARCHOMP, Species.EXCADRILL ]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.GASTRODON, Species.SEISMITOAD ], TrainerSlot.TRAINER, true, p => {
if (p.species.speciesId === Species.GASTRODON) {
p.abilityIndex = 0; // Storm Drain
} else if (p.species.speciesId === Species.SEISMITOAD) {
p.abilityIndex = 2; // Water Absorb
}
}))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.KANGASKHAN ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL;
p.formIndex = 1; // Mega Kangaskhan
p.generateName();
}))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.GASTRODON, Species.SEISMITOAD ], TrainerSlot.TRAINER, true, p => {
//Storm Drain Gastrodon, Water Absorb Seismitoad
if (p.species.speciesId === Species.GASTRODON) {
p.abilityIndex = 0;
} else if (p.species.speciesId === Species.SEISMITOAD) {
p.abilityIndex = 2;
}
}))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.MEWTWO ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.MASTER_BALL;
})),
[TrainerType.MAXIE]: new TrainerConfig(++t).setName("Maxie").initForEvilTeamLeader("Magma Boss", []).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.MIGHTYENA ]))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.CROBAT, Species.GLISCOR ]))
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SOLROCK ]))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.TALONFLAME ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.WEEZING, Species.GALAR_WEEZING ]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.MAGMORTAR, Species.TORKOAL ]))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.FLYGON ]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.TORKOAL ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.abilityIndex = 1; // Drought
}))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.DONPHAN ]))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.CAMERUPT ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
@ -1992,16 +2211,20 @@ export const trainerConfigs: TrainerConfigs = {
p.gender = Gender.MALE;
})),
[TrainerType.MAXIE_2]: new TrainerConfig(++t).setName("Maxie").initForEvilTeamLeader("Magma Boss", [], true).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SOLROCK, Species.TYPHLOSION ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.TYPHLOSION, Species.SOLROCK ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL;
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.TORKOAL, Species.NINETALES ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.NINETALES, Species.TORKOAL ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.abilityIndex = 2; // Drought
if (p.species.speciesId === Species.NINETALES) {
p.abilityIndex = 2; // Drought
} else if (p.species.speciesId === Species.TORKOAL) {
p.abilityIndex = 1; // Drought
}
}))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SHIFTRY, Species.SCOVILLAIN ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SCOVILLAIN ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.abilityIndex = 0; // Chlorophyll
}))
@ -2020,11 +2243,17 @@ export const trainerConfigs: TrainerConfigs = {
p.pokeball = PokeballType.MASTER_BALL;
})),
[TrainerType.ARCHIE]: new TrainerConfig(++t).setName("Archie").initForEvilTeamLeader("Aqua Boss", []).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.LINOONE ]))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.CROBAT, Species.PELIPPER ]))
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.LUDICOLO ]))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.PELIPPER ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.abilityIndex = 1; // Drizzle
}))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.MUK, Species.ALOLA_MUK ]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.TENTACRUEL ]))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.RELICANTH, Species.WAILORD ]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.WAILORD ]))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.QWILFISH ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.abilityIndex = 1; // Swift Swim
}))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.SHARPEDO ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
@ -2034,19 +2263,20 @@ export const trainerConfigs: TrainerConfigs = {
p.gender = Gender.MALE;
})),
[TrainerType.ARCHIE_2]: new TrainerConfig(++t).setName("Archie").initForEvilTeamLeader("Aqua Boss", [], true).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.EMPOLEON, Species.LUDICOLO ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.LUDICOLO, Species.EMPOLEON ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL;
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.POLITOED, Species.PELIPPER ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.abilityIndex = 2; // Drizzle
}))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.BEARTIC, Species.ARMALDO ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.abilityIndex = 2; // Swift Swim
if (p.species.speciesId === Species.POLITOED) {
p.abilityIndex = 2; // Drizzle
} else if (p.species.speciesId === Species.PELIPPER) {
p.abilityIndex = 1; // Drizzle
}
}))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.DHELMISE ]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.OVERQWIL ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.abilityIndex = 1; // Swift Swim
@ -2067,8 +2297,8 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerType.CYRUS]: new TrainerConfig(++t).setName("Cyrus").initForEvilTeamLeader("Galactic Boss", []).setMixedBattleBgm("battle_galactic_boss").setVictoryBgm("victory_team_plasma")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.GYARADOS ]))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.HONCHKROW, Species.HISUI_BRAVIARY ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.CROBAT, Species.GLISCOR ]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.AZELF, Species.UXIE, Species.MESPRIT ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.MAGNEZONE ]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.UXIE, Species.MESPRIT, Species.AZELF ]))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.HOUNDOOM ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL;
@ -2082,35 +2312,35 @@ export const trainerConfigs: TrainerConfigs = {
p.gender = Gender.MALE;
})),
[TrainerType.CYRUS_2]: new TrainerConfig(++t).setName("Cyrus").initForEvilTeamLeader("Galactic Boss", [], true).setMixedBattleBgm("battle_galactic_boss").setVictoryBgm("victory_team_plasma")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.AZELF, Species.UXIE, Species.MESPRIT ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.CROBAT ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.ELECTRODE, Species.HISUI_ELECTRODE ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SALAMENCE, Species.ROARING_MOON ]))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.MAGNEZONE ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.UXIE, Species.MESPRIT, Species.AZELF ]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.HOUNDOOM ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL;
p.formIndex = 1; // Mega Houndoom
p.generateName();
}))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.WEAVILE, Species.SNEASLER ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.WEAVILE ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL;
p.gender = Gender.MALE;
}))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.DARKRAI ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.DIALGA, Species.PALKIA ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.MASTER_BALL;
})),
[TrainerType.GHETSIS]: new TrainerConfig(++t).setName("Ghetsis").initForEvilTeamLeader("Plasma Boss", []).setMixedBattleBgm("battle_plasma_boss").setVictoryBgm("victory_team_plasma")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.COFAGRIGUS, Species.RUNERIGUS ]))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.BOUFFALANT ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SEISMITOAD, Species.CARRACOSTA ]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.EELEKTROSS, Species.GALVANTULA ]))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.VOLCARONA ]))
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.COFAGRIGUS ]))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.SEISMITOAD ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.GALVANTULA, Species.EELEKTROSS ]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.DRAPION, Species.TOXICROAK ]))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.KINGAMBIT ]))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.HYDREIGON ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
@ -2118,19 +2348,17 @@ export const trainerConfigs: TrainerConfigs = {
p.gender = Gender.MALE;
})),
[TrainerType.GHETSIS_2]: new TrainerConfig(++t).setName("Ghetsis").initForEvilTeamLeader("Plasma Boss", [], true).setMixedBattleBgm("battle_plasma_boss").setVictoryBgm("victory_team_plasma")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.GENESECT ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.RUNERIGUS ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL;
p.formIndex = Utils.randSeedInt(4, 1); // Shock, Burn, Chill, or Douse Drive
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.BASCULEGION, Species.JELLICENT ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.JELLICENT, Species.BASCULEGION ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.gender = Gender.MALE;
p.formIndex = 0;
}))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.KINGAMBIT ]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.VOLCARONA, Species.SLITHER_WING ]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.VOLCARONA, Species.IRON_MOTH ]))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.HYDREIGON, Species.IRON_JUGULIS ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
@ -2153,8 +2381,11 @@ export const trainerConfigs: TrainerConfigs = {
p.generateAndPopulateMoveset();
p.gender = Gender.MALE;
}))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.CLAWITZER, Species.DRAGALGE ]))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.HELIOLISK, Species.MALAMAR ]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.DRAGALGE, Species.CLAWITZER ]))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.GALLADE ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.abilityIndex = 1; // Sharpness
}))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.GYARADOS ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
@ -2164,17 +2395,17 @@ export const trainerConfigs: TrainerConfigs = {
p.gender = Gender.MALE;
})),
[TrainerType.LYSANDRE_2]: new TrainerConfig(++t).setName("Lysandre").initForEvilTeamLeader("Flare Boss", [], true).setMixedBattleBgm("battle_flare_boss").setVictoryBgm("victory_team_plasma")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SCREAM_TAIL, Species.FLUTTER_MANE ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.PYROAR ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL;
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.PYROAR ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.gender = Gender.MALE;
}))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.IRON_MOTH ]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.GOODRA, Species.HISUI_GOODRA ]))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.DRAGALGE, Species.CLAWITZER ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.AEGISLASH, Species.HISUI_GOODRA ]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.IRON_VALIANT ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ROGUE_BALL;
}))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.GYARADOS ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
@ -2183,10 +2414,11 @@ export const trainerConfigs: TrainerConfigs = {
p.generateName();
p.gender = Gender.MALE;
}))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.YVELTAL ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.ZYGARDE ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.MASTER_BALL;
p.formIndex = 0; // 50% Forme, Aura Break
})),
[TrainerType.LUSAMINE]: new TrainerConfig(++t).setName("Lusamine").initForEvilTeamLeader("Aether Boss", []).setMixedBattleBgm("battle_aether_boss").setVictoryBgm("victory_team_plasma")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.CLEFABLE ], TrainerSlot.TRAINER, true, p => {
@ -2203,46 +2435,51 @@ export const trainerConfigs: TrainerConfigs = {
p.pokeball = PokeballType.ROGUE_BALL;
})),
[TrainerType.LUSAMINE_2]: new TrainerConfig(++t).setName("Lusamine").initForEvilTeamLeader("Aether Boss", [], true).setMixedBattleBgm("battle_aether_boss").setVictoryBgm("victory_team_plasma")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.NIHILEGO ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.CLEFABLE ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ROGUE_BALL;
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.MILOTIC, Species.PRIMARINA ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.CLEFABLE ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.gender = Gender.FEMALE;
}))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.STAKATAKA, Species.CELESTEELA, Species.GUZZLORD ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.MILOTIC, Species.PRIMARINA ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SILVALLY ], TrainerSlot.TRAINER, true, p => {
p.formIndex = Utils.randSeedInt(18); // Random Silvally Form
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ROGUE_BALL;
if (!p.moveset.some(move => !Utils.isNullOrUndefined(move) && move.moveId === Moves.MULTI_ATTACK)) { // Check if Multi Attack is in the moveset, if not, replace the first move with Multi Attack.
p.moveset[0] = new PokemonMove(Moves.MULTI_ATTACK);
}
}))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.PHEROMOSA ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ROGUE_BALL;
}))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.PHEROMOSA ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.NIHILEGO ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ROGUE_BALL;
}))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.NECROZMA ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.formIndex = 2; // Dawn Wings
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.MASTER_BALL;
})),
[TrainerType.GUZMA]: new TrainerConfig(++t).setName("Guzma").initForEvilTeamLeader("Skull Boss", []).setMixedBattleBgm("battle_skull_boss").setVictoryBgm("victory_team_plasma")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.LOKIX, Species.YANMEGA ], TrainerSlot.TRAINER, true, p => {
//Tinted Lens Lokix, Tinted Lens Yanmega
if (p.species.speciesId === Species.LOKIX) {
p.abilityIndex = 2;
} else if (p.species.speciesId === Species.YANMEGA) {
p.abilityIndex = 1;
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.YANMEGA, Species.LOKIX ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
if (p.species.speciesId === Species.YANMEGA) {
p.abilityIndex = 1; // Tinted Lens
} else if (p.species.speciesId === Species.LOKIX) {
p.abilityIndex = 2; // Tinted Lens
}
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.HERACROSS ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SCIZOR, Species.KLEAVOR ], TrainerSlot.TRAINER, true, p => {
//Technician Scizor, Sharpness Kleavor
p.generateAndPopulateMoveset();
if (p.species.speciesId === Species.SCIZOR) {
p.abilityIndex = 1;
p.abilityIndex = 1; // Technician
} else if (p.species.speciesId === Species.KLEAVOR) {
p.abilityIndex = 2;
p.abilityIndex = 2; // Sharpness
}
}))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.GALVANTULA, Species.VIKAVOLT ]))
@ -2256,49 +2493,48 @@ export const trainerConfigs: TrainerConfigs = {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
p.gender = Gender.MALE;
p.pokeball = PokeballType.ULTRA_BALL;
})),
[TrainerType.GUZMA_2]: new TrainerConfig(++t).setName("Guzma").initForEvilTeamLeader("Skull Boss", [], true).setMixedBattleBgm("battle_skull_boss").setVictoryBgm("victory_team_plasma")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.GOLISOPOD ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
p.abilityIndex = 2; //Anticipation
p.abilityIndex = 2; // Anticipation
p.gender = Gender.MALE;
p.pokeball = PokeballType.ULTRA_BALL;
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.SCIZOR, Species.KLEAVOR ], TrainerSlot.TRAINER, true, p => {
//Technician Scizor, Sharpness Kleavor
if (p.species.speciesId === Species.SCIZOR) {
p.abilityIndex = 1;
} else if (p.species.speciesId === Species.KLEAVOR) {
p.abilityIndex = 2;
}
}))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.HISUI_SAMUROTT, Species.CRAWDAUNT ], TrainerSlot.TRAINER, true, p => {
p.abilityIndex = 2; //Sharpness Hisui Samurott, Adaptability Crawdaunt
}))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.BUZZWOLE ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.BUZZWOLE ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ROGUE_BALL;
}))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.XURKITREE ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.CRAWDAUNT, Species.HISUI_SAMUROTT ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.abilityIndex = 2; // Sharpness Hisui Samurott, Adaptability Crawdaunt
}))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.XURKITREE ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ROGUE_BALL;
}))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.GENESECT ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ROGUE_BALL;
p.pokeball = PokeballType.ULTRA_BALL;
p.formIndex = Utils.randSeedInt(4, 1); // Shock, Burn, Chill, or Douse Drive
if (!p.moveset.some(move => !Utils.isNullOrUndefined(move) && move.moveId === Moves.TECHNO_BLAST)) { // Check if Techno Blast is in the moveset, if not, replace the first move with Techno Blast.
p.moveset[0] = new PokemonMove(Moves.TECHNO_BLAST);
}
}))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.PINSIR ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.formIndex = 1;
p.formIndex = 1; // Mega Pinsir
p.generateAndPopulateMoveset();
p.generateName();
p.pokeball = PokeballType.ULTRA_BALL;
})),
[TrainerType.ROSE]: new TrainerConfig(++t).setName("Rose").initForEvilTeamLeader("Macro Boss", []).setMixedBattleBgm("battle_macro_boss").setVictoryBgm("victory_team_plasma")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.ARCHALUDON ]))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.FERROTHORN, Species.ESCAVALIER ]))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.ESCAVALIER, Species.FERROTHORN ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SIRFETCHD, Species.MR_RIME ]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.CORVIKNIGHT ]))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.PERRSERKER, Species.KLINKLANG ]))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.KLINKLANG, Species.PERRSERKER ]))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.COPPERAJAH ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
@ -2313,7 +2549,7 @@ export const trainerConfigs: TrainerConfigs = {
p.generateAndPopulateMoveset();
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.AEGISLASH, Species.GHOLDENGO ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.DRACOVISH, Species.DRACOZOLT ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.DRACOZOLT, Species.DRACOVISH ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.abilityIndex = 1; //Strong Jaw Dracovish, Hustle Dracozolt
}))
@ -2332,16 +2568,10 @@ export const trainerConfigs: TrainerConfigs = {
p.gender = Gender.FEMALE;
})),
[TrainerType.PENNY]: new TrainerConfig(++t).setName("Cassiopeia").initForEvilTeamLeader("Star Boss", []).setMixedBattleBgm("battle_star_boss").setVictoryBgm("victory_team_plasma")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.VAPOREON, Species.JOLTEON, Species.FLAREON ]))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.ESPEON, Species.UMBREON ], TrainerSlot.TRAINER, true, p => {
p.abilityIndex = 2; // Magic Bounce Espeon, Inner Focus Umbreon
p.generateAndPopulateMoveset();
}))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.LEAFEON, Species.GLACEON ]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.ROTOM ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.formIndex = Utils.randSeedInt(5, 1); // Heat, Wash, Frost, Fan, or Mow
}))
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.JOLTEON, Species.LEAFEON ]))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.VAPOREON, Species.UMBREON ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.ESPEON, Species.GLACEON ]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.FLAREON ]))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.SYLVEON ], TrainerSlot.TRAINER, true, p => {
p.abilityIndex = 2; // Pixilate
p.generateAndPopulateMoveset();
@ -2365,28 +2595,28 @@ export const trainerConfigs: TrainerConfigs = {
p.generateAndPopulateMoveset();
p.gender = Gender.FEMALE;
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.ENTEI, Species.RAIKOU, Species.SUICUNE ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.ROTOM ], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL;
p.formIndex = Utils.randSeedInt(5, 1); // Heat, Wash, Frost, Fan, or Mow
}))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.WALKING_WAKE, Species.GOUGING_FIRE, Species.RAGING_BOLT ]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.RAIKOU, Species.ENTEI, Species.SUICUNE ]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.REVAVROOM ], TrainerSlot.TRAINER, true, p => {
p.formIndex = Utils.randSeedInt(5, 1); //Random Starmobile form
p.formIndex = Utils.randSeedInt(5, 1); // Random Starmobile form
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ROGUE_BALL;
}))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.EEVEE ], TrainerSlot.TRAINER, true, p => {
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.ZAMAZENTA ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.MASTER_BALL;
}))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.EEVEE ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
p.formIndex = 2;
p.generateName();
p.pokeball = PokeballType.ULTRA_BALL;
}))
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.ZAMAZENTA ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.MASTER_BALL;
}))
.setGenModifiersFunc(party => {
const teraPokemon = party[0];
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ]; //TODO: is the bang correct?

View File

@ -375,8 +375,8 @@ export function getRandomWeatherType(arena: Arena): WeatherType {
break;
}
if (arena.biomeType === Biome.TOWN && globalScene.eventManager.isEventActive() && (globalScene.eventManager.activeEvent()?.weather?.length ?? 0) > 0) {
globalScene.eventManager.activeEvent()?.weather?.map(w => weatherPool.push(w));
if (arena.biomeType === Biome.TOWN && globalScene.eventManager.isEventActive()) {
globalScene.eventManager.getWeather()?.map(w => weatherPool.push(w));
}
if (weatherPool.length > 1) {

View File

@ -695,6 +695,7 @@ export class Arena {
globalScene.loadBgm(this.bgm);
}
/** The loop point of any given biome track, read as seconds and milliseconds. */
getBgmLoopPoint(): number {
switch (this.biomeType) {
case Biome.TOWN:

View File

@ -215,11 +215,12 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con
resolve();
}
const shinyPromises: Promise<void>[] = [];
this.spriteConfigs.forEach((config) => {
if (config.isPokemon) {
globalScene.loadPokemonAtlas(config.spriteKey, config.fileRoot);
if (config.isShiny) {
globalScene.loadPokemonVariantAssets(config.spriteKey, config.fileRoot, config.variant);
shinyPromises.push(globalScene.loadPokemonVariantAssets(config.spriteKey, config.fileRoot, config.variant));
}
} else if (config.isItem) {
globalScene.loadAtlas("items", "");
@ -254,7 +255,7 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con
return true;
});
resolve();
Promise.all(shinyPromises).then(() => resolve());
});
if (!globalScene.load.isLoading()) {

View File

@ -10,8 +10,7 @@ import type Move from "#app/data/move";
import { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, VariableMoveTypeAttr, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatStagesAttr, SacrificialAttr, VariableMoveCategoryAttr, CounterDamageAttr, StatStageChangeAttr, RechargeAttr, IgnoreWeatherTypeDebuffAttr, BypassBurnDamageReductionAttr, SacrificialAttrOnHit, OneHitKOAccuracyAttr, RespectAttackTypeImmunityAttr, MoveTarget, CombinedPledgeStabBoostAttr, VariableMoveTypeChartAttr } from "#app/data/move";
import type { PokemonSpeciesForm } from "#app/data/pokemon-species";
import { default as PokemonSpecies, getFusedSpeciesName, getPokemonSpecies, getPokemonSpeciesForm } from "#app/data/pokemon-species";
import { CLASSIC_CANDY_FRIENDSHIP_MULTIPLIER, getStarterValueFriendshipCap, speciesStarterCosts } from "#app/data/balance/starters";
import { starterPassiveAbilities } from "#app/data/balance/passives";
import { getStarterValueFriendshipCap, speciesStarterCosts } from "#app/data/balance/starters";
import type { Constructor } from "#app/utils";
import { isNullOrUndefined, randSeedInt, type nil } from "#app/utils";
import * as Utils from "#app/utils";
@ -1108,6 +1107,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return this.getStat(Stat.HP);
}
/** Returns the amount of hp currently missing from this {@linkcode Pokemon} (max - current) */
getInverseHp(): integer {
return this.getMaxHp() - this.hp;
}
@ -1400,11 +1400,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return allAbilities[this.customPokemonData.passive];
}
let starterSpeciesId = this.species.speciesId;
while (pokemonPrevolutions.hasOwnProperty(starterSpeciesId)) {
starterSpeciesId = pokemonPrevolutions[starterSpeciesId];
}
return allAbilities[starterPassiveAbilities[starterSpeciesId]];
return allAbilities[this.species.getPassiveAbility(this.formIndex)];
}
/**
@ -1955,7 +1951,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
* @param thresholdOverride number that is divided by 2^16 (65536) to get the shiny chance, overrides {@linkcode shinyThreshold} if set (bypassing shiny rate modifiers such as Shiny Charm)
* @returns true if the Pokemon has been set as a shiny, false otherwise
*/
trySetShiny(thresholdOverride?: integer): boolean {
trySetShiny(thresholdOverride?: number): boolean {
// Shiny Pokemon should not spawn in the end biome in endless
if (globalScene.gameMode.isEndless && globalScene.arena.biomeType === Biome.END) {
return false;
@ -1967,7 +1963,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const E = globalScene.gameData.trainerId ^ globalScene.gameData.secretId;
const F = rand1 ^ rand2;
const shinyThreshold = new Utils.IntegerHolder(BASE_SHINY_CHANCE);
const shinyThreshold = new Utils.NumberHolder(BASE_SHINY_CHANCE);
if (thresholdOverride === undefined) {
if (globalScene.eventManager.isEventActive()) {
shinyThreshold.value *= globalScene.eventManager.getShinyMultiplier();
@ -2058,6 +2054,38 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}
}
/**
* Function that tries to set a Pokemon to have its hidden ability based on seed, if it exists.
* For manual use only, usually to roll a Pokemon's hidden ability chance a second time.
*
* The base hidden ability odds are {@linkcode BASE_HIDDEN_ABILITY_CHANCE} / `65536`
* @param thresholdOverride number that is divided by `2^16` (`65536`) to get the HA chance, overrides {@linkcode haThreshold} if set (bypassing HA rate modifiers such as Ability Charm)
* @param applyModifiersToOverride If {@linkcode thresholdOverride} is set and this is true, will apply Ability Charm to {@linkcode thresholdOverride}
* @returns `true` if the Pokemon has been set to have its hidden ability, `false` otherwise
*/
public tryRerollHiddenAbilitySeed(thresholdOverride?: number, applyModifiersToOverride?: boolean): boolean {
if (!this.species.abilityHidden) {
return false;
}
const haThreshold = new Utils.NumberHolder(BASE_HIDDEN_ABILITY_CHANCE);
if (thresholdOverride === undefined || applyModifiersToOverride) {
if (thresholdOverride !== undefined && applyModifiersToOverride) {
haThreshold.value = thresholdOverride;
}
if (!this.hasTrainer()) {
globalScene.applyModifiers(HiddenAbilityRateBoosterModifier, true, haThreshold);
}
} else {
haThreshold.value = thresholdOverride;
}
if (randSeedInt(65536) < haThreshold.value) {
this.abilityIndex = 2;
}
return this.abilityIndex === 2;
}
public generateFusionSpecies(forStarter?: boolean): void {
const hiddenAbilityChance = new Utils.NumberHolder(BASE_HIDDEN_ABILITY_CHANCE);
if (!this.hasTrainer()) {
@ -2391,8 +2419,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.battleInfo.toggleFlyout(visible);
}
addExp(exp: integer) {
const maxExpLevel = globalScene.getMaxExpLevel();
/**
* Adds experience to this PlayerPokemon, subject to wave based level caps.
* @param exp The amount of experience to add
* @param ignoreLevelCap Whether to ignore level caps when adding experience (defaults to false)
*/
addExp(exp: integer, ignoreLevelCap: boolean = false) {
const maxExpLevel = globalScene.getMaxExpLevel(ignoreLevelCap);
const initialExp = this.exp;
this.exp += exp;
while (this.level < maxExpLevel && this.exp >= getLevelTotalExp(this.level + 1, this.species.growthRate)) {
@ -3606,6 +3639,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (!this.canSetStatus(effect, asPhase, false, sourcePokemon)) {
return false;
}
if (this.isFainted() && effect !== StatusEffect.FAINT) {
return false;
}
/**
* If this Pokemon falls asleep or freezes in the middle of a multi-hit attack,
@ -4324,10 +4360,7 @@ export class PlayerPokemon extends Pokemon {
].filter(d => !!d);
const amount = new Utils.NumberHolder(friendship);
globalScene.applyModifier(PokemonFriendshipBoosterModifier, true, this, amount);
let candyFriendshipMultiplier = CLASSIC_CANDY_FRIENDSHIP_MULTIPLIER;
if (globalScene.eventManager.isEventActive()) {
candyFriendshipMultiplier *= globalScene.eventManager.getFriendshipMultiplier();
}
const candyFriendshipMultiplier = globalScene.eventManager.getClassicFriendshipMultiplier();
const starterAmount = new Utils.NumberHolder(Math.floor(amount.value * (globalScene.gameMode.isClassic ? candyFriendshipMultiplier : 1) / (fusionStarterSpeciesId ? 2 : 1)));
// Add friendship to this PlayerPokemon
@ -5286,7 +5319,10 @@ export class PokemonSummonData {
}
export class PokemonBattleData {
/** counts the hits the pokemon received */
public hitCount: number = 0;
/** used for {@linkcode Moves.RAGE_FIST} in order to save hit Counts received before Rage Fist is applied */
public prevHitCount: number = 0;
public endured: boolean = false;
public berriesEaten: BerryType[] = [];
public abilitiesApplied: Abilities[] = [];

View File

@ -246,9 +246,9 @@ export class LoadingScene extends SceneBase {
}
const availableLangs = [ "en", "de", "it", "fr", "ja", "ko", "es-ES", "pt-BR", "zh-CN" ];
if (lang && availableLangs.includes(lang)) {
this.loadImage("winter_holidays2024-event-" + lang, "events");
this.loadImage("yearofthesnakeevent-" + lang, "events");
} else {
this.loadImage("winter_holidays2024-event-en", "events");
this.loadImage("yearofthesnakeevent-en", "events");
}
this.loadAtlas("statuses", "");
@ -319,6 +319,7 @@ export class LoadingScene extends SceneBase {
this.loadSe("pb_move");
this.loadSe("pb_catch");
this.loadSe("pb_lock");
this.loadSe("crit_throw");
this.loadSe("pb_tray_enter");
this.loadSe("pb_tray_ball");

View File

@ -2537,9 +2537,10 @@ export function getPartyLuckValue(party: Pokemon[]): integer {
}, 0, globalScene.seed);
return DailyLuck.value;
}
const luck = Phaser.Math.Clamp(party.map(p => p.isAllowedInBattle() ? p.getLuck() : 0)
const eventSpecies = globalScene.eventManager.getEventLuckBoostedSpecies();
const luck = Phaser.Math.Clamp(party.map(p => p.isAllowedInBattle() ? p.getLuck() + (eventSpecies.includes(p.species.speciesId) ? 1 : 0) : 0)
.reduce((total: integer, value: integer) => total += value, 0), 0, 14);
return luck ?? 0;
return Math.min(globalScene.eventManager.getEventLuckBoost() + (luck ?? 0), 14);
}
export function getLuckString(luckValue: integer): string {

View File

@ -1,19 +1,20 @@
/* eslint-disable @typescript-eslint/consistent-type-imports */
import { type PokeballCounts } from "#app/battle-scene";
import type { Gender } from "#app/data/gender";
import type { Variant } from "#app/data/variant";
import { Gender } from "#app/data/gender";
import { Variant } from "#app/data/variant";
import { type ModifierOverride } from "#app/modifier/modifier-type";
import type { Unlockables } from "#app/system/unlockables";
import { Unlockables } from "#app/system/unlockables";
import { Abilities } from "#enums/abilities";
import { Biome } from "#enums/biome";
import type { EggTier } from "#enums/egg-type";
import type { Moves } from "#enums/moves";
import type { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { EggTier } from "#enums/egg-type";
import { Moves } from "#enums/moves";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { PokeballType } from "#enums/pokeball";
import type { Species } from "#enums/species";
import { Species } from "#enums/species";
import { StatusEffect } from "#enums/status-effect";
import type { TimeOfDay } from "#enums/time-of-day";
import type { VariantTier } from "#enums/variant-tier";
import { TimeOfDay } from "#enums/time-of-day";
import { VariantTier } from "#enums/variant-tier";
import { WeatherType } from "#enums/weather-type";
/**
@ -21,7 +22,7 @@ import { WeatherType } from "#enums/weather-type";
*
* Any override added here will be used instead of the value in {@linkcode DefaultOverrides}
*
* If an override name starts with "STARTING", it will apply when a new run begins
* If an override name starts with "STARTING", it will only apply when a new run begins.
*
* @example
* ```
@ -38,7 +39,7 @@ const overrides = {} satisfies Partial<InstanceType<typeof DefaultOverrides>>;
* ---
* Defaults for Overrides that are used when testing different in game situations
*
* If an override name starts with "STARTING", it will apply when a new run begins
* If an override name starts with "STARTING", it will only apply when a new run begins.
*/
class DefaultOverrides {
// -----------------
@ -62,8 +63,11 @@ class DefaultOverrides {
readonly STARTING_WAVE_OVERRIDE: number = 0;
readonly STARTING_BIOME_OVERRIDE: Biome = Biome.TOWN;
readonly ARENA_TINT_OVERRIDE: TimeOfDay | null = null;
/** Multiplies XP gained by this value including 0. Set to null to ignore the override */
/** Multiplies XP gained by this value including 0. Set to null to ignore the override. */
readonly XP_MULTIPLIER_OVERRIDE: number | null = null;
/** Sets the level cap to this number during experience gain calculations. Set to `0` to disable override & use normal wave-based level caps,
or any negative number to set it to 9 quadrillion (effectively disabling it). */
readonly LEVEL_CAP_OVERRIDE: number = 0;
readonly NEVER_CRIT_OVERRIDE: boolean = false;
/** default 1000 */
readonly STARTING_MONEY_OVERRIDE: number = 0;

View File

@ -64,7 +64,7 @@ export class AttemptCapturePhase extends PokemonPhase {
this.pokeball.setOrigin(0.5, 0.625);
globalScene.field.add(this.pokeball);
globalScene.playSound("se/pb_throw", isCritical ? { rate: 0.2 } : undefined); // Crit catch throws are higher pitched
globalScene.playSound(isCritical ? "se/crit_throw" : "se/pb_throw");
globalScene.time.delayedCall(300, () => {
globalScene.field.moveBelow(this.pokeball as Phaser.GameObjects.GameObject, pokemon);
});

View File

@ -104,6 +104,12 @@ export class EncounterPhase extends BattlePhase {
}
if (!this.loaded) {
if (battle.battleType === BattleType.TRAINER) {
//resets hitRecCount during Trainer ecnounter
for (const pokemon of globalScene.getPlayerParty()) {
if (pokemon) {
pokemon.customPokemonData.resetHitReceivedCount();
}
}
battle.enemyParty[e] = battle.trainer?.genPartyMember(e)!; // TODO:: is the bang correct here?
} else {
let enemySpecies = globalScene.randomSpecies(battle.waveIndex, level, true);

View File

@ -26,7 +26,7 @@ export enum LearnMoveType {
export class LearnMovePhase extends PlayerPartyMemberPokemonPhase {
private moveId: Moves;
private messageMode: Mode;
private learnMoveType;
private learnMoveType: LearnMoveType;
private cost: number;
constructor(partyMemberIndex: integer, moveId: Moves, learnMoveType: LearnMoveType = LearnMoveType.LEARN_MOVE, cost: number = -1) {

View File

@ -14,6 +14,7 @@ export class NewBiomeEncounterPhase extends NextEncounterPhase {
for (const pokemon of globalScene.getPlayerParty()) {
if (pokemon) {
pokemon.resetBattleData();
pokemon.customPokemonData.resetHitReceivedCount();
}
}

View File

@ -39,7 +39,11 @@ export class TrainerVictoryPhase extends BattlePhase {
// Validate Voucher for boss trainers
if (vouchers.hasOwnProperty(TrainerType[trainerType])) {
if (!globalScene.validateVoucher(vouchers[TrainerType[trainerType]]) && globalScene.currentBattle.trainer?.config.isBoss) {
globalScene.unshiftPhase(new ModifierRewardPhase([ modifierTypes.VOUCHER, modifierTypes.VOUCHER, modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PREMIUM ][vouchers[TrainerType[trainerType]].voucherType]));
if (globalScene.eventManager.getUpgradeUnlockedVouchers()) {
globalScene.unshiftPhase(new ModifierRewardPhase([ modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PREMIUM ][vouchers[TrainerType[trainerType]].voucherType]));
} else {
globalScene.unshiftPhase(new ModifierRewardPhase([ modifierTypes.VOUCHER, modifierTypes.VOUCHER, modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PREMIUM ][vouchers[TrainerType[trainerType]].voucherType]));
}
}
}
// Breeders in Space achievement

View File

@ -204,6 +204,7 @@ export async function initI18n(): Promise<void> {
"nature",
"pokeball",
"pokemon",
"pokemonEvolutions",
"pokemonForm",
"pokemonInfo",
"pokemonInfoContainer",

View File

@ -292,7 +292,6 @@ export function getAchievementDescription(localizationKey: string): string {
}
export const achvs = {
_10K_MONEY: new MoneyAchv("10K_MONEY", "", 10000, "nugget", 10),
_100K_MONEY: new MoneyAchv("100K_MONEY", "", 100000, "big_nugget", 25).setSecret(true),
@ -365,7 +364,7 @@ export const achvs = {
FRESH_START: new ChallengeAchv("FRESH_START", "", "FRESH_START.description", "reviver_seed", 100, (c) => c instanceof FreshStartChallenge && c.value > 0 && !globalScene.gameMode.challenges.some(c => [ Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT ].includes(c.id) && c.value > 0)),
INVERSE_BATTLE: new ChallengeAchv("INVERSE_BATTLE", "", "INVERSE_BATTLE.description", "inverse", 100, (c) => c instanceof InverseBattleChallenge && c.value > 0),
FLIP_STATS: new ChallengeAchv("FLIP_STATS", "", "FLIP_STATS.description", "dubious_disc", 100, (c) => c instanceof FlipStatChallenge && c.value > 0),
FLIP_INVERSE: new ChallengeAchv("FLIP_INVERSE", "", "FLIP_INVERSE.description", "cracked_pot", 100, (c) => c instanceof FlipStatChallenge && c.value > 0 && globalScene.gameMode.challenges.every(c => [ Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT ].includes(c.id) && c.value > 0)),
FLIP_INVERSE: new ChallengeAchv("FLIP_INVERSE", "", "FLIP_INVERSE.description", "cracked_pot", 100, (c) => c instanceof FlipStatChallenge && c.value > 0 && globalScene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)).setSecret(),
BREEDERS_IN_SPACE: new Achv("BREEDERS_IN_SPACE", "", "BREEDERS_IN_SPACE.description", "moon_stone", 50).setSecret(),
};

View File

@ -166,7 +166,7 @@ export const SettingKeys = {
Field_Volume: "FIELD_VOLUME",
SE_Volume: "SE_VOLUME",
UI_Volume: "UI_SOUND_EFFECTS",
Music_Preference: "MUSIC_PREFERENCE",
Battle_Music: "BATTLE_MUSIC",
Show_BGM_Bar: "SHOW_BGM_BAR",
Move_Touch_Controls: "MOVE_TOUCH_CONTROLS",
Shop_Overlay_Opacity: "SHOP_OVERLAY_OPACITY"
@ -577,8 +577,8 @@ export const Setting: Array<Setting> = [
label: i18next.t("settings:consistent")
},
{
value: "Mixed Animated",
label: i18next.t("settings:mixedAnimated")
value: "Experimental",
label: i18next.t("settings:experimental")
}
],
default: 0,
@ -658,11 +658,11 @@ export const Setting: Array<Setting> = [
type: SettingType.AUDIO
},
{
key: SettingKeys.Music_Preference,
label: i18next.t("settings:musicPreference"),
key: SettingKeys.Battle_Music,
label: i18next.t("settings:battleMusic"),
options: [
{
value: "Gen V + PMD",
value: "Gen V",
label: i18next.t("settings:musicGenFive")
},
{
@ -741,7 +741,7 @@ export function setSetting(setting: string, value: integer): boolean {
case SettingKeys.UI_Volume:
globalScene.uiVolume = value ? parseInt(Setting[index].options[value].value) * 0.01 : 0;
break;
case SettingKeys.Music_Preference:
case SettingKeys.Battle_Music:
globalScene.musicPreference = value;
break;
case SettingKeys.Damage_Numbers:

View File

@ -7,7 +7,6 @@ import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
describe("Abilities - Dancer", () => {
let phaserGame: Phaser.Game;
let game: GameManager;
@ -24,20 +23,21 @@ describe("Abilities - Dancer", () => {
beforeEach(() => {
game = new GameManager(phaserGame);
game.override
.battleType("double")
.moveset([ Moves.SWORDS_DANCE, Moves.SPLASH ])
.enemySpecies(Species.MAGIKARP)
.enemyAbility(Abilities.DANCER)
.enemyMoveset([ Moves.VICTORY_DANCE ]);
game.override.battleType("double");
});
// Reference Link: https://bulbapedia.bulbagarden.net/wiki/Dancer_(Ability)
it("triggers when dance moves are used, doesn't consume extra PP", async () => {
game.override
.enemyAbility(Abilities.DANCER)
.enemySpecies(Species.MAGIKARP)
.enemyMoveset(Moves.VICTORY_DANCE);
await game.classicMode.startBattle([ Species.ORICORIO, Species.FEEBAS ]);
const [ oricorio ] = game.scene.getPlayerField();
const [ oricorio, feebas ] = game.scene.getPlayerField();
game.move.changeMoveset(oricorio, [ Moves.SWORDS_DANCE, Moves.VICTORY_DANCE, Moves.SPLASH ]);
game.move.changeMoveset(feebas, [ Moves.SWORDS_DANCE, Moves.SPLASH ]);
game.move.select(Moves.SPLASH);
game.move.select(Moves.SWORDS_DANCE, 1);
@ -59,5 +59,44 @@ describe("Abilities - Dancer", () => {
// doesn't use PP if copied move is also in moveset
expect(oricorio.moveset[0]?.ppUsed).toBe(0);
expect(oricorio.moveset[1]?.ppUsed).toBe(0);
});
// TODO: Enable after Dancer rework to not push to move history
it.todo("should not count as the last move used for mirror move/instruct", async () => {
game.override
.moveset([ Moves.FIERY_DANCE, Moves.REVELATION_DANCE ])
.enemyMoveset([ Moves.INSTRUCT, Moves.MIRROR_MOVE, Moves.SPLASH ])
.enemySpecies(Species.SHUCKLE)
.enemyLevel(10);
await game.classicMode.startBattle([ Species.ORICORIO, Species.FEEBAS ]);
const [ oricorio ] = game.scene.getPlayerField();
const [ , shuckle2 ] = game.scene.getEnemyField();
game.move.select(Moves.REVELATION_DANCE, BattlerIndex.PLAYER, BattlerIndex.ENEMY_2);
game.move.select(Moves.FIERY_DANCE, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY_2);
await game.forceEnemyMove(Moves.INSTRUCT, BattlerIndex.PLAYER);
await game.forceEnemyMove(Moves.MIRROR_MOVE, BattlerIndex.PLAYER);
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY_2, BattlerIndex.ENEMY ]);
await game.phaseInterceptor.to("MovePhase"); // Oricorio rev dance
await game.phaseInterceptor.to("MovePhase"); // Feebas fiery dance
await game.phaseInterceptor.to("MovePhase"); // Oricorio fiery dance (from dancer)
await game.phaseInterceptor.to("MoveEndPhase", false);
// dancer copied move doesn't appear in move history
expect(oricorio.getLastXMoves(-1)[0].move).toBe(Moves.REVELATION_DANCE);
await game.phaseInterceptor.to("MovePhase"); // shuckle 2 mirror moves oricorio
await game.phaseInterceptor.to("MovePhase"); // calls instructed rev dance
let currentPhase = game.scene.getCurrentPhase() as MovePhase;
expect(currentPhase.pokemon).toBe(shuckle2);
expect(currentPhase.move.moveId).toBe(Moves.REVELATION_DANCE);
await game.phaseInterceptor.to("MovePhase"); // shuckle 1 instructs oricorio
await game.phaseInterceptor.to("MovePhase");
currentPhase = game.scene.getCurrentPhase() as MovePhase;
expect(currentPhase.pokemon).toBe(oricorio);
expect(currentPhase.move.moveId).toBe(Moves.REVELATION_DANCE);
});
});

View File

@ -1,4 +1,5 @@
import { Status } from "#app/data/status-effect";
import { BattlerTagType } from "#app/enums/battler-tag-type";
import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase";
import { TurnEndPhase } from "#app/phases/turn-end-phase";
import { Abilities } from "#enums/abilities";
@ -29,7 +30,7 @@ describe("Abilities - SHIELDS DOWN", () => {
game.override.battleType("single");
game.override.ability(Abilities.SHIELDS_DOWN);
game.override.moveset([ moveToUse ]);
game.override.enemyMoveset([ Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE ]);
game.override.enemyMoveset([ Moves.TACKLE ]);
});
test(
@ -42,7 +43,7 @@ describe("Abilities - SHIELDS DOWN", () => {
[Species.MINIOR]: coreForm,
});
await game.startBattle([ Species.MAGIKARP, Species.MINIOR ]);
await game.classicMode.startBattle([ Species.MAGIKARP, Species.MINIOR ]);
const minior = game.scene.getPlayerParty().find((p) => p.species.speciesId === Species.MINIOR)!;
expect(minior).not.toBe(undefined);
@ -61,4 +62,131 @@ describe("Abilities - SHIELDS DOWN", () => {
expect(minior.formIndex).toBe(meteorForm);
},
);
test("should ignore non-volatile status moves",
async () => {
game.override.enemyMoveset([ Moves.SPORE ]);
await game.classicMode.startBattle([ Species.MINIOR ]);
game.move.select(Moves.SPLASH);
await game.phaseInterceptor.to(TurnEndPhase);
expect(game.scene.getPlayerPokemon()!.status).toBe(undefined);
}
);
test("should still ignore non-volatile status moves used by a pokemon with mold breaker",
async () => {
game.override.enemyAbility(Abilities.MOLD_BREAKER);
game.override.enemyMoveset([ Moves.SPORE ]);
await game.classicMode.startBattle([ Species.MINIOR ]);
game.move.select(Moves.SPLASH);
await game.forceEnemyMove(Moves.SPORE);
await game.phaseInterceptor.to(TurnEndPhase);
expect(game.scene.getPlayerPokemon()!.status).toBe(undefined);
}
);
test("should ignore non-volatile secondary status effects",
async() => {
game.override.enemyMoveset([ Moves.NUZZLE ]);
await game.classicMode.startBattle([ Species.MINIOR ]);
game.move.select(Moves.SPLASH);
await game.phaseInterceptor.to(TurnEndPhase);
expect(game.scene.getPlayerPokemon()!.status).toBe(undefined);
}
);
test("should ignore status moves even through mold breaker",
async () => {
game.override.enemyMoveset([ Moves.SPORE ]);
game.override.enemyAbility(Abilities.MOLD_BREAKER);
await game.classicMode.startBattle([ Species.MINIOR ]);
game.move.select(Moves.SPLASH);
await game.phaseInterceptor.to(TurnEndPhase);
expect(game.scene.getPlayerPokemon()!.status).toBe(undefined);
}
);
// toxic spikes currently does not poison flying types when gravity is in effect
test.todo("should become poisoned by toxic spikes when grounded",
async () => {
game.override.enemyMoveset([ Moves.GRAVITY, Moves.TOXIC_SPIKES, Moves.SPLASH ]);
game.override.moveset([ Moves.GRAVITY, Moves.SPLASH ]);
await game.classicMode.startBattle([ Species.MAGIKARP, Species.MINIOR ]);
// turn 1
game.move.select(Moves.GRAVITY);
await game.forceEnemyMove(Moves.TOXIC_SPIKES);
await game.toNextTurn();
// turn 2
game.doSwitchPokemon(1);
await game.forceEnemyMove(Moves.SPLASH);
await game.toNextTurn();
expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(Species.MINIOR);
expect(game.scene.getPlayerPokemon()!.species.formIndex).toBe(0);
expect(game.scene.getPlayerPokemon()!.status?.effect).toBe(StatusEffect.POISON);
}
);
test("should ignore yawn",
async () => {
game.override.enemyMoveset([ Moves.YAWN ]);
await game.classicMode.startBattle([ Species.MAGIKARP, Species.MINIOR ]);
game.move.select(Moves.SPLASH);
await game.forceEnemyMove(Moves.YAWN);
await game.phaseInterceptor.to(TurnEndPhase);
expect(game.scene.getPlayerPokemon()!.findTag( (tag ) => tag.tagType === BattlerTagType.DROWSY)).toBe(undefined);
}
);
test("should not ignore volatile status effects",
async () => {
game.override.enemyMoveset([ Moves.CONFUSE_RAY ]);
await game.classicMode.startBattle([ Species.MINIOR ]);
game.move.select(Moves.SPLASH);
await game.forceEnemyMove(Moves.CONFUSE_RAY);
await game.phaseInterceptor.to(TurnEndPhase);
expect(game.scene.getPlayerPokemon()!.findTag( (tag ) => tag.tagType === BattlerTagType.CONFUSED)).not.toBe(undefined);
}
);
// the `NoTransformAbilityAbAttr` attribute is not checked anywhere, so this test cannot pass.
test.todo("ditto should not be immune to status after transforming",
async () => {
game.override.enemySpecies(Species.DITTO);
game.override.enemyAbility(Abilities.IMPOSTER);
game.override.moveset([ Moves.SPLASH, Moves.SPORE ]);
await game.classicMode.startBattle([ Species.MINIOR ]);
game.move.select(Moves.SPORE);
await game.forceEnemyMove(Moves.SPLASH);
await game.phaseInterceptor.to(TurnEndPhase);
expect(game.scene.getEnemyPokemon()!.status?.effect).toBe(StatusEffect.SLEEP);
}
);
});

View File

@ -400,4 +400,42 @@ describe("Status Effects", () => {
expect(player.getLastXMoves(1)[0].result).toBe(MoveResult.SUCCESS);
});
});
describe("Behavior", () => {
let phaserGame: Phaser.Game;
let game: GameManager;
beforeAll(() => {
phaserGame = new Phaser.Game({
type: Phaser.HEADLESS,
});
});
afterEach(() => {
game.phaseInterceptor.restoreOg();
});
beforeEach(() => {
game = new GameManager(phaserGame);
game.override
.moveset([ Moves.SPLASH ])
.ability(Abilities.BALL_FETCH)
.battleType("single")
.disableCrits()
.enemySpecies(Species.MAGIKARP)
.enemyAbility(Abilities.BALL_FETCH)
.enemyMoveset(Moves.NUZZLE)
.enemyLevel(2000);
});
it("should not inflict a 0 HP mon with a status", async () => {
await game.classicMode.startBattle([ Species.FEEBAS, Species.MILOTIC ]);
const player = game.scene.getPlayerPokemon()!;
player.hp = 0;
expect(player.trySetStatus(StatusEffect.BURN)).toBe(false);
expect(player.status?.effect).not.toBe(StatusEffect.BURN);
});
});
});

View File

@ -1,6 +1,7 @@
import { BattlerIndex } from "#app/battle";
import type Pokemon from "#app/field/pokemon";
import { MoveResult } from "#app/field/pokemon";
import type { MovePhase } from "#app/phases/move-phase";
import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
@ -12,10 +13,10 @@ describe("Moves - Instruct", () => {
let phaserGame: Phaser.Game;
let game: GameManager;
function instructSuccess(pokemon: Pokemon, move: Moves): void {
expect(pokemon.getLastXMoves(-1)[0].move).toBe(move);
expect(pokemon.getLastXMoves(-1)[1].move).toBe(pokemon.getLastXMoves()[0].move);
expect(pokemon.getMoveset().find(m => m?.moveId === move)?.ppUsed).toBe(2);
function instructSuccess(target: Pokemon, move: Moves): void {
expect(target.getLastXMoves(-1)[0].move).toBe(move);
expect(target.getLastXMoves(-1)[1].move).toBe(target.getLastXMoves()[0].move);
expect(target.getMoveset().find(m => m?.moveId === move)?.ppUsed).toBe(2);
}
beforeAll(() => {
@ -36,27 +37,40 @@ describe("Moves - Instruct", () => {
.enemyAbility(Abilities.NO_GUARD)
.enemyLevel(100)
.startingLevel(100)
.ability(Abilities.BALL_FETCH)
.moveset([ Moves.INSTRUCT, Moves.SONIC_BOOM, Moves.SPLASH, Moves.TORMENT ])
.disableCrits();
});
it("should repeat enemy's attack move when moving last", async () => {
it("should repeat target's last used move", async () => {
game.override
.moveset(Moves.INSTRUCT)
.enemyLevel(1000); // ensures shuckle no die
await game.classicMode.startBattle([ Species.AMOONGUSS ]);
const enemy = game.scene.getEnemyPokemon()!;
game.move.changeMoveset(enemy, Moves.SONIC_BOOM);
game.move.select(Moves.INSTRUCT, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
await game.forceEnemyMove(Moves.SONIC_BOOM, BattlerIndex.PLAYER);
game.move.select(Moves.INSTRUCT);
await game.forceEnemyMove(Moves.SONIC_BOOM);
await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]);
await game.phaseInterceptor.to("MovePhase"); // enemy attacks us
await game.phaseInterceptor.to("MovePhase", false); // instruct
let currentPhase = game.scene.getCurrentPhase() as MovePhase;
expect(currentPhase.pokemon).toBe(game.scene.getPlayerPokemon());
await game.phaseInterceptor.to("MoveEndPhase");
await game.phaseInterceptor.to("MovePhase", false); // enemy repeats move
currentPhase = game.scene.getCurrentPhase() as MovePhase;
expect(currentPhase.pokemon).toBe(enemy);
expect(currentPhase.move.moveId).toBe(Moves.SONIC_BOOM);
await game.phaseInterceptor.to("TurnEndPhase", false);
expect(game.scene.getPlayerPokemon()?.getInverseHp()).toBe(40);
instructSuccess(enemy, Moves.SONIC_BOOM);
expect(game.scene.getPlayerPokemon()?.getInverseHp()).toBe(40);
});
it("should repeat enemy's move through substitute", async () => {
game.override.moveset([ Moves.INSTRUCT, Moves.SPLASH ]);
await game.classicMode.startBattle([ Species.AMOONGUSS ]);
const enemy = game.scene.getEnemyPokemon()!;
@ -72,75 +86,94 @@ describe("Moves - Instruct", () => {
await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]);
await game.phaseInterceptor.to("TurnEndPhase", false);
expect(game.scene.getPlayerPokemon()?.getInverseHp()).toBe(40);
instructSuccess(game.scene.getEnemyPokemon()!, Moves.SONIC_BOOM);
expect(game.scene.getPlayerPokemon()?.getInverseHp()).toBe(40);
});
it("should repeat ally's attack on enemy", async () => {
game.override
.battleType("double")
.moveset([]);
.enemyMoveset(Moves.SPLASH);
await game.classicMode.startBattle([ Species.AMOONGUSS, Species.SHUCKLE ]);
const [ amoonguss, shuckle ] = game.scene.getPlayerField();
game.move.changeMoveset(amoonguss, Moves.INSTRUCT);
game.move.changeMoveset(shuckle, Moves.SONIC_BOOM);
game.move.changeMoveset(amoonguss, [ Moves.INSTRUCT, Moves.SONIC_BOOM ]);
game.move.changeMoveset(shuckle, [ Moves.INSTRUCT, Moves.SONIC_BOOM ]);
game.move.select(Moves.INSTRUCT, BattlerIndex.PLAYER, BattlerIndex.PLAYER_2);
game.move.select(Moves.SONIC_BOOM, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY);
await game.forceEnemyMove(Moves.SPLASH);
await game.forceEnemyMove(Moves.SPLASH);
await game.setTurnOrder([ BattlerIndex.PLAYER_2, BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
await game.phaseInterceptor.to("TurnEndPhase", false);
expect(game.scene.getEnemyField()[0].getInverseHp()).toBe(40);
instructSuccess(shuckle, Moves.SONIC_BOOM);
expect(game.scene.getEnemyField()[0].getInverseHp()).toBe(40);
});
// TODO: Enable test case once gigaton hammer (and blood moon) is fixed
// TODO: Enable test case once gigaton hammer (and blood moon) are reworked
it.todo("should repeat enemy's Gigaton Hammer", async () => {
game.override
.moveset(Moves.INSTRUCT)
.enemyLevel(5);
await game.classicMode.startBattle([ Species.AMOONGUSS ]);
const enemy = game.scene.getEnemyPokemon()!;
game.move.changeMoveset(enemy, Moves.GIGATON_HAMMER);
game.move.changeMoveset(enemy, [ Moves.GIGATON_HAMMER, Moves.BLOOD_MOON ]);
game.move.select(Moves.INSTRUCT);
await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]);
await game.phaseInterceptor.to("TurnEndPhase", false);
await game.phaseInterceptor.to("BerryPhase");
instructSuccess(enemy, Moves.GIGATON_HAMMER);
expect(game.scene.getPlayerPokemon()!.turnData.attacksReceived.length).toBe(2);
});
it("should add moves to move queue for copycat", async () => {
game.override
.battleType("double")
.moveset(Moves.INSTRUCT)
.enemyLevel(5);
await game.classicMode.startBattle([ Species.AMOONGUSS ]);
const [ enemy1, enemy2 ] = game.scene.getEnemyField()!;
game.move.changeMoveset(enemy1, Moves.WATER_GUN);
game.move.changeMoveset(enemy2, Moves.COPYCAT);
game.move.select(Moves.INSTRUCT, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER, BattlerIndex.ENEMY_2 ]);
await game.phaseInterceptor.to("BerryPhase");
instructSuccess(enemy1, Moves.WATER_GUN);
// amoonguss gets hit by water gun thrice; once by original attack, once by instructed use and once by copycat
expect(game.scene.getPlayerPokemon()!.turnData.attacksReceived.length).toBe(3);
});
it("should respect enemy's status condition", async () => {
game.override
.moveset([ Moves.THUNDER_WAVE, Moves.INSTRUCT ])
.enemyMoveset([ Moves.SPLASH, Moves.SONIC_BOOM ]);
.moveset([ Moves.INSTRUCT, Moves.THUNDER_WAVE ])
.enemyMoveset(Moves.SONIC_BOOM);
await game.classicMode.startBattle([ Species.AMOONGUSS ]);
game.move.select(Moves.THUNDER_WAVE);
await game.forceEnemyMove(Moves.SONIC_BOOM);
await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]);
await game.toNextTurn();
game.move.select(Moves.INSTRUCT);
await game.forceEnemyMove(Moves.SPLASH);
await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]);
await game.move.forceStatusActivation(true);
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
await game.phaseInterceptor.to("MovePhase");
// force enemy's instructed move to bork and then immediately thaw out
await game.move.forceStatusActivation(true);
await game.move.forceStatusActivation(false);
await game.phaseInterceptor.to("TurnEndPhase", false);
const moveHistory = game.scene.getEnemyPokemon()!.getMoveHistory();
expect(moveHistory.length).toBe(3);
expect(moveHistory[0].move).toBe(Moves.SONIC_BOOM);
expect(moveHistory[1].move).toBe(Moves.NONE);
expect(moveHistory[2].move).toBe(Moves.SONIC_BOOM);
const moveHistory = game.scene.getEnemyPokemon()?.getLastXMoves(-1)!;
expect(moveHistory.map(m => m.move)).toEqual([ Moves.SONIC_BOOM, Moves.NONE, Moves.SONIC_BOOM ]);
expect(game.scene.getPlayerPokemon()?.getInverseHp()).toBe(40);
});
it("should not repeat enemy's out of pp move", async () => {
game.override.enemySpecies(Species.UNOWN);
game.override
.moveset(Moves.INSTRUCT)
.enemySpecies(Species.UNOWN);
await game.classicMode.startBattle([ Species.AMOONGUSS ]);
const enemyPokemon = game.scene.getEnemyPokemon()!;
@ -153,13 +186,85 @@ describe("Moves - Instruct", () => {
await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]);
await game.phaseInterceptor.to("TurnEndPhase", false);
const playerMove = game.scene.getPlayerPokemon()!.getLastXMoves()!;
expect(playerMove[0].result).toBe(MoveResult.FAIL);
const playerMoves = game.scene.getPlayerPokemon()!.getLastXMoves(-1)!;
expect(playerMoves[0].result).toBe(MoveResult.FAIL);
expect(enemyPokemon.getMoveHistory().length).toBe(1);
});
it("should redirect attacking moves if enemy faints", async () => {
game.override
.battleType("double")
.enemyMoveset(Moves.SPLASH)
.enemySpecies(Species.MAGIKARP)
.enemyLevel(1);
await game.classicMode.startBattle([ Species.HISUI_ELECTRODE, Species.KOMMO_O ]);
const [ electrode, kommo_o ] = game.scene.getPlayerField()!;
game.move.changeMoveset(electrode, Moves.CHLOROBLAST);
game.move.changeMoveset(kommo_o, Moves.INSTRUCT);
game.move.select(Moves.CHLOROBLAST, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
game.move.select(Moves.INSTRUCT, BattlerIndex.PLAYER_2, BattlerIndex.PLAYER);
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
await game.phaseInterceptor.to("BerryPhase");
// Chloroblast always deals 50% max HP% recoil UNLESS you whiff
// due to lack of targets or similar,
// so all we have to do is check whether electrode fainted or not.
// Naturally, both karps should also be dead as well.
expect(electrode.isFainted()).toBe(true);
const [ karp1, karp2 ] = game.scene.getEnemyField()!;
expect(karp1.isFainted()).toBe(true);
expect(karp2.isFainted()).toBe(true);
}),
it("should allow for dancer copying of instructed dance move", async () => {
game.override
.battleType("double")
.enemyMoveset([ Moves.INSTRUCT, Moves.SPLASH ]);
await game.classicMode.startBattle([ Species.ORICORIO, Species.VOLCARONA ]);
const [ oricorio, volcarona ] = game.scene.getPlayerField();
game.move.changeMoveset(oricorio, Moves.SPLASH);
game.move.changeMoveset(volcarona, Moves.FIERY_DANCE);
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER);
game.move.select(Moves.FIERY_DANCE, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY);
await game.forceEnemyMove(Moves.INSTRUCT, BattlerIndex.PLAYER_2);
await game.forceEnemyMove(Moves.SPLASH);
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
await game.phaseInterceptor.to("BerryPhase");
// fiery dance triggered dancer successfully for a total of 4 hits
// Volcarona fiery dance has a _small_ chance to 3HKO a shuckle in worst case, so we add the hit count of both
// foes to account for spillover
instructSuccess(volcarona, Moves.FIERY_DANCE);
expect(game.scene.getEnemyField()[0].turnData.attacksReceived.length +
game.scene.getEnemyField()[1].turnData.attacksReceived.length).toBe(4);
});
it("should not repeat move when switching out", async () => {
game.override
.enemyMoveset(Moves.INSTRUCT)
.enemySpecies(Species.UNOWN);
await game.classicMode.startBattle([ Species.AMOONGUSS, Species.TOXICROAK ]);
const amoonguss = game.scene.getPlayerPokemon()!;
game.move.changeMoveset(amoonguss, Moves.SEED_BOMB);
amoonguss.battleSummonData.moveHistory = [{ move: Moves.SEED_BOMB, targets: [ BattlerIndex.ENEMY ], result: MoveResult.SUCCESS }];
game.doSwitchPokemon(1);
await game.phaseInterceptor.to("TurnEndPhase", false);
const enemyMoves = game.scene.getEnemyPokemon()!.getLastXMoves(-1)!;
expect(enemyMoves[0].result).toBe(MoveResult.FAIL);
});
it("should fail if no move has yet been used by target", async () => {
game.override.enemyMoveset(Moves.SPLASH);
game.override
.moveset(Moves.INSTRUCT)
.enemyMoveset(Moves.SPLASH);
await game.classicMode.startBattle([ Species.AMOONGUSS ]);
game.move.select(Moves.INSTRUCT);
@ -183,48 +288,46 @@ describe("Moves - Instruct", () => {
game.move.select(Moves.INSTRUCT, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
game.move.select(Moves.DISABLE, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY);
await game.forceEnemyMove(Moves.SONIC_BOOM, BattlerIndex.PLAYER);
await game.forceEnemyMove(Moves.SPLASH);
await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER_2, BattlerIndex.PLAYER, BattlerIndex.ENEMY_2 ]);
await game.phaseInterceptor.to("TurnEndPhase", false);
expect(game.scene.getPlayerField()[0].getLastXMoves()[0].result).toBe(MoveResult.SUCCESS);
const enemyMove = game.scene.getEnemyPokemon()!.getLastXMoves()[0];
const enemyMove = game.scene.getEnemyField()[0]!.getLastXMoves()[0];
expect(enemyMove.result).toBe(MoveResult.FAIL);
expect(game.scene.getEnemyPokemon()!.getMoveset().find(m => m?.moveId === Moves.SONIC_BOOM)?.ppUsed).toBe(1);
expect(game.scene.getEnemyField()[0].getMoveset().find(m => m?.moveId === Moves.SONIC_BOOM)?.ppUsed).toBe(1);
});
it("should not repeat enemy's move through protect", async () => {
game.override.moveset([ Moves.INSTRUCT ]);
await game.classicMode.startBattle([ Species.AMOONGUSS ]);
const MoveToUse = Moves.PROTECT;
const enemyPokemon = game.scene.getEnemyPokemon()!;
game.move.changeMoveset(enemyPokemon, MoveToUse);
const enemy = game.scene.getEnemyPokemon()!;
game.move.changeMoveset(enemy, Moves.PROTECT);
game.move.select(Moves.INSTRUCT);
await game.forceEnemyMove(Moves.PROTECT);
await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]);
await game.phaseInterceptor.to("TurnEndPhase", false);
expect(enemyPokemon.getLastXMoves(-1)[0].move).toBe(Moves.PROTECT);
expect(enemyPokemon.getLastXMoves(-1)[1]).toBeUndefined(); // undefined because protect failed
expect(enemyPokemon.getMoveset().find(m => m?.moveId === Moves.PROTECT)?.ppUsed).toBe(1);
expect(enemy.getLastXMoves(-1)[0].move).toBe(Moves.PROTECT);
expect(enemy.getLastXMoves(-1)[1]).toBeUndefined(); // undefined because instruct failed and didn't repeat
expect(enemy.getMoveset().find(m => m?.moveId === Moves.PROTECT)?.ppUsed).toBe(1);
});
it("should not repeat enemy's charging move", async () => {
game.override
.enemyMoveset([ Moves.SONIC_BOOM, Moves.HYPER_BEAM ])
.enemyLevel(5);
.moveset([ Moves.INSTRUCT ])
.enemyMoveset([ Moves.SONIC_BOOM, Moves.HYPER_BEAM ]);
await game.classicMode.startBattle([ Species.SHUCKLE ]);
const player = game.scene.getPlayerPokemon()!;
const enemyPokemon = game.scene.getEnemyPokemon()!;
enemyPokemon.battleSummonData.moveHistory = [{ move: Moves.SONIC_BOOM, targets: [ BattlerIndex.PLAYER ], result: MoveResult.SUCCESS, virtual: false }];
const enemy = game.scene.getEnemyPokemon()!;
enemy.battleSummonData.moveHistory = [{ move: Moves.SONIC_BOOM, targets: [ BattlerIndex.PLAYER ], result: MoveResult.SUCCESS, virtual: false }];
game.move.select(Moves.INSTRUCT);
await game.forceEnemyMove(Moves.HYPER_BEAM);
await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]);
await game.toNextTurn();
// instruct fails at copying last move due to charging turn (rather than instructing sonic boom)
expect(player.getLastXMoves()[0].result).toBe(MoveResult.FAIL);
game.move.select(Moves.INSTRUCT);
@ -234,31 +337,162 @@ describe("Moves - Instruct", () => {
expect(player.getLastXMoves()[0].result).toBe(MoveResult.FAIL);
});
it("should not repeat dance move not known by target", async () => {
it("should not repeat move since forgotten by target", async () => {
game.override
.battleType("double")
.moveset([ Moves.INSTRUCT, Moves.FIERY_DANCE ])
.enemyMoveset(Moves.SPLASH)
.enemyAbility(Abilities.DANCER);
await game.classicMode.startBattle([ Species.SHUCKLE, Species.SHUCKLE ]);
.enemyLevel(5)
.xpMultiplier(0)
.enemySpecies(Species.WURMPLE)
.enemyMoveset(Moves.INSTRUCT);
await game.classicMode.startBattle([ Species.REGIELEKI ]);
game.move.select(Moves.INSTRUCT, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
game.move.select(Moves.FIERY_DANCE, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY);
const regieleki = game.scene.getPlayerPokemon()!;
// fill out moveset with random moves
game.move.changeMoveset(regieleki, [ Moves.ELECTRO_DRIFT, Moves.SPLASH, Moves.ICE_BEAM, Moves.ANCIENT_POWER ]);
game.move.select(Moves.ELECTRO_DRIFT);
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
await game.phaseInterceptor.to("FaintPhase");
await game.move.learnMove(Moves.ELECTROWEB);
await game.toNextWave();
game.move.select(Moves.SPLASH);
await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]);
await game.phaseInterceptor.to("TurnEndPhase", false);
expect(game.scene.getEnemyField()[0].getLastXMoves()[0].result).toBe(MoveResult.FAIL);
});
it("should disregard priority of instructed move on use", async () => {
game.override
.enemyMoveset([ Moves.SPLASH, Moves.WHIRLWIND ])
.moveset(Moves.INSTRUCT);
await game.classicMode.startBattle([ Species.LUCARIO, Species.BANETTE ]);
const enemyPokemon = game.scene.getEnemyPokemon()!;
enemyPokemon.battleSummonData.moveHistory = [{ move: Moves.WHIRLWIND, targets: [ BattlerIndex.PLAYER ], result: MoveResult.SUCCESS, virtual: false }];
game.move.select(Moves.INSTRUCT);
await game.forceEnemyMove(Moves.SPLASH);
await game.phaseInterceptor.to("TurnEndPhase", false);
// lucario instructed enemy whirlwind at 0 priority to switch itself out
const instructedMove = enemyPokemon.getLastXMoves(-1)[1];
expect(instructedMove.result).toBe(MoveResult.SUCCESS);
expect(instructedMove.move).toBe(Moves.WHIRLWIND);
expect(game.scene.getPlayerPokemon()?.species.speciesId).toBe(Species.BANETTE);
});
it("should respect moves' original priority for psychic terrain", async () => {
game.override.
battleType("double")
.moveset([ Moves.QUICK_ATTACK, Moves.SPLASH, Moves.INSTRUCT ])
.enemyMoveset([ Moves.SPLASH, Moves.PSYCHIC_TERRAIN ]);
await game.classicMode.startBattle([ Species.BANETTE, Species.KLEFKI ]);
game.move.select(Moves.QUICK_ATTACK, BattlerIndex.PLAYER, BattlerIndex.ENEMY); // succeeds due to terrain no
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER_2);
await game.forceEnemyMove(Moves.SPLASH);
await game.forceEnemyMove(Moves.PSYCHIC_TERRAIN);
await game.toNextTurn();
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER);
game.move.select(Moves.INSTRUCT, BattlerIndex.PLAYER_2, BattlerIndex.PLAYER);
await game.setTurnOrder([ BattlerIndex.PLAYER_2, BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
await game.phaseInterceptor.to("TurnEndPhase", false);
expect(game.scene.getPlayerField()[0].getLastXMoves()[0].result).toBe(MoveResult.FAIL);
// quick attack failed when instructed
const banette = game.scene.getPlayerPokemon()!;
expect(banette.getLastXMoves(-1)[1].move).toBe(Moves.QUICK_ATTACK);
expect(banette.getLastXMoves(-1)[1].result).toBe(MoveResult.FAIL);
});
it("should still work w/ prankster in psychic terrain", async () => {
game.override.
battleType("double")
.enemyMoveset([ Moves.SPLASH, Moves.PSYCHIC_TERRAIN ]);
await game.classicMode.startBattle([ Species.BANETTE, Species.KLEFKI ]);
const [ banette, klefki ] = game.scene.getPlayerField()!;
game.move.changeMoveset(banette, [ Moves.VINE_WHIP, Moves.SPLASH ]);
game.move.changeMoveset(klefki, [ Moves.INSTRUCT, Moves.SPLASH ]);
game.move.select(Moves.VINE_WHIP, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER_2);
await game.forceEnemyMove(Moves.SPLASH);
await game.forceEnemyMove(Moves.PSYCHIC_TERRAIN);
await game.toNextTurn();
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER);
game.move.select(Moves.INSTRUCT, BattlerIndex.PLAYER_2, BattlerIndex.PLAYER); // copies vine whip
await game.setTurnOrder([ BattlerIndex.PLAYER_2, BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
await game.phaseInterceptor.to("TurnEndPhase", false);
expect(banette.getLastXMoves(-1)[1].move).toBe(Moves.VINE_WHIP);
expect(banette.getLastXMoves(-1)[2].move).toBe(Moves.VINE_WHIP);
expect(banette.getMoveset().find(m => m?.moveId === Moves.VINE_WHIP )?.ppUsed).toBe(2);
});
it("should cause spread moves to correctly hit targets in doubles after singles", async () => {
game.override
.battleType("even-doubles")
.moveset([ Moves.BREAKING_SWIPE, Moves.INSTRUCT, Moves.SPLASH ])
.enemyMoveset(Moves.SONIC_BOOM)
.enemySpecies(Species.AXEW)
.startingLevel(500);
await game.classicMode.startBattle([ Species.KORAIDON, Species.KLEFKI ]);
const koraidon = game.scene.getPlayerField()[0]!;
game.move.select(Moves.BREAKING_SWIPE);
await game.phaseInterceptor.to("TurnEndPhase", false);
expect(koraidon.getInverseHp()).toBe(0);
expect(koraidon.getLastXMoves(-1)[0].targets).toEqual([ BattlerIndex.ENEMY ]);
await game.toNextWave();
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER);
game.move.select(Moves.INSTRUCT, BattlerIndex.PLAYER_2, BattlerIndex.PLAYER);
await game.setTurnOrder([ BattlerIndex.PLAYER_2, BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
await game.phaseInterceptor.to("TurnEndPhase", false);
// did not take damage since enemies died beforehand;
// last move used hit both enemies
expect(koraidon.getInverseHp()).toBe(0);
expect(koraidon.getLastXMoves(-1)[1].targets?.sort()).toEqual([ BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
});
it("should cause AoE moves to correctly hit everyone in doubles after singles", async () => {
game.override
.battleType("even-doubles")
.moveset([ Moves.BRUTAL_SWING, Moves.INSTRUCT, Moves.SPLASH ])
.enemySpecies(Species.AXEW)
.enemyMoveset(Moves.SONIC_BOOM)
.startingLevel(500);
await game.classicMode.startBattle([ Species.KORAIDON, Species.KLEFKI ]);
const koraidon = game.scene.getPlayerField()[0]!;
game.move.select(Moves.BRUTAL_SWING);
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
await game.phaseInterceptor.to("TurnEndPhase", false);
expect(koraidon.getInverseHp()).toBe(0);
expect(koraidon.getLastXMoves(-1)[0].targets).toEqual([ BattlerIndex.ENEMY ]);
await game.toNextWave();
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER);
game.move.select(Moves.INSTRUCT, BattlerIndex.PLAYER_2, BattlerIndex.PLAYER);
await game.setTurnOrder([ BattlerIndex.PLAYER_2, BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
await game.phaseInterceptor.to("TurnEndPhase", false);
// did not take damage since enemies died beforehand;
// last move used hit everything around it
expect(koraidon.getInverseHp()).toBe(0);
expect(koraidon.getLastXMoves(-1)[1].targets?.sort()).toEqual([ BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
});
it("should cause multi-hit moves to hit the appropriate number of times in singles", async () => {
game.override
.enemyAbility(Abilities.SKILL_LINK)
.moveset([ Moves.SPLASH, Moves.INSTRUCT ])
.enemyMoveset(Moves.BULLET_SEED);
await game.classicMode.startBattle([ Species.BULBASAUR ]);
const player = game.scene.getPlayerPokemon()!;
const bulbasaur = game.scene.getPlayerPokemon()!;
game.move.select(Moves.SPLASH);
await game.toNextTurn();
@ -267,34 +501,35 @@ describe("Moves - Instruct", () => {
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
await game.phaseInterceptor.to("BerryPhase");
expect(player.turnData.attacksReceived.length).toBe(10);
expect(bulbasaur.turnData.attacksReceived.length).toBe(10);
await game.toNextTurn();
game.move.select(Moves.INSTRUCT);
await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]);
await game.phaseInterceptor.to("BerryPhase");
expect(player.turnData.attacksReceived.length).toBe(10);
expect(bulbasaur.turnData.attacksReceived.length).toBe(10);
});
it("should cause multi-hit moves to hit the appropriate number of times in doubles", async () => {
game.override
.battleType("double")
.enemyAbility(Abilities.SKILL_LINK)
.moveset([ Moves.SPLASH, Moves.INSTRUCT ])
.enemyMoveset([ Moves.BULLET_SEED, Moves.SPLASH ])
.enemyLevel(5);
await game.classicMode.startBattle([ Species.BULBASAUR, Species.IVYSAUR ]);
const [ , ivysaur ] = game.scene.getPlayerField();
game.move.select(Moves.SPLASH);
game.move.select(Moves.SPLASH, 1);
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER);
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER_2);
await game.forceEnemyMove(Moves.BULLET_SEED, BattlerIndex.PLAYER_2);
await game.forceEnemyMove(Moves.SPLASH);
await game.toNextTurn();
game.move.select(Moves.INSTRUCT, 0, BattlerIndex.ENEMY);
game.move.select(Moves.INSTRUCT, 1, BattlerIndex.ENEMY);
game.move.select(Moves.INSTRUCT, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
game.move.select(Moves.INSTRUCT, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY);
await game.forceEnemyMove(Moves.BULLET_SEED, BattlerIndex.PLAYER_2);
await game.forceEnemyMove(Moves.SPLASH);
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
@ -303,8 +538,8 @@ describe("Moves - Instruct", () => {
expect(ivysaur.turnData.attacksReceived.length).toBe(15);
await game.toNextTurn();
game.move.select(Moves.INSTRUCT, 0, BattlerIndex.ENEMY);
game.move.select(Moves.INSTRUCT, 1, BattlerIndex.ENEMY);
game.move.select(Moves.INSTRUCT, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
game.move.select(Moves.INSTRUCT, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY);
await game.forceEnemyMove(Moves.BULLET_SEED, BattlerIndex.PLAYER_2);
await game.forceEnemyMove(Moves.SPLASH);
await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER, BattlerIndex.PLAYER_2 ]);

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