feat: give the player embodied hunger, energy, and starvation death

This commit is contained in:
2026-08-08 23:38:50 +02:00
parent 21b2eb06da
commit 9678526c5a
11 changed files with 488 additions and 65 deletions
+152
View File
@@ -0,0 +1,152 @@
class_name PlayerStateRecord
extends RefCounted
const SCHEMA_VERSION := 1
const HUNGER_DEATH_THRESHOLD := 100.0
const STACK_THRESHOLD := 90.0
const DEATH_STANDING_PENALTY := 0.5
const RESET_HUNGER := 20.0
const RESET_ENERGY := 70.0
var data: Dictionary
func _init(record_data: Dictionary = {}) -> void:
data = record_data.duplicate(true)
static func create() -> PlayerStateRecord:
return (
PlayerStateRecord
. new(
{
"schema_version": SCHEMA_VERSION,
"hunger": 20.0,
"energy": 90.0,
"is_starving": false,
"starvation_ticks": 0,
"starvation_death_threshold": 600,
"is_dead": false,
"deaths": 0,
}
)
)
static func from_dictionary(record_data: Dictionary) -> PlayerStateRecord:
if int(record_data.get("schema_version", -1)) != SCHEMA_VERSION:
return null
if not (
record_data
. has_all(
[
"hunger",
"energy",
"is_starving",
"starvation_ticks",
"starvation_death_threshold",
"is_dead",
"deaths",
]
)
):
return null
var hunger := float(record_data["hunger"])
var energy := float(record_data["energy"])
var starvation_ticks := int(record_data["starvation_ticks"])
var death_threshold := int(record_data["starvation_death_threshold"])
var deaths := int(record_data["deaths"])
if (
not is_finite(hunger)
or hunger < 0.0
or hunger > HUNGER_DEATH_THRESHOLD
or not is_finite(energy)
or energy < 0.0
or energy > 100.0
or starvation_ticks < 0
or death_threshold < 1
or deaths < 0
):
return null
return (
PlayerStateRecord
. new(
{
"schema_version": SCHEMA_VERSION,
"hunger": hunger,
"energy": energy,
"is_starving": bool(record_data["is_starving"]),
"starvation_ticks": starvation_ticks,
"starvation_death_threshold": death_threshold,
"is_dead": bool(record_data["is_dead"]),
"deaths": deaths,
}
)
)
func get_hunger() -> float:
return float(data["hunger"])
func get_energy() -> float:
return float(data["energy"])
func is_starving() -> bool:
return bool(data["is_starving"])
func is_dead() -> bool:
return bool(data["is_dead"])
func get_starvation_ticks() -> int:
return int(data["starvation_ticks"])
func get_deaths() -> int:
return int(data["deaths"])
func eat(amount: float) -> float:
if amount <= 0.0 or is_dead():
return 0.0
var previous := get_hunger()
data["hunger"] = clampf(previous - amount, 0.0, HUNGER_DEATH_THRESHOLD)
var consumed := previous - get_hunger()
if consumed > 0.0:
data["energy"] = minf(get_energy() + consumed * 0.5, 100.0)
return consumed
func advance(hunger_rate: float, energy_rate: float) -> bool:
if is_dead():
return false
data["hunger"] = minf(get_hunger() + maxf(hunger_rate, 0.0), HUNGER_DEATH_THRESHOLD)
data["energy"] = clampf(get_energy() - maxf(energy_rate, 0.0), 0.0, 100.0)
data["is_starving"] = get_hunger() >= STACK_THRESHOLD
if is_starving():
data["starvation_ticks"] = int(data["starvation_ticks"]) + 1
if get_starvation_ticks() >= int(data["starvation_death_threshold"]):
return true
else:
data["starvation_ticks"] = 0
return false
func die() -> void:
data["is_dead"] = true
data["deaths"] = int(data["deaths"]) + 1
func respawn() -> void:
data["hunger"] = RESET_HUNGER
data["energy"] = RESET_ENERGY
data["is_starving"] = false
data["starvation_ticks"] = 0
data["is_dead"] = false
func to_dictionary() -> Dictionary:
return data.duplicate(true)