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

+20 -4
View File
@@ -241,7 +241,7 @@ export interface BattleView {
/** A choice the battle is waiting for, if any. */
prompt?: Extract<
BattleEffect,
{ kind: "action" | "yesno" | "forget" | "stats" | "name" | "party" }
{ kind: "action" | "yesno" | "forget" | "stats" | "name" | "party" | "move" }
>;
/** Yes/No cursor, as on the original boxes. */
selected: 0 | 1;
@@ -1822,6 +1822,7 @@ export class GameWorld {
this.assets.map(this.mapId).landmark,
),
tutorial: effect.tutorial,
landmark: this.assets.map(this.mapId).landmark,
});
this.battle = { engine, selected: 1 };
this.battleRun = engine.run();
@@ -1853,6 +1854,10 @@ export class GameWorld {
this.townMap = true;
this.dialogue = { pages: ["Town Map"], index: 0 };
return true;
case "stats":
this.statsScreen = effect.mon;
this.dialogue = { pages: ["Stats"], index: 0 };
return true;
case "menu":
this.dialogue = {
pages: effect.pages.length ? effect.pages : [""],
@@ -2248,6 +2253,7 @@ export class GameWorld {
this.script = undefined;
this.memScript ??= script.memScript;
this.townMap = false;
this.statsScreen = undefined;
this.dialogue = undefined;
this.emote = undefined;
this.picture = undefined;
@@ -2275,6 +2281,7 @@ export class GameWorld {
this.spawned = script.rollback.spawned;
this.script = undefined;
this.townMap = false;
this.statsScreen = undefined;
this.dialogue = undefined;
this.emote = undefined;
this.picture = undefined;
@@ -2346,14 +2353,16 @@ export class GameWorld {
return;
this.pumpBattle(name);
}
/** Answer a battle Yes/No (1/0), the move to forget (0-3, 4 cancels)
* or a party menu (a party index, or -1 to go back). */
/** Answer a battle Yes/No (1/0), the move to forget (0-3, 4 cancels),
* a party menu (a party index, or -1 to go back) or an item's move
* choice (0-3, or -1 to go back). */
battleChoose(answer: number) {
const prompt = this.battle?.prompt;
if (
prompt?.kind === "yesno" ||
prompt?.kind === "forget" ||
prompt?.kind === "party"
prompt?.kind === "party" ||
prompt?.kind === "move"
)
this.pumpBattle(answer);
}
@@ -2372,6 +2381,7 @@ export class GameWorld {
if (prompt?.kind === "yesno") return this.pumpBattle(0);
if (prompt?.kind === "forget") return this.pumpBattle(4);
if (prompt?.kind === "party" && prompt.cancel) return this.pumpBattle(-1);
if (prompt?.kind === "move") return this.pumpBattle(-1);
if (prompt?.kind === "stats") return this.pumpBattle();
if (!prompt && view.message?.prompt) this.pumpBattle();
}
@@ -2695,6 +2705,8 @@ export class GameWorld {
/** One overworld tick. `held` is the direction the player is holding. */
/** Overworld ticks run so far, for presentation such as tile animation. */
townMap = false;
/** The Pokémon a script's stats screen shows (Bill's PC). */
statsScreen: PartyMon | undefined;
ticks = 0;
tick(held?: Direction) {
@@ -2723,6 +2735,7 @@ export class GameWorld {
) {
if (--dialogue.holdTicks <= 0) {
this.townMap = false;
this.statsScreen = undefined;
this.dialogue = undefined;
this.pump();
}
@@ -3144,6 +3157,7 @@ export class GameWorld {
return;
}
this.townMap = false;
this.statsScreen = undefined;
this.dialogue = undefined;
this.pump();
}
@@ -3214,6 +3228,7 @@ export class GameWorld {
)
return;
this.townMap = false;
this.statsScreen = undefined;
this.dialogue = undefined;
this.pump(answer);
}
@@ -3475,6 +3490,7 @@ export class GameWorld {
this.tilesWalked = save.tilesWalked;
this.playerId = save.playerId;
this.townMap = false;
this.statsScreen = undefined;
this.dialogue = undefined;
this.emote = undefined;
this.picture = undefined;