Merge branch 'beta' into hebrew-pr

This commit is contained in:
Lugiad 2025-03-20 23:24:31 +01:00 committed by GitHub
commit f213747500
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
37 changed files with 2559 additions and 1954 deletions

1
.gitattributes vendored
View File

@ -1,2 +1,3 @@
# Auto detect text files and perform LF normalization # Auto detect text files and perform LF normalization
* text=auto * text=auto
* -crlf

View File

@ -1,6 +1,7 @@
name: Bug Report name: Bug Report
description: Create a report to help us improve description: Create a report to help us improve
title: "[Bug] " title: "[Bug] "
type: bug
labels: ["Bug", "Triage"] labels: ["Bug", "Triage"]
body: body:
- type: markdown - type: markdown

View File

@ -1,6 +1,7 @@
name: Feature Request name: Feature Request
description: Suggest an idea for this project description: Suggest an idea for this project
title: "[Feature] " title: "[Feature] "
type: 'feature'
labels: ["Enhancement", "Triage"] labels: ["Enhancement", "Triage"]
body: body:
- type: markdown - type: markdown

View File

@ -13,10 +13,10 @@
"1005", "1005",
"1006", "1006",
"1006", "1006",
"1007-apex", "1007-apex-build-Disabled",
"1007-apex", "1007-apex-build-Disabled",
"1008-ultimate", "1008-ultimate-mode-Disabled",
"1008-ultimate", "1008-ultimate-mode-Disabled",
"115-mega", "115-mega",
"115-mega", "115-mega",
"127-mega", "127-mega",
@ -185,9 +185,9 @@
"531-mega", "531-mega",
"569-gigantamax", "569-gigantamax",
"569-gigantamax", "569-gigantamax",
"6-mega",
"6-mega",
"6-mega-x", "6-mega-x",
"6-mega-x",
"6-mega-y",
"6-mega-y", "6-mega-y",
"6058", "6058",
"6058", "6058",
@ -825,8 +825,8 @@
"873", "873",
"874", "874",
"874", "874",
"875-no", "875-no-ice",
"875-no", "875-no-ice",
"875", "875",
"875", "875",
"876-female", "876-female",
@ -963,26 +963,26 @@
"929", "929",
"930", "930",
"930", "930",
"931-blue", "931-blue-plumage-Disabled",
"931-blue", "931-blue-plumage-Disabled",
"931-green", "931-green-plumage-Disabled",
"931-green", "931-green-plumage-Disabled",
"931-white", "931-white-plumage-Disabled",
"931-white", "931-white-plumage-Disabled",
"931-yellow", "931-yellow-plumage-Disabled",
"931-yellow", "931-yellow-plumage-Disabled",
"932", "932",
"932", "932",
"933", "933",
"933", "933",
"934", "934",
"934", "934",
"935", "935-Disabled",
"935", "935-Disabled",
"936", "936-Disabled",
"936", "936-Disabled",
"937", "937-Disabled",
"937", "937-Disabled",
"938", "938",
"938", "938",
"939", "939",
@ -1073,6 +1073,8 @@
"978-droopy", "978-droopy",
"978-stretchy", "978-stretchy",
"978-stretchy", "978-stretchy",
"979-Disabled",
"979-Disabled",
"980", "980",
"980", "980",
"981", "981",
@ -1131,10 +1133,10 @@
"1005b", "1005b",
"1006b", "1006b",
"1006b", "1006b",
"1007b-apex", "1007b-apex-build-Disabled",
"1007b-apex", "1007b-apex-build-Disabled",
"1008b-ultimate", "1008b-ultimate-mode-Disabled",
"1008b-ultimate", "1008b-ultimate-mode-Disabled",
"115b-mega", "115b-mega",
"115b-mega", "115b-mega",
"127b-mega", "127b-mega",
@ -1303,9 +1305,9 @@
"531b-mega", "531b-mega",
"569b-gigantamax", "569b-gigantamax",
"569b-gigantamax", "569b-gigantamax",
"6b-mega",
"6b-mega",
"6b-mega-x", "6b-mega-x",
"6b-mega-x",
"6b-mega-y",
"6b-mega-y", "6b-mega-y",
"6058b", "6058b",
"6058b", "6058b",
@ -1943,8 +1945,8 @@
"873b", "873b",
"874b", "874b",
"874b", "874b",
"875b-no", "875b-no-ice",
"875b-no", "875b-no-ice",
"875b", "875b",
"875b", "875b",
"876b-female", "876b-female",
@ -2083,26 +2085,26 @@
"929b", "929b",
"930b", "930b",
"930b", "930b",
"931b-blue", "931b-blue-plumage-Disabled",
"931b-blue", "931b-blue-plumage-Disabled",
"931b-green", "931b-green-plumage-Disabled",
"931b-green", "931b-green-plumage-Disabled",
"931b-white", "931b-white-plumage-Disabled",
"931b-white", "931b-white-plumage-Disabled",
"931b-yellow", "931b-yellow-plumage-Disabled",
"931b-yellow", "931b-yellow-plumage-Disabled",
"932b", "932b",
"932b", "932b",
"933b", "933b",
"933b", "933b",
"934b", "934b",
"934b", "934b",
"935b", "935b-Disabled",
"935b", "935b-Disabled",
"936b", "936b-Disabled",
"936b", "936b-Disabled",
"937b", "937b-Disabled",
"937b", "937b-Disabled",
"938b", "938b",
"938b", "938b",
"939b", "939b",
@ -2251,10 +2253,10 @@
"1005sb", "1005sb",
"1006sb", "1006sb",
"1006sb", "1006sb",
"1007sb-apex", "1007sb-apex-build-Disabled",
"1007sb-apex", "1007sb-apex-build-Disabled",
"1008sb-ultimate", "1008sb-ultimate-mode-Disabled",
"1008sb-ultimate", "1008sb-ultimate-mode-Disabled",
"115sb-mega", "115sb-mega",
"115sb-mega", "115sb-mega",
"127sb-mega", "127sb-mega",
@ -3063,8 +3065,8 @@
"873sb", "873sb",
"874sb", "874sb",
"874sb", "874sb",
"875sb-no", "875sb-no-ice",
"875sb-no", "875sb-no-ice",
"875sb", "875sb",
"875sb", "875sb",
"876sb-female", "876sb-female",
@ -3203,26 +3205,26 @@
"929sb", "929sb",
"930sb", "930sb",
"930sb", "930sb",
"931sb-blue", "931sb-blue-plumage-Disabled",
"931sb-blue", "931sb-blue-plumage-Disabled",
"931sb-green", "931sb-green-plumage-Disabled",
"931sb-green", "931sb-green-plumage-Disabled",
"931sb-white", "931sb-white-plumage-Disabled",
"931sb-white", "931sb-white-plumage-Disabled",
"931sb-yellow", "931sb-yellow-plumage-Disabled",
"931sb-yellow", "931sb-yellow-plumage-Disabled",
"932sb", "932sb",
"932sb", "932sb",
"933sb", "933sb",
"933sb", "933sb",
"934sb", "934sb",
"934sb", "934sb",
"935sb", "935sb-Disabled",
"935sb", "935sb-Disabled",
"936sb", "936sb-Disabled",
"936sb", "936sb-Disabled",
"937sb", "937sb-Disabled",
"937sb", "937sb-Disabled",
"938sb", "938sb",
"938sb", "938sb",
"939sb", "939sb",
@ -3376,10 +3378,10 @@
"1005s", "1005s",
"1006s", "1006s",
"1006s", "1006s",
"1007s-apex", "1007s-apex-build-Disabled",
"1007s-apex", "1007s-apex-build-Disabled",
"1008s-ultimate", "1008s-ultimate-mode-Disabled",
"1008s-ultimate", "1008s-ultimate-mode-Disabled",
"115s-mega", "115s-mega",
"115s-mega", "115s-mega",
"127s-mega", "127s-mega",
@ -4188,8 +4190,8 @@
"873s", "873s",
"874s", "874s",
"874s", "874s",
"875s-no", "875s-no-ice",
"875s-no", "875s-no-ice",
"875s", "875s",
"875s", "875s",
"876s-female", "876s-female",
@ -4328,26 +4330,26 @@
"929s", "929s",
"930s", "930s",
"930s", "930s",
"931s-blue", "931s-blue-plumage-Disabled",
"931s-blue", "931s-blue-plumage-Disabled",
"931s-green", "931s-green-plumage-Disabled",
"931s-green", "931s-green-plumage-Disabled",
"931s-white", "931s-white-plumage-Disabled",
"931s-white", "931s-white-plumage-Disabled",
"931s-yellow", "931s-yellow-plumage-Disabled",
"931s-yellow", "931s-yellow-plumage-Disabled",
"932s", "932s",
"932s", "932s",
"933s", "933s",
"933s", "933s",
"934s", "934s",
"934s", "934s",
"935s", "935s-Disabled",
"935s", "935s-Disabled",
"936s", "936s-Disabled",
"936s", "936s-Disabled",
"937s", "937s-Disabled",
"937s", "937s-Disabled",
"938s", "938s",
"938s", "938s",
"939s", "939s",
@ -4438,6 +4440,8 @@
"978s-droopy", "978s-droopy",
"978s-stretchy", "978s-stretchy",
"978s-stretchy", "978s-stretchy",
"979s-Disabled",
"979s-Disabled",
"980s", "980s",
"980s", "980s",
"981s", "981s",
@ -4485,11 +4489,10 @@
"1000", "1000",
"1001", "1001",
"1004", "1004",
"1007-apex", "1007-apex-build-Disabled",
"1007-apex", "1007-apex-build-Disabled",
"1007-apex", "1008-ultimate-mode-Disabled",
"1007-apex", "1008-ultimate-mode-Disabled",
"1008-ultimate",
"127-mega", "127-mega",
"142-mega", "142-mega",
"150-mega", "150-mega",
@ -4698,21 +4701,21 @@
"933_3", "933_3",
"933_3", "933_3",
"934", "934",
"935", "935-Disabled",
"935_3", "935_3-Disabled",
"935_3", "935_3-Disabled",
"936_1", "936_1-Disabled",
"936_1", "936_1-Disabled",
"936_2", "936_2-Disabled",
"936_2", "936_2-Disabled",
"936_3", "936_3-Disabled",
"936_3", "936_3-Disabled",
"937_1", "937_1-Disabled",
"937_1", "937_1-Disabled",
"937_2", "937_2-Disabled",
"937_2", "937_2-Disabled",
"937_3", "937_3-Disabled",
"937_3", "937_3-Disabled",
"94-mega_1", "94-mega_1",
"94-mega_1", "94-mega_1",
"94-mega_2", "94-mega_2",
@ -4755,11 +4758,10 @@
"1000b", "1000b",
"1001b", "1001b",
"1004b", "1004b",
"1007b-apex", "1007b-apex-build-Disabled",
"1007b-apex", "1007b-apex-build-Disabled",
"1007b-apex", "1008b-ultimate-mode-Disabled",
"1007b-apex", "1008b-ultimate-mode-Disabled",
"1008b-ultimate",
"127b-mega", "127b-mega",
"142b-mega", "142b-mega",
"150b-mega", "150b-mega",
@ -4920,24 +4922,24 @@
"932b", "932b",
"933b", "933b",
"934b", "934b",
"935_1b", "935_1b-Disabled",
"935_1b", "935_1b-Disabled",
"935_2b", "935_2b-Disabled",
"935_2b", "935_2b-Disabled",
"935_3b", "935_3b-Disabled",
"935_3b", "935_3b-Disabled",
"936_1b", "936_1b-Disabled",
"936_1b", "936_1b-Disabled",
"936_2b", "936_2b-Disabled",
"936_2b", "936_2b-Disabled",
"936_3b", "936_3b-Disabled",
"936_3b", "936_3b-Disabled",
"937_1b", "937_1b-Disabled",
"937_1b", "937_1b-Disabled",
"937_2b", "937_2b-Disabled",
"937_2b", "937_2b-Disabled",
"937_3b", "937_3b-Disabled",
"937_3b", "937_3b-Disabled",
"94b-mega", "94b-mega",
"948b", "948b",
"949b", "949b",

