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.