- Enable Route 29, its Route 46 gate, Cherrygrove City and its buildings. - Run item balls through FindItemInBallScript and fruit trees through FruitTreeScript, with a native daily reset of the daily engine flags. - Port the Pokémon Center nurse (HealParty with the PP Up clamp, CheckPokerus, phone-call checks) and record the whiteout spawn on entering a Pokémon Center, as EnterMapWarp does. - Port standard Poké Marts with keyboard, D-pad and pointer menus. - Add the recoil battle command (Struggle) and VAR_BOXSPACE. - Save fruit trees, the daily reset day and the last spawn map; older version-3 backups migrate by absence. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
11d1153802
commit
796fe8f6d5
24 files changed
+1549
-59
No files matched your search
@@ -3,6 +3,7 @@ import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
||||
import { createHash } from "node:crypto";
|
||||
import { resolve } from "node:path";
|
||||
import { CrystalAssets } from "../src/game/rom/assets";
|
||||
import { generatePartyMon } from "../src/game/party/pokemon";
|
||||
import { GameWorld } from "../src/game/world/world";
|
||||
import type { Direction } from "../src/game/world/types";
|
||||
import { VECTORS } from "../src/game/world/types";
|
||||
@@ -362,6 +363,55 @@ test("a home exit mat survives save/reload and waits for the exit direction", as
|
||||
await expect(page.locator("#game-notice")).toHaveText("");
|
||||
});
|
||||
|
||||
test("walks from New Bark Town onto Route 29 after receiving a starter", async ({
|
||||
page,
|
||||
}, testInfo) => {
|
||||
test.skip(!existsSync(romPath), "Requires a local user-supplied ROM.");
|
||||
const bytes = readFileSync(romPath);
|
||||
const assets = new CrystalAssets(new Uint8Array(bytes));
|
||||
const world = new GameWorld(assets);
|
||||
const town = assets.map("24:4");
|
||||
const edge = Array.from({ length: town.height }, (_, y) => y).find(
|
||||
(y) => assets.permission(assets.collision(town, 0, y)) === 0,
|
||||
)!;
|
||||
world.state.party.push(
|
||||
generatePartyMon(assets.pokemon, {
|
||||
species: 155, level: 5, item: 0, otId: world.playerId,
|
||||
ot: "CHRIS", dvs: 0x823b, caughtData: 0,
|
||||
}),
|
||||
);
|
||||
// SCENE_NEWBARKTOWN_NOOP: after the starter the teacher no longer stops you.
|
||||
world.restore({ ...world.save(), map: "24:4", x: 0, y: edge, direction: "left", scenes: { "24:4": 1 } });
|
||||
const backup = testInfo.outputPath("new-bark-edge.crystal-save.json");
|
||||
writeFileSync(
|
||||
backup,
|
||||
JSON.stringify({
|
||||
version: 1,
|
||||
romHash: createHash("sha1").update(bytes).digest("hex"),
|
||||
coreId: "crystal-native-world-v1",
|
||||
savedAt: new Date().toISOString(),
|
||||
state: Buffer.from(JSON.stringify(world.save())).toString("base64"),
|
||||
}),
|
||||
);
|
||||
await page.goto("/");
|
||||
await page.locator("#rom-file").setInputFiles(romPath);
|
||||
await expect(page.locator("#status")).toContainText("verified");
|
||||
await page.locator("#tab-saves").click();
|
||||
page.once("dialog", (dialog) => dialog.accept());
|
||||
await page.locator("#save-file").setInputFiles(backup);
|
||||
await expect(page.locator("#status")).toContainText("Backup restored");
|
||||
await page.locator("#play").click();
|
||||
const screen = page.locator("#game-screen");
|
||||
await page.keyboard.down("ArrowLeft");
|
||||
await page.waitForFunction(
|
||||
() => document.querySelector("#game-screen")?.getAttribute("data-map") === "24:3",
|
||||
);
|
||||
await page.keyboard.up("ArrowLeft");
|
||||
await expect(screen).toHaveAttribute("data-activity", "idle");
|
||||
await expect(page.locator("#location")).toHaveText("Route 29");
|
||||
await expect(page.locator("#game-notice")).toHaveText("");
|
||||
});
|
||||
|
||||
test("development server does not serve ROMs or the private reference checkout", async ({
|
||||
request,
|
||||
}) => {
|
||||
|
||||
Reference in new issue
Block a user