Files
warren/src/vaults.lua
T

65 lines
2.3 KiB
Lua

-- Lever-gated treasure rooms. A vault door only swings open once every lever
-- sharing its id has been pulled; the builder places the door at a doorway
-- pinch point and scatters its levers only on the side already reachable
-- without crossing it, so the puzzle is always solvable and the reward
-- sealed behind the door is always genuinely gated by it (see builder.lua's
-- vault placement, drawn dead last so it never perturbs any earlier
-- system's rng sequence).
local Items = require("items")
local Affixes = require("affixes")
local Vaults = {}
local treasureWeapons = {
{ name = "vault greatsword", power = 7 },
{ name = "vault warhammer", power = 8 },
}
local treasureArmors = {
{ name = "vault aegis", power = 6 },
}
-- A guaranteed affix on a base already well above anything the floor's own
-- loot table can roll at this depth - the deterministic reward for solving
-- the puzzle, distinct from a normal drop's coin-flip affix (see
-- affixes.rollWeapon/rollArmor).
function Vaults.treasure(rng, depth)
if rng:chance(1, 2) then
local base = treasureWeapons[rng:range(1, #treasureWeapons)]
local item = Items.weapon(base.name, base.power + depth // 3)
return Affixes.decorate(item, Affixes.weapon[rng:range(1, #Affixes.weapon)])
end
local base = treasureArmors[rng:range(1, #treasureArmors)]
local item = Items.armor(base.name, base.power + depth // 3)
return Affixes.decorate(item, Affixes.armor[rng:range(1, #Affixes.armor)])
end
function Vaults.doorFor(level, id)
for _, door in ipairs(level.vaultDoors) do
if door.id == id then return door end
end
return nil
end
local function allPulled(level, id)
for _, lever in ipairs(level.vaultLevers) do
if lever.id == id and not lever.pulled then return false end
end
return true
end
-- Pulls `lever`, an idempotent no-op returning false if it was already
-- thrown. Returns (true, door) the instant this pull completes every lever
-- sharing its id and the door has not opened yet, or (true, nil) for a pull
-- that leaves the vault still sealed (or already open).
function Vaults.pull(level, lever)
if lever.pulled then return false end
lever.pulled = true
if not allPulled(level, lever.id) then return true, nil end
local door = Vaults.doorFor(level, lever.id)
if door and not door.opened then return true, door end
return true, nil
end
return Vaults