Skip to content

Commit

Permalink
[Balance] Endure Tokens only endure one hit (#4875)
Browse files Browse the repository at this point in the history
* Endure Tokens only endure one hit

* Add tests for Endure

* Update docs

---------

Co-authored-by: NightKev <[email protected]>
  • Loading branch information
innerthunder and DayKev authored Nov 15, 2024
1 parent 413f2b8 commit 360a897
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 6 deletions.
13 changes: 10 additions & 3 deletions src/data/battler-tags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1502,9 +1502,14 @@ export class ContactBurnProtectedTag extends DamageProtectedTag {
}
}

/**
* `BattlerTag` class for effects that cause the affected Pokemon to survive lethal attacks at 1 HP.
* Used for {@link https://bulbapedia.bulbagarden.net/wiki/Endure_(move) | Endure} and
* Endure Tokens.
*/
export class EnduringTag extends BattlerTag {
constructor(sourceMove: Moves) {
super(BattlerTagType.ENDURING, BattlerTagLapseType.TURN_END, 0, sourceMove);
constructor(tagType: BattlerTagType, lapseType: BattlerTagLapseType, sourceMove: Moves) {
super(tagType, lapseType, 0, sourceMove);
}

onAdd(pokemon: Pokemon): void {
Expand Down Expand Up @@ -3009,7 +3014,9 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source
case BattlerTagType.BURNING_BULWARK:
return new ContactBurnProtectedTag(sourceMove);
case BattlerTagType.ENDURING:
return new EnduringTag(sourceMove);
return new EnduringTag(tagType, BattlerTagLapseType.TURN_END, sourceMove);
case BattlerTagType.ENDURE_TOKEN:
return new EnduringTag(tagType, BattlerTagLapseType.AFTER_HIT, sourceMove);
case BattlerTagType.STURDY:
return new SturdyTag(sourceMove);
case BattlerTagType.PERISH_SONG:
Expand Down
1 change: 1 addition & 0 deletions src/enums/battler-tag-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,5 @@ export enum BattlerTagType {
COMMANDED = "COMMANDED",
GRUDGE = "GRUDGE",
PSYCHO_SHIFT = "PSYCHO_SHIFT",
ENDURE_TOKEN = "ENDURE_TOKEN",
}
2 changes: 2 additions & 0 deletions src/field/pokemon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2955,6 +2955,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
surviveDamage.value = this.lapseTag(BattlerTagType.ENDURING);
} else if (this.hp > 1 && this.getTag(BattlerTagType.STURDY)) {
surviveDamage.value = this.lapseTag(BattlerTagType.STURDY);
} else if (this.hp >= 1 && this.getTag(BattlerTagType.ENDURE_TOKEN)) {
surviveDamage.value = this.lapseTag(BattlerTagType.ENDURE_TOKEN);
}
if (!surviveDamage.value) {
this.scene.applyModifiers(SurviveDamageModifier, this.isPlayer(), this, surviveDamage);
Expand Down
6 changes: 3 additions & 3 deletions src/modifier/modifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3647,16 +3647,16 @@ export class EnemyEndureChanceModifier extends EnemyPersistentModifier {
}

/**
* Applies {@linkcode EnemyEndureChanceModifier}
* @param target {@linkcode Pokemon} to apply the {@linkcode BattlerTagType.ENDURING} chance to
* Applies a chance of enduring a lethal hit of an attack
* @param target the {@linkcode Pokemon} to apply the {@linkcode BattlerTagType.ENDURING} chance to
* @returns `true` if {@linkcode Pokemon} endured
*/
override apply(target: Pokemon): boolean {
if (target.battleData.endured || target.randSeedInt(100) >= (this.chance * this.getStackCount())) {
return false;
}

target.addTag(BattlerTagType.ENDURING, 1);
target.addTag(BattlerTagType.ENDURE_TOKEN, 1);

target.battleData.endured = true;

Expand Down
65 changes: 65 additions & 0 deletions src/test/moves/endure.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";

describe("Moves - Endure", () => {
let phaserGame: Phaser.Game;
let game: GameManager;

beforeAll(() => {
phaserGame = new Phaser.Game({
type: Phaser.HEADLESS,
});
});

afterEach(() => {
game.phaseInterceptor.restoreOg();
});

beforeEach(() => {
game = new GameManager(phaserGame);
game.override
.moveset([ Moves.THUNDER, Moves.BULLET_SEED, Moves.TOXIC ])
.ability(Abilities.SKILL_LINK)
.startingLevel(100)
.battleType("single")
.disableCrits()
.enemySpecies(Species.MAGIKARP)
.enemyAbility(Abilities.NO_GUARD)
.enemyMoveset(Moves.ENDURE);
});

it("should let the pokemon survive with 1 HP", async () => {
await game.classicMode.startBattle([ Species.ARCEUS ]);

game.move.select(Moves.THUNDER);
await game.phaseInterceptor.to("BerryPhase");

expect(game.scene.getEnemyPokemon()!.hp).toBe(1);
});

it("should let the pokemon survive with 1 HP when hit with a multihit move", async () => {
await game.classicMode.startBattle([ Species.ARCEUS ]);

game.move.select(Moves.BULLET_SEED);
await game.phaseInterceptor.to("BerryPhase");

expect(game.scene.getEnemyPokemon()!.hp).toBe(1);
});

it("shouldn't prevent fainting from indirect damage", async () => {
game.override.enemyLevel(100);
await game.classicMode.startBattle([ Species.ARCEUS ]);

const enemy = game.scene.getEnemyPokemon()!;
enemy.hp = 2;

game.move.select(Moves.TOXIC);
await game.phaseInterceptor.to("VictoryPhase");

expect(enemy.isFainted()).toBe(true);
});
});

0 comments on commit 360a897

Please sign in to comment.