feat: extend tiles with Tiles.isLava and Tiles.isChasm
This commit is contained in:
1 parent
b7a55eabed
commit
598dfaf79e
3 files changed
+137
No files matched your search
@@ -14,6 +14,14 @@ Tiles.DOOR_LOCKED = "x"
|
|||||||
Tiles.TRAP = "^"
|
Tiles.TRAP = "^"
|
||||||
Tiles.WATER = "~"
|
Tiles.WATER = "~"
|
||||||
Tiles.RUBBLE = ":"
|
Tiles.RUBBLE = ":"
|
||||||
|
Tiles.LAVA = "%"
|
||||||
|
Tiles.CHASM = "V"
|
||||||
|
Tiles.ICE = "-"
|
||||||
|
Tiles.LEVER = "H"
|
||||||
|
Tiles.LEVER_PULLED = "I"
|
||||||
|
Tiles.VAULT_DOOR = "K"
|
||||||
|
Tiles.GATE_CLOSED = "8"
|
||||||
|
Tiles.GATE_OPEN = "9"
|
||||||
|
|
||||||
local props = {
|
local props = {
|
||||||
[Tiles.WALL] = { walkable = false, blocksSight = true, door = false },
|
[Tiles.WALL] = { walkable = false, blocksSight = true, door = false },
|
||||||
@@ -26,6 +34,14 @@ local props = {
|
|||||||
[Tiles.TRAP] = { walkable = true, blocksSight = false, door = false },
|
[Tiles.TRAP] = { walkable = true, blocksSight = false, door = false },
|
||||||
[Tiles.WATER] = { walkable = true, blocksSight = false, door = false },
|
[Tiles.WATER] = { walkable = true, blocksSight = false, door = false },
|
||||||
[Tiles.RUBBLE] = { walkable = true, blocksSight = false, door = false },
|
[Tiles.RUBBLE] = { walkable = true, blocksSight = false, door = false },
|
||||||
|
[Tiles.LAVA] = { walkable = true, blocksSight = false, door = false, lava = true },
|
||||||
|
[Tiles.CHASM] = { walkable = true, blocksSight = false, door = false, chasm = true },
|
||||||
|
[Tiles.ICE] = { walkable = true, blocksSight = false, door = false, ice = true },
|
||||||
|
[Tiles.LEVER] = { walkable = true, blocksSight = false, door = false },
|
||||||
|
[Tiles.LEVER_PULLED] = { walkable = true, blocksSight = false, door = false },
|
||||||
|
[Tiles.VAULT_DOOR] = { walkable = false, blocksSight = true, door = false, vault = true },
|
||||||
|
[Tiles.GATE_CLOSED] = { walkable = false, blocksSight = true, door = false, gate = true },
|
||||||
|
[Tiles.GATE_OPEN] = { walkable = true, blocksSight = false, door = false, gate = true },
|
||||||
}
|
}
|
||||||
|
|
||||||
local wallProps = props[Tiles.WALL]
|
local wallProps = props[Tiles.WALL]
|
||||||
@@ -50,4 +66,24 @@ function Tiles.isClosedDoor(glyph)
|
|||||||
return glyph == Tiles.DOOR_CLOSED or glyph == Tiles.DOOR_LOCKED
|
return glyph == Tiles.DOOR_CLOSED or glyph == Tiles.DOOR_LOCKED
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Tiles.isLava(glyph)
|
||||||
|
return Tiles.of(glyph).lava == true
|
||||||
|
end
|
||||||
|
|
||||||
|
function Tiles.isChasm(glyph)
|
||||||
|
return Tiles.of(glyph).chasm == true
|
||||||
|
end
|
||||||
|
|
||||||
|
function Tiles.isIce(glyph)
|
||||||
|
return Tiles.of(glyph).ice == true
|
||||||
|
end
|
||||||
|
|
||||||
|
function Tiles.isVaultDoor(glyph)
|
||||||
|
return Tiles.of(glyph).vault == true
|
||||||
|
end
|
||||||
|
|
||||||
|
function Tiles.isGate(glyph)
|
||||||
|
return Tiles.of(glyph).gate == true
|
||||||
|
end
|
||||||
|
|
||||||
return Tiles
|
return Tiles
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
-- Renown-gated titles: a flavor rank meta.lua's own banked renown climbs
|
||||||
|
-- through, one tier per crossed threshold, entirely separate from a
|
||||||
|
-- character's class - a title describes how far this save file's whole
|
||||||
|
-- history has come, not what any single run's build looked like.
|
||||||
|
|
||||||
|
local Titles = {}
|
||||||
|
|
||||||
|
Titles.LADDER = {
|
||||||
|
{ threshold = 0, name = "Whelp" },
|
||||||
|
{ threshold = 50, name = "Delver" },
|
||||||
|
{ threshold = 150, name = "Warden" },
|
||||||
|
{ threshold = 350, name = "Vanquisher" },
|
||||||
|
{ threshold = 700, name = "Warren Lord" },
|
||||||
|
{ threshold = 1500, name = "Undying" },
|
||||||
|
}
|
||||||
|
|
||||||
|
-- The highest title whose threshold `renown` clears, walked from the top of
|
||||||
|
-- the ladder down so a renown total that clears several thresholds at once
|
||||||
|
-- always resolves to the hardest-earned name rather than the first match.
|
||||||
|
function Titles.forRenown(renown)
|
||||||
|
for i = #Titles.LADDER, 1, -1 do
|
||||||
|
if renown >= Titles.LADDER[i].threshold then return Titles.LADDER[i].name end
|
||||||
|
end
|
||||||
|
return Titles.LADDER[1].name
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Renown still needed to clear the next threshold above `renown`, or nil
|
||||||
|
-- once renown has already cleared the top of the ladder and there is
|
||||||
|
-- nothing left to climb toward.
|
||||||
|
function Titles.toNext(renown)
|
||||||
|
for _, tier in ipairs(Titles.LADDER) do
|
||||||
|
if renown < tier.threshold then return tier.threshold - renown end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
return Titles
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
-- 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
|
||||||
Reference in new issue
Block a user