61 lines
1.6 KiB
Lua
61 lines
1.6 KiB
Lua
-- Owns every floor. Each level's layout is derived from the world seed and its
|
|
-- depth alone, through a private rng that never touches the world rng stream, so
|
|
-- a floor generates identically no matter when it is first entered. Generated
|
|
-- floors are cached, which is what makes revisiting one restore its exact state.
|
|
|
|
local Rng = require("rng")
|
|
local Builder = require("builder")
|
|
local Level = require("level")
|
|
|
|
local Dungeon = {}
|
|
Dungeon.__index = Dungeon
|
|
|
|
local SALT = 0x9E3779B97F4A7C15
|
|
|
|
function Dungeon.new(worldSeed, options)
|
|
return setmetatable({
|
|
worldSeed = worldSeed,
|
|
options = options or {},
|
|
levels = {},
|
|
}, Dungeon)
|
|
end
|
|
|
|
function Dungeon:levelSeed(depth)
|
|
return math.tointeger(self.worldSeed ~ (depth * SALT)) or 0
|
|
end
|
|
|
|
function Dungeon:get(depth)
|
|
if not self.levels[depth] then
|
|
local rng = Rng.new(self:levelSeed(depth))
|
|
self.levels[depth] = Builder.build(depth, rng, self.options)
|
|
end
|
|
return self.levels[depth]
|
|
end
|
|
|
|
function Dungeon:isGenerated(depth)
|
|
return self.levels[depth] ~= nil
|
|
end
|
|
|
|
function Dungeon:toData()
|
|
local depths = {}
|
|
for depth in pairs(self.levels) do
|
|
depths[#depths + 1] = depth
|
|
end
|
|
table.sort(depths)
|
|
local stored = {}
|
|
for _, depth in ipairs(depths) do
|
|
stored[#stored + 1] = { depth = depth, level = self.levels[depth]:toData() }
|
|
end
|
|
return { worldSeed = self.worldSeed, options = self.options, levels = stored }
|
|
end
|
|
|
|
function Dungeon.fromData(snapshot)
|
|
local dungeon = Dungeon.new(snapshot.worldSeed, snapshot.options)
|
|
for _, entry in ipairs(snapshot.levels) do
|
|
dungeon.levels[entry.depth] = Level.fromData(entry.level)
|
|
end
|
|
return dungeon
|
|
end
|
|
|
|
return Dungeon
|