Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Linq;
- using System.Threading.Tasks;
- using System.Windows.Controls;
- using log4net;
- using Loki.Bot;
- using Loki.Common;
- using Loki.Game;
- using Loki.Game.GameData;
- using Loki.Game.Objects;
- using Loki.Game.Objects.Items;
- namespace ExtendedPlayerMover
- {
- internal class ExtendedPlayerMover : IPlugin
- {
- private static readonly ILog Log = Logger.GetLoggerInstanceForType();
- private bool _enabled;
- private SkillPlayerMover _mover = new SkillPlayerMover();
- /// <summary> The name of the plugin. </summary>
- public string Name
- {
- get { return "ExtendedPlayerMover"; }
- }
- /// <summary> The description of the plugin. </summary>
- public string Description
- {
- get { return "A modified version of CustomPlayerMover compatible with all four movement skills and quicksilver flasks."; }
- }
- /// <summary>The author of the plugin.</summary>
- public string Author
- {
- get { return "Bossland GmbH & Infinite Monkeys"; }
- }
- /// <summary>The version of the plugin.</summary>
- public string Version
- {
- get
- {
- return "1.0";
- }
- }
- /// <summary>Initializes this plugin.</summary>
- public void Initialize()
- {
- Log.DebugFormat("[ExtendedPlayerMover] Initialize");
- }
- public void Deinitialize()
- {
- Log.DebugFormat("[ExtendedPlayerMover] Deinitialize");
- }
- /// <summary> The plugin start callback. Do any initialization here. </summary>
- public void Start()
- {
- Log.DebugFormat("[ExtendedPlayerMover] Start");
- // This is all that needs to be done. All movement logic that uses PlayerMover.MoveTowards
- // will now use this new instance's implementation.
- PlayerMover.Instance = _mover;
- _mover.SkillSlot = -1; // reset the skill slot in case the user changed something
- Log.InfoFormat("[ExtendedPlayerMover] Now setting the SkillPlayerMover.");
- }
- /// <summary> The plugin tick callback. Do any update logic here. </summary>
- public void Tick()
- {
- }
- /// <summary> The plugin stop callback. Do any pre-dispose cleanup here. </summary>
- public void Stop()
- {
- Log.DebugFormat("[ExtendedPlayerMover] Stop");
- }
- #region Implementation of IConfigurable
- public JsonSettings Settings
- {
- get { return null; }
- }
- /// <summary> The plugin's settings control. This will be added to the Exilebuddy Settings tab.</summary>
- public UserControl Control
- {
- get { return null; }
- }
- #endregion
- #region Implementation of ILogic
- /// <summary>
- /// Coroutine logic to execute.
- /// </summary>
- /// <param name="type">The requested type of logic to execute.</param>
- /// <param name="param">Data sent to the object from the caller.</param>
- /// <returns>true if logic was executed to handle this type and false otherwise.</returns>
- public async Task<bool> Logic(string type, params dynamic[] param)
- {
- return false;
- }
- /// <summary>
- /// Non-coroutine logic to execute.
- /// </summary>
- /// <param name="name">The name of the logic to invoke.</param>
- /// <param name="param">The data passed to the logic.</param>
- /// <returns>Data from the executed logic.</returns>
- public object Execute(string name, params dynamic[] param)
- {
- return null;
- }
- #endregion
- #region Implementation of IEnableable
- /// <summary> The plugin is being enabled.</summary>
- public void Enable()
- {
- Log.DebugFormat("[ExtenderPlayerMover] Enable");
- }
- /// <summary> The plugin is being disabled.</summary>
- public void Disable()
- {
- Log.DebugFormat("[ExtenderPlayerMover] Disable");
- }
- #endregion
- #region Override of Object
- /// <summary>Returns a string that represents the current object.</summary>
- /// <returns>A string that represents the current object.</returns>
- public override string ToString()
- {
- return Name + ": " + Description;
- }
- #endregion
- }
- /// <summary>
- /// A player mover that uses movement skills and adrenaline potions to try and move around.
- /// This mover pathfinds each operation to the destination to try and avoid desync issues.
- /// </summary>
- public class SkillPlayerMover : IPlayerMover
- {
- private static readonly ILog Log = Logger.GetLoggerInstanceForType();
- private readonly Stopwatch _speedFlaskCd = new Stopwatch();
- internal int SkillSlot = -1;
- internal bool useQuicksilver = false;
- //Position of each skill, so that if there's more than one available
- //we can find the one with the highest slot value and use that.
- private int Skill1Slot = -1;
- private int Skill2Slot = -1;
- private int Skill3Slot = -1;
- private int Skill4Slot = -1;
- private string _activeMoveSkill;
- private readonly Stopwatch _skillStopwatch = new Stopwatch();
- //Stolen from ExtenderPlayerMover
- private bool FlaskHelper(Stopwatch sw, int flaskCdMs, IEnumerable<Item> flasks)
- {
- var useFlask = false;
- if (!sw.IsRunning)
- {
- sw.Start();
- useFlask = true;
- }
- else if (sw.ElapsedMilliseconds > Loki.Bot.Logic.Bots.OldGrindBot.Utility.LatencySafeValue(flaskCdMs))
- {
- sw.Restart();
- useFlask = true;
- }
- if (useFlask)
- {
- var flask = flasks.FirstOrDefault();
- if (flask != null)
- {
- var err = LokiPoe.InGameState.QuickFlaskPanel.UseFlask(flask);
- if (err != LokiPoe.InGameState.UseFlaskError.None)
- {
- Log.ErrorFormat("[FlaskHelper] QuickFlaskPanel.UseFlask returned {0}.", err);
- }
- return true;
- }
- }
- return false;
- }
- //Quicksilver Flasks
- public static IEnumerable<Item> SpeedFlasks
- {
- get
- {
- var inv = LokiPoe.InGameState.QuickFlaskPanel.Flasks;
- return from item in inv
- let flask = item as Flask
- where flask != null && flask.Name.Contains("Quicksilver Flask") && flask.CanUse
- select item;
- }
- }
- /// <summary>
- /// Attempts to move towards a position. This function will perform pathfinding logic and take into consideration move distance
- /// to try and smoothly move towards a point.
- /// </summary>
- /// <param name="position">The position to move towards.</param>
- /// <param name="user">A user object passed.</param>
- /// <returns>true if the position was moved towards, and false if there was a pathfinding error.</returns>
- public bool MoveTowards(Vector2i position, params dynamic[] user)
- {
- var me = LokiPoe.Me;
- var myPos = me.Position;
- var path = new Loki.Bot.Pathfinding.PathfindingCommand(myPos, position, 10);
- if (Loki.Bot.Pathfinding.ExilePather.FindPath(ref path))
- {
- if (path.Error == Loki.Bot.Pathfinding.PathfindingError.StartNotNavigable ||
- path.Error == Loki.Bot.Pathfinding.PathfindingError.StartAndEndAreSame)
- {
- var rnd = LokiPoe.Me.Position;
- rnd += new Vector2i(Loki.Game.LokiPoe.Random.Next(-25, 26), Loki.Game.LokiPoe.Random.Next(-25, 26));
- Log.DebugFormat("[MoveTowards] FindPath returned {0}. Now clicking the random position {1}.",
- path.Error, rnd);
- LokiPoe.Input.SetMousePos(rnd);
- LokiPoe.Input.Move();
- return true;
- }
- Log.ErrorFormat("[MoveTowards] FindPath returned {0}.", path.Error);
- return false;
- }
- var distance = myPos.Distance(position); ; //As the crow flies, for now at least.
- if (distance > 200)
- {
- FlaskHelper(_speedFlaskCd, 5000, SpeedFlasks); //I'll un-hardcode this at some point, maybe
- }
- var point = Vector2i.Zero;
- var checkSkill = true;
- var canSkill = false;
- var skillPos = Vector2i.Zero;
- // Only check for using skill once every 300ms.
- if (_skillStopwatch.IsRunning && _skillStopwatch.ElapsedMilliseconds < 300)
- {
- checkSkill = false;
- }
- // Don't try to custom move in these areas.
- if (LokiPoe.Me.IsInTown || LokiPoe.Me.IsInMapRoom || LokiPoe.Me.IsInHideout)
- checkSkill = false;
- if (SkillSlot == -1 && useQuicksilver == false)
- {
- //This isn't very neat but it works so whatever
- var LW = LokiPoe.Me.AvailableSkills.FirstOrDefault(s => s.Name == "Lightning Warp" && s.IsOnSkillBar);
- var LS = LokiPoe.Me.AvailableSkills.FirstOrDefault(s => s.Name == "Leap Slam" && s.IsOnSkillBar);
- var WB = LokiPoe.Me.AvailableSkills.FirstOrDefault(s => s.Name == "Whirling Blades" && s.IsOnSkillBar);
- var BA = LokiPoe.Me.AvailableSkills.FirstOrDefault(s => s.Name == "Blink Arrow" && s.IsOnSkillBar);
- List<int> skills = new List<int>();
- if (LW != null)
- {
- skills.Add(LW.Slot);
- Log.DebugFormat("[ExtendedPlayerMover] Found Lightning Warp in slot {0}", LW.Slot);
- }
- if (LS != null)
- {
- skills.Add(LS.Slot);
- Log.DebugFormat("[ExtendedPlayerMover] Found Leap Slam in slot {0}", LS.Slot);
- }
- if (WB != null)
- {
- skills.Add(WB.Slot);
- Log.DebugFormat("[ExtendedPlayerMover] Found Whirling Blades in slot {0}", WB.Slot);
- }
- if (BA != null)
- {
- skills.Add(BA.Slot);
- Log.DebugFormat("[ExtendedPlayerMover] Found Blink Arrow in slot {0}", BA.Slot);
- }
- if (skills.Count != 0)
- SkillSlot = skills.Max();
- // No movement skill, see if they have any quicksilver flasks.
- if (SkillSlot == -1)
- {
- checkSkill = false;
- Log.DebugFormat("[ExtendedPlayerMover] No movement skill found, checking for quicksilver flasks");
- if (SpeedFlasks != null)
- {
- useQuicksilver = true;
- Log.DebugFormat("[ExtendedPlayerMover] Found quicksilver flask(s), using them");
- }
- }
- }
- if (LokiPoe.CurrentWorldArea.IsTown)
- {
- // To avoid some issues in Act 2 stairs, we try to take points closer to us rather than the other way around.
- point = path.Path.FirstOrDefault(e => e.Distance(myPos) > 8);
- }
- else
- {
- // TODO: Tweak/change this logic as needed per tileset.
- // Smaller closed areas should probably just skip trying to use movement skills.
- for (var i = path.Path.Count - 1; i > 0; --i)
- {
- point = path.Path[i];
- if (checkSkill && !canSkill && point.Distance(myPos) <= 60)
- {
- if (Loki.Bot.Pathfinding.ExilePather.CanObjectSee(LokiPoe.Me, point) && !Loki.Bot.Logic.Bots.OldGrindBot.Utility.ClosedDoorBetween(myPos, point))
- {
- canSkill = true;
- skillPos = point;
- }
- }
- if (point.Distance(myPos) <= 20)
- break;
- }
- }
- if (point == Vector2i.Zero)
- {
- point = path.Path.Last();
- }
- // Find a point in the direction we want to move, but keep it random to make sure bots do not do the same thing everytime.
- var abc = myPos.GetPointAtDistanceAfterThis(point, Loki.Game.LokiPoe.Random.Next(14, 20));
- point += new Vector2i(Loki.Game.LokiPoe.Random.Next(-2, 3), Loki.Game.LokiPoe.Random.Next(-2, 3));
- // Try to use movement skill
- if (canSkill)
- {
- var res = LokiPoe.InGameState.SkillBarPanel.UseAt(SkillSlot, false, skillPos);
- if (res == LokiPoe.InGameState.UseError.None)
- {
- if (LokiPoe.Me.HasCurrentAction)
- {
- if (LokiPoe.Me.CurrentAction.Skill.Name == _activeMoveSkill)
- {
- _skillStopwatch.Restart();
- return true;
- }
- }
- }
- }
- // Otherwise, normal movement to keep on going.
- LokiPoe.Input.SetMousePos(point);
- LokiPoe.Input.Move();
- return true;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement