Port the remaining battle items, the stats screen and hBattleTurn at the menu

- Run every non-ball item effect usable in battle from the ROM's
  ItemEffects: Full Restore, revives, bitter medicine, Bitter Berry, Ethers
  and Elixers, X items, X Accuracy, Guard Spec, Dire Hit and Poké Doll.
- Read happiness changes from HappinessChanges, including the larger
  level-up gain where a Pokémon was caught.
- Model hBattleTurn at the battle menu, including the trainer AI's writes,
  and drop the status-heal refusal.
- Port the stats screen for battles and Bill's PC.
- Compare the send-out and withdraw texts, RestoreHealth, RestorePP,
  ChangeHappiness and CalcPlayerStats with the original routines.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Sébastien QUEROLandClaude Opus 5.5 committed 2026-09-30 11:24:55 +02:00
1 parent cfd083c16d
commit b13e09ec20
22 files changed
+1547 -171

No files matched your search

+52 -18
View File
@@ -156,7 +156,7 @@ triggers, declining and the repeat offer, and mid-battle reloads. Browser
tests cover PACK, catching and naming. No emulator comparison of the
capture routines has been run.
## Switching and healing items in battle
## Switching, battle items and the stats screen
`engine/battle/core.asm`: `BattleMenu_PKMN` and `TryPlayerSwitch` ("is
already out", "can't be recalled" while wrapped or blocked by Mean Look,
@@ -181,26 +181,60 @@ switching clears both participant sets as the original does.
`engine/items/item_effects.asm` and `pack.asm`: `BattlePack` shows the Items
and Balls pockets. `CheckItemContext` gives Oak's "This isn't the time"
text for items with no battle use. `ItemEffects` is read from the ROM:
`RestoreHPEffect` (`ItemRestoreHP`, `HealingHPAmounts`, `RestoreHealth`) and
`StatusHealingEffect` (`UseStatusHealer`, `StatusHealingActions`,
`HealStatus`, `IsItemUsedOnConfusedMon`) run with `UseItem_SelectMon`, the
party menu action texts and `UseDisposableItem`. "Won't have any effect"
and a cancelled menu keep the item and the turn. `wItemEffectSucceeded`
shares `wBattlePlayerAction`'s byte, so a used item takes the turn.
text for items with no battle use. `ItemEffects` is read from the ROM and
dispatches every non-ball effect usable in battle:
- Party items (`.BattleField`): `RestoreHPEffect` (`ItemRestoreHP`,
`HealingHPAmounts`, `RestoreHealth`), `StatusHealingEffect`
(`UseStatusHealer`, `StatusHealingActions`, `HealStatus`,
`IsItemUsedOnConfusedMon`), `FullRestoreEffect`, `ReviveEffect` (half or
full HP; a revived participant shares the experience again through
`wBattleParticipantsIncludingFainted`), the bitter Energypowder, Energy
Root, Heal Powder and Revival Herb (`ChangeHappiness` and "It looks
bitter…"), `BitterBerryEffect` and `RestorePPEffect` (Ether, Max Ether,
Elixer, Max Elixer, MysteryBerry; `GetMaxPPOfMove`, `BattleRestorePP`, a
`move` prompt for `MoveSelectionScreen` whose B reopens the party menu).
- Battle-only items (`.BattleOnly`): `XItemEffect` (`XItemStats`,
`RaiseStat` with `hBattleTurn` on the player, used even when the stat
cannot rise, and the X-item happiness gain), X Accuracy, Guard Spec and
Dire Hit (set once; a second use keeps the item), and `PokeDollEffect`
(ends a wild battle as a draw; Oak's warning in a trainer battle).
"Won't have any effect" and a cancelled menu keep the item and the turn.
`wItemEffectSucceeded` shares `wBattlePlayerAction`'s byte, so a used item
takes the turn. `UseItemText` waits for a button. `ChangeHappiness` reads
`HappinessChanges` and updates the battle Pokémon's copy only when
`wCurPartyMon` equals the 1-based `wPartyMenuCursor`, as in the original;
fainting and levelling up use it too, and `LevelUpHappinessMod` gives the
larger gain on the map where the Pokémon was caught.
`CalcPlayerStats` reapplies the paralysis and burn penalties to the side
named by `hBattleTurn` after a switch of turns, which can be the enemy.
Because `hBattleTurn` at the battle menu is not modelled everywhere, a
status heal that would reapply a penalty to a paralysed or burned enemy is
refused. Other item effects (X items, Poké Doll, Full Restore, revives,
Ether) are refused.
`hBattleTurn` at the battle menu is modelled: `DoBattle` leaves the
player's turn, `HandleHealingItems` ends a full turn on the enemy's, and
the trainer AI reports when `AI_Types`, `AI_Status` or `AIDamageCalc`
set it. A status heal after a full turn therefore penalises a paralysed
or burned enemy again, as the original does. Remaining gaps: the special
Kurt and Park balls.
`engine/pokemon/stats_screen.asm`: the stats screen's three pages (HP,
status, types, experience to the next level; item and moves with PP; ID,
OT and stats) with the ROM's strings, `TypeNames`, `GetGender` and the
front picture. It opens from BattleMonMenu (B returns to the party menu,
as `BattleMenuPKMN_ReturnFromStats` does) and from Bill's PC, where a
boxed Pokémon shows `CalcTempmonStats`' full HP and no status.
Tests: local-ROM battles cover switching, cancelling, the withdrawal texts,
forced choices (including a fainted pick and a cancelled forced menu), run
after NO, Shift mode's offer (accepted and declined), a trainer double
faint, Potion, Max Potion, a Berry on a benched Pokémon, no-effect cases,
Antidote and PSNCUREBERRY, Parlyz Heal restoring Speed, Oak's warning and a
refused X Attack. Browser tests switch through the party menu and its
SWITCH/STATS/CANCEL submenu and use a Potion from the Items pocket. The
stats screen is not ported. No emulator comparison of these routines has
been run.
faint, and every item effect above, including the reapplied enemy penalty
and the caught-location level-up bonus. Trainer AI tests pin its
`hBattleTurn` reporting. The reference suite runs the original
`SendOutMonText` (its final jump to `BattleTextbox` patched to `ret` in the
test's ROM copy), `WithdrawMonText`'s text routine, `RestoreHealth`,
`RestorePP`, `ChangeHappiness` and `CalcPlayerStats` with both values of
`hBattleTurn`: 300, 300, 200, 300 and 200 cases. Browser tests switch
through the party menu, use a Potion from the Items pocket and page
through the stats screen. `WithdrawMonText` still assumes the leftover
multiplicand high byte is zero; a whole battle has not been compared with
the original.
+11 -7
View File
@@ -130,7 +130,7 @@ The numbered sections below keep their full scope. Each one opens with a checkli
- Capture with a full party runs `SendMonIntoBox`: the Pokémon goes first in the current box, with restored PP and `SetBoxMonCaughtData`, can be nicknamed and shows `BallSentToPCText`. If the box is already full the ball is not used (`Ball_BoxIsFullMessage`). A catch that fills the box sets `BATTLERESULT_BOX_FULL`; `reloadmapafterbattle` then queues Bill's call (`Script_SpecialBillCall`) as a memory script that runs at the next `PlayerEvents` and is not saved, as in the original.
- `VAR_BOXSPACE` reads the current box.
- Save format 3 gained `storage` (boxes, the current box and box names; a null name is the ROM default) and `pcItems`, migrated by absence to empty storage.
- Not ported: MOVE PKMN W/O MAIL and the stats screen (both show a notice and return to the menu), printing, a `givepoke` with a full party (refused; no open map reaches it) and the tutorial with a full party and box (the original repeats the unusable ball). Changing boxes does not show the save messages; the native session saves continuously.
- Not ported: MOVE PKMN W/O MAIL (a notice returns to the menu; the stats screen is now ported), printing, a `givepoke` with a full party (refused; no open map reaches it) and the tutorial with a full party and box (the original repeats the unusable ball). Changing boxes does not show the save messages; the native session saves continuously.
- Next: the introduction's naming and clock screens, player switching and other items in battle, then party and bag menus.
## Implemented: the introduction's naming and clock screens
@@ -144,7 +144,7 @@ The numbered sections below keep their full scope. Each one opens with a checkli
- Save format 3 gained `intro` and `clock.minuteOffset`, migrated by absence to a finished intro on the device clock.
- Intentional change: the steppers start at the device's current time rather than 10:00, so confirming keeps the device clock.
- Not presented: the palette fades, Wooper's cry, the picture slide during name selection, `ShrinkPlayer` and the Route 30 music (no audio yet).
- Next: MOVE PKMN W/O MAIL and the stats screen with the party menu.
- Next: MOVE PKMN W/O MAIL with the party menu.
## Implemented: evolution data, reference vectors and the opening playthrough
@@ -152,15 +152,19 @@ The numbered sections below keep their full scope. Each one opens with a checkli
- The reference suite also runs the original `CalcMonStats` (300 cases, with and without stat experience, including levels above 100 that reach the 999 cap) and `CalcExpAtLevel` (every growth rate at levels 1–100).
- `tests/playthrough.test.ts` plays a new game from the introduction to the catching tutorial with a seeded RNG: Mom, Elm, the starter and Potion, Route 29, Cherrygrove, Route 30, Mr. Pokémon, Elm's call, the rival battle, the officer, the Egg, the aide's Poké Balls and the Dude's demonstration. Wild battles are fought, or fled below half HP. Each stage ends with a JSON save loaded into a fresh world. It uses no fixtures or hand-set flags, but drives `GameWorld` directly rather than the browser UI.
## Implemented: switching and healing items in battle
## Implemented: switching, battle items and the stats screen
- PKMN opens the party menu; SWITCH sends out the chosen Pokémon (STATS is not ported). The texts, the trapped and fainted checks, and the enemy's turn after the switch follow the original. Both Pokémon share the experience.
- PKMN opens the party menu; SWITCH sends out the chosen Pokémon and STATS opens the stats screen. The texts, the trapped and fainted checks, and the enemy's turn after the switch follow the original. Both Pokémon share the experience.
- After a faint, wild battles ask "Use next POKéMON?" (NO tries to run) and the party menu cannot be cancelled. Trainers' next Pokémon come with Shift mode's offer to switch; a double faint sends out both sides.
- PACK's Items pocket uses HP items (Potion, Berry and the rest of `HealingHPAmounts`) and status healers (Antidote, Parlyz Heal, Awakening, PSNCUREBERRY and the rest of `StatusHealingActions`) on any party Pokémon. Items with no battle use get Oak's warning. X items, Poké Doll, Full Restore and revives are refused.
- PACK's Items pocket uses HP items (Potion, Berry and the rest of `HealingHPAmounts`) and status healers (Antidote, Parlyz Heal, Awakening, PSNCUREBERRY and the rest of `StatusHealingActions`) on any party Pokémon. Items with no battle use get Oak's warning.
- Every other battle item effect runs too: Full Restore, revives, the bitter herbs, Bitter Berry, Ethers and Elixers, X items, X Accuracy, Guard Spec, Dire Hit and Poké Doll. Happiness changes come from the ROM's `HappinessChanges`.
- `hBattleTurn` at the battle menu is modelled, so `CalcPlayerStats` after a status heal penalises the side the original does.
- The stats screen shows its three pages from BattleMonMenu and Bill's PC.
- The reference suite compares the send-out and withdraw texts, `RestoreHealth`, `RestorePP`, `ChangeHappiness` and `CalcPlayerStats` with the original routines.
## Native battles: current state
The battle core, ROM tables, encounter hooks, battle UI and whiteout hooks are present. Unit tests cover wins, escape, loss, experience, move learning and capture; reference tests compare damage, type effectiveness, stat calculation and experience curves. Browser tests drive a test-only wild encounter through the real UI: victory with level-up and move learning, escape, whiteout, catching with a nickname, keyboard and on-screen D-pad menu navigation, mid-battle backup restore, rollback of unsupported effects, switching through the party menu and a Potion from the Items pocket. Real Route 29 encounters now use the ROM's encounter tables. Other battle items (X items, Poké Doll, Full Restore, revives) remain unfinished.
The battle core, ROM tables, encounter hooks, battle UI and whiteout hooks are present. Unit tests cover wins, escape, loss, experience, move learning and capture; reference tests compare damage, type effectiveness, stat calculation and experience curves. Browser tests drive a test-only wild encounter through the real UI: victory with level-up and move learning, escape, whiteout, catching with a nickname, keyboard and on-screen D-pad menu navigation, mid-battle backup restore, rollback of unsupported effects, switching through the party menu and a Potion from the Items pocket. Real Route 29 encounters now use the ROM's encounter tables. Only the special Kurt and Park balls remain unported among battle items.
This is still not a complete new game. Full party/bag/Pokégear menus, story progression beyond Route 30 and Mr. Pokémon's house, and audio remain unfinished. The Key Items menu supports the Bicycle; the PCs store Pokémon, items and decorations. Surfing and terrain animation now have native implementations; later maps remain gated. Save slots, a Johto/Kanto atlas, Pokédex records, online Link, friends and real-world steps come later.
@@ -228,7 +232,7 @@ their scripts and story progression are supported.
- [x] The Cherrygrove rival battle, Elm's call and the return to Elm
- [x] Capture and the catching tutorial
- [x] Battles: stats, damage, types, accuracy, criticals, status, turn order, fainting, experience, move learning, trainer AI, trainer send-outs and prize money
- [x] Player switching, and HP and status healing items, in battle (X items, Poké Doll, Full Restore and revives are refused)
- [x] Player switching and every non-ball battle item, with the stats screen
- [x] The PC and boxes (catching with a full party)
- [x] The introduction's naming and clock screens
- [ ] Controlled-seed comparisons with the original for random-driven routines (accuracy, criticals, damage variation, capture). Damage, types, stats and experience curves are compared.
+42 -2
View File
@@ -1,7 +1,7 @@
# Recovered Claude session
Latest continuation: see **Remaining opening-milestone items: 2026-09-30** at the end of
this file. Earlier sections are historical snapshots.
Latest continuation: see **Battle items, hBattleTurn and the stats screen: 2026-09-30**
at the end of this file. Earlier sections are historical snapshots.
Recovered on 2026-09-23 from the local Claude Code transcript
`~/.claude/projects/-Users-kawa-Crystal/4ac88f30-29e6-4fd5-a4b2-b6a318dd83b3.jsonl`.
@@ -566,3 +566,43 @@ Next (PLAN section 2): controlled-seed comparisons of random-driven
battle routines. Then PLAN section 3/4 items: the party and bag menus
outside battle (with the stats screen and MOVE PKMN W/O MAIL), evolution
itself, and the remaining battle items.
## Battle items, hBattleTurn and the stats screen: 2026-09-30
After `f8e0f9c`/`cfd083c`, the user asked for the items the previous
summary listed as refused or not ported:
- Every non-ball item effect usable in battle, found by reading each
item's battle context and `ItemEffects` entry from the ROM: Full
Restore, Revive/Max Revive, Energypowder, Energy Root, Heal Powder,
Revival Herb, Bitter Berry, Ether/Max Ether/Elixer/Max Elixer/
MysteryBerry (new `move` prompt), X items, X Accuracy, Guard Spec, Dire
Hit and Poké Doll. `ChangeHappiness` now reads `HappinessChanges`
(including the `wPartyMenuCursor` quirk), which also fixed level-ups:
`LevelUpHappinessMod`'s larger gain where the Pokémon was caught was
missing (new `landmark` battle option). A second participant set
(`wBattleParticipantsIncludingFainted`) serves revives.
- `hBattleTurn` at the battle menu: `DoBattle` ends on the player's turn,
full turns end on the enemy's, and `chooseTrainerMove` now returns
`enemyTurn` when `AI_Types`, `AI_Status` or `AIDamageCalc` ran. The
status-heal refusal is gone; the enemy's penalty is reapplied as in the
original.
- Stats screen: three pages from ROM strings (`STATS` profile table,
verified by `check:reference`), `TypeNames` and `GetGender`. It opens from
BattleMonMenu and from Bill's PC (a `stats` script effect;
`world.statsScreen`).
- Emulator comparisons: a new reference test runs `SendOutMonText` (with
its final `jp BattleTextbox` patched to `ret` in the in-page ROM copy),
`WithdrawMonText`'s text routine, `RestoreHealth` (with `wHPBuffer1` set
as `ItemRestoreHP` leaves it), `RestorePP`, `ChangeHappiness` and
`CalcPlayerStats` with both turns. A mutation of `calcPlayerStats` was
confirmed to fail. The pure helpers are exported from `battle.ts`.
Remaining: Kurt's and the Park Ball; the leftover multiplicand byte in
`WithdrawMonText` is assumed zero; no whole battle has been compared with
the original.
Checks: 337 unit tests with the local ROM (131 passed, 206 skipped
without it); 97 Chromium/WebKit browser tests passed, 19 skipped
intentionally; native and reference builds; reference, release and
vendor checks; `git diff --check`. Not committed.