Add input sound cues to battle controls

This commit is contained in:
2026-06-20 10:06:42 +09:00
parent a455eee3e8
commit cfe0532ee1
2 changed files with 64 additions and 5 deletions

View File

@@ -89,6 +89,7 @@ const BGM_VOLUME_DB := -8.0
const SFX_VOLUME_DB := -2.0
const UI_SFX_VOLUME_DB := -4.0
const AUDIO_MUTED_DB := -80.0
const MAX_RECENT_SFX_KEYS := 32
const FLOATING_TEXT_LIFETIME := 1.0
const FLOATING_TEXT_RISE := 42.0
const OBJECTIVE_NOTICE_DURATION := 2.6
@@ -631,6 +632,7 @@ var missing_portrait_paths := {}
var bgm_player: AudioStreamPlayer
var current_bgm_key := ""
var audio_stream_cache := {}
var recent_sfx_keys: Array[String] = []
var last_announced_battle_status := ""
var floating_texts: Array[Dictionary] = []
var objective_notice_timer := 0.0
@@ -4818,6 +4820,7 @@ func _play_sfx(key: String, volume_db := SFX_VOLUME_DB) -> void:
var stream := _sfx_stream_for(key)
if stream == null:
return
_remember_sfx_key(key)
var player := AudioStreamPlayer.new()
player.name = "Sfx_%s" % key
player.stream = stream
@@ -4830,6 +4833,15 @@ func _play_sfx(key: String, volume_db := SFX_VOLUME_DB) -> void:
player.play()
func _remember_sfx_key(key: String) -> void:
var normalized_key := key.strip_edges()
if normalized_key.is_empty():
return
recent_sfx_keys.append(normalized_key)
while recent_sfx_keys.size() > MAX_RECENT_SFX_KEYS:
recent_sfx_keys.pop_front()
func _sfx_stream_for(key: String) -> AudioStream:
if key == "bow_release":
return _audio_stream_from_path(SFX_BOW_RELEASE_PATH)
@@ -4950,7 +4962,8 @@ func _handle_board_click(screen_position: Vector2) -> void:
selected_item_id = ""
basic_attack_targeting = false
_clear_pending_move_state()
state.select_unit(clicked_unit["id"])
if state.select_unit(clicked_unit["id"]):
_play_ui_click()
return
if not selected_item_id.is_empty():
@@ -4964,7 +4977,8 @@ func _handle_board_click(screen_position: Vector2) -> void:
if not clicked_unit.is_empty() and clicked_unit.get("team", "") == selected_unit.get("team", "") and _can_select(clicked_unit):
selected_item_id = ""
basic_attack_targeting = false
state.select_unit(clicked_unit["id"])
if state.select_unit(clicked_unit["id"]):
_play_ui_click()
return
if not selected_skill_id.is_empty():
@@ -4979,7 +4993,8 @@ func _handle_board_click(screen_position: Vector2) -> void:
selected_skill_id = ""
selected_item_id = ""
basic_attack_targeting = false
state.select_unit(clicked_unit["id"])
if state.select_unit(clicked_unit["id"]):
_play_ui_click()
return
if not clicked_unit.is_empty() and clicked_unit.get("team", "") != selected_unit.get("team", ""):
@@ -5003,7 +5018,8 @@ func _handle_board_click(screen_position: Vector2) -> void:
selected_item_id = ""
basic_attack_targeting = false
_clear_pending_move_state()
state.select_unit(clicked_unit["id"])
if state.select_unit(clicked_unit["id"]):
_play_ui_click()
return
var selected_start_cell: Vector2i = selected_unit.get("pos", Vector2i(-1, -1))
@@ -5028,7 +5044,8 @@ func _handle_board_click(screen_position: Vector2) -> void:
selected_item_id = ""
basic_attack_targeting = false
_clear_pending_move_state()
state.select_unit(clicked_unit["id"])
if state.select_unit(clicked_unit["id"]):
_play_ui_click()
func _has_pending_move() -> bool:
@@ -8924,6 +8941,7 @@ func _handle_minimap_mouse_button(event: InputEventMouseButton) -> bool:
return false
if inside_map_body:
minimap_dragging = true
_play_ui_click()
_scroll_board_to_minimap_position(event.position)
return true
if minimap_dragging:

View File

@@ -12,6 +12,7 @@ func _init() -> void:
_check_scene_post_move_edge_positioning(failures)
_check_scene_post_move_scrolled_view_positioning(failures)
_check_scene_post_move_menu_tracks_map_scroll(failures)
_check_scene_input_audio_cues(failures)
_check_scene_post_move_text_fit(failures)
_check_scene_post_move_blocked_command_labels(failures)
_check_scene_post_move_tactic_picker_flow(failures)
@@ -315,6 +316,46 @@ func _check_scene_post_move_menu_tracks_map_scroll(failures: Array[String]) -> v
scene.free()
func _check_scene_input_audio_cues(failures: Array[String]) -> void:
var scene = BattleSceneScript.new()
scene._create_hud()
scene._create_audio()
if not scene.state.load_battle("res://data/scenarios/001_yellow_turbans.json"):
failures.append("could not load opening battle for input audio cues")
scene.free()
return
scene.battle_started = true
scene.campaign_complete_screen = false
scene.briefing_panel.visible = false
scene.result_panel.visible = false
scene._clear_pending_move_state()
var cao_cao: Dictionary = scene.state.get_unit("cao_cao")
var cao_cell: Vector2i = cao_cao.get("pos", Vector2i(-1, -1))
scene.recent_sfx_keys.clear()
scene._handle_board_click(_screen_for_cell(cao_cell))
if not scene.recent_sfx_keys.has("ui_click"):
failures.append("selecting a unit from the map should request a UI click sound: %s" % str(scene.recent_sfx_keys))
scene.recent_sfx_keys.clear()
var minimap_press := InputEventMouseButton.new()
minimap_press.button_index = MOUSE_BUTTON_LEFT
minimap_press.pressed = true
minimap_press.position = scene._minimap_map_rect().get_center()
if not scene._handle_minimap_mouse_button(minimap_press):
failures.append("minimap press should be handled for audio cue validation")
if not scene.recent_sfx_keys.has("ui_click"):
failures.append("clicking the minimap should request a UI click sound: %s" % str(scene.recent_sfx_keys))
scene.title_sfx_enabled = false
scene.state.clear_selection()
scene.recent_sfx_keys.clear()
scene._handle_board_click(_screen_for_cell(cao_cell))
if not scene.recent_sfx_keys.is_empty():
failures.append("disabled SFX should suppress input audio requests: %s" % str(scene.recent_sfx_keys))
scene.free()
func _check_scene_post_move_text_fit(failures: Array[String]) -> void:
var scene = BattleSceneScript.new()
scene._create_hud()