Index: cpp/frams/genetics/f1/conv_f1.cpp
===================================================================
--- cpp/frams/genetics/f1/conv_f1.cpp	(revision 743)
+++ cpp/frams/genetics/f1/conv_f1.cpp	(revision 759)
@@ -8,11 +8,9 @@
 #include <frams/util/multirange.h>
 #include <frams/util/multimap.h>
+#include <frams/genetics/geneprops.h>
 #include <ctype.h>
 #include <assert.h>
 
 //#define v1f1COMPATIBLE //as in ancient Framsticks 1.x
-
-F1Props stdprops = { 1, 0, 1, 0.4, 0.25, 0.25, 0.25, 0.25, 0.0, 1.0, 1.0, 1,
-0.2, 0.5, 0.5, 0.5 };
 
 class Builder
@@ -43,11 +41,11 @@
 	double model_energy;
 	int model_energy_count;
-	void grow(int part1, const char*g, Pt3D k, F1Props c, int branching_part);
+	void grow(int part1, const char*g, Pt3D k, GeneProps c, int branching_part);
 	void setPartMapping(int p, const char* g);
-	int growJoint(int part1, int part2, Pt3D &angle, F1Props &c, const char *g);
-	int growPart(F1Props &c, const char *g);
+	int growJoint(int part1, int part2, Pt3D &angle, GeneProps &c, const char *g);
+	int growPart(GeneProps &c, const char *g);
 	const char *skipNeuro(const char *z);
-	const char* growNeuro(const char* t, F1Props &c, int&);
-	void growConnection(const char* begin, const char* colon, const char* end, F1Props& props);
+	const char* growNeuro(const char* t, GeneProps &c, int&);
+	void growConnection(const char* begin, const char* colon, const char* end, GeneProps& props);
 	int countBranches(const char*g, SList &out);
 	SyntParam* lastNeuroClassParam();
@@ -96,13 +94,4 @@
 }
 
-void F1Props::normalizeBiol4()
-{
-	double sum = muscle_power + assimilation + stamina + ingestion;
-	muscle_power /= sum;
-	assimilation /= sum;
-	stamina /= sum;
-	ingestion /= sum;
-}
-
 /** main conversion function - with conversion map support */
 SString GenoConv_f1::convert(SString &i, MultiMap *map, bool using_checkpoints)
@@ -111,5 +100,5 @@
 	Builder builder(g, map ? 1 : 0);
 	builder.model.open(using_checkpoints);
-	builder.grow(-1, g, Pt3D_0, stdprops, -1); // uses Model::addFromString() to create model elements
+	builder.grow(-1, g, Pt3D_0, GeneProps::standard_values, -1); // uses Model::addFromString() to create model elements
 	if (builder.invalid) return SString();
 	builder.addPendingInputs();
@@ -133,5 +122,5 @@
 }
 
