-- Parity: S.S. Anne 1F door→room contents match pokered; after layout -- patch, L→R hallway doors also land in rooms-map reading order (#189). package.path = "./?.lua;./?/init.lua;" .. package.path if not _G.love then _G.love = require("tests.love_stub") end local S = require("tests.harness").suite("parity ss anne rooms") local check, eq = S.check, S.eq local maps = dofile("data/generated/maps.lua") local SsAnneLayout = require("src.world.SsAnneLayout") local Warp = require("src.world.Warp") -- OG occupants behind each hallway door, left → right (pokered + guides) local OG_BY_DOOR = { { "SSANNE1FROOMS_GENTLEMAN3" }, { "SSANNE1FROOMS_YOUNGSTER", "SSANNE1FROOMS_COOLTRAINER_F", "SSANNE1FROOMS_GIRL2", "SSANNE1FROOMS_TM_BODY_SLAM" }, { "SSANNE1FROOMS_MIDDLE_AGED_MAN", "SSANNE1FROOMS_LITTLE_GIRL", "SSANNE1FROOMS_WIGGLYTUFF" }, { "SSANNE1FROOMS_GIRL1" }, { "SSANNE1FROOMS_GENTLEMAN2" }, { "SSANNE1FROOMS_GENTLEMAN1" }, } local function copyMaps() local ok, ser = pcall(require, "serpent") if ok and ser and ser.dump and ser.load then return ser.load(ser.dump(maps)) end -- deep-ish copy of the Anne maps only local function deep(t) if type(t) ~= "table" then return t end local o = {} for k, v in pairs(t) do o[k] = deep(v) end return o end return { SS_ANNE_1F = deep(maps.SS_ANNE_1F), SS_ANNE_1F_ROOMS = deep(maps.SS_ANNE_1F_ROOMS), } end local function roomDoors(hall) local doors = {} for i, w in ipairs(hall.warps) do if w.destMap == "SS_ANNE_1F_ROOMS" then doors[#doors + 1] = { index = i, w = w } end end table.sort(doors, function(a, b) return a.w.x < b.w.x end) return doors end local function objsAt(rooms, x, y) local names = {} local col, row = math.floor(x / 10), math.floor(y / 10) for _, o in ipairs(rooms.objects) do if math.floor(o.x / 10) == col and math.floor(o.y / 10) == row then names[#names + 1] = o.name end end table.sort(names) return names end local function hasAll(got, want) local set = {} for _, n in ipairs(got) do set[n] = true end for _, n in ipairs(want) do if not set[n] then return false, n end end return true end -- raw ROM extract order: leftmost door → rooms warp 6 do local doors = roomDoors(maps.SS_ANNE_1F) eq(doors[1].w.destWarp, 6, "raw extract: leftmost door → rooms #6") eq(doors[#doors].w.destWarp, 1, "raw extract: rightmost door → rooms #1") end local m = copyMaps() check(SsAnneLayout.apply(m) == true, "layout patch applies once") check(SsAnneLayout.apply(m) == false, "layout patch is idempotent") local data = { maps = m } local doors = roomDoors(m.SS_ANNE_1F) eq(#doors, 6, "six cabin doors") local prevCell for i, d in ipairs(doors) do eq(d.w.destWarp, i, ("L→R door %d → rooms warp %d"):format(i, i)) local mid, x, y = Warp.destination(data, d.w, nil) eq(mid, "SS_ANNE_1F_ROOMS", "door lands in 1F rooms") local cell = math.floor(y / 10) * 3 + math.floor(x / 10) if prevCell then check(cell > prevCell, ("door %d cell %d is after door %d cell %d"):format(i, cell, i - 1, prevCell)) end prevCell = cell local got = objsAt(m.SS_ANNE_1F_ROOMS, x, y) local ok, missing = hasAll(got, OG_BY_DOOR[i]) check(ok, ("door %d keeps OG occupant %s (got %s)") :format(i, tostring(missing), table.concat(got, ","))) end -- return warps: rooms #1 exits to leftmost hall cabin door (warp 8) eq(m.SS_ANNE_1F_ROOMS.warps[1].destWarp, 8, "rooms #1 returns to hall #8") eq(m.SS_ANNE_1F_ROOMS.warps[6].destWarp, 3, "rooms #6 returns to hall #3") S.finish()