diff --git a/OpenRA.Mods.RA/AttackBase.cs b/OpenRA.Mods.RA/AttackBase.cs index 7d4825a670..71fd41e5ef 100644 --- a/OpenRA.Mods.RA/AttackBase.cs +++ b/OpenRA.Mods.RA/AttackBase.cs @@ -50,9 +50,6 @@ namespace OpenRA.Mods.RA public abstract class AttackBase : IIssueOrder, IResolveOrder, ITick, IExplodeModifier, IOrderVoice, ISync { - [Sync] - int nextScanTime = 0; - public bool IsAttacking { get; internal set; } public List Weapons = new List(); @@ -99,8 +96,6 @@ namespace OpenRA.Mods.RA public virtual void Tick(Actor self) { - --nextScanTime; - foreach (var w in Weapons) w.Tick(); @@ -190,45 +185,6 @@ namespace OpenRA.Mods.RA self.QueueActivity(queued, GetAttackActivity(self, target, allowMove)); } - public void ScanAndAttack(Actor self, bool allowMovement, bool holdStill) - { - var targetActor = ScanForTarget(self, null); - if (targetActor != null) - AttackTarget(Target.FromActor(targetActor), false, allowMovement && !holdStill); - } - - public Actor ScanForTarget(Actor self, Actor currentTarget) - { - var range = GetMaximumRange(); - - if (self.IsIdle || currentTarget == null || !Combat.IsInRange(self.CenterLocation, range, currentTarget)) - if(nextScanTime <= 0) - return ChooseTarget(self, range); - - return currentTarget; - } - - public void ScanAndAttack(Actor self, bool allowMovement) - { - ScanAndAttack(self, allowMovement, false); - } - - Actor ChooseTarget(Actor self, float range) - { - var info = self.Info.Traits.Get(); - nextScanTime = (int)(25 * (info.ScanTimeAverage + - (self.World.SharedRandom.NextDouble() * 2 - 1) * info.ScanTimeSpread)); - - var inRange = self.World.FindUnitsInCircle(self.CenterLocation, Game.CellSize * range); - - return inRange - .Where(a => a.Owner != null && a.AppearsHostileTo(self)) - .Where(a => !a.HasTrait()) - .Where(a => HasAnyValidWeapons(Target.FromActor(a))) - .OrderBy(a => (a.CenterLocation - self.CenterLocation).LengthSquared) - .FirstOrDefault(); - } - class AttackOrderTargeter : IOrderTargeter { readonly bool isHeal; diff --git a/OpenRA.Mods.RA/AttackMove.cs b/OpenRA.Mods.RA/AttackMove.cs index 0b9a92779c..b65a9501f7 100644 --- a/OpenRA.Mods.RA/AttackMove.cs +++ b/OpenRA.Mods.RA/AttackMove.cs @@ -80,7 +80,7 @@ namespace OpenRA.Mods.RA public override IActivity Tick( Actor self ) { - self.Trait().ScanAndAttack(self, true); + self.Trait().ScanAndAttack(self, true, false); if( inner == null ) return NextActivity; diff --git a/OpenRA.Mods.RA/AutoTarget.cs b/OpenRA.Mods.RA/AutoTarget.cs index d4d68a2c08..b35d40cdd1 100644 --- a/OpenRA.Mods.RA/AutoTarget.cs +++ b/OpenRA.Mods.RA/AutoTarget.cs @@ -11,16 +11,32 @@ using OpenRA.Traits; using OpenRA.Traits.Activities; using System.Drawing; +using System.Linq; namespace OpenRA.Mods.RA { - class AutoTargetInfo : TraitInfo, ITraitPrerequisite + public class AutoTargetInfo : ITraitInfo, ITraitPrerequisite { public readonly bool AllowMovement = true; + public readonly int ScanRadius = -1; + + public object Create(ActorInitializer init) { return new AutoTarget(init.self, this); } } - class AutoTarget : INotifyIdle, INotifyDamage + public class AutoTarget : INotifyIdle, INotifyDamage, ITick { + readonly AutoTargetInfo Info; + readonly AttackBase attack; + + [Sync] + int nextScanTime = 0; + + public AutoTarget(Actor self, AutoTargetInfo info) + { + Info = info; + attack = self.Trait(); + } + public void Damaged(Actor self, AttackInfo e) { if (!self.IsIdle) return; @@ -35,21 +51,59 @@ namespace OpenRA.Mods.RA if (e.Damage < 0) return; // don't retaliate against healers - self.Trait().AttackTarget(Target.FromActor(e.Attacker), false, self.Info.Traits.Get().AllowMovement); + attack.AttackTarget(Target.FromActor(e.Attacker), false, Info.AllowMovement); } public void TickIdle(Actor self) { - var attack = self.Trait(); - var target = attack.ScanForTarget(self, null); + var target = ScanForTarget(self, null); if (target != null) { self.SetTargetLine(Target.FromActor(target), Color.Red, false); self.QueueActivity(attack.GetAttackActivity(self, Target.FromActor(target), - self.Info.Traits.Get().AllowMovement)); + Info.AllowMovement)); } } + + public void Tick(Actor self) + { + --nextScanTime; + } + + public Actor ScanForTarget(Actor self, Actor currentTarget) + { + var range = Info.ScanRadius > 0 ? Info.ScanRadius : attack.GetMaximumRange(); + + if (self.IsIdle || currentTarget == null || !Combat.IsInRange(self.CenterLocation, range, currentTarget)) + if(nextScanTime <= 0) + return ChooseTarget(self, range); + + return currentTarget; + } + + public void ScanAndAttack(Actor self, bool allowMovement, bool holdStill) + { + var targetActor = ScanForTarget(self, null); + if (targetActor != null) + attack.AttackTarget(Target.FromActor(targetActor), false, allowMovement && !holdStill); + } + + Actor ChooseTarget(Actor self, float range) + { + var info = self.Info.Traits.Get(); + nextScanTime = (int)(25 * (info.ScanTimeAverage + + (self.World.SharedRandom.NextDouble() * 2 - 1) * info.ScanTimeSpread)); + + var inRange = self.World.FindUnitsInCircle(self.CenterLocation, Game.CellSize * range); + + return inRange + .Where(a => a.Owner != null && a.AppearsHostileTo(self)) + .Where(a => !a.HasTrait()) + .Where(a => attack.HasAnyValidWeapons(Target.FromActor(a))) + .OrderBy(a => (a.CenterLocation - self.CenterLocation).LengthSquared) + .FirstOrDefault(); + } } class AutoTargetIgnoreInfo : TraitInfo { } diff --git a/mods/cnc/rules/civilian.yaml b/mods/cnc/rules/civilian.yaml index 534f5c9966..44b597c85f 100644 --- a/mods/cnc/rules/civilian.yaml +++ b/mods/cnc/rules/civilian.yaml @@ -270,6 +270,7 @@ VICE: TargetableUnit: TargetTypes: Ground AutoTarget: + ScanRadius: 4 AttackMove: HiddenUnderFog: GainsExperience: