Index: binaries/data/mods/public/maps/random/survivalofthefittest_triggers.js
===================================================================
--- binaries/data/mods/public/maps/random/survivalofthefittest_triggers.js	(revision 18434)
+++ binaries/data/mods/public/maps/random/survivalofthefittest_triggers.js	(working copy)
@@ -1,5 +1,8 @@
-var treasures =
-[
+/*
+ * This is the Script containing all the Triggers for the "Survival of the Fittest" Map.
+ */
+
+var treasures = [
 	"gaia/special_treasure_food_barrel",
 	"gaia/special_treasure_food_bin",
 	"gaia/special_treasure_food_crate",
@@ -10,36 +13,42 @@
 	"gaia/special_treasure_wood",
 	"gaia/special_treasure_wood"
 ];
-var attackerEntityTemplates =
-[
+
+var resourceLoopCount = 0;
+
+var resourceLoopTime = 1.25; // Time in minutes when resources are distributed periodically without random offset.
+var resourceLoopOffset = 14 + 2 * Math.random(); // Time in minutes after which resources are distributed periodically.
+
+// These are the templates of the attacking units, sorted by civ
+var attackerEntityTemplates = [
 	[
 		"units/athen_champion_infantry",
 		"units/athen_champion_marine",
 		"units/athen_champion_ranged",
-		"units/athen_siege_lithobolos_packed",
-		"units/athen_siege_oxybeles_packed",
+		"units/athen_mechanical_siege_lithobolos_packed",
+		"units/athen_mechanical_siege_oxybeles_packed"
 	],
 	[
 		"units/brit_champion_cavalry",
 		"units/brit_champion_infantry",
-		"units/brit_mechanical_siege_ram",
+		"units/brit_mechanical_siege_ram"
 	],
 	[
 		"units/cart_champion_cavalry",
 		"units/cart_champion_elephant",
 		"units/cart_champion_infantry",
-		"units/cart_champion_pikeman",
+		"units/cart_champion_pikeman"
 	],
 	[
 		"units/gaul_champion_cavalry",
 		"units/gaul_champion_fanatic",
 		"units/gaul_champion_infantry",
-		"units/gaul_mechanical_siege_ram",
+		"units/gaul_mechanical_siege_ram"
 	],
 	[
 		"units/iber_champion_cavalry",
 		"units/iber_champion_infantry",
-		"units/iber_mechanical_siege_ram",
+		"units/iber_mechanical_siege_ram"
 	],
 	[
 		"units/mace_champion_cavalry",
@@ -46,7 +55,7 @@
 		"units/mace_champion_infantry_a",
 		"units/mace_champion_infantry_e",
 		"units/mace_mechanical_siege_lithobolos_packed",
-		"units/mace_mechanical_siege_oxybeles_packed",
+		"units/mace_mechanical_siege_oxybeles_packed"
 	],
 	[
 		"units/maur_champion_chariot",
@@ -53,22 +62,23 @@
 		"units/maur_champion_elephant",
 		"units/maur_champion_infantry",
 		"units/maur_champion_maiden",
-		"units/maur_champion_maiden_archer",
+		"units/maur_champion_maiden_archer"
 	],
 	[
 		"units/pers_champion_cavalry",
-		"units/pers_champion_infantry",
 		"units/pers_champion_elephant",
+		"units/pers_champion_infantry"
+
 	],
 	[
 		"units/ptol_champion_cavalry",
-		"units/ptol_champion_elephant",
+		"units/ptol_champion_elephant"
 	],
 	[
 		"units/rome_champion_cavalry",
 		"units/rome_champion_infantry",
 		"units/rome_mechanical_siege_ballista_packed",
-		"units/rome_mechanical_siege_scorpio_packed",
+		"units/rome_mechanical_siege_scorpio_packed"
 	],
 	[
 		"units/sele_champion_cavalry",
@@ -75,13 +85,13 @@
 		"units/sele_champion_chariot",
 		"units/sele_champion_elephant",
 		"units/sele_champion_infantry_pikeman",
-		"units/sele_champion_infantry_swordsman",
+		"units/sele_champion_infantry_swordsman"
 	],
 	[
 		"units/spart_champion_infantry_pike",
 		"units/spart_champion_infantry_spear",
 		"units/spart_champion_infantry_sword",
-		"units/spart_mechanical_siege_ram",
+		"units/spart_mechanical_siege_ram"
 	],
 ];
 
@@ -93,8 +103,8 @@
 	let nextTime = Math.round(120000 + Math.random() * 60000);
 	let attackerCount = Math.round(cmpTimer.GetTime() / nextTime / attackerEntities.length);
 
-	// spawn attackers
-	let attackers =  [];
+	// Spawn attackers
+	let attackers = [];
 	for (let attackerEntity of attackerEntities)
 		attackers.push(TriggerHelper.SpawnUnitsFromTriggerPoints("A", attackerEntity, attackerCount, 0));
 
@@ -103,21 +113,21 @@
 		for (let origin in entityType)
 		{
 			let cmpPlayer = QueryOwnerInterface(+origin, IID_Player);
-			if (cmpPlayer.GetState() != "active")
+			if (!cmpPlayer || !cmpTrigger.playerCivicCenter[cmpPlayer.GetPlayerID()])
 				continue;
 
-			let cmpPosition =  Engine.QueryInterface(this.playerCivicCenter[cmpPlayer.GetPlayerID()], IID_Position);
-			// this shouldn't happen if the player is still active
+			let cmpPosition = Engine.QueryInterface(cmpTrigger.playerCivicCenter[cmpPlayer.GetPlayerID()], IID_Position);
+			// This shouldn't happen if the player is still active
 			if (!cmpPosition || !cmpPosition.IsInWorld)
 				continue;
 
-			// store the x and z coordinates in the command
+			// Store the x and z coordinates in the command
 			let cmd = cmpPosition.GetPosition();
 			cmd.type = "attack-walk";
 			cmd.entities = entityType[origin];
 			cmd.queued = true;
 			cmd.targetClasses = undefined;
-			// send the attack-walk command
+			// Send the attack-walk command
 			ProcessCommand(0, cmd);
 		}
 	}
@@ -130,18 +140,36 @@
 	cmpTrigger.DoAfterDelay(nextTime, "StartAnEnemyWave", {}); // The next wave will come in 3 minutes
 };
 
