-- pokecrystal/engine/menus/init_gender.asm:23-41
-- pokecrystal/engine/menus/intro_menu.asm:645-696,854-872
-- pokecrystal/home/fade.asm:22-113
-- POKEPORT_DRIVER=tests/drivers/gen2_intro_2194.lua POKEPORT_IDENTITY=crystal-sep04 POKEPORT_VERSION=crystal POKEPORT_TOUCH=0 POKEPORT_SHOT_DIR=
love .
local U = require("tests.drivers.util")
local GbcPalette = require("src.render.GbcPalette")
local GenderSelect = require("src.ui.gen2.GenderSelect")
local InitClock = require("src.ui.gen2.InitClock")
local MainMenu = require("src.ui.gen2.MainMenu")
local OakSpeech = require("src.ui.gen2.OakSpeech")
local GameVersion = require("src.core.GameVersion")
return function(game)
local out = os.getenv("POKEPORT_SHOT_DIR") or "/tmp/2194-intro"
local log = io.open(out .. "/driver.log", "w")
local function say(line)
print("[driver] " .. line)
if log then log:write(line .. "\n"); log:flush() end
end
local function bail(reason)
say("FAIL " .. reason)
if log then log:close() end
love.event.quit(1)
error(reason, 0)
end
local function top() return game.stack:top() end
local function isA(class)
local state = top()
return state ~= nil and getmetatable(state) == class
end
local function tap(button, frames)
game.input.pressQueue[#game.input.pressQueue + 1] = button
game.input.state[button] = true
U.wait(2)
game.input.state[button] = false
U.wait(frames or 4)
end
local function waitFor(label, predicate, frames)
for _ = 1, frames or 900 do
if predicate() then return end
U.wait(1)
end
bail(("stalled waiting for %s (top is %s)"):format(label, tostring(top())))
end
local function shoot(name, label)
if not U.shot(game, out .. "/" .. name) then bail("no shot " .. name) end
say("OK " .. label .. " -> " .. name)
end
local version = tostring(GameVersion.get())
say("version=" .. version .. " engine=" .. tostring(GameVersion.engine()))
for _ = 1, 900 do
if isA(MainMenu) then break end
tap("start", 2)
end
if not isA(MainMenu) then
for _ = 1, 400 do
if isA(MainMenu) then break end
tap("a", 2)
end
end
waitFor("the intro menu", function() return isA(MainMenu) end)
local menu = top()
for i, item in ipairs(menu.list.items) do
if item.value == "new" then menu.list.index = i end
end
tap("a")
U.wait(4)
if isA(GenderSelect) then
local gender = top()
if gender:menuOpen() then bail("the box was up before PrintText finished") end
shoot("2194_01_gender_typing_no_box.png",
"the prompt typing with no menu on it")
if top():menuOpen() then bail("the box opened while the text still typed") end
waitFor("the menu to open",
function() return isA(GenderSelect) and top():menuOpen() end, 600)
if not top().typer:done() then bail("the box opened before the text ended") end
shoot("2194_02_gender_box_after_text.png", "LoadMenuHeader after PrintText")
tap("a")
waitFor("RotateFourPalettesLeft", function()
if not isA(GenderSelect) then return false end
local f = top().fade
return f ~= nil and f.kind == "outBlack" and f.frame >= 12
end, 600)
local byte = top().fade:bgp()
local rotated = GbcPalette.remap(GenderSelect.PALETTE, byte)
if rotated[1][1] == GenderSelect.PALETTE[1][1]
and rotated[1][2] == GenderSelect.PALETTE[1][2]
and rotated[1][3] == GenderSelect.PALETTE[1][3] then
bail(("outBlack 0x%02X left the textbox white"):format(byte))
end
shoot("2194_03_gender_rotated_blue.png",
("the screen palette permuted by 0x%02X"):format(byte))
else
say("OK no gender screen on " .. version)
end
waitFor("the clock screen", function() return isA(InitClock) end, 600)
for _ = 1, 200 do
if isA(OakSpeech) then break end
if isA(InitClock) and top().fade == nil then tap("a", 3) else U.wait(1) end
end
waitFor("the Oak speech", function() return isA(OakSpeech) end, 600)
waitFor("Oak's palette walk", function()
local r = isA(OakSpeech) and top().picReveal
return r ~= nil and r.kind == "rotate" and r.t >= 12
end, 600)
local speech = top()
local row = OakSpeech.frontpicBgp(speech.picReveal.t)
if row ~= 0xA8 and row ~= 0xFC then
bail(("the walk is on 0x%02X at frame %d, not a flat silhouette")
:format(row, speech.picReveal.t))
end
if getmetatable(top()) ~= OakSpeech then
bail("OakText1 printed before the walk finished")
end
shoot("2194_04_oak_silhouette_col2.png",
("Oak flat on row 0x%02X"):format(row))
waitFor("OakText1", function()
return isA(OakSpeech) == false and top() ~= nil
end, 600)
say("OK the text box is up only after the walk")
local shotWhite = false
for _ = 1, 900 do
if isA(OakSpeech) then
local state = top()
local f = state.fade
if f and f.kind == "outWhite" and f.frame >= 10 then
shoot("2194_05_oak_to_white_rotated.png",
"RotateThreePalettesRight between Oak's pages")
shotWhite = true
break
elseif f or state.picReveal then
U.wait(1)
else
tap("a", 2)
end
else
tap("a", 2)
end
end
if not shotWhite then bail("no fade to white between Oak's pages") end
say("PASS gen2 intro 2194 (" .. version .. ") in " .. out)
if log then log:close() end
love.event.quit(0)
end