Index: cpp/frams/genetics/fS/fS_general.cpp
===================================================================
--- cpp/frams/genetics/fS/fS_general.cpp	(revision 968)
+++ cpp/frams/genetics/fS/fS_general.cpp	(revision 969)
@@ -10,14 +10,9 @@
 #include "frams/util/rndutil.h"
 #include "frams/neuro/neurolibrary.h"
-
+#include "../genooperators.h"
 
 int fS_Genotype::precision = 4;
-
-
-double round2(double var)
-{
-	double value = (int) (var * 100 + .5);
-	return (double) value / 100;
-}
+bool fS_Genotype::TURN_WITH_ROTATION = false;
+
 
 double fS_stod(const string&  str, int start, size_t* size)
@@ -30,4 +25,8 @@
 	{
 		throw fS_Exception("Invalid numeric value", start);
+	}
+	catch(const std::out_of_range& ex)
+	{
+		throw fS_Exception("Invalid numeric value; out of range", start);
 	}
 }
@@ -39,4 +38,5 @@
 	fr = _state->fr;
 	s = _state->s;
+	stif = _state->stif;
 }
 
@@ -55,9 +55,5 @@
 {
 	Orient rotmatrix = Orient_1;
-	rotmatrix.rotate(Pt3D(
-			Convert::toRadians(rotation.x),
-			Convert::toRadians(rotation.y),
-			Convert::toRadians(rotation.z)
-	));
+	rotmatrix.rotate(rotation);
 	vector = rotmatrix.transform(vector);
 }
@@ -115,10 +111,7 @@
 }
 
-Node::Node(Substring &restOfGeno, bool _modifierMode, bool _paramMode, bool _cycleMode, Node *_parent)
+Node::Node(Substring &restOfGeno, Node *_parent)
 {
 	parent = _parent;
-	modifierMode = _modifierMode;
-	paramMode = _paramMode;
-	cycleMode = _cycleMode;
 	partDescription = new Substring(restOfGeno);
 
@@ -293,5 +286,5 @@
 		return item->second;
 	else
-		return defaultParamValues.at(key);
+		return defaultValues.at(key);
 }
 
@@ -415,20 +408,25 @@
 }
 
-double getDistance(Pt3D radiiParent, Pt3D radii, Pt3D vector, Pt3D rotationParent, Pt3D rotation)
-{
+double Node::getDistance()
+{
+	Pt3D size = calculateSize();
+	Pt3D parentSize = parent->calculateSize();	// Here we are sure that parent is not nullptr
 	int parentSphereCount, sphereCount;
 	double parentSphereRadius, sphereRadius;
-	Pt3D *centersParent = findSphereCenters(parentSphereCount, parentSphereRadius, radiiParent, rotationParent);
-	Pt3D *centers = findSphereCenters(sphereCount, sphereRadius, radii, rotation);
+	Pt3D *centersParent = findSphereCenters(parentSphereCount, parentSphereRadius, parentSize, parent->getRotation());
+	Pt3D *centers = findSphereCenters(sphereCount, sphereRadius, size, getRotation());
 
 	double distanceThreshold = sphereRadius + parentSphereRadius;
 	double minDistance = 0.0;
-	double maxDistance = 2 * (max3(radiiParent) + max3(radii));
+	double maxDistance = 2 * (max3(parentSize) + max3(size));
 	double currentDistance = avg(maxDistance, minDistance);
 	int result = -1;
+	int iterationNo = 0;
 	while (result != ADJACENT)
 	{
-		Pt3D currentVector = vector * currentDistance;
+		iterationNo++;
+		Pt3D currentVector = state->v * currentDistance;
 		result = isCollision(centersParent, centers, parentSphereCount, sphereCount, currentVector, distanceThreshold);
+
 		if (result == DISJOINT)
 		{
@@ -440,6 +438,11 @@
 			currentDistance = avg(maxDistance, currentDistance);
 		}
+
+		if(maxDistance <= 0 || iterationNo > 1000)
+			throw fS_Exception("Computing of distances between parts failed", 0);
 		if (currentDistance > maxDistance)
+		{
 			throw fS_Exception("Internal error; then maximal distance between parts exceeded.", 0);
+		}
 		if (currentDistance < minDistance)
 			throw fS_Exception("Internal error; the minimal distance between parts exceeded.", 0);
@@ -449,8 +452,8 @@
 	delete[] centersParent;
 	delete[] centers;
-	return round2(currentDistance);
-}
-
-void Node::getState(State *_state, const Pt3D &parentSize)
+	return currentDistance;
+}
+
+void Node::getState(State *_state)
 {
 	if (state != nullptr)
@@ -473,7 +476,8 @@
 		else if (mod == MODIFIERS[2])
 			state->s *= multiplier;
-	}
-
-	Pt3D size = calculateSize();
+		else if (mod == MODIFIERS[3])
+			state->stif *= multiplier;
+	}
+
 	if (parent != nullptr)
 	{
@@ -481,9 +485,9 @@
 		state->rotate(getVectorRotation());
 
-		double distance = getDistance(parentSize, size, state->v, getRotation(), getRotation());
+		double distance = getDistance();
 		state->addVector(distance);
 	}
 	for (int i = 0; i < int(children.size()); i++)
