[Move] Implemented Magnet Rise (#2081)
* Partially implemented Magnet Rise * Implemented Magnet Rise * Changed pokemon.ts so all TypeImmune tags work instead of just MagnetRisen * Magnet Risen is now removed when Gravity is used. * Magnet Rise is ignored by Thousand Arrows and Smack Down. * Fixed a bug where status ground type moves would also be ignored by Magnet Rise * Added a message when Magnet Rise is removed * Inserted TypeImmuneTag check in getAttackMoveEffectiveness() for the AI * Created a magnetRiseCondition separately * Created a test for Magnet Rise * Bug Fix in Magnet Rise test * Created Magnet Rise test with Gravity * Shifted the code from getAttackMoveEffectiveness and apply into getAttackTypeEffectiveness instead * Replaced onNextPrompt with doAttack * Removed redundant runFrom(Phase) * Replaced magnetRiseCondition with battlerTags.every anonymous function * Fixed import errors * Added an undefined check for summonData for TypeImmuneTag in getAttackTypeEffectiveness * Replaced undefined-check with optional chaining
This commit is contained in:
parent
4e8cafcdb4
commit
89eba349c9
|
@ -633,6 +633,11 @@ export class GravityTag extends ArenaTag {
|
|||
|
||||
onAdd(arena: Arena): void {
|
||||
arena.scene.queueMessage("Gravity intensified!");
|
||||
arena.scene.getField(true).forEach((pokemon) => {
|
||||
if (pokemon !== null) {
|
||||
pokemon.removeTag(BattlerTagType.MAGNET_RISEN);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onRemove(arena: Arena): void {
|
||||
|
|
|
@ -1187,8 +1187,11 @@ export class HideSpriteTag extends BattlerTag {
|
|||
|
||||
export class TypeImmuneTag extends BattlerTag {
|
||||
public immuneType: Type;
|
||||
constructor(tagType: BattlerTagType, sourceMove: Moves, immuneType: Type, length: number) {
|
||||
super(tagType, BattlerTagLapseType.TURN_END, 1, sourceMove);
|
||||
|
||||
constructor(tagType: BattlerTagType, sourceMove: Moves, immuneType: Type, length: number = 1) {
|
||||
super(tagType, BattlerTagLapseType.TURN_END, length, sourceMove);
|
||||
|
||||
this.immuneType = immuneType;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1205,6 +1208,18 @@ export class MagnetRisenTag extends TypeImmuneTag {
|
|||
constructor(tagType: BattlerTagType, sourceMove: Moves) {
|
||||
super(tagType, sourceMove, Type.GROUND, 5);
|
||||
}
|
||||
|
||||
onAdd(pokemon: Pokemon): void {
|
||||
super.onAdd(pokemon);
|
||||
|
||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " levitated with electromagnetism!"));
|
||||
}
|
||||
|
||||
onRemove(pokemon: Pokemon): void {
|
||||
super.onRemove(pokemon);
|
||||
|
||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " stopped levitating!"));
|
||||
}
|
||||
}
|
||||
|
||||
export class TypeBoostTag extends BattlerTag {
|
||||
|
|
|
@ -6585,10 +6585,7 @@ export function initMoves() {
|
|||
.attr(AddBattlerTagAttr, BattlerTagType.AQUA_RING, true, true),
|
||||
new SelfStatusMove(Moves.MAGNET_RISE, Type.ELECTRIC, -1, 10, -1, 0, 4)
|
||||
.attr(AddBattlerTagAttr, BattlerTagType.MAGNET_RISEN, true, true)
|
||||
.condition((user, target, move) => !user.scene.arena.getTag(ArenaTagType.GRAVITY) &&
|
||||
!user.getTag(BattlerTagType.IGNORE_FLYING) && !user.getTag(BattlerTagType.INGRAIN) &&
|
||||
!user.getTag(BattlerTagType.MAGNET_RISEN))
|
||||
.unimplemented(),
|
||||
.condition((user, target, move) => !user.scene.arena.getTag(ArenaTagType.GRAVITY) && [BattlerTagType.MAGNET_RISEN, BattlerTagType.IGNORE_FLYING, BattlerTagType.INGRAIN].every((tag) => !user.getTag(tag))),
|
||||
new AttackMove(Moves.FLARE_BLITZ, Type.FIRE, MoveCategory.PHYSICAL, 120, 100, 15, 10, 0, 4)
|
||||
.attr(RecoilAttr, false, 0.33)
|
||||
.attr(HealStatusEffectAttr, true, StatusEffect.FREEZE)
|
||||
|
@ -6821,7 +6818,7 @@ export function initMoves() {
|
|||
new AttackMove(Moves.SMACK_DOWN, Type.ROCK, MoveCategory.PHYSICAL, 50, 100, 15, 100, 0, 5)
|
||||
.attr(AddBattlerTagAttr, BattlerTagType.IGNORE_FLYING, false, false, 5)
|
||||
.attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED)
|
||||
.attr(RemoveBattlerTagAttr, [BattlerTagType.FLYING])
|
||||
.attr(RemoveBattlerTagAttr, [BattlerTagType.FLYING, BattlerTagType.MAGNET_RISEN])
|
||||
.attr(HitsTagAttr, BattlerTagType.FLYING, false)
|
||||
.makesContact(false),
|
||||
new AttackMove(Moves.STORM_THROW, Type.FIGHTING, MoveCategory.PHYSICAL, 60, 100, 10, -1, 0, 5)
|
||||
|
@ -7205,7 +7202,7 @@ export function initMoves() {
|
|||
.attr(NeutralDamageAgainstFlyingTypeMultiplierAttr)
|
||||
.attr(HitsTagAttr, BattlerTagType.FLYING, false)
|
||||
.attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED)
|
||||
.attr(RemoveBattlerTagAttr, [BattlerTagType.FLYING])
|
||||
.attr(RemoveBattlerTagAttr, [BattlerTagType.FLYING, BattlerTagType.MAGNET_RISEN])
|
||||
.makesContact(false)
|
||||
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
||||
new AttackMove(Moves.THOUSAND_WAVES, Type.GROUND, MoveCategory.PHYSICAL, 90, 100, 10, -1, 0, 6)
|
||||
|
|
|
@ -18,7 +18,7 @@ import { pokemonEvolutions, pokemonPrevolutions, SpeciesFormEvolution, SpeciesEv
|
|||
import { reverseCompatibleTms, tmSpecies, tmPoolTiers } from "../data/tms";
|
||||
import { DamagePhase, FaintPhase, LearnMovePhase, ObtainStatusEffectPhase, StatChangePhase, SwitchSummonPhase, ToggleDoublePositionPhase } from "../phases";
|
||||
import { BattleStat } from "../data/battle-stat";
|
||||
import { BattlerTag, BattlerTagLapseType, EncoreTag, HelpingHandTag, HighestStatBoostTag, TypeBoostTag, getBattlerTag } from "../data/battler-tags";
|
||||
import { BattlerTag, BattlerTagLapseType, EncoreTag, HelpingHandTag, HighestStatBoostTag, TypeBoostTag, TypeImmuneTag, getBattlerTag } from "../data/battler-tags";
|
||||
import { WeatherType } from "../data/weather";
|
||||
import { TempBattleStat } from "../data/temp-battle-stat";
|
||||
import { ArenaTagSide, WeakenMoveScreenTag, WeakenMoveTypeTag } from "../data/arena-tag";
|
||||
|
@ -1096,7 +1096,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
}
|
||||
|
||||
isGrounded(): boolean {
|
||||
return !this.isOfType(Type.FLYING, true, true) && !this.hasAbility(Abilities.LEVITATE);
|
||||
return !this.isOfType(Type.FLYING, true, true) && !this.hasAbility(Abilities.LEVITATE) && !this.getTag(BattlerTagType.MAGNET_RISEN);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1134,6 +1134,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
if (!cancelled.value && !ignoreAbility) {
|
||||
applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, typeMultiplier, true);
|
||||
}
|
||||
|
||||
return (!cancelled.value ? typeMultiplier.value : 0) as TypeDamageMultiplier;
|
||||
}
|
||||
|
||||
|
@ -1161,6 +1162,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
if (!ignoreStrongWinds && this.scene.arena.weather?.weatherType === WeatherType.STRONG_WINDS && !this.scene.arena.weather.isEffectSuppressed(this.scene) && multiplier >= 2 && this.isOfType(Type.FLYING) && getTypeDamageMultiplier(moveType, Type.FLYING) === 2) {
|
||||
multiplier /= 2;
|
||||
}
|
||||
|
||||
if (!!this.summonData?.tags.find((tag) => tag instanceof TypeImmuneTag && tag.immuneType === moveType)) {
|
||||
multiplier = 0;
|
||||
}
|
||||
|
||||
return multiplier;
|
||||
}
|
||||
|
||||
|
@ -1728,6 +1734,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
typeMultiplier.value = 0;
|
||||
}
|
||||
|
||||
|
||||
// Apply arena tags for conditional protection
|
||||
if (!move.checkFlag(MoveFlags.IGNORE_PROTECT, source, this) && !move.isAllyTarget()) {
|
||||
const defendingSide = this.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
import {beforeAll, afterEach, beforeEach, describe, vi, it, expect} from "vitest";
|
||||
import Phaser from "phaser";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import * as overrides from "#app/overrides";
|
||||
import {Moves} from "#enums/moves";
|
||||
import {Species} from "#enums/species";
|
||||
import {CommandPhase, TurnEndPhase} from "#app/phases.js";
|
||||
|
||||
describe("Moves - Magnet Rise", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
const moveToUse = Moves.MAGNET_RISE;
|
||||
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(overrides, "STARTER_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MAGNEZONE);
|
||||
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.RATTATA);
|
||||
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.DRILL_RUN, Moves.DRILL_RUN, Moves.DRILL_RUN, Moves.DRILL_RUN]);
|
||||
vi.spyOn(overrides, "NEVER_CRIT_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(overrides, "OPP_LEVEL_OVERRIDE", "get").mockReturnValue(1);
|
||||
vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([moveToUse, Moves.SPLASH, Moves.GRAVITY, Moves.BATON_PASS]);
|
||||
});
|
||||
|
||||
it("MAGNET RISE", async () => {
|
||||
await game.startBattle();
|
||||
|
||||
const startingHp = game.scene.getParty()[0].hp;
|
||||
game.doAttack(0);
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
const finalHp = game.scene.getParty()[0].hp;
|
||||
const hpLost = finalHp - startingHp;
|
||||
expect(hpLost).toBe(0);
|
||||
}, 20000);
|
||||
|
||||
it("MAGNET RISE - Gravity", async () => {
|
||||
await game.startBattle();
|
||||
|
||||
const startingHp = game.scene.getParty()[0].hp;
|
||||
game.doAttack(0);
|
||||
await game.phaseInterceptor.to(CommandPhase);
|
||||
let finalHp = game.scene.getParty()[0].hp;
|
||||
let hpLost = finalHp - startingHp;
|
||||
expect(hpLost).toBe(0);
|
||||
game.doAttack(2);
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
finalHp = game.scene.getParty()[0].hp;
|
||||
hpLost = finalHp - startingHp;
|
||||
expect(hpLost).not.toBe(0);
|
||||
}, 20000);
|
||||
});
|
Loading…
Reference in New Issue