+/*
+ * The main init function, called at the start
+ */
 Trigger.prototype.InitGame = function()
 {
 	let numberOfPlayers = TriggerHelper.GetNumberOfPlayers();
-	// Find all of the civic centers, disable some structures
+	// Find all of the civic centers and females, disable some structures, setup activity watch
 	for (let i = 1; i < numberOfPlayers; ++i)
 	{
+		/*// At first, determine how many players are actually playing (humans)
+		let cmpPlayer = TriggerHelper.GetPlayerComponent(i);
+		warn(cmpPlayer.GetState());*/
+
+		// Now handle the other stuff
 		let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
 		let playerEntities = cmpRangeManager.GetEntitiesByPlayer(i); // Get all of each player's entities
 
 		for (let entity of playerEntities)
+		{
 			if (TriggerHelper.EntityHasClass(entity, "CivilCentre"))
 				cmpTrigger.playerCivicCenter[i] = entity;
+			if (TriggerHelper.EntityHasClass(entity, "Female"))
+			{
+				let cmpDamageReceiver = Engine.QueryInterface(entity, IID_DamageReceiver);
+				cmpDamageReceiver.SetInvulnerability(true);
+
+				let cmpHealth = Engine.QueryInterface(entity, IID_Health);
+				cmpHealth.SetUndeletability(true);
+			}
+		}
 	}
 
 	// Fix alliances
@@ -183,27 +211,73 @@
 	let triggerPoints = cmpTrigger.GetTriggerPoints(point);
 	for (let point of triggerPoints)
 	{
-		let template = treasures[Math.floor(Math.random() * treasures.length)]
-		TriggerHelper.SpawnUnits(point, template, 1, 0);
+		let template = treasures[Math.floor(Math.random() * treasures.length)];
+		let cmpPosition = Engine.QueryInterface(point, IID_Position);
+		let ent = Engine.AddEntity(template);
+
+		let cmpEntOwnership = Engine.QueryInterface(ent, IID_Ownership);
+		let cmpEntPosition = Engine.QueryInterface(ent, IID_Position);
+
+		if (cmpEntOwnership)
+			cmpEntOwnership.SetOwner(0);
+
+		let xOffset = RandomInt(0,23);
+		let zOffset = RandomInt(0,23);
+
+		if (Math.random() >= 0.8 )
+		{
+			xOffset += RandomInt(5,8);
+			zOffset += RandomInt(5,8);
+		}
+
+		if (Math.round(Math.random()) == 1)
+			xOffset = xOffset * -1;
+
+		if (Math.round(Math.random()) == 1)
+			zOffset = zOffset * -1;
+
+		cmpEntPosition.JumpTo(cmpPosition.GetPosition().x + xOffset, cmpPosition.GetPosition().z - zOffset);
 	}
-	cmpTrigger.DoAfterDelay(4*60*1000, "PlaceTreasures", {}); //Place more treasures after 4 minutes
+	let time = (3 + Math.random()) * 60 * 1000; // Place more treasures after 3-4 minutes
+	cmpTrigger.DoAfterDelay(time, "PlaceTreasures", {});
+
+	let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
+	cmpGUIInterface.PushNotification({
+		"message": markForTranslation("New treasures have been placed!"),
+		"translateMessage": true
+	});
 };
 
