Skip to content

Commit

Permalink
Merged from official repos
Browse files Browse the repository at this point in the history
  • Loading branch information
MikeyTheA committed Jul 7, 2024
2 parents 7f291a3 + 694616e commit b61594a
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 9 deletions.
30 changes: 25 additions & 5 deletions src/data/move.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2961,9 +2961,29 @@ export class HpPowerAttr extends VariablePowerAttr {
}
}

/**
* Attribute used for moves whose base power scales with the opponent's HP
* Used for Crush Grip, Wring Out, and Hard Press
* maxBasePower 100 for Hard Press, 120 for others
*/
export class OpponentHighHpPowerAttr extends VariablePowerAttr {
maxBasePower: number;

constructor(maxBasePower: number) {
super();
this.maxBasePower = maxBasePower;
}

/**
* Changes the base power of the move to be the target's HP ratio times the maxBasePower with a min value of 1
* @param user n/a
* @param target the Pokemon being attacked
* @param move n/a
* @param args holds the base power of the move at args[0]
* @returns true
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
(args[0] as Utils.NumberHolder).value = Math.max(Math.floor(120 * target.getHpRatio()), 1);
(args[0] as Utils.NumberHolder).value = Math.max(Math.floor(this.maxBasePower * target.getHpRatio()), 1);

return true;
}
Expand Down Expand Up @@ -6685,7 +6705,7 @@ export function initMoves() {
.target(MoveTarget.ALL_NEAR_ENEMIES)
.unimplemented(),
new AttackMove(Moves.WRING_OUT, Type.NORMAL, MoveCategory.SPECIAL, -1, 100, 5, -1, 0, 4)
.attr(OpponentHighHpPowerAttr)
.attr(OpponentHighHpPowerAttr, 120)
.makesContact(),
new SelfStatusMove(Moves.POWER_TRICK, Type.PSYCHIC, -1, 10, -1, 0, 4)
.unimplemented(),
Expand Down Expand Up @@ -6909,7 +6929,7 @@ export function initMoves() {
.triageMove()
.unimplemented(),
new AttackMove(Moves.CRUSH_GRIP, Type.NORMAL, MoveCategory.PHYSICAL, -1, 100, 5, -1, 0, 4)
.attr(OpponentHighHpPowerAttr),
.attr(OpponentHighHpPowerAttr, 120),
new AttackMove(Moves.MAGMA_STORM, Type.FIRE, MoveCategory.SPECIAL, 100, 75, 5, -1, 0, 4)
.attr(TrapAttr, BattlerTagType.MAGMA_STORM),
new StatusMove(Moves.DARK_VOID, Type.DARK, 50, 10, -1, 0, 4)
Expand Down Expand Up @@ -8379,8 +8399,8 @@ export function initMoves() {
new AttackMove(Moves.TACHYON_CUTTER, Type.STEEL, MoveCategory.SPECIAL, 50, -1, 10, -1, 0, 9)
.attr(MultiHitAttr, MultiHitType._2)
.slicingMove(),
new AttackMove(Moves.HARD_PRESS, Type.STEEL, MoveCategory.PHYSICAL, 100, 100, 5, -1, 0, 9)
.attr(OpponentHighHpPowerAttr),
new AttackMove(Moves.HARD_PRESS, Type.STEEL, MoveCategory.PHYSICAL, -1, 100, 10, -1, 0, 9)
.attr(OpponentHighHpPowerAttr, 100),
new StatusMove(Moves.DRAGON_CHEER, Type.DRAGON, -1, 15, -1, 0, 9)
.attr(AddBattlerTagAttr, BattlerTagType.CRIT_BOOST, false, true)
.target(MoveTarget.NEAR_ALLY)
Expand Down
8 changes: 4 additions & 4 deletions src/system/achv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -316,10 +316,10 @@ export const achvs = {
CATCH_LEGENDARY: new Achv("CATCH_LEGENDARY", "", "CATCH_LEGENDARY.description","mb", 100).setSecret(),
SEE_SHINY: new Achv("SEE_SHINY", "", "SEE_SHINY.description","pb_gold", 75),
SHINY_PARTY: new Achv("SHINY_PARTY", "", "SHINY_PARTY.description","shiny_charm", 100).setSecret(true),
HATCH_MYTHICAL: new Achv("HATCH_MYTHICAL", "", "HATCH_MYTHICAL.description","pair_of_tickets", 75).setSecret(),
HATCH_SUB_LEGENDARY: new Achv("HATCH_SUB_LEGENDARY","", "HATCH_SUB_LEGENDARY.description","mystic_ticket", 100).setSecret(),
HATCH_LEGENDARY: new Achv("HATCH_LEGENDARY","", "HATCH_LEGENDARY.description","mystic_ticket", 125).setSecret(),
HATCH_SHINY: new Achv("HATCH_SHINY","", "HATCH_SHINY.description","golden_mystic_ticket", 100).setSecret(),
HATCH_MYTHICAL: new Achv("HATCH_MYTHICAL", "", "HATCH_MYTHICAL.description","mystery_egg", 75).setSecret(),
HATCH_SUB_LEGENDARY: new Achv("HATCH_SUB_LEGENDARY","", "HATCH_SUB_LEGENDARY.description","oval_stone", 100).setSecret(),
HATCH_LEGENDARY: new Achv("HATCH_LEGENDARY","", "HATCH_LEGENDARY.description","lucky_egg", 125).setSecret(),
HATCH_SHINY: new Achv("HATCH_SHINY","", "HATCH_SHINY.description","golden_egg", 100).setSecret(),
HIDDEN_ABILITY: new Achv("HIDDEN_ABILITY","", "HIDDEN_ABILITY.description","ability_charm", 75),
PERFECT_IVS: new Achv("PERFECT_IVS","", "PERFECT_IVS.description","blunder_policy", 100),
CLASSIC_VICTORY: new Achv("CLASSIC_VICTORY","", "CLASSIC_VICTORY.description","relic_crown", 150),
Expand Down
83 changes: 83 additions & 0 deletions src/test/moves/hard_press.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import Phaser from "phaser";
import GameManager from "#app/test/utils/gameManager";
import * as overrides from "#app/overrides";
import { Species } from "#enums/species";
import {
MoveEffectPhase,
} from "#app/phases";
import { Moves } from "#enums/moves";
import { getMovePosition } from "#app/test/utils/gameManagerUtils";
import { Abilities } from "#enums/abilities";
import { NumberHolder } from "#app/utils.js";
import Move from "#app/data/move.js";
import Pokemon from "#app/field/pokemon.js";
import { allMoves, OpponentHighHpPowerAttr } from "#app/data/move.js";

describe("Moves - Hard Press", () => {
let phaserGame: Phaser.Game;
let game: GameManager;

beforeAll(() => {
phaserGame = new Phaser.Game({
type: Phaser.HEADLESS,
});
});

afterEach(() => {
game.phaseInterceptor.restoreOg();
});

beforeEach(() => {
game = new GameManager(phaserGame);
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.SNORLAX);
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.NONE);
vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.HARD_PRESS]);
});

it("power varies between 1 and 100, and is greater the more HP the target has", async () => {
await game.startBattle([Species.GRAVELER]);
const moveToBeUsed = allMoves[Moves.HARD_PRESS];

game.doAttack(getMovePosition(game.scene, 0, moveToBeUsed));
await game.phaseInterceptor.to(MoveEffectPhase);

const enemy = game.scene.getEnemyPokemon();
const movePower = getMockedMovePower(enemy, game.scene.getPlayerPokemon(), moveToBeUsed);
const moveMaxBasePower = getMoveMaxBasePower(moveToBeUsed);

expect(movePower).toBe(moveMaxBasePower * enemy.getHpRatio());
});
});

/**
* Calculates the mocked move power based on the attributes of the move and the opponent's high HP.
*
* @param defender - The defending Pokémon.
* @param attacker - The attacking Pokémon.
* @param move - The move being used.
* @returns The calculated move power.
*/
const getMockedMovePower = (defender: Pokemon, attacker: Pokemon, move: Move) => {
const powerHolder = new NumberHolder(move.power);

if (move.hasAttr(OpponentHighHpPowerAttr)) {
const attr = move.getAttrs(OpponentHighHpPowerAttr);
attr[0].apply(attacker, defender, move, [ powerHolder ]);
}

return powerHolder.value;
};

/**
* Retrieves the maximum base power of a move based on its attributes.
*
* @param move - The move which maximum base power is being retrieved.
* @returns The maximum base power of the move.
*/
const getMoveMaxBasePower = (move: Move) => {
const attr = move.getAttrs(OpponentHighHpPowerAttr);

return (attr[0] as OpponentHighHpPowerAttr)["maxBasePower"];
};

0 comments on commit b61594a

Please sign in to comment.