From 2f1a6e88073742ac795ac997a1c4f67bc1fb2a42 Mon Sep 17 00:00:00 2001 From: reaperrr Date: Thu, 16 Jun 2016 15:22:38 +0200 Subject: [PATCH] Add maximum and minimum range vs. target checks This adresses the issue that actors would ignore the validity of weapons when deciding the attack distance versus a target. This could result in actors staying out of range of a weapon valid versus target if they carried a weapon with higher range but invalid versus target. --- .../Activities/Air/HeliAttack.cs | 4 +- .../Traits/Attack/AttackBase.cs | 48 ++++++++++++++++++- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/OpenRA.Mods.Common/Activities/Air/HeliAttack.cs b/OpenRA.Mods.Common/Activities/Air/HeliAttack.cs index c389c2f4ad..1cfc95144d 100644 --- a/OpenRA.Mods.Common/Activities/Air/HeliAttack.cs +++ b/OpenRA.Mods.Common/Activities/Air/HeliAttack.cs @@ -82,12 +82,12 @@ namespace OpenRA.Mods.Common.Activities // Fly towards the target // TODO: Fix that the helicopter won't do anything if it has multiple weapons with different ranges // and the weapon with the longest range is out of ammo - if (!target.IsInRange(self.CenterPosition, attackHeli.GetMaximumRange())) + if (!target.IsInRange(self.CenterPosition, attackHeli.GetMaximumRangeVersusTarget(target))) helicopter.SetPosition(self, helicopter.CenterPosition + helicopter.FlyStep(desiredFacing)); // Fly backwards from the target // TODO: Same problem as with MaximumRange - if (target.IsInRange(self.CenterPosition, attackHeli.GetMinimumRange())) + if (target.IsInRange(self.CenterPosition, attackHeli.GetMinimumRangeVersusTarget(target))) { // Facing 0 doesn't work with the following position change var facing = 1; diff --git a/OpenRA.Mods.Common/Traits/Attack/AttackBase.cs b/OpenRA.Mods.Common/Traits/Attack/AttackBase.cs index a50e61a309..bbceaae98c 100644 --- a/OpenRA.Mods.Common/Traits/Attack/AttackBase.cs +++ b/OpenRA.Mods.Common/Traits/Attack/AttackBase.cs @@ -230,6 +230,52 @@ namespace OpenRA.Mods.Common.Traits return max; } + public WDist GetMinimumRangeVersusTarget(Target target) + { + if (IsTraitDisabled) + return WDist.Zero; + + // PERF: Avoid LINQ. + var min = WDist.MaxValue; + foreach (var armament in Armaments) + { + if (armament.IsTraitDisabled) + continue; + + if (!armament.Weapon.IsValidAgainst(target, self.World, self)) + continue; + + var range = armament.Weapon.MinRange; + if (min > range) + min = range; + } + + return min != WDist.MaxValue ? min : WDist.Zero; + } + + public WDist GetMaximumRangeVersusTarget(Target target) + { + if (IsTraitDisabled) + return WDist.Zero; + + // PERF: Avoid LINQ. + var max = WDist.Zero; + foreach (var armament in Armaments) + { + if (armament.IsTraitDisabled) + continue; + + if (!armament.Weapon.IsValidAgainst(target, self.World, self)) + continue; + + var range = armament.MaxRange(); + if (max < range) + max = range; + } + + return max; + } + // Enumerates all armaments, that this actor possesses, that can be used against Target t public IEnumerable ChooseArmamentsForTarget(Target t, bool forceAttack) { @@ -282,7 +328,7 @@ namespace OpenRA.Mods.Common.Traits public bool IsReachableTarget(Target target, bool allowMove) { return HasAnyValidWeapons(target) - && (target.IsInRange(self.CenterPosition, GetMaximumRange()) || (allowMove && self.Info.HasTraitInfo())); + && (target.IsInRange(self.CenterPosition, GetMaximumRangeVersusTarget(target)) || (allowMove && self.Info.HasTraitInfo())); } public Stance UnforcedAttackTargetStances()