diff --git a/ACManager.csproj b/ACManager.csproj index 9af7cec..bc71921 100644 --- a/ACManager.csproj +++ b/ACManager.csproj @@ -91,6 +91,7 @@ + diff --git a/FilterCore.cs b/FilterCore.cs index 3e79d3c..f33f705 100644 --- a/FilterCore.cs +++ b/FilterCore.cs @@ -135,6 +135,10 @@ private void FilterCore_ClientDispatch(object sender, NetworkMessageEventArgs e) Machine.ManaThreshold = Machine.Utility.BotSettings.ManaThreshold; Machine.StaminaThreshold = Machine.Utility.BotSettings.StaminaThreshold; Machine.DefaultHeading = Machine.Utility.BotSettings.DefaultHeading; + Machine.DesiredLandBlock = Machine.Utility.BotSettings.DesiredLandBlock; + Machine.DesiredBotLocationX = Machine.Utility.BotSettings.DesiredBotLocationX; + Machine.DesiredBotLocationY = Machine.Utility.BotSettings.DesiredBotLocationY; + Machine.EnablePositioning = Machine.Utility.BotSettings.BotPositioning; Machine.LoggedIn = true; } diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index 1d8a995..a7fee65 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("2.0.0")] -[assembly: AssemblyFileVersion("2.0.0")] +[assembly: AssemblyVersion("2.1.0")] +[assembly: AssemblyFileVersion("2.1.0")] diff --git a/Settings/BotSettings.cs b/Settings/BotSettings.cs index de79bae..415e2c6 100644 --- a/Settings/BotSettings.cs +++ b/Settings/BotSettings.cs @@ -30,6 +30,18 @@ public class BotSettings [XmlElement(IsNullable = false)] public double DefaultHeading; + [XmlElement(IsNullable = false)] + public int DesiredLandBlock; + + [XmlElement(IsNullable = false)] + public double DesiredBotLocationX; + + [XmlElement(IsNullable = false)] + public double DesiredBotLocationY; + + [XmlElement(IsNullable = false)] + public bool BotPositioning = false; + public List Advertisements = new List(); } diff --git a/StateMachine/Machine.cs b/StateMachine/Machine.cs index 3737de0..d77c6f6 100644 --- a/StateMachine/Machine.cs +++ b/StateMachine/Machine.cs @@ -188,6 +188,26 @@ internal class Machine /// public double DefaultHeading { get; set; } + /// + /// Navigation landblock to maintain. + /// + public int DesiredLandBlock { get; set; } + + /// + /// X coordinate in the landblock to maintain. + /// + public double DesiredBotLocationX { get; set; } + + /// + /// Y coordinate in the landblock to maintain. + /// + public double DesiredBotLocationY { get; set; } + + /// + /// Enable/disable navigation. + /// + public bool EnablePositioning { get; set; } = false; + /// /// Create the state machine in the StoppedState and begin processing commands on intervals (every time a frame is rendered). /// @@ -221,7 +241,7 @@ private void Clock(object sender, EventArgs e) // Gets the character's skill levels Skills = Core.CharacterFilter.EffectiveSkill; - + if (NextState == null) { CurrentState.Process(this); diff --git a/StateMachine/States/Idle.cs b/StateMachine/States/Idle.cs index 471db4b..cfeae62 100644 --- a/StateMachine/States/Idle.cs +++ b/StateMachine/States/Idle.cs @@ -27,7 +27,21 @@ public void Process(Machine machine) { if (machine.Enabled) { - if (machine.SpellsToCast.Count > 0 && machine.Core.CharacterFilter.Name.Equals(machine.NextCharacter)) // If there is a portal in the queue and it is on this character, enter casting state + if (!(machine.Core.Actions.Landcell == machine.DesiredLandBlock && Math.Abs(machine.Core.Actions.LocationX - machine.DesiredBotLocationX) < 1 && Math.Abs(machine.Core.Actions.LocationY - machine.DesiredBotLocationY) < 1) && machine.EnablePositioning) // If bot is not in the correct spot, get there + { + if (machine.DesiredLandBlock.Equals(0) && machine.DesiredBotLocationX.Equals(0) && machine.DesiredBotLocationY.Equals(0)) // no location settings, use current location + { + machine.DesiredLandBlock = machine.Core.Actions.Landcell; + machine.DesiredBotLocationX = machine.Core.Actions.LocationX; + machine.DesiredBotLocationY = machine.Core.Actions.LocationY; + Debug.ToChat("Bot location set to current location since one was not set previously."); + } + else // location settings were set - reposition the bot + { + machine.NextState = Positioning.GetInstance; + } + } + else if (machine.SpellsToCast.Count > 0 && machine.Core.CharacterFilter.Name.Equals(machine.NextCharacter)) // If there is a portal in the queue and it is on this character, enter casting state { if ((machine.Core.Actions.Heading <= machine.NextHeading + 2 && machine.Core.Actions.Heading >= machine.NextHeading - 2) || machine.NextHeading.Equals(-1)) { diff --git a/StateMachine/States/Positioning.cs b/StateMachine/States/Positioning.cs new file mode 100644 index 0000000..ead6ef3 --- /dev/null +++ b/StateMachine/States/Positioning.cs @@ -0,0 +1,132 @@ +using System; + +namespace ACManager.StateMachine.States +{ + /// + /// State that is used to place the bot in the desired (X, Y) coordinate location in the world. + /// + class Positioning : StateBase, IState + { + double tempHeading; + bool autoRunEnabled = false; + + public void Enter(Machine machine) + { + + } + + public void Exit(Machine machine) + { + + } + + public void Process(Machine machine) + { + if (machine.Enabled) + { + if (!(Math.Abs(machine.Core.Actions.LocationX - machine.DesiredBotLocationX) < 1 && Math.Abs(machine.Core.Actions.LocationY - machine.DesiredBotLocationY) < 1 && machine.Core.Actions.Landcell == machine.DesiredLandBlock)) + { + tempHeading = GetHeading(machine.Core.Actions.Landcell, machine.DesiredLandBlock, machine.Core.Actions.LocationX, machine.Core.Actions.LocationY, machine.DesiredBotLocationX, machine.DesiredBotLocationY); + + if (machine.Core.Actions.Heading <= tempHeading + 2 && machine.Core.Actions.Heading >= tempHeading - 2) + { + if (!autoRunEnabled) + { + machine.Core.Actions.SetAutorun(true); + autoRunEnabled = !autoRunEnabled; + } + } + else + { + if (autoRunEnabled) + { + machine.Core.Actions.SetAutorun(false); + autoRunEnabled = !autoRunEnabled; + } + machine.Core.Actions.Heading = tempHeading; + + } + } + else // Have made it to the desired location + { + if (autoRunEnabled) + { + machine.Core.Actions.SetAutorun(false); + autoRunEnabled = !autoRunEnabled; + } + machine.NextState = Idle.GetInstance; + } + } + else + { + machine.NextState = Idle.GetInstance; + } + } + + public override string ToString() + { + return nameof(Positioning); + } + + private double GetHeading(int currentLB, int targetLB, double currentX, double currentY, double targetX, double targetY) + { + int currentLBint, targetLBint, currentLB_EW, currentLB_NS, targetLB_EW, targetLB_NS, headingModifier; + + currentLBint = LandblockToInt(currentLB); + targetLBint = LandblockToInt(targetLB); + + currentLB_EW = EWLandblockToInt(currentLB); + currentLB_NS = NSLandblockToInt(currentLB); + + targetLB_EW = EWLandblockToInt(targetLB); + targetLB_NS = NSLandblockToInt(targetLB); + + if (currentLBint.Equals(targetLBint)) + { + if (currentX < targetX) + { + headingModifier = 90; + } + else + { + headingModifier = 270; + } + } + else if (currentLB_EW < targetLB_EW) + { + headingModifier = 90; + } + else + { + headingModifier = 270; + } + return headingModifier - RadToDegrees(Math.Atan(CalculateCoordDiff(currentLB_NS, targetLB_NS, currentY, targetY) / CalculateCoordDiff(currentLB_EW, targetLB_EW, currentX, targetX))); + } + + private double RadToDegrees(double radians) + { + return radians * (180 / Math.PI); + } + + private int LandblockToInt(int landblock) + { + return Convert.ToInt32(landblock.ToString("X").Substring(0, 3), 16); + } + + private int EWLandblockToInt(int landblock) + { + return Convert.ToInt32(landblock.ToString("X").Substring(0, 2), 16); + } + + private int NSLandblockToInt(int landblock) + { + return Convert.ToInt32(landblock.ToString("X").Substring(2, 2), 16); + } + + private double CalculateCoordDiff(int currentLBEW_NS, int targetLBEW_NS, double currentXY, double targetXY) + { + return currentXY + ((currentLBEW_NS - targetLBEW_NS) * 192) - targetXY; + } + + } +} diff --git a/Views/PortalBotView.cs b/Views/PortalBotView.cs index 51bdf52..b12558d 100644 --- a/Views/PortalBotView.cs +++ b/Views/PortalBotView.cs @@ -15,8 +15,12 @@ internal class PortalBotView : IDisposable private CoreManager Core { get; set; } internal HudView View { get; set; } internal HudCheckBox BotEnabled { get; set; } + internal HudButton ClearLocation { get; set; } + internal HudButton SetLocation { get; set; } + internal HudStaticText LocationSetpoint { get; set; } internal HudCheckBox RespondToGeneralChat { get; set; } internal HudCheckBox AdsEnabled { get; set; } + internal HudCheckBox BotPositioning { get; set; } internal HudTextBox AdInterval { get; set; } internal HudButton SetHeading { get; set; } internal HudTextBox DefaultHeading { get; set; } @@ -53,12 +57,24 @@ public PortalBotView(FilterCore parent, CoreManager core) BotEnabled = View != null ? (HudCheckBox)View["Bot"] : new HudCheckBox(); BotEnabled.Change += BotEnabled_Change; + ClearLocation = View != null ? (HudButton)View["ClearLocation"] : new HudButton(); + ClearLocation.Hit += ClearLocation_Hit; + + LocationSetpoint = View != null ? (HudStaticText)View["LocationSetpoint"] : new HudStaticText(); + LocationSetpoint.TextAlignment = VirindiViewService.WriteTextFormats.Center; + + SetLocation = View != null ? (HudButton)View["SetLocation"] : new HudButton(); + SetLocation.Hit += SetLocation_Hit; + RespondToGeneralChat = View != null ? (HudCheckBox)View["GeneralChatResponse"] : new HudCheckBox(); RespondToGeneralChat.Change += RespondToGeneralChat_Change; AdsEnabled = View != null ? (HudCheckBox)View["AdsEnabled"] : new HudCheckBox(); AdsEnabled.Change += AdsEnabled_Change; + BotPositioning = View != null ? (HudCheckBox)View["BotPositioning"] : new HudCheckBox(); + BotPositioning.Change += BotPositioning_Change; + AdInterval = View != null ? (HudTextBox)View["AdInterval"] : new HudTextBox(); AdInterval.Change += AdInterval_Change; @@ -126,6 +142,43 @@ public PortalBotView(FilterCore parent, CoreManager core) catch (Exception ex) { Debug.LogException(ex); } } + private void ClearLocation_Hit(object sender, EventArgs e) + { + try + { + Filter.Machine.DesiredLandBlock = Filter.Machine.Utility.BotSettings.DesiredLandBlock = 0; + Filter.Machine.DesiredBotLocationX = Filter.Machine.Utility.BotSettings.DesiredBotLocationX = 0; + Filter.Machine.DesiredBotLocationY = Filter.Machine.Utility.BotSettings.DesiredBotLocationY = 0; + LocationSetpoint.Text = "No location set"; + Filter.Machine.Utility.SaveBotSettings(); + } + catch (Exception ex) { Debug.LogException(ex); } + } + + private void BotPositioning_Change(object sender, EventArgs e) + { + try + { + Filter.Machine.EnablePositioning = Filter.Machine.Utility.BotSettings.BotPositioning = BotPositioning.Checked; + Filter.Machine.Utility.SaveBotSettings(); + Debug.ToChat($"The bot will {(Filter.Machine.EnablePositioning ? "now" : "no longer")} try to automatically position itself to the set navigation point."); + } + catch (Exception ex) { Debug.LogException(ex); } + } + + private void SetLocation_Hit(object sender, EventArgs e) + { + try + { + Filter.Machine.DesiredLandBlock = Filter.Machine.Utility.BotSettings.DesiredLandBlock = Filter.Machine.Core.Actions.Landcell; + Filter.Machine.DesiredBotLocationX = Filter.Machine.Utility.BotSettings.DesiredBotLocationX = Filter.Machine.Core.Actions.LocationX; + Filter.Machine.DesiredBotLocationY = Filter.Machine.Utility.BotSettings.DesiredBotLocationY = Filter.Machine.Core.Actions.LocationY; + LocationSetpoint.Text = $"{Filter.Machine.DesiredLandBlock.ToString("X").Substring(0, 4)} - X: { Math.Round(Filter.Machine.DesiredBotLocationX, 2)} Y: {Math.Round(Filter.Machine.DesiredBotLocationY, 2)}"; + Filter.Machine.Utility.SaveBotSettings(); + } + catch (Exception ex) { Debug.LogException(ex); } + } + private void SetHeading_Hit(object sender, EventArgs e) { try @@ -228,6 +281,8 @@ private void LoadSettings() StamThresholdText.Text = $"{StaminaThreshold.Position}%"; AdsEnabled.Checked = Filter.Machine.Utility.BotSettings.AdsEnabled; BotEnabled.Checked = Filter.Machine.Utility.BotSettings.BotEnabled; + BotPositioning.Checked = Filter.Machine.Utility.BotSettings.BotPositioning; + LocationSetpoint.Text = $"{Filter.Machine.Utility.BotSettings.DesiredLandBlock.ToString("X").Substring(0,4)} - X: { Math.Round(Filter.Machine.Utility.BotSettings.DesiredBotLocationX, 2)} Y: {Math.Round(Filter.Machine.Utility.BotSettings.DesiredBotLocationY, 2)}"; } catch (Exception ex) { @@ -297,7 +352,6 @@ private void BotEnabled_Change(object sender, EventArgs e) try { Filter.Machine.Enabled = Filter.Machine.Utility.BotSettings.BotEnabled = BotEnabled.Checked; - Debug.ToChat($"{(Filter.Machine.Utility.BotSettings.BotEnabled ? "Starting machine..." : "Stopping machine...")}"); if (Filter.Machine.Utility.BotSettings.BotEnabled) { Filter.Machine.ChatManager.Broadcast($"/me is running ACManager Bot {Filter.Machine.Utility.Version}. Whisper /help to get started."); @@ -873,8 +927,11 @@ protected virtual void Dispose(bool disposing) { Filter = null; BotEnabled.Change -= BotEnabled_Change; + ClearLocation.Hit -= ClearLocation_Hit; + SetLocation.Hit -= SetHeading_Hit; RespondToGeneralChat.Change -= RespondToGeneralChat_Change; AdsEnabled.Change -= AdsEnabled_Change; + BotPositioning.Change -= BotPositioning_Change; AdInterval.Change -= AdInterval_Change; SetHeading.Hit -= SetHeading_Hit; DefaultHeading.Change -= DefaultHeading_Change; diff --git a/Views/mainView.xml b/Views/mainView.xml index ad913d1..ca30043 100644 --- a/Views/mainView.xml +++ b/Views/mainView.xml @@ -22,27 +22,27 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/Views/portalBotView.xml b/Views/portalBotView.xml index 269e5dd..6415452 100644 --- a/Views/portalBotView.xml +++ b/Views/portalBotView.xml @@ -4,15 +4,20 @@ - + + + + + + - +