-void Builder::grow(int part1, const char*g, Pt3D k, F1Props c, int branching_part)
+void Builder::grow(int part1, const char*g, Pt3D k, GeneProps c, int branching_part)
 {
 	int hasmuscles = 0;
@@ -139,125 +128,86 @@
 	while (1)
 	{
-		switch (*g)
-		{
-		case 0: return;
-		case ',': case ')': setPartMapping(branching_part, g); return;
-		case 'R': k.x += 0.7853; setPartMapping(part1, g); break;
-		case 'r': k.x -= 0.7853;	setPartMapping(part1, g); break;
-		case 'Q': c.twist += (1.58 - c.twist)*0.3; setPartMapping(part1, g); break;
-		case 'q': c.twist += (-1.58 - c.twist)*0.3; setPartMapping(part1, g); break;
-#ifdef v1f1COMPATIBLE
-		case 'L': c.length += (3.0 - c.length)*0.3; setPartMapping(part1, g); break;
-#else
-		case 'L': c.length += (2.0 - c.length)*0.3; setPartMapping(part1, g); break;
-#endif                                       
-		case 'l': c.length += (0.33 - c.length)*0.3; setPartMapping(part1, g); break;
-		case 'A': c.assimilation += (1 - c.assimilation)*0.8;	c.normalizeBiol4(); setPartMapping(part1, g);  break;
-		case 'a': c.assimilation -= c.assimilation*0.4;	c.normalizeBiol4(); setPartMapping(part1, g); break;
-		case 'I': c.ingestion += (1 - c.ingestion)*0.8;	c.normalizeBiol4(); setPartMapping(part1, g); break;
-		case 'i': c.ingestion -= c.ingestion*0.4;	c.normalizeBiol4(); setPartMapping(part1, g); break;
-		case 'S': c.stamina += (1 - c.stamina)*0.8; c.normalizeBiol4(); setPartMapping(part1, g); break;
-		case 's': c.stamina -= c.stamina*0.4; c.normalizeBiol4(); setPartMapping(part1, g); break;
-		case 'M': c.muscle_power += (1 - c.muscle_power)*0.8;	c.normalizeBiol4(); setPartMapping(part1, g); break;
-		case 'm': c.muscle_power -= c.muscle_power*0.4;	c.normalizeBiol4(); setPartMapping(part1, g); break;
-		case 'C': c.curvedness += (2.0 - c.curvedness)*0.25;	setPartMapping(part1, g); break;
-		case 'c': c.curvedness += (-2.0 - c.curvedness)*0.25; setPartMapping(part1, g); break;
-		case 'F': c.friction += (4 - c.friction)*0.2; setPartMapping(part1, g); break;
-		case 'f': c.friction -= c.friction*0.2; setPartMapping(part1, g); break;
-		case 'W': c.weight += (2.0 - c.weight)*0.3; setPartMapping(part1, g); break;
-		case 'w': c.weight += (0.5 - c.weight)*0.3; setPartMapping(part1, g); break;
-		case 'E': c.energy += (10.0 - c.energy)*0.1; setPartMapping(part1, g); break;
-		case 'e': c.energy -= c.energy*0.1;	setPartMapping(part1, g); break;
-
-		case 'D': c.cred += (1.0 - c.cred)*0.25; setPartMapping(part1, g); break;
-		case 'd': c.cred += (0.0 - c.cred)*0.25; setPartMapping(part1, g); break;
-		case 'G': c.cgreen += (1.0 - c.cgreen)*0.25; setPartMapping(part1, g); break;
-		case 'g': c.cgreen += (0.0 - c.cgreen)*0.25; setPartMapping(part1, g); break;
-		case 'B': c.cblue += (1.0 - c.cblue)*0.25; setPartMapping(part1, g); break;
-		case 'b': c.cblue += (0.0 - c.cblue)*0.25; setPartMapping(part1, g); break;
-		case 'H': c.visual_size += (0.7 - c.visual_size)*0.25; setPartMapping(part1, g); break;
-		case 'h': c.visual_size += (0.05 - c.visual_size)*0.25; setPartMapping(part1, g); break;
-
-		case '[': //neuron
-			//		setdebug(g-(char*)geny,DEBUGNEURO | !l_neu);
-			if (model.getJointCount())
-				g = growNeuro(g + 1, c, hasmuscles);
-			else
-			{
-				logMessage("GenoConv_F1", "grow", 1, "Illegal neuron position (ignored)");
-				g = skipNeuro(g + 1);
-			}
-			break;
-		case 'X':
-		{
-			int freshpart = 0;
-			//setdebug(g-(char*)geny,DEBUGEST | !l_est);
-			if (part1 < 0) //initial grow
-			{
-				if (model.getPartCount() > 0)
-					part1 = 0;
+		if (c.executeModifier(*g) == 0)
+		{
+			setPartMapping(part1, g);
+		}
+		else
+		{
+			switch (*g)
+			{
+			case 0: return;
+			case ',': case ')': setPartMapping(branching_part, g); return;
+			case 'R': k.x += 0.7853; setPartMapping(part1, g); break;
+			case 'r': k.x -= 0.7853;	setPartMapping(part1, g); break;
+			case '[': //neuron
+				//		setdebug(g-(char*)geny,DEBUGNEURO | !l_neu);
+				if (model.getJointCount())
+					g = growNeuro(g + 1, c, hasmuscles);
 				else
 				{
-					part1 = growPart(c, g);
-					freshpart = 1;
-					if (first_part_mapping)
+					logMessage("GenoConv_F1", "grow", 1, "Illegal neuron position (ignored)");
+					g = skipNeuro(g + 1);
+				}
+				break;
+			case 'X':
+			{
+				int freshpart = 0;
+				//setdebug(g-(char*)geny,DEBUGEST | !l_est);
+				if (part1 < 0) //initial grow
+				{
+					if (model.getPartCount() > 0)
+						part1 = 0;
+					else
 					{
-						//mapping was defined before creating this initial Part -> put it into the Part
-						assert(own_first_part_mapping);
-						model.getPart(part1)->setMapping(*first_part_mapping);
-						delete first_part_mapping;
-						//first_part_mapping can be still used later but from now on it references the internal Part mapping
-						first_part_mapping = model.getPart(part1)->getMapping();
-						own_first_part_mapping = false;
+						part1 = growPart(c, g);
+						freshpart = 1;
+						if (first_part_mapping)
+						{
+							//mapping was defined before creating this initial Part -> put it into the Part
+							assert(own_first_part_mapping);
+							model.getPart(part1)->setMapping(*first_part_mapping);
+							delete first_part_mapping;
+							//first_part_mapping can be still used later but from now on it references the internal Part mapping
+							first_part_mapping = model.getPart(part1)->getMapping();
+							own_first_part_mapping = false;
+						}
 					}
 				}
-			}
-			if (!freshpart)
-			{
-				Part *part = model.getPart(part1);
-				part->density = ((part->mass*part->density) + 1.0 / c.weight) / (part->mass + 1.0); // v=m*d
-				//			part->volume+=1.0/c.weight;
-				part->mass += 1.0;
-			}
-			model_energy += 0.9*c.energy + 0.1;
-			model_energy_count++;
-
-			int part2 = growPart(c, g);
-			growJoint(part1, part2, k, c, g);
-			//		est* e = new est(*s,*s2,k,c,zz,this);
-
-			// attenuate properties as they are propagated along the structure
-			c.length = 0.5*c.length + 0.5*stdprops.length;
-			c.visual_size = 0.5*c.visual_size + 0.5*stdprops.visual_size;
-			c.curvedness = 0.66*c.curvedness;
-			c.twist = 0.66*c.twist;
-			c.friction = 0.8*c.friction + 0.2*stdprops.friction;
-
-			c.assimilation = 0.8*c.assimilation + 0.2*stdprops.assimilation;
-			c.stamina = 0.8*c.stamina + 0.2*stdprops.stamina;
-			c.muscle_power = 0.8*c.muscle_power + 0.2*stdprops.muscle_power;
-			c.ingestion = 0.8*c.ingestion + 0.2*stdprops.ingestion;
-			c.weight += (stdprops.weight - c.weight)*0.5;
-			c.normalizeBiol4();
-
-			if (c.muscle_reset_range) c.muscle_bend_range = 1.0; else c.muscle_reset_range = true;
-			model.checkpoint();
-			grow(part2, g + 1, Pt3D_0, c, branching_part);
-			return;
-		}
-		case '(':
-		{
-			setPartMapping(part1, g);
-			SList ga;
-			int i, count;
-			count = countBranches(g + 1, ga);
-			c.muscle_reset_range = false;
-			c.muscle_bend_range = 1.0 / count;
-			for (i = 0; i < count; i++)
-				grow(part1, (char*)ga(i), k + Pt3D(0, 0, -M_PI + (i + 1)*(2 * M_PI / (count + 1))), c, part1);
-			return;
-		}
-		case ' ': case '\t': case '\n': case '\r': break;
-		default: invalid = 1; return;
+				if (!freshpart)
+				{
+					Part *part = model.getPart(part1);
+					part->density = ((part->mass*part->density) + 1.0 / c.weight) / (part->mass + 1.0); // v=m*d
+					//			part->volume+=1.0/c.weight;
+					part->mass += 1.0;
+				}
+				model_energy += 0.9*c.energy + 0.1;
+				model_energy_count++;
+
+				int part2 = growPart(c, g);
+				growJoint(part1, part2, k, c, g);
+				//		est* e = new est(*s,*s2,k,c,zz,this);
+
+				// attenuate properties as they are propagated along the structure
+				c.propagateAlong(true);
+
+				model.checkpoint();
+				grow(part2, g + 1, Pt3D_0, c, branching_part);
+				return;
+			}
+			case '(':
+			{
+				setPartMapping(part1, g);
+				SList ga;
+				int i, count;
+				count = countBranches(g + 1, ga);
+				c.muscle_reset_range = false;
+				c.muscle_bend_range = 1.0 / count;
+				for (i = 0; i < count; i++)
+					grow(part1, (char*)ga(i), k + Pt3D(0, 0, -M_PI + (i + 1)*(2 * M_PI / (count + 1))), c, part1);
+				return;
+			}
+			case ' ': case '\t': case '\n': case '\r': break;
+			default: invalid = 1; return;
+			}
 		}
 		g++;
@@ -321,5 +271,5 @@
 }
 
-int Builder::growJoint(int part1, int part2, Pt3D &angle, F1Props &c, const char *g)
+int Builder::growJoint(int part1, int part2, Pt3D &angle, GeneProps &c, const char *g)
 {
 	double len = min(2.0, c.length);
@@ -330,5 +280,5 @@
 }
 
-int Builder::growPart(F1Props &c, const char *g)
+int Builder::growPart(GeneProps &c, const char *g)
 {
 	sprintf(tmp, "dn=%lg,fr=%lg,ing=%lg,as=%lg,vs=%g,vr=%g,vg=%g,vb=%g",
@@ -343,5 +293,5 @@
 }
 
-const char* Builder::growNeuro(const char* t, F1Props& props, int &hasmuscles)
+const char* Builder::growNeuro(const char* t, GeneProps& props, int &hasmuscles)
 {
 	const char*neuroend = skipNeuro(t);
@@ -441,5 +391,5 @@
 	return t;
 }
-void Builder::growConnection(const char* begin, const char* colon, const char* end, F1Props& props)
+void Builder::growConnection(const char* begin, const char* colon, const char* end, GeneProps& props)
 {
 	while (*begin && *begin <= ' ') begin++;