+/*
+ * This function starts the timer for the waves
+ */
 Trigger.prototype.InitializeEnemyWaves = function()
 {
 	let time = (5 + Math.round(Math.random() * 10)) * 60 * 1000;
 	let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
+	cmpGUIInterface.PushNotification({
+		"message": markForTranslation("Welcome to Survival of the Fittest"),
+		"translateMessage": true
+	});
+	cmpGUIInterface.PushNotification({
+		"message": markForTranslation("Collect treasures with your woman to prepare for the enemies."),
+		"translateMessage": true
+	});
 	cmpGUIInterface.AddTimeNotification({
 		"message": markForTranslation("The first wave will start in %(time)s!"),
 		"translateMessage": true
 	}, time);
+
 	cmpTrigger.DoAfterDelay(time, "StartAnEnemyWave", {});
 };
 
+/*
+ * DefeatPlayerOnceCCIsDestroyed occurs when a unit dies, and checks for anything to be done in case its a civic center
+ */
 Trigger.prototype.DefeatPlayerOnceCCIsDestroyed = function(data)
 {
 	// Defeat a player that has lost his civic center
-	if (data.entity == cmpTrigger.playerCivicCenter[data.from])
+	if (data.entity == cmpTrigger.playerCivicCenter[data.from] && data.to == -1)
 	{
 		TriggerHelper.DefeatPlayer(data.from);
 
@@ -224,9 +298,42 @@
 	}
 };
 
+/*
+ * This function is constantly Looping and provides resources to all players.
+ * It starts after resourceLoopOffset
+ */
+Trigger.prototype.ResourceLoop = function(data)
+{
+	++resourceLoopCount;
+
+	if (resourceLoopCount == 1)
+	{
+		let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
+		cmpGUIInterface.PushNotification({
+			"message": markForTranslation("From now on, all players will receive some resources from time to time"),
+			"translateMessage": true
+		});
+	}
+
+	let numberOfPlayers = TriggerHelper.GetNumberOfPlayers();
+	for (let i = 1; i < numberOfPlayers; ++i)
+	{
+		let cmpPlayer = QueryPlayerIDInterface(i);
+		cmpPlayer.AddResources({
+			"wood": 100,
+			"stone": 100,
+			"metal": 100,
+			"food": 100
+		});
+	}
+	cmpTrigger.DoAfterDelay((resourceLoopTime + Math.random() / 2) * 60 * 1000, "ResourceLoop" , {});
+};
+
 var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
 cmpTrigger.playerCivicCenter = {};
+
 cmpTrigger.DoAfterDelay(0, "InitGame", {});
 cmpTrigger.DoAfterDelay(1000, "InitializeEnemyWaves", {});
+cmpTrigger.DoAfterDelay(resourceLoopOffset * 60 * 1000, "ResourceLoop" , {});
 
 cmpTrigger.RegisterTrigger("OnOwnershipChanged", "DefeatPlayerOnceCCIsDestroyed", { "enabled": true });
Index: binaries/data/mods/public/simulation/components/Health.js
===================================================================
--- binaries/data/mods/public/simulation/components/Health.js	(revision 18434)
+++ binaries/data/mods/public/simulation/components/Health.js	(working copy)
@@ -63,6 +63,7 @@
 	this.hitpoints = +(this.template.Initial || this.GetMaxHitpoints());
 	this.regenRate = ApplyValueModificationsToEntity("Health/RegenRate", +this.template.RegenRate, this.entity);
 	this.idleRegenRate = ApplyValueModificationsToEntity("Health/IdleRegenRate", +this.template.IdleRegenRate, this.entity);
+	this.undeletable = this.template.Undeletable;
 	this.CheckRegenTimer();
 	this.UpdateActor();
 };
@@ -123,9 +124,14 @@
 
 Health.prototype.IsUndeletable = function()
 {
-	return this.template.Undeletable == "true";
+	return this.undeletable;
 };
 
+Health.prototype.SetUndeletability = function(undeletability)
+{
+	this.undeletable = undeletability;
+};
+
 Health.prototype.GetIdleRegenRate = function()
 {
 	return this.idleRegenRate;
