/// <summary> /// Builds a list of targets which would be hit by a line attack performed by a siege cannon. /// </summary> /// <param name="instigator">The player firing the cannon.</param> /// <returns>The farthest target from the siege weapon which would be struck by the attack, for use as the target of the ability.</returns> public Unit BuildTargetList(Unit instigator) { CurrentTargetList.Clear(); Unit initialTarget = _weapon.CbtInterface.GetTarget(TargetTypes.TARGETTYPES_TARGET_ENEMY); Unit bestTarget = initialTarget; int bestDist = _weapon.GetDistanceToObject(initialTarget); CurrentTargetList.Add(initialTarget); Vector3 unitDir = new Vector3(initialTarget.WorldPosition.X - _weapon.WorldPosition.X, initialTarget.WorldPosition.Y - _weapon.WorldPosition.Y, initialTarget.WorldPosition.Z - _weapon.WorldPosition.Z); unitDir.Normalize(); Vector3 toTarget = new Vector3(); Vector3 projection = new Vector3(); foreach (Object obj in _weapon.ObjectsInRange) { Unit unit = obj as Unit; if (unit == null || unit == initialTarget || unit.Realm == instigator.Realm || !_weapon.IsObjectInFront(unit, 45) || !CombatInterface.CanAttack(instigator, unit)) { continue; } // Determine whether this unit is within 5ft on either side of the cannon's attack. // Unit vector in direction of cannon's view projection.X = unitDir.X; projection.Y = unitDir.Y; projection.Z = unitDir.Z; toTarget.X = unit.WorldPosition.X - _weapon.WorldPosition.X; toTarget.Y = unit.WorldPosition.Y - _weapon.WorldPosition.Y; toTarget.Z = unit.WorldPosition.Z - _weapon.WorldPosition.Z; // Vector projection ((a dot ^b) ^b) projection.Multiply(Vector3.DotProduct3D(toTarget, unitDir)); // Vector rejection (a - (a dot ^b) ^b) toTarget.X -= projection.X; toTarget.Y -= projection.Y; toTarget.Z -= projection.Z; if (toTarget.MagnitudeSquare < 60 * 60 && _weapon.LOSHit(unit)) // 5ft either side { CurrentTargetList.Add(unit); // Select the target furthest away as the target of the ability, for the projectile effect to look best if (!_weapon.IsWithinRadiusFeet(unit, bestDist)) { bestTarget = unit; bestDist = _weapon.GetDistanceToObject(bestTarget); } } } return(bestTarget); }