Index: 0ad/binaries/data/mods/public/simulation/components/PlayerManager.js
===================================================================
--- 0ad/binaries/data/mods/public/simulation/components/PlayerManager.js	(revision 13411)
+++ 0ad/binaries/data/mods/public/simulation/components/PlayerManager.js	(working copy)
@@ -45,5 +45,8 @@
 	}
 	this.playerEntities = [];
 };
-
+PlayerManager.prototype.GetAllPlayers = function()
+{
+	return this.playerEntities;
+};
 Engine.RegisterComponentType(IID_PlayerManager, "PlayerManager", PlayerManager);
Index: 0ad/binaries/data/mods/public/simulation/components/GuiInterface.js
===================================================================
--- 0ad/binaries/data/mods/public/simulation/components/GuiInterface.js	(revision 13411)
+++ 0ad/binaries/data/mods/public/simulation/components/GuiInterface.js	(working copy)
@@ -1759,8 +1759,16 @@
 	"SetObstructionDebugOverlay": 1,
 	"SetMotionDebugOverlay": 1,
 	"SetRangeDebugOverlay": 1,
+	"TestSD": 1,
 };
 
+GuiInterface.prototype.TestSD = function(pl, d)
+{
+	var dm = Engine.QueryInterface(SYSTEM_ENTITY, IID_Damage);
+	if (!dm) warn("IID_Damage is returning " + dm);
+	else return dm.CauseSplashDamage({"origin":{"x":d.x, "z":d.z}, "shape":"circular", "radius":d.r, "playersToDamage":undefined, "direction":undefined, "strengths":{"hack":20.0, "pierce":20.0, "crush":20.0}});
+};
+
 GuiInterface.prototype.ScriptCall = function(player, name, args)
 {
 	if (exposedFunctions[name])
Index: 0ad/binaries/data/mods/public/simulation/components/Damage.js
===================================================================
--- 0ad/binaries/data/mods/public/simulation/components/Damage.js	(revision 0)
+++ 0ad/binaries/data/mods/public/simulation/components/Damage.js	(working copy)
@@ -0,0 +1,69 @@
+function Damage() {}
+
+Damage.prototype.Schema = "<a:component type='system'/><empty/>";
+
+/* Damages units around a given origin.
+ * The data parameter should contain {"origin":{'x':<int>, 'z':<int>}, 'shape':<'circular' or 'linear'>, 'radius':<int>, 'playersToDamage':<array>, 'direction':<x and z which form a vector from the origin>, 'strengths':{'hack':<float>, 'pierce':<float>, 'crush':<float>}}
+ */
+Damage.prototype.CauseSplashDamage = function(data)
+{
+	// Get nearby entities and define variables
+	var nearEnts = this.EntitiesNearPoint(data.origin, data.radius, data.playersToDamage);
+	var damageMultiplier = 1;
+	// Cycle through all the nearby entities and damage it appropriatly based on its disance from the origin.
+	for each (var entity in nearEnts)
+	{
+		var entityPosition = Engine.QueryInterface(entity, IID_Position).GetPosition();
+		var squaredDistanceFromorigin = this.VectorDistanceSquared(data.origin, entityPosition);
+		if(shape=='circular') // circular effect with quadratic falloff in every direction
+		{
+			damageMultiplier == 1 - ((squaredDistanceFromOrgin) / (data.radius * data.radius));
+		}
+		else if(shape=='linear') // linear effect with quadratic falloff in two directions (only used for certain missiles)
+		{
+			warn("Not Implemented");
+		}
+		else
+		{
+			warn("Not Implemented");
+		}
+		var cmpDamageReceiver = Engine.QueryInterface(entity, IID_DamageReceiver);
+		if (cmpDamageReceiver)
+			cmpDamageReceiver.TakeDamage(strengths.hack * damageMultiplier, strengths.pierce * damageMultiplier, strengths.crush * damageMultiplier);
+	}
+};
+
+/* Gets entities near a give point for given players.
+ * origin = {'x':<int>, 'z':<int>}
+ * radius = <int>
+ * players = <array>
+ * If players is not included, entities from all players are returned.
+ */
+Damage.prototype.EntitiesNearPoint = function(origin, radius, players)
+{
+	if(!origin || !radius) return [];
+	// Make a dummy entity at origin then call range manager with dummy entity
+	var dummyTargetEntity = Engine.AddEntity();
+	var cmpDummyPosition = Engine.QueryInterface(dummyTargetEntity, IID_Position);
+	cmpDummyPosition.moveTo(origin.x, origin.z);
+	var rangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
+	if(players)
+	{
+		var rangeQuery = rangeManager.ExecuteQuery(dummyTargetEntity, 0, radius, players, IID_DamageReceiver);
+	}
+	else
+	{
+		var allPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetAllPlayers;
+		var rangeQuery = rangeManager.ExecuteQuery(dummyTargetEntity, 0, radius, allPlayers, IID_DamageReceiver);
+	}
+	Engine.DestroyEntity(dummyTargetEntity);
+	return rangeQuery;
+};
+
+// Gets the straight line distance between p1 and p2
+Damage.prototype.VectorDistanceSquared = function(p1, p2)
+{
+	return ((p1.x - p2.x)*(p1.x - p2.x) + (p1.z - p2.z)*(p1.z - p2.z));
+};
+
+Engine.RegisterComponentType(IID_Damage, "Damage", Damage);
Index: 0ad/binaries/data/mods/public/simulation/components/interfaces/Damage.js
===================================================================
--- 0ad/binaries/data/mods/public/simulation/components/interfaces/Damage.js	(revision 0)
+++ 0ad/binaries/data/mods/public/simulation/components/interfaces/Damage.js	(working copy)
@@ -0,0 +1 @@
+Engine.RegisterInterface("Damage");
Index: 0ad/source/simulation2/Simulation2.cpp
===================================================================
--- 0ad/source/simulation2/Simulation2.cpp	(revision 13411)
+++ 0ad/source/simulation2/Simulation2.cpp	(working copy)
@@ -127,6 +127,7 @@
 			LOAD_SCRIPTED_COMPONENT("PlayerManager");
 			LOAD_SCRIPTED_COMPONENT("TechnologyTemplateManager");
 			LOAD_SCRIPTED_COMPONENT("Timer");
+			LOAD_SCRIPTED_COMPONENT("Damage");
 
 #undef LOAD_SCRIPTED_COMPONENT
 
