mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 05:32:07 -04:00
220 lines
8.0 KiB
Lua
220 lines
8.0 KiB
Lua
#!/usr/bin/env luajit
|
|
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
require("tests.fixture_data.game3_items").install()
|
|
require("tests.fixture_data.game3_map_sections").install()
|
|
package.loaded["src.core.game3.rom_text"] = {
|
|
plain = function(key) return key end, box = function(key) return key end,
|
|
ascii = function(key) return key end, has = function() return true end,
|
|
key = function(n, i, j) return j and (n .. "[" .. i .. "][" .. j .. "]") or (n .. "[" .. i .. "]") end,
|
|
at = function(n, i, j) return j and (n .. "[" .. i .. "][" .. j .. "]") or (n .. "[" .. i .. "]") end,
|
|
count = function() return 0 end, list = function() return {} end,
|
|
lazy = function(map) return setmetatable({}, { __index = function(_, k) return map[k] end }) end,
|
|
}
|
|
|
|
local failed = 0
|
|
local function check(cond, msg)
|
|
if cond then
|
|
print("[ok] " .. msg)
|
|
else
|
|
failed = failed + 1
|
|
print("[FAIL] " .. msg)
|
|
end
|
|
end
|
|
|
|
local SE_SELECT, SE_WIN_OPEN, SE_EXIT, SE_FAILURE, SE_SHOP = 5, 6, 9, 26, 248
|
|
|
|
local played = {}
|
|
package.loaded["src.core.game3.audio"] = {
|
|
playSe = function(id) played[#played + 1] = id end,
|
|
playSong = function() end,
|
|
playFanfare = function() end,
|
|
stopAll = function() end,
|
|
waitSe = function(_, cb) if cb then cb() end end,
|
|
}
|
|
package.loaded["src.ui.game3.stack"] = {
|
|
push = function() end,
|
|
pop = function() end,
|
|
contains = function() return false end,
|
|
top = function() return nil end,
|
|
}
|
|
|
|
print("[test] 1. Start menu close plays SE_SELECT (start_menu.c:1005)")
|
|
local StartMenu = require("src.ui.game3.start_menu")
|
|
played = {}
|
|
StartMenu.close()
|
|
check(#played == 1 and played[1] == SE_SELECT,
|
|
"StartMenu.close -> SE_SELECT only (got " .. table.concat(played, ",") .. ")")
|
|
|
|
print("[test] 2. Backing out of the EXIT confirm with B is silent (menu.c:381)")
|
|
StartMenu._confirmExit = true
|
|
played = {}
|
|
StartMenu.cancel()
|
|
check(#played == 0, "StartMenu.cancel on confirm -> silence (got " .. table.concat(played, ",") .. ")")
|
|
|
|
print("[test] 3. Save dialog opens silently (start_menu.c:518)")
|
|
local SaveMenu = require("src.ui.game3.save_menu")
|
|
played = {}
|
|
SaveMenu.show({})
|
|
check(#played == 0, "SaveMenu.show -> silence (got " .. table.concat(played, ",") .. ")")
|
|
|
|
print("[test] 4. Save dialog NO plays SE_SELECT, B is silent (menu.c:373/381)")
|
|
SaveMenu.show({})
|
|
SaveMenu.cursor = 2
|
|
played = {}
|
|
SaveMenu.confirm()
|
|
check(#played == 1 and played[1] == SE_SELECT,
|
|
"SaveMenu NO -> SE_SELECT only (got " .. table.concat(played, ",") .. ")")
|
|
SaveMenu.show({})
|
|
played = {}
|
|
SaveMenu.cancel()
|
|
check(#played == 0, "SaveMenu B press -> silence (got " .. table.concat(played, ",") .. ")")
|
|
|
|
print("[test] 4b. Dismissing the saved message is silent (start_menu.c:583)")
|
|
StartMenu.open = true
|
|
SaveMenu.show({})
|
|
SaveMenu._phase = "saved"
|
|
played = {}
|
|
SaveMenu.confirm()
|
|
check(#played == 0, "SaveMenu saved-phase A -> silence (got " .. table.concat(played, ",") .. ")")
|
|
check(StartMenu.open == false, "saved-phase dismissal still tears the start menu down")
|
|
StartMenu.open = true
|
|
SaveMenu.show({})
|
|
SaveMenu._phase = "saved"
|
|
played = {}
|
|
SaveMenu.cancel()
|
|
check(#played == 0, "SaveMenu saved-phase B -> silence (got " .. table.concat(played, ",") .. ")")
|
|
StartMenu.open = false
|
|
|
|
print("[test] 5. Shop menu opens silently and quits with SE_SELECT (shop.c:213/265)")
|
|
local ShopMenu = require("src.ui.game3.shop_menu")
|
|
played = {}
|
|
ShopMenu.show({ items = {}, session = {} })
|
|
check(#played == 0, "ShopMenu.show -> silence (got " .. table.concat(played, ",") .. ")")
|
|
played = {}
|
|
ShopMenu.close()
|
|
check(#played == 0, "ShopMenu.close -> silence (the A/B press sounds, not the teardown)")
|
|
|
|
print("[test] 5b. Purchase YES plays SE_SELECT, SE_SHOP follows the message (shop.c:999)")
|
|
local function shop_input(map)
|
|
return { wasPressed = function(_, k) return map[k] == true end,
|
|
isDown = function(_, k) return map[k] == true end }
|
|
end
|
|
local Bag = require("src.core.game3.bag")
|
|
local shopSession = { money = 5000, bag = Bag.new() }
|
|
ShopMenu.show({ items = { 4 }, session = shopSession })
|
|
ShopMenu.mode = "buy_confirm"
|
|
ShopMenu._pending = { id = 4, price = 200, name = "POKe BALL" }
|
|
ShopMenu.qty = 1
|
|
ShopMenu.yesNoCursor = 1
|
|
played = {}
|
|
ShopMenu.handleInput(shop_input({ a = true }))
|
|
check(ShopMenu.mode == "buy_msg" and shopSession.money == 4800, "purchase committed")
|
|
check(#played == 1 and played[1] == SE_SELECT,
|
|
"YES frame -> SE_SELECT only (got " .. table.concat(played, ",") .. ")")
|
|
local waited = 0
|
|
while #played == 1 and waited < 600 do
|
|
ShopMenu.handleInput(shop_input({}))
|
|
waited = waited + 1
|
|
end
|
|
check(#played == 2 and played[2] == SE_SHOP and waited > 1,
|
|
"SE_SHOP lands " .. waited .. " frames later (got " .. table.concat(played, ",") .. ")")
|
|
played = {}
|
|
ShopMenu.handleInput(shop_input({ a = true }))
|
|
check(ShopMenu.mode == "buy" and #played == 1 and played[1] == SE_SELECT,
|
|
"message dismissal -> SE_SELECT only (got " .. table.concat(played, ",") .. ")")
|
|
ShopMenu.mode = "buy_confirm"
|
|
ShopMenu._pending = { id = 4, price = 200, name = "POKe BALL" }
|
|
ShopMenu.qty = 1
|
|
ShopMenu.yesNoCursor = 1
|
|
ShopMenu.handleInput(shop_input({ a = true }))
|
|
played = {}
|
|
ShopMenu.handleInput(shop_input({ a = true }))
|
|
check(ShopMenu.mode == "buy" and #played == 1 and played[1] == SE_SHOP,
|
|
"early dismissal still plays SE_SHOP exactly once (got " .. table.concat(played, ",") .. ")")
|
|
ShopMenu.close()
|
|
|
|
print("[test] 6. Generic yes/no cancel plays SE_SELECT (menu_helpers.c:57)")
|
|
local Choice = require("src.ui.game3.choice")
|
|
Choice.active = true
|
|
Choice.kind = "yesno"
|
|
Choice.options = { "YES", "NO" }
|
|
Choice.cursor = 1
|
|
Choice.ignoreBPress = false
|
|
Choice.done = nil
|
|
played = {}
|
|
Choice.cancel()
|
|
check(#played == 1 and played[1] == SE_SELECT,
|
|
"Choice.cancel -> SE_SELECT only (got " .. table.concat(played, ",") .. ")")
|
|
|
|
print("[test] 7. No game3 UI source plays SE_EXIT")
|
|
local UI_SOURCES = {
|
|
"src/ui/game3/start_menu.lua",
|
|
"src/ui/game3/save_menu.lua",
|
|
"src/ui/game3/shop_menu.lua",
|
|
"src/ui/game3/choice.lua",
|
|
"src/ui/game3/bag_menu.lua",
|
|
"src/ui/game3/party_menu.lua",
|
|
"src/ui/game3/berry_pouch.lua",
|
|
"src/ui/game3/tm_case.lua",
|
|
"src/ui/game3/box_storage_ui.lua",
|
|
"src/ui/game3/pc_menu.lua",
|
|
"src/ui/game3/summary_menu.lua",
|
|
"src/ui/game3/region_map.lua",
|
|
"src/ui/game3/release_seq.lua",
|
|
}
|
|
for _, path in ipairs(UI_SOURCES) do
|
|
local f = io.open(path, "r")
|
|
if not f then
|
|
check(false, "missing source " .. path)
|
|
else
|
|
local src = f:read("*a")
|
|
f:close()
|
|
local hits = {}
|
|
local lineNo = 0
|
|
for line in (src .. "\n"):gmatch("([^\n]*)\n") do
|
|
lineNo = lineNo + 1
|
|
local code = line:gsub("%-%-.*$", "")
|
|
if code:find("se%(9%)") or code:find("playSe%(%s*9%s*%)") or code:find("SE_EXIT") then
|
|
hits[#hits + 1] = tostring(lineNo)
|
|
end
|
|
end
|
|
check(#hits == 0, path .. " has no SE_EXIT site (lines " .. table.concat(hits, ",") .. ")")
|
|
end
|
|
end
|
|
|
|
print("[test] 8. SE_EXIT still owned by the warp/door path (field_fadetransition.c:541)")
|
|
for _, path in ipairs({ "src/core/game3/warp.lua", "src/core/game3/doors.lua" }) do
|
|
local f = assert(io.open(path, "r"))
|
|
local src = f:read("*a")
|
|
f:close()
|
|
check(src:find("SE_EXIT") ~= nil, path .. " still references SE_EXIT")
|
|
end
|
|
|
|
print("[test] 9. One-shot SEs bake to their natural end (battle_anim_special.c:1200)")
|
|
local captured = nil
|
|
package.loaded["src.core.game3.m4a_player"] = {
|
|
mixQuantum = function() return 256 end,
|
|
loadPack = function() return {} end,
|
|
songInfo = function(_, id) return { kind = "se", player = 2, hasGoto = false, id = id } end,
|
|
start = function() return true end,
|
|
bakeSlot = function(_, opts) captured = opts; return { 0 }, { 0 } end,
|
|
renderBuffered = function() return {}, {} end,
|
|
updateSlot = function() end,
|
|
}
|
|
package.loaded["src.core.game3.audio"] = nil
|
|
local Audio = require("src.core.game3.audio")
|
|
Audio._ready = true
|
|
Audio._pack = {}
|
|
Audio.playSe(319)
|
|
check(captured ~= nil, "playSe reached Player.bakeSlot")
|
|
check(captured and captured.maxSec and captured.maxSec >= 4.6,
|
|
"MUS_CAUGHT_INTRO bake ceiling covers the full cue (maxSec = "
|
|
.. tostring(captured and captured.maxSec) .. ")")
|
|
|
|
if failed > 0 then
|
|
print(string.format("\n%d check(s) failed", failed))
|
|
os.exit(1)
|
|
end
|
|
print("\nall menu SFX checks passed")
|