diff --git a/public/images/pokemon/back/shiny/774.json b/public/images/pokemon/back/shiny/774.json index cabd0eb027b8..7643e0ccc87c 100644 --- a/public/images/pokemon/back/shiny/774.json +++ b/public/images/pokemon/back/shiny/774.json @@ -1,41 +1,41 @@ -{ - "textures": [ - { - "image": "774.png", - "format": "RGBA8888", - "size": { - "w": 37, - "h": 37 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 37, - "h": 35 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 37, - "h": 35 - }, - "frame": { - "x": 0, - "y": 0, - "w": 37, - "h": 35 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:fa61a53a0684a1d00e0ed5d6737743af:3e6463caf33bbb58cfba4bd9c20890aa:37281ac0aa1e619ef385b889b64064b7$" - } -} +{ + "textures": [ + { + "image": "774.png", + "format": "RGBA8888", + "size": { + "w": 37, + "h": 37 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 37, + "h": 37 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 37, + "h": 37 + }, + "frame": { + "x": 0, + "y": 0, + "w": 37, + "h": 37 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:241dff4083e172e8503b54a7f0210f8d:982b194223ffeef2ba672b3c5979a426:37281ac0aa1e619ef385b889b64064b7$" + } +} diff --git a/public/images/pokemon/back/shiny/774.png b/public/images/pokemon/back/shiny/774.png index 3f91ba876a4d..6f93da7a00db 100644 Binary files a/public/images/pokemon/back/shiny/774.png and b/public/images/pokemon/back/shiny/774.png differ diff --git a/public/images/pokemon/exp/back/shiny/774-blue.png b/public/images/pokemon/exp/back/shiny/774-blue.png index dba2d268b0d8..bffbc41e81cc 100644 Binary files a/public/images/pokemon/exp/back/shiny/774-blue.png and b/public/images/pokemon/exp/back/shiny/774-blue.png differ diff --git a/public/images/pokemon/exp/back/shiny/774-green.png b/public/images/pokemon/exp/back/shiny/774-green.png index 59ae18f321ca..f5a85c1ba0fe 100644 Binary files a/public/images/pokemon/exp/back/shiny/774-green.png and b/public/images/pokemon/exp/back/shiny/774-green.png differ diff --git a/public/images/pokemon/exp/back/shiny/774-indigo.png b/public/images/pokemon/exp/back/shiny/774-indigo.png index 25984abc9c27..115365f11b8e 100644 Binary files a/public/images/pokemon/exp/back/shiny/774-indigo.png and b/public/images/pokemon/exp/back/shiny/774-indigo.png differ diff --git a/public/images/pokemon/exp/back/shiny/774-orange.png b/public/images/pokemon/exp/back/shiny/774-orange.png index a6a13f0ab7d1..bf3db830ef89 100644 Binary files a/public/images/pokemon/exp/back/shiny/774-orange.png and b/public/images/pokemon/exp/back/shiny/774-orange.png differ diff --git a/public/images/pokemon/exp/back/shiny/774-red.png b/public/images/pokemon/exp/back/shiny/774-red.png index e3db7f300020..bc3407019f83 100644 Binary files a/public/images/pokemon/exp/back/shiny/774-red.png and b/public/images/pokemon/exp/back/shiny/774-red.png differ diff --git a/public/images/pokemon/exp/back/shiny/774-violet.png b/public/images/pokemon/exp/back/shiny/774-violet.png index 25984abc9c27..68da27cc9604 100644 Binary files a/public/images/pokemon/exp/back/shiny/774-violet.png and b/public/images/pokemon/exp/back/shiny/774-violet.png differ diff --git a/public/images/pokemon/exp/back/shiny/774-yellow.png b/public/images/pokemon/exp/back/shiny/774-yellow.png index bdeaccaf3d85..569b836a2075 100644 Binary files a/public/images/pokemon/exp/back/shiny/774-yellow.png and b/public/images/pokemon/exp/back/shiny/774-yellow.png differ diff --git a/public/images/pokemon/exp/shiny/774-blue.png b/public/images/pokemon/exp/shiny/774-blue.png index 82b53ea3d81b..a6d5fd10f188 100644 Binary files a/public/images/pokemon/exp/shiny/774-blue.png and b/public/images/pokemon/exp/shiny/774-blue.png differ diff --git a/public/images/pokemon/exp/shiny/774-green.png b/public/images/pokemon/exp/shiny/774-green.png index 9ee225dc61cd..ed8deff92bd7 100644 Binary files a/public/images/pokemon/exp/shiny/774-green.png and b/public/images/pokemon/exp/shiny/774-green.png differ diff --git a/public/images/pokemon/exp/shiny/774-indigo.png b/public/images/pokemon/exp/shiny/774-indigo.png index f378b8284509..4c2c954f2e79 100644 Binary files a/public/images/pokemon/exp/shiny/774-indigo.png and b/public/images/pokemon/exp/shiny/774-indigo.png differ diff --git a/public/images/pokemon/exp/shiny/774-orange.png b/public/images/pokemon/exp/shiny/774-orange.png index 54b6eb8eaeda..4edcc654418e 100644 Binary files a/public/images/pokemon/exp/shiny/774-orange.png and b/public/images/pokemon/exp/shiny/774-orange.png differ diff --git a/public/images/pokemon/exp/shiny/774-red.png b/public/images/pokemon/exp/shiny/774-red.png index 539e8d17913b..d04e4468df91 100644 Binary files a/public/images/pokemon/exp/shiny/774-red.png and b/public/images/pokemon/exp/shiny/774-red.png differ diff --git a/public/images/pokemon/exp/shiny/774-violet.png b/public/images/pokemon/exp/shiny/774-violet.png index 840e8dbaeb83..d0721c118a0a 100644 Binary files a/public/images/pokemon/exp/shiny/774-violet.png and b/public/images/pokemon/exp/shiny/774-violet.png differ diff --git a/public/images/pokemon/exp/shiny/774-yellow.png b/public/images/pokemon/exp/shiny/774-yellow.png index 64b10fdae1e9..ab2f44c185a3 100644 Binary files a/public/images/pokemon/exp/shiny/774-yellow.png and b/public/images/pokemon/exp/shiny/774-yellow.png differ diff --git a/public/images/pokemon/shiny/774.json b/public/images/pokemon/shiny/774.json index 11d07b823e02..c61c17918623 100644 --- a/public/images/pokemon/shiny/774.json +++ b/public/images/pokemon/shiny/774.json @@ -1,41 +1,41 @@ -{ - "textures": [ - { - "image": "774.png", - "format": "RGBA8888", - "size": { - "w": 37, - "h": 37 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 37, - "h": 35 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 37, - "h": 35 - }, - "frame": { - "x": 0, - "y": 0, - "w": 37, - "h": 35 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:29265d2eed2689ecb95874383b7e7da7:1339971def468ab6d7c93a72472c7b3d:37281ac0aa1e619ef385b889b64064b7$" - } -} +{ + "textures": [ + { + "image": "774.png", + "format": "RGBA8888", + "size": { + "w": 37, + "h": 37 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 37, + "h": 37 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 37, + "h": 37 + }, + "frame": { + "x": 0, + "y": 0, + "w": 37, + "h": 37 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:566b51540ed595250ead15a4733d98d6:172aa05dcc207383119cd2f2f7977e0e:37281ac0aa1e619ef385b889b64064b7$" + } +} diff --git a/public/images/pokemon/shiny/774.png b/public/images/pokemon/shiny/774.png index 5efd0bc8da14..7d9f5a9cb009 100644 Binary files a/public/images/pokemon/shiny/774.png and b/public/images/pokemon/shiny/774.png differ diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 7d5371b39804..234045ed95a4 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -92,6 +92,7 @@ import { Species } from "#enums/species"; import { UiTheme } from "#enums/ui-theme"; import { TimedEventManager } from "#app/timed-event-manager.js"; import i18next from "i18next"; +import {TrainerType} from "#enums/trainer-type"; import MysteryEncounter, { MysteryEncounterTier, MysteryEncounterVariant } from "./data/mystery-encounter"; import { mysteryEncountersByBiome, @@ -1111,6 +1112,10 @@ export default class BattleScene extends SceneBase { this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance); playerField.forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, doubleChance)); doubleTrainer = !Utils.randSeedInt(doubleChance.value); + // Add a check that special trainers can't be double except for tate and liza - they should use the normal double chance + if (trainerConfigs[trainerType].trainerTypeDouble && !(trainerType === TrainerType.TATE || trainerType === TrainerType.LIZA)) { + doubleTrainer = false; + } } newTrainer = trainerData !== undefined ? trainerData.toTrainer(this) : new Trainer(this, trainerType, doubleTrainer ? TrainerVariant.DOUBLE : Utils.randSeedInt(2) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT); this.field.add(newTrainer); diff --git a/src/data/move.ts b/src/data/move.ts index 4e8c8b2ae989..72d2d6c3879c 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -3058,9 +3058,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; } @@ -6802,7 +6822,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(), @@ -7026,7 +7046,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) @@ -8498,8 +8518,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) diff --git a/src/locales/de/modifier-type.ts b/src/locales/de/modifier-type.ts index 58c866bb38f8..d60179062c30 100644 --- a/src/locales/de/modifier-type.ts +++ b/src/locales/de/modifier-type.ts @@ -151,7 +151,7 @@ export const modifierType: ModifierTypeTranslationEntries = { "SACRED_ASH": { name: "Zauberasche" }, - "REVIVER_SEED": { name: "Belebersamen", description: "Belebt den Träger mit der Hälfte seiner KP wieder sollte er kampfunfähig werden." }, + "REVIVER_SEED": { name: "Belebersamen", description: "Belebt den Träger mit der Hälfte seiner KP wieder, sollte er durch einen direkten Treffer kampfunfähig werden." }, "ETHER": { name: "Äther" }, "MAX_ETHER": { name: "Top-Äther" }, diff --git a/src/locales/en/modifier-type.ts b/src/locales/en/modifier-type.ts index ca953f0c5ea6..5cb21c6fd19f 100644 --- a/src/locales/en/modifier-type.ts +++ b/src/locales/en/modifier-type.ts @@ -151,7 +151,7 @@ export const modifierType: ModifierTypeTranslationEntries = { "SACRED_ASH": { name: "Sacred Ash" }, - "REVIVER_SEED": { name: "Reviver Seed", description: "Revives the holder for 1/2 HP upon fainting." }, + "REVIVER_SEED": { name: "Reviver Seed", description: "Revives the holder for 1/2 HP upon fainting from a direct hit." }, "WHITE_HERB": { name: "White Herb", description: "An item to be held by a Pokémon. It will restore any lowered stat in battle." }, "ETHER": { name: "Ether" }, diff --git a/src/locales/es/modifier-type.ts b/src/locales/es/modifier-type.ts index 2ad7c0eb7030..d7f8441c50d0 100644 --- a/src/locales/es/modifier-type.ts +++ b/src/locales/es/modifier-type.ts @@ -151,7 +151,7 @@ export const modifierType: ModifierTypeTranslationEntries = { "SACRED_ASH": { name: "Cen. Sagrada" }, - "REVIVER_SEED": { name: "Semilla Revivir", description: "Revive al portador con la mitad de sus PS al debilitarse." }, + "REVIVER_SEED": { name: "Semilla Revivir", description: "Revive al portador con la mitad de sus PS al debilitarse por un golpe directo." }, "ETHER": { name: "Éter" }, "MAX_ETHER": { name: "Éter Máx." }, diff --git a/src/locales/fr/modifier-type.ts b/src/locales/fr/modifier-type.ts index 167428af6e65..73069b16e945 100644 --- a/src/locales/fr/modifier-type.ts +++ b/src/locales/fr/modifier-type.ts @@ -151,7 +151,7 @@ export const modifierType: ModifierTypeTranslationEntries = { "SACRED_ASH": { name: "Cendre Sacrée" }, - "REVIVER_SEED": { name: "Résugraine", description: "Réanime et restaure la moitié des PV de son porteur s’il tombe K.O. ." }, + "REVIVER_SEED": { name: "Résugraine", description: "Réanime et restaure la moitié des PV de son porteur s’il est mis K.O. par une capacité directe." }, "ETHER": { name: "Huile" }, "MAX_ETHER": { name: "Huile Max" }, diff --git a/src/locales/it/modifier-type.ts b/src/locales/it/modifier-type.ts index 481ba2f947bd..8e737ba879bf 100644 --- a/src/locales/it/modifier-type.ts +++ b/src/locales/it/modifier-type.ts @@ -151,7 +151,7 @@ export const modifierType: ModifierTypeTranslationEntries = { "SACRED_ASH": { name: "Cenere magica" }, - "REVIVER_SEED": { name: "Revitalseme", description: "Il possessore recupera 1/2 di PS in caso di KO." }, + "REVIVER_SEED": { name: "Revitalseme", description: "Il possessore recupera 1/2 di PS in caso di KO causato da un colpo diretto." }, "ETHER": { name: "Etere" }, "MAX_ETHER": { name: "Etere max" }, diff --git a/src/locales/ko/modifier-type.ts b/src/locales/ko/modifier-type.ts index 118844f2350e..ebd7daa63146 100644 --- a/src/locales/ko/modifier-type.ts +++ b/src/locales/ko/modifier-type.ts @@ -151,7 +151,7 @@ export const modifierType: ModifierTypeTranslationEntries = { "SACRED_ASH": { name: "성스러운분말" }, - "REVIVER_SEED": { name: "부활의씨앗", description: "포켓몬이 쓰러지려 할 때 HP를 절반 회복한다." }, + "REVIVER_SEED": { name: "부활의씨앗", description: "포켓몬이 공격을 받고 쓰러지려 할 때 HP를 절반 회복한다." }, "ETHER": { name: "PP에이드" }, "MAX_ETHER": { name: "PP회복" }, diff --git a/src/locales/pt_BR/modifier-type.ts b/src/locales/pt_BR/modifier-type.ts index 8c3762842f9e..e298b7764002 100644 --- a/src/locales/pt_BR/modifier-type.ts +++ b/src/locales/pt_BR/modifier-type.ts @@ -151,7 +151,7 @@ export const modifierType: ModifierTypeTranslationEntries = { "SACRED_ASH": { name: "Cinza Sagrada" }, - "REVIVER_SEED": { name: "Semente Reanimadora", description: "Após desmaiar, reanima com 50% de PS." }, + "REVIVER_SEED": { name: "Semente Reanimadora", description: "Após desmaiar por um ataque direto, reanima com 50% de PS." }, "ETHER": { name: "Éter" }, "MAX_ETHER": { name: "Éter Máximo" }, diff --git a/src/locales/zh_CN/modifier-type.ts b/src/locales/zh_CN/modifier-type.ts index d9c9bc5f1052..1175012a58e4 100644 --- a/src/locales/zh_CN/modifier-type.ts +++ b/src/locales/zh_CN/modifier-type.ts @@ -151,7 +151,7 @@ export const modifierType: ModifierTypeTranslationEntries = { "SACRED_ASH": { name: "圣灰" }, - "REVIVER_SEED": { name: "复活种子", description: "恢复1只濒死宝可梦的HP至1/2。" }, + "REVIVER_SEED": { name: "复活种子", description: "受到技能攻击伤害濒死时,\n恢复该宝可梦的HP至1/2。" }, "ETHER": { name: "PP单项小补剂" }, "MAX_ETHER": { name: "PP单项全补剂" }, diff --git a/src/locales/zh_TW/modifier-type.ts b/src/locales/zh_TW/modifier-type.ts index 51a7381aed80..2293b8a9183d 100644 --- a/src/locales/zh_TW/modifier-type.ts +++ b/src/locales/zh_TW/modifier-type.ts @@ -153,7 +153,7 @@ export const modifierType: ModifierTypeTranslationEntries = { SACRED_ASH: { name: "聖灰" }, REVIVER_SEED: { name: "復活種子", - description: "恢復1隻瀕死寶可夢的HP至1/2。", + description: "受到技能攻擊傷害瀕死時,\n恢復該瀕死寶可夢的HP至1/2。", }, ETHER: { name: "PP單項小補劑" }, MAX_ETHER: { name: "PP單項全補劑" }, diff --git a/src/phases.ts b/src/phases.ts index 7bcacf2a2b7b..887703adaf34 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -3889,7 +3889,9 @@ export class DamagePhase extends PokemonPhase { super.start(); if (this.damageResult === HitResult.ONE_HIT_KO) { - this.scene.toggleInvert(true); + if (this.scene.moveAnimations) { + this.scene.toggleInvert(true); + } this.scene.time.delayedCall(Utils.fixedInt(1000), () => { this.scene.toggleInvert(false); this.applyDamage(); diff --git a/src/system/achv.ts b/src/system/achv.ts index 511ddd1eb8e6..dda6e5c511bf 100644 --- a/src/system/achv.ts +++ b/src/system/achv.ts @@ -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), diff --git a/src/test/moves/hard_press.test.ts b/src/test/moves/hard_press.test.ts new file mode 100644 index 000000000000..c6f071a699f0 --- /dev/null +++ b/src/test/moves/hard_press.test.ts @@ -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"]; +};