[Ability] Fully implement Sheer Force (#4890)
* Added checks for Sheer Force interactions currently in the code. * Test for Relic Song interaction * Test for Shell Bell interaction * Created new Modifier class MoveEffectModifier * Applied new modifier class. * Revert "Applied new modifier class." This reverts commit222bc8d428
. * Revert "Created new Modifier class MoveEffectModifier" This reverts commit0e57ed03ff
. * Added checks for Shell Bell, Scope Lens, Wide Lens, Leek, and Golden Punch * Fixing function calls. * Fixed getSecondaryChanceMultiplier to just look at sheer force. * Rewrote old Sheer Force tests in accordance to current testing standards. * Resetting modifiers.ts * Update src/data/pokemon-forms.ts Co-authored-by: innerthunder <168692175+innerthunder@users.noreply.github.com> * Moved getSecondaryChanceMultiplier to FlinchChanceModifier and revised Serene Grace tests * Adding an additional override to prevent test failures. * Removed Serene Grace factor from modifier. * Added forgotten conditional. * Added comment --------- Co-authored-by: frutescens <info@laptop> Co-authored-by: innerthunder <168692175+innerthunder@users.noreply.github.com>
This commit is contained in:
parent
d6854c4969
commit
cef2f2adf7
|
@ -5713,9 +5713,7 @@ export function initAbilities() {
|
|||
.condition(getSheerForceHitDisableAbCondition()),
|
||||
new Ability(Abilities.SHEER_FORCE, 5)
|
||||
.attr(MovePowerBoostAbAttr, (user, target, move) => move.chance >= 1, 5461 / 4096)
|
||||
.attr(MoveEffectChanceMultiplierAbAttr, 0)
|
||||
.edgeCase() // Should disable shell bell and Meloetta's relic song transformation
|
||||
.edgeCase(), // Should disable life orb, eject button, red card, kee/maranga berry if they get implemented
|
||||
.attr(MoveEffectChanceMultiplierAbAttr, 0), // Should disable life orb, eject button, red card, kee/maranga berry if they get implemented
|
||||
new Ability(Abilities.CONTRARY, 5)
|
||||
.attr(StatStageChangeMultiplierAbAttr, -1)
|
||||
.ignorable(),
|
||||
|
|
|
@ -351,6 +351,10 @@ export class MeloettaFormChangePostMoveTrigger extends SpeciesFormChangePostMove
|
|||
if (pokemon.scene.gameMode.hasChallenge(Challenges.SINGLE_TYPE)) {
|
||||
return false;
|
||||
} else {
|
||||
// Meloetta will not transform if it has the ability Sheer Force when using Relic Song
|
||||
if (pokemon.hasAbility(Abilities.SHEER_FORCE)) {
|
||||
return false;
|
||||
}
|
||||
return super.canChange(pokemon);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ import type { VoucherType } from "#app/system/voucher";
|
|||
import { Command } from "#app/ui/command-ui-handler";
|
||||
import { addTextObject, TextStyle } from "#app/ui/text";
|
||||
import { BooleanHolder, hslToHex, isNullOrUndefined, NumberHolder, toDmgValue } from "#app/utils";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||
import { BerryType } from "#enums/berry-type";
|
||||
import { Moves } from "#enums/moves";
|
||||
|
@ -726,22 +725,6 @@ export abstract class PokemonHeldItemModifier extends PersistentModifier {
|
|||
return 1;
|
||||
}
|
||||
|
||||
//Applies to items with chance of activating secondary effects ie Kings Rock
|
||||
getSecondaryChanceMultiplier(pokemon: Pokemon): number {
|
||||
// Temporary quickfix to stop game from freezing when the opponet uses u-turn while holding on to king's rock
|
||||
if (!pokemon.getLastXMoves()[0]) {
|
||||
return 1;
|
||||
}
|
||||
const sheerForceAffected = allMoves[pokemon.getLastXMoves()[0].move].chance >= 0 && pokemon.hasAbility(Abilities.SHEER_FORCE);
|
||||
|
||||
if (sheerForceAffected) {
|
||||
return 0;
|
||||
} else if (pokemon.hasAbility(Abilities.SERENE_GRACE)) {
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
getMaxStackCount(scene: BattleScene, forThreshold?: boolean): number {
|
||||
const pokemon = this.getPokemon(scene);
|
||||
if (!pokemon) {
|
||||
|
@ -1614,9 +1597,16 @@ export class BypassSpeedChanceModifier extends PokemonHeldItemModifier {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for Pokemon held items like King's Rock
|
||||
* Because King's Rock can be stacked in PokeRogue, unlike mainline, it does not receive a boost from Abilities.SERENE_GRACE
|
||||
*/
|
||||
export class FlinchChanceModifier extends PokemonHeldItemModifier {
|
||||
private chance: number;
|
||||
constructor(type: ModifierType, pokemonId: number, stackCount?: number) {
|
||||
super(type, pokemonId, stackCount);
|
||||
|
||||
this.chance = 10;
|
||||
}
|
||||
|
||||
matchType(modifier: Modifier) {
|
||||
|
@ -1644,7 +1634,8 @@ export class FlinchChanceModifier extends PokemonHeldItemModifier {
|
|||
* @returns `true` if {@linkcode FlinchChanceModifier} has been applied
|
||||
*/
|
||||
override apply(pokemon: Pokemon, flinched: BooleanHolder): boolean {
|
||||
if (!flinched.value && pokemon.randSeedInt(10) < (this.getStackCount() * this.getSecondaryChanceMultiplier(pokemon))) {
|
||||
// The check for pokemon.battleSummonData is to ensure that a crash doesn't occur when a Pokemon with King's Rock procs a flinch
|
||||
if (pokemon.battleSummonData && !flinched.value && pokemon.randSeedInt(100) < (this.getStackCount() * this.chance)) {
|
||||
flinched.value = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -1652,7 +1643,7 @@ export class FlinchChanceModifier extends PokemonHeldItemModifier {
|
|||
return false;
|
||||
}
|
||||
|
||||
getMaxHeldItemCount(pokemon: Pokemon): number {
|
||||
getMaxHeldItemCount(_pokemon: Pokemon): number {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
import { BattlerIndex } from "#app/battle";
|
||||
import { applyAbAttrs, MoveEffectChanceMultiplierAbAttr } from "#app/data/ability";
|
||||
import { Stat } from "#enums/stat";
|
||||
import { MoveEffectPhase } from "#app/phases/move-effect-phase";
|
||||
import * as Utils from "#app/utils";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { Species } from "#enums/species";
|
||||
import GameManager from "#test/utils/gameManager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
|
||||
import { allMoves } from "#app/data/move";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { FlinchAttr } from "#app/data/move";
|
||||
|
||||
describe("Abilities - Serene Grace", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
|
@ -27,66 +24,26 @@ describe("Abilities - Serene Grace", () => {
|
|||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
const movesToUse = [ Moves.AIR_SLASH, Moves.TACKLE ];
|
||||
game.override.battleType("single");
|
||||
game.override.enemySpecies(Species.ONIX);
|
||||
game.override.startingLevel(100);
|
||||
game.override.moveset(movesToUse);
|
||||
game.override.enemyMoveset([ Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE ]);
|
||||
game.override
|
||||
.battleType("single")
|
||||
.ability(Abilities.SERENE_GRACE)
|
||||
.moveset([ Moves.AIR_SLASH, Moves.TACKLE ])
|
||||
.enemyLevel(10)
|
||||
.enemyMoveset([ Moves.SPLASH ]);
|
||||
});
|
||||
|
||||
it("Move chance without Serene Grace", async () => {
|
||||
const moveToUse = Moves.AIR_SLASH;
|
||||
await game.startBattle([
|
||||
Species.PIDGEOT
|
||||
]);
|
||||
it("Serene Grace should double the secondary effect chance of a move", async () => {
|
||||
await game.classicMode.startBattle([ Species.SHUCKLE ]);
|
||||
|
||||
const airSlashMove = allMoves[Moves.AIR_SLASH];
|
||||
const airSlashFlinchAttr = airSlashMove.getAttrs(FlinchAttr)[0];
|
||||
vi.spyOn(airSlashFlinchAttr, "getMoveChance");
|
||||
|
||||
game.scene.getEnemyParty()[0].stats[Stat.SPDEF] = 10000;
|
||||
expect(game.scene.getPlayerParty()[0].formIndex).toBe(0);
|
||||
|
||||
game.move.select(moveToUse);
|
||||
|
||||
game.move.select(Moves.AIR_SLASH);
|
||||
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
|
||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||
await game.move.forceHit();
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
// Check chance of Air Slash without Serene Grace
|
||||
const phase = game.scene.getCurrentPhase() as MoveEffectPhase;
|
||||
const move = phase.move.getMove();
|
||||
expect(move.id).toBe(Moves.AIR_SLASH);
|
||||
|
||||
const chance = new Utils.IntegerHolder(move.chance);
|
||||
console.log(move.chance + " Their ability is " + phase.getUserPokemon()!.getAbility().name);
|
||||
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getFirstTarget(), false);
|
||||
expect(chance.value).toBe(30);
|
||||
|
||||
}, 20000);
|
||||
|
||||
it("Move chance with Serene Grace", async () => {
|
||||
const moveToUse = Moves.AIR_SLASH;
|
||||
game.override.ability(Abilities.SERENE_GRACE);
|
||||
await game.startBattle([
|
||||
Species.TOGEKISS
|
||||
]);
|
||||
|
||||
game.scene.getEnemyParty()[0].stats[Stat.SPDEF] = 10000;
|
||||
expect(game.scene.getPlayerParty()[0].formIndex).toBe(0);
|
||||
|
||||
game.move.select(moveToUse);
|
||||
|
||||
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
|
||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||
|
||||
// Check chance of Air Slash with Serene Grace
|
||||
const phase = game.scene.getCurrentPhase() as MoveEffectPhase;
|
||||
const move = phase.move.getMove();
|
||||
expect(move.id).toBe(Moves.AIR_SLASH);
|
||||
|
||||
const chance = new Utils.IntegerHolder(move.chance);
|
||||
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getFirstTarget(), false);
|
||||
expect(chance.value).toBe(60);
|
||||
|
||||
}, 20000);
|
||||
|
||||
//TODO King's Rock Interaction Unit Test
|
||||
expect(airSlashFlinchAttr.getMoveChance).toHaveLastReturnedWith(60);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
import { BattlerIndex } from "#app/battle";
|
||||
import { applyAbAttrs, applyPostDefendAbAttrs, applyPreAttackAbAttrs, MoveEffectChanceMultiplierAbAttr, MovePowerBoostAbAttr, PostDefendTypeChangeAbAttr } from "#app/data/ability";
|
||||
import { MoveEffectPhase } from "#app/phases/move-effect-phase";
|
||||
import { NumberHolder } from "#app/utils";
|
||||
import { Type } from "#app/enums/type";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { Species } from "#enums/species";
|
||||
import { Stat } from "#enums/stat";
|
||||
import GameManager from "#test/utils/gameManager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
import { allMoves } from "#app/data/move";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { allMoves, FlinchAttr } from "#app/data/move";
|
||||
|
||||
describe("Abilities - Sheer Force", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
|
@ -27,143 +25,91 @@ describe("Abilities - Sheer Force", () => {
|
|||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
const movesToUse = [ Moves.AIR_SLASH, Moves.BIND, Moves.CRUSH_CLAW, Moves.TACKLE ];
|
||||
game.override.battleType("single");
|
||||
game.override.enemySpecies(Species.ONIX);
|
||||
game.override.startingLevel(100);
|
||||
game.override.moveset(movesToUse);
|
||||
game.override.enemyMoveset([ Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE ]);
|
||||
game.override
|
||||
.battleType("single")
|
||||
.ability(Abilities.SHEER_FORCE)
|
||||
.enemySpecies(Species.ONIX)
|
||||
.enemyAbility(Abilities.BALL_FETCH)
|
||||
.enemyMoveset([ Moves.SPLASH ])
|
||||
.disableCrits();
|
||||
});
|
||||
|
||||
it("Sheer Force", async () => {
|
||||
const moveToUse = Moves.AIR_SLASH;
|
||||
game.override.ability(Abilities.SHEER_FORCE);
|
||||
const SHEER_FORCE_MULT = 5461 / 4096;
|
||||
|
||||
it("Sheer Force should boost the power of the move but disable secondary effects", async () => {
|
||||
game.override.moveset([ Moves.AIR_SLASH ]);
|
||||
await game.classicMode.startBattle([ Species.SHUCKLE ]);
|
||||
|
||||
const airSlashMove = allMoves[Moves.AIR_SLASH];
|
||||
vi.spyOn(airSlashMove, "calculateBattlePower");
|
||||
const airSlashFlinchAttr = airSlashMove.getAttrs(FlinchAttr)[0];
|
||||
vi.spyOn(airSlashFlinchAttr, "getMoveChance");
|
||||
|
||||
game.move.select(Moves.AIR_SLASH);
|
||||
|
||||
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
|
||||
await game.move.forceHit();
|
||||
await game.phaseInterceptor.to("BerryPhase", false);
|
||||
|
||||
expect(airSlashMove.calculateBattlePower).toHaveLastReturnedWith(airSlashMove.power * SHEER_FORCE_MULT);
|
||||
expect(airSlashFlinchAttr.getMoveChance).toHaveLastReturnedWith(0);
|
||||
});
|
||||
|
||||
it("Sheer Force does not affect the base damage or secondary effects of binding moves", async () => {
|
||||
game.override.moveset([ Moves.BIND ]);
|
||||
await game.classicMode.startBattle([ Species.SHUCKLE ]);
|
||||
|
||||
const bindMove = allMoves[Moves.BIND];
|
||||
vi.spyOn(bindMove, "calculateBattlePower");
|
||||
|
||||
game.move.select(Moves.BIND);
|
||||
|
||||
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
|
||||
await game.move.forceHit();
|
||||
await game.phaseInterceptor.to("BerryPhase", false);
|
||||
|
||||
expect(bindMove.calculateBattlePower).toHaveLastReturnedWith(bindMove.power);
|
||||
}, 20000);
|
||||
|
||||
it("Sheer Force does not boost the base damage of moves with no secondary effect", async () => {
|
||||
game.override.moveset([ Moves.TACKLE ]);
|
||||
await game.classicMode.startBattle([ Species.PIDGEOT ]);
|
||||
|
||||
game.scene.getEnemyPokemon()!.stats[Stat.SPDEF] = 10000;
|
||||
expect(game.scene.getPlayerPokemon()!.formIndex).toBe(0);
|
||||
|
||||
game.move.select(moveToUse);
|
||||
const tackleMove = allMoves[Moves.TACKLE];
|
||||
vi.spyOn(tackleMove, "calculateBattlePower");
|
||||
|
||||
game.move.select(Moves.TACKLE);
|
||||
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
|
||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||
await game.move.forceHit();
|
||||
await game.phaseInterceptor.to("BerryPhase", false);
|
||||
|
||||
const phase = game.scene.getCurrentPhase() as MoveEffectPhase;
|
||||
const move = phase.move.getMove();
|
||||
expect(move.id).toBe(Moves.AIR_SLASH);
|
||||
expect(tackleMove.calculateBattlePower).toHaveLastReturnedWith(tackleMove.power);
|
||||
});
|
||||
|
||||
//Verify the move is boosted and has no chance of secondary effects
|
||||
const power = new NumberHolder(move.power);
|
||||
const chance = new NumberHolder(move.chance);
|
||||
it("Sheer Force can disable the on-hit activation of specific abilities", async () => {
|
||||
game.override
|
||||
.moveset([ Moves.HEADBUTT ])
|
||||
.enemySpecies(Species.SQUIRTLE)
|
||||
.enemyLevel(10)
|
||||
.enemyAbility(Abilities.COLOR_CHANGE);
|
||||
|
||||
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getFirstTarget(), false);
|
||||
applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getFirstTarget()!, move, false, power);
|
||||
|
||||
expect(chance.value).toBe(0);
|
||||
expect(power.value).toBe(move.power * 5461 / 4096);
|
||||
|
||||
|
||||
}, 20000);
|
||||
|
||||
it("Sheer Force with exceptions including binding moves", async () => {
|
||||
const moveToUse = Moves.BIND;
|
||||
game.override.ability(Abilities.SHEER_FORCE);
|
||||
await game.classicMode.startBattle([ Species.PIDGEOT ]);
|
||||
const enemyPokemon = game.scene.getEnemyPokemon();
|
||||
const headbuttMove = allMoves[Moves.HEADBUTT];
|
||||
vi.spyOn(headbuttMove, "calculateBattlePower");
|
||||
const headbuttFlinchAttr = headbuttMove.getAttrs(FlinchAttr)[0];
|
||||
vi.spyOn(headbuttFlinchAttr, "getMoveChance");
|
||||
|
||||
|
||||
game.scene.getEnemyPokemon()!.stats[Stat.DEF] = 10000;
|
||||
expect(game.scene.getPlayerPokemon()!.formIndex).toBe(0);
|
||||
|
||||
game.move.select(moveToUse);
|
||||
game.move.select(Moves.HEADBUTT);
|
||||
|
||||
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
|
||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||
await game.move.forceHit();
|
||||
await game.phaseInterceptor.to("BerryPhase", false);
|
||||
|
||||
const phase = game.scene.getCurrentPhase() as MoveEffectPhase;
|
||||
const move = phase.move.getMove();
|
||||
expect(move.id).toBe(Moves.BIND);
|
||||
|
||||
//Binding moves and other exceptions are not affected by Sheer Force and have a chance.value of -1
|
||||
const power = new NumberHolder(move.power);
|
||||
const chance = new NumberHolder(move.chance);
|
||||
|
||||
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getFirstTarget(), false);
|
||||
applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getFirstTarget()!, move, false, power);
|
||||
|
||||
expect(chance.value).toBe(-1);
|
||||
expect(power.value).toBe(move.power);
|
||||
|
||||
|
||||
}, 20000);
|
||||
|
||||
it("Sheer Force with moves with no secondary effect", async () => {
|
||||
const moveToUse = Moves.TACKLE;
|
||||
game.override.ability(Abilities.SHEER_FORCE);
|
||||
await game.classicMode.startBattle([ Species.PIDGEOT ]);
|
||||
|
||||
|
||||
game.scene.getEnemyPokemon()!.stats[Stat.DEF] = 10000;
|
||||
expect(game.scene.getPlayerPokemon()!.formIndex).toBe(0);
|
||||
|
||||
game.move.select(moveToUse);
|
||||
|
||||
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
|
||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||
|
||||
const phase = game.scene.getCurrentPhase() as MoveEffectPhase;
|
||||
const move = phase.move.getMove();
|
||||
expect(move.id).toBe(Moves.TACKLE);
|
||||
|
||||
//Binding moves and other exceptions are not affected by Sheer Force and have a chance.value of -1
|
||||
const power = new NumberHolder(move.power);
|
||||
const chance = new NumberHolder(move.chance);
|
||||
|
||||
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getFirstTarget(), false);
|
||||
applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getFirstTarget()!, move, false, power);
|
||||
|
||||
expect(chance.value).toBe(-1);
|
||||
expect(power.value).toBe(move.power);
|
||||
|
||||
|
||||
}, 20000);
|
||||
|
||||
it("Sheer Force Disabling Specific Abilities", async () => {
|
||||
const moveToUse = Moves.CRUSH_CLAW;
|
||||
game.override.enemyAbility(Abilities.COLOR_CHANGE);
|
||||
game.override.startingHeldItems([{ name: "KINGS_ROCK", count: 1 }]);
|
||||
game.override.ability(Abilities.SHEER_FORCE);
|
||||
await game.startBattle([ Species.PIDGEOT ]);
|
||||
|
||||
|
||||
game.scene.getEnemyPokemon()!.stats[Stat.DEF] = 10000;
|
||||
expect(game.scene.getPlayerPokemon()!.formIndex).toBe(0);
|
||||
|
||||
game.move.select(moveToUse);
|
||||
|
||||
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
|
||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||
|
||||
const phase = game.scene.getCurrentPhase() as MoveEffectPhase;
|
||||
const move = phase.move.getMove();
|
||||
expect(move.id).toBe(Moves.CRUSH_CLAW);
|
||||
|
||||
//Disable color change due to being hit by Sheer Force
|
||||
const power = new NumberHolder(move.power);
|
||||
const chance = new NumberHolder(move.chance);
|
||||
const user = phase.getUserPokemon()!;
|
||||
const target = phase.getFirstTarget()!;
|
||||
const opponentType = target.getTypes()[0];
|
||||
|
||||
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, user, null, false, chance, move, target, false);
|
||||
applyPreAttackAbAttrs(MovePowerBoostAbAttr, user, target, move, false, power);
|
||||
applyPostDefendAbAttrs(PostDefendTypeChangeAbAttr, target, user, move, target.apply(user, move));
|
||||
|
||||
expect(chance.value).toBe(0);
|
||||
expect(power.value).toBe(move.power * 5461 / 4096);
|
||||
expect(target.getTypes().length).toBe(2);
|
||||
expect(target.getTypes()[0]).toBe(opponentType);
|
||||
|
||||
}, 20000);
|
||||
expect(enemyPokemon?.getTypes()[0]).toBe(Type.WATER);
|
||||
expect(headbuttMove.calculateBattlePower).toHaveLastReturnedWith(headbuttMove.power * SHEER_FORCE_MULT);
|
||||
expect(headbuttFlinchAttr.getMoveChance).toHaveLastReturnedWith(0);
|
||||
});
|
||||
|
||||
it("Two Pokemon with abilities disabled by Sheer Force hitting each other should not cause a crash", async () => {
|
||||
const moveToUse = Moves.CRUNCH;
|
||||
|
@ -191,5 +137,19 @@ describe("Abilities - Sheer Force", () => {
|
|||
expect(onix.getTypes()).toStrictEqual(expectedTypes);
|
||||
});
|
||||
|
||||
//TODO King's Rock Interaction Unit Test
|
||||
it("Sheer Force should disable Meloetta's transformation from Relic Song", async () => {
|
||||
game.override
|
||||
.ability(Abilities.SHEER_FORCE)
|
||||
.moveset([ Moves.RELIC_SONG ])
|
||||
.enemyMoveset([ Moves.SPLASH ])
|
||||
.enemyLevel(100);
|
||||
await game.classicMode.startBattle([ Species.MELOETTA ]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon();
|
||||
const formKeyStart = playerPokemon?.getFormKey();
|
||||
|
||||
game.move.select(Moves.RELIC_SONG);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
expect(formKeyStart).toBe(playerPokemon?.getFormKey());
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue