Open the Radio Tower takeover, Ice Path, Blackthorn and Dragon's Den (#32)
The Rocket-held Radio Tower, the Underground's switch room and warehouse, Ice Path, Blackthorn City and its gym, Routes 45 and 46, Dark Cave's Blackthorn entrance, Dragon's Den and the Dragon Shrine are open. The story plays through the Basement Key, the switches and the director, the Clear Bell, Ice Path's falling boulder, Clair's gym and the shrine's test for the RISINGBADGE, TM24 and the elder's Dratini. New specials: GiveDratini and MoveDeletion. A save keeps an object that a script made disappear (or appear against its flag) as Continue does, so the Radio Tower director no longer blocks the 5F stairs after a reload. A whiteout from a battle started in an scall no longer refuses. The playthrough driver pushes boulders into their holes (planned breadth first), clears whirlpools, chooses the move a TM replaces and heals with the strongest potion; the run gains six stages to the Rising Badge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
061ca4d59d
commit
9c3579937c
15 files changed
+855
-43
No files matched your search
@@ -172,6 +172,41 @@ const RED_SCALE = 0x42,
|
||||
EVENT_RADIO_TOWER_ROCKET_TAKEOVER = 0x6ce,
|
||||
ENGINE_GLACIERBADGE = 0x21,
|
||||
ENGINE_ROCKETS_IN_RADIO_TOWER = 0x13;
|
||||
const RADIO_TOWER = ["3:17", "3:18", "3:19", "3:20", "3:21"],
|
||||
UNDERGROUND = "3:53",
|
||||
SWITCH_ROOM = "3:54",
|
||||
DEPT_STORE_B1F = "3:55",
|
||||
WAREHOUSE = "3:56",
|
||||
DEPT_STORE_1F = "11:11",
|
||||
ELEVATOR = "11:17",
|
||||
ROUTE_44 = "2:6",
|
||||
ICE_PATH = ["3:61", "3:62", "3:63", "3:64", "3:65"],
|
||||
BLACKTHORN = "5:10",
|
||||
BLACKTHORN_CENTER = "5:6",
|
||||
BLACKTHORN_MART = "5:5",
|
||||
BLACKTHORN_GYM = ["5:1", "5:2"],
|
||||
ROUTE_45 = "5:8",
|
||||
DRAGONS_DEN = ["3:80", "3:81"],
|
||||
DRAGON_SHRINE = "3:82";
|
||||
const BASEMENT_KEY = 0x85,
|
||||
CARD_KEY = 0x7f,
|
||||
CLEAR_BELL = 0x46,
|
||||
HM06 = 0xf8,
|
||||
DRATINI = 147,
|
||||
EXTREMESPEED = 245,
|
||||
EVENT_BEAT_ROCKET_EXECUTIVEM_3 = 0x573,
|
||||
EVENT_USED_BASEMENT_KEY = 0x49,
|
||||
EVENT_RIVAL_GOLDENROD_UNDERGROUND = 0x6c1,
|
||||
EVENT_RECEIVED_CARD_KEY = 0x4a,
|
||||
EVENT_USED_THE_CARD_KEY_IN_THE_RADIO_TOWER = 0x25,
|
||||
EVENT_CLEARED_RADIO_TOWER = 0x21,
|
||||
EVENT_GOT_CLEAR_BELL = 0x78,
|
||||
EVENT_BOULDER_IN_ICE_PATH_2A = 0x70e,
|
||||
EVENT_BEAT_CLAIR = 0x4c4,
|
||||
EVENT_GOT_TM24_DRAGONBREATH = 0xf,
|
||||
EVENT_GOT_DRATINI = 0xbd,
|
||||
EVENT_ANSWERED_DRAGON_MASTER_QUIZ_WRONG = 0xc1,
|
||||
ENGINE_RISINGBADGE = 0x22;
|
||||
|
||||
/** The acceptance run for PLAN section 2: a new game played from the
|
||||
* introduction to the catching tutorial through the world's own inputs,
|
||||
@@ -1185,5 +1220,216 @@ describe.skipIf(!existsSync(romPath))(
|
||||
reload();
|
||||
writeTestSave("mahogany-town");
|
||||
}, 240_000);
|
||||
/** Mahogany to Goldenrod the long way round: Route 42, Ecruteak,
|
||||
* Routes 37 and 36, the National Park and Route 35. */
|
||||
const mahoganyToGoldenrod = () => {
|
||||
cross("left", ROUTE_42, { water: true });
|
||||
sail(2, 8); // Route 42's pond, then ashore by the gate
|
||||
stairs(ROUTE_42_GATE);
|
||||
stairs(ECRUTEAK);
|
||||
cross("down", ROUTE_37);
|
||||
cross("down", ROUTE_36);
|
||||
stairs(ROUTE_36_NATIONAL_PARK_GATE);
|
||||
stairs(NATIONAL_PARK);
|
||||
stairs(ROUTE_35_NATIONAL_PARK_GATE);
|
||||
stairs(ROUTE_35);
|
||||
stairs(ROUTE_35_GATE);
|
||||
stairs(GOLDENROD);
|
||||
};
|
||||
|
||||
it("walks back to Goldenrod and climbs the Rocket-held Radio Tower to the fake director", () => {
|
||||
traceFailures();
|
||||
mahoganyToGoldenrod();
|
||||
heal(GOLDENROD_CENTER, GOLDENROD);
|
||||
enter(RADIO_TOWER[0], "up");
|
||||
for (const floor of RADIO_TOWER.slice(1)) stairs(floor);
|
||||
walk(0, 3); // FakeDirectorScript
|
||||
expect(p.world.state.events.has(EVENT_BEAT_ROCKET_EXECUTIVEM_3)).toBe(true);
|
||||
expect(p.world.state.bag.keyItems).toContain(BASEMENT_KEY);
|
||||
expect(p.log.join(" ")).toContain("UNDERGROUND\nWAREHOUSE.");
|
||||
travel(GOLDENROD, RADIO_TOWER);
|
||||
reload();
|
||||
}, 240_000);
|
||||
|
||||
it("opens the basement door, works the Underground switches and frees the director", () => {
|
||||
traceFailures();
|
||||
// Fresh PP before the rival waiting in the switch room.
|
||||
heal(GOLDENROD_CENTER, GOLDENROD);
|
||||
stairs(SWITCH_ROOM);
|
||||
stairs(UNDERGROUND);
|
||||
walk(18, 7);
|
||||
p.world.move("up");
|
||||
p.world.interact();
|
||||
play();
|
||||
expect(p.world.state.events.has(EVENT_USED_BASEMENT_KEY)).toBe(true);
|
||||
// The door leads to the Underground's other corner.
|
||||
p.world.move("up");
|
||||
play();
|
||||
stairs(SWITCH_ROOM);
|
||||
// From all off, switches 3, 2 and 1 leave doors 3, 5, 6, 8, 9 and 11
|
||||
// open: a way from the switches down to the warehouse.
|
||||
for (const [x, y] of [[2, 1], [10, 1], [16, 1]]) {
|
||||
walk(x, y + 1);
|
||||
p.world.move("up");
|
||||
p.world.interact();
|
||||
play([1]);
|
||||
}
|
||||
expect(p.world.save().memory).toMatchObject({ wUndergroundSwitchPositions: 6 });
|
||||
expect(p.world.state.events.has(EVENT_RIVAL_GOLDENROD_UNDERGROUND)).toBe(true);
|
||||
stairs(WAREHOUSE);
|
||||
// The warehouse resets the switches when entered.
|
||||
expect(p.world.save().memory).toMatchObject({ wUndergroundSwitchPositions: 0 });
|
||||
talkTo(p.world.map.objects[3].id);
|
||||
play();
|
||||
expect(p.world.state.events.has(EVENT_RECEIVED_CARD_KEY)).toBe(true);
|
||||
expect(p.world.state.bag.keyItems).toContain(CARD_KEY);
|
||||
// Out through the department store's basement and elevator.
|
||||
stairs(DEPT_STORE_B1F);
|
||||
stairs(ELEVATOR);
|
||||
walk(3, 1);
|
||||
p.world.move("up");
|
||||
p.world.interact();
|
||||
play([1]); // 1F
|
||||
walk(2, 3);
|
||||
p.world.move("down");
|
||||
play();
|
||||
expect(p.world.mapId).toBe(DEPT_STORE_1F);
|
||||
exit(GOLDENROD);
|
||||
reload();
|
||||
}, 240_000);
|
||||
|
||||
it("opens the 3F shutters with the Card Key and beats the executive for the Clear Bell", () => {
|
||||
traceFailures();
|
||||
heal(GOLDENROD_CENTER, GOLDENROD);
|
||||
enter(RADIO_TOWER[0], "up");
|
||||
stairs(RADIO_TOWER[1]);
|
||||
stairs(RADIO_TOWER[2]);
|
||||
walk(14, 3); // CardKeySlotScript faces up
|
||||
p.world.move("up");
|
||||
p.world.interact();
|
||||
play();
|
||||
expect(p.world.state.events.has(EVENT_USED_THE_CARD_KEY_IN_THE_RADIO_TOWER)).toBe(true);
|
||||
walk(17, 0); // the stairs behind the shutters
|
||||
expect(p.world.mapId).toBe(RADIO_TOWER[3]);
|
||||
stairs(RADIO_TOWER[4]);
|
||||
walk(16, 5); // RadioTower5FRocketBossScript
|
||||
expect(p.world.state.events.has(EVENT_CLEARED_RADIO_TOWER)).toBe(true);
|
||||
expect(p.world.state.flags.has(ENGINE_ROCKETS_IN_RADIO_TOWER)).toBe(false);
|
||||
expect(p.world.state.events.has(EVENT_GOT_CLEAR_BELL)).toBe(true);
|
||||
expect(p.world.state.bag.keyItems).toContain(CLEAR_BELL);
|
||||
// The director walks out and disappears; a save keeps him gone.
|
||||
reload();
|
||||
travel(RADIO_TOWER[0], RADIO_TOWER.slice(1));
|
||||
exit(GOLDENROD);
|
||||
reload();
|
||||
}, 240_000);
|
||||
|
||||
it("crosses Route 44 and Ice Path's boulders to Blackthorn City", () => {
|
||||
traceFailures();
|
||||
toRoute36();
|
||||
cross("up", ROUTE_37);
|
||||
cross("up", ECRUTEAK);
|
||||
stairs(ROUTE_42_GATE);
|
||||
stairs(ROUTE_42);
|
||||
cross("right", MAHOGANY, { water: true });
|
||||
heal(MAHOGANY_CENTER, MAHOGANY);
|
||||
cross("right", ROUTE_44);
|
||||
stairs(ICE_PATH[0]);
|
||||
stairs(ICE_PATH[1]);
|
||||
// B1F: drop boulder 2 down its hole, then fall through another; on
|
||||
// B2F's ice it stops a slide on the way to B3F.
|
||||
p.boulders([{ id: 3, x: 4, y: 7 }], [2]);
|
||||
expect(p.world.state.events.has(EVENT_BOULDER_IN_ICE_PATH_2A)).toBe(false);
|
||||
walk(5, 12);
|
||||
expect(p.world.mapId).toBe(ICE_PATH[2]);
|
||||
walk(9, 11);
|
||||
expect(p.world.mapId).toBe(ICE_PATH[4]);
|
||||
travel(BLACKTHORN, [ICE_PATH[0], ICE_PATH[1], ICE_PATH[3], ICE_PATH[4]]);
|
||||
reload();
|
||||
}, 240_000);
|
||||
|
||||
it("trains on Route 45, drops the gym's boulders and beats Clair", () => {
|
||||
traceFailures();
|
||||
// Clair's Kingdra outclasses a level 53 lead; a player trains first.
|
||||
cross("down", ROUTE_45);
|
||||
train(62, () => {
|
||||
cross("up", BLACKTHORN);
|
||||
heal(BLACKTHORN_CENTER, BLACKTHORN);
|
||||
cross("down", ROUTE_45);
|
||||
});
|
||||
cross("up", BLACKTHORN);
|
||||
enter(BLACKTHORN_MART, "up");
|
||||
buy(p.world.map.objects[0].id, C.MAX_POTION, 4);
|
||||
exit(BLACKTHORN);
|
||||
heal(BLACKTHORN_CENTER, BLACKTHORN);
|
||||
enter(BLACKTHORN_GYM[0], "up");
|
||||
stairs(BLACKTHORN_GYM[1]);
|
||||
// Boulders 1 and 3 fall to 1F and bridge the way to Clair.
|
||||
p.boulders(
|
||||
[
|
||||
{ id: 4, x: 8, y: 3 },
|
||||
{ id: 6, x: 8, y: 7 },
|
||||
],
|
||||
[5, 7, 8, 9],
|
||||
);
|
||||
expect(route(BLACKTHORN_GYM[0], BLACKTHORN_GYM, 4, { x: 5, y: 4 })).toBe(true);
|
||||
talkTo(p.world.map.objects[0].id);
|
||||
play([1]);
|
||||
expect(p.world.state.events.has(EVENT_BEAT_CLAIR)).toBe(true);
|
||||
expect(p.world.state.flags.has(ENGINE_RISINGBADGE)).toBe(false);
|
||||
expect(p.log.join(" ")).toContain("DRAGON'S DEN");
|
||||
travel(BLACKTHORN, BLACKTHORN_GYM);
|
||||
reload();
|
||||
}, 360_000);
|
||||
|
||||
it("passes the Dragon Shrine's test for the RISINGBADGE, TM24 and Dratini", () => {
|
||||
traceFailures();
|
||||
heal(BLACKTHORN_CENTER, BLACKTHORN);
|
||||
// Krabby learns Whirlpool in place of Leer for Dragon's Den.
|
||||
p.teach(HM06, 4, 1);
|
||||
expect(p.world.state.party[4].moves).toContain(250);
|
||||
const den = p.world.map.warps.find((warp) => warp.targetMap === DRAGONS_DEN[0])!;
|
||||
sail(den.x, den.y + 1);
|
||||
p.world.move("up");
|
||||
play();
|
||||
walk(3, 4); // the ladder down to 1F's lower part
|
||||
p.world.move("up");
|
||||
play();
|
||||
stairs(DRAGONS_DEN[1]);
|
||||
sail(19, 31, { whirlpools: true });
|
||||
walk(19, 30);
|
||||
// DragonShrineTakeTestScript: five questions, all answered right.
|
||||
p.world.move("up");
|
||||
play([0, 0, 1, 0, 1]);
|
||||
expect(p.world.mapId).toBe(DRAGON_SHRINE);
|
||||
expect(p.world.state.flags.has(ENGINE_RISINGBADGE)).toBe(true);
|
||||
expect(p.world.state.events.has(EVENT_ANSWERED_DRAGON_MASTER_QUIZ_WRONG)).toBe(false);
|
||||
// Clair waits by the door with TM24 (DragonsDenB1F_ClairScene).
|
||||
stairs(DRAGONS_DEN[1]);
|
||||
expect(p.world.state.events.has(EVENT_GOT_TM24_DRAGONBREATH)).toBe(true);
|
||||
expect(p.world.state.bag.tmsHms[23]).toBe(1); // TM24
|
||||
// Back inside, the elder gives Dratini with Extremespeed.
|
||||
p.world.move("up");
|
||||
play();
|
||||
talkTo(p.world.map.objects[0].id);
|
||||
play();
|
||||
expect(p.world.state.events.has(EVENT_GOT_DRATINI)).toBe(true);
|
||||
const dratini = p.world.state.party.at(-1)!;
|
||||
expect(dratini).toMatchObject({ species: DRATINI, level: 15 });
|
||||
expect(dratini.moves).toEqual([35, 86, 239, EXTREMESPEED]);
|
||||
expect(dratini.pp).toEqual([20, 20, 20, 5]);
|
||||
// Out: the whirlpool is back after the map reload.
|
||||
stairs(DRAGONS_DEN[1]);
|
||||
sail(20, 4, { whirlpools: true });
|
||||
p.world.move("up");
|
||||
play();
|
||||
walk(5, 14);
|
||||
p.world.move("up");
|
||||
play();
|
||||
stairs(BLACKTHORN);
|
||||
sail(17, 14);
|
||||
reload();
|
||||
writeTestSave("blackthorn-city");
|
||||
}, 240_000);
|
||||
},
|
||||
);
|
||||
Reference in new issue
Block a user