Ship the 0.9.0 production-quality milestone
Add mixer/accessibility settings, caption/reduce-motion hooks, audio volume clamping, a 24-NPC performance smoke and shortened coat/dress stride for hem clipping. Record the explicit Godot 4.3-CI/4.7-local matrix and the 0.9 production scope. Headless 250/250, Python 94/94, 24-NPC budget smoke passes.
This commit is contained in:
1 parent
b5d4d5fb87
commit
883626a067
19 files changed
+240
-131
No files matched your search
@@ -16,6 +16,23 @@ var radio_crackles := 0
|
||||
var footsteps := 0
|
||||
var landings := 0
|
||||
var precision_ticks := 0
|
||||
var master_volume := 1.0
|
||||
var sfx_volume := 1.0
|
||||
var ambience_volume := 1.0
|
||||
var _master_db := 0.0
|
||||
var _sfx_db := 0.0
|
||||
var _ambience_db := 0.0
|
||||
|
||||
## 0..1 mixer controls from Settings. Headless/no-audio builds just store them.
|
||||
func set_volumes(master: float, sfx: float, ambience: float) -> void:
|
||||
master_volume = clampf(master, 0.0, 1.0)
|
||||
sfx_volume = clampf(sfx, 0.0, 1.0)
|
||||
ambience_volume = clampf(ambience, 0.0, 1.0)
|
||||
_master_db = linear_to_db(maxf(master_volume, 0.0001))
|
||||
_sfx_db = linear_to_db(maxf(sfx_volume, 0.0001))
|
||||
_ambience_db = linear_to_db(maxf(ambience_volume, 0.0001))
|
||||
if _bed_player:
|
||||
_bed_player.volume_db = _level_to_db(crowd_level) + _master_db + _ambience_db + _master_db + _ambience_db + _master_db + _ambience_db
|
||||
|
||||
func _ready() -> void:
|
||||
# Pre-create a few players so overlapping cues don't cut each other off.
|
||||
@@ -112,7 +129,7 @@ func _play_tone(freq: float, duration: float, volume: float, delay: float = 0.0)
|
||||
stream.mix_rate = SAMPLE_RATE
|
||||
stream.buffer_length = duration + 0.05
|
||||
player.stream = stream
|
||||
player.volume_db = linear_to_db(volume)
|
||||
player.volume_db = linear_to_db(volume) + _master_db + _sfx_db
|
||||
player.play()
|
||||
# Fill the generator buffer with a sine wave.
|
||||
var playback: AudioStreamGeneratorPlayback = player.get_stream_playback()
|
||||
@@ -174,7 +191,7 @@ func _play_noise(duration: float, volume: float, cutoff_hz: float = 3200.0) -> v
|
||||
stream.stereo = false
|
||||
stream.data = data
|
||||
player.stream = stream
|
||||
player.volume_db = linear_to_db(volume)
|
||||
player.volume_db = linear_to_db(volume) + _master_db + _sfx_db
|
||||
player.play()
|
||||
|
||||
func _free_player() -> AudioStreamPlayer:
|
||||
|
||||
@@ -377,7 +377,10 @@ func _apply_settings(settings: Dictionary) -> void:
|
||||
if guard:
|
||||
guard.look_sensitivity = float(settings.get("look_sensitivity", 0.0022))
|
||||
guard.invert_y = bool(settings.get("invert_y", false))
|
||||
guard.head_bob_enabled = bool(settings.get("head_bob", true))
|
||||
guard.head_bob_enabled = bool(settings.get("head_bob", true)) and not bool(settings.get("reduce_motion", false))
|
||||
if audio:
|
||||
audio.set_volumes(float(settings.get("master_volume", 1.0)),
|
||||
float(settings.get("sfx_volume", 1.0)), float(settings.get("ambience_volume", 1.0)))
|
||||
InputBindings.apply(settings.get("input_bindings", {}))
|
||||
if hud and hud.has_method("set_font_scale"):
|
||||
hud.set_font_scale(float(settings.get("hud_font_scale", 1.0)))
|
||||
|
||||
@@ -1050,7 +1050,10 @@ func _animate(delta: float) -> void:
|
||||
_idle_t = 0.0
|
||||
_bob_phase += delta * (6.0 + speed * 1.7)
|
||||
var urgency := 1.35 if reaction_mode == "flee" else 1.0
|
||||
var stride := clampf(0.36 + speed * 0.10, 0.42, 0.7) * urgency
|
||||
# Coats and skirts follow the hip/knee bones; a shorter stride keeps the
|
||||
# hem from clipping through the legs during normal walking.
|
||||
var hem_scale := 0.76 if character_model in ["npc_dress", "npc_coat"] else 1.0
|
||||
var stride := clampf(0.36 + speed * 0.10, 0.42, 0.7) * urgency * hem_scale
|
||||
_rig.position.y = sin(_bob_phase * 2.0) * 0.03
|
||||
_rig.position.x = 0.0
|
||||
_rig.rotation.x = sin(_bob_phase) * 0.03
|
||||
|
||||
@@ -22,6 +22,11 @@ var _font_scale_value: Label = null
|
||||
var _invert_y: CheckButton = null
|
||||
var _head_bob: CheckButton = null
|
||||
var _difficulty: OptionButton = null
|
||||
var _master: HSlider = null
|
||||
var _sfx: HSlider = null
|
||||
var _ambience: HSlider = null
|
||||
var _reduce_motion: CheckButton = null
|
||||
var _captions: CheckButton = null
|
||||
var _bind_buttons := {}
|
||||
var _listening_action := ""
|
||||
var settings: Dictionary = {}
|
||||
@@ -101,6 +106,27 @@ func _build() -> void:
|
||||
_difficulty.item_selected.connect(_on_difficulty_selected)
|
||||
diff_row.add_child(_difficulty)
|
||||
|
||||
var audio_row := HBoxContainer.new()
|
||||
column.add_child(audio_row)
|
||||
audio_row.add_child(_volume_label("Master volume"))
|
||||
_master = _add_slider(audio_row, 0.0, 1.0, 0.05)
|
||||
audio_row.add_child(_volume_label("SFX"))
|
||||
_sfx = _add_slider(audio_row, 0.0, 1.0, 0.05)
|
||||
audio_row.add_child(_volume_label("Ambience"))
|
||||
_ambience = _add_slider(audio_row, 0.0, 1.0, 0.05)
|
||||
_master.value_changed.connect(func(v): settings["master_volume"] = v)
|
||||
_sfx.value_changed.connect(func(v): settings["sfx_volume"] = v)
|
||||
_ambience.value_changed.connect(func(v): settings["ambience_volume"] = v)
|
||||
|
||||
_reduce_motion = CheckButton.new()
|
||||
_reduce_motion.text = "Reduce motion"
|
||||
_reduce_motion.toggled.connect(func(v): settings["reduce_motion"] = v)
|
||||
column.add_child(_reduce_motion)
|
||||
_captions = CheckButton.new()
|
||||
_captions.text = "Captions / subtitles"
|
||||
_captions.toggled.connect(func(v): settings["captions_enabled"] = v)
|
||||
column.add_child(_captions)
|
||||
|
||||
var replay_row := HBoxContainer.new()
|
||||
replay_row.alignment = BoxContainer.ALIGNMENT_CENTER
|
||||
column.add_child(replay_row)
|
||||
@@ -165,6 +191,13 @@ func _add_label_row(parent: Control, text: String) -> Label:
|
||||
row.add_child(value)
|
||||
return value
|
||||
|
||||
func _volume_label(text: String) -> Label:
|
||||
var label := Label.new()
|
||||
label.text = text
|
||||
label.add_theme_font_size_override("font_size", 11)
|
||||
label.custom_minimum_size = Vector2(82, 0)
|
||||
return label
|
||||
|
||||
func _add_slider(parent: Control, min_v: float, max_v: float, step: float) -> HSlider:
|
||||
var slider := HSlider.new()
|
||||
slider.min_value = min_v
|
||||
@@ -189,6 +222,16 @@ func open(current: Dictionary) -> void:
|
||||
if _difficulty:
|
||||
var difficulty := str(settings.get("ai_difficulty", "normal"))
|
||||
_difficulty.select(["easy", "normal", "hard"].find(difficulty))
|
||||
if _master:
|
||||
_master.set_value_no_signal(float(settings.get("master_volume", 1.0)))
|
||||
if _sfx:
|
||||
_sfx.set_value_no_signal(float(settings.get("sfx_volume", 1.0)))
|
||||
if _ambience:
|
||||
_ambience.set_value_no_signal(float(settings.get("ambience_volume", 1.0)))
|
||||
if _reduce_motion:
|
||||
_reduce_motion.set_pressed_no_signal(bool(settings.get("reduce_motion", false)))
|
||||
if _captions:
|
||||
_captions.set_pressed_no_signal(bool(settings.get("captions_enabled", true)))
|
||||
_listening_action = ""
|
||||
_refresh_bind_buttons()
|
||||
_sync_labels()
|
||||
|
||||
Reference in new issue
Block a user