Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Ability] Implement Wimp Out and Emergency Exit #4701

Open
wants to merge 14 commits into
base: beta
Choose a base branch
from
Open
19 changes: 9 additions & 10 deletions src/data/ability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4914,20 +4914,19 @@ export class PostDamageForceSwitchAttr extends PostDamageAbAttr {
if (moveHistory.length > 0) {
const lastMoveUsed = moveHistory[moveHistory.length - 1];
// Will not activate if the Pokémon's HP falls below half while it is in the air during Sky Drop.
if (fordbiddenAttackingMoves.includes(lastMoveUsed.move) || (lastMoveUsed.move === Moves.SKY_DROP && lastMoveUsed.result === MoveResult.OTHER)) {
return false;
// Will not activate if the Pokémon's HP falls below half due to hurting itself in confusion
} else if (lastMoveUsed.move === 0 && pokemon.getTag(BattlerTagType.CONFUSED)) {
if (fordbiddenAttackingMoves.includes(lastMoveUsed.move)) {
return false;
}
}

// Dragon Tail and Circle Throw switch out Pokémon before the Ability activates.
const fordbiddenDefendingMoves = [ Moves.DRAGON_TAIL, Moves.CIRCLE_THROW ];
for (const opponent of pokemon.getOpponents()) {
const getField = [ ...pokemon.getOpponents(), ...pokemon.getAlliedField() ];
for (const opponent of getField) {
const enemyMoveHistory = opponent.getMoveHistory();
if (enemyMoveHistory.length > 0) {
const enemyLastMoveUsed = enemyMoveHistory[enemyMoveHistory.length - 1];
if (fordbiddenDefendingMoves.includes(enemyLastMoveUsed.move)) {
if (fordbiddenDefendingMoves.includes(enemyLastMoveUsed.move) || enemyLastMoveUsed.move === Moves.SKY_DROP && enemyLastMoveUsed.result === MoveResult.OTHER) {
return false;
// Will not activate if the Pokémon's HP falls below half by a move affected by Sheer Force.
} else if (allMoves[enemyLastMoveUsed.move].chance >= 0 && opponent.hasAbility(Abilities.SHEER_FORCE)) {
Expand Down Expand Up @@ -5746,11 +5745,11 @@ export function initAbilities() {
new Ability(Abilities.STAMINA, 7)
.attr(PostDefendStatStageChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, Stat.DEF, 1),
new Ability(Abilities.WIMP_OUT, 7)
.attr(PostDamageForceSwitchAttr),
// .condition(getSheerForceHitDisableAbCondition()),
.attr(PostDamageForceSwitchAttr)
.edgeCase(), // Should not trigger when hurting itself in confusion
new Ability(Abilities.EMERGENCY_EXIT, 7)
.attr(PostDamageForceSwitchAttr),
// .condition(getSheerForceHitDisableAbCondition()),
.attr(PostDamageForceSwitchAttr)
.edgeCase(), // Should not trigger when hurting itself in confusion
new Ability(Abilities.WATER_COMPACTION, 7)
.attr(PostDefendStatStageChangeAbAttr, (target, user, move) => user.getMoveType(move) === Type.WATER && move.category !== MoveCategory.STATUS, Stat.DEF, 2),
new Ability(Abilities.MERCILESS, 7)
Expand Down
30 changes: 0 additions & 30 deletions src/test/abilities/wimp_out.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { allMoves } from "#app/data/move";
import { Abilities } from "#app/enums/abilities";
import { ArenaTagType } from "#app/enums/arena-tag-type";
import { BattlerTagType } from "#app/enums/battler-tag-type";
import { Stat } from "#app/enums/stat";
import { StatusEffect } from "#app/enums/status-effect";
import { WeatherType } from "#app/enums/weather-type";
import { TurnEndPhase } from "#app/phases/turn-end-phase";
Expand Down Expand Up @@ -477,35 +476,6 @@ describe("Abilities - Wimp Out", () => {
expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase");
expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(Species.TYRUNT);
});
it("Wimp Out will not activate if the Pokémon's HP falls below half due to hurting itself in confusion", async () => {
// arrange
game.override
.moveset([ Moves.SWORDS_DANCE ])
.enemyMoveset([ Moves.SWAGGER ]);
await game.startBattle([
Species.WIMPOD,
Species.TYRUNT
]);
const playerPokemon = game.scene.getPlayerPokemon()!;
const playerHp = playerPokemon.hp;
playerPokemon.hp = playerHp * 0.51;
playerPokemon.setStatStage(Stat.ATK, 6);
playerPokemon.addTag(BattlerTagType.CONFUSED);
vi.spyOn(playerPokemon, "randSeedInt").mockReturnValue(0);
vi.spyOn(allMoves[Moves.SWAGGER], "accuracy", "get").mockReturnValue(100);

// act
while (playerPokemon.getHpRatio() > 0.49) {
game.move.select(Moves.SWORDS_DANCE);
game.move.select(Moves.SWAGGER);
await game.phaseInterceptor.to(TurnEndPhase);
}

// assert
expect(playerPokemon.getHpRatio()).toBeLessThan(0.5);
expect(game.phaseInterceptor.log).not.toContain("SwitchSummonPhase");
expect(playerPokemon.species.speciesId).toBe(Species.WIMPOD);
});
muscode13 marked this conversation as resolved.
Show resolved Hide resolved
it("Magic Guard passive should not allow indirect damage to trigger Wimp Out", async () => {
// arrange
game.scene.arena.addTag(ArenaTagType.STEALTH_ROCK, 1, Moves.STEALTH_ROCK, 0, ArenaTagSide.ENEMY);
Expand Down