-		children[i]->getState(state, size);
+		children[i]->getState(state);
 }
 
@@ -493,5 +497,5 @@
 	for (int i = 0; i < int(branches.size()); i++)
 	{
-		children.push_back(new Node(branches[i], modifierMode, paramMode, cycleMode, this));
+		children.push_back(new Node(branches[i], this));
 	}
 }
@@ -593,16 +597,13 @@
 Pt3D Node::getVectorRotation()
 {
-	double rx = getParam(ROT_X);
-	double ry = getParam(ROT_Y);
-	double rz = getParam(ROT_Z);
-	return Pt3D(rx, ry, rz);
+	return Pt3D(getParam(ROT_X), getParam(ROT_Y), getParam(ROT_Z));
 }
 
 Pt3D Node::getRotation()
 {
-	double rx = getParam(RX);
-	double ry = getParam(RY);
-	double rz = getParam(RZ);
-	return Pt3D(rx, ry, rz);
+	Pt3D rotation = Pt3D(getParam(RX), getParam(RY), getParam(RZ));
+	if(fS_Genotype::TURN_WITH_ROTATION)
+		rotation += getVectorRotation();
+	return rotation;
 }
 
@@ -614,5 +615,4 @@
 		addJointsToModel(model, parent);
 
-
 	for (int i = 0; i < int(neurons.size()); i++)
 	{
@@ -639,14 +639,14 @@
 {
 	part = new Part(partType);
-	part->p = Pt3D(round2(state->location.x),
-				   round2(state->location.y),
-				   round2(state->location.z));
-
-	part->friction = round2(getParam(FRICTION) * state->fr);
-	part->ingest = round2(getParam(INGESTION) * state->ing);
+	part->p = Pt3D(state->location.x,
+				   state->location.y,
+				   state->location.z);
+
+	part->friction = getParam(FRICTION) * state->fr;
+	part->ingest = getParam(INGESTION) * state->ing;
 	Pt3D size = calculateSize();
-	part->scale.x = round2(size.x);
-	part->scale.y = round2(size.y);
-	part->scale.z = round2(size.z);
+	part->scale.x = size.x;
+	part->scale.y = size.y;
+	part->scale.z = size.z;
 	part->setRot(getRotation());
 }
@@ -655,4 +655,7 @@
 {
 	Joint *j = new Joint();
+	j->stif = getParam(STIFFNESS) * state->stif;
+	j->rotstif = j->stif;
+
 	j->attachToParts(parent->part, part);
 	switch (joint)
@@ -698,10 +701,9 @@
 			if (i != 0)
 				result += NEURON_SEPARATOR;
-			if (n->getClassName() != "N")
-			{
-				result += n->getDetails();
-				if (!n->inputs.empty())
-					result += NEURON_INTERNAL_SEPARATOR;
-			}
+
+			result += n->getDetails();
+			if (!n->inputs.empty())
+				result += NEURON_INTERNAL_SEPARATOR;
+
 			for (auto it = n->inputs.begin(); it != n->inputs.end(); ++it)
 			{
@@ -714,5 +716,4 @@
 					result += SString::valueOf(it->second);
 				}
-
 			}
 		}
