context: using System;
  using System.Collections.Generic;
  using System.Linq;
  using LeagueSharp;
  using LeagueSharp.Common;
  using SharpDX;
  using Color = System.Drawing.Color;
  
  
  using EloBuddy; 
   using LeagueSharp.Common; 
   namespace Slutty_Lucian
  {
      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,
              Burst,
              FastHarass,
              None
          }
          // Buffs that disable attack and movement
          public static readonly BuffType[] DisableBuff =
          {
              BuffType.Charm,
              BuffType.Fear,
              BuffType.Stun,
              BuffType.Knockup,
              BuffType.Knockup,
              BuffType.Taunt,
              BuffType.Suppression
          };
          //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", "sivirwattackbounce"
          };
  
          //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 int LastAaCommandTick;
          public static bool Attack = true;
          public static bool DisableNextAttack;
          public static bool Move = true;
          public static bool StopMove = false;
          public static int Winduptime;
          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 bool _missileLaunched;
          private static readonly Random _random = new Random(DateTime.Now.Millisecond);
  
          static Orbwalking()
          {
              Player = ObjectManager.Player;
              Obj_AI_Base.OnProcessSpellCast += OnProcessSpell;
              MissileClient.OnCreate += MissileClient_OnCreate;
              Spellbook.OnStopCast += SpellbookOnStopCast;
              Obj_AI_Base.OnSpellCast += Obj_AI_Base_OnSpellCast;
          }
  
  
          /// <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()
          {
              return Utils.GameTimeTickCount + Game.Ping / 2 + 25 >= LastAATick + Player.AttackDelay * 1000 && Attack
                  && !DisableBuff.Where(x => Player.HasBuffOfType(x)).Any() && !Player.IsDashing();
              //&& (Utils.GameTimeTickCount >= LastAACommandTick + 100 + Game.Ping);
          }
  
          /// <summary>
          ///     Returns true if moving won't cancel the auto-attack.
          /// </summary>
          public static bool CanMove(float extraWindup)
          {
              if (!Move)
              {
                  return false;
              }
  
              if (_missileLaunched && Orbwalker.MissileCheck)
              {
                  return true;
              }
              if (StopMove == false)
              {
                  return true;
              }
              return NoCancelChamps.Contains(Player.ChampionName) ||
                  ((Utils.GameTimeTickCount + Game.Ping / 2 >= LastAATick + Player.AttackCastDelay * 1000 + extraWindup)
                  && (Utils.GameTimeTickCount >= LastAaCommandTick + 100 + Game.Ping));
          }
  
          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;
  
              var playerPosition = Player.ServerPosition;
  
              if (playerPosition.Distance(position, true) < holdAreaRadius * holdAreaRadius)
              {
                  if (Player.Path.Length > 0)
                  {
                      EloBuddy.Player.IssueOrder(GameObjectOrder.Stop, playerPosition);
                      LastMoveCommandPosition = playerPosition;
                  }
                  return;
              }
  
              var point = position;
              if (useFixedDistance)
              {
                  point = playerPosition.Extend(
                      position, (randomizeMinDistance ? (_random.NextFloat(0.6f, 1) + 0.2f) * _minDistance : _minDistance));
              }
              else
              {
                  if (randomizeMinDistance)
                  {
                      point = playerPosition.Extend(position, (_random.NextFloat(0.6f, 1) + 0.2f) * _minDistance);
                  }
                  else if (playerPosition.Distance(position) > _minDistance)
                  {
                      point = playerPosition.Extend(position, _minDistance);
                  }
              }
  
              EloBuddy.Player.IssueOrder(GameObjectOrder.MoveTo, point);
              LastMoveCommandPosition = point;
          }
  
          /// <summary>
          ///     Orbwalk a target while moving to Position.
          /// </summary>
          public static void Orbwalk(AttackableUnit target,
              Vector3 position,
              float extraWindup = 90,
              float holdAreaRadius = 0,
              bool useFixedDistance = true,
              bool randomizeMinDistance = true)
          {
              try
              {
                  if (target.IsValidTarget() && CanAttack())
                  {
                      DisableNextAttack = false;
                      FireBeforeAttack(target);
  
                      if (!DisableNextAttack)
                      {
                          if (!NoCancelChamps.Contains(Player.ChampionName))
                          {
                              LastAaCommandTick = Utils.GameTimeTickCount - 4;
                              //LastAATick = Utils.GameTimeTickCount + Game.Ping + 100 - (int)(ObjectManager.Player.AttackCastDelay * 1000f);
                              _missileLaunched = false;
                              StopMove = true;
                          }
                          EloBuddy.Player.IssueOrder(GameObjectOrder.AttackUnit, target);
                          _lastTarget = target;
                          return;
                      }
                  }
  
                  if (CanMove(extraWindup))
                  {
                      MoveTo(position, holdAreaRadius, false, useFixedDistance, randomizeMinDistance);
                  }
                  Winduptime = (int)extraWindup;
              }
              catch (Exception e)
              {
                  Console.WriteLine(e.ToString());
              }
          }
  
          /// <summary>
          ///     Resets the Auto-Attack timer.
          /// </summary>
          public static void ResetAutoAttackTimer()
          {
              LastAATick = 0;
              LastAaCommandTick = 0;
          }
  
          private static void SpellbookOnStopCast(Obj_AI_Base spellbook, SpellbookStopCastEventArgs args)
          {
              if (spellbook.IsValid && spellbook.IsMe && args.DestroyMissile && args.StopAnimation)
              {
                  ResetAutoAttackTimer();
              }
          }
  
          private static void MissileClient_OnCreate(GameObject sender, EventArgs args)
          {
              if (!Orbwalker.Enabled)
                  return;
              var missile = sender as MissileClient;
              if (missile != null && missile.SpellCaster.IsMe && IsAutoAttack(missile.SData.Name))
              {
                  // _missileLaunched = true;
              }
          }
  
          private static void OnProcessSpell(Obj_AI_Base unit, GameObjectProcessSpellCastEventArgs Spell)
          {
              if (!Orbwalker.Enabled)
                  return;
              try
              {
                  var spellName = Spell.SData.Name;
  
                  if (IsAutoAttackReset(spellName) && unit.IsMe)
                  {
                      ResetAutoAttackTimer();
                  }
  
                  if (!IsAutoAttack(spellName))
                  {
                      return;
                  }
                  if (!unit.IsMe)
                      return;
                  if (!Player.Spellbook.IsAutoAttacking)
                  {
                      Chat.Say("/d");
                      return;
                  }
                  if (unit.IsMe &&
                      (Spell.Target is Obj_AI_Base || Spell.Target is Obj_BarracksDampener || Spell.Target is Obj_HQ))
                  {
                      LastAATick = Utils.GameTimeTickCount - Game.Ping / 2;
                      _missileLaunched = false;
                      StopMove = true;
                      if (Spell.Target is Obj_AI_Base)
                      {
                          var target = (Obj_AI_Base)Spell.Target;
                          if (target.IsValid)
                          {
                              FireOnTargetSwitch(target);
                              _lastTarget = target;
                          }
  
                          //Trigger it for ranged until the missiles catch normal attacks again!
                          //LeagueSharp.Common.Utility.DelayAction.Add(
                          //    (int)(unit.AttackCastDelay * 1000 + 40), () => FireAfterAttack(unit, _lastTarget));
                      }
                  }
  
                  FireOnAttack(unit, _lastTarget);
              }
              catch (Exception e)
              {
                  Console.WriteLine(e);
              }
          }
          private static void Obj_AI_Base_OnSpellCast(Obj_AI_Base sender, GameObjectProcessSpellCastEventArgs args)
          {
              if (!Orbwalker.Enabled)
                  return;
              try
              {
                  var spellName = args.SData.Name;
  
                  if (!IsAutoAttack(spellName))
                  {
                      return;
                  }
                  if (sender.IsMe &&
                      (args.Target is Obj_AI_Base || args.Target is Obj_BarracksDampener || args.Target is Obj_HQ))
                  {
                      var windup = Orbwalking.Orbwalker._config.Item("ExtraDoCastWindup").GetValue<Slider>().Value;
                      //_missileLaunched = true;
                      LeagueSharp.Common.Utility.DelayAction.Add(40 + windup > Game.Ping ? 40 + windup - Game.Ping : 0, () => FireAfterAttack(sender, _lastTarget));
                      LeagueSharp.Common.Utility.DelayAction.Add(40 + windup > Game.Ping ? 40 + windup - Game.Ping : 0, () => StopMove = false);
                      if (args.Target is Obj_AI_Base)
                      {
                          //Trigger it for ranged until the missiles catch normal attacks again!
  
                      }
                  }
              }
              catch (Exception e)
              {
                  Console.WriteLine(e);
              }
          }
          public class BeforeAttackEventArgs
          {
              private bool _process = true;
              public AttackableUnit Target;
              public Obj_AI_Base Unit = ObjectManager.Player;
  
              public bool Process
              {
                  get { return _process; }
                  set
                  {
                      DisableNextAttack = !value;
                      _process = value;
                  }
              }
          }
  
          /// <summary>
          ///     This class allows you to add an instance of "Orbwalker" to your assembly in order to control the orbwalking in an
          ///     easy way.
          /// </summary>
          public class Orbwalker
          {
              private static bool enabled;
  
              public static bool Enabled
              {
                  get
                  {
                      return enabled;
                  }
  
                  set
                  {
                      enabled = value;
                      if (_config != null)
                      {
                          _config.Item("enableOption").SetValue(value);
                      }
                  }
              }
              private const float LaneClearWaitTimeMod = 2f;
              public static Menu _config;
              private readonly AIHeroClient Player;
              private Obj_AI_Base _forcedTarget;
              private OrbwalkingMode _mode = OrbwalkingMode.None;
              private Vector3 _orbwalkingPoint;
              private Obj_AI_Minion _prevMinion;
              public static List<Orbwalker> Instances = new List<Orbwalker>();
  
              public Orbwalker(Menu attachToMenu)
              {
                  _config = attachToMenu;
                  _config.AddItem(new MenuItem("enableOption", "Enable Orbwalker").SetValue(true))
                      .ValueChanged += (sender, args) => enabled = args.GetNewValue<bool>();
                  enabled = _config.Item("enableOption").GetValue<bool>();
                  /* Drawings submenu */
                  var drawings = new Menu("Drawings", "drawings");
                  drawings.AddItem(
                      new MenuItem("AACircle", "AACircle").SetShared()
                          .SetValue(new Circle(true, Color.FromArgb(255, 255, 0, 255))));
                  drawings.AddItem(
                      new MenuItem("AACircle2", "Enemy AA circle").SetShared()
                          .SetValue(new Circle(false, Color.FromArgb(255, 255, 0, 255))));
                  drawings.AddItem(
                      new MenuItem("HoldZone", "HoldZone").SetShared()
                          .SetValue(new Circle(false, Color.FromArgb(255, 255, 0, 255))));
                  _config.AddSubMenu(drawings);
  
                  /* Misc options */
                  var misc = new Menu("Misc", "Misc");
                  misc.AddItem(
                      new MenuItem("HoldPosRadius", "Hold Position Radius").SetShared().SetValue(new Slider(0, 0, 250)));
                  misc.AddItem(new MenuItem("PriorizeFarm", "Priorize farm over harass").SetShared().SetValue(true));
  
                  _config.AddSubMenu(misc);
  
                  /* Missile check */
                  _config.AddItem(new MenuItem("MissileCheck", "Use Missile Check").SetShared().SetValue(true));
  
                  /* Delay sliders */
                  _config.AddItem(
                      new MenuItem("ExtraWindup", "Extra windup time").SetShared().SetValue(new Slider(80, 0, 200)));
                  _config.AddItem(
                      new MenuItem("ExtraDoCastWindup", "Extra windup time for ondocast").SetShared().SetValue(new Slider(0, 0, 10)));
  
                  _config.AddItem(new MenuItem("FarmDelay", "Farm delay").SetShared().SetValue(new Slider(0, 0, 200)));
                  _config.AddItem(
                      new MenuItem("MovementDelay", "Movement delay").SetShared().SetValue(new Slider(30, 0, 250)))
                      .ValueChanged += (sender, args) => SetMovementDelay(args.GetNewValue<Slider>().Value);
  
  
                  /*Load the menu*/
                  _config.AddItem(
                      new MenuItem("LastHit", "Last hit").SetShared().SetValue(new KeyBind('X', KeyBindType.Press)));
  
                  _config.AddItem(new MenuItem("Farm", "Mixed").SetShared().SetValue(new KeyBind('C', KeyBindType.Press)));
  
                  _config.AddItem(
                      new MenuItem("LaneClear", "LaneClear").SetShared().SetValue(new KeyBind('V', KeyBindType.Press)));
  
                  _config.AddItem(
                      new MenuItem("Orbwalk", "Combo").SetShared().SetValue(new KeyBind(32, KeyBindType.Press)));
  
                  _config.AddItem(
                    new MenuItem("Burst", "Burst").SetShared().SetValue(new KeyBind('T', KeyBindType.Press)));
  
                  _config.AddItem(
                     new MenuItem("FastHarass", "FastHarass").SetShared().SetValue(new KeyBind('Y', KeyBindType.Press)));
  
  
                  _delay = _config.Item("MovementDelay").GetValue<Slider>().Value;
  
  
                  Player = ObjectManager.Player;
                  Game.OnUpdate += GameOnOnGameUpdate;
                  Drawing.OnDraw += DrawingOnOnDraw;
                  Instances.Add(this);
              }
  
              public virtual bool InAutoAttackRange(AttackableUnit target)
              {
                  return Orbwalking.InAutoAttackRange(target);
              }
  
              private int FarmDelay
              {
                  get { return _config.Item("FarmDelay").GetValue<Slider>().Value; }
              }
  
              public static bool MissileCheck
              {
  
gt:                 get { return _config.Item("MissileCheck").GetValue<bool>(); }