The Cove's shore life: crabs up the beach from dusk till dawn (keep to the sand, pinch if you get close, crab meat to cook), gulls after food on the sand and fish on a smoking rack; online too
This commit is contained in:
113
scripts/creatures/crab.gd
Normal file
113
scripts/creatures/crab.gd
Normal file
@@ -0,0 +1,113 @@
|
||||
extends "res://scripts/creatures/creature.gd"
|
||||
## A crab (0.6.0, the Cove only): shore.gd brings them up out of the sea
|
||||
## onto the beach at dusk. They scuttle about the sand sideways and keep to
|
||||
## it. Walk within NIP of one and it comes at you, claws up, and pinches
|
||||
## (not much, but it adds up with three of them about). Leave it NIP_GIVE_UP
|
||||
## behind and it forgets you. Hit one hard enough and it runs for it. At
|
||||
## dawn they all go back into the sea. A dead one gives crab meat.
|
||||
|
||||
const NIP := 2.2 ## this close and it comes for you
|
||||
const NIP_GIVE_UP := 6.0 ## this far and it lets you go
|
||||
const HOME_FOR := 40.0 ## at dawn: this long to reach the water before it simply goes
|
||||
|
||||
func interact_prompt(p: Node) -> String:
|
||||
if is_dead():
|
||||
return "Crab [E] Crack it open"
|
||||
match state:
|
||||
"charge": return "Crab (claws up!)"
|
||||
"home": return "Crab (heading back to the sea)"
|
||||
return "Crab (keep your distance, or it'll pinch)"
|
||||
|
||||
## Daytime: back to the sea.
|
||||
func _daytime() -> bool:
|
||||
var h: float = world.day_night.hours()
|
||||
return h >= 6.5 and h < 17.5
|
||||
|
||||
## Which way the sea is: straight out from the middle of the bay.
|
||||
func _seaward() -> Vector3:
|
||||
var a := deg_to_rad(float(terrain.beach_angle_deg))
|
||||
return Vector3(cos(a), 0.0, sin(a))
|
||||
|
||||
func _think(dt: float) -> void:
|
||||
if state != "home" and state != "flee" and _daytime():
|
||||
state = "home"
|
||||
_state_t = HOME_FOR
|
||||
var pp: Vector3 = player.global_position
|
||||
var d := global_position.distance_to(pp)
|
||||
match state:
|
||||
"home":
|
||||
var to := _seaward()
|
||||
steer(atan2(-to.x, -to.z))
|
||||
_state_t -= dt
|
||||
if _state_t <= 0.0 or global_position.y < terrain.water_level - 0.25:
|
||||
queue_free() # (into the waves)
|
||||
return
|
||||
"idle", "wander":
|
||||
if d < NIP:
|
||||
state = "charge"
|
||||
_aggro = def.aggro
|
||||
_attack_cd = 0.5 # (a moment to see it coming)
|
||||
return
|
||||
"charge":
|
||||
if d < NIP_GIVE_UP:
|
||||
_aggro = def.aggro # (it keeps on at you while you're close)
|
||||
else:
|
||||
_aggro = 0.0
|
||||
super._think(dt)
|
||||
|
||||
func _desired_speed() -> float:
|
||||
if state == "home":
|
||||
return def.walk * 1.6
|
||||
return super._desired_speed()
|
||||
|
||||
## Keeps to the sand (and out of the water) until it's going home.
|
||||
func _blocked(dir: Vector3) -> bool:
|
||||
var probe := global_position + dir * (0.8 + speed * 0.15)
|
||||
if not terrain.inside_boundary(probe.x, probe.z, 4.0):
|
||||
return true
|
||||
if state == "home":
|
||||
return false # (straight down the beach and into the sea)
|
||||
if not terrain.on_sand(probe.x, probe.z):
|
||||
return true
|
||||
return super._blocked(dir)
|
||||
|
||||
## Hit: it fights back while it can, then runs.
|
||||
func _react(from: Vector3) -> void:
|
||||
if hp > def.hp * 0.35:
|
||||
state = "charge"
|
||||
_aggro = def.aggro
|
||||
_attack_cd = 0.3
|
||||
else:
|
||||
_start_flee(from)
|
||||
_state_t = 5.0
|
||||
|
||||
## Sideways, legs a-flicker; the claws come up when it's after you.
|
||||
func _animate(dt: float) -> void:
|
||||
_visual.rotation.y = PI * 0.5 # (it walks sideways)
|
||||
if is_dead():
|
||||
return
|
||||
var k := clampf(speed / maxf(def.run, 0.01), 0.0, 1.0)
|
||||
_phase += dt * (6.0 + speed * 14.0)
|
||||
for i in range(_legs.size()):
|
||||
var l: Node3D = _legs[i]
|
||||
var s := -1.0 if l.position.x < 0.0 else 1.0
|
||||
l.rotation.z = s * (1.0 + sin(_phase + i * 1.9) * (0.08 + 0.3 * k))
|
||||
l.rotation.x = cos(_phase + i * 1.9) * 0.25 * k
|
||||
var up := 0.12 if state == "charge" or (puppet and speed > 1.5) else 0.0
|
||||
_visual.rotation.x = lerpf(_visual.rotation.x, -up, minf(dt * 6.0, 1.0))
|
||||
_visual.position.y = absf(sin(_phase * 0.5)) * 0.01 * k
|
||||
|
||||
## A crab doesn't topple onto its side: it ends up on its back.
|
||||
func _die(_from: Vector3) -> void:
|
||||
state = "dead"
|
||||
speed = 0.0
|
||||
hp = 0.0
|
||||
_flash = 0.0
|
||||
_set_material(_mat)
|
||||
remove_from_group("creature")
|
||||
add_to_group("carcass")
|
||||
collision_layer = 2
|
||||
_visual.rotation = Vector3(0.0, PI * 0.5, PI)
|
||||
_visual.position.y = 0.1
|
||||
if not puppet:
|
||||
died.emit(self)
|
||||
Reference in New Issue
Block a user