context: // Copyright 2014 - 2014 Esk0r
  // Program.cs is part of Evade.
  // 
  // Evade is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  // 
  // Evade is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  // 
  // You should have received a copy of the GNU General Public License
  // along with Evade. If not, see <http://www.gnu.org/licenses/>.
  
  using EloBuddy; 
   using LeagueSharp.SDK; 
   namespace Flowers_Series.Common.Evade
  {
      using LeagueSharp;
      using LeagueSharp.SDK;
      using LeagueSharp.SDK.UI;
      using LeagueSharp.SDK.Utils;
      using Pathfinding;
      using SharpDX;
      using System;
      using System.Collections.Generic;
      using System.Linq;
      using Color = System.Drawing.Color;
      using GamePath = System.Collections.Generic.List<SharpDX.Vector2>;
  
      internal class Evade
      {
          public static SpellList<Skillshot> DetectedSkillshots = new SpellList<Skillshot>();
          public static bool _evading;
          public static bool NoSolutionFound = false;
          public static bool ForcePathFollowing = false;
          public static int LastWardJumpAttempt = 0;
          public static string PlayerChampionName;
          public static Vector2 _evadePoint;
          public static Vector2 EvadeToPoint = new Vector2();
          public static Vector2 PreviousTickPosition = new Vector2();
          public static Vector2 PlayerPosition = new Vector2();
          public static readonly Random RandomN = new Random();
  
          public static bool Evading
          {
              get
              {
                  return _evading;
              }
              set
              {
                  if (value == true)
                  {
                      ForcePathFollowing = true;
                  }
  
                  _evading = value;
              }
          }
  
          public static Vector2 EvadePoint
          {
              get
              {
                  return _evadePoint;
              }
              set
              {
                  _evadePoint = value;
              }
          }
          
          public static void InjectEvade()
          {
              PlayerChampionName = GameObjects.Player.ChampionName;
  
              Config.CreateMenu();
  
              Game.OnUpdate += Game_OnOnGameUpdate;
              EloBuddy.Player.OnIssueOrder += ObjAiHeroOnOnIssueOrder;
              Spellbook.OnCastSpell += Spellbook_OnCastSpell;
              SkillshotDetector.OnDetectSkillshot += OnDetectSkillshot;
              SkillshotDetector.OnDeleteMissile += SkillshotDetectorOnOnDeleteMissile;
              Drawing.OnDraw += Drawing_OnDraw;
              Events.OnDash += Events_OnDash; ;
              DetectedSkillshots.OnAdd += DetectedSkillshots_OnAdd;
  
              Collision.Init();
          }
  
          private static void Events_OnDash(object sender, Events.DashArgs e)
          {
              if (e.Unit.IsMe)
              {
                  EvadeToPoint = e.EndPos;
              }
          }
  
          private static void DetectedSkillshots_OnAdd(object sender, EventArgs e)
          {
              Evading = false;
          }
  
          private static void SkillshotDetectorOnOnDeleteMissile(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.TickCount, 
                              missile.Position.ToVector2(), 
                              missile.Position.ToVector2() + i * direction * spellData.Range, 
                              skillshot.Unit);
  
                          DetectedSkillshots.Add(skillshotToAdd);
                      }
                  }
              }
          }
  
          private static void OnDetectSkillshot(Skillshot skillshot)
          {
              var alreadyAdded = false;
  
              if (Config.Menu["Misc"]["DisableFow"] && !skillshot.Unit.IsVisible)
              {
                  return;
              }
                  
              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.Start.Distance(PlayerPosition) > (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;
                      }
  
                      if (skillshot.SpellData.SpellName == "TaricE" && (skillshot.Unit as AIHeroClient).ChampionName == "Taric")
                      {
                          var target = GameObjects.AllyHeroes.FirstOrDefault(h => h.Team == skillshot.Unit.Team && h.IsVisible && h.HasBuff("taricwleashactive"));
                          if (target != null)
                          {
                              var start = target.ServerPosition.ToVector2();
                              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.ToVector2()).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 != GameObjects.Player.Team))
                              {
                                  positions.Add(minion.ServerPosition.ToVector2());
                              }
                          }
  
                          foreach (var position in positions)
                          {
                              var v = position - skillshot.Unit.ServerPosition.ToVector2();
                              if (edge1.CrossProduct(v) > 0 && v.CrossProduct(edge2) > 0 && position.Distance(skillshot.Unit) < 800 )
                              {
                                  var start = position;
                                  var end = skillshot.Unit.ServerPosition.ToVector2().Extend(position, skillshot.Unit.Distance(position) > 200 ? 1300 : 1000);
                                  var startTime = skillshot.StartTick;
  
                                  startTime += (int)(150 + skillshot.Unit.Distance(position) / 2.5f);
  
                                  var skillshotToAdd = new Skillshot(
                                      skillshot.DetectionType, 
                                      skillshot.SpellData, 
                                      startTime,
                                      start, 
                                      end,
                                      skillshot.Unit);
  
                                  DetectedSkillshots.Add(skillshotToAdd);
                              }
                          }
  
                          return;
                      }
  
                      if (skillshot.SpellData.SpellName == "MalzaharQ")
                      {
                          var start = skillshot.End - skillshot.Direction.Perpendicular() * 400;
                          var end = skillshot.End + skillshot.Direction.Perpendicular() * 400;
  
                          var skillshotToAdd = new Skillshot(
                              skillshot.DetectionType, 
                              skillshot.SpellData, 
                              skillshot.StartTick,
                              start, 
                              end,
                              skillshot.Unit);
  
                          DetectedSkillshots.Add(skillshotToAdd);
  
                          return;
                      }
  
                      if (skillshot.SpellData.SpellName == "ZyraQ")
                      {
                          var start = skillshot.End - skillshot.Direction.Perpendicular() * 450;
                          var end = skillshot.End + skillshot.Direction.Perpendicular() * 450;
  
                          var skillshotToAdd = new Skillshot(
                              skillshot.DetectionType, 
                              skillshot.SpellData,
                              skillshot.StartTick,
                              start,
                              end,
                              skillshot.Unit);
  
                          DetectedSkillshots.Add(skillshotToAdd);
                          return;
                      }
  
  
gt:                     if (skillshot.SpellData.SpellName == "DianaArc")