diff --git a/binaries/data/mods/public/gui/session/messages.js b/binaries/data/mods/public/gui/session/messages.js
index f296bcf..2440e17 100644
--- a/binaries/data/mods/public/gui/session/messages.js
+++ b/binaries/data/mods/public/gui/session/messages.js
@@ -78,6 +78,13 @@ function handleNotifications()
 			"amounts": notification.amounts
 		});
 	}
+	else if (notification.type == "attack")
+	{
+		if (notification.player == Engine.GetPlayerID())
+		{
+			Engine.GuiInterfaceCall("PlaySound", { "name":"attacked", "entity": notification.message.target });
+		}
+	}
 	else
 	{
 		// Only display notifications directed to this player
@@ -356,6 +363,12 @@ function addChatMessage(msg, playerAssignments)
 
 		formatted = "[color=\"" + playerColor + "\"]" + username + "[/color] has sent you " + amounts + ".";
 		break;
+	case "attack":
+		if (msg.player != Engine.GetPlayerID()) 
+			return;
+
+		formatted = "We're under attack!";
+		break;
 	case "message":
 		// May have been hidden by the 'team' command.
 		if (msg.hide)
diff --git a/binaries/data/mods/public/simulation/components/Armour.js b/binaries/data/mods/public/simulation/components/Armour.js
index eef945e..f5457ea 100644
--- a/binaries/data/mods/public/simulation/components/Armour.js
+++ b/binaries/data/mods/public/simulation/components/Armour.js
@@ -42,7 +42,7 @@ Armour.prototype.SetInvulnerability = function(invulnerability)
 	this.invulnerable = invulnerability;
 };
 
