示例#1
0
 public RenderRangeCircle(Actor self)
 {
     this.self = self;
     attack    = self.Trait <AttackBase>();
 }
 public AttackOrderTargeter(AttackBase ab, int priority)
 {
     this.ab       = ab;
     OrderID       = ab.attackOrderName;
     OrderPriority = priority;
 }
 public AttackOrderTargeter(AttackBase ab, int priority, bool negativeDamage)
 {
     this.ab       = ab;
     OrderID       = ab.attackOrderName;
     OrderPriority = priority;
 }
示例#4
0
        Target ChooseTarget(Actor self, AttackBase ab, Stance attackStances, WDist scanRange, bool allowMove, bool allowTurn)
        {
            var chosenTarget         = Target.Invalid;
            var chosenTargetPriority = int.MinValue;
            int chosenTargetRange    = 0;

            var activePriorities = activeTargetPriorities.ToList();

            if (activePriorities.Count == 0)
            {
                return(chosenTarget);
            }

            var targetsInRange = self.World.FindActorsInCircle(self.CenterPosition, scanRange)
                                 .Select(Target.FromActor)
                                 .Concat(self.Owner.FrozenActorLayer.FrozenActorsInCircle(self.World, self.CenterPosition, scanRange)
                                         .Select(Target.FromFrozenActor));

            foreach (var target in targetsInRange)
            {
                BitSet <TargetableType> targetTypes;
                Player owner;
                if (target.Type == TargetType.Actor)
                {
                    // PERF: Most units can only attack enemy units. If this is the case but the target is not an enemy, we
                    // can bail early and avoid the more expensive targeting checks and armament selection. For groups of
                    // allied units, this helps significantly reduce the cost of auto target scans. This is important as
                    // these groups will continuously rescan their allies until an enemy finally comes into range.
                    if (attackStances == OpenRA.Traits.Stance.Enemy && !target.Actor.AppearsHostileTo(self))
                    {
                        continue;
                    }

                    // Check whether we can auto-target this actor
                    targetTypes = target.Actor.GetEnabledTargetTypes();

                    if (PreventsAutoTarget(self, target.Actor) || !target.Actor.CanBeViewedByPlayer(self.Owner))
                    {
                        continue;
                    }

                    owner = target.Actor.Owner;
                }
                else if (target.Type == TargetType.FrozenActor)
                {
                    if (attackStances == OpenRA.Traits.Stance.Enemy && self.Owner.Stances[target.FrozenActor.Owner] == OpenRA.Traits.Stance.Ally)
                    {
                        continue;
                    }

                    targetTypes = target.FrozenActor.TargetTypes;
                    owner       = target.FrozenActor.Owner;
                }
                else
                {
                    continue;
                }

                var validPriorities = activePriorities.Where(ati =>
                {
                    // Already have a higher priority target
                    if (ati.Priority < chosenTargetPriority)
                    {
                        return(false);
                    }

                    // Incompatible stances
                    if (!ati.ValidStances.HasStance(self.Owner.Stances[owner]))
                    {
                        return(false);
                    }

                    // Incompatible target types
                    if (!ati.ValidTargets.Overlaps(targetTypes) || ati.InvalidTargets.Overlaps(targetTypes))
                    {
                        return(false);
                    }

                    return(true);
                }).ToList();

                if (validPriorities.Count == 0)
                {
                    continue;
                }

                // Make sure that we can actually fire on the actor
                var armaments = ab.ChooseArmamentsForTarget(target, false);
                if (!allowMove)
                {
                    armaments = armaments.Where(arm =>
                                                target.IsInRange(self.CenterPosition, arm.MaxRange()) &&
                                                !target.IsInRange(self.CenterPosition, arm.Weapon.MinRange));
                }

                if (!armaments.Any())
                {
                    continue;
                }

                if (!allowTurn && !ab.TargetInFiringArc(self, target, 4 * ab.Info.FacingTolerance))
                {
                    continue;
                }

                // Evaluate whether we want to target this actor
                var targetRange = (target.CenterPosition - self.CenterPosition).Length;
                foreach (var ati in validPriorities)
                {
                    if (chosenTarget.Type == TargetType.Invalid || chosenTargetPriority < ati.Priority ||
                        (chosenTargetPriority == ati.Priority && targetRange < chosenTargetRange))
                    {
                        chosenTarget         = target;
                        chosenTargetPriority = ati.Priority;
                        chosenTargetRange    = targetRange;
                    }
                }
            }

            return(chosenTarget);
        }
