Merge branch 'beta' into activation-order

This commit is contained in:
Dean 2025-03-23 11:37:13 -07:00 committed by GitHub
commit e2f7bdebb7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 455 additions and 326 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

@ -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",

View File

@ -3862,7 +3862,7 @@ export class PostTurnStatusHealAbAttr extends PostTurnAbAttr {
} }
override canApplyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { override canApplyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean {
return (pokemon.status !== null) && this.effects.includes(pokemon.status.effect) && !pokemon.isFullHp(); return !Utils.isNullOrUndefined(pokemon.status) && this.effects.includes(pokemon.status.effect) && !pokemon.isFullHp();
} }
/** /**
@ -4105,7 +4105,7 @@ export class FetchBallAbAttr extends PostTurnAbAttr {
} }
override canApplyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { override canApplyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean {
return !simulated && globalScene.currentBattle.lastUsedPokeball !== null && !!pokemon.isPlayer; return !simulated && !Utils.isNullOrUndefined(globalScene.currentBattle.lastUsedPokeball) && !!pokemon.isPlayer;
} }
/** /**

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,11 +1427,7 @@ 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(true)) { for (const fieldPokemon of globalScene.getField(true)) {
if (fieldPokemon && fieldPokemon.id !== pokemon.id) { if (fieldPokemon && fieldPokemon.id !== pokemon.id) {
@ -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 {
@ -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

@ -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

@ -3,144 +3,46 @@ import { Moves } from "#enums/moves";
/** Set of moves that cannot be called by {@linkcode Moves.METRONOME Metronome} */ /** Set of moves that cannot be called by {@linkcode Moves.METRONOME Metronome} */
export const invalidMetronomeMoves: ReadonlySet<Moves> = new Set([ export const invalidMetronomeMoves: ReadonlySet<Moves> = new Set([
Moves.AFTER_YOU, Moves.AFTER_YOU,
Moves.APPLE_ACID,
Moves.ARMOR_CANNON,
Moves.ASSIST, Moves.ASSIST,
Moves.ASTRAL_BARRAGE,
Moves.AURA_WHEEL,
Moves.BANEFUL_BUNKER, Moves.BANEFUL_BUNKER,
Moves.BEAK_BLAST, Moves.BEAK_BLAST,
Moves.BEHEMOTH_BASH,
Moves.BEHEMOTH_BLADE,
Moves.BELCH, Moves.BELCH,
Moves.BESTOW, Moves.BESTOW,
Moves.BLAZING_TORQUE,
Moves.BODY_PRESS,
Moves.BRANCH_POKE,
Moves.BREAKING_SWIPE,
Moves.CELEBRATE,
Moves.CHATTER,
Moves.CHILLING_WATER,
Moves.CHILLY_RECEPTION,
Moves.CLANGOROUS_SOUL,
Moves.COLLISION_COURSE,
Moves.COMBAT_TORQUE,
Moves.COMEUPPANCE, Moves.COMEUPPANCE,
Moves.COPYCAT, Moves.COPYCAT,
Moves.COUNTER, Moves.COUNTER,
Moves.COVET,
Moves.CRAFTY_SHIELD, Moves.CRAFTY_SHIELD,
Moves.DECORATE,
Moves.DESTINY_BOND, Moves.DESTINY_BOND,
Moves.DETECT, Moves.DETECT,
Moves.DIAMOND_STORM,
Moves.DOODLE,
Moves.DOUBLE_IRON_BASH,
Moves.DOUBLE_SHOCK,
Moves.DRAGON_ASCENT,
Moves.DRAGON_ENERGY,
Moves.DRUM_BEATING,
Moves.DYNAMAX_CANNON,
Moves.ELECTRO_DRIFT,
Moves.ENDURE, Moves.ENDURE,
Moves.ETERNABEAM,
Moves.FALSE_SURRENDER,
Moves.FEINT, Moves.FEINT,
Moves.FIERY_WRATH,
Moves.FILLET_AWAY,
Moves.FLEUR_CANNON,
Moves.FOCUS_PUNCH, Moves.FOCUS_PUNCH,
Moves.FOLLOW_ME, Moves.FOLLOW_ME,
Moves.FREEZE_SHOCK,
Moves.FREEZING_GLARE,
Moves.GLACIAL_LANCE,
Moves.GRAV_APPLE,
Moves.HELPING_HAND, Moves.HELPING_HAND,
Moves.HOLD_HANDS,
Moves.HYPER_DRILL,
Moves.HYPERSPACE_FURY,
Moves.HYPERSPACE_HOLE,
Moves.ICE_BURN,
Moves.INSTRUCT, Moves.INSTRUCT,
Moves.JET_PUNCH,
Moves.JUNGLE_HEALING,
Moves.KINGS_SHIELD, Moves.KINGS_SHIELD,
Moves.LIFE_DEW,
Moves.LIGHT_OF_RUIN,
Moves.MAKE_IT_RAIN,
Moves.MAGICAL_TORQUE,
Moves.MAT_BLOCK, Moves.MAT_BLOCK,
Moves.ME_FIRST, Moves.ME_FIRST,
Moves.METEOR_ASSAULT,
Moves.METRONOME, Moves.METRONOME,
Moves.MIMIC, Moves.MIMIC,
Moves.MIND_BLOWN,
Moves.MIRROR_COAT, Moves.MIRROR_COAT,
Moves.MIRROR_MOVE, Moves.MIRROR_MOVE,
Moves.MOONGEIST_BEAM,
Moves.NATURE_POWER,
Moves.NATURES_MADNESS,
Moves.NOXIOUS_TORQUE,
Moves.OBSTRUCT, Moves.OBSTRUCT,
Moves.ORDER_UP,
Moves.ORIGIN_PULSE,
Moves.OVERDRIVE,
Moves.PHOTON_GEYSER,
Moves.PLASMA_FISTS,
Moves.POPULATION_BOMB,
Moves.POUNCE,
Moves.POWER_SHIFT,
Moves.PRECIPICE_BLADES,
Moves.PROTECT, Moves.PROTECT,
Moves.PYRO_BALL,
Moves.QUASH, Moves.QUASH,
Moves.QUICK_GUARD, Moves.QUICK_GUARD,
Moves.RAGE_FIST,
Moves.RAGE_POWDER, Moves.RAGE_POWDER,
Moves.RAGING_BULL,
Moves.RAGING_FURY,
Moves.RELIC_SONG,
Moves.REVIVAL_BLESSING, Moves.REVIVAL_BLESSING,
Moves.RUINATION,
Moves.SALT_CURE,
Moves.SECRET_SWORD,
Moves.SHED_TAIL,
Moves.SHELL_TRAP, Moves.SHELL_TRAP,
Moves.SILK_TRAP, Moves.SILK_TRAP,
Moves.SKETCH, Moves.SKETCH,
Moves.SLEEP_TALK, Moves.SLEEP_TALK,
Moves.SNAP_TRAP,
Moves.SNARL,
Moves.SNATCH, Moves.SNATCH,
Moves.SNORE, Moves.SNORE,
Moves.SNOWSCAPE,
Moves.SPECTRAL_THIEF,
Moves.SPICY_EXTRACT,
Moves.SPIKY_SHIELD, Moves.SPIKY_SHIELD,
Moves.SPIRIT_BREAK,
Moves.SPOTLIGHT, Moves.SPOTLIGHT,
Moves.STEAM_ERUPTION,
Moves.STEEL_BEAM,
Moves.STRANGE_STEAM,
Moves.STRUGGLE, Moves.STRUGGLE,
Moves.SUNSTEEL_STRIKE,
Moves.SURGING_STRIKES,
Moves.SWITCHEROO,
Moves.TECHNO_BLAST,
Moves.TERA_STARSTORM,
Moves.THIEF,
Moves.THOUSAND_ARROWS,
Moves.THOUSAND_WAVES,
Moves.THUNDER_CAGE,
Moves.THUNDEROUS_KICK,
Moves.TIDY_UP,
Moves.TRAILBLAZE,
Moves.TRANSFORM, Moves.TRANSFORM,
Moves.TRICK,
Moves.TWIN_BEAM,
Moves.V_CREATE,
Moves.WICKED_BLOW,
Moves.WICKED_TORQUE,
Moves.WIDE_GUARD, Moves.WIDE_GUARD,
]); ]);
@ -157,7 +59,6 @@ export const invalidAssistMoves: ReadonlySet<Moves> = new Set([
Moves.CIRCLE_THROW, Moves.CIRCLE_THROW,
Moves.COPYCAT, Moves.COPYCAT,
Moves.COUNTER, Moves.COUNTER,
Moves.COVET,
Moves.DESTINY_BOND, Moves.DESTINY_BOND,
Moves.DETECT, Moves.DETECT,
Moves.DIG, Moves.DIG,
@ -192,7 +93,6 @@ export const invalidAssistMoves: ReadonlySet<Moves> = new Set([
Moves.SPOTLIGHT, Moves.SPOTLIGHT,
Moves.STRUGGLE, Moves.STRUGGLE,
Moves.SWITCHEROO, Moves.SWITCHEROO,
Moves.THIEF,
Moves.TRANSFORM, Moves.TRANSFORM,
Moves.TRICK, Moves.TRICK,
Moves.WHIRLWIND, Moves.WHIRLWIND,
@ -208,7 +108,6 @@ export const invalidSleepTalkMoves: ReadonlySet<Moves> = new Set([
Moves.COPYCAT, Moves.COPYCAT,
Moves.DIG, Moves.DIG,
Moves.DIVE, Moves.DIVE,
Moves.DYNAMAX_CANNON,
Moves.FREEZE_SHOCK, Moves.FREEZE_SHOCK,
Moves.FLY, Moves.FLY,
Moves.FOCUS_PUNCH, Moves.FOCUS_PUNCH,
@ -238,15 +137,12 @@ export const invalidCopycatMoves: ReadonlySet<Moves> = new Set([
Moves.ASSIST, Moves.ASSIST,
Moves.BANEFUL_BUNKER, Moves.BANEFUL_BUNKER,
Moves.BEAK_BLAST, Moves.BEAK_BLAST,
Moves.BEHEMOTH_BASH,
Moves.BEHEMOTH_BLADE,
Moves.BESTOW, Moves.BESTOW,
Moves.CELEBRATE, Moves.CELEBRATE,
Moves.CHATTER, Moves.CHATTER,
Moves.CIRCLE_THROW, Moves.CIRCLE_THROW,
Moves.COPYCAT, Moves.COPYCAT,
Moves.COUNTER, Moves.COUNTER,
Moves.COVET,
Moves.DESTINY_BOND, Moves.DESTINY_BOND,
Moves.DETECT, Moves.DETECT,
Moves.DRAGON_TAIL, Moves.DRAGON_TAIL,
@ -274,8 +170,73 @@ export const invalidCopycatMoves: ReadonlySet<Moves> = new Set([
Moves.SPOTLIGHT, Moves.SPOTLIGHT,
Moves.STRUGGLE, Moves.STRUGGLE,
Moves.SWITCHEROO, Moves.SWITCHEROO,
Moves.THIEF,
Moves.TRANSFORM, Moves.TRANSFORM,
Moves.TRICK, Moves.TRICK,
Moves.WHIRLWIND, Moves.WHIRLWIND,
]); ]);
export const invalidMirrorMoveMoves: ReadonlySet<Moves> = new Set([
Moves.ACUPRESSURE,
Moves.AFTER_YOU,
Moves.AROMATIC_MIST,
Moves.BEAK_BLAST,
Moves.BELCH,
Moves.CHILLY_RECEPTION,
Moves.COACHING,
Moves.CONVERSION_2,
Moves.COUNTER,
Moves.CRAFTY_SHIELD,
Moves.CURSE,
Moves.DECORATE,
Moves.DOODLE,
Moves.DOOM_DESIRE,
Moves.DRAGON_CHEER,
Moves.ELECTRIC_TERRAIN,
Moves.FINAL_GAMBIT,
Moves.FLORAL_HEALING,
Moves.FLOWER_SHIELD,
Moves.FOCUS_PUNCH,
Moves.FUTURE_SIGHT,
Moves.GEAR_UP,
Moves.GRASSY_TERRAIN,
Moves.GRAVITY,
Moves.GUARD_SPLIT,
Moves.HAIL,
Moves.HAZE,
Moves.HEAL_PULSE,
Moves.HELPING_HAND,
Moves.HOLD_HANDS,
Moves.INSTRUCT,
Moves.ION_DELUGE,
Moves.MAGNETIC_FLUX,
Moves.MAT_BLOCK,
Moves.ME_FIRST,
Moves.MIMIC,
Moves.MIRROR_COAT,
Moves.MIRROR_MOVE,
Moves.MIST,
Moves.MISTY_TERRAIN,
Moves.MUD_SPORT,
Moves.PERISH_SONG,
Moves.POWER_SPLIT,
Moves.PSYCH_UP,
Moves.PSYCHIC_TERRAIN,
Moves.PURIFY,
Moves.QUICK_GUARD,
Moves.RAIN_DANCE,
Moves.REFLECT_TYPE,
Moves.ROLE_PLAY,
Moves.ROTOTILLER,
Moves.SANDSTORM,
Moves.SHELL_TRAP,
Moves.SKETCH,
Moves.SNOWSCAPE,
Moves.SPIT_UP,
Moves.SPOTLIGHT,
Moves.STRUGGLE,
Moves.SUNNY_DAY,
Moves.TEATIME,
Moves.TRANSFORM,
Moves.WATER_SPORT,
Moves.WIDE_GUARD,
]);

View File

@ -125,7 +125,7 @@ import { MoveTarget } from "#enums/MoveTarget";
import { MoveFlags } from "#enums/MoveFlags"; import { MoveFlags } from "#enums/MoveFlags";
import { MoveEffectTrigger } from "#enums/MoveEffectTrigger"; import { MoveEffectTrigger } from "#enums/MoveEffectTrigger";
import { MultiHitType } from "#enums/MultiHitType"; import { MultiHitType } from "#enums/MultiHitType";
import { invalidAssistMoves, invalidCopycatMoves, invalidMetronomeMoves, invalidSleepTalkMoves } from "./invalid-moves"; import { invalidAssistMoves, invalidCopycatMoves, invalidMetronomeMoves, invalidMirrorMoveMoves, invalidSleepTalkMoves } from "./invalid-moves";
type MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => boolean; type MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => boolean;
type UserMoveConditionFunc = (user: Pokemon, move: Move) => boolean; type UserMoveConditionFunc = (user: Pokemon, move: Move) => boolean;
@ -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
@ -6941,7 +6966,8 @@ export class CopyMoveAttr extends CallMoveAttr {
getCondition(): MoveConditionFunc { getCondition(): MoveConditionFunc {
return (user, target, move) => { return (user, target, move) => {
if (this.mirrorMove) { if (this.mirrorMove) {
return target.getMoveHistory().length !== 0; const lastMove = target.getLastXMoves()[0]?.move;
return !!lastMove && !this.invalidMoves.has(lastMove);
} else { } else {
const lastMove = globalScene.currentBattle.lastMove; const lastMove = globalScene.currentBattle.lastMove;
return lastMove !== undefined && !this.invalidMoves.has(lastMove); return lastMove !== undefined && !this.invalidMoves.has(lastMove);
@ -8537,7 +8563,7 @@ export function initMoves() {
new SelfStatusMove(Moves.METRONOME, PokemonType.NORMAL, -1, 10, -1, 0, 1) new SelfStatusMove(Moves.METRONOME, PokemonType.NORMAL, -1, 10, -1, 0, 1)
.attr(RandomMoveAttr, invalidMetronomeMoves), .attr(RandomMoveAttr, invalidMetronomeMoves),
new StatusMove(Moves.MIRROR_MOVE, PokemonType.FLYING, -1, 20, -1, 0, 1) new StatusMove(Moves.MIRROR_MOVE, PokemonType.FLYING, -1, 20, -1, 0, 1)
.attr(CopyMoveAttr, true), .attr(CopyMoveAttr, true, invalidMirrorMoveMoves),
new AttackMove(Moves.SELF_DESTRUCT, PokemonType.NORMAL, MoveCategory.PHYSICAL, 200, 100, 5, -1, 0, 1) new AttackMove(Moves.SELF_DESTRUCT, PokemonType.NORMAL, MoveCategory.PHYSICAL, 200, 100, 5, -1, 0, 1)
.attr(SacrificialAttr) .attr(SacrificialAttr)
.makesContact(false) .makesContact(false)
@ -9646,7 +9672,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 +10123,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

@ -23,6 +23,7 @@ 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 { 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;
@ -1811,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")
@ -1918,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)
@ -1936,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)
@ -2074,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)
@ -2104,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

@ -673,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

@ -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) {

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

@ -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

@ -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);