Fixed Flame Burst/substitute interaction

This commit is contained in:
innerthunder 2024-11-17 15:48:47 -08:00
parent cae4342d98
commit 698aa62fdd
2 changed files with 42 additions and 16 deletions

View File

@ -1837,6 +1837,15 @@ export class PartyStatusCureAttr extends MoveEffectAttr {
* @extends MoveEffectAttr
*/
export class FlameBurstAttr extends MoveEffectAttr {
constructor() {
/**
* This is self-targeted to bypass immunity to target-facing secondary
* effects when the target has an active Substitute doll.
* TODO: Find a more intuitive way to implement Substitute bypassing.
*/
super(true);
}
/**
* @param user - n/a
* @param target - The target Pokémon.
@ -5176,21 +5185,19 @@ export class AddBattlerTagAttr extends MoveEffectAttr {
public tagType: BattlerTagType;
public turnCountMin: integer;
public turnCountMax: integer;
protected cancelOnFail: boolean;
private failOnOverlap: boolean;
constructor(tagType: BattlerTagType, selfTarget: boolean = false, failOnOverlap: boolean = false, turnCountMin: integer = 0, turnCountMax?: integer, lastHitOnly: boolean = false, cancelOnFail: boolean = false) {
constructor(tagType: BattlerTagType, selfTarget: boolean = false, failOnOverlap: boolean = false, turnCountMin: integer = 0, turnCountMax?: integer, lastHitOnly: boolean = false) {
super(selfTarget, { lastHitOnly: lastHitOnly });
this.tagType = tagType;
this.turnCountMin = turnCountMin;
this.turnCountMax = turnCountMax !== undefined ? turnCountMax : turnCountMin;
this.failOnOverlap = !!failOnOverlap;
this.cancelOnFail = cancelOnFail;
}
canApply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if (!super.canApply(user, target, move, args) || (this.cancelOnFail === true && user.getLastXMoves(1)[0]?.result === MoveResult.FAIL)) {
if (!super.canApply(user, target, move, args)) {
return false;
} else {
return true;
@ -5452,7 +5459,7 @@ export class ConfuseAttr extends AddBattlerTagAttr {
export class RechargeAttr extends AddBattlerTagAttr {
constructor() {
super(BattlerTagType.RECHARGING, true, false, 1, 1, true, true);
super(BattlerTagType.RECHARGING, true, false, 1, 1, true);
}
}

View File

@ -1,7 +1,7 @@
import { BattlerIndex } from "#app/battle";
import { allAbilities } from "#app/data/ability";
import { Abilities } from "#app/enums/abilities";
import Pokemon from "#app/field/pokemon";
import { TurnEndPhase } from "#app/phases/turn-end-phase";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
@ -46,12 +46,12 @@ describe("Moves - Flame Burst", () => {
});
it("inflicts damage to the target's ally equal to 1/16 of its max HP", async () => {
await game.startBattle([ Species.PIKACHU, Species.PIKACHU ]);
await game.classicMode.startBattle([ Species.PIKACHU, Species.PIKACHU ]);
const [ leftEnemy, rightEnemy ] = game.scene.getEnemyField();
game.move.select(Moves.FLAME_BURST, 0, leftEnemy.getBattlerIndex());
game.move.select(Moves.SPLASH, 1);
await game.phaseInterceptor.to(TurnEndPhase);
await game.phaseInterceptor.to("TurnEndPhase");
expect(leftEnemy.hp).toBeLessThan(leftEnemy.getMaxHp());
expect(rightEnemy.hp).toBe(rightEnemy.getMaxHp() - getEffectDamage(rightEnemy));
@ -60,46 +60,65 @@ describe("Moves - Flame Burst", () => {
it("does not inflict damage to the target's ally if the target was not affected by Flame Burst", async () => {
game.override.enemyAbility(Abilities.FLASH_FIRE);
await game.startBattle([ Species.PIKACHU, Species.PIKACHU ]);
await game.classicMode.startBattle([ Species.PIKACHU, Species.PIKACHU ]);
const [ leftEnemy, rightEnemy ] = game.scene.getEnemyField();
game.move.select(Moves.FLAME_BURST, 0, leftEnemy.getBattlerIndex());
game.move.select(Moves.SPLASH, 1);
await game.phaseInterceptor.to(TurnEndPhase);
await game.phaseInterceptor.to("TurnEndPhase");
expect(leftEnemy.hp).toBe(leftEnemy.getMaxHp());
expect(rightEnemy.hp).toBe(rightEnemy.getMaxHp());
});
it("does not interact with the target ally's abilities", async () => {
await game.startBattle([ Species.PIKACHU, Species.PIKACHU ]);
await game.classicMode.startBattle([ Species.PIKACHU, Species.PIKACHU ]);
const [ leftEnemy, rightEnemy ] = game.scene.getEnemyField();
vi.spyOn(rightEnemy, "getAbility").mockReturnValue(allAbilities[Abilities.FLASH_FIRE]);
game.move.select(Moves.FLAME_BURST, 0, leftEnemy.getBattlerIndex());
game.move.select(Moves.SPLASH, 1);
await game.phaseInterceptor.to(TurnEndPhase);
await game.phaseInterceptor.to("TurnEndPhase");
expect(leftEnemy.hp).toBeLessThan(leftEnemy.getMaxHp());
expect(rightEnemy.hp).toBe(rightEnemy.getMaxHp() - getEffectDamage(rightEnemy));
});
it("effect damage is prevented by Magic Guard", async () => {
await game.startBattle([ Species.PIKACHU, Species.PIKACHU ]);
await game.classicMode.startBattle([ Species.PIKACHU, Species.PIKACHU ]);
const [ leftEnemy, rightEnemy ] = game.scene.getEnemyField();
vi.spyOn(rightEnemy, "getAbility").mockReturnValue(allAbilities[Abilities.MAGIC_GUARD]);
game.move.select(Moves.FLAME_BURST, 0, leftEnemy.getBattlerIndex());
game.move.select(Moves.SPLASH, 1);
await game.phaseInterceptor.to(TurnEndPhase);
await game.phaseInterceptor.to("TurnEndPhase");
expect(leftEnemy.hp).toBeLessThan(leftEnemy.getMaxHp());
expect(rightEnemy.hp).toBe(rightEnemy.getMaxHp());
});
it("is not affected by protection moves and Endure", async () => {
it("effect damage should apply even when targeting a Substitute", async () => {
game.override.enemyMoveset([ Moves.SUBSTITUTE, Moves.SPLASH ]);
await game.classicMode.startBattle([ Species.PIKACHU, Species.PIKACHU ]);
const [ leftEnemy, rightEnemy ] = game.scene.getEnemyField();
game.move.select(Moves.FLAME_BURST, 0, leftEnemy.getBattlerIndex());
game.move.select(Moves.SPLASH, 1);
await game.forceEnemyMove(Moves.SUBSTITUTE);
await game.forceEnemyMove(Moves.SPLASH);
await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY_2 ]);
await game.phaseInterceptor.to("TurnEndPhase");
expect(rightEnemy.hp).toBe(rightEnemy.getMaxHp() - getEffectDamage(rightEnemy));
});
it.skip("is not affected by protection moves and Endure", async () => {
// TODO: update this test when it's possible to select move for each enemy
}, { skip: true });
});
});