65 lines
2.3 KiB
Lua
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
|