mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-28 23:00:21 -04:00
209 lines
6.6 KiB
Lua
209 lines
6.6 KiB
Lua
local U = require("tests.drivers.util")
|
|
|
|
local X = {}
|
|
|
|
function X.new(name, defaultDir)
|
|
local d = {
|
|
name = name,
|
|
dir = os.getenv("POKEPORT_SHOT_DIR") or defaultDir,
|
|
failures = 0,
|
|
vmLogs = {},
|
|
}
|
|
function d.check(ok, label)
|
|
print((ok and "PASS " or "FAIL ") .. label)
|
|
if not ok then d.failures = d.failures + 1 end
|
|
return ok
|
|
end
|
|
function d.note(msg) print("[driver] " .. msg) end
|
|
local function capture(msg)
|
|
msg = tostring(msg)
|
|
if msg:find("skip unknown", 1, true) or msg:find("skip op", 1, true) or msg:find("not ported", 1, true)
|
|
or msg:find("missing script", 1, true) or msg:find("runaway", 1, true) or msg:find("LUA ERROR", 1, true) then
|
|
d.vmLogs[#d.vmLogs + 1] = msg
|
|
end
|
|
end
|
|
local origPrint = print
|
|
print = function(...)
|
|
local parts = {}
|
|
for i = 1, select("#", ...) do parts[i] = tostring((select(i, ...))) end
|
|
capture(table.concat(parts, "\t"))
|
|
return origPrint(...)
|
|
end
|
|
local Vm = require("src.core.game3.scripting.vm")
|
|
local origNew = Vm.new
|
|
Vm.new = function(opts)
|
|
local vm = origNew(opts)
|
|
local a = vm.adapters
|
|
if a and a.log and not a._xaWrapped then
|
|
local inner = a.log
|
|
a.log = function(msg) capture(msg) return inner(msg) end
|
|
a._xaWrapped = true
|
|
end
|
|
return vm
|
|
end
|
|
function d.finish(label)
|
|
if d.finished then return end
|
|
d.finished = true
|
|
d.check(#d.vmLogs == 0, "no unknown-op / unported-system VM logs" .. (label and (" " .. label) or "") .. " (" .. #d.vmLogs .. ")")
|
|
for i = 1, math.min(#d.vmLogs, 10) do d.note("VM LOG " .. d.vmLogs[i]) end
|
|
print((d.failures == 0 and "PASS" or "FAIL") .. " " .. d.name .. " failures=" .. d.failures)
|
|
love.event.quit(d.failures == 0 and 0 or 1)
|
|
U.wait(10)
|
|
end
|
|
function d.try(label, fn)
|
|
local ok, err = xpcall(fn, debug.traceback)
|
|
if not ok then d.note(label .. " error: " .. tostring(err)) end
|
|
return ok, err
|
|
end
|
|
function d.shot(game, file)
|
|
return U.shot(game, d.dir .. "/" .. file)
|
|
end
|
|
function d.still(game, file)
|
|
return U.still(game, d.dir .. "/" .. file)
|
|
end
|
|
return d
|
|
end
|
|
|
|
function X.newGame(d, game, gender)
|
|
for _ = 1, 900 do
|
|
if game.phase == "boot" and game.boot then break end
|
|
U.wait(1)
|
|
end
|
|
if not d.check(game.boot ~= nil, "boot reached") then return nil end
|
|
d.try("new_game", function()
|
|
game:_handleBootAction({ action = "new_game", name = gender == 1 and "MAY" or "BRENDAN", gender = gender or 0 })
|
|
end)
|
|
U.wait(30)
|
|
local Runtime = require("src.core.game3.runtime")
|
|
local session = Runtime.getSession()
|
|
d.check(session ~= nil, "new game session exists")
|
|
return session
|
|
end
|
|
|
|
function X.session()
|
|
return require("src.core.game3.runtime").getSession()
|
|
end
|
|
|
|
function X.settle(game, frames)
|
|
local Warp = require("src.core.game3.warp")
|
|
local Message = require("src.ui.game3.message")
|
|
for _ = 1, frames or 600 do
|
|
local busy = Warp.isBusy() or (Message.isOpen and Message.isOpen())
|
|
if not busy then break end
|
|
if Message.isOpen and Message.isOpen() then U.tap(game, "b") end
|
|
U.wait(1)
|
|
end
|
|
end
|
|
|
|
function X.goTo(d, game, mapId, x, y, facing)
|
|
local Map = require("src.core.game3.map")
|
|
local Player = require("src.core.game3.player")
|
|
X.settle(game)
|
|
local ok = d.try("Map.load " .. mapId, function()
|
|
Map.load(nil, game, mapId, { x = x, y = y, facing = facing })
|
|
end)
|
|
local s = X.session()
|
|
if s then s.x, s.y, s.facing = x, y, facing end
|
|
Player.cellX, Player.cellY = x, y
|
|
Player.px, Player.py = x * 16, y * 16
|
|
Player.targetX, Player.targetY = x, y
|
|
Player.facing = facing
|
|
U.wait(40)
|
|
return ok and s and s.map == mapId
|
|
end
|
|
|
|
function X.flags()
|
|
local Flags = require("src.core.game3.scripting.flags")
|
|
return Flags.forVersion("emerald")
|
|
end
|
|
|
|
function X.setFlag(name, on)
|
|
local Space = require("src.core.game3.scripting.space")
|
|
local F = X.flags()
|
|
require("src.core.game3.scripting.flags").setFlag(Space.store, nil, assert(F.IDS[name], name), on ~= false)
|
|
end
|
|
|
|
function X.flag(name)
|
|
local Space = require("src.core.game3.scripting.space")
|
|
local F = X.flags()
|
|
return require("src.core.game3.scripting.flags").getFlag(Space.store, nil, assert(F.IDS[name], name)) == true
|
|
end
|
|
|
|
function X.setVar(name, v)
|
|
local Space = require("src.core.game3.scripting.space")
|
|
local F = X.flags()
|
|
require("src.core.game3.scripting.flags").setVar(Space.store, nil, assert(F.VAR_IDS[name], name), v)
|
|
end
|
|
|
|
function X.var(name)
|
|
local Space = require("src.core.game3.scripting.space")
|
|
local F = X.flags()
|
|
return tonumber(require("src.core.game3.scripting.flags").getVar(Space.store, nil, assert(F.VAR_IDS[name], name))) or 0
|
|
end
|
|
|
|
function X.scriptRunning()
|
|
local Space = require("src.core.game3.scripting.space")
|
|
return Space.vm and Space.vm:isRunning()
|
|
end
|
|
|
|
function X.vmWhere()
|
|
local Space = require("src.core.game3.scripting.space")
|
|
local vm = Space.vm
|
|
if not (vm and vm:isRunning()) then return "idle" end
|
|
local pc = vm.ctx.pc
|
|
local list = pc and vm.scripts[pc.listKey]
|
|
local row = list and list[pc.index]
|
|
return string.format("%s/%s #%s op=%s mode=%s status=%s", tostring(vm._scriptKey), tostring(pc and pc.listKey), tostring(pc and pc.index),
|
|
tostring(row and row.op), tostring(vm.ctx.mode), tostring(vm.ctx.status))
|
|
end
|
|
|
|
function X.stepOnto(d, game, mapId, tx, ty)
|
|
local Player = require("src.core.game3.player")
|
|
local Warp = require("src.core.game3.warp")
|
|
local Collision = require("src.core.game3.collision")
|
|
for _, n in ipairs({ { 0, 1, "up" }, { 0, -1, "down" }, { 1, 0, "left" }, { -1, 0, "right" } }) do
|
|
if X.session().map == mapId and not Collision.canEnter(game, tx + n[1], ty + n[2]) then goto continue end
|
|
X.goTo(d, game, mapId, tx + n[1], ty + n[2], n[3])
|
|
X.settle(game, 120)
|
|
Player.forceStep(n[3])
|
|
for _ = 1, 200 do
|
|
if not Player.moving and not Warp.isBusy() then break end
|
|
U.wait(1)
|
|
end
|
|
if Player.cellX == tx and Player.cellY == ty then return true end
|
|
::continue::
|
|
end
|
|
return false
|
|
end
|
|
|
|
function X.metatile(x, y)
|
|
local Collision = package.loaded["src.core.game3.collision"]
|
|
local def = Collision and Collision._mapDef
|
|
local layout = def and def.midLayout
|
|
return layout and layout:midAt(x, y) or nil
|
|
end
|
|
|
|
function X.label(name)
|
|
local C = require("src.core.game3.constants").of("emerald")
|
|
return C:require("metatile_labels", name)
|
|
end
|
|
|
|
function X.mash(game, until_, frames, button, gap)
|
|
for _ = 1, frames or 1200 do
|
|
if until_() then return true end
|
|
U.tap(game, button or "a")
|
|
U.wait(gap or 2)
|
|
end
|
|
return until_()
|
|
end
|
|
|
|
function X.waitFor(pred, frames)
|
|
for _ = 1, frames or 1200 do
|
|
if pred() then return true end
|
|
U.wait(1)
|
|
end
|
|
return pred()
|
|
end
|
|
|
|
return X
|