diff --git a/OpenRA.Game/Traits/Activities/Move.cs b/OpenRA.Game/Traits/Activities/Move.cs index 9d2fe99d26..0e66bd3c20 100755 --- a/OpenRA.Game/Traits/Activities/Move.cs +++ b/OpenRA.Game/Traits/Activities/Move.cs @@ -70,6 +70,16 @@ namespace OpenRA.Traits.Activities this.nearEnough = range; } + public Move(Target target, int range) + : this() + { + this.getPath = self => self.World.PathFinder.FindUnitPathToRange( + self.Location, Util.CellContaining(target.CenterLocation), + range, self); + this.destination = null; + this.nearEnough = range; + } + public Move(Func> getPath) : this() { diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index 4832981243..52ba39f694 100644 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -165,6 +165,9 @@ namespace OpenRA.Traits public static Target FromActor(Actor a) { return new Target { actor = a, valid = true }; } public static Target FromPos(float2 p) { return new Target { pos = p, valid = true }; } + public static Target FromOrder(Order o) { return o.TargetActor != null ? Target.FromActor(o.TargetActor) : Target.FromPos(o.TargetLocation); } + + public static readonly Target None = new Target(); public bool IsValid { get { return valid && (actor == null || actor.IsInWorld); } } public float2 CenterLocation { get { return actor != null ? actor.CenterLocation : pos; } } diff --git a/OpenRA.Mods.RA/Activities/Attack.cs b/OpenRA.Mods.RA/Activities/Attack.cs index 7ea3d9e195..0bf4f98800 100755 --- a/OpenRA.Mods.RA/Activities/Attack.cs +++ b/OpenRA.Mods.RA/Activities/Attack.cs @@ -57,9 +57,6 @@ namespace OpenRA.Mods.RA.Activities return this; } - public void Cancel(Actor self) - { - Target = new Target(); - } + public void Cancel(Actor self) { Target = Target.None; } } } diff --git a/OpenRA.Mods.RA/Activities/FlyAttack.cs b/OpenRA.Mods.RA/Activities/FlyAttack.cs index a3322ad65c..dd618714aa 100644 --- a/OpenRA.Mods.RA/Activities/FlyAttack.cs +++ b/OpenRA.Mods.RA/Activities/FlyAttack.cs @@ -15,13 +15,13 @@ namespace OpenRA.Mods.RA.Activities public class FlyAttack : IActivity { public IActivity NextActivity { get; set; } - Actor Target; + Target Target; - public FlyAttack(Actor target) { Target = target; } + public FlyAttack(Target target) { Target = target; } public IActivity Tick(Actor self) { - if (Target == null || Target.IsDead) + if (!Target.IsValid) return NextActivity; var limitedAmmo = self.traits.GetOrDefault(); @@ -34,7 +34,7 @@ namespace OpenRA.Mods.RA.Activities this); } - public void Cancel(Actor self) { Target = null; NextActivity = null; } + public void Cancel(Actor self) { Target = Target.None; NextActivity = null; } } public class FlyCircle : IActivity diff --git a/OpenRA.Mods.RA/Activities/Follow.cs b/OpenRA.Mods.RA/Activities/Follow.cs index 77b8819988..55b298071c 100644 --- a/OpenRA.Mods.RA/Activities/Follow.cs +++ b/OpenRA.Mods.RA/Activities/Follow.cs @@ -15,10 +15,10 @@ namespace OpenRA.Mods.RA.Activities { public class Follow : IActivity { - Actor Target; + Target Target; int Range; - public Follow(Actor target, int range) + public Follow(Target target, int range) { Target = target; Range = range; @@ -28,10 +28,10 @@ namespace OpenRA.Mods.RA.Activities public IActivity Tick( Actor self ) { - if (Target == null || Target.IsDead) + if (!Target.IsValid) return NextActivity; - var inRange = ( Target.Location - self.Location ).LengthSquared < Range * Range; + var inRange = ( Util.CellContaining( Target.CenterLocation ) - self.Location ).LengthSquared < Range * Range; if( !inRange ) return new Move( Target, Range ) { NextActivity = this }; @@ -41,7 +41,7 @@ namespace OpenRA.Mods.RA.Activities public void Cancel(Actor self) { - Target = null; + Target = Target.None; } } } diff --git a/OpenRA.Mods.RA/Activities/HeliAttack.cs b/OpenRA.Mods.RA/Activities/HeliAttack.cs index f59408eb07..e13ff1a5d9 100644 --- a/OpenRA.Mods.RA/Activities/HeliAttack.cs +++ b/OpenRA.Mods.RA/Activities/HeliAttack.cs @@ -16,14 +16,14 @@ namespace OpenRA.Mods.RA.Activities { public class HeliAttack : IActivity { - Actor target; - public HeliAttack( Actor target ) { this.target = target; } + Target target; + public HeliAttack( Target target ) { this.target = target; } public IActivity NextActivity { get; set; } public IActivity Tick(Actor self) { - if (target == null || target.IsDead) + if (!target.IsValid) return NextActivity; var limitedAmmo = self.traits.GetOrDefault(); @@ -55,6 +55,6 @@ namespace OpenRA.Mods.RA.Activities return this; } - public void Cancel(Actor self) { target = null; NextActivity = null; } + public void Cancel(Actor self) { target = Target.None; NextActivity = null; } } } diff --git a/OpenRA.Mods.RA/AttackBase.cs b/OpenRA.Mods.RA/AttackBase.cs index 262845ce68..fda23d7b88 100755 --- a/OpenRA.Mods.RA/AttackBase.cs +++ b/OpenRA.Mods.RA/AttackBase.cs @@ -203,26 +203,36 @@ namespace OpenRA.Mods.RA public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor) { - if (mi.Button == MouseButton.Left || underCursor == null || underCursor.Owner == null) return null; + if (mi.Button == MouseButton.Left) return null; if (self == underCursor) return null; + var target = underCursor == null ? Target.FromPos(Util.CenterOfCell(xy)) : Target.FromActor(underCursor); + var isHeal = self.GetPrimaryWeapon().Warheads.First().Damage < 0; var forceFire = mi.Modifiers.HasModifier(Modifiers.Ctrl); if (isHeal) { - if (underCursor.Owner == null) - return null; - if (self.Owner.Stances[ underCursor.Owner ] != Stance.Ally && !forceFire) - return null; - if (underCursor.Health >= underCursor.GetMaxHP()) - return null; // don't allow healing of fully-healed stuff! + // we can never "heal ground"; that makes no sense. + if (!target.IsActor) return null; + // unless forced, only heal allies. + if (self.Owner.Stances[underCursor.Owner] != Stance.Ally && !forceFire) return null; + // don't allow healing of fully-healed stuff! + if (underCursor.Health >= underCursor.GetMaxHP()) return null; } else - if ((self.Owner.Stances[ underCursor.Owner ] != Stance.Enemy) && !forceFire) + { + if (!target.IsActor) + { + if (!forceFire) return null; + return new Order("Attack", self, xy); + } + + if ((self.Owner.Stances[underCursor.Owner] != Stance.Enemy) && !forceFire) return null; + } - if (!Combat.HasAnyValidWeapons(self, Target.FromActor(underCursor))) return null; + if (!Combat.HasAnyValidWeapons(self, target)) return null; return new Order(isHeal ? "Heal" : "Attack", self, underCursor); } @@ -234,11 +244,11 @@ namespace OpenRA.Mods.RA self.CancelActivity(); QueueAttack(self, order); - if (self.Owner == self.World.LocalPlayer) + if (self.Owner == self.World.LocalPlayer && order.TargetActor != null) self.World.AddFrameEndTask(w => w.Add(new FlashTarget(order.TargetActor))); } else - target = new Target(); + target = Target.None; } public string CursorForOrderString(string s, Actor a, int2 location) @@ -255,8 +265,9 @@ namespace OpenRA.Mods.RA { /* todo: choose the appropriate weapon, when only one works against this target */ var weapon = self.GetPrimaryWeapon() ?? self.GetSecondaryWeapon(); - - self.QueueActivity(new Activities.Attack(Target.FromActor(order.TargetActor), + self.QueueActivity( + new Activities.Attack( + Target.FromOrder(order), Math.Max(0, (int)weapon.Range))); } } diff --git a/OpenRA.Mods.RA/AttackHeli.cs b/OpenRA.Mods.RA/AttackHeli.cs index 6fe592ec7a..f63e96a409 100644 --- a/OpenRA.Mods.RA/AttackHeli.cs +++ b/OpenRA.Mods.RA/AttackHeli.cs @@ -23,8 +23,8 @@ namespace OpenRA.Mods.RA protected override void QueueAttack(Actor self, Order order) { - target = Target.FromActor(order.TargetActor); - self.QueueActivity(new HeliAttack(order.TargetActor)); + target = Target.FromOrder(order); + self.QueueActivity(new HeliAttack(target)); } } } diff --git a/OpenRA.Mods.RA/AttackOmni.cs b/OpenRA.Mods.RA/AttackOmni.cs index 09f81f2dcd..bf6fffa11c 100644 --- a/OpenRA.Mods.RA/AttackOmni.cs +++ b/OpenRA.Mods.RA/AttackOmni.cs @@ -38,7 +38,7 @@ namespace OpenRA.Mods.RA protected override void QueueAttack(Actor self, Order order) { - target = Target.FromActor(order.TargetActor); + target = Target.FromOrder(order); } } } diff --git a/OpenRA.Mods.RA/AttackPlane.cs b/OpenRA.Mods.RA/AttackPlane.cs index 21a84fa38a..5b06dde2c9 100644 --- a/OpenRA.Mods.RA/AttackPlane.cs +++ b/OpenRA.Mods.RA/AttackPlane.cs @@ -23,8 +23,8 @@ namespace OpenRA.Mods.RA protected override void QueueAttack(Actor self, Order order) { - target = Target.FromActor(order.TargetActor); - self.QueueActivity(new FlyAttack(order.TargetActor)); + target = Target.FromOrder(order); + self.QueueActivity(new FlyAttack(target)); } } } diff --git a/OpenRA.Mods.RA/AttackTurreted.cs b/OpenRA.Mods.RA/AttackTurreted.cs index e7d9b53a77..f3726096d6 100644 --- a/OpenRA.Mods.RA/AttackTurreted.cs +++ b/OpenRA.Mods.RA/AttackTurreted.cs @@ -52,12 +52,11 @@ namespace OpenRA.Mods.RA /* todo: choose the appropriate weapon, when only one works against this target */ var weapon = order.Subject.GetPrimaryWeapon() ?? order.Subject.GetSecondaryWeapon(); - if (self.traits.Contains()) - self.QueueActivity( new Follow( order.TargetActor, - Math.Max( 0, (int)weapon.Range - RangeTolerance ) ) ); + target = Target.FromOrder(order); - target = Target.FromActor(order.TargetActor); - + if (self.traits.Contains()) + self.QueueActivity( new Follow( target, + Math.Max( 0, (int)weapon.Range - RangeTolerance ) ) ); } bool buildComplete = false; diff --git a/OpenRA.Mods.RA/Combat.cs b/OpenRA.Mods.RA/Combat.cs index 10ed1ef7a8..3833f5edcd 100755 --- a/OpenRA.Mods.RA/Combat.cs +++ b/OpenRA.Mods.RA/Combat.cs @@ -162,7 +162,8 @@ namespace OpenRA.Mods.RA public static bool WeaponValidForTarget(WeaponInfo weapon, Target target) { // todo: fix this properly. - if (!target.IsValid || !target.IsActor) return false; + if (!target.IsValid) return false; + if (!target.IsActor) return weapon.ValidTargets.Contains("Ground"); // hack! var ownedInfo = target.Actor.Info.Traits.GetOrDefault();