feat: add Shrines.costFor and Shrines.curseChance
This commit is contained in:
1 parent
3fe3f21de4
commit
23fdd0245e
1 file changed
+111
+111
@@ -0,0 +1,111 @@
|
|||||||
|
-- Wayside altars the player can pray at for a permanent boon at a gold price.
|
||||||
|
-- A shrine's favor wears thin with use: each prayer at the same altar is more
|
||||||
|
-- likely to backfire into a curse than the last, so greedily re-praying at a
|
||||||
|
-- single shrine is a real risk rather than a free stat pump. Shrines are plain
|
||||||
|
-- data on level.shrines, keyed by position, so they serialize like traps and
|
||||||
|
-- hazards do with no special save-format handling.
|
||||||
|
|
||||||
|
local Status = require("status")
|
||||||
|
local Curses = require("curses")
|
||||||
|
|
||||||
|
local Shrines = {}
|
||||||
|
|
||||||
|
Shrines.WAR = "war"
|
||||||
|
Shrines.VITALITY = "vitality"
|
||||||
|
Shrines.WISDOM = "wisdom"
|
||||||
|
Shrines.FORTUNE = "fortune"
|
||||||
|
|
||||||
|
-- Fixed order so a given rng draw always names the same kind.
|
||||||
|
Shrines.order = { Shrines.WAR, Shrines.VITALITY, Shrines.WISDOM, Shrines.FORTUNE }
|
||||||
|
|
||||||
|
Shrines.names = {
|
||||||
|
[Shrines.WAR] = "shrine of war",
|
||||||
|
[Shrines.VITALITY] = "shrine of vitality",
|
||||||
|
[Shrines.WISDOM] = "shrine of wisdom",
|
||||||
|
[Shrines.FORTUNE] = "shrine of fortune",
|
||||||
|
}
|
||||||
|
|
||||||
|
local BASE_COST = 20
|
||||||
|
local COST_STEP = 10
|
||||||
|
|
||||||
|
-- Prayer cost climbs with prior use at this specific altar, the same shape as
|
||||||
|
-- its rising curse risk: the shrine asks more and gives worse odds once its
|
||||||
|
-- patience with the petitioner is spent.
|
||||||
|
function Shrines.costFor(shrine)
|
||||||
|
return BASE_COST + shrine.uses * COST_STEP
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Numerator over a denominator of 6: the first prayer risks 1-in-6, climbing
|
||||||
|
-- by one for every prior use, capped at a certainty of 6-in-6.
|
||||||
|
function Shrines.curseChance(shrine)
|
||||||
|
return math.min(shrine.uses + 1, 6), 6
|
||||||
|
end
|
||||||
|
|
||||||
|
local function grantBlessing(player, kind)
|
||||||
|
if kind == Shrines.WAR then
|
||||||
|
player.attack = player.attack + 1
|
||||||
|
player.baseAttack = player.baseAttack + 1
|
||||||
|
return "your grip tightens with martial favor"
|
||||||
|
elseif kind == Shrines.VITALITY then
|
||||||
|
player.maxHp = player.maxHp + 5
|
||||||
|
player.hp = player.hp + 5
|
||||||
|
return "vigor floods through you"
|
||||||
|
elseif kind == Shrines.WISDOM then
|
||||||
|
player.maxMana = player.maxMana + 3
|
||||||
|
player.mana = player.maxMana
|
||||||
|
return "arcane insight fills your mind"
|
||||||
|
else
|
||||||
|
local cleansed = false
|
||||||
|
local kept = {}
|
||||||
|
for _, active in ipairs(player.statuses) do
|
||||||
|
if active.kind == Status.POISON or active.kind == Status.BURNING
|
||||||
|
or active.kind == Status.WEAKEN or active.kind == Status.SLOW then
|
||||||
|
cleansed = true
|
||||||
|
else
|
||||||
|
kept[#kept + 1] = active
|
||||||
|
end
|
||||||
|
end
|
||||||
|
player.statuses = kept
|
||||||
|
Status.apply(player, Status.SHIELD, 10, 1)
|
||||||
|
if Curses.cleanseWorn(player) > 0 then cleansed = true end
|
||||||
|
if cleansed then
|
||||||
|
return "fortune cleanses your ailments and wards you"
|
||||||
|
end
|
||||||
|
return "fortune wards you against harm"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function inflictCurse(player)
|
||||||
|
Status.apply(player, Status.WEAKEN, 8, 1)
|
||||||
|
Status.apply(player, Status.SLOW, 8, 1)
|
||||||
|
return "the shrine's favor turns against you"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Attempts a prayer at `shrine` for `game.player`. When the price cannot be
|
||||||
|
-- met nothing is spent and this returns (false, lines). Otherwise the gold is
|
||||||
|
-- always spent, the shrine's use count always advances (so its price and
|
||||||
|
-- curse odds keep climbing), and this returns (true, lines) describing
|
||||||
|
-- whichever of a blessing or a curse landed.
|
||||||
|
function Shrines.pray(game, shrine)
|
||||||
|
local player = game.player
|
||||||
|
local cost = Shrines.costFor(shrine)
|
||||||
|
if player.gold < cost then
|
||||||
|
return false, { "you cannot afford " .. Shrines.names[shrine.kind] .. "'s price" }
|
||||||
|
end
|
||||||
|
player.gold = player.gold - cost
|
||||||
|
local numerator, denominator = Shrines.curseChance(shrine)
|
||||||
|
local cursed = game.rng:chance(numerator, denominator)
|
||||||
|
shrine.uses = shrine.uses + 1
|
||||||
|
local line
|
||||||
|
if cursed then
|
||||||
|
line = inflictCurse(player)
|
||||||
|
else
|
||||||
|
line = grantBlessing(player, shrine.kind)
|
||||||
|
end
|
||||||
|
return true, {
|
||||||
|
string.format("you pray at the %s for %d gold", Shrines.names[shrine.kind], cost),
|
||||||
|
line,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
return Shrines
|
||||||
Reference in new issue
Block a user