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 (target.Type == TargetT.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); } armaments = armaments.OrderByDescending(x => x.MaxRange()); var a = armaments.FirstOrDefault(x => !x.IsTraitPaused); if (a == null) { a = armaments.First(); } 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); }
/// <summary> /// 选择攻击目标 /// </summary> /// <param name="self"></param> /// <param name="ab"></param> /// <param name="attackStances"></param> /// <param name="scanRange"></param> /// <param name="allowMove"></param> /// <returns></returns> 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 armaments 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 == EW.Traits.Stance.Enemy && !actor.AppearsHostileTo(self)) { continue; } 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); }