@@ -754,13 +755,13 @@
 
 
-bool Node::changeSizeParam(string paramKey, double multiplier, bool ensureCircleSection)
-{
-	double oldValue = getParam(paramKey);
-	params[paramKey] = oldValue * multiplier;
+bool Node::changeSizeParam(string key, bool ensureCircleSection)
+{
+	double oldValue = getParam(key);
+	params[key] = GenoOperators::mutateCreep('f', params[key], minValues.at(key), maxValues.at(key), true);
 	if (!ensureCircleSection || isPartSizeValid())
 		return true;
 	else
 	{
-		params[paramKey] = oldValue;
+		params[key] = oldValue;
 		return false;
 	}
@@ -786,17 +787,6 @@
 	{
 		string geno = genotype.c_str();
-		// M - modifier mode, S - standard mode
-		size_t modeSeparatorIndex = geno.find(':');
-		if (modeSeparatorIndex == string::npos)
-			throw fS_Exception("No mode separator", 0);
-
-		string modeStr = geno.substr(0, modeSeparatorIndex).c_str();
-		bool modifierMode = modeStr.find(MODIFIER_MODE) != string::npos;
-		bool paramMode = modeStr.find(PARAM_MODE) != string::npos;
-		bool cycleMode = modeStr.find(CYCLE_MODE) != string::npos;
-
-		int actualGenoStart = modeSeparatorIndex + 1;
-		Substring substring(geno.c_str(), actualGenoStart, geno.length() - actualGenoStart);
-		startNode = new Node(substring, modifierMode, paramMode, cycleMode, nullptr);
+		Substring substring(geno.c_str(), 0, geno.length());
+		startNode = new Node(substring, nullptr);
 		validateNeuroInputs();
 	}
@@ -816,15 +806,5 @@
 {
 	State *initialState = new State(Pt3D(0), Pt3D(1, 0, 0));
-	startNode->getState(initialState, Pt3D(1.0));
-}
-
-double fS_Genotype::randomParamMultiplier()
-{
-	double multiplier = 1 + fabs(RndGen.GaussStd());
-	if (multiplier > PARAM_MAX_MULTIPLIER)
-		multiplier = PARAM_MAX_MULTIPLIER;
-	if (rndUint(2) == 0)
-		multiplier = 1.0 / multiplier;
-	return multiplier;
+	startNode->getState(initialState);
 }
 
@@ -833,30 +813,5 @@
 	getState();
 	startNode->buildModel(model, nullptr);
-
 	buildNeuroConnections(model);
-
-	// Additional joints
-	vector<Node*> allNodes = getAllNodes();
-	for (int i = 0; i < int(allNodes.size()); i++)
-	{
-		Node *node = allNodes[i];
-		if (node->params.find(JOINT_DISTANCE) != node->params.end())
-		{
-			Node *otherNode = getNearestNode(allNodes, node);
-			if (otherNode != nullptr)
-			{
-				// If other node is close enough, add a joint
-				double distance = node->state->location.distanceTo(otherNode->state->location);
-				if (distance < node->params[JOINT_DISTANCE])
-				{
-					Joint *joint = new Joint();
-					joint->attachToParts(node->part, otherNode->part);
-
-					joint->shape = Joint::Shape::SHAPE_FIXED;
-					model.addJoint(joint);
-				}
-			}
-		}
-	}
 }
 
@@ -905,13 +860,4 @@
 	SString geno;
 	geno.memoryHint(100);     // Provide a small buffer from the start to improve performance
-
-	if (startNode->modifierMode)
-		geno += MODIFIER_MODE;
-	if (startNode->paramMode)
-		geno += PARAM_MODE;
-	if (startNode->cycleMode)
-		geno += CYCLE_MODE;
-
-	geno += ':';
 	startNode->getGeno(geno);
 	return geno;
@@ -1010,5 +956,5 @@
 		if (!nodes[i]->isPartSizeValid())
 		{
-			return nodes[i]->partDescription->start;
+			return 1 + nodes[i]->partDescription->start;
 		}
 	}
Index: cpp/frams/genetics/fS/fS_general.h
===================================================================
--- cpp/frams/genetics/fS/fS_general.h	(revision 968)
+++ cpp/frams/genetics/fS/fS_general.h	(revision 969)
@@ -14,16 +14,9 @@
 #include "frams/util/multirange.h"
 
-/** @name Names of genotype modes */
-//@{
-#define MODIFIER_MODE 'M'
-#define PARAM_MODE 'S'
-#define CYCLE_MODE 'J'
-//@}
-
 /** @name Values of constants used in encoding */
 //@{
 #define BRANCH_START '('
 #define BRANCH_END ')'
-#define BRANCH_SEPARATOR ','
+#define BRANCH_SEPARATOR '^'
 #define PARAM_START '{'
 #define PARAM_END '}'
@@ -45,7 +38,4 @@
 /** @name Every modifier changes the underlying value by this multiplier */
 const double MODIFIER_MULTIPLIER = 1.1;
