From f8e6245903ac271c8b7bdfbf378feeb3334d5416 Mon Sep 17 00:00:00 2001 From: Bob Date: Sun, 14 Nov 2010 15:48:02 +1300 Subject: [PATCH] make order queuing work for buildings and turreted units, too --- OpenRA.Game/Traits/TraitsInterfaces.cs | 2 +- OpenRA.Mods.RA/Activities/Attack.cs | 1 - OpenRA.Mods.RA/Air/AttackPlane.cs | 4 +- OpenRA.Mods.RA/Air/FlyAttack.cs | 1 - OpenRA.Mods.RA/Air/HeliAttack.cs | 1 - OpenRA.Mods.RA/AttackBase.cs | 85 +++++++++------------- OpenRA.Mods.RA/AttackFrontal.cs | 4 +- OpenRA.Mods.RA/AttackLeap.cs | 3 +- OpenRA.Mods.RA/AttackOmni.cs | 13 ++-- OpenRA.Mods.RA/AttackTesla.cs | 8 +- OpenRA.Mods.RA/AttackTurreted.cs | 20 ++--- OpenRA.Mods.RA/AutoHeal.cs | 93 ++++++++++++++---------- OpenRA.Mods.RA/AutoTarget.cs | 2 +- OpenRA.Mods.RA/DefaultShellmapScript.cs | 6 +- OpenRA.Mods.RA/UnitStances/UnitStance.cs | 12 +-- OpenRA.Mods.RA/Weapon.cs | 2 +- 16 files changed, 128 insertions(+), 129 deletions(-) diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index b04843ef2d..e58bcede5b 100755 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -218,7 +218,7 @@ namespace OpenRA.Traits float2 pos; bool valid; - public static Target FromActor(Actor a) { return new Target { actor = a, valid = true }; } + public static Target FromActor(Actor a) { return new Target { actor = a, valid = (a != null) }; } public static Target FromPos(float2 p) { return new Target { pos = p, valid = true }; } public static Target FromCell(int2 c) { return new Target { pos = Util.CenterOfCell(c), valid = true }; } public static Target FromOrder(Order o) diff --git a/OpenRA.Mods.RA/Activities/Attack.cs b/OpenRA.Mods.RA/Activities/Attack.cs index d538d4a7d2..25678ac18f 100755 --- a/OpenRA.Mods.RA/Activities/Attack.cs +++ b/OpenRA.Mods.RA/Activities/Attack.cs @@ -61,7 +61,6 @@ namespace OpenRA.Mods.RA.Activities if (facing.Facing != desiredFacing) return Util.SequenceActivities( new Turn( desiredFacing ), this ); - attack.target = Target; attack.DoAttack(self, Target); return this; } diff --git a/OpenRA.Mods.RA/Air/AttackPlane.cs b/OpenRA.Mods.RA/Air/AttackPlane.cs index 620c06b3eb..ee8500156d 100755 --- a/OpenRA.Mods.RA/Air/AttackPlane.cs +++ b/OpenRA.Mods.RA/Air/AttackPlane.cs @@ -27,10 +27,10 @@ namespace OpenRA.Mods.RA.Air return new FlyAttack( newTarget ); } - protected override bool CanAttack(Actor self) + protected override bool CanAttack(Actor self, Target target) { // dont fire while landed - return base.CanAttack(self) + return base.CanAttack(self, target) && self.Trait().Altitude > 0; } } diff --git a/OpenRA.Mods.RA/Air/FlyAttack.cs b/OpenRA.Mods.RA/Air/FlyAttack.cs index 0971e71b6d..8938e67a10 100755 --- a/OpenRA.Mods.RA/Air/FlyAttack.cs +++ b/OpenRA.Mods.RA/Air/FlyAttack.cs @@ -28,7 +28,6 @@ namespace OpenRA.Mods.RA.Air Cancel( self ); var attack = self.Trait(); - attack.target = Target; attack.DoAttack( self, Target ); if( inner == null ) diff --git a/OpenRA.Mods.RA/Air/HeliAttack.cs b/OpenRA.Mods.RA/Air/HeliAttack.cs index 25cb166a3a..db1c84f5c7 100755 --- a/OpenRA.Mods.RA/Air/HeliAttack.cs +++ b/OpenRA.Mods.RA/Air/HeliAttack.cs @@ -46,7 +46,6 @@ namespace OpenRA.Mods.RA.Air if( !float2.WithinEpsilon( float2.Zero, dist, range * Game.CellSize ) ) aircraft.TickMove( 1024 * aircraft.MovementSpeed, desiredFacing ); - attack.target = target; attack.DoAttack( self, target ); return this; diff --git a/OpenRA.Mods.RA/AttackBase.cs b/OpenRA.Mods.RA/AttackBase.cs index 1e8e069dcf..32a5c581b8 100644 --- a/OpenRA.Mods.RA/AttackBase.cs +++ b/OpenRA.Mods.RA/AttackBase.cs @@ -48,7 +48,6 @@ namespace OpenRA.Mods.RA int nextScanTime = 0; public bool IsAttacking { get; internal set; } - public Target target; public List Weapons = new List(); public List Turrets = new List(); @@ -73,7 +72,7 @@ namespace OpenRA.Mods.RA info.SecondaryOffset != null ? Turrets[1] : Turrets[0], info.SecondaryLocalOffset)); } - protected virtual bool CanAttack(Actor self) + protected virtual bool CanAttack(Actor self, Target target) { if (!target.IsValid) return false; if (Weapons.All(w => w.IsReloading)) return false; @@ -113,7 +112,7 @@ namespace OpenRA.Mods.RA public void DoAttack(Actor self, Target target) { - if( !CanAttack( self ) ) return; + if( !CanAttack( self, target ) ) return; var move = self.TraitOrDefault(); var facing = self.TraitOrDefault(); @@ -121,7 +120,7 @@ namespace OpenRA.Mods.RA w.CheckFire(self, this, move, facing, target); } - public virtual int FireDelay( Actor self, AttackBaseInfo info ) + public virtual int FireDelay( Actor self, Target target, AttackBaseInfo info ) { return info.FireDelay; } @@ -147,31 +146,18 @@ namespace OpenRA.Mods.RA public void ResolveOrder(Actor self, Order order) { - if (order.OrderString == "Attack" || order.OrderString == "AttackHold") + if (order.OrderString == "Attack") + AttackTarget( Target.FromOrder( order ), order.Queued, true ); + + else if(order.OrderString == "AttackHold") + AttackTarget( Target.FromOrder( order ), order.Queued, false ); + + else { - bool allowMove = order.OrderString == "Attack"; - self.QueueActivity(order.Queued, GetAttackActivity(self, Target.FromOrder(order), allowMove)); - - if (self.Owner == self.World.LocalPlayer) - self.World.AddFrameEndTask(w => - { - if (self.Destroyed) return; - if (order.TargetActor != null) - w.Add(new FlashTarget(order.TargetActor)); - - var line = self.TraitOrDefault(); - if (line != null) - if (order.TargetActor != null) line.SetTarget(self, Target.FromOrder(order), Color.Red); - else line.SetTarget(self, Target.FromOrder(order), Color.Red); - }); - return; - } // else not an attack order - - target = Target.None; - - /* hack */ - if (self.HasTrait() && self.Info.Traits.Get().AlignIdleTurrets) - self.Trait().desiredFacing = null; + /* hack */ + if (self.HasTrait() && self.Info.Traits.Get().AlignIdleTurrets) + self.Trait().desiredFacing = null; + } } public string VoicePhraseForOrder(Actor self, Order order) @@ -186,31 +172,32 @@ namespace OpenRA.Mods.RA public Weapon ChooseWeaponForTarget(Target t) { return Weapons.FirstOrDefault(w => w.IsValidAgainst(self.World, t)); } - public void AttackTarget(Actor self, Actor target, bool allowMovement) + public void AttackTarget( Target target, bool queued, bool allowMove ) { - AttackTarget(self, target, allowMovement, false); - } + if( !target.IsValid ) return; + self.QueueActivity(queued, GetAttackActivity(self, target, allowMove)); - public void AttackTarget(Actor self, Actor target, bool allowMovement, bool holdStill) - { - var attack = self.Trait(); - if (target != null) - { - if (allowMovement) - attack.ResolveOrder(self, new Order((holdStill) ? "AttackHold" : "Attack", self, target, false)); - else - attack.target = Target.FromActor(target); // for turreted things on rails. - } + if (self.Owner == self.World.LocalPlayer) + self.World.AddFrameEndTask(w => + { + if (self.Destroyed) return; + if (target.IsActor) + w.Add(new FlashTarget(target.Actor)); + + var line = self.TraitOrDefault(); + if (line != null) + line.SetTarget(self, target, Color.Red); + }); } public void ScanAndAttack(Actor self, bool allowMovement, bool holdStill) { if (--nextScanTime <= 0) { - var targetActor = ScanForTarget(self); + var targetActor = ScanForTarget(self, null); if (targetActor != null) - AttackTarget(self, targetActor, allowMovement, holdStill); + AttackTarget(Target.FromActor(targetActor), false, allowMovement && !holdStill); var info = self.Info.Traits.Get(); nextScanTime = (int)(25 * (info.ScanTimeAverage + @@ -218,15 +205,14 @@ namespace OpenRA.Mods.RA } } - public Actor ScanForTarget(Actor self) + public Actor ScanForTarget(Actor self, Actor currentTarget) { - var attack = self.Trait(); - var range = attack.GetMaximumRange(); + var range = GetMaximumRange(); - if ((!attack.target.IsValid || self.IsIdle) || !Combat.IsInRange(self.CenterLocation, range, attack.target)) + if (self.IsIdle || currentTarget == null || !Combat.IsInRange(self.CenterLocation, range, currentTarget)) return ChooseTarget(self, range); - return null; + return currentTarget; } public void ScanAndAttack(Actor self, bool allowMovement) @@ -237,11 +223,10 @@ namespace OpenRA.Mods.RA Actor ChooseTarget(Actor self, float range) { var inRange = self.World.FindUnitsInCircle(self.CenterLocation, Game.CellSize * range); - var attack = self.Trait(); return inRange .Where(a => a.Owner != null && self.Owner.Stances[a.Owner] == Stance.Enemy) - .Where(a => attack.HasAnyValidWeapons(Target.FromActor(a))) + .Where(a => HasAnyValidWeapons(Target.FromActor(a))) .Where(a => !a.HasTrait() || a.Trait().IsVisible(a, self.Owner)) .OrderBy(a => (a.CenterLocation - self.CenterLocation).LengthSquared) .FirstOrDefault(); diff --git a/OpenRA.Mods.RA/AttackFrontal.cs b/OpenRA.Mods.RA/AttackFrontal.cs index 77ca57c99e..956653d0d6 100644 --- a/OpenRA.Mods.RA/AttackFrontal.cs +++ b/OpenRA.Mods.RA/AttackFrontal.cs @@ -26,9 +26,9 @@ namespace OpenRA.Mods.RA public AttackFrontal(Actor self, AttackFrontalInfo info) : base( self ) { this.info = info; } - protected override bool CanAttack( Actor self ) + protected override bool CanAttack( Actor self, Target target ) { - if( !base.CanAttack( self ) ) + if( !base.CanAttack( self, target ) ) return false; var facing = self.Trait().Facing; diff --git a/OpenRA.Mods.RA/AttackLeap.cs b/OpenRA.Mods.RA/AttackLeap.cs index 47eff0edb9..07b4ee86b6 100644 --- a/OpenRA.Mods.RA/AttackLeap.cs +++ b/OpenRA.Mods.RA/AttackLeap.cs @@ -22,6 +22,7 @@ namespace OpenRA.Mods.RA class AttackLeap : AttackBase { internal bool IsLeaping; + protected Target target; public AttackLeap(Actor self) : base(self) {} @@ -33,7 +34,7 @@ namespace OpenRA.Mods.RA if (!target.IsValid) return; if (IsLeaping) return; - var weapon = self.Trait().Weapons[0].Info; + var weapon = Weapons[0].Info; if( !Combat.IsInRange( self.CenterLocation, weapon.Range, target ) ) return; self.CancelActivity(); diff --git a/OpenRA.Mods.RA/AttackOmni.cs b/OpenRA.Mods.RA/AttackOmni.cs index 224d7b2464..517de83a36 100644 --- a/OpenRA.Mods.RA/AttackOmni.cs +++ b/OpenRA.Mods.RA/AttackOmni.cs @@ -22,14 +22,15 @@ namespace OpenRA.Mods.RA class AttackOmni : AttackBase, INotifyBuildComplete { bool buildComplete = false; + protected Target target; public void BuildingComplete(Actor self) { buildComplete = true; } public AttackOmni(Actor self) : base(self) { } - protected override bool CanAttack( Actor self ) + protected override bool CanAttack( Actor self, Target target ) { var isBuilding = ( self.HasTrait() && !buildComplete ); - return base.CanAttack( self ) && !isBuilding; + return base.CanAttack( self, target ) && !isBuilding; } public override void Tick(Actor self) @@ -50,9 +51,11 @@ namespace OpenRA.Mods.RA public override IActivity Tick( Actor self ) { - if( !IsCanceled ) - self.Trait().target = target; - return NextActivity; + if( IsCanceled || !target.IsValid ) + return NextActivity; + + self.Trait().target = target; + return this; } } } diff --git a/OpenRA.Mods.RA/AttackTesla.cs b/OpenRA.Mods.RA/AttackTesla.cs index f4b5d21ce6..c281f3edb4 100644 --- a/OpenRA.Mods.RA/AttackTesla.cs +++ b/OpenRA.Mods.RA/AttackTesla.cs @@ -32,9 +32,9 @@ namespace OpenRA.Mods.RA charges = self.Info.Traits.Get().MaxCharges; } - protected override bool CanAttack( Actor self ) + protected override bool CanAttack( Actor self, Target target ) { - return base.CanAttack( self ) && ( charges > 0 ); + return base.CanAttack( self, target ) && ( charges > 0 ); } public override void Tick( Actor self ) @@ -53,9 +53,9 @@ namespace OpenRA.Mods.RA Actor previousTarget; - public override int FireDelay( Actor self, AttackBaseInfo info ) + public override int FireDelay( Actor self, Target target, AttackBaseInfo info ) { - return target.Actor == previousTarget ? 3 : base.FireDelay(self, info); + return target.Actor == previousTarget ? 3 : base.FireDelay(self, target, info); } public void Attacking(Actor self) diff --git a/OpenRA.Mods.RA/AttackTurreted.cs b/OpenRA.Mods.RA/AttackTurreted.cs index 610411f575..9c161ef62d 100644 --- a/OpenRA.Mods.RA/AttackTurreted.cs +++ b/OpenRA.Mods.RA/AttackTurreted.cs @@ -24,9 +24,10 @@ namespace OpenRA.Mods.RA class AttackTurreted : AttackBase, INotifyBuildComplete { + protected Target target; public AttackTurreted(Actor self) : base(self) { } - protected override bool CanAttack( Actor self ) + protected override bool CanAttack( Actor self, Target target ) { if( self.HasTrait() && !buildComplete ) return false; @@ -37,7 +38,7 @@ namespace OpenRA.Mods.RA if( turreted.desiredFacing != turreted.turretFacing ) return false; - return base.CanAttack( self ); + return base.CanAttack( self, target ); } public override void Tick(Actor self) @@ -56,26 +57,27 @@ namespace OpenRA.Mods.RA class AttackActivity : CancelableActivity { - readonly Target newTarget; - public AttackActivity( Target newTarget ) { this.newTarget = newTarget; } + readonly Target target; + public AttackActivity( Target newTarget ) { this.target = newTarget; } public override IActivity Tick( Actor self ) { - if( IsCanceled ) return NextActivity; + if( IsCanceled || !target.IsValid ) return NextActivity; if (self.TraitsImplementing().Any(d => d.Disabled)) return this; var attack = self.Trait(); const int RangeTolerance = 1; /* how far inside our maximum range we should try to sit */ - var weapon = attack.ChooseWeaponForTarget(newTarget); + var weapon = attack.ChooseWeaponForTarget(target); if (weapon != null) { - attack.target = newTarget; + attack.target = target; if (self.HasTrait() && !self.Info.Traits.Get().OnRails) - self.QueueActivity( new Follow( newTarget, - Math.Max( 0, (int)weapon.Info.Range - RangeTolerance ) ) ); + return Util.SequenceActivities( + new Follow( target, Math.Max( 0, (int)weapon.Info.Range - RangeTolerance ) ), + this ); } return NextActivity; } diff --git a/OpenRA.Mods.RA/AutoHeal.cs b/OpenRA.Mods.RA/AutoHeal.cs index 6e805de634..953670e6c5 100644 --- a/OpenRA.Mods.RA/AutoHeal.cs +++ b/OpenRA.Mods.RA/AutoHeal.cs @@ -11,61 +11,76 @@ using System.Linq; using OpenRA.Mods.RA.Activities; using OpenRA.Traits; +using OpenRA.Traits.Activities; namespace OpenRA.Mods.RA { class AutoHealInfo : TraitInfo { } - class AutoHeal : ITick + class AutoHeal : INotifyIdle { - void AttackTarget(Actor self, Actor target) + public void Idle( Actor self ) { - var attack = self.Trait(); - if (target != null) - attack.ResolveOrder(self, new Order("Attack", self, target, false)); - else - if (attack.IsAttacking) - self.CancelActivity(); + self.QueueActivity( new IdleHealActivity() ); } - bool NeedsNewTarget(Actor self) + class IdleHealActivity : Idle { - var attack = self.Trait(); - var range = attack.GetMaximumRange(); + Actor currentTarget; - if (!attack.target.IsValid) - return true; // he's dead. - if( !Combat.IsInRange( self.CenterLocation, range, attack.target ) ) - return true; // wandered off faster than we could follow - - if (attack.target.IsActor - && attack.target.Actor.GetDamageState() == DamageState.Undamaged) - return true; // fully healed + public override IActivity Tick( Actor self ) + { + if( NextActivity != null ) + return NextActivity; - return false; - } + var attack = self.Trait(); + var range = attack.GetMaximumRange(); - public void Tick(Actor self) - { - var attack = self.Trait(); - var range = attack.GetMaximumRange(); + if (NeedsNewTarget(self)) + AttackTarget(self, ChooseTarget(self, range)); - if (NeedsNewTarget(self)) - AttackTarget(self, ChooseTarget(self, range)); - } + return this; + } - Actor ChooseTarget(Actor self, float range) - { - var inRange = self.World.FindUnitsInCircle(self.CenterLocation, Game.CellSize * range); - var attack = self.Trait(); + void AttackTarget(Actor self, Actor target) + { + var attack = self.Trait(); + if (target != null) + attack.AttackTarget(Target.FromActor( target), false, true ); + else + if (attack.IsAttacking) + self.CancelActivity(); + } - return inRange - .Where(a => a != self && self.Owner.Stances[a.Owner] == Stance.Ally) - .Where(a => a.IsInWorld && !a.IsDead()) - .Where(a => a.HasTrait() && a.GetDamageState() > DamageState.Undamaged) - .Where(a => attack.HasAnyValidWeapons(Target.FromActor(a))) - .OrderBy(a => (a.CenterLocation - self.CenterLocation).LengthSquared) - .FirstOrDefault(); + bool NeedsNewTarget(Actor self) + { + var attack = self.Trait(); + var range = attack.GetMaximumRange(); + + if (currentTarget == null || !currentTarget.IsInWorld) + return true; // he's dead. + if( !Combat.IsInRange( self.CenterLocation, range, currentTarget ) ) + return true; // wandered off faster than we could follow + + if (currentTarget.GetDamageState() == DamageState.Undamaged) + return true; // fully healed + + return false; + } + + Actor ChooseTarget(Actor self, float range) + { + var inRange = self.World.FindUnitsInCircle(self.CenterLocation, Game.CellSize * range); + var attack = self.Trait(); + + return inRange + .Where(a => a != self && self.Owner.Stances[a.Owner] == Stance.Ally) + .Where(a => a.IsInWorld && !a.IsDead()) + .Where(a => a.HasTrait() && a.GetDamageState() > DamageState.Undamaged) + .Where(a => attack.HasAnyValidWeapons(Target.FromActor(a))) + .OrderBy(a => (a.CenterLocation - self.CenterLocation).LengthSquared) + .FirstOrDefault(); + } } } } diff --git a/OpenRA.Mods.RA/AutoTarget.cs b/OpenRA.Mods.RA/AutoTarget.cs index 0818611334..b040204db6 100644 --- a/OpenRA.Mods.RA/AutoTarget.cs +++ b/OpenRA.Mods.RA/AutoTarget.cs @@ -40,7 +40,7 @@ namespace OpenRA.Mods.RA if (e.Damage < 0) return; // don't retaliate against healers - self.Trait().AttackTarget(self, e.Attacker, self.Info.Traits.Get().AllowMovement); + self.Trait().AttackTarget(Target.FromActor(e.Attacker), false, self.Info.Traits.Get().AllowMovement); } } } diff --git a/OpenRA.Mods.RA/DefaultShellmapScript.cs b/OpenRA.Mods.RA/DefaultShellmapScript.cs index ef75ca8f0e..a748563eed 100755 --- a/OpenRA.Mods.RA/DefaultShellmapScript.cs +++ b/OpenRA.Mods.RA/DefaultShellmapScript.cs @@ -58,9 +58,9 @@ namespace OpenRA.Mods.RA if (ticks == 430) { - Actors["mig1"].Trait().AttackTarget(Actors["mig1"], Actors["greeceweap"], true); - Actors["mig2"].Trait().AttackTarget(Actors["mig2"], Actors["greeceweap"], true); - Actors["mig3"].Trait().AttackTarget(Actors["mig3"], Actors["greeceweap"], true); + Actors["mig1"].Trait().AttackTarget(Target.FromActor(Actors["greeceweap"]), false, true); + Actors["mig2"].Trait().AttackTarget(Target.FromActor(Actors["greeceweap"]), false, true); + Actors["mig3"].Trait().AttackTarget(Target.FromActor(Actors["greeceweap"]), false, true); } ticks++; diff --git a/OpenRA.Mods.RA/UnitStances/UnitStance.cs b/OpenRA.Mods.RA/UnitStances/UnitStance.cs index a58367c273..a37342a078 100644 --- a/OpenRA.Mods.RA/UnitStances/UnitStance.cs +++ b/OpenRA.Mods.RA/UnitStances/UnitStance.cs @@ -8,7 +8,7 @@ using OpenRA.Traits; namespace OpenRA.Mods.RA { - public class UnitStanceInfo : ITraitInfo + public class UnitStanceInfo : ITraitInfo, ITraitPrerequisite { public readonly bool Default = false; public readonly int ScanDelayMin = 12; @@ -167,12 +167,8 @@ namespace OpenRA.Mods.RA public static void AttackTarget(Actor self, Actor target, bool holdStill) { - var attack = self.Trait(); - - if (attack != null && target != null) - { - attack.ResolveOrder(self, new Order((holdStill) ? "AttackHold" : "Attack", self, target, false)); - } + if (target != null) + self.Trait().AttackTarget(Target.FromActor(target), false, !holdStill); } public static void StopAttack(Actor self) @@ -199,7 +195,7 @@ namespace OpenRA.Mods.RA public static Actor ScanForTarget(Actor self) { - return self.Trait().ScanForTarget(self); + return self.Trait().ScanForTarget(self, null); } public void ResolveOrder(Actor self, Order order) diff --git a/OpenRA.Mods.RA/Weapon.cs b/OpenRA.Mods.RA/Weapon.cs index df55a0eba2..b5093d44d9 100644 --- a/OpenRA.Mods.RA/Weapon.cs +++ b/OpenRA.Mods.RA/Weapon.cs @@ -135,7 +135,7 @@ namespace OpenRA.Mods.RA .Product() }; - attack.ScheduleDelayedAction( attack.FireDelay( self, self.Info.Traits.Get() ), () => + attack.ScheduleDelayedAction( attack.FireDelay( self, target, self.Info.Traits.Get() ), () => { if (args.weapon.Projectile != null) {