Run the forced-shiny, trap, forced-item, Celebi, Suicune, roaming and Bug-Catching Contest battle types. Roaming battles keep their struct's DVs and HP byte, and every other battle makes CleanUpBattleRAM's roaming roll. The contest shows PARKBALL×, counts down Park Balls, ends when they run out, keeps its catch outside the party and asks before switching. Scripts load the special types with loadvar, and while a contest runs, encounters use BugCatchingContestBattleScript and ContestMons. Validated with 596 unit tests, 155 browser tests (including the contest menu and switch screen), native/reference builds and reference/vendor/release checks. National Park's contest event, the roaming release and the Ilex Forest Celebi event come with their maps. Closes #28 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b547ca29ff
commit
8fae1f0c0f
15 files changed
+787
-42
No files matched your search
@@ -34,6 +34,18 @@ async function start(page: Page, scenario: BattleScenario = "win") {
|
||||
await page.keyboard.up(key);
|
||||
await page.clock.runFor(300);
|
||||
}
|
||||
if (scenario === "contest") {
|
||||
// The contest's 20% roll: pace on and off the test grass.
|
||||
for (let step = 0; step < 100 && !(await page.locator("#battle").isVisible()); step++) {
|
||||
const key = step % 2 ? "ArrowRight" : "ArrowLeft";
|
||||
await page.keyboard.down(key);
|
||||
await page.clock.runFor(250);
|
||||
await page.keyboard.up(key);
|
||||
await page.clock.runFor(300);
|
||||
}
|
||||
await expect(page.locator("#battle")).toBeVisible();
|
||||
return;
|
||||
}
|
||||
await expect(page.locator("#battle")).toBeVisible();
|
||||
await expect(page.locator("#battle-foe-name")).toHaveText("PIDGEY");
|
||||
}
|
||||
@@ -300,3 +312,34 @@ test("battle PKMN STATS shows the stats screen's three pages and returns with B"
|
||||
// BattleMenuPKMN_ReturnFromStats: back to the party menu.
|
||||
await expect(menu.getByRole("button", { name: /^CYNDAQUIL/ })).toBeVisible();
|
||||
});
|
||||
|
||||
test("throws Park Balls from the contest menu and switches the stocked Pokémon", async ({ page }) => {
|
||||
await start(page, "contest");
|
||||
const menu = page.locator("#battle-menu");
|
||||
let balls = 20,
|
||||
switched = false;
|
||||
const texts: string[] = [];
|
||||
for (let guard = 0; guard < 200 && (await page.locator("#battle").isVisible()); guard++) {
|
||||
texts.push(await page.locator("#battle-text").innerText());
|
||||
const ball = menu.getByRole("button", { name: /^PARKBALL×\d\d$/ });
|
||||
if (await ball.count()) {
|
||||
// ContestBattleMenu replaces PACK, with the count in two digits.
|
||||
await expect(ball).toHaveText(`PARKBALL×${String(balls).padStart(2, "0")}`);
|
||||
await expect(menu.getByRole("button", { name: "PACK" })).toHaveCount(0);
|
||||
await ball.click();
|
||||
balls--;
|
||||
} else if (await menu.getByRole("button", { name: /^STOCK SCYTHER :L14/ }).count()) {
|
||||
await expect(menu.getByRole("button", { name: /^THIS / })).toBeVisible();
|
||||
await expect(page.locator("#battle-text")).toContainText("Switch");
|
||||
// The cursor skips the two boxes: down to NO, back up to YES, then A.
|
||||
await page.keyboard.press("ArrowDown");
|
||||
await page.keyboard.press("ArrowUp");
|
||||
await page.keyboard.press("KeyX");
|
||||
switched = true;
|
||||
} else if (await menu.getByRole("button", { name: /Continue/ }).count())
|
||||
await menu.getByRole("button", { name: /Continue/ }).click();
|
||||
else await page.clock.runFor(1200);
|
||||
}
|
||||
expect(switched, texts.join(" | ")).toBe(true);
|
||||
expect(texts.join(" ").replace(/\n/g, " ")).toMatch(/Caught [A-Z]+!/);
|
||||
});
|
||||
Reference in new issue
Block a user