示例#5
0
        Actor ChooseTarget(Actor self, AttackBase ab, Stance attackStances, WDist scanRange, bool allowMove)
        {
            Actor chosenTarget         = null;
            var   chosenTargetPriority = int.MinValue;
            int   chosenTargetRange    = 0;

            var activePriorities = targetPriorities.Where(Exts.IsTraitEnabled)
                                   .Select(at => at.Info)
                                   .OrderByDescending(ati => ati.Priority)
                                   .ToList();

            if (!activePriorities.Any())
            {
                return(null);
            }

            var actorsInRange = self.World.FindActorsInCircle(self.CenterPosition, scanRange);

            foreach (var actor in actorsInRange)
            {
                // PERF: Most units can only attack enemy units. If this is the case but the target is not an enemy, we
                // can bail early and avoid the more expensive targeting checks and armament selection. For groups of
                // allied units, this helps significantly reduce the cost of auto target scans. This is important as
                // these groups will continuously rescan their allies until an enemy finally comes into range.
                if (attackStances == OpenRA.Traits.Stance.Enemy && !actor.AppearsHostileTo(self))
                {
                    continue;
                }

                // Check whether we can auto-target this actor
                var targetTypes = actor.TraitsImplementing <ITargetable>()
                                  .Where(Exts.IsTraitEnabled).SelectMany(t => t.TargetTypes)
                                  .ToHashSet();

                var target          = Target.FromActor(actor);
                var validPriorities = activePriorities.Where(ati =>
                {
                    // Already have a higher priority target
                    if (ati.Priority < chosenTargetPriority)
                    {
                        return(false);
                    }

                    // Incompatible target types
                    if (!targetTypes.Overlaps(ati.ValidTargets) || targetTypes.Overlaps(ati.InvalidTargets))
                    {
                        return(false);
                    }

                    return(true);
                }).ToList();

                if (!validPriorities.Any() || PreventsAutoTarget(self, actor) || !actor.CanBeViewedByPlayer(self.Owner))
                {
                    continue;
                }

                // Make sure that we can actually fire on the actor
                var armaments = ab.ChooseArmamentsForTarget(target, false);
                if (!allowMove)
                {
                    armaments = armaments.Where(arm =>
                                                target.IsInRange(self.CenterPosition, arm.MaxRange()) &&
                                                !target.IsInRange(self.CenterPosition, arm.Weapon.MinRange));
                }

                if (!armaments.Any())
                {
                    continue;
                }

                // Evaluate whether we want to target this actor
                var targetRange = (target.CenterPosition - self.CenterPosition).Length;
                foreach (var ati in validPriorities)
                {
                    if (chosenTarget == null || chosenTargetPriority < ati.Priority ||
                        (chosenTargetPriority == ati.Priority && targetRange < chosenTargetRange))
                    {
                        chosenTarget         = actor;
                        chosenTargetPriority = ati.Priority;
                        chosenTargetRange    = targetRange;
                    }
                }
            }

            return(chosenTarget);
        }
示例#6
0
        Actor ChooseTarget(Actor self, AttackBase ab, Stance attackStances, WDist range, bool allowMove)
        {
            var actorsByArmament = new Dictionary <Armament, List <Actor> >();
            var actorsInRange    = self.World.FindActorsInCircle(self.CenterPosition, range);

            foreach (var actor in actorsInRange)
            {
                // PERF: Most units can only attack enemy units. If this is the case but the target is not an enemy, we
                // can bail early and avoid the more expensive targeting checks and armament selection. For groups of
                // allied units, this helps significantly reduce the cost of auto target scans. This is important as
                // these groups will continuously rescan their allies until an enemy finally comes into range.
                if (attackStances == OpenRA.Traits.Stance.Enemy && !actor.AppearsHostileTo(self))
                {
                    continue;
                }

                if (PreventsAutoTarget(self, actor) || !self.Owner.CanTargetActor(actor))
                {
                    continue;
                }

                // Select only the first compatible armament for each actor: if this actor is selected
                // it will be thanks to the first armament anyways, since that is the first selection
                // criterion
                var target    = Target.FromActor(actor);
                var armaments = ab.ChooseArmamentsForTarget(target, false);
                if (!allowMove)
                {
                    armaments = armaments.Where(arm =>
                                                target.IsInRange(self.CenterPosition, arm.MaxRange()) &&
                                                !target.IsInRange(self.CenterPosition, arm.Weapon.MinRange));
                }

                var armament = armaments.FirstOrDefault();
                if (armament == null)
                {
                    continue;
                }

                List <Actor> actors;
                if (actorsByArmament.TryGetValue(armament, out actors))
                {
                    actors.Add(actor);
                }
                else
                {
                    actorsByArmament.Add(armament, new List <Actor> {
                        actor
                    });
                }
            }

            // Armaments are enumerated in attack.Armaments in construct order
            // When autotargeting, first choose targets according to the used armament construct order
            // And then according to distance from actor
            // This enables preferential treatment of certain armaments
            // (e.g. tesla trooper's tesla zap should have precedence over tesla charge)
            foreach (var arm in ab.Armaments)
            {
                List <Actor> actors;
                if (actorsByArmament.TryGetValue(arm, out actors))
                {
                    return(actors.ClosestTo(self));
                }
            }

            return(null);
        }