Port Headbutt and Rock Smash encounters

Facing a Headbutt tree asks to HEADBUTT it, and HEADBUTT from the party
menu skips the question. ShakeHeadbuttTree shakes the tree as a sprite over
grass, then TreeMonEncounter scores the facing tile against the trainer ID
and draws from the map's common or rare tree table. A Pokémon that falls
fights as BATTLETYPE_TREE: "fell out of the tree!", and the time of day's
AsleepTreeMons species start asleep.

Smashable rocks run SmashRockScript, and ROCK SMASH from the party menu
acts on the facing rock; after the rock breaks, RockMonEncounter gives the
map's rock set a 40% chance of a wild battle.

Closes #26

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Sébastien QUEROLandClaude Opus 5.5 committed 2026-10-02 12:20:13 +02:00
1 parent ee55d344af
commit f259163da9
18 files changed
+789 -36

No files matched your search

+28 -1
View File
@@ -18,7 +18,8 @@ async function start(
| "candy"
| "pokegear"
| "mom"
| "fly" = false,
| "fly"
| "headbutt" = false,
) {
await page.route("**/src/game/runtime.ts", async (route) => {
const response = await route.fetch(),
@@ -480,6 +481,32 @@ test("Fly picks a visited town on the Fly map and lands there", async ({
expect([state.map, state.x, state.y]).toEqual(["26:3", 29, 4]);
});
test("Headbutt shakes a tree and a sleeping Hoothoot falls out", async ({
page,
}) => {
await start(page, "headbutt");
const text = page.locator("#dialogue-text"),
choices = page.locator("#dialogue-choice"),
screen = page.locator("#game-screen");
await page.keyboard.press("KeyX");
await expect(text).toHaveText(/A POKéMON could be\s+in this tree\./);
await page.keyboard.press("KeyX");
await expect(text).toHaveText(/Want to HEADBUTT\s+it\?/);
await choices.getByRole("button", { name: "YES" }).click();
await expect(text).toHaveText(/TOTODILE did a\s+HEADBUTT!/);
await page.keyboard.press("KeyX");
await expect(page.locator("#native-dialogue")).toBeHidden();
await page.clock.runFor(5_000);
await expect(page.locator("#battle")).toBeVisible();
await expect(page.locator("#battle-text")).toHaveText(
/HOOTHOOT fell\s+out of the tree!/,
);
await expect(page.locator("#battle-foe-name")).toHaveText("HOOTHOOT");
await expect(page.locator("#battle-foe-status")).toHaveText("SLP");
await expect(page.locator("#game-notice")).toHaveText("");
await expect(screen).toHaveAttribute("data-map", "24:3");
});
test("Mom keeps the player's money with the digit box", async ({ page }) => {
await start(page, "mom");
const text = page.locator("#dialogue-text"),