Index: cpp/frams/genetics/f4/conv_f4.cpp
===================================================================
--- cpp/frams/genetics/f4/conv_f4.cpp	(revision 759)
+++ cpp/frams/genetics/f4/conv_f4.cpp	(revision 760)
@@ -4,4 +4,6 @@
 
 // Copyright (C) 1999,2000  Adam Rotaru-Varga (adam_rotaru@yahoo.com), GNU LGPL
+// Copyright (C) since 2001 Maciej Komosinski
+// 2018, Grzegorz Latosinski, added support for new API for neuron types and their properties
 
 #include "conv_f4.h"
@@ -27,5 +29,5 @@
 	int res;
 	f4_Model * model = new f4_Model();
-	res = model->buildFromF4(in);
+	res = model->buildFromF4(in, using_checkpoints);
 	if (GENOPER_OK != res) return SString();  // oops
 	if (NULL != map)
@@ -52,5 +54,5 @@
 	int res;
 	f4_Model * model = new f4_Model();
-	res = model->buildFromF4(in);
+	res = model->buildFromF4(in, using_checkpoints);
 	if (GENOPER_OK != res) return SString();  // oops
 	SString out;
@@ -71,5 +73,5 @@
 }
 
-int f4_Model::buildFromF4(SString &geno)
+int f4_Model::buildFromF4(SString &geno, bool using_checkpoints)
 {
 	int i;
@@ -101,5 +103,5 @@
 		cells->C[i]->recProcessedFlag = 0;
 
-	open(); // begin model build
+	open(using_checkpoints); // begin model build
 
 	// process every cell
@@ -184,4 +186,5 @@
 			partidx = addFromString(PartType, tmpLine, &range);
 			if (partidx < 0) return -1;
+			this->checkpoint();
 			jj_p1_refno = partidx;
 		}
@@ -200,4 +203,5 @@
 		partidx = addFromString(PartType, tmpLine, &range);
 		if (partidx < 0) return -2;
+		this->checkpoint();
 		C->p2_refno = partidx;
 
@@ -220,4 +224,5 @@
 		partidx = addFromString(JointType, tmpLine, &range);
 		if (partidx < 0) return -13;
+		this->checkpoint();
 		C->joint_refno = partidx;
 	}
@@ -225,18 +230,52 @@
 	if (C->type == T_NEURON4) ///<this case was updated by MacKo
 	{
-		// new neuron object
-		// it is linked to a part (not a joint!)
-		int p_refno = C->dadlink->p2_refno;
-		if ((p_refno < 0) || (p_refno >= getPartCount())) return -21;
-		// joint_refno is currently not used
-		sprintf(tmpLine, "p=%ld,d=\"N:in=%g,fo=%g,si=%g\"",
-			p_refno,
-			C->inertia, C->force, C->sigmo);
-		partidx = addFromString(NeuronType, tmpLine, &range);
-		if (partidx < 0) return -22;
+		const char * nclass = C->neuclass->name.c_str();
+		int partno, jointno;
+		if (C->neuclass->getPreferredLocation() == 0)
+		{
+			if (strcmp(nclass, "N") == 0)
+			{
+				partno = C->dadlink->p2_refno;
+				if ((partno < 0) || (partno >= getPartCount())) return -21;
+				else sprintf(tmpLine, "p=%ld,d=\"N:in=%g,fo=%g,si=%g\"", partno, C->inertia, C->force, C->sigmo);
+			}
+			else
+			{
+				sprintf(tmpLine, "d=\"%s\"", nclass);
+			}
+			partidx = addFromString(NeuronType, tmpLine, &range);
+			if (partidx < 0) return -22;
+			this->checkpoint();
+			C->neuro_refno = partidx;
+		}
+		else if (C->neuclass->getPreferredLocation() == 1) // attached to Part or have no required attachment - also part
+		{
+			partno = C->dadlink->p2_refno;
+			if ((partno < 0) || (partno >= getPartCount())) return -21;
+			if (strcmp(nclass, "N") == 0)
+			{
+				sprintf(tmpLine, "d=\"N:in=%g,fo=%g,si=%g\"", partno, C->inertia, C->force, C->sigmo);
+			}
+			else
+			{
+				sprintf(tmpLine, "p=%ld,d=\"%s\"", partno, nclass);
+			}
+			partidx = addFromString(NeuronType, tmpLine, &range);
+			if (partidx < 0) return -22;
+			this->checkpoint();
+			C->neuro_refno = partidx;
+		}
+		else // attached to Joint
+		{
+			jointno = C->dadlink->joint_refno;
+			sprintf(tmpLine, "n:j=%d,d=\"%s\"", jointno, nclass);
+			partidx = addFromString(NeuronType, tmpLine, &range);
+			if (partidx < 0) return -32;
+			this->checkpoint();
+		}
 		C->neuro_refno = partidx;
 		int n_refno = C->neuro_refno;
 
-		if (C->ctrl)
+		if ((strcmp(nclass,"N") == 0) && C->ctrl)
 		{
 			if (1 == C->ctrl)
@@ -248,4 +287,5 @@
 			sprintf(tmpLine, "%d,%d", partidx, n_refno);
 			if (addFromString(NeuronConnectionType, tmpLine, &range) < 0) return -33;
+			this->checkpoint();
 		}
 
@@ -256,8 +296,34 @@
 
 			tmpLine[0] = 0;
-			if (1 == C->links[j]->t) sprintf(tmpLine, "p=%d,d=\"*\"", p_refno);
-			if (2 == C->links[j]->t) sprintf(tmpLine, "j=%d,d=\"G\"", C->dadlink->joint_refno);
-			if (3 == C->links[j]->t) sprintf(tmpLine, "p=%d,d=\"T\"", p_refno);
-			if (4 == C->links[j]->t) sprintf(tmpLine, "p=%d,d=\"S\"", p_refno);
+			if (C->links[j]->from == NULL)
+			{
+				const char * nclass = C->links[j]->t.c_str();
+				char * temp = (char*)C->links[j]->t.c_str();
+				NeuroClass * sensortest = GenoOperators::parseNeuroClass(temp);
+				//backward compatibility for G*TS
+				if (C->links[j]->t == "*" || C->links[j]->t == "S" || C->links[j]->t == "T")
+				{
+					sprintf(tmpLine, "p=%d,d=\"%s\"", partno, nclass);
+				}
+				else if (C->links[j]->t == "G")
+				{
+					jointno = C->dadlink->joint_refno;
+					sprintf(tmpLine, "j=%d,d=\"%s\"", jointno, nclass);
+				}				
+				else if (sensortest->getPreferredLocation() == 0)
+				{
+					sprintf(tmpLine, "d=\"%s\"",nclass);
+				}
+				else if (sensortest->getPreferredLocation() == 1)
+				{
+					sprintf(tmpLine, "p=%d,d=\"%s\"", partno, nclass);
+				}
+				else
+				{
+					jointno = C->dadlink->joint_refno;
+					sprintf(tmpLine, "j=%d,d=\"%s\"", jointno, nclass);
+				}
+
+			}
 			int from = -1;
 			if (tmpLine[0]) //input from receptor
@@ -265,5 +331,7 @@
 				from = addFromString(NeuronType, tmpLine, &range);
 				if (from < 0) return -34;
+				this->checkpoint();
 			} /*could be 'else'...*/
+
 			if (NULL != C->links[j]->from) // input from another neuron
 				from = C->links[j]->from->neuro_refno;
@@ -272,4 +340,5 @@
 				sprintf(tmpLine, "%d,%d,%g", n_refno, from, C->links[j]->w);
 				if (addFromString(NeuronConnectionType, tmpLine, &range) < 0) return -35;
+				this->checkpoint();
 			}
 		}
Index: cpp/frams/genetics/f4/conv_f4.h
===================================================================
--- cpp/frams/genetics/f4/conv_f4.h	(revision 759)
+++ cpp/frams/genetics/f4/conv_f4.h	(revision 760)
@@ -5,4 +5,5 @@
 // Copyright (C) 1999,2000  Adam Rotaru-Varga (adam_rotaru@yahoo.com), GNU LGPL
 // Copyright (C) since 2001 Maciej Komosinski
+// 2018, Grzegorz Latosinski, added support for new API for neuron types and their properties
 
 #ifndef _CONV_F4_H_
@@ -15,23 +16,52 @@
 
 
-// The f4->f0 converter
+/**
+ * Genotype converter from f4 to f0.
+ */
 class GenoConv_f40 : public GenoConverter
 {
 public:
 	GenoConv_f40();
+
+	/**
+	 * Performs conversion from f4 to f0. Creates f4_Model from f4 genotype
+	 * and converts the Model to the f0 genotype string.
+	 * @param in f4 genotype
+	 * @param map mapping from f4 to Model
+	 * @param using_checkpoints determines if checkpoints will be available
+	 * @return generated f0 genotype
+	 */
 	SString convert(SString &in, MultiMap * map, bool using_checkpoints);
 };
 
 
-// a test-only f4->f1 converter, approximates only
+/**
+ * Genotype converter from f4 to f1. This is only experimental conversion and
+ * returns an approximate f1 genotype.
+ */
 class GenoConv_F41_TestOnly : public GenoConverter
 {
 public:
+	/**
+	 * Initializes converter.
+	 */
 	GenoConv_F41_TestOnly();
+
+	/**
+	 * Performs conversion from f4 to f1. Creates f4_Model from f4 genotype
+	 * and converts the Model to the f1 genotype string. The final f1 genotype is
+	 * an approximation.
+	 * @param in f4 genotype
+	 * @param map mapping from f4 to Model
+	 * @param using_checkpoints determines if checkpoints will be available
+	 * @return generated approximate f1 genotype
+	 */
 	SString convert(SString &in, MultiMap * map, bool using_checkpoints);
 };
 
 