-Armour.prototype.TakeDamage = function(hack, pierce, crush)
+Armour.prototype.TakeDamage = function(hack, pierce, crush, source)
 {
 	if (this.invulnerable) 
 		return { "killed": false };
@@ -57,6 +57,15 @@ Armour.prototype.TakeDamage = function(hack, pierce, crush)
 	//	Round to nearest integer, since HP is integral
 	var total = Math.max(1, Math.round(adjHack + adjPierce + adjCrush));
 
+	// Alert target owner of attack
+	var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
+	var cmpAttackDetection = QueryPlayerIDInterface(cmpOwnership.GetOwner(), IID_AttackDetection);
+	var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
+	var now = cmpTimer.GetTime();
+	if (!(this.lastAttack > now - cmpAttackDetection.GetSuppressionTime()))
+		cmpAttackDetection.AttackAlert(this.entity, source);
+	this.lastAttack = now;
+
 	// Reduce health
 	var cmpHealth = Engine.QueryInterface(this.entity, IID_Health);
 	return cmpHealth.Reduce(total);
diff --git a/binaries/data/mods/public/simulation/components/Attack.js b/binaries/data/mods/public/simulation/components/Attack.js
index 0a9a707..469a582 100644
--- a/binaries/data/mods/public/simulation/components/Attack.js
+++ b/binaries/data/mods/public/simulation/components/Attack.js
@@ -691,7 +691,7 @@ Attack.prototype.CauseDamage = function(data)
 	var cmpDamageReceiver = Engine.QueryInterface(data.target, IID_DamageReceiver);
 	if (!cmpDamageReceiver)
 		return;
-	var targetState = cmpDamageReceiver.TakeDamage(strengths.hack * damageMultiplier, strengths.pierce * damageMultiplier, strengths.crush * damageMultiplier);
+	var targetState = cmpDamageReceiver.TakeDamage(strengths.hack * damageMultiplier, strengths.pierce * damageMultiplier, strengths.crush * damageMultiplier, this.entity);
 	// if target killed pick up loot and credit experience
 	if (targetState.killed == true)
 	{
diff --git a/binaries/data/mods/public/simulation/components/AttackDetection.js b/binaries/data/mods/public/simulation/components/AttackDetection.js
new file mode 100644
index 0000000..98448b8
--- /dev/null
+++ b/binaries/data/mods/public/simulation/components/AttackDetection.js
@@ -0,0 +1,113 @@
+function AttackDetection() {}
+
+AttackDetection.prototype.Schema =
+	"<a:help>Detects incoming attacks.</a:help>" +
+	"<a:example/>" +
+	"<a:component type='system'/>" +
+	"<empty/>";
+
+AttackDetection.prototype.Init = function()
+{
+	this.suppressionTransferRange = 50; // Any attacks within this range will replace the previous attack suppression.
+	this.suppressionRange = 150; // Other attacks within this distance will not be registered.
+	this.suppressionTime = 40 * 1000; // Other attacks within this time will not be registered.
+
+	this.suppressedList = [];
+};
+
+// Utility function for calculating the distance between two attack events.
+AttackDetection.prototype.distance = function(pos1, pos2)
+{
+	var xs = pos2.x - pos1.x;
+	var zs = pos2.z - pos1.z;
+	return Math.sqrt(Math.pow(xs, 2) + Math.pow(zs, 2));
+}
+
+AttackDetection.prototype.addSuppression = function(event)
+{
+	this.suppressedList.push(event);
+
+	var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
+	cmpTimer.SetTimeout(this.entity, IID_AttackDetection, "HandleTimeout", this.suppressionTime);
+}
+
+AttackDetection.prototype.handleAttack = function(target, attacker)
+{
+	var cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);
+	var cmpOwnership = Engine.QueryInterface(target, IID_Ownership);
+	// Don't register attacks dealt against others.
+	if (cmpPlayer.GetPlayerID() != cmpOwnership.GetOwner())
+		return;
+
+	var cmpPosition = Engine.QueryInterface(target, IID_Position);
+	if (!cmpPosition || !cmpPosition.IsInWorld())
+		return;
+	var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
+	var event = {target: target, position: cmpPosition.GetPosition(), time: cmpTimer.GetTime()};
+
+	for (var i = 0; i < this.suppressedList.length; i++)
+	{
+		var element = this.suppressedList[i];
+		
+		// If the new attack is within suppression distance of this element then check if the element should be updated
+		// and then return.
+		var dist = this.distance(element.position, event.position);
+		if (dist < this.suppressionRange)
+		{
+			if (dist < this.suppressionTransferRange)
+				element = event;
+			return;
+		}
+	}
+	
+	this.addSuppression(event);
+	Engine.PostMessage(this.entity, MT_AttackDetected, { "player": cmpPlayer.GetPlayerID(), "event": event });
+	var cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
+	cmpGuiInterface.PushNotification({"type": "attack", "player": cmpPlayer.GetPlayerID(), "message": event});
+};
+
+//// Message handlers ////
+
+AttackDetection.prototype.OnGlobalAttacked = function(msg)
+{
+	var cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);
+	var cmpOwnership = Engine.QueryInterface(msg.target, IID_Ownership);
+	if (cmpOwnership.GetOwner() == cmpPlayer.GetPlayerID())
+		Engine.PostMessage(msg.target, MT_PingOwner);
+};
+
+//// External interface ////
+
+AttackDetection.prototype.AttackAlert = function(target, attacker)
+{
+	this.handleAttack(target, attacker);
+};
+
+AttackDetection.prototype.GetSuppressionTime = function()
+{
+	return this.suppressionTime;
+};
+
+AttackDetection.prototype.HandleTimeout = function()
+{
+	var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
+	for (var i = 0; i < this.suppressedList.length; i++)
+	{
+		var event = this.suppressedList[i];
+		
+		// Check if this event has timed out.
+		if (cmpTimer.GetTime() - event.time >= this.suppressionTime)
+		{
+			this.suppressedList.splice(i, 1);
+			i--;
+			return;
+		}
+	}
+};
+
+AttackDetection.prototype.GetIncomingAttacks = function()
+{
+	return this.suppressedList;
+};
+
+Engine.RegisterComponentType(IID_AttackDetection, "AttackDetection", AttackDetection);
diff --git a/binaries/data/mods/public/simulation/components/GuiInterface.js b/binaries/data/mods/public/simulation/components/GuiInterface.js
index a5418be..da8dc99 100644
--- a/binaries/data/mods/public/simulation/components/GuiInterface.js
+++ b/binaries/data/mods/public/simulation/components/GuiInterface.js
@@ -620,6 +620,13 @@ GuiInterface.prototype.GetBattleState = function(player)
 	return cmpBattleDetection.GetState();
 };
 
