Files
gen1recomp/tests/drivers/game3_map_preview_transition.lua
2026-09-23 16:34:15 -04:00

224 lines
8.7 KiB
Lua

local U = require("tests.drivers.util")
local DIR = os.getenv("POKEPORT_SHOT_DIR") or "/tmp/game3_map_preview_transition"
return function(game)
local failures = 0
local function pass(label) print("PASS " .. label) end
local function fail(label, why)
failures = failures + 1
print("FAIL " .. label .. (why and (" " .. why) or ""))
end
local function check(ok, label, why) if ok then pass(label) else fail(label, why) end end
for _ = 1, 900 do
if game.phase == "boot" and game.boot then break end
U.wait(1)
end
game:_handleBootAction({ action = "new_game", name = "RED" })
U.wait(240)
local Runtime = require("src.core.game3.runtime")
local Map = require("src.core.game3.map")
local Player = require("src.core.game3.player")
local Party = require("src.core.game3.party")
local Field = require("src.core.game3.field")
local Warp = require("src.core.game3.warp")
local MPS = require("src.ui.game3.map_preview_screen")
local Cave = require("src.ui.game3.cave_transition")
local Fade = require("src.ui.game3.fade")
local MapCatalog = require("src.import.gba.map_catalog")
local session = Runtime.getSession()
if not session then print("FAIL no session") love.event.quit(1) return end
session.party = {}
Party.giveMon(session, 6, 50)
local function placeAt(mapId, x, y, facing)
Map.load(nil, game, mapId, { x = x, y = y, facing = facing or "down" })
if game.session then
game.session.x, game.session.y, game.session.facing = x, y, facing or "down"
end
Player.cellX, Player.cellY = x, y
Player.px, Player.py = x * 16, y * 16
Player.targetX, Player.targetY = x, y
Player.facing = facing or "down"
MPS.dismiss()
Field.locked = false
U.wait(30)
end
local gate = MapCatalog.pretToEngine("Route2_ViridianForest_SouthEntrance")
local forest = MapCatalog.pretToEngine("ViridianForest")
local r4 = MapCatalog.pretToEngine("Route4")
local moon = MapCatalog.pretToEngine("MtMoon_1F")
local function probeNameWindow()
local canvas = love.graphics.newCanvas(240, 160)
love.graphics.push("all")
love.graphics.setCanvas(canvas)
love.graphics.origin()
love.graphics.clear(0, 0, 0, 1)
MPS.draw()
love.graphics.setCanvas()
love.graphics.pop()
local data = canvas:newImageData()
local black, grey, white = 0, 0, 0
for y = 0, 15 do
for x = 0, 103 do
local r, g, b = data:getPixel(x, y)
r, g, b = math.floor(r * 255 + 0.5), math.floor(g * 255 + 0.5), math.floor(b * 255 + 0.5)
if r == 0 and g == 0 and b == 0 then black = black + 1
elseif r == 214 and g == 214 and b == 214 then grey = grey + 1
elseif r == 247 and g == 247 and b == 255 then white = white + 1 end
end
end
data:release()
canvas:release()
return black, grey, white
end
local function forestRun(label, opts)
opts = opts or {}
placeAt(gate, 7, 2, "up")
Warp.request(nil, game, forest, 29, 61, "up")
local hold, dissolve, lockedAll, dur = 0, 0, true, nil
local shotHold, shotMid = false, false
for _ = 1, 900 do
U.wait(1)
if MPS.isForestActive() then
if MPS._state == MPS.STATE.HOLD and not Fade.isActive() then
hold = hold + 1
dur = MPS._duration
if opts.shots and not shotHold and hold == 30 then
shotHold = true
U.still(game, DIR .. "/pv_forest_hold_black_surround.png")
local black, grey, white = probeNameWindow()
print(string.format("[pv] name window black=%d grey=%d white=%d", black, grey, white))
-- src/menu2.c:469
check(black > 0 and grey > 0 and grey < 2 * black and white > black + grey,
"forest_name_black_text_grey_shadow",
("black=%d grey=%d white=%d"):format(black, grey, white))
end
elseif MPS._state == MPS.STATE.FADE_OUT then
dissolve = dissolve + 1
if opts.shots and not shotMid and dissolve == 24 then
shotMid = true
print(string.format("[pv] mid-dissolve eva=%d evb=%d", MPS._eva, MPS._evb))
U.still(game, DIR .. "/pv_forest_mid_dissolve.png")
end
end
if not Field.locked then lockedAll = false end
elseif hold > 0 then
break
end
end
U.wait(2)
print(string.format("[pv] %s dur=%s hold=%d dissolve=%d lockedAll=%s lockedAfter=%s",
label, tostring(dur), hold, dissolve, tostring(lockedAll), tostring(Field.locked)))
return dur, hold, dissolve, lockedAll
end
local dur1, hold1, diss1, locked1 = forestRun("forest first")
check(dur1 == 120 and hold1 + 1 == 121, "forest_first_visit_hold_120", "dur=" .. tostring(dur1) .. " hold=" .. hold1)
check(diss1 == 47, "forest_dissolve_47_frames", "dissolve=" .. diss1)
check(locked1, "forest_field_locked_during_preview")
check(not Field.locked, "forest_field_unlocked_after_preview")
local dur2, hold2 = forestRun("forest repeat")
check(dur2 == 40 and hold2 + 1 == 41, "forest_repeat_visit_hold_40", "dur=" .. tostring(dur2) .. " hold=" .. hold2)
placeAt(gate, 7, 2, "up")
Warp.request(nil, game, forest, 29, 61, "up")
for _ = 1, 400 do
U.wait(1)
if MPS.isForestActive() and MPS._state == MPS.STATE.HOLD and not Fade.isActive() then break end
end
local y0 = Player.cellY
U.hold(game, "up", 20)
check(Player.cellY == y0 and MPS.isForestActive(), "forest_walk_blocked_during_hold",
"y0=" .. tostring(y0) .. " y=" .. tostring(Player.cellY))
for _ = 1, 300 do U.wait(1) if not MPS.isActive() then break end end
forestRun("forest shots", { shots = true })
local function caveRun(label, opts)
opts = opts or {}
placeAt(r4, 19, 6, "up")
Warp.request(nil, game, moon, 18, 36, "up")
local counts = { black = 0, fadein = 0, hold = 0, white = 0, flash = 0 }
local dur, started, shots = nil, false, {}
for _ = 1, 900 do
U.wait(1)
local c = MPS._cave
if c then
started = true
if opts.holdB then game.input.state.b = true end
if c.step <= 2 then counts.black = counts.black + 1
elseif c.step == 3 then counts.fadein = counts.fadein + 1
elseif c.step == 4 then
counts.hold = counts.hold + 1
dur = c.duration
if opts.shots and counts.hold == 30 and not shots.hold then
shots.hold = true
U.still(game, DIR .. "/pv_mtmoon_cave_preview.png")
end
elseif c.step == 5 then
counts.white = counts.white + 1
if opts.shots and counts.white == 7 and not shots.white then
shots.white = true
U.still(game, DIR .. "/pv_mtmoon_fade_to_white.png")
end
end
elseif Cave.isActive() then
counts.flash = counts.flash + 1
local run = Cave._run
if opts.shots and run and run.task == "2" and run.d2 == 8 and not shots.flash then
shots.flash = true
U.still(game, DIR .. "/pv_mtmoon_flash_mid.png")
end
if opts.shots and run and run.task == "3" and run.d1 == 8 and not shots.dim then
shots.dim = true
U.still(game, DIR .. "/pv_mtmoon_flash_dimming.png")
end
elseif started then
break
end
end
game.input.state.b = false
for _ = 1, 120 do U.wait(1) if not Warp.isBusy() then break end end
print(string.format("[pv] %s dur=%s black=%d fadein=%d hold=%d white=%d flash=%d map=%s",
label, tostring(dur), counts.black, counts.fadein, counts.hold, counts.white, counts.flash,
tostring(Map.current)))
return dur, counts
end
local cd1, c1 = caveRun("mtmoon first")
check(cd1 == 120 and c1.hold == 121, "mtmoon_first_visit_hold_120", "dur=" .. tostring(cd1) .. " hold=" .. c1.hold)
-- pokefirered/src/fldeff_flash.c:199 CB2_ChangeMapMain
check(c1.fadein == 15, "mtmoon_fade_in_15_frames", "fadein=" .. c1.fadein)
check(c1.white == 11, "mtmoon_fade_to_white_11_frames", "white=" .. c1.white)
check(c1.flash == 27, "mtmoon_flash_27_frames", "flash=" .. c1.flash)
check(Map.current == moon, "mtmoon_map_loaded_after_flash", tostring(Map.current))
local cd2, c2 = caveRun("mtmoon repeat")
check(cd2 == 40 and c2.hold == 41, "mtmoon_repeat_visit_hold_40", "dur=" .. tostring(cd2) .. " hold=" .. c2.hold)
local _, c3 = caveRun("mtmoon b skip", { holdB = true })
check(c3.hold == 1, "mtmoon_b_skips_hold", "hold=" .. c3.hold)
caveRun("mtmoon shots", { shots = true })
placeAt(moon, 18, 36, "down")
Warp.request(nil, game, r4, 19, 6, "down")
local exitFrames = 0
for _ = 1, 300 do
U.wait(1)
if Cave.isActive() then exitFrames = exitFrames + 1
elseif exitFrames > 0 then break end
end
print("[pv] exit flash frames=" .. exitFrames)
check(exitFrames == 38, "cave_exit_flash_38_frames", "frames=" .. exitFrames)
love.event.quit(failures == 0 and 0 or 1)
end