using Buddy.Coroutines; using Clio.Utilities; using Clio.XmlEngine; using ff14bot.Managers; using ff14bot.Helpers; using ff14bot.Navigation; using System; using System.ComponentModel; using System.Diagnostics; using System.Runtime.InteropServices; using System.Globalization; using System.Threading.Tasks; using System.Windows.Forms; using System.ComponentModel.Design.Serialization; using System.Text; using System.Collections; using TreeSharp; using System.Reflection; using System.Collections.Generic; namespace ff14bot.NeoProfiles { [XmlElement("FlightPathTo")] public class FlightPathTo : ProfileBehavior { private bool _done = false; private SlideMover _slideMover = new SlideMover(); private List _waypoints = new List(); public override bool IsDone { get { return _done; } } [XmlAttribute("XYZ")] public Vector3 Target { get; set; } [XmlAttribute("Radius")] public float Radius { get; set; } [XmlAttribute("Smoothing")] public float Smoothing { get; set; } [DefaultValue(45)] [XmlAttribute("MountId")] public int MountId { get; set; } [DefaultValue(20.0f)] [XmlAttribute("NavHeight")] public float NavHeight { get; set; } [DefaultValue(true)] [XmlAttribute("DismountAtDestination")] public bool DismountAtDestination { get; set; } protected override Composite CreateBehavior() { return new ActionRunCoroutine(r => Fly()); } public async Task Fly() { _waypoints = await FindWaypoints(Target); if(_waypoints.Count > 0){ foreach(var waypoint in _waypoints){ Logging.Write("Moving to waypoint: {0}", waypoint); await MoveToWithinRadius(waypoint, Radius); } } else { Logging.Write("No viable path computed for {0}.", Target); } if(DismountAtDestination) { await DescendAndDismount(); } _done = true; return true; } public static float Lerp(float value1, float value2, float amount) { return value1 + (value2 - value1) * amount; } public static Vector3 Lerp(Vector3 value1, Vector3 value2, float amount) { return new Vector3( Lerp(value1.X, value2.X, amount), Lerp(value1.Y, value2.Y, amount), Lerp(value1.Z, value2.Z, amount)); } public static float Distance2D(Vector3 l, Vector3 r) { return Convert.ToSingle(Math.Sqrt((r.X - l.X) * (r.X - l.X) + (r.Z - l.Z) * (r.Z - l.Z))); } public static async Task SampleParabola ( Vector3 start, Vector3 end, float height, float t ) { if ( Math.Abs( start.Y - end.Y ) < 0.1f ) { //start and end are roughly level, pretend they are - simpler solution with less steps Vector3 travelDirection = end - start; Vector3 computed = start + t * travelDirection; computed.Y += (float)(Math.Sin( (double)(t * (float)Math.PI) )) * height; return computed; } else { //start and end are not level, gets more complicated Vector3 travelDirection = end - start; Vector3 levelDirecteion = end - new Vector3( start.X, end.Y, start.Z ); Vector3 right = Vector3.Cross( travelDirection, levelDirecteion ); Vector3 up = Vector3.Cross( right, travelDirection ); if ( end.Y > start.Y ) up = -up; Vector3 computed = start + t * travelDirection; up.Normalize(); computed += ( (float)(Math.Sin( (double)(t * (float)Math.PI) )) * height ) * up; return computed; } } public async Task> FindWaypoints(Vector3 target){ var waypoints = new List(); var distance = Distance2D(GameObjectManager.LocalPlayer.Location, target); var desiredNumberOfPoints = Math.Max(Math.Floor(distance * Smoothing), 1); var height = target.Y + NavHeight; Vector3 waypoint; for(var i=0.0f; i<=1.0f; i+=(1.0f/((float)desiredNumberOfPoints))){ waypoint = await SampleParabola(GameObjectManager.LocalPlayer.Location, target, (float)height, i); waypoints.Add(waypoint); } return waypoints; } public async Task PathIsClear(Vector3 from, Vector3 to){ Vector3 hit, distances; var somethingInTheWay = WorldManager.Raycast(from, to, out hit, out distances); return !somethingInTheWay; } public async Task TakeFlight() { MovementManager.Jump(); await Coroutine.Sleep(200); MovementManager.Jump(); await Coroutine.Sleep(200); return true; } public async Task EnsureMounted() { while(!GameObjectManager.LocalPlayer.IsMounted){ Actionmanager.Mount(Convert.ToUInt32(MountId)); await Coroutine.Sleep(2000); } return true; } public async Task EnsureFlying() { await EnsureMounted(); if(!ff14bot.Managers.MovementManager.IsFlying){ await TakeFlight(); } return true; } public async Task MoveToWithinRadius(Vector3 target, float radius){ while(Distance2D(GameObjectManager.LocalPlayer.Location, target) > Radius){ await EnsureFlying(); _slideMover.MoveTowards(target); await Coroutine.Sleep(200); } _slideMover.MoveStop(); return true; } public async Task DescendAndDismount(){ while(GameObjectManager.LocalPlayer.IsMounted){ Actionmanager.Dismount(); await Coroutine.Sleep(500); } return true; } } }