Add suggested .bypassFaint() to Unburden

This commit is contained in:
Michael Li 2024-11-09 20:44:30 -05:00
parent b2a2d0ffa3
commit 282d165750
3 changed files with 58 additions and 18 deletions

View File

@ -5603,6 +5603,7 @@ export function initAbilities() {
.attr(PostDefendCritStatStageChangeAbAttr, Stat.ATK, 6),
new Ability(Abilities.UNBURDEN, 4)
.attr(PostItemLostApplyBattlerTagAbAttr, BattlerTagType.UNBURDEN)
.bypassFaint() // Allows reviver seed to activate Unburden
.edgeCase(), // Should not restore Unburden boost if Pokemon loses then regains Unburden ability
new Ability(Abilities.HEATPROOF, 4)
.attr(ReceivedTypeDamageMultiplierAbAttr, Type.FIRE, 0.5)

View File

@ -1,6 +1,6 @@
import { BattlerIndex, BattleType } from "#app/battle";
import BattleScene from "#app/battle-scene";
import { applyPostFaintAbAttrs, applyPostItemLostAbAttrs, applyPostKnockOutAbAttrs, applyPostVictoryAbAttrs, PostFaintAbAttr, PostItemLostAbAttr, PostKnockOutAbAttr, PostVictoryAbAttr } from "#app/data/ability";
import { applyPostFaintAbAttrs, applyPostKnockOutAbAttrs, applyPostVictoryAbAttrs, PostFaintAbAttr, PostKnockOutAbAttr, PostVictoryAbAttr } from "#app/data/ability";
import { BattlerTagLapseType, DestinyBondTag, GrudgeTag } from "#app/data/battler-tags";
import { battleSpecDialogue } from "#app/data/dialogue";
import { allMoves, PostVictoryStatStageChangeAttr } from "#app/data/move";
@ -69,22 +69,9 @@ export class FaintPhase extends PokemonPhase {
const instantReviveModifier = this.scene.applyModifier(PokemonInstantReviveModifier, this.player, faintPokemon) as PokemonInstantReviveModifier;
if (instantReviveModifier) {
if (faintPokemon.loseHeldItem(instantReviveModifier)) {
if (faintPokemon.hp <= 0) {
// The code doesn't allow fainted Pokemon to apply their abilities, so we have
// to temporarily un-faint the Pokemon to apply `PostItemLostAbAttr`.
faintPokemon.hp = 1;
applyPostItemLostAbAttrs(PostItemLostAbAttr, faintPokemon, false);
faintPokemon.hp = 0;
} else {
applyPostItemLostAbAttrs(PostItemLostAbAttr, faintPokemon, false);
}
this.scene.updateModifiers(this.player);
return this.end();
}
faintPokemon.loseHeldItem(instantReviveModifier);
this.scene.updateModifiers(this.player);
return this.end();
}
}

View File

@ -1,3 +1,4 @@
import { BattlerIndex } from "#app/battle";
import { PostItemLostAbAttr } from "#app/data/ability";
import { allMoves, StealHeldItemChanceAttr } from "#app/data/move";
import Pokemon from "#app/field/pokemon";
@ -60,6 +61,8 @@ describe("Abilities - Unburden", () => {
{ name: "BERRY", type: BerryType.SITRUS, count: 1 },
{ name: "BERRY", type: BerryType.LUM, count: 1 },
]);
// For the various tests that use Thief, give it a 100% steal rate
vi.spyOn(allMoves[Moves.THIEF], "attrs", "get").mockReturnValue([ new StealHeldItemChanceAttr(1.0) ]);
});
it("should activate when a berry is eaten", async () => {
@ -165,7 +168,6 @@ describe("Abilities - Unburden", () => {
});
it("should activate when an item is stolen via move", async () => {
vi.spyOn(allMoves[Moves.THIEF], "attrs", "get").mockReturnValue([ new StealHeldItemChanceAttr(1.0) ]); // give Thief 100% steal rate
game.override.moveset(Moves.THIEF)
.startingHeldItems([]); // Remove player's full stacks of held items so it can steal opponent's held items
await game.classicMode.startBattle([ Species.TREECKO ]);
@ -346,4 +348,54 @@ describe("Abilities - Unburden", () => {
expect(getHeldItemCount(playerPokemon)).toBeLessThan(playerHeldItems);
expect(playerPokemon.getEffectiveStat(Stat.SPD)).toBe(initialPlayerSpeed * 2);
});
// test for `.bypassFaint()` - singles
it("shouldn't persist when revived normally if activated while fainting", async () => {
game.override.enemyMoveset([ Moves.SPLASH, Moves.THIEF ]);
await game.classicMode.startBattle([ Species.TREECKO, Species.FEEBAS ]);
const treecko = game.scene.getPlayerPokemon()!;
const treeckoInitialHeldItems = getHeldItemCount(treecko);
const initialSpeed = treecko.getStat(Stat.SPD);
game.move.select(Moves.SPLASH);
await game.forceEnemyMove(Moves.THIEF);
game.doSelectPartyPokemon(1);
await game.toNextTurn();
game.doRevivePokemon(1);
game.doSwitchPokemon(1);
await game.forceEnemyMove(Moves.SPLASH);
await game.toNextTurn();
expect(game.scene.getPlayerPokemon()!).toBe(treecko);
expect(getHeldItemCount(treecko)).toBeLessThan(treeckoInitialHeldItems);
expect(treecko.getEffectiveStat(Stat.SPD)).toBe(initialSpeed);
});
// test for `.bypassFaint()` - doubles
it("shouldn't persist when revived by revival blessing if activated while fainting", async () => {
game.override
.battleType("double")
.enemyMoveset([ Moves.SPLASH, Moves.THIEF ])
.moveset([ Moves.SPLASH, Moves.REVIVAL_BLESSING ])
.startingHeldItems([{ name: "WIDE_LENS" }]);
await game.classicMode.startBattle([ Species.TREECKO, Species.FEEBAS, Species.MILOTIC ]);
const treecko = game.scene.getPlayerField()[0];
const treeckoInitialHeldItems = getHeldItemCount(treecko);
const initialSpeed = treecko.getStat(Stat.SPD);
game.move.select(Moves.SPLASH);
game.move.select(Moves.REVIVAL_BLESSING, 1);
await game.forceEnemyMove(Moves.THIEF, BattlerIndex.PLAYER);
await game.forceEnemyMove(Moves.SPLASH);
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2 ]);
game.doSelectPartyPokemon(0, "MoveEffectPhase");
await game.toNextTurn();
expect(game.scene.getPlayerField()[0]).toBe(treecko);
expect(getHeldItemCount(treecko)).toBeLessThan(treeckoInitialHeldItems);
expect(treecko.getEffectiveStat(Stat.SPD)).toBe(initialSpeed);
});
});