Index: experiments/frams/capture-the-flag/data/scripts/Flag.neuro
===================================================================
--- experiments/frams/capture-the-flag/data/scripts/Flag.neuro	(revision 232)
+++ experiments/frams/capture-the-flag/data/scripts/Flag.neuro	(revision 232)
@@ -0,0 +1,27 @@
+class:
+name:Flag
+longname:Flag detection neuron
+description:Outputs signal strength
+prefinputs:0
+prefoutput:1
+icon:~
+40,3,3,25,0,25,100,75,50,25,0,1,75,50,100,50,11,30,50,38,50,40,48,42,52,44,47,46,48,48,57,50,42,52,52,54,47,57,50,65,50~
+code:~
+function init(){
+//	Neuro.signals.add("Flag");
+//	Neuro.signals[0].flavor = Fields.team;
+//	Neuro.signals[0].power = 0;
+}
+
+function go()
+{
+	var output = Neuro.signals.receiveFilter("Flag", 2000, Fields.team, 0.5);
+	Neuro.state = output;
+	
+}
+~
+
+prop:
+id:team
+name:Team number
+type:d
Index: experiments/frams/capture-the-flag/data/scripts/FlagDef.neuro
===================================================================
--- experiments/frams/capture-the-flag/data/scripts/FlagDef.neuro	(revision 232)
+++ experiments/frams/capture-the-flag/data/scripts/FlagDef.neuro	(revision 232)
@@ -0,0 +1,39 @@
+class:
+name:FlagDef
+longname:Flag detection neuron
+description:Outputs signal strength
+prefinputs:0
+prefoutput:1
+icon:~
+40,3,3,25,0,25,100,75,50,25,0,1,75,50,100,50,11,30,50,38,50,40,48,42,52,44,47,46,48,48,57,50,42,52,52,54,47,57,50,65,50~
+code:~
+function init(){
+//	Neuro.signals.add("Flag");
+//	Neuro.signals[0].flavor = Fields.team;
+//	Neuro.signals[0].power = 0;
+}
+
+function go()
+{
+	//Check own flag
+	if (Neuro.signals.receiveFilter("Flag", 2000, Fields.my + 100, 0.5) > 0)
+		Neuro.state = Neuro.signals.receiveFilter("Flag", 2000, Fields.my + 100, 0.5);
+	//Check opponent flag
+	//If flag is taken -> go to own flag
+	else if (Neuro.signals.receiveFilter("Flag", 2000, Fields.opp + 100, 0.5) > 0)	
+		Neuro.state = Neuro.signals.receiveFilter("Flag", 2000, Fields.my, 0.5);
+	//else -> go to opponent flag
+	else
+		Neuro.state = Neuro.signals.receiveFilter("Flag", 2000, Fields.opp, 0.5);
+}
+~
+
+prop:
+id:opp
+name:Opponent team number
+type:d
+
+prop:
+id:my
+name:My team number
+type:d
Index: experiments/frams/capture-the-flag/data/scripts/capture-the-flag.expdef
===================================================================
--- experiments/frams/capture-the-flag/data/scripts/capture-the-flag.expdef	(revision 232)
+++ experiments/frams/capture-the-flag/data/scripts/capture-the-flag.expdef	(revision 232)
@@ -0,0 +1,468 @@
+expdef:
+name:Capture The Flag game
+info:~
+A simple Capture The Flag game. Read more at
+http://www.framsticks.com/capture-the-flag
+~
+code:~
+
+//Flag positions
+global flagsX;
+global flagsY;
+
+//global log;
+
+//Sum of team points and events
+global points;
+global scored;
+global taken;
+global retrieved;
+
+function onExpDefLoad()
+{
+	GenePools.clear();
+	Populations.clear();
+   	
+   	World.wrldsiz = 100;
+   	World.wrldtyp = 0;
+   	World.wrldbnd = 2; //Teleport
+   	
+   	ExpParams.memberssno = 4;
+   	ExpParams.teamsno = 2;
+   	ExpParams.mindistance = 60;
+   	
+   	ExpParams.pointsCapture = 10;
+   	ExpParams.pointsRetrieve = 5;
+   	ExpParams.pointsScoring = 50;
+
+	//Styles of flags
+   	Shapes.set("1p_flag0","lllX(X, RRllX(, RRllX(, (X, lllX, X),), LLLLLLLX(,, llllX)), X)", 0xFF0000);
+   	Shapes.set("1p_flag1","lllX(X, RRllX(, RRllX(, (X, lllX, X),), LLLLLLLX(,, llllX)), X)", 0x0000FF);
+   	Shapes.set("1p_flag2","lllX(X, RRllX(, RRllX(, (X, lllX, X),), LLLLLLLX(,, llllX)), X)", 0x00FF00);
+   	Shapes.set("1p_flag3","lllX(X, RRllX(, RRllX(, (X, lllX, X),), LLLLLLLX(,, llllX)), X)", 0x00FFFF);
+   	Shapes.set("1p_flag4","lllX(X, RRllX(, RRllX(, (X, lllX, X),), LLLLLLLX(,, llllX)), X)", 0xFF00FF);
+   	
+//   	log = File.createDirect("statistics"+Math.time+".txt","CTF statistics");
+//   	log.writeString("Step;Team1_Points;Team1_Scored;Team1_Captured;Team1_Retrieved;Team2_Points;Team2_Scored;Team2_Captured;Team2_Retrieved;\n");
+
+}
+
+function onExpInit()
+{
+	ExpParams_create_call();
+
+}
+
+function onBorn()
+{
+  Creature.energ0 = 100;
+  Creature.energy = Creature.energ0;
+}
+
+function onDied()
+{
+  
+}
+
+function onExpLoad()
+{
+ 
+}
+
+function onExpLoad_Unknown()
+{
+ 
+}
+
+function onExpSave()
+{
+ 
+}
+
+function createTeams(){
+	
+}
+
+function ExpParams_create_call(){
+	//Create GenePool and Population for each team
+	GenePools.clear();
+	GenePool.name = "Team1";
+   	GenePool.fitness = "return this.user3;";
+   	while (GenePools[0].size > 0)
+   		GenePools[0].delete(0);
+   	
+	Populations.clear();
+	Population.name = "Team1";
+	
+	while (Population.size > 0)
+			Population.delete(0);
+	
+	
+	
+	Population.selfmask = 0x50001;
+    Population.othermask = 0x60001;
+	
+	var i = 2;
+	for (i = 2; i <= ExpParams.teamsno; i++){
+		Populations.addGroup("Team"+i);
+		Population.selfmask = 0x50001;
+    	Population.othermask = 0x60001;
+		GenePools.addGroup("Team"+i);
+		GenePool.fitness = "return this.user3;";	
+	}
+	
+	//Create GenePool for flags and fill it
+	GenePools.addGroup("Flags");
+	
+	GenePool.addGeno(Geno.newFrom("m:Vstyle=flag0\np:",48,"Flag","Single flag object"));
+	GenePool.addGeno(Geno.newFrom("m:Vstyle=flag1\np:",48,"Flag","Single flag object"));
+	GenePool.addGeno(Geno.newFrom("m:Vstyle=flag2\np:",48,"Flag","Single flag object"));
+	GenePool.addGeno(Geno.newFrom("m:Vstyle=flag3\np:",48,"Flag","Single flag object"));
+	GenePool.addGeno(Geno.newFrom("m:Vstyle=flag4\np:",48,"Flag","Single flag object"));
+}
+
+function ExpParams_fill_call(){
+	var team = 0;
+	var player = 0;
+	
+	//Reset all global points vectors
+	flagsX = Vector.new();
+	flagsY = Vector.new();
+	
+	points = Vector.new();
+	scored = Vector.new();
+	taken = Vector.new();
+	retrieved = Vector.new();
+	
+	//Init global vectors
+	var x, y, i;
+	var ok = 0;
+	
+	for (i = 0; i < ExpParams.teamsno; i++){
+		points.add(0);
+		scored.add(0);
+		taken.add(0);
+		retrieved.add(0);	
+	}
+	
+	//Clear Populations
+	for (team = 0; team < ExpParams.teamsno; team++){
+		while (Populations[team].size > 0)
+			Populations[team].delete(0);
+	}
+	
+	//Draw flag positions according to minimal distance parameter
+	var totalTries = 0, flagTries = 0, done = 0;
+	
+	while (totalTries < 1000 && done == 0){
+		flagsX = Vector.new();
+		flagsY = Vector.new();
+
+		ok = 1;		
+		while (flagsX.size < ExpParams.teamsno && ok == 1){
+			ok = 0;
+			flagTries = 0;
+			while (ok == 0 && flagTries < 1000){
+				x = Math.random(80) + 10;
+				y = Math.random(80) + 10;
+				
+				ok = 1;
+				for (i = 0; i < flagsX.size; i++){
+					if (Math.sqrt(Math.pow(flagsX[i] - x, 2)+Math.pow(flagsY[i] - y,2)) < ExpParams.mindistance){
+						ok = 0;
+						break;
+					}
+				}
+				if (ok == 1){
+					flagsX.add(x);
+					flagsY.add(y);
+				} else 
+					flagTries += 1;
+			}
+			
+		}
+		
+		if (flagsX.size == ExpParams.teamsno)
+			done = 1;
+		else
+			totalTries += 1;
+	}
+	//Flags weren't placed successfully'
+	if (done != 1){
+		Simulator.message("Flags could not be placed correctly. Consider lowering minimal distance between flags.", 2);
+		Simulator.beep();
+		return;
+	}
+	
+	
+	//Fill each team's Population with players and a flag and place players close to their flag
+	for (team = 0; team < ExpParams.teamsno; team++){
+		while (Populations[team].size > 0)
+			Populations[team].delete(0);
+		
+		GenePools.group = ExpParams.teamsno;
+		GenePools.genotype = team;
+		
+		Populations[team].createFromGenotype();
+		placeFlag(Populations[team][0]);
+		Creature.signals.add("Flag");
+		Creature.signals[0].flavor = team;
+		Creature.signals[0].power=1000;
+		Creature.user1 = 0;
+		Creature.user2 = 0;
+		Creature.user3 = 0;
+		
+		GenePools.group = team;
+
+		var crX, crY;
+		
+		for (player = 0; player < ExpParams.memberssno; player++){
+			GenePools.genotype = player % GenePool.size;
+			Populations[team].createFromGenotype();
+			crX = Math.random(30) - 15;
+			if (crX >=0 && crX < 5)
+				crX = 5;
+			else if (crX > -5 && crX < 0)
+				crX = -5;
+			crY = Math.random(30) - 15;
+			if (crY >=0 && crY < 5)
+				crY = 5;
+			else if (crY > -5 && crY < 0)
+				crY = -5;
+			Creature.moveAbs(flagsX[team] + crX, flagsY[team] + crY, 0);
+			Creature.user1 = 0;
+			Creature.user2 = 0;
+			Creature.user3 = 0;
+		}
+	}
+}
+
+function ExpParams_default_call(){
+	//Insert default player genotype in team's GenePools
+	var team = 0;
+	for (team = 0; team < ExpParams.teamsno; team++){
+		while (GenePools[team].size > 0)
+			GenePools[team].delete(0);
+		if (team != 1)
+			GenePools[team].addGeno(Geno.newFrom("lllfffX[0:2.420, 2:-2, 1:-1][-1:1, 0:1, 0:-1][-1:1](RRlllfffMMMX[|-1:-10]lllFFFMMMX[|-2:-1], fffIXlllfffMMMsX[|6:10, 3:-10](RRlllfffMMMIX[|-4:-10]lllFFFMMMIX[|-5:-1][*], , RRlllfffMMMIX[|-7:10]lllFFFMMMIX[|-8:-1][*]), RRlllfffMMMX[|-10:10]lllFFFMMMX[|-11:-1.784])", 49, "Player", "Player"));
+		else if (team == 1)
+			GenePools[team].addGeno(Geno.newFrom("lllfffX[0:2.420, 2:-2, 1:-1][-1:1, 0:1, 0:-1][-1:1](RRlllfffMMMX[|-1:-10]lllFFFMMMX[|-2:-1], fffIXlllfffMMMsX[|1:1][Thr2,lo:-0.75,hi:0.75,t:0.75,3:-10,6:10](RRlllfffMMMIX[|-4:-10]lllFFFMMMIX[|-5:-1][FlagDef,opp:0,my:1], , RRlllfffMMMIX[|-7:10]lllFFFMMMIX[|-8:-1][FlagDef,opp:0,my:1]), RRlllfffMMMX[|-10:10]lllFFFMMMX[|-11:-1.784])", 49, "Inteligent Player", "Inteligent Player"));
+	}
+}
+
+function onStep(){
+	var team = 0;
+	var player = 0;
+	
+	//Update flags position if taken and cooldown if recently retrieved
+	for (team = 0; team < Populations.size; team++){
+		Populations.group = team;
+		Populations.creature = 0;
+		if (Creature.user3 > 0)
+			Creature.user3 -= 1;
+		
+		for (player = 1; player < Population.size; player++){
+			Populations.creature = player;
+			if (Creature.user1 == 1){
+				Creature.user2.moveAbs(Creature.pos_x, Creature.pos_y, Creature.size_z + 1);
+			}
+		}
+	}
+	
+//	if (Simulator.time % 100 == 0){
+//		var i = 0;
+//		var line = "";
+//		line=line+Simulator.time+";";
+//		
+//		for (i = 0; i < ExpParams.teamsno; i++){
+//			line=line+points[i]+";"+scored[i]+";"+taken[i]+";"+retrieved[i]+";";
+//		}
+//		line=line+"\n";
+//		log.writeString(line);
+//		
+//	}
+	
+}
+
+function placeFlag(flag){
+	flag.moveAbs(flagsX[flag.group.index], flagsY[flag.group.index], 0);
+}
+
+function takeFlag(flag, creature){
+	//If the cooldown is on - do nothing
+	if (flag.user3 > 0)
+		return;
+	
+	//Take flag by changing its flavour and setting flag in player and player in flag fields
+	flag.signals[0].flavor = flag.group.index + 100;
+	flag.user1 = 1;
+	flag.user2 = creature;
+	creature.user1 = 1;
+	creature.user2 = flag;
+	
+	//Score points for taking a flag
+	creature.user3 += ExpParams.pointsCapture;
+	
+//	Simulator.print("Flag "+(flag.group.index+1)+" taken by team "+(creature.group.index+1));
+	
+	//Update team points and events
+	points.set(creature.group.index, points[creature.group.index] + ExpParams.pointsCapture);
+	taken.set(creature.group.index, taken[creature.group.index] + 1);
+
+}
+
+function retrieveFlag(flag, creature){
+	//Retrieve flag by changing its flavour and deleting it from player and player from flag
+	flag.signals[0].flavor = flag.group.index;
+	flag.user1 = 0;
+	
+	flag.user2.user1 = 0;
+	flag.user2.user2 = 0;
+	
+	flag.user2 = 0;
+	
+	//Set cooldown for taking a flag
+	flag.user3 = 1000;
+	
+	placeFlag(flag);
+
+	//Score points for retrieving a flag
+	creature.user3 += ExpParams.pointsRetrieve;
+	
+//	Simulator.print("Flag "+ (flag.group.index+1) +" retrieved");
+	
+	//Update team scores
+	points.set(creature.group.index, points[creature.group.index] + ExpParams.pointsRetrieve);
+	retrieved.set(creature.group.index, retrieved[creature.group.index] + 1);
+}
+
+function scoreFlag(flag, creature){
+	//Put the flag back on its spot and delete references between player and flag
+	creature.user2.signals[0].flavor = creature.user2.group.index;
+	creature.user2.user1 = 0;
+	creature.user2.user2 = 0;
+	
+	placeFlag(creature.user2);
+	
+	creature.user1 = 0;
+	creature.user2 = 0;
+	
+	//Score points for scoring a flag
+	creature.user3 += ExpParams.pointsScoring;
+	
+//	Simulator.print("Team "+ (creature.group.index + 1) +" scored");
+	
+	//Update team points
+	points.set(creature.group.index, points[creature.group.index] + ExpParams.pointsScoring);
+	scored.set(creature.group.index, scored[creature.group.index] + 1);
+}
+
+function onTeam1CrCollision, onTeam2CrCollision, onTeam3CrCollision, onTeam4CrCollision, onTeam5CrCollision(){
+	var c1 = CrCollision.Creature1;
+	var c2 = CrCollision.Creature2;
+
+	//Flag vs. flag collision - do nothing
+	if (c1.geno.name == "Flag" && c2.geno.name == "Flag"){
+		return;	
+	}
+	
+	var flag;
+	var creature;
+	var colFlag = 0;
+	
+	//Try to assign colliding creatures to flag and player
+	if (c1.geno.name == "Flag"){
+		flag = c1;
+		creature = c2;
+		colFlag = 1;
+	} else if (c2.geno.name == "Flag"){
+		flag = c2;
+		creature = c1;
+		colFlag = 1;
+	}
+
+	//Flag vs. player collision
+	if (colFlag == 1){
+		//Collision with my flag which is taken
+		if (flag.group.index == creature.group.index && flag.user1 == 1){
+			retrieveFlag(flag, creature);
+		} //Collision with my flag which is not taken while carrying another team's flag 
+		else if (flag.group.index == creature.group.index && flag.user1 == 0 && creature.user1 == 1 && flag.user3 != 1){
+			scoreFlag(flag, creature);
+		} //Collision with another team's flag which is not taken while not carrying any flag 
+		else if (flag.group.index != creature.group.index && flag.user1 == 0 && creature.user1 == 0 && flag.user3 != 1){
+			takeFlag(flag, creature);
+		}
+	} 
+	//Player vs. player collision
+	else {
+		//Players of different teams
+		if (c1.group.index != c2.group.index){
+			//If player 1 has a flag ...
+			if (c1.user1 == 1){
+				// ... and the flag is of my team ...
+				if (c2.group.index == c1.user2.group.index){
+					//... retrieve it
+					retrieveFlag(c1.user2, c2);
+				}
+			}
+			//If player 2 has a flag ...
+			if (c2.user1 == 1){
+				// ... and the flag is of my team ...
+				 if (c1.group.index == c2.user2.group.index){
+					//... retrieve it
+					retrieveFlag(c2.user2, c1);
+				}
+			}
+		}
+	}
+
+}  
+
+~
+
+prop:
+id:teamsno
+name:Number of teams
+type:d 2 5
+
+prop:
+id:memberssno
+name:Number of members in team
+type:d 1 8
+
+prop:
+id:mindistance
+name:Minimal distance between flags
+type:d 1 100
+
+prop:
+id:create
+name:Create teams
+type:p
+
+prop:
+id:default
+name:Insert default player
+type:p
+
+prop:
+id:fill
+name:Fill teams
+type:p
+
+prop:
+id:pointsCapture
+name:Points for flag capture
+type:d 0 100
+
+prop:
+id:pointsRetrieve
+name:Points for flag retrieve
+type:d 0 100
+
+prop:
+id:pointsScoring
+name:Points for scoring a flag
+type:d 0 100
+
Index: experiments/frams/capture-the-flag/data/scripts/threshold2.neuro
===================================================================
--- experiments/frams/capture-the-flag/data/scripts/threshold2.neuro	(revision 232)
+++ experiments/frams/capture-the-flag/data/scripts/threshold2.neuro	(revision 232)
@@ -0,0 +1,45 @@
+class:
+name:Thr2
+longname:Threshold 2
+description:~
+If (input>=t) then output=hi, else if (output<=-t) output=lo, else pass through.
+
+This is a modified Threshold neuron to use with a sample Capture The Flag battle.
+This neuron passess signal without altering it in the range [-t, t].
+Outside of this range, the neuron outputs the truncated input.
+This neuron is used to "steer" the food finder according to sensory inputs from left and right side.~
+prefinputs:-1
+prefoutput:1
+icon:~
+24,3,3,25,0,25,100,75,50,25,0,1,75,50,100,50,3,30,75,40,75,40,40,60,40~
+code:~
+function init()
+{
+}
+
+function go()
+{
+  if (Neuro.weightedInputSum >= Fields.t)
+    Neuro.state = Fields.hi;
+  else if (Neuro.weightedInputSum <= -Fields.t)
+    Neuro.state = Fields.lo;
+  else
+    Neuro.state = Neuro.weightedInputSum;
+}
+~
+
+prop:
+id:t
+name:threshold
+type:f
+
+prop:
+id:lo
+name:low output value
+type:f
+
+prop:
+id:hi
+name:high output value
+type:f
+
