From 445f922168e3f5084e157232832c6b751c9e6b52 Mon Sep 17 00:00:00 2001 From: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com> Date: Thu, 10 Apr 2025 10:43:22 -0500 Subject: [PATCH] Ensure force switches cannot pull pokemon from the wrong trainer --- src/data/moves/move.ts | 50 ++++++++++++++++++++---------------------- src/overrides.ts | 2 +- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index c75d7c91a58..2d1ef39922e 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -75,7 +75,7 @@ import { PreserveBerryModifier, } from "../../modifier/modifier"; import type { BattlerIndex } from "../../battle"; -import { BattleType } from "../../battle"; +import { BattleType } from "#enums/battle-type"; import { TerrainType } from "../terrain"; import { ModifierPoolType } from "#app/modifier/modifier-type"; import { Command } from "../../ui/command-ui-handler"; @@ -121,6 +121,7 @@ import { MoveFlags } from "#enums/MoveFlags"; import { MoveEffectTrigger } from "#enums/MoveEffectTrigger"; import { MultiHitType } from "#enums/MultiHitType"; import { invalidAssistMoves, invalidCopycatMoves, invalidMetronomeMoves, invalidMirrorMoveMoves, invalidSleepTalkMoves } from "./invalid-moves"; +import { TrainerVariant } from "#app/field/trainer"; type MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => boolean; type UserMoveConditionFunc = (user: Pokemon, move: Move) => boolean; @@ -6229,8 +6230,10 @@ export class ForceSwitchOutAttr extends MoveEffectAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { // Check if the move category is not STATUS or if the switch out condition is not met if (!this.getSwitchOutCondition()(user, target, move)) { + console.log("=========== Switch out condition was false!==========="); return false; } + console.log("=========== Switch out condition was true!==========="); /** The {@linkcode Pokemon} to be switched out with this effect */ const switchOutTarget = this.selfSwitch ? user : target; @@ -6295,9 +6298,10 @@ export class ForceSwitchOutAttr extends MoveEffectAttr { return false; } else if (globalScene.currentBattle.battleType !== BattleType.WILD) { // Switch out logic for enemy trainers // Find indices of off-field Pokemon that are eligible to be switched into + const isPartnerTrainer = globalScene.currentBattle.trainer?.isPartner(); const eligibleNewIndices: number[] = []; globalScene.getEnemyParty().forEach((pokemon, index) => { - if (pokemon.isAllowedInBattle() && !pokemon.isOnField() && (pokemon as EnemyPokemon).trainerSlot === (switchOutTarget as EnemyPokemon).trainerSlot) { + if (pokemon.isAllowedInBattle() && !pokemon.isOnField() && (!isPartnerTrainer || pokemon.trainerSlot === (switchOutTarget as EnemyPokemon).trainerSlot)) { eligibleNewIndices.push(index); } }); @@ -6347,15 +6351,6 @@ export class ForceSwitchOutAttr extends MoveEffectAttr { } } - if (globalScene.currentBattle.waveIndex % 10 === 0) { - return false; - } - - // Don't allow wild mons to flee with U-turn et al. - if (this.selfSwitch && !user.isPlayer() && move.category !== MoveCategory.STATUS) { - return false; - } - const allyPokemon = switchOutTarget.getAlly(); if (switchOutTarget.hp > 0) { @@ -6368,13 +6363,12 @@ export class ForceSwitchOutAttr extends MoveEffectAttr { } } - if (!allyPokemon?.isActive(true)) { - globalScene.clearEnemyHeldItemModifiers(); + // clear out enemy held item modifiers of the switch out target + globalScene.clearEnemyHeldItemModifiers(switchOutTarget); - if (switchOutTarget.hp) { + if (!allyPokemon?.isActive(true) && switchOutTarget.hp) { globalScene.pushPhase(new BattleEndPhase(false)); globalScene.pushPhase(new NewBattlePhase()); - } } } @@ -6416,23 +6410,27 @@ export class ForceSwitchOutAttr extends MoveEffectAttr { const blockedByAbility = new BooleanHolder(false); applyAbAttrs(ForceSwitchOutImmunityAbAttr, target, blockedByAbility); - return !blockedByAbility.value; + if (blockedByAbility.value) { + return false; + } } if (!player && globalScene.currentBattle.battleType === BattleType.WILD) { - if (this.isBatonPass()) { - return false; - } - // Don't allow wild opponents to flee on the boss stage since it can ruin a run early on - if (globalScene.currentBattle.waveIndex % 10 === 0) { - return false; - } + // Prevent wild pokemon fr + return !(this.isBatonPass() + // Don't allow boss waves of wild pokemon to flee + && globalScene.currentBattle.waveIndex % 10 === 0 + // Don't allow wild mons to flee with U-turn et al. + && this.selfSwitch && move.category !== MoveCategory.STATUS) } const party = player ? globalScene.getPlayerParty() : globalScene.getEnemyParty(); - return (!player && !globalScene.currentBattle.battleType) - || party.filter(p => p.isAllowedInBattle() - && (player || (p as EnemyPokemon).trainerSlot === (switchOutTarget as EnemyPokemon).trainerSlot)).length > globalScene.currentBattle.getBattlerCount(); + // Determine if this is a + const currentBattle = globalScene.currentBattle; + // If the trainer battle is a partner, then they can switch out as long as they have at least one pokemon in the back + const MIN_BATTLE_COUNT = (!player && currentBattle.trainer?.variant === TrainerVariant.DOUBLE) ? 1 : currentBattle.getBattlerCount(); + return party.filter(p => p.isAllowedInBattle() + && (player || (p as EnemyPokemon).trainerSlot === (switchOutTarget as EnemyPokemon).trainerSlot)).length > MIN_BATTLE_COUNT; }; } diff --git a/src/overrides.ts b/src/overrides.ts index 21c72cd7b98..919b87ba29e 100644 --- a/src/overrides.ts +++ b/src/overrides.ts @@ -15,7 +15,7 @@ import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { PokeballType } from "#enums/pokeball"; import { PokemonType } from "#enums/pokemon-type"; import { Species } from "#enums/species"; -import { Stat } from "#enums/stat"; +import { BATTLE_STATS, Stat } from "#enums/stat"; import { StatusEffect } from "#enums/status-effect"; import { TimeOfDay } from "#enums/time-of-day"; import { VariantTier } from "#enums/variant-tier";