mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-10-02 07:50:13 -04:00
90 lines
4.7 KiB
Lua
90 lines
4.7 KiB
Lua
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
love = love or require("tests.love_stub")
|
|
|
|
local T = require("tests.harness")
|
|
local Ctx = require("src.save_convert.Gen2MapContext")
|
|
local Codec = require("src.save_convert.Gen2Save")
|
|
local G2 = require("tests.fixtures.save.gen2_build")
|
|
local B = require("tests.fixtures.save.bytes")
|
|
local K = require("tests.save_compat._codec")
|
|
local Events = require("src.world.gen2.Events")
|
|
|
|
local data = { items = K.gen2Data.items, maps = {}, scripts = {
|
|
door = { { op = "checkevent", event = 803 }, { op = "iffalse", script = "flag" },
|
|
{ op = "changeblock", args = { 2, 2, 42 } }, { op = "sjump", script = "flag" } },
|
|
flag = { { op = "checkflag", flag = 11 }, { op = "iftrue", script = "open" }, { op = "endcallback" } },
|
|
open = { { op = "changeblock", args = { 4, 2, 22 } }, { op = "endcallback" } },
|
|
} }
|
|
local blocks = {}
|
|
for i = 1, 16 do blocks[i] = i end
|
|
data.maps.TEST_ROOM = { group = 24, map = 7, width = 4, height = 4, blocks = blocks,
|
|
objectEventsAddr = 0x4000, objects = {}, callbacks = { { callback = "MAPCALLBACK_TILES", scriptKey = "door" } } }
|
|
|
|
local function window(version, save)
|
|
local ctx = assert(Ctx.build(data, version, 24, 7, 4, 4, save))
|
|
return ctx.writes[Ctx.offsetsFor(version).screenSave]
|
|
end
|
|
|
|
for _, version in ipairs({ "gold", "silver", "crystal" }) do
|
|
local events = Events.new({ 803 }):serialize()
|
|
local save = { events = events, engineFlags = { [11] = true } }
|
|
local win = window(version, save)
|
|
T.eq(win[8], 42, version .. " event callback closes the door in the saved window")
|
|
T.eq(win[9], 22, version .. " engine flag callback opens the second door")
|
|
T.eq(window(version, {})[8], 6, version .. " untaken branches retain ROM blocks")
|
|
local moved = assert(Ctx.reposition(data, version, 24, 7, 4, 4, save))
|
|
T.eq(moved.writes[Ctx.offsetsFor(version).screenSave][8], 42, version .. " reposition applies callbacks")
|
|
local image = G2.build({ version = version })
|
|
local model = assert(Codec.decode(image, version, data))
|
|
model.rawImport = nil
|
|
model.position.x, model.position.y = 4, 4
|
|
model.events = events
|
|
local initial = assert(Codec.encode(model, version, nil, data))
|
|
model = assert(Codec.decode(initial, version, data))
|
|
local unchanged = assert(Codec.encode(model, version, initial, data))
|
|
T.eq(unchanged, initial, version .. " unchanged callback save remains byte exact")
|
|
local live = Events.new():restore(model.events)
|
|
live:set(803, false)
|
|
model.events = live:serialize()
|
|
local opened = assert(Codec.encode(model, version, initial, data))
|
|
T.eq(opened:byte(Ctx.offsetsFor(version).screenSave + 8), 6,
|
|
version .. " changing the event at the same position refreshes the saved window")
|
|
model = assert(Codec.decode(initial, version, data))
|
|
model.engineFlags[11] = true
|
|
local flagChanged = assert(Codec.encode(model, version, initial, data))
|
|
T.eq(flagChanged:byte(Ctx.offsetsFor(version).screenSave + 9), 22,
|
|
version .. " changing the engine flag at the same position refreshes the saved window")
|
|
model = assert(Codec.decode(initial, version, data))
|
|
model.events[20] = 7
|
|
local bytes = B.fromString(initial)
|
|
B.put(bytes, Ctx.offsetsFor(version).screenSave, 99)
|
|
G2.seal(bytes, version)
|
|
local decorated = B.pack(bytes)
|
|
local changed = assert(Codec.encode(model, version, decorated, data))
|
|
T.eq(changed:byte(Ctx.offsetsFor(version).screenSave + 1), 99,
|
|
version .. " unrelated events preserve transient saved blocks")
|
|
end
|
|
|
|
local room = data.maps.TEST_ROOM
|
|
local noScripts = { maps = data.maps }
|
|
local bad, why = Ctx.build(noScripts, "gold", 24, 7, 4, 4, {})
|
|
T.eq(bad, nil, "missing callback scripts refuse the export")
|
|
T.eq(why:find("re-import the ROM", 1, true) ~= nil, true, "missing scripts name the recovery")
|
|
data.scripts.door = { { op = "changeblock", args = { 2, 2, 42 } }, { op = "special", id = 7 } }
|
|
bad, why = Ctx.build(data, "gold", 24, 7, 4, 4, {})
|
|
T.eq(bad, nil, "unsupported commands refuse partially evaluated callbacks")
|
|
T.eq(why:find("unsupported command special", 1, true) ~= nil, true, "unsupported commands are named")
|
|
data.scripts.door = { { op = "sjump", script = "missing" } }
|
|
bad, why = Ctx.build(data, "gold", 24, 7, 4, 4, {})
|
|
T.eq(bad, nil, "missing jump destinations refuse callbacks")
|
|
data.scripts.door = { { op = "sjump", script = "door" } }
|
|
bad, why = Ctx.build(data, "gold", 24, 7, 4, 4, {})
|
|
T.eq(bad, nil, "callback loops are bounded")
|
|
T.eq(why:find("command limit", 1, true) ~= nil, true, "bounded callback failure is named")
|
|
room.callbacks = { { callback = "MAPCALLBACK_TILES", scriptKey = "noop" },
|
|
{ callback = "MAPCALLBACK_TILES", scriptKey = "missing" } }
|
|
data.scripts.noop = { { op = "endcallback" } }
|
|
T.eq(window("gold", {})[8], 6, "only the first callback of a type executes")
|
|
|
|
T.finish()
|