-/** @name In mutation parameters will be multiplied by at most this value */
-const double PARAM_MAX_MULTIPLIER = 1.5;
-
 /**
  * Used in finding the proper distance between the parts
@@ -70,4 +60,5 @@
 #define INGESTION "i"
 #define FRICTION "f"
+#define STIFFNESS "st"
 #define SIZE "s"
 #define SIZE_X "x"
@@ -80,5 +71,4 @@
 #define RY "ry"
 #define RZ "rz"
-#define JOINT_DISTANCE "j"
 //@}
 /** @name Macros and values used in collision detection */
@@ -113,15 +103,23 @@
 const char DEFAULT_JOINT = 'a';
 const string JOINTS = "bc";
+const string ALL_JOINTS = "abc";
 const int JOINT_COUNT = JOINTS.length();
-const string MODIFIERS = "IFS";
+const string MODIFIERS = "IFST";
 const char SIZE_MODIFIER = 's';
 const vector<string> PARAMS {INGESTION, FRICTION, ROT_X, ROT_Y, ROT_Z, RX, RY, RZ, SIZE, SIZE_X, SIZE_Y, SIZE_Z,
-							  JOINT_DISTANCE};
+							 STIFFNESS};
 
 /** @name Default values of node parameters*/
 static const Part defPart = Model::getDefPart();
