diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
index 80738fe31c..f5cefcbe86 100644
--- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
+++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
@@ -285,6 +285,7 @@
+
diff --git a/OpenRA.Mods.Common/Traits/Infantry/TerrainModifiesDamage.cs b/OpenRA.Mods.Common/Traits/Infantry/TerrainModifiesDamage.cs
new file mode 100644
index 0000000000..02f77edb26
--- /dev/null
+++ b/OpenRA.Mods.Common/Traits/Infantry/TerrainModifiesDamage.cs
@@ -0,0 +1,75 @@
+ #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.Collections.Generic;
+using System.Linq;
+using OpenRA.GameRules;
+using OpenRA.Traits;
+
+namespace OpenRA.Mods.Common.Traits
+{
+ public class TerrainModifiesDamageInfo : ITraitInfo
+ {
+ [FieldLoader.LoadUsing("LoadPercents")]
+ [Desc("Damage percentage for specific terrain types. 120 = 120%, 80 = 80%, etc.")]
+ public readonly Dictionary TerrainModifier = null;
+
+ [Desc("Modify healing damage? For example: A friendly medic.")]
+ public readonly bool ModifyHealing = false;
+
+ public object Create(ActorInitializer init) { return new TerrainModifiesDamage(init.Self, this); }
+
+ static object LoadPercents(MiniYaml y)
+ {
+ MiniYaml percents;
+
+ if (!y.ToDictionary().TryGetValue("TerrainModifier", out percents))
+ return new Dictionary();
+
+ return percents.Nodes.ToDictionary(
+ kv => FieldLoader.GetValue("(key)", kv.Key),
+ kv => FieldLoader.GetValue("(value)", kv.Value.Value));
+ }
+ }
+
+ public class TerrainModifiesDamage : IDamageModifier
+ {
+ public readonly TerrainModifiesDamageInfo Info;
+
+ readonly Actor self;
+
+ public TerrainModifiesDamage(Actor self, TerrainModifiesDamageInfo info)
+ {
+ Info = info;
+ this.self = self;
+ }
+
+ public int GetDamageModifier(Actor attacker, DamageWarhead warhead)
+ {
+ var percent = 100;
+ if (attacker.Owner.IsAlliedWith(self.Owner) && warhead.Damage < 0 && !Info.ModifyHealing)
+ return percent;
+
+ var world = self.World;
+ var map = world.Map;
+ var tileSet = world.TileSet;
+
+ var tiles = map.MapTiles.Value;
+ var pos = map.CellContaining(self.CenterPosition);
+ var terrainType = tileSet[tileSet.GetTerrainIndex(tiles[pos])].Type;
+
+ if (!Info.TerrainModifier.ContainsKey(terrainType))
+ return percent;
+
+ return Info.TerrainModifier[terrainType];
+ }
+ }
+}
diff --git a/mods/d2k/rules/defaults.yaml b/mods/d2k/rules/defaults.yaml
index f17699fa80..76d648ac8f 100644
--- a/mods/d2k/rules/defaults.yaml
+++ b/mods/d2k/rules/defaults.yaml
@@ -233,6 +233,9 @@
MustBeDestroyed:
AnnounceOnSeen:
Notification: EnemyUnitsApproaching
+ TerrainModifiesDamage:
+ TerrainModifier:
+ Rough: 80
^Plane:
AppearsOnRadar:
@@ -326,4 +329,3 @@
Range: 2c0, 5c0
ScriptTriggers:
WithMakeAnimation:
-