From 3eee9d9b4e7b53373e2c5f56b541458c5e70fb54 Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Fri, 22 Aug 2025 21:43:17 -0700 Subject: [PATCH 01/24] Update version to 1.10.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 74e98e37f89..9648361341a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "pokemon-rogue-battle", "private": true, - "version": "1.10.1", + "version": "1.10.2", "type": "module", "scripts": { "start": "vite", From c027b5562b7fdd227bdfceb736968fd816d8794c Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Sat, 23 Aug 2025 00:37:50 -0700 Subject: [PATCH 02/24] [i18n] Update locales submodule --- public/locales | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/locales b/public/locales index 58fa5f9b6e9..a73ea68fdda 160000 --- a/public/locales +++ b/public/locales @@ -1 +1 @@ -Subproject commit 58fa5f9b6e94469017bfbe69bef992ed48ef5343 +Subproject commit a73ea68fdda09bb5018f524cbe6b7e73a3ddf4e0 From 961d30f75ec15f39eddb89b5162665991b6a3e6d Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Sat, 23 Aug 2025 07:42:41 -0700 Subject: [PATCH 03/24] [Bug] Wild Pokemon can now generate as female again (#6352) --- src/data/pokemon-species.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index 064ad57cfb3..fd8551f2289 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -795,7 +795,7 @@ export class PokemonSpecies extends PokemonSpeciesForm implements Localizable { return Gender.GENDERLESS; } - if (randSeedFloat() <= this.malePercent) { + if (randSeedFloat() * 100 <= this.malePercent) { return Gender.MALE; } return Gender.FEMALE; From e752e7a93d9b1b1f5a319d0790b1445d2562df08 Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Sat, 23 Aug 2025 16:43:33 +0200 Subject: [PATCH 04/24] [Bug][Item] Items can be transfered from 6th item slot again. (#6357) * Added check for transferMode --- src/ui/party-ui-handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/party-ui-handler.ts b/src/ui/party-ui-handler.ts index d3c67f66ec9..9ad56476441 100644 --- a/src/ui/party-ui-handler.ts +++ b/src/ui/party-ui-handler.ts @@ -563,7 +563,7 @@ export class PartyUiHandler extends MessageUiHandler { const ui = this.getUi(); const option = this.options[this.optionsCursor]; - if (option === PartyOption.TRANSFER) { + if (this.transferMode && option === PartyOption.TRANSFER) { return this.processTransferOption(); } From 8b371395bcf2adbb08f031d3899e8f7b4f9ec22a Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Sat, 23 Aug 2025 07:43:56 -0700 Subject: [PATCH 05/24] [Bug] Fix typo in i18n key for second Berries Abound ME option (#6354) --- .../mystery-encounters/encounters/berries-abound-encounter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/mystery-encounters/encounters/berries-abound-encounter.ts b/src/data/mystery-encounters/encounters/berries-abound-encounter.ts index 196ca873f4e..358bba92a09 100644 --- a/src/data/mystery-encounters/encounters/berries-abound-encounter.ts +++ b/src/data/mystery-encounters/encounters/berries-abound-encounter.ts @@ -237,7 +237,7 @@ export const BerriesAboundEncounter: MysteryEncounter = MysteryEncounterBuilder. const config = globalScene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]; config.pokemonConfigs![0].tags = [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON]; config.pokemonConfigs![0].mysteryEncounterBattleEffects = (pokemon: Pokemon) => { - queueEncounterMessage(`${namespace}:option.2.boss_enraged`); + queueEncounterMessage(`${namespace}:option.2.bossEnraged`); globalScene.phaseManager.unshiftNew( "StatStageChangePhase", pokemon.getBattlerIndex(), From e63effa311ef229e0edf4dad10b5bac01aa0128b Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Sat, 23 Aug 2025 16:45:11 +0200 Subject: [PATCH 06/24] [Challenge][Bug] Fix fresh starters for real (#6355) * Including side evolutions of starters --- src/constants.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index 589a091153c..6bb7138e354 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,3 +1,4 @@ +import { pokemonEvolutions } from "#balance/pokemon-evolutions"; import { SpeciesId } from "#enums/species-id"; /** The maximum size of the player's party */ @@ -53,11 +54,14 @@ export const defaultStarterSpecies: SpeciesId[] = [ SpeciesId.QUAXLY, ]; -export const defaultStarterSpeciesAndEvolutions: SpeciesId[] = defaultStarterSpecies.flatMap(id => [ - id, - (id + 1) as SpeciesId, - (id + 2) as SpeciesId, -]); +/** + * The default species and all their evolutions + */ +export const defaultStarterSpeciesAndEvolutions: SpeciesId[] = defaultStarterSpecies.flatMap(id => { + const stage2ids = pokemonEvolutions[id]?.map(e => e.speciesId) ?? []; + const stage3ids = stage2ids.flatMap(s2id => pokemonEvolutions[s2id]?.map(e => e.speciesId) ?? []); + return [id, ...stage2ids, ...stage3ids]; +}); export const saveKey = "x0i2O7WRiANTqPmZ"; // Temporary; secure encryption is not yet necessary From 3dd1948634111155904245dfea5308e050c79c39 Mon Sep 17 00:00:00 2001 From: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com> Date: Sat, 23 Aug 2025 10:00:00 -0500 Subject: [PATCH 07/24] [Misc] Fix circular dep (#6361) --- src/constants.ts | 10 ---------- src/data/balance/pokemon-evolutions.ts | 10 ++++++++++ src/data/challenge.ts | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index 6bb7138e354..17cf08aa7e2 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,4 +1,3 @@ -import { pokemonEvolutions } from "#balance/pokemon-evolutions"; import { SpeciesId } from "#enums/species-id"; /** The maximum size of the player's party */ @@ -54,15 +53,6 @@ export const defaultStarterSpecies: SpeciesId[] = [ SpeciesId.QUAXLY, ]; -/** - * The default species and all their evolutions - */ -export const defaultStarterSpeciesAndEvolutions: SpeciesId[] = defaultStarterSpecies.flatMap(id => { - const stage2ids = pokemonEvolutions[id]?.map(e => e.speciesId) ?? []; - const stage3ids = stage2ids.flatMap(s2id => pokemonEvolutions[s2id]?.map(e => e.speciesId) ?? []); - return [id, ...stage2ids, ...stage3ids]; -}); - export const saveKey = "x0i2O7WRiANTqPmZ"; // Temporary; secure encryption is not yet necessary /** diff --git a/src/data/balance/pokemon-evolutions.ts b/src/data/balance/pokemon-evolutions.ts index d42bce041c2..bf90ebb7edc 100644 --- a/src/data/balance/pokemon-evolutions.ts +++ b/src/data/balance/pokemon-evolutions.ts @@ -1,3 +1,4 @@ +import { defaultStarterSpecies } from "#app/constants"; import { globalScene } from "#app/global-scene"; import { speciesStarterCosts } from "#balance/starters"; import { allMoves } from "#data/data-lists"; @@ -1883,6 +1884,15 @@ export function initPokemonPrevolutions(): void { // TODO: This may cause funny business for double starters such as Pichu/Pikachu export const pokemonStarters: PokemonPrevolutions = {}; +/** + * The default species and all their evolutions + */ +export const defaultStarterSpeciesAndEvolutions: SpeciesId[] = defaultStarterSpecies.flatMap(id => { + const stage2ids = pokemonEvolutions[id]?.map(e => e.speciesId) ?? []; + const stage3ids = stage2ids.flatMap(s2id => pokemonEvolutions[s2id]?.map(e => e.speciesId) ?? []); + return [id, ...stage2ids, ...stage3ids]; +}); + export function initPokemonStarters(): void { const starterKeys = Object.keys(pokemonPrevolutions); starterKeys.forEach(pk => { diff --git a/src/data/challenge.ts b/src/data/challenge.ts index 3c282e7640e..01e6fa78ffc 100644 --- a/src/data/challenge.ts +++ b/src/data/challenge.ts @@ -1,6 +1,6 @@ import type { FixedBattleConfig } from "#app/battle"; import { getRandomTrainerFunc } from "#app/battle"; -import { defaultStarterSpeciesAndEvolutions } from "#app/constants"; +import { defaultStarterSpeciesAndEvolutions } from "#balance/pokemon-evolutions"; import { speciesStarterCosts } from "#balance/starters"; import type { PokemonSpecies } from "#data/pokemon-species"; import { AbilityAttr } from "#enums/ability-attr"; From 16adb02ad26a49b48ca960df10c76e50c4fe63ac Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Sat, 23 Aug 2025 17:00:27 +0200 Subject: [PATCH 08/24] [Item][Bug] No more free sacred ash (#6356) --- src/phases/select-modifier-phase.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/phases/select-modifier-phase.ts b/src/phases/select-modifier-phase.ts index 05c890136ee..06a02af38b0 100644 --- a/src/phases/select-modifier-phase.ts +++ b/src/phases/select-modifier-phase.ts @@ -177,7 +177,7 @@ export class SelectModifierPhase extends BattlePhase { this.openModifierMenu(modifierType, cost, modifierSelectCallback); } } else { - this.applyModifier(modifierType.newModifier()!); + this.applyModifier(modifierType.newModifier()!, cost); } return cost === -1; } From 3b290ee9a2b9afed8b01e6977d233c3c628879a0 Mon Sep 17 00:00:00 2001 From: Fabi <192151969+fabske0@users.noreply.github.com> Date: Sat, 23 Aug 2025 17:05:48 +0200 Subject: [PATCH 09/24] [UI/UX][Bug] Prevent switch to discard mode while transferring item (#6358) --- src/ui/party-ui-handler.ts | 3 +- test/ui/item-manage-button.test.ts | 47 +++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/ui/party-ui-handler.ts b/src/ui/party-ui-handler.ts index 9ad56476441..de10571f44c 100644 --- a/src/ui/party-ui-handler.ts +++ b/src/ui/party-ui-handler.ts @@ -1021,7 +1021,8 @@ export class PartyUiHandler extends MessageUiHandler { } // Toggle item transfer mode to discard items or vice versa - if (this.cursor === 7) { + // Prevent changing mode, when currently transfering an item + if (this.cursor === 7 && !this.transferMode) { switch (this.partyUiMode) { case PartyUiMode.DISCARD: this.partyUiMode = PartyUiMode.MODIFIER_TRANSFER; diff --git a/test/ui/item-manage-button.test.ts b/test/ui/item-manage-button.test.ts index a7ea76918a5..f31c5e8e7e5 100644 --- a/test/ui/item-manage-button.test.ts +++ b/test/ui/item-manage-button.test.ts @@ -6,7 +6,7 @@ import { UiMode } from "#enums/ui-mode"; import type { Pokemon } from "#field/pokemon"; import { GameManager } from "#test/test-utils/game-manager"; import type { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; -import type { PartyUiHandler } from "#ui/party-ui-handler"; +import { type PartyUiHandler, PartyUiMode } from "#ui/party-ui-handler"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; @@ -169,4 +169,49 @@ describe("UI - Transfer Items", () => { expect(pokemon.getHeldItems().map(h => h.stackCount)).toEqual([2, 2]); } }); + + it("should not allow changing to discard mode when transfering items", async () => { + let handler: PartyUiHandler | undefined; + + await new Promise(resolve => { + game.onNextPrompt("SelectModifierPhase", UiMode.MODIFIER_SELECT, async () => { + await new Promise(r => setTimeout(r, 100)); + const modifierHandler = game.scene.ui.getHandler() as ModifierSelectUiHandler; + + modifierHandler.processInput(Button.DOWN); + modifierHandler.setCursor(1); + modifierHandler.processInput(Button.ACTION); + }); + + game.onNextPrompt("SelectModifierPhase", UiMode.PARTY, async () => { + await new Promise(r => setTimeout(r, 100)); + handler = game.scene.ui.getHandler() as PartyUiHandler; + + handler.setCursor(0); + handler.processInput(Button.ACTION); + + await new Promise(r => setTimeout(r, 100)); + handler.processInput(Button.ACTION); + + resolve(); + }); + }); + + expect(handler).toBeDefined(); + if (handler) { + const partyMode = handler["partyUiMode"]; + expect(partyMode).toBe(PartyUiMode.MODIFIER_TRANSFER); + + handler.setCursor(7); + handler.processInput(Button.ACTION); + // Should not change mode to discard + expect(handler["partyUiMode"]).toBe(PartyUiMode.MODIFIER_TRANSFER); + + handler.processInput(Button.CANCEL); + handler.setCursor(7); + handler.processInput(Button.ACTION); + // Should change mode to discard + expect(handler["partyUiMode"]).toBe(PartyUiMode.DISCARD); + } + }); }); From 908886d78b57a25a55d66605042d15dcdb190e18 Mon Sep 17 00:00:00 2001 From: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com> Date: Sat, 23 Aug 2025 11:23:15 -0500 Subject: [PATCH 10/24] Fix unpauseEvolutions key in party select --- src/ui/party-ui-handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/party-ui-handler.ts b/src/ui/party-ui-handler.ts index de10571f44c..927d6ce5154 100644 --- a/src/ui/party-ui-handler.ts +++ b/src/ui/party-ui-handler.ts @@ -1610,7 +1610,7 @@ export class PartyUiHandler extends MessageUiHandler { const modifier = formChangeItemModifiers[option - PartyOption.FORM_CHANGE_ITEM]; optionName = `${modifier.active ? i18next.t("partyUiHandler:deactivate") : i18next.t("partyUiHandler:activate")} ${modifier.type.name}`; } else if (option === PartyOption.UNPAUSE_EVOLUTION) { - optionName = `${pokemon.pauseEvolutions ? i18next.t("partyUiHandler:unpausedEvolution") : i18next.t("partyUiHandler:pauseEvolution")}`; + optionName = `${pokemon.pauseEvolutions ? i18next.t("partyUiHandler:unpausedEvolutions") : i18next.t("partyUiHandler:pauseEvolution")}`; } else { if (this.localizedOptions.includes(option)) { optionName = i18next.t(`partyUiHandler:${toCamelCase(PartyOption[option])}`); From 053976daecbf417007aa3a2775b050cb18e1261c Mon Sep 17 00:00:00 2001 From: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com> Date: Sat, 23 Aug 2025 11:41:30 -0500 Subject: [PATCH 11/24] [Bug] Fix ssui passives (#6362) Fix passives not being persisted in starter select --- src/ui/starter-select-ui-handler.ts | 36 ++++++++++++----------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 25d5277b4c2..9f6a3647972 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -2095,27 +2095,21 @@ export class StarterSelectUiHandler extends MessageUiHandler { const passiveAttr = starterData.passiveAttr; if (passiveAttr & PassiveAttr.UNLOCKED) { // this is for enabling and disabling the passive - if (!(passiveAttr & PassiveAttr.ENABLED)) { - options.push({ - label: i18next.t("starterSelectUiHandler:enablePassive"), - handler: () => { - starterData.passiveAttr |= PassiveAttr.ENABLED; - ui.setMode(UiMode.STARTER_SELECT); - this.setSpeciesDetails(this.lastSpecies); - return true; - }, - }); - } else { - options.push({ - label: i18next.t("starterSelectUiHandler:disablePassive"), - handler: () => { - starterData.passiveAttr ^= PassiveAttr.ENABLED; - ui.setMode(UiMode.STARTER_SELECT); - this.setSpeciesDetails(this.lastSpecies); - return true; - }, - }); - } + const label = i18next.t( + passiveAttr & PassiveAttr.ENABLED + ? "starterSelectUiHandler:disablePassive" + : "starterSelectUiHandler:enablePassive", + ); + options.push({ + label, + handler: () => { + starterData.passiveAttr ^= PassiveAttr.ENABLED; + persistentStarterData.passiveAttr ^= PassiveAttr.ENABLED; + ui.setMode(UiMode.STARTER_SELECT); + this.setSpeciesDetails(this.lastSpecies); + return true; + }, + }); } // if container.favorite is false, show the favorite option const isFavorite = starterAttributes?.favorite ?? false; From 873e12f9ad45720ce529ca5c152230aeb0093439 Mon Sep 17 00:00:00 2001 From: Blitzy <118096277+Blitz425@users.noreply.github.com> Date: Sat, 23 Aug 2025 11:42:02 -0500 Subject: [PATCH 12/24] [Balance] Clamperl Egg Moves / Passive Tweaks (#6365) Clamperl changes --- src/data/balance/egg-moves.ts | 2 +- src/data/balance/passives.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data/balance/egg-moves.ts b/src/data/balance/egg-moves.ts index 2d2e981219d..5dd7bcbd9e2 100644 --- a/src/data/balance/egg-moves.ts +++ b/src/data/balance/egg-moves.ts @@ -187,7 +187,7 @@ export const speciesEggMoves = { [SpeciesId.WYNAUT]: [ MoveId.RECOVER, MoveId.SHED_TAIL, MoveId.TAUNT, MoveId.COMEUPPANCE ], [SpeciesId.SNORUNT]: [ MoveId.SPARKLY_SWIRL, MoveId.NASTY_PLOT, MoveId.EARTH_POWER, MoveId.BLOOD_MOON ], [SpeciesId.SPHEAL]: [ MoveId.FLIP_TURN, MoveId.FREEZE_DRY, MoveId.SLACK_OFF, MoveId.STEAM_ERUPTION ], - [SpeciesId.CLAMPERL]: [ MoveId.SHELL_SIDE_ARM, MoveId.BOUNCY_BUBBLE, MoveId.FREEZE_DRY, MoveId.STEAM_ERUPTION ], + [SpeciesId.CLAMPERL]: [ MoveId.SHELL_SIDE_ARM, MoveId.SNIPE_SHOT, MoveId.GIGA_DRAIN, MoveId.BOUNCY_BUBBLE ], [SpeciesId.RELICANTH]: [ MoveId.DRAGON_DANCE, MoveId.SHORE_UP, MoveId.WAVE_CRASH, MoveId.DIAMOND_STORM ], [SpeciesId.LUVDISC]: [ MoveId.BATON_PASS, MoveId.HEART_SWAP, MoveId.GLITZY_GLOW, MoveId.REVIVAL_BLESSING ], [SpeciesId.BAGON]: [ MoveId.HEADLONG_RUSH, MoveId.FIRE_LASH, MoveId.DRAGON_DANCE, MoveId.DRAGON_DARTS ], diff --git a/src/data/balance/passives.ts b/src/data/balance/passives.ts index 0e34917fd80..1297ad71c36 100644 --- a/src/data/balance/passives.ts +++ b/src/data/balance/passives.ts @@ -402,7 +402,7 @@ export const starterPassiveAbilities: StarterPassiveAbilities = { [SpeciesId.SPHEAL]: { 0: AbilityId.UNAWARE }, [SpeciesId.SEALEO]: { 0: AbilityId.UNAWARE }, [SpeciesId.WALREIN]: { 0: AbilityId.UNAWARE }, - [SpeciesId.CLAMPERL]: { 0: AbilityId.DAUNTLESS_SHIELD }, + [SpeciesId.CLAMPERL]: { 0: AbilityId.OVERCOAT }, [SpeciesId.GOREBYSS]: { 0: AbilityId.ARENA_TRAP }, [SpeciesId.HUNTAIL]: { 0: AbilityId.ARENA_TRAP }, [SpeciesId.RELICANTH]: { 0: AbilityId.PRIMORDIAL_SEA }, From 99bf639ea7dc39b0b9989e7eeadf34369d2df956 Mon Sep 17 00:00:00 2001 From: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com> Date: Sat, 23 Aug 2025 11:42:10 -0500 Subject: [PATCH 13/24] [Bug] [Move] Fix pollen puff (#6363) * Ensure pollen puff does not heal enemy after damage * Add test to ensure pollen puff does not heal enemy --- src/data/moves/move.ts | 7 +++++++ test/moves/pollen-puff.test.ts | 12 ++++++++++++ test/test-utils/phase-interceptor.ts | 2 ++ 3 files changed, 21 insertions(+) diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index dc9f2306101..a8ea61f7187 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -2325,6 +2325,13 @@ export class HealOnAllyAttr extends HealAttr { // Don't trigger if not targeting an ally return target === user.getAlly() && super.canApply(user, target, _move, _args); } + + override apply(user: Pokemon, target: Pokemon, _move: Move, _args: any[]): boolean { + if (user.isOpponent(target)) { + return false; + } + return super.apply(user, target, _move, _args); + } } /** diff --git a/test/moves/pollen-puff.test.ts b/test/moves/pollen-puff.test.ts index 76732a39c43..02772055f1f 100644 --- a/test/moves/pollen-puff.test.ts +++ b/test/moves/pollen-puff.test.ts @@ -61,4 +61,16 @@ describe("Moves - Pollen Puff", () => { expect(target.battleData.hitCount).toBe(2); }); + + // Regression test for pollen puff healing an enemy after dealing damage + it("should not heal an enemy after dealing damage", async () => { + await game.classicMode.startBattle([SpeciesId.FEEBAS]); + const target = game.field.getEnemyPokemon(); + game.move.use(MoveId.POLLEN_PUFF); + + await game.phaseInterceptor.to("BerryPhase", false); + + expect(target.hp).not.toBe(target.getMaxHp()); + expect(game.phaseInterceptor.log).not.toContain("PokemonHealPhase"); + }); }); diff --git a/test/test-utils/phase-interceptor.ts b/test/test-utils/phase-interceptor.ts index 0d357a75557..996f00806c6 100644 --- a/test/test-utils/phase-interceptor.ts +++ b/test/test-utils/phase-interceptor.ts @@ -37,6 +37,7 @@ import { NewBiomeEncounterPhase } from "#phases/new-biome-encounter-phase"; import { NextEncounterPhase } from "#phases/next-encounter-phase"; import { PartyExpPhase } from "#phases/party-exp-phase"; import { PartyHealPhase } from "#phases/party-heal-phase"; +import { PokemonHealPhase } from "#phases/pokemon-heal-phase"; import { PokemonTransformPhase } from "#phases/pokemon-transform-phase"; import { PositionalTagPhase } from "#phases/positional-tag-phase"; import { PostGameOverPhase } from "#phases/post-game-over-phase"; @@ -181,6 +182,7 @@ export class PhaseInterceptor { UnlockPhase, PostGameOverPhase, RevivalBlessingPhase, + PokemonHealPhase, ]; private endBySetMode = [ From cd137062eaeec57a9052e9324e49e144e23288fa Mon Sep 17 00:00:00 2001 From: damocleas Date: Sat, 23 Aug 2025 13:28:09 -0400 Subject: [PATCH 14/24] Fix Option 1 Leftovers text in Trash to Treasure encounter --- .../encounters/trash-to-treasure-encounter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/mystery-encounters/encounters/trash-to-treasure-encounter.ts b/src/data/mystery-encounters/encounters/trash-to-treasure-encounter.ts index af576ffd8be..ed588ea2884 100644 --- a/src/data/mystery-encounters/encounters/trash-to-treasure-encounter.ts +++ b/src/data/mystery-encounters/encounters/trash-to-treasure-encounter.ts @@ -249,7 +249,7 @@ async function tryApplyDigRewardItems() { await showEncounterText( i18next.t("battle:rewardGainCount", { modifierName: leftovers.name, - count: 2, + count: 1, }), null, undefined, From af963c79027bbb39425a48f868d10582cb019f4b Mon Sep 17 00:00:00 2001 From: Bertie690 <136088738+Bertie690@users.noreply.github.com> Date: Sat, 23 Aug 2025 17:00:00 -0400 Subject: [PATCH 15/24] [Bug] Fixed delayed attacks pushing to move history twice on charging turn (#6371) --- src/data/moves/move.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index a8ea61f7187..4a744d6e9c3 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -3277,7 +3277,6 @@ export class DelayedAttackAttr extends OverrideMoveEffectAttr { ) ) - user.pushMoveHistory({move: move.id, targets: [target.getBattlerIndex()], result: MoveResult.OTHER, useMode, turn: globalScene.currentBattle.turn}) user.pushMoveHistory({move: move.id, targets: [target.getBattlerIndex()], result: MoveResult.OTHER, useMode, turn: globalScene.currentBattle.turn}) // Queue up an attack on the given slot. globalScene.arena.positionalTagManager.addTag({ From d2eb3dba53592b897ebadcc3bb4af0e0f8ef0491 Mon Sep 17 00:00:00 2001 From: Dean <69436131+emdeann@users.noreply.github.com> Date: Sat, 23 Aug 2025 14:02:36 -0700 Subject: [PATCH 16/24] [Test] Fix leftovers test not running heal phase (#6370) Fix leftovers test --- test/items/leftovers.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/items/leftovers.test.ts b/test/items/leftovers.test.ts index 6ae4094799b..484843b81ff 100644 --- a/test/items/leftovers.test.ts +++ b/test/items/leftovers.test.ts @@ -2,7 +2,6 @@ import { AbilityId } from "#enums/ability-id"; import { MoveId } from "#enums/move-id"; import { SpeciesId } from "#enums/species-id"; import { DamageAnimPhase } from "#phases/damage-anim-phase"; -import { TurnEndPhase } from "#phases/turn-end-phase"; import { GameManager } from "#test/test-utils/game-manager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; @@ -54,7 +53,7 @@ describe("Items - Leftovers", () => { const leadHpAfterDamage = leadPokemon.hp; // Check if leftovers heal us - await game.phaseInterceptor.to(TurnEndPhase); + await game.phaseInterceptor.to("PokemonHealPhase"); expect(leadPokemon.hp).toBeGreaterThan(leadHpAfterDamage); }); }); From a8b54eba6df008995d8c79aa02e7ae9654e1f7f3 Mon Sep 17 00:00:00 2001 From: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com> Date: Sat, 23 Aug 2025 16:56:58 -0500 Subject: [PATCH 17/24] [Test] Mark failing test/ui/manage-item-button.test.ts as TODO (#6375) * Ensure hotfix runs tests * Unnest promise * ensure workflows run when pushed to hotfix * Mark test todo --- .github/workflows/github-pages.yml | 2 ++ .github/workflows/linting.yml | 2 ++ .github/workflows/tests.yml | 2 ++ test/ui/item-manage-button.test.ts | 44 ++++++++++++++++-------------- 4 files changed, 29 insertions(+), 21 deletions(-) diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml index 84d5964064f..55ff05d7726 100644 --- a/.github/workflows/github-pages.yml +++ b/.github/workflows/github-pages.yml @@ -6,11 +6,13 @@ on: - main - beta - release + - 'hotfix*' pull_request: branches: - main - beta - release + - 'hotfix*' merge_group: types: [checks_requested] diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index a5e8f96961e..ae23a515c4f 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -6,11 +6,13 @@ on: - main - beta - release + - 'hotfix*' pull_request: branches: - main - beta - release + - 'hotfix*' merge_group: types: [checks_requested] diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2b9f6dc9c0d..748072c536f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -6,11 +6,13 @@ on: - main - beta - release + - 'hotfix*' pull_request: branches: - main - beta - release + - 'hotfix*' merge_group: types: [checks_requested] workflow_dispatch: diff --git a/test/ui/item-manage-button.test.ts b/test/ui/item-manage-button.test.ts index f31c5e8e7e5..c28cd9e802e 100644 --- a/test/ui/item-manage-button.test.ts +++ b/test/ui/item-manage-button.test.ts @@ -170,33 +170,35 @@ describe("UI - Transfer Items", () => { } }); - it("should not allow changing to discard mode when transfering items", async () => { + // TODO: This test breaks when running all tests on github. Fix this once hotfix period is over. + it.todo("should not allow changing to discard mode when transfering items", async () => { let handler: PartyUiHandler | undefined; - await new Promise(resolve => { - game.onNextPrompt("SelectModifierPhase", UiMode.MODIFIER_SELECT, async () => { - await new Promise(r => setTimeout(r, 100)); - const modifierHandler = game.scene.ui.getHandler() as ModifierSelectUiHandler; + const { resolve, promise } = Promise.withResolvers(); - modifierHandler.processInput(Button.DOWN); - modifierHandler.setCursor(1); - modifierHandler.processInput(Button.ACTION); - }); + game.onNextPrompt("SelectModifierPhase", UiMode.MODIFIER_SELECT, async () => { + await new Promise(r => setTimeout(r, 100)); + const modifierHandler = game.scene.ui.getHandler() as ModifierSelectUiHandler; - game.onNextPrompt("SelectModifierPhase", UiMode.PARTY, async () => { - await new Promise(r => setTimeout(r, 100)); - handler = game.scene.ui.getHandler() as PartyUiHandler; - - handler.setCursor(0); - handler.processInput(Button.ACTION); - - await new Promise(r => setTimeout(r, 100)); - handler.processInput(Button.ACTION); - - resolve(); - }); + modifierHandler.processInput(Button.DOWN); + modifierHandler.setCursor(1); + modifierHandler.processInput(Button.ACTION); }); + game.onNextPrompt("SelectModifierPhase", UiMode.PARTY, async () => { + await new Promise(r => setTimeout(r, 100)); + handler = game.scene.ui.getHandler() as PartyUiHandler; + + handler.setCursor(0); + handler.processInput(Button.ACTION); + + await new Promise(r => setTimeout(r, 100)); + handler.processInput(Button.ACTION); + + resolve(); + }); + + await promise; expect(handler).toBeDefined(); if (handler) { const partyMode = handler["partyUiMode"]; From 1b2c69408449ce66e90ed1441a28cb2858df2128 Mon Sep 17 00:00:00 2001 From: Fabi <192151969+fabske0@users.noreply.github.com> Date: Sun, 24 Aug 2025 00:26:12 +0200 Subject: [PATCH 18/24] [bug/i18n] Fix stealth rock message (#6377) replace pokemonName with pokemonNameWithAffix --- src/data/arena-tag.ts | 2 +- test/moves/entry-hazards.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data/arena-tag.ts b/src/data/arena-tag.ts index b03cc5b951a..cd02455af0f 100644 --- a/src/data/arena-tag.ts +++ b/src/data/arena-tag.ts @@ -937,7 +937,7 @@ class StealthRockTag extends DamagingTrapTag { protected override getTriggerMessage(pokemon: Pokemon): string { return i18next.t("arenaTag:stealthRockActivateTrap", { - pokemonName: getPokemonNameWithAffix(pokemon), + pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), }); } diff --git a/test/moves/entry-hazards.test.ts b/test/moves/entry-hazards.test.ts index c4dead1bb67..af8145183a3 100644 --- a/test/moves/entry-hazards.test.ts +++ b/test/moves/entry-hazards.test.ts @@ -200,7 +200,7 @@ describe("Moves - Entry Hazards", () => { expect(enemy).toHaveTakenDamage(enemy.getMaxHp() * 0.125 * multi); expect(game.textInterceptor.logs).toContain( i18next.t("arenaTag:stealthRockActivateTrap", { - pokemonName: getPokemonNameWithAffix(enemy), + pokemonNameWithAffix: getPokemonNameWithAffix(enemy), }), ); }); From 1192825d515aaef4dd1a0ef4fbae4de2415f8f7d Mon Sep 17 00:00:00 2001 From: Fabi <192151969+fabske0@users.noreply.github.com> Date: Sun, 24 Aug 2025 00:59:01 +0200 Subject: [PATCH 19/24] [Bug/i18n] Fix unpause evolution option in party ui (#6379) --- src/ui/party-ui-handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/party-ui-handler.ts b/src/ui/party-ui-handler.ts index 927d6ce5154..446fa37ec4a 100644 --- a/src/ui/party-ui-handler.ts +++ b/src/ui/party-ui-handler.ts @@ -1610,7 +1610,7 @@ export class PartyUiHandler extends MessageUiHandler { const modifier = formChangeItemModifiers[option - PartyOption.FORM_CHANGE_ITEM]; optionName = `${modifier.active ? i18next.t("partyUiHandler:deactivate") : i18next.t("partyUiHandler:activate")} ${modifier.type.name}`; } else if (option === PartyOption.UNPAUSE_EVOLUTION) { - optionName = `${pokemon.pauseEvolutions ? i18next.t("partyUiHandler:unpausedEvolutions") : i18next.t("partyUiHandler:pauseEvolution")}`; + optionName = `${pokemon.pauseEvolutions ? i18next.t("partyUiHandler:unpauseEvolution") : i18next.t("partyUiHandler:pauseEvolution")}`; } else { if (this.localizedOptions.includes(option)) { optionName = i18next.t(`partyUiHandler:${toCamelCase(PartyOption[option])}`); From 842f0e88b0ab95255fb14025b2da48a01d63c4f5 Mon Sep 17 00:00:00 2001 From: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com> Date: Sat, 23 Aug 2025 18:45:15 -0500 Subject: [PATCH 20/24] [Bug] Fix saveslot deletion (#6380) Fix saveslot deletion --- src/ui/save-slot-select-ui-handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/save-slot-select-ui-handler.ts b/src/ui/save-slot-select-ui-handler.ts index e9f9c5a0038..97cd3016479 100644 --- a/src/ui/save-slot-select-ui-handler.ts +++ b/src/ui/save-slot-select-ui-handler.ts @@ -181,7 +181,7 @@ export class SaveSlotSelectUiHandler extends MessageUiHandler { ui.setOverlayMode( UiMode.CONFIRM, () => { - globalScene.gameData.tryClearSession(cursor).then(response => { + globalScene.gameData.deleteSession(cursor).then(response => { if (response[0] === false) { globalScene.reset(true); } else { From 70b47945e89547937cdde6ece0aa2f89d0965495 Mon Sep 17 00:00:00 2001 From: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com> Date: Sat, 23 Aug 2025 18:47:39 -0500 Subject: [PATCH 21/24] [Bug] Fix nicknames not showing up in battle (#6378) --- src/field/pokemon.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index e73d1cdf273..4904964ac1b 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -454,7 +454,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container { getNameToRender(useIllusion = true) { const illusion = this.summonData.illusion; const name = useIllusion ? (illusion?.name ?? this.name) : this.name; - const nickname: string | undefined = useIllusion ? illusion?.nickname : this.nickname; + const nickname: string | undefined = useIllusion ? (illusion?.nickname ?? this.nickname) : this.nickname; try { if (nickname) { return decodeURIComponent(escape(atob(nickname))); // TODO: Remove `atob` and `escape`... eventually... From c44e5893039a2148ec128aecd8a7335d2e9dbc80 Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Sun, 24 Aug 2025 01:50:44 +0200 Subject: [PATCH 22/24] [UI/UX][Bug] Saving preferences when leaving ssui (#6376) Save starter preferences when leaving ssui --- src/ui/starter-select-ui-handler.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 9f6a3647972..a29a65aca80 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -4612,6 +4612,8 @@ export class StarterSelectUiHandler extends MessageUiHandler { clear(): void { super.clear(); + saveStarterPreferences(this.originalStarterPreferences); + this.clearStarterPreferences(); this.cursor = -1; this.hideInstructions(); From 746ea6947559e76577e5a67ea4d78f4dbbd277b9 Mon Sep 17 00:00:00 2001 From: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com> Date: Sat, 23 Aug 2025 18:58:29 -0500 Subject: [PATCH 23/24] [Bug] Fix missing fusion icon (#6381) Fix nullish coalescing in `pokemon#isFusion` --- src/field/pokemon.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 4904964ac1b..f02c9a1f30c 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -1781,7 +1781,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container { * @returns Whether this Pokemon is currently fused with another species. */ isFusion(useIllusion = false): boolean { - return useIllusion ? !!this.summonData.illusion?.fusionSpecies : !!this.fusionSpecies; + return !!(useIllusion ? (this.summonData.illusion?.fusionSpecies ?? this.fusionSpecies) : this.fusionSpecies); } /** From c446eaf9703ea8ede731e5007b3e07b1b8e94d09 Mon Sep 17 00:00:00 2001 From: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com> Date: Sat, 23 Aug 2025 18:59:47 -0500 Subject: [PATCH 24/24] [Sprite] Revert ribbon icons (#6382) --- public/images/ui/champion_ribbon.png | Bin 207 -> 151 bytes public/images/ui/champion_ribbon_emerald.png | Bin 207 -> 151 bytes public/images/ui/legacy/champion_ribbon.png | Bin 207 -> 151 bytes .../ui/legacy/champion_ribbon_emerald.png | Bin 207 -> 151 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/public/images/ui/champion_ribbon.png b/public/images/ui/champion_ribbon.png index b188f4c92d284f8bc8a04c4f2918299191c31588..a19bb01279b2928c9aa32fbbd40db6103bdffe3f 100644 GIT binary patch delta 134 zcmX@lIGu5VL_G^L0|Nt3nf3%AB@y5g;tHhw7#Qjq7~0|(w$^Z6TjKHK!Gz!EYds>C zd3_tCM4*y3TZ7o$He1xu8oPur>lvF h$BU_nNuWuPgR$-iOG%~hl0!g^44$rjF6*2UngBp{C#C=Z delta 191 zcmV;w06_nj0nY)D7=H)`0002~ST>^o0004VQb$4nuFf3k0001oNklKPb%b`IB@$=&0 h(c|*s5@_P&VC-DO8pS<%aWzmQgQu&X%Q~loCIIR;C5Qk3 delta 191 zcmV;w06_nj0nY)D7=H)`0002~ST>^o0004VQb$4nuFf3k0001oNklC zd3_tCM4*y3TZ7o$He1xu8oPur>lvF h$BU_nNuWuPgR$-iOG%~hl0!g^44$rjF6*2UngBp{C#C=Z delta 191 zcmV;w06_nj0nY)D7=H)`0002~ST>^o0004VQb$4nuFf3k0001oNklKPb%b`IB@$=&0 h(c|*s5@_P&VC-DO8pS<%aWzmQgQu&X%Q~loCIIR;C5Qk3 delta 191 zcmV;w06_nj0nY)D7=H)`0002~ST>^o0004VQb$4nuFf3k0001oNkl