mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2024-11-25 16:26:25 +00:00
[Bug] Fix Thousand Arrows not hitting targets under the effects of Magnet Rise (#3100)
* Fix Thousand Arrows not hitting through Magnet Rise * Add integration test for Thousand Arrows vs. Magnet Rise * ESLint * Remove unnecessary checks in integration tests
This commit is contained in:
parent
630deb92e5
commit
1d39f8d638
@ -7531,6 +7531,7 @@ export function initMoves() {
|
|||||||
.attr(NeutralDamageAgainstFlyingTypeMultiplierAttr)
|
.attr(NeutralDamageAgainstFlyingTypeMultiplierAttr)
|
||||||
.attr(AddBattlerTagAttr, BattlerTagType.IGNORE_FLYING, false, false, 1, 1, true)
|
.attr(AddBattlerTagAttr, BattlerTagType.IGNORE_FLYING, false, false, 1, 1, true)
|
||||||
.attr(HitsTagAttr, BattlerTagType.FLYING, false)
|
.attr(HitsTagAttr, BattlerTagType.FLYING, false)
|
||||||
|
.attr(HitsTagAttr, BattlerTagType.MAGNET_RISEN, false)
|
||||||
.attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED)
|
.attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED)
|
||||||
.attr(RemoveBattlerTagAttr, [BattlerTagType.FLYING, BattlerTagType.MAGNET_RISEN])
|
.attr(RemoveBattlerTagAttr, [BattlerTagType.FLYING, BattlerTagType.MAGNET_RISEN])
|
||||||
.makesContact(false)
|
.makesContact(false)
|
||||||
|
@ -1170,7 +1170,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
getAttackMoveEffectiveness(source: Pokemon, pokemonMove: PokemonMove, ignoreAbility: boolean = false): TypeDamageMultiplier {
|
getAttackMoveEffectiveness(source: Pokemon, pokemonMove: PokemonMove, ignoreAbility: boolean = false): TypeDamageMultiplier {
|
||||||
const move = pokemonMove.getMove();
|
const move = pokemonMove.getMove();
|
||||||
const typeless = move.hasAttr(TypelessAttr);
|
const typeless = move.hasAttr(TypelessAttr);
|
||||||
const typeMultiplier = new Utils.NumberHolder(this.getAttackTypeEffectiveness(move.type, source));
|
const typeMultiplier = new Utils.NumberHolder(this.getAttackTypeEffectiveness(move, source));
|
||||||
const cancelled = new Utils.BooleanHolder(false);
|
const cancelled = new Utils.BooleanHolder(false);
|
||||||
applyMoveAttrs(VariableMoveTypeMultiplierAttr, source, this, move, typeMultiplier);
|
applyMoveAttrs(VariableMoveTypeMultiplierAttr, source, this, move, typeMultiplier);
|
||||||
if (!typeless && !ignoreAbility) {
|
if (!typeless && !ignoreAbility) {
|
||||||
@ -1185,13 +1185,20 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the type effectiveness multiplier for an attack type
|
* Calculates the type effectiveness multiplier for an attack type
|
||||||
* @param moveType Type of the move
|
* @param moveOrType The move being used, or a type if the move is unknown
|
||||||
* @param source the Pokemon using the move
|
* @param source the Pokemon using the move
|
||||||
* @param ignoreStrongWinds whether or not this ignores strong winds (anticipation, forewarn, stealth rocks)
|
* @param ignoreStrongWinds whether or not this ignores strong winds (anticipation, forewarn, stealth rocks)
|
||||||
* @param simulated tag to only apply the strong winds effect message when the move is used
|
* @param simulated tag to only apply the strong winds effect message when the move is used
|
||||||
* @returns a multiplier for the type effectiveness
|
* @returns a multiplier for the type effectiveness
|
||||||
*/
|
*/
|
||||||
getAttackTypeEffectiveness(moveType: Type, source?: Pokemon, ignoreStrongWinds: boolean = false, simulated: boolean = true): TypeDamageMultiplier {
|
getAttackTypeEffectiveness(moveOrType: Move | Type, source?: Pokemon, ignoreStrongWinds: boolean = false, simulated: boolean = true): TypeDamageMultiplier {
|
||||||
|
const move = (moveOrType instanceof Move)
|
||||||
|
? moveOrType
|
||||||
|
: undefined;
|
||||||
|
const moveType = (moveOrType instanceof Move)
|
||||||
|
? move.type
|
||||||
|
: moveOrType;
|
||||||
|
|
||||||
if (moveType === Type.STELLAR) {
|
if (moveType === Type.STELLAR) {
|
||||||
return this.isTerastallized() ? 2 : 1;
|
return this.isTerastallized() ? 2 : 1;
|
||||||
}
|
}
|
||||||
@ -1219,9 +1226,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!!this.summonData?.tags.find((tag) => tag instanceof TypeImmuneTag && tag.immuneType === moveType)) {
|
const immuneTags = this.findTags(tag => tag instanceof TypeImmuneTag && tag.immuneType === moveType);
|
||||||
multiplier = 0;
|
immuneTags.forEach(tag => {
|
||||||
}
|
if (move !== undefined) {
|
||||||
|
const hitsTagAttrs = move.getAttrs(HitsTagAttr).filter(attr => attr.tagType === tag.tagType);
|
||||||
|
if (hitsTagAttrs.length === 0) {
|
||||||
|
multiplier = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return multiplier;
|
return multiplier;
|
||||||
}
|
}
|
||||||
@ -1806,7 +1819,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
const cancelled = new Utils.BooleanHolder(false);
|
const cancelled = new Utils.BooleanHolder(false);
|
||||||
const typeless = move.hasAttr(TypelessAttr);
|
const typeless = move.hasAttr(TypelessAttr);
|
||||||
const typeMultiplier = new Utils.NumberHolder(!typeless && (moveCategory !== MoveCategory.STATUS || move.getAttrs(StatusMoveTypeImmunityAttr).find(attr => types.includes(attr.immuneType)))
|
const typeMultiplier = new Utils.NumberHolder(!typeless && (moveCategory !== MoveCategory.STATUS || move.getAttrs(StatusMoveTypeImmunityAttr).find(attr => types.includes(attr.immuneType)))
|
||||||
? this.getAttackTypeEffectiveness(move.type, source, false, false)
|
? this.getAttackTypeEffectiveness(move, source, false, false)
|
||||||
: 1);
|
: 1);
|
||||||
applyMoveAttrs(VariableMoveTypeMultiplierAttr, source, this, move, typeMultiplier);
|
applyMoveAttrs(VariableMoveTypeMultiplierAttr, source, this, move, typeMultiplier);
|
||||||
if (typeless) {
|
if (typeless) {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import {afterEach, beforeAll, beforeEach, describe, expect, test, vi} from "vitest";
|
import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest";
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import GameManager from "#app/test/utils/gameManager";
|
import GameManager from "#app/test/utils/gameManager";
|
||||||
import overrides from "#app/overrides";
|
import overrides from "#app/overrides";
|
||||||
import {
|
import {
|
||||||
MoveEffectPhase,
|
BerryPhase,
|
||||||
TurnEndPhase
|
MoveEffectPhase
|
||||||
} from "#app/phases";
|
} from "#app/phases";
|
||||||
import {getMovePosition} from "#app/test/utils/gameManagerUtils";
|
import {getMovePosition} from "#app/test/utils/gameManagerUtils";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
@ -38,18 +38,12 @@ describe("Moves - Thousand Arrows", () => {
|
|||||||
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH,Moves.SPLASH,Moves.SPLASH,Moves.SPLASH]);
|
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH,Moves.SPLASH,Moves.SPLASH,Moves.SPLASH]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test(
|
it(
|
||||||
"move should hit and ground Flying-type targets",
|
"move should hit and ground Flying-type targets",
|
||||||
async () => {
|
async () => {
|
||||||
await game.startBattle([ Species.ILLUMISE ]);
|
await game.startBattle([ Species.ILLUMISE ]);
|
||||||
|
|
||||||
const leadPokemon = game.scene.getPlayerPokemon();
|
|
||||||
expect(leadPokemon).toBeDefined();
|
|
||||||
|
|
||||||
const enemyPokemon = game.scene.getEnemyPokemon();
|
const enemyPokemon = game.scene.getEnemyPokemon();
|
||||||
expect(enemyPokemon).toBeDefined();
|
|
||||||
|
|
||||||
const enemyStartingHp = enemyPokemon.hp;
|
|
||||||
|
|
||||||
game.doAttack(getMovePosition(game.scene, 0, Moves.THOUSAND_ARROWS));
|
game.doAttack(getMovePosition(game.scene, 0, Moves.THOUSAND_ARROWS));
|
||||||
|
|
||||||
@ -57,14 +51,14 @@ describe("Moves - Thousand Arrows", () => {
|
|||||||
// Enemy should not be grounded before move effect is applied
|
// Enemy should not be grounded before move effect is applied
|
||||||
expect(enemyPokemon.getTag(BattlerTagType.IGNORE_FLYING)).toBeUndefined();
|
expect(enemyPokemon.getTag(BattlerTagType.IGNORE_FLYING)).toBeUndefined();
|
||||||
|
|
||||||
await game.phaseInterceptor.to(TurnEndPhase);
|
await game.phaseInterceptor.to(BerryPhase, false);
|
||||||
|
|
||||||
expect(enemyPokemon.getTag(BattlerTagType.IGNORE_FLYING)).toBeDefined();
|
expect(enemyPokemon.getTag(BattlerTagType.IGNORE_FLYING)).toBeDefined();
|
||||||
expect(enemyPokemon.hp).toBeLessThan(enemyStartingHp);
|
expect(enemyPokemon.hp).toBeLessThan(enemyPokemon.getMaxHp());
|
||||||
}, TIMEOUT
|
}, TIMEOUT
|
||||||
);
|
);
|
||||||
|
|
||||||
test(
|
it(
|
||||||
"move should hit and ground targets with Levitate",
|
"move should hit and ground targets with Levitate",
|
||||||
async () => {
|
async () => {
|
||||||
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.SNORLAX);
|
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.SNORLAX);
|
||||||
@ -72,13 +66,7 @@ describe("Moves - Thousand Arrows", () => {
|
|||||||
|
|
||||||
await game.startBattle([ Species.ILLUMISE ]);
|
await game.startBattle([ Species.ILLUMISE ]);
|
||||||
|
|
||||||
const leadPokemon = game.scene.getPlayerPokemon();
|
|
||||||
expect(leadPokemon).toBeDefined();
|
|
||||||
|
|
||||||
const enemyPokemon = game.scene.getEnemyPokemon();
|
const enemyPokemon = game.scene.getEnemyPokemon();
|
||||||
expect(enemyPokemon).toBeDefined();
|
|
||||||
|
|
||||||
const enemyStartingHp = enemyPokemon.hp;
|
|
||||||
|
|
||||||
game.doAttack(getMovePosition(game.scene, 0, Moves.THOUSAND_ARROWS));
|
game.doAttack(getMovePosition(game.scene, 0, Moves.THOUSAND_ARROWS));
|
||||||
|
|
||||||
@ -86,10 +74,31 @@ describe("Moves - Thousand Arrows", () => {
|
|||||||
// Enemy should not be grounded before move effect is applied
|
// Enemy should not be grounded before move effect is applied
|
||||||
expect(enemyPokemon.getTag(BattlerTagType.IGNORE_FLYING)).toBeUndefined();
|
expect(enemyPokemon.getTag(BattlerTagType.IGNORE_FLYING)).toBeUndefined();
|
||||||
|
|
||||||
await game.phaseInterceptor.to(TurnEndPhase, false);
|
await game.phaseInterceptor.to(BerryPhase, false);
|
||||||
|
|
||||||
expect(enemyPokemon.getTag(BattlerTagType.IGNORE_FLYING)).toBeDefined();
|
expect(enemyPokemon.getTag(BattlerTagType.IGNORE_FLYING)).toBeDefined();
|
||||||
expect(enemyPokemon.hp).toBeLessThan(enemyStartingHp);
|
expect(enemyPokemon.hp).toBeLessThan(enemyPokemon.getMaxHp());
|
||||||
}, TIMEOUT
|
}, TIMEOUT
|
||||||
);
|
);
|
||||||
|
|
||||||
|
it(
|
||||||
|
"move should hit and ground targets under the effects of Magnet Rise",
|
||||||
|
async () => {
|
||||||
|
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.SNORLAX);
|
||||||
|
|
||||||
|
await game.startBattle([ Species.ILLUMISE ]);
|
||||||
|
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon();
|
||||||
|
|
||||||
|
enemyPokemon.addTag(BattlerTagType.MAGNET_RISEN, null, Moves.MAGNET_RISE);
|
||||||
|
|
||||||
|
game.doAttack(getMovePosition(game.scene, 0, Moves.THOUSAND_ARROWS));
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to(BerryPhase, false);
|
||||||
|
|
||||||
|
expect(enemyPokemon.getTag(BattlerTagType.MAGNET_RISEN)).toBeUndefined();
|
||||||
|
expect(enemyPokemon.getTag(BattlerTagType.IGNORE_FLYING)).toBeDefined();
|
||||||
|
expect(enemyPokemon.hp).toBeLessThan(enemyPokemon.getMaxHp());
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user