private void GetAreaOfEffectPrediction(PredictionInput input, PredictionOutput output) { var targets = new List <PredictionOutput>(); // aoe targets foreach (var target in input.AreaOfEffectTargets.Where(e => e.Handle != output.Unit.Handle)) { var targetPrediction = this.GetSimplePrediction(input.WithTarget(target)); if (this.IsInRange(input, targetPrediction.UnitPosition)) { targets.Add(targetPrediction); } } switch (input.PredictionSkillshotType) { case PredictionSkillshotType.SkillshotCircle: if (input.AreaOfEffectHitMainTarget) { // main target targets.Insert(0, output); while (targets.Count > 1) { var mecResult = MEC.GetMec(targets.Select((target) => target.UnitPosition.ToVector2()).ToList()); // add hullradius? if (mecResult.Radius != 0f && mecResult.Radius < input.Radius && this.IsInRange(input, mecResult.Center.ToVector3())) { output.CastPosition = new Vector3( targets.Count <= 2 ? (targets[0].UnitPosition.ToVector2() + targets[1].UnitPosition.ToVector2()) / 2 : mecResult.Center, output.CastPosition.Z); output.AoeTargetsHit = targets.Where((target) => output.CastPosition.IsInRange(target.UnitPosition, input.Radius)).ToList(); break; } var itemToRemove = targets.MaxOrDefault((target) => targets[0].UnitPosition.DistanceSquared(target.UnitPosition)); targets.Remove(itemToRemove); } } else { // TODO: handle the AreaOfEffectHitMainTarget=false case } break; case PredictionSkillshotType.SkillshotCone: break; case PredictionSkillshotType.SkillshotLine: break; } }
public PredictionOutput GetPrediction(PredictionInput input) { var result = this.GetSimplePrediction(input); // Handle AreaOfEffect if (input.AreaOfEffect) { result = this.GetAreaOfEffectPrediction(input, result); } // check range if (input.Range != float.MaxValue) { if (!this.IsInRange(input, result.CastPosition, false)) { result.HitChance = HitChance.OutOfRange; } else if (!this.IsInRange(input, result.UnitPosition, true)) { result.HitChance = HitChance.OutOfRange; } } // check collision if (input.CollisionTypes != CollisionTypes.None) { var scanRange = input.Owner.Distance2D(result.CastPosition); var movingObjects = new List <Unit>(); var collisionObjects = new List <CollisionObject>(); if (input.CollisionTypes.HasFlag(CollisionTypes.AllyCreeps)) { movingObjects.AddRange( EntityManager <Creep> .Entities.Where( unit => unit.IsAlly(input.Owner) && unit.IsValidTarget(float.MaxValue, false) && input.Owner.IsInRange(unit, scanRange))); } if (input.CollisionTypes.HasFlag(CollisionTypes.EnemyCreeps)) { movingObjects.AddRange( EntityManager <Creep> .Entities.Where( unit => unit.IsEnemy(input.Owner) && unit.IsValidTarget(float.MaxValue, false) && input.Owner.IsInRange(unit, scanRange))); } if (input.CollisionTypes.HasFlag(CollisionTypes.AllyHeroes)) { movingObjects.AddRange( EntityManager <Hero> .Entities.Where( unit => unit.IsAlly(input.Owner) && unit.IsValidTarget(float.MaxValue, false) && input.Owner.IsInRange(unit, scanRange) && unit != input.Owner)); } if (input.CollisionTypes.HasFlag(CollisionTypes.EnemyHeroes)) { movingObjects.AddRange( EntityManager <Hero> .Entities.Where( unit => unit.IsEnemy(input.Owner) && unit.IsValidTarget(float.MaxValue, false) && input.Owner.IsInRange(unit, scanRange) && unit != input.Target)); } // add units foreach (var unit in movingObjects) { var predictedPos = this.GetSimplePrediction(input.WithTarget(unit)); collisionObjects.Add(new CollisionObject(unit, predictedPos.UnitPosition, unit.HullRadius + 10f)); collisionObjects.Add(new CollisionObject(unit, unit.NetworkPosition, unit.HullRadius)); // optional } // add trees and buildings, use NavMeshCellFlags for less lag? if (input.CollisionTypes.HasFlag(CollisionTypes.Trees)) { foreach (var tree in EntityManager <Tree> .Entities.Where(unit => input.Owner.IsInRange(unit, scanRange))) { collisionObjects.Add(new CollisionObject(tree, tree.NetworkPosition, 75f)); } } var collisionResult = Collision.Collision.GetCollision(input.Owner.NetworkPosition.ToVector2(), result.CastPosition.ToVector2(), input.Radius, collisionObjects); if (collisionResult.Collides) { result.HitChance = HitChance.Collision; } result.CollisionResult = collisionResult; } return(result); }