Index: binaries/data/mods/public/globalscripts/random.js
===================================================================
--- binaries/data/mods/public/globalscripts/random.js	(nonexistent)
+++ binaries/data/mods/public/globalscripts/random.js	(working copy)
@@ -0,0 +1,49 @@
+// TODO: rename/change these functions, so the bounds are more clear
+
+/*
+ * Return a random floating point number using Math.random library
+ *
+ * If no parameter given, the returned float is in the interval [0, 1)
+ * If one parameter given, it's maxval, and the returned float is in the interval [0, maxval)
+ * If two parameters are given, they are minval and maxval, and the returned float is in the interval [minval, maxval)
+ */
+function randFloat()
+{
+	if (arguments.length == 0)
+		return Math.random();
+	else if (arguments.length == 1)
+		return randFloat() * arguments[0];
+	else if (arguments.length == 2)
+	{
+		let minVal = arguments[0]; 
+		let maxVal = arguments[1];
+		return minVal + randFloat() * (maxVal - minVal);
+	}
+	else
+	{
+		error("randFloat: invalid number of arguments: "+arguments.length);
+		return undefined;
+	}
+}
+
+/*
+ * Return a random integer using Math.random library
+ *
+ * If no parameter given, the returned integer is in the interval [0, 1]
+ * If one parameter given, it's maxval, and the returned integer is in the interval [0, maxval)
+ * If two parameters are given, they are minval and maxval, and the returned integer is in the interval [minval, maxval]
+ */
+function randInt()
+{
+	if (arguments.length == 0)
+		return Math.round(randFloat());
+	else if (arguments.length == 1)
+		return Math.floor(randFloat(arguments[0]));
+	else if (arguments.length == 2)
+		return Math.floor(randFloat(arguments[0], arguments[1]));
+	else
+	{
+		error("randInt: invalid number of arguments: "+arguments.length);
+		return undefined;
+	}
+}
Index: binaries/data/mods/public/maps/random/rmgen/random.js
===================================================================
--- binaries/data/mods/public/maps/random/rmgen/random.js	(revision 18600)
+++ binaries/data/mods/public/maps/random/rmgen/random.js	(nonexistent)
@@ -1,54 +0,0 @@
-// TODO: rename/change these functions, so the bounds are more clear
-
-/*
- * Return a random floating point number using Math.random library
- *
- * If no parameter given, the returned float is in the interval [0, 1)
- * If two parameters are given, they are minval and maxval, and the returned float is in the interval [minval, maxval)
- */
-function randFloat()
-{
-	if (arguments.length == 0)
-	{
-		return Math.random();
-	}
-	else if (arguments.length == 2)
-	{
-		var minVal = arguments[0]; 
-		var maxVal = arguments[1];
-		
-		return minVal + randFloat() * (maxVal - minVal);
-	}
-	else
-	{
-		error("randFloat: invalid number of arguments: "+arguments.length);
-		return undefined;
-	}
-}
-
-/*
- * Return a random integer using Math.random library
- *
- * If one parameter given, it's maxval, and the returned integer is in the interval [0, maxval)
- * If two parameters are given, they are minval and maxval, and the returned integer is in the interval [minval, maxval]
- */
-function randInt()
-{	
-	if (arguments.length == 1)
-	{
-		var maxVal = arguments[0]; 
-		return Math.floor(Math.random() * maxVal);
-	}
-	else if (arguments.length == 2)
-	{
-		var minVal = arguments[0];
-		var maxVal = arguments[1];
-		
-		return minVal + randInt(maxVal - minVal + 1);
-	}
-	else
-	{
-		error("randInt: invalid number of arguments: "+arguments.length);
-		return undefined;
-	}
-}

Property changes on: binaries/data/mods/public/maps/random/rmgen/random.js
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Index: binaries/data/mods/public/maps/random/survivalofthefittest.js
===================================================================
--- binaries/data/mods/public/maps/random/survivalofthefittest.js	(revision 18600)
+++ binaries/data/mods/public/maps/random/survivalofthefittest.js	(working copy)
@@ -198,7 +198,7 @@
 	);
 	createArea(placer, [terrainPainter, elevationPainter, paintClass(clWater)], null);
 	
