feat: add Disease.isInfected and Disease.hasErupted
This commit is contained in:
1 parent
c214f5c127
commit
fc02e0fe8d
1 file changed
+131
+131
@@ -0,0 +1,131 @@
|
||||
-- Progressive affliction caught from a carrier's bite, distinct from both
|
||||
-- status.lua's per-turn buffs/debuffs (a fixed potency for a fixed
|
||||
-- duration) and curses.lua's item-bound penalties (permanent until a
|
||||
-- specific remedy). A disease sits silently through its incubation with no
|
||||
-- outward sign at all, then erupts and starts dealing damage every turn,
|
||||
-- worsening to a harsher stage on a fixed clock if nothing cures it first.
|
||||
-- Its tick damage routes through resistances.lua exactly like poison's own
|
||||
-- damage-over-time (see status.lua's POISON tick), so a plague-resistant
|
||||
-- survivor shrugs off what would gut anyone else. A disease is plain data
|
||||
-- on entity.disease, so it serializes with no special handling; the carrier
|
||||
-- tag a species bite leaves on entity.biteDisease (see monsters.lua) is
|
||||
-- copied on exactly like breath or ability already are.
|
||||
|
||||
local Resistances = require("resistances")
|
||||
|
||||
local Disease = {}
|
||||
|
||||
Disease.ROT = "rot"
|
||||
Disease.PLAGUE = "plague"
|
||||
Disease.PARASITES = "parasites"
|
||||
|
||||
-- Fixed order so a given rng draw always names the same affliction.
|
||||
Disease.order = { Disease.ROT, Disease.PLAGUE, Disease.PARASITES }
|
||||
|
||||
Disease.MAX_STAGE = 3
|
||||
|
||||
Disease.defs = {
|
||||
[Disease.ROT] = {
|
||||
name = "wound rot", incubation = 4, stageTurns = 8,
|
||||
stagePotency = { 2, 4, 7 },
|
||||
},
|
||||
[Disease.PLAGUE] = {
|
||||
name = "black plague", incubation = 6, stageTurns = 6,
|
||||
stagePotency = { 3, 6, 10 },
|
||||
},
|
||||
[Disease.PARASITES] = {
|
||||
name = "gut parasites", incubation = 3, stageTurns = 10,
|
||||
stagePotency = { 1, 3, 5 },
|
||||
},
|
||||
}
|
||||
|
||||
function Disease.isInfected(entity)
|
||||
return entity.disease ~= nil
|
||||
end
|
||||
|
||||
-- Whether the infection has finished incubating and is actively dealing
|
||||
-- damage each tick, as opposed to sitting silent and undetected.
|
||||
function Disease.hasErupted(entity)
|
||||
return entity.disease ~= nil and entity.disease.stage > 0
|
||||
end
|
||||
|
||||
-- Seeds a fresh infection of `key` on `entity`, refusing to pile a second
|
||||
-- affliction on top of one already incubating or erupted - the same
|
||||
-- one-at-a-time rule status.lua's own stacking already enforces for e.g.
|
||||
-- poison overwriting duration rather than compounding. Returns whether the
|
||||
-- infection actually took hold.
|
||||
function Disease.infect(entity, key)
|
||||
if Disease.isInfected(entity) then return false end
|
||||
local def = Disease.defs[key]
|
||||
if not def then return false end
|
||||
entity.disease = { key = key, incubation = def.incubation, stage = 0, sinceStage = 0 }
|
||||
return true
|
||||
end
|
||||
|
||||
-- Lifts whatever infection `entity` is carrying, incubating or already
|
||||
-- erupted alike. Returns false without state change when there was nothing
|
||||
-- to cure.
|
||||
function Disease.cure(entity)
|
||||
if not Disease.isInfected(entity) then return false end
|
||||
entity.disease = nil
|
||||
return true
|
||||
end
|
||||
|
||||
-- The stage's flat tick damage before resistance is applied, or 0 while
|
||||
-- still incubating (no outward symptom yet) or entirely uninfected.
|
||||
function Disease.stagePotency(entity)
|
||||
local infection = entity.disease
|
||||
if not infection or infection.stage == 0 then return 0 end
|
||||
return Disease.defs[infection.key].stagePotency[infection.stage]
|
||||
end
|
||||
|
||||
-- One tick per turn on the host's own clock: counts incubation down in
|
||||
-- silence, breaks out into stage one the moment it reaches zero, then
|
||||
-- deals that stage's potency each further tick and escalates to the next
|
||||
-- stage once it has lingered untreated for its full stageTurns window (the
|
||||
-- top stage simply keeps ticking rather than escalating further). Returns a
|
||||
-- log line for anything a player would actually notice - the eruption
|
||||
-- itself, an escalation, or a nonzero tick of damage - and nil for a turn
|
||||
-- that only ticked incubation down uneventfully.
|
||||
-- True only for the player, whose entity.name is the pronoun "you" - a
|
||||
-- subject that takes plain ("you break out", "you are wracked") verb forms
|
||||
-- in English rather than the third-person-singular ("breaks out", "is
|
||||
-- wracked") a named host like "orc" takes. Every message below branches on
|
||||
-- this exactly like Game:springTrap and Game:checkTerrainFor already branch
|
||||
-- on the same pronoun problem elsewhere in the engine.
|
||||
local function isPlayer(entity)
|
||||
return entity.kind == "player"
|
||||
end
|
||||
|
||||
function Disease.tick(entity)
|
||||
local infection = entity.disease
|
||||
if not infection then return nil end
|
||||
local def = Disease.defs[infection.key]
|
||||
if infection.stage == 0 then
|
||||
infection.incubation = infection.incubation - 1
|
||||
if infection.incubation <= 0 then
|
||||
infection.stage = 1
|
||||
infection.sinceStage = 0
|
||||
return isPlayer(entity) and string.format("you break out in %s", def.name)
|
||||
or string.format("%s breaks out in %s", entity.name, def.name)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
local dealt = Resistances.apply(entity, def.stagePotency[infection.stage], Resistances.POISON)
|
||||
entity.hp = entity.hp - dealt
|
||||
infection.sinceStage = infection.sinceStage + 1
|
||||
local line = nil
|
||||
if dealt > 0 then
|
||||
line = isPlayer(entity) and string.format("you are wracked by %s for %d", def.name, dealt)
|
||||
or string.format("%s is wracked by %s for %d", entity.name, def.name, dealt)
|
||||
end
|
||||
if infection.sinceStage >= def.stageTurns and infection.stage < Disease.MAX_STAGE then
|
||||
infection.stage = infection.stage + 1
|
||||
infection.sinceStage = 0
|
||||
line = isPlayer(entity) and string.format("your %s worsens", def.name)
|
||||
or string.format("%s's %s worsens", entity.name, def.name)
|
||||
end
|
||||
return line
|
||||
end
|
||||
|
||||
return Disease
|
||||
Reference in new issue
Block a user