Port field moves from the menu, SEL with Select, and moving Pokémon in Bill's PC
Checks / web (push) Canceled after 0s

Field moves chosen in the party menu run their original checks and the
ROM's from-menu scripts (Cut, Surf, Strength, Flash, Whirlpool, Waterfall,
Sweet Scent), and Softboiled and Milk Drink share HP. SEL registers a key
item that Select then uses, replacing the Key Items shortcut, and Bill's
PC moves Pokémon between the party and every box.

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 17:22:56 +02:00
1 parent 45275ba83b
commit 3456aa4e11
25 files changed
+1129 -186

No files matched your search

+99 -2
View File
@@ -33,6 +33,7 @@ const BICYCLE = 7,
LEFTOVERS = 0x92,
FLOWER_MAIL = 0x9e,
BERRY = 0xad;
const SOFTBOILED = 0x87;
const CUT = 0x0f,
GUST = 0x10,
SAND_ATTACK = 0x1c,
@@ -197,8 +198,11 @@ describe.skipIf(!existsSync(romPath))("the start menu", () => {
pick(world, "CANCEL");
pick(world, "PIDGEY");
expect(menuItems(world)).toEqual(["CUT", "STATS", "SWITCH", "MOVE", "ITEM", "CANCEL"]);
pick(world, "CUT");
expect(world.notice).toBe("Using CUT from the menu is not ported yet.");
// CutFunction's CheckBadge, then the party menu again.
expect(pick(world, "CUT")).toEqual([
"Sorry! A new BADGE is required.",
"Choose a POKéMON.",
]);
// STATS shows the stats screen, and B returns to the party.
pick(world, "PIDGEY");
world.choose(menuItems(world).indexOf("STATS"));
@@ -209,6 +213,56 @@ describe.skipIf(!existsSync(romPath))("the start menu", () => {
close(world);
});
it("shares HP with Softboiled, which needs more than a fifth of it", () => {
const world = fixture();
const data = world.assets.pokemon;
const chansey = generatePartyMon(data, {
species: 113,
level: 20,
item: 0,
otId: world.playerId,
ot: "CHRIS",
dvs: 0x9abc,
caughtData: 0,
});
chansey.moves = [SOFTBOILED, 0, 0, 0];
world.state.party.push(chansey);
world.state.party[0].hp = 3;
const fifth = Math.floor(chansey.stats[0] / 5);
open(world);
pick(world, "POKéMON");
pick(world, "CHANSEY");
expect(pick(world, "SOFTBOILED")).toEqual(["Use on which POKéMON?"]);
// Not on itself, and not on a Pokémon at full HP.
expect(pick(world, "CHANSEY")).toEqual([
"That can't be used on this POKéMON.",
"Use on which POKéMON?",
]);
expect(pick(world, "PIDGEY")[0]).toBe("That can't be used on this POKéMON.");
expect(pick(world, "CYNDAQUIL")).toEqual([
`CYNDAQUIL recovered ${Math.min(fifth, world.liveState.party[0].stats[0] - 3)}HP!`,
"Choose a POKéMON.",
]);
// The cursor returns to the user.
const party = world.dialogue?.choice;
expect(party?.kind === "menu" && party.selected).toBe(2);
close(world);
expect(world.state.party[2].hp).toBe(chansey.stats[0] - fifth);
expect(world.state.party[0].hp).toBe(
Math.min(world.state.party[0].stats[0], 3 + fifth),
);
world.state.party[2].hp = fifth;
open(world);
pick(world, "POKéMON");
pick(world, "CHANSEY");
expect(pick(world, "SOFTBOILED")).toEqual([
"Not enough HP!",
"Choose a POKéMON.",
]);
close(world);
});
it("switches two Pokémon, and B cancels the move", () => {
const world = fixture();
open(world);
@@ -525,6 +579,49 @@ describe.skipIf(!existsSync(romPath))("the start menu", () => {
expect(indoors.state.playerState).toBe(0);
});
it("registers the Bicycle with SEL, and Select rides it without a message", () => {
const world = fixture();
// Nothing registered yet.
expect(world.useSelect()).toBe(true);
expect(until(world)).toEqual([
"An item in your PACK may be",
"registered for use on SELECT Button.",
]);
close(world);
open(world);
pick(world, "PACK");
pickItem(world, BICYCLE);
expect(pick(world, "SEL")).toEqual(["Registered the BICYCLE."]);
close(world);
expect(world.state.registeredItem).toEqual({ which: 0x81, item: BICYCLE });
// The registration is saved.
world.restore(world.save());
expect(world.state.registeredItem).toEqual({ which: 0x81, item: BICYCLE });
expect(world.useSelect()).toBe(true);
expect(settle(world)).toEqual([]);
expect(world.diagnostic).toBe("");
expect(world.state.playerState).toBe(1);
expect(world.useSelect()).toBe(true);
expect(settle(world)).toEqual([]);
expect(world.state.playerState).toBe(0);
const indoors = fixture(PLAYERS_HOUSE, 7, 4);
indoors.state.registeredItem = { which: 0x81, item: BICYCLE };
indoors.useSelect();
expect(until(indoors)).toEqual(["OAK: CHRIS! This isn't the time to use that!"]);
close(indoors);
expect(indoors.state.playerState).toBe(0);
});
it("forgets a registered item that left its slot", () => {
const world = fixture();
world.state.registeredItem = { which: 0x02, item: POTION };
world.useSelect();
expect(until(world)[0]).toBe("An item in your PACK may be");
close(world);
expect(world.state.registeredItem).toEqual({ which: 0, item: 0 });
});
it("offers no USE without a field menu, and a notice for unported effects", () => {
const world = fixture();
world.state.bag.items.push(