From b8814d098a2ed3e4c2aaba1411f97425fc89d599 Mon Sep 17 00:00:00 2001 From: MattEqualsCoder Date: Sat, 21 Dec 2024 23:08:15 -0500 Subject: [PATCH 1/2] Add initial setup window --- .../Options/GeneralOptions.cs | 2 + .../Options/RandomizerOptions.cs | 18 ++ .../TrackerCouncil.Smz3.Data.csproj | 2 +- .../TrackerCouncil.Smz3.PatchBuilder.csproj | 2 +- .../TrackerCouncil.Smz3.Shared.csproj | 2 +- .../TrackerCouncil.Smz3.Tracking.csproj | 2 +- src/TrackerCouncil.Smz3.UI/Assets/Tracker.png | Bin 0 -> 49261 bytes .../Services/MainWindowService.cs | 2 +- .../Services/SetupWindowService.cs | 257 ++++++++++++++++++ .../TrackerCouncil.Smz3.UI.csproj | 2 +- .../ViewModels/MainWindowViewModel.cs | 2 +- .../ViewModels/SetupWindowViewModel.cs | 82 ++++++ .../Views/AutoTrackingHelpWindow.axaml | 66 ++++- .../Views/AutoTrackingHelpWindow.axaml.cs | 20 ++ .../Views/MainWindow.axaml.cs | 30 +- .../Views/SetupWindow.axaml | 257 ++++++++++++++++++ .../Views/SetupWindow.axaml.cs | 157 +++++++++++ .../Views/SoloRomListPanel.axaml.cs | 17 +- 18 files changed, 894 insertions(+), 26 deletions(-) create mode 100644 src/TrackerCouncil.Smz3.UI/Assets/Tracker.png create mode 100644 src/TrackerCouncil.Smz3.UI/Services/SetupWindowService.cs create mode 100644 src/TrackerCouncil.Smz3.UI/ViewModels/SetupWindowViewModel.cs create mode 100644 src/TrackerCouncil.Smz3.UI/Views/SetupWindow.axaml create mode 100644 src/TrackerCouncil.Smz3.UI/Views/SetupWindow.axaml.cs diff --git a/src/TrackerCouncil.Smz3.Data/Options/GeneralOptions.cs b/src/TrackerCouncil.Smz3.Data/Options/GeneralOptions.cs index 4e0097a94..f253012da 100644 --- a/src/TrackerCouncil.Smz3.Data/Options/GeneralOptions.cs +++ b/src/TrackerCouncil.Smz3.Data/Options/GeneralOptions.cs @@ -22,6 +22,8 @@ public class GeneralOptions : INotifyPropertyChanged private string? _twitchChannel; private string? _twitchId; + public bool HasOpenedSetupWindow { get; set; } + public string? Z3RomPath { get; set; } public string? SMRomPath { get; set; } diff --git a/src/TrackerCouncil.Smz3.Data/Options/RandomizerOptions.cs b/src/TrackerCouncil.Smz3.Data/Options/RandomizerOptions.cs index 8a16c271a..c91ec0eb7 100644 --- a/src/TrackerCouncil.Smz3.Data/Options/RandomizerOptions.cs +++ b/src/TrackerCouncil.Smz3.Data/Options/RandomizerOptions.cs @@ -98,6 +98,8 @@ public static RandomizerOptions Load(string loadPath, string savePath, bool isYa var options = serializer.Deserialize(fileText); options.FilePath = savePath; + var settingsUpdated = false; + // Update from AutoTracker connector settings to SnesConnector settings if (options.GeneralOptions.AutoTrackerDefaultConnectionType != EmulatorConnectorType.None) { @@ -108,6 +110,7 @@ public static RandomizerOptions Load(string loadPath, string savePath, bool isYa options.GeneralOptions.SnesConnectorSettings.Usb2SnesAddress = options.GeneralOptions.AutoTrackerQUsb2SnesIp ?? ""; options.GeneralOptions.AutoTrackerDefaultConnectionType = EmulatorConnectorType.None; + settingsUpdated = true; } if (options.GeneralOptions.MsuTrackDisplayStyle != null) @@ -122,6 +125,7 @@ public static RandomizerOptions Load(string loadPath, string savePath, bool isYa _ => TrackDisplayFormat.Vertical }; options.GeneralOptions.MsuTrackDisplayStyle = null; + settingsUpdated = true; } // Update AutoTrackerChangeMap to AutoMapUpdateBehavior @@ -130,6 +134,7 @@ public static RandomizerOptions Load(string loadPath, string savePath, bool isYa options.GeneralOptions.AutoMapUpdateBehavior = options.GeneralOptions.AutoTrackerChangeMap ? AutoMapUpdateBehavior.UpdateOnRegionChange : AutoMapUpdateBehavior.Disabled; + settingsUpdated = true; } // Remove deprecated config profiles @@ -137,6 +142,19 @@ public static RandomizerOptions Load(string loadPath, string savePath, bool isYa { options.GeneralOptions.SelectedProfiles = options.GeneralOptions.SelectedProfiles .Where(p => p != null && !ConfigProvider.DeprecatedConfigProfiles.Contains(p)).ToList(); + settingsUpdated = true; + } + + // Update HasOpenedSetupWindow if the Z3 rom path is populated + if (!options.GeneralOptions.HasOpenedSetupWindow && !string.IsNullOrEmpty(options.GeneralOptions.Z3RomPath)) + { + options.GeneralOptions.HasOpenedSetupWindow = true; + settingsUpdated = true; + } + + if (settingsUpdated) + { + options.Save(); } return options; diff --git a/src/TrackerCouncil.Smz3.Data/TrackerCouncil.Smz3.Data.csproj b/src/TrackerCouncil.Smz3.Data/TrackerCouncil.Smz3.Data.csproj index ac272ec37..239e94e08 100644 --- a/src/TrackerCouncil.Smz3.Data/TrackerCouncil.Smz3.Data.csproj +++ b/src/TrackerCouncil.Smz3.Data/TrackerCouncil.Smz3.Data.csproj @@ -25,7 +25,7 @@ - + diff --git a/src/TrackerCouncil.Smz3.PatchBuilder/TrackerCouncil.Smz3.PatchBuilder.csproj b/src/TrackerCouncil.Smz3.PatchBuilder/TrackerCouncil.Smz3.PatchBuilder.csproj index ee579531a..5017dc8ca 100644 --- a/src/TrackerCouncil.Smz3.PatchBuilder/TrackerCouncil.Smz3.PatchBuilder.csproj +++ b/src/TrackerCouncil.Smz3.PatchBuilder/TrackerCouncil.Smz3.PatchBuilder.csproj @@ -13,7 +13,7 @@ - + diff --git a/src/TrackerCouncil.Smz3.Shared/TrackerCouncil.Smz3.Shared.csproj b/src/TrackerCouncil.Smz3.Shared/TrackerCouncil.Smz3.Shared.csproj index 4a9d5f1e6..b889ce60b 100644 --- a/src/TrackerCouncil.Smz3.Shared/TrackerCouncil.Smz3.Shared.csproj +++ b/src/TrackerCouncil.Smz3.Shared/TrackerCouncil.Smz3.Shared.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/TrackerCouncil.Smz3.Tracking/TrackerCouncil.Smz3.Tracking.csproj b/src/TrackerCouncil.Smz3.Tracking/TrackerCouncil.Smz3.Tracking.csproj index 0b674238e..2a0a6e59c 100644 --- a/src/TrackerCouncil.Smz3.Tracking/TrackerCouncil.Smz3.Tracking.csproj +++ b/src/TrackerCouncil.Smz3.Tracking/TrackerCouncil.Smz3.Tracking.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/TrackerCouncil.Smz3.UI/Assets/Tracker.png b/src/TrackerCouncil.Smz3.UI/Assets/Tracker.png new file mode 100644 index 0000000000000000000000000000000000000000..8622fdb3eaa54e3970653fc25fa67b6120b77ec9 GIT binary patch literal 49261 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

{%}k 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 romPaths) + { + var anyInvalidRom = false; + + foreach (var path in romPaths) + { + if (CheckFileHash(path, Z3Hash)) + { + _model.ZeldaRomPath = path; + _model.IsValidZeldaRom = true; + } + else if (CheckFileHash(path, SMHash)) + { + _model.MetroidRomPath = path; + _model.IsValidMetroidRom = true; + } + else + { + anyInvalidRom = true; + } + } + + return !anyInvalidRom; + } + + public async Task TestAutoTracking() + { + if (_model.IsConnecting) + { + return; + } + + _model.IsConnecting = true; + _cancellationTokenSource = new CancellationTokenSource(); + _model.AutoTrackerOpacity = 0.2f; + _model.AutoTrackerIconKind = MaterialIconKind.CircleOutline; + _model.AutoTrackerBrush = Brushes.White; + _model.AutoTrackerMessage = "Connecting..."; + + snesConnectorService.Connect(GetSnesConnectorSettings()); + + try + { + await Task.Delay(TimeSpan.FromSeconds(20), _cancellationTokenSource.Token); + + // If the task wasn't cancelled, then it didn't connect at all fully + _model.AutoTrackerOpacity = 1; + _model.AutoTrackerIconKind = MaterialIconKind.CloseCircleOutline; + _model.AutoTrackerBrush = Brushes.IndianRed; + _model.AutoTrackerMessage = "Unable to connect"; + await _cancellationTokenSource.CancelAsync(); + } + catch + { + // Do nothing + } + + _model.IsConnecting = false; + snesConnectorService.Disconnect(); + } + + public void SaveSettings() + { + if (_model.IsValidZeldaRom) + { + _randomizerOptions.GeneralOptions.Z3RomPath = _model.ZeldaRomPath; + } + + if (_model.IsValidMetroidRom) + { + _randomizerOptions.GeneralOptions.SMRomPath = _model.MetroidRomPath; + } + + _randomizerOptions.GeneralOptions.SnesConnectorSettings = GetSnesConnectorSettings(); + + if (!_model.TrackerVoiceEnabled) + { + _randomizerOptions.GeneralOptions.SpeechRecognitionMode = SpeechRecognitionMode.Disabled; + _randomizerOptions.GeneralOptions.TrackerVoiceFrequency = TrackerVoiceFrequency.Disabled; + } + + _randomizerOptions.GeneralOptions.SelectedProfiles = GetSelectedProfiles(); + _randomizerOptions.Save(); + } + + public void OnClose() + { + snesConnectorService.GameDetected -= SnesConnectorServiceOnConnected; + snesConnectorService.Disconnect(); + } + + private SnesConnectorSettings GetSnesConnectorSettings() + { + var snesConnectorSettings = new SnesConnectorSettings(); + + if (_model.AutoTrackingDisable) + { + snesConnectorSettings.ConnectorType = SnesConnectorType.None; + } + else if (_model.AutoTrackingLua) + { + snesConnectorSettings.ConnectorType = SnesConnectorType.Lua; + } + else if (_model.AutoTrackingEmoTracker) + { + snesConnectorSettings.ConnectorType = SnesConnectorType.LuaEmoTracker; + } + else if (_model.AutoTrackingUsb2Snes) + { + snesConnectorSettings.ConnectorType = SnesConnectorType.Usb2Snes; + snesConnectorSettings.Usb2SnesAddress = _model.ConnectorIpAddress; + } + else if (_model.AutoTrackingSni) + { + snesConnectorSettings.ConnectorType = SnesConnectorType.Sni; + snesConnectorSettings.SniAddress = _model.ConnectorIpAddress; + } + + return snesConnectorSettings; + } + + private List GetSelectedProfiles() + { + var profiles = new List(); + + if (_model.TrackerSassEnabled) + { + profiles.Add("Sassy"); + } + + if (_model.TrackerCursingEnabled) + { + profiles.Add("Rated T for Teen"); + } + + if (_model.TrackerBcuEnabled) + { + profiles.Add("BCU"); + } + + return profiles; + } + + private void SetZeldaRomPath(string? path) + { + if (File.Exists(path) && CheckFileHash(path, Z3Hash)) + { + _model.ZeldaRomPath = path; + _model.IsValidZeldaRom = true; + } + else + { + _model.ZeldaRomPath = "Not Selected"; + _model.IsValidZeldaRom = false; + } + } + + private void SetMetroidRomPath(string? path) + { + if (File.Exists(path) && CheckFileHash(path, SMHash)) + { + _model.MetroidRomPath = path; + _model.IsValidMetroidRom = true; + } + else + { + _model.MetroidRomPath = "Not Selected"; + _model.IsValidMetroidRom = false; + } + } + + private bool CheckFileHash(string path, string expectedHash) + { + var bytes = File.ReadAllBytes(path); + var hash = MD5.HashData(bytes); + var hashString = BitConverter.ToString(hash).Replace("-", ""); + return expectedHash.Equals(hashString, StringComparison.OrdinalIgnoreCase); + } + + private void SnesConnectorServiceOnConnected(object? sender, EventArgs e) + { + _ = TestGetMemoryAsync(); + } + + private async Task TestGetMemoryAsync() + { + for (var i = 0; i < 5 && !_cancellationTokenSource.IsCancellationRequested; i++) + { + var response = await snesConnectorService.MakeMemoryRequestAsync(new SnesSingleMemoryRequest() + { + MemoryRequestType = SnesMemoryRequestType.RetrieveMemory, + SnesMemoryDomain = SnesMemoryDomain.ConsoleRAM, + AddressFormat = AddressFormat.Snes9x, + SniMemoryMapping = MemoryMapping.Unknown, + Address = 0x7e0000, + Length = 0x1 + }); + + if (response is { Successful: true, HasData: true }) + { + _model.AutoTrackerOpacity = 1; + _model.AutoTrackerIconKind = MaterialIconKind.CheckCircleOutline; + _model.AutoTrackerBrush = Brushes.Lime; + _model.AutoTrackerMessage = "Connection successful!"; + break; + } + else + { + _model.AutoTrackerOpacity = 1; + _model.AutoTrackerIconKind = MaterialIconKind.CloseCircleOutline; + _model.AutoTrackerBrush = Brushes.IndianRed; + _model.AutoTrackerMessage = "Invalid response"; + await Task.Delay(TimeSpan.FromSeconds(2f)); + } + } + + await _cancellationTokenSource.CancelAsync(); + } +} diff --git a/src/TrackerCouncil.Smz3.UI/TrackerCouncil.Smz3.UI.csproj b/src/TrackerCouncil.Smz3.UI/TrackerCouncil.Smz3.UI.csproj index a481bd2d2..40ac3512f 100644 --- a/src/TrackerCouncil.Smz3.UI/TrackerCouncil.Smz3.UI.csproj +++ b/src/TrackerCouncil.Smz3.UI/TrackerCouncil.Smz3.UI.csproj @@ -21,7 +21,7 @@ - + diff --git a/src/TrackerCouncil.Smz3.UI/ViewModels/MainWindowViewModel.cs b/src/TrackerCouncil.Smz3.UI/ViewModels/MainWindowViewModel.cs index 11f7140ee..7fed220cd 100644 --- a/src/TrackerCouncil.Smz3.UI/ViewModels/MainWindowViewModel.cs +++ b/src/TrackerCouncil.Smz3.UI/ViewModels/MainWindowViewModel.cs @@ -13,5 +13,5 @@ public MainWindowViewModel() public string NewVersionGitHubUrl { get; set; } = ""; - public bool HasInvalidOptions { get; set; } + public bool OpenSetupWindow { get; set; } } diff --git a/src/TrackerCouncil.Smz3.UI/ViewModels/SetupWindowViewModel.cs b/src/TrackerCouncil.Smz3.UI/ViewModels/SetupWindowViewModel.cs new file mode 100644 index 000000000..d15306e92 --- /dev/null +++ b/src/TrackerCouncil.Smz3.UI/ViewModels/SetupWindowViewModel.cs @@ -0,0 +1,82 @@ +using Avalonia.Markup.Xaml.MarkupExtensions; +using Avalonia.Media; +using AvaloniaControls.Models; +using Material.Icons; +using ReactiveUI.Fody.Helpers; + +namespace TrackerCouncil.Smz3.UI.ViewModels; + +public class SetupWindowViewModel : ViewModelBase +{ + + [Reactive, + ReactiveLinkedProperties(nameof(Step2BorderOpacity), nameof(Step3BorderOpacity), nameof(Step4BorderOpacity), + nameof(Step1ButtonOpacity), nameof(Step2ButtonOpacity), nameof(Step3ButtonOpacity), + nameof(Step4ButtonOpacity), nameof(DisplayPage1), nameof(DisplayPage2), nameof(DisplayPage3), + nameof(DisplayPage4), nameof(PreviousButtonEnabled), nameof(SkipStepVisible), nameof(NextButtonText), + nameof(NextButtonEnabled))] + public int StepNumber { get; set; } = 2; + + public float Step1ButtonOpacity => StepNumber == 1 ? 1f : 0.2f; + public float Step2ButtonOpacity => StepNumber == 2 ? 1f : 0.2f; + public float Step3ButtonOpacity => StepNumber == 3 ? 1f : 0.2f; + public float Step4ButtonOpacity => StepNumber == 4 ? 1f : 0.2f; + + public float Step1BorderOpacity => 1; + public float Step2BorderOpacity => StepNumber > 1 ? 1f : 0.2f; + public float Step3BorderOpacity => StepNumber > 2 ? 1f : 0.2f; + public float Step4BorderOpacity => StepNumber > 3 ? 1f : 0.2f; + + public bool PreviousButtonEnabled => StepNumber > 1; + public bool SkipStepVisible => StepNumber == 1; + public string NextButtonText => StepNumber == 4 ? "Close" : "Next"; + public bool NextButtonEnabled => (StepNumber == 1 && IsValidZeldaRom && IsValidMetroidRom) || StepNumber != 1; + + // Page 1 Properties + public bool DisplayPage1 => StepNumber == 1; + + [Reactive, ReactiveLinkedProperties(nameof(ZeldaRomIconOpacity), nameof(ZeldaRomBrush), nameof(ZeldaRomIconKind), nameof(NextButtonEnabled))] + public bool IsValidZeldaRom { get; set; } + public float ZeldaRomIconOpacity => IsValidZeldaRom ? 1f : 0.2f; + public IBrush ZeldaRomBrush => IsValidZeldaRom ? Brushes.LimeGreen : Brushes.White; + public MaterialIconKind ZeldaRomIconKind => IsValidZeldaRom ? MaterialIconKind.CheckCircleOutline : MaterialIconKind.CircleOutline; + [Reactive] public string ZeldaRomPath { get; set; } = "Not Selected"; + + [Reactive, ReactiveLinkedProperties(nameof(MetroidRomIconOpacity), nameof(MetroidRomBrush), nameof(MetroidRomIconKind), nameof(NextButtonEnabled))] + public bool IsValidMetroidRom { get; set; } + public float MetroidRomIconOpacity => IsValidMetroidRom ? 1f : 0.2f; + public IBrush MetroidRomBrush => IsValidMetroidRom ? Brushes.LimeGreen : Brushes.White; + public MaterialIconKind MetroidRomIconKind => IsValidMetroidRom ? MaterialIconKind.CheckCircleOutline : MaterialIconKind.CircleOutline; + [Reactive] public string MetroidRomPath { get; set; } = "Not Selected"; + + // Page 2 Properties + public bool DisplayPage2 => StepNumber == 2; + [Reactive, ReactiveLinkedProperties(nameof(TestAutoTrackerEnabled))] public bool AutoTrackingDisable { get; set; } = true; + public bool AutoTrackingLua { get; set; } + public bool AutoTrackingEmoTracker { get; set; } + [Reactive, ReactiveLinkedProperties(nameof(ConnectorIpAddressTextBoxEnabled))] public bool AutoTrackingUsb2Snes { get; set; } + [Reactive, ReactiveLinkedProperties(nameof(ConnectorIpAddressTextBoxEnabled))] public bool AutoTrackingSni { get; set; } + public string ConnectorIpAddress { get; set; } = ""; + public bool ConnectorIpAddressTextBoxEnabled => AutoTrackingUsb2Snes || AutoTrackingSni; + public bool TestAutoTrackerEnabled => !AutoTrackingDisable && !IsConnecting; + [Reactive] public IBrush AutoTrackerBrush { get; set; } = Brushes.White; + [Reactive] public MaterialIconKind AutoTrackerIconKind { get; set; } = MaterialIconKind.CircleOutline; + [Reactive] public float AutoTrackerOpacity { get; set; } = 0.2f; + [Reactive] public string AutoTrackerMessage { get; set; } = ""; + [Reactive, ReactiveLinkedProperties(nameof(TestAutoTrackerEnabled))] public bool IsConnecting { get; set; } + + // Page 3 Properties + public bool DisplayPage3 => StepNumber == 3; + public bool TrackerVoiceEnabled { get; set; } = true; + public bool TrackerVoiceDisabled { get; set; } + public bool TrackerSassEnabled { get; set; } = true; + public bool TrackerSassDisabled { get; set; } + public bool TrackerCursingEnabled { get; set; } + public bool TrackerCursingDisabled { get; set; } = true; + public bool TrackerBcuEnabled { get; set; } + public bool TrackerBcuDisabled { get; set; } = true; + + public bool DisplayPage4 => StepNumber == 4; + + +} diff --git a/src/TrackerCouncil.Smz3.UI/Views/AutoTrackingHelpWindow.axaml b/src/TrackerCouncil.Smz3.UI/Views/AutoTrackingHelpWindow.axaml index ae69d87f3..f51ffadb1 100644 --- a/src/TrackerCouncil.Smz3.UI/Views/AutoTrackingHelpWindow.axaml +++ b/src/TrackerCouncil.Smz3.UI/Views/AutoTrackingHelpWindow.axaml @@ -44,8 +44,48 @@ • BizHawk (BSNES Core Only) + + An alternate Lua Script mode for compatibility with the EmoTracker Lua script is also available if you use that for other randomizers. + + - • QUSB2SNES + • (Q)Usb2Snes + + + + Supported Emulators: + + + + • RetroArch (SNES9X or BSNES Cores) + • Snes9x-emunwa + • Snes9x-rr (by loading the QUsb2Snes Lua Script) + • BizHawk (by loading the QUsb2Snes Lua Script) + • Hardware such as the FxPakPro + + + + QUsb2Snes must be installed and running to connect to the emulator. + + + + • Super Nintendo Interface (SNI) + + + + Supported Emulators: + + + + • RetroArch (SNES9X or BSNES Cores) + • Snes9x-emunwa + • Snes9x-rr (by loading the SNI Lua Script) + • BizHawk (by loading the SNI Lua Script) + • Hardware such as the FxPakPro + + + + SNI must be installed and running to connect to the emulator. @@ -88,6 +128,30 @@ 3. Open the connector.lua script file. + + Enabling Connectivity in RetroArch + + + + 1. Open RetroArch + + + + 2. Go to Settings + + + + 3. Go to Network + + + + 4. Set Network Commands to "On" + + ().ShowDialog(this); - } - if (_service == null) { return; @@ -94,6 +86,20 @@ await MessageWindow.ShowInfoDialog( _ = ITaskService.Run(_service.ValidateTwitchToken); _ = ITaskService.Run(_service.DownloadConfigsAsync); _ = ITaskService.Run(_service.DownloadSpritesAsync); + + if (_model.OpenSetupWindow && _serviceProvider != null) + { + var result = await _serviceProvider.GetRequiredService() + .ShowDialog(this, SetupWindowStep.Roms); + if (result == SetupWindowCloseBehavior.OpenSettingsWindow) + { + _serviceProvider?.GetRequiredService().ShowDialog(this); + } + else if (result == SetupWindowCloseBehavior.OpenGenerationWindow) + { + _ = SoloRomListPanel.OpenGenerationWindow(); + } + } } private void OptionsMenuItem_OnClick(object? sender, RoutedEventArgs e) diff --git a/src/TrackerCouncil.Smz3.UI/Views/SetupWindow.axaml b/src/TrackerCouncil.Smz3.UI/Views/SetupWindow.axaml new file mode 100644 index 000000000..b5851d237 --- /dev/null +++ b/src/TrackerCouncil.Smz3.UI/Views/SetupWindow.axaml @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Tracker Presents: SMZ3 Cas' Randomizer + + + + + + + Let's get you setup. First, we need the ROMs for A Link to the Past and Super Metroid. + + + + + + + File: + + + + + + + + + File: + + + + + + + + + + + + + Want to make your life easier? Tracker can track items, bosses, rewards, and more automatically by connecting to your emulator. + + + + + + Disable Auto Tracking + + + Enable Lua Auto Tracking (snes9x-rr, BizHawk) + Open Lua Script Folder + + + Enable EmoTracker Lua Auto Tracking (snes9x-rr, BizHawk) + Enable QUsb2Snes Auto Tracking (RetroArch, snes9x-emunwa, snes9x-rr, FxPakPro) + Enable SNI Auto Tracking (RetroArch, snes9x-emunwa, snes9x-rr, FxPakPro) + + + + + + + + + + + + + + + + Tracker can be your randomizer assistant. Let's customize your interactions with tracker. + + + + + Would you like to talk with Tracker? + + + Yes, let her speak! + No, I want peace and quiet. + + + Would you like Tracker to have a personality? + + + Yes, bring on the sass! + No, keep it to strictly business. + + + Are you okay with Tracker cursing? + + + Hell yeah! + Heck no. + + + Do you know who betus is? + + + Yeah, give me the in-jokes! + Who is that? + + + + + + + + + + + The basic setup is now complete! What would you like to do next? + + + + + + You can open the full settings window to change other settings such as enabling Twitch integration, + modifying the tracker UI background, and modifying other tracking behavior. + + + + + + Or, if you're ready to get started, you can open the window to start generating your first randomizer seed! + + + + + + + + + + + + + Art by Dr. Dubz + + + + + +