Implement Lash Out

This commit is contained in:
NightKev 2024-08-21 04:26:04 -07:00
parent 47c95658ae
commit 0b5741ea1b
5 changed files with 121 additions and 14 deletions

View File

@ -5891,7 +5891,6 @@ export class DestinyBondAttr extends MoveEffectAttr {
/**
* Attribute to apply a battler tag to the target if they have had their stats boosted this turn.
*
* @extends AddBattlerTagAttr
*/
export class AddBattlerTagIfBoostedAttr extends AddBattlerTagAttr {
@ -5907,7 +5906,7 @@ export class AddBattlerTagIfBoostedAttr extends AddBattlerTagAttr {
* @returns true
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if (target.turnData.battleStatsChange.find(v => v > 0)) {
if (target.turnData.battleStatsIncrease) {
super.apply(user, target, move, args);
}
return true;
@ -5916,7 +5915,6 @@ export class AddBattlerTagIfBoostedAttr extends AddBattlerTagAttr {
/**
* Attribute to apply a status effect to the target if they have had their stats boosted this turn.
*
* @extends MoveEffectAttr
*/
export class StatusIfBoostedAttr extends MoveEffectAttr {
@ -5935,7 +5933,7 @@ export class StatusIfBoostedAttr extends MoveEffectAttr {
* @returns true
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if (target.turnData.battleStatsChange.find(v => v > 0)) {
if (target.turnData.battleStatsIncrease) {
target.trySetStatus(this.effect, true, user);
}
return true;
@ -8573,7 +8571,7 @@ export function initMoves() {
.attr(StatusIfBoostedAttr, StatusEffect.BURN)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.LASH_OUT, Type.DARK, MoveCategory.PHYSICAL, 75, 100, 5, -1, 0, 8)
.partial(),
.attr(MovePowerMultiplierAttr, (user, target, move) => user.turnData.battleStatsDecrease ? 2 : 1),
new AttackMove(Moves.POLTERGEIST, Type.GHOST, MoveCategory.PHYSICAL, 110, 90, 5, -1, 0, 8)
.attr(AttackedByItemAttr)
.makesContact(false),

View File

@ -4278,7 +4278,8 @@ export class PokemonTurnData {
public damageTaken: number = 0;
public attacksReceived: AttackMoveResult[] = [];
public order: number;
public battleStatsChange: number[] = [0, 0, 0, 0, 0, 0, 0];
public battleStatsIncrease: boolean = false;
public battleStatsDecrease: boolean = false;
}
export enum AiType {

View File

@ -72,7 +72,7 @@ export class StatChangePhase extends PokemonPhase {
}
const battleStats = this.getPokemon().summonData.battleStats;
const relLevels = filteredStats.map(stat => (levels.value >= 1 ? Math.min(battleStats![stat] + levels.value, 6) : Math.max(battleStats![stat] + levels.value, -6)) - battleStats![stat]);
const relLevels = filteredStats.map(stat => (levels.value >= 1 ? Math.min(battleStats[stat] + levels.value, 6) : Math.max(battleStats[stat] + levels.value, -6)) - battleStats[stat]);
this.onChange && this.onChange(this.getPokemon(), filteredStats, relLevels);
@ -85,12 +85,18 @@ export class StatChangePhase extends PokemonPhase {
}
for (const stat of filteredStats) {
if (levels.value > 0 && pokemon.summonData.battleStats[stat] + levels.value <= 6) {
if (levels.value > 0 && pokemon.summonData.battleStats[stat] < 6) {
if (!pokemon.turnData) {
// Temporary fix for missing turn data struct on turn 1
pokemon.resetTurnData();
}
pokemon.turnData.battleStatsChange[stat] += levels.value;
pokemon.turnData.battleStatsIncrease = true;
} else if (levels.value < 0 && pokemon.summonData.battleStats[stat] > -6) {
if (!pokemon.turnData) {
// Temporary fix for missing turn data struct on turn 1
pokemon.resetTurnData();
}
pokemon.turnData.battleStatsDecrease = true;
}
pokemon.summonData.battleStats[stat] = Math.max(Math.min(pokemon.summonData.battleStats[stat] + levels.value, 6), -6);

View File

@ -1,13 +1,14 @@
import { BattlerIndex } from "#app/battle";
import { allMoves } from "#app/data/move";
import { Abilities } from "#app/enums/abilities";
import { StatusEffect } from "#app/enums/status-effect";
import { BerryPhase } from "#app/phases/berry-phase";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { SPLASH_ONLY } from "../utils/testUtils";
const TIMEOUT = 20 * 1000;
@ -37,7 +38,7 @@ describe("Moves - Burning Jealousy", () => {
.enemyLevel(10)
.starterSpecies(Species.FEEBAS)
.ability(Abilities.BALL_FETCH)
.moveset([Moves.BURNING_JEALOUSY]);
.moveset([Moves.BURNING_JEALOUSY, Moves.GROWL]);
});
@ -48,8 +49,56 @@ describe("Moves - Burning Jealousy", () => {
game.doAttack(getMovePosition(game.scene, 0, Moves.BURNING_JEALOUSY));
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await game.phaseInterceptor.to(BerryPhase);
await game.phaseInterceptor.to("BerryPhase");
expect(enemy.status?.effect).toBe(StatusEffect.BURN);
}, TIMEOUT);
it("should still burn the opponent if their stats were both raised and lowered in the same turn", async () => {
game.override
.starterSpecies(0)
.battleType("double");
await game.startBattle([Species.FEEBAS, Species.ABRA]);
const enemy = game.scene.getEnemyPokemon()!;
game.doAttack(getMovePosition(game.scene, 0, Moves.BURNING_JEALOUSY));
game.doAttack(getMovePosition(game.scene, 1, Moves.GROWL));
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER_2, BattlerIndex.PLAYER, BattlerIndex.ENEMY_2]);
await game.phaseInterceptor.to("BerryPhase");
expect(enemy.status?.effect).toBe(StatusEffect.BURN);
}, TIMEOUT);
it("should ignore stats raised by imposter", async () => {
game.override
.enemySpecies(Species.DITTO)
.enemyAbility(Abilities.IMPOSTER)
.enemyMoveset(SPLASH_ONLY);
await game.startBattle();
const enemy = game.scene.getEnemyPokemon()!;
game.doAttack(getMovePosition(game.scene, 0, Moves.BURNING_JEALOUSY));
await game.phaseInterceptor.to("BerryPhase");
expect(enemy.status?.effect).toBeUndefined();
}, TIMEOUT);
it.skip("should ignore weakness policy", async () => { // TODO: Make this test if WP is implemented
await game.startBattle();
}, TIMEOUT);
it("should be boosted by Sheer Force even if opponent didn't raise stats", async () => {
game.override
.ability(Abilities.SHEER_FORCE)
.enemyMoveset(SPLASH_ONLY);
vi.spyOn(allMoves[Moves.BURNING_JEALOUSY], "calculateBattlePower");
await game.startBattle();
game.doAttack(getMovePosition(game.scene, 0, Moves.BURNING_JEALOUSY));
await game.phaseInterceptor.to("BerryPhase");
expect(allMoves[Moves.BURNING_JEALOUSY].calculateBattlePower).toHaveReturnedWith(allMoves[Moves.BURNING_JEALOUSY].power * 5461 / 4096);
}, TIMEOUT);
});

View File

@ -0,0 +1,53 @@
import { BattlerIndex } from "#app/battle";
import { allMoves } from "#app/data/move";
import { Abilities } from "#app/enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const TIMEOUT = 20 * 1000;
describe("Moves - Burning Jealousy", () => {
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
.battleType("single")
.disableCrits()
.enemySpecies(Species.MAGIKARP)
.enemyAbility(Abilities.FUR_COAT)
.enemyMoveset(Array(4).fill(Moves.GROWL))
.startingLevel(10)
.enemyLevel(10)
.starterSpecies(Species.FEEBAS)
.ability(Abilities.BALL_FETCH)
.moveset([Moves.LASH_OUT]);
});
it("should deal double damage if the user's stats were lowered this turn", async () => {
vi.spyOn(allMoves[Moves.LASH_OUT], "calculateBattlePower");
await game.startBattle();
game.doAttack(getMovePosition(game.scene, 0, Moves.LASH_OUT));
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await game.phaseInterceptor.to("BerryPhase");
expect(allMoves[Moves.LASH_OUT].calculateBattlePower).toHaveReturnedWith(150);
}, TIMEOUT);
});