Checks / web (push) Canceled after 0s
Port forced movement (turn delays, bumps, ice, currents, pits), dynamic return warps, elevators, Surf, Cut, Strength and cycling rules, working map blocks with changeblock/changemapblocks, and the remaining NPC movement types and movement commands. Add tileset animation from the ROM's command tables, grass sprite priority and special map palettes; room decorations with ownership, the bedroom PC and save migration; and Key Items access to the Bicycle. Fourteen original-engine traces compare positions, facing, actors, event flags and scripted poses. Tile animation matches original VRAM for four tilesets, and LoadMapPals matches 192 palette cases. skyfall_top now keeps the $60 sprite offset its step function leaves behind. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
88 lines
3.3 KiB
TypeScript
88 lines
3.3 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { existsSync, readFileSync } from "node:fs";
|
|
import { drawTile } from "../src/game/rendering/pixels";
|
|
import { TilesetAnimator } from "../src/game/rendering/tileset-animation";
|
|
import { CrystalAssets } from "../src/game/rom/assets";
|
|
import { OW } from "../src/game/world/constants";
|
|
import type { Palette } from "../src/game/world/types";
|
|
|
|
it("grass priority uses background indices, preserving transparent sprite pixels", () => {
|
|
const palette: Palette = [
|
|
[255, 255, 255],
|
|
[80, 160, 80],
|
|
[32, 64, 32],
|
|
[0, 0, 0],
|
|
];
|
|
const target = new Uint8ClampedArray(8 * 8 * 4);
|
|
const indices = new Uint8Array(8 * 8);
|
|
const background = new Uint8Array(16);
|
|
background[0] = 0x80; // Colored grass at x=0; color zero elsewhere.
|
|
drawTile(target, 8, 8, background, 0, 0, 0, palette, { indices });
|
|
const sprite = new Uint8Array(16);
|
|
sprite[1] = 0xc0; // Sprite color 2 at x=0 and x=1, transparent at x=2.
|
|
drawTile(target, 8, 8, sprite, 0, 0, 0, palette, {
|
|
indices,
|
|
behind: true,
|
|
transparent: true,
|
|
});
|
|
expect([...target.slice(0, 12)]).toEqual([
|
|
80, 160, 80, 255, 32, 64, 32, 255, 255, 255, 255, 255,
|
|
]);
|
|
expect([...indices.slice(0, 3)]).toEqual([1, 0, 0]);
|
|
drawTile(target, 8, 8, sprite, 0, 0, 0, palette, {
|
|
indices,
|
|
transparent: true,
|
|
});
|
|
expect([...target.slice(0, 4)]).toEqual([32, 64, 32, 255]);
|
|
});
|
|
|
|
const romPath =
|
|
process.env.CRYSTAL_ROM_PATH ??
|
|
"Pokemon - Crystal Version (UE) (V1.1) [C][!].gbc";
|
|
describe.skipIf(!existsSync(romPath))(
|
|
"overworld rendering with the local ROM",
|
|
() => {
|
|
it("runs every tileset animation without changing the cached ROM graphics", () => {
|
|
const assets = new CrystalAssets(new Uint8Array(readFileSync(romPath)));
|
|
const base = assets.map("24:4");
|
|
for (let tileset = 1; tileset <= OW.NUM_TILESETS; tileset++) {
|
|
const map = { ...base, tileset };
|
|
const graphics = assets.tileset(map).graphics;
|
|
const original = graphics.slice();
|
|
const animator = new TilesetAnimator(assets, map, graphics);
|
|
animator.advance(1024, false);
|
|
animator.advance(1024, true);
|
|
expect(graphics, `tileset ${tileset}`).toEqual(original);
|
|
expect(animator.graphics.length).toBe(original.length);
|
|
}
|
|
});
|
|
|
|
it("keeps special indoor palettes fixed and uses normal palettes for the Hall of Fame", () => {
|
|
const assets = new CrystalAssets(new Uint8Array(readFileSync(romPath)));
|
|
const base = assets.map("24:6");
|
|
for (const tileset of [
|
|
OW.TILESET_POKECOM_CENTER,
|
|
OW.TILESET_BATTLE_TOWER_INSIDE,
|
|
OW.TILESET_HOUSE,
|
|
OW.TILESET_RADIO_TOWER,
|
|
OW.TILESET_MANSION,
|
|
]) {
|
|
const map = { ...base, tileset };
|
|
expect(assets.palettes(map, 0)).toEqual(assets.palettes(map, 2));
|
|
expect(assets.palettes(map, 0)).toHaveLength(8);
|
|
}
|
|
const ice = {
|
|
...base,
|
|
tileset: OW.TILESET_ICE_PATH,
|
|
environment: OW.CAVE,
|
|
};
|
|
expect(assets.palettes(ice, 0)).toEqual(assets.palettes(ice, 2));
|
|
const hall = { ...ice, environment: OW.INDOOR };
|
|
expect(assets.palettes(hall, 1)).not.toEqual(assets.palettes(ice, 1));
|
|
expect(assets.palettes(hall, 1)).toEqual(
|
|
assets.palettes({ ...hall, tileset: OW.TILESET_POKECENTER }, 1),
|
|
);
|
|
});
|
|
},
|
|
);
|