mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-28 23:00:21 -04:00
277 lines
11 KiB
Lua
277 lines
11 KiB
Lua
local U = require("tests.drivers.util")
|
|
local DIR = os.getenv("POKEPORT_SHOT_DIR") or "/tmp/em_new_game"
|
|
|
|
return function(game)
|
|
local ok = true
|
|
local function check(c, label)
|
|
print((c and "PASS " or "FAIL ") .. label)
|
|
if not c then ok = false end
|
|
end
|
|
local function finish()
|
|
love.event.quit(ok and 0 or 1)
|
|
U.wait(10)
|
|
end
|
|
|
|
for _ = 1, 900 do
|
|
if game.phase == "boot" and game.boot then break end
|
|
U.wait(1)
|
|
end
|
|
check(game.boot ~= nil, "boot reached")
|
|
if not game.boot then return finish() end
|
|
|
|
local Boot = require("src.ui.game3.boot")
|
|
local MainMenu = require("src.ui.game3.rse.main_menu_rse")
|
|
local Birch = require("src.ui.game3.rse.birch_speech")
|
|
local Truck = require("src.core.game3.truck_sequence")
|
|
local Options = require("src.core.game3.options")
|
|
|
|
if os.getenv("EM_NG_TIMING") == "1" then
|
|
local textSpeed0 = Options.block(game.options).textSpeed
|
|
local b = Birch.new({ textSpeed = textSpeed0 })
|
|
local marks, seen = {}, {}
|
|
local function mark(name, f)
|
|
if not seen[name] then
|
|
seen[name] = true
|
|
marks[#marks + 1] = string.format("%s=%d", name, f)
|
|
end
|
|
end
|
|
b.onEvent = mark
|
|
local firstPress, period = tonumber(os.getenv("EM_NG_FIRST") or "39"), 60
|
|
for f = 1, 8000 do
|
|
local new, held = {}, {}
|
|
local k = f - firstPress
|
|
if k >= 0 and k % period == 0 then new.a, held.a = true, true end
|
|
if k >= 1 and (k - 1) % period == 0 then held.a = true end
|
|
local r = b:frame({ new = new, held = held, rep = new })
|
|
if b.ball and not b.ball.invisible then mark("ball_visible", f) end
|
|
if b.genderMenu then mark("gender_menu_visible", f) end
|
|
if b.naming and b.naming.stage == "input" then mark("naming_input", f) end
|
|
if b.yesNo then mark("yes_no_visible", f) end
|
|
if r then
|
|
mark("result", f)
|
|
break
|
|
end
|
|
end
|
|
print("[driver] timing (port GBA frames from Init=1, A every 60 from " .. firstPress .. "): "
|
|
.. table.concat(marks, " "))
|
|
print("[driver] timing name=" .. tostring(b.playerName) .. " gender=" .. tostring(b.gender))
|
|
if b.naming then b:destroy() end
|
|
return finish()
|
|
end
|
|
|
|
local okMods, BootModules = pcall(require, "src.ui.game3.boot_modules")
|
|
local realPath = okMods and type(BootModules) == "table"
|
|
print("[driver] boot modules resolver " .. (realPath and "present" or "absent (driver hosts the rse screens)"))
|
|
|
|
local host = { screen = nil, result = nil, events = {} }
|
|
local origUpdate, origDraw = Boot.update, Boot.draw
|
|
|
|
local demo = MainMenu.new({
|
|
hasContinue = true, saveStatus = "ok",
|
|
continueInfo = { name = "MAY", gender = 1, hours = 12, minutes = 34, hasDex = true, dexCount = 27,
|
|
badges = 3, mysteryGift = true, frameType = 0 },
|
|
})
|
|
Boot.draw = function() demo:draw() end
|
|
demo.pal = require("src.core.game3.pal_fade").new()
|
|
demo.state = "input"
|
|
U.still(game, DIR .. "/00a_main_menu_continue_gift.png")
|
|
check(#demo.items == 5 and demo.items[5] == "EXIT", "gift menu: CONTINUE/NEW GAME/MYSTERY GIFT/OPTION/EXIT")
|
|
demo.cursor = 5
|
|
demo:_fixScroll()
|
|
U.still(game, DIR .. "/00b_main_menu_scrolled_exit.png")
|
|
check(demo.scroll > 0, "EXIT row scrolls into view")
|
|
Boot.draw = origDraw
|
|
local textSpeed = Options.block(game.options).textSpeed
|
|
local routed = realPath and game.boot.custom ~= nil
|
|
if routed then
|
|
print("[driver] routing through BootModules (boot.lua custom state)")
|
|
BootModules.startMenu(Boot, game.boot)
|
|
host.screen = game.boot.custom.menu
|
|
host.kind = "menu"
|
|
Boot.update = function(state, input, dt)
|
|
local r = origUpdate(state, input, dt)
|
|
local c = state.custom
|
|
if c and c.newGame and host.kind ~= "birch" then
|
|
host.screen = c.newGame
|
|
host.screen.onEvent = function(name, f) host.events[#host.events + 1] = { name = name, frame = f } end
|
|
host.kind = "birch"
|
|
end
|
|
if r and host.kind == "birch" then host.result = r end
|
|
return r
|
|
end
|
|
else
|
|
host.screen = MainMenu.new({ hasContinue = false, saveStatus = "ok", textSpeed = textSpeed, game = game })
|
|
host.kind = "menu"
|
|
Boot.update = function(_, input, dt)
|
|
local r = host.screen:update(input, dt)
|
|
if r == "newGame" and host.kind == "menu" then
|
|
host.screen = Birch.new({ textSpeed = textSpeed })
|
|
host.screen.onEvent = function(name, f) host.events[#host.events + 1] = { name = name, frame = f } end
|
|
host.kind = "birch"
|
|
return nil
|
|
end
|
|
if r and host.kind == "birch" then
|
|
host.result = r
|
|
return r
|
|
end
|
|
return nil
|
|
end
|
|
Boot.draw = function() host.screen:draw() end
|
|
end
|
|
|
|
U.wait(40)
|
|
U.still(game, DIR .. "/01_main_menu_no_save.png")
|
|
check(host.screen.items[#host.screen.items] == "EXIT", "main menu shows a visible EXIT row")
|
|
U.tap(game, "a")
|
|
for _ = 1, 200 do
|
|
if host.kind == "birch" then break end
|
|
U.wait(1)
|
|
end
|
|
check(host.kind == "birch", "NEW GAME opens the Birch speech")
|
|
local birch = host.screen
|
|
local function waitFunc(name, limit)
|
|
for _ = 1, limit or 3000 do
|
|
if birch.main.func == name then return true end
|
|
U.wait(1)
|
|
end
|
|
return false
|
|
end
|
|
local function waitEvent(name, limit)
|
|
for _ = 1, limit or 3000 do
|
|
for _, e in ipairs(host.events) do if e.name == name then return e end end
|
|
U.wait(1)
|
|
end
|
|
return nil
|
|
end
|
|
|
|
check(waitEvent("birch_fade_in", 600) ~= nil, "Birch fades in")
|
|
U.wait(30)
|
|
U.still(game, DIR .. "/02_birch_appears.png")
|
|
check(waitFunc("ThisIsAPokemon", 800), "welcome text")
|
|
U.still(game, DIR .. "/03_welcome_text.png")
|
|
for _ = 1, 3000 do
|
|
if birch.ball then break end
|
|
if birch.printer and (birch.printer.state == "clear" or birch.printer.state == "scroll_start") then U.tap(game, "a") end
|
|
U.wait(1)
|
|
end
|
|
local rel = waitEvent("lotad_release", 200)
|
|
check(rel ~= nil, "Poke Ball releases Lotad")
|
|
U.wait(6)
|
|
U.still(game, DIR .. "/04_lotad_release.png")
|
|
check(waitEvent("lotad_cry", 200) ~= nil, "Lotad lands and cries")
|
|
U.wait(20)
|
|
U.still(game, DIR .. "/05_lotad_out.png")
|
|
|
|
for _ = 1, 4000 do
|
|
if birch.main.func == "ChooseGender" then break end
|
|
if birch.printer and (birch.printer.state == "clear" or birch.printer.state == "scroll_start") then U.tap(game, "a") end
|
|
U.wait(1)
|
|
end
|
|
check(birch.main.func == "ChooseGender", "gender menu reached")
|
|
U.wait(4)
|
|
U.still(game, DIR .. "/06_gender_menu_boy.png")
|
|
U.tap(game, "down")
|
|
check(waitEvent("gender_slide", 30) ~= nil, "gender slide starts")
|
|
U.wait(12)
|
|
U.still(game, DIR .. "/07_gender_slide.png")
|
|
check(waitFunc("ChooseGender", 200), "slide finished")
|
|
U.still(game, DIR .. "/08_may_selected.png")
|
|
U.tap(game, "a")
|
|
check(waitEvent("chose_girl", 30) ~= nil, "girl chosen")
|
|
for _ = 1, 2000 do
|
|
if birch.main.func == "WaitPressBeforeNameChoice" then break end
|
|
U.wait(1)
|
|
end
|
|
U.tap(game, "a")
|
|
for _ = 1, 400 do
|
|
if birch.naming and birch.naming.stage == "input" then break end
|
|
U.wait(1)
|
|
end
|
|
check(birch.naming ~= nil and birch.naming.stage == "input", "naming screen open")
|
|
U.wait(10)
|
|
U.still(game, DIR .. "/09_naming.png")
|
|
local preset = birch.playerName
|
|
for _, k in ipairs({ "a", "right", "a" }) do
|
|
U.tap(game, k)
|
|
U.wait(3)
|
|
end
|
|
U.tap(game, "start")
|
|
U.wait(3)
|
|
U.still(game, DIR .. "/10_naming_typed.png")
|
|
U.tap(game, "a")
|
|
check(waitEvent("naming_return", 400) ~= nil, "back from naming")
|
|
print("[driver] preset " .. tostring(preset) .. " typed name " .. tostring(birch.playerName)
|
|
.. " trainerIdLower " .. tostring(birch.trainerIdLower))
|
|
check(birch.playerName == "AB", "typed name kept")
|
|
check(type(birch.trainerIdLower) == "number", "trainer id seeded from naming timer")
|
|
check(waitFunc("ProcessNameYesNoMenu", 600), "name yes/no")
|
|
U.still(game, DIR .. "/11_name_yes_no.png")
|
|
U.tap(game, "a")
|
|
check(waitEvent("name_confirmed", 60) ~= nil, "name confirmed")
|
|
for _ = 1, 3000 do
|
|
if birch.main.func == "WaitForPlayerShrink" then break end
|
|
if birch.printer and (birch.printer.state == "clear" or birch.printer.state == "scroll_start") then U.tap(game, "a") end
|
|
U.wait(1)
|
|
end
|
|
check(birch.main.func == "WaitForPlayerShrink", "shrink starts")
|
|
U.wait(24)
|
|
U.still(game, DIR .. "/12_shrink.png")
|
|
check(waitEvent("white_fade_start", 200) ~= nil, "fade player to white")
|
|
U.wait(8)
|
|
U.still(game, DIR .. "/13_white_fade.png")
|
|
|
|
for _ = 1, 400 do
|
|
if game.phase == "field" then break end
|
|
U.wait(1)
|
|
end
|
|
Boot.update, Boot.draw = origUpdate, origDraw
|
|
local r = host.result
|
|
check(r ~= nil and r.action == "new_game" and r.fieldCallback == "truck" and r.gender == 1,
|
|
"Birch hands off {new_game, gender=1, fieldCallback=truck}")
|
|
check(game.phase == "field", "field entered")
|
|
local ev = {}
|
|
for _, e in ipairs(host.events) do ev[e.name] = e.frame end
|
|
local function span(a, b) return ev[a] and ev[b] and (ev[b] - ev[a]) or -1 end
|
|
print(string.format("[driver] beats (GBA frames) mus=%s birch_in=%s welcome=%s release=%s cry=%s gender=%s",
|
|
tostring(ev.mus_route122), tostring(ev.birch_fade_in), tostring(ev.welcome_text), tostring(ev.lotad_release),
|
|
tostring(ev.lotad_cry), tostring(ev.gender_menu)))
|
|
print(string.format("[driver] shrink->white=%d white->cleanup=%d", span("shrink_start", "white_fade_start"),
|
|
span("white_fade_start", "cleanup")))
|
|
check(span("mus_route122", "birch_fade_in") == 0xD8 + 1, "Birch appears 216 frames after MUS_ROUTE122")
|
|
|
|
local truckEvents = {}
|
|
if not Truck.isRunning() then
|
|
print("[driver] Game3 did not start the truck (crossfile hand-off pending); driver starts it")
|
|
Truck.execute(nil, { onEvent = function(n, f) truckEvents[#truckEvents + 1] = { name = n, frame = f } end })
|
|
else
|
|
local seq = Truck._state.seq
|
|
if seq then seq.onEvent = function(n, f) truckEvents[#truckEvents + 1] = { name = n, frame = f } end end
|
|
end
|
|
local Runtime = require("src.core.game3.runtime")
|
|
local session = Runtime.getSession()
|
|
check(session and session.map == "EM_INSIDE_OF_TRUCK", "new game starts inside the truck")
|
|
U.wait(60)
|
|
U.still(game, DIR .. "/14_truck_black.png")
|
|
for _ = 1, 2000 do
|
|
local seen = false
|
|
for _, e in ipairs(truckEvents) do if e.name == "fade_in" then seen = true end end
|
|
if seen then break end
|
|
U.wait(1)
|
|
end
|
|
U.wait(40)
|
|
U.still(game, DIR .. "/15_truck_ride.png")
|
|
for _ = 1, 3000 do
|
|
if not Truck.isRunning() then break end
|
|
U.wait(1)
|
|
end
|
|
check(not Truck.isRunning(), "truck sequence finished")
|
|
local names = {}
|
|
for _, e in ipairs(truckEvents) do names[#names + 1] = e.name .. "@" .. e.frame end
|
|
print("[driver] truck " .. table.concat(names, " "))
|
|
U.wait(4)
|
|
U.still(game, DIR .. "/16_truck_door_open.png")
|
|
local Field = require("src.core.game3.field")
|
|
check(Field.locked == false, "player controls unlocked after the door opens")
|
|
finish()
|
|
end
|