feat: build out builder
This commit is contained in:
1 parent
364ea34db4
commit
72e2969146
1 file changed
+131
+131
@@ -855,14 +855,145 @@ function Builder.build(depth, rng, options)
|
|||||||
-- can never end up sealed unreachably deep inside solid rock no digger
|
-- can never end up sealed unreachably deep inside solid rock no digger
|
||||||
-- could ever find. Its monster and loot markers (see gen/prefab.lua) draw
|
-- could ever find. Its monster and loot markers (see gen/prefab.lua) draw
|
||||||
-- from the same eligible roster and item tables every earlier pass in this
|
-- from the same eligible roster and item tables every earlier pass in this
|
||||||
|
-- floor already used. Drawn dead last of all before the grave below -
|
||||||
|
-- which must stay the true last word (see its own comment) - so this can
|
||||||
|
-- never perturb any earlier system's rng sequence either.
|
||||||
|
local prefabVaults = {}
|
||||||
|
if depth >= 3 and rng:chance(1, 5) then
|
||||||
|
local vault = Prefab.vaults[rng:range(1, #Prefab.vaults)]
|
||||||
|
local w, h = Prefab.size(vault)
|
||||||
|
local vaultReach = reachSet(map, upX, upY, false)
|
||||||
|
for _ = 1, 40 do
|
||||||
|
local ox = rng:range(2, map.width - w)
|
||||||
|
local oy = rng:range(2, map.height - h)
|
||||||
|
if Prefab.fits(map, vault, ox, oy) then
|
||||||
|
local untouched = true
|
||||||
|
for y = oy, oy + h - 1 do
|
||||||
|
for x = ox, ox + w - 1 do
|
||||||
|
if map:get(x, y) ~= Tiles.WALL then untouched = false end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local bordersReachable = false
|
||||||
|
for y = oy - 1, oy + h do
|
||||||
|
for x = ox - 1, ox + w do
|
||||||
|
local onPerimeter = x < ox or x > ox + w - 1 or y < oy or y > oy + h - 1
|
||||||
|
if onPerimeter and map:inBounds(x, y) and vaultReach[map:index(x, y)] then
|
||||||
|
bordersReachable = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if untouched and bordersReachable then
|
||||||
|
local stamp = Prefab.stamp(map, vault, ox, oy)
|
||||||
|
for _, spot in ipairs(stamp.treasure) do
|
||||||
|
floorItems[#floorItems + 1] = { x = spot.x, y = spot.y, item = Vaults.treasure(rng, depth) }
|
||||||
|
mark(spot.x, spot.y)
|
||||||
|
end
|
||||||
|
for _, spot in ipairs(stamp.loot) do
|
||||||
|
floorItems[#floorItems + 1] = { x = spot.x, y = spot.y, item = rollItem(rng, depth) }
|
||||||
|
mark(spot.x, spot.y)
|
||||||
|
end
|
||||||
|
for _, spot in ipairs(stamp.monsters) do
|
||||||
|
local spec = eligible[rng:range(1, #eligible)]
|
||||||
|
local monster = Monsters.create(spec, #entities + 1, spot.x, spot.y, depth)
|
||||||
|
monster.awareness = Stealth.DORMANT
|
||||||
|
entities[#entities + 1] = monster
|
||||||
|
mark(spot.x, spot.y)
|
||||||
|
end
|
||||||
|
prefabVaults[#prefabVaults + 1] = { name = stamp.name, x = ox, y = oy, w = w, h = h }
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- A net turns up from depth five on, rarer than a miner's pick, drawn dead
|
||||||
|
-- last of all - after even the prefab vault pass above - so it can never
|
||||||
|
-- perturb any earlier system's rng sequence: the one way a run carries the
|
||||||
|
-- means to subdue a battered monster alive instead of finishing it off
|
||||||
|
-- (see captives.lua), rather than a strictly worse copy of an ordinary
|
||||||
|
-- weapon. Gated this deep so it can never turn up in the fixed shallow
|
||||||
|
-- worlds the win-condition tests build with a low --maxDepth.
|
||||||
|
if depth >= 5 and rng:chance(1, 6) then
|
||||||
|
local x, y = pickFree(reachable, rng, freeFloor)
|
||||||
|
if x then
|
||||||
|
floorItems[#floorItems + 1] = { x = x, y = y, item = Items.net() }
|
||||||
|
mark(x, y)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- A rift shard turns up from depth four on, rarer than a net, drawn dead
|
||||||
|
-- last of all - after the net above - so it can never perturb any earlier
|
||||||
|
-- system's rng sequence: fuel for the one crossing a rift (below) actually
|
||||||
|
-- costs (see branches.lua), found a couple of floors ahead of where a rift
|
||||||
|
-- can itself first appear so a run always has a real chance to be carrying
|
||||||
|
-- one the day it matters.
|
||||||
|
if depth >= 4 and rng:chance(1, 6) then
|
||||||
|
local x, y = pickFree(reachable, rng, freeFloor)
|
||||||
|
if x then
|
||||||
|
floorItems[#floorItems + 1] = { x = x, y = y, item = Items.riftstone() }
|
||||||
|
mark(x, y)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- A rift tears open rarer still, only from depth six on, drawn dead last
|
||||||
|
-- of all - after the shard above - so it can never perturb any earlier
|
||||||
|
-- system's rng sequence: a shimmering, unstable seam in the floor a
|
||||||
|
-- carried rift shard alone can stabilize into a crossing onto a short,
|
||||||
|
-- harsher pocket floor (see branches.lua and Game:enterRift). Plain
|
||||||
|
-- position-keyed level data exactly like a shrine or a node, never a tile
|
||||||
|
-- of its own, so it needs no new entry in tiles.lua.
|
||||||
|
local rifts = {}
|
||||||
|
if depth >= 6 and rng:chance(1, 8) then
|
||||||
|
local x, y = pickFree(reachable, rng, freeFloor)
|
||||||
|
if x then
|
||||||
|
rifts[#rifts + 1] = { x = x, y = y }
|
||||||
|
mark(x, y)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- A previous run's grave turns up rarer than a pick, dead last of all -
|
||||||
|
-- after the lockpick, chest, secret door, biome, gate and net pass above -
|
||||||
|
-- so it can never perturb any earlier system's rng sequence: cross-run
|
||||||
|
-- bones (see graves.lua), rolled only when the caller actually supplies
|
||||||
|
-- any - a run without --meta, or a fresh meta with no recorded deaths
|
||||||
|
-- yet, makes no extra rng draw here at all, so its floors stay
|
||||||
|
-- byte-identical to a build with no graves system in play.
|
||||||
|
if options and options.graves and #options.graves > 0 then
|
||||||
|
local eligibleGraves = Graves.eligibleFor(options.graves, depth)
|
||||||
|
if #eligibleGraves > 0 and rng:chance(1, 5) then
|
||||||
|
local x, y = pickFree(reachable, rng, freeFloor)
|
||||||
|
if x then
|
||||||
|
local grave = eligibleGraves[rng:range(1, #eligibleGraves)]
|
||||||
|
floorItems[#floorItems + 1] = { x = x, y = y, item = Graves.floorItem(grave) }
|
||||||
|
mark(x, y)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return Level.new({
|
return Level.new({
|
||||||
depth = depth,
|
depth = depth,
|
||||||
generator = generator,
|
generator = generator,
|
||||||
|
weather = weather,
|
||||||
|
biome = biome.key,
|
||||||
map = map,
|
map = map,
|
||||||
entities = entities,
|
entities = entities,
|
||||||
floorItems = floorItems,
|
floorItems = floorItems,
|
||||||
traps = traps,
|
traps = traps,
|
||||||
lights = lights,
|
lights = lights,
|
||||||
|
hazards = hazards,
|
||||||
|
shrines = shrines,
|
||||||
|
questBoards = questBoards,
|
||||||
|
cauldrons = cauldrons,
|
||||||
|
nodes = nodes,
|
||||||
|
chests = chests,
|
||||||
|
vaultLevers = vaultLevers,
|
||||||
|
vaultDoors = vaultDoors,
|
||||||
|
secretDoors = secretDoors,
|
||||||
|
blocks = blocks,
|
||||||
|
plates = plates,
|
||||||
|
gates = gates,
|
||||||
|
prefabVaults = prefabVaults,
|
||||||
|
rifts = rifts,
|
||||||
dark = dark,
|
dark = dark,
|
||||||
explored = {},
|
explored = {},
|
||||||
upX = upX, upY = upY,
|
upX = upX, upY = upY,
|
||||||
|
|||||||
Reference in new issue
Block a user