M1b: survival stats, day/night, fire fuel, cooking, foraging, torches, death + grave
- Health, stamina, hunger, warmth and wet with HUD bars, status tags and clock - 20-minute day/night cycle with moon, stars and lit clouds - Campfire fuel (2 min start, 15 min max), heat radius, cooking needs a lit fire - Berry bushes (regrow 10 min), mushrooms, roasted mushroom, torch - Stamina costs for sprint, jump and harvest hits - Death respawns at island start and leaves a grave bag - Saves include stats, time of day, fire fuel, regrowth timers and graves - New test_survival_stats suite; tests fail if a script error aborts them
This commit is contained in:
@@ -10,6 +10,7 @@ extends Node3D
|
||||
|
||||
signal prompt_changed(text: String)
|
||||
|
||||
const Campfire = preload("res://scripts/building/campfire.gd")
|
||||
const REACH := 3.2
|
||||
const PLACE_REACH := 6.0
|
||||
const SWING_TIME := 0.5
|
||||
@@ -27,6 +28,9 @@ var _place_xf := Transform3D()
|
||||
var _place_ok := false
|
||||
var _prompt := ""
|
||||
var _held_shown := "~"
|
||||
var _torch_light: OmniLight3D
|
||||
var _torch_flame: CPUParticles3D
|
||||
var _t := 0.0
|
||||
|
||||
func _ready() -> void:
|
||||
_ray = RayCast3D.new()
|
||||
@@ -51,6 +55,22 @@ func _ready() -> void:
|
||||
_ghost.top_level = true
|
||||
add_child(_ghost)
|
||||
|
||||
_torch_light = OmniLight3D.new()
|
||||
_torch_light.light_color = Color(1.0, 0.65, 0.35)
|
||||
_torch_light.omni_attenuation = 1.3
|
||||
_torch_light.shadow_enabled = true
|
||||
_torch_light.position = Vector3(0, 0.62, 0)
|
||||
_torch_light.visible = false
|
||||
_view.add_child(_torch_light)
|
||||
_torch_flame = Campfire._particles(
|
||||
"TorchFlame", 14, 0.4, Vector3(0, 0.58, 0), 0.2, 0.5, 0.25, 0.5,
|
||||
Campfire._gradient([
|
||||
[0.0, Color(1.0, 0.8, 0.35, 0.0)], [0.2, Color(1.0, 0.6, 0.2, 0.8)], [1.0, Color(0.6, 0.1, 0.02, 0.0)]]),
|
||||
true, 0.12, 0.03)
|
||||
_torch_flame.local_coords = false
|
||||
_torch_flame.emitting = false
|
||||
_view.add_child(_torch_flame)
|
||||
|
||||
player.inventory.changed.connect(_refresh_held)
|
||||
player.selected_changed.connect(_refresh_held)
|
||||
_refresh_held()
|
||||
@@ -82,6 +102,17 @@ func _refresh_held() -> void:
|
||||
_ghost_yaw = 0.0
|
||||
else:
|
||||
_ghost.visible = false
|
||||
# Torch: a flickering light at the head of the held torch.
|
||||
var light: Dictionary = def.get("light", {})
|
||||
_torch_light.visible = not light.is_empty()
|
||||
_torch_flame.emitting = not light.is_empty()
|
||||
if not light.is_empty():
|
||||
_torch_light.omni_range = float(light.get("range", 8.0))
|
||||
_torch_light.light_energy = float(light.get("energy", 1.5))
|
||||
|
||||
## 0..1 warmth from what's held (a torch).
|
||||
func held_heat() -> float:
|
||||
return float(_held_def().get("light", {}).get("heat", 0.0))
|
||||
|
||||
func _set_prompt(t: String) -> void:
|
||||
if t != _prompt:
|
||||
@@ -110,8 +141,16 @@ func _physics_process(delta: float) -> void:
|
||||
_set_prompt("[LMB] Place %s [R] Rotate" % def.name)
|
||||
return
|
||||
_ghost.visible = false
|
||||
if _torch_light.visible:
|
||||
_t += delta
|
||||
_torch_light.light_energy = float(def.get("light", {}).get("energy", 1.5)) * (0.85 + 0.15 * sin(_t * 17.0) * sin(_t * 5.3))
|
||||
var t := _target()
|
||||
_set_prompt(t.interact_prompt(player) if t != null else "")
|
||||
if t != null:
|
||||
_set_prompt(t.interact_prompt(player))
|
||||
elif def.has("food"):
|
||||
_set_prompt("[RMB] Eat %s" % def.name)
|
||||
else:
|
||||
_set_prompt("")
|
||||
|
||||
func _update_ghost(def: Dictionary) -> void:
|
||||
var cam := get_parent() as Camera3D
|
||||
@@ -142,7 +181,10 @@ func _unhandled_input(event: InputEvent) -> void:
|
||||
player.select(player.selected - 1)
|
||||
elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
|
||||
player.select(player.selected + 1)
|
||||
if event.is_action_pressed("rotate_piece"):
|
||||
if event.is_action_pressed("use_item") and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
|
||||
if _held_def().has("food"):
|
||||
Actions.eat(player, player.selected)
|
||||
elif event.is_action_pressed("rotate_piece"):
|
||||
_ghost_yaw += deg_to_rad(22.5)
|
||||
elif event.is_action_pressed("interact"):
|
||||
var t := _target()
|
||||
|
||||
Reference in New Issue
Block a user