Wolves with a den, fishing, and a mixed diet
Wolves - Den: a boulder cave at the foot of the rim, sited from the seed (away from the sea and spawn, mouth toward the valley, clearing in front) - Grace period: no wolves days 1-2; they move in on day 3 and howl; hunting from night 4; pack of 2, 3 from day 6, 4 from day 9; replaced by day - Wary pack hunters: circle and dart in one at a time; a lit campfire is a safe zone, a torch makes them hesitate, walls block bites (line of sight); hit one and the pack turns; hurt wolves flee; a lone wolf is timid; by day they defend the den; home at dawn - Glowing eyes, synthesised howls, can't sleep with wolves prowling - Wolf pelt and Wolf Cloak (+25 warmth) - Animals take a committed detour around obstacles Fishing - Fishing rod (workbench); cast a float onto the lake, 1.5 s to land a bite - Perch and rarer trout; faster bites at dawn/dusk and in rain; grill them - Visible fish near the shore that jump with splash rings Mixed diet - Foods belong to meat, fish or greens; each level runs down over ~1.5 days - One group low: no healing; two low: Malnourished (health drains); all three good: Balanced diet (heal x1.5); HUD diet bars; saved Tests: test_wolves and test_fishing_diet; run_all.sh covers 9 suites
This commit is contained in:
@@ -34,6 +34,11 @@ const KINDS := {
|
||||
"notice": 0.0, "notice_loud": 0.0, "calm": 30.0,
|
||||
"damage": 14.0, "attack_range": 1.7, "attack_cd": 1.6, "aggro": 18.0,
|
||||
"drops": {"raw_meat": [3, 4], "hide": [1, 2]}},
|
||||
# Wolves are driven by wolf.gd + wolf_pack.gd; "notice" is unused.
|
||||
"wolf": {"name": "Wolf", "hp": 45.0, "walk": 1.6, "run": 8.6, "turn": 6.0,
|
||||
"notice": 0.0, "notice_loud": 0.0, "calm": 40.0,
|
||||
"damage": 9.0, "attack_range": 1.8, "attack_cd": 1.2,
|
||||
"drops": {"raw_meat": [1, 2], "wolf_pelt": [1, 1]}},
|
||||
}
|
||||
const CARCASS_SECONDS := 300.0
|
||||
|
||||
@@ -60,6 +65,13 @@ var _phase := 0.0
|
||||
var _visual: Node3D
|
||||
var _legs: Array[Node3D] = []
|
||||
var _flash := 0.0
|
||||
var _detour_t := 0.0 ## > 0: following a detour round an obstacle
|
||||
var _detour_side := 1.0
|
||||
|
||||
## Sets the heading, unless the animal is in the middle of a detour.
|
||||
func steer(y: float) -> void:
|
||||
if _detour_t <= 0.0:
|
||||
target_yaw = y
|
||||
var _mat: StandardMaterial3D
|
||||
var _hit_mat: StandardMaterial3D
|
||||
|
||||
@@ -88,6 +100,18 @@ func setup(k: String, w: Node3D, pos: Vector3, seed: int) -> void:
|
||||
body.mesh = parts.body
|
||||
body.material_override = _mat
|
||||
_visual.add_child(body)
|
||||
if parts.has("eyes"):
|
||||
# Eyes that catch the light: you see a wolf's eyes in the dark first.
|
||||
var eyes := MeshInstance3D.new()
|
||||
eyes.mesh = parts.eyes
|
||||
var em := StandardMaterial3D.new()
|
||||
em.albedo_color = Color(1.0, 0.85, 0.4)
|
||||
em.emission_enabled = true
|
||||
em.emission = Color(1.0, 0.75, 0.3)
|
||||
em.emission_energy_multiplier = 2.5
|
||||
eyes.material_override = em
|
||||
eyes.set_meta("keep_mat", true)
|
||||
_visual.add_child(eyes)
|
||||
for h: Vector3 in parts.hips:
|
||||
var pivot := Node3D.new()
|
||||
pivot.position = h
|
||||
@@ -105,7 +129,7 @@ func setup(k: String, w: Node3D, pos: Vector3, seed: int) -> void:
|
||||
cs.position = Vector3(0, parts.height * 0.5, 0)
|
||||
if k != "rabbit":
|
||||
# Long bodies: lay the capsule along the spine.
|
||||
cap.height = 1.5 if k == "deer" else 1.4
|
||||
cap.height = {"deer": 1.5, "boar": 1.4, "wolf": 1.25}.get(k, 1.4)
|
||||
cs.rotation.x = PI * 0.5
|
||||
cs.position = Vector3(0, parts.height * 0.55, 0)
|
||||
add_child(cs)
|
||||
@@ -219,12 +243,19 @@ func _move(dt: float) -> void:
|
||||
yaw = rotate_toward(yaw, target_yaw, def.turn * dt)
|
||||
if speed < 0.01:
|
||||
return
|
||||
_detour_t = maxf(_detour_t - dt, 0.0)
|
||||
var dir := Vector3(-sin(yaw), 0, -cos(yaw))
|
||||
if _blocked(dir):
|
||||
# Turn away; fleeing animals turn harder.
|
||||
var turn := rng.randf_range(0.8, 2.2) * (1.0 if rng.randf() < 0.5 else -1.0)
|
||||
# Turn away and keep to the new heading for a moment (a detour), so
|
||||
# an animal heading somewhere slides round an obstacle instead of
|
||||
# turning straight back into it. Keep turning the same way while
|
||||
# still blocked.
|
||||
if _detour_t <= 0.0:
|
||||
_detour_side = 1.0 if rng.randf() < 0.5 else -1.0
|
||||
var turn := rng.randf_range(0.8, 1.6) * _detour_side
|
||||
target_yaw = yaw + turn
|
||||
yaw += turn * 0.35
|
||||
_detour_t = rng.randf_range(1.0, 1.8)
|
||||
speed *= 0.5
|
||||
if state == "charge":
|
||||
return
|
||||
@@ -253,6 +284,13 @@ func _blocked(dir: Vector3) -> bool:
|
||||
return not get_world_3d().direct_space_state.intersect_ray(q).is_empty()
|
||||
|
||||
func _animate(dt: float) -> void:
|
||||
if state == "rest":
|
||||
# Lying down: body lowered, legs folded under.
|
||||
_visual.position.y = lerpf(_visual.position.y, -0.3, minf(dt * 3.0, 1.0))
|
||||
_visual.rotation.x = lerpf(_visual.rotation.x, 0.0, minf(dt * 4.0, 1.0))
|
||||
for l in _legs:
|
||||
l.rotation.x = lerpf(l.rotation.x, 1.35 * (1.0 if l.position.z < 0.0 else -1.0), minf(dt * 3.0, 1.0))
|
||||
return
|
||||
var k := speed / maxf(def.run, 0.01)
|
||||
_phase += dt * (3.0 + speed * 2.2)
|
||||
var amp := clampf(speed / 2.0, 0.0, 1.0) * 0.6
|
||||
@@ -288,6 +326,10 @@ func take_hit(damage: float, from: Vector3, embed_id: String = "") -> void:
|
||||
if hp <= 0.0:
|
||||
_die(from)
|
||||
return
|
||||
_react(from)
|
||||
|
||||
## How a living animal responds to being hit (wolves override this).
|
||||
func _react(from: Vector3) -> void:
|
||||
if kind == "boar" and hp > def.hp * 0.3:
|
||||
state = "charge"
|
||||
_aggro = def.aggro
|
||||
@@ -328,10 +370,10 @@ func butcher_drops() -> Dictionary:
|
||||
|
||||
func _set_material(m: Material) -> void:
|
||||
for c in _visual.get_children():
|
||||
if c is MeshInstance3D:
|
||||
if c is MeshInstance3D and not c.has_meta("keep_mat"):
|
||||
c.material_override = m
|
||||
for g in c.get_children():
|
||||
if g is MeshInstance3D:
|
||||
if g is MeshInstance3D and not g.has_meta("keep_mat"):
|
||||
g.material_override = m
|
||||
|
||||
func _burst() -> void:
|
||||
|
||||
Reference in New Issue
Block a user