-// A Model descendant, which support build from an f4 genotype.
+/**
+ * A Model descendant which supports building from an f4 genotype.
+ */
 class f4_Model : public Model
 {
@@ -39,5 +69,15 @@
 	f4_Model();
 	~f4_Model();
-	int      buildFromF4(SString &geno);
+
+	/**
+	 * Builds a Model from the f4 genotype string.
+	 * @param geno genotype string
+	 * @return GENOPER_OK if a Model could be created, error code otherwise
+	 */
+	int      buildFromF4(SString &geno, bool using_checkpoints);
+	/**
+	 * Outputs a Model in f1 format. It is an approximation of the input f4 genotype.
+	 * @param out the reference that stores the conversion result
+	 */
 	void     toF1Geno(SString &out);       // output to f1 format, approximation
 private:
Index: cpp/frams/genetics/f4/f4_general.cpp
===================================================================
--- cpp/frams/genetics/f4/f4_general.cpp	(revision 759)
+++ cpp/frams/genetics/f4/f4_general.cpp	(revision 760)
@@ -1,14 +1,14 @@
 // This file is a part of Framsticks SDK.  http://www.framsticks.com/
-// Copyright (C) 1999-2017  Maciej Komosinski and Szymon Ulatowski.
+// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
 // See LICENSE.txt for details.
 
 // Copyright (C) 1999,2000  Adam Rotaru-Varga (adam_rotaru@yahoo.com), GNU LGPL
+// 2018, Grzegorz Latosinski, added support for new API for neuron types and their properties
 
 #include "f4_general.h"
+#include "../oper_fx.h" //for GENOPER_ constants
 #include <common/nonstd_stl.h>
 #include <common/log.h>
 #include <frams/model/model.h> // for min and max attributes
-#include "../oper_fx.h" //for GENOPER_ constants
-#include <stdio.h>
 #include <common/nonstd_math.h>
 
@@ -17,76 +17,4 @@
 #endif
 
-
-f4_Props::f4_Props()
-{
-	length = 1.0;
-	curvedness = 0.0;
-	weight = 1.0;
-	friction = 0.4;
-	muscle_power = 0.25; // biol
-	assimilation = 0.25; // biol
-	stamina = 0.25; // biol
-	ingestion = 0.25; // biol
-	twist = 0.0;
-	energy = 1.0;
-	normalizeBiol4();
-}
-
-void f4_Props::normalizeBiol4()
-{
-	// make them sum to 1
-	double sum = muscle_power + assimilation + stamina + ingestion;
-	if (sum == 0)
-	{
-		muscle_power = assimilation = stamina = ingestion = 0.25;
-	}
-	else
-	{
-		muscle_power /= sum;
-		assimilation /= sum;
-		stamina /= sum;
-		ingestion /= sum;
-	}
-}
-
-void f4_Props::executeModifier(char modif)
-{
-	switch (modif)
-	{
-	case 'L': length += (2.5 - length) * 0.3;
-		length = min(length, Model::getMaxJoint().d.x); break;
-	case 'l': length += (0.3 - length) * 0.3;
-		length = max(length, Model::getMinJoint().d.x); break;
-	case 'C': curvedness += (2.0 - curvedness) * 0.25;  break;
-	case 'c': curvedness += (-2.0 - curvedness) * 0.25;  break;
-	case 'Q': twist += (1.58 - twist) * 0.3; break;
-	case 'q': twist += (-1.58 - twist) * 0.3; break;
-	case 'A': assimilation += (1 - assimilation) * 0.8; normalizeBiol4(); break;
-	case 'a': assimilation -= assimilation * 0.4;       normalizeBiol4(); break;
-	case 'I': ingestion += (1 - ingestion) * 0.8;   normalizeBiol4(); break;
-	case 'i': ingestion -= ingestion * 0.4;         normalizeBiol4(); break;
-	case 'S': stamina += (1 - stamina) * 0.8; normalizeBiol4(); break;
-	case 's': stamina -= stamina * 0.4;       normalizeBiol4(); break;
-	case 'M': muscle_power += (1 - muscle_power) * 0.8;   normalizeBiol4(); break;
-	case 'm': muscle_power -= muscle_power * 0.4;         normalizeBiol4(); break;
-	case 'F': friction += (4 - friction) * 0.2; break;
-	case 'f': friction -= friction * 0.2;       break;
-	case 'W': weight += (2.0 - weight) * 0.3;   break;
-	case 'w': weight += (0.5 - weight) * 0.3;   break;
-	case 'E': energy += (10.0 - energy) * 0.1; break;
-	case 'e': energy -= energy * 0.1;          break;
-	}
-}
-
-void f4_Props::adjust()
-{
-	length = 0.5*length + 0.5*stdProps.length;
-	curvedness = 0.66 * curvedness;
-	twist = 0.66 * twist;
-}
-
-f4_Props stdProps;
-
-
 void rolling_dec(double * v)
 {
@@ -98,5 +26,4 @@
 	*v += 0.7853;  // 0.7853981  45 degrees
 }
-
 
 int scanrec(const char * s, unsigned int slen, char stopchar)
@@ -136,5 +63,5 @@
 
 f4_Cell::f4_Cell(int nname,
-	f4_Cell * ndad, int nangle, f4_Props newP)
+	f4_Cell * ndad, int nangle, GeneProps newP)
 {
 	name = nname;
@@ -145,5 +72,5 @@
 	gcur = NULL;
 	active = 1;
-	repeat.null();
+	repeat.clear();
 	//genoRange.clear(); -- implicit
 
@@ -187,5 +114,5 @@
 
 
-f4_Cell::f4_Cell(f4_Cells * nO, int nname, f4_node * ngeno, f4_node * ngcur, f4_Cell * ndad, int nangle, f4_Props newP)
+f4_Cell::f4_Cell(f4_Cells * nO, int nname, f4_node * ngeno, f4_node * ngcur, f4_Cell * ndad, int nangle, GeneProps newP)
 {
 	name = nname;
@@ -196,5 +123,5 @@
 	gcur = ngcur;
 	active = 1;
-	repeat.null();
+	repeat.clear();
 	//genoRange.clear(); -- implicit
 	// preserve geno range of parent cell
@@ -261,8 +188,4 @@
 int f4_Cell::onestep()
 {
-	int i, j, k, relfrom, t;
-	double w;
-	f4_Cell * tmp;
-	f4_Cell * tneu;
 	if (gcur == NULL)
 	{
@@ -275,340 +198,430 @@
 		// currently this is the last one processed
 		// the current genotype code is processed
-		genoRange.add(gcur->pos);
-		switch (gcur->name)
-		{
-		case '<':
-			// cell division!
-			//DB( printf("  div! %d\n", name); )
-
-			// error: sticks cannot divide
-			if (T_STICK4 == type)
-			{
-				// cannot fix
-				org->setError(gcur->pos);
-				return 1;  // stop
-			}
-
-			// undiff divides
-			if (T_UNDIFF4 == type)
-			{
-				// commacount is set only when daughter turns into X
-				// daughter cell
-				// adjust new len
-				f4_Props newP = P;
-				newP.adjust();
-				tmp = new f4_Cell(org, org->nc, genot, gcur->child2, this, commacount, newP);
-				tmp->repeat = repeat;
-				repeat.null();
-				org->addCell(tmp);
-			}
-			// a neuron divides: create a new, duplicate links
-			if (T_NEURON4 == type) {
-				// daughter cell
-				tmp = new f4_Cell(org, org->nc, genot, gcur->child2,
-					// has the same dadlink
-					this->dadlink, commacount, P);
-				tmp->repeat = repeat;
-				repeat.null();
-				// it is a neuron from start
-				tmp->type = T_NEURON4;
-				// duplicate links
-				f4_CellLink * ll;
-				for (i = 0; i < nolink; i++)
-				{
-					ll = links[i];
-					tmp->addlink(ll->from, ll->w, ll->t);
-				}
-				org->addCell(tmp);
-			}
-			// adjustments for this cell
-			gcur = gcur->child;
-			// halt development
-			return 0;
-
-		case '>':
-			// finish
-			// see if there is a repet count
-			if (repeat.top > 0)
-			{ // there is a repeat counter
-				if (!repeat.first()->isNull())
-				{ // repeat counter is not null
-					repeat.first()->dec();
-					if (repeat.first()->count > 0)
+		//genoRange.add(gcur->pos,gcur->pos+gcur->name.length()-1);
+		bool neuclasshandler = false; // if set to true, then there is a set of characters that can be assigned to a neuron class type
+		// old semantics, one-character
+		if (gcur->name.length() == 1)
+		{
+			genoRange.add(gcur->pos, gcur->pos);
+			char name = gcur->name[0];
+			switch (name)
+			{
+			case '<':
+			{
+				// cell division!
+				//DB( printf("  div! %d\n", name); )
+
+				// error: sticks cannot divide
+				if (T_STICK4 == type)
+				{
+					// cannot fix
+					org->setError(gcur->pos);
+					return 1;  // stop
+				}
+
+				// undiff divides
+				if (T_UNDIFF4 == type)
+				{
+					// commacount is set only when daughter turns into X
+					// daughter cell
+					// adjust new len
+					GeneProps newP = P;
+					newP.propagateAlong(false);
+					f4_Cell * tmp = new f4_Cell(org, org->nc, genot, gcur->child2, this, commacount, newP);
+					tmp->repeat = repeat;
+					repeat.clear();
+					org->addCell(tmp);
+				}
+				// a neuron divides: create a new, duplicate links
+				if (T_NEURON4 == type) {
+					// daughter cell
+					f4_Cell *tmp = new f4_Cell(org, org->nc, genot, gcur->child2,
+						// has the same dadlink
+						this->dadlink, commacount, P);
+					tmp->repeat = repeat;
+					repeat.clear();
+					// it is a neuron from start
+					tmp->type = T_NEURON4;
+					// it has the same type as the parent neuron
+					tmp->neuclass = neuclass;
+					// duplicate links
+					f4_CellLink * ll;
+					for (int i = 0; i < nolink; i++)
 					{
-						// return to repeat
-						gcur = repeat.first()->node->child;
+						ll = links[i];
+						tmp->addlink(ll->from, ll->w, ll->t);
+					}
+					org->addCell(tmp);
+				}
+				// adjustments for this cell
+				gcur = gcur->child;
+				// halt development
+				return 0;
+			}
+			case '>':
+			{
+				// finish
+				// see if there is a repet count
+				if (repeat.top > 0)
+				{ // there is a repeat counter
+					if (!repeat.first()->isNull())
+					{ // repeat counter is not null
+						repeat.first()->dec();
+						if (repeat.first()->count > 0)
+						{
+							// return to repeat
+							gcur = repeat.first()->node->child;
+						}
+						else
+						{
+							// continue
+							gcur = repeat.first()->node->child2;
+							repeat.pop();
+						}
+						break;
 					}
 					else
 					{
-						// continue
-						gcur = repeat.first()->node->child2;
 						repeat.pop();
 					}
+				}
+				else
+				{
+					// error: still undiff
+					if (T_UNDIFF4 == type)
+					{
+						// fix it: insert an 'X'
+						f4_node *insertnode = new f4_node("X", NULL, gcur->pos);
+						if (org->setRepairInsert(gcur->pos, gcur, insertnode)) // not in repair mode, release
+							delete insertnode;
+						return 1;
+					}
+					repeat.clear();
+					active = 0;  // stop
+					// eat up rest
+					gcur = NULL;
+					return 0;
+				}
+			}
+				/* no break */
+			case '#':
+			{
+				// repetition marker
+				if (repeat.top >= repeat_stack::stackSize)
+				{
+					// repeat pointer stack is full, cannot remember this one.
+					// fix: delete it
+					org->setRepairRemove(gcur->pos, gcur);
+					return 1;  // stop
+				}
+				repeat.push(repeat_ptr(gcur, gcur->i1));
+				gcur = gcur->child;
+				break;
+			}
+			case ',':
+			{
+				commacount++;
+				gcur = gcur->child;
+				break;
+			}
+			case 'r':  case 'R':
+			{
+				// error: if neuron
+				if (T_NEURON4 == type)
+				{
+					// fix: delete it
+					org->setRepairRemove(gcur->pos, gcur);
+					return 1;  // stop
+				}
+				switch (name)
+				{
+				case 'r':   rolling_dec(&rolling); break;
+				case 'R':   rolling_inc(&rolling); break;
+				}
+				gcur = gcur->child;
+				break;
+			}
+			case 'l':  case 'L':
+			case 'c':  case 'C':
+			case 'q':  case 'Q':
+			case 'a':  case 'A':
+			case 'i':  case 'I':
+			case 's':  case 'S':
+			case 'm':  case 'M':
+			case 'f':  case 'F':
+			case 'w':  case 'W':
+			case 'e':  case 'E':
+			case 'd':  case 'D':
+			case 'g':  case 'G':
+			case 'b':  case 'B':
+			case 'h':  case 'H':
+			{
+				// error: if neuron
+				if (T_NEURON4 == type)
+				{
+					// fix: delete it
+					org->setRepairRemove(gcur->pos, gcur);
+					return 1;  // stop
+				}
+				P.executeModifier(name);
+				gcur = gcur->child;
+				break;
+			}
+			case 'X':
+			{
+				// turn undiff. cell into a stick
+				// error: already differentiated
+				if (T_UNDIFF4 != type)
+				{
+					// fix: delete this node
+					org->setRepairRemove(gcur->pos, gcur);
+					return 1;  // stop
+				}
+				type = T_STICK4;
+				// fix dad commacount and own anglepos
+				if (NULL != dadlink)
+				{
+					dadlink->commacount++;
+					anglepos = dadlink->commacount;
+				}
+				// change of type halts developments, see comment at 'N'
+				gcur = gcur->child;
+				return 0;
+			}
+			case 'N':
+			{
+				// turn undiff. cell into a neuron
+				// error: already differentiated
+				if (T_UNDIFF4 != type)
+				{
+					// fix: delete this node
+					org->setRepairRemove(gcur->pos, gcur);
+					return 1;  // stop
+				}
+				// error: if no previous
+				if (NULL == dadlink)
+				{
+					// fix: delete it
+					org->setRepairRemove(gcur->pos, gcur);
+					return 1;  // stop
+				}
+				string temp1 = "N";
+				char *temp = (char*)temp1.c_str();
+				neuclass = GenoOperators::parseNeuroClass(temp);
+				type = T_NEURON4;
+				// change of type also halts development, to give other
+				// cells a chance for adjustment.  Namely, it is important
+				// to wait for other cells to turn N before adding links
+				gcur = gcur->child;
+				return 0;
+			}
+			case '@':
+			case '|':
+			{
+				// neuron rotating / bending
+				int j = 1;
+				if ('@' == name) j = 1; // rot
+				else
+					if ('|' == name) j = 2; // bend
+
+				// if undiff, then this is a new muscle. Thanks to f4_processrec @ and | case we can skip repairing
+				if (T_UNDIFF4 == type)
+				{
+					neuclasshandler = true;
 					break;
 				}
-				else
-				{
-					repeat.pop();
-				}
-			}
-			else
-			{
-				// error: still undiff
-				if (T_UNDIFF4 == type)
-				{
-					// fix it: insert an 'X'
-					f4_node * insertnode = new f4_node('X', NULL, gcur->pos);
-					if (org->setRepairInsert(gcur->pos, gcur, insertnode)) // not in repair mode, release						
-						delete insertnode;
-					return 1;
-				}
-				repeat.null();
-				active = 0;  // stop
-				// eat up rest
-				gcur = NULL;
-				return 0;
-			}
-
-		case '#':
-			// repetition marker
-			if (repeat.top >= repeat_stack::stackSize)
-			{
-				// repepeat pointer stack is full, cannot remember this one.
+
+				// error: not a neuron (stick)
+				if (T_NEURON4 != type)
+				{
+					// fix: delete it
+					org->setRepairRemove(gcur->pos, gcur);
+					return 1;  // stop
+				}
+				// error: already has control
+				if (ctrl != 0)
+				{
+					// fix: delete it
+					org->setRepairRemove(gcur->pos, gcur);
+					return 1;  // stop
+				}
+				// make neuron ctrl = 1 or 2
+				ctrl = j;
+				gcur = gcur->child;
+				break;
+			}
+			case '[':
+			{
+				// link to neuron
+				// error: not a neuron
+				if (T_NEURON4 != type)
+				{
+					// fix: delete it
+					org->setRepairRemove(gcur->pos, gcur);
+					return 1;  // stop
+				}
+				// input (sensor or %d)
+				int t = gcur->i1;
+				int relfrom = gcur->l1;
+				float w = gcur->f1;
+				f4_Cell *tneu = NULL;
+				if (t > 0) // sensors
+				{
+					char *temp = (char*)gcur->s1.c_str();
+					NeuroClass *sensortest = GenoOperators::parseNeuroClass(temp);
+					if (sensortest == NULL || sensortest->getPreferredInputs() != 0)
+					{
+						// error: unknown code
+						string buf = "wrong sensor in link '";
+						buf.append(gcur->s1);
+						buf.append("'");
+						logMessage("f4_Cell", "onestep", LOG_WARN, buf.c_str()); //TODO ask
+						org->setRepairRemove(gcur->pos, gcur);
+						return 1;
+					}
+				}
+				else {
+					// input from other neuron
+					// find neuron at relative i
+					// find own index
+					int j = 0, k = 0;
+					for (int i = 0; i < org->nc; i++)
+					{
+						if (org->C[i]->type == T_NEURON4) k++;
+						if (org->C[i] == this) { j = k - 1; break; }
+					}
+					// find index of incoming
+					j = j + relfrom;
+					if (j < 0) goto wait_link;
+					if (j >= org->nc) goto wait_link;
+					// find that neuron
+					k = 0;
+					int i;
+					for (i = 0; i < org->nc; i++)
+					{
+						if (org->C[i]->type == T_NEURON4) k++;
+						if (j == (k - 1)) break;
+					}
+					if (i >= org->nc) goto wait_link;
+					tneu = org->C[i];
+				}
+				// add link
+				// error: could not add link (too many?)
+				if (addlink(tneu, w, gcur->s1))
+				{
+					// cannot fix
+					org->setError(gcur->pos);
+					return 1;  // stop
+				}
+				gcur = gcur->child;
+				break;
+			}
+			wait_link:
+			{
+				// wait for other neurons to develop
+				// if there are others still active
+				active = 0;
+				int j = 0;
+				for (int i = 0; i < org->nc; i++)
+				{
+					if (org->C[i]->active) j++;
+				}
+				if (j > 0)
+					return 0;  // there is other active, halt, try again
+				// no more actives, cannot add link, ignore, but treat not as an error
+				gcur = gcur->child;
+			}
+				break;
+			case ':':
+			{
+				// neuron parameter
+				// error: not a neuron
+				if (T_NEURON4 != type)
+				{
+					// fix: delete it
+					org->setRepairRemove(gcur->pos, gcur);
+					return 1;  // stop
+				}
+				int j = (int)gcur->l1;
+				switch ((char)gcur->i1)
+				{
+				case '!':
+					if (j)
+						force += (1.0 - force) * 0.2;
+					else
+						force -= force * 0.2;
+					break;
+				case '=':
+					if (j)
+						inertia += (1.0 - inertia) * 0.2;
+					else
+						inertia -= inertia * 0.2;
+					break;
+				case '/':
+					if (j)
+						sigmo *= 1.4;
+					else
+						sigmo /= 1.4;
+					break;
+				default:
+					org->setRepairRemove(gcur->pos, gcur);
+					return 1;  // stop
+				}
+				gcur = gcur->child;
+				break;
+			}
+			case ' ':
+			{
+				// space has no effect, should not occur
+				// fix: delete it
+				org->setRepairRemove(gcur->pos, gcur);
+				gcur = gcur->child;
+				break;
+			}
+			default:
+			{
+				// because there are one-character neuron classes, default move control to neuclasshandler
+				neuclasshandler = true;
+			}
+			}
+		}
+		else
+		{
+			// if many characters, then it needs to be parsed below
+			neuclasshandler = true;
+		}
+
+		if (neuclasshandler)
+		{
+			genoRange.add(gcur->pos, gcur->pos + gcur->name.length() + 2 - 1); // +2 for N:
+			if (T_UNDIFF4 != type)
+			{
+				// fix: delete this node
+				org->setRepairRemove(gcur->pos, gcur);
+				return 1;  // stop
+			}
+			// error: if no previous
+			if (NULL == dadlink)
+			{
 				// fix: delete it
 				org->setRepairRemove(gcur->pos, gcur);
 				return 1;  // stop
 			}
-			repeat.push(repeat_ptr(gcur, gcur->i1));
+			// multiple characters are neuron types. Need to check if exists
+			char *temp = (char*)gcur->name.c_str();
+			neuclass = GenoOperators::parseNeuroClass(temp);
+			if (neuclass == NULL)
+			{
+				// error: unknown code
+				string buf = "unknown code '";
+				buf.append(gcur->name);
+				buf.append("'");
+				logMessage("f4_Cell", "onestep", 2, buf.c_str());
+				org->setRepairRemove(gcur->pos, gcur);
+				return 1;
+			}
+			type = T_NEURON4; //they belong to neurons
 			gcur = gcur->child;
-			break;
-
-		case ',':
-			commacount++;
-			gcur = gcur->child;
-			break;
-
-		case 'r':  case 'R':
-			// error: if neuron
-			if (T_NEURON4 == type)
-			{
-				// fix: delete it
-				org->setRepairRemove(gcur->pos, gcur);
-				return 1;  // stop
-			}
-			switch (gcur->name)
-			{
-			case 'r':   rolling_dec(&rolling); break;
-			case 'R':   rolling_inc(&rolling); break;
-			}
-			gcur = gcur->child;
-			break;
-
-		case 'l':  case 'L':
-		case 'c':  case 'C':
-		case 'q':  case 'Q':
-		case 'a':  case 'A':
-		case 'i':  case 'I':
-		case 's':  case 'S':
-		case 'm':  case 'M':
-		case 'f':  case 'F':
-		case 'w':  case 'W':
-		case 'e':  case 'E':
-			// error: if neuron
-			if (T_NEURON4 == type)
-			{
-				// fix: delete it
-				org->setRepairRemove(gcur->pos, gcur);
-				return 1;  // stop
-			}
-			P.executeModifier(gcur->name);
-			gcur = gcur->child;
-			break;
-
-		case 'X':
-			// turn undiff. cell into a stick
-			// error: already differentiated
-			if (T_UNDIFF4 != type)
-			{
-				// fix: delete this node
-				org->setRepairRemove(gcur->pos, gcur);
-				return 1;  // stop
-			}
-			type = T_STICK4;
-			// fix dad commacount and own anglepos
-			if (NULL != dadlink)
-			{
-				dadlink->commacount++;
-				anglepos = dadlink->commacount;
-			}
-			// change of type halts developments, see comment at 'N'
-			gcur = gcur->child;
-			return 0;
-
-		case 'N':
-			// turn undiff. cell into a neuron
-			// error: already differentiated
-			if (T_UNDIFF4 != type)
-			{
-				// fix: delete this node
-				org->setRepairRemove(gcur->pos, gcur);
-				return 1;  // stop
-			}
-			// error: if no previous
-			if (NULL == dadlink)
-			{
-				// fix: delete it
-				org->setRepairRemove(gcur->pos, gcur);
-				return 1;  // stop
-			}
-			type = T_NEURON4;
-			// change of type also halts development, to give other
-			// cells a chance for adjustment.  Namely, it is important
-			// to wait for other cells to turn N before adding links
-			gcur = gcur->child;
-			return 0;
-
-		case '@':
-		case '|':
-			// neuron rotating / bending
-			j = 1;
-			if ('@' == gcur->name) j = 1; // rot
-			if ('|' == gcur->name) j = 2; // bend
-			// error: not a neuron (undiff)
-			if (T_UNDIFF4 == type)
-			{
-				// fix: delete it
-				org->setRepairRemove(gcur->pos, gcur);
-				return 1;  // stop
-			}
-			// error: not a neuron (stick)
-			if (T_NEURON4 != type)
-			{
-				// fix: delete it
-				org->setRepairRemove(gcur->pos, gcur);
-				return 1;  // stop
-			}
-			// error: already has control
-			if (ctrl != 0)
-			{
-				// fix: delete it
-				org->setRepairRemove(gcur->pos, gcur);
-				return 1;  // stop
-			}
-			// make neuron ctrl = 1 or 2
-			ctrl = j;
-			gcur = gcur->child;
-			break;
-
-		case '[':
-			// link to neuron
-			// error: not a neuron
-			if (T_NEURON4 != type)
-			{
-				// fix: delete it
-				org->setRepairRemove(gcur->pos, gcur);
-				return 1;  // stop
-			}
-			// input ('*', 'G', 'T', 'S', or %d)
-			t = gcur->i1;
-			relfrom = gcur->l1;
-			w = gcur->f1;
-			if (t > 0)
-			{
-				// * or G
-				tneu = NULL;
-			}
-			else {
-				// input from other neuron
-				// find neuron at relative i
-				// find own index
-				j = 0; k = 0;
-				for (i = 0; i < org->nc; i++)
-				{
-					if (org->C[i]->type == T_NEURON4) k++;
-					if (org->C[i] == this) { j = k - 1; break; }
-				}
-				// find index of incoming
-				j = j + relfrom;
-				if (j < 0) goto wait_link;
-				if (j >= org->nc) goto wait_link;
-				// find that neuron
-				k = 0;
-				for (i = 0; i < org->nc; i++)
-				{
-					if (org->C[i]->type == T_NEURON4) k++;
-					if (j == (k - 1)) break;
-				}
-				if (i >= org->nc) goto wait_link;
-				tneu = org->C[i];
-			}
-			// add link
-			// error: could not add link (too many?)
-			if (addlink(tneu, w, t))
-			{
-				// cannot fix
-				org->setError(gcur->pos);
-				return 1;  // stop
-			}
-			gcur = gcur->child;
-			break;
-		wait_link:
-			// wait for other neurons to develop
-			// if there are others still active
-			active = 0;
-			j = 0;
-			for (i = 0; i < org->nc; i++)
-			{
-				if (org->C[i]->active) j++;
-			}
-			if (j > 0)
-				return 0;  // there is other active, halt, try again
-			// no more actives, cannot add link, ignore, but treat not as an error
-			gcur = gcur->child;
-			break;
-
-		case ':':
-			// neuron parameter
-			// error: not a neuron
-			if (T_NEURON4 != type)
-			{
-				// fix: delete it
-				org->setRepairRemove(gcur->pos, gcur);
-				return 1;  // stop
-			}
-			j = (int)gcur->l1;
-			switch ((char)gcur->i1)
-			{
-			case '!':
-				if (j) force += (1.0 - force) * 0.2;
-				else   force -= force * 0.2; break;
-			case '=':
-				if (j) inertia += (1.0 - inertia) * 0.2;
-				else   inertia -= inertia * 0.2; break;
-			case '/':
-				if (j) sigmo *= 1.4;
-				else   sigmo /= 1.4; break;
-			default:
-				org->setRepairRemove(gcur->pos, gcur);
-				return 1;  // stop
-			}
-			gcur = gcur->child;
-			break;
-
-		case ' ':
-			// space has no effect, should not occur
-			// fix: delete it
-			org->setRepairRemove(gcur->pos, gcur);
-			gcur = gcur->child;
-			break;
-
-		default:
-			// error: unknown code
-			char buf[40];
-			sprintf(buf, "unknown code '%c'", gcur->name);
-			logMessage("f4_Cell", "onestep", 2, buf);
-			// fix: delete it
-			org->setRepairRemove(gcur->pos, gcur);
-			return 1; // stop
+			return 0; //stop
 		}
 	}
@@ -618,6 +631,9 @@
 
 
-int f4_Cell::addlink(f4_Cell * nfrom, double nw, int nt)
-{
+int f4_Cell::addlink(f4_Cell * nfrom, double nw, string nt)
+{
+	// if incoming neuron does not produce output, return error
+	if (nfrom != NULL && nfrom->neuclass->getPreferredOutput() == 0) return -1;
+	if (neuclass->getPreferredInputs() != -1 && nolink >= neuclass->getPreferredInputs()) return -1;
 	if (nolink >= MAXINPUTS - 1) return -1; // full!
 	links[nolink] = new f4_CellLink(nfrom, nw, nt);
@@ -664,7 +680,7 @@
 		{
 			//firstend = dadlink->lastend;
-			f4_Props Pdad = dadlink->P;
-			f4_Props Padj = Pdad;
-			Padj.adjust();
+			GeneProps Pdad = dadlink->P;
+			GeneProps Padj = Pdad;
+			Padj.propagateAlong(false);
 
 			//rot = Orient_1;
@@ -700,5 +716,5 @@
 
 
-f4_CellLink::f4_CellLink(f4_Cell * nfrom, double nw, int nt)
+f4_CellLink::f4_CellLink(f4_Cell * nfrom, double nw, string nt)
 {
 	from = nfrom;
@@ -720,6 +736,5 @@
 	tmpcel = NULL;
 	f4rootnode = NULL;
-
-	C[0] = new f4_Cell(this, 0, genome, genome, NULL, 0, stdProps);
+	C[0] = new f4_Cell(this, 0, genome, genome, NULL, 0, GeneProps::standard_values);
 	nc = 1;
 }
@@ -748,5 +763,5 @@
 
 	// create ancestor cell
-	C[0] = new f4_Cell(this, 0, f4rootnode->child, f4rootnode->child, NULL, 0, stdProps);
+	C[0] = new f4_Cell(this, 0, f4rootnode->child, f4rootnode->child, NULL, 0, GeneProps::standard_values);
 	nc = 1;
 }
@@ -939,5 +954,5 @@
 {
 	if (tmpcel) delete tmpcel;
-	tmpcel = new f4_Cell(-1, NULL, 0, stdProps);
+	tmpcel = new f4_Cell(-1, NULL, 0, GeneProps::standard_values);
 	out = "";
 	toF1GenoRec(0, out);
@@ -962,5 +977,5 @@
 
 	// adjust length, curvedness, etc.
-	tmpcel->P.adjust();
+	tmpcel->P.propagateAlong(false);
 	while (tmpcel->P.length > thisti->P.length)
 	{
@@ -1015,9 +1030,6 @@
 					if (NULL == thneu->links[j]->from)
 					{
-						// sensory
-						if (1 == thneu->links[j]->t) out += "*";
-						if (2 == thneu->links[j]->t) out += "G";
-						if (3 == thneu->links[j]->t) out += "T";
-						if (4 == thneu->links[j]->t) out += "S";
+						// sensors
+						out += thneu->links[j]->t.c_str();
 					}
 					else
@@ -1073,12 +1085,15 @@
 f4_node::f4_node()
 {
-	name = '?';
+	name = "?";
 	parent = NULL;
 	child = NULL;
 	child2 = NULL;
 	pos = -1;
-}
-
-f4_node::f4_node(char nname, f4_node * nparent, int npos)
+	l1 = 0;
+	i1 = 0;
+	f1 = 0.0f;
+}
+
+f4_node::f4_node(string nname, f4_node *nparent, int npos)
 {
 	name = nname;
@@ -1088,4 +1103,20 @@
 	pos = npos;
 	if (parent) parent->addChild(this);
+	l1 = 0;
+	i1 = 0;
+	f1 = 0.0f;
+}
+
+f4_node::f4_node(char nname, f4_node * nparent, int npos)
+{
+	name = nname;
+	parent = nparent;
+	child = NULL;
+	child2 = NULL;
+	pos = npos;
+	if (parent) parent->addChild(this);
+	l1 = 0;
+	i1 = 0;
+	f1 = 0.0f;
 }
 
@@ -1194,20 +1225,20 @@
 }
 
-void f4_node::sprint(SString & out)
-{
-	char buf2[20];
+void f4_node::sprint(SString& out)
+{
+	string buf2 = "";
 	// special case: repetition code
-	if ('#' == name)
+	if (name == "#")
 	{
 		out += "#";
 		if (i1 != 1)
 		{
-			sprintf(buf2, "%d", i1);
-			out += buf2;
+			sprintf((char*)buf2.c_str(), "%d", i1);
+			out += buf2.c_str();
 		}
 	}
 	else {
 		// special case: neuron link
-		if ('[' == name)
+		if (name == "[")
 		{
 			out += "[";
@@ -1215,27 +1246,43 @@
 			{
 				// sensor input
-				if (1 == i1) out += "*";
-				if (2 == i1) out += "G";
-				if (3 == i1) out += "T";
-				if (4 == i1) out += "S";
+				out += s1.c_str();
 			}
 			else
 			{
-				sprintf(buf2, "%ld", l1);
-				out += buf2;
-			}
-			sprintf(buf2, ":%g]", f1);
-			out += buf2;
-		}
-		else if (':' == name)
-		{
-			sprintf(buf2, ":%c%c:", l1 ? '+' : '-', (char)i1);
-			out += buf2;
+				sprintf((char*)buf2.c_str(), "%ld", l1);
+				out += buf2.c_str();
+			}
+			sprintf((char*)buf2.c_str(), ":%g]", f1);
+			out += buf2.c_str();
+		}
+		else if (name == ":")
+		{
+			sprintf((char*)buf2.c_str(), ":%c%c:", l1 ? '+' : '-', (char)i1);
+			out += buf2.c_str();
+		}
+		else if (name == "@" || name == "|")
+		{
+			if (parent->name == "N")
+			{
+				buf2 = name;
+				out += buf2.c_str();
+			}
+			else
+			{
+				out += "N:";
+				buf2 = name;
+				out += buf2.c_str();
+			}
 		}
 		else
 		{
-			buf2[0] = name;
-			buf2[1] = 0;
-			out += buf2;
+			char *temp = (char*)name.c_str();
+			NeuroClass * nc = GenoOperators::parseNeuroClass(temp);
+			if (nc != NULL)
+			{
+				out += "N:";
+			}
+			buf2 = name;
+			out += buf2.c_str();
 		}
 	}
@@ -1301,15 +1348,16 @@
 }
 
-
 // scan genotype string and build tree
 // return >1 for error (errorpos)
 int f4_processrec(const char * genot, unsigned pos0, f4_node * parent)
 {
-	int i, j, t, res;
-	char tc1, tc2;
+	int i, j, res, t;
+	char tc1, tc2, tc3; // tc3 is only to ensure that in the end  of neuron parameter definition
 	int relfrom;
 	double w;
 	unsigned gpos, oldpos;
 	f4_node * node1, *par;
+	unsigned beginindex;
+	string neutype = "";
 
 	gpos = pos0;
@@ -1318,15 +1366,14 @@
 	while (gpos < strlen(genot))
 	{
-		//DB( printf(" processing '%c' %d %s\n", genot[gpos], gpos, genot); )
+		neutype = "";
+		// first switch across cell dividers and old semantics
 		switch (genot[gpos])
 		{
 		case '<':
-			// cell division!
-			//DB( printf("  div! %d\n", name); )
-
+		{
 			// find out genotype start for child
 			j = scanrec(genot + gpos + 1, strlen(genot + gpos + 1), '>');
 
-			node1 = new f4_node('<', par, gpos);
+			node1 = new f4_node("<", par, gpos);
 			par = node1;
 			res = f4_processrec(genot, gpos + 1, par);
@@ -1339,18 +1386,19 @@
 			else // ran out
 			{
-				node1 = new f4_node('>', par, strlen(genot) - 1);
+				node1 = new f4_node(">", par, strlen(genot) - 1);
 				par = node1;
 			}
-			// adjustments
 			gpos++;
 			return 0;  // OK
-
+		}
 		case '>':
-			node1 = new f4_node('>', par, gpos);
+		{
+			node1 = new f4_node(">", par, gpos);
 			par = node1;
 			gpos = strlen(genot);
 			return 0;  // OK
-
+		}
 		case '#':
+		{
 			// repetition marker, 1 by default
 			if (sscanf(genot + gpos, "#%d", &i) != 1) i = 1;
@@ -1361,5 +1409,5 @@
 			gpos++;
 			while ((genot[gpos] >= '0') && (genot[gpos] <= '9')) gpos++;
-			node1 = new f4_node('#', par, oldpos);
+			node1 = new f4_node("#", par, oldpos);
 			node1->i1 = i;
 			par = node1;
@@ -1373,16 +1421,22 @@
 			else // ran out
 			{
-				node1 = new f4_node('>', par, strlen(genot) - 1);
+				node1 = new f4_node(">", par, strlen(genot) - 1);
 			}
 			return 0;  // OK
-
-			// 'simple' nodes:
-		case ',':
+		}
+		case ' ':
+		case '\n':
+		case '\r':
+		case '\t':
+		{
+			// whitespace: ignore
+			gpos++;
+			break;
+		}
 		case 'l':  case 'L':
 		case 'c':  case 'C':
 		case 'q':  case 'Q':
 		case 'r':  case 'R':
-		case 'X':  case 'N':
-		case '@':  case '|':
+		case 'X':  case ',':
 		case 'a':  case 'A':
 		case 's':  case 'S':
@@ -1392,21 +1446,93 @@
 		case 'w':  case 'W':
 		case 'e':  case 'E':
+		{
 			node1 = new f4_node(genot[gpos], par, gpos);
 			par = node1;
 			gpos++;
 			break;
-
+		}
+		case '@':  case '|':
+		{
+			// in order to prevent the presence of "free muscles", we need to ensure that a muscle is written as N@/N| or N:@/N:|
+			if (par != NULL && par->name == "N")
+			{
+				node1 = new f4_node(genot[gpos], par, gpos);
+				par = node1;
+				gpos++;
+			}
+			else
+			{
+				return gpos + 1;
+			}
+			break;
+		}
+
+		case 'N':
+		{
+			// if there is no colon after N, then there is no class definition
+			if (gpos + 1 >= strlen(genot) || genot[gpos + 1] != ':')
+			{
+				node1 = new f4_node(genot[gpos], par, gpos);
+				par = node1;
+				gpos++;
+				break;
+			}
+			// if there is a colon determining neuron parameter, then let the switch case colon handle this
+			else if (sscanf(genot + gpos + 1, ":%c%c%[:]", &tc1, &tc2, &tc3) == 3)
+			{
+				node1 = new f4_node(genot[gpos], par, gpos);
+				par = node1;
+				gpos++;
+				break;
+			}
+			int forgenorange = gpos;
+			gpos += 2; //skipping "N:"
+			beginindex = gpos;
+			char * end = (char*)genot + beginindex;
+			GenoOperators::parseNeuroClass(end);
+			gpos += end - genot - beginindex;
+			neutype = string(genot + beginindex, genot + gpos);
+			node1 = new f4_node(neutype, par, forgenorange);
+			par = node1;
+			break;
+		}
+		case ':':
+		{
+			// neuron parameter  +! -! += -= +/ or -/
+			if (sscanf(genot + gpos, ":%c%c%[:]", &tc1, &tc2, &tc3) != 3)
+				// error: incorrect format
+				return gpos + 1 + 1;
+			if ('+' == tc1) j = 1;
+			else if ('-' == tc1) j = 0;
+			else return gpos + 1 + 1;
+			switch (tc2)
+			{
+			case '!':  case '=':  case '/':  break;
+			default:
+				return gpos + 1 + 1;
+			}
+			node1 = new f4_node(":", par, gpos);
+			node1->l1 = j;
+			node1->i1 = (int)tc2;
+			par = node1;
+			j = scanrec(genot + gpos + 1, strlen(genot + gpos + 1), ':');
+			gpos += j + 2;
+			break;
+		}
 		case '[':
-			// link to neuron
-			// input (%d, '*', 'G', 'T', 'S')
-			t = -1;
-			if (sscanf(genot + gpos, "[%ld:%lf]", &relfrom, &w) == 2) t = 0;
-			else if (sscanf(genot + gpos, "[*:%lf]", &w) == 1) t = 1;
-			else if (sscanf(genot + gpos, "[G:%lf]", &w) == 1) t = 2;
-			else if (sscanf(genot + gpos, "[T:%lf]", &w) == 1) t = 3;
-			else if (sscanf(genot + gpos, "[S:%lf]", &w) == 1) t = 4;
-			// error: no correct format
-			if (t < 0) return gpos + 1 + 1;
-			node1 = new f4_node('[', par, gpos);
+		{
+			const char *end = parseConnection(genot + gpos, relfrom, w);
+			if (end == NULL)
+			{
+				end = parseConnectionWithNeuron(genot + gpos, neutype, w);
+				if (end == NULL) t = -1;
+				t = 1;
+			}
+			else
+			{
+				t = 0;
+			}
+			node1 = new f4_node("[", par, gpos);
+			node1->s1 = neutype;
 			node1->i1 = t;
 			node1->l1 = relfrom;
@@ -1416,37 +1542,7 @@
 			gpos += j + 2;
 			break;
-
-		case ':':
-			// neuron parameter  +! -! += -= +/ or -/
-			if (sscanf(genot + gpos, ":%c%c:", &tc1, &tc2) != 2)
-				// error: incorrect format
-				return gpos + 1 + 1;
-			if ('+' == tc1) j = 1;
-			else if ('-' == tc1) j = 0;
-			else return gpos + 1 + 1;
-			switch (tc2)
-			{
-			case '!':  case '=':  case '/':  break;
-			default:
-				return gpos + 1 + 1;
-			}
-			node1 = new f4_node(':', par, gpos);
-			node1->l1 = j;
-			node1->i1 = (int)tc2;
-			par = node1;
-			j = scanrec(genot + gpos + 1, strlen(genot + gpos + 1), ':');
-			gpos += j + 2;
-			break;
-
-		case ' ':
-		case '\n':
-		case '\t':
-			// whitespace: ignore
-			//node1 = new f4_node(' ', par, gpos );
-			//par = node1;
-			gpos++;
-			break;
-
+		}
 		default:
+		{
 			//DB( printf("unknown character '%c' ! \n", genot[gpos]); )
 			//add it, build will give the error or repair
@@ -1456,9 +1552,11 @@
 			break;
 		}
-	}
+		}
+	}
+
 	// should end with a '>'
 	if (par)
 	{
-		if ('>' != par->name)
+		if (par->name != ">")
 		{
 			node1 = new f4_node('>', par, strlen(genot) - 1);
@@ -1467,7 +1565,45 @@
 	}
 
-	return 0;  // OK
-}
-
+	return 0;
+}
+
+const char* parseConnection(const char *fragm, int& relfrom, double &weight)
+{
+	const char *parser = fragm;
+	if (*parser != '[') return NULL;
+	parser++;
+	ExtValue val;
+	parser = val.parseNumber(parser, ExtPType::TInt);
+	if (parser == NULL) return NULL;
+	relfrom = val.getInt();
+	if (*parser != ':') return NULL;
+	parser++;
+	parser = val.parseNumber(parser, ExtPType::TDouble);
+	if (parser == NULL) return NULL;
+	weight = val.getDouble();
+	if (*parser != ']') return NULL;
+	parser++;
+	return parser;
+}
+
+const char* parseConnectionWithNeuron(const char *fragm, string &neutype, double &weight)
+{
+	const char *parser = fragm;
+	if (*parser != '[') return NULL;
+	parser++;
+	char * p = (char*)parser;
+	if (GenoOperators::parseNeuroClass(p) == NULL) return NULL;
+	neutype = string(parser, (const char *)p);
+	parser = p;
+	if (*parser != ':') return NULL;
+	parser++;
+	ExtValue val;
+	parser = val.parseNumber(parser, ExtPType::TDouble);
+	if (parser == NULL) return NULL;
+	weight = val.getDouble();
+	if (*parser != ']') return NULL;
+	parser++;
+	return parser;
+}
 
 f4_node * f4_processtree(const char * geno)
Index: cpp/frams/genetics/f4/f4_general.h
===================================================================
--- cpp/frams/genetics/f4/f4_general.h	(revision 759)
+++ cpp/frams/genetics/f4/f4_general.h	(revision 760)
@@ -8,8 +8,8 @@
 #define _F4_GENERAL_H_
 
-//#include "f4_orientmat.h"
 #include <frams/util/3d.h>
 #include <frams/util/sstring.h>
 #include <frams/util/multirange.h>
+#include <frams/genetics/geneprops.h>
 
 #ifdef DMALLOC
@@ -17,34 +17,15 @@
 #endif
 
-
-class f4_Props
-{
-public:
-	// fill with default values
-	f4_Props();
-	// must sum to 1
-	void normalizeBiol4();
-	void executeModifier(char modif);
-	void adjust();
-
-	double length;
-	double curvedness;
-	double weight;
-	double friction;
-	double muscle_power;
-	double assimilation;
-	double stamina;
-	double ingestion;
-	double twist;
-	double energy;
-};
-
-extern f4_Props stdProps;
-
-
-// rolling (one-time)
+/**
+ * Performs single rotation angle decrementation on a given value.
+ * @param v pointer to the decremented value
+ */
 void rolling_dec(double * v);
+
+/**
+ * Performs single rotation angle incrementation on a given value.
+ * @param v pointer to the incremented value
+ */
 void rolling_inc(double * v);
-
 
 class f4_node;   // later
@@ -53,129 +34,323 @@
 
 
-// cell types
-#define T_UNDIFF4 40
-#define T_STICK4  41
-#define T_NEURON4 42
-
+/** @name Types of f4_Cell's */
+//@{
+#define T_UNDIFF4 40 ///<undifferentiated cell
+#define T_STICK4  41 ///<differentiated to stick, cannot divide
+#define T_NEURON4 42 ///<differentiated to neuron, can divide
+//@}
+
+/**
+ * Scans f4 genotype string for a stopping character and returns the position of
+ * this stopping character or 1 if the end of string was reached. This method is used
+ * for closing braces, like ), >, ]. It runs recursively when opening braces
+ * like (, <, # are found.
+ * @param s string with the f4 genotype
+ * @param slen length of a given string
+ * @param stopchar character to be found
+ * @return 1 if end of string was reached, or position of found character in sequence
+ */
 int scanrec(const char * s, unsigned int slen, char stopchar);
 
 
 class f4_CellLink;
-#define MAXINPUTS 100
-
-// an abstract cell type, extension of part/stick -- for developmental encoding
+
+/** @name Constraints of f4 genotype structures */
+//@{
+#define MAXINPUTS 100 ///<maximum number of neuron inputs
+#define MAX4CELLS 100 ///<maximum number of f4 organism cells
+//@}
+
+/**
+ * Abstract cell type - the representation of single component in the  developmental
+ * encoding. In the beginning, each f4_Cell is undifferentiated. During the process
+ * of development it can divide or differentiate into a stick or a neuron. If it
+ * differentiates to a neuron, then it preserves the ability to divide, but divided
+ * cells will be the same type as the parent cell. If it is a stick, then it cannot
+ * be divided anymore.
+ *
+ * From f4_Cell array the final Model of a creature is created.
+ */
 class f4_Cell
 {
 public:
+	/**
+	 * Represents the repetition marker. It holds information about the pointer
+	 * to the repetition node and the count of repetitions.
+	 */
 	class repeat_ptr
 	{
 	public:
 		repeat_ptr() : node(NULL), count(-1) { };
-		repeat_ptr(f4_node * a, int b) : node(a), count(b) { };
-		inline void null() { node = NULL; count = -1; };
+
+		/**
+		 * A constructor that takes the pointer to the repetition node and the count of repetitions.
+		 * @param a pointer to f4_node for repetition character
+		 * @param b the number of repetitions
+		 */
+		repeat_ptr(f4_node *a, int b) : node(a), count(b) { };
+
+		inline void makeNull() { node = NULL; count = -1; };
+
 		inline bool isNull() const { return ((node == NULL) || (count <= 0)); };
+
 		inline void dec() { count--; };
-		f4_node *  node;  // ptr to repetition code
-		char       count; // repetition counter
+		f4_node    *node; ///<pointer to the repetition code
+		char       count; ///<repetition counter
 	};
 
-	class repeat_stack  // a stack of repet_ptr's
+	/**
+	 * Represents the stack of repeat_ptr objects. The objects are
+	 * pushed to the stack when '#' repetition symbol appears, and are popped when
+	 * the end of the current cell definition, i.e. the '>' character, appears. After the
+	 * '>' character, the cell is duplicated as many times as it is defined after the
+	 * repetition marker.
+	 */
+	class repeat_stack
 	{
 	public:
-		repeat_stack() { top = 0; };
-		inline void null() { top = 0; };
-		inline void push(repeat_ptr A) { if (top >= stackSize) return; ptr[top] = A; top++; };
-		inline void pop() { if (top > 0) top--; };
-		inline repeat_ptr * first() { return &(ptr[top - (top > 0)]); };
-		static const int stackSize = 4;  // max 4 nested levels
-		repeat_ptr ptr[stackSize];
-		short int top;  // top of the stack
+		repeat_stack() { top = 0; }
+
+		inline void clear() { top = 0; }
+
+		/**
+		 * Pushes repeat_ptr object onto the stack. If the stack size is exceeded, then no
+		 * information is provided.
+		 * @param rn repetition node info
+		 */
+		inline void push(repeat_ptr rn) { if (top >= stackSize) return; ptr[top] = rn; top++; }
+
+		inline void pop() { if (top > 0) top--; }
+
+		/**
+		 * Gets the current top element.
+		 * @return pointer to the element on top of the repeat_stack object
+		 */
+		inline repeat_ptr* first() { return &(ptr[top - (top > 0)]); };
+		static const int stackSize = 4;  ///<max 4 nested levels
+		repeat_ptr ptr[stackSize]; ///<array holding pointers to repeat_ptr
+		short int top;  ///<index of the top of the stack
 	};
 
+	/**
+	 * Creates a new f4_Cell object.
+	 * @param nname name of a cell, can be T_UNDIFF4, T_STICK4 or T_NEURON4
+	 * @param ndad pointer to the parent of the created cell
+	 * @param nangle the amount of commas affecting branch angles
+	 * @param newP genotype properties of a given cell
+	 */
 	f4_Cell(int nname,
-		f4_Cell * ndad, int nangle, f4_Props newP);
-	f4_Cell(f4_Cells * nO, int nname, f4_node * ngeno, f4_node * ngcur,
-		f4_Cell * ndad, int nangle, f4_Props newP);
+		f4_Cell * ndad, int nangle, GeneProps newP);
+	/**
+	 * Creates a new f4_Cell object.
+	 * @param nO pointer to an organism containing the cell
+	 * @param nname name of the cell, can be T_UNDIFF4, T_STICK4 or T_NEURON4
+	 * @param ngeno pointer to the root of the genotype tree
+	 * @param ngcur pointer to the f4_node representing the current cell in the genotype tree
+	 * @param ndad pointer to the parent of the created cell
+	 * @param nangle the number of commas affecting branch angles
+	 * @param newP genotype properties of a given cell
+	 */
+	f4_Cell(f4_Cells *nO, int nname, f4_node *ngeno, f4_node *ngcur,
+		f4_Cell *ndad, int nangle, GeneProps newP);
+
 	~f4_Cell();
 
+	/**
+	 * Performs one step of cell development. This method requires pointer to
+	 * f4_Cells object in org attribute. If the current node in genotype tree
+	 * represents branching, then the cell divides into two cells, unless the
+	 * cell was already differentiated into stick cell. Otherwise the current
+	 * differentiation or modification is performed on cell. If current node is
+	 * creating a connection between two neuron nodes, and the input node is not
+	 * yet developed, then the simulation of current cell halts and waits until
+	 * the input node will be developed. The onestep method is ran on each cell
+	 * at least once and if one cell requires another to develop, then onestep
+	 * should be deployed again on this cell. This method, unlike genotype tree
+	 * creation, checks semantics. This means that this function will fail if:
+	 *  - the stick cell will have divide node,
+	 *  - the undifferentiated cell will have '>' node (end of cell development),
+	 *  - the stack of repetition marker '#' will be overflowed,
+	 *  - the stick modifiers, like rotation, will be applied on neuron cell,
+	 *  - the differentiated cell will be differentiated again,
+	 *  - the neuron class inside cell connection definition is not a sensor,
+	 *  - the connection between neurons could not be established,
+	 *  - the neuron class is not valid.
+	 *
+	 * @return 0 if development was successful, 1 if there was an error in genotype tree
+	 */
 	int onestep();	// execute one simulation step (till a division)
 
-	int   addlink(f4_Cell * nfrom, double nw, int nt);
+	/**
+	 * Add link between this neuron cell and a given neuron cell. If nfrom object
+	 * is not given, than neuron type in nt holds the sensor type.
+	 * @param nfrom input neuron cell, or NULL if not given
+	 * @param nw weight of connection
+	 * @param nt empty string or name of sensor class
+	 * @return 0 if link is established, -1 otherwise
+	 */
+	int   addlink(f4_Cell * nfrom, double nw, string nt);
+
+	/**
+	 * Adjusts properties of stick objects.
+	 */
 	void  adjustRec();
 
-	int        name;     // name (number)
-	int        type;     // type
-	f4_Cell *  dadlink;
-	f4_Cells * org;	// uplink to organism
-
-	f4_node *  genot;	  // genotype
-	f4_node *  gcur;        // current genotype execution pointer
-	int        active;      // whether development is still active
-	repeat_stack repeat;
-	int        recProcessedFlag;  // used during recursive traverse
-	// remember the genotype codes affecting this cell so far
-	MultiRange genoRange;
-
-	f4_Props     P;             // properties
-	int          anglepos;      // number of position within dad's children (,)
-	int          childcount;    // number of children
-	int          commacount;    // number of postitions at lastend (>=childcount)
-	double       rolling;       // rolling angle ('R') (around x)
-	double       xrot;
-	double       zrot;          // horizontal rotation angle due to
-	// branching (around z)
-	//Pt3D         firstend;      // coord.s of first end (connects to parent)
-	//Pt3D         lastend;       // last end
-	//f4_OrientMat OM;
-	double       mz;            // freedom in z
-	int          p2_refno;   // number of last end part object, used in f0
-	int          joint_refno;   // number of the joint object, used in f0
-	int          neuro_refno;   // number of the neuro object, used in f0
-
-	int          ctrl;  // neuron type
-	double       state;
-	double       inertia;
-	double       force;
-	double       sigmo;
-	f4_CellLink* links[MAXINPUTS];
-	int          nolink;
+	int        name;               ///<name of cell(number)
+	int        type;               ///<type
+	f4_Cell *  dadlink;            ///<pointer to cell parent
+	f4_Cells * org;	               ///<uplink to organism
+
+	f4_node *  genot;	           ///<genotype tree
+	f4_node *  gcur;               ///<current genotype execution pointer
+	int        active;             ///<whether development is still active
+	repeat_stack repeat;           ///<stack holding repetition nodes and counters
+	int        recProcessedFlag;   ///<used during recursive traverse
+	MultiRange genoRange;          ///<remember the genotype codes affecting this cell so far
+
+	GeneProps     P;               ///<properties
+	int          anglepos;         ///<number of position within dad's children (,)
+	int          childcount;       ///<number of children
+	int          commacount;       ///<number of postitions at lastend (>=childcount)
+	double       rolling;          ///<rolling angle ('R') (around x)
+	double       xrot;			   ///<rotation angle around x
+	double       zrot;             ///<horizontal rotation angle due to branching (around z)
+
+	double       mz;               ///<freedom in z
+	int          p2_refno;         ///<number of last end part object, used in f0
+	int          joint_refno;      ///<number of the joint object, used in f0
+	int          neuro_refno;      ///<number of the neuro object, used in f0
+
+	int          ctrl;             ///<neuron type
+	double       state;            ///<state of neuron
+	double       inertia;          ///<inertia of neuron
+	double       force;            ///<force of neuron
+	double       sigmo;            ///<sigmoid of neuron
+	f4_CellLink* links[MAXINPUTS]; ///<array of neuron links
+	int          nolink;           ///<number of links
+	NeuroClass * neuclass = NULL;  ///<pointer to neuron class
 };
 
-
-// an input link to a neuron
+/**
+ * Class representing link between neuron cells.
+ */
 class f4_CellLink
 {
 public:
-	f4_CellLink(f4_Cell * nfrom, double nw, int nt);
-	f4_Cell *    from;
-	// type: 0: input, 1 '*', 2 'G', 3 'T', 4 'S'
-	int          t;
-	double       w;
+	/**
+	 * Constructor for f4_CellLink class. Parameter nfrom can represent input
+	 * neuron cell or be NULL, if connection has neuron cell definition inside.
+	 * The inside definition must be hold in nt parameter and a neuron class
+	 * must represent sensor.
+	 * @param nfrom pointer to input neuron cell or NULL
+	 * @param nw weight of connection
+	 * @param nt name of neuron class or empty string
+	 */
+	f4_CellLink(f4_Cell * nfrom, double nw, string nt);
+
+	f4_Cell *    from; ///<pointer to input neuron cell
+	string  t;    ///<empty if from cell is given, NeuroClass name otherwise
+	double       w;    ///<weight of connection
 };
 
 
 // a collection of cells, like Organism, for developmental encoding
-#define MAX4CELLS 100
+/**
+ * Class representing a collection of cells. It is equivalent of organism.
+ */
 class f4_Cells
 {
 public:
+
+	/**
+	 * Constructor taking genotype in a form of a tree.
+	 * @param genome genotype tree
+	 * @param nrepair 0 if nothing to repair
+	 */
 	f4_Cells(f4_node * genome, int nrepair);
+
+	/**
+	 * Constructor taking genotype in a form of a string.
+	 * @param genome genotype string
+	 * @param nrepair 0 if nothing to repair
+	 */
 	f4_Cells(SString &genome, int nrepair);
+
+	/**
+	 * Destructor removing cells from memory.
+	 */
 	~f4_Cells();
+
+	/**
+	 * Adds new cell to organism.
+	 * @param newcell cell to be added
+	 */
 	void addCell(f4_Cell * newcell);
-	void toF1Geno(SString &out);       // output to f1 format, approximation
-	int  onestep();       // simulate all parts for one step
-	int  simulate();      // simulate development, return error (0 for ok)
-	// for error reporting / genotype fixing
+
+	/**
+	 * Creates approximate genotype in f1 encoding and stores it in a given
+	 * parameter.
+	 * @param out the string in which approximate f1 genotype will be stored
+	 */
+	void toF1Geno(SString &out);
+
+	/**
+	 * Performs single step of organism development. It runs each active cell
+	 * in organism.
+	 * @return 0 if all cells are developed, or 1 otherwise
+	 */
+	int  onestep();
+
+	/**
+	 * Performs full development of organism and returns error code if something
+	 * went wrong.
+	 * @return 0 if organism developed successfully, error code if something went wrong
+	 */
+	int  simulate();
+
+	/**
+	 * Returns error code of last simulation.
+	 * @return error code
+	 */
 	int  geterror() { return error; };
+
+	/**
+	 * Returns position of error in genotype.
+	 * @return position of error
+	 */
 	int  geterrorpos() { return errorpos; };
+
+	/**
+	 * Sets error code GENOPER_OPFAIL for simulation on a given position.
+	 * @param nerrpos position of error
+	 */
 	void setError(int nerrpos);
+
+	/**
+	 * Sets the element of genotype to be repaired by removal.
+	 * @param nerrpos position of error in genotype
+	 * @param rem the f4_node to be removed from genotype tree in order to repair
+	 */
 	void setRepairRemove(int nerrpos, f4_node * rem);
+
+	/**
+	 * Sets repairing of genotype by inserting new node to current genotype.
+	 * @param nerrpos position of error in genotype
+	 * @param parent the parent of new element
+	 * @param insert the element to be inserted
+	 * @return 0 if repair can be performed, -1 otherwise (the repair flag wasn't set in constructor)
+	 */
 	int  setRepairInsert(int nerrpos, f4_node * parent, f4_node * insert);
+
+	/**
+	 * Repairs genotype according to setRepairRemove or setRepairInsert method.
+	 * @param geno pointer to genotype tree
+	 * @param whichchild 1 if first child, 2 otherwise
+	 */
 	void repairGeno(f4_node * geno, int whichchild);
 
 	// the cells
-	f4_Cell * C[MAX4CELLS];
-	int       nc;
+	f4_Cell * C[MAX4CELLS]; ///<Array of all cells of organism
+	int       nc;           ///<Number of cells in organism
 
 private:
@@ -199,26 +374,103 @@
 {
 public:
-	char      name;	// one-letter 'name'
-	f4_node * parent;	// parent link, or NULL
-	f4_node * child;	// child, or NULL
-	f4_node * child2;	// second child, or NULL
-	int       pos;        // original position in string
-	int       i1;		// internal int  parameter1
-	int       l1;		// internal long parameter1
-	double    f1;		// internal double parameter1
-
+	string name; ///<one-letter 'name', multiple characters for classes
+	f4_node *parent; ///<parent link, or NULL
+	f4_node *child; ///<child, or NULL
+	f4_node *child2; ///<second child, or NULL
+	int         pos; ///<original position in string
+	int         i1; ///<internal int  parameter1
+	int         l1; ///<internal long parameter1
+	double      f1; ///<internal double parameter1
+	string s1; ///<internal string parameter1
+
+	/**
+	 * Default constructor.
+	 */
 	f4_node();
+
+	/**
+	 * Multiple-character name constructor.
+	 * @param nname string from genotype representing node
+	 * @param nparent pointer to parent of node
+	 * @param npos position of node substring in genotype string
+	 */
+	f4_node(string nname, f4_node * nparent, int npos);
+
+	/**
+	 * One-character name constructor.
+	 * @param nname character from genotype representing node
+	 * @param nparent pointer to parent of node
+	 * @param npos position of node character in genotype string
+	 */
 	f4_node(char nname, f4_node * nparent, int npos);
+
+	/**
+	 * Desctructor of object.
+	 */
 	~f4_node();
+
+	/**
+	 * Method for adding child to a node.
+	 * @param nchi child to be added to node
+	 * @return 0 if child could be added, -1 otherwise
+	 */
 	int       addChild(f4_node * nchi);
+
+	/**
+	 * Method for removing child from node.
+	 * @param nchi child to be removed from node
+	 * @return 0 if child could be removed, -1 otherwise
+	 */
 	int       removeChild(f4_node * nchi);
-	int       childCount();	// return no of children, 0, 1, or 2
-	int       count();	// return no of nodes (recursive)
-	f4_node * ordNode(int n);	// returns the nth subnode (0-)
-	f4_node * randomNode();	// returns a random subnode
-	f4_node * randomNodeWithSize(int min, int max);	// returns a random subnode with given size
-	void      sprintAdj(char *& buf);	// print recursively
-	f4_node * duplicate();         // create duplicate copy. recursive.
-	void      destroy();	// release memory. recursive.
+
+	/**
+	 * Returns number of children.
+	 * @return 0, 1 or 2
+	 */
+	int       childCount();
+
+	/**
+	 * Returns number of nodes coming from this node in a recursive way.
+	 * @return number of nodes from this node
+	 */
+	int       count();
+
+	/**
+	 * Returns the nth subnode (0-)
+	 * @param n index of child to be found
+	 * @return pointer to nth subnode or NULL if not found
+	 */
+	f4_node * ordNode(int n);
+
+	/**
+	 * Returns a random subnode.
+	 * @return random subnode
+	 */
+	f4_node * randomNode();
+
+	/**
+	 * Returns a random subnode with given size.
+	 * @param min minimum size
+	 * @param max maximum size
+	 * @return a random subnode with given size or NULL
+	 */
+	f4_node * randomNodeWithSize(int min, int max);
+
+	/**
+	 * Prints recursively tree from a given node.
+	 * @param buf variable storing printing result
+	 */
+	void      sprintAdj(char *& buf);
+
+	/**
+	 * Recursively copies genotype tree from this node.
+	 * @return pointer to a tree copy
+	 */
+	f4_node * duplicate();
+
+	/**
+	 * Recursively releases memory from all node children.
+	 */
+	void      destroy();
 private:
 	void     sprint(SString & out);	// print recursively
@@ -226,7 +478,54 @@
 
 // convert f4 geno string to tree structure (internal)
+
+/**
+ * Main function to perform conversion of f4 geno to tree structure. Prepares
+ * f4_node root of tree and runs f4_processrec function for it.
+ * @param geno string representing f4 genotype
+ * @return pointer to f4_node object representing f4 tree root
+ */
 f4_node * f4_processtree(const char * geno);
+
+/**
+ * Scans genotype string from a given position. This recursive method creates
+ * tree of f4_node objects. The method extract each potentially functional element
+ * of genotype string to separate f4_nodes. When branching character '<' occurs,
+ * then f4_processrec is ran for latest f4_node element. This method does not
+ * analyse genotype semantically, it checks only if syntax is proper. The only
+ * semantic aspect is neuron class name extraction, in which the GenoOperators
+ * class is used to parse possible neuron class in genotype.
+ * @param genot the string holding all genotype
+ * @param pos0 the current position of processing in string
+ * @param current parent of analysed branch of genotype
+ * @return 0 if processing was successful or position of error in genotype
+ */
 int f4_processrec(const char * genot, unsigned pos0, f4_node * parent);
 
+/**
+ * Function parses notation of neuron connection - it takes beginning of connection
+ * definition, extracts relative position of input neurons and weight of connection.
+ * After successful parsing it returns pointer to first character after connection
+ * definition, or NULL if connection definition was not valid - lack of [, :, ]
+ * characters or wrong value of relfrom or weight.
+ * @param fragm the beginning of connection definition, it should be '[' character
+ * @param relfrom the reference to int variable, in which relative position of input neuron will be stored
+ * @param weight the reference to double variable, in which weight of connection will be stored
+ * @return the pointer to first character in string after connection definition
+ */
+const char * parseConnection(const char * fragm, int& relfrom, double &weight);
+
+/**
+ * Function parses notation of neuron connection with neuron definition - it
+ * takes beginning of connection definition, extracts the name of neuron class
+ * that will be the input for current neuron and weight of connection.
+ * After successful parsing it returns pointer to first character after connection
+ * definition, or NULL if connection definition was not valid - lack of [, :, ]
+ * characters, wrong value of weight or invalid neuron class name.
+ * @param fragm the beginning of connection definition, it should be '[' character
+ * @param neutype the reference to string representing input neuron class name. The name of class is validated with GenoOperators::parseNeuroClass
+ * @param weight the reference to double variable, in which weight of connection will be stored
+ * @return the pointer to first character in string after connection definition
+ */
+const char * parseConnectionWithNeuron(const char * fragm, string& neutype, double &weight);
 
 #endif
Index: cpp/frams/genetics/f4/oper_f4.cpp
===================================================================
--- cpp/frams/genetics/f4/oper_f4.cpp	(revision 759)
+++ cpp/frams/genetics/f4/oper_f4.cpp	(revision 760)
@@ -5,4 +5,5 @@
 // Copyright (C) 1999,2000  Adam Rotaru-Varga (adam_rotaru@yahoo.com), GNU LGPL
 // Copyright (C) since 2001 Maciej Komosinski
+// 2018, Grzegorz Latosinski, added support for new API for neuron types and their properties
 
 #include "oper_f4.h"
@@ -138,10 +139,10 @@
 #define REP_MAXCOUNT 19
 
-	f4_node * n1, *n2, *n3, *n4, *n5;
-
 	// do the mutation
 	// pick a random node
-	n1 = g->child->randomNode();
+	f4_node *n1 = g->child->randomNode();
+	vector<NeuroClass*> neulist;
 	//DB( printf("%c\n", n1->name); )
+	int neuronid = -1;
 
 	switch (roulette(prob, F4_COUNT))
@@ -155,29 +156,55 @@
 		{
 			// add division ('<')
-			n3 = n1->parent;
+			f4_node *n3 = n1->parent;
 			n3->removeChild(n1);
-			n2 = new f4_node('<', n3, n3->pos);
+			f4_node *n2 = new f4_node('<', n3, n3->pos);
 			n2->addChild(n1);
 			// new cell is stick or neuron
 			// "X>" or "N>"
+			f4_node *n5 = NULL;
 			double pr = rnd01;
 			pr -= 0.5;
-			if (pr < 0) n3 = new f4_node('X', n2, n2->pos);
+			if (pr < 0) n5 = new f4_node('X', n2, n2->pos);
 			else
 			{
-				pr -= 0.5;
-				if (pr < 0)
-				{
-					// if neuron, make muscle and add a link
-					n3 = new f4_node('N', n2, n2->pos);
-					if (randomN(2) == 0)
-						n4 = new f4_node('|', n3, n2->pos);
-					else
-						n4 = new f4_node('@', n3, n2->pos);
-					n5 = new f4_node('[', n4, n2->pos);
-					linkNodeMakeRandom(n5);
-				}
-			}
-			new f4_node('>', n3, n3->pos);
+				// make neuron
+				NeuroClass * rndclass = GenoOperators::getRandomNeuroClass();
+				if (rndclass == NULL)
+				{
+					n5 = new f4_node('X', n2, n2->pos);
+				}
+				else
+				{
+					f4_node *n4 = new f4_node(rndclass->getName().c_str(), n2, n2->pos); //TODO move this above
+					if (rndclass->getPreferredInputs() != 0)
+					{
+						neuronid = -1;
+						for (int i = 0; i < g->count(); i++)
+						{
+							f4_node * gcur = g->ordNode(i);
+							char * temp = (char*)gcur->name.c_str();
+							NeuroClass * neuclass = GenoOperators::parseNeuroClass(temp);
+							if (neuclass != NULL)
+							{
+								neulist.push_back(neuclass);
+							}
+							if (g->ordNode(i) == n3)
+							{
+								neuronid = neulist.size()-1;
+							}
+						}
+						if (neuronid == -1)
+						{
+							return GENOPER_OPFAIL;
+						}
+						n5 = new f4_node('[', n4, n2->pos);
+						linkNodeMakeRandom(n5, neuronid, neulist);
+					}
+					else {
+						n5 = n4;
+					}
+				}
+			}
+			new f4_node('>', n5, n5->pos);
 			n1->parent = n2;
 			// now with 50% chance swap children
@@ -193,9 +220,34 @@
 		{
 			// add link
-			n1->parent->removeChild(n1);
-			n2 = new f4_node('[', n1->parent, n1->parent->pos);
-			linkNodeMakeRandom(n2);
-			n2->addChild(n1);
-			n1->parent = n2;
+			f4_node * par = n1->parent;
+			char * temp = (char*)par->name.c_str();
+			NeuroClass * neuclass = GenoOperators::parseNeuroClass(temp);
+			if (neuclass != NULL)
+			{
+				n1->parent->removeChild(n1);
+				f4_node *n2 = new f4_node('[', n1->parent, n1->parent->pos);
+				n2->addChild(n1);
+				n1->parent = n2;
+				neuronid = -1;
+				for (int i = 0; i < g->count(); i++)
+				{
+					f4_node *gcur = g->ordNode(i);
+					temp = (char*)gcur->name.c_str();
+					NeuroClass *neuclass = GenoOperators::parseNeuroClass(temp);
+					if (neuclass != NULL)
+					{
+						neulist.push_back(neuclass);
+					}
+					if (gcur == par)
+					{
+						neuronid = neulist.size()-1;
+					}
+				}
+				if (neuronid == -1)
+				{
+					return GENOPER_OPFAIL;
+				}
+				linkNodeMakeRandom(n2, neuronid, neulist);
+			}
 		}
 			break;
@@ -204,5 +256,5 @@
 			// add neuron modifier
 			n1->parent->removeChild(n1);
-			n2 = new f4_node(':', n1->parent, n1->parent->pos);
+			f4_node *n2 = new f4_node(':', n1->parent, n1->parent->pos);
 			nparNodeMakeRandom(n2);
 			n2->addChild(n1);
@@ -214,7 +266,7 @@
 			// add repetition ('#')
 			// repeated code (left child) is the original, right child is empty, count is 2
-			n3 = n1->parent;
+			f4_node *n3 = n1->parent;
 			n3->removeChild(n1);
-			n2 = new f4_node('#', n3, n3->pos);
+			f4_node *n2 = new f4_node('#', n3, n3->pos);
 			n2->i1 = 2;
 			n2->addChild(n1);
@@ -228,5 +280,5 @@
 			// choose a simple node from ADD_SIMPLE_CODES
 			n1->parent->removeChild(n1);
-			n2 = new f4_node(ADD_SIMPLE_CODES[randomN(strlen(ADD_SIMPLE_CODES))], n1->parent, n1->parent->pos);
+			f4_node *n2 = new f4_node(ADD_SIMPLE_CODES[randomN(strlen(ADD_SIMPLE_CODES))], n1->parent, n1->parent->pos);
 			n2->addChild(n1);
 			n1->parent = n2;
@@ -258,5 +310,5 @@
 			case 1:  // one child
 			{
-				n2 = n1->parent;
+				f4_node *n2 = n1->parent;
 				n2->removeChild(n1);
 				if (NULL != n1->child)
@@ -281,5 +333,5 @@
 			{
 				// two children
-				n2 = n1->parent;
+				f4_node *n2 = n1->parent;
 				n2->removeChild(n1);
 				// n1 has two children. pick one randomly 50-50, destroy other
@@ -318,5 +370,5 @@
 		while (1)
 		{
-			if (strchr(MUT_CHAN_CODES, n1->name)) break;
+			if (strchr(MUT_CHAN_CODES, n1->name[0])) break;
 			// try a new one
 			n1 = g->child->randomNode();
@@ -324,15 +376,41 @@
 			if (i >= 20) return GENOPER_OPFAIL;
 		}
-		switch (n1->name)
+		switch (n1->name[0])
 		{
 		case '<':
+		{
 			// swap children
-			n2 = n1->child; n1->child = n1->child2; n1->child2 = n2;
+			f4_node *n2 = n1->child; n1->child = n1->child2; n1->child2 = n2;
+		}
 			break;
 		case '[':
-			linkNodeChangeRandom(n1);
+		{
+			neuronid = -1;
+			for (int i = 0; i < g->count(); i++)
+			{
+				f4_node *gcur = g->ordNode(i);
+				char *temp = (char*)gcur->name.c_str();
+				NeuroClass *neuclass = GenoOperators::parseNeuroClass(temp);
+				if (neuclass != NULL)
+				{
+					neulist.push_back(neuclass);
+				}
+				if (gcur == n1)
+				{
+					neuronid = neulist.size()-1;
+				}
+			}
+			if (neuronid == -1)
+			{
+				return GENOPER_OPFAIL;
+			}
+			linkNodeChangeRandom(n1, neuronid, neulist);
+		}
 			break;
+
 		case '#':
+		{
 			repeatNodeChangeRandom(n1);
+		}
 			break;
 		}
@@ -348,10 +426,9 @@
 
 // make a random [ node
-void Geno_f4::linkNodeMakeRandom(f4_node * nn) const
-{
-	int i;
+void Geno_f4::linkNodeMakeRandom(f4_node *nn, int neuid, vector<NeuroClass*> neulist) const
+{
 	float prob1;
-
-	i = 0;
+	NeuroClass *nc = NULL;
+
 	// 35% chance one of *GTS
 	prob1 = rnd01;
@@ -360,24 +437,30 @@
 	{
 		// '*', 'G', 'T', or 'S', 1/4 chance each
-		i = 1 + (int)(3.999f * rnd01);
-	}
-	nn->i1 = i;
-	nn->l1 = 0;
-	if (0 == i)
+		nc =  GenoOperators::getRandomNeuroClassWithOutputAndNoInputs();
+	}
+	if (nc != NULL)
+	{
+		nn->i1 = 1;
+		nn->s1 = nc->getName().c_str();
+		nn->l1 = 0;
+	}
+	else
 	{
 		// relative input link
-		nn->l1 = (int)(4.0f * (rnd01 - 0.5f));
+		int id = GenoOperators::getRandomNeuroClassWithOutput(neulist);
+		int relid = neuid - id;
+		nn->l1 = relid;
+		//nn->l1 = (int)(4.0f * (rnd01 - 0.5f));
 	}
 	// weight
-	nn->f1 = 10.0f * (rnd01 - 0.5f);
+	nn->f1 = GenoOperators::mutateNeuProperty(nn->f1,NULL,-1);
+	//nn->f1 = 10.0f * (rnd01 - 0.5f);
 }
 
 // change a [ node
-void Geno_f4::linkNodeChangeRandom(f4_node * nn) const      //rewritten by M.K. - should work as before (not tested)
-{
-	int i;
-	float prob2;
-
+void Geno_f4::linkNodeChangeRandom(f4_node * nn, int neuid, std::vector<NeuroClass*> neulist) const      //rewritten by M.K. - should work as before (not tested)
+{
 	double probs[3] = { 0.1, 0.3, 0.6 };
+	NeuroClass *cl;
 	// 10% change type
 	// 30% change link
@@ -387,16 +470,27 @@
 	{
 	case 0: // change type
-		i = 0;
-		// * G, 10% chance each
-		prob2 = rnd01 - 0.10f;
-		if (prob2 < 0) i = 1; else { prob2 -= 0.10f; if (prob2 < 0) i = 2; }
-		nn->i1 = i;
+		// 80% for link, 20% for random sensor
+		if (rnd01 < 0.2f)
+		{
+			cl = GenoOperators::getRandomNeuroClassWithOutputAndNoInputs();
+			if (cl != NULL)
+			{
+				nn->i1 = 1;
+				nn->s1 = cl->name.c_str();
+				nn->l1 = 0;
+			}
+		}
 		break;
 	case 1: // change link
 		if (0 == nn->i1) // relative input link
-			nn->l1 += (int)(2.0f * (rnd01 - 0.5f));
+		{
+			int id = GenoOperators::getRandomNeuroClassWithOutput(neulist);
+			nn->l1 = neuid - id;
+		}
+			//nn->l1 += (int)(2.0f * (rnd01 - 0.5f));
 		break;
 	case 2: // change weight
-		nn->f1 += 1.0f * (rnd01 - 0.5f);
+		nn->f1 = GenoOperators::mutateNeuProperty(nn->f1,NULL,-1);
+		//nn->f1 += 1.0f * (rnd01 - 0.5f);
 		break;
 	}
Index: cpp/frams/genetics/f4/oper_f4.h
===================================================================
--- cpp/frams/genetics/f4/oper_f4.h	(revision 759)
+++ cpp/frams/genetics/f4/oper_f4.h	(revision 760)
@@ -15,10 +15,14 @@
 #include <frams/param/param.h>
 
+/** @name Codes for general mutation types */
+//@{
+#define F4_ADD           0 ///<Adding new node
+#define F4_DEL           1 ///<Deletion of node
+#define F4_MOD           2 ///<Modification of node
+#define F4_COUNT         3 ///<Count of mutation types
+//@}
 
-#define F4_ADD           0
-#define F4_DEL           1
-#define F4_MOD           2
-#define F4_COUNT         3
-
+/** @name Codes for specific F4_ADD mutation subtypes */
+//@{
 #define F4_ADD_DIV       0
 #define F4_ADD_CONN      1
@@ -27,5 +31,5 @@
 #define F4_ADD_SIMP      4
 #define F4_ADD_COUNT     5
-
+//@}
 
 class Geno_f4 : public GenoOperators
@@ -43,21 +47,92 @@
 
 	// mutation probabilities
-	double prob[F4_COUNT], probadd[F4_ADD_COUNT];
+	double prob[F4_COUNT];            ///<reltive probabilities of selecting mutation types in f4 genotype
+	double probadd[F4_ADD_COUNT];     ///<relative probabilities of selecting mutation addition subtypes
 
-	SString excluded_modifiers; //not to be used in mutations
+	SString excluded_modifiers;       ///<Modifiers that are excluded in mutation process
 	static const char *all_modifiers;
 
 protected:
-	/* int MutateMany(char *& g, float & chg); // not used anymore */
+
+	/**
+	 * Validates a f4 genotype. If the genotype is invalid, the genotype is repaired
+	 * and the validation is repeated. Validation is performed as long as repairing
+	 * is not effective, or the number of retries exceeded the given limit.
+	 * @param geno genotype tree
+	 * @param retrycount maximum amount of repair retries
+	 * @return GENOOPER_OK if genotype is valid, GENOPER_REPAIR if genotype can be repaired, GENOPER_OPFAIL if genotype can't be repaired
+	 */
 	int  ValidateRec(f4_node * geno, int retrycount) const;
+
+	/**
+	 * Performs mutation of an f4 genotype. The mutation is performed on a random node
+	 * from a given tree. The method of mutation is chosen via the roulette selection,
+	 * where probabilities of choosing each mutation type are given in the 'prob'
+	 * array. Possible mutation types are:
+	 *  - F4_ADD - adds new element to the genotype by:
+	 *   - F4_ADD_DIV - replacing randomly selected node with division node '<', setting this node as a child and creating new stick or neuron sibling of the selected cell (the neuron-type sibling will be connected to a random existing neuron),
+	 *   - F4_ADD_CONN - adding connection for an existing neuron,
+	 *   - F4_ADD_NEUPAR - adding neuron property to the selected node, if it is a neuron node,
+	 *   - F4_ADD_REP - adding a repetition node before a randomly selected node (the repetition node has 2 repetitions),
+	 *   - F4_ADD_SIMP - adding a simple node before a selected node,
+	 *  - F4_DEL - removes a randomly selected node (the node needs to have a parent and at least one child, otherwise returns GENOPER_OPFAIL),
+	 *  - F4_MOD - modifies one of simple nodes by:
+	 *   - '<' - swapping children in division
+	 *   - '[' - modifying connection of a neuron
+	 *   - '#' - incrementing or decrementing repetition count
+	 *
+	 * @param g input genotype; the result of mutation will be stored in this parameter
+	 * @param method reference to the variable that will get the selected method of mutation
+	 * @return GENOPER_OK if mutation was performed successfully, GENOPER_FAIL otherwise
+	 */
 	int  MutateOne(f4_node *& g, int &method) const;
-	void linkNodeMakeRandom(f4_node * nn) const;
-	void linkNodeChangeRandom(f4_node * nn) const;
-	void nparNodeMakeRandom(f4_node * nn) const;
-	void repeatNodeChangeRandom(f4_node * nn) const;
+
+	/**
+	 * Creates a random connection to an existing neuron or creates an additional
+	 * sensor for a neuron.
+	 * @param nn neuron class node
+	 * @param neuid id of a neuron
+	 * @param neulist list of genotype neuron classes
+	 */
+	void linkNodeMakeRandom(f4_node * nn, int neuid, std::vector<NeuroClass*> neulist) const;
+
+	/**
+	 * Changes connection to an existing neuron or creates an additional
+	 * sensor for neuron.
+	 * @param nn neuron connection node
+	 * @param neuid id of a neuron
+	 * @param neulist list of genotype neuron classes
+	 */
+	void linkNodeChangeRandom(f4_node * nn, int neuid, std::vector<NeuroClass*> neulist) const;
+
+	/**
+	 * Introduces a random modification to the neuron node.
+	 * @param nn neuron node
+	 */
+	void nparNodeMakeRandom(f4_node *nn) const;
+
+	/**
+	 * Increases or decreases the amount of repetitions in the repetition node.
+	 * @param nn repetition node
+	 */
+	void repeatNodeChangeRandom(f4_node *nn) const;
+
+	/**
+	 * Tries to perform a mutation until success. There is a maximum of 20 tries. Returns GENOPER_OK or GENOPER_OPFAIL.
+	 * @param g genotype tree
+	 * @param method reference to the variable that will get the selected method of mutation
+	 * @return GENOPER_OK if performed successful mutation, GENOPER_FAIL otherwise
+	 */
 	int  MutateOneValid(f4_node * &g, int &method) const;
+
+	/**
+	 * Performs crossover of two creatures. The 'chg' parameter determines approximately what
+	 * percentage of the first creature should form the offspring. '1-chg' is the percentage
+	 * of the second creature in the offspring.
+	 * @param g1 first parent
+	 * @param g2 second parent
+	 * @param chg percentage of the first parent in offspring (the second parent has the rest)
+	 */
 	int  CrossOverOne(f4_node *g1, f4_node *g2, float chg) const;
-	// returns GENOPER_OK or GENOPER_OPFAIL
-	// chg: fraction of parent1 genes in child (in g1) (parent2 has the rest)
 };
 
