context: using EloBuddy; 
  using LeagueSharp.Common; 
  namespace Flowers_Fiora.Evade
  {
      using System;
      using System.Collections.Generic;
      using System.Linq;
      using LeagueSharp;
      using LeagueSharp.Common;
      using SharpDX;
      using static Common.Common;
      using Geometry = GE;
  
      public static class EvadeManager
      {
          public const int SkillShotsExtraRadius = 9;
          public const int SkillShotsExtraRange = 20;
          public const int GridSize = 10;
          public const int EvadingFirstTimeOffset = 250;
          public const int EvadingSecondTimeOffset = 80;
  
          public static Menu Menu = Logic.Menu;
  
          public static List<Skillshot> DetectedSkillshots = new List<Skillshot>();
  
          public static void Init()
          {
              Collision.Init();
  
              Game.OnUpdate += OnUpdate;
              SkillshotDetector.OnDeleteMissile += OnDeleteMissile;
              SkillshotDetector.OnDetectSkillshot += OnDetectSkillshot;
          }
  
          private static void OnUpdate(EventArgs args)
          {
              DetectedSkillshots.RemoveAll(skillshot => !skillshot.IsActive());
  
              foreach (var skillshot in DetectedSkillshots)
              {
                  skillshot.OnUpdate();
              }
  
              if (ObjectManager.Player.IsDead)
              {
                  return;
              }
  
              if (ObjectManager.Player.HasBuffOfType(BuffType.SpellImmunity) || ObjectManager.Player.HasBuffOfType(BuffType.SpellShield))
              {
                  return;
              }
  
              var currentPath = ObjectManager.Player.Path.ToList().To2D();
              var safeResult = IsSafe(ObjectManager.Player.ServerPosition.To2D());
              var safePath = IsSafePath(currentPath, 100);
  
              if (!safePath.IsSafe)
              {
                  if (!safeResult.IsSafe)
                  {
                      TryToEvade(safeResult.SkillshotList, Game.CursorPos.To2D());
                  }
              }
          }
  
          private static void TryToEvade(List<Skillshot> HitBy, Vector2 Pos)
          {
              var dangerLevel = 0;
  
              foreach (var skillshot in HitBy)
              {
                  dangerLevel = Math.Max(dangerLevel, skillshot.GetValue<Slider>("DangerLevel").Value);
              }
  
              foreach (var evadeSpell in EvadeSpellDatabase.Spells)
              {
                  if (evadeSpell.Enabled && evadeSpell.DangerLevel <= dangerLevel)
                  {
                      if (evadeSpell.IsReady())
                      {
                          switch (evadeSpell.Slot)
                          {
                              case SpellSlot.Q:
                                  var points = GetEvadePoints(evadeSpell.Speed, evadeSpell.Delay);
  
                                  points.RemoveAll(
                                      item => item.Distance(ObjectManager.Player.ServerPosition) > evadeSpell.Range);
  
                                  for (var i = 0; i < points.Count; i++)
                                  {
                                      points[i] = ObjectManager.Player.ServerPosition.To2D().Extend(points[i], evadeSpell.Range);
                                  }
  
                                  for (var i = points.Count - 1; i > 0; i--)
                                  {
                                      if (!IsSafe(points[i]).IsSafe)
                                      {
                                          points.RemoveAt(i);
                                      }
                                  }
  
                                  if (points.Count > 0)
                                  {
                                      ObjectManager.Player.Spellbook.CastSpell(evadeSpell.Slot, Pos.Closest(points).To3D());
                                      return;
                                  }
                                  break;
                              case SpellSlot.W:
                                  var skillShotList =
                                      HitBy.Where(
                                          x => x.SpellData.CollisionObjects.Contains(CollisionObjectTypes.YasuoWall));
  
                                  if (skillShotList.Any())
                                  {
                                      var willHitList =
                                          skillShotList.Where(
                                              x =>
                                                  x.IsAboutToHit(
                                                      150 + evadeSpell.Delay,
                                                      ObjectManager.Player));
  
                                      if (willHitList.Any())
                                      {
                                          if (
                                              willHitList.OrderByDescending(
                                                      x => dangerLevel)
                                                  .Any(
                                                      x =>
                                                          Logic.W.Cast(
                                                              ObjectManager.Player.ServerPosition.Extend(x.Start.To3D(),
                                                                  300))))
                                          {
                                              return;
                                          }
                                      }
                                  }
                                  break;
                          }
                      }
                  }
              }
          }
  
  
          private static void OnDeleteMissile(Skillshot skillshot, MissileClient missile)
          {
              if (skillshot.SpellData.SpellName == "VelkozQ")
              {
                  var spellData = SpellDatabase.GetByName("VelkozQSplit");
                  var direction = skillshot.Direction.Perpendicular();
  
                  if (DetectedSkillshots.Count(s => s.SpellData.SpellName == "VelkozQSplit") == 0)
                  {
                      for (var i = -1; i <= 1; i = i + 2)
                      {
                          var skillshotToAdd = new Skillshot(
                              DetectionType.ProcessSpell, spellData, Utils.GameTimeTickCount, missile.Position.To2D(),
                              missile.Position.To2D() + i * direction * spellData.Range, skillshot.Unit);
                          DetectedSkillshots.Add(skillshotToAdd);
                      }
                  }
              }
          }
  
          private static void OnDetectSkillshot(Skillshot skillshot)
          {
              var alreadyAdded = false;
  
              foreach (var item in DetectedSkillshots)
              {
                  if (item.SpellData.SpellName == skillshot.SpellData.SpellName &&
                      item.Unit.NetworkId == skillshot.Unit.NetworkId &&
                      skillshot.Direction.AngleBetween(item.Direction) < 5 &&
                      (skillshot.Start.Distance(item.Start) < 100 || skillshot.SpellData.FromObjects.Length == 0))
                  {
                      alreadyAdded = true;
                  }
              }
  
              if (skillshot.Unit.Team == ObjectManager.Player.Team)
              {
                  return;
              }
  
              if (skillshot.Start.Distance(ObjectManager.Player.ServerPosition.To2D()) >
                  (skillshot.SpellData.Range + skillshot.SpellData.Radius + 1000) * 1.5)
              {
                  return;
              }
  
              if (!alreadyAdded || skillshot.SpellData.DontCheckForDuplicates)
              {
                  if (skillshot.DetectionType == DetectionType.ProcessSpell)
                  {
                      if (skillshot.SpellData.MultipleNumber != -1)
                      {
                          var originalDirection = skillshot.Direction;
  
                          for (var i = -(skillshot.SpellData.MultipleNumber - 1) / 2;
                              i <= (skillshot.SpellData.MultipleNumber - 1) / 2;
                              i++)
                          {
                              var end = skillshot.Start +
                                        skillshot.SpellData.Range *
                                        originalDirection.Rotated(skillshot.SpellData.MultipleAngle * i);
                              var skillshotToAdd = new Skillshot(
                                  skillshot.DetectionType, skillshot.SpellData, skillshot.StartTick, skillshot.Start, end,
                                  skillshot.Unit);
  
                              DetectedSkillshots.Add(skillshotToAdd);
                          }
                          return;
                      }
  
                      if (skillshot.SpellData.SpellName == "UFSlash")
                      {
                          skillshot.SpellData.MissileSpeed = 1600 + (int)skillshot.Unit.MoveSpeed;
                      }
  
                      if (skillshot.SpellData.SpellName == "SionR")
                      {
                          skillshot.SpellData.MissileSpeed = (int)skillshot.Unit.MoveSpeed;
                      }
  
                      if (skillshot.SpellData.Invert)
                      {
                          var newDirection = -(skillshot.End - skillshot.Start).Normalized();
                          var end = skillshot.Start + newDirection * skillshot.Start.Distance(skillshot.End);
                          var skillshotToAdd = new Skillshot(
                              skillshot.DetectionType, skillshot.SpellData, skillshot.StartTick, skillshot.Start, end,
                              skillshot.Unit);
                          DetectedSkillshots.Add(skillshotToAdd);
                          return;
                      }
  
                      if (skillshot.SpellData.Centered)
                      {
                          var start = skillshot.Start - skillshot.Direction * skillshot.SpellData.Range;
                          var end = skillshot.Start + skillshot.Direction * skillshot.SpellData.Range;
                          var skillshotToAdd = new Skillshot(
                              skillshot.DetectionType, skillshot.SpellData, skillshot.StartTick, start, end,
                              skillshot.Unit);
                          DetectedSkillshots.Add(skillshotToAdd);
                          return;
                      }
  
                      var unit = skillshot.Unit as AIHeroClient;
  
                      if (unit != null && skillshot.SpellData.SpellName == "TaricE" && unit.ChampionName == "Taric")
                      {
                          var target =
                              HeroManager.AllHeroes.FirstOrDefault(
                                  h => h.Team == skillshot.Unit.Team && h.IsVisible && h.HasBuff("taricwleashactive"));
  
                          if (target != null)
                          {
                              var start = target.ServerPosition.To2D();
                              var direction = (skillshot.OriginalEnd - start).Normalized();
                              var end = start + direction * skillshot.SpellData.Range;
                              var skillshotToAdd = new Skillshot(
                                      skillshot.DetectionType, skillshot.SpellData, skillshot.StartTick,
                                      start, end, target)
                              {
                                  OriginalEnd = skillshot.OriginalEnd
                              };
                              DetectedSkillshots.Add(skillshotToAdd);
                          }
                      }
  
                      if (skillshot.SpellData.SpellName == "SyndraE" || skillshot.SpellData.SpellName == "syndrae5")
                      {
                          var angle = 60;
                          var edge1 =
                              (skillshot.End - skillshot.Unit.ServerPosition.To2D()).Rotated(
                                  -angle / 2 * (float)Math.PI / 180);
                          var edge2 = edge1.Rotated(angle * (float)Math.PI / 180);
  
                          var positions = new List<Vector2>();
  
                          var explodingQ = DetectedSkillshots.FirstOrDefault(s => s.SpellData.SpellName == "SyndraQ");
  
                          if (explodingQ != null)
                          {
                              positions.Add(explodingQ.End);
                          }
  
                          foreach (var minion in ObjectManager.Get<Obj_AI_Minion>())
                          {
                              if (minion.Name == "Seed" && !minion.IsDead && minion.Team != ObjectManager.Player.Team)
                              {
                                  positions.Add(minion.ServerPosition.To2D());
                              }
                          }
  
                          foreach (var position in positions)
                          {
                              var v = position - skillshot.Unit.ServerPosition.To2D();
                              if (edge1.CrossProduct(v) > 0 && v.CrossProduct(edge2) > 0 &&
                                  position.Distance(skillshot.Unit) < 800)
                              {
                                  var start = position;
  
gt:                                 var end = skillshot.Unit.ServerPosition.To2D()