mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
185 lines
6.2 KiB
Lua
185 lines
6.2 KiB
Lua
#!/usr/bin/env luajit
|
|
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
|
|
local failed = 0
|
|
local function check(cond, msg)
|
|
if cond then
|
|
print("[ok] " .. msg)
|
|
else
|
|
failed = failed + 1
|
|
print("[FAIL] " .. msg)
|
|
end
|
|
end
|
|
|
|
local function done()
|
|
if failed > 0 then
|
|
print("[test] FAILED " .. failed)
|
|
os.exit(1)
|
|
end
|
|
print("[test] all passed")
|
|
os.exit(0)
|
|
end
|
|
|
|
local Space = require("src.core.game3.scripting.space")
|
|
|
|
local Cache = require("tests.game3_cache")
|
|
local cacheRoot = Cache.mount("scripts/events.lua", { native = true })
|
|
if not cacheRoot then
|
|
print("[skip] game3_stitchfield_onframe_test: " .. tostring(Cache.reason))
|
|
done()
|
|
end
|
|
print("[info] FireRed cache at " .. cacheRoot)
|
|
|
|
local ExtractScripts = require("src.import.gba.extract_scripts")
|
|
Space.bundle = ExtractScripts.loadBundle(Cache.cache(), cacheRoot, { allowIncomplete = true })
|
|
check(Space.bundle ~= nil, "script bundle loads")
|
|
|
|
local ModRuntime = require("src.mods.Runtime")
|
|
local startedLog = {}
|
|
local bus = { listeners = { ["script.started"] = true } }
|
|
function bus:emit(name, payload)
|
|
if name == "script.started" and payload and payload.key then
|
|
startedLog[#startedLog + 1] = payload.key
|
|
end
|
|
end
|
|
function bus:removeOwner() end
|
|
ModRuntime.install(bus, {
|
|
call = function(_, _, vanilla, ...) return vanilla(...) end,
|
|
removeOwner = function() end,
|
|
})
|
|
|
|
local Dataset = require("src.core.game3.dataset")
|
|
local Runtime = require("src.core.game3.runtime")
|
|
local Map = require("src.core.game3.map")
|
|
local Field = require("src.core.game3.field")
|
|
local Flags = require("src.core.game3.scripting.flags")
|
|
|
|
local game = { data = {} }
|
|
Dataset.hydrate(game)
|
|
local session = { map = "FR_PALLET_TOWN", x = 12, y = 20, facing = "down", flags = {}, vars = {} }
|
|
game.session = session
|
|
Runtime.start(nil, game, session, { reason = "new_game" })
|
|
|
|
local ICEFALL = "FR_FOUR_ISLAND_ICEFALL_CAVE_1F"
|
|
local SEAFOAM_B3F = "FR_SEAFOAM_ISLANDS_B3F"
|
|
local NEUTRAL = "FR_PALLET_TOWN"
|
|
local VAR_TEMP_1 = 0x4001
|
|
|
|
local mark = 0
|
|
local function since()
|
|
local out = {}
|
|
for i = mark + 1, #startedLog do out[#out + 1] = startedLog[i] end
|
|
mark = #startedLog
|
|
return out
|
|
end
|
|
|
|
local function frames(n)
|
|
for _ = 1, n do Field.update(1 / 60) end
|
|
end
|
|
|
|
local function warpTo(mapId, x, y)
|
|
Map.load(nil, game, mapId, { x = x, y = y, facing = "down" })
|
|
frames(4)
|
|
end
|
|
|
|
local function var(id) return Flags.getVar(Space.store, Space.vm and Space.vm.ctx, id) end
|
|
local function setVar(id, v) Flags.setVar(Space.store, Space.vm and Space.vm.ctx, id, v) end
|
|
|
|
print("[test] 1. the two fall maps carry an ON_FRAME row keyed on VAR_TEMP_1")
|
|
local iceRows = Space.bundle.events[ICEFALL].mapScripts.onFrame
|
|
local seaRows = Space.bundle.events[SEAFOAM_B3F].mapScripts.onFrame
|
|
check(type(iceRows) == "table" and iceRows[1] and iceRows[1].var == VAR_TEMP_1
|
|
and iceRows[1].value == 1,
|
|
"Icefall Cave 1F ON_FRAME is VAR_TEMP_1 == 1, script="
|
|
.. tostring(iceRows[1] and iceRows[1].script))
|
|
check(type(seaRows) == "table" and seaRows[1] and seaRows[1].var == VAR_TEMP_1
|
|
and seaRows[1].value == 1,
|
|
"Seafoam B3F ON_FRAME is VAR_TEMP_1 == 1, script="
|
|
.. tostring(seaRows[1] and seaRows[1].script))
|
|
local ICE_SCRIPT = iceRows[1].script
|
|
local SEA_SCRIPT = seaRows[1].script
|
|
|
|
print("[test] 2. entering Icefall Cave 1F with VAR_TEMP_1 clear starts nothing")
|
|
warpTo(NEUTRAL, 12, 20)
|
|
warpTo(ICEFALL, 9, 21)
|
|
since()
|
|
check(var(VAR_TEMP_1) == 0, "VAR_TEMP_1 is 0 on entry, got " .. var(VAR_TEMP_1))
|
|
check(Space.vm:isRunning() == false, "no map script is running after the entry drain")
|
|
check(Field.locked == false, "the entry lock was released because no ON_FRAME claimed it")
|
|
|
|
print("[test] 3. standing still for a second does not spuriously fire it")
|
|
frames(60)
|
|
check(#since() == 0, "60 field frames, no script started")
|
|
check(Space._pendingOnFrame == false, "and the claim flag stayed cleared")
|
|
|
|
print("[test] 4. the ice per-step callback's VarSet is noticed on the very next frame")
|
|
-- pokefirered/src/field_tasks.c:243
|
|
setVar(VAR_TEMP_1, 1)
|
|
check(Space._pendingOnFrame == false, "nothing re-armed the claim flag")
|
|
frames(1)
|
|
local ran = since()
|
|
check(#ran == 1 and ran[1] == ICE_SCRIPT,
|
|
"one frame later FallDownHole " .. tostring(ICE_SCRIPT) .. " started, got "
|
|
.. tostring(ran[1]) .. " x" .. #ran)
|
|
check(Space.vm:isRunning() == true, "it is parked on its delay")
|
|
check(Field.locked == true, "its lockall took the field")
|
|
|
|
print("[test] 5. a locked field is not polled (pret ArePlayerFieldControlsLocked)")
|
|
Space.vm:halt(true)
|
|
warpTo(NEUTRAL, 12, 20)
|
|
warpTo(ICEFALL, 9, 21)
|
|
since()
|
|
check(var(VAR_TEMP_1) == 0, "temp vars cleared by the map load, got " .. var(VAR_TEMP_1))
|
|
Field.lock()
|
|
setVar(VAR_TEMP_1, 1)
|
|
frames(30)
|
|
check(#since() == 0, "30 frames under a field lock start nothing")
|
|
Field.unlock()
|
|
frames(1)
|
|
local ran5 = since()
|
|
check(#ran5 == 1 and ran5[1] == ICE_SCRIPT,
|
|
"and the first unlocked frame starts it, got " .. tostring(ran5[1]))
|
|
|
|
print("[test] 6. Seafoam B3F catches the surf-arrival VarSet the same way")
|
|
-- pokefirered/src/field_effect.c:1285
|
|
Space.vm:halt(true)
|
|
Field.unlock()
|
|
warpTo(NEUTRAL, 12, 20)
|
|
warpTo(SEAFOAM_B3F, 20, 8)
|
|
since()
|
|
check(var(VAR_TEMP_1) == 0, "B3F entered with VAR_TEMP_1 clear, got " .. var(VAR_TEMP_1))
|
|
frames(120)
|
|
check(#since() == 0,
|
|
"two seconds of frames, the length of the fall animation, start nothing")
|
|
setVar(VAR_TEMP_1, 1)
|
|
frames(1)
|
|
local ran6 = since()
|
|
check(ran6[1] == SEA_SCRIPT,
|
|
"EnterByFalling " .. tostring(SEA_SCRIPT) .. " started, got " .. tostring(ran6[1]))
|
|
|
|
print("[test] 7. the row stops matching once the var moves, so the poll stays quiet")
|
|
if Space.vm:isRunning() then Space.vm:halt(true) end
|
|
Field.unlock()
|
|
setVar(VAR_TEMP_1, 0)
|
|
since()
|
|
frames(60)
|
|
check(#since() == 0, "VAR_TEMP_1 back to 0, 60 more frames start nothing")
|
|
|
|
print("[test] 8. the no-match poll allocates nothing")
|
|
warpTo(NEUTRAL, 12, 20)
|
|
warpTo(ICEFALL, 9, 21)
|
|
since()
|
|
check(var(VAR_TEMP_1) == 0, "back in the cave with the row unmatched")
|
|
for _ = 1, 20000 do Space.runOnFrame() end
|
|
collectgarbage("collect")
|
|
local before = collectgarbage("count")
|
|
for _ = 1, 20000 do Space.runOnFrame() end
|
|
local perPoll = (collectgarbage("count") - before) * 1024 / 20000
|
|
check(#since() == 0, "40000 polls started nothing")
|
|
check(perPoll < 1,
|
|
"the unmatched poll allocates " .. string.format("%.4f", perPoll) .. " bytes per frame")
|
|
|
|
ModRuntime.reset()
|
|
done()
|