FireSystem¶
FireSystem
| Phase · priority | Environment · 40 |
| Reads | OnFire, Combustible; temperature, ignition_point, fuel, water_level, controlled_fire |
| Writes | OnFire (add/remove); temperature via PropagationIntent on channel heat; fuel; events ignition, fire_spread, extinguished |
| Settings | HeatOutputPerFuel, FuelBurnPerHour, ExtinguishWaterThreshold, DeltaFactor 0.8, MinThreshold 0.5 |
| Status | designed · Phase 1 (#34) |
| PLAN | §11.1, §11.3, §11.5, §18.5, §10.2 (ownership rule) |
| Player | Fire and heat · The campfire |
Combustion and heat generation. For every OnFire node: radiate heat as a propagation, burn fuel, check whether neighbours have crossed their kindling point, and check whether water has put the fire out. Fire spreads by heat only; there is no "fire jumps" rule.
foreach (var node in view.NodesWithComponent("OnFire"))
{
var heat = view.GetOrDefault(node, "fuel", 0f) > 0 ? s.HeatOutputPerFuel * … : 0f;
yield return new PropagationIntent(node, channel: "heat", attribute: "temperature",
initialIntensity: heat, deltaFactor: 0.8f, minThreshold: 0.5f);
yield return new DeltaAttributeIntent(node, "fuel", -ctx.PerTick(s.FuelBurnPerDay));
foreach (var n in view.GetAdjacentLocations(node)) // ignition — the trace needs the numbers
{
var t = view.GetOrDefault(n, "temperature", 0f); var ig = view.GetOrDefault(n, "ignition_point", float.MaxValue);
if (t >= ig && view.HasComponent(n, "Combustible") && !view.HasComponent(n, "OnFire"))
yield return new AddComponentIntent(n, "OnFire") { Inputs = new() { [$"{n}.temperature"] = t, [$"{n}.ignition_point"] = ig } };
}
if (view.GetOrDefault(node, "water_level", 0f) >= s.ExtinguishWaterThreshold || fuel <= 0)
yield return new RemoveComponentIntent(node, "OnFire"); // baseline physics lives here, not in a rule
}
Reach is bounded by permeability × threshold, never a hop cap. The village's edges (0.3 open air, 0.8 between adjacent buildings, 0.4 fire pit → inn) are the firebreaks; a fire that reaches too far has the wrong fuel or intensity, not a missing radius.
Water extinguishes fire here (PLAN §18.5, invariant 10), not in data/rules/: two places that can disagree about whether a fire goes out is the bug.
Campfire: controlled_fire: true, ignition_point: 9999 — it burns, radiates, consumes fuel, never spreads to itself, and can heat the inn's wall.
Hot-toggle: off, burning nodes stay OnFire and stop radiating; spreading halts; on, it resumes from the current state. Trace: ignition intents carry Inputs so Explain can say because the smithy's heat crossed 250°; propagation records keep per-hop intensities.
History¶
| Phase | Change |
|---|---|
| 1 | Introduced; fuel burn per hour; ignition intents carry Inputs; extinguish-on-water in the system. |
See also: HeatSystem · Intents and the resolver (propagation)