-const std::map<string, double> defaultParamValues = {
+static const Joint defJoint = Model::getDefJoint();
+const std::map<Part::Shape, double> volumeMultipliers = {
+		{Part::Shape::SHAPE_CUBOID, 8.0},
+		{Part::Shape::SHAPE_CYLINDER, 2.0 * M_PI},
+		{Part::Shape::SHAPE_ELLIPSOID, (4.0 / 3.0) * M_PI},
+};
+const std::map<string, double> defaultValues = {
 		{INGESTION,      defPart.ingest},
 		{FRICTION,       defPart.friction},
+		{STIFFNESS,	 	 defJoint.stif},
 		{ROT_X,          0.0},
 		{ROT_Y,          0.0},
@@ -133,6 +131,37 @@
 		{SIZE_X,         1.0},
 		{SIZE_Y,         1.0},
-		{SIZE_Z,         1.0},
-		{JOINT_DISTANCE, 1.0}
+		{SIZE_Z,         1.0}
+};
+
+const std::map<string, double> minValues = {
+		{INGESTION,      0},
+		{FRICTION,       0},
+		{STIFFNESS,	 0.0},
+		{ROT_X,          -M_PI},
+		{ROT_Y,          -M_PI},
+		{ROT_Z,          -M_PI},
+		{RX,             -M_PI},
+		{RY,             -M_PI},
+		{RZ,             -M_PI},
+		{SIZE,           0.01},
+		{SIZE_X,         0.01},
+		{SIZE_Y,         0.01},
+		{SIZE_Z,         0.01}
+};
+
+const std::map<string, double> maxValues = {
+		{INGESTION,      1.0},
+		{FRICTION,       1.0},
+		{STIFFNESS,	 0.0},
+		{ROT_X,          M_PI},
+		{ROT_Y,          M_PI},
+		{ROT_Z,          M_PI},
+		{RX,             M_PI},
+		{RY,             M_PI},
+		{RZ,             M_PI},
+		{SIZE,           100.0},
+		{SIZE_X,         100.0},
+		{SIZE_Y,         100.0},
+		{SIZE_Z,         100.0}
 };
 
@@ -252,4 +281,5 @@
 	double ing = 1.0;      /// Ingestion multiplier
 	double s = 1.0;      /// Size multipliers
+	double stif = 1.0;	/// Stiffness multipliers
 
 	State(State *_state); /// Derive the state from parent
@@ -301,5 +331,4 @@
 private:
 	Substring *partDescription = nullptr;
-	bool cycleMode, modifierMode, paramMode; /// Possible modes
 	Node *parent;
 	Part *part;     /// A part object built from node. Used in building the Model
@@ -309,26 +338,7 @@
 	vector<Node *> children;    /// Vector of all direct children
 	std::map<char, int> modifiers;     /// Vector of all modifiers
-	char joint = DEFAULT_JOINT;           /// Set of all joints
 	vector<fS_Neuron *> neurons;    /// Vector of all the neurons
 
-	static double calculateRadiusFromVolume(Part::Shape partType, double volume)
-	{
-		double result;
-		switch (partType)
-		{
-			case Part::Shape::SHAPE_CUBOID:
-				result = std::cbrt(volume / 8.0);
-				break;
-			case Part::Shape::SHAPE_CYLINDER:
-				result = std::cbrt(volume / (2.0 * M_PI));
-				break;
-			case Part::Shape::SHAPE_ELLIPSOID:
-				result = std::cbrt(volume / ((4.0 / 3.0) * M_PI));
-				break;
-			default:
-				logMessage("fS", "calculateVolume", LOG_ERROR, "Invalid part type");
-		}
-		return result;
-	}
+	double getDistance();
 
 	void cleanUp();
@@ -384,5 +394,5 @@
 	 * @param _state state of the parent
 	 */
-	void getState(State *_state, const Pt3D &parentSize);
+	void getState(State *_state);
 
 	/**
@@ -419,8 +429,9 @@
 
 public:
+	char joint = DEFAULT_JOINT;           /// Set of all joints
 	Part::Shape partType;  /// The type of the part
 	State *state = nullptr; /// The phenotypic state that inherits from ancestors
 
-	Node(Substring &genotype, bool _modifierMode, bool _paramMode, bool _cycleMode, Node *parent);
+	Node(Substring &genotype, Node *parent);
 
 	~Node();
@@ -452,5 +463,5 @@
 	 * @return True if the parameter value was change, false otherwise
 	 */
-	bool changeSizeParam(string paramKey, double multiplier, bool ensureCircleSection);
+	bool changeSizeParam(string paramKey,  bool ensureCircleSection);
 
 	/**
@@ -501,4 +512,5 @@
 
 	static int precision;
+	static bool TURN_WITH_ROTATION;
 
 	/**
@@ -511,10 +523,4 @@
 
 	void getState();
-
-	/**
-	 * Get a random multiplier for parameter mutation
-	 * @return Random parameter multiplier
-	 */
-	static double randomParamMultiplier();
 
 	/**
Index: cpp/frams/genetics/fS/fS_oper.cpp
===================================================================
--- cpp/frams/genetics/fS/fS_oper.cpp	(revision 968)
+++ cpp/frams/genetics/fS/fS_oper.cpp	(revision 969)
@@ -15,6 +15,5 @@
 				{"fS_mut_rem_part",         0, 0, "Remove part",              "f 0 100 10", FIELD(prob[FS_REM_PART]),             "mutation: probability of deleting a part",},
 				{"fS_mut_mod_part",         0, 0, "Modify part",              "f 0 100 10", FIELD(prob[FS_MOD_PART]),             "mutation: probability of changing the part type",},
-				{"fS_mut_add_joint",        0, 0, "Add joint",                "f 0 100 10", FIELD(prob[FS_ADD_JOINT]),            "mutation: probability of adding a joint",},
-				{"fS_mut_rem_joint",        0, 0, "Remove joint",             "f 0 100 10", FIELD(prob[FS_REM_JOINT]),            "mutation: probability of removing a joint",},
+				{"fS_mut_change_joint",        0, 0, "Change joint",                "f 0 100 10", FIELD(prob[FS_CHANGE_JOINT]),            "mutation: probability of changing a joint",},
 				{"fS_mut_add_param",        0, 0, "Add param",                "f 0 100 10", FIELD(prob[FS_ADD_PARAM]),            "mutation: probability of adding a parameter",},
 				{"fS_mut_rem_param",        0, 0, "Remove param",             "f 0 100 10", FIELD(prob[FS_REM_PARAM]),            "mutation: probability of removing a parameter",},
@@ -41,5 +40,5 @@
 	par.select(this);
 	par.setDefault();
-	supported_format = "S";
+	supported_format = 'S';
 }
 
@@ -53,5 +52,5 @@
 		{
 			logPrintf("GenoOper_fS", "checkValidity", LOG_ERROR, "Invalid part size");
-			return 1 + errorPosition;
+			return errorPosition;
 		}
 	}
@@ -92,9 +91,6 @@
 			result = changePartType(genotype, availableTypes);
 			break;
-		case FS_ADD_JOINT:
-			result = addJoint(genotype);
-			break;
-		case FS_REM_JOINT:
-			result = removeJoint(genotype);
+		case FS_CHANGE_JOINT:
+			result = changeJoint(genotype);
 			break;
 		case FS_ADD_PARAM:
@@ -214,5 +210,5 @@
 const char* GenoOper_fS::getSimplest()
 {
-	return "S:C{x=0.80599;y=0.80599;z=0.80599}";
+	return "C{x=0.80599;y=0.80599;z=0.80599}";
 }
 
@@ -233,9 +229,9 @@
 		style = GENSTYLE_RGBS(0, 200, 0, GENSTYLE_NONE);
 	}
-	else if (isdigit(ch) || strchr(".=", ch)) // Numerical value
+	else if (isdigit(ch) || strchr(".", ch)) // Numerical value
 	{
 		style = GENSTYLE_RGBS(200, 0, 0, GENSTYLE_NONE);
 	}
-	else if(strchr("()_;[],", ch))
+	else if(strchr("()_;[],=", ch))
 	{
 		style = GENSTYLE_CS(0, GENSTYLE_BOLD); // Important char
@@ -292,5 +288,5 @@
 
 	Substring substring(&partType, 0, 1);
-	Node *newNode = new Node(substring, node->modifierMode, node->paramMode, node->cycleMode, node);
+	Node *newNode = new Node(substring, node);
 	// Add random rotation
 	string rotationParams[]{ROT_X, ROT_Y, ROT_Z};
@@ -298,10 +294,10 @@
 	{
 		for(int i=0; i < 3; i++)
-			newNode->params[rotationParams[i]] = RndGen.Uni(-90, 90);
+			newNode->params[rotationParams[i]] = RndGen.Uni(-M_PI / 2, M_PI / 2);
 	}
 	else
 	{
 		string selectedParam = rotationParams[rndUint(3)];
-		newNode->params[selectedParam] = RndGen.Uni(-90, 90);
+		newNode->params[selectedParam] = RndGen.Uni(-M_PI / 2, M_PI / 2);
 	}
 	string rParams[]{RX, RY, RZ};
@@ -309,10 +305,10 @@
 	{
 		for(int i=0; i < 3; i++)
-			newNode->params[rParams[i]] = RndGen.Uni(-90, 90);
+			newNode->params[rParams[i]] = RndGen.Uni(-M_PI / 2, M_PI / 2);
 	}
 	else
 	{
 		string selectedParam = rParams[rndUint(3)];
-		newNode->params[selectedParam] = RndGen.Uni(-90, 90);
+		newNode->params[selectedParam] = RndGen.Uni(-M_PI / 2, M_PI / 2);
 	}
 	// Assign part size to default value
@@ -324,5 +320,5 @@
 	double relativeVolume = volume / volumeMultiplier;    // Volume without applying modifiers
 
-	double newRadius = Node::calculateRadiusFromVolume(newNode->partType, relativeVolume);
+	double newRadius = std::cbrt(relativeVolume / volumeMultipliers.at(newNode->partType));
 	newNode->params[SIZE_X] = newRadius;
 	newNode->params[SIZE_Y] = newRadius;
@@ -333,7 +329,7 @@
 	{
 		geno.getState();
-		newNode->changeSizeParam(SIZE_X, fS_Genotype::randomParamMultiplier(), true);
-		newNode->changeSizeParam(SIZE_Y, fS_Genotype::randomParamMultiplier(), true);
-		newNode->changeSizeParam(SIZE_Z, fS_Genotype::randomParamMultiplier(), true);
+		newNode->changeSizeParam(SIZE_X, true);
+		newNode->changeSizeParam(SIZE_Y, true);
+		newNode->changeSizeParam(SIZE_Z, true);
 	}
 	return true;
@@ -374,5 +370,5 @@
 		int index = rndUint(availTypesLength);
 		if (availTypes[index] == SHAPETYPE_TO_GENE.at(randomNode->partType))
-			index = (index + 1 + rndUint(availTypesLength)) % availTypesLength;
+			index = (index + 1 + rndUint(availTypesLength - 1)) % availTypesLength;
 		char newTypeChr = availTypes[index];
 
@@ -385,17 +381,32 @@
 #endif
 
-		if (ensureCircleSection)
-		{
-			geno.getState();
-			if (randomNode->partType == Part::Shape::SHAPE_CUBOID
-				|| (randomNode->partType == Part::Shape::SHAPE_CYLINDER && newType == Part::Shape::SHAPE_ELLIPSOID))
-			{
-				double sizeMultiplier = randomNode->getParam(SIZE) * randomNode->state->s;
-				double relativeVolume = randomNode->calculateVolume() / pow(sizeMultiplier, 3.0);
-				double newRelativeRadius = Node::calculateRadiusFromVolume(newType, relativeVolume);
-				randomNode->params[SIZE_X] = newRelativeRadius;
-				randomNode->params[SIZE_Y] = newRelativeRadius;
-				randomNode->params[SIZE_Z] = newRelativeRadius;
-			}
+		geno.getState();
+		double sizeMultiplier = randomNode->getParam(SIZE) * randomNode->state->s;
+		double relativeVolume = randomNode->calculateVolume() / pow(sizeMultiplier, 3.0);
+
+		if(!ensureCircleSection || newType == Part::Shape::SHAPE_CUBOID || (randomNode->partType == Part::Shape::SHAPE_ELLIPSOID && newType == Part::Shape::SHAPE_CYLINDER))
+		{
+			double radiusQuotient = std::cbrt(volumeMultipliers.at(randomNode->partType) / volumeMultipliers.at(newType));
+			randomNode->params[SIZE_X] = randomNode->getParam(SIZE_X) * radiusQuotient;
+			randomNode->params[SIZE_Y] = randomNode->getParam(SIZE_Y) * radiusQuotient;
+			randomNode->params[SIZE_Z] = randomNode->getParam(SIZE_Z) * radiusQuotient;
+		}
+		else if(randomNode->partType == Part::Shape::SHAPE_CUBOID && newType == Part::Shape::SHAPE_CYLINDER)
+		{
+			double newRadius = 0.5 * (randomNode->getParam(SIZE_X) + randomNode->getParam(SIZE_Y));
+			randomNode->params[SIZE_X] = newRadius;
+			randomNode->params[SIZE_Y] = newRadius;
+			randomNode->params[SIZE_Z] = 0.5 * relativeVolume / (M_PI * newRadius * newRadius);
+		}
+		else if(newType == Part::Shape::SHAPE_ELLIPSOID)
+		{
+			double newRelativeRadius = cbrt(relativeVolume / volumeMultipliers.at(newType));
+			randomNode->params[SIZE_X] = newRelativeRadius;
+			randomNode->params[SIZE_Y] = newRelativeRadius;
+			randomNode->params[SIZE_Z] = newRelativeRadius;
+		}
+		else
+		{
+			throw fS_Exception("Invalid part type", 1);
 		}
 		randomNode->partType = newType;
@@ -405,41 +416,17 @@
 }
 
-bool GenoOper_fS::addJoint(fS_Genotype &geno)
+bool GenoOper_fS::changeJoint(fS_Genotype &geno)
 {
 	if (geno.startNode->children.empty())
 		return false;
 
-	Node *randomNode;
-	for (int i = 0; i < mutationTries; i++)
-	{
-		char randomJoint = JOINTS[rndUint(JOINT_COUNT)];
-		randomNode = geno.chooseNode(1);        // First part does not have joints
-		if (randomNode->joint == DEFAULT_JOINT)
-		{
-			randomNode->joint = randomJoint;
-			return true;
-		}
-	}
-	return false;
-}
-
-
-bool GenoOper_fS::removeJoint(fS_Genotype &geno)
-{
-	// This operator may can lower success rate that others, as it does not work when there is only one node
-	if (geno.startNode->children.size() < 1) // Only one node; there are no joints
-		return false;
-
-	// Choose a node with joints
-	for (int i = 0; i < mutationTries; i++)
-	{
-		Node *randomNode = geno.chooseNode(1);    // First part does not have joints
-		if (randomNode->joint != DEFAULT_JOINT)
-		{
-			randomNode->joint = DEFAULT_JOINT;
-			return true;
-		}
-	}
-	return false;
+	Node *randomNode = geno.chooseNode(1);        // First part does not have joints
+	int jointLen  = ALL_JOINTS.length();
+	int index = rndUint(jointLen);
+	if (ALL_JOINTS[index] == randomNode->joint)
+		index = (index + 1 + rndUint(jointLen - 1)) % jointLen;
+
+	randomNode->joint = ALL_JOINTS[index];
+	return true;
 }
 
@@ -450,13 +437,10 @@
 	if (paramCount == int(PARAMS.size()))
 		return false;
-	string selectedParam = PARAMS[rndUint(PARAMS.size())];
-	// Not allow 'j' parameter when the cycle mode is not on
-	if (selectedParam == JOINT_DISTANCE && !geno.startNode->cycleMode)
-		return false;
-	if (randomNode->params.count(selectedParam) > 0)
+	string key = PARAMS[rndUint(PARAMS.size())];
+	if (randomNode->params.count(key) > 0)
 		return false;
 	// Do not allow invalid changes in part size
-	bool isRadiusOfBase = selectedParam == SIZE_X || selectedParam == SIZE_Y;
-	bool isRadius = isRadiusOfBase || selectedParam == SIZE_Z;
+	bool isRadiusOfBase = key == SIZE_X || key == SIZE_Y;
+	bool isRadius = isRadiusOfBase || key == SIZE_Z;
 	if (ensureCircleSection && isRadius)
 	{
@@ -467,5 +451,5 @@
 	}
 	// Add modified default value for param
-	randomNode->params[selectedParam] = defaultParamValues.at(selectedParam);
+	randomNode->params[key] = mutateCreep('f', defaultValues.at(key), minValues.at(key), maxValues.at(key), true);
 	return true;
 }
@@ -501,14 +485,11 @@
 			advance(it, rndUint(paramCount));
 
-			double multiplier = fS_Genotype::randomParamMultiplier();
-
-
 			// Do not allow invalid changes in part size
 			if (it->first != SIZE_X && it->first != SIZE_Y && it->first != SIZE_Z)
 			{
-				it->second *= multiplier;
+				it->second = GenoOperators::mutateCreep('f', it->second, minValues.at(it->first), maxValues.at(it->first), true);
 				return true;
 			} else
-				return randomNode->changeSizeParam(it->first, multiplier, ensureCircleSection);
+				return randomNode->changeSizeParam(it->first, ensureCircleSection);
 		}
 	}
@@ -607,5 +588,5 @@
 			advance(it, rndUint(inputCount));
 
-			it->second = GenoOperators::getMutatedNeuroClassProperty(it->second, selectedNeuron, -1);
+			it->second = GenoOperators::getMutatedNeuronConnectionWeight(it->second);
 			return true;
 		}
@@ -673,27 +654,4 @@
 
 	fS_Neuron *neu = neurons[rndUint(neurons.size())];
-	SyntParam par = neu->classProperties();
-
-	if (par.getPropCount() > 0)
-	{
-		int i = rndUint(par.getPropCount());
-		if (*par.type(i) == 'f')
-		{
-			double change = GenoOperators::getMutatedNeuroClassProperty(par.getDouble(i), neu, GenoOperators::NEUROCLASS_PROP_OFFSET + i);
-			par.setDouble(i, change);
-		}
-		SString line;
-		int tmp = 0;
-		par.update(&line);
-		SString props;
-		line.getNextToken(tmp, props, '\n'); // removal of newline character
-		if (props != "")
-		{
-			SString det = neu->getClass()->name + ": " + props;
-			neu->setDetails(det);
-			return true;
-		}
-	}
-
-	return false;
-}
+	return GenoOperators::mutateRandomNeuroClassProperty(neu);
+}
Index: cpp/frams/genetics/fS/fS_oper.h
===================================================================
--- cpp/frams/genetics/fS/fS_oper.h	(revision 968)
+++ cpp/frams/genetics/fS/fS_oper.h	(revision 969)
@@ -15,17 +15,16 @@
 #define FS_REM_PART 1
 #define FS_MOD_PART 2
-#define FS_ADD_JOINT 3
-#define FS_REM_JOINT 4
-#define FS_ADD_PARAM 5
-#define FS_REM_PARAM 6
-#define FS_MOD_PARAM 7
-#define FS_MOD_MOD 8
-#define FS_ADD_NEURO 9
-#define FS_REM_NEURO 10
-#define FS_MOD_NEURO_CONNECTION 11
-#define FS_ADD_NEURO_CONNECTION 12
-#define FS_REM_NEURO_CONNECTION 13
-#define FS_MOD_NEURO_PARAMS 14
-#define FS_OPCOUNT 15
+#define FS_CHANGE_JOINT 3
+#define FS_ADD_PARAM 4
+#define FS_REM_PARAM 5
+#define FS_MOD_PARAM 6
+#define FS_MOD_MOD 7
+#define FS_ADD_NEURO 8
+#define FS_REM_NEURO 9
+#define FS_MOD_NEURO_CONNECTION 10
+#define FS_ADD_NEURO_CONNECTION 11
+#define FS_REM_NEURO_CONNECTION 12
+#define FS_MOD_NEURO_PARAMS 13
+#define FS_OPCOUNT 14
 //@}
 
@@ -90,14 +89,8 @@
 
 	/**
-	 * Performs add joint mutation on genotype
+	 * Changes the type of one joint in genotype
 	 * @return true if mutation succeeded, false otherwise
 	 */
-	bool addJoint(fS_Genotype &geno);
-
-	/**
-	 * Performs remove mutation on genotype
-	 * @return true if mutation succeeded, false otherwise
-	 */
-	bool removeJoint(fS_Genotype &geno);
+	bool changeJoint(fS_Genotype &geno);
 
 	/**
