diff --git a/HighRollerClassic/DataStructures/Settings.cs b/HighRollerClassic/DataStructures/Settings.cs index dd96d7d..86b8b7a 100644 --- a/HighRollerClassic/DataStructures/Settings.cs +++ b/HighRollerClassic/DataStructures/Settings.cs @@ -5,17 +5,17 @@ namespace HighRollerClassic.DataStructures; public struct Settings { /// - /// Contains data about each multiplier, roll, etc. + /// Contains data bout each multiplier, roll, etc. /// - private List rolls; - + public List rolls; + /// - /// Maximum bet that will be allowed to set + /// Maximum bet that will be allowed to set /// - private uint maxBet; - + public uint maxBet; + /// - /// How much the bet will change when user adjusts their bet via +/- keys + /// How much the bet will change when user adjusts their bet via +/- keys /// - private uint step; + public uint step; } diff --git a/HighRollerClassic/Player.cs b/HighRollerClassic/Player.cs index ec705b0..460ea2b 100644 --- a/HighRollerClassic/Player.cs +++ b/HighRollerClassic/Player.cs @@ -7,8 +7,6 @@ public class Player(MenuTargetDefault target) { private Roll rolls = new(); public int Bank { get; private set; } = 0; - public string Name { get; private set; } = target.TargetName; - // todo maybe remove it and tie it to dalamud's api to get accurate character name once per session public ulong ContentId { get; private set; } = target.TargetContentId; } diff --git a/HighRollerClassic/PlayerManager.cs b/HighRollerClassic/PlayerManager.cs index 6108d4b..3839ab3 100644 --- a/HighRollerClassic/PlayerManager.cs +++ b/HighRollerClassic/PlayerManager.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Linq; using Dalamud.Game.Gui.ContextMenu; namespace HighRollerClassic; @@ -8,13 +7,15 @@ public class PlayerManager { private List Players { get; set; } = []; - public Player GetPlayer(MenuTargetDefault target) + public Player? GetOrCreatePlayer(MenuTargetDefault? target) { - foreach (var player in Players) - if (player.ContentId == target.TargetContentId) - return player; + if (target is null) return null; - Players.Add(new Player(target)); - return Players.Last(); + var player = Players.Find(p => p.ContentId == target.TargetContentId); + if (player is not null) return player; + + player = new Player(target); + Players.Add(player); + return player; } } diff --git a/HighRollerClassic/Plugin.cs b/HighRollerClassic/Plugin.cs index 3939e24..ce78a92 100644 --- a/HighRollerClassic/Plugin.cs +++ b/HighRollerClassic/Plugin.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Dalamud.Game.ClientState.Objects.SubKinds; using Dalamud.Game.Command; using Dalamud.Game.Gui.ContextMenu; @@ -7,40 +8,37 @@ using Dalamud.IoC; using Dalamud.Plugin; using Dalamud.Plugin.Services; using HighRollerClassic.Windows; +using Lumina.Data.Parsing.Layer; namespace HighRollerClassic; public sealed class Plugin : IDalamudPlugin { private const string CommandName = "/hrc"; - private readonly PluginState state = new(); - - public readonly WindowSystem WindowSystem = new("HighRollerClassic"); + private readonly WindowSystem windowSystem = new("HighRollerClassic"); + private readonly List gambaWindows = []; public Plugin() { Configuration = PluginInterface.GetPluginConfig() as Configuration ?? new Configuration(); SettingsWindow = new SettingsWindow(this); - MainWindow = new MainWindow(this, state); - - WindowSystem.AddWindow(SettingsWindow); - WindowSystem.AddWindow(MainWindow); + windowSystem.AddWindow(SettingsWindow); CommandManager.AddHandler(CommandName, new CommandInfo(OnCommand) { - HelpMessage = "Opens the High Roller Classic window" + HelpMessage = "Opens the HRC Settings" }); // Tell the UI system that we want our windows to be drawn through the window system - PluginInterface.UiBuilder.Draw += WindowSystem.Draw; + PluginInterface.UiBuilder.Draw += windowSystem.Draw; // This adds a button to the plugin installer entry of this plugin which allows // toggling the display status of the configuration ui - PluginInterface.UiBuilder.OpenConfigUi += ToggleConfigUi; + PluginInterface.UiBuilder.OpenConfigUi += ToggleSettingsUi; // Adds another button doing the same but for the main ui of the plugin - PluginInterface.UiBuilder.OpenMainUi += ToggleMainUi; + // PluginInterface.UiBuilder.OpenMainUi += ToggleMainUi; // Add a simple message to the log with level set to information // Use /xllog to open the log window in-game @@ -77,19 +75,21 @@ public sealed class Plugin : IDalamudPlugin public Configuration Configuration { get; init; } private SettingsWindow SettingsWindow { get; init; } - private MainWindow MainWindow { get; init; } + private List Windows { get; init; } public void Dispose() { // Unregister all actions to not leak anything during disposal of plugin - PluginInterface.UiBuilder.Draw -= WindowSystem.Draw; - PluginInterface.UiBuilder.OpenConfigUi -= ToggleConfigUi; - PluginInterface.UiBuilder.OpenMainUi -= ToggleMainUi; + PluginInterface.UiBuilder.Draw -= windowSystem.Draw; + PluginInterface.UiBuilder.OpenConfigUi -= ToggleSettingsUi; - WindowSystem.RemoveAllWindows(); + windowSystem.RemoveAllWindows(); SettingsWindow.Dispose(); - MainWindow.Dispose(); + foreach (var window in gambaWindows) + { + window.Dispose(); + } CommandManager.RemoveHandler(CommandName); @@ -99,17 +99,12 @@ public sealed class Plugin : IDalamudPlugin private void OnCommand(string command, string args) { // In response to the slash command, toggle the display status of our main ui - MainWindow.Toggle(); - } - - public void ToggleConfigUi() - { SettingsWindow.Toggle(); } - public void ToggleMainUi() + public void ToggleSettingsUi() { - MainWindow.Toggle(); + SettingsWindow.Toggle(); } public bool PlayerIsLoaded() @@ -121,12 +116,12 @@ public sealed class Plugin : IDalamudPlugin { if (args.MenuType == ContextMenuType.Inventory) return; - // get character's (persistent) id var target = (MenuTargetDefault)args.Target; - if (target.TargetObject is not IPlayerCharacter) + // target must be a player that is not self + if (target.TargetObject is not IPlayerCharacter || target.TargetContentId == PlayerState.ContentId) { - Log.Debug("Not a player, returning"); + Log.Debug("Not a foreign player"); return; } @@ -141,11 +136,28 @@ public sealed class Plugin : IDalamudPlugin private Action ContextMenuPlayerGameStart(MenuTargetDefault target) { - return args => + return _ => { - Log.Debug($"Starting match with {target.TargetName}"); - state.Target = target; - MainWindow.Toggle(); + Log.Debug($"Starting gamba with {target.TargetName}"); + CreateGambaWindow(target); }; } + + private void CreateGambaWindow(MenuTargetDefault target) + { + var existingWindow = gambaWindows.Find(p => p.WindowName.Contains(target.TargetContentId.ToString())); + if (existingWindow is { IsOpen: false }) + { + existingWindow.Toggle(); + return; + } + + var window = new GambaWindow(this, target) + { + IsOpen = true, + }; + + gambaWindows.Add(window); + windowSystem.AddWindow(window); + } } diff --git a/HighRollerClassic/PluginState.cs b/HighRollerClassic/PluginState.cs deleted file mode 100644 index deb2ffe..0000000 --- a/HighRollerClassic/PluginState.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Dalamud.Game.Gui.ContextMenu; - -namespace HighRollerClassic; - -public sealed class PluginState -{ - /// tracks selected target as we pass it to the window - public MenuTargetDefault? Target { get; set; } -} diff --git a/HighRollerClassic/Windows/MainWindow.cs b/HighRollerClassic/Windows/GambaWindow.cs similarity index 67% rename from HighRollerClassic/Windows/MainWindow.cs rename to HighRollerClassic/Windows/GambaWindow.cs index 024c31e..7159be2 100644 --- a/HighRollerClassic/Windows/MainWindow.cs +++ b/HighRollerClassic/Windows/GambaWindow.cs @@ -1,18 +1,22 @@ using System; using System.Numerics; using Dalamud.Bindings.ImGui; +using Dalamud.Game.Gui.ContextMenu; using Dalamud.Interface.Windowing; namespace HighRollerClassic.Windows; -public class MainWindow : Window, IDisposable +public class GambaWindow : Window, IDisposable { private readonly Configuration configuration; - private readonly Plugin plugin; - private readonly PluginState state; - public MainWindow(Plugin plugin, PluginState state) - : base($"High Roller Classic###{state.Target?.TargetName ?? "null"}", + // todo remove state as the window will only be opened by us calling it with parameters window id + private readonly Player? player; + private readonly Plugin plugin; + private string name; + + public GambaWindow(Plugin plugin, MenuTargetDefault target) + : base($"High Roller Classic###{target.TargetContentId}", ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse) { SizeConstraints = new WindowSizeConstraints @@ -23,7 +27,9 @@ public class MainWindow : Window, IDisposable this.plugin = plugin; configuration = this.plugin.Configuration; - this.state = state; + + player = configuration.players.GetOrCreatePlayer(target); + name = target.TargetName; } public void Dispose() { } @@ -42,19 +48,16 @@ public class MainWindow : Window, IDisposable roll settings message/macro settings */ - // TODO create player project and clear the existing shared state + // todo if player is null, then allow user to set user by clicking on them manually - if (state.Target == null) + if (player == null) { ImGui.Text( "No target selected, please open HRC by right clicking the player and choosing the 'High Roller Classic' option"); return; } - var player = configuration.players.GetPlayer(state.Target); - state.Target = null; - - ImGui.Text($"Player: {player}"); + ImGui.Text($"Player: {name}"); ImGui.Spacing(); ImGui.Text($"Bank balance: {player.Bank} gil"); diff --git a/HighRollerClassic/Windows/SettingsWindow.cs b/HighRollerClassic/Windows/SettingsWindow.cs index 6383032..40dc503 100644 --- a/HighRollerClassic/Windows/SettingsWindow.cs +++ b/HighRollerClassic/Windows/SettingsWindow.cs @@ -9,6 +9,14 @@ namespace HighRollerClassic.Windows; public class SettingsWindow : Window, IDisposable { private readonly Configuration configuration; + private Settings settings; + + private const int XOffset = 80; + private const int Spacing = 5; + private const int InputWidth = 105; + private const int InputMaxLen = 11; + + private const uint MaxPossibleBet = 999_999_999; // We give this window a constant ID using ###. // This allows for labels to be dynamic, like "{FPS Counter}fps###XYZ counter window", @@ -18,10 +26,11 @@ public class SettingsWindow : Window, IDisposable Flags = ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse; - Size = new Vector2(232, 90); + Size = new Vector2(500, 300); SizeCondition = ImGuiCond.Always; configuration = plugin.Configuration; + settings = configuration.settings; } public void Dispose() { } @@ -30,13 +39,58 @@ public class SettingsWindow : Window, IDisposable public override void Draw() { - Settings settings; - // todo set up multiplier, roll, color, etc // todo add button for rolls - // todo setup max bet, change + ImGui.LabelText("###max_bet_label", "Max bet: "); + ImGui.SameLine(XOffset, Spacing); + ImGui.SetNextItemWidth(InputWidth); + + // TODO maybe throw it in a function because we have 2 fields behaving the same except for variables and label + var betBuf = settings.maxBet.ToString("N0"); + if (ImGui.InputText("###max_bet_text", ref betBuf, InputMaxLen)) + { + var num = betBuf.Replace(",", string.Empty).Replace(".", string.Empty); + if (uint.TryParse(num, out var parsedValue)) settings.maxBet = parsedValue; + } - // todo save button which will copy our settings to configuration and invoke .Save() to save configuration to disk + ImGui.Spacing(); + + ImGui.LabelText("###step_label", "Step: "); + ImGui.SameLine(XOffset, Spacing); + ImGui.SetNextItemWidth(InputWidth); + + var stepBuf = settings.step.ToString("N0"); + if (ImGui.InputText("###step_input", ref stepBuf, InputMaxLen)) + { + var num = stepBuf.Replace(",", string.Empty).Replace(".", string.Empty); + if (uint.TryParse(num, out var parsedValue)) settings.step = parsedValue; + } + + ImGui.Spacing(); + + // todo validation step? + var invalidInput = !ValidateInput(); + + ImGui.BeginDisabled(invalidInput); + if (ImGui.Button("Save")) + { + configuration.settings = settings; + configuration.Save(); + } + ImGui.EndDisabled(); + } + + /// + /// Validates inputs for Max bet and Step + /// + /// + private bool ValidateInput() + { + // TODO add explanation why input validation failed + if (settings.maxBet > MaxPossibleBet) return false; + if (settings.step > configuration.settings.maxBet) return false; + + return true; } }