Exemplo n.º 1
0
            bool CanTargetActor(Actor self, Target target, ref TargetModifiers modifiers, ref string cursor)
            {
                IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);

                if (modifiers.HasModifier(TargetModifiers.ForceMove))
                {
                    return(false);
                }

                if (ab.Info.ForceFireIgnoresActors && modifiers.HasModifier(TargetModifiers.ForceAttack))
                {
                    return(false);
                }

                // Disguised actors are revealed by the attack cursor
                // HACK: works around limitations in the targeting code that force the
                // targeting and attacking logic (which should be logically separate)
                // to use the same code
                if (target.Type == TargetType.Actor && target.Actor.EffectiveOwner != null &&
                    target.Actor.EffectiveOwner.Disguised && self.Owner.Stances[target.Actor.Owner] == Stance.Enemy)
                {
                    modifiers |= TargetModifiers.ForceAttack;
                }

                var forceAttack = modifiers.HasModifier(TargetModifiers.ForceAttack);
                var armaments   = ab.ChooseArmamentsForTarget(target, forceAttack);

                if (!armaments.Any())
                {
                    return(false);
                }

                // Use valid armament with highest range out of those that have ammo
                // If all are out of ammo, just use valid armament with highest range
                armaments = armaments.OrderByDescending(x => x.MaxRange());
                var a = armaments.FirstOrDefault(x => !x.IsTraitPaused);

                if (a == null)
                {
                    a = armaments.First();
                }

                var outOfRange = !target.IsInRange(self.CenterPosition, a.MaxRange()) ||
                                 (!forceAttack && target.Type == TargetType.FrozenActor && !ab.Info.TargetFrozenActors);

                if (outOfRange && ab.Info.OutsideRangeRequiresForceFire && !modifiers.HasModifier(TargetModifiers.ForceAttack))
                {
                    return(false);
                }

                cursor = outOfRange ? ab.Info.OutsideRangeCursor ?? a.Info.OutsideRangeCursor : ab.Info.Cursor ?? a.Info.Cursor;

                if (!forceAttack)
                {
                    return(true);
                }

                OrderID = ab.forceAttackOrderName;
                return(true);
            }
Exemplo n.º 2
0
            bool CanTargetActor(Actor self, Target target, ref TargetModifiers modifiers, ref string cursor)
            {
                IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);

                if (modifiers.HasModifier(TargetModifiers.ForceMove))
                {
                    return(false);
                }

                // Disguised actors are revealed by the attack cursor
                // HACK: works around limitations in the targeting code that force the
                // targeting and attacking logic (which should be logically separate)
                // to use the same code
                if (target.Type == TargetType.Actor && target.Actor.EffectiveOwner != null &&
                    target.Actor.EffectiveOwner.Disguised && self.Owner.Stances[target.Actor.Owner] == Stance.Enemy)
                {
                    modifiers |= TargetModifiers.ForceAttack;
                }

                var forceAttack = modifiers.HasModifier(TargetModifiers.ForceAttack);
                var a           = ab.ChooseArmamentsForTarget(target, forceAttack).FirstOrDefault();

                if (a == null)
                {
                    return(false);
                }

                cursor = !target.IsInRange(self.CenterPosition, a.MaxRange())
                                        ? ab.Info.OutsideRangeCursor ?? a.Info.OutsideRangeCursor
                                        : ab.Info.Cursor ?? a.Info.Cursor;

                if (!forceAttack)
                {
                    return(true);
                }

                OrderID = ab.forceAttackOrderName;
                return(true);
            }
Exemplo n.º 3
0
        Actor ChooseTarget(Actor self, WDist range, bool allowMove)
        {
            var inRange = self.World.FindActorsInCircle(self.CenterPosition, range)
                          .Where(a => !a.Info.HasTraitInfo <AutoTargetIgnoreInfo>());

            // 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)
            var actorByArmament = inRange

                                  // 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
                                  .Select(a =>
            {
                var target = Target.FromActor(a);
                return(new KeyValuePair <Armament, Actor>(
                           attack.ChooseArmamentsForTarget(target, false)
                           .FirstOrDefault(arm => allowMove ||
                                           (target.IsInRange(self.CenterPosition, arm.MaxRange()) &&
                                            !target.IsInRange(self.CenterPosition, arm.Weapon.MinRange))), a));
            })

                                  .Where(kv => kv.Key != null && (self.Owner.HasFogVisibility || self.Owner.CanViewActor(kv.Value)))
                                  .GroupBy(kv => kv.Key, kv => kv.Value)
                                  .ToDictionary(kv => kv.Key, kv => kv.ClosestTo(self));

            foreach (var arm in attack.Armaments)
            {
                Actor actor;
                if (actorByArmament.TryGetValue(arm, out actor))
                {
                    return(actor);
                }
            }

            return(null);
        }
Exemplo n.º 4
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);
        }
Exemplo n.º 5
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, 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);
        }
Exemplo n.º 6
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);
        }