Refactor audio effect handling: remove cooldown logic and enhance sound playback functionality

This commit is contained in:
Kirill
2026-10-03 13:36:33 +03:00
parent 9e13c8bbe3
commit 6f6a1be3bd
8 changed files with 58 additions and 22 deletions
+1 -1
View File
@@ -23,7 +23,7 @@ const EFFECTS: Dictionary = {
"select": preload("res://sound/effects/select.ogg"), "select": preload("res://sound/effects/select.ogg"),
"star_birth": preload("res://sound/effects/star_birth.ogg"), "star_birth": preload("res://sound/effects/star_birth.ogg"),
"structure_decay": preload("res://sound/effects/structure_decay.ogg"), "structure_decay": preload("res://sound/effects/structure_decay.ogg"),
"swipe": preload("res://sound/effects/swipe.ogg"), #"swipe": preload("res://sound/effects/swipe.ogg"),
"time_minus": preload("res://sound/effects/time_minus.ogg"), "time_minus": preload("res://sound/effects/time_minus.ogg"),
"time_plus": preload("res://sound/effects/time_plus.ogg"), "time_plus": preload("res://sound/effects/time_plus.ogg"),
"trend_action": preload("res://sound/effects/trend_action.ogg"), "trend_action": preload("res://sound/effects/trend_action.ogg"),
+23 -1
View File
@@ -94,6 +94,7 @@ var g_active_items: Dictionary = {}
var pending_page: int = -1 var pending_page: int = -1
var active_actions_dirty: bool = true var active_actions_dirty: bool = true
var active_actions_elapsed: float = 0.0 var active_actions_elapsed: float = 0.0
var interface_sounds_enabled: bool = false
var owniverse:Owniverse = Owniverse.new() var owniverse:Owniverse = Owniverse.new()
var owniverse_items: Dictionary[String, OwniverseItem] = {} var owniverse_items: Dictionary[String, OwniverseItem] = {}
@@ -323,6 +324,11 @@ func _ready() -> void:
for pa in page_actions: for pa in page_actions:
page_actions[pa].action_pressed.connect(_page_action_pressed) page_actions[pa].action_pressed.connect(_page_action_pressed)
page_actions[pa].page_id = pa page_actions[pa].page_id = pa
_enable_interface_sounds.call_deferred()
func _enable_interface_sounds() -> void:
interface_sounds_enabled = true
## Starts a fresh universe. Can be connected directly to a button's pressed signal. ## Starts a fresh universe. Can be connected directly to a button's pressed signal.
@@ -398,10 +404,15 @@ func _process(delta: float) -> void:
func _change_speed(delta: int) -> void: func _change_speed(delta: int) -> void:
var previous_speed: int = owniverse.speed
owniverse.speed = owniverse.speed + delta owniverse.speed = owniverse.speed + delta
var speed: int = owniverse.speed var speed: int = owniverse.speed
if speed > previous_speed:
effects_player.play_effect("time_plus")
elif speed < previous_speed:
effects_player.play_effect("time_minus")
var ind: int = 1 var ind: int = 1
for icon in g_speed_icons: for icon in g_speed_icons:
if ind <= speed: if ind <= speed:
@@ -421,6 +432,17 @@ func _change_speed(delta: int) -> void:
func _on_topmenu_button_pressed(screen_name: String) -> void: func _on_topmenu_button_pressed(screen_name: String) -> void:
var current_screen: String = ""
for screen_id in screens:
if screens[screen_id].visible:
current_screen = screen_id
break
if current_screen == screen_name:
return
if interface_sounds_enabled:
effects_player.play_effect("window_close" if screen_name == "World" else "window_open")
for screen_id in screens: for screen_id in screens:
#print(screen_name, " ←→ ", screen_id) #print(screen_name, " ←→ ", screen_id)
+4 -7
View File
@@ -25,17 +25,14 @@ func run() -> void:
check(not player.play_effect("select"), "Playing effect is not restarted") check(not player.play_effect("select"), "Playing effect is not restarted")
check(player.stream == selected_stream and player.playing, "Rejected duplicate keeps current playback") check(player.stream == selected_stream and player.playing, "Rejected duplicate keeps current playback")
player.stop() player.stop()
check(not player.play_effect("select"), "Named effect is rejected during its two-second cooldown") check(player.play_effect("select"), "Stopped effect can start again immediately")
check(player.play_effect("blast"), "Different effect starts without waiting for another name") check(player.play_effect("blast"), "Different effect starts immediately")
player.stop()
player._last_played_msec.select -= player.EFFECT_COOLDOWN_MSEC
check(player.play_effect("select"), "Named effect starts after its cooldown")
check(not player.play_effect("missing_effect"), "Unknown effect is rejected") check(not player.play_effect("missing_effect"), "Unknown effect is rejected")
check(player.stream == player._effects.select, "Unknown effect does not interrupt playback") check(player.stream == player._effects.blast, "Unknown effect does not interrupt playback")
player.set_enabled(false) player.set_enabled(false)
check(player.stream_paused, "Disabling effects pauses current playback") check(player.stream_paused, "Disabling effects pauses current playback")
check(not player.play_effect("blast") and player.stream == player._effects.select, "Disabled player rejects new effects") check(not player.play_effect("select") and player.stream == player._effects.blast, "Disabled player rejects new effects")
player.set_enabled(true) player.set_enabled(true)
check(not player.stream_paused, "Enabling effects resumes current playback") check(not player.stream_paused, "Enabling effects resumes current playback")
+13 -2
View File
@@ -176,8 +176,19 @@ func run() -> void:
world.state.amount.Met = 100 world.state.amount.Met = 100
world.state.auto_resources.H = 100 world.state.auto_resources.H = 100
world.evolute(E.of("0.1")) world.evolute(E.of("0.1"))
check((E.eq(world.state.amount.RD, 101) and E.eq(world.state.amount.H, 0)), "Automatic formation uses its resource budget") check((E.eq(world.state.amount.RD, 1) and E.eq(world.state.amount.H, 100)), "Automatic formation cannot spend hydrogen retained from an earlier cycle")
check(E.ge(world.state.binds.RD.HP, 1), "Automatic formation also creates planets") check(E.eq(world.state.auto_resources.get("H", 0), 0), "Unused automatic hydrogen becomes an ordinary free resource")
dispose(world)
world = fixture()
world.catalog.entities.N.auto = 1
world.state.amount.RD = 1
world.state.amount.H = 100
world.state.amount.Met = 100
world.evolute(100)
check(E.gt(world.state.amount.RD, 1), "Automatic formation can spend newly produced hydrogen")
check(E.ge(world.state.amount.H, 100), "Automatic formation preserves hydrogen available before the cycle")
check(E.ge(world.state.binds.get("RD", {}).get("HP", 0), 1), "Automatic formation also creates planets")
dispose(world) dispose(world)
world = fixture() world = fixture()
+11
View File
@@ -21,6 +21,7 @@ func run() -> void:
root.add_child(scene) root.add_child(scene)
await process_frame await process_frame
await process_frame await process_frame
check(stage.effects_player.stream == null, "Startup does not play a UI sound")
stage.stage_page_scroller.scroll_horizontal = stage.PAGE_WIDTH stage.stage_page_scroller.scroll_horizontal = stage.PAGE_WIDTH
await process_frame await process_frame
stage.owniverse.state.amount.H = 1000 stage.owniverse.state.amount.H = 1000
@@ -54,6 +55,16 @@ func run() -> void:
stage.owniverse.state.time.year = E.of("1234.5") stage.owniverse.state.time.year = E.of("1234.5")
stage._refresh_universe_ui() stage._refresh_universe_ui()
check(E.eq(stage.date_time.text, "1 234.5"), "Time displays tenths with thousands separator") check(E.eq(stage.date_time.text, "1 234.5"), "Time displays tenths with thousands separator")
stage.effects_player.set_enabled(true)
stage.owniverse.speed = 1
stage._change_speed(1)
check(stage.effects_player.stream == stage.effects_player._effects.time_plus, "Increasing speed plays its effect")
stage._change_speed(-1)
check(stage.effects_player.stream == stage.effects_player._effects.time_minus, "Decreasing speed plays its effect")
stage._on_topmenu_button_pressed("MainMenu")
check(stage.effects_player.stream == stage.effects_player._effects.window_open, "Opening a window plays its effect")
stage._on_topmenu_button_pressed("World")
check(stage.effects_player.stream == stage.effects_player._effects.window_close, "Closing a window plays its effect")
for entity in stage.owniverse.catalog.entities.values(): entity.free() for entity in stage.owniverse.catalog.entities.values(): entity.free()
stage.owniverse.free() stage.owniverse.free()
scene.free() scene.free()
-7
View File
@@ -1,11 +1,8 @@
class_name OwniverseEffectsPlayer class_name OwniverseEffectsPlayer
extends AudioStreamPlayer extends AudioStreamPlayer
const EFFECT_COOLDOWN_MSEC := 2000
var enabled: bool = true var enabled: bool = true
var _effects: Dictionary = OwniverseAudioLoader.get_effects() var _effects: Dictionary = OwniverseAudioLoader.get_effects()
var _last_played_msec: Dictionary = {}
func set_enabled(value: bool) -> void: func set_enabled(value: bool) -> void:
@@ -21,11 +18,7 @@ func play_effect(effect_id: String) -> bool:
return false return false
if playing and stream == _effects[effect_id]: if playing and stream == _effects[effect_id]:
return false return false
var now: int = Time.get_ticks_msec()
if now - int(_last_played_msec.get(effect_id, -EFFECT_COOLDOWN_MSEC)) < EFFECT_COOLDOWN_MSEC:
return false
stream = _effects[effect_id] stream = _effects[effect_id]
play() play()
_last_played_msec[effect_id] = now
return true return true
+2 -2
View File
@@ -2,8 +2,8 @@ class_name OwniverseMusicPlayer
extends AudioStreamPlayer extends AudioStreamPlayer
const EXCLUDED_TRACK := "apocalypse_the_end" const EXCLUDED_TRACK := "apocalypse_the_end"
const MIN_PAUSE_SECONDS := 120.0 const MIN_PAUSE_SECONDS := 2 * 60.0
const MAX_PAUSE_SECONDS := 300.0 const MAX_PAUSE_SECONDS := 5 * 60.0
var enabled: bool = true var enabled: bool = true
var last_track: String = "" var last_track: String = ""
+4 -2
View File
@@ -58,8 +58,10 @@ func produce_for_period(previous: Dictionary, target: Dictionary, quantities: Di
amount = world.ledger.credit(target, id, amount) amount = world.ledger.credit(target, id, amount)
world.batches.append_batch(target, id, amount, from_year, to_year) world.batches.append_batch(target, id, amount, from_year, to_year)
# Keep unused automatic resources across cycles; they are part of free amounts. # Automation may spend only the automatic output produced during this cycle.
var budget: Dictionary = previous.get("auto_resources", {}).duplicate(true) # Any unused part becomes an ordinary free resource on the next cycle instead
# of remaining eligible for later automatic production.
var budget: Dictionary = {}
for id in automatic: for id in automatic:
budget[id] = E.add(budget.get(id, 0), automatic[id]) budget[id] = E.add(budget.get(id, 0), automatic[id])
for id in budget: for id in budget: