P4 hazards: food spoilage with rot speed setting, smoking rack and salt, food poisoning, harsher blizzards, hard winters with lake ice, lightning on trees, snow on roofs (protocol 11)

This commit is contained in:
Paul Bailey
2026-11-05 11:49:13 +00:00
parent 657c3140fe
commit 3389ec9a21
27 changed files with 1541 additions and 56 deletions

View File

@@ -37,6 +37,8 @@ var _shelter_left := 0.0
var _rest_build := 0.0
## Food buffs: id -> {name, left (s), stamina_regen, health_regen (multipliers)}.
var buffs: Dictionary = {}
var sick := 0.0 ## seconds of food poisoning left (P4): slow stamina, can't eat
const SICK_SECONDS := 60.0
var _hurt_cd := 0.0 ## no natural healing for a few seconds after a hit
var cause := "" ## what last hurt you, as the death screen says it ("You froze")
var drain_mult := 1.0 ## hunger and diet drain (a server's difficulty, rules.gd)
@@ -128,7 +130,9 @@ func step(dt: float) -> void:
wet = maxf(wet - dt * (3.0 if heat > 0.3 else 1.0), 0.0) # fires dry you off
target = clampf(target, 0.0, MAX)
# Warm up faster than you cool down: getting to a fire should feel good.
warmth = move_toward(warmth, target, (7.0 if target > warmth else 1.6) * dt)
# (Out in a blizzard you lose it twice as fast.)
var cool := 1.6 * (2.0 if world.weather.blizzard_chill(sheltered) > 0.0 else 1.0)
warmth = move_toward(warmth, target, (7.0 if target > warmth else cool) * dt)
hunger = maxf(hunger - HUNGER_DRAIN * drain_mult * dt * (1.5 if warmth < 30.0 else 1.0), 0.0)
@@ -137,6 +141,7 @@ func step(dt: float) -> void:
else:
var malnourished := diet_lacking().size() >= 2
stamina = minf(stamina + STAMINA_REGEN * (1.5 if rested > 0.0 else 1.0) * buff_mult("stamina_regen")
* (0.5 if sick > 0.0 else 1.0)
* (0.7 if malnourished else 1.0) * dt, MAX)
for g in DIET_GROUPS:
@@ -148,6 +153,7 @@ func step(dt: float) -> void:
if buffs[id].left <= 0.0:
buffs.erase(id)
_hurt_cd = maxf(_hurt_cd - dt, 0.0)
sick = maxf(sick - dt, 0.0)
var dmg := 0.0
if hunger <= 0.0:
@@ -196,6 +202,8 @@ func _update_statuses() -> void:
statuses.append("%s (need %s)" % ["Malnourished" if lacking.size() >= 2 else "Poor diet", ", ".join(need)])
elif balanced_diet():
statuses.append("Balanced diet")
if sick > 0.0:
statuses.append("Food poisoning")
if sheltered:
statuses.append("Sheltered")
if cozy:
@@ -230,6 +238,13 @@ func eat(food: Dictionary) -> void:
func soak() -> void:
wet = WET_SECONDS
## Something you ate disagreed with you (raw meat, raw fish): stamina comes
## back at half speed and you can't keep anything down for a minute.
func poison() -> void:
sick = SICK_SECONDS
_update_statuses()
changed.emit()
## After a night's sleep: a little hungrier, dry, warm and rested.
func after_sleep(seconds: float) -> void:
hunger = maxf(hunger - HUNGER_DRAIN * seconds * 0.3, 0.0)
@@ -284,7 +299,7 @@ func add_buff(b: Dictionary) -> void:
func to_data() -> Dictionary:
return {"health": health, "stamina": stamina, "hunger": hunger, "warmth": warmth, "wet": wet, "rested": rested,
"buffs": buffs.duplicate(true), "diet": diet.duplicate()}
"buffs": buffs.duplicate(true), "diet": diet.duplicate(), "sick": sick}
func load_data(d: Dictionary) -> void:
health = float(d.get("health", health))
@@ -293,6 +308,7 @@ func load_data(d: Dictionary) -> void:
warmth = float(d.get("warmth", warmth))
wet = float(d.get("wet", 0.0))
rested = float(d.get("rested", 0.0))
sick = float(d.get("sick", 0.0))
buffs = (d.get("buffs", {}) as Dictionary).duplicate(true)
# Older saves have no diet: start it where a new world does.
var sd: Dictionary = d.get("diet", {})