M2.4: the server decides online (characters, inventory, stats, death, owned graves, per-player saves); death screen with Respawn after 3 s

This commit is contained in:
Paul Bailey
2026-11-04 19:18:31 +00:00
parent 8e8f10eb96
commit 35a656e996
16 changed files with 1124 additions and 477 deletions

View File

@@ -38,6 +38,7 @@ var _rest_build := 0.0
## Food buffs: id -> {name, left (s), stamina_regen, health_regen (multipliers)}.
var buffs: Dictionary = {}
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")
signal hurt(amount: float, from: Vector3)
const HURT_NO_REGEN := 6.0
@@ -71,19 +72,20 @@ func balanced_diet() -> bool:
return false
return true
var player: CharacterBody3D
var player: Node3D ## the local player, or a server_player.gd on a server
var world: Node3D
var _stamina_wait := 0.0
func _process(delta: float) -> void:
if world != null and not world.menu_mode:
# (Online, the server runs our stats and sends them: player_net.gd.)
if world != null and not world.menu_mode and not world.is_online():
step(delta)
func step(dt: float) -> void:
if dead:
return
var p := player.global_position
heat = world.heat_at(p)
heat = world.heat_at(p, player)
_shelter_left -= dt
if _shelter_left <= 0.0:
_shelter_left = 0.25
@@ -137,6 +139,12 @@ func step(dt: float) -> void:
dmg += MALNOURISHED_DRAIN
if dmg > 0.0:
health = maxf(health - dmg * dt, 0.0)
if hunger <= 0.0:
cause = "You starved"
elif warmth < 12.0:
cause = "You froze to death"
else:
cause = "Malnourished: you needed %s" % " and ".join(PackedStringArray(lacking.map(func(g): return DIET_NAMES[g])))
elif hunger > 40.0 and warmth > 35.0 and _hurt_cd <= 0.0 and lacking.is_empty():
var diet_mult := 1.5 if balanced_diet() else 1.0
health = minf(health + 0.5 * buff_mult("health_regen") * diet_mult * dt, MAX)
@@ -219,15 +227,18 @@ func reset_after_death() -> void:
warmth = 60.0
wet = 0.0
buffs.clear()
cause = ""
# Don't respawn straight back into malnutrition.
for g in DIET_GROUPS:
diet[g] = maxf(float(diet[g]), 30.0)
changed.emit()
## Takes a hit (a boar, later wolves). Pauses natural healing briefly.
func damage(amount: float, from: Vector3) -> void:
## `by` is what did it ("a wolf"), for the death screen.
func damage(amount: float, from: Vector3, by: String = "") -> void:
if dead:
return
cause = "Killed by %s" % by if not by.is_empty() else "You were killed"
health = maxf(health - amount, 0.0)
_hurt_cd = HURT_NO_REGEN
hurt.emit(amount, from)