[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:
Frisk17 2024-06-17 15:35:06 +00:00 committed by GitHub
parent 4e8cafcdb4
commit 89eba349c9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 95 additions and 10 deletions

View File

@ -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 {

View File

@ -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 {

View File

@ -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)

View File

@ -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;

View File

@ -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);
});