Restore landing fade and missing event sounds
This commit is contained in:
parent
546107efb9
commit
eb1615ab6b
10 changed files with 91 additions and 15 deletions
|
|
@ -24,12 +24,16 @@ const VOICES: int = 12
|
|||
|
||||
const SHOT: String = "shot"
|
||||
const SHIP_DEATH: String = "ship_death"
|
||||
const ENEMY_DEATH: String = "enemy_death"
|
||||
const BUILDING_DEATH: String = "building_death"
|
||||
const DIALOG: String = "dialog"
|
||||
|
||||
const SOUNDS: Dictionary = {
|
||||
SHOT: "res://audio/sfx_shot.wav",
|
||||
SHIP_DEATH: "res://audio/sfx_ship_death.wav",
|
||||
ENEMY_DEATH: "res://audio/sfx_ship_death.wav",
|
||||
BUILDING_DEATH: "res://audio/sfx_building_death.wav",
|
||||
DIALOG: "res://audio/sfx_dialog.wav",
|
||||
}
|
||||
|
||||
# Per-sound level. A shot is fired constantly and a death happens once, so
|
||||
|
|
@ -37,7 +41,9 @@ const SOUNDS: Dictionary = {
|
|||
const LEVELS: Dictionary = {
|
||||
SHOT: -26.0,
|
||||
SHIP_DEATH: -23.0,
|
||||
ENEMY_DEATH: -23.0,
|
||||
BUILDING_DEATH: -23.0,
|
||||
DIALOG: -19.0,
|
||||
}
|
||||
|
||||
# Shots vary a little in pitch so a stream of them does not turn into one
|
||||
|
|
|
|||
|
|
@ -125,6 +125,28 @@ def shot(seconds=0.22):
|
|||
return [_saturate(v, 2.0) * _attack(i, 0.0015) for i, v in enumerate(mixed)]
|
||||
|
||||
|
||||
def dialog(seconds=0.24):
|
||||
"""A short radio handshake when a transmission line appears.
|
||||
|
||||
Two rising digital tones establish the signal; a small static tail keeps
|
||||
it in the same physical world as the scan-line presentation without
|
||||
turning every revealed character into a click."""
|
||||
n = int(RATE * seconds)
|
||||
tone = [0.0] * n
|
||||
for start, end, level, delay in ((520.0, 820.0, 0.55, 0.0),
|
||||
(940.0, 1380.0, 0.32, 0.045)):
|
||||
begin = int(RATE * delay)
|
||||
part = _sweep(n - begin, start, end, 0.8)
|
||||
for i, value in enumerate(part):
|
||||
at = begin + i
|
||||
tone[at] += value * level * _decay(i, len(part), 2.8)
|
||||
static = [value * _decay(i, n, 2.1) * 0.16
|
||||
for i, value in enumerate(_noise(n, 17, lambda t: 0.55 - 0.42 * t))]
|
||||
mixed = _mix(tone, static)
|
||||
return [_saturate(value, 1.8) * _attack(i, 0.002)
|
||||
for i, value in enumerate(mixed)]
|
||||
|
||||
|
||||
def explosion(seconds, sub_from, sub_to, roar_seed, debris_level, drive):
|
||||
"""A blast in three layers on three clocks: the crack is over in a
|
||||
fifth of a second, the roar runs most of the length, and the debris
|
||||
|
|
@ -163,6 +185,7 @@ def explosion(seconds, sub_from, sub_to, roar_seed, debris_level, drive):
|
|||
|
||||
if __name__ == "__main__":
|
||||
_write("sfx_shot", shot())
|
||||
_write("sfx_dialog", dialog())
|
||||
# A vessel coming apart: bright, fast, with real low end under it.
|
||||
_write("sfx_ship_death", explosion(1.45, 260.0, 38.0, 5, 0.16, 2.6))
|
||||
# A structure: longer, deeper, and it keeps coming down afterwards.
|
||||
|
|
|
|||
BIN
audio/sfx_dialog.wav
Normal file
BIN
audio/sfx_dialog.wav
Normal file
Binary file not shown.
24
audio/sfx_dialog.wav.import
Normal file
24
audio/sfx_dialog.wav.import
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
[remap]
|
||||
|
||||
importer="wav"
|
||||
type="AudioStreamWAV"
|
||||
uid="uid://dxg516krws85k"
|
||||
path="res://.godot/imported/sfx_dialog.wav-d50ed12ab44ac60044a5fcd0eb2c25c1.sample"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://audio/sfx_dialog.wav"
|
||||
dest_files=["res://.godot/imported/sfx_dialog.wav-d50ed12ab44ac60044a5fcd0eb2c25c1.sample"]
|
||||
|
||||
[params]
|
||||
|
||||
force/8_bit=false
|
||||
force/mono=false
|
||||
force/max_rate=false
|
||||
force/max_rate_hz=44100
|
||||
edit/trim=false
|
||||
edit/normalize=false
|
||||
edit/loop_mode=0
|
||||
edit/loop_begin=0
|
||||
edit/loop_end=-1
|
||||
compress/mode=2
|
||||
|
|
@ -92,6 +92,7 @@ func take_damage(amount: int) -> void:
|
|||
hp -= amount
|
||||
if hp <= 0:
|
||||
EnemyExplosionVFX.spawn(get_tree().root, position)
|
||||
Sfx.play(get_tree(), Sfx.ENEMY_DEATH)
|
||||
destroyed.emit()
|
||||
queue_free()
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ func _verify() -> void:
|
|||
return _fail("Main.tscn did not load")
|
||||
var main: Node = packed.instantiate()
|
||||
root.add_child(main)
|
||||
if main.get_node_or_null("FadeOverlay/FadeRect") == null:
|
||||
return _fail("Main lost the atmosphere fade overlay")
|
||||
for menu_name in MENUS:
|
||||
var menu: Node = main.get_node_or_null("UI/%s" % menu_name)
|
||||
if menu == null:
|
||||
|
|
@ -26,6 +28,8 @@ func _verify() -> void:
|
|||
% [menu_name, expected])
|
||||
if menu.get_script() == null:
|
||||
return _fail("%s has no owning script" % menu_name)
|
||||
if menu.get_node_or_null("FadeOverlay") != null:
|
||||
return _fail("%s incorrectly owns Main's atmosphere fade overlay" % menu_name)
|
||||
|
||||
var source: String = FileAccess.get_file_as_string(
|
||||
"res://controllers/BuildController.gd")
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@ extends SceneTree
|
|||
|
||||
# Headless test: run with
|
||||
# godot --headless -s res://tests/test_sfx.gd
|
||||
# Forgejo #146: a shot, a vessel dying and a structure coming down should be
|
||||
# heard.
|
||||
# Forgejo #146: shots and destruction should be heard. Enemy destruction and
|
||||
# incoming narration are covered too, so visual events cannot silently miss
|
||||
# the shared sound pool.
|
||||
#
|
||||
# The interesting failures here are not "no sound came out" - they are the
|
||||
# ones a play-through would not reveal for weeks. A voice pool that runs dry
|
||||
|
|
@ -16,7 +17,7 @@ extends SceneTree
|
|||
# B. firing plays a shot, and it survives a fleet firing together - no
|
||||
# voice is lost, none is left stuck
|
||||
# C. a dying ship is heard, from a node that is freed on the same frame
|
||||
# D. a destroyed structure is heard
|
||||
# D. enemy and structure destruction are heard
|
||||
# E. levels are in proportion: a shot fires constantly and a death happens
|
||||
# once, so a shot must be the quieter of the two
|
||||
# F. sound keeps working while a dialog has the game stopped (#128)
|
||||
|
|
@ -116,8 +117,12 @@ func _process(delta: float) -> bool:
|
|||
% [Sfx.VOICES * 3, Sfx.VOICES, busy])
|
||||
|
||||
# --- F. and a dialog does not silence it -----------------
|
||||
for voice in _pool().get_children():
|
||||
(voice as AudioStreamPlayer).stop()
|
||||
var narration: Control = scene.get_node("UI/NarrationBanner")
|
||||
narration.say("Everything stops but this.", "TEST")
|
||||
if _sounding() == 0:
|
||||
return _fail("a narration line appeared in silence")
|
||||
if not paused:
|
||||
return _fail("the dialog did not stop the game, so this proves nothing")
|
||||
for voice in _pool().get_children():
|
||||
|
|
@ -149,6 +154,19 @@ func _process(delta: float) -> bool:
|
|||
return _fail("a vessel died in silence")
|
||||
print("a vessel freed on the frame it dies is still heard")
|
||||
|
||||
# An enemy uses the same persistent pool. Its own node is freed on
|
||||
# this frame too, so the call must happen before queue_free().
|
||||
for voice in _pool().get_children():
|
||||
(voice as AudioStreamPlayer).stop()
|
||||
var enemy: Node2D = load("res://enemies/Enemy.tscn").instantiate()
|
||||
scene.add_child(enemy)
|
||||
enemy.take_damage(enemy.hp)
|
||||
if not enemy.is_queued_for_deletion():
|
||||
return _fail("the enemy was not destroyed")
|
||||
if _sounding() == 0:
|
||||
return _fail("an enemy vessel exploded in silence")
|
||||
print("an enemy vessel explosion is heard")
|
||||
|
||||
# --- D. a structure ------------------------------------
|
||||
for voice in _pool().get_children():
|
||||
(voice as AudioStreamPlayer).stop()
|
||||
|
|
|
|||
|
|
@ -238,6 +238,7 @@ func _advance() -> void:
|
|||
label.visible_characters = 0
|
||||
speaker_label.text = speaker
|
||||
visible = true
|
||||
Sfx.play(get_tree(), Sfx.DIALOG)
|
||||
_layout()
|
||||
queue_redraw()
|
||||
_sync_pause()
|
||||
|
|
|
|||
|
|
@ -76,15 +76,3 @@ offset_top = 24
|
|||
offset_bottom = 172
|
||||
script = ExtResource("10")
|
||||
icon = 1
|
||||
|
||||
[node name="FadeOverlay" type="CanvasLayer" parent="."]
|
||||
layer = 10
|
||||
|
||||
[node name="FadeRect" type="ColorRect" parent="FadeOverlay"]
|
||||
mouse_filter = 2
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
color = Color(0, 0, 0, 0)
|
||||
|
|
|
|||
|
|
@ -493,3 +493,14 @@ offset_top = 300.0
|
|||
offset_bottom = 428.0
|
||||
script = ExtResource("36")
|
||||
|
||||
[node name="FadeOverlay" type="CanvasLayer" parent="."]
|
||||
layer = 10
|
||||
|
||||
[node name="FadeRect" type="ColorRect" parent="FadeOverlay"]
|
||||
mouse_filter = 2
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
color = Color(0, 0, 0, 0)
|
||||
|
|
|
|||
Loading…
Reference in a new issue