context: using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Threading.Tasks;
  using LeagueSharp;
  using LeagueSharp.Common;
  using LeagueSharp.Common.Data;
  using SharpDX;
  using Color = System.Drawing.Color;
  
  using EloBuddy; 
   using LeagueSharp.Common; 
   namespace BadaoDraven
  {
      public static class Orbwalking
      {
          public delegate void AfterAttackEvenH(AttackableUnit unit, AttackableUnit target);
  
          public delegate void BeforeAttackEvenH(BeforeAttackEventArgs args);
  
          public delegate void OnAttackEvenH(AttackableUnit unit, AttackableUnit target);
  
          public delegate void OnNonKillableMinionH(AttackableUnit minion);
  
          public delegate void OnTargetChangeH(AttackableUnit oldTarget, AttackableUnit newTarget);
  
          public enum OrbwalkingMode
          {
              LastHit,
              Mixed,
              LaneClear,
              Combo,
              None
          }
  
          //Spells that reset the attack timer.
          private static readonly string[] AttackResets =
          {
              "dariusnoxiantacticsonh", "fioraflurry", "garenq",
              "hecarimrapidslash", "jaxempowertwo", "jaycehypercharge", "leonashieldofdaybreak", "luciane", "lucianq",
              "monkeykingdoubleattack", "mordekaisermaceofspades", "nasusq", "nautiluspiercinggaze", "netherblade",
              "parley", "poppydevastatingblow", "powerfist", "renektonpreexecute", "rengarq", "shyvanadoubleattack",
              "sivirw", "takedown", "talonnoxiandiplomacy", "trundletrollsmash", "vaynetumble", "vie", "volibearq",
              "xenzhaocombotarget", "yorickspectral", "reksaiq"
          };
  
          //Spells that are not attacks even if they have the "attack" word in their name.
          private static readonly string[] NoAttacks =
          {
              "jarvanivcataclysmattack", "monkeykingdoubleattack",
              "shyvanadoubleattack", "shyvanadoubleattackdragon", "zyragraspingplantattack", "zyragraspingplantattack2",
              "zyragraspingplantattackfire", "zyragraspingplantattack2fire", "viktorpowertransfer"
          };
  
          //Spells that are attacks even if they dont have the "attack" word in their name.
          private static readonly string[] Attacks =
          {
              "caitlynheadshotmissile", "frostarrow", "garenslash2",
              "kennenmegaproc", "lucianpassiveattack", "masteryidoublestrike", "quinnwenhanced", "renektonexecute",
              "renektonsuperexecute", "rengarnewpassivebuffdash", "trundleq", "xenzhaothrust", "xenzhaothrust2",
              "xenzhaothrust3", "viktorqbuff"
          };
  
          // Champs whose auto attacks can't be cancelled
          private static readonly string[] NoCancelChamps = { "Kalista" };
          public static int LastAATick;
          public static bool Attack = true;
          public static bool DisableNextAttack;
          public static bool Move = true;
          public static int LastMoveCommandT;
          public static Vector3 LastMoveCommandPosition = Vector3.Zero;
          private static AttackableUnit _lastTarget;
          private static readonly AIHeroClient Player;
          private static int _delay;
          private static float _minDistance = 400;
          private static readonly Random _random = new Random(DateTime.Now.Millisecond);
  
          static Orbwalking()
          {
              Player = ObjectManager.Player;
              Obj_AI_Base.OnProcessSpellCast += OnProcessSpell;
              GameObject.OnCreate += Obj_SpellMissile_OnCreate;
              Spellbook.OnStopCast += SpellbookOnStopCast;
          }
  
          private static void Obj_SpellMissile_OnCreate(GameObject sender, EventArgs args)
          {
              if (sender.IsValid<MissileClient>())
              {
                  var missile = (MissileClient)sender;
                  if (missile.SpellCaster.IsValid<AIHeroClient>() && IsAutoAttack(missile.SData.Name))
                  {
                      FireAfterAttack(missile.SpellCaster, _lastTarget);
                  }
              }
          }
  
          /// <summary>
          ///     This event is fired before the player auto attacks.
          /// </summary>
          public static event BeforeAttackEvenH BeforeAttack;
  
          /// <summary>
          ///     This event is fired when a unit is about to auto-attack another unit.
          /// </summary>
          public static event OnAttackEvenH OnAttack;
  
          /// <summary>
          ///     This event is fired after a unit finishes auto-attacking another unit (Only works with player for now).
          /// </summary>
          public static event AfterAttackEvenH AfterAttack;
  
          /// <summary>
          ///     Gets called on target changes
          /// </summary>
          public static event OnTargetChangeH OnTargetChange;
  
          //  <summary>
          //      Gets called if you can't kill a minion with auto attacks
          //  </summary>
          public static event OnNonKillableMinionH OnNonKillableMinion;
  
          private static void FireBeforeAttack(AttackableUnit target)
          {
              if (BeforeAttack != null)
              {
                  BeforeAttack(new BeforeAttackEventArgs { Target = target });
              }
              else
              {
                  DisableNextAttack = false;
              }
          }
  
          private static void FireOnAttack(AttackableUnit unit, AttackableUnit target)
          {
              if (OnAttack != null)
              {
                  OnAttack(unit, target);
              }
          }
  
          private static void FireAfterAttack(AttackableUnit unit, AttackableUnit target)
          {
              if (AfterAttack != null && target.IsValidTarget())
              {
                  AfterAttack(unit, target);
              }
          }
  
          private static void FireOnTargetSwitch(AttackableUnit newTarget)
          {
              if (OnTargetChange != null && (!_lastTarget.IsValidTarget() || _lastTarget != newTarget))
              {
                  OnTargetChange(_lastTarget, newTarget);
              }
          }
  
          private static void FireOnNonKillableMinion(AttackableUnit minion)
          {
              if (OnNonKillableMinion != null)
              {
                  OnNonKillableMinion(minion);
              }
          }
  
          /// <summary>
          ///     Returns true if the spellname resets the attack timer.
          /// </summary>
          public static bool IsAutoAttackReset(string name)
          {
              return AttackResets.Contains(name.ToLower());
          }
  
          /// <summary>
          ///     Returns true if the unit is melee
          /// </summary>
          public static bool IsMelee(this Obj_AI_Base unit)
          {
              return unit.CombatType == GameObjectCombatType.Melee;
          }
  
          /// <summary>
          ///     Returns true if the spellname is an auto-attack.
          /// </summary>
          public static bool IsAutoAttack(string name)
          {
              return (name.ToLower().Contains("attack") && !NoAttacks.Contains(name.ToLower())) ||
                     Attacks.Contains(name.ToLower());
          }
  
          /// <summary>
          ///     Returns the auto-attack range.
          /// </summary>
          public static float GetRealAutoAttackRange(AttackableUnit target)
          {
              var result = Player.AttackRange + Player.BoundingRadius;
              if (target.IsValidTarget())
              {
                  return result + target.BoundingRadius;
              }
              return result;
          }
  
          /// <summary>
          ///     Returns true if the target is in auto-attack range.
          /// </summary>
          public static bool InAutoAttackRange(AttackableUnit target)
          {
              if (!target.IsValidTarget())
              {
                  return false;
              }
              var myRange = GetRealAutoAttackRange(target);
              return
                  Vector2.DistanceSquared(
                      (target is Obj_AI_Base) ? ((Obj_AI_Base)target).ServerPosition.To2D() : target.Position.To2D(),
                      Player.ServerPosition.To2D()) <= myRange * myRange;
          }
  
          /// <summary>
          ///     Returns player auto-attack missile speed.
          /// </summary>
          public static float GetMyProjectileSpeed()
          {
              return IsMelee(Player) || Player.ChampionName == "Azir" ? float.MaxValue : Player.BasicAttack.MissileSpeed;
          }
  
          /// <summary>
          ///     Returns if the player's auto-attack is ready.
          /// </summary>
          public static bool CanAttack()
          {
              if (LastAATick <= Utils.GameTimeTickCount)
              {
                  return Utils.GameTimeTickCount + Game.Ping / 2 + 25 >= LastAATick + Player.AttackDelay * 1000 && Attack;
              }
  
              return false;
          }
  
          /// <summary>
          ///     Returns true if moving won't cancel the auto-attack.
          /// </summary>
          public static bool CanMove(float extraWindup)
          {
              if (LastAATick <= Utils.GameTimeTickCount)
              {
                  return Move && /*NoCancelChamps.Contains(Player.ChampionName)
                      ? (Utils.TickCount - LastAATick > 250)
                      :*/ (Utils.GameTimeTickCount + Game.Ping / 2 >= LastAATick + Player.AttackCastDelay * 1000 + extraWindup);
              }
  
              return false;
          }
  
          public static void SetMovementDelay(int delay)
          {
              _delay = delay;
          }
  
          public static void SetMinimumOrbwalkDistance(float d)
          {
              _minDistance = d;
          }
  
          public static float GetLastMoveTime()
          {
              return LastMoveCommandT;
          }
  
          public static Vector3 GetLastMovePosition()
          {
              return LastMoveCommandPosition;
          }
  
          public static void MoveTo(Vector3 position,
              float holdAreaRadius = 0,
              bool overrideTimer = false,
              bool useFixedDistance = true,
              bool randomizeMinDistance = true)
          {
              if (Utils.GameTimeTickCount - LastMoveCommandT < _delay && !overrideTimer)
              {
                  return;
              }
  
              LastMoveCommandT = Utils.GameTimeTickCount;
  
              if (Player.ServerPosition.Distance(position, true) < holdAreaRadius * holdAreaRadius)
              {
  
gt:                 if (Player.Path.Count() > 1)