-	//creating female citizens
+	// Creating seeker woman (these need to have a lower ID than other starting woman for InitGame to identify them)
 	var femaleLocation = getTIPIADBON([ix, iz], [mapSize / 2, mapSize / 2], [-3 , 3.5], 1, 3);
 	if (femaleLocation !== undefined)
 	{
Index: binaries/data/mods/public/maps/random/survivalofthefittest_triggers.js
===================================================================
--- binaries/data/mods/public/maps/random/survivalofthefittest_triggers.js	(revision 18600)
+++ binaries/data/mods/public/maps/random/survivalofthefittest_triggers.js	(working copy)
@@ -1,5 +1,39 @@
-var treasures =
-[
+/**
+ * Time in minutes to the first enemy wave.
+ */
+var firstAttackWave = [5, 15];
+
+/**
+ * Time after which resources are distributed periodically.
+ */
+var provideResourcesOffset = [14, 16];
+
+/**
+ * Time interval between enemy waves.
+ */
+var attackerWaveInterval = [2, 3];
+
+/**
+ * Time interval when treasures are distributed periodically.
+ */
+var treasureInterval = [3, 4];
+
+/**
+ * Time interval after which resources are distributed periodically.
+ */
+var provideResourcesInterval = [1.25, 1.75];
+
+/**
+ * Amount interval of resources distributed.
+ */
+var resourceAmountInterval = [50, 150];
+
+/**
+ * Amount of miliseconds in minute.
+ */
+const minutes = 60 * 1000;
+
+var treasures = [
 	"gaia/special_treasure_food_barrel",
 	"gaia/special_treasure_food_bin",
 	"gaia/special_treasure_food_crate",
@@ -10,14 +44,17 @@
 	"gaia/special_treasure_wood",
 	"gaia/special_treasure_wood"
 ];
-var attackerEntityTemplates =
-[
+
+/**
+ * Templates of the attacking units, sorted by civ
+ */
+var attackerTemplates = [
 	[
 		"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",
@@ -88,39 +125,39 @@
 Trigger.prototype.StartAnEnemyWave = function()
 {
 	let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
-	let attackerEntities = attackerEntityTemplates[Math.floor(Math.random() * attackerEntityTemplates.length)];
-	// A soldier for each 2-3 minutes of the game. Should be waves of 20 soldiers after an hour
-	let nextTime = Math.round(120000 + Math.random() * 60000);
-	let attackerCount = Math.round(cmpTimer.GetTime() / nextTime / attackerEntities.length);
+	let templates = attackerTemplates[Math.floor(Math.random() * attackerTemplates.length)];
+	let nextTime = randFloat(attackerWaveInterval[0], attackerWaveInterval[1]) * minutes;
+	let attackerCount = Math.ceil(cmpTimer.GetTime() / nextTime / templates.length);
 
-	// spawn attackers
-	let attackers =  [];
-	for (let attackerEntity of attackerEntities)
-		attackers.push(TriggerHelper.SpawnUnitsFromTriggerPoints("A", attackerEntity, attackerCount, 0));
+	let attackers = templates.map(ent =>
+		TriggerHelper.SpawnUnitsFromTriggerPoints("A", ent, attackerCount, 0));
 
 	for (let entityType of attackers)
-	{
 		for (let origin in entityType)
 		{
+			// Destroy attackers for non active players
 			let cmpPlayer = QueryOwnerInterface(+origin, IID_Player);
-			if (cmpPlayer.GetState() != "active")
+			if (!cmpPlayer || !cmpTrigger.playerCivicCenter[cmpPlayer.GetPlayerID()])
+			{
+				Engine.DestroyEntity(+entityType[origin])
 				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
-			let cmd = cmpPosition.GetPosition();
-			cmd.type = "attack-walk";
-			cmd.entities = entityType[origin];
-			cmd.queued = true;
-			cmd.targetClasses = undefined;
-			// send the attack-walk command
-			ProcessCommand(0, cmd);
+			let pos = cmpPosition.GetPosition();
+			ProcessCommand(0, {
+				"type": "attack-walk",
+				"entities": entityType[origin],
+				"x": pos.x,
+				"z": pos.z,
+				"targetClasses": undefined, 
+				"queued": true
+			});
 		}
-	}
 
 	let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
 	cmpGUIInterface.PushNotification({
@@ -127,21 +164,40 @@
 		"message": markForTranslation("An enemy wave is attacking!"),
 		"translateMessage": true
 	});
-	cmpTrigger.DoAfterDelay(nextTime, "StartAnEnemyWave", {}); // The next wave will come in 3 minutes
+	cmpTrigger.DoAfterDelay(nextTime, "StartAnEnemyWave", {});
 };
 
+/**
+ * Find all of the civic centers and females, disable some structures, setup activity watch.
+ */
 Trigger.prototype.InitGame = function()
 {
+	// Set random offset on consts
+	firstAttackWave = randFloat(firstAttackWave[0], firstAttackWave[1]);
+	provideResourcesOffset = randFloat(provideResourcesOffset[0], provideResourcesOffset[1]);
+
 	let numberOfPlayers = TriggerHelper.GetNumberOfPlayers();
-	// Find all of the civic centers, disable some structures
 	for (let i = 1; i < numberOfPlayers; ++i)
 	{
 		let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
 		let playerEntities = cmpRangeManager.GetEntitiesByPlayer(i); // Get all of each player's entities
 
+		let foundSeeker = false;
 		for (let entity of playerEntities)
+		{
 			if (TriggerHelper.EntityHasClass(entity, "CivilCentre"))
 				cmpTrigger.playerCivicCenter[i] = entity;
+
+			if (TriggerHelper.EntityHasClass(entity, "Female") && !foundSeeker)
+			{
+				foundSeeker = true;
+				let cmpDamageReceiver = Engine.QueryInterface(entity, IID_DamageReceiver);
+				cmpDamageReceiver.SetInvulnerability(true);
+
+				let cmpHealth = Engine.QueryInterface(entity, IID_Health);
+				cmpHealth.SetUndeletable(true);
+			}
+		}
 	}
 
 	// Fix alliances
@@ -158,7 +214,6 @@
 	// Make gaia black
 	QueryPlayerIDInterface(0).SetColor(0, 0, 0);
 
-	// Place the treasures
 	this.PlaceTreasures();
 
 	// Disable farms, civic centers and walls for all players
@@ -166,6 +221,7 @@
 	{
 		let cmpPlayer = QueryPlayerIDInterface(i);
 		let civ = cmpPlayer.GetCiv();
+
 		cmpPlayer.SetDisabledTemplates([
 			"structures/" + civ + "_field",
 			"structures/" + civ + "_corral",
@@ -172,6 +228,7 @@
 			"structures/" + civ + "_civil_centre",
 			"structures/" + civ + "_military_colony",
 			"structures/" + civ + "_wallset_stone",
+			"structures/brit_crannog",
 			"other/wallset_palisade"
 		]);
 	}
@@ -183,16 +240,58 @@
 	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 = randInt(0, 23);
+		let zOffset = randInt(0, 23);
+
+		if (Math.random() >= 0.8)
+		{
+			xOffset += randInt(5, 8);
+			zOffset += randInt(5, 8);
+		}
+
+		if (Math.round(Math.random()) == 1)
+			xOffset = -xOffset;
+
+		if (Math.round(Math.random()) == 1)
+			zOffset = -zOffset;
+
+		cmpEntPosition.JumpTo(cmpPosition.GetPosition().x + xOffset, cmpPosition.GetPosition().z - zOffset);
 	}
-	cmpTrigger.DoAfterDelay(4*60*1000, "PlaceTreasures", {}); //Place more treasures after 4 minutes
+
+	cmpTrigger.DoAfterDelay(randFloat(treasureInterval[0], treasureInterval[1]) * minutes, "PlaceTreasures", {});
+
+	let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
+	cmpGUIInterface.PushNotification({
+		"message": markForTranslation("New treasures have been placed!"),
+		"translateMessage": true
+	});
 };
 
 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
+	});
+
+	let time = firstAttackWave * minutes;
 	cmpGUIInterface.AddTimeNotification({
 		"message": markForTranslation("The first wave will start in %(time)s!"),
 		"translateMessage": true
@@ -202,31 +301,37 @@
 
 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);
+};
 
-		// Check if only one player remains. He will be the winner.
-		let lastPlayerStanding = 0;
-		let numPlayersStanding = 0;
-		let numberOfPlayers = TriggerHelper.GetNumberOfPlayers();
-		for (let i = 1; i < numberOfPlayers; ++i)
-		{
-			if (QueryPlayerIDInterface(i).GetState() == "active")
-			{
-				lastPlayerStanding = i;
-				++numPlayersStanding;
-			}
-		}
-		if (numPlayersStanding == 1)
-			TriggerHelper.SetPlayerWon(lastPlayerStanding);
+Trigger.prototype.ProvideResources = function(data)
+{
+	if (data.first)
+	{
+		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 resources = {};
+	for (let type of ["food", "wood", "stone", "metal"])
+		resources[type] = randInt(resourceAmountInterval[0], resourceAmountInterval[1]);
+
+	let numberOfPlayers = TriggerHelper.GetNumberOfPlayers();
+	for (let i = 1; i < numberOfPlayers; ++i)
+		QueryPlayerIDInterface(i).AddResources(resources);
+
+	cmpTrigger.DoAfterDelay(randFloat(provideResourcesInterval[0], provideResourcesInterval[1]) * minutes, "ProvideResources", {});
 };
 
 var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
 cmpTrigger.playerCivicCenter = {};
+
 cmpTrigger.DoAfterDelay(0, "InitGame", {});
 cmpTrigger.DoAfterDelay(1000, "InitializeEnemyWaves", {});
+cmpTrigger.DoAfterDelay(provideResourcesOffset * minutes, "ProvideResources", { "first": true });
 
 cmpTrigger.RegisterTrigger("OnOwnershipChanged", "DefeatPlayerOnceCCIsDestroyed", { "enabled": true });
Index: binaries/data/mods/public/simulation/components/UnitAI.js
===================================================================
--- binaries/data/mods/public/simulation/components/UnitAI.js	(revision 18600)
+++ binaries/data/mods/public/simulation/components/UnitAI.js	(working copy)
@@ -3115,7 +3115,7 @@
 				this.SelectAnimation("walk", false, this.GetWalkSpeed());
 				this.MoveRandomly(+this.template.RoamDistance);
 				// Set a random timer to switch to feeding state
-				this.StartTimer(RandomInt(+this.template.RoamTimeMin, +this.template.RoamTimeMax));
+				this.StartTimer(randInt(+this.template.RoamTimeMin, +this.template.RoamTimeMax));
 				this.SetFacePointAfterMove(false);
 			},
 
@@ -3160,7 +3160,7 @@
 				// Stop and eat for a while
 				this.SelectAnimation("feeding");
 				this.StopMoving();
-				this.StartTimer(RandomInt(+this.template.FeedTimeMin, +this.template.FeedTimeMax));
+				this.StartTimer(randInt(+this.template.FeedTimeMin, +this.template.FeedTimeMax));
 			},
 
 			"leave": function() {
Index: binaries/data/mods/public/simulation/helpers/Random.js
===================================================================
--- binaries/data/mods/public/simulation/helpers/Random.js	(revision 18600)
+++ binaries/data/mods/public/simulation/helpers/Random.js	(nonexistent)
@@ -1,9 +0,0 @@
-/**
- * Returns a random integer from min (inclusive) to max (exclusive)
- */
-function RandomInt(min, max)
-{
-	return Math.floor(min + Math.random() * (max-min));
-}
-
-Engine.RegisterGlobal("RandomInt", RandomInt);

Property changes on: binaries/data/mods/public/simulation/helpers/Random.js
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
