M2.5: wildlife, wolves, hunting, fishing and sleeping on the server

This commit is contained in:
Paul Bailey
2026-11-04 21:25:10 +00:00
parent 26be17b05f
commit a211fe4c63
20 changed files with 1258 additions and 88 deletions

View File

@@ -168,6 +168,9 @@ func step(dt: float) -> void:
_flash -= dt
if _flash <= 0.0:
_set_material(_mat)
if puppet:
_puppet_step(dt)
return
if is_dead():
carcass_left -= dt
if carcass_left <= 0.0:
@@ -175,10 +178,58 @@ func step(dt: float) -> void:
return
_attack_cd = maxf(_attack_cd - dt, 0.0)
_aggro = maxf(_aggro - dt, 0.0)
_think(dt)
# Who it's reacting to: the player (or on a server, the nearest one).
var t := _pick_target()
if t != null:
player = t
_think(dt)
elif state in ["flee", "charge"]:
state = "idle" # nobody about
_move(dt)
_animate(dt)
func _pick_target() -> Node3D:
return world.nearest_player(global_position)
# --- on a client playing online: the server's animal, shown here ------------
## A puppet only shows what the server's copy is doing (creature_net.gd):
## no thinking, no damage dealt. It can still be hit (that's sent to the
## server) and butchered.
var puppet := false
var _net_pos := Vector3.ZERO
var _net_yaw := 0.0
func net_update(pos: Vector3, y: float, st: String, spd: float, new_hp: float) -> void:
if not puppet:
return
_net_pos = pos
_net_yaw = y
speed = spd
if new_hp < hp - 0.01 and st != "dead":
_flash = 0.15
_set_material(_hit_mat)
_burst()
hp = new_hp
if st == "dead" and state != "dead":
_burst()
_die(global_position + global_basis.z)
return
if state != "dead":
state = st
func _puppet_step(dt: float) -> void:
if is_dead():
return
var k := 1.0 - exp(-12.0 * dt)
var p := global_position.lerp(_net_pos, k)
if p.distance_to(_net_pos) > 6.0:
p = _net_pos # (a jump: a wolf slipping home to the den)
global_position = p
yaw = lerp_angle(yaw, _net_yaw, k)
rotation.y = yaw
_animate(dt)
## Whether the player is close enough to be noticed. Sprinting, or moving
## fast while swimming or jumping, is loud.
func _notices_player(d: float) -> bool:
@@ -313,6 +364,8 @@ func _animate(dt: float) -> void:
## Applies a hit (Actions validates who hit what). `from` = where it came
## from, for the reaction.
func take_hit(damage: float, from: Vector3, embed_id: String = "") -> void:
if puppet:
return # (online the server's copy takes the hit)
if is_dead():
if not embed_id.is_empty():
embedded[embed_id] = embedded.get(embed_id, 0) + 1
@@ -349,6 +402,9 @@ func _die(from: Vector3) -> void:
collision_layer = 2
for l in _legs:
l.rotation.x = 0.4
if puppet:
_visual.rotation.z = -PI * 0.5
return
# Topple onto its side, away from the blow.
var side := 1.0 if (global_position - from).dot(global_basis.x) > 0.0 else -1.0
if is_inside_tree() and DisplayServer.get_name() != "headless":