+// Returns a list of ongoing attacks against the player.
+GuiInterface.prototype.GetIncomingAttacks = function(player)
+{
+	var cmpAttackDetection = QueryPlayerIDInterface(player, IID_AttackDetection);
+	return cmpAttackDetection.GetIncomingAttacks();
+};
+
 // Used to show a red square over GUI elements you can't yet afford.
 GuiInterface.prototype.GetNeededResources = function(player, amounts)
 {
@@ -1720,6 +1727,7 @@ var exposedFunctions = {
 	"CheckTechnologyRequirements": 1,
 	"GetStartedResearch": 1,
 	"GetBattleState": 1,
+	"GetIncomingAttacks": 1,
 	"GetNeededResources": 1,
 	"GetNextNotification": 1,
 
diff --git a/binaries/data/mods/public/simulation/components/interfaces/AttackDetection.js b/binaries/data/mods/public/simulation/components/interfaces/AttackDetection.js
new file mode 100644
index 0000000..d168646
--- /dev/null
+++ b/binaries/data/mods/public/simulation/components/interfaces/AttackDetection.js
@@ -0,0 +1,9 @@
+Engine.RegisterInterface("AttackDetection");
+
+// Message of the form { "event": { "target": 123, "position": { "x": 123, "z": 456 }, "time": 1 }.
+// sent when an entity is attacked.
+//Engine.RegisterMessageType("EntityAttacked");
+
+// Message of the form { "player": 1, "event": { "target": 123 , "position": { "x": 123, "z": 456 }, "time": 1, }.
+// sent when a new attack is detected.
+Engine.RegisterMessageType("AttackDetected");
diff --git a/binaries/data/mods/public/simulation/templates/special/player.xml b/binaries/data/mods/public/simulation/templates/special/player.xml
index eaa28e6..97ff335 100644
--- a/binaries/data/mods/public/simulation/templates/special/player.xml
+++ b/binaries/data/mods/public/simulation/templates/special/player.xml
@@ -12,6 +12,7 @@
   <Player/>
   <StatisticsTracker/>
   <TechnologyManager/>
+  <AttackDetection/>
   <BattleDetection>
     <TimerInterval>200</TimerInterval>
     <RecordLength>12</RecordLength>
diff --git a/binaries/data/mods/public/simulation/templates/template_structure.xml b/binaries/data/mods/public/simulation/templates/template_structure.xml
index bfe0e5e..f20fdfc 100644
--- a/binaries/data/mods/public/simulation/templates/template_structure.xml
+++ b/binaries/data/mods/public/simulation/templates/template_structure.xml
@@ -85,6 +85,7 @@
       <select>interface/select/building/sel_universal.xml</select>
       <constructed>interface/complete/building/complete_universal.xml</constructed>
       <death>attack/destruction/building_collapse_large.xml</death>
+      <attacked>interface/alarm/alarm_attackplayer.xml</attacked>   
     </SoundGroups>
   </Sound>
   <StatusBars>
diff --git a/binaries/data/mods/public/simulation/templates/template_unit_cavalry.xml b/binaries/data/mods/public/simulation/templates/template_unit_cavalry.xml
index 420836e..a16aa0c 100644
--- a/binaries/data/mods/public/simulation/templates/template_unit_cavalry.xml
+++ b/binaries/data/mods/public/simulation/templates/template_unit_cavalry.xml
@@ -79,6 +79,7 @@
       <walk>actor/mounted/movement/walk.xml</walk>
       <run>actor/mounted/movement/walk.xml</run>
       <attack>attack/weapon/sword.xml</attack>
+      <attacked>interface/alarm/alarm_attackplayer.xml</attacked>
       <death>actor/fauna/death/death_horse.xml</death>
       <trained>interface/alarm/alarm_create_cav.xml</trained>
     </SoundGroups>
diff --git a/binaries/data/mods/public/simulation/templates/template_unit_champion.xml b/binaries/data/mods/public/simulation/templates/template_unit_champion.xml
index 11b332e..16f5745 100644
--- a/binaries/data/mods/public/simulation/templates/template_unit_champion.xml
+++ b/binaries/data/mods/public/simulation/templates/template_unit_champion.xml
@@ -14,4 +14,9 @@
     <stone>0</stone>
     <metal>20</metal>
   </Loot>
+  <Sound>
+    <SoundGroups>
+      <attacked>interface/alarm/alarm_attackplayer.xml</attacked>
+    </SoundGroups>
+  </Sound>
 </Entity>
diff --git a/binaries/data/mods/public/simulation/templates/template_unit_hero.xml b/binaries/data/mods/public/simulation/templates/template_unit_hero.xml
index b36b629..9e8daaa 100644
--- a/binaries/data/mods/public/simulation/templates/template_unit_hero.xml
+++ b/binaries/data/mods/public/simulation/templates/template_unit_hero.xml
@@ -60,6 +60,7 @@
   <Sound>
     <SoundGroups>
       <attack>attack/weapon/sword.xml</attack>
+      <attacked>interface/alarm/alarm_attackplayer.xml</attacked>
       <death>actor/human/death/death.xml</death>
     </SoundGroups>
   </Sound>
diff --git a/binaries/data/mods/public/simulation/templates/template_unit_infantry.xml b/binaries/data/mods/public/simulation/templates/template_unit_infantry.xml
index 427a03a..fe16b3b 100644
--- a/binaries/data/mods/public/simulation/templates/template_unit_infantry.xml
+++ b/binaries/data/mods/public/simulation/templates/template_unit_infantry.xml
@@ -92,6 +92,7 @@
   <Sound>
     <SoundGroups>
       <select>voice/hellenes/civ/civ_male_select.xml</select>
+      <attacked>interface/alarm/alarm_attackplayer.xml</attacked>
       <order_walk>voice/hellenes/civ/civ_male_ack.xml</order_walk>
       <order_attack>voice/hellenes/civ/civ_male_attack.xml</order_attack>
       <order_gather>voice/hellenes/civ/civ_male_ack.xml</order_gather>
diff --git a/binaries/data/mods/public/simulation/templates/template_unit_mechanical.xml b/binaries/data/mods/public/simulation/templates/template_unit_mechanical.xml
index 3a73cc7..67d63bd 100644
--- a/binaries/data/mods/public/simulation/templates/template_unit_mechanical.xml
+++ b/binaries/data/mods/public/simulation/templates/template_unit_mechanical.xml
@@ -21,4 +21,9 @@
     <stone>0</stone>
     <metal>25</metal>
   </Loot>
+  <Sound>
+    <SoundGroups>
+      <attacked>interface/alarm/alarm_attackplayer.xml</attacked>
+    </SoundGroups>
+  </Sound>
 </Entity>
diff --git a/binaries/data/mods/public/simulation/templates/template_unit_support.xml b/binaries/data/mods/public/simulation/templates/template_unit_support.xml
index 7c37c1a..a327fac 100644
--- a/binaries/data/mods/public/simulation/templates/template_unit_support.xml
+++ b/binaries/data/mods/public/simulation/templates/template_unit_support.xml
@@ -23,6 +23,7 @@
   <Sound>
     <SoundGroups>
       <trained>interface/alarm/alarm_create_worker.xml</trained>
+      <attacked>interface/alarm/alarm_attackplayer.xml</attacked>
     </SoundGroups>
   </Sound>
   <UnitAI>
diff --git a/source/gui/MiniMap.cpp b/source/gui/MiniMap.cpp
index ad1b7f9..793578b 100644
--- a/source/gui/MiniMap.cpp
+++ b/source/gui/MiniMap.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2012 Wildfire Games.
+/* Copyright (C) 2013 Wildfire Games.
  * This file is part of 0 A.D.
  *
  * 0 A.D. is free software: you can redistribute it and/or modify
@@ -69,6 +69,8 @@ static unsigned int ScaleColor(unsigned int color, float x)
 		m_ShallowPassageHeight = pathingSettings.GetChild("default").GetChild("MaxWaterDepth").ToFloat();
 	else
 		m_ShallowPassageHeight = 0.0f;
+
+	m_ChangePingColor = 0;
 }
 
 CMiniMap::~CMiniMap()
@@ -469,11 +471,40 @@ void CMiniMap::Draw()
 				v.a = 255;
 				v.x = posX.ToFloat()*sx;
 				v.y = -posZ.ToFloat()*sy;
+
+				// Check minimap pinging to indicate something
+				if (cmpMinimap->IsEntityPinging()) {
+
+					// Override the normal rendering of the entity with the ping color
+					// Note: If the pinged entity's dot is rendered over by another entity's
+					// dot then it will be invisible & the ping will be not be seen.
+					// We can try to move the pinged dots towards the end in the vertexArray
+					// Keep 2 pointers and insert pinged dots at end, unpinged at current position
+					if (m_ChangePingColor > PING_DURATION/2) {
+						v.r = 255; // bright red
+						v.g = 1;
+						v.b = 1;
+					}
+
+					// Must reduce ping count every frame
+					u32 pingCount = cmpMinimap->GetRemainingPingCount();
+					if (pingCount <= 0) {
+						// Also turns off ping flag if 0 passed in
+						cmpMinimap->SetRemainingPingCount(0);
+					}
+					else {
+						cmpMinimap->SetRemainingPingCount(pingCount - 1);
+					}
+				}
+
 				vertexArray.push_back(v);
 			}
 		}
 	}
 
+	// Cycle the ping color counter as needed
+	m_ChangePingColor = (m_ChangePingColor + 1) > PING_DURATION ? 0 : (m_ChangePingColor + 1);
+
 	if (!vertexArray.empty())
 	{
 		glEnableClientState(GL_VERTEX_ARRAY);
@@ -497,7 +528,7 @@ void CMiniMap::Draw()
 	}
 
 	PROFILE_END("minimap units");
-	
+
 	if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
 	{
 		tech->EndPass();
diff --git a/source/gui/MiniMap.h b/source/gui/MiniMap.h
index 4fbc34a..5c6c7a2 100644
--- a/source/gui/MiniMap.h
+++ b/source/gui/MiniMap.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2012 Wildfire Games.
+/* Copyright (C) 2013 Wildfire Games.
  * This file is part of 0 A.D.
  *
  * 0 A.D. is free software: you can redistribute it and/or modify
@@ -18,17 +18,26 @@
 #ifndef INCLUDED_MINIMAP
 #define INCLUDED_MINIMAP
 
+// GUI
 #include "gui/GUI.h"
 
+// Types
+#include "lib/types.h"
+
 class CCamera;
 class CTerrain;
 
+// Pinging constants - Controls blink duration of the ping, smaller means higher
+// ping frequency
+const unsigned int PING_DURATION = 50;
+
 class CMiniMap : public IGUIObject
 {
 	GUI_OBJECT(CMiniMap)
 public:
 	CMiniMap();
 	virtual ~CMiniMap();
+
 protected:
 	virtual void Draw();
 
@@ -81,6 +90,9 @@ class CMiniMap : public IGUIObject
 	// maximal water height to allow the passage of a unit (for underwater shallows).
 	float m_ShallowPassageHeight;
 
+	// For tracking the ping color
+	u32 m_ChangePingColor;
+
 	void DrawTexture(float coordMax, float angle, float x, float y, float x2, float y2, float z);
 
 	void DrawViewRect();
diff --git a/source/simulation2/MessageTypes.h b/source/simulation2/MessageTypes.h
index de8a31b..9ca5f9b 100644
--- a/source/simulation2/MessageTypes.h
+++ b/source/simulation2/MessageTypes.h
@@ -398,4 +398,17 @@ class CMessageVisionRangeChanged : public CMessage
 	entity_pos_t newRange;
 };
 
+/**
+ * Sent when an entity is pinged
+ */
+class CMessagePingOwner : public CMessage
+{
+public:
+	DEFAULT_MESSAGE_IMPL(PingOwner)
+
+	CMessagePingOwner() 
+	{
+	}
+};
+
 #endif // INCLUDED_MESSAGETYPES
diff --git a/source/simulation2/TypeList.h b/source/simulation2/TypeList.h
index f14848c..663f3e7 100644
--- a/source/simulation2/TypeList.h
+++ b/source/simulation2/TypeList.h
@@ -49,6 +49,7 @@
 MESSAGE(PathResult)
 MESSAGE(TechnologyModification)
 MESSAGE(VisionRangeChanged)
+MESSAGE(PingOwner)
 
 // TemplateManager must come before all other (non-test) components,
 // so that it is the first to be (de)serialized
diff --git a/source/simulation2/components/CCmpMinimap.cpp b/source/simulation2/components/CCmpMinimap.cpp
index ac8004d..fb3daf9 100644
--- a/source/simulation2/components/CCmpMinimap.cpp
+++ b/source/simulation2/components/CCmpMinimap.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2012 Wildfire Games.
+/* Copyright (C) 2013 Wildfire Games.
  * This file is part of 0 A.D.
  *
  * 0 A.D. is free software: you can redistribute it and/or modify
@@ -22,9 +22,11 @@
 
 #include "simulation2/components/ICmpPlayerManager.h"
 #include "simulation2/components/ICmpPlayer.h"
+#include "simulation2/components/ICmpOwnership.h"
 #include "simulation2/MessageTypes.h"
 
 #include "ps/Overlay.h"
+#include "ps/Game.h"
 
 class CCmpMinimap : public ICmpMinimap
 {
@@ -33,6 +35,7 @@ class CCmpMinimap : public ICmpMinimap
 	{
 		componentManager.SubscribeToMessageType(MT_PositionChanged);
 		componentManager.SubscribeToMessageType(MT_OwnershipChanged);
+		componentManager.SubscribeToMessageType(MT_PingOwner);
 	}
 
 	DEFAULT_COMPONENT_ALLOCATOR(Minimap)
@@ -48,6 +51,15 @@ class CCmpMinimap : public ICmpMinimap
 	bool m_Active;
 	entity_pos_t m_X, m_Z; // cache the latest position for more efficient rendering; only valid when m_Active true
 
+
+	// Used by the minimap while pinging this entity to indicate something (e.g. an attack)
+	// Entity not pinged after MAX_PING_TURNS if it wasn't notified in between
+	static const u32 MAX_PING_FRAMES = 500;
+	bool m_PingEntity;
+	u32 m_PingCount;
+
+
+
 	static std::string GetSchema()
 	{
 		return
@@ -82,6 +94,7 @@ class CCmpMinimap : public ICmpMinimap
 	virtual void Init(const CParamNode& paramNode)
 	{
 		m_Active = true;
+		m_PingEntity = false;
 
 		const CParamNode& colour = paramNode.GetChild("Colour");
 		if (colour.IsOk())
@@ -183,6 +196,25 @@ class CCmpMinimap : public ICmpMinimap
 
 			break;
 		}
+		case MT_PingOwner:
+		{
+			// UNUSED: const CMessagePingOwner& data = static_cast<const CMessagePingOwner&> (msg);
+
+			if (!g_Game)
+				break;
+
+			CmpPtr<ICmpOwnership> cmpOwnership(GetSimContext(), GetEntityId());
+			if (!cmpOwnership)
+				break;
+			if(g_Game->GetPlayerID() != (int)cmpOwnership->GetOwner())
+				break;
+
+			m_Active = true;
+			m_PingEntity = true;
+			m_PingCount = MAX_PING_FRAMES;
+
+			break;
+		}
 		}
 	}
 
@@ -198,6 +230,27 @@ class CCmpMinimap : public ICmpMinimap
 		z = m_Z;
 		return true;
 	}
+
+	virtual bool IsEntityPinging(void)
+	{
+		if (!m_Active)
+			return false;
+
+		return m_PingEntity;
+	}
+
+	virtual u32 GetRemainingPingCount(void)
+	{
+		return m_PingCount;
+	}
+
+	virtual void SetRemainingPingCount(u32 pingCount)
+	{
+		m_PingCount = pingCount;
+
+		if (m_PingCount == 0)
+			m_PingEntity = false;
+	}
 };
 
 REGISTER_COMPONENT_TYPE(Minimap)
diff --git a/source/simulation2/components/ICmpMinimap.h b/source/simulation2/components/ICmpMinimap.h
index e2ebf9b..fe906dd 100644
--- a/source/simulation2/components/ICmpMinimap.h
+++ b/source/simulation2/components/ICmpMinimap.h
@@ -35,6 +35,21 @@ class ICmpMinimap : public IComponent
 	 */
 	virtual bool GetRenderData(u8& r, u8& g, u8& b, entity_pos_t& x, entity_pos_t& z) = 0;
 
+	/**
+	 * Returns true if the unit is pinging.
+	 */
+	virtual bool IsEntityPinging(void) = 0;
+
+	/**
+	 * Returns the current ping count.
+	 */
+	virtual u32 GetRemainingPingCount(void) = 0;
+
+	/**
+	 * Used by the minimap to set the ping count, controls pinging.
+	 */
+	virtual void SetRemainingPingCount(u32 pingCount) = 0;
+
 	DECLARE_INTERFACE_TYPE(Minimap)
 };
 
diff --git a/source/simulation2/scripting/MessageTypeConversions.cpp b/source/simulation2/scripting/MessageTypeConversions.cpp
index c4109d7..9160b07 100644
--- a/source/simulation2/scripting/MessageTypeConversions.cpp
+++ b/source/simulation2/scripting/MessageTypeConversions.cpp
@@ -336,6 +336,20 @@ CMessage* CMessageVisionRangeChanged::FromJSVal(ScriptInterface& scriptInterface
 	return new CMessageVisionRangeChanged(entity, oldRange, newRange);
 }
 
+////////////////////////////////
+
+jsval CMessagePingOwner::ToJSVal(ScriptInterface& scriptInterface) const
+{
+	TOJSVAL_SETUP();
+	return OBJECT_TO_JSVAL(obj);
+}
+
+CMessage* CMessagePingOwner::FromJSVal(ScriptInterface& UNUSED(scriptInterface), jsval UNUSED(val))
+{
+	// FROMJSVAL_SETUP();
+	return new CMessagePingOwner();
+}
+
 ////////////////////////////////////////////////////////////////
 
 CMessage* CMessageFromJSVal(int mtid, ScriptInterface& scriptingInterface, jsval val)
