[Move] Fully Implement Gulp Missile (#3438)
* Fix Dive + Gulp Missile interaction * Fix animation + remove tests for inaccurate behavior * Fix strict-null issue in new test
This commit is contained in:
parent
15106b83fb
commit
7f5e873457
|
@ -6,7 +6,7 @@ import { BattleStat, getBattleStatName } from "./battle-stat";
|
|||
import { MovePhase, PokemonHealPhase, ShowAbilityPhase, StatChangePhase } from "../phases";
|
||||
import { getPokemonNameWithAffix } from "../messages";
|
||||
import { Weather, WeatherType } from "./weather";
|
||||
import { BattlerTag, GroundedTag, GulpMissileTag } from "./battler-tags";
|
||||
import { BattlerTag, GroundedTag, GulpMissileTag, SemiInvulnerableTag } from "./battler-tags";
|
||||
import { StatusEffect, getNonVolatileStatusEffects, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect";
|
||||
import { Gender } from "./gender";
|
||||
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr, VariableMoveTypeAttr, RandomMovesetMoveAttr, RandomMoveAttr, NaturePowerAttr, CopyMoveAttr, MoveAttr, MultiHitAttr, ChargeAttr, SacrificialAttr, SacrificialAttrOnHit } from "./move";
|
||||
|
@ -517,7 +517,7 @@ export class PostDefendGulpMissileAbAttr extends PostDefendAbAttr {
|
|||
*/
|
||||
applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean | Promise<boolean> {
|
||||
const battlerTag = pokemon.getTag(GulpMissileTag);
|
||||
if (!battlerTag || move.category === MoveCategory.STATUS) {
|
||||
if (!battlerTag || move.category === MoveCategory.STATUS || pokemon.getTag(SemiInvulnerableTag)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -5138,9 +5138,7 @@ export function initAbilities() {
|
|||
.attr(NoFusionAbilityAbAttr)
|
||||
.attr(UncopiableAbilityAbAttr)
|
||||
.attr(UnswappableAbilityAbAttr)
|
||||
.attr(PostDefendGulpMissileAbAttr)
|
||||
// Does not transform when Surf/Dive misses/is protected
|
||||
.partial(),
|
||||
.attr(PostDefendGulpMissileAbAttr),
|
||||
new Ability(Abilities.STALWART, 8)
|
||||
.attr(BlockRedirectAbAttr),
|
||||
new Ability(Abilities.STEAM_ENGINE, 8)
|
||||
|
|
|
@ -4356,7 +4356,7 @@ export class AddBattlerTagAttr extends MoveEffectAttr {
|
|||
*/
|
||||
export class GulpMissileTagAttr extends MoveEffectAttr {
|
||||
constructor() {
|
||||
super(true, MoveEffectTrigger.POST_APPLY);
|
||||
super(true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -6954,7 +6954,7 @@ export function initMoves() {
|
|||
.makesContact(false)
|
||||
.partial(),
|
||||
new AttackMove(Moves.DIVE, Type.WATER, MoveCategory.PHYSICAL, 80, 100, 10, -1, 0, 3)
|
||||
.attr(ChargeAttr, ChargeAnim.DIVE_CHARGING, i18next.t("moveTriggers:hidUnderwater", {pokemonName: "{USER}"}), BattlerTagType.UNDERWATER)
|
||||
.attr(ChargeAttr, ChargeAnim.DIVE_CHARGING, i18next.t("moveTriggers:hidUnderwater", {pokemonName: "{USER}"}), BattlerTagType.UNDERWATER, true)
|
||||
.attr(GulpMissileTagAttr)
|
||||
.ignoresVirtual(),
|
||||
new AttackMove(Moves.ARM_THRUST, Type.FIGHTING, MoveCategory.PHYSICAL, 15, 100, 20, -1, 0, 3)
|
||||
|
|
|
@ -11,6 +11,7 @@ import { BattleSpec } from "#enums/battle-spec";
|
|||
import { BattlePhase, MovePhase, PokemonHealPhase } from "./phases";
|
||||
import { getTypeRgb } from "./data/type";
|
||||
import { getPokemonNameWithAffix } from "./messages";
|
||||
import { SemiInvulnerableTag } from "./data/battler-tags";
|
||||
|
||||
export class FormChangePhase extends EvolutionPhase {
|
||||
private formChange: SpeciesFormChange;
|
||||
|
@ -194,7 +195,7 @@ export class QuietFormChangePhase extends BattlePhase {
|
|||
|
||||
const preName = getPokemonNameWithAffix(this.pokemon);
|
||||
|
||||
if (!this.pokemon.isOnField()) {
|
||||
if (!this.pokemon.isOnField() || this.pokemon.getTag(SemiInvulnerableTag)) {
|
||||
this.pokemon.changeForm(this.formChange).then(() => {
|
||||
this.scene.ui.showText(getSpeciesFormChangeMessage(this.pokemon, this.formChange, preName), null, () => this.end(), 1500);
|
||||
});
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { BattlerTagType } from "#app/enums/battler-tag-type.js";
|
||||
import {
|
||||
BerryPhase,
|
||||
MoveEndPhase,
|
||||
TurnEndPhase,
|
||||
TurnStartPhase,
|
||||
|
@ -14,7 +15,6 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vite
|
|||
import { SPLASH_ONLY } from "../utils/testUtils";
|
||||
import { BattleStat } from "#app/data/battle-stat.js";
|
||||
import { StatusEffect } from "#app/enums/status-effect.js";
|
||||
import { GulpMissileTag } from "#app/data/battler-tags.js";
|
||||
import Pokemon from "#app/field/pokemon.js";
|
||||
|
||||
describe("Abilities - Gulp Missile", () => {
|
||||
|
@ -84,6 +84,17 @@ describe("Abilities - Gulp Missile", () => {
|
|||
expect(cramorant.formIndex).toBe(GORGING_FORM);
|
||||
});
|
||||
|
||||
it("changes form during Dive's charge turn", async () => {
|
||||
await game.startBattle([Species.CRAMORANT]);
|
||||
const cramorant = game.scene.getPlayerPokemon()!;
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.DIVE));
|
||||
await game.phaseInterceptor.to(MoveEndPhase);
|
||||
|
||||
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
|
||||
expect(cramorant.formIndex).toBe(GULPING_FORM);
|
||||
});
|
||||
|
||||
it("deals ¼ of the attacker's maximum HP when hit by a damaging attack", async () => {
|
||||
game.override.enemyMoveset(Array(4).fill(Moves.TACKLE));
|
||||
await game.startBattle([Species.CRAMORANT]);
|
||||
|
@ -165,29 +176,16 @@ describe("Abilities - Gulp Missile", () => {
|
|||
});
|
||||
|
||||
it("does not activate the ability when underwater", async () => {
|
||||
game.override
|
||||
.enemyMoveset(Array(4).fill(Moves.SURF))
|
||||
.enemySpecies(Species.REGIELEKI)
|
||||
.enemyAbility(Abilities.BALL_FETCH)
|
||||
.enemyLevel(5);
|
||||
game.override.enemyMoveset(Array(4).fill(Moves.SURF));
|
||||
await game.startBattle([Species.CRAMORANT]);
|
||||
|
||||
const cramorant = game.scene.getPlayerPokemon()!;
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.DIVE));
|
||||
await game.toNextTurn();
|
||||
await game.phaseInterceptor.to(BerryPhase, false);
|
||||
|
||||
// Turn 2 underwater, enemy moves first
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.DIVE));
|
||||
await game.phaseInterceptor.to(MoveEndPhase);
|
||||
|
||||
expect(cramorant.formIndex).toBe(NORMAL_FORM);
|
||||
expect(cramorant.getTag(GulpMissileTag)).toBeUndefined();
|
||||
|
||||
// Turn 2 Cramorant comes out and changes form
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
expect(cramorant.formIndex).not.toBe(NORMAL_FORM);
|
||||
expect(cramorant.getTag(GulpMissileTag)).toBeDefined();
|
||||
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
|
||||
expect(cramorant.formIndex).toBe(GULPING_FORM);
|
||||
});
|
||||
|
||||
it("prevents effect damage but inflicts secondary effect on attacker with Magic Guard", async () => {
|
||||
|
|
Loading…
Reference in New Issue