[Bug] Fix Toxic Chain applying for non-damaging moves (#1814)

* Fix Toxic Chain applying for non-damaging moves

* Addressing code review to change a boolean to a PokemonAttackCondition

* Adding comments to introduced methods

* Update src/data/ability.ts

---------

Co-authored-by: Tempoanon <163687446+Tempo-anon@users.noreply.github.com>
This commit is contained in:
drew9696 2024-07-30 17:44:40 -04:00 committed by GitHub
parent 64ca6dd827
commit 78c3906088
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 38 additions and 10 deletions

View File

@ -1531,23 +1531,50 @@ export class BattleStatMultiplierAbAttr extends AbAttr {
}
export class PostAttackAbAttr extends AbAttr {
private attackCondition: PokemonAttackCondition;
/** The default attackCondition requires that the selected move is a damaging move */
constructor(attackCondition: PokemonAttackCondition = (user, target, move) => (move.category !== MoveCategory.STATUS)) {
super();
this.attackCondition = attackCondition;
}
/**
* Please override {@link applyPostAttackAfterMoveTypeCheck} instead of this method. By default, this method checks that the move used is a damaging attack before
* applying the effect of any inherited class. This can be changed by providing a different {@link attackCondition} to the constructor. See {@link ConfusionOnStatusEffectAbAttr}
* for an example of an effect that does not require a damaging move.
*/
applyPostAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean | Promise<boolean> {
// When attackRequired is true, we require the move to be an attack move and to deal damage before checking secondary requirements.
// If attackRequired is false, we always defer to the secondary requirements.
if (this.attackCondition(pokemon, defender, move)) {
return this.applyPostAttackAfterMoveTypeCheck(pokemon, passive, defender, move, hitResult, args);
} else {
return false;
}
}
/**
* This method is only called after {@link applyPostAttack} has already been applied. Use this for handling checks specific to the ability in question.
*/
applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean | Promise<boolean> {
return false;
}
}
export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr {
private condition: PokemonAttackCondition;
private stealCondition: PokemonAttackCondition;
constructor(condition?: PokemonAttackCondition) {
constructor(stealCondition?: PokemonAttackCondition) {
super();
this.condition = condition;
this.stealCondition = stealCondition;
}
applyPostAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, hitResult: HitResult, args: any[]): Promise<boolean> {
applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, hitResult: HitResult, args: any[]): Promise<boolean> {
return new Promise<boolean>(resolve => {
if (hitResult < HitResult.NO_EFFECT && (!this.condition || this.condition(pokemon, defender, move))) {
if (hitResult < HitResult.NO_EFFECT && (!this.stealCondition || this.stealCondition(pokemon, defender, move))) {
const heldItems = this.getTargetHeldItems(defender).filter(i => i.isTransferrable);
if (heldItems.length) {
const stolenItem = heldItems[pokemon.randSeedInt(heldItems.length)];
@ -1583,7 +1610,7 @@ export class PostAttackApplyStatusEffectAbAttr extends PostAttackAbAttr {
this.effects = effects;
}
applyPostAttack(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
/**Status inflicted by abilities post attacking are also considered additional effects.*/
if (!attacker.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr) && pokemon !== attacker && (!this.contactRequired || move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) && pokemon.randSeedInt(100) < this.chance && !pokemon.status) {
const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)];
@ -1614,7 +1641,7 @@ export class PostAttackApplyBattlerTagAbAttr extends PostAttackAbAttr {
this.effects = effects;
}
applyPostAttack(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
/**Battler tags inflicted by abilities post attacking are also considered additional effects.*/
if (!attacker.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr) && pokemon !== attacker && (!this.contactRequired || move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) && pokemon.randSeedInt(100) < this.chance(attacker, pokemon, move) && !pokemon.status) {
const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)];
@ -2414,7 +2441,8 @@ export class ConfusionOnStatusEffectAbAttr extends PostAttackAbAttr {
private effects: StatusEffect[];
constructor(...effects: StatusEffect[]) {
super();
/** This effect does not require a damaging move */
super((user, target, move) => true);
this.effects = effects;
}
/**
@ -2427,7 +2455,7 @@ export class ConfusionOnStatusEffectAbAttr extends PostAttackAbAttr {
* @param args [0] {@linkcode StatusEffect} applied by move
* @returns true if defender is confused
*/
applyPostAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
if (this.effects.indexOf(args[0]) > -1 && !defender.isFainted()) {
return defender.addTag(BattlerTagType.CONFUSED, pokemon.randSeedInt(3,2), move.id, defender.id);
}
@ -4273,7 +4301,7 @@ export const allAbilities = [ new Ability(Abilities.NONE, 3) ];
export function initAbilities() {
allAbilities.push(
new Ability(Abilities.STENCH, 3)
.attr(PostAttackApplyBattlerTagAbAttr, false, (user, target, move) => (move.category !== MoveCategory.STATUS && !move.hasAttr(FlinchAttr)) ? 10 : 0, BattlerTagType.FLINCHED),
.attr(PostAttackApplyBattlerTagAbAttr, false, (user, target, move) => !move.hasAttr(FlinchAttr) ? 10 : 0, BattlerTagType.FLINCHED),
new Ability(Abilities.DRIZZLE, 3)
.attr(PostSummonWeatherChangeAbAttr, WeatherType.RAIN)
.attr(PostBiomeChangeWeatherChangeAbAttr, WeatherType.RAIN),