BIN
public/images/types_de.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -168,6 +168,8 @@ import { BattlerTagType } from "#enums/battler-tag-type";
import { FRIENDSHIP_GAIN_FROM_BATTLE } from "#app/data/balance/starters"; import { FRIENDSHIP_GAIN_FROM_BATTLE } from "#app/data/balance/starters";
import { StatusEffect } from "#enums/status-effect"; import { StatusEffect } from "#enums/status-effect";
import { initGlobalScene } from "#app/global-scene"; import { initGlobalScene } from "#app/global-scene";
import { ShowAbilityPhase } from "#app/phases/show-ability-phase";
import { HideAbilityPhase } from "#app/phases/hide-ability-phase";
export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1"; export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1";
@ -2904,6 +2906,21 @@ export default class BattleScene extends SceneBase {
} }
} }
/**
* Queues an ability bar flyout phase
* @param pokemon The pokemon who has the ability
* @param passive Whether the ability is a passive
* @param show Whether to show or hide the bar
*/
public queueAbilityDisplay(pokemon: Pokemon, passive: boolean, show: boolean): void {
this.unshiftPhase(
show
? new ShowAbilityPhase(pokemon.getBattlerIndex(), passive)
: new HideAbilityPhase(pokemon.getBattlerIndex(), passive),
);
this.clearPhaseQueueSplice();
}
/** /**
* Moves everything from nextCommandPhaseQueue to phaseQueue (keeping order) * Moves everything from nextCommandPhaseQueue to phaseQueue (keeping order)
*/ */
@ -3133,6 +3150,41 @@ export default class BattleScene extends SceneBase {
return false; return false;
} }
canTransferHeldItemModifier(itemModifier: PokemonHeldItemModifier, target: Pokemon, transferQuantity = 1): boolean {
const mod = itemModifier.clone() as PokemonHeldItemModifier;
const source = mod.pokemonId ? mod.getPokemon() : null;
const cancelled = new Utils.BooleanHolder(false);
if (source && source.isPlayer() !== target.isPlayer()) {
applyAbAttrs(BlockItemTheftAbAttr, source, cancelled);
}
if (cancelled.value) {
return false;
}
const matchingModifier = this.findModifier(
m => m instanceof PokemonHeldItemModifier && m.matchType(mod) && m.pokemonId === target.id,
target.isPlayer(),
) as PokemonHeldItemModifier;
if (matchingModifier) {
const maxStackCount = matchingModifier.getMaxStackCount();
if (matchingModifier.stackCount >= maxStackCount) {
return false;
}
const countTaken = Math.min(transferQuantity, mod.stackCount, maxStackCount - matchingModifier.stackCount);
mod.stackCount -= countTaken;
} else {
const countTaken = Math.min(transferQuantity, mod.stackCount);
mod.stackCount -= countTaken;
}
const removeOld = mod.stackCount === 0;
return !removeOld || !source || this.hasModifier(itemModifier, !source.isPlayer());
}
removePartyMemberModifiers(partyMemberIndex: number): Promise<void> { removePartyMemberModifiers(partyMemberIndex: number): Promise<void> {
return new Promise(resolve => { return new Promise(resolve => {
const pokemonId = this.getPlayerParty()[partyMemberIndex].id; const pokemonId = this.getPlayerParty()[partyMemberIndex].id;
@ -3290,6 +3342,11 @@ export default class BattleScene extends SceneBase {
}); });
} }
hasModifier(modifier: PersistentModifier, enemy = false): boolean {
const modifiers = !enemy ? this.modifiers : this.enemyModifiers;
return modifiers.indexOf(modifier) > -1;
}
/** /**
* Removes a currently owned item. If the item is stacked, the entire item stack * Removes a currently owned item. If the item is stacked, the entire item stack
* gets removed. This function does NOT apply in-battle effects, such as Unburden. * gets removed. This function does NOT apply in-battle effects, such as Unburden.

File diff suppressed because it is too large Load Diff

View File

@ -64,7 +64,7 @@ export abstract class ArenaTag {
} }
} }
onOverlap(_arena: Arena): void {} onOverlap(_arena: Arena, _source: Pokemon | null): void {}
lapse(_arena: Arena): boolean { lapse(_arena: Arena): boolean {
return this.turnCount < 1 || !!--this.turnCount; return this.turnCount < 1 || !!--this.turnCount;
@ -706,7 +706,7 @@ export class ArenaTrapTag extends ArenaTag {
this.maxLayers = maxLayers; this.maxLayers = maxLayers;
} }
onOverlap(arena: Arena): void { onOverlap(arena: Arena, _source: Pokemon | null): void {
if (this.layers < this.maxLayers) { if (this.layers < this.maxLayers) {
this.layers++; this.layers++;
@ -1427,13 +1427,9 @@ export class SuppressAbilitiesTag extends ArenaTag {
public override onAdd(_arena: Arena): void { public override onAdd(_arena: Arena): void {
const pokemon = this.getSourcePokemon(); const pokemon = this.getSourcePokemon();
if (pokemon) { if (pokemon) {
globalScene.queueMessage( this.playActivationMessage(pokemon);
i18next.t("arenaTag:neutralizingGasOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
);
for (const fieldPokemon of globalScene.getField()) { for (const fieldPokemon of globalScene.getField(true)) {
if (fieldPokemon && fieldPokemon.id !== pokemon.id) { if (fieldPokemon && fieldPokemon.id !== pokemon.id) {
[true, false].forEach(passive => applyOnLoseAbAttrs(fieldPokemon, passive)); [true, false].forEach(passive => applyOnLoseAbAttrs(fieldPokemon, passive));
} }
@ -1441,8 +1437,9 @@ export class SuppressAbilitiesTag extends ArenaTag {
} }
} }
public override onOverlap(_arena: Arena): void { public override onOverlap(_arena: Arena, source: Pokemon | null): void {
this.sourceCount++; this.sourceCount++;
this.playActivationMessage(source);
} }
public onSourceLeave(arena: Arena): void { public onSourceLeave(arena: Arena): void {
@ -1466,7 +1463,7 @@ export class SuppressAbilitiesTag extends ArenaTag {
globalScene.queueMessage(i18next.t("arenaTag:neutralizingGasOnRemove")); globalScene.queueMessage(i18next.t("arenaTag:neutralizingGasOnRemove"));
} }
for (const pokemon of globalScene.getField()) { for (const pokemon of globalScene.getField(true)) {
// There is only one pokemon with this attr on the field on removal, so its abilities are already active // There is only one pokemon with this attr on the field on removal, so its abilities are already active
if (pokemon && !pokemon.hasAbilityWithAttr(PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr, false)) { if (pokemon && !pokemon.hasAbilityWithAttr(PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr, false)) {
[true, false].forEach(passive => applyOnGainAbAttrs(pokemon, passive)); [true, false].forEach(passive => applyOnGainAbAttrs(pokemon, passive));
@ -1481,6 +1478,16 @@ export class SuppressAbilitiesTag extends ArenaTag {
public isBeingRemoved() { public isBeingRemoved() {
return this.beingRemoved; return this.beingRemoved;
} }
private playActivationMessage(pokemon: Pokemon | null) {
if (pokemon) {
globalScene.queueMessage(
i18next.t("arenaTag:neutralizingGasOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
);
}
}
} }
// TODO: swap `sourceMove` and `sourceId` and make `sourceMove` an optional parameter // TODO: swap `sourceMove` and `sourceId` and make `sourceMove` an optional parameter

View File

@ -1680,7 +1680,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.BOSS_ULTRA_RARE]: [] [BiomePoolTier.BOSS_ULTRA_RARE]: []
}, },
[Biome.METROPOLIS]: { [Biome.METROPOLIS]: {
[BiomePoolTier.COMMON]: [ TrainerType.CLERK, TrainerType.CYCLIST, TrainerType.OFFICER, TrainerType.WAITER ], [BiomePoolTier.COMMON]: [ TrainerType.CLERK, TrainerType.CYCLIST, TrainerType.OFFICER, TrainerType.WAITER, TrainerType.BEAUTY ],
[BiomePoolTier.UNCOMMON]: [ TrainerType.BREEDER, TrainerType.DEPOT_AGENT, TrainerType.GUITARIST ], [BiomePoolTier.UNCOMMON]: [ TrainerType.BREEDER, TrainerType.DEPOT_AGENT, TrainerType.GUITARIST ],
[BiomePoolTier.RARE]: [ TrainerType.ARTIST ], [BiomePoolTier.RARE]: [ TrainerType.ARTIST ],
[BiomePoolTier.SUPER_RARE]: [], [BiomePoolTier.SUPER_RARE]: [],
@ -1713,7 +1713,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.BOSS_ULTRA_RARE]: [] [BiomePoolTier.BOSS_ULTRA_RARE]: []
}, },
[Biome.SWAMP]: { [Biome.SWAMP]: {
[BiomePoolTier.COMMON]: [], [BiomePoolTier.COMMON]: [ TrainerType.PARASOL_LADY ],
[BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER ], [BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER ],
[BiomePoolTier.RARE]: [ TrainerType.BLACK_BELT ], [BiomePoolTier.RARE]: [ TrainerType.BLACK_BELT ],
[BiomePoolTier.SUPER_RARE]: [], [BiomePoolTier.SUPER_RARE]: [],
@ -1724,7 +1724,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.BOSS_ULTRA_RARE]: [] [BiomePoolTier.BOSS_ULTRA_RARE]: []
}, },
[Biome.BEACH]: { [Biome.BEACH]: {
[BiomePoolTier.COMMON]: [ TrainerType.FISHERMAN, TrainerType.PARASOL_LADY, TrainerType.SAILOR ], [BiomePoolTier.COMMON]: [ TrainerType.FISHERMAN, TrainerType.SAILOR ],
[BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER, TrainerType.BREEDER ], [BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER, TrainerType.BREEDER ],
[BiomePoolTier.RARE]: [ TrainerType.BLACK_BELT ], [BiomePoolTier.RARE]: [ TrainerType.BLACK_BELT ],
[BiomePoolTier.SUPER_RARE]: [], [BiomePoolTier.SUPER_RARE]: [],
@ -1735,7 +1735,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.BOSS_ULTRA_RARE]: [] [BiomePoolTier.BOSS_ULTRA_RARE]: []
}, },
[Biome.LAKE]: { [Biome.LAKE]: {
[BiomePoolTier.COMMON]: [ TrainerType.BREEDER, TrainerType.FISHERMAN ], [BiomePoolTier.COMMON]: [ TrainerType.BREEDER, TrainerType.FISHERMAN, TrainerType.PARASOL_LADY ],
[BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER ], [BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER ],
[BiomePoolTier.RARE]: [ TrainerType.BLACK_BELT ], [BiomePoolTier.RARE]: [ TrainerType.BLACK_BELT ],
[BiomePoolTier.SUPER_RARE]: [], [BiomePoolTier.SUPER_RARE]: [],
@ -1790,7 +1790,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.BOSS_ULTRA_RARE]: [] [BiomePoolTier.BOSS_ULTRA_RARE]: []
}, },
[Biome.DESERT]: { [Biome.DESERT]: {
[BiomePoolTier.COMMON]: [ TrainerType.SCIENTIST ], [BiomePoolTier.COMMON]: [ TrainerType.SCIENTIST, TrainerType.BACKPACKER ],
[BiomePoolTier.UNCOMMON]: [], [BiomePoolTier.UNCOMMON]: [],
[BiomePoolTier.RARE]: [], [BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [], [BiomePoolTier.SUPER_RARE]: [],
@ -1812,8 +1812,8 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.BOSS_ULTRA_RARE]: [] [BiomePoolTier.BOSS_ULTRA_RARE]: []
}, },
[Biome.MEADOW]: { [Biome.MEADOW]: {
[BiomePoolTier.COMMON]: [ TrainerType.PARASOL_LADY ], [BiomePoolTier.COMMON]: [ TrainerType.PARASOL_LADY, TrainerType.BEAUTY ],
[BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER, TrainerType.BREEDER ], [BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER, TrainerType.BREEDER, TrainerType.BAKER ],
[BiomePoolTier.RARE]: [], [BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [], [BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [], [BiomePoolTier.ULTRA_RARE]: [],
@ -1879,7 +1879,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
}, },
[Biome.RUINS]: { [Biome.RUINS]: {
[BiomePoolTier.COMMON]: [ TrainerType.PSYCHIC, TrainerType.SCIENTIST ], [BiomePoolTier.COMMON]: [ TrainerType.PSYCHIC, TrainerType.SCIENTIST ],
[BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER, TrainerType.BLACK_BELT ], [BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER, TrainerType.BLACK_BELT, TrainerType.HEX_MANIAC ],
[BiomePoolTier.RARE]: [], [BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [], [BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [], [BiomePoolTier.ULTRA_RARE]: [],
@ -7165,14 +7165,18 @@ export function initBiomes() {
[ Biome.MOUNTAIN, BiomePoolTier.COMMON ], [ Biome.MOUNTAIN, BiomePoolTier.COMMON ],
[ Biome.CAVE, BiomePoolTier.COMMON ], [ Biome.CAVE, BiomePoolTier.COMMON ],
[ Biome.BADLANDS, BiomePoolTier.COMMON ], [ Biome.BADLANDS, BiomePoolTier.COMMON ],
[ Biome.JUNGLE, BiomePoolTier.COMMON ] [ Biome.JUNGLE, BiomePoolTier.COMMON ],
[ Biome.DESERT, BiomePoolTier.COMMON ]
] ]
], ],
[ TrainerType.BAKER, [ [ TrainerType.BAKER, [
[ Biome.SLUM, BiomePoolTier.UNCOMMON ] [ Biome.SLUM, BiomePoolTier.UNCOMMON ],
[ Biome.MEADOW, BiomePoolTier.UNCOMMON ]
] ]
], ],
[ TrainerType.BEAUTY, [ [ TrainerType.BEAUTY, [
[ Biome.METROPOLIS, BiomePoolTier.COMMON ],
[ Biome.MEADOW, BiomePoolTier.COMMON ],
[ Biome.FAIRY_CAVE, BiomePoolTier.COMMON ] [ Biome.FAIRY_CAVE, BiomePoolTier.COMMON ]
]], ]],
[ TrainerType.BIKER, [ [ TrainerType.BIKER, [
@ -7247,7 +7251,8 @@ export function initBiomes() {
] ]
], ],
[ TrainerType.PARASOL_LADY, [ [ TrainerType.PARASOL_LADY, [
[ Biome.BEACH, BiomePoolTier.COMMON ], [ Biome.SWAMP, BiomePoolTier.COMMON ],
[ Biome.LAKE, BiomePoolTier.COMMON ],
[ Biome.MEADOW, BiomePoolTier.COMMON ] [ Biome.MEADOW, BiomePoolTier.COMMON ]
] ]
], ],
@ -7313,6 +7318,7 @@ export function initBiomes() {
] ]
], ],
[ TrainerType.HEX_MANIAC, [ [ TrainerType.HEX_MANIAC, [
[ Biome.RUINS, BiomePoolTier.UNCOMMON ],
[ Biome.GRAVEYARD, BiomePoolTier.UNCOMMON ] [ Biome.GRAVEYARD, BiomePoolTier.UNCOMMON ]
] ]
], ],

View File

@ -0,0 +1,162 @@
import { Species } from "#enums/species";
export type SignatureSpecies = {
[key in string]: (Species | Species[])[];
};
/*
* The signature species for each Gym Leader, Elite Four member, and Champion.
* The key is the trainer type, and the value is an array of Species or Species arrays.
* This is in a separate const so it can be accessed from other places and not just the trainerConfigs
*/
export const signatureSpecies: SignatureSpecies = {
// Gym Leaders- Kanto
BROCK: [Species.GEODUDE, Species.ONIX],
MISTY: [Species.STARYU, Species.PSYDUCK],
LT_SURGE: [Species.VOLTORB, Species.PIKACHU, Species.ELECTABUZZ],
ERIKA: [Species.ODDISH, Species.BELLSPROUT, Species.TANGELA, Species.HOPPIP],
JANINE: [Species.VENONAT, Species.SPINARAK, Species.ZUBAT],
SABRINA: [Species.ABRA, Species.MR_MIME, Species.ESPEON],
BLAINE: [Species.GROWLITHE, Species.PONYTA, Species.MAGMAR],
GIOVANNI: [Species.SANDILE, Species.MURKROW, Species.NIDORAN_M, Species.NIDORAN_F],
// Gym Leaders- Johto
FALKNER: [Species.PIDGEY, Species.HOOTHOOT, Species.DODUO],
BUGSY: [Species.SCYTHER, Species.HERACROSS, Species.SHUCKLE, Species.PINSIR],
WHITNEY: [Species.JIGGLYPUFF, Species.MILTANK, Species.AIPOM, Species.GIRAFARIG],
MORTY: [Species.GASTLY, Species.MISDREAVUS, Species.SABLEYE],
CHUCK: [Species.POLIWRATH, Species.MANKEY],
JASMINE: [Species.MAGNEMITE, Species.STEELIX],
PRYCE: [Species.SEEL, Species.SWINUB],
CLAIR: [Species.DRATINI, Species.HORSEA, Species.GYARADOS],
// Gym Leaders- Hoenn
ROXANNE: [Species.GEODUDE, Species.NOSEPASS],
BRAWLY: [Species.MACHOP, Species.MAKUHITA],
WATTSON: [Species.MAGNEMITE, Species.VOLTORB, Species.ELECTRIKE],
FLANNERY: [Species.SLUGMA, Species.TORKOAL, Species.NUMEL],
NORMAN: [Species.SLAKOTH, Species.SPINDA, Species.ZIGZAGOON, Species.KECLEON],
WINONA: [Species.SWABLU, Species.WINGULL, Species.TROPIUS, Species.SKARMORY],
TATE: [Species.SOLROCK, Species.NATU, Species.CHIMECHO, Species.GALLADE],
LIZA: [Species.LUNATONE, Species.SPOINK, Species.BALTOY, Species.GARDEVOIR],
JUAN: [Species.HORSEA, Species.BARBOACH, Species.SPHEAL, Species.RELICANTH],
// Gym Leaders- Sinnoh
ROARK: [Species.CRANIDOS, Species.LARVITAR, Species.GEODUDE],
GARDENIA: [Species.ROSELIA, Species.TANGELA, Species.TURTWIG],
MAYLENE: [Species.LUCARIO, Species.MEDITITE, Species.CHIMCHAR],
CRASHER_WAKE: [Species.BUIZEL, Species.WOOPER, Species.PIPLUP, Species.MAGIKARP],
FANTINA: [Species.MISDREAVUS, Species.DRIFLOON, Species.SPIRITOMB],
BYRON: [Species.SHIELDON, Species.BRONZOR, Species.AGGRON],
CANDICE: [Species.SNEASEL, Species.SNOVER, Species.SNORUNT],
VOLKNER: [Species.SHINX, Species.CHINCHOU, Species.ROTOM],
// Gym Leaders- Unova
CILAN: [Species.PANSAGE, Species.FOONGUS, Species.PETILIL],
CHILI: [Species.PANSEAR, Species.DARUMAKA, Species.NUMEL],
CRESS: [Species.PANPOUR, Species.TYMPOLE, Species.SLOWPOKE],
CHEREN: [Species.LILLIPUP, Species.MINCCINO, Species.PIDOVE],
LENORA: [Species.PATRAT, Species.DEERLING, Species.AUDINO],
ROXIE: [Species.VENIPEDE, Species.TRUBBISH, Species.SKORUPI],
BURGH: [Species.SEWADDLE, Species.SHELMET, Species.KARRABLAST],
ELESA: [Species.EMOLGA, Species.BLITZLE, Species.JOLTIK],
CLAY: [Species.DRILBUR, Species.SANDILE, Species.GOLETT],
SKYLA: [Species.DUCKLETT, Species.WOOBAT, Species.RUFFLET],
BRYCEN: [Species.CRYOGONAL, Species.VANILLITE, Species.CUBCHOO],
DRAYDEN: [Species.DRUDDIGON, Species.AXEW, Species.DEINO],
MARLON: [Species.WAILMER, Species.FRILLISH, Species.TIRTOUGA],
// Gym Leaders- Kalos
VIOLA: [Species.SURSKIT, Species.SCATTERBUG],
GRANT: [Species.AMAURA, Species.TYRUNT],
KORRINA: [Species.HAWLUCHA, Species.LUCARIO, Species.MIENFOO],
RAMOS: [Species.SKIDDO, Species.HOPPIP, Species.BELLSPROUT],
CLEMONT: [Species.HELIOPTILE, Species.MAGNEMITE, Species.EMOLGA],
VALERIE: [Species.SYLVEON, Species.MAWILE, Species.MR_MIME],
OLYMPIA: [Species.ESPURR, Species.SIGILYPH, Species.SLOWKING],
WULFRIC: [Species.BERGMITE, Species.SNOVER, Species.CRYOGONAL],
// Gym Leaders- Galar
MILO: [Species.GOSSIFLEUR, Species.APPLIN, Species.BOUNSWEET],
NESSA: [Species.CHEWTLE, Species.ARROKUDA, Species.WIMPOD],
KABU: [Species.SIZZLIPEDE, Species.VULPIX, Species.TORKOAL],
BEA: [Species.GALAR_FARFETCHD, Species.MACHOP, Species.CLOBBOPUS],
ALLISTER: [Species.GALAR_YAMASK, Species.GALAR_CORSOLA, Species.GASTLY],
OPAL: [Species.MILCERY, Species.TOGETIC, Species.GALAR_WEEZING],
BEDE: [Species.HATENNA, Species.GALAR_PONYTA, Species.GARDEVOIR],
GORDIE: [Species.ROLYCOLY, Species.STONJOURNER, Species.BINACLE],
MELONY: [Species.SNOM, Species.GALAR_DARUMAKA, Species.GALAR_MR_MIME],
PIERS: [Species.GALAR_ZIGZAGOON, Species.SCRAGGY, Species.INKAY],
MARNIE: [Species.IMPIDIMP, Species.PURRLOIN, Species.MORPEKO],
RAIHAN: [Species.DURALUDON, Species.TURTONATOR, Species.GOOMY],
// Gym Leaders- Paldea; First slot is Tera
KATY: [Species.TEDDIURSA, Species.NYMBLE, Species.TAROUNTULA], // Tera Bug Teddiursa
BRASSIUS: [Species.SUDOWOODO, Species.BRAMBLIN, Species.SMOLIV], // Tera Grass Sudowoodo
IONO: [Species.MISDREAVUS, Species.TADBULB, Species.WATTREL], // Tera Ghost Misdreavus
KOFU: [Species.CRABRAWLER, Species.VELUZA, Species.WIGLETT, Species.WINGULL], // Tera Water Crabrawler
LARRY: [Species.STARLY, Species.DUNSPARCE, Species.LECHONK, Species.KOMALA], // Tera Normal Starly
RYME: [Species.TOXEL, Species.GREAVARD, Species.SHUPPET, Species.MIMIKYU], // Tera Ghost Toxel
TULIP: [Species.FLABEBE, Species.FLITTLE, Species.RALTS, Species.GIRAFARIG], // Tera Psychic Flabebe
GRUSHA: [Species.SWABLU, Species.CETODDLE, Species.CUBCHOO, Species.ALOLA_VULPIX], // Tera Ice Swablu
// Elite Four- Kanto
LORELEI: [
Species.JYNX,
[Species.SLOWBRO, Species.GALAR_SLOWBRO],
Species.LAPRAS,
[Species.CLOYSTER, Species.ALOLA_SANDSLASH],
],
BRUNO: [Species.MACHAMP, Species.HITMONCHAN, Species.HITMONLEE, [Species.GOLEM, Species.ALOLA_GOLEM]],
AGATHA: [Species.GENGAR, [Species.ARBOK, Species.WEEZING], Species.CROBAT, Species.ALOLA_MAROWAK],
LANCE: [Species.DRAGONITE, Species.GYARADOS, Species.AERODACTYL, Species.ALOLA_EXEGGUTOR],
// Elite Four- Johto (Bruno included)
WILL: [Species.XATU, Species.JYNX, [Species.SLOWBRO, Species.SLOWKING], Species.EXEGGUTOR],
KOGA: [[Species.MUK, Species.WEEZING], [Species.VENOMOTH, Species.ARIADOS], Species.CROBAT, Species.TENTACRUEL],
KAREN: [Species.UMBREON, Species.HONCHKROW, Species.HOUNDOOM, Species.WEAVILE],
// Elite Four- Hoenn
SIDNEY: [
[Species.SHIFTRY, Species.CACTURNE],
[Species.SHARPEDO, Species.CRAWDAUNT],
Species.ABSOL,
Species.MIGHTYENA,
],
PHOEBE: [Species.SABLEYE, Species.DUSKNOIR, Species.BANETTE, [Species.DRIFBLIM, Species.MISMAGIUS]],
GLACIA: [Species.GLALIE, Species.WALREIN, Species.FROSLASS, Species.ABOMASNOW],
DRAKE: [Species.ALTARIA, Species.SALAMENCE, Species.FLYGON, Species.KINGDRA],
// Elite Four- Sinnoh
AARON: [[Species.SCIZOR, Species.KLEAVOR], Species.HERACROSS, [Species.VESPIQUEN, Species.YANMEGA], Species.DRAPION],
BERTHA: [Species.WHISCASH, Species.HIPPOWDON, Species.GLISCOR, Species.RHYPERIOR],
FLINT: [
[Species.RAPIDASH, Species.FLAREON],
Species.MAGMORTAR,
[Species.STEELIX, Species.LOPUNNY],
Species.INFERNAPE,
], // Tera Fire Steelix or Lopunny
LUCIAN: [Species.MR_MIME, Species.GALLADE, Species.BRONZONG, [Species.ALAKAZAM, Species.ESPEON]],
// Elite Four- Unova
SHAUNTAL: [Species.COFAGRIGUS, Species.CHANDELURE, Species.GOLURK, Species.JELLICENT],
MARSHAL: [Species.CONKELDURR, Species.MIENSHAO, Species.THROH, Species.SAWK],
GRIMSLEY: [Species.LIEPARD, Species.KINGAMBIT, Species.SCRAFTY, Species.KROOKODILE],
CAITLIN: [Species.MUSHARNA, Species.GOTHITELLE, Species.SIGILYPH, Species.REUNICLUS],
// Elite Four- Kalos
MALVA: [Species.PYROAR, Species.TORKOAL, Species.CHANDELURE, Species.TALONFLAME],
SIEBOLD: [Species.CLAWITZER, Species.GYARADOS, Species.BARBARACLE, Species.STARMIE],
WIKSTROM: [Species.KLEFKI, Species.PROBOPASS, Species.SCIZOR, Species.AEGISLASH],
DRASNA: [Species.DRAGALGE, Species.DRUDDIGON, Species.ALTARIA, Species.NOIVERN],
// Elite Four- Alola
HALA: [Species.HARIYAMA, Species.BEWEAR, Species.CRABOMINABLE, [Species.POLIWRATH, Species.ANNIHILAPE]],
MOLAYNE: [Species.KLEFKI, Species.MAGNEZONE, Species.METAGROSS, Species.ALOLA_DUGTRIO],
OLIVIA: [Species.RELICANTH, Species.CARBINK, Species.ALOLA_GOLEM, Species.LYCANROC],
ACEROLA: [[Species.BANETTE, Species.DRIFBLIM], Species.MIMIKYU, Species.DHELMISE, Species.PALOSSAND],
KAHILI: [[Species.BRAVIARY, Species.MANDIBUZZ], Species.HAWLUCHA, Species.ORICORIO, Species.TOUCANNON],
// Elite Four- Galar
MARNIE_ELITE: [Species.MORPEKO, Species.LIEPARD, [Species.TOXICROAK, Species.SCRAFTY], Species.GRIMMSNARL],
NESSA_ELITE: [Species.GOLISOPOD, [Species.QUAGSIRE, Species.PELIPPER], Species.TOXAPEX, Species.DREDNAW],
BEA_ELITE: [Species.HAWLUCHA, [Species.GRAPPLOCT, Species.SIRFETCHD], Species.FALINKS, Species.MACHAMP],
ALLISTER_ELITE: [Species.DUSKNOIR, [Species.POLTEAGEIST, Species.RUNERIGUS], Species.CURSOLA, Species.GENGAR],
RAIHAN_ELITE: [Species.GOODRA, [Species.TORKOAL, Species.TURTONATOR], Species.FLYGON, Species.ARCHALUDON],
// Elite Four- Paldea
RIKA: [Species.CLODSIRE, [Species.DUGTRIO, Species.DONPHAN], Species.CAMERUPT, Species.WHISCASH], // Tera Ground Clodsire
POPPY: [Species.TINKATON, Species.BRONZONG, Species.CORVIKNIGHT, Species.COPPERAJAH], // Tera Steel Tinkaton
LARRY_ELITE: [Species.FLAMIGO, Species.STARAPTOR, [Species.ALTARIA, Species.TROPIUS], Species.ORICORIO], // Tera Flying Flamigo; random Oricorio
HASSEL: [Species.BAXCALIBUR, [Species.FLAPPLE, Species.APPLETUN], Species.DRAGALGE, Species.NOIVERN], // Tera Dragon Baxcalibur
// Elite Four- BBL
CRISPIN: [Species.BLAZIKEN, Species.MAGMORTAR, [Species.CAMERUPT, Species.TALONFLAME], Species.ROTOM], // Tera Fire Blaziken; Heat Rotom
AMARYS: [Species.METAGROSS, Species.SCIZOR, Species.EMPOLEON, Species.SKARMORY], // Tera Steel Metagross
LACEY: [Species.EXCADRILL, Species.PRIMARINA, [Species.WHIMSICOTT, Species.ALCREMIE], Species.GRANBULL], // Tera Fairy Excadrill
DRAYTON: [Species.ARCHALUDON, Species.DRAGONITE, Species.HAXORUS, Species.SCEPTILE], // Tera Dragon Archaludon
};

View File

@ -1922,10 +1922,6 @@ export class SlowStartTag extends AbilityBattlerTag {
i18next.t("battlerTags:slowStartOnAdd", { i18next.t("battlerTags:slowStartOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}), }),
null,
false,
null,
true,
); );
} }

View File

@ -5542,6 +5542,31 @@ export class LeechSeedAttr extends AddBattlerTagAttr {
} }
} }
/**
* Adds the appropriate battler tag for Smack Down and Thousand arrows
* @extends AddBattlerTagAttr
*/
export class FallDownAttr extends AddBattlerTagAttr {
constructor() {
super(BattlerTagType.IGNORE_FLYING, false, false, 1, 1, true);
}
/**
* Adds Grounded Tag to the target and checks if fallDown message should be displayed
* @param user the {@linkcode Pokemon} using the move
* @param target the {@linkcode Pokemon} targeted by the move
* @param move the {@linkcode Move} invoking this effect
* @param args n/a
* @returns `true` if the effect successfully applies; `false` otherwise
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if (!target.isGrounded()) {
globalScene.queueMessage(i18next.t("moveTriggers:fallDown", { targetPokemonName: getPokemonNameWithAffix(target) }));
}
return super.apply(user, target, move, args);
}
}
/** /**
* Adds the appropriate battler tag for Gulp Missile when Surf or Dive is used. * Adds the appropriate battler tag for Gulp Missile when Surf or Dive is used.
* @extends MoveEffectAttr * @extends MoveEffectAttr
@ -9646,7 +9671,7 @@ export function initMoves() {
.target(MoveTarget.BOTH_SIDES) .target(MoveTarget.BOTH_SIDES)
.unimplemented(), .unimplemented(),
new AttackMove(Moves.SMACK_DOWN, PokemonType.ROCK, MoveCategory.PHYSICAL, 50, 100, 15, 100, 0, 5) new AttackMove(Moves.SMACK_DOWN, PokemonType.ROCK, MoveCategory.PHYSICAL, 50, 100, 15, 100, 0, 5)
.attr(AddBattlerTagAttr, BattlerTagType.IGNORE_FLYING, false, false, 1, 1, true) .attr(FallDownAttr)
.attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED) .attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED)
.attr(RemoveBattlerTagAttr, [ BattlerTagType.FLYING, BattlerTagType.FLOATING, BattlerTagType.TELEKINESIS ]) .attr(RemoveBattlerTagAttr, [ BattlerTagType.FLYING, BattlerTagType.FLOATING, BattlerTagType.TELEKINESIS ])
.attr(HitsTagAttr, BattlerTagType.FLYING) .attr(HitsTagAttr, BattlerTagType.FLYING)
@ -10097,7 +10122,7 @@ export function initMoves() {
.triageMove(), .triageMove(),
new AttackMove(Moves.THOUSAND_ARROWS, PokemonType.GROUND, MoveCategory.PHYSICAL, 90, 100, 10, -1, 0, 6) new AttackMove(Moves.THOUSAND_ARROWS, PokemonType.GROUND, MoveCategory.PHYSICAL, 90, 100, 10, -1, 0, 6)
.attr(NeutralDamageAgainstFlyingTypeMultiplierAttr) .attr(NeutralDamageAgainstFlyingTypeMultiplierAttr)
.attr(AddBattlerTagAttr, BattlerTagType.IGNORE_FLYING, false, false, 1, 1, true) .attr(FallDownAttr)
.attr(HitsTagAttr, BattlerTagType.FLYING) .attr(HitsTagAttr, BattlerTagType.FLYING)
.attr(HitsTagAttr, BattlerTagType.FLOATING) .attr(HitsTagAttr, BattlerTagType.FLOATING)
.attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED) .attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED)

View File

@ -2987,11 +2987,11 @@ export function initSpecies() {
new PokemonSpecies(Species.VAROOM, 9, false, false, false, "Single-Cyl Pokémon", PokemonType.STEEL, PokemonType.POISON, 1, 35, Abilities.OVERCOAT, Abilities.NONE, Abilities.SLOW_START, 300, 45, 70, 63, 30, 45, 47, 190, 50, 60, GrowthRate.MEDIUM_FAST, 50, false), new PokemonSpecies(Species.VAROOM, 9, false, false, false, "Single-Cyl Pokémon", PokemonType.STEEL, PokemonType.POISON, 1, 35, Abilities.OVERCOAT, Abilities.NONE, Abilities.SLOW_START, 300, 45, 70, 63, 30, 45, 47, 190, 50, 60, GrowthRate.MEDIUM_FAST, 50, false),
new PokemonSpecies(Species.REVAVROOM, 9, false, false, false, "Multi-Cyl Pokémon", PokemonType.STEEL, PokemonType.POISON, 1.8, 120, Abilities.OVERCOAT, Abilities.NONE, Abilities.FILTER, 500, 80, 119, 90, 54, 67, 90, 75, 50, 175, GrowthRate.MEDIUM_FAST, 50, false, false, new PokemonSpecies(Species.REVAVROOM, 9, false, false, false, "Multi-Cyl Pokémon", PokemonType.STEEL, PokemonType.POISON, 1.8, 120, Abilities.OVERCOAT, Abilities.NONE, Abilities.FILTER, 500, 80, 119, 90, 54, 67, 90, 75, 50, 175, GrowthRate.MEDIUM_FAST, 50, false, false,
new PokemonForm("Normal", "", PokemonType.STEEL, PokemonType.POISON, 1.8, 120, Abilities.OVERCOAT, Abilities.NONE, Abilities.FILTER, 500, 80, 119, 90, 54, 67, 90, 75, 50, 175, false, null, true), new PokemonForm("Normal", "", PokemonType.STEEL, PokemonType.POISON, 1.8, 120, Abilities.OVERCOAT, Abilities.NONE, Abilities.FILTER, 500, 80, 119, 90, 54, 67, 90, 75, 50, 175, false, null, true),
new PokemonForm("Segin Starmobile", "segin-starmobile", PokemonType.STEEL, PokemonType.DARK, 1.8, 240, Abilities.INTIMIDATE, Abilities.NONE, Abilities.INTIMIDATE, 600, 110, 129, 100, 77, 79, 105, 75, 50, 175), new PokemonForm("Segin Starmobile", "segin-starmobile", PokemonType.STEEL, PokemonType.DARK, 1.8, 240, Abilities.INTIMIDATE, Abilities.NONE, Abilities.INTIMIDATE, 600, 110, 129, 100, 77, 79, 105, 75, 50, 175, false, null, false, true),
new PokemonForm("Schedar Starmobile", "schedar-starmobile", PokemonType.STEEL, PokemonType.FIRE, 1.8, 240, Abilities.SPEED_BOOST, Abilities.NONE, Abilities.SPEED_BOOST, 600, 110, 129, 100, 77, 79, 105, 75, 50, 175), new PokemonForm("Schedar Starmobile", "schedar-starmobile", PokemonType.STEEL, PokemonType.FIRE, 1.8, 240, Abilities.SPEED_BOOST, Abilities.NONE, Abilities.SPEED_BOOST, 600, 110, 129, 100, 77, 79, 105, 75, 50, 175, false, null, false, true),
new PokemonForm("Navi Starmobile", "navi-starmobile", PokemonType.STEEL, PokemonType.POISON, 1.8, 240, Abilities.TOXIC_DEBRIS, Abilities.NONE, Abilities.TOXIC_DEBRIS, 600, 110, 129, 100, 77, 79, 105, 75, 50, 175), new PokemonForm("Navi Starmobile", "navi-starmobile", PokemonType.STEEL, PokemonType.POISON, 1.8, 240, Abilities.TOXIC_DEBRIS, Abilities.NONE, Abilities.TOXIC_DEBRIS, 600, 110, 129, 100, 77, 79, 105, 75, 50, 175, false, null, false, true),
new PokemonForm("Ruchbah Starmobile", "ruchbah-starmobile", PokemonType.STEEL, PokemonType.FAIRY, 1.8, 240, Abilities.MISTY_SURGE, Abilities.NONE, Abilities.MISTY_SURGE, 600, 110, 129, 100, 77, 79, 105, 75, 50, 175), new PokemonForm("Ruchbah Starmobile", "ruchbah-starmobile", PokemonType.STEEL, PokemonType.FAIRY, 1.8, 240, Abilities.MISTY_SURGE, Abilities.NONE, Abilities.MISTY_SURGE, 600, 110, 129, 100, 77, 79, 105, 75, 50, 175, false, null, false, true),
new PokemonForm("Caph Starmobile", "caph-starmobile", PokemonType.STEEL, PokemonType.FIGHTING, 1.8, 240, Abilities.STAMINA, Abilities.NONE, Abilities.STAMINA, 600, 110, 129, 100, 77, 79, 105, 75, 50, 175), new PokemonForm("Caph Starmobile", "caph-starmobile", PokemonType.STEEL, PokemonType.FIGHTING, 1.8, 240, Abilities.STAMINA, Abilities.NONE, Abilities.STAMINA, 600, 110, 129, 100, 77, 79, 105, 75, 50, 175, false, null, false, true),
), ),
new PokemonSpecies(Species.CYCLIZAR, 9, false, false, false, "Mount Pokémon", PokemonType.DRAGON, PokemonType.NORMAL, 1.6, 63, Abilities.SHED_SKIN, Abilities.NONE, Abilities.REGENERATOR, 501, 70, 95, 65, 85, 65, 121, 190, 50, 175, GrowthRate.MEDIUM_SLOW, 50, false), new PokemonSpecies(Species.CYCLIZAR, 9, false, false, false, "Mount Pokémon", PokemonType.DRAGON, PokemonType.NORMAL, 1.6, 63, Abilities.SHED_SKIN, Abilities.NONE, Abilities.REGENERATOR, 501, 70, 95, 65, 85, 65, 121, 190, 50, 175, GrowthRate.MEDIUM_SLOW, 50, false),
new PokemonSpecies(Species.ORTHWORM, 9, false, false, false, "Earthworm Pokémon", PokemonType.STEEL, null, 2.5, 310, Abilities.EARTH_EATER, Abilities.NONE, Abilities.SAND_VEIL, 480, 70, 85, 145, 60, 55, 65, 25, 50, 240, GrowthRate.SLOW, 50, false), new PokemonSpecies(Species.ORTHWORM, 9, false, false, false, "Earthworm Pokémon", PokemonType.STEEL, null, 2.5, 310, Abilities.EARTH_EATER, Abilities.NONE, Abilities.SAND_VEIL, 480, 70, 85, 145, 60, 55, 65, 25, 50, 240, GrowthRate.SLOW, 50, false),

View File

@ -22,6 +22,8 @@ import { PartyMemberStrength } from "#enums/party-member-strength";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import { TrainerType } from "#enums/trainer-type"; import { TrainerType } from "#enums/trainer-type";
import { Gender } from "#app/data/gender"; import { Gender } from "#app/data/gender";
import { signatureSpecies } from "./balance/signature-species";
import { Abilities } from "#enums/abilities";
/** Minimum BST for Pokemon generated onto the Elite Four's teams */ /** Minimum BST for Pokemon generated onto the Elite Four's teams */
const ELITE_FOUR_MINIMUM_BST = 460; const ELITE_FOUR_MINIMUM_BST = 460;
@ -1744,148 +1746,6 @@ function getSpeciesFilterRandomPartyMemberFunc(
}; };
} }
type SignatureSpecies = {
[key in string]: (Species | Species[])[];
};
/*
* The signature species for each Gym Leader, Elite Four member, and Champion.
* The key is the trainer type, and the value is an array of Species or Species arrays.
* This is in a separate const so it can be accessed from other places and not just the trainerConfigs
*/
export const signatureSpecies: SignatureSpecies = {
BROCK: [Species.GEODUDE, Species.ONIX],
MISTY: [Species.STARYU, Species.PSYDUCK],
LT_SURGE: [Species.VOLTORB, Species.PIKACHU, Species.ELECTABUZZ],
ERIKA: [Species.ODDISH, Species.BELLSPROUT, Species.TANGELA, Species.HOPPIP],
JANINE: [Species.VENONAT, Species.SPINARAK, Species.ZUBAT],
SABRINA: [Species.ABRA, Species.MR_MIME, Species.ESPEON],
BLAINE: [Species.GROWLITHE, Species.PONYTA, Species.MAGMAR],
GIOVANNI: [Species.SANDILE, Species.MURKROW, Species.NIDORAN_M, Species.NIDORAN_F],
FALKNER: [Species.PIDGEY, Species.HOOTHOOT, Species.DODUO],
BUGSY: [Species.SCYTHER, Species.HERACROSS, Species.SHUCKLE, Species.PINSIR],
WHITNEY: [Species.JIGGLYPUFF, Species.MILTANK, Species.AIPOM, Species.GIRAFARIG],
MORTY: [Species.GASTLY, Species.MISDREAVUS, Species.SABLEYE],
CHUCK: [Species.POLIWRATH, Species.MANKEY],
JASMINE: [Species.MAGNEMITE, Species.STEELIX],
PRYCE: [Species.SEEL, Species.SWINUB],
CLAIR: [Species.DRATINI, Species.HORSEA, Species.GYARADOS],
ROXANNE: [Species.GEODUDE, Species.NOSEPASS],
BRAWLY: [Species.MACHOP, Species.MAKUHITA],
WATTSON: [Species.MAGNEMITE, Species.VOLTORB, Species.ELECTRIKE],
FLANNERY: [Species.SLUGMA, Species.TORKOAL, Species.NUMEL],
NORMAN: [Species.SLAKOTH, Species.SPINDA, Species.ZIGZAGOON, Species.KECLEON],
WINONA: [Species.SWABLU, Species.WINGULL, Species.TROPIUS, Species.SKARMORY],
TATE: [Species.SOLROCK, Species.NATU, Species.CHIMECHO, Species.GALLADE],
LIZA: [Species.LUNATONE, Species.SPOINK, Species.BALTOY, Species.GARDEVOIR],
JUAN: [Species.HORSEA, Species.BARBOACH, Species.SPHEAL, Species.RELICANTH],
ROARK: [Species.CRANIDOS, Species.LARVITAR, Species.GEODUDE],
GARDENIA: [Species.ROSELIA, Species.TANGELA, Species.TURTWIG],
MAYLENE: [Species.LUCARIO, Species.MEDITITE, Species.CHIMCHAR],
CRASHER_WAKE: [Species.BUIZEL, Species.WOOPER, Species.PIPLUP, Species.MAGIKARP],
FANTINA: [Species.MISDREAVUS, Species.DRIFLOON, Species.SPIRITOMB],
BYRON: [Species.SHIELDON, Species.BRONZOR, Species.AGGRON],
CANDICE: [Species.SNEASEL, Species.SNOVER, Species.SNORUNT],
VOLKNER: [Species.SHINX, Species.CHINCHOU, Species.ROTOM],
CILAN: [Species.PANSAGE, Species.FOONGUS, Species.PETILIL],
CHILI: [Species.PANSEAR, Species.DARUMAKA, Species.NUMEL],
CRESS: [Species.PANPOUR, Species.TYMPOLE, Species.SLOWPOKE],
CHEREN: [Species.LILLIPUP, Species.MINCCINO, Species.PIDOVE],
LENORA: [Species.PATRAT, Species.DEERLING, Species.AUDINO],
ROXIE: [Species.VENIPEDE, Species.TRUBBISH, Species.SKORUPI],
BURGH: [Species.SEWADDLE, Species.SHELMET, Species.KARRABLAST],
ELESA: [Species.EMOLGA, Species.BLITZLE, Species.JOLTIK],
CLAY: [Species.DRILBUR, Species.SANDILE, Species.GOLETT],
SKYLA: [Species.DUCKLETT, Species.WOOBAT, Species.RUFFLET],
BRYCEN: [Species.CRYOGONAL, Species.VANILLITE, Species.CUBCHOO],
DRAYDEN: [Species.DRUDDIGON, Species.AXEW, Species.DEINO],
MARLON: [Species.WAILMER, Species.FRILLISH, Species.TIRTOUGA],
VIOLA: [Species.SURSKIT, Species.SCATTERBUG],
GRANT: [Species.AMAURA, Species.TYRUNT],
KORRINA: [Species.HAWLUCHA, Species.LUCARIO, Species.MIENFOO],
RAMOS: [Species.SKIDDO, Species.HOPPIP, Species.BELLSPROUT],
CLEMONT: [Species.HELIOPTILE, Species.MAGNEMITE, Species.EMOLGA],
VALERIE: [Species.SYLVEON, Species.MAWILE, Species.MR_MIME],
OLYMPIA: [Species.ESPURR, Species.SIGILYPH, Species.SLOWKING],
WULFRIC: [Species.BERGMITE, Species.SNOVER, Species.CRYOGONAL],
MILO: [Species.GOSSIFLEUR, Species.APPLIN, Species.BOUNSWEET],
NESSA: [Species.CHEWTLE, Species.ARROKUDA, Species.WIMPOD],
KABU: [Species.SIZZLIPEDE, Species.VULPIX, Species.TORKOAL],
BEA: [Species.GALAR_FARFETCHD, Species.MACHOP, Species.CLOBBOPUS],
ALLISTER: [Species.GALAR_YAMASK, Species.GALAR_CORSOLA, Species.GASTLY],
OPAL: [Species.MILCERY, Species.TOGETIC, Species.GALAR_WEEZING],
BEDE: [Species.HATENNA, Species.GALAR_PONYTA, Species.GARDEVOIR],
GORDIE: [Species.ROLYCOLY, Species.STONJOURNER, Species.BINACLE],
MELONY: [Species.SNOM, Species.GALAR_DARUMAKA, Species.GALAR_MR_MIME],
PIERS: [Species.GALAR_ZIGZAGOON, Species.SCRAGGY, Species.INKAY],
MARNIE: [Species.IMPIDIMP, Species.PURRLOIN, Species.MORPEKO],
RAIHAN: [Species.DURALUDON, Species.TURTONATOR, Species.GOOMY],
KATY: [Species.TEDDIURSA, Species.NYMBLE, Species.TAROUNTULA], // Tera Bug Teddiursa
BRASSIUS: [Species.SUDOWOODO, Species.BRAMBLIN, Species.SMOLIV], // Tera Grass Sudowoodo
IONO: [Species.MISDREAVUS, Species.TADBULB, Species.WATTREL], // Tera Ghost Misdreavus
KOFU: [Species.CRABRAWLER, Species.VELUZA, Species.WIGLETT, Species.WINGULL], // Tera Water Crabrawler
LARRY: [Species.STARLY, Species.DUNSPARCE, Species.LECHONK, Species.KOMALA], // Tera Normal Starly
RYME: [Species.TOXEL, Species.GREAVARD, Species.SHUPPET, Species.MIMIKYU], // Tera Ghost Toxel
TULIP: [Species.FLABEBE, Species.FLITTLE, Species.RALTS, Species.GIRAFARIG], // Tera Psychic Flabebe
GRUSHA: [Species.SWABLU, Species.CETODDLE, Species.CUBCHOO, Species.ALOLA_VULPIX], // Tera Ice Swablu
LORELEI: [
Species.JYNX,
[Species.SLOWBRO, Species.GALAR_SLOWBRO],
Species.LAPRAS,
[Species.CLOYSTER, Species.ALOLA_SANDSLASH],
],
BRUNO: [Species.MACHAMP, Species.HITMONCHAN, Species.HITMONLEE, [Species.GOLEM, Species.ALOLA_GOLEM]],
AGATHA: [Species.GENGAR, [Species.ARBOK, Species.WEEZING], Species.CROBAT, Species.ALOLA_MAROWAK],
LANCE: [Species.DRAGONITE, Species.GYARADOS, Species.AERODACTYL, Species.ALOLA_EXEGGUTOR],
WILL: [Species.XATU, Species.JYNX, [Species.SLOWBRO, Species.SLOWKING], Species.EXEGGUTOR],
KOGA: [[Species.MUK, Species.WEEZING], [Species.VENOMOTH, Species.ARIADOS], Species.CROBAT, Species.TENTACRUEL],
KAREN: [Species.UMBREON, Species.HONCHKROW, Species.HOUNDOOM, Species.WEAVILE],
SIDNEY: [
[Species.SHIFTRY, Species.CACTURNE],
[Species.SHARPEDO, Species.CRAWDAUNT],
Species.ABSOL,
Species.MIGHTYENA,
],
PHOEBE: [Species.SABLEYE, Species.DUSKNOIR, Species.BANETTE, [Species.DRIFBLIM, Species.MISMAGIUS]],
GLACIA: [Species.GLALIE, Species.WALREIN, Species.FROSLASS, Species.ABOMASNOW],
DRAKE: [Species.ALTARIA, Species.SALAMENCE, Species.FLYGON, Species.KINGDRA],
AARON: [[Species.SCIZOR, Species.KLEAVOR], Species.HERACROSS, [Species.VESPIQUEN, Species.YANMEGA], Species.DRAPION],
BERTHA: [Species.WHISCASH, Species.HIPPOWDON, Species.GLISCOR, Species.RHYPERIOR],
FLINT: [
[Species.RAPIDASH, Species.FLAREON],
Species.MAGMORTAR,
[Species.STEELIX, Species.LOPUNNY],
Species.INFERNAPE,
], // Tera Fire Steelix or Lopunny
LUCIAN: [Species.MR_MIME, Species.GALLADE, Species.BRONZONG, [Species.ALAKAZAM, Species.ESPEON]],
SHAUNTAL: [Species.COFAGRIGUS, Species.CHANDELURE, Species.GOLURK, Species.JELLICENT],
MARSHAL: [Species.CONKELDURR, Species.MIENSHAO, Species.THROH, Species.SAWK],
GRIMSLEY: [Species.LIEPARD, Species.KINGAMBIT, Species.SCRAFTY, Species.KROOKODILE],
CAITLIN: [Species.MUSHARNA, Species.GOTHITELLE, Species.SIGILYPH, Species.REUNICLUS],
MALVA: [Species.PYROAR, Species.TORKOAL, Species.CHANDELURE, Species.TALONFLAME],
SIEBOLD: [Species.CLAWITZER, Species.GYARADOS, Species.BARBARACLE, Species.STARMIE],
WIKSTROM: [Species.KLEFKI, Species.PROBOPASS, Species.SCIZOR, Species.AEGISLASH],
DRASNA: [Species.DRAGALGE, Species.DRUDDIGON, Species.ALTARIA, Species.NOIVERN],
HALA: [Species.HARIYAMA, Species.BEWEAR, Species.CRABOMINABLE, [Species.POLIWRATH, Species.ANNIHILAPE]],
MOLAYNE: [Species.KLEFKI, Species.MAGNEZONE, Species.METAGROSS, Species.ALOLA_DUGTRIO],
OLIVIA: [Species.RELICANTH, Species.CARBINK, Species.ALOLA_GOLEM, Species.LYCANROC],
ACEROLA: [[Species.BANETTE, Species.DRIFBLIM], Species.MIMIKYU, Species.DHELMISE, Species.PALOSSAND],
KAHILI: [[Species.BRAVIARY, Species.MANDIBUZZ], Species.HAWLUCHA, Species.ORICORIO, Species.TOUCANNON],
MARNIE_ELITE: [Species.MORPEKO, Species.LIEPARD, [Species.TOXICROAK, Species.SCRAFTY], Species.GRIMMSNARL],
NESSA_ELITE: [Species.GOLISOPOD, [Species.QUAGSIRE, Species.PELIPPER], Species.TOXAPEX, Species.DREDNAW],
BEA_ELITE: [Species.HAWLUCHA, [Species.GRAPPLOCT, Species.SIRFETCHD], Species.FALINKS, Species.MACHAMP],
ALLISTER_ELITE: [Species.DUSKNOIR, [Species.POLTEAGEIST, Species.RUNERIGUS], Species.CURSOLA, Species.GENGAR],
RAIHAN_ELITE: [Species.GOODRA, [Species.TORKOAL, Species.TURTONATOR], Species.FLYGON, Species.ARCHALUDON],
RIKA: [Species.CLODSIRE, [Species.DUGTRIO, Species.DONPHAN], Species.CAMERUPT, Species.WHISCASH], // Tera Ground Clodsire
POPPY: [Species.TINKATON, Species.BRONZONG, Species.CORVIKNIGHT, Species.COPPERAJAH], // Tera Steel Tinkaton
LARRY_ELITE: [Species.FLAMIGO, Species.STARAPTOR, [Species.ALTARIA, Species.TROPIUS], Species.ORICORIO], // Tera Flying Flamigo; random Oricorio
HASSEL: [Species.BAXCALIBUR, [Species.FLAPPLE, Species.APPLETUN], Species.DRAGALGE, Species.NOIVERN], // Tera Dragon Baxcalibur
CRISPIN: [Species.BLAZIKEN, Species.MAGMORTAR, [Species.CAMERUPT, Species.TALONFLAME], Species.ROTOM], // Tera Fire Blaziken; Heat Rotom
AMARYS: [Species.METAGROSS, Species.SCIZOR, Species.EMPOLEON, Species.SKARMORY], // Tera Steel Metagross
LACEY: [Species.EXCADRILL, Species.PRIMARINA, [Species.WHIMSICOTT, Species.ALCREMIE], Species.GRANBULL], // Tera Fairy Excadrill
DRAYTON: [Species.ARCHALUDON, Species.DRAGONITE, Species.HAXORUS, Species.SCEPTILE], // Tera Dragon Archaludon
};
export const trainerConfigs: TrainerConfigs = { export const trainerConfigs: TrainerConfigs = {
[TrainerType.UNKNOWN]: new TrainerConfig(0).setHasGenders(), [TrainerType.UNKNOWN]: new TrainerConfig(0).setHasGenders(),
[TrainerType.ACE_TRAINER]: new TrainerConfig(++t) [TrainerType.ACE_TRAINER]: new TrainerConfig(++t)
@ -1952,12 +1812,92 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerType.BAKER]: new TrainerConfig(++t) [TrainerType.BAKER]: new TrainerConfig(++t)
.setEncounterBgm(TrainerType.CLERK) .setEncounterBgm(TrainerType.CLERK)
.setMoneyMultiplier(1.35) .setMoneyMultiplier(1.35)
.setSpeciesFilter(s => s.isOfType(PokemonType.GRASS) || s.isOfType(PokemonType.FIRE)), .setSpeciesFilter(
[TrainerType.BEAUTY]: new TrainerConfig(++t).setMoneyMultiplier(1.55).setEncounterBgm(TrainerType.PARASOL_LADY), s =>
[s.ability1, s.ability2, s.abilityHidden].some(
a =>
!!a &&
[
Abilities.WHITE_SMOKE,
Abilities.GLUTTONY,
Abilities.HONEY_GATHER,
Abilities.HARVEST,
Abilities.CHEEK_POUCH,
Abilities.SWEET_VEIL,
Abilities.RIPEN,
Abilities.PURIFYING_SALT,
Abilities.WELL_BAKED_BODY,
Abilities.SUPERSWEET_SYRUP,
Abilities.HOSPITALITY,
].includes(a),
) ||
s
.getLevelMoves()
.some(plm =>
[Moves.SOFT_BOILED, Moves.SPORE, Moves.MILK_DRINK, Moves.OVERHEAT, Moves.TEATIME].includes(plm[1]),
),
), // Mons with baking related abilities or who learn Overheat, Teatime, Milk Drink, Spore, or Soft-Boiled by level
[TrainerType.BEAUTY]: new TrainerConfig(++t)
.setMoneyMultiplier(1.55)
.setEncounterBgm(TrainerType.PARASOL_LADY)
.setPartyTemplates(
trainerPartyTemplates.TWO_AVG_SAME_ONE_AVG,
trainerPartyTemplates.TWO_AVG_SAME_ONE_STRONG,
trainerPartyTemplates.THREE_AVG_SAME,
trainerPartyTemplates.THREE_AVG,
trainerPartyTemplates.FOUR_WEAK,
trainerPartyTemplates.ONE_STRONG,
)
.setSpeciesPools({
[TrainerPoolTier.COMMON]: [
Species.MEOWTH,
Species.GOLDEEN,
Species.MAREEP,
Species.MARILL,
Species.SKITTY,
Species.GLAMEOW,
Species.PURRLOIN,
],
[TrainerPoolTier.UNCOMMON]: [
Species.SMOOCHUM,
Species.ROSELIA,
Species.LUVDISC,
Species.BLITZLE,
Species.SEWADDLE,
Species.PETILIL,
Species.MINCCINO,
Species.GOTHITA,
Species.SPRITZEE,
Species.FLITTLE,
],
[TrainerPoolTier.RARE]: [
Species.FEEBAS,
Species.FURFROU,
Species.SALANDIT,
Species.BRUXISH,
Species.HATENNA,
Species.SNOM,
Species.ALOLA_VULPIX,
],
[TrainerPoolTier.SUPER_RARE]: [Species.CLAMPERL, Species.AMAURA, Species.SYLVEON, Species.GOOMY, Species.POPPLIO],
}),
[TrainerType.BIKER]: new TrainerConfig(++t) [TrainerType.BIKER]: new TrainerConfig(++t)
.setMoneyMultiplier(1.4) .setMoneyMultiplier(1.4)
.setEncounterBgm(TrainerType.ROUGHNECK) .setEncounterBgm(TrainerType.ROUGHNECK)
.setSpeciesFilter(s => s.isOfType(PokemonType.POISON)), .setSpeciesPools({
[TrainerPoolTier.COMMON]: [Species.EKANS, Species.KOFFING, Species.CROAGUNK, Species.VENIPEDE, Species.SCRAGGY],
[TrainerPoolTier.UNCOMMON]: [
Species.GRIMER,
Species.VOLTORB,
Species.TEDDIURSA,
Species.MAGBY,
Species.SKORUPI,
Species.SANDILE,
Species.PAWNIARD,
Species.SHROODLE,
],
[TrainerPoolTier.RARE]: [Species.VAROOM, Species.CYCLIZAR],
}),
[TrainerType.BLACK_BELT]: new TrainerConfig(++t) [TrainerType.BLACK_BELT]: new TrainerConfig(++t)
.setHasGenders("Battle Girl", TrainerType.PSYCHIC) .setHasGenders("Battle Girl", TrainerType.PSYCHIC)
.setHasDouble("Crush Kin") .setHasDouble("Crush Kin")
@ -2059,9 +1999,15 @@ export const trainerConfigs: TrainerConfigs = {
.setEncounterBgm(TrainerType.CYCLIST) .setEncounterBgm(TrainerType.CYCLIST)
.setPartyTemplates(trainerPartyTemplates.TWO_WEAK, trainerPartyTemplates.ONE_AVG) .setPartyTemplates(trainerPartyTemplates.TWO_WEAK, trainerPartyTemplates.ONE_AVG)
.setSpeciesPools({ .setSpeciesPools({
[TrainerPoolTier.COMMON]: [Species.PICHU, Species.STARLY, Species.TAILLOW, Species.BOLTUND], [TrainerPoolTier.COMMON]: [Species.DODUO, Species.PICHU, Species.TAILLOW, Species.STARLY, Species.PONYTA],
[TrainerPoolTier.UNCOMMON]: [Species.DODUO, Species.ELECTRIKE, Species.BLITZLE, Species.WATTREL], [TrainerPoolTier.UNCOMMON]: [
[TrainerPoolTier.RARE]: [Species.YANMA, Species.NINJASK, Species.WHIRLIPEDE, Species.EMOLGA], Species.ELECTRIKE,
Species.SHINX,
Species.BLITZLE,
Species.DUCKLETT,
Species.WATTREL,
],
[TrainerPoolTier.RARE]: [Species.YANMA, Species.NINJASK, Species.WHIRLIPEDE, Species.EMOLGA, Species.SKIDDO],
[TrainerPoolTier.SUPER_RARE]: [Species.ACCELGOR, Species.DREEPY], [TrainerPoolTier.SUPER_RARE]: [Species.ACCELGOR, Species.DREEPY],
}), }),
[TrainerType.DANCER]: new TrainerConfig(++t) [TrainerType.DANCER]: new TrainerConfig(++t)
@ -2077,7 +2023,7 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerPoolTier.COMMON]: [Species.RALTS, Species.SPOINK, Species.LOTAD, Species.BUDEW], [TrainerPoolTier.COMMON]: [Species.RALTS, Species.SPOINK, Species.LOTAD, Species.BUDEW],
[TrainerPoolTier.UNCOMMON]: [Species.SPINDA, Species.SWABLU, Species.MARACTUS], [TrainerPoolTier.UNCOMMON]: [Species.SPINDA, Species.SWABLU, Species.MARACTUS],
[TrainerPoolTier.RARE]: [Species.BELLOSSOM, Species.HITMONTOP, Species.MIME_JR, Species.ORICORIO], [TrainerPoolTier.RARE]: [Species.BELLOSSOM, Species.HITMONTOP, Species.MIME_JR, Species.ORICORIO],
[TrainerPoolTier.SUPER_RARE]: [Species.POPPLIO], [TrainerPoolTier.SUPER_RARE]: [Species.QUAXLY, Species.JANGMO_O],
}), }),
[TrainerType.DEPOT_AGENT]: new TrainerConfig(++t).setMoneyMultiplier(1.45).setEncounterBgm(TrainerType.CLERK), [TrainerType.DEPOT_AGENT]: new TrainerConfig(++t).setMoneyMultiplier(1.45).setEncounterBgm(TrainerType.CLERK),
[TrainerType.DOCTOR]: new TrainerConfig(++t) [TrainerType.DOCTOR]: new TrainerConfig(++t)
@ -2215,7 +2161,7 @@ export const trainerConfigs: TrainerConfigs = {
trainerPartyTemplates.THREE_AVG, trainerPartyTemplates.THREE_AVG,
trainerPartyTemplates.TWO_STRONG, trainerPartyTemplates.TWO_STRONG,
) )
.setSpeciesFilter(s => s.isOfType(PokemonType.GHOST)), .setSpeciesFilter(s => s.isOfType(PokemonType.GHOST) || s.isOfType(PokemonType.PSYCHIC)),
[TrainerType.NURSERY_AIDE]: new TrainerConfig(++t).setMoneyMultiplier(1.3).setEncounterBgm("lass"), [TrainerType.NURSERY_AIDE]: new TrainerConfig(++t).setMoneyMultiplier(1.3).setEncounterBgm("lass"),
[TrainerType.OFFICER]: new TrainerConfig(++t) [TrainerType.OFFICER]: new TrainerConfig(++t)
.setMoneyMultiplier(1.55) .setMoneyMultiplier(1.55)
@ -2245,7 +2191,28 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerType.PARASOL_LADY]: new TrainerConfig(++t) [TrainerType.PARASOL_LADY]: new TrainerConfig(++t)
.setMoneyMultiplier(1.55) .setMoneyMultiplier(1.55)
.setEncounterBgm(TrainerType.PARASOL_LADY) .setEncounterBgm(TrainerType.PARASOL_LADY)
.setSpeciesFilter(s => s.isOfType(PokemonType.WATER)), .setPartyTemplates(
trainerPartyTemplates.TWO_AVG_SAME_ONE_AVG,
trainerPartyTemplates.TWO_AVG_SAME_ONE_STRONG,
trainerPartyTemplates.TWO_AVG,
trainerPartyTemplates.FOUR_WEAK,
trainerPartyTemplates.ONE_STRONG,
)
.setSpeciesFilter(
s =>
[s.ability1, s.ability2, s.abilityHidden].some(
a =>
!!a &&
[
Abilities.DRIZZLE,
Abilities.SWIFT_SWIM,
Abilities.HYDRATION,
Abilities.RAIN_DISH,
Abilities.DRY_SKIN,
Abilities.WIND_POWER,
].includes(a),
) || s.getLevelMoves().some(plm => plm[1] === Moves.RAIN_DANCE),
), // Mons with rain abilities or who learn Rain Dance by level
[TrainerType.PILOT]: new TrainerConfig(++t) [TrainerType.PILOT]: new TrainerConfig(++t)
.setEncounterBgm(TrainerType.CLERK) .setEncounterBgm(TrainerType.CLERK)
.setSpeciesFilter(s => tmSpecies[Moves.FLY].indexOf(s.speciesId) > -1), .setSpeciesFilter(s => tmSpecies[Moves.FLY].indexOf(s.speciesId) > -1),

