using Buddy.Coroutines; using Clio.Utilities; using Clio.XmlEngine; using ff14bot.Managers; using ff14bot.Behavior; 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("FlyParabolicArcTo")] public class FlyParabolicArcTo : ProfileBehavior { private bool _done = false; private SlideMover _slideMover = new SlideMover(); [XmlAttribute("XYZ")] public Vector3 XYZ { get; set; } [DefaultValue(2.0f)] [XmlAttribute("Radius")] public float Radius { get; set; } [DefaultValue(45)] [XmlAttribute("MountId")] public int MountId { get; set; } [DefaultValue(30.0f)] [XmlAttribute("MaxHeight")] public float MaxHeight { get; set; } [DefaultValue(10.0f)] [XmlAttribute("MinDistanceToFly")] public float MinDistanceToFly { get; set; } [DefaultValue(true)] [XmlAttribute("LandAtDestination")] public bool LandAtDestination { get; set; } [DefaultValue(true)] [XmlAttribute("DismountAtDestination")] public bool DismountAtDestination { get; set; } protected override void OnStart() { _done = false; } public override bool IsDone { get { return _done; } } protected override void OnDone() { _done = false; } protected override Composite CreateBehavior() { return new Decorator( ret => !IsDone, new ActionRunCoroutine(r => Fly())); } protected override void OnResetCachedDone() { _done = false; } public static bool IsBetween(Vector2 a, Vector2 b, Vector2 c) { //Logging.Write("Is {0} between {1} and {2}?",c,a,b); //var crossProduct = Math.Abs((c.Y-a.Y)*(b.X-a.X)-(c.X-a.X)*(b.Y-a.Y)); //if (crossProduct > Single.Epsilon) //{ //Logging.Write("No: crossProduct {0} > Single.Epsilon {1}",crossProduct,Single.Epsilon); //return false; //} var dotProduct = (c.X-a.X)*(b.X-a.X)+(c.Y-a.Y)*(b.Y-a.Y); if (dotProduct < 0f) { //Logging.Write("No: dotProduct {0} > 0 {1}",dotProduct); return false; } var squaredLengthBa = (b.X-a.X)*(b.X-a.X)+(b.Y-a.Y)*(b.Y-a.Y); if (dotProduct > squaredLengthBa) { //Logging.Write("No: dotProduct {0} > squaredLengthBa {1}",dotProduct,squaredLengthBa); return false; } //Logging.Write("Yes"); return true; } public static float Distance3D(Vector3 l, Vector3 r) { var distance3D = Convert.ToSingle(Math.Sqrt((r.X - l.X) * (r.X - l.X) + (r.Y - l.Y)*(r.Y - l.Y) + (r.Z - l.Z) * (r.Z - l.Z))); //Logging.Write("Distance between {0} and {1} is {2}",l,r,distance3D); return distance3D; } public static Vector3 NextParabolaPoint(Vector3 startPoint, float a, float b, float c, float h, float t) { var x = startPoint.X+a*t; var y = startPoint.Y+b*t+4.0f*h*(t-t*t); var z = startPoint.Z+c*t; Vector3 point = new Vector3( x, y, z); return point; } public async Task MoveToWithinRadius(Vector3 wayPoint) { var startPoint = GameObjectManager.LocalPlayer.Location; while(true) { var currentPoint = GameObjectManager.LocalPlayer.Location; if (Distance3D(currentPoint, wayPoint) <= Radius || !IsBetween(new Vector2(startPoint.X,startPoint.Z), new Vector2(wayPoint.X,wayPoint.Z), new Vector2(currentPoint.X,currentPoint.Z))) { break; } _slideMover.MoveTowards(wayPoint); await Coroutine.Sleep(150); } _slideMover.MoveStop(); return true; } public async Task Fly() { Vector3 endPoint = XYZ; Vector3 startPoint = GameObjectManager.LocalPlayer.Location; var D = Distance3D(startPoint, endPoint); if (D > MinDistanceToFly) { await CommonTasks.TakeOff(); var numWayPoints = Convert.ToSingle(Math.Max(Math.Floor(D/Radius), 1.0f)); var a = endPoint.X-startPoint.X; var b = endPoint.Y-startPoint.Y; var c = endPoint.Z-startPoint.Z; var deltaT = 1.0f/numWayPoints; for(var t=deltaT; t<=1.0f; t+=deltaT) { Vector3 waypoint = NextParabolaPoint(startPoint,a,b,c,MaxHeight,t); await MoveToWithinRadius(waypoint); } if(LandAtDestination) { await CommonTasks.Land(); if (DismountAtDestination) { Actionmanager.Dismount(); } } } else { await MoveToWithinRadius(XYZ); if (DismountAtDestination) { Actionmanager.Dismount(); } } _done = true; return true; } } }