feat: extend horde with Horde.essenceFor and Horde.pool
This commit is contained in:
1 parent
58994a6132
commit
1f4ea71a1f
3 files changed
+198
-1
No files matched your search
+112
@@ -0,0 +1,112 @@
|
||||
-- Named bands layered over the player's raw satiation counter, the same
|
||||
-- shape sanity.lua already gives its own slow-moving meter: a plain number
|
||||
-- that Game:hungerTorchTick drains by one every round (untouched here),
|
||||
-- classified into FED/HUNGRY/WEAK/STARVING tiers that a caller reads back
|
||||
-- instead of re-deriving the cutoffs itself. Falling into WEAK or worse
|
||||
-- costs real attack and defense - wired into entity.lua's effectiveAttack/
|
||||
-- effectiveDefense alongside Sanity's own penalty, so a gaunt fighter hits
|
||||
-- and blocks softer without combat.lua needing to know hunger exists at
|
||||
-- all - and blocks the passive mending hungerTorchTick already grants from
|
||||
-- a worn ring, an ironclad set or consecrated ground: a starving adventurer
|
||||
-- can still down a potion, just not coast on a ring of regeneration while
|
||||
-- fading. STARVING alone keeps hungerTorchTick's own flat hp drain, exactly
|
||||
-- as before.
|
||||
--
|
||||
-- Eating is the mirror case: Hunger.eat folds fresh nutrition into the same
|
||||
-- counter, capped at Hunger.CAP, but food eaten while already at that cap
|
||||
-- is entirely wasted and leaves the diner Status.SLOW for a few turns - the
|
||||
-- same overfull stumble a real glutton earns, reusing a status the engine
|
||||
-- already ticks, serializes and renders with no special handling of its own.
|
||||
|
||||
local Status = require("status")
|
||||
|
||||
local Hunger = {}
|
||||
|
||||
Hunger.FED = "fed"
|
||||
Hunger.HUNGRY = "hungry"
|
||||
Hunger.WEAK = "weak"
|
||||
Hunger.STARVING = "starving"
|
||||
|
||||
-- Starting ration for a fresh game (Game.new) and the ceiling Hunger.eat
|
||||
-- refuses to bank past. Comfortably above START so a couple of found
|
||||
-- rations can stack up before a long dive, without letting the pool grow
|
||||
-- without bound.
|
||||
Hunger.START = 1000
|
||||
Hunger.CAP = 1200
|
||||
|
||||
-- Tier ceilings: a value at or below HUNGRY_MAX but above WEAK_MAX reads as
|
||||
-- HUNGRY, and so on downward. 0 itself is always STARVING regardless of
|
||||
-- where these ceilings sit.
|
||||
Hunger.HUNGRY_MAX = 300
|
||||
Hunger.WEAK_MAX = 100
|
||||
|
||||
Hunger.BLOAT_DURATION = 4
|
||||
|
||||
local ATTACK_PENALTY = {
|
||||
[Hunger.FED] = 0, [Hunger.HUNGRY] = 0, [Hunger.WEAK] = -2, [Hunger.STARVING] = -4,
|
||||
}
|
||||
local DEFENSE_PENALTY = {
|
||||
[Hunger.FED] = 0, [Hunger.HUNGRY] = 0, [Hunger.WEAK] = -1, [Hunger.STARVING] = -3,
|
||||
}
|
||||
|
||||
-- A fresh entity - or a monster, which never accrues hunger of its own
|
||||
-- since nothing ever calls Hunger.tick for one - reads as fully fed.
|
||||
function Hunger.current(entity)
|
||||
return entity.satiation or Hunger.CAP
|
||||
end
|
||||
|
||||
function Hunger.tierOf(entity)
|
||||
local value = Hunger.current(entity)
|
||||
if value <= 0 then return Hunger.STARVING end
|
||||
if value <= Hunger.WEAK_MAX then return Hunger.WEAK end
|
||||
if value <= Hunger.HUNGRY_MAX then return Hunger.HUNGRY end
|
||||
return Hunger.FED
|
||||
end
|
||||
|
||||
function Hunger.attackPenalty(entity)
|
||||
return ATTACK_PENALTY[Hunger.tierOf(entity)]
|
||||
end
|
||||
|
||||
function Hunger.defensePenalty(entity)
|
||||
return DEFENSE_PENALTY[Hunger.tierOf(entity)]
|
||||
end
|
||||
|
||||
-- WEAK or worse blocks the passive regen hungerTorchTick otherwise grants
|
||||
-- from a ring, a set bonus or friendly weather - a fading body has nothing
|
||||
-- left over to spend on mending.
|
||||
function Hunger.suppressesRegen(entity)
|
||||
local tier = Hunger.tierOf(entity)
|
||||
return tier == Hunger.WEAK or tier == Hunger.STARVING
|
||||
end
|
||||
|
||||
-- One round of drain. Returns a log line only when the tier actually
|
||||
-- changes, except STARVING which - matching the flat drain this replaces -
|
||||
-- reports and bites for 1 hp every single round it holds, not just on the
|
||||
-- turn it is first reached.
|
||||
function Hunger.tick(entity)
|
||||
local before = Hunger.tierOf(entity)
|
||||
entity.satiation = math.max(0, Hunger.current(entity) - 1)
|
||||
local after = Hunger.tierOf(entity)
|
||||
if after == Hunger.STARVING then
|
||||
entity.hp = entity.hp - 1
|
||||
return "you are starving"
|
||||
end
|
||||
if after ~= before then
|
||||
return "you feel " .. after
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Feeds `nutrition` in, clamped at Hunger.CAP. Returns true when the diner
|
||||
-- was already at the cap - all of it wasted, and left Status.SLOW for
|
||||
-- Hunger.BLOAT_DURATION turns - or false for an ordinary meal that landed.
|
||||
function Hunger.eat(entity, nutrition)
|
||||
local wasFull = Hunger.current(entity) >= Hunger.CAP
|
||||
entity.satiation = math.min(Hunger.CAP, Hunger.current(entity) + nutrition)
|
||||
if wasFull then
|
||||
Status.apply(entity, Status.SLOW, Hunger.BLOAT_DURATION, 1)
|
||||
end
|
||||
return wasFull
|
||||
end
|
||||
|
||||
return Hunger
|
||||
Reference in new issue
Block a user