View File

@ -303,6 +303,11 @@ export class Arena {
return true; return true;
} }
/** Returns weather or not the weather can be changed to {@linkcode weather} */
canSetWeather(weather: WeatherType): boolean {
return !(this.weather?.weatherType === (weather || undefined));
}
/** /**
* Attempts to set a new weather to the battle * Attempts to set a new weather to the battle
* @param weather {@linkcode WeatherType} new {@linkcode WeatherType} to set * @param weather {@linkcode WeatherType} new {@linkcode WeatherType} to set
@ -314,7 +319,7 @@ export class Arena {
return this.trySetWeatherOverride(Overrides.WEATHER_OVERRIDE); return this.trySetWeatherOverride(Overrides.WEATHER_OVERRIDE);
} }
if (this.weather?.weatherType === (weather || undefined)) { if (!this.canSetWeather(weather)) {
return false; return false;
} }
@ -388,8 +393,13 @@ export class Arena {
}); });
} }
/** Returns whether or not the terrain can be set to {@linkcode terrain} */
canSetTerrain(terrain: TerrainType): boolean {
return !(this.terrain?.terrainType === (terrain || undefined));
}
trySetTerrain(terrain: TerrainType, hasPokemonSource: boolean, ignoreAnim = false): boolean { trySetTerrain(terrain: TerrainType, hasPokemonSource: boolean, ignoreAnim = false): boolean {
if (this.terrain?.terrainType === (terrain || undefined)) { if (!this.canSetTerrain(terrain)) {
return false; return false;
} }
@ -663,7 +673,7 @@ export class Arena {
): boolean { ): boolean {
const existingTag = this.getTagOnSide(tagType, side); const existingTag = this.getTagOnSide(tagType, side);
if (existingTag) { if (existingTag) {
existingTag.onOverlap(this); existingTag.onOverlap(this, globalScene.getPokemonById(sourceId));
if (existingTag instanceof ArenaTrapTag) { if (existingTag instanceof ArenaTrapTag) {
const { tagType, side, turnCount, layers, maxLayers } = existingTag as ArenaTrapTag; const { tagType, side, turnCount, layers, maxLayers } = existingTag as ArenaTrapTag;

View File

@ -6916,10 +6916,10 @@ export class EnemyPokemon extends Pokemon {
if ( if (
speciesId in Overrides.OPP_FORM_OVERRIDES && speciesId in Overrides.OPP_FORM_OVERRIDES &&
Overrides.OPP_FORM_OVERRIDES[speciesId] && !isNullOrUndefined(Overrides.OPP_FORM_OVERRIDES[speciesId]) &&
this.species.forms[Overrides.OPP_FORM_OVERRIDES[speciesId]] this.species.forms[Overrides.OPP_FORM_OVERRIDES[speciesId]]
) { ) {
this.formIndex = Overrides.OPP_FORM_OVERRIDES[speciesId] ?? 0; this.formIndex = Overrides.OPP_FORM_OVERRIDES[speciesId];
} }
if (!dataSource) { if (!dataSource) {

View File

@ -9,7 +9,6 @@ import {
TrainerSlot, TrainerSlot,
trainerConfigs, trainerConfigs,
trainerPartyTemplates, trainerPartyTemplates,
signatureSpecies,
TeraAIMode, TeraAIMode,
} from "#app/data/trainer-config"; } from "#app/data/trainer-config";
import type { EnemyPokemon } from "#app/field/pokemon"; import type { EnemyPokemon } from "#app/field/pokemon";
@ -22,6 +21,7 @@ import i18next from "i18next";
import { PartyMemberStrength } from "#enums/party-member-strength"; import { PartyMemberStrength } from "#enums/party-member-strength";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import { TrainerType } from "#enums/trainer-type"; import { TrainerType } from "#enums/trainer-type";
import { signatureSpecies } from "#app/data/balance/signature-species";
export enum TrainerVariant { export enum TrainerVariant {
DEFAULT, DEFAULT,

View File

@ -79,6 +79,7 @@ export class LoadingScene extends SceneBase {
this.loadImage("icon_owned", "ui"); this.loadImage("icon_owned", "ui");
this.loadImage("icon_egg_move", "ui"); this.loadImage("icon_egg_move", "ui");
this.loadImage("ability_bar_left", "ui"); this.loadImage("ability_bar_left", "ui");
this.loadImage("ability_bar_right", "ui");
this.loadImage("bgm_bar", "ui"); this.loadImage("bgm_bar", "ui");
this.loadImage("party_exp_bar", "ui"); this.loadImage("party_exp_bar", "ui");
this.loadImage("achv_bar", "ui"); this.loadImage("achv_bar", "ui");

View File

@ -3566,10 +3566,10 @@ function getNewModifierTypeOption(
} else if (upgradeCount === undefined && player) { } else if (upgradeCount === undefined && player) {
upgradeCount = 0; upgradeCount = 0;
if (tier < ModifierTier.MASTER && allowLuckUpgrades) { if (tier < ModifierTier.MASTER && allowLuckUpgrades) {
const partyShinyCount = party.filter(p => p.isShiny() && !p.isFainted()).length; const partyLuckValue = getPartyLuckValue(party);
const upgradeOdds = Math.floor(32 / ((partyShinyCount + 2) / 2)); const upgradeOdds = Math.floor(128 / ((partyLuckValue + 4) / 4));
while (modifierPool.hasOwnProperty(tier + upgradeCount + 1) && modifierPool[tier + upgradeCount + 1].length) { while (modifierPool.hasOwnProperty(tier + upgradeCount + 1) && modifierPool[tier + upgradeCount + 1].length) {
if (!randSeedInt(upgradeOdds)) { if (randSeedInt(upgradeOdds) < 4) {
upgradeCount++; upgradeCount++;
} else { } else {
break; break;

View File

@ -1,5 +1,3 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/consistent-type-imports */
import { type PokeballCounts } from "#app/battle-scene"; import { type PokeballCounts } from "#app/battle-scene";
import { EvolutionItem } from "#app/data/balance/pokemon-evolutions"; import { EvolutionItem } from "#app/data/balance/pokemon-evolutions";
import { Gender } from "#app/data/gender"; import { Gender } from "#app/data/gender";

View File

@ -1,11 +1,7 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
export class Phase { export class Phase {
start() { start() {}
if (globalScene.abilityBar.shown) {
globalScene.abilityBar.resetAutoHideTimer();
}
}
end() { end() {
globalScene.shiftPhase(); globalScene.shiftPhase();

View File

@ -0,0 +1,27 @@
import { globalScene } from "#app/global-scene";
import type { BattlerIndex } from "#app/battle";
import { PokemonPhase } from "./pokemon-phase";
export class HideAbilityPhase extends PokemonPhase {
private passive: boolean;
constructor(battlerIndex: BattlerIndex, passive = false) {
super(battlerIndex);
this.passive = passive;
}
start() {
super.start();
const pokemon = this.getPokemon();
if (pokemon) {
globalScene.abilityBar.hide().then(() => {
this.end();
});
} else {
this.end();
}
}
}

View File

@ -28,17 +28,28 @@ export class MessagePhase extends Phase {
super.start(); super.start();
if (this.text.indexOf("$") > -1) { if (this.text.indexOf("$") > -1) {
const pokename: string[] = [];
const repname = [ "#POKEMON1", "#POKEMON2" ];
for (let p = 0; p < globalScene.getPlayerField().length; p++) {
pokename.push(globalScene.getPlayerField()[p].getNameToRender());
this.text = this.text.split(pokename[p]).join(repname[p]);
}
const pageIndex = this.text.indexOf("$"); const pageIndex = this.text.indexOf("$");
globalScene.unshiftPhase( for (let p = 0; p < globalScene.getPlayerField().length; p++) {
new MessagePhase( this.text = this.text.split(repname[p]).join(pokename[p]);
this.text.slice(pageIndex + 1), }
this.callbackDelay, if (pageIndex !== -1) {
this.prompt, globalScene.unshiftPhase(
this.promptDelay, new MessagePhase(
this.speaker, this.text.slice(pageIndex + 1),
), this.callbackDelay,
); this.prompt,
this.text = this.text.slice(0, pageIndex).trim(); this.promptDelay,
this.speaker,
),
);
this.text = this.text.slice(0, pageIndex).trim();
}
} }
if (this.speaker) { if (this.speaker) {
@ -61,12 +72,4 @@ export class MessagePhase extends Phase {
); );
} }
} }
end() {
if (globalScene.abilityBar.shown) {
globalScene.abilityBar.hide();
}
super.end();
}
} }

View File

@ -504,7 +504,7 @@ export class MovePhase extends BattlePhase {
globalScene globalScene
.getField(true) .getField(true)
.filter(p => p !== this.pokemon) .filter(p => p !== this.pokemon)
.forEach(p => applyAbAttrs(RedirectMoveAbAttr, p, null, false, this.move.moveId, redirectTarget)); .forEach(p => applyAbAttrs(RedirectMoveAbAttr, p, null, false, this.move.moveId, redirectTarget, this.pokemon));
/** `true` if an Ability is responsible for redirecting the move to another target; `false` otherwise */ /** `true` if an Ability is responsible for redirecting the move to another target; `false` otherwise */
let redirectedByAbility = currentTarget !== redirectTarget.value; let redirectedByAbility = currentTarget !== redirectTarget.value;

View File

@ -5,6 +5,8 @@ import { EFFECTIVE_STATS, BATTLE_STATS } from "#enums/stat";
import { PokemonMove } from "#app/field/pokemon"; import { PokemonMove } from "#app/field/pokemon";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { PokemonPhase } from "./pokemon-phase"; import { PokemonPhase } from "./pokemon-phase";
import { getPokemonNameWithAffix } from "#app/messages";
import i18next from "i18next";
/** /**
* Transforms a Pokemon into another Pokemon on the field. * Transforms a Pokemon into another Pokemon on the field.
@ -62,6 +64,13 @@ export class PokemonTransformPhase extends PokemonPhase {
globalScene.playSound("battle_anims/PRSFX- Transform"); globalScene.playSound("battle_anims/PRSFX- Transform");
} }
globalScene.queueMessage(
i18next.t("abilityTriggers:postSummonTransform", {
pokemonNameWithAffix: getPokemonNameWithAffix(user),
targetName: target.name,
}),
);
promises.push( promises.push(
user.loadAssets(false).then(() => { user.loadAssets(false).then(() => {
user.playAnim(); user.playAnim();

View File

@ -53,6 +53,7 @@ export class SelectStarterPhase extends Phase {
let starterFormIndex = Math.min(starterProps.formIndex, Math.max(starter.species.forms.length - 1, 0)); let starterFormIndex = Math.min(starterProps.formIndex, Math.max(starter.species.forms.length - 1, 0));
if ( if (
starter.species.speciesId in Overrides.STARTER_FORM_OVERRIDES && starter.species.speciesId in Overrides.STARTER_FORM_OVERRIDES &&
!Utils.isNullOrUndefined(Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]) &&
starter.species.forms[Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]!] starter.species.forms[Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]!]
) { ) {
starterFormIndex = Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]!; starterFormIndex = Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]!;

View File

@ -1,36 +1,60 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import type { BattlerIndex } from "#app/battle"; import type { BattlerIndex } from "#app/battle";
import { PokemonPhase } from "./pokemon-phase"; import { PokemonPhase } from "./pokemon-phase";
import { getPokemonNameWithAffix } from "#app/messages";
import { HideAbilityPhase } from "#app/phases/hide-ability-phase";
export class ShowAbilityPhase extends PokemonPhase { export class ShowAbilityPhase extends PokemonPhase {
private passive: boolean; private passive: boolean;
private pokemonName: string;
private abilityName: string;
private pokemonOnField: boolean;
constructor(battlerIndex: BattlerIndex, passive = false) { constructor(battlerIndex: BattlerIndex, passive = false) {
super(battlerIndex); super(battlerIndex);
this.passive = passive; this.passive = passive;
const pokemon = this.getPokemon();
if (pokemon) {
// Set these now as the pokemon object may change before the queued phase is run
this.pokemonName = getPokemonNameWithAffix(pokemon);
this.abilityName = (passive ? this.getPokemon().getPassiveAbility() : this.getPokemon().getAbility()).name;
this.pokemonOnField = true;
} else {
this.pokemonOnField = false;
}
} }
start() { start() {
super.start(); super.start();
if (!this.pokemonOnField || !this.getPokemon()) {
return this.end();
}
// If the bar is already out, hide it before showing the new one
if (globalScene.abilityBar.isVisible()) {
globalScene.unshiftPhase(new HideAbilityPhase(this.battlerIndex, this.passive));
globalScene.unshiftPhase(new ShowAbilityPhase(this.battlerIndex, this.passive));
return this.end();
}
const pokemon = this.getPokemon(); const pokemon = this.getPokemon();
if (pokemon) { if (!pokemon.isPlayer()) {
if (!pokemon.isPlayer()) { /** If its an enemy pokemon, list it as last enemy to use ability or move */
/** If its an enemy pokemon, list it as last enemy to use ability or move */ globalScene.currentBattle.lastEnemyInvolved = pokemon.getBattlerIndex() % 2;
globalScene.currentBattle.lastEnemyInvolved = pokemon.getBattlerIndex() % 2; } else {
} else { globalScene.currentBattle.lastPlayerInvolved = pokemon.getBattlerIndex() % 2;
globalScene.currentBattle.lastPlayerInvolved = pokemon.getBattlerIndex() % 2; }
}
globalScene.abilityBar.showAbility(pokemon, this.passive);
globalScene.abilityBar.showAbility(this.pokemonName, this.abilityName, this.passive, this.player).then(() => {
if (pokemon?.battleData) { if (pokemon?.battleData) {
pokemon.battleData.abilityRevealed = true; pokemon.battleData.abilityRevealed = true;
} }
}
this.end(); this.end();
});
} }
} }

View File

@ -1,31 +1,33 @@
import { getPokemonNameWithAffix } from "#app/messages";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import type Pokemon from "../field/pokemon";
import { TextStyle, addTextObject } from "./text"; import { TextStyle, addTextObject } from "./text";
import i18next from "i18next"; import i18next from "i18next";
const hiddenX = -118; const barWidth = 118;
const shownX = 0; const screenLeft = 0;
const baseY = -116; const baseY = -116;
export default class AbilityBar extends Phaser.GameObjects.Container { export default class AbilityBar extends Phaser.GameObjects.Container {
private bg: Phaser.GameObjects.Image; private abilityBars: Phaser.GameObjects.Image[];
private abilityBarText: Phaser.GameObjects.Text; private abilityBarText: Phaser.GameObjects.Text;
private player: boolean;
private tween: Phaser.Tweens.Tween | null; private screenRight: number; // hold screenRight in case size changes between show and hide
private autoHideTimer: NodeJS.Timeout | null; private shown: boolean;
public shown: boolean;
constructor() { constructor() {
super(globalScene, hiddenX, baseY); super(globalScene, barWidth, baseY);
this.abilityBars = [];
this.player = true;
this.shown = false;
} }
setup(): void { setup(): void {
this.bg = globalScene.add.image(0, 0, "ability_bar_left"); for (const key of ["ability_bar_right", "ability_bar_left"]) {
this.bg.setOrigin(0, 0); const bar = globalScene.add.image(0, 0, key);
bar.setOrigin(0, 0);
this.add(this.bg); bar.setVisible(false);
this.add(bar);
this.abilityBars.push(bar);
}
this.abilityBarText = addTextObject(15, 3, "", TextStyle.MESSAGE, { this.abilityBarText = addTextObject(15, 3, "", TextStyle.MESSAGE, {
fontSize: "72px", fontSize: "72px",
@ -33,72 +35,80 @@ export default class AbilityBar extends Phaser.GameObjects.Container {
this.abilityBarText.setOrigin(0, 0); this.abilityBarText.setOrigin(0, 0);
this.abilityBarText.setWordWrapWidth(600, true); this.abilityBarText.setWordWrapWidth(600, true);
this.add(this.abilityBarText); this.add(this.abilityBarText);
this.bringToTop(this.abilityBarText);
this.setVisible(false); this.setVisible(false);
this.shown = false; this.setX(-barWidth); // start hidden (right edge of bar at x=0)
} }
showAbility(pokemon: Pokemon, passive = false): void { public override setVisible(value: boolean): this {
this.abilityBarText.setText( this.abilityBars[+this.player].setVisible(value);
`${i18next.t("fightUiHandler:abilityFlyInText", { pokemonName: getPokemonNameWithAffix(pokemon), passive: passive ? i18next.t("fightUiHandler:passive") : "", abilityName: !passive ? pokemon.getAbility().name : pokemon.getPassiveAbility().name })}`, this.shown = value;
); return this;
}
if (this.shown) { public async startTween(config: any, text?: string): Promise<void> {
return; this.setVisible(true);
if (text) {
this.abilityBarText.setText(text);
} }
return new Promise(resolve => {
globalScene.tweens.add({
...config,
onComplete: () => {
if (config.onComplete) {
config.onComplete();
}
resolve();
},
});
});
}
public async showAbility(pokemonName: string, abilityName: string, passive = false, player = true): Promise<void> {
const text = `${i18next.t("fightUiHandler:abilityFlyInText", { pokemonName: pokemonName, passive: passive ? i18next.t("fightUiHandler:passive") : "", abilityName: abilityName })}`;
this.screenRight = globalScene.scaledCanvas.width;
if (player !== this.player) {
// Move the bar if it has changed from the player to enemy side (or vice versa)
this.setX(player ? -barWidth : this.screenRight);
this.player = player;
}
globalScene.fieldUI.bringToTop(this); globalScene.fieldUI.bringToTop(this);
this.y = baseY + (globalScene.currentBattle.double ? 14 : 0); let y = baseY;
this.tween = globalScene.tweens.add({ if (this.player) {
targets: this, y += globalScene.currentBattle.double ? 14 : 0;
x: shownX, } else {
duration: 500, y -= globalScene.currentBattle.double ? 28 : 14;
ease: "Sine.easeOut", }
onComplete: () => {
this.tween = null;
this.resetAutoHideTimer();
},
});
this.setVisible(true); this.setY(y);
this.shown = true;
return this.startTween(
{
targets: this,
x: this.player ? screenLeft : this.screenRight - barWidth,
duration: 500,
ease: "Sine.easeOut",
hold: 1000,
},
text,
);
} }
hide(): void { public async hide(): Promise<void> {
if (!this.shown) { return this.startTween({
return;
}
if (this.autoHideTimer) {
clearInterval(this.autoHideTimer);
}
if (this.tween) {
this.tween.stop();
}
this.tween = globalScene.tweens.add({
targets: this, targets: this,
x: -91, x: this.player ? -barWidth : this.screenRight,
duration: 500, duration: 200,
ease: "Sine.easeIn", ease: "Sine.easeIn",
onComplete: () => { onComplete: () => {
this.tween = null;
this.setVisible(false); this.setVisible(false);
}, },
}); });
this.shown = false;
} }
resetAutoHideTimer(): void { public isVisible(): boolean {
if (this.autoHideTimer) { return this.shown;
clearInterval(this.autoHideTimer);
}
this.autoHideTimer = setTimeout(() => {
this.hide();
this.autoHideTimer = null;
}, 2500);
} }
} }

View File

@ -76,6 +76,12 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler {
const fadeMap = new Map<number, number>(); const fadeMap = new Map<number, number>();
const actionPattern = /@(c|d|s|f)\{(.*?)\}/; const actionPattern = /@(c|d|s|f)\{(.*?)\}/;
let actionMatch: RegExpExecArray | null; let actionMatch: RegExpExecArray | null;
const pokename: string[] = [];
const repname = [ "#POKEMON1", "#POKEMON2" ];
for (let p = 0; p < globalScene.getPlayerField().length; p++) {
pokename.push(globalScene.getPlayerField()[p].getNameToRender());
text = text.split(pokename[p]).join(repname[p]);
}
while ((actionMatch = actionPattern.exec(text))) { while ((actionMatch = actionPattern.exec(text))) {
switch (actionMatch[1]) { switch (actionMatch[1]) {
case "c": case "c":
@ -94,6 +100,9 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler {
text = text.slice(0, actionMatch.index) + text.slice(actionMatch.index + actionMatch[2].length + 4); text = text.slice(0, actionMatch.index) + text.slice(actionMatch.index + actionMatch[2].length + 4);
} }
for (let p = 0; p < globalScene.getPlayerField().length; p++) {
text = text.split(repname[p]).join(pokename[p]);
}
if (text) { if (text) {
// Predetermine overflow line breaks to avoid words breaking while displaying // Predetermine overflow line breaks to avoid words breaking while displaying
const textWords = text.split(" "); const textWords = text.split(" ");

View File

@ -1742,36 +1742,26 @@ export default class PokedexUiHandler extends MessageUiHandler {
container.icon.setTint(0); container.icon.setTint(0);
} }
if (data.eggMove1) { const pairs: [boolean | undefined, Phaser.GameObjects.Image][] = [
container.eggMove1Icon.setVisible(true); [data.eggMove1, container.eggMove1Icon],
} else { [data.eggMove2, container.eggMove2Icon],
container.eggMove1Icon.setVisible(false); [data.tmMove1, container.tmMove1Icon],
} [data.tmMove2, container.tmMove2Icon],
if (data.eggMove2) { [data.passive1, container.passive1Icon],
container.eggMove2Icon.setVisible(true); [data.passive2, container.passive2Icon],
} else { ];
container.eggMove2Icon.setVisible(false);
} pairs.forEach(([unlocked, icon]) => {
if (data.tmMove1) { if (unlocked) {
container.tmMove1Icon.setVisible(true); icon.setVisible(true);
} else { icon.clearTint();
container.tmMove1Icon.setVisible(false); } else if (unlocked === false) {
} icon.setVisible(true);
if (data.tmMove2) { icon.setTint(0x808080);
container.tmMove2Icon.setVisible(true); } else {
} else { icon.setVisible(false);
container.tmMove2Icon.setVisible(false); }
} });
if (data.passive1) {
container.passive1Icon.setVisible(true);
} else {
container.passive1Icon.setVisible(false);
}
if (data.passive2) {
container.passive2Icon.setVisible(true);
} else {
container.passive2Icon.setVisible(false);
}
if (this.showDecorations) { if (this.showDecorations) {
if (this.pokerusSpecies.includes(data.species)) { if (this.pokerusSpecies.includes(data.species)) {

View File

@ -328,17 +328,28 @@ export default class UI extends Phaser.GameObjects.Container {
prompt?: boolean | null, prompt?: boolean | null,
promptDelay?: number | null, promptDelay?: number | null,
): void { ): void {
const pokename: string[] = [];
const repname = [ "#POKEMON1", "#POKEMON2" ];
for (let p = 0; p < globalScene.getPlayerField().length; p++) {
pokename.push(globalScene.getPlayerField()[p].getNameToRender());
text = text.split(pokename[p]).join(repname[p]);
}
if (prompt && text.indexOf("$") > -1) { if (prompt && text.indexOf("$") > -1) {
const messagePages = text.split(/\$/g).map(m => m.trim()); const messagePages = text.split(/\$/g).map(m => m.trim());
// biome-ignore lint/complexity/useOptionalChain: optional chain would change this to be null instead of undefined. // biome-ignore lint/complexity/useOptionalChain: optional chain would change this to be null instead of undefined.
let showMessageAndCallback = () => callback && callback(); let showMessageAndCallback = () => callback && callback();
for (let p = messagePages.length - 1; p >= 0; p--) { for (let p = messagePages.length - 1; p >= 0; p--) {
const originalFunc = showMessageAndCallback; const originalFunc = showMessageAndCallback;
messagePages[p] = messagePages[p].split(repname[0]).join(pokename[0]);
messagePages[p] = messagePages[p].split(repname[1]).join(pokename[1]);
showMessageAndCallback = () => this.showText(messagePages[p], null, originalFunc, null, true); showMessageAndCallback = () => this.showText(messagePages[p], null, originalFunc, null, true);
} }
showMessageAndCallback(); showMessageAndCallback();
} else { } else {
const handler = this.getHandler(); const handler = this.getHandler();
for (let p = 0; p < globalScene.getPlayerField().length; p++) {
text = text.split(repname[p]).join(pokename[p]);
}
if (handler instanceof MessageUiHandler) { if (handler instanceof MessageUiHandler) {
(handler as MessageUiHandler).showText(text, delay, callback, callbackDelay, prompt, promptDelay); (handler as MessageUiHandler).showText(text, delay, callback, callbackDelay, prompt, promptDelay);
} else { } else {

View File

@ -0,0 +1,115 @@
import { BattlerIndex } from "#app/battle";
import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import { Stat } from "#enums/stat";
import GameManager from "#test/testUtils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
describe("Abilities - Lightningrod", () => {
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, Moves.SHOCK_WAVE ])
.ability(Abilities.BALL_FETCH)
.battleType("double")
.disableCrits()
.enemySpecies(Species.MAGIKARP)
.enemyAbility(Abilities.BALL_FETCH)
.enemyMoveset(Moves.SPLASH);
});
it("should redirect electric type moves", async () => {
await game.classicMode.startBattle([ Species.FEEBAS, Species.MAGIKARP ]);
const enemy1 = game.scene.getEnemyField()[0];
const enemy2 = game.scene.getEnemyField()[1];
enemy2.summonData.ability = Abilities.LIGHTNING_ROD;
game.move.select(Moves.SHOCK_WAVE, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER_2);
await game.phaseInterceptor.to("BerryPhase");
expect(enemy1.isFullHp()).toBe(true);
});
it("should not redirect non-electric type moves", async () => {
game.override.moveset([ Moves.SPLASH, Moves.AERIAL_ACE ]);
await game.classicMode.startBattle([ Species.FEEBAS, Species.MAGIKARP ]);
const enemy1 = game.scene.getEnemyField()[0];
const enemy2 = game.scene.getEnemyField()[1];
enemy2.summonData.ability = Abilities.LIGHTNING_ROD;
game.move.select(Moves.AERIAL_ACE, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER_2);
await game.phaseInterceptor.to("BerryPhase");
expect(enemy1.isFullHp()).toBe(false);
});
it("should boost the user's spatk without damaging", async () => {
await game.classicMode.startBattle([ Species.FEEBAS, Species.MAGIKARP ]);
const enemy2 = game.scene.getEnemyField()[1];
enemy2.summonData.ability = Abilities.LIGHTNING_ROD;
game.move.select(Moves.SHOCK_WAVE, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER_2);
await game.phaseInterceptor.to("BerryPhase");
expect(enemy2.isFullHp()).toBe(true);
expect(enemy2.getStatStage(Stat.SPATK)).toBe(1);
});
it("should not redirect moves changed from electric type via ability", async () => {
game.override.ability(Abilities.NORMALIZE);
await game.classicMode.startBattle([ Species.FEEBAS, Species.MAGIKARP ]);
const enemy1 = game.scene.getEnemyField()[0];
const enemy2 = game.scene.getEnemyField()[1];
enemy2.summonData.ability = Abilities.LIGHTNING_ROD;
game.move.select(Moves.SHOCK_WAVE, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER_2);
await game.phaseInterceptor.to("BerryPhase");
expect(enemy1.isFullHp()).toBe(false);
});
it("should redirect moves changed to electric type via ability", async () => {
game.override.ability(Abilities.GALVANIZE)
.moveset(Moves.TACKLE);
await game.classicMode.startBattle([ Species.FEEBAS, Species.MAGIKARP ]);
const enemy1 = game.scene.getEnemyField()[0];
const enemy2 = game.scene.getEnemyField()[1];
enemy2.summonData.ability = Abilities.LIGHTNING_ROD;
game.move.select(Moves.TACKLE, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER_2);
await game.phaseInterceptor.to("BerryPhase");
expect(enemy1.isFullHp()).toBe(true);
expect(enemy2.getStatStage(Stat.SPATK)).toBe(1);
});
});

View File

@ -1,4 +1,5 @@
import { BattlerIndex } from "#app/battle"; import { BattlerIndex } from "#app/battle";
import { PostSummonWeatherChangeAbAttr } from "#app/data/ability";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { ArenaTagType } from "#enums/arena-tag-type"; import { ArenaTagType } from "#enums/arena-tag-type";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
@ -7,7 +8,7 @@ import { Species } from "#enums/species";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import GameManager from "#test/testUtils/gameManager"; import GameManager from "#test/testUtils/gameManager";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
describe("Abilities - Neutralizing Gas", () => { describe("Abilities - Neutralizing Gas", () => {
let phaserGame: Phaser.Game; let phaserGame: Phaser.Game;
@ -155,4 +156,25 @@ describe("Abilities - Neutralizing Gas", () => {
expect(game.scene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS)).toBeUndefined(); expect(game.scene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS)).toBeUndefined();
}); });
it("should not activate abilities of pokemon no longer on the field", async () => {
game.override
.battleType("single")
.ability(Abilities.NEUTRALIZING_GAS)
.enemyAbility(Abilities.DELTA_STREAM);
await game.classicMode.startBattle([ Species.MAGIKARP ]);
const enemy = game.scene.getEnemyPokemon()!;
const weatherChangeAttr = enemy.getAbilityAttrs(PostSummonWeatherChangeAbAttr, false)[0];
vi.spyOn(weatherChangeAttr, "applyPostSummon");
expect(game.scene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS)).toBeDefined();
game.move.select(Moves.SPLASH);
await game.killPokemon(enemy);
await game.killPokemon(game.scene.getPlayerPokemon()!);
expect(game.scene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS)).toBeUndefined();
expect(weatherChangeAttr.applyPostSummon).not.toHaveBeenCalled();
});
}); });

View File

@ -0,0 +1,115 @@
import { BattlerIndex } from "#app/battle";
import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import { Stat } from "#enums/stat";
import GameManager from "#test/testUtils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
describe("Abilities - Storm Drain", () => {
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, Moves.WATER_GUN ])
.ability(Abilities.BALL_FETCH)
.battleType("double")
.disableCrits()
.enemySpecies(Species.MAGIKARP)
.enemyAbility(Abilities.BALL_FETCH)
.enemyMoveset(Moves.SPLASH);
});
it("should redirect water type moves", async () => {
await game.classicMode.startBattle([ Species.FEEBAS, Species.MAGIKARP ]);
const enemy1 = game.scene.getEnemyField()[0];
const enemy2 = game.scene.getEnemyField()[1];
enemy2.summonData.ability = Abilities.STORM_DRAIN;
game.move.select(Moves.WATER_GUN, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER_2);
await game.phaseInterceptor.to("BerryPhase");
expect(enemy1.isFullHp()).toBe(true);
});
it("should not redirect non-water type moves", async () => {
game.override.moveset([ Moves.SPLASH, Moves.AERIAL_ACE ]);
await game.classicMode.startBattle([ Species.FEEBAS, Species.MAGIKARP ]);
const enemy1 = game.scene.getEnemyField()[0];
const enemy2 = game.scene.getEnemyField()[1];
enemy2.summonData.ability = Abilities.STORM_DRAIN;
game.move.select(Moves.AERIAL_ACE, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER_2);
await game.phaseInterceptor.to("BerryPhase");
expect(enemy1.isFullHp()).toBe(false);
});
it("should boost the user's spatk without damaging", async () => {
await game.classicMode.startBattle([ Species.FEEBAS, Species.MAGIKARP ]);
const enemy2 = game.scene.getEnemyField()[1];
enemy2.summonData.ability = Abilities.STORM_DRAIN;
game.move.select(Moves.WATER_GUN, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER_2);
await game.phaseInterceptor.to("BerryPhase");
expect(enemy2.isFullHp()).toBe(true);
expect(enemy2.getStatStage(Stat.SPATK)).toBe(1);
});
it("should not redirect moves changed from water type via ability", async () => {
game.override.ability(Abilities.NORMALIZE);
await game.classicMode.startBattle([ Species.FEEBAS, Species.MAGIKARP ]);
const enemy1 = game.scene.getEnemyField()[0];
const enemy2 = game.scene.getEnemyField()[1];
enemy2.summonData.ability = Abilities.STORM_DRAIN;
game.move.select(Moves.WATER_GUN, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER_2);
await game.phaseInterceptor.to("BerryPhase");
expect(enemy1.isFullHp()).toBe(false);
});
it("should redirect moves changed to water type via ability", async () => {
game.override.ability(Abilities.LIQUID_VOICE)
.moveset(Moves.PSYCHIC_NOISE);
await game.classicMode.startBattle([ Species.FEEBAS, Species.MAGIKARP ]);
const enemy1 = game.scene.getEnemyField()[0];
const enemy2 = game.scene.getEnemyField()[1];
enemy2.summonData.ability = Abilities.STORM_DRAIN;
game.move.select(Moves.PSYCHIC_NOISE, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER_2);
await game.phaseInterceptor.to("BerryPhase");
expect(enemy1.isFullHp()).toBe(true);
expect(enemy2.getStatStage(Stat.SPATK)).toBe(1);
});
});

View File

@ -27,8 +27,8 @@ describe("Moves - Chilly Reception", () => {
.battleType("single") .battleType("single")
.moveset([Moves.CHILLY_RECEPTION, Moves.SNOWSCAPE]) .moveset([Moves.CHILLY_RECEPTION, Moves.SNOWSCAPE])
.enemyMoveset(Array(4).fill(Moves.SPLASH)) .enemyMoveset(Array(4).fill(Moves.SPLASH))
.enemyAbility(Abilities.NONE) .enemyAbility(Abilities.BALL_FETCH)
.ability(Abilities.NONE); .ability(Abilities.BALL_FETCH);
}); });
it("should still change the weather if user can't switch out", async () => { it("should still change the weather if user can't switch out", async () => {
@ -72,7 +72,6 @@ describe("Moves - Chilly Reception", () => {
game.override game.override
.battleType("single") .battleType("single")
.enemyMoveset([Moves.CHILLY_RECEPTION, Moves.TACKLE]) .enemyMoveset([Moves.CHILLY_RECEPTION, Moves.TACKLE])
.enemyAbility(Abilities.NONE)
.moveset(Array(4).fill(Moves.SPLASH)); .moveset(Array(4).fill(Moves.SPLASH));
await game.classicMode.startBattle([Species.SLOWKING, Species.MEOWTH]); await game.classicMode.startBattle([Species.SLOWKING, Species.MEOWTH]);
@ -89,7 +88,6 @@ describe("Moves - Chilly Reception", () => {
.battleType("single") .battleType("single")
.startingWave(8) .startingWave(8)
.enemyMoveset(Array(4).fill(Moves.CHILLY_RECEPTION)) .enemyMoveset(Array(4).fill(Moves.CHILLY_RECEPTION))
.enemyAbility(Abilities.NONE)
.enemySpecies(Species.MAGIKARP) .enemySpecies(Species.MAGIKARP)
.moveset([Moves.SPLASH, Moves.THUNDERBOLT]); .moveset([Moves.SPLASH, Moves.THUNDERBOLT]);

View File

@ -68,7 +68,7 @@ describe("Moves - Secret Power", () => {
await game.classicMode.startBattle([Species.BLASTOISE, Species.CHARIZARD]); await game.classicMode.startBattle([Species.BLASTOISE, Species.CHARIZARD]);
const sereneGraceAttr = allAbilities[Abilities.SERENE_GRACE].getAttrs(MoveEffectChanceMultiplierAbAttr)[0]; const sereneGraceAttr = allAbilities[Abilities.SERENE_GRACE].getAttrs(MoveEffectChanceMultiplierAbAttr)[0];
vi.spyOn(sereneGraceAttr, "apply"); vi.spyOn(sereneGraceAttr, "canApply");
game.move.select(Moves.WATER_PLEDGE, 0, BattlerIndex.ENEMY); game.move.select(Moves.WATER_PLEDGE, 0, BattlerIndex.ENEMY);
game.move.select(Moves.FIRE_PLEDGE, 1, BattlerIndex.ENEMY_2); game.move.select(Moves.FIRE_PLEDGE, 1, BattlerIndex.ENEMY_2);
@ -86,8 +86,8 @@ describe("Moves - Secret Power", () => {
await game.phaseInterceptor.to("BerryPhase", false); await game.phaseInterceptor.to("BerryPhase", false);
expect(sereneGraceAttr.apply).toHaveBeenCalledOnce(); expect(sereneGraceAttr.canApply).toHaveBeenCalledOnce();
expect(sereneGraceAttr.apply).toHaveLastReturnedWith(true); expect(sereneGraceAttr.canApply).toHaveLastReturnedWith(true);
expect(rainbowEffect.apply).toHaveBeenCalledTimes(0); expect(rainbowEffect.apply).toHaveBeenCalledTimes(0);
}); });

View File

@ -1,9 +1,9 @@
import { Stat } from "#enums/stat";
import { ArenaTagSide } from "#app/data/arena-tag"; import { ArenaTagSide } from "#app/data/arena-tag";
import { ArenaTagType } from "#app/enums/arena-tag-type"; import { ArenaTagType } from "#app/enums/arena-tag-type";
import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import { Stat } from "#enums/stat";
import GameManager from "#test/testUtils/gameManager"; import GameManager from "#test/testUtils/gameManager";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
@ -24,13 +24,16 @@ describe("Moves - Tailwind", () => {
beforeEach(() => { beforeEach(() => {
game = new GameManager(phaserGame); game = new GameManager(phaserGame);
game.override.battleType("double"); game.override
game.override.moveset([Moves.TAILWIND, Moves.SPLASH, Moves.PETAL_BLIZZARD, Moves.SANDSTORM]); .battleType("double")
game.override.enemyMoveset(Moves.SPLASH); .moveset([Moves.TAILWIND, Moves.SPLASH])
.enemyMoveset(Moves.SPLASH)
.enemyAbility(Abilities.BALL_FETCH)
.ability(Abilities.BALL_FETCH);
}); });
it("doubles the Speed stat of the Pokemons on its side", async () => { it("doubles the Speed stat of the Pokemons on its side", async () => {
await game.startBattle([Species.MAGIKARP, Species.MEOWTH]); await game.classicMode.startBattle([Species.MAGIKARP, Species.MEOWTH]);
const magikarp = game.scene.getPlayerField()[0]; const magikarp = game.scene.getPlayerField()[0];
const meowth = game.scene.getPlayerField()[1]; const meowth = game.scene.getPlayerField()[1];
@ -43,7 +46,7 @@ describe("Moves - Tailwind", () => {
game.move.select(Moves.TAILWIND); game.move.select(Moves.TAILWIND);
game.move.select(Moves.SPLASH, 1); game.move.select(Moves.SPLASH, 1);
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to("TurnEndPhase");
expect(magikarp.getEffectiveStat(Stat.SPD)).toBe(magikarpSpd * 2); expect(magikarp.getEffectiveStat(Stat.SPD)).toBe(magikarpSpd * 2);
expect(meowth.getEffectiveStat(Stat.SPD)).toBe(meowthSpd * 2); expect(meowth.getEffectiveStat(Stat.SPD)).toBe(meowthSpd * 2);
@ -53,7 +56,7 @@ describe("Moves - Tailwind", () => {
it("lasts for 4 turns", async () => { it("lasts for 4 turns", async () => {
game.override.battleType("single"); game.override.battleType("single");
await game.startBattle([Species.MAGIKARP]); await game.classicMode.startBattle([Species.MAGIKARP]);
game.move.select(Moves.TAILWIND); game.move.select(Moves.TAILWIND);
await game.toNextTurn(); await game.toNextTurn();
@ -76,7 +79,7 @@ describe("Moves - Tailwind", () => {
it("does not affect the opposing side", async () => { it("does not affect the opposing side", async () => {
game.override.battleType("single"); game.override.battleType("single");
await game.startBattle([Species.MAGIKARP]); await game.classicMode.startBattle([Species.MAGIKARP]);
const ally = game.scene.getPlayerPokemon()!; const ally = game.scene.getPlayerPokemon()!;
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.scene.getEnemyPokemon()!;
@ -91,7 +94,7 @@ describe("Moves - Tailwind", () => {
game.move.select(Moves.TAILWIND); game.move.select(Moves.TAILWIND);
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to("TurnEndPhase");
expect(ally.getEffectiveStat(Stat.SPD)).toBe(allySpd * 2); expect(ally.getEffectiveStat(Stat.SPD)).toBe(allySpd * 2);
expect(enemy.getEffectiveStat(Stat.SPD)).equal(enemySpd); expect(enemy.getEffectiveStat(Stat.SPD)).equal(enemySpd);