Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 62 additions & 21 deletions C7/Audio/AudioManager.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

using System;
using System.Collections.Generic;
using C7Engine;
using Godot;
using Serilog;
Expand All @@ -18,8 +19,6 @@ public partial class AudioManager : Node {
private PolyphonicAudioPlayer _polyUiAudioPlayer;
private PolyphonicAudioPlayer _polyAmbienceAudioPlayer;

private static string AudioSettingsSection = "audio";

public static string MusicBus = "Music";
public static string SfxAudioBus = "Sfx";
public static string UIAudioBus = "UI";
Expand All @@ -29,27 +28,39 @@ public partial class AudioManager : Node {
private bool sfxAudioEnabled = true;
private bool uiAudioEnabled = true;
private bool ambienceAudioEnabled = true;
// Maps a bus to the settings key holding its volume. Public so settings UI
// can drive a bus without repeating the magic strings.
public static readonly Dictionary<string, string> BusVolumeKeys = new() {
{ MusicBus, C7Settings.Audio.MusicVolume },
{ SfxAudioBus, C7Settings.Audio.SfxAudioVolume },
{ UIAudioBus, C7Settings.Audio.UiAudioVolume },
{ AmbienceAudioBus, C7Settings.Audio.AmbienceAudioVolume },
};



public override void _Ready() {
log = LogManager.ForContext<AudioManager>();

musicEnabled = ConfigureVolume("musicVolume", MusicBus);
musicEnabled = ConfigureVolume(C7Settings.Audio.MusicVolume, MusicBus);
_polyMusicPlayer = new PolyphonicAudioPlayer(musicPlayer, 2);

sfxAudioEnabled = ConfigureVolume("sfxAudioVolume", SfxAudioBus);
sfxAudioEnabled = ConfigureVolume(C7Settings.Audio.SfxAudioVolume, SfxAudioBus);
_polySfxAudioPlayer = new PolyphonicAudioPlayer(sfxAudioPlayer, 32);

uiAudioEnabled = ConfigureVolume("uiAudioVolume", UIAudioBus);
uiAudioEnabled = ConfigureVolume(C7Settings.Audio.UiAudioVolume, UIAudioBus);
_polyUiAudioPlayer = new PolyphonicAudioPlayer(uiAudioPlayer, 8);

ambienceAudioEnabled = ConfigureVolume("ambienceAudioVolume", AmbienceAudioBus);
ambienceAudioEnabled = ConfigureVolume(C7Settings.Audio.AmbienceAudioVolume, AmbienceAudioBus);
_polyAmbienceAudioPlayer = new PolyphonicAudioPlayer(ambienceAudioPlayer, 8);
}

private bool ConfigureVolume(string volumeKey, string audioBus) {
try {
string volume = C7Settings.GetSettingValue(AudioSettingsSection, volumeKey);
float volumeDb = LogicalVolumeAsDecibel(volume, volumeKey);
// A missing key means the user never set it, so fall back to full
// volume rather than letting int.Parse throw on null.
string volume = C7Settings.GetSettingsValueOrDefault(C7Settings.Audio.SectionName, volumeKey, "100");
float volumeDb = LogicalVolumeAsDecibel(int.Parse(volume));

if (volumeDb == float.MinValue) {
return false;
Expand All @@ -75,22 +86,14 @@ private bool ConfigureVolume(string volumeKey, string audioBus) {
* Our users are probably more used to a 0% to 100% system.
* So this method converts between them.
*/
private float LogicalVolumeAsDecibel(string volume, string volumeKey) {
if (volume == null) {
//First run. Save the setting.
C7Settings.SetValue(AudioSettingsSection, volumeKey, "100");
C7Settings.SaveSettings();
return 0;
public static float LogicalVolumeAsDecibel(int volume) {
if (volume <= 0) {
return float.MinValue;
}
int userVolumeSetting = int.Parse(volume);
if (userVolumeSetting == 100) {
if (volume >= 100) {
return 0;
} else if (userVolumeSetting == 0) {
return float.MinValue;
} else {
//Conversion math based on https://stackoverflow.com/a/37810295/3534605
return 20.0f * (float)(Math.Log10(userVolumeSetting / 100.0f));
}
return 20.0f * (float)(Math.Log10(volume / 100.0f));
}

// TODO: playlists, mixing, transitions
Expand Down Expand Up @@ -123,6 +126,44 @@ public void StopMusic() {
}
}


/// <summary>
/// The user's volume for a bus, as a 0-100 percentage, or -1 if the bus is
/// unknown.
/// </summary>
public int GetBusVolume(string bus) {
if (!BusVolumeKeys.TryGetValue(bus, out string key)) {
log.Warning("No volume setting known for bus {bus}", bus);
return -1;
}
string stored = C7Settings.GetSettingsValueOrDefault(C7Settings.Audio.SectionName, key, "100");
return int.TryParse(stored, out int volume) ? volume : 100;
}

public void SetBusVolume(string bus, int volume) {
if (!BusVolumeKeys.TryGetValue(bus, out string key)) {
log.Warning("No volume setting known for bus {bus}", bus);
return;
}
volume = Mathf.Clamp(volume, 0, 100);
C7Settings.SetValue(C7Settings.Audio.SectionName, key, volume.ToString());
C7Settings.SaveSettings();
SetBusVolumeDb(bus, LogicalVolumeAsDecibel(volume));
}

public void SetBusVolumePercent(string bus, int volume) {
SetBusVolumeDb(bus, LogicalVolumeAsDecibel(Mathf.Clamp(volume, 0, 100)));
}

private void SetBusVolumeDb(string bus, float volumeDb) {
int busIndex = AudioServer.GetBusIndex(bus);
if (busIndex < 0) {
log.Warning("Audio bus {bus} not found", bus);
return;
}
AudioServer.SetBusVolumeDb(busIndex, volumeDb);
AudioServer.SetBusMute(busIndex, volumeDb == float.MinValue);
}
public void PlaySfxAudio(string configKey) {
var stream = AudioLoader.Load(configKey);
if (stream != null)
Expand Down
14 changes: 13 additions & 1 deletion C7/C7Game.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
[ext_resource type="Script" uid="uid://cfenrvu7tnp40" path="res://DoubleClickHandler.cs" id="2_t735q"]
[ext_resource type="Script" uid="uid://dflpmvue8o7uo" path="res://UnitSelector.cs" id="2_w8hq2"]
[ext_resource type="Script" uid="uid://ifoasmoofo6r" path="res://UIElements/Advisors/Advisors.cs" id="3"]
[ext_resource type="PackedScene" path="res://UIElements/preferences.tscn" id="3_prefs"]
[ext_resource type="Script" uid="uid://bvmc8fimjfo2j" path="res://Animations/AnimationController.cs" id="3_rmrhh"]
[ext_resource type="Script" uid="uid://3wtlmr00bmfb" path="res://UIElements/UpperLeftNav/MenuButton.cs" id="4"]
[ext_resource type="Script" uid="uid://cproyms6andlc" path="res://UIElements/UpperLeftNav/CivilopediaButton.cs" id="5"]
Expand All @@ -30,14 +31,15 @@
[ext_resource type="PackedScene" uid="uid://bwe87nwkg01n1" path="res://UIElements/GameViews/space_race_view.tscn" id="25_y31gw"]
[ext_resource type="PackedScene" uid="uid://dvrx5adwjd0w4" path="res://UIElements/GameViews/demographics_view.tscn" id="27_gbxbf"]

[node name="C7Game" type="Node" node_paths=PackedStringArray("Toolbar", "popupOverlay", "cityScreen", "advisor", "gameViews", "diplomacy", "doubleClickHandler", "animationController", "unitSelector")]
[node name="C7Game" type="Node" node_paths=PackedStringArray("Toolbar", "popupOverlay", "cityScreen", "advisor", "gameViews", "diplomacy", "preferences", "doubleClickHandler", "animationController", "unitSelector")]
script = ExtResource("1")
Toolbar = NodePath("CanvasLayer/Control/ToolBar/MarginContainer/HBoxContainer")
popupOverlay = NodePath("CanvasLayer/PopupOverlay")
cityScreen = NodePath("CanvasLayer/CityScreen")
advisor = NodePath("CanvasLayer/Advisor")
gameViews = NodePath("CanvasLayer/GameViews")
diplomacy = NodePath("CanvasLayer/Diplomacy")
preferences = NodePath("CanvasLayer/Preferences")
doubleClickHandler = NodePath("DoubleClickHandler")
animationController = NodePath("AnimationController")
unitSelector = NodePath("UnitSelector")
Expand Down Expand Up @@ -198,6 +200,15 @@ script = ExtResource("8_7a2mf")
text = "S"
tooltipText = "Spaceship"

[node name="Preferences" parent="CanvasLayer" instance=ExtResource("3_prefs")]
visible = false
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2

[node name="Advisor" type="CenterContainer" parent="CanvasLayer" node_paths=PackedStringArray("domesticAdvisor", "tradeAdvisor", "militaryAdvisor", "foreignAdvisor", "culturalAdvisor", "scienceAdvisor")]
anchors_preset = 15
anchor_right = 1.0
Expand Down Expand Up @@ -335,3 +346,4 @@ visible = false
[connection signal="Retire" from="CanvasLayer/PopupOverlay" to="." method="OnRetire"]
[connection signal="SaveGame" from="CanvasLayer/PopupOverlay" to="." method="OnSaveGame"]
[connection signal="LoadGame" from="CanvasLayer/PopupOverlay" to="." method="OnLoadGame"]
[connection signal="OpenPreferences" from="CanvasLayer/PopupOverlay" to="." method="OnOpenPreferences"]
36 changes: 35 additions & 1 deletion C7/Game.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ public partial class Game : Node {
private GameViews gameViews;
[Export]
private Diplomacy diplomacy;
[Export]
private Preferences preferences;

[Export]
private DoubleClickHandler doubleClickHandler;
Expand Down Expand Up @@ -581,6 +583,15 @@ public void OnLoadGame() {
FileDialog.Popup();
}

public void OnOpenPreferences() {
popupOverlay.OnHidePopup();
if (preferences.Visible) {
preferences.HidePreferences();
} else {
preferences.ShowPreferences();
}
}

public void OnResolved() {
popupOverlay.OnHidePopup();
}
Expand Down Expand Up @@ -817,6 +828,15 @@ private void HandleKeyboardInput(InputEventKey eventKeyDown) {
ToggleObserverMode();
}

if (eventKeyDown.Keycode == Godot.Key.P && eventKeyDown.IsCommandOrControlPressed()) {
if (preferences.Visible) {
preferences.HidePreferences();
} else {
preferences.ShowPreferences();
}
return;
}

if (eventKeyDown.Keycode == Godot.Key.F1) {
EmitSignal(SignalName.ShowSpecificAdvisor, C7Action.ShowDomesticAdvisor);
}
Expand Down Expand Up @@ -955,7 +975,7 @@ private bool HasVisibleModal() {
if (popupOverlay.Visible || cityScreen.Visible || diplomacy.Visible)
return true;

if (advisor.Visible || gameViews.Visible)
if (advisor.Visible || gameViews.Visible || preferences.Visible)
return true;

return false;
Expand Down Expand Up @@ -990,6 +1010,20 @@ private void ProcessAction(string currentAction) {
return;
}

if (currentAction == C7Action.OpenPreferences) {
if (preferences.Visible) {
preferences.HidePreferences();
} else {
preferences.ShowPreferences();
}
return;
}

if (currentAction == C7Action.Escape && preferences.Visible) {
preferences.HidePreferences();
return;
}

if (currentAction == C7Action.Escape && gameViews.Visible) {
gameViews.Hide();
return;
Expand Down
23 changes: 23 additions & 0 deletions C7/PreferencesSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using C7Engine;

namespace C7.UIElements;

/// <summary>
/// User preferences, stored outside the save file so they stay stable across
/// games and scenarios. Surfaced by the Preferences scene, reachable from the
/// main menu, the in-game GameMenu, and Ctrl-P.
/// </summary>
public static class PreferencesSettings {
public const string SectionName = "Preferences";
public const string PromptForResearch = nameof(PromptForResearch);
public const bool DefaultPromptForResearch = true;

public static bool GetPromptForResearch() {
return C7Settings.GetBoolOrDefault(SectionName, PromptForResearch, DefaultPromptForResearch);
}

public static void SetPromptForResearch(bool value) {
C7Settings.SetBool(SectionName, PromptForResearch, value);
C7Settings.SaveSettings();
}
}
29 changes: 25 additions & 4 deletions C7/UIElements/Civ3Checkbox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@ public enum TextPosition {
TextBelowIcon
}

private Texture2D normalTexture = TextureLoader.Load("ui.checkbox.inactive");
private Texture2D hoverTexture = TextureLoader.Load("ui.checkbox.hover");
private Texture2D pressedTexture = TextureLoader.Load("ui.checkbox.pressed");
private Texture2D normalTexture;
private Texture2D hoverTexture;
private Texture2D pressedTexture;

public Civ3Checkbox() {
}

private string _text;
[Export]
Expand All @@ -24,6 +27,7 @@ public string Text {
_text = value;
if (label != null) {
label.Text = _text;
RefreshMinimumSize();
}
}
}
Expand All @@ -35,10 +39,11 @@ public int FontSize {
_fontSize = value;
if (label != null) {
label.AddThemeFontSizeOverride("font_size", _fontSize);
RefreshMinimumSize();
}
}
}
private TextPosition _textPosition;
private TextPosition _textPosition = TextPosition.TextRightOfIcon;
[Export]
public TextPosition textPosition {
get => _textPosition;
Expand Down Expand Up @@ -70,6 +75,10 @@ public Civ3Checkbox(TextPosition textPosition = TextPosition.TextRightOfIcon) {
}

public override void _Ready() {
normalTexture = TextureLoader.Load("ui.checkbox.inactive");
hoverTexture = TextureLoader.Load("ui.checkbox.hover");
pressedTexture = TextureLoader.Load("ui.checkbox.pressed");

fontColor = GetThemeColor("font_color", "Button");
hoverColor = GetThemeColor("font_hover_color", "Button");
pressedColor = GetThemeColor("font_pressed_color", "Button");
Expand Down Expand Up @@ -139,6 +148,18 @@ private void SetUpLayout() {
boxContainer.AddChild(textureRect);
boxContainer.AddChild(label);
}

RefreshMinimumSize();
}

// Grow the button to cover the icon and the label so the whole thing is
// clickable. Godot caches the bare CheckBox size, so it has to be set
// explicitly whenever the contents change.
private void RefreshMinimumSize() {
if (boxContainer == null) {
return;
}
CustomMinimumSize = boxContainer.GetCombinedMinimumSize();
}

// Expand the size of the button to contain the texture and the label.
Expand Down
10 changes: 6 additions & 4 deletions C7/UIElements/MainMenu/MainMenu.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public partial class MainMenu : Node {
Civ3FileDialog LoadScenarioDialog;
[Export]
MenuButtonContainer ButtonContainer;
[Export]
Preferences preferences;

GlobalSingleton Global;
AudioManager AudioManager;
Expand Down Expand Up @@ -63,9 +65,8 @@ private void DisplayTitleScreen() {
ButtonContainer.LoadScenario.Pressed += LoadScenario;
ButtonContainer.HallOfFame.Pressed += HallOfFame;
ButtonContainer.HallOfFame.Visible = false;
ButtonContainer.Preferences.Pressed += Preferences;
ButtonContainer.Preferences.Visible = false;
ButtonContainer.AudioPreferences.Pressed += Preferences;
ButtonContainer.Preferences.Pressed += ShowPreferences;
ButtonContainer.AudioPreferences.Pressed += ShowPreferences;
ButtonContainer.AudioPreferences.Visible = false;
ButtonContainer.Credits.Pressed += showCredits;
ButtonContainer.Exit.Pressed += _on_Exit_pressed;
Expand Down Expand Up @@ -142,8 +143,9 @@ public void HallOfFame() {
PlayButtonPressedSound();
}

public void Preferences() {
public void ShowPreferences() {
PlayButtonPressedSound();
preferences.ShowPreferences();
}

public void _on_Exit_pressed() {
Expand Down
Loading
Loading