chroma_solstice/world_seed.lua
2026-08-07 01:39:47 -04:00

70 lines
2.7 KiB
Lua

-- Make a first 18x18 layout from the exit links preserved in the legacy saves.
-- Some old test rooms share the same one-way exit, so a grid cannot represent
-- every such link at once. Those rooms are still placed, but isolated, rather
-- than silently overwriting a room that already occupies that neighbour.
function seedWorldFromLegacyExits(world)
local available = {}
for _, name in ipairs(world:listRoomNames()) do available[name] = true end
local legacy = {}
for name in pairs(available) do
local raw = readFromSource("rooms/_pre_migration_backup/" .. name .. ".sav")
if raw then
local ok, save = pcall(TSerial.unpack, raw)
if ok and type(save) == "table" then legacy[name] = save.exits or {} end
end
end
world.rooms, world.roomByName = {}, {}
local root = available.start and "start" or world:listRoomNames()[1]
if not root then return { placed = 0, links = 0, conflicts = 0 } end
world:_putRoom(root, 9, 11)
local queue, queued = { root }, { [root] = true }
local directions = {
top = { x = 0, y = -1 }, right = { x = 1, y = 0 },
bottom = { x = 0, y = 1 }, left = { x = -1, y = 0 },
}
local order = { "top", "right", "bottom", "left" }
local links, conflicts = 0, 0
local index = 1
while index <= #queue do
local name = queue[index]
local source = world:roomLocation(name)
for _, exit in ipairs(order) do
local target = legacy[name] and legacy[name][exit]
target = target and tostring(target)
local direction = directions[exit]
if target and available[target] then
local x, y = source.x + direction.x, source.y + direction.y
local occupied, known = world:roomAt(x, y), world:roomLocation(target)
if world:isInBounds(x, y) and (not occupied or occupied == target) and (not known or (known.x == x and known.y == y)) then
if not known then world:_putRoom(target, x, y) end
links = links + 1
if not queued[target] then table.insert(queue, target); queued[target] = true end
else
conflicts = conflicts + 1
end
end
end
index = index + 1
end
-- Keep every migrated room visible/selectable without creating accidental
-- exits between the disconnected legacy variants.
for _, name in ipairs(world:listRoomNames()) do
if not world:roomLocation(name) then
local placed = false
for y = 1, world.height do
for x = 1, world.width do
if not world:roomAt(x, y) then
local nearby = false
for dy = -1, 1 do for dx = -1, 1 do if world:roomAt(x + dx, y + dy) then nearby = true end end end
if not nearby then world:_putRoom(name, x, y); placed = true; break end
end
end
if placed then break end
end
end
end
world:save()
return { placed = #world.rooms, links = links, conflicts = conflicts }
end