Skip to content

Commit

Permalink
Gravity now cancels Fly, etc. after charge turn
Browse files Browse the repository at this point in the history
  • Loading branch information
innerthunder committed Oct 7, 2024
1 parent 185f7f2 commit a602c2f
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 31 deletions.
3 changes: 3 additions & 0 deletions src/data/arena-tag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -875,6 +875,9 @@ export class GravityTag extends ArenaTag {
arena.scene.getField(true).forEach((pokemon) => {
if (pokemon !== null) {
pokemon.removeTag(BattlerTagType.MAGNET_RISEN);
if (pokemon.getTag(BattlerTagType.FLYING)) {
pokemon.addTag(BattlerTagType.INTERRUPTED);
}
}
});
}
Expand Down
1 change: 0 additions & 1 deletion src/data/move.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7121,7 +7121,6 @@ export function initMoves() {
new ChargingAttackMove(Moves.FLY, Type.FLYING, MoveCategory.PHYSICAL, 90, 95, 15, -1, 0, 1)
.chargeText(i18next.t("moveTriggers:flewUpHigh", { pokemonName: "{USER}" }))
.chargeAttr(SemiInvulnerableAttr, BattlerTagType.FLYING)
// TODO: double check Gravity interactions
.condition(failOnGravityCondition)
.ignoresVirtual(),
new AttackMove(Moves.BIND, Type.NORMAL, MoveCategory.PHYSICAL, 15, 85, 20, -1, 0, 1)
Expand Down
81 changes: 51 additions & 30 deletions src/test/arena/arena_gravity.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { BattlerIndex } from "#app/battle";
import { allMoves } from "#app/data/move";
import { Abilities } from "#app/enums/abilities";
import { ArenaTagType } from "#app/enums/arena-tag-type";
import { MoveEffectPhase } from "#app/phases/move-effect-phase";
import { TurnEndPhase } from "#app/phases/turn-end-phase";
import { Abilities } from "#enums/abilities";
import { ArenaTagType } from "#enums/arena-tag-type";
import { BattlerTagType } from "#enums/battler-tag-type";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
Expand Down Expand Up @@ -31,7 +31,9 @@ describe("Arena - Gravity", () => {
.ability(Abilities.UNNERVE)
.enemyAbility(Abilities.BALL_FETCH)
.enemySpecies(Species.SHUCKLE)
.enemyMoveset(Moves.SPLASH);
.enemyMoveset(Moves.SPLASH)
.startingLevel(5)
.enemyLevel(5);
});

// Reference: https://bulbapedia.bulbagarden.net/wiki/Gravity_(move)
Expand All @@ -42,102 +44,121 @@ describe("Arena - Gravity", () => {
vi.spyOn(moveToCheck, "calculateBattleAccuracy");

// Setup Gravity on first turn
await game.startBattle([ Species.PIKACHU ]);
await game.classicMode.startBattle([ Species.PIKACHU ]);
game.move.select(Moves.GRAVITY);
await game.phaseInterceptor.to(TurnEndPhase);
await game.phaseInterceptor.to("TurnEndPhase");

expect(game.scene.arena.getTag(ArenaTagType.GRAVITY)).toBeDefined();

// Use non-OHKO move on second turn
await game.toNextTurn();
game.move.select(Moves.TACKLE);
await game.phaseInterceptor.to(MoveEffectPhase);
await game.phaseInterceptor.to("MoveEffectPhase");

expect(moveToCheck.calculateBattleAccuracy).toHaveReturnedWith(100 * 1.67);
expect(moveToCheck.calculateBattleAccuracy).toHaveLastReturnedWith(100 * 1.67);
});

it("OHKO move accuracy is not affected", async () => {
game.override.startingLevel(5);
game.override.enemyLevel(5);

/** See Fissure {@link https://bulbapedia.bulbagarden.net/wiki/Fissure_(move)} */
const moveToCheck = allMoves[Moves.FISSURE];

vi.spyOn(moveToCheck, "calculateBattleAccuracy");

// Setup Gravity on first turn
await game.startBattle([ Species.PIKACHU ]);
await game.classicMode.startBattle([ Species.PIKACHU ]);
game.move.select(Moves.GRAVITY);
await game.phaseInterceptor.to(TurnEndPhase);
await game.phaseInterceptor.to("TurnEndPhase");

expect(game.scene.arena.getTag(ArenaTagType.GRAVITY)).toBeDefined();

// Use OHKO move on second turn
await game.toNextTurn();
game.move.select(Moves.FISSURE);
await game.phaseInterceptor.to(MoveEffectPhase);
await game.phaseInterceptor.to("MoveEffectPhase");

expect(moveToCheck.calculateBattleAccuracy).toHaveReturnedWith(30);
expect(moveToCheck.calculateBattleAccuracy).toHaveLastReturnedWith(30);
});

describe("Against flying types", () => {
it("can be hit by ground-type moves now", async () => {
game.override
.startingLevel(5)
.enemyLevel(5)
.enemySpecies(Species.PIDGEOT)
.moveset([ Moves.GRAVITY, Moves.EARTHQUAKE ]);

await game.startBattle([ Species.PIKACHU ]);
await game.classicMode.startBattle([ Species.PIKACHU ]);

const pidgeot = game.scene.getEnemyPokemon()!;
vi.spyOn(pidgeot, "getAttackTypeEffectiveness");

// Try earthquake on 1st turn (fails!);
game.move.select(Moves.EARTHQUAKE);
await game.phaseInterceptor.to(TurnEndPhase);
await game.phaseInterceptor.to("TurnEndPhase");

expect(pidgeot.getAttackTypeEffectiveness).toHaveReturnedWith(0);
expect(pidgeot.getAttackTypeEffectiveness).toHaveLastReturnedWith(0);

// Setup Gravity on 2nd turn
await game.toNextTurn();
game.move.select(Moves.GRAVITY);
await game.phaseInterceptor.to(TurnEndPhase);
await game.phaseInterceptor.to("TurnEndPhase");

expect(game.scene.arena.getTag(ArenaTagType.GRAVITY)).toBeDefined();

// Use ground move on 3rd turn
await game.toNextTurn();
game.move.select(Moves.EARTHQUAKE);
await game.phaseInterceptor.to(TurnEndPhase);
await game.phaseInterceptor.to("TurnEndPhase");

expect(pidgeot.getAttackTypeEffectiveness).toHaveReturnedWith(1);
expect(pidgeot.getAttackTypeEffectiveness).toHaveLastReturnedWith(1);
});

it("keeps super-effective moves super-effective after using gravity", async () => {
game.override
.startingLevel(5)
.enemyLevel(5)
.enemySpecies(Species.PIDGEOT)
.moveset([ Moves.GRAVITY, Moves.THUNDERBOLT ]);

await game.startBattle([ Species.PIKACHU ]);
await game.classicMode.startBattle([ Species.PIKACHU ]);

const pidgeot = game.scene.getEnemyPokemon()!;
vi.spyOn(pidgeot, "getAttackTypeEffectiveness");

// Setup Gravity on 1st turn
game.move.select(Moves.GRAVITY);
await game.phaseInterceptor.to(TurnEndPhase);
await game.phaseInterceptor.to("TurnEndPhase");

expect(game.scene.arena.getTag(ArenaTagType.GRAVITY)).toBeDefined();

// Use electric move on 2nd turn
await game.toNextTurn();
game.move.select(Moves.THUNDERBOLT);
await game.phaseInterceptor.to(TurnEndPhase);
await game.phaseInterceptor.to("TurnEndPhase");

expect(pidgeot.getAttackTypeEffectiveness).toHaveReturnedWith(2);
expect(pidgeot.getAttackTypeEffectiveness).toHaveLastReturnedWith(2);
});
});

it("cancels Fly if its user is semi-invulnerable", async () => {
game.override
.enemySpecies(Species.SNORLAX)
.enemyMoveset(Moves.FLY)
.moveset([ Moves.GRAVITY, Moves.SPLASH ]);

await game.classicMode.startBattle([ Species.CHARIZARD ]);

const charizard = game.scene.getPlayerPokemon()!;
const snorlax = game.scene.getEnemyPokemon()!;

game.move.select(Moves.SPLASH);

await game.toNextTurn();
expect(snorlax.getTag(BattlerTagType.FLYING)).toBeDefined();

game.move.select(Moves.GRAVITY);
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);

await game.phaseInterceptor.to("MoveEffectPhase");
expect(snorlax.getTag(BattlerTagType.INTERRUPTED)).toBeDefined();

await game.phaseInterceptor.to("TurnEndPhase");
expect(charizard.hp).toBe(charizard.getMaxHp());
});
});

0 comments on commit a602c2f

Please sign in to comment.