Files
gen1recomp/tests/game3_multichoice_grid_test.lua
T
1jamie aed3bbced7 fix(game3): battle animation timing, RNG parity, pokedex habitats, multichoice UI and overworld events
- Battle Animation Pipeline:
  * Eliminate 90-frame audio polling stall in anim_vm end/waitsound opcodes,
    allowing attack animations to transition instantly into target hit flicker
    and HP bar drain.
  * Correct visual task counting in AnimVm:visualCount to match pret gAnimVisualTaskCount.
  * Signal bg task completion on restorebg (vm.args[7] = -1).
  * Fix termination conditions on shake tasks (ShakeMon, ShakeMon2, ShakeBattleTerrain),
    WaterSport droplet arcs, and StartSinAnimTimer.
  * Handle RGB555 color args in start_blend_anim_sprite_color and route P.destroyTask
    to AnimTasks.destroy.

- RNG System & Seeding Parity:
  * Replace math.random in Party.giveMon with Rng.Random32() for personality values
    and Rng.Random() for IV bitfield extraction (HP/Atk/Def/Spe/SpA/SpD) matching GBA format.
  * Seed RNG on Title Screen A/Start press via Rng.seedNewGame() (matching SeedRngAndSetTrainerId)
    and perturb RNG state on title menu inputs.
  * Route NPC overworld idle/wander timers and wild encounter slot rolls through Rng.compat.

- Pokédex Habitat & Area Maps:
  * Fix encounter tables extraction and map indexing to resolve Pokemon habitat
    locations across Kanto/Sevii maps rather than showing Area Unknown.
  * Render steady semi-transparent red overlays for Pokédex area map locations.

- Multichoice Menus & UI:
  * Implement multichoice table extraction and data population for Viridian blackboard
    status ailments and special dialog interactions.
  * Improve choice box borders, pagination, and Town Map wall viewing.

- Overworld Events & Flags:
  * Fix Route 1 entrance girl NPC spawning and script triggers after starter selection.
  * Ensure consistent save reload state in Oak's Lab.
2026-09-19 01:30:46 -05:00

101 lines
3.2 KiB
Lua

-- Unit tests for game3 multichoice resolution, grid layout, and navigation
package.path = "./?.lua;./src/?.lua;" .. package.path
local Multi = require("src.core.game3.scripting.multichoice")
local Choice = require("src.ui.game3.choice")
local passed = 0
local failed = 0
local function assert_eq(actual, expected, msg)
if actual == expected then
passed = passed + 1
else
failed = failed + 1
print(string.format("FAIL: %s (expected %s, got %s)", tostring(msg), tostring(expected), tostring(actual)))
end
end
-- 1. Test Multichoice.resolve for list 15 (Trainer School Whiteboard)
local labels15, layout15 = Multi.resolve(15, 6)
assert_eq(#labels15, 6, "List 15 has 6 labels")
assert_eq(labels15[1], "SLP", "List 15 item 1 is SLP")
assert_eq(labels15[2], "PSN", "List 15 item 2 is PSN")
assert_eq(labels15[3], "PAR", "List 15 item 3 is PAR")
assert_eq(labels15[4], "BRN", "List 15 item 4 is BRN")
assert_eq(labels15[5], "FRZ", "List 15 item 5 is FRZ")
assert_eq(labels15[6], "EXIT", "List 15 item 6 is EXIT")
-- 2. Test Multichoice.resolve for list 0 (YES/NO)
local labels0 = Multi.resolve(0, 2)
assert_eq(#labels0, 2, "List 0 has 2 labels")
assert_eq(labels0[1], "YES", "List 0 item 1 is YES")
assert_eq(labels0[2], "NO", "List 0 item 2 is NO")
-- 3. Test Choice module 2D Grid navigation (3 columns, 2 rows)
local result = nil
Choice.multi(labels15, 0, function(sel)
result = sel
end, { cols = 3, left = 7, top = 1 })
assert_eq(Choice.active, true, "Choice is active")
assert_eq(Choice.cursor, 1, "Cursor starts at 1 (SLP)")
-- Move Right: 1 -> 2 (PSN)
Choice.move(0, 1)
assert_eq(Choice.cursor, 2, "Move Right -> PSN (2)")
-- Move Right: 2 -> 3 (PAR)
Choice.move(0, 1)
assert_eq(Choice.cursor, 3, "Move Right -> PAR (3)")
-- Move Right: 3 wraps to 1 (SLP) in column space
Choice.move(0, 1)
assert_eq(Choice.cursor, 1, "Move Right wraps -> SLP (1)")
-- Move Down: 1 -> 4 (BRN)
Choice.move(1, 0)
assert_eq(Choice.cursor, 4, "Move Down -> BRN (4)")
-- Move Right: 4 -> 5 (FRZ)
Choice.move(0, 1)
assert_eq(Choice.cursor, 5, "Move Right -> FRZ (5)")
-- Move Right: 5 -> 6 (EXIT)
Choice.move(0, 1)
assert_eq(Choice.cursor, 6, "Move Right -> EXIT (6)")
-- Move Down: 6 -> 3 (PAR) (row wraps)
Choice.move(1, 0)
assert_eq(Choice.cursor, 3, "Move Down wraps row -> PAR (3)")
-- Move Up: 3 -> 6 (EXIT) (row wraps back)
Choice.move(-1, 0)
assert_eq(Choice.cursor, 6, "Move Up wraps row back -> EXIT (6)")
-- Confirm selection of EXIT (index 6 -> result 5)
Choice.confirm()
assert_eq(Choice.active, false, "Choice is no longer active after confirm")
assert_eq(result, 5, "Result is 5 for EXIT")
-- 4. Test Choice cancel (B press returns 127)
local cancelResult = nil
Choice.multi(labels15, 0, function(sel)
cancelResult = sel
end, { cols = 3 })
Choice.cancel()
assert_eq(cancelResult, 127, "Cancel returns 127")
-- 5. Test ignoreBPress
local ignoreResult = nil
Choice.multi(labels15, 0, function(sel)
ignoreResult = sel
end, { cols = 3, ignoreBPress = true })
Choice.cancel()
assert_eq(Choice.active, true, "Choice remains active when ignoreBPress is true")
Choice.confirm()
assert_eq(ignoreResult, 0, "Confirm picked item 0")
print(string.format("Multichoice Grid Tests: %d passed, %d failed", passed, failed))
if failed > 0 then os.exit(1) end