mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-07-18 14:22:19 +02:00
Merge branch 'beta' into pr-illusion
This commit is contained in:
commit
68f0de1f50
BIN
public/images/pokemon/icons/7/791-radiant-sun.png
Normal file
BIN
public/images/pokemon/icons/7/791-radiant-sun.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 491 B |
BIN
public/images/pokemon/icons/7/791s-radiant-sun.png
Normal file
BIN
public/images/pokemon/icons/7/791s-radiant-sun.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 508 B |
BIN
public/images/pokemon/icons/7/792-full-moon.png
Normal file
BIN
public/images/pokemon/icons/7/792-full-moon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 461 B |
BIN
public/images/pokemon/icons/7/792s-full-moon.png
Normal file
BIN
public/images/pokemon/icons/7/792s-full-moon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 470 B |
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 51 KiB |
@ -4587,9 +4587,19 @@ export class PostFaintHPDamageAbAttr extends PostFaintAbAttr {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirects a move to the pokemon with this ability if it meets the conditions
|
||||
*/
|
||||
export class RedirectMoveAbAttr extends AbAttr {
|
||||
/**
|
||||
* @param pokemon - The Pokemon with the redirection ability
|
||||
* @param args - The args passed to the `AbAttr`:
|
||||
* - `[0]` - The id of the {@linkcode Move} used
|
||||
* - `[1]` - The target's battler index (before redirection)
|
||||
* - `[2]` - The Pokemon that used the move being redirected
|
||||
*/
|
||||
apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||
if (this.canRedirect(args[0] as Moves)) {
|
||||
if (this.canRedirect(args[0] as Moves, args[2] as Pokemon)) {
|
||||
const target = args[1] as Utils.NumberHolder;
|
||||
const newTarget = pokemon.getBattlerIndex();
|
||||
if (target.value !== newTarget) {
|
||||
@ -4601,7 +4611,7 @@ export class RedirectMoveAbAttr extends AbAttr {
|
||||
return false;
|
||||
}
|
||||
|
||||
canRedirect(moveId: Moves): boolean {
|
||||
canRedirect(moveId: Moves, user: Pokemon): boolean {
|
||||
const move = allMoves[moveId];
|
||||
return !![ MoveTarget.NEAR_OTHER, MoveTarget.OTHER ].find(t => move.moveTarget === t);
|
||||
}
|
||||
@ -4615,8 +4625,8 @@ export class RedirectTypeMoveAbAttr extends RedirectMoveAbAttr {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
canRedirect(moveId: Moves): boolean {
|
||||
return super.canRedirect(moveId) && allMoves[moveId].type === this.type;
|
||||
canRedirect(moveId: Moves, user: Pokemon): boolean {
|
||||
return super.canRedirect(moveId, user) && user.getMoveType(allMoves[moveId]) === this.type;
|
||||
}
|
||||
}
|
||||
|
||||
@ -6417,7 +6427,7 @@ export function initAbilities() {
|
||||
.conditionalAttr(pokemon => !!pokemon.status || pokemon.hasAbility(Abilities.COMATOSE), StatMultiplierAbAttr, Stat.SPD, 1.5),
|
||||
new Ability(Abilities.NORMALIZE, 4)
|
||||
.attr(MoveTypeChangeAbAttr, PokemonType.NORMAL, 1.2, (user, target, move) => {
|
||||
return ![ Moves.HIDDEN_POWER, Moves.WEATHER_BALL, Moves.NATURAL_GIFT, Moves.JUDGMENT, Moves.TECHNO_BLAST ].includes(move.id);
|
||||
return ![ Moves.MULTI_ATTACK, Moves.REVELATION_DANCE, Moves.TERRAIN_PULSE, Moves.HIDDEN_POWER, Moves.WEATHER_BALL, Moves.NATURAL_GIFT, Moves.JUDGMENT, Moves.TECHNO_BLAST ].includes(move.id);
|
||||
}),
|
||||
new Ability(Abilities.SNIPER, 4)
|
||||
.attr(MultCritAbAttr, 1.5),
|
||||
|
@ -1433,7 +1433,7 @@ export class SuppressAbilitiesTag extends ArenaTag {
|
||||
}),
|
||||
);
|
||||
|
||||
for (const fieldPokemon of globalScene.getField()) {
|
||||
for (const fieldPokemon of globalScene.getField(true)) {
|
||||
if (fieldPokemon && fieldPokemon.id !== pokemon.id) {
|
||||
[true, false].forEach(passive => applyOnLoseAbAttrs(fieldPokemon, passive));
|
||||
}
|
||||
@ -1466,7 +1466,7 @@ export class SuppressAbilitiesTag extends ArenaTag {
|
||||
globalScene.queueMessage(i18next.t("arenaTag:neutralizingGasOnRemove"));
|
||||
}
|
||||
|
||||
for (const pokemon of globalScene.getField()) {
|
||||
for (const pokemon of globalScene.getField(true)) {
|
||||
// There is only one pokemon with this attr on the field on removal, so its abilities are already active
|
||||
if (pokemon && !pokemon.hasAbilityWithAttr(PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr, false)) {
|
||||
[true, false].forEach(passive => applyOnGainAbAttrs(pokemon, passive));
|
||||
|
@ -912,12 +912,24 @@ export const pokemonFormChanges: PokemonFormChanges = {
|
||||
new SpeciesFormChange(Species.MIMIKYU, "disguised", "busted", new SpeciesFormChangeAbilityTrigger(), true),
|
||||
new SpeciesFormChange(Species.MIMIKYU, "busted", "disguised", new SpeciesFormChangeAbilityTrigger(), true)
|
||||
],
|
||||
[Species.SOLGALEO]: [
|
||||
new SpeciesFormChange(Species.SOLGALEO, "", "radiant-sun", new SpeciesFormChangePreMoveTrigger(Moves.SUNSTEEL_STRIKE), true),
|
||||
new SpeciesFormChange(Species.SOLGALEO, "radiant-sun", "", new SpeciesFormChangeActiveTrigger(false), true)
|
||||
],
|
||||
[Species.LUNALA]: [
|
||||
new SpeciesFormChange(Species.LUNALA, "", "full-moon", new SpeciesFormChangePreMoveTrigger(Moves.MOONGEIST_BEAM), true),
|
||||
new SpeciesFormChange(Species.LUNALA, "full-moon", "", new SpeciesFormChangeActiveTrigger(false), true)
|
||||
],
|
||||
[Species.NECROZMA]: [
|
||||
new SpeciesFormChange(Species.NECROZMA, "", "dawn-wings", new SpeciesFormChangeItemTrigger(FormChangeItem.N_LUNARIZER), false, getSpeciesDependentFormChangeCondition(Species.LUNALA)),
|
||||
new SpeciesFormChange(Species.NECROZMA, "", "dusk-mane", new SpeciesFormChangeItemTrigger(FormChangeItem.N_SOLARIZER), false, getSpeciesDependentFormChangeCondition(Species.SOLGALEO)),
|
||||
new SpeciesFormChange(Species.NECROZMA, "dawn-wings", "ultra", new SpeciesFormChangeItemTrigger(FormChangeItem.ULTRANECROZIUM_Z)),
|
||||
new SpeciesFormChange(Species.NECROZMA, "dusk-mane", "ultra", new SpeciesFormChangeItemTrigger(FormChangeItem.ULTRANECROZIUM_Z))
|
||||
],
|
||||
[Species.MARSHADOW]: [
|
||||
new SpeciesFormChange(Species.MARSHADOW, "", "zenith", new SpeciesFormChangePreMoveTrigger(Moves.SPECTRAL_THIEF), true),
|
||||
new SpeciesFormChange(Species.MARSHADOW, "zenith", "", new SpeciesFormChangeActiveTrigger(false), true)
|
||||
],
|
||||
[Species.MELMETAL]: [
|
||||
new SpeciesFormChange(Species.MELMETAL, "", SpeciesFormKey.GIGANTAMAX, new SpeciesFormChangeItemTrigger(FormChangeItem.MAX_MUSHROOMS))
|
||||
],
|
||||
|
@ -63,6 +63,8 @@ export const normalForm: Species[] = [
|
||||
Species.FROGADIER,
|
||||
Species.GRENINJA,
|
||||
Species.ROCKRUFF,
|
||||
Species.SOLGALEO,
|
||||
Species.LUNALA,
|
||||
Species.NECROZMA,
|
||||
Species.MAGEARNA,
|
||||
Species.MARSHADOW,
|
||||
@ -2676,8 +2678,14 @@ export function initSpecies() {
|
||||
new PokemonSpecies(Species.TAPU_FINI, 7, true, false, false, "Land Spirit Pokémon", PokemonType.WATER, PokemonType.FAIRY, 1.3, 21.2, Abilities.MISTY_SURGE, Abilities.NONE, Abilities.TELEPATHY, 570, 70, 75, 115, 95, 130, 85, 3, 50, 285, GrowthRate.SLOW, null, false),
|
||||
new PokemonSpecies(Species.COSMOG, 7, true, false, false, "Nebula Pokémon", PokemonType.PSYCHIC, null, 0.2, 0.1, Abilities.UNAWARE, Abilities.NONE, Abilities.NONE, 200, 43, 29, 31, 29, 31, 37, 45, 0, 40, GrowthRate.SLOW, null, false),
|
||||
new PokemonSpecies(Species.COSMOEM, 7, true, false, false, "Protostar Pokémon", PokemonType.PSYCHIC, null, 0.1, 999.9, Abilities.STURDY, Abilities.NONE, Abilities.NONE, 400, 43, 29, 131, 29, 131, 37, 45, 0, 140, GrowthRate.SLOW, null, false),
|
||||
new PokemonSpecies(Species.SOLGALEO, 7, false, true, false, "Sunne Pokémon", PokemonType.PSYCHIC, PokemonType.STEEL, 3.4, 230, Abilities.FULL_METAL_BODY, Abilities.NONE, Abilities.NONE, 680, 137, 137, 107, 113, 89, 97, 45, 0, 340, GrowthRate.SLOW, null, false),
|
||||
new PokemonSpecies(Species.LUNALA, 7, false, true, false, "Moone Pokémon", PokemonType.PSYCHIC, PokemonType.GHOST, 4, 120, Abilities.SHADOW_SHIELD, Abilities.NONE, Abilities.NONE, 680, 137, 113, 89, 137, 107, 97, 45, 0, 340, GrowthRate.SLOW, null, false),
|
||||
new PokemonSpecies(Species.SOLGALEO, 7, false, true, false, "Sunne Pokémon", PokemonType.PSYCHIC, PokemonType.STEEL, 3.4, 230, Abilities.FULL_METAL_BODY, Abilities.NONE, Abilities.NONE, 680, 137, 137, 107, 113, 89, 97, 45, 0, 340, GrowthRate.SLOW, null, false, true,
|
||||
new PokemonForm("Normal", "", PokemonType.PSYCHIC, PokemonType.STEEL, 3.4, 230, Abilities.FULL_METAL_BODY, Abilities.NONE, Abilities.NONE, 680, 137, 137, 107, 113, 89, 97, 45, 0, 340, false, null, true),
|
||||
new PokemonForm("Radiant Sun", "radiant-sun", PokemonType.PSYCHIC, PokemonType.STEEL, 3.4, 230, Abilities.FULL_METAL_BODY, Abilities.NONE, Abilities.NONE, 680, 137, 137, 107, 113, 89, 97, 45, 0, 340),
|
||||
),
|
||||
new PokemonSpecies(Species.LUNALA, 7, false, true, false, "Moone Pokémon", PokemonType.PSYCHIC, PokemonType.GHOST, 4, 120, Abilities.SHADOW_SHIELD, Abilities.NONE, Abilities.NONE, 680, 137, 113, 89, 137, 107, 97, 45, 0, 340, GrowthRate.SLOW, null, false, true,
|
||||
new PokemonForm("Normal", "", PokemonType.PSYCHIC, PokemonType.GHOST, 4, 120, Abilities.SHADOW_SHIELD, Abilities.NONE, Abilities.NONE, 680, 137, 113, 89, 137, 107, 97, 45, 0, 340, false, null, true),
|
||||
new PokemonForm("Full Moon", "full-moon", PokemonType.PSYCHIC, PokemonType.GHOST, 4, 120, Abilities.SHADOW_SHIELD, Abilities.NONE, Abilities.NONE, 680, 137, 113, 89, 137, 107, 97, 45, 0, 340),
|
||||
),
|
||||
new PokemonSpecies(Species.NIHILEGO, 7, true, false, false, "Parasite Pokémon", PokemonType.ROCK, PokemonType.POISON, 1.2, 55.5, Abilities.BEAST_BOOST, Abilities.NONE, Abilities.NONE, 570, 109, 53, 47, 127, 131, 103, 45, 0, 285, GrowthRate.SLOW, null, false),
|
||||
new PokemonSpecies(Species.BUZZWOLE, 7, true, false, false, "Swollen Pokémon", PokemonType.BUG, PokemonType.FIGHTING, 2.4, 333.6, Abilities.BEAST_BOOST, Abilities.NONE, Abilities.NONE, 570, 107, 139, 139, 53, 53, 79, 45, 0, 285, GrowthRate.SLOW, null, false),
|
||||
new PokemonSpecies(Species.PHEROMOSA, 7, true, false, false, "Lissome Pokémon", PokemonType.BUG, PokemonType.FIGHTING, 1.8, 25, Abilities.BEAST_BOOST, Abilities.NONE, Abilities.NONE, 570, 71, 137, 37, 137, 37, 151, 45, 0, 285, GrowthRate.SLOW, null, false),
|
||||
@ -2697,7 +2705,7 @@ export function initSpecies() {
|
||||
),
|
||||
new PokemonSpecies(Species.MARSHADOW, 7, false, false, true, "Gloomdweller Pokémon", PokemonType.FIGHTING, PokemonType.GHOST, 0.7, 22.2, Abilities.TECHNICIAN, Abilities.NONE, Abilities.NONE, 600, 90, 125, 80, 90, 90, 125, 3, 0, 300, GrowthRate.SLOW, null, false, true,
|
||||
new PokemonForm("Normal", "", PokemonType.FIGHTING, PokemonType.GHOST, 0.7, 22.2, Abilities.TECHNICIAN, Abilities.NONE, Abilities.NONE, 600, 90, 125, 80, 90, 90, 125, 3, 0, 300, false, null, true),
|
||||
new PokemonForm("Zenith", "zenith", PokemonType.FIGHTING, PokemonType.GHOST, 0.7, 22.2, Abilities.TECHNICIAN, Abilities.NONE, Abilities.NONE, 600, 90, 125, 80, 90, 90, 125, 3, 0, 300, false, null, false, true)
|
||||
new PokemonForm("Zenith", "zenith", PokemonType.FIGHTING, PokemonType.GHOST, 0.7, 22.2, Abilities.TECHNICIAN, Abilities.NONE, Abilities.NONE, 600, 90, 125, 80, 90, 90, 125, 3, 0, 300),
|
||||
),
|
||||
new PokemonSpecies(Species.POIPOLE, 7, true, false, false, "Poison Pin Pokémon", PokemonType.POISON, null, 0.6, 1.8, Abilities.BEAST_BOOST, Abilities.NONE, Abilities.NONE, 420, 67, 73, 67, 73, 67, 73, 45, 0, 210, GrowthRate.SLOW, null, false),
|
||||
new PokemonSpecies(Species.NAGANADEL, 7, true, false, false, "Poison Pin Pokémon", PokemonType.POISON, PokemonType.DRAGON, 3.6, 150, Abilities.BEAST_BOOST, Abilities.NONE, Abilities.NONE, 540, 73, 73, 73, 127, 73, 121, 45, 0, 270, GrowthRate.SLOW, null, false),
|
||||
|
@ -3566,10 +3566,10 @@ function getNewModifierTypeOption(
|
||||
} else if (upgradeCount === undefined && player) {
|
||||
upgradeCount = 0;
|
||||
if (tier < ModifierTier.MASTER && allowLuckUpgrades) {
|
||||
const partyShinyCount = party.filter(p => p.isShiny() && !p.isFainted()).length;
|
||||
const upgradeOdds = Math.floor(32 / ((partyShinyCount + 2) / 2));
|
||||
const partyLuckValue = getPartyLuckValue(party);
|
||||
const upgradeOdds = Math.floor(128 / ((partyLuckValue + 4) / 4));
|
||||
while (modifierPool.hasOwnProperty(tier + upgradeCount + 1) && modifierPool[tier + upgradeCount + 1].length) {
|
||||
if (!randSeedInt(upgradeOdds)) {
|
||||
if (randSeedInt(upgradeOdds) < 4) {
|
||||
upgradeCount++;
|
||||
} else {
|
||||
break;
|
||||
|
@ -504,7 +504,7 @@ export class MovePhase extends BattlePhase {
|
||||
globalScene
|
||||
.getField(true)
|
||||
.filter(p => p !== this.pokemon)
|
||||
.forEach(p => applyAbAttrs(RedirectMoveAbAttr, p, null, false, this.move.moveId, redirectTarget));
|
||||
.forEach(p => applyAbAttrs(RedirectMoveAbAttr, p, null, false, this.move.moveId, redirectTarget, this.pokemon));
|
||||
|
||||
/** `true` if an Ability is responsible for redirecting the move to another target; `false` otherwise */
|
||||
let redirectedByAbility = currentTarget !== redirectTarget.value;
|
||||
|
115
test/abilities/lightningrod.test.ts
Normal file
115
test/abilities/lightningrod.test.ts
Normal file
@ -0,0 +1,115 @@
|
||||
import { BattlerIndex } from "#app/battle";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { Species } from "#enums/species";
|
||||
import { Stat } from "#enums/stat";
|
||||
import GameManager from "#test/testUtils/gameManager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
|
||||
describe("Abilities - Lightningrod", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
game.override
|
||||
.moveset([ Moves.SPLASH, Moves.SHOCK_WAVE ])
|
||||
.ability(Abilities.BALL_FETCH)
|
||||
.battleType("double")
|
||||
.disableCrits()
|
||||
.enemySpecies(Species.MAGIKARP)
|
||||
.enemyAbility(Abilities.BALL_FETCH)
|
||||
.enemyMoveset(Moves.SPLASH);
|
||||
});
|
||||
|
||||
it("should redirect electric type moves", async () => {
|
||||
await game.classicMode.startBattle([ Species.FEEBAS, Species.MAGIKARP ]);
|
||||
|
||||
const enemy1 = game.scene.getEnemyField()[0];
|
||||
const enemy2 = game.scene.getEnemyField()[1];
|
||||
|
||||
enemy2.summonData.ability = Abilities.LIGHTNING_ROD;
|
||||
|
||||
game.move.select(Moves.SHOCK_WAVE, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
|
||||
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER_2);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(enemy1.isFullHp()).toBe(true);
|
||||
});
|
||||
|
||||
it("should not redirect non-electric type moves", async () => {
|
||||
game.override.moveset([ Moves.SPLASH, Moves.AERIAL_ACE ]);
|
||||
await game.classicMode.startBattle([ Species.FEEBAS, Species.MAGIKARP ]);
|
||||
|
||||
const enemy1 = game.scene.getEnemyField()[0];
|
||||
const enemy2 = game.scene.getEnemyField()[1];
|
||||
|
||||
enemy2.summonData.ability = Abilities.LIGHTNING_ROD;
|
||||
|
||||
game.move.select(Moves.AERIAL_ACE, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
|
||||
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER_2);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(enemy1.isFullHp()).toBe(false);
|
||||
});
|
||||
|
||||
it("should boost the user's spatk without damaging", async () => {
|
||||
await game.classicMode.startBattle([ Species.FEEBAS, Species.MAGIKARP ]);
|
||||
|
||||
const enemy2 = game.scene.getEnemyField()[1];
|
||||
|
||||
enemy2.summonData.ability = Abilities.LIGHTNING_ROD;
|
||||
|
||||
game.move.select(Moves.SHOCK_WAVE, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
|
||||
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER_2);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(enemy2.isFullHp()).toBe(true);
|
||||
expect(enemy2.getStatStage(Stat.SPATK)).toBe(1);
|
||||
});
|
||||
|
||||
it("should not redirect moves changed from electric type via ability", async () => {
|
||||
game.override.ability(Abilities.NORMALIZE);
|
||||
await game.classicMode.startBattle([ Species.FEEBAS, Species.MAGIKARP ]);
|
||||
|
||||
const enemy1 = game.scene.getEnemyField()[0];
|
||||
const enemy2 = game.scene.getEnemyField()[1];
|
||||
|
||||
enemy2.summonData.ability = Abilities.LIGHTNING_ROD;
|
||||
|
||||
game.move.select(Moves.SHOCK_WAVE, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
|
||||
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER_2);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(enemy1.isFullHp()).toBe(false);
|
||||
});
|
||||
|
||||
it("should redirect moves changed to electric type via ability", async () => {
|
||||
game.override.ability(Abilities.GALVANIZE)
|
||||
.moveset(Moves.TACKLE);
|
||||
await game.classicMode.startBattle([ Species.FEEBAS, Species.MAGIKARP ]);
|
||||
|
||||
const enemy1 = game.scene.getEnemyField()[0];
|
||||
const enemy2 = game.scene.getEnemyField()[1];
|
||||
|
||||
enemy2.summonData.ability = Abilities.LIGHTNING_ROD;
|
||||
|
||||
game.move.select(Moves.TACKLE, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
|
||||
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER_2);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(enemy1.isFullHp()).toBe(true);
|
||||
expect(enemy2.getStatStage(Stat.SPATK)).toBe(1);
|
||||
});
|
||||
});
|
@ -1,4 +1,5 @@
|
||||
import { BattlerIndex } from "#app/battle";
|
||||
import { PostSummonWeatherChangeAbAttr } from "#app/data/ability";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { ArenaTagType } from "#enums/arena-tag-type";
|
||||
import { Moves } from "#enums/moves";
|
||||
@ -7,7 +8,7 @@ import { Species } from "#enums/species";
|
||||
import { Stat } from "#enums/stat";
|
||||
import GameManager from "#test/testUtils/gameManager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
describe("Abilities - Neutralizing Gas", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
@ -155,4 +156,25 @@ describe("Abilities - Neutralizing Gas", () => {
|
||||
|
||||
expect(game.scene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS)).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should not activate abilities of pokemon no longer on the field", async () => {
|
||||
game.override
|
||||
.battleType("single")
|
||||
.ability(Abilities.NEUTRALIZING_GAS)
|
||||
.enemyAbility(Abilities.DELTA_STREAM);
|
||||
await game.classicMode.startBattle([ Species.MAGIKARP ]);
|
||||
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const weatherChangeAttr = enemy.getAbilityAttrs(PostSummonWeatherChangeAbAttr, false)[0];
|
||||
vi.spyOn(weatherChangeAttr, "applyPostSummon");
|
||||
|
||||
expect(game.scene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS)).toBeDefined();
|
||||
|
||||
game.move.select(Moves.SPLASH);
|
||||
await game.killPokemon(enemy);
|
||||
await game.killPokemon(game.scene.getPlayerPokemon()!);
|
||||
|
||||
expect(game.scene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS)).toBeUndefined();
|
||||
expect(weatherChangeAttr.applyPostSummon).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
115
test/abilities/storm_drain.test.ts
Normal file
115
test/abilities/storm_drain.test.ts
Normal file
@ -0,0 +1,115 @@
|
||||
import { BattlerIndex } from "#app/battle";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { Species } from "#enums/species";
|
||||
import { Stat } from "#enums/stat";
|
||||
import GameManager from "#test/testUtils/gameManager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
|
||||
describe("Abilities - Storm Drain", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
game.override
|
||||
.moveset([ Moves.SPLASH, Moves.WATER_GUN ])
|
||||
.ability(Abilities.BALL_FETCH)
|
||||
.battleType("double")
|
||||
.disableCrits()
|
||||
.enemySpecies(Species.MAGIKARP)
|
||||
.enemyAbility(Abilities.BALL_FETCH)
|
||||
.enemyMoveset(Moves.SPLASH);
|
||||
});
|
||||
|
||||
it("should redirect water type moves", async () => {
|
||||
await game.classicMode.startBattle([ Species.FEEBAS, Species.MAGIKARP ]);
|
||||
|
||||
const enemy1 = game.scene.getEnemyField()[0];
|
||||
const enemy2 = game.scene.getEnemyField()[1];
|
||||
|
||||
enemy2.summonData.ability = Abilities.STORM_DRAIN;
|
||||
|
||||
game.move.select(Moves.WATER_GUN, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
|
||||
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER_2);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(enemy1.isFullHp()).toBe(true);
|
||||
});
|
||||
|
||||
it("should not redirect non-water type moves", async () => {
|
||||
game.override.moveset([ Moves.SPLASH, Moves.AERIAL_ACE ]);
|
||||
await game.classicMode.startBattle([ Species.FEEBAS, Species.MAGIKARP ]);
|
||||
|
||||
const enemy1 = game.scene.getEnemyField()[0];
|
||||
const enemy2 = game.scene.getEnemyField()[1];
|
||||
|
||||
enemy2.summonData.ability = Abilities.STORM_DRAIN;
|
||||
|
||||
game.move.select(Moves.AERIAL_ACE, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
|
||||
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER_2);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(enemy1.isFullHp()).toBe(false);
|
||||
});
|
||||
|
||||
it("should boost the user's spatk without damaging", async () => {
|
||||
await game.classicMode.startBattle([ Species.FEEBAS, Species.MAGIKARP ]);
|
||||
|
||||
const enemy2 = game.scene.getEnemyField()[1];
|
||||
|
||||
enemy2.summonData.ability = Abilities.STORM_DRAIN;
|
||||
|
||||
game.move.select(Moves.WATER_GUN, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
|
||||
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER_2);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(enemy2.isFullHp()).toBe(true);
|
||||
expect(enemy2.getStatStage(Stat.SPATK)).toBe(1);
|
||||
});
|
||||
|
||||
it("should not redirect moves changed from water type via ability", async () => {
|
||||
game.override.ability(Abilities.NORMALIZE);
|
||||
await game.classicMode.startBattle([ Species.FEEBAS, Species.MAGIKARP ]);
|
||||
|
||||
const enemy1 = game.scene.getEnemyField()[0];
|
||||
const enemy2 = game.scene.getEnemyField()[1];
|
||||
|
||||
enemy2.summonData.ability = Abilities.STORM_DRAIN;
|
||||
|
||||
game.move.select(Moves.WATER_GUN, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
|
||||
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER_2);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(enemy1.isFullHp()).toBe(false);
|
||||
});
|
||||
|
||||
it("should redirect moves changed to water type via ability", async () => {
|
||||
game.override.ability(Abilities.LIQUID_VOICE)
|
||||
.moveset(Moves.PSYCHIC_NOISE);
|
||||
await game.classicMode.startBattle([ Species.FEEBAS, Species.MAGIKARP ]);
|
||||
|
||||
const enemy1 = game.scene.getEnemyField()[0];
|
||||
const enemy2 = game.scene.getEnemyField()[1];
|
||||
|
||||
enemy2.summonData.ability = Abilities.STORM_DRAIN;
|
||||
|
||||
game.move.select(Moves.PSYCHIC_NOISE, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
|
||||
game.move.select(Moves.SPLASH, BattlerIndex.PLAYER_2);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(enemy1.isFullHp()).toBe(true);
|
||||
expect(enemy2.getStatStage(Stat.SPATK)).toBe(1);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user