mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
aed3bbced7
- 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.
185 lines
7.3 KiB
Lua
185 lines
7.3 KiB
Lua
#!/usr/bin/env luajit
|
|
-- Kanto Town Map & Region Map Unit Test Suite
|
|
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
|
|
local failed = 0
|
|
local function check(cond, msg)
|
|
if cond then
|
|
print("[ok] " .. msg)
|
|
else
|
|
failed = failed + 1
|
|
print("[FAIL] " .. msg)
|
|
end
|
|
end
|
|
|
|
local RegionExtract = require("src.import.gba.region_map_extract")
|
|
local RegionMap = require("src.ui.game3.region_map")
|
|
local ItemUse = require("src.core.game3.item_use")
|
|
local Bag = require("src.core.game3.bag")
|
|
|
|
print("=== [TEST 1] Kanto Map Section Grid Resolution ===")
|
|
do
|
|
-- 1. Pallet Town (x=4, y=11)
|
|
local locPallet = RegionExtract.resolveLocation("PALLET_TOWN", nil)
|
|
check(locPallet.x == 4 and locPallet.y == 11, "Pallet Town resolved to (4, 11)")
|
|
check(locPallet.name == "PALLET TOWN", "Pallet Town name verified")
|
|
|
|
-- 2. Viridian City (x=4, y=8)
|
|
local locViridian = RegionExtract.resolveLocation("VIRIDIAN_CITY", nil)
|
|
check(locViridian.x == 4 and locViridian.y == 8, "Viridian City resolved to (4, 8)")
|
|
check(locViridian.name == "VIRIDIAN CITY", "Viridian City name verified")
|
|
|
|
-- 3. Pewter City (x=4, y=4)
|
|
local locPewter = RegionExtract.resolveLocation("PEWTER_CITY", nil)
|
|
check(locPewter.x == 4 and locPewter.y == 4, "Pewter City resolved to (4, 4)")
|
|
|
|
-- 4. Cerulean City (x=14, y=3)
|
|
local locCerulean = RegionExtract.resolveLocation("CERULEAN_CITY", nil)
|
|
check(locCerulean.x == 14 and locCerulean.y == 3, "Cerulean City resolved to (14, 3)")
|
|
|
|
-- 5. Sub-location / Building (Red's House -> Pallet Town coords)
|
|
local locHouse = RegionExtract.resolveLocation("REDS_HOUSE_1F", nil)
|
|
check(locHouse.x == 4 and locHouse.y == 11, "Red's House maps to Pallet Town coordinates")
|
|
|
|
-- 6. Dungeon (Viridian Forest -> 4, 6)
|
|
local locForest = RegionExtract.resolveLocation("VIRIDIAN_FOREST", "MAPSEC_VIRIDIAN_FOREST")
|
|
check(locForest.x == 4 and locForest.y == 6, "Viridian Forest maps to (4, 6)")
|
|
check(locForest.name == "VIRIDIAN FOREST", "Viridian Forest name verified")
|
|
end
|
|
|
|
print("=== [TEST 2] RegionMap Interactive Cursor Navigation & Landmark Updates ===")
|
|
do
|
|
local closed = false
|
|
local session = { map = "PALLET_TOWN", gender = 0 }
|
|
RegionMap.show({
|
|
session = session,
|
|
onClose = function() closed = true end,
|
|
})
|
|
|
|
check(RegionMap.isOpen() == true, "RegionMap is open")
|
|
check(RegionMap.playerX == 4 and RegionMap.playerY == 11, "player location initialized at Pallet Town (4, 11)")
|
|
check(RegionMap.cursorX == 4 and RegionMap.cursorY == 11, "cursor location initialized at (4, 11)")
|
|
check(RegionMap.currentLocationName() == "PALLET TOWN", "initial landmark name is PALLET TOWN")
|
|
|
|
local function press(btn)
|
|
local inp = {
|
|
wasPressed = function(_, k) return k == btn end,
|
|
isDown = function() return false end,
|
|
}
|
|
RegionMap.handleInput(inp)
|
|
end
|
|
|
|
-- Move UP: (4, 11) -> (4, 10) (Route 1)
|
|
press("up")
|
|
check(RegionMap.cursorX == 4 and RegionMap.cursorY == 10, "cursor moved UP to (4, 10)")
|
|
check(RegionMap.currentLocationName() == "ROUTE 1", "landmark name updated to ROUTE 1")
|
|
|
|
-- Move UP twice: (4, 10) -> (4, 9) -> (4, 8) (Viridian City)
|
|
press("up")
|
|
press("up")
|
|
check(RegionMap.cursorX == 4 and RegionMap.cursorY == 8, "cursor moved UP to (4, 8)")
|
|
check(RegionMap.currentLocationName() == "VIRIDIAN CITY", "landmark name updated to VIRIDIAN CITY")
|
|
|
|
-- Press B to close
|
|
press("b")
|
|
check(RegionMap.isOpen() == false, "RegionMap closed on B button")
|
|
check(closed == true, "onClose callback executed")
|
|
end
|
|
|
|
print("=== [TEST 3] Inventory TOWN_MAP Item Use Integration ===")
|
|
do
|
|
local bag = Bag.new()
|
|
Bag.add(bag, 361, 1) -- Town Map
|
|
local session = { map = "CELADON_CITY", bag = bag }
|
|
|
|
local ok, reason, msg = ItemUse.useField(session, bag, 361, nil)
|
|
check(ok == true, "ItemUse.useField accepts TOWN_MAP (item 361)")
|
|
check(reason == "map", "useField returns 'map' reason")
|
|
check(RegionMap.isOpen() == true, "RegionMap opened via ItemUse")
|
|
check(RegionMap.playerX == 11 and RegionMap.playerY == 6, "player position placed at Celadon City (11, 6)")
|
|
check(RegionMap.currentLocationName() == "CELADON CITY", "Celadon City landmark active")
|
|
RegionMap.close()
|
|
check(RegionMap.isOpen() == false, "RegionMap closed cleanly")
|
|
end
|
|
|
|
print("=== [TEST 4] Start Snapping & Dungeon Guide Modal ===")
|
|
do
|
|
local session = { map = "VIRIDIAN_CITY", gender = 0 }
|
|
RegionMap.show({ session = session })
|
|
|
|
local function press(btn)
|
|
local inp = {
|
|
wasPressed = function(_, k) return k == btn end,
|
|
isDown = function() return false end,
|
|
}
|
|
RegionMap.handleInput(inp)
|
|
end
|
|
|
|
check(RegionMap.cursorX == 4 and RegionMap.cursorY == 8, "cursor at Viridian City (4, 8)")
|
|
|
|
-- Press START: Snaps to Cancel Button (21, 13)
|
|
press("start")
|
|
check(RegionMap.cursorX == 21 and RegionMap.cursorY == 13, "START snapped to Cancel button (21, 13)")
|
|
|
|
-- Press START again: Snaps back to Player Icon (4, 8)
|
|
press("start")
|
|
check(RegionMap.cursorX == 4 and RegionMap.cursorY == 8, "START snapped back to Player Icon (4, 8)")
|
|
|
|
-- Move UP to (4, 6) (Viridian Forest dungeon)
|
|
press("up")
|
|
press("up")
|
|
check(RegionMap.cursorX == 4 and RegionMap.cursorY == 6, "cursor at Viridian Forest (4, 6)")
|
|
check(RegionMap.currentDungeonName() == "VIRIDIAN FOREST", "current dungeon is VIRIDIAN FOREST")
|
|
|
|
-- Press A on dungeon: Opens Dungeon Preview Modal
|
|
press("a")
|
|
check(RegionMap.previewDungeon == "MAPSEC_VIRIDIAN_FOREST", "Dungeon Preview Modal opened for Viridian Forest")
|
|
|
|
-- Press B on modal: Closes Dungeon Preview Modal
|
|
press("b")
|
|
check(RegionMap.previewDungeon == nil, "Dungeon Preview Modal closed on B")
|
|
check(RegionMap.isOpen() == true, "RegionMap still open after closing modal")
|
|
|
|
-- Press B on map: Closes RegionMap
|
|
press("b")
|
|
check(RegionMap.isOpen() == false, "RegionMap closed on B")
|
|
end
|
|
|
|
print("=== [TEST 5] Wall Town Map Metatile & Script Execution ===")
|
|
do
|
|
local Interaction = require("src.core.game3.scripting.interaction_scripts")
|
|
local Std = require("src.core.game3.scripting.stdscripts")
|
|
local CollisionStd = require("src.core.game3.scripting.collision_std")
|
|
|
|
local scriptKey = Interaction.scriptFor(0x85, "up")
|
|
check(scriptKey == "EventScript_WallTownMap", "Behavior 0x85 (MB_TOWN_MAP) maps to EventScript_WallTownMap")
|
|
|
|
local collScript = CollisionStd.scriptFor(0x95)
|
|
check(collScript == "EventScript_WallTownMap", "COLL_TOWN_MAP (0x95) maps to EventScript_WallTownMap")
|
|
|
|
local script = Std.SCRIPTS.EventScript_WallTownMap
|
|
check(script ~= nil, "EventScript_WallTownMap is defined in Std.SCRIPTS")
|
|
check(script[1].op == "lockall", "WallTownMap step 1 is lockall")
|
|
check(script[4].op == "fadescreen", "WallTownMap step 4 is fadescreen")
|
|
check(script[5].op == "special" and script[5].id == Std.SPECIAL.FieldShowRegionMap, "WallTownMap step 5 is special FieldShowRegionMap")
|
|
|
|
local Adapters = require("src.core.game3.scripting.adapters")
|
|
local hostAdapters = Adapters.host(nil, { session = { map = "VIRIDIAN_CITY" } }, nil)
|
|
local mapOpened = false
|
|
hostAdapters.showTownMap(function()
|
|
mapOpened = true
|
|
end)
|
|
check(RegionMap.isOpen() == true, "adapters.showTownMap opens RegionMap")
|
|
RegionMap.close()
|
|
check(RegionMap.isOpen() == false, "RegionMap closed cleanly")
|
|
check(mapOpened == true, "showTownMap callback was executed")
|
|
end
|
|
|
|
if failed > 0 then
|
|
print(string.format("\n[FAILED] %d test(s) failed", failed))
|
|
os.exit(1)
|
|
else
|
|
print("\nALL TOWN MAP & REGION MAP TESTS PASSED CLEANLY!")
|
|
end
|