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

+36 -3
View File
@@ -66,8 +66,8 @@ export function battleOptions(
}
/** Run a battle. Menus take queued answers per prompt kind, then the
* defaults: the first move, YES, cancelling a move to forget and the
* first party slot. */
* defaults: the first move, YES, cancelling a move to forget, and the
* first party slot or move slot. */
export function playBattle(
battle: Battle,
queued: Partial<Record<BattleEffect["kind"], BattleInput[]>> = {},
@@ -94,10 +94,43 @@ export function playBattle(
? 1
: effect.kind === "forget"
? 4
: effect.kind === "party"
: effect.kind === "party" || effect.kind === "move"
? 0
: undefined;
}
}
throw new Error("Battle did not end.");
}
/** Step a battle by hand: texts are collected up to each prompt, and
* `answer` feeds the current prompt's input. */
export function battleSteps(battle: Battle) {
const run = battle.run();
const texts: string[] = [];
let next = run.next();
const collect = () => {
while (
!next.done &&
(next.value.kind === "text" || next.value.kind === "hud")
) {
if (next.value.kind === "text")
texts.push(next.value.text.replace(/\n/g, " "));
next = run.next();
}
};
collect();
return {
texts,
get prompt(): BattleEffect | undefined {
return next.done ? undefined : next.value;
},
get done() {
return Boolean(next.done);
},
answer(input: BattleInput) {
next = run.next(input);
collect();
return this;
},
};
}