Open Route 31, Violet City and Sprout Tower (#31)

Enable Route 31 and its gate, Dark Cave's Violet entrance, Violet City with its buildings and Sprout Tower. Port the script commands they use: gettrainername, askforphonenumber (with AddPhoneNumber's room for Mom and Elm; addcellnum now reports failure as the original does), checkpokemail, loadmenu/_2dmenu/closewindow, giveegg and trade (NPCTrade, with wTradeFlags saved).

Eggs keep their species with an egg flag, as wPartySpecies does. The pack's TM/HM counts receive, check and toss TMs and HMs, which are named TM01-HM07.

The playthrough continues through Route 31 (with Mom's call), Violet City and Sprout Tower to Elder Li's Flash.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Sébastien QUEROLandClaude Opus 5.5 committed 2026-10-03 16:24:29 +02:00
1 parent ec3d1cd5c4
commit 7909302db1
16 files changed
+585 -63

No files matched your search

+20 -1
View File
@@ -72,6 +72,7 @@ import {
} from "../party/mail";
import type { MovementPose, MovementStep } from "../scripts/movement";
import { emptyBag, validBag, type Bag, type ItemSlot } from "../party/bag";
import { NUM_TMS_HMS } from "../rom/pokemon";
import {
copyStorage,
emptyStorage,
@@ -165,6 +166,8 @@ export interface NativeSave {
repel: number;
coins: number;
blueCardBalance: number;
/** wTradeFlags: the in-game trades done, one bit per NPCTRADE_*. */
tradeFlags: number;
/** The option bytes, saved with the game as sOptions is. */
options: GameOptions;
}
@@ -3852,7 +3855,7 @@ export class GameWorld {
/** CheckPartyMove: the first party member (not an Egg) knowing `move`. */
private partyMove(move: number): number {
return this.state.party.findIndex(
(mon) => mon.species !== OW.EGG && mon.moves.includes(move as never),
(mon) => !mon.egg && mon.moves.includes(move as never),
);
}
@@ -4280,6 +4283,7 @@ export class GameWorld {
mailbox: state.mailbox.map(copyMail),
repel: state.repel,
coins: state.coins,
tradeFlags: state.tradeFlags,
blueCardBalance: state.blueCardBalance,
options: { ...state.options },
};
@@ -4400,6 +4404,7 @@ export class GameWorld {
!integer(save.registeredItem.item, 0, 255) ||
!integer(save.repel, 0, 255) ||
!integer(save.coins, 0, C.MAX_COINS) ||
!integer(save.tradeFlags, 0, 0x7f) ||
!integer(save.blueCardBalance, 0, 255) ||
!validOptions(save.options)
) {
@@ -4471,6 +4476,7 @@ export class GameWorld {
mailbox: save.mailbox.map(copyMail),
repel: save.repel,
coins: save.coins,
tradeFlags: save.tradeFlags,
blueCardBalance: save.blueCardBalance,
options: { ...save.options },
specialPhoneCall: save.specialPhoneCall,
@@ -4589,6 +4595,18 @@ export function migrateSave(
coins: 0,
blueCardBalance: 0,
}),
// Packs saved before the TM/HM pocket had no TMs or HMs.
...(typeof save.bag === "object" &&
save.bag !== null &&
!Object.hasOwn(save.bag, "tmsHms")
? {
bag: {
...(save.bag as object),
tmsHms: Array<number>(NUM_TMS_HMS).fill(0),
},
}
: {}),
...(!Object.hasOwn(save, "tradeFlags") && { tradeFlags: 0 }),
...(!Object.hasOwn(save, "intro") && { intro: false }),
...(!Object.hasOwn(save, "gameTime") && { gameTime: emptyGameTime() }),
...(!Object.hasOwn(save, "options") && { options: defaultOptions() }),
@@ -4641,6 +4659,7 @@ export function migrateSave(
repel: 0,
coins: 0,
blueCardBalance: 0,
tradeFlags: 0,
intro: false,
gameTime: emptyGameTime(),
options: defaultOptions(),