diff --git a/src/data/ability.ts b/src/data/ability.ts index c236aa85805..fefded66fb2 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -1391,7 +1391,20 @@ export class PostIntimidateStatChangeAbAttr extends AbAttr { } } +/** + * Base class for defining all {@linkcode Ability} Attributes post summon + * @abstract + * @see {@linkcode applyPostSummon()} + */ export class PostSummonAbAttr extends AbAttr { + /** + * Applies ability post summon (after switching in) + * @abstract + * @param pokemon {@linkcode Pokemon} with this ability + * @param passive Whether this ability is a passive + * @param args Set of unique arguments needed by this attribute + * @returns true if application of the ability succeeds + */ applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { return false; } @@ -1612,8 +1625,57 @@ export class PostSummonFormChangeAbAttr extends PostSummonAbAttr { } } -export class TraceAbAttr extends PostSummonAbAttr { +/** Attempts to copy `copyTarget` after entering the battle */ +export class PostSummonCopyAbAttr extends PostSummonAbAttr { + /** + * @param copyTarget what to attempt to copy + * @param test this is a test + */ + constructor( + private copyTarget: "OPP_ABILITY" | "ALLY_STAT_CHANGES", /** Extend this to add more options */ + ) { + super() + } + applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + switch (this.copyTarget) { + case "OPP_ABILITY": + return this.copyAbility(pokemon) + case "ALLY_STAT_CHANGES": + return this.copyAllyStatChanges(pokemon) + default: + return false + } + } + + /** + * Copy the stat changes on an ally pokemon + * @param pokemon - that will receive the stat changes + * @returns true if successful + */ + copyAllyStatChanges(pokemon: Pokemon): boolean { + if (!pokemon.scene.currentBattle.double) { + return false + } + + const ally = pokemon.getAlly() + if (!ally || !ally.summonData.battleStats.some(change => change > 0)) { + return false + } + + pokemon.summonData.battleStats = ally.summonData.battleStats + pokemon.updateInfo() + pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` copied ${ally.name}'s stat changes!`)) + + return true + } + + /** + * Copy the ability of an enemy pokemon post summon + * @param pokemon - that will receive the ability + * @returns true if successful + */ + copyAbility(pokemon: Pokemon): boolean { const targets = pokemon.getOpponents(); if (!targets.length) return false; @@ -1624,12 +1686,16 @@ export class TraceAbAttr extends PostSummonAbAttr { else target = targets[0]; - // Wonder Guard is normally uncopiable so has the attribute, but trace specifically can copy it - if (target.getAbility().hasAttr(UncopiableAbilityAbAttr) && target.getAbility().id !== Abilities.WONDER_GUARD) - return false; + if ( + target.getAbility().hasAttr(UncopiableAbilityAbAttr) && + // Wonder Guard is normally uncopiable so has the attribute, but trace specifically can copy it + !(pokemon.hasAbility(Abilities.TRACE) && target.getAbility().id === Abilities.WONDER_GUARD) + ) { + return false + } pokemon.summonData.ability = target.getAbility().id; - + pokemon.updateInfo() pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` traced ${target.name}'s\n${allAbilities[target.getAbility().id].name}!`)); return true; @@ -3107,7 +3173,7 @@ export function initAbilities() { .attr(DoubleBattleChanceAbAttr) .ignorable(), new Ability(Abilities.TRACE, 3) - .attr(TraceAbAttr) + .attr(PostSummonCopyAbAttr, "OPP_ABILITY") .attr(UncopiableAbilityAbAttr), new Ability(Abilities.HUGE_POWER, 3) .attr(BattleStatMultiplierAbAttr, BattleStat.ATK, 2), @@ -3901,6 +3967,7 @@ export function initAbilities() { new Ability(Abilities.SUPREME_OVERLORD, 9) .unimplemented(), new Ability(Abilities.COSTAR, 9) + .attr(PostSummonCopyAbAttr, "ALLY_STAT_CHANGES") .unimplemented(), new Ability(Abilities.TOXIC_DEBRIS, 9) .attr(PostDefendApplyArenaTrapTagAbAttr, (target, user, move) => move.category === MoveCategory.PHYSICAL, ArenaTagType.TOXIC_SPIKES)