Files
Crystal/tests/movement-fixture.ts
T
Sébastien QUEROLandClaude Opus 5.5 209778cabe
Checks / web (push) Canceled after 0s
Port the Pokégear, phone calls and Mom's bank
POKéGEAR in the start menu runs the clock, Town Map and phone cards with
the original joypad rules. Calls to Elm and Mom run their callee scripts,
with the out-of-area and out-of-hours cases and HangUp's corrected timing.
Mom saves a quarter of trainer prizes once asked, talking to her at home
opens BankOfMom (GET, SAVE, CHANGE and the DST checks) with its digit
amount box, and MomTriesToBuySomething buys items and dolls with her
savings. Saves gain Mom's money, her next item and its trigger balance.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:38:22 +02:00

92 lines
2.8 KiB
TypeScript

import { emptyDecorations } from "../src/game/world/decorations";
import { CrystalAssets } from "../src/game/rom/assets";
import { GameWorld } from "../src/game/world/world";
import type { GameMap } from "../src/game/world/types";
/** Synthetic maps and script bytes: these tests run without a private ROM. */
export class MovementAssets extends CrystalAssets {
readonly fixtures = new Map<string, GameMap>();
readonly tiles = new Map<string, number>();
readonly bytes: Uint8Array;
constructor() {
const bytes = new Uint8Array(0xa0000);
bytes[0] = 0x50; // Empty weekday name for synthetic script hosts.
super(bytes);
this.bytes = bytes;
for (const id of ["24:7", "24:6"]) {
this.fixtures.set(id, {
id,
group: 24,
number: Number(id.split(":")[1]),
name: id,
location: id,
landmark: 1,
width: 8,
height: 8,
border: 0,
tileset: 1,
environment: 1,
paletteMode: 1,
phoneService: 0,
blocks: new Uint8Array(16),
warps: [],
backgroundEvents: [],
objects: [],
connections: [],
sceneScripts: [],
callbacks: [],
coordinateEvents: [],
});
}
}
override map(id: string) {
return this.fixtures.get(id)!;
}
override isPorted(id: string) {
return this.fixtures.has(id);
}
override sceneOwner() {
return undefined;
}
override collision(map: GameMap, x: number, y: number) {
if (x < 0 || y < 0 || x >= map.width || y >= map.height) return 7;
return this.tiles.get(`${map.id}:${x},${y}`) ?? 0;
}
/** CollisionPermissionTable in brief: walls, then the water rows
* ($2x, $3x, buoys $cx) apart from ice and the wall-like buoy tiles. */
override permission(collision: number) {
if (collision === 7 || collision === 0x27 || collision === 0x2f) return 15;
if (collision === 0x23 || collision === 0x2b) return 0;
return [0x20, 0x30, 0xc0].includes(collision & 0xf0) ? 1 : 0;
}
override grassCollisions() {
return [];
}
override sprite(id: number) {
return id ? { graphics: new Uint8Array(0), palette: 0, walking: false } : undefined;
}
tile(x: number, y: number, collision: number, map = "24:7") {
this.tiles.set(`${map}:${x},${y}`, collision);
}
}
export function fixture() {
const assets = new MovementAssets();
const world = new GameWorld(
assets,
() => new Date("2026-09-22T12:00:00"),
() => 0,
);
world.state.decorations = emptyDecorations();
return { assets, world };
}
export function connectWarp(assets: MovementAssets, x = 3, y = 4) {
assets.map("24:7").warps.push({ x, y, targetMap: "24:6", targetWarp: 1 });
assets
.map("24:6")
.warps.push({ x: 2, y: 2, targetMap: "24:7", targetWarp: 1 });
assets.tile(2, 2, 0x70, "24:6");
}