Files
gen1recomp/tests/game3_multi_connection_test.lua

172 lines
7.6 KiB
Lua

package.path = "./?.lua;./?/init.lua;" .. package.path
local Connections = require("src.core.game3.connections")
local Map = require("src.core.game3.map")
local Collision = require("src.core.game3.collision")
local Itemfinder = require("src.core.game3.itemfinder")
local failures = 0
local function check(ok, label)
print((ok and "PASS " or "FAIL ") .. label)
if not ok then failures = failures + 1 end
end
local function layout(tag, w, h)
local L = { width = w, height = h, pair = tag }
function L:midAt(x, y) return tag .. ":" .. x .. "," .. y end
function L:collAt() return 0 end
return L
end
local function def(tag, w, h, conns)
return { id = tag, midLayout = layout(tag, w, h), pair = tag, connections = conns or {} }
end
local maps = {
SRC = def("SRC", 24, 100, {
{ dir = "west", map = "GREEN", offset = 0 },
{ dir = "west", map = "SIX", offset = 40 },
{ dir = "west", map = "RUIN", offset = 80 },
{ dir = "north", map = "TOP", offset = 0 },
}),
GREEN = def("GREEN", 72, 20),
SIX = def("SIX", 24, 30, { { dir = "east", map = "SRC", offset = -40 } }),
RUIN = def("RUIN", 48, 40),
TOP = def("TOP", 24, 10),
KEYED = def("KEYED", 10, 10, { east = { map = "SIX", offset = 2 }, left = { map = "GREEN", offset = 0 } }),
}
local game = { data = { maps = maps } }
local each = Connections.each(maps.SRC)
check(#each == 4 and each[1].map == "GREEN" and each[2].map == "SIX" and each[3].map == "RUIN"
and each[4].dir == "north", "list form keeps ROM order")
local keyed = Connections.each(maps.KEYED)
check(#keyed == 2 and keyed[1].dir == "east" and keyed[1].offset == 2
and keyed[2].dir == "west" and keyed[2].map == "GREEN", "keyed form still resolves")
local function destOf(id) return maps[id] end
for _, row in ipairs({ { 10, "GREEN" }, { 50, "SIX" }, { 90, "RUIN" } }) do
local c = Connections.incoming(maps.SRC, "left", 0, row[1], destOf)
check(c and c.map == row[2], "incoming west row " .. row[1] .. " -> " .. row[2])
end
check(Connections.incoming(maps.SRC, "west", 0, 30, destOf) == nil, "incoming gap row 30 has no connection")
check(Connections.incoming(maps.SRC, "east", 23, 10, destOf) == nil, "incoming east with no east connection")
local c20 = Connections.incoming(maps.SRC, "west", 0, 20, destOf)
check(c20 and c20.map == "GREEN", "incoming bound is inclusive like fieldmap.c:724")
Map.loadNeighborsDepth1(game, maps.SRC)
check(#Map.neighborList == 4, "neighborList has every connection")
check(Map.neighbors.west and Map.neighbors.west.map == "GREEN", "neighbors[dir] keeps the first entry")
check(Map.worldMidAt(-1, 10, maps.SRC) == "GREEN:71,10", "west row 10 draws Green Path")
check(Map.worldMidAt(-1, 50, maps.SRC) == "SIX:23,10", "west row 50 draws Six Island")
check(Map.worldMidAt(-3, 95, maps.SRC) == "RUIN:45,15", "west row 95 draws Ruin Valley")
local _, _, void = Map.worldMidAt(-1, 30, maps.SRC)
check(void == true, "west gap row draws border")
local world = Map.computeWorld(maps, "SRC", 1, nil, nil)
local placed = {}
for _, e in ipairs(world) do placed[e.id] = e end
check(placed.GREEN and placed.GREEN.ox == -72 and placed.GREEN.oy == 0, "computeWorld places Green Path")
check(placed.SIX and placed.SIX.ox == -24 and placed.SIX.oy == 40, "computeWorld places Six Island")
check(placed.RUIN and placed.RUIN.ox == -48 and placed.RUIN.oy == 80, "computeWorld places Ruin Valley")
local conn = Connections.incoming(maps.SRC, "west", 0, 50, destOf)
local lx, ly = Collision.connectionLanding(maps.SIX, conn, "left", 0, 50)
check(lx == 23 and ly == 10, "landing on Six Island at (23,10)")
check(Collision.connectionLanding(maps.SIX, conn, "left", 0, 70) == nil, "landing outside the span is refused, not clamped")
local back = Connections.incoming(maps.SIX, "right", 23, 10, destOf)
local bx, by = Collision.connectionLanding(maps.SRC, back, "right", 23, 10)
check(back and back.map == "SRC" and bx == 0 and by == 50, "Six Island east lands on the source at row 50")
local n, nx, ny = Connections.atPos(Map.neighborList, -2, 45, 24, 100)
check(n and n.map == "SIX" and nx == 22 and ny == 5, "atPos resolves the covering west connection")
check(Connections.atPos(Map.neighborList, -2, 75, 24, 100) == nil, "atPos gap row has none")
local events = {
SIX = { { type = "hidden_item", x = 22, y = 5 } },
GREEN = {},
RUIN = { { type = "hidden_item", x = 47, y = 1 } },
}
local scan = Itemfinder.scan({
px = 1, py = 46, events = {}, flagSet = function() return false end,
width = 24, height = 100, neighborList = Map.neighborList,
eventsFor = function(id) return events[id] or {} end,
})
check(scan ~= nil, "itemfinder sees a hidden item on the middle west connection")
local scanRuin = Itemfinder.scan({
px = 1, py = 84, events = {}, flagSet = function() return false end,
width = 24, height = 100, neighborList = Map.neighborList,
eventsFor = function(id) return events[id] or {} end,
})
check(scanRuin ~= nil, "itemfinder sees a hidden item on the last west connection")
check(Map.worldMidAt(2, -2, maps.SRC) == "TOP:2,8", "north row draws the north connection")
require("src.core.GameVersion").set("firered")
local Cache = require("tests.game3_cache")
if not Cache.mount("connections.lua", { native = true }) then
print("[skip] game3_multi_connection_test cache section: " .. tostring(Cache.reason))
os.exit(failures == 0 and 0 or 1)
end
local Dataset = require("src.core.game3.dataset")
local Player = require("src.core.game3.player")
local Runtime = require("src.core.game3.runtime")
local Field = require("src.core.game3.field")
local Ghosts = require("src.core.game3.ghosts")
local Space = require("src.core.game3.scripting.space")
local rgame = { data = {}, save = {}, session = { flags = {}, vars = {} } }
Dataset.hydrate(rgame)
Runtime.session = rgame.session
Field._game, Field._session, Field.running = rgame, rgame.session, true
Space.runEnterScripts = function() end
Space.vm = nil
local function setup(map, x, y, dir)
Ghosts.clear()
Map.load(nil, rgame, map, { x = x, y = y, facing = dir })
rgame.session = Runtime.getSession()
rgame.session.x, rgame.session.y = Player.cellX, Player.cellY
Field.locked = false
Player.surfing, Player.elevation = false, 3
end
local function finishStep()
Player._onStepDone = function() end
for _ = 1, 32 do
if not Player.moving then break end
Player.tick(rgame)
end
end
local WP = "FR_SIX_ISLAND_WATER_PATH"
local wpDef = rgame.data.maps[WP]
local west = {}
for _, c in ipairs(Connections.each(wpDef)) do
if c.dir == "west" then west[#west + 1] = c.map .. "@" .. c.offset end
end
check(table.concat(west, " ") == "FR_SIX_ISLAND_GREEN_PATH@0 FR_SIX_ISLAND@40 FR_SIX_ISLAND_RUIN_VALLEY@80",
"cache Water Path west connections in ROM order")
setup("FR_SIX_ISLAND", 23, 12, "right")
check(Player.tryMove("right", rgame, false) == "connection", "Six Island east crosses")
finishStep()
check(Map.current == WP and Player.cellX == 0 and Player.cellY == 52, "Six Island east lands on Water Path (0,52)")
check(#Map.neighborList == 3, "Water Path loads all three west neighbors")
local mid, _, void = Map.worldMidAt(-1, 52, wpDef)
check(mid ~= nil and not void and mid == rgame.data.maps.FR_SIX_ISLAND.midLayout:midAt(23, 12),
"Water Path west of row 52 draws Six Island")
for _, r in ipairs({
{ 52, "FR_SIX_ISLAND", 23, 12 },
{ 10, "FR_SIX_ISLAND_GREEN_PATH", 71, 10 },
{ 90, "FR_SIX_ISLAND_RUIN_VALLEY", 47, 10 },
}) do
setup(WP, 0, r[1], "left")
check(Player.tryMove("left", rgame, false) == "connection", "Water Path row " .. r[1] .. " crosses west")
finishStep()
check(Map.current == r[2] and Player.cellX == r[3] and Player.cellY == r[4],
"Water Path row " .. r[1] .. " lands on " .. r[2])
end
os.exit(failures == 0 and 0 or 1)