diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj
index 3ea793d682..9540200910 100644
--- a/OpenRa.Game/OpenRa.Game.csproj
+++ b/OpenRa.Game/OpenRa.Game.csproj
@@ -172,6 +172,7 @@
+
diff --git a/OpenRa.Game/Traits/AutoHeal.cs b/OpenRa.Game/Traits/AutoHeal.cs
new file mode 100644
index 0000000000..2015140ccd
--- /dev/null
+++ b/OpenRa.Game/Traits/AutoHeal.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace OpenRa.Game.Traits
+{
+ class AutoHeal : ITick
+ {
+ public AutoHeal(Actor self) { }
+
+ void AttackTarget(Actor self, Actor target)
+ {
+ var attack = self.traits.WithInterface().First();
+ if (target != null)
+ attack.ResolveOrder(self, new Order("Attack", self, target, int2.Zero, null));
+ }
+
+ float GetMaximumRange(Actor self)
+ {
+ return new[] { self.Info.Primary, self.Info.Secondary }
+ .Where(w => w != null)
+ .Max(w => Rules.WeaponInfo[w].Range);
+ }
+
+ bool NeedsNewTarget(Actor self)
+ {
+ var attack = self.traits.WithInterface().First();
+ var range = GetMaximumRange(self);
+
+ if (attack.target == null)
+ return true; // he's dead.
+ if ((attack.target.Location - self.Location).LengthSquared > range * range + 2)
+ return true; // wandered off faster than we could follow
+ if (attack.target.Health == attack.target.Info.Strength)
+ return true; // fully healed
+
+ return false;
+ }
+
+ public void Tick(Actor self)
+ {
+ if (!self.IsIdle) return;
+
+ var attack = self.traits.WithInterface().First();
+ var range = GetMaximumRange(self);
+
+ if (NeedsNewTarget(self))
+ AttackTarget(self, ChooseTarget(self, range));
+ }
+
+ Actor ChooseTarget(Actor self, float range)
+ {
+ var inRange = Game.FindUnitsInCircle(self.CenterLocation, Game.CellSize * range);
+
+ return inRange
+ .Where(a => a.Owner == self.Owner) /* todo: one day deal with friendly players */
+ .Where(a => Combat.HasAnyValidWeapons(self, a))
+ .Where(a => a.Health < a.Info.Strength)
+ .OrderBy(a => (a.Location - self.Location).LengthSquared)
+ .FirstOrDefault();
+ }
+ }
+}
diff --git a/units.ini b/units.ini
index 2644c3a949..633e89a442 100755
--- a/units.ini
+++ b/units.ini
@@ -569,7 +569,7 @@ LongDesc=Elite commando infantry, armed with \ndual pistols and C4.\n Strong vs
[MEDI]
Description=Medic
Voice=MedicVoice
-Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover, Infantry, AutoTarget
+Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover, Infantry, AutoHeal
LongDesc=Heals nearby infantry.\n Strong vs Nothing\n Weak vs Everything