Old Tam speaks (Kokoro); CC0 birdsong, crickets and owls; no plants through floors; menu and marker fixes

This commit is contained in:
Paul Bailey
2026-11-06 00:03:59 +00:00
parent 0550a4daa0
commit 787d8d1d65
70 changed files with 495 additions and 87 deletions

View File

@@ -42,10 +42,16 @@ var _b: AudioStreamPlayer
var _cur: AudioStreamPlayer
var _birds: AudioStreamPlayer
var _crickets: AudioStreamPlayer
var _owl: AudioStreamPlayer3D
var _owl_left := 20.0
var _owl_calls: Array = [] ## a few different calls, so it doesn't repeat itself
var owls := 0 ## hoots so far (tests)
const OWL_EVERY := [35.0, 110.0]
var _tracks: Dictionary = {}
var _rng := RandomNumberGenerator.new()
var _quiet := false
var _fading := 0 ## crossfades in progress
var duck := false ## Old Tam is talking (narrator.gd): the music dips
func _ready() -> void:
process_mode = Node.PROCESS_MODE_ALWAYS # (the pause menu stops the game, not the music)
@@ -58,6 +64,15 @@ func _ready() -> void:
_cur = _a
_birds = _player("Ambience", _load(AMB + "birds.ogg", true))
_crickets = _player("Ambience", _load(AMB + "crickets.ogg", true))
_owl = AudioStreamPlayer3D.new()
_owl.bus = "Ambience"
for i in range(2):
var call: Variant = _load(AMB + "owl_%d.ogg" % i, false)
if call is AudioStream:
_owl_calls.append(call)
_owl.unit_size = 30.0 # (far off in the trees, but clearly heard)
_owl.max_distance = 120.0
add_child(_owl)
for p in [_a, _b]:
p.finished.connect(_on_finished.bind(p))
@@ -204,7 +219,7 @@ func _indoors() -> bool:
return sv != null and bool(sv.get("sheltered"))
func _target_db() -> float:
return -6.0 if _indoors() else -2.0
return (-6.0 if _indoors() else -2.0) - (7.0 if duck else 0.0)
func _ambience(dt: float) -> void:
if _quiet or _birds == null:
@@ -218,10 +233,36 @@ func _ambience(dt: float) -> void:
wet = 1.0 if s in ["rain", "storm", "blizzard"] else 0.0
snow = s in ["snow", "blizzard"]
var inside := 0.35 if _indoors() else 1.0
if world == null or not is_instance_valid(world) or world.get("menu_mode"):
inside = 0.0 # (the title screen: music only, no birds or crickets)
var birds := clampf((day - 0.35) / 0.4, 0.0, 1.0) * (1.0 - wet) * inside
var crickets := clampf((0.45 - day) / 0.3, 0.0, 1.0) * (0.0 if snow else 1.0) * (1.0 - wet * 0.8) * inside
_owl_step(dt, crickets > 0.5, inside)
var k := clampf(dt * 0.8, 0.0, 1.0)
_birds.volume_db = lerpf(_birds.volume_db, linear_to_db(maxf(birds * 0.8, 0.0001)), k)
_crickets.volume_db = lerpf(_crickets.volume_db, linear_to_db(maxf(crickets * 0.7, 0.0001)), k)
_birds.volume_db = lerpf(_birds.volume_db, linear_to_db(maxf(birds * 0.28, 0.0001)), k) # (in the background: the recording is full-scale)
_crickets.volume_db = lerpf(_crickets.volume_db, linear_to_db(maxf(crickets * 0.4, 0.0001)), k) # (a recording, full-scale)
if _cur != null and _cur.playing and _fading == 0:
_cur.volume_db = lerpf(_cur.volume_db, _target_db(), k)
## Now and then at night (when the crickets are out: dark, dry, no snow), an
## owl hoots from somewhere 25-45 m off in a random direction. Only you hear
## your owl; online, everyone's night has its own.
func _owl_step(dt: float, night_out: bool, inside: float) -> void:
if _owl == null or _owl_calls.is_empty() or not night_out:
_owl_left = maxf(_owl_left, 8.0)
return
_owl_left -= dt
if _owl_left > 0.0 or _owl.playing:
return
_owl_left = _rng.randf_range(OWL_EVERY[0], OWL_EVERY[1])
var me: Node3D = world.get("player") if world != null else null
if me == null:
return
var a := _rng.randf() * TAU
var r := _rng.randf_range(25.0, 45.0)
_owl.global_position = me.global_position + Vector3(cos(a) * r, _rng.randf_range(6.0, 12.0), sin(a) * r)
_owl.stream = _owl_calls[_rng.randi() % _owl_calls.size()]
_owl.pitch_scale = _rng.randf_range(0.96, 1.04)
_owl.volume_db = -8.0 + linear_to_db(maxf(inside, 0.05))
_owl.play()
owls += 1