context: using System;
  using System.Collections.Generic;
  using System.Linq;
  using LeagueSharp;
  using LeagueSharp.Common;
  using SharpDX;
  namespace Kalista
  {
  public class ActiveModes
  {
  private static Obj_AI_Hero player = ObjectManager.Player;
  private static Spell Q
  {
  get { return SpellManager.Q; }
  }
  private static Spell W
  {
  get { return SpellManager.W; }
  }
  private static Spell E
  {
  get { return SpellManager.E; }
  }
  private static Spell R
  {
  get { return SpellManager.R; }
  }
  public static int? wallJumpInitTime;
  public static Vector3? wallJumpTarget;
  public static bool wallJumpPossible = false;
  public static Vector3? fleeTargetPosition;
  private class Mode
  {
  public const string COMBO = "combo";
  public const string HARASS = "harass";
  public const string WAVE = "wave";
  public const string JUNGLE = "jungle";
  public const string FLEE = "flee";
  }
  public static void OnPermaActive()
  {
  var debug = TargetSelector.GetTarget(float.MaxValue, TargetSelector.DamageType.Physical);
  if (debug != null)
  {
  var buff = debug.Buffs.Find(b => b.DisplayName == "KalistaCoopStrikeProtect" && b.Caster.IsMe);
  //Game.PrintChat("Waiting time: " + (buff != null ? buff.EndTime - Game.Time : 0));
  // Game.PrintChat(string.Join(" | ", debug.Buffs.FindAll(b => b.Caster.IsMe).Select(b => b.DisplayName)));
  }
  // Clear the forced target
  Config.Menu.Orbwalker.ForceTarget(null);
  if (E.IsReady())
  {
  #region Killsteal
  if (Config.BoolLinks["miscKillstealE"].Value &&
  HeroManager.Enemies.Any(h => h.IsValidTarget(E.Range) && h.IsRendKillable()))
  {
  E.Cast();
  }
  #endregion
  #region E on big mobs
  else if (Config.BoolLinks["miscBigE"].Value &&
  ObjectManager.Get<Obj_AI_Minion>().Any(m => m.IsValidTarget(E.Range) && (m.BaseSkinName.Contains("MinionSiege") || m.BaseSkinName.Contains("Dragon") || m.BaseSkinName.Contains("Baron")) && m.IsRendKillable()))
  {
  E.Cast();
  }
  #endregion
  #region E combo (minion + champ)
  else if (Config.BoolLinks["miscAutoEchamp"].Value)
  {
  var enemy = HeroManager.Enemies.Where(o => o.HasRendBuff()).OrderBy(o => o.Distance(player, true)).FirstOrDefault();
  if (enemy != null)
  {
  if (enemy.Distance(player, true) < Math.Pow(E.Range + 200, 2))
  {
  if (ObjectManager.Get<Obj_AI_Minion>().Any(o => o.IsRendKillable() && E.IsInRange(o)))
  {
  E.Cast();
  }
  }
  }
  }
  #endregion
  }
  }
  public static void OnCombo(bool afterAttack = false, Obj_AI_Base afterAttackTarget = null)
  {
  // Item usage
  if (afterAttack && afterAttackTarget is Obj_AI_Hero && Config.BoolLinks["comboUseItems"].Value)
  {
  ItemManager.UseBotrk(afterAttackTarget as Obj_AI_Hero);
  ItemManager.UseYoumuu(afterAttackTarget);
  }
  // Validate spell usage
  if (!Q.IsEnabled(Mode.COMBO) && !E.IsEnabled(Mode.COMBO))
  return;
  var target = TargetSelector.GetTarget(Q.IsEnabledAndReady(Mode.COMBO) ? Q.Range : (E.Range * 1.2f), TargetSelector.DamageType.Physical);
  if (target != null)
  {
  // Q usage
  if (Q.IsEnabledAndReady(Mode.COMBO) && !player.IsDashing())
  Q.Cast(target);
  // E usage
  if (E.IsEnabled(Mode.COMBO) && (E.Instance.State == SpellState.Ready || E.Instance.State == SpellState.Surpressed) && target.HasRendBuff())
  {
  // Target is not in range but has E stacks on
  if (player.Distance(target, true) > Math.Pow(Orbwalking.GetRealAutoAttackRange(target), 2))
  {
  // Get minions around
  var minions = ObjectManager.Get<Obj_AI_Minion>().Where(m => m.IsValidTarget(Orbwalking.GetRealAutoAttackRange(m)));
  // Check if a minion can die with the current E stacks
  if (minions.Any(m => m.IsRendKillable()))
  {
  E.Cast(true);
  }
  else
  {
  // Check if a minion can die with one AA and E. Also, the AA minion has be be behind the player direction for a further leap
  var minion = VectorHelper.GetDashObjects(minions).Find(m => m.Health > player.GetAutoAttackDamage(m) && m.Health < player.GetAutoAttackDamage(m) + Damages.GetRendDamage(m, 1));
  if (minion != null)
  {
  Config.Menu.Orbwalker.ForceTarget(minion);
  }
  }
  }
  // Target is in range and has at least the set amount of E stacks on
  else if (E.IsInRange(target) &&
  (target.IsRendKillable() || target.GetRendBuff().Count >= Config.SliderLinks["comboNumE"].Value.Value))
  {
  // Check if the target would die from E
  if (target.IsRendKillable())
  {
  E.Cast(true);
  }
  else
  {
  // Check if target is about to leave our E range or the buff is about to run out
  if (target.ServerPosition.Distance(player.ServerPosition, true) > Math.Pow(E.Range * 0.8, 2) ||
  target.GetRendBuff().EndTime - Game.Time < 0.3)
  {
  E.Cast(true);
  }
  }
  }
  }
  }
  }
  public static void OnHarass()
  {
  if (Q.IsEnabledAndReady(Mode.HARASS))
  {
  // Mana check
  if (player.ManaPercentage() < Config.SliderLinks["harassMana"].Value.Value)
  return;
  var target = Q.GetTarget();
  if (target != null)
  Q.Cast(target);
  }
  }
  public static void OnWaveClear()
  {
  // Mana check
  if (player.ManaPercentage() < Config.SliderLinks["waveMana"].Value.Value)
  return;
  // Check spells
  if (!Q.IsEnabledAndReady(Mode.WAVE) && !E.IsEnabledAndReady(Mode.WAVE))
  return;
  // Minions around
  var minions = MinionManager.GetMinions(Q.Range, MinionTypes.All, MinionTeam.Enemy, MinionOrderTypes.MaxHealth);
  if (minions.Count == 0)
  return;
  // Q usage
  if (Q.IsEnabledAndReady(Mode.WAVE) && !player.IsDashing())
  {
  int hitNumber = Config.SliderLinks["waveNumQ"].Value.Value;
  // Validate available minions
  if (minions.Count >= hitNumber)
  {
  // Get only killable minions
  var killable = minions.Where(m => m.Health < Q.GetDamage(m));
  if (killable.Count() > 0)
  {
  // Prepare prediction input for Collision check
  var input = new PredictionInput()
  {
  From = Q.From,
  Collision = Q.Collision,
  Delay = Q.Delay,
  Radius = Q.Width,
  Range = Q.Range,
  RangeCheckFrom = Q.RangeCheckFrom,
  Speed = Q.Speed,
  Type = Q.Type,
  CollisionObjects = new[] { CollisionableObjects.Heroes, CollisionableObjects.Minions, CollisionableObjects.YasuoWall }
  };
  // Helpers
  var currentHitNumber = 0;
  var castPosition = Vector3.Zero;
  // Validate the collision
  foreach (var target in killable)
  {
  // Update unit in the input
  input.Unit = target;
  // Get colliding objects
  var colliding = LeagueSharp.Common.Collision.GetCollision(new List<Vector3>() { player.ServerPosition.Extend(Prediction.GetPrediction(input).UnitPosition, Q.Range) }, input)
  .MakeUnique()
  .OrderBy(e => e.Distance(player, true))
  .ToList();
  // Validate collision
  if (colliding.Count >= hitNumber && !colliding.Contains(player))
  {
  // Calculate hit number
  int i = 0;
  foreach (var collide in colliding)
  {
  // Break loop here since we can't kill the target
  if (Q.GetDamage(collide) < collide.Health)
  {
  if (currentHitNumber < i && i >= hitNumber)
  {
  currentHitNumber = i;
  castPosition = Q.GetPrediction(collide).CastPosition;
  }
  break;
  }
  // Increase hit count
  i++;
  }
  }
  }
  // Check if we have a valid target with enough targets being killed
  if (castPosition != Vector3.Zero)
  {
  if (Q.Cast(castPosition))
  return;
  }
  }
  }
  }
  // General E usage
  if (E.IsEnabledAndReady(Mode.WAVE))
  {
  
gt: int hitNumber = Config.SliderLinks["waveNumE"].Value.Value;