OPTION in the start menu runs _Option with the ROM's labels and settings, OptionsControl's cursor wrapping and each option's bit handling. The four option bytes live in the script state and saves, defaulting to DefaultOptions. The battle style now decides whether a trainer's next Pokémon brings an offer to switch, and the menu account whether the start menu describes its items; the other settings are kept for later. Closes #24 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
47698565ab
commit
c4cc0e756c
19 files changed
+732
-21
No files matched your search
+32
-3
@@ -26,6 +26,14 @@ import {
|
||||
refreshTrainerCard,
|
||||
type TrainerCardView,
|
||||
} from "../scripts/trainer-card";
|
||||
import {
|
||||
OPTIONS_BUTTONS,
|
||||
shiftBattleStyle,
|
||||
validOptions,
|
||||
defaultOptions,
|
||||
type GameOptions,
|
||||
type OptionsView,
|
||||
} from "../scripts/options";
|
||||
import {
|
||||
advanceGameTime,
|
||||
emptyGameTime,
|
||||
@@ -138,6 +146,8 @@ export interface NativeSave {
|
||||
noWildEncounters: boolean;
|
||||
/** wWhichRegisteredItem and wRegisteredItem, for Select. */
|
||||
registeredItem: { which: number; item: number };
|
||||
/** The option bytes, saved with the game as sOptions is. */
|
||||
options: GameOptions;
|
||||
}
|
||||
|
||||
/** A random byte from the platform's secure generator. */
|
||||
@@ -259,6 +269,8 @@ export type Choice =
|
||||
| { kind: "mombank"; view: MomBankView; selected: 0 }
|
||||
/** A trainer card page, answered with the button pressed. */
|
||||
| { kind: "trainercard"; view: TrainerCardView; selected: 0 }
|
||||
/** The options screen, answered with the button pressed. */
|
||||
| { kind: "options"; view: OptionsView; selected: 0 }
|
||||
/** The mart's 1-99 quantity stepper; `selected` is the current amount. */
|
||||
| {
|
||||
kind: "martquantity";
|
||||
@@ -275,7 +287,8 @@ export type Choice =
|
||||
const buttonChoice = (choice: Choice) =>
|
||||
choice.kind === "pokegear" ||
|
||||
choice.kind === "mombank" ||
|
||||
choice.kind === "trainercard";
|
||||
choice.kind === "trainercard" ||
|
||||
choice.kind === "options";
|
||||
export interface Dialogue {
|
||||
pages: string[];
|
||||
index: number;
|
||||
@@ -2178,6 +2191,7 @@ export class GameWorld {
|
||||
saving: Number(draft.flags.has(OW.ENGINE_MOM_SAVING_MONEY)),
|
||||
money: draft.momsMoney,
|
||||
},
|
||||
shift: shiftBattleStyle(draft.options),
|
||||
});
|
||||
this.battle = { engine, selected: 1 };
|
||||
this.battleRun = engine.run();
|
||||
@@ -2237,6 +2251,14 @@ export class GameWorld {
|
||||
choice: { kind: "trainercard", view: effect.view, selected: 0 },
|
||||
};
|
||||
return true;
|
||||
case "options":
|
||||
if (!effect.view) return false;
|
||||
this.dialogue = {
|
||||
pages: [""],
|
||||
index: 0,
|
||||
choice: { kind: "options", view: effect.view, selected: 0 },
|
||||
};
|
||||
return true;
|
||||
case "mombank":
|
||||
this.dialogue = {
|
||||
pages: effect.pages.length ? effect.pages : [""],
|
||||
@@ -3754,7 +3776,9 @@ export class GameWorld {
|
||||
(dialogue.choice.kind === "mombank" &&
|
||||
!MOM_BANK_BUTTONS.includes(answer as never)) ||
|
||||
(dialogue.choice.kind === "trainercard" &&
|
||||
!TRAINER_CARD_BUTTONS.includes(answer as never))
|
||||
!TRAINER_CARD_BUTTONS.includes(answer as never)) ||
|
||||
(dialogue.choice.kind === "options" &&
|
||||
!OPTIONS_BUTTONS.includes(answer as never))
|
||||
)
|
||||
return;
|
||||
this.townMap = false;
|
||||
@@ -3827,6 +3851,7 @@ export class GameWorld {
|
||||
flash: state.flash,
|
||||
noWildEncounters: state.noWildEncounters,
|
||||
registeredItem: { ...state.registeredItem },
|
||||
options: { ...state.options },
|
||||
};
|
||||
}
|
||||
restore(value: unknown) {
|
||||
@@ -3929,7 +3954,8 @@ export class GameWorld {
|
||||
typeof save.noWildEncounters !== "boolean" ||
|
||||
!save.registeredItem ||
|
||||
!integer(save.registeredItem.which, 0, 255) ||
|
||||
!integer(save.registeredItem.item, 0, 255)
|
||||
!integer(save.registeredItem.item, 0, 255) ||
|
||||
!validOptions(save.options)
|
||||
) {
|
||||
throw new Error(
|
||||
"Invalid native save. Emulator snapshots cannot be imported into this port.",
|
||||
@@ -3995,6 +4021,7 @@ export class GameWorld {
|
||||
flash: save.flash,
|
||||
noWildEncounters: save.noWildEncounters,
|
||||
registeredItem: { ...save.registeredItem },
|
||||
options: { ...save.options },
|
||||
specialPhoneCall: save.specialPhoneCall,
|
||||
rivalName: save.rivalName,
|
||||
};
|
||||
@@ -4105,6 +4132,7 @@ export function migrateSave(
|
||||
}),
|
||||
...(!Object.hasOwn(save, "intro") && { intro: false }),
|
||||
...(!Object.hasOwn(save, "gameTime") && { gameTime: emptyGameTime() }),
|
||||
...(!Object.hasOwn(save, "options") && { options: defaultOptions() }),
|
||||
// Clocks saved before InitClock was ported follow the device time.
|
||||
...(save.clock !== null &&
|
||||
typeof save.clock === "object" &&
|
||||
@@ -4151,5 +4179,6 @@ export function migrateSave(
|
||||
registeredItem: { which: 0, item: 0 },
|
||||
intro: false,
|
||||
gameTime: emptyGameTime(),
|
||||
options: defaultOptions(),
|
||||
} as unknown as NativeSave;
|
||||
}
|
||||
Reference in new issue
Block a user