using Chickensoft.AutoInject; using Chickensoft.Introspection; using Godot; using System; using System.Linq; namespace Zennysoft.Game.Ma; [Meta(typeof(IAutoNode))] public partial class OptionsMenu : Control { public override void _Notification(int what) => this.Notify(what); [Node] public OptionButton ResolutionOptions { get; set; } [Node] public OptionButton SoundDeviceOptions { get; set; } [Node] public HSlider MasterVolumeSlider { get; set; } [Node] public HSlider MusicVolumeSlider { get; set; } [Node] public HSlider SFXVolumeSlider { get; set; } [Node] public Button SELabel { get; set; } [Node] public Button MusicLabel { get; set; } [Node] public Button MasterLabel { get; set; } [Node] public InputMapper Controller { get; set; } [Node] public CheckBox SkipOpeningCSCheck { get; set; } [Node] public Button DeleteSaveButton { get; set; } [Node] public Control ConfirmDeletePopup { get; set; } [Node] public Button YesDeleteButton { get; set; } [Node] public Button NoDeleteButton { get; set; } [Node] public Control Game { get; set; } [Node] public Control Audio { get; set; } [Node] public Button GameTab { get; set; } [Node] public Button AudioTab { get; set; } [Node] public Button ControllerTab { get; set; } private TabOption _currentTab = TabOption.Game; public OptionsData OptionsData; private int _masterBusIndex; private int _musicBusIndex; private int _sfxBusIndex; private Control _currentFocus; private readonly DisplayServer.WindowMode[] _windowModes = [DisplayServer.WindowMode.Windowed, DisplayServer.WindowMode.Maximized, DisplayServer.WindowMode.Fullscreen, DisplayServer.WindowMode.ExclusiveFullscreen]; [Signal] public delegate void OptionsMenuExitedEventHandler(); [Signal] public delegate void DeleteSaveDataEventHandler(); public void OnReady() { ResolutionOptions.AddItem("Windowed"); ResolutionOptions.AddItem("Maximized"); ResolutionOptions.AddItem("Fullscreen"); ResolutionOptions.AddItem("Exclusive Fullscreen"); ResolutionOptions.Select(0); var devices = AudioServer.GetOutputDeviceList(); foreach (var device in devices) SoundDeviceOptions.AddItem(device); SoundDeviceOptions.Select(0); SoundDeviceOptions.AllowReselect = true; SoundDeviceOptions.Pressed += SoundDeviceOptions_Pressed; SoundDeviceOptions.ItemSelected += ChangeAudioDevice; OptionsData = new OptionsData() { MasterVolumeLevel = MasterVolumeSlider.Value, MusicVolumeLevel = MusicVolumeSlider.Value, SFXVolumeLevel = SFXVolumeSlider.Value, AudioDeviceName = "Default", ScreenResolution = ResolutionOptions.GetSelectedId(), SkipCutscene = SkipOpeningCSCheck.ButtonPressed }; SkipOpeningCSCheck.Pressed += SkipOpeningCS_Pressed; DeleteSaveButton.Pressed += DeleteSaveButton_Pressed; YesDeleteButton.Pressed += YesDeleteButton_Pressed; NoDeleteButton.Pressed += NoDeleteButton_Pressed; MasterVolumeSlider.ValueChanged += MasterVolumeSlider_Changed; MusicVolumeSlider.ValueChanged += MusicVolumeSlider_Changed; SFXVolumeSlider.ValueChanged += SFXVolumeSlider_Changed; ResolutionOptions.ItemSelected += ResolutionOptions_ItemSelected; _masterBusIndex = AudioServer.GetBusIndex("Master"); _musicBusIndex = AudioServer.GetBusIndex("MUSIC"); _sfxBusIndex = AudioServer.GetBusIndex("SFX"); GameTab.FocusEntered += Game_FocusEntered; AudioTab.FocusEntered += Audio_FocusEntered; ControllerTab.FocusEntered += Controller_FocusEntered; SELabel.Pressed += SELabel_Pressed; MusicLabel.Pressed += MusicLabel_Pressed; MasterLabel.Pressed += MasterLabel_Pressed; GetViewport().GuiFocusChanged += OptionsMenu_GuiFocusChanged; } public override void _Input(InputEvent @event) { if (!Visible) return; if (Input.IsActionJustPressed(GameInputs.Interact) || Input.IsActionJustPressed(GameInputs.Attack)) { if (SFXVolumeSlider.HasFocus()) { SELabel.GrabFocus(); AcceptEvent(); return; } if (MusicVolumeSlider.HasFocus()) { MusicLabel.GrabFocus(); AcceptEvent(); return; } if (MasterVolumeSlider.HasFocus()) { MasterLabel.GrabFocus(); AcceptEvent(); return; } } if (Input.IsActionJustPressed(GameInputs.Interact) || Input.IsActionJustPressed(GameInputs.Pause)) { if (GameTab.HasFocus() || AudioTab.HasFocus() || ControllerTab.HasFocus()) { AcceptEvent(); SaveAndExitMenu(); } else { var path = GetPathTo(_currentFocus).ToString(); if (path.Contains("Game")) GameTab.GrabFocus(); else if (path.Contains("Audio")) AudioTab.GrabFocus(); else if (path.Contains("Controller")) ControllerTab.GrabFocus(); } } } private void ResolutionOptions_ItemSelected(long index) { var resolutionIndex = ResolutionOptions.GetSelectedId(); OptionsData.ScreenResolution = resolutionIndex; DisplayServer.WindowSetMode(_windowModes[resolutionIndex]); } private void ChangeAudioDevice(long index) { var i = SoundDeviceOptions.GetSelectedId(); var deviceName = SoundDeviceOptions.GetItemText(i); AudioServer.SetOutputDevice(deviceName); OptionsData.AudioDeviceName = deviceName; } public void Load(OptionsData optionsData) { MasterVolumeSlider.Value = optionsData.MasterVolumeLevel; MusicVolumeSlider.Value = optionsData.MusicVolumeLevel; SFXVolumeSlider.Value = optionsData.SFXVolumeLevel; ResolutionOptions.Select(optionsData.ScreenResolution); var audioDevices = AudioServer.GetOutputDeviceList(); if (!audioDevices.Contains(optionsData.AudioDeviceName)) SoundDeviceOptions.Select(0); else { var selectedDeviceIndex = AudioServer.GetOutputDeviceList().ToList().IndexOf(optionsData.AudioDeviceName); SoundDeviceOptions.Select(selectedDeviceIndex); } SkipOpeningCSCheck.ButtonPressed = optionsData.SkipCutscene; DisplayServer.WindowSetMode(_windowModes[optionsData.ScreenResolution]); } private void OptionsMenu_GuiFocusChanged(Control node) => _currentFocus = node; private void MasterLabel_Pressed() { MasterVolumeSlider.GrabFocus(); } private void MusicLabel_Pressed() { MusicVolumeSlider.GrabFocus(); } private void SELabel_Pressed() { SFXVolumeSlider.GrabFocus(); } private void SoundDeviceOptions_Pressed() { var selectedItem = SoundDeviceOptions.Selected; SoundDeviceOptions.Clear(); var devices = AudioServer.GetOutputDeviceList(); foreach (var device in devices) SoundDeviceOptions.AddItem(device); SoundDeviceOptions.Select(selectedItem); } private void SkipOpeningCS_Pressed() => OptionsData.SkipCutscene = SkipOpeningCSCheck.ButtonPressed; private void NoDeleteButton_Pressed() { ReleaseFocus(); ConfirmDeletePopup.Hide(); DeleteSaveButton.GrabFocus(); } private void YesDeleteButton_Pressed() { EmitSignal(SignalName.DeleteSaveData); ReleaseFocus(); ConfirmDeletePopup.Hide(); DeleteSaveButton.GrabFocus(); } private void DeleteSaveButton_Pressed() { NoDeleteButton.GrabFocus(); ConfirmDeletePopup.Show(); } private void SaveAndExitMenu() => EmitSignal(SignalName.OptionsMenuExited); private void MasterVolumeSlider_Changed(double valueChanged) { OptionsData.MasterVolumeLevel = valueChanged; AudioServer.SetBusVolumeDb(_masterBusIndex, Mathf.LinearToDb((float)valueChanged)); } private void MusicVolumeSlider_Changed(double valueChanged) { OptionsData.MusicVolumeLevel = valueChanged; AudioServer.SetBusVolumeDb(_musicBusIndex, Mathf.LinearToDb((float)valueChanged)); } private void SFXVolumeSlider_Changed(double valueChanged) { OptionsData.SFXVolumeLevel = valueChanged; AudioServer.SetBusVolumeDb(_sfxBusIndex, Mathf.LinearToDb((float)valueChanged)); } private void Controller_FocusEntered() { Audio.Hide(); Controller.Show(); Game.Hide(); } private void Game_FocusEntered() { Audio.Hide(); Controller.Hide(); Game.Show(); } private void Audio_FocusEntered() { Audio.Show(); Controller.Hide(); Game.Hide(); } } public enum TabOption { Game, Audio, Controls }