132 lines
5.3 KiB
Lua
132 lines
5.3 KiB
Lua
-- 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
|