From 527675db8d1fa0b035d554d80e606e79134f221d Mon Sep 17 00:00:00 2001 From: atlimit8 Date: Sat, 27 Jun 2015 13:52:00 -0500 Subject: [PATCH 1/4] Attack activities use armaments directly through constructor --- OpenRA.Mods.Common/Activities/Attack.cs | 6 +++--- OpenRA.Mods.Common/Activities/Heal.cs | 4 ++-- OpenRA.Mods.Common/Traits/Attack/AttackFrontal.cs | 2 +- OpenRA.Mods.Common/Traits/Attack/AttackMedic.cs | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/OpenRA.Mods.Common/Activities/Attack.cs b/OpenRA.Mods.Common/Activities/Attack.cs index 9036d5fff7..d48334ffea 100644 --- a/OpenRA.Mods.Common/Activities/Attack.cs +++ b/OpenRA.Mods.Common/Activities/Attack.cs @@ -25,11 +25,11 @@ namespace OpenRA.Mods.Common.Activities readonly WDist maxRange; readonly IPositionable positionable; - public Attack(Actor self, Target target, WDist minRange, WDist maxRange, bool allowMovement) + public Attack(Actor self, Target target, Armament armament, bool allowMovement) { Target = target; - this.minRange = minRange; - this.maxRange = maxRange; + this.minRange = armament.Weapon.MinRange; + this.maxRange = armament.Weapon.Range; attack = self.Trait(); facing = self.Trait(); diff --git a/OpenRA.Mods.Common/Activities/Heal.cs b/OpenRA.Mods.Common/Activities/Heal.cs index d50b485ef8..157dea71ab 100644 --- a/OpenRA.Mods.Common/Activities/Heal.cs +++ b/OpenRA.Mods.Common/Activities/Heal.cs @@ -16,8 +16,8 @@ namespace OpenRA.Mods.Common.Activities { public class Heal : Attack { - public Heal(Actor self, Target target, WDist minRange, WDist maxRange, bool allowMovement) - : base(self, target, minRange, maxRange, allowMovement) { } + public Heal(Actor self, Target target, Armament armament, bool allowMovement) + : base(self, target, armament, allowMovement) { } protected override Activity InnerTick(Actor self, AttackBase attack) { diff --git a/OpenRA.Mods.Common/Traits/Attack/AttackFrontal.cs b/OpenRA.Mods.Common/Traits/Attack/AttackFrontal.cs index 99d7079dd9..b9ce88c635 100644 --- a/OpenRA.Mods.Common/Traits/Attack/AttackFrontal.cs +++ b/OpenRA.Mods.Common/Traits/Attack/AttackFrontal.cs @@ -52,7 +52,7 @@ namespace OpenRA.Mods.Common.Traits if (a == null) return null; - return new Activities.Attack(self, newTarget, a.Weapon.MinRange, a.Weapon.Range, allowMove); + return new Activities.Attack(self, newTarget, a, allowMove); } } } diff --git a/OpenRA.Mods.Common/Traits/Attack/AttackMedic.cs b/OpenRA.Mods.Common/Traits/Attack/AttackMedic.cs index b0c4aeef0b..89795550d1 100644 --- a/OpenRA.Mods.Common/Traits/Attack/AttackMedic.cs +++ b/OpenRA.Mods.Common/Traits/Attack/AttackMedic.cs @@ -32,7 +32,7 @@ namespace OpenRA.Mods.Common.Traits if (a == null) return null; - return new Activities.Heal(self, newTarget, a.Weapon.MinRange, a.Weapon.Range, allowMove); + return new Activities.Heal(self, newTarget, a, allowMove); } } } From a8106a999901e3a3d988f632baaee80bfe545b6a Mon Sep 17 00:00:00 2001 From: atlimit8 Date: Sat, 27 Jun 2015 13:52:00 -0500 Subject: [PATCH 2/4] Made UpgradeMultiplierTraitInfo implement ITraitInfo --- OpenRA.Mods.Common/Traits/Multipliers/DamageMultiplier.cs | 4 ++-- OpenRA.Mods.Common/Traits/Multipliers/FirepowerMultiplier.cs | 4 ++-- OpenRA.Mods.Common/Traits/Multipliers/InaccuracyMultiplier.cs | 4 ++-- OpenRA.Mods.Common/Traits/Multipliers/PowerMultiplier.cs | 4 ++-- .../Traits/Multipliers/ReloadDelayMultiplier.cs | 4 ++-- OpenRA.Mods.Common/Traits/Multipliers/SpeedMultiplier.cs | 4 ++-- .../Traits/Multipliers/UpgradableMultiplierTrait.cs | 4 +++- 7 files changed, 15 insertions(+), 13 deletions(-) diff --git a/OpenRA.Mods.Common/Traits/Multipliers/DamageMultiplier.cs b/OpenRA.Mods.Common/Traits/Multipliers/DamageMultiplier.cs index 57050bc3e0..17ec29be1d 100644 --- a/OpenRA.Mods.Common/Traits/Multipliers/DamageMultiplier.cs +++ b/OpenRA.Mods.Common/Traits/Multipliers/DamageMultiplier.cs @@ -16,9 +16,9 @@ namespace OpenRA.Mods.Common.Traits [Desc("Damage taken by this actor is multiplied based on upgrade level.", "Decrease to increase actor's apparent strength.", "Use 0 to make actor invulnerable.")] - public class DamageMultiplierInfo : UpgradeMultiplierTraitInfo, ITraitInfo + public class DamageMultiplierInfo : UpgradeMultiplierTraitInfo { - public object Create(ActorInitializer init) { return new DamageMultiplier(this, init.Self.Info.Name); } + public override object Create(ActorInitializer init) { return new DamageMultiplier(this, init.Self.Info.Name); } } public class DamageMultiplier : UpgradeMultiplierTrait, IDamageModifier diff --git a/OpenRA.Mods.Common/Traits/Multipliers/FirepowerMultiplier.cs b/OpenRA.Mods.Common/Traits/Multipliers/FirepowerMultiplier.cs index 34de5380ac..7b6cd97569 100644 --- a/OpenRA.Mods.Common/Traits/Multipliers/FirepowerMultiplier.cs +++ b/OpenRA.Mods.Common/Traits/Multipliers/FirepowerMultiplier.cs @@ -13,9 +13,9 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("The firepower of this actor is multiplied based on upgrade level if specified.")] - public class FirepowerMultiplierInfo : UpgradeMultiplierTraitInfo, ITraitInfo + public class FirepowerMultiplierInfo : UpgradeMultiplierTraitInfo { - public object Create(ActorInitializer init) { return new FirepowerMultiplier(this, init.Self.Info.Name); } + public override object Create(ActorInitializer init) { return new FirepowerMultiplier(this, init.Self.Info.Name); } } public class FirepowerMultiplier : UpgradeMultiplierTrait, IFirepowerModifier diff --git a/OpenRA.Mods.Common/Traits/Multipliers/InaccuracyMultiplier.cs b/OpenRA.Mods.Common/Traits/Multipliers/InaccuracyMultiplier.cs index 382142ef06..a879877727 100644 --- a/OpenRA.Mods.Common/Traits/Multipliers/InaccuracyMultiplier.cs +++ b/OpenRA.Mods.Common/Traits/Multipliers/InaccuracyMultiplier.cs @@ -13,9 +13,9 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("The inaccuracy of this actor is multipled based on upgrade level if specified.")] - public class InaccuracyMultiplierInfo : UpgradeMultiplierTraitInfo, ITraitInfo + public class InaccuracyMultiplierInfo : UpgradeMultiplierTraitInfo { - public object Create(ActorInitializer init) { return new InaccuracyMultiplier(this, init.Self.Info.Name); } + public override object Create(ActorInitializer init) { return new InaccuracyMultiplier(this, init.Self.Info.Name); } } public class InaccuracyMultiplier : UpgradeMultiplierTrait, IInaccuracyModifier diff --git a/OpenRA.Mods.Common/Traits/Multipliers/PowerMultiplier.cs b/OpenRA.Mods.Common/Traits/Multipliers/PowerMultiplier.cs index 2b3a5c8f75..b4312ef2ac 100644 --- a/OpenRA.Mods.Common/Traits/Multipliers/PowerMultiplier.cs +++ b/OpenRA.Mods.Common/Traits/Multipliers/PowerMultiplier.cs @@ -14,9 +14,9 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common { [Desc("The power usage/output of this actor is multiplied based on upgrade level if specified.")] - public class PowerMultiplierInfo : UpgradeMultiplierTraitInfo, ITraitInfo + public class PowerMultiplierInfo : UpgradeMultiplierTraitInfo { - public object Create(ActorInitializer init) { return new PowerMultiplier(init.Self, this); } + public override object Create(ActorInitializer init) { return new PowerMultiplier(init.Self, this); } } public class PowerMultiplier : UpgradeMultiplierTrait, IPowerModifier, INotifyOwnerChanged diff --git a/OpenRA.Mods.Common/Traits/Multipliers/ReloadDelayMultiplier.cs b/OpenRA.Mods.Common/Traits/Multipliers/ReloadDelayMultiplier.cs index f1fddd1c22..d8edcea81e 100644 --- a/OpenRA.Mods.Common/Traits/Multipliers/ReloadDelayMultiplier.cs +++ b/OpenRA.Mods.Common/Traits/Multipliers/ReloadDelayMultiplier.cs @@ -13,9 +13,9 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("The reloading time of this actor is multiplied based on upgrade level if specified.")] - public class ReloadDelayMultiplierInfo : UpgradeMultiplierTraitInfo, ITraitInfo + public class ReloadDelayMultiplierInfo : UpgradeMultiplierTraitInfo { - public object Create(ActorInitializer init) { return new ReloadDelayMultiplier(this, init.Self.Info.Name); } + public override object Create(ActorInitializer init) { return new ReloadDelayMultiplier(this, init.Self.Info.Name); } } public class ReloadDelayMultiplier : UpgradeMultiplierTrait, IReloadModifier diff --git a/OpenRA.Mods.Common/Traits/Multipliers/SpeedMultiplier.cs b/OpenRA.Mods.Common/Traits/Multipliers/SpeedMultiplier.cs index dfab9a0b68..9705406c55 100644 --- a/OpenRA.Mods.Common/Traits/Multipliers/SpeedMultiplier.cs +++ b/OpenRA.Mods.Common/Traits/Multipliers/SpeedMultiplier.cs @@ -13,9 +13,9 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("The speed of this actor is multiplied based on upgrade level if specified.")] - public class SpeedMultiplierInfo : UpgradeMultiplierTraitInfo, ITraitInfo + public class SpeedMultiplierInfo : UpgradeMultiplierTraitInfo { - public object Create(ActorInitializer init) { return new SpeedMultiplier(this, init.Self.Info.Name); } + public override object Create(ActorInitializer init) { return new SpeedMultiplier(this, init.Self.Info.Name); } } public class SpeedMultiplier : UpgradeMultiplierTrait, ISpeedModifier diff --git a/OpenRA.Mods.Common/Traits/Multipliers/UpgradableMultiplierTrait.cs b/OpenRA.Mods.Common/Traits/Multipliers/UpgradableMultiplierTrait.cs index e2bb8e47df..1789b85d66 100644 --- a/OpenRA.Mods.Common/Traits/Multipliers/UpgradableMultiplierTrait.cs +++ b/OpenRA.Mods.Common/Traits/Multipliers/UpgradableMultiplierTrait.cs @@ -15,7 +15,7 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { - public abstract class UpgradeMultiplierTraitInfo + public abstract class UpgradeMultiplierTraitInfo : ITraitInfo { [UpgradeUsedReference] [Desc("Accepted upgrade types.")] @@ -29,6 +29,8 @@ namespace OpenRA.Mods.Common.Traits "Repeat last entry to accept time extensions.", "If no upgrade types are specified, then the first/only modifier is always applied.")] public readonly int[] Modifier = { }; + + public abstract object Create(ActorInitializer init); } public abstract class UpgradeMultiplierTrait : IUpgradable, IDisabledTrait, ISync From 65c1d2f5c1715e7d627a336d016ea28fae06cd4e Mon Sep 17 00:00:00 2001 From: atlimit8 Date: Sun, 20 Sep 2015 10:23:41 -0500 Subject: [PATCH 3/4] Add IRulesetLoaded for late binding in trait info getting all rules --- OpenRA.Game/GameRules/Ruleset.cs | 5 +++++ OpenRA.Game/Traits/TraitsInterfaces.cs | 2 ++ 2 files changed, 7 insertions(+) diff --git a/OpenRA.Game/GameRules/Ruleset.cs b/OpenRA.Game/GameRules/Ruleset.cs index 84b6b720e3..19dbf28449 100644 --- a/OpenRA.Game/GameRules/Ruleset.cs +++ b/OpenRA.Game/GameRules/Ruleset.cs @@ -12,6 +12,7 @@ using System.Collections.Generic; using System.Linq; using OpenRA.GameRules; using OpenRA.Graphics; +using OpenRA.Traits; namespace OpenRA { @@ -41,6 +42,10 @@ namespace OpenRA Music = new ReadOnlyDictionary(music); TileSets = new ReadOnlyDictionary(tileSets); Sequences = new ReadOnlyDictionary(sequences); + + foreach (var a in Actors.Values) + foreach (var t in a.TraitInfos()) + t.RulesetLoaded(this, a); } public IEnumerable> InstalledMusic { get { return Music.Where(m => m.Value.Exists); } } diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index 5e0ffbdeb5..a66d204fbd 100644 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -368,4 +368,6 @@ namespace OpenRA.Traits { bool RemoveActor(Actor self, Player owner); } + + public interface IRulesetLoaded : ITraitInfo { void RulesetLoaded(Ruleset rules, ActorInfo ai); } } From 74a9dc67935037c4ad06a6e8d2a966301b377b90 Mon Sep 17 00:00:00 2001 From: atlimit8 Date: Sat, 27 Jun 2015 13:52:00 -0500 Subject: [PATCH 4/4] Added IRangeMultiplier --- OpenRA.Game/GameRules/WeaponInfo.cs | 1 + OpenRA.Game/Traits/TraitsInterfaces.cs | 2 + OpenRA.Mods.Common/Activities/Attack.cs | 5 ++- OpenRA.Mods.Common/Effects/Bullet.cs | 3 +- OpenRA.Mods.Common/OpenRA.Mods.Common.csproj | 1 + OpenRA.Mods.Common/Traits/Air/AttackBomber.cs | 6 +-- OpenRA.Mods.Common/Traits/Armament.cs | 27 ++++++++++++-- .../Traits/Attack/AttackBase.cs | 4 +- .../Traits/Attack/AttackFollow.cs | 5 ++- .../Traits/Multipliers/RangeMultiplier.cs | 37 +++++++++++++++++++ .../Traits/Render/RenderRangeCircle.cs | 21 +++++++---- OpenRA.Mods.Common/Traits/ThrowsShrapnel.cs | 3 ++ OpenRA.Mods.D2k/Traits/AttackSwallow.cs | 2 +- OpenRA.Mods.RA/Traits/Attack/AttackLeap.cs | 2 +- 14 files changed, 96 insertions(+), 23 deletions(-) create mode 100644 OpenRA.Mods.Common/Traits/Multipliers/RangeMultiplier.cs diff --git a/OpenRA.Game/GameRules/WeaponInfo.cs b/OpenRA.Game/GameRules/WeaponInfo.cs index 00838d70a8..e512c8c153 100644 --- a/OpenRA.Game/GameRules/WeaponInfo.cs +++ b/OpenRA.Game/GameRules/WeaponInfo.cs @@ -21,6 +21,7 @@ namespace OpenRA.GameRules public WeaponInfo Weapon; public int[] DamageModifiers; public int[] InaccuracyModifiers; + public int[] RangeModifiers; public int Facing; public WPos Source; public Actor SourceActor; diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index a66d204fbd..6e2278eb8b 100644 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -218,6 +218,8 @@ namespace OpenRA.Traits public interface IFirepowerModifier { int GetFirepowerModifier(); } public interface IReloadModifier { int GetReloadModifier(); } public interface IInaccuracyModifier { int GetInaccuracyModifier(); } + public interface IRangeModifier { int GetRangeModifier(); } + public interface IRangeModifierInfo : ITraitInfo { int GetRangeModifierDefault(); } public interface IPowerModifier { int GetPowerModifier(); } public interface ILoadsPalettes { void LoadPalettes(WorldRenderer wr); } public interface ILoadsPlayerPalettes { void LoadPlayerPalettes(WorldRenderer wr, string playerName, HSLColor playerColor, bool replaceExisting); } diff --git a/OpenRA.Mods.Common/Activities/Attack.cs b/OpenRA.Mods.Common/Activities/Attack.cs index d48334ffea..d92e2b487e 100644 --- a/OpenRA.Mods.Common/Activities/Attack.cs +++ b/OpenRA.Mods.Common/Activities/Attack.cs @@ -21,15 +21,15 @@ namespace OpenRA.Mods.Common.Activities readonly AttackBase attack; readonly IMove move; readonly IFacing facing; + readonly Armament armament; readonly WDist minRange; - readonly WDist maxRange; readonly IPositionable positionable; public Attack(Actor self, Target target, Armament armament, bool allowMovement) { Target = target; this.minRange = armament.Weapon.MinRange; - this.maxRange = armament.Weapon.Range; + this.armament = armament; attack = self.Trait(); facing = self.Trait(); @@ -65,6 +65,7 @@ namespace OpenRA.Mods.Common.Activities return NextActivity; // Try to move within range + var maxRange = armament.MaxRange(); if (move != null && (!Target.IsInRange(self.CenterPosition, maxRange) || Target.IsInRange(self.CenterPosition, minRange))) return Util.SequenceActivities(move.MoveWithinRange(Target, minRange, maxRange), this); diff --git a/OpenRA.Mods.Common/Effects/Bullet.cs b/OpenRA.Mods.Common/Effects/Bullet.cs index ac65568ad7..92199ee377 100644 --- a/OpenRA.Mods.Common/Effects/Bullet.cs +++ b/OpenRA.Mods.Common/Effects/Bullet.cs @@ -108,7 +108,8 @@ namespace OpenRA.Mods.Common.Effects if (info.Inaccuracy.Length > 0) { var inaccuracy = OpenRA.Traits.Util.ApplyPercentageModifiers(info.Inaccuracy.Length, args.InaccuracyModifiers); - var maxOffset = inaccuracy * (target - pos).Length / args.Weapon.Range.Length; + var range = OpenRA.Traits.Util.ApplyPercentageModifiers(args.Weapon.Range.Length, args.RangeModifiers); + var maxOffset = inaccuracy * (target - pos).Length / range; target += WVec.FromPDF(world.SharedRandom, 2) * maxOffset / 1024; } diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index 7f6549ee7d..b43c5df25f 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -365,6 +365,7 @@ + diff --git a/OpenRA.Mods.Common/Traits/Air/AttackBomber.cs b/OpenRA.Mods.Common/Traits/Air/AttackBomber.cs index 15350deeee..3bdc737c13 100644 --- a/OpenRA.Mods.Common/Traits/Air/AttackBomber.cs +++ b/OpenRA.Mods.Common/Traits/Air/AttackBomber.cs @@ -60,7 +60,7 @@ namespace OpenRA.Mods.Common.Traits // Bombs drop anywhere in range foreach (var a in Armaments.Where(a => a.Info.Name == info.Bombs)) { - if (!target.IsInRange(self.CenterPosition, a.Weapon.Range)) + if (!target.IsInRange(self.CenterPosition, a.MaxRange())) continue; inAttackRange = true; @@ -72,10 +72,10 @@ namespace OpenRA.Mods.Common.Traits { foreach (var a in Armaments.Where(a => a.Info.Name == info.Guns)) { - if (!target.IsInRange(self.CenterPosition, a.Weapon.Range)) + if (!target.IsInRange(self.CenterPosition, a.MaxRange())) continue; - var t = Target.FromPos(cp - new WVec(0, a.Weapon.Range.Length / 2, cp.Z).Rotate(WRot.FromFacing(f))); + var t = Target.FromPos(cp - new WVec(0, a.MaxRange().Length / 2, cp.Z).Rotate(WRot.FromFacing(f))); inAttackRange = true; a.CheckFire(self, facing.Value, t); } diff --git a/OpenRA.Mods.Common/Traits/Armament.cs b/OpenRA.Mods.Common/Traits/Armament.cs index c26feedb22..b65250ea2a 100644 --- a/OpenRA.Mods.Common/Traits/Armament.cs +++ b/OpenRA.Mods.Common/Traits/Armament.cs @@ -24,7 +24,7 @@ namespace OpenRA.Mods.Common.Traits } [Desc("Allows you to attach weapons to the unit (use @IdentifierSuffix for > 1)")] - public class ArmamentInfo : UpgradableTraitInfo, Requires + public class ArmamentInfo : UpgradableTraitInfo, IRulesetLoaded, Requires { public readonly string Name = "primary"; @@ -62,7 +62,18 @@ namespace OpenRA.Mods.Common.Traits [Desc("Use multiple muzzle images if non-zero")] public readonly int MuzzleSplitFacings = 0; + public WeaponInfo WeaponInfo { get; private set; } + public WDist ModifiedRange { get; private set; } + public override object Create(ActorInitializer init) { return new Armament(init.Self, this); } + + public void RulesetLoaded(Ruleset rules, ActorInfo ai) + { + WeaponInfo = rules.Weapons[Weapon.ToLowerInvariant()]; + ModifiedRange = new WDist(Util.ApplyPercentageModifiers( + WeaponInfo.Range.Length, + ai.TraitInfos().Select(m => m.GetRangeModifierDefault()))); + } } public class Armament : UpgradableTrait, ITick, IExplodeModifier @@ -75,6 +86,7 @@ namespace OpenRA.Mods.Common.Traits Lazy coords; Lazy ammoPool; List> delayedActions = new List>(); + Lazy> rangeModifiers; public WDist Recoil; public int FireDelay { get; private set; } @@ -89,8 +101,9 @@ namespace OpenRA.Mods.Common.Traits turret = Exts.Lazy(() => self.TraitsImplementing().FirstOrDefault(t => t.Name == info.Turret)); coords = Exts.Lazy(() => self.Trait()); ammoPool = Exts.Lazy(() => self.TraitsImplementing().FirstOrDefault(la => la.Info.Name == info.AmmoPoolName)); + rangeModifiers = Exts.Lazy(() => self.TraitsImplementing().ToArray().Select(m => m.GetRangeModifier())); - Weapon = self.World.Map.Rules.Weapons[info.Weapon.ToLowerInvariant()]; + Weapon = info.WeaponInfo; Burst = Weapon.Burst; var barrels = new List(); @@ -109,6 +122,11 @@ namespace OpenRA.Mods.Common.Traits Barrels = barrels.ToArray(); } + public WDist MaxRange() + { + return new WDist(Util.ApplyPercentageModifiers(Weapon.Range.Length, rangeModifiers.Value)); + } + public void Tick(Actor self) { if (IsTraitDisabled) @@ -148,7 +166,7 @@ namespace OpenRA.Mods.Common.Traits if (ammoPool.Value != null && !ammoPool.Value.HasAmmo()) return null; - if (!target.IsInRange(self.CenterPosition, Weapon.Range)) + if (!target.IsInRange(self.CenterPosition, MaxRange())) return null; if (Weapon.MinRange != WDist.Zero && target.IsInRange(self.CenterPosition, Weapon.MinRange)) @@ -172,6 +190,9 @@ namespace OpenRA.Mods.Common.Traits InaccuracyModifiers = self.TraitsImplementing() .Select(a => a.GetInaccuracyModifier()).ToArray(), + RangeModifiers = self.TraitsImplementing() + .Select(a => a.GetRangeModifier()).ToArray(), + Source = muzzlePosition, SourceActor = self, PassiveTarget = target.CenterPosition, diff --git a/OpenRA.Mods.Common/Traits/Attack/AttackBase.cs b/OpenRA.Mods.Common/Traits/Attack/AttackBase.cs index ac9e214668..24d2a14f50 100644 --- a/OpenRA.Mods.Common/Traits/Attack/AttackBase.cs +++ b/OpenRA.Mods.Common/Traits/Attack/AttackBase.cs @@ -179,7 +179,7 @@ namespace OpenRA.Mods.Common.Traits return WDist.Zero; return Armaments.Where(a => !a.IsTraitDisabled) - .Select(a => a.Weapon.Range) + .Select(a => a.MaxRange()) .Append(WDist.Zero).Max(); } @@ -227,7 +227,7 @@ namespace OpenRA.Mods.Common.Traits IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue); var a = ab.ChooseArmamentForTarget(target); - cursor = a != null && !target.IsInRange(self.CenterPosition, a.Weapon.Range) + cursor = a != null && !target.IsInRange(self.CenterPosition, a.MaxRange()) ? ab.Info.OutsideRangeCursor : ab.Info.Cursor; diff --git a/OpenRA.Mods.Common/Traits/Attack/AttackFollow.cs b/OpenRA.Mods.Common/Traits/Attack/AttackFollow.cs index d992065111..2ac3e2372d 100644 --- a/OpenRA.Mods.Common/Traits/Attack/AttackFollow.cs +++ b/OpenRA.Mods.Common/Traits/Attack/AttackFollow.cs @@ -85,8 +85,9 @@ namespace OpenRA.Mods.Common.Traits || (target.Type == TargetType.FrozenActor && target.FrozenActor.Info.HasTraitInfo()); // Try and sit at least one cell closer than the max range to give some leeway if the target starts moving. - var maxRange = targetIsMobile ? new WDist(Math.Max(weapon.Weapon.MinRange.Length, weapon.Weapon.Range.Length - 1024)) - : weapon.Weapon.Range; + var modifiedRange = weapon.MaxRange(); + var maxRange = targetIsMobile ? new WDist(Math.Max(weapon.Weapon.MinRange.Length, modifiedRange.Length - 1024)) + : modifiedRange; attack.Target = target; diff --git a/OpenRA.Mods.Common/Traits/Multipliers/RangeMultiplier.cs b/OpenRA.Mods.Common/Traits/Multipliers/RangeMultiplier.cs new file mode 100644 index 0000000000..4995bd0665 --- /dev/null +++ b/OpenRA.Mods.Common/Traits/Multipliers/RangeMultiplier.cs @@ -0,0 +1,37 @@ +#region Copyright & License Information +/* + * Copyright 2007-2015 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Linq; +using OpenRA; +using OpenRA.GameRules; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Range of this actor is multiplied based on upgrade level.")] + public class RangeMultiplierInfo : UpgradeMultiplierTraitInfo, IRangeModifierInfo + { + public override object Create(ActorInitializer init) { return new RangeMultiplier(this, init.Self.Info.Name); } + + public int GetRangeModifierDefault() + { + return BaseLevel > 0 || UpgradeTypes.Length == 0 ? 100 : Modifier[0]; + } + } + + public class RangeMultiplier : UpgradeMultiplierTrait, IRangeModifier + { + public RangeMultiplier(RangeMultiplierInfo info, string actorType) + : base(info, "RangeMultiplier", actorType) { } + + public int GetRangeModifier() { return GetModifier(); } + } +} diff --git a/OpenRA.Mods.Common/Traits/Render/RenderRangeCircle.cs b/OpenRA.Mods.Common/Traits/Render/RenderRangeCircle.cs index 5df4978fbe..d04c628042 100644 --- a/OpenRA.Mods.Common/Traits/Render/RenderRangeCircle.cs +++ b/OpenRA.Mods.Common/Traits/Render/RenderRangeCircle.cs @@ -18,22 +18,18 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("Draw a circle indicating my weapon's range.")] - class RenderRangeCircleInfo : ITraitInfo, IPlaceBuildingDecorationInfo, Requires + class RenderRangeCircleInfo : ITraitInfo, IPlaceBuildingDecorationInfo, IRulesetLoaded, Requires { public readonly string RangeCircleType = null; [Desc("Range to draw if no armaments are available")] public readonly WDist FallbackRange = WDist.Zero; + // Computed range + WDist range; + public IEnumerable Render(WorldRenderer wr, World w, ActorInfo ai, WPos centerPosition) { - var armaments = ai.TraitInfos() - .Where(a => a.UpgradeMinEnabledLevel == 0); - var range = FallbackRange; - - if (armaments.Any()) - range = armaments.Select(a => w.Map.Rules.Weapons[a.Weapon.ToLowerInvariant()].Range).Max(); - if (range == WDist.Zero) yield break; @@ -52,6 +48,15 @@ namespace OpenRA.Mods.Common.Traits } public object Create(ActorInitializer init) { return new RenderRangeCircle(init.Self); } + public void RulesetLoaded(Ruleset rules, ActorInfo ai) + { + var armaments = ai.TraitInfos().Where(a => a.UpgradeMinEnabledLevel == 0); + + if (armaments.Any()) + range = armaments.Select(a => a.ModifiedRange).Max(); + else + range = FallbackRange; + } } class RenderRangeCircle : IPostRenderSelection diff --git a/OpenRA.Mods.Common/Traits/ThrowsShrapnel.cs b/OpenRA.Mods.Common/Traits/ThrowsShrapnel.cs index da862fae0a..9fb377d3b7 100644 --- a/OpenRA.Mods.Common/Traits/ThrowsShrapnel.cs +++ b/OpenRA.Mods.Common/Traits/ThrowsShrapnel.cs @@ -55,6 +55,9 @@ namespace OpenRA.Mods.Common.Traits InaccuracyModifiers = self.TraitsImplementing() .Select(a => a.GetInaccuracyModifier()).ToArray(), + RangeModifiers = self.TraitsImplementing() + .Select(a => a.GetRangeModifier()).ToArray(), + Source = self.CenterPosition, SourceActor = self, PassiveTarget = self.CenterPosition + new WVec(range, 0, 0).Rotate(rotation) diff --git a/OpenRA.Mods.D2k/Traits/AttackSwallow.cs b/OpenRA.Mods.D2k/Traits/AttackSwallow.cs index a6e8600f1e..931c37b7db 100644 --- a/OpenRA.Mods.D2k/Traits/AttackSwallow.cs +++ b/OpenRA.Mods.D2k/Traits/AttackSwallow.cs @@ -52,7 +52,7 @@ namespace OpenRA.Mods.D2k.Traits if (a == null) return; - if (!target.IsInRange(self.CenterPosition, a.Weapon.Range)) + if (!target.IsInRange(self.CenterPosition, a.MaxRange())) return; self.CancelActivity(); diff --git a/OpenRA.Mods.RA/Traits/Attack/AttackLeap.cs b/OpenRA.Mods.RA/Traits/Attack/AttackLeap.cs index 8965dd47fa..f615d5000f 100644 --- a/OpenRA.Mods.RA/Traits/Attack/AttackLeap.cs +++ b/OpenRA.Mods.RA/Traits/Attack/AttackLeap.cs @@ -43,7 +43,7 @@ namespace OpenRA.Mods.RA.Traits if (a == null) return; - if (!target.IsInRange(self.CenterPosition, a.Weapon.Range)) + if (!target.IsInRange(self.CenterPosition, a.MaxRange())) return; self.CancelActivity();