diff --git a/OpenRA.Game/Traits/Health.cs b/OpenRA.Game/Traits/Health.cs index 9955ec78ed..6566068d21 100755 --- a/OpenRA.Game/Traits/Health.cs +++ b/OpenRA.Game/Traits/Health.cs @@ -100,16 +100,21 @@ namespace OpenRA.Traits public void InflictDamage(Actor self, Actor attacker, int damage, DamageWarhead warhead, bool ignoreModifiers) { - if (IsDead) return; /* overkill! don't count extra hits as more kills! */ + // Overkill! don't count extra hits as more kills! + if (IsDead) + return; var oldState = this.DamageState; - /* apply the damage modifiers, if we have any. */ - var modifier = self.TraitsImplementing() - .Concat(self.Owner.PlayerActor.TraitsImplementing()) - .Select(t => t.GetDamageModifier(attacker, warhead)).Product(); - if (!ignoreModifiers) - damage = damage > 0 ? (int)(damage * modifier) : damage; + // Apply any damage modifiers + if (!ignoreModifiers && damage > 0) + { + var modifiers = self.TraitsImplementing() + .Concat(self.Owner.PlayerActor.TraitsImplementing()) + .Select(t => t.GetDamageModifier(attacker, warhead)); + + damage = Util.ApplyPercentageModifiers(damage, modifiers); + } hp = Exts.Clamp(hp - damage, 0, MaxHP); diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index e8fb764998..2314ead991 100644 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -155,7 +155,7 @@ namespace OpenRA.Traits } public interface IRenderModifier { IEnumerable ModifyRender(Actor self, WorldRenderer wr, IEnumerable r); } - public interface IDamageModifier { float GetDamageModifier(Actor attacker, DamageWarhead warhead); } + public interface IDamageModifier { int GetDamageModifier(Actor attacker, DamageWarhead warhead); } public interface ISpeedModifier { decimal GetSpeedModifier(); } public interface IFirepowerModifier { float GetFirepowerModifier(); } public interface ILoadsPalettes { void LoadPalettes(WorldRenderer wr); } diff --git a/OpenRA.Game/Traits/Util.cs b/OpenRA.Game/Traits/Util.cs index 6268bcf1d5..0a6a999f82 100644 --- a/OpenRA.Game/Traits/Util.cs +++ b/OpenRA.Game/Traits/Util.cs @@ -138,5 +138,15 @@ namespace OpenRA.Traits var cells = target.Positions.Select(p => w.Map.CellContaining(p)).Distinct(); return ExpandFootprint(cells, true); } + + public static int ApplyPercentageModifiers(int number, IEnumerable percentages) + { + // See the comments of PR#6079 for a faster algorithm if this becomes a performance bottleneck + var a = (decimal)number; + foreach (var p in percentages) + a *= p / 100m; + + return (int)a; + } } } diff --git a/OpenRA.Mods.RA/Activities/Demolish.cs b/OpenRA.Mods.RA/Activities/Demolish.cs index 97f9a97924..045eccbea0 100644 --- a/OpenRA.Mods.RA/Activities/Demolish.cs +++ b/OpenRA.Mods.RA/Activities/Demolish.cs @@ -50,16 +50,17 @@ namespace OpenRA.Mods.RA.Activities if (target.Type != TargetType.Actor) return; - // Invulnerable actors can't be demolished - var modifier = (float)target.Actor.TraitsImplementing() - .Concat(self.Owner.PlayerActor.TraitsImplementing()) - .Select(t => t.GetDamageModifier(self, null)).Product(); + var demolishable = target.Actor.TraitOrDefault(); if (demolishable == null || !demolishable.IsValidTarget(target.Actor, self)) return; - if (modifier > 0) + var modifiers = target.Actor.TraitsImplementing() + .Concat(self.Owner.PlayerActor.TraitsImplementing()) + .Select(t => t.GetDamageModifier(self, null)); + + if (Util.ApplyPercentageModifiers(100, modifiers) > 0) demolishable.Demolish(target.Actor, self); })); }); diff --git a/OpenRA.Mods.RA/Attack/AttackPopupTurreted.cs b/OpenRA.Mods.RA/Attack/AttackPopupTurreted.cs index a4a66b8a92..85a36478fc 100644 --- a/OpenRA.Mods.RA/Attack/AttackPopupTurreted.cs +++ b/OpenRA.Mods.RA/Attack/AttackPopupTurreted.cs @@ -23,8 +23,8 @@ namespace OpenRA.Mods.RA public int CloseDelay = 125; public int DefaultFacing = 0; - [Desc("The factor damage received is multiplied by while this actor is closed.")] - public float ClosedDamageMultiplier = 0.5f; + [Desc("The percentage of damage that is received while this actor is closed.")] + public int ClosedDamageMultiplier = 50; public override object Create(ActorInitializer init) { return new AttackPopupTurreted(init, this); } } @@ -105,9 +105,9 @@ namespace OpenRA.Mods.RA } } - public float GetDamageModifier(Actor attacker, DamageWarhead warhead) + public int GetDamageModifier(Actor attacker, DamageWarhead warhead) { - return state == PopupState.Closed ? info.ClosedDamageMultiplier : 1f; + return state == PopupState.Closed ? info.ClosedDamageMultiplier : 100; } } } diff --git a/OpenRA.Mods.RA/GainsStatUpgrades.cs b/OpenRA.Mods.RA/GainsStatUpgrades.cs index f7889e1446..80e1e7543a 100644 --- a/OpenRA.Mods.RA/GainsStatUpgrades.cs +++ b/OpenRA.Mods.RA/GainsStatUpgrades.cs @@ -22,7 +22,7 @@ namespace OpenRA.Mods.RA public readonly float[] FirepowerModifier = { 1.1f, 1.15f, 1.2f, 1.5f }; public readonly string ArmorUpgrade = "armor"; - public readonly float[] ArmorModifier = { 1.1f, 1.2f, 1.3f, 1.5f }; + public readonly int[] ArmorModifier = { 110, 120, 130, 150 }; public readonly string SpeedUpgrade = "speed"; public readonly decimal[] SpeedModifier = { 1.1m, 1.15m, 1.2m, 1.5m }; @@ -60,9 +60,9 @@ namespace OpenRA.Mods.RA speedLevel = (speedLevel + mod).Clamp(0, info.SpeedModifier.Length); } - public float GetDamageModifier(Actor attacker, DamageWarhead warhead) + public int GetDamageModifier(Actor attacker, DamageWarhead warhead) { - return armorLevel > 0 ? 1 / info.ArmorModifier[armorLevel - 1] : 1; + return armorLevel > 0 ? 1 / info.ArmorModifier[armorLevel - 1] : 100; } public float GetFirepowerModifier() diff --git a/OpenRA.Mods.RA/Invulnerable.cs b/OpenRA.Mods.RA/Invulnerable.cs index b05950fed7..b4407d3377 100644 --- a/OpenRA.Mods.RA/Invulnerable.cs +++ b/OpenRA.Mods.RA/Invulnerable.cs @@ -18,6 +18,6 @@ namespace OpenRA.Mods.RA class Invulnerable : IDamageModifier { - public float GetDamageModifier(Actor attacker, DamageWarhead warhead) { return 0.0f; } + public int GetDamageModifier(Actor attacker, DamageWarhead warhead) { return 0; } } } diff --git a/OpenRA.Mods.RA/IronCurtainable.cs b/OpenRA.Mods.RA/IronCurtainable.cs index 0c8db3f3ab..dfe50c7dc2 100644 --- a/OpenRA.Mods.RA/IronCurtainable.cs +++ b/OpenRA.Mods.RA/IronCurtainable.cs @@ -28,9 +28,9 @@ namespace OpenRA.Mods.RA RemainingTicks--; } - public float GetDamageModifier(Actor attacker, DamageWarhead warhead) + public int GetDamageModifier(Actor attacker, DamageWarhead warhead) { - return (RemainingTicks > 0) ? 0.0f : 1.0f; + return RemainingTicks > 0 ? 0 : 100; } public void Activate(Actor self, int duration) diff --git a/OpenRA.Mods.RA/Scripting/ScriptInvulnerable.cs b/OpenRA.Mods.RA/Scripting/ScriptInvulnerable.cs index eebcf35013..f2c8e5f067 100644 --- a/OpenRA.Mods.RA/Scripting/ScriptInvulnerable.cs +++ b/OpenRA.Mods.RA/Scripting/ScriptInvulnerable.cs @@ -20,9 +20,9 @@ namespace OpenRA.Mods.RA { public bool Invulnerable = false; - public float GetDamageModifier(Actor attacker, DamageWarhead warhead) + public int GetDamageModifier(Actor attacker, DamageWarhead warhead) { - return Invulnerable ? 0.0f : 1.0f; + return Invulnerable ? 0 : 100; } } } diff --git a/OpenRA.Mods.RA/TakeCover.cs b/OpenRA.Mods.RA/TakeCover.cs index 6d64de1782..c8d60071b2 100644 --- a/OpenRA.Mods.RA/TakeCover.cs +++ b/OpenRA.Mods.RA/TakeCover.cs @@ -61,9 +61,9 @@ namespace OpenRA.Mods.RA LocalOffset = WVec.Zero; } - public float GetDamageModifier(Actor attacker, DamageWarhead warhead) + public int GetDamageModifier(Actor attacker, DamageWarhead warhead) { - return IsProne && warhead != null ? warhead.ProneModifier / 100f : 1f; + return IsProne && warhead != null ? warhead.ProneModifier : 100; } public decimal GetSpeedModifier() diff --git a/OpenRA.Utility/UpgradeRules.cs b/OpenRA.Utility/UpgradeRules.cs index bb6ef61b7c..a8a2027182 100644 --- a/OpenRA.Utility/UpgradeRules.cs +++ b/OpenRA.Utility/UpgradeRules.cs @@ -26,6 +26,12 @@ namespace OpenRA.Utility input = "{0}c{1}".F(cells, subcells); } + static void ConvertFloatArrayToPercentArray(ref string input) + { + input = string.Join(", ", input.Split(',') + .Select(s => ((int)(float.Parse(s) * 100)).ToString())); + } + static void ConvertPxToRange(ref string input) { ConvertPxToRange(ref input, 1, 1); @@ -402,6 +408,16 @@ namespace OpenRA.Utility } } + // Modifiers were changed to integer percentages + if (engineVersion < 20140809) + { + if (depth == 2 && node.Key == "ClosedDamageMultiplier" && parentKey == "AttackPopupTurreted") + ConvertFloatArrayToPercentArray(ref node.Value.Value); + + if (depth == 2 && node.Key == "ArmorModifier" && parentKey == "GainsStatUpgrades") + ConvertFloatArrayToPercentArray(ref node.Value.Value); + } + UpgradeActorRules(engineVersion, ref node.Value.Nodes, node, depth + 1); } }