Hotfix 1.11.3 to Beta

Hotfix 1.11.3 to beta
This commit is contained in:
damocleas 2025-11-08 10:31:28 -05:00 committed by GitHub
commit e438536dc3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 212 additions and 267 deletions

2
assets

@ -1 +1 @@
Subproject commit d2d9309cd1acfcebeefbf4c1c63e1104a1294ed8 Subproject commit 9d391bd666f339c31db3d48a9907139950c14d1e

@ -1 +1 @@
Subproject commit ddf9509e1c6abe8fc93b455d79bfaa0202e05ede Subproject commit b5b0d94eee7cbcf0e055f8074ca1ebedb920e59e

View File

@ -1,7 +1,7 @@
{ {
"name": "pokemon-rogue-battle", "name": "pokemon-rogue-battle",
"private": true, "private": true,
"version": "1.11.2", "version": "1.11.3",
"type": "module", "type": "module",
"scripts": { "scripts": {
"start:prod": "vite --mode production", "start:prod": "vite --mode production",

View File

@ -1833,13 +1833,13 @@ export class PokemonTypeChangeAbAttr extends PreAttackAbAttr {
} }
/** /**
* Parameters for abilities that modify the hit count and damage of a move * Parameters for abilities that modify the hit count of a move.
*/ */
export interface AddSecondStrikeAbAttrParams extends Omit<AugmentMoveInteractionAbAttrParams, "opponent"> { export interface AddSecondStrikeAbAttrParams extends Omit<AugmentMoveInteractionAbAttrParams, "opponent"> {
/** Holder for the number of hits. May be modified by ability application */ /** Holder for the number of hits. Modified by ability application */
hitCount?: NumberHolder; hitCount: NumberHolder;
/** Holder for the damage multiplier _of the current hit_ */ /** The Pokemon on the other side of this interaction */
multiplier?: NumberHolder; opponent: Pokemon | undefined;
} }
/** /**
@ -1847,36 +1847,13 @@ export interface AddSecondStrikeAbAttrParams extends Omit<AugmentMoveInteraction
* Used by {@linkcode MoveId.PARENTAL_BOND | Parental Bond}. * Used by {@linkcode MoveId.PARENTAL_BOND | Parental Bond}.
*/ */
export class AddSecondStrikeAbAttr extends PreAttackAbAttr { export class AddSecondStrikeAbAttr extends PreAttackAbAttr {
/** The damage multiplier for the second strike, relative to the first */ override canApply({ pokemon, opponent, move }: AddSecondStrikeAbAttrParams): boolean {
private readonly damageMultiplier: number; return move.canBeMultiStrikeEnhanced(pokemon, true, opponent);
/**
* @param damageMultiplier - The damage multiplier for the second strike, relative to the first
*/
constructor(damageMultiplier: number) {
super(false);
this.damageMultiplier = damageMultiplier;
} }
/** override apply({ hitCount }: AddSecondStrikeAbAttrParams): void {
* Return whether the move can be multi-strike enhanced.
*/
override canApply({ pokemon, move }: AddSecondStrikeAbAttrParams): boolean {
return move.canBeMultiStrikeEnhanced(pokemon, true);
}
/**
* Add one to the move's hit count, and, if the pokemon has only one hit left, sets the damage multiplier
* to the damage multiplier of this ability.
*/
override apply({ hitCount, multiplier, pokemon }: AddSecondStrikeAbAttrParams): void {
if (hitCount?.value) {
hitCount.value += 1; hitCount.value += 1;
} }
if (multiplier?.value && pokemon.turnData.hitsLeft === 1) {
multiplier.value = this.damageMultiplier;
}
}
} }
/** /**
@ -1895,10 +1872,12 @@ export interface PreAttackModifyDamageAbAttrParams extends AugmentMoveInteractio
* @param damageMultiplier the amount to multiply the damage by * @param damageMultiplier the amount to multiply the damage by
* @param condition the condition for this ability to be applied * @param condition the condition for this ability to be applied
*/ */
export class DamageBoostAbAttr extends PreAttackAbAttr { export class MoveDamageBoostAbAttr extends PreAttackAbAttr {
private readonly damageMultiplier: number; private readonly damageMultiplier: number;
private readonly condition: PokemonAttackCondition; private readonly condition: PokemonAttackCondition;
// TODO: This should not take a `PokemonAttackCondition` (with nullish parameters)
// as it's effectively offloading nullishness checks to its child attributes
constructor(damageMultiplier: number, condition: PokemonAttackCondition) { constructor(damageMultiplier: number, condition: PokemonAttackCondition) {
super(false); super(false);
this.damageMultiplier = damageMultiplier; this.damageMultiplier = damageMultiplier;
@ -6657,7 +6636,7 @@ const AbilityAttrs = Object.freeze({
MoveTypeChangeAbAttr, MoveTypeChangeAbAttr,
PokemonTypeChangeAbAttr, PokemonTypeChangeAbAttr,
AddSecondStrikeAbAttr, AddSecondStrikeAbAttr,
DamageBoostAbAttr, MoveDamageBoostAbAttr,
MovePowerBoostAbAttr, MovePowerBoostAbAttr,
MoveTypePowerBoostAbAttr, MoveTypePowerBoostAbAttr,
LowHpMoveTypePowerBoostAbAttr, LowHpMoveTypePowerBoostAbAttr,
@ -7298,7 +7277,7 @@ export function initAbilities() {
.ignorable() .ignorable()
.build(), .build(),
new AbBuilder(AbilityId.TINTED_LENS, 4) new AbBuilder(AbilityId.TINTED_LENS, 4)
.attr(DamageBoostAbAttr, 2, (user, target, move) => (target?.getMoveEffectiveness(user!, move) ?? 1) <= 0.5) .attr(MoveDamageBoostAbAttr, 2, (user, target, move) => (target?.getMoveEffectiveness(user!, move) ?? 1) <= 0.5)
.build(), .build(),
new AbBuilder(AbilityId.FILTER, 4) new AbBuilder(AbilityId.FILTER, 4)
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => target.getMoveEffectiveness(user, move) >= 2, 0.75) .attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => target.getMoveEffectiveness(user, move) >= 2, 0.75)
@ -7636,7 +7615,15 @@ export function initAbilities() {
.attr(MoveTypeChangeAbAttr, PokemonType.FLYING, 1.2, (_user, _target, move) => move.type === PokemonType.NORMAL) .attr(MoveTypeChangeAbAttr, PokemonType.FLYING, 1.2, (_user, _target, move) => move.type === PokemonType.NORMAL)
.build(), .build(),
new AbBuilder(AbilityId.PARENTAL_BOND, 6) new AbBuilder(AbilityId.PARENTAL_BOND, 6)
.attr(AddSecondStrikeAbAttr, 0.25) .attr(AddSecondStrikeAbAttr)
// Only multiply damage on the last strike of multi-strike moves
.attr(MoveDamageBoostAbAttr, 0.25, (user, target, move) => (
!!user
&& user.turnData.hitCount > 1 // move was originally multi hit
&& user.turnData.hitsLeft === 1 // move is on its final strike
&& move.canBeMultiStrikeEnhanced(user, true, target)
)
)
.build(), .build(),
new AbBuilder(AbilityId.DARK_AURA, 6) new AbBuilder(AbilityId.DARK_AURA, 6)
.attr(PostSummonMessageAbAttr, (pokemon: Pokemon) => i18next.t("abilityTriggers:postSummonDarkAura", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) })) .attr(PostSummonMessageAbAttr, (pokemon: Pokemon) => i18next.t("abilityTriggers:postSummonDarkAura", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }))

View File

@ -319,7 +319,11 @@ export class MistTag extends SerializableArenaTag {
cancelled.value = true; cancelled.value = true;
if (!simulated) { if (!simulated) {
globalScene.phaseManager.queueMessage(i18next.t("arenaTag:mistApply")); globalScene.phaseManager.queueMessage(
i18next.t("arenaTag:mistApply", {
pokemonNameWithAffix: getPokemonNameWithAffix(this.getSourcePokemon()),
}),
);
} }
return true; return true;
@ -1532,6 +1536,11 @@ export class SuppressAbilitiesTag extends SerializableArenaTag {
const setter = globalScene const setter = globalScene
.getField(true) .getField(true)
.filter(p => p.hasAbilityWithAttr("PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr", false))[0]; .filter(p => p.hasAbilityWithAttr("PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr", false))[0];
// Setter may not exist if both NG Pokemon faint simultaneously
if (setter == null) {
return;
}
applyOnGainAbAttrs({ applyOnGainAbAttrs({
pokemon: setter, pokemon: setter,
passive: setter.getAbility().hasAttr("PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr"), passive: setter.getAbility().hasAttr("PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr"),

View File

@ -100,7 +100,6 @@ import i18next from "i18next";
import { MovePhaseTimingModifier } from "#enums/move-phase-timing-modifier"; import { MovePhaseTimingModifier } from "#enums/move-phase-timing-modifier";
import { inSpeedOrder } from "#utils/speed-order-generator"; import { inSpeedOrder } from "#utils/speed-order-generator";
import { canSpeciesTera, willTerastallize } from "#utils/pokemon-utils"; import { canSpeciesTera, willTerastallize } from "#utils/pokemon-utils";
import type { ReadonlyGenericUint8Array } from "#types/typed-arrays";
import { MovePriorityInBracket } from "#enums/move-priority-in-bracket"; import { MovePriorityInBracket } from "#enums/move-priority-in-bracket";
/** /**
@ -1117,20 +1116,34 @@ export abstract class Move implements Localizable {
} }
/** /**
* Returns `true` if this move can be given additional strikes * Check whether this Move can be given additional strikes from enhancing effects.
* by enhancing effects.
* Currently used for {@link https://bulbapedia.bulbagarden.net/wiki/Parental_Bond_(Ability) | Parental Bond} * Currently used for {@link https://bulbapedia.bulbagarden.net/wiki/Parental_Bond_(Ability) | Parental Bond}
* and {@linkcode PokemonMultiHitModifier | Multi-Lens}. * and {@linkcode PokemonMultiHitModifier | Multi Lens}.
* @param user The {@linkcode Pokemon} using the move * @param user - The {@linkcode Pokemon} using the move
* @param restrictSpread `true` if the enhancing effect * @param restrictSpread - Whether the enhancing effect should ignore multi-target moves; default `false`
* should not affect multi-target moves (default `false`) * @returns Whether this Move can be given additional strikes.
*/ */
canBeMultiStrikeEnhanced(user: Pokemon, restrictSpread: boolean = false): boolean { // TODO: Remove target parameter used solely to circumvent Pollen Puff shenanigans - the entire move needs to be fixed anyhow
public canBeMultiStrikeEnhanced(user: Pokemon, restrictSpread: boolean = false, target?: Pokemon | null): boolean {
// Multi-strike enhancers... // Multi-strike enhancers...
// ...cannot enhance moves that hit multiple targets // ...cannot enhance charging or 2-turn moves
if (this.isChargingMove()) {
return false;
}
// ...cannot enhance moves hitting multiple targets unless specified
const { targets, multiple } = getMoveTargets(user, this.id); const { targets, multiple } = getMoveTargets(user, this.id);
const isMultiTarget = multiple && targets.length > 1; if (restrictSpread && multiple && targets.length > 1) {
return false;
};
// ...cannot enhance status moves, including ally-targeting Pollen Puff
if (
this.category === MoveCategory.STATUS
|| (target != null && user.getMoveCategory(target, this) === MoveCategory.STATUS)) {
return false;
}
// ...cannot enhance multi-hit or sacrificial moves // ...cannot enhance multi-hit or sacrificial moves
const exceptAttrs: MoveAttrString[] = [ const exceptAttrs: MoveAttrString[] = [
@ -1138,6 +1151,9 @@ export abstract class Move implements Localizable {
"SacrificialAttr", "SacrificialAttr",
"SacrificialAttrOnHit" "SacrificialAttrOnHit"
]; ];
if (exceptAttrs.some(attr => this.hasAttr(attr))) {
return false;
}
// ...and cannot enhance these specific moves // ...and cannot enhance these specific moves
const exceptMoves: MoveId[] = [ const exceptMoves: MoveId[] = [
@ -1147,17 +1163,11 @@ export abstract class Move implements Localizable {
MoveId.ICE_BALL, MoveId.ICE_BALL,
MoveId.ENDEAVOR MoveId.ENDEAVOR
]; ];
if (exceptMoves.includes(this.id)) {
return false;
}
// ...and cannot enhance Pollen Puff when targeting an ally. return true;
const ally = user.getAlly();
const exceptPollenPuffAlly: boolean = this.id === MoveId.POLLEN_PUFF && ally != null && targets.includes(ally.getBattlerIndex())
return (!restrictSpread || !isMultiTarget)
&& !this.isChargingMove()
&& !exceptAttrs.some(attr => this.hasAttr(attr))
&& !exceptMoves.some(id => this.id === id)
&& !exceptPollenPuffAlly
&& this.category !== MoveCategory.STATUS;
} }
} }
@ -9033,7 +9043,7 @@ export function initMoves() {
new AttackMove(MoveId.STRUGGLE, PokemonType.NORMAL, MoveCategory.PHYSICAL, 50, -1, 1, -1, 0, 1) new AttackMove(MoveId.STRUGGLE, PokemonType.NORMAL, MoveCategory.PHYSICAL, 50, -1, 1, -1, 0, 1)
.attr(RecoilAttr, true, 0.25, true) .attr(RecoilAttr, true, 0.25, true)
.attr(TypelessAttr) .attr(TypelessAttr)
.attr(PreMoveMessageAttr, (user: Pokemon) => i18next.t("moveTriggers:struggleMessage", { pokemonName: getPokemonNameWithAffix(user) })) .attr(PreMoveMessageAttr, (user: Pokemon) => i18next.t("moveTriggers:struggle", { pokemonName: getPokemonNameWithAffix(user) }))
.target(MoveTarget.RANDOM_NEAR_ENEMY), .target(MoveTarget.RANDOM_NEAR_ENEMY),
new StatusMove(MoveId.SKETCH, PokemonType.NORMAL, -1, 1, -1, 0, 2) new StatusMove(MoveId.SKETCH, PokemonType.NORMAL, -1, 1, -1, 0, 2)
.ignoresSubstitute() .ignoresSubstitute()
@ -10700,7 +10710,7 @@ export function initMoves() {
.attr(HealOnAllyAttr, 0.5, true, false) .attr(HealOnAllyAttr, 0.5, true, false)
.ballBombMove() .ballBombMove()
// Fail if used against an ally that is affected by heal block, during the second failure check // Fail if used against an ally that is affected by heal block, during the second failure check
.condition((user, target) => target.isOpponent(user) || !!target.getTag(BattlerTagType.HEAL_BLOCK), 2), .condition((user, target) => target == null || target.isOpponent(user) || !target.getTag(BattlerTagType.HEAL_BLOCK), 2),
new AttackMove(MoveId.ANCHOR_SHOT, PokemonType.STEEL, MoveCategory.PHYSICAL, 80, 100, 20, 100, 0, 7) new AttackMove(MoveId.ANCHOR_SHOT, PokemonType.STEEL, MoveCategory.PHYSICAL, 80, 100, 20, 100, 0, 7)
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, false, 1, 1, true), .attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, false, 1, 1, true),
new StatusMove(MoveId.PSYCHIC_TERRAIN, PokemonType.PSYCHIC, -1, 10, -1, 0, 7) new StatusMove(MoveId.PSYCHIC_TERRAIN, PokemonType.PSYCHIC, -1, 10, -1, 0, 7)

View File

@ -223,57 +223,47 @@ const PLASMA_COLRESS: TrainerTierPools = {
const FLARE: TrainerTierPools = { const FLARE: TrainerTierPools = {
[TrainerPoolTier.COMMON]: [ [TrainerPoolTier.COMMON]: [
SpeciesId.FOONGUS,
SpeciesId.SCRAGGY, SpeciesId.SCRAGGY,
SpeciesId.DRUDDIGON, SpeciesId.FOONGUS,
SpeciesId.BUNNELBY, SpeciesId.BUNNELBY,
SpeciesId.FLETCHLING, SpeciesId.FLETCHLING,
SpeciesId.PANCHAM, SpeciesId.PANCHAM,
SpeciesId.ESPURR, SpeciesId.ESPURR,
SpeciesId.PUMPKABOO, SpeciesId.SKRELP,
SpeciesId.PHANTUMP,
SpeciesId.CLAUNCHER, SpeciesId.CLAUNCHER,
SpeciesId.HELIOPTILE,
SpeciesId.KLEFKI, SpeciesId.KLEFKI,
SpeciesId.PHANTUMP,
SpeciesId.PUMPKABOO,
], ],
[TrainerPoolTier.UNCOMMON]: [ [TrainerPoolTier.UNCOMMON]: [
SpeciesId.LITWICK, SpeciesId.LITWICK,
SpeciesId.HEATMOR, SpeciesId.HEATMOR,
SpeciesId.BINACLE, SpeciesId.BINACLE,
SpeciesId.SKRELP, SpeciesId.HELIOPTILE,
SpeciesId.BERGMITE, SpeciesId.AVALUGG,
SpeciesId.CAPSAKID, SpeciesId.CAPSAKID,
], ],
[TrainerPoolTier.RARE]: [SpeciesId.GOODRA, SpeciesId.HONEDGE], [TrainerPoolTier.RARE]: [SpeciesId.AERODACTYL, SpeciesId.HONEDGE, SpeciesId.GOOMY],
}; };
const FLARE_XEROSIC: TrainerTierPools = { const FLARE_XEROSIC: TrainerTierPools = {
[TrainerPoolTier.COMMON]: [ [TrainerPoolTier.COMMON]: [
SpeciesId.EKANS,
SpeciesId.LITWICK,
SpeciesId.PANCHAM, SpeciesId.PANCHAM,
SpeciesId.BINACLE, SpeciesId.BINACLE,
[SpeciesId.SKRELP, SpeciesId.CLAUNCHER],
SpeciesId.HELIOPTILE, SpeciesId.HELIOPTILE,
SpeciesId.CLAUNCHER, SpeciesId.KLEFKI,
SpeciesId.BUNNELBY,
SpeciesId.FLETCHLING,
SpeciesId.LITLEO,
SpeciesId.PANGORO,
SpeciesId.ESPURR,
SpeciesId.INKAY,
SpeciesId.CLAUNCHER,
SpeciesId.HELIOPTILE,
], ],
[TrainerPoolTier.UNCOMMON]: [ [TrainerPoolTier.UNCOMMON]: [
[SpeciesId.AMAURA, SpeciesId.TYRUNT], SpeciesId.ROTOM, // Always Rotom-Heat, Xerosic has their specialty type set to fire
SpeciesId.SNEASEL, [SpeciesId.TYRUNT, SpeciesId.AMAURA],
SpeciesId.LITWICK,
SpeciesId.LITLEO,
SpeciesId.BINACLE,
SpeciesId.SKRELP,
SpeciesId.NOIBAT, SpeciesId.NOIBAT,
SpeciesId.PHANTUMP, SpeciesId.SIZZLIPEDE,
SpeciesId.PUMPKABOO, SpeciesId.CAPSAKID,
], ],
[TrainerPoolTier.RARE]: [SpeciesId.HISUI_GOODRA, SpeciesId.HONEDGE], [TrainerPoolTier.RARE]: [SpeciesId.BELDUM, SpeciesId.HISUI_SLIGGOO, SpeciesId.HISUI_AVALUGG],
}; };
const AETHER: TrainerTierPools = { const AETHER: TrainerTierPools = {

View File

@ -420,7 +420,7 @@ const SLOT_4_FIGHT_3 = [
SpeciesId.GOLISOPOD, SpeciesId.GOLISOPOD,
SpeciesId.MIMIKYU, SpeciesId.MIMIKYU,
SpeciesId.DHELMISE, SpeciesId.DHELMISE,
SpeciesId.POLTEAGEIST, [SpeciesId.POLTEAGEIST, SpeciesId.SINISTCHA],
SpeciesId.COPPERAJAH, SpeciesId.COPPERAJAH,
SpeciesId.KLEAVOR, SpeciesId.KLEAVOR,
SpeciesId.BASCULIN, SpeciesId.BASCULIN,
@ -431,7 +431,6 @@ const SLOT_4_FIGHT_3 = [
SpeciesId.DONDOZO, SpeciesId.DONDOZO,
SpeciesId.DUDUNSPARCE, SpeciesId.DUDUNSPARCE,
SpeciesId.GHOLDENGO, SpeciesId.GHOLDENGO,
SpeciesId.POLTCHAGEIST,
[SpeciesId.GALAR_SLOWBRO, SpeciesId.GALAR_SLOWKING], [SpeciesId.GALAR_SLOWBRO, SpeciesId.GALAR_SLOWKING],
SpeciesId.HISUI_ARCANINE, SpeciesId.HISUI_ARCANINE,
SpeciesId.PALDEA_TAUROS, SpeciesId.PALDEA_TAUROS,
@ -485,7 +484,7 @@ const SLOT_4_FINAL = [
SpeciesId.GOLISOPOD, SpeciesId.GOLISOPOD,
SpeciesId.MIMIKYU, SpeciesId.MIMIKYU,
SpeciesId.DHELMISE, SpeciesId.DHELMISE,
SpeciesId.POLTEAGEIST, [SpeciesId.POLTEAGEIST, SpeciesId.SINISTCHA],
SpeciesId.COPPERAJAH, SpeciesId.COPPERAJAH,
SpeciesId.KLEAVOR, SpeciesId.KLEAVOR,
SpeciesId.BASCULEGION, // Ensure gender does not change SpeciesId.BASCULEGION, // Ensure gender does not change
@ -496,7 +495,6 @@ const SLOT_4_FINAL = [
SpeciesId.DONDOZO, SpeciesId.DONDOZO,
SpeciesId.DUDUNSPARCE, SpeciesId.DUDUNSPARCE,
SpeciesId.GHOLDENGO, SpeciesId.GHOLDENGO,
SpeciesId.POLTCHAGEIST,
[SpeciesId.GALAR_SLOWBRO, SpeciesId.GALAR_SLOWKING], [SpeciesId.GALAR_SLOWBRO, SpeciesId.GALAR_SLOWKING],
SpeciesId.HISUI_ARCANINE, SpeciesId.HISUI_ARCANINE,
SpeciesId.PALDEA_TAUROS, SpeciesId.PALDEA_TAUROS,

View File

@ -592,15 +592,9 @@ export class TrainerConfig {
* @param poolName - The evil team the admin belongs to. * @param poolName - The evil team the admin belongs to.
* @param signatureSpecies - The signature species for the evil team leader. * @param signatureSpecies - The signature species for the evil team leader.
* @param specialtyType - The specialty Type of the admin, if they have one * @param specialtyType - The specialty Type of the admin, if they have one
* @param starAdminInstantTeraSlot - (default `4`); If the admin is a Star Admin, the slot that should instantly Tera in {@linkcode ClassicFixedBossWaves.EVIL_ADMIN_3}
* @returns The updated TrainerConfig instance. * @returns The updated TrainerConfig instance.
*/ */
initForEvilTeamAdmin( initForEvilTeamAdmin(title: string, poolName: EvilTeam, specialtyType?: PokemonType): TrainerConfig {
title: string,
poolName: EvilTeam,
specialtyType?: PokemonType,
starAdminInstantTeraSlot = 4,
): TrainerConfig {
if (!getIsInitialized()) { if (!getIsInitialized()) {
initI18n(); initI18n();
} }
@ -609,13 +603,6 @@ export class TrainerConfig {
this.setSpecialtyType(specialtyType); this.setSpecialtyType(specialtyType);
} }
if (title === "star_admin") {
this.setInstantTera(
starAdminInstantTeraSlot,
() => globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3,
);
}
this.setPartyTemplates(trainerPartyTemplates.RIVAL_5); this.setPartyTemplates(trainerPartyTemplates.RIVAL_5);
// Set the species pools for the evil team admin. // Set the species pools for the evil team admin.
@ -2070,7 +2057,6 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerPoolTier.SUPER_RARE]: [SpeciesId.DRATINI, SpeciesId.LARVITAR], [TrainerPoolTier.SUPER_RARE]: [SpeciesId.DRATINI, SpeciesId.LARVITAR],
}), }),
[TrainerType.ARCHER]: new TrainerConfig(++t) [TrainerType.ARCHER]: new TrainerConfig(++t)
.setMoneyMultiplier(1.5)
.initForEvilTeamAdmin("rocket_admin", "rocket_archer") .initForEvilTeamAdmin("rocket_admin", "rocket_archer")
.setEncounterBgm(TrainerType.PLASMA_GRUNT) .setEncounterBgm(TrainerType.PLASMA_GRUNT)
.setBattleBgm("battle_plasma_grunt") .setBattleBgm("battle_plasma_grunt")
@ -2091,7 +2077,6 @@ export const trainerConfigs: TrainerConfigs = {
}), }),
), ),
[TrainerType.ARIANA]: new TrainerConfig(++t) [TrainerType.ARIANA]: new TrainerConfig(++t)
.setMoneyMultiplier(1.5)
.initForEvilTeamAdmin("rocket_admin_female", "rocket_ariana") .initForEvilTeamAdmin("rocket_admin_female", "rocket_ariana")
.setEncounterBgm(TrainerType.PLASMA_GRUNT) .setEncounterBgm(TrainerType.PLASMA_GRUNT)
.setBattleBgm("battle_plasma_grunt") .setBattleBgm("battle_plasma_grunt")
@ -2103,16 +2088,12 @@ export const trainerConfigs: TrainerConfigs = {
.setPartyMemberFunc( .setPartyMemberFunc(
5, 5,
getRandomPartyMemberFunc([SpeciesId.ARBOK], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.ARBOK], TrainerSlot.TRAINER, true, p => {
if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) {
p.setBoss(true, 2);
}
p.abilityIndex = 0; // Intimidate p.abilityIndex = 0; // Intimidate
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL; p.pokeball = PokeballType.ULTRA_BALL;
}), }),
), ),
[TrainerType.PROTON]: new TrainerConfig(++t) [TrainerType.PROTON]: new TrainerConfig(++t)
.setMoneyMultiplier(1.5)
.initForEvilTeamAdmin("rocket_admin", "rocket_proton") .initForEvilTeamAdmin("rocket_admin", "rocket_proton")
.setEncounterBgm(TrainerType.PLASMA_GRUNT) .setEncounterBgm(TrainerType.PLASMA_GRUNT)
.setBattleBgm("battle_plasma_grunt") .setBattleBgm("battle_plasma_grunt")
@ -2124,15 +2105,11 @@ export const trainerConfigs: TrainerConfigs = {
.setPartyMemberFunc( .setPartyMemberFunc(
5, 5,
getRandomPartyMemberFunc([SpeciesId.CROBAT], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.CROBAT], TrainerSlot.TRAINER, true, p => {
if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) {
p.setBoss(true, 2);
}
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL; p.pokeball = PokeballType.ULTRA_BALL;
}), }),
), ),
[TrainerType.PETREL]: new TrainerConfig(++t) [TrainerType.PETREL]: new TrainerConfig(++t)
.setMoneyMultiplier(1.5)
.initForEvilTeamAdmin("rocket_admin", "rocket_petrel") .initForEvilTeamAdmin("rocket_admin", "rocket_petrel")
.setEncounterBgm(TrainerType.PLASMA_GRUNT) .setEncounterBgm(TrainerType.PLASMA_GRUNT)
.setBattleBgm("battle_plasma_grunt") .setBattleBgm("battle_plasma_grunt")
@ -2188,7 +2165,6 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerPoolTier.SUPER_RARE]: [SpeciesId.RHYHORN, SpeciesId.ARON], [TrainerPoolTier.SUPER_RARE]: [SpeciesId.RHYHORN, SpeciesId.ARON],
}), }),
[TrainerType.TABITHA]: new TrainerConfig(++t) [TrainerType.TABITHA]: new TrainerConfig(++t)
.setMoneyMultiplier(1.5)
.initForEvilTeamAdmin("magma_admin", "magma") .initForEvilTeamAdmin("magma_admin", "magma")
.setEncounterBgm(TrainerType.PLASMA_GRUNT) .setEncounterBgm(TrainerType.PLASMA_GRUNT)
.setBattleBgm("battle_plasma_grunt") .setBattleBgm("battle_plasma_grunt")
@ -2200,16 +2176,12 @@ export const trainerConfigs: TrainerConfigs = {
.setPartyMemberFunc( .setPartyMemberFunc(
5, 5,
getRandomPartyMemberFunc([SpeciesId.CAMERUPT], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.CAMERUPT], TrainerSlot.TRAINER, true, p => {
if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) {
p.setBoss(true, 2);
}
p.abilityIndex = 1; // Solid Rock p.abilityIndex = 1; // Solid Rock
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL; p.pokeball = PokeballType.ULTRA_BALL;
}), }),
), ),
[TrainerType.COURTNEY]: new TrainerConfig(++t) [TrainerType.COURTNEY]: new TrainerConfig(++t)
.setMoneyMultiplier(1.5)
.initForEvilTeamAdmin("magma_admin_female", "magma") .initForEvilTeamAdmin("magma_admin_female", "magma")
.setEncounterBgm(TrainerType.PLASMA_GRUNT) .setEncounterBgm(TrainerType.PLASMA_GRUNT)
.setBattleBgm("battle_plasma_grunt") .setBattleBgm("battle_plasma_grunt")
@ -2221,9 +2193,6 @@ export const trainerConfigs: TrainerConfigs = {
.setPartyMemberFunc( .setPartyMemberFunc(
5, 5,
getRandomPartyMemberFunc([SpeciesId.CAMERUPT], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.CAMERUPT], TrainerSlot.TRAINER, true, p => {
if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) {
p.setBoss(true, 2);
}
p.abilityIndex = 1; // Solid Rock p.abilityIndex = 1; // Solid Rock
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL; p.pokeball = PokeballType.ULTRA_BALL;
@ -2273,7 +2242,6 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerPoolTier.SUPER_RARE]: [SpeciesId.FEEBAS, SpeciesId.DONDOZO], [TrainerPoolTier.SUPER_RARE]: [SpeciesId.FEEBAS, SpeciesId.DONDOZO],
}), }),
[TrainerType.MATT]: new TrainerConfig(++t) [TrainerType.MATT]: new TrainerConfig(++t)
.setMoneyMultiplier(1.5)
.initForEvilTeamAdmin("aqua_admin", "aqua") .initForEvilTeamAdmin("aqua_admin", "aqua")
.setEncounterBgm(TrainerType.PLASMA_GRUNT) .setEncounterBgm(TrainerType.PLASMA_GRUNT)
.setBattleBgm("battle_plasma_grunt") .setBattleBgm("battle_plasma_grunt")
@ -2285,15 +2253,11 @@ export const trainerConfigs: TrainerConfigs = {
.setPartyMemberFunc( .setPartyMemberFunc(
5, 5,
getRandomPartyMemberFunc([SpeciesId.SHARPEDO], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.SHARPEDO], TrainerSlot.TRAINER, true, p => {
if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) {
p.setBoss(true, 2);
}
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL; p.pokeball = PokeballType.ULTRA_BALL;
}), }),
), ),
[TrainerType.SHELLY]: new TrainerConfig(++t) [TrainerType.SHELLY]: new TrainerConfig(++t)
.setMoneyMultiplier(1.5)
.initForEvilTeamAdmin("aqua_admin_female", "aqua") .initForEvilTeamAdmin("aqua_admin_female", "aqua")
.setEncounterBgm(TrainerType.PLASMA_GRUNT) .setEncounterBgm(TrainerType.PLASMA_GRUNT)
.setBattleBgm("battle_plasma_grunt") .setBattleBgm("battle_plasma_grunt")
@ -2305,9 +2269,6 @@ export const trainerConfigs: TrainerConfigs = {
.setPartyMemberFunc( .setPartyMemberFunc(
5, 5,
getRandomPartyMemberFunc([SpeciesId.SHARPEDO], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.SHARPEDO], TrainerSlot.TRAINER, true, p => {
if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) {
p.setBoss(true, 2);
}
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL; p.pokeball = PokeballType.ULTRA_BALL;
}), }),
@ -2354,7 +2315,6 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerPoolTier.SUPER_RARE]: [SpeciesId.SPIRITOMB, SpeciesId.ROTOM], [TrainerPoolTier.SUPER_RARE]: [SpeciesId.SPIRITOMB, SpeciesId.ROTOM],
}), }),
[TrainerType.JUPITER]: new TrainerConfig(++t) [TrainerType.JUPITER]: new TrainerConfig(++t)
.setMoneyMultiplier(1.5)
.initForEvilTeamAdmin("galactic_commander_female", "galactic_jupiter") .initForEvilTeamAdmin("galactic_commander_female", "galactic_jupiter")
.setEncounterBgm(TrainerType.PLASMA_GRUNT) .setEncounterBgm(TrainerType.PLASMA_GRUNT)
.setBattleBgm("battle_plasma_grunt") .setBattleBgm("battle_plasma_grunt")
@ -2366,15 +2326,11 @@ export const trainerConfigs: TrainerConfigs = {
.setPartyMemberFunc( .setPartyMemberFunc(
5, 5,
getRandomPartyMemberFunc([SpeciesId.SKUNTANK], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.SKUNTANK], TrainerSlot.TRAINER, true, p => {
if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) {
p.setBoss(true, 2);
}
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL; p.pokeball = PokeballType.ULTRA_BALL;
}), }),
), ),
[TrainerType.MARS]: new TrainerConfig(++t) [TrainerType.MARS]: new TrainerConfig(++t)
.setMoneyMultiplier(1.5)
.initForEvilTeamAdmin("galactic_commander_female", "galactic_mars") .initForEvilTeamAdmin("galactic_commander_female", "galactic_mars")
.setEncounterBgm(TrainerType.PLASMA_GRUNT) .setEncounterBgm(TrainerType.PLASMA_GRUNT)
.setBattleBgm("battle_plasma_grunt") .setBattleBgm("battle_plasma_grunt")
@ -2386,16 +2342,12 @@ export const trainerConfigs: TrainerConfigs = {
.setPartyMemberFunc( .setPartyMemberFunc(
5, 5,
getRandomPartyMemberFunc([SpeciesId.PURUGLY], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.PURUGLY], TrainerSlot.TRAINER, true, p => {
if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) {
p.setBoss(true, 2);
}
p.abilityIndex = 0; // Thick Fat p.abilityIndex = 0; // Thick Fat
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL; p.pokeball = PokeballType.ULTRA_BALL;
}), }),
), ),
[TrainerType.SATURN]: new TrainerConfig(++t) [TrainerType.SATURN]: new TrainerConfig(++t)
.setMoneyMultiplier(1.5)
.initForEvilTeamAdmin("galactic_commander", "galactic_saturn") .initForEvilTeamAdmin("galactic_commander", "galactic_saturn")
.setEncounterBgm(TrainerType.PLASMA_GRUNT) .setEncounterBgm(TrainerType.PLASMA_GRUNT)
.setBattleBgm("battle_plasma_grunt") .setBattleBgm("battle_plasma_grunt")
@ -2407,9 +2359,6 @@ export const trainerConfigs: TrainerConfigs = {
.setPartyMemberFunc( .setPartyMemberFunc(
5, 5,
getRandomPartyMemberFunc([SpeciesId.TOXICROAK], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.TOXICROAK], TrainerSlot.TRAINER, true, p => {
if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) {
p.setBoss(true, 2);
}
p.abilityIndex = 1; // Dry Skin p.abilityIndex = 1; // Dry Skin
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL; p.pokeball = PokeballType.ULTRA_BALL;
@ -2460,7 +2409,6 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerPoolTier.SUPER_RARE]: [SpeciesId.AXEW, SpeciesId.DRUDDIGON, SpeciesId.DEINO, SpeciesId.HISUI_ZORUA], [TrainerPoolTier.SUPER_RARE]: [SpeciesId.AXEW, SpeciesId.DRUDDIGON, SpeciesId.DEINO, SpeciesId.HISUI_ZORUA],
}), }),
[TrainerType.ZINZOLIN]: new TrainerConfig(++t) [TrainerType.ZINZOLIN]: new TrainerConfig(++t)
.setMoneyMultiplier(1.5)
.initForEvilTeamAdmin("plasma_sage", "plasma_zinzolin") .initForEvilTeamAdmin("plasma_sage", "plasma_zinzolin")
.setEncounterBgm(TrainerType.PLASMA_GRUNT) .setEncounterBgm(TrainerType.PLASMA_GRUNT)
.setBattleBgm("battle_plasma_grunt") .setBattleBgm("battle_plasma_grunt")
@ -2477,7 +2425,6 @@ export const trainerConfigs: TrainerConfigs = {
}), }),
), ),
[TrainerType.COLRESS]: new TrainerConfig(++t) [TrainerType.COLRESS]: new TrainerConfig(++t)
.setMoneyMultiplier(1.5)
.initForEvilTeamAdmin("plasma_boss", "plasma_colress") .initForEvilTeamAdmin("plasma_boss", "plasma_colress")
.setEncounterBgm(TrainerType.PLASMA_GRUNT) .setEncounterBgm(TrainerType.PLASMA_GRUNT)
.setBattleBgm("battle_colress") .setBattleBgm("battle_colress")
@ -2489,9 +2436,6 @@ export const trainerConfigs: TrainerConfigs = {
.setPartyMemberFunc( .setPartyMemberFunc(
5, 5,
getRandomPartyMemberFunc([SpeciesId.KLINKLANG], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.KLINKLANG], TrainerSlot.TRAINER, true, p => {
if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) {
p.setBoss(true, 2);
}
p.abilityIndex = 2; // Clear Body p.abilityIndex = 2; // Clear Body
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL; p.pokeball = PokeballType.ULTRA_BALL;
@ -2537,7 +2481,6 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerPoolTier.SUPER_RARE]: [SpeciesId.GOOMY, SpeciesId.HONEDGE], [TrainerPoolTier.SUPER_RARE]: [SpeciesId.GOOMY, SpeciesId.HONEDGE],
}), }),
[TrainerType.BRYONY]: new TrainerConfig(++t) [TrainerType.BRYONY]: new TrainerConfig(++t)
.setMoneyMultiplier(1.5)
.initForEvilTeamAdmin("flare_admin_female", "flare") .initForEvilTeamAdmin("flare_admin_female", "flare")
.setEncounterBgm(TrainerType.PLASMA_GRUNT) .setEncounterBgm(TrainerType.PLASMA_GRUNT)
.setBattleBgm("battle_plasma_grunt") .setBattleBgm("battle_plasma_grunt")
@ -2553,7 +2496,6 @@ export const trainerConfigs: TrainerConfigs = {
}), }),
), ),
[TrainerType.XEROSIC]: new TrainerConfig(++t) [TrainerType.XEROSIC]: new TrainerConfig(++t)
.setMoneyMultiplier(1.5)
.initForEvilTeamAdmin("flare_admin", "flare_xerosic", PokemonType.FIRE) .initForEvilTeamAdmin("flare_admin", "flare_xerosic", PokemonType.FIRE)
.setEncounterBgm(TrainerType.PLASMA_GRUNT) .setEncounterBgm(TrainerType.PLASMA_GRUNT)
.setBattleBgm("battle_plasma_grunt") .setBattleBgm("battle_plasma_grunt")
@ -2564,9 +2506,6 @@ export const trainerConfigs: TrainerConfigs = {
.setPartyMemberFunc( .setPartyMemberFunc(
5, 5,
getRandomPartyMemberFunc([SpeciesId.MALAMAR], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.MALAMAR], TrainerSlot.TRAINER, true, p => {
if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) {
p.setBoss(true, 2);
}
p.abilityIndex = 0; // Contrary p.abilityIndex = 0; // Contrary
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL; p.pokeball = PokeballType.ULTRA_BALL;
@ -2624,7 +2563,6 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerPoolTier.SUPER_RARE]: [SpeciesId.PORYGON, SpeciesId.JANGMO_O], [TrainerPoolTier.SUPER_RARE]: [SpeciesId.PORYGON, SpeciesId.JANGMO_O],
}), }),
[TrainerType.FABA]: new TrainerConfig(++t) [TrainerType.FABA]: new TrainerConfig(++t)
.setMoneyMultiplier(1.5)
.initForEvilTeamAdmin("aether_admin", "aether") .initForEvilTeamAdmin("aether_admin", "aether")
.setEncounterBgm(TrainerType.PLASMA_GRUNT) .setEncounterBgm(TrainerType.PLASMA_GRUNT)
.setBattleBgm("battle_plasma_grunt") .setBattleBgm("battle_plasma_grunt")
@ -2636,9 +2574,6 @@ export const trainerConfigs: TrainerConfigs = {
.setPartyMemberFunc( .setPartyMemberFunc(
5, 5,
getRandomPartyMemberFunc([SpeciesId.HYPNO], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.HYPNO], TrainerSlot.TRAINER, true, p => {
if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) {
p.setBoss(true, 2);
}
p.abilityIndex = 1; // FOREWARN p.abilityIndex = 1; // FOREWARN
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL; p.pokeball = PokeballType.ULTRA_BALL;
@ -2691,7 +2626,6 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerPoolTier.SUPER_RARE]: [SpeciesId.PAWNIARD, SpeciesId.GRUBBIN], [TrainerPoolTier.SUPER_RARE]: [SpeciesId.PAWNIARD, SpeciesId.GRUBBIN],
}), }),
[TrainerType.PLUMERIA]: new TrainerConfig(++t) [TrainerType.PLUMERIA]: new TrainerConfig(++t)
.setMoneyMultiplier(1.5)
.initForEvilTeamAdmin("skull_admin", "skull") .initForEvilTeamAdmin("skull_admin", "skull")
.setEncounterBgm(TrainerType.PLASMA_GRUNT) .setEncounterBgm(TrainerType.PLASMA_GRUNT)
.setBattleBgm("battle_plasma_grunt") .setBattleBgm("battle_plasma_grunt")
@ -2703,9 +2637,6 @@ export const trainerConfigs: TrainerConfigs = {
.setPartyMemberFunc( .setPartyMemberFunc(
5, 5,
getRandomPartyMemberFunc([SpeciesId.SALAZZLE], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.SALAZZLE], TrainerSlot.TRAINER, true, p => {
if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) {
p.setBoss(true, 2);
}
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL; p.pokeball = PokeballType.ULTRA_BALL;
}), }),
@ -2756,7 +2687,6 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerPoolTier.SUPER_RARE]: [SpeciesId.DURALUDON, SpeciesId.DREEPY], [TrainerPoolTier.SUPER_RARE]: [SpeciesId.DURALUDON, SpeciesId.DREEPY],
}), }),
[TrainerType.OLEANA]: new TrainerConfig(++t) [TrainerType.OLEANA]: new TrainerConfig(++t)
.setMoneyMultiplier(1.5)
.initForEvilTeamAdmin("macro_admin", "macro_cosmos") .initForEvilTeamAdmin("macro_admin", "macro_cosmos")
.setEncounterBgm(TrainerType.PLASMA_GRUNT) .setEncounterBgm(TrainerType.PLASMA_GRUNT)
.setBattleBgm("battle_plasma_grunt") .setBattleBgm("battle_plasma_grunt")
@ -2768,9 +2698,6 @@ export const trainerConfigs: TrainerConfigs = {
.setPartyMemberFunc( .setPartyMemberFunc(
5, 5,
getRandomPartyMemberFunc([SpeciesId.GARBODOR], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.GARBODOR], TrainerSlot.TRAINER, true, p => {
if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) {
p.setBoss(true, 2);
}
p.abilityIndex = 1; // Weak Armor p.abilityIndex = 1; // Weak Armor
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL; p.pokeball = PokeballType.ULTRA_BALL;
@ -2836,7 +2763,6 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerPoolTier.SUPER_RARE]: [SpeciesId.DONDOZO, SpeciesId.GIMMIGHOUL], [TrainerPoolTier.SUPER_RARE]: [SpeciesId.DONDOZO, SpeciesId.GIMMIGHOUL],
}), }),
[TrainerType.GIACOMO]: new TrainerConfig(++t) [TrainerType.GIACOMO]: new TrainerConfig(++t)
.setMoneyMultiplier(1.5)
.initForEvilTeamAdmin("star_admin", "star_dark", PokemonType.DARK) .initForEvilTeamAdmin("star_admin", "star_dark", PokemonType.DARK)
.setEncounterBgm(TrainerType.PLASMA_GRUNT) .setEncounterBgm(TrainerType.PLASMA_GRUNT)
.setBattleBgm("battle_plasma_grunt") .setBattleBgm("battle_plasma_grunt")
@ -2853,6 +2779,7 @@ export const trainerConfigs: TrainerConfigs = {
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
} else { } else {
p.formIndex = 1; // Segin Starmobile p.formIndex = 1; // Segin Starmobile
p.gender = Gender.GENDERLESS;
p.moveset = [ p.moveset = [
new PokemonMove(MoveId.WICKED_TORQUE), new PokemonMove(MoveId.WICKED_TORQUE),
new PokemonMove(MoveId.SPIN_OUT), new PokemonMove(MoveId.SPIN_OUT),
@ -2863,7 +2790,6 @@ export const trainerConfigs: TrainerConfigs = {
}), }),
), ),
[TrainerType.MELA]: new TrainerConfig(++t) [TrainerType.MELA]: new TrainerConfig(++t)
.setMoneyMultiplier(1.5)
.initForEvilTeamAdmin("star_admin", "star_fire", PokemonType.FIRE) .initForEvilTeamAdmin("star_admin", "star_fire", PokemonType.FIRE)
.setEncounterBgm(TrainerType.PLASMA_GRUNT) .setEncounterBgm(TrainerType.PLASMA_GRUNT)
.setBattleBgm("battle_plasma_grunt") .setBattleBgm("battle_plasma_grunt")
@ -2880,6 +2806,7 @@ export const trainerConfigs: TrainerConfigs = {
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
} else { } else {
p.formIndex = 2; // Schedar Starmobile p.formIndex = 2; // Schedar Starmobile
p.gender = Gender.GENDERLESS;
p.moveset = [ p.moveset = [
new PokemonMove(MoveId.BLAZING_TORQUE), new PokemonMove(MoveId.BLAZING_TORQUE),
new PokemonMove(MoveId.SPIN_OUT), new PokemonMove(MoveId.SPIN_OUT),
@ -2890,7 +2817,6 @@ export const trainerConfigs: TrainerConfigs = {
}), }),
), ),
[TrainerType.ATTICUS]: new TrainerConfig(++t) [TrainerType.ATTICUS]: new TrainerConfig(++t)
.setMoneyMultiplier(1.5)
.initForEvilTeamAdmin("star_admin", "star_poison", PokemonType.POISON) .initForEvilTeamAdmin("star_admin", "star_poison", PokemonType.POISON)
.setEncounterBgm(TrainerType.PLASMA_GRUNT) .setEncounterBgm(TrainerType.PLASMA_GRUNT)
.setBattleBgm("battle_plasma_grunt") .setBattleBgm("battle_plasma_grunt")
@ -2907,6 +2833,7 @@ export const trainerConfigs: TrainerConfigs = {
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
} else { } else {
p.formIndex = 3; // Navi Starmobile p.formIndex = 3; // Navi Starmobile
p.gender = Gender.GENDERLESS;
p.moveset = [ p.moveset = [
new PokemonMove(MoveId.NOXIOUS_TORQUE), new PokemonMove(MoveId.NOXIOUS_TORQUE),
new PokemonMove(MoveId.SPIN_OUT), new PokemonMove(MoveId.SPIN_OUT),
@ -2917,7 +2844,6 @@ export const trainerConfigs: TrainerConfigs = {
}), }),
), ),
[TrainerType.ORTEGA]: new TrainerConfig(++t) [TrainerType.ORTEGA]: new TrainerConfig(++t)
.setMoneyMultiplier(1.5)
.initForEvilTeamAdmin("star_admin", "star_fairy", PokemonType.FAIRY) .initForEvilTeamAdmin("star_admin", "star_fairy", PokemonType.FAIRY)
.setEncounterBgm(TrainerType.PLASMA_GRUNT) .setEncounterBgm(TrainerType.PLASMA_GRUNT)
.setBattleBgm("battle_plasma_grunt") .setBattleBgm("battle_plasma_grunt")
@ -2934,6 +2860,7 @@ export const trainerConfigs: TrainerConfigs = {
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
} else { } else {
p.formIndex = 4; // Ruchbah Starmobile p.formIndex = 4; // Ruchbah Starmobile
p.gender = Gender.GENDERLESS;
p.moveset = [ p.moveset = [
new PokemonMove(MoveId.MAGICAL_TORQUE), new PokemonMove(MoveId.MAGICAL_TORQUE),
new PokemonMove(MoveId.SPIN_OUT), new PokemonMove(MoveId.SPIN_OUT),
@ -2944,7 +2871,6 @@ export const trainerConfigs: TrainerConfigs = {
}), }),
), ),
[TrainerType.ERI]: new TrainerConfig(++t) [TrainerType.ERI]: new TrainerConfig(++t)
.setMoneyMultiplier(1.5)
.initForEvilTeamAdmin("star_admin", "star_fighting", PokemonType.FIGHTING) .initForEvilTeamAdmin("star_admin", "star_fighting", PokemonType.FIGHTING)
.setEncounterBgm(TrainerType.PLASMA_GRUNT) .setEncounterBgm(TrainerType.PLASMA_GRUNT)
.setBattleBgm("battle_plasma_grunt") .setBattleBgm("battle_plasma_grunt")
@ -2961,6 +2887,7 @@ export const trainerConfigs: TrainerConfigs = {
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
} else { } else {
p.formIndex = 5; // Caph Starmobile p.formIndex = 5; // Caph Starmobile
p.gender = Gender.GENDERLESS;
p.moveset = [ p.moveset = [
new PokemonMove(MoveId.COMBAT_TORQUE), new PokemonMove(MoveId.COMBAT_TORQUE),
new PokemonMove(MoveId.SPIN_OUT), new PokemonMove(MoveId.SPIN_OUT),
@ -4385,6 +4312,8 @@ export const trainerConfigs: TrainerConfigs = {
getRandomPartyMemberFunc([SpeciesId.TOGEKISS], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.TOGEKISS], TrainerSlot.TRAINER, true, p => {
p.abilityIndex = 1; // Serene Grace p.abilityIndex = 1; // Serene Grace
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.moveset[0] = new PokemonMove(MoveId.DAZZLING_GLEAM);
p.moveset[1] = new PokemonMove(MoveId.AIR_SLASH);
p.teraType = p.species.type1; p.teraType = p.species.type1;
}), }),
) )
@ -4401,9 +4330,13 @@ export const trainerConfigs: TrainerConfigs = {
getRandomPartyMemberFunc([SpeciesId.GARCHOMP], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.GARCHOMP], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2); p.setBoss(true, 2);
p.formIndex = 1; // Mega Garchomp p.formIndex = 1; // Mega Garchomp
p.generateAndPopulateMoveset();
p.generateName(); p.generateName();
p.gender = Gender.FEMALE; p.gender = Gender.FEMALE;
p.generateAndPopulateMoveset();
if (!p.moveset.some(move => move != null && move.moveId === MoveId.SANDSTORM)) {
// Check if Sandstorm is in the moveset, if not, replace the fourth move with Sandstorm.
p.moveset[3] = new PokemonMove(MoveId.SANDSTORM);
}
}), }),
) )
.setInstantTera(2), // Tera Fairy Togekiss .setInstantTera(2), // Tera Fairy Togekiss
@ -4559,16 +4492,10 @@ export const trainerConfigs: TrainerConfigs = {
) )
.setPartyMemberFunc( .setPartyMemberFunc(
2, 2,
getRandomPartyMemberFunc( getRandomPartyMemberFunc([SpeciesId.SNORLAX], TrainerSlot.TRAINER, true, p => {
[SpeciesId.TORNADUS, SpeciesId.THUNDURUS, SpeciesId.LANDORUS], p.formIndex = 1; // G-Max
TrainerSlot.TRAINER,
true,
p => {
p.formIndex = 1; // Therian Formes
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ROGUE_BALL; }),
},
),
) )
.setPartyMemberFunc( .setPartyMemberFunc(
3, 3,
@ -4580,9 +4507,9 @@ export const trainerConfigs: TrainerConfigs = {
) )
.setPartyMemberFunc( .setPartyMemberFunc(
4, 4,
getRandomPartyMemberFunc([SpeciesId.SNORLAX], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.LUNALA], TrainerSlot.TRAINER, true, p => {
p.formIndex = 1; // G-Max Snorlax
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.MASTER_BALL;
}), }),
) )
.setPartyMemberFunc( .setPartyMemberFunc(
@ -5522,9 +5449,12 @@ export const trainerConfigs: TrainerConfigs = {
5, 5,
getRandomPartyMemberFunc([SpeciesId.NECROZMA], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.NECROZMA], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2); p.setBoss(true, 2);
p.formIndex = 2; // Dawn Wings
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.MASTER_BALL; p.pokeball = PokeballType.MASTER_BALL;
p.generateAndPopulateMoveset();
if (!p.moveset.some(move => move != null && move.moveId === MoveId.PHOTON_GEYSER)) {
// Check if Photon Geyser is in the moveset, if not, replace the first move with Photon Geyser.
p.moveset[0] = new PokemonMove(MoveId.PHOTON_GEYSER);
}
}), }),
), ),
[TrainerType.GUZMA]: new TrainerConfig(++t) [TrainerType.GUZMA]: new TrainerConfig(++t)
@ -5543,18 +5473,15 @@ export const trainerConfigs: TrainerConfigs = {
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
}), }),
) )
.setPartyMemberFunc(1, getRandomPartyMemberFunc([SpeciesId.HERACROSS]))
.setPartyMemberFunc( .setPartyMemberFunc(
2, 1,
getRandomPartyMemberFunc([SpeciesId.SCIZOR, SpeciesId.KLEAVOR], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.SCIZOR], TrainerSlot.TRAINER, true, p => {
if (p.species.speciesId === SpeciesId.SCIZOR) {
p.abilityIndex = 1; // Technician p.abilityIndex = 1; // Technician
} else if (p.species.speciesId === SpeciesId.KLEAVOR) {
p.abilityIndex = 2; // Sharpness
}
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.gender = Gender.MALE;
}), }),
) )
.setPartyMemberFunc(2, getRandomPartyMemberFunc([SpeciesId.HERACROSS]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.GALVANTULA, SpeciesId.VIKAVOLT])) .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.GALVANTULA, SpeciesId.VIKAVOLT]))
.setPartyMemberFunc( .setPartyMemberFunc(
4, 4,
@ -5562,6 +5489,7 @@ export const trainerConfigs: TrainerConfigs = {
p.formIndex = 1; // Mega Pinsir p.formIndex = 1; // Mega Pinsir
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL; p.pokeball = PokeballType.ULTRA_BALL;
p.gender = Gender.MALE;
p.generateName(); p.generateName();
}), }),
) )
@ -5569,11 +5497,11 @@ export const trainerConfigs: TrainerConfigs = {
5, 5,
getRandomPartyMemberFunc([SpeciesId.GOLISOPOD], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.GOLISOPOD], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2); p.setBoss(true, 2);
p.gender = Gender.MALE;
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
if (!p.moveset.some(move => move != null && move.moveId === MoveId.FIRST_IMPRESSION)) { if (!p.moveset.some(move => move != null && move.moveId === MoveId.FIRST_IMPRESSION)) {
// Check if First Impression is in the moveset, if not, replace the third move with First Impression. // Check if First Impression is in the moveset, if not, replace the third move with First Impression.
p.moveset[2] = new PokemonMove(MoveId.FIRST_IMPRESSION); p.moveset[2] = new PokemonMove(MoveId.FIRST_IMPRESSION);
p.gender = Gender.MALE;
} }
}), }),
), ),
@ -5586,27 +5514,36 @@ export const trainerConfigs: TrainerConfigs = {
0, 0,
getRandomPartyMemberFunc([SpeciesId.GOLISOPOD], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.GOLISOPOD], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2); p.setBoss(true, 2);
p.abilityIndex = 2; // Anticipation
p.gender = Gender.MALE;
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
if (!p.moveset.some(move => move != null && move.moveId === MoveId.FIRST_IMPRESSION)) { if (!p.moveset.some(move => move != null && move.moveId === MoveId.FIRST_IMPRESSION)) {
// Check if First Impression is in the moveset, if not, replace the third move with First Impression. // Check if First Impression is in the moveset, if not, replace the third move with First Impression.
p.moveset[2] = new PokemonMove(MoveId.FIRST_IMPRESSION); p.moveset[2] = new PokemonMove(MoveId.FIRST_IMPRESSION);
p.abilityIndex = 2; // Anticipation
p.gender = Gender.MALE;
} }
}), }),
) )
.setPartyMemberFunc( .setPartyMemberFunc(
1, 1,
getRandomPartyMemberFunc([SpeciesId.BUZZWOLE], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.SCIZOR], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ROGUE_BALL; p.abilityIndex = 1; // Technician
p.moveset[0] = new PokemonMove(MoveId.BUG_BITE);
p.moveset[1] = new PokemonMove(MoveId.BULLET_PUNCH);
p.gender = Gender.MALE;
p.pokeball = PokeballType.ULTRA_BALL;
}), }),
) )
.setPartyMemberFunc( .setPartyMemberFunc(
2, 2,
getRandomPartyMemberFunc([SpeciesId.CRAWDAUNT, SpeciesId.HISUI_SAMUROTT], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.CRAWDAUNT, SpeciesId.HISUI_SAMUROTT], TrainerSlot.TRAINER, true, p => {
p.abilityIndex = 2; // Sharpness Hisuian Samurott, Adaptability Crawdaunt p.abilityIndex = 2; // Adaptability Crawdaunt, Sharpness Samurott
p.pokeball = PokeballType.ULTRA_BALL;
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
if (!p.moveset.some(move => move != null && move.moveId === MoveId.AQUA_JET)) {
// Check if Aqua Jet is in the moveset, if not, replace the third move with Aqua Jet.
p.moveset[2] = new PokemonMove(MoveId.AQUA_JET);
}
}), }),
) )
.setPartyMemberFunc( .setPartyMemberFunc(
@ -5618,26 +5555,22 @@ export const trainerConfigs: TrainerConfigs = {
) )
.setPartyMemberFunc( .setPartyMemberFunc(
4, 4,
getRandomPartyMemberFunc([SpeciesId.GENESECT], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ROGUE_BALL;
p.formIndex = randSeedInt(4, 1); // Shock, Burn, Chill, or Douse Drive
if (!p.moveset.some(move => move != null && move.moveId === MoveId.TECHNO_BLAST)) {
// Check if Techno Blast is in the moveset, if not, replace the third move with Techno Blast.
p.moveset[2] = new PokemonMove(MoveId.TECHNO_BLAST);
}
}),
)
.setPartyMemberFunc(
5,
getRandomPartyMemberFunc([SpeciesId.PINSIR], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.PINSIR], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2); p.setBoss(true, 2);
p.formIndex = 1; // Mega Pinsir p.formIndex = 1; // Mega Pinsir
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.generateName(); p.generateName();
p.gender = Gender.MALE;
p.pokeball = PokeballType.ULTRA_BALL; p.pokeball = PokeballType.ULTRA_BALL;
}), }),
)
.setPartyMemberFunc(
5,
getRandomPartyMemberFunc([SpeciesId.BUZZWOLE], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ROGUE_BALL;
}),
), ),
[TrainerType.ROSE]: new TrainerConfig(++t) [TrainerType.ROSE]: new TrainerConfig(++t)
.setName("Rose") .setName("Rose")
@ -5825,6 +5758,7 @@ export const trainerConfigs: TrainerConfigs = {
getRandomPartyMemberFunc([SpeciesId.REVAVROOM], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.REVAVROOM], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2); p.setBoss(true, 2);
p.formIndex = randSeedInt(5, 1); // Random Starmobile form p.formIndex = randSeedInt(5, 1); // Random Starmobile form
p.gender = Gender.GENDERLESS;
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ROGUE_BALL; p.pokeball = PokeballType.ROGUE_BALL;
}), }),

