rounds
The round of NINE BELLS: five patients, seven infected, nine tolls, and the contagion meter that decides how the night ends.
rounds
The round of NINE BELLS: five patients, seven infected, nine tolls, and the contagion meter that decides how the night ends.
What it puts in the world
M.start() — called once by the scene entrypoint — places the round and starts
a per-frame loop.
- Five patients (
Patient.component), spread up the district behind their quarantine sheets. Reaching one is a spoken moment; treating one is a hold that leaves the physician standing still in the open. Every treated lantern stays lit, and the lit lanterns are the progress display — the counter in the HUD is the second-best way to read it. - Seven infected (
Infected.component), pacing the stretches of street between them. Never killed: routed around, warded off by the censer's smoke, or calmed by a longer hold that sits them down beside a small lamp for good. - The nine bells (
game.bells), one everyNB.RULES.secondsPerBell. Each toll thickens the air and emboldens the infected; the ninth bricks the district shut.
Where the round goes
Placement is a fraction of the district's real extent, which it reads off
Camera2D's bounds on the CameraRig — the city slice writes them, so that is
the one published statement of how big Ashcross is. Each nominal point is then
dropped onto whatever NB.provide.solidAt says is solid beneath it. When the
city slice calls NB.claimVisual("city") the whole round is placed again, so it
lands on the real district whichever order the two slices finish in.
With no city at all it falls back to a 28 x 104 strip and stands on the skeleton floor, which is enough to play against.
Win and lose
| Win | every patient treated and "gate.reached" |
| Lose | contagion reaches NB.RULES.contagionMax, or the ninth bell tolls |
Contagion rises in standing miasma (NB.provide.inMiasmaAt), rises by
NB.RULES.contagionPerTouch on contact with an infected, rises with the air
itself after the fourth bell (bells.miasmaRise()), and decays in clean air.
The Vinegar Cloth tincture (NB.state.activeTincture) makes the physician
immune to all of it while it lasts.
Events
Emits "patient.reached", "patient.treated", "infected.warded",
"infected.treated", "hurt", "bell" and "phase".
Listens for "gate.reached", "hurt", "bell", "patient.treated",
"infected.treated", "visual.claimed" and "phase".
Reading it from outside
require("game.rounds") and require("game.nb") reach the live round from
anywhere, including an execute call. Patient also carries the round's
control surface, which is the shorter way in when you already have an entity:
local c = entity.find("patient_vetch").component.get("Patient")
c:round() -- the live blackboard
c:status() -- that patient
c:setPhase("play") -- drive the phase
c:raise("gate.reached", { x = 0, y = 0 }) -- raise an event on the live bus
c:treatNow() -- finish the hold now
entity.find("infected_sh1").component.get("Infected"):status()
The API
local Rounds = require("game.rounds")
Rounds.start() -- the entrypoint calls this once
Rounds.place() -- lay the round out over the district again
Rounds.reset() -- back to the top of the night, every lantern dark
Rounds.tick(dt) -- one frame; the loop calls it
Rounds.reachGate() -- the physician is at the lazaretto gate
Rounds.stop() -- drop the loop and every subscription
Rounds.patients -- the five entities
Rounds.infected -- the seven entities
Scoped to this part · feeds back into the world's score.