diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
index 60e34ed772..55ae30fc65 100644
--- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
+++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
@@ -591,6 +591,9 @@
+
+
+
@@ -876,6 +879,7 @@
+
diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/ScaleDefaultModHealth.cs b/OpenRA.Mods.Common/UpdateRules/Rules/ScaleDefaultModHealth.cs
new file mode 100644
index 0000000000..c71a2ca58d
--- /dev/null
+++ b/OpenRA.Mods.Common/UpdateRules/Rules/ScaleDefaultModHealth.cs
@@ -0,0 +1,33 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2018 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, either version 3 of
+ * the License, or (at your option) any later version. For more
+ * information, see COPYING.
+ */
+#endregion
+
+using System.Collections.Generic;
+using OpenRA.Primitives;
+
+namespace OpenRA.Mods.Common.UpdateRules.Rules
+{
+ public class ScaleDefaultModHealth : ScaleModHealth
+ {
+ static readonly Dictionary ModScales = new Dictionary()
+ {
+ { "cnc", 100 },
+ { "ra", 100 },
+ { "d2k", 10 },
+ { "ts", 100 }
+ };
+
+ public override IEnumerable BeforeUpdate(ModData modData)
+ {
+ ModScales.TryGetValue(modData.Manifest.Id, out scale);
+ return base.BeforeUpdate(modData);
+ }
+ }
+}
diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/ScaleModHealth.cs b/OpenRA.Mods.Common/UpdateRules/Rules/ScaleModHealth.cs
new file mode 100644
index 0000000000..2542cd7f1f
--- /dev/null
+++ b/OpenRA.Mods.Common/UpdateRules/Rules/ScaleModHealth.cs
@@ -0,0 +1,111 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2018 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, either version 3 of
+ * the License, or (at your option) any later version. For more
+ * information, see COPYING.
+ */
+#endregion
+
+using System.Collections.Generic;
+using OpenRA.Primitives;
+
+namespace OpenRA.Mods.Common.UpdateRules.Rules
+{
+ public class ScaleModHealth : UpdateRule
+ {
+ public override string Name { get { return "Scale health and damage in the default OpenRA mods"; } }
+ public override string Description
+ {
+ get
+ {
+ return "All health and damage values are increased by a factor of 100 (ra, cnc, ts) or 10 (d2k)\n"
+ + "in order to reduce numerical inaccuracies in damage calculations.";
+ }
+ }
+
+ static readonly Dictionary[]> TraitMapping = new Dictionary[]>()
+ {
+ { "Health", new[] { Pair.New("HP", string.Empty) } },
+ { "SelfHealing", new[] { Pair.New("Step", "500") } },
+ { "RepairsUnits", new[] { Pair.New("HpPerStep", "1000") } },
+ { "RepairableBuilding", new[] { Pair.New("RepairStep", "700") } },
+ { "Burns", new[] { Pair.New("Damage", "100") } },
+ { "DamagedByTerrain", new[] { Pair.New("Damage", string.Empty) } },
+ };
+
+ static readonly Dictionary WarheadMapping = new Dictionary()
+ {
+ { "SpreadDamage", "Damage" },
+ { "TargetDamage", "Damage" },
+ };
+
+ public ScaleModHealth(int scale = 100)
+ {
+ this.scale = scale;
+ }
+
+ protected int scale;
+
+ bool updated;
+
+ public override IEnumerable BeforeUpdate(ModData modData)
+ {
+ updated = false;
+ yield break;
+ }
+
+ public override IEnumerable AfterUpdate(ModData modData)
+ {
+ if (updated)
+ yield return "Health and damage values have been muliplied by a factor of {0}.\n".F(scale)
+ + "The increased calculation precision will affect game balance and may need to be manually adjusted.\n";
+ }
+
+ public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode)
+ {
+ foreach (var kv in TraitMapping)
+ {
+ foreach (var trait in actorNode.ChildrenMatching(kv.Key))
+ {
+ foreach (var parameter in kv.Value)
+ {
+ var node = trait.LastChildMatching(parameter.First);
+ if (node != null)
+ node.ReplaceValue((scale * node.NodeValue()).ToString());
+ else if (!string.IsNullOrEmpty(parameter.Second))
+ trait.AddNode(parameter.First, parameter.Second);
+
+ updated = true;
+ }
+ }
+ }
+
+ yield break;
+ }
+
+ public override IEnumerable UpdateWeaponNode(ModData modData, MiniYamlNode weaponNode)
+ {
+ foreach (var warheadNode in weaponNode.ChildrenMatching("Warhead"))
+ {
+ var name = warheadNode.NodeValue();
+ if (name == null)
+ continue;
+
+ string parameterName;
+ if (!WarheadMapping.TryGetValue(name, out parameterName))
+ continue;
+
+ foreach (var node in warheadNode.ChildrenMatching(parameterName))
+ {
+ node.ReplaceValue((scale * node.NodeValue()).ToString());
+ updated = true;
+ }
+ }
+
+ yield break;
+ }
+ }
+}
diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/ScaleModHealthBy10.cs b/OpenRA.Mods.Common/UpdateRules/Rules/ScaleModHealthBy10.cs
new file mode 100644
index 0000000000..7c41d91e77
--- /dev/null
+++ b/OpenRA.Mods.Common/UpdateRules/Rules/ScaleModHealthBy10.cs
@@ -0,0 +1,24 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2018 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, either version 3 of
+ * the License, or (at your option) any later version. For more
+ * information, see COPYING.
+ */
+#endregion
+
+using System.Collections.Generic;
+
+namespace OpenRA.Mods.Common.UpdateRules.Rules
+{
+ public class ScaleModHealthBy10 : ScaleModHealth
+ {
+ public override IEnumerable BeforeUpdate(ModData modData)
+ {
+ scale = 10;
+ return base.BeforeUpdate(modData);
+ }
+ }
+}
diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/ScaleModHealthBy100.cs b/OpenRA.Mods.Common/UpdateRules/Rules/ScaleModHealthBy100.cs
new file mode 100644
index 0000000000..6cfece9d94
--- /dev/null
+++ b/OpenRA.Mods.Common/UpdateRules/Rules/ScaleModHealthBy100.cs
@@ -0,0 +1,24 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2018 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, either version 3 of
+ * the License, or (at your option) any later version. For more
+ * information, see COPYING.
+ */
+#endregion
+
+using System.Collections.Generic;
+
+namespace OpenRA.Mods.Common.UpdateRules.Rules
+{
+ public class ScaleModHealthBy100 : ScaleModHealth
+ {
+ public override IEnumerable BeforeUpdate(ModData modData)
+ {
+ scale = 100;
+ return base.BeforeUpdate(modData);
+ }
+ }
+}
diff --git a/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs b/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs
index 1bcfde03b8..789c2f1f47 100644
--- a/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs
+++ b/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs
@@ -42,7 +42,8 @@ namespace OpenRA.Mods.Common.UpdateRules
new CapturableChanges(),
new DecoupleSelfReloading(),
new RemovePlayerPaletteTileset(),
- new RenameWithTurreted()
+ new RenameWithTurreted(),
+ new ScaleDefaultModHealth()
}),
new UpdatePath("release-20180218", "release-20180307", new UpdateRule[0]),