View File

@ -3675,15 +3675,6 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
multiStrikeEnhancementMultiplier, multiStrikeEnhancementMultiplier,
); );
if (!ignoreSourceAbility) {
applyAbAttrs("AddSecondStrikeAbAttr", {
pokemon: source,
move,
simulated,
multiplier: multiStrikeEnhancementMultiplier,
});
}
/** Doubles damage if this Pokemon's last move was Glaive Rush */ /** Doubles damage if this Pokemon's last move was Glaive Rush */
const glaiveRushMultiplier = new NumberHolder(1); const glaiveRushMultiplier = new NumberHolder(1);
if (this.getTag(BattlerTagType.RECEIVE_DOUBLE_DAMAGE)) { if (this.getTag(BattlerTagType.RECEIVE_DOUBLE_DAMAGE)) {
@ -3772,9 +3763,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
* mistyTerrainMultiplier, * mistyTerrainMultiplier,
); );
/** Doubles damage if the attacker has Tinted Lens and is using a resisted move */
if (!ignoreSourceAbility) { if (!ignoreSourceAbility) {
applyAbAttrs("DamageBoostAbAttr", { applyAbAttrs("MoveDamageBoostAbAttr", {
pokemon: source, pokemon: source,
opponent: this, opponent: this,
move, move,

View File

@ -276,7 +276,7 @@ export class MoveEffectPhase extends PokemonPhase {
// Assume single target for multi hit // Assume single target for multi hit
applyMoveAttrs("MultiHitAttr", user, this.getFirstTarget() ?? null, move, hitCount); applyMoveAttrs("MultiHitAttr", user, this.getFirstTarget() ?? null, move, hitCount);
// If Parental Bond is applicable, add another hit // If Parental Bond is applicable, add another hit
applyAbAttrs("AddSecondStrikeAbAttr", { pokemon: user, move, hitCount }); applyAbAttrs("AddSecondStrikeAbAttr", { pokemon: user, move, hitCount, opponent: this.getFirstTarget() });
// If Multi-Lens is applicable, add hits equal to the number of held Multi-Lenses // If Multi-Lens is applicable, add hits equal to the number of held Multi-Lenses
globalScene.applyModifiers(PokemonMultiHitModifier, user.isPlayer(), user, move.id, hitCount); globalScene.applyModifiers(PokemonMultiHitModifier, user.isPlayer(), user, move.id, hitCount);
// Set the user's relevant turnData fields to reflect the final hit count // Set the user's relevant turnData fields to reflect the final hit count

View File

@ -205,7 +205,7 @@ export class MovePhase extends PokemonPhase {
user.cureStatus( user.cureStatus(
StatusEffect.FREEZE, StatusEffect.FREEZE,
i18next.t("statusEffect:freeze.healByMove", { i18next.t("statusEffect:freeze.healByMove", {
pokemonName: getPokemonNameWithAffix(user), pokemonNameWithAffix: getPokemonNameWithAffix(user),
moveName: this.move.getMove().name, moveName: this.move.getMove().name,
}), }),
); );
@ -509,6 +509,9 @@ export class MovePhase extends PokemonPhase {
) { ) {
this.showFailedText(); this.showFailedText();
this.fail(); this.fail();
// clear out 2 turn moves
// TODO: Make a helper for this atp
this.pokemon.getMoveQueue().shift();
this.pokemon.pushMoveHistory(this.moveHistoryEntry); this.pokemon.pushMoveHistory(this.moveHistoryEntry);
return true; return true;
} }

View File

@ -268,7 +268,13 @@ export class TitlePhase extends Phase {
globalScene.addModifier(m, true, false, false, true); globalScene.addModifier(m, true, false, false, true);
} }
for (const m of timedEventManager.getEventDailyStartingItems()) { for (const m of timedEventManager.getEventDailyStartingItems()) {
globalScene.addModifier(modifierTypes[m]().newModifier(), true, false, false, true); globalScene.addModifier(
modifierTypes[m]().withIdFromFunc(modifierTypes[m]).newModifier(),
true,
false,
false,
true,
);
} }
globalScene.updateModifiers(true, true); globalScene.updateModifiers(true, true);

View File

@ -396,7 +396,7 @@ const timedEvents: readonly TimedEvent[] = [
name: "Halloween 25", name: "Halloween 25",
eventType: EventType.SHINY, eventType: EventType.SHINY,
startDate: new Date(Date.UTC(2025, 9, 30)), startDate: new Date(Date.UTC(2025, 9, 30)),
endDate: new Date(Date.UTC(2025, 10, 10)), endDate: new Date(Date.UTC(2025, 10, 12)),
bannerKey: "halloween2025", bannerKey: "halloween2025",
scale: 0.19, scale: 0.19,
availableLangs: ["en", "de", "it", "fr", "ja", "ko", "es-ES", "es-419", "pt-BR", "zh-Hans", "zh-Hant", "da", "ru"], availableLangs: ["en", "de", "it", "fr", "ja", "ko", "es-ES", "es-419", "pt-BR", "zh-Hans", "zh-Hant", "da", "ru"],

View File

@ -384,4 +384,24 @@ describe("Abilities - Parental Bond", () => {
// TODO: Update hit count to 1 once Future Sight is fixed to not activate abilities if user is off the field // TODO: Update hit count to 1 once Future Sight is fixed to not activate abilities if user is off the field
expect(enemyPokemon.damageAndUpdate).toHaveBeenCalledTimes(2); expect(enemyPokemon.damageAndUpdate).toHaveBeenCalledTimes(2);
}); });
it("should not reduce damage against the remaining target if the first one faints", async () => {
game.override.battleStyle("double").enemySpecies(SpeciesId.MAGIKARP);
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
const feebas = game.field.getPlayerPokemon();
const [karp1, karp2] = game.scene.getEnemyField();
// Mock base damage for both mons for consistent results
vi.spyOn(karp1, "getBaseDamage").mockReturnValue(100);
vi.spyOn(karp2, "getBaseDamage").mockReturnValue(100);
karp1.hp = 1;
game.move.use(MoveId.HYPER_VOICE);
await game.toEndOfTurn();
expect(karp1).toHaveFainted();
expect(feebas).not.toHaveAbilityApplied(AbilityId.PARENTAL_BOND);
expect(karp2).toHaveTakenDamage(100);
});
}); });

View File

@ -26,6 +26,7 @@ describe("Items - Multi Lens", () => {
game.override game.override
.moveset([MoveId.TACKLE, MoveId.TRAILBLAZE, MoveId.TACHYON_CUTTER, MoveId.FUTURE_SIGHT]) .moveset([MoveId.TACKLE, MoveId.TRAILBLAZE, MoveId.TACHYON_CUTTER, MoveId.FUTURE_SIGHT])
.ability(AbilityId.BALL_FETCH) .ability(AbilityId.BALL_FETCH)
.passiveAbility(AbilityId.NO_GUARD)
.startingHeldItems([{ name: "MULTI_LENS" }]) .startingHeldItems([{ name: "MULTI_LENS" }])
.battleStyle("single") .battleStyle("single")
.criticalHits(false) .criticalHits(false)
@ -135,61 +136,36 @@ describe("Items - Multi Lens", () => {
expect(damageResults[1]).toBe(Math.floor(playerPokemon.level * 0.25)); expect(damageResults[1]).toBe(Math.floor(playerPokemon.level * 0.25));
}); });
it("should result in correct damage for hp% attacks with 1 lens", async () => { it.each([1, 2])("should result in original damage for HP-cutting attacks with %d lenses", async lensCount => {
game.override game.override
.startingHeldItems([{ name: "MULTI_LENS", count: 1 }]) .startingHeldItems([{ name: "MULTI_LENS", count: lensCount }])
.moveset(MoveId.SUPER_FANG)
.ability(AbilityId.COMPOUND_EYES)
.enemyLevel(1000) .enemyLevel(1000)
.enemySpecies(SpeciesId.BLISSEY); // allows for unrealistically high levels of accuracy .enemySpecies(SpeciesId.BLISSEY); // allows for unrealistically high levels of accuracy
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); const blissey = game.field.getEnemyPokemon();
const enemyPokemon = game.field.getEnemyPokemon(); game.move.use(MoveId.SUPER_FANG);
await game.toEndOfTurn();
game.move.select(MoveId.SUPER_FANG); expect(blissey.getHpRatio()).toBeCloseTo(0.5, 5);
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to("MoveEndPhase");
expect(enemyPokemon.getHpRatio()).toBeCloseTo(0.5, 5);
}); });
it("should result in correct damage for hp% attacks with 2 lenses", async () => { it("should result in original damage for HP-cutting attacks with 2 lenses + Parental Bond", async () => {
game.override game.override
.startingHeldItems([{ name: "MULTI_LENS", count: 2 }]) .startingHeldItems([{ name: "MULTI_LENS", count: 2 }])
.moveset(MoveId.SUPER_FANG)
.ability(AbilityId.COMPOUND_EYES)
.enemyMoveset(MoveId.SPLASH)
.enemyLevel(1000)
.enemySpecies(SpeciesId.BLISSEY); // allows for unrealistically high levels of accuracy
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const enemyPokemon = game.field.getEnemyPokemon();
game.move.select(MoveId.SUPER_FANG);
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to("MoveEndPhase");
expect(enemyPokemon.getHpRatio()).toBeCloseTo(0.5, 5);
});
it("should result in correct damage for hp% attacks with 2 lenses + Parental Bond", async () => {
game.override
.startingHeldItems([{ name: "MULTI_LENS", count: 2 }])
.moveset(MoveId.SUPER_FANG)
.ability(AbilityId.PARENTAL_BOND) .ability(AbilityId.PARENTAL_BOND)
.passiveAbility(AbilityId.COMPOUND_EYES)
.enemyMoveset(MoveId.SPLASH)
.enemyLevel(1000) .enemyLevel(1000)
.enemySpecies(SpeciesId.BLISSEY); // allows for unrealistically high levels of accuracy .enemySpecies(SpeciesId.BLISSEY); // allows for unrealistically high levels of accuracy
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.FEEBAS]);
const enemyPokemon = game.field.getEnemyPokemon(); const blissey = game.field.getEnemyPokemon();
game.move.select(MoveId.SUPER_FANG); game.move.use(MoveId.SUPER_FANG);
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.toEndOfTurn();
await game.phaseInterceptor.to("MoveEndPhase");
expect(enemyPokemon.getHpRatio()).toBeCloseTo(0.25, 5); expect(blissey.getHpRatio()).toBeCloseTo(0.25, 5);
}); });
it("should not allow Future Sight to hit infinitely many times if the user switches out", async () => { it("should not allow Future Sight to hit infinitely many times if the user switches out", async () => {

View File

@ -131,4 +131,26 @@ describe("Moves - Dig", () => {
expect(postDigEarthquakeDmg).toBeGreaterThanOrEqual(2 * preDigEarthquakeDmg); expect(postDigEarthquakeDmg).toBeGreaterThanOrEqual(2 * preDigEarthquakeDmg);
expect(postDigEarthquakeDmg).toBeLessThan(2 * (preDigEarthquakeDmg + 1)); expect(postDigEarthquakeDmg).toBeLessThan(2 * (preDigEarthquakeDmg + 1));
}); });
it("should not softlock when used against a dying enemy 2 in Doubles", async () => {
game.override.battleStyle("double");
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
const feebas = game.field.getPlayerPokemon();
const enemy2 = game.scene.getEnemyField()[1];
// use dig and make the targeted enemy faint post charge
game.move.use(MoveId.DIG, BattlerIndex.PLAYER, BattlerIndex.ENEMY_2);
await game.toEndOfTurn();
await game.killPokemon(enemy2);
await game.phaseInterceptor.to("CommandPhase");
expect(feebas.getMoveQueue()[0]?.targets).toEqual([BattlerIndex.ENEMY_2]);
expect(enemy2).toHaveFainted();
await game.toEndOfTurn();
// TODO: Does this redirect to the other enemy?
expect(feebas.getMoveQueue()).toHaveLength(0);
});
}); });