Index: /cpp/frams/Makefile-SDK-files
===================================================================
--- /cpp/frams/Makefile-SDK-files	(revision 758)
+++ /cpp/frams/Makefile-SDK-files	(revision 759)
@@ -10,11 +10,12 @@
 GENMANFN=frams/genetics/fn/oper_fn.o
 
-CONVF1=frams/genetics/f1/conv_f1.o
-CONVF4=frams/genetics/f4/conv_f4.o frams/genetics/f4/f4_general.o
+CONVF1=frams/genetics/f1/conv_f1.o frams/genetics/geneprops.o
+CONVF4=frams/genetics/f4/conv_f4.o frams/genetics/f4/f4_general.o frams/genetics/geneprops.o
 CONVF9=frams/genetics/f9/conv_f9.o
 CONVFF=frams/genetics/fF/conv_fF.o frams/genetics/fF/fF_genotype.o frams/genetics/fF/fF_chamber3d.o
 CONVFN=frams/genetics/fn/conv_fn.o
 
-GENOCONV_SDK_OBJS=frams/genetics/defgenoconv.o frams/vm/classes/genoobj.o frams/model/autoname.o $(CONVF1) $(CONVF4) $(CONVF9) $(CONVFF) $(CONVFN)
+# $(sort - remove duplicates
+GENOCONV_SDK_OBJS=$(sort frams/genetics/defgenoconv.o frams/vm/classes/genoobj.o frams/model/autoname.o $(CONVF1) $(CONVF4) $(CONVF9) $(CONVFF) $(CONVFN))
 GENMAN_SDK_OBJS=$(GENMAN_COMMON_OBJS) $(GENMANF4) $(GENMANF9) $(GENMANFF) $(GENMANFT) $(GENMANFN)
 
Index: /cpp/frams/genetics/f1/conv_f1.cpp
===================================================================
--- /cpp/frams/genetics/f1/conv_f1.cpp	(revision 758)
+++ /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++;
Index: /cpp/frams/genetics/f1/conv_f1.h
===================================================================
--- /cpp/frams/genetics/f1/conv_f1.h	(revision 758)
+++ /cpp/frams/genetics/f1/conv_f1.h	(revision 759)
@@ -8,13 +8,4 @@
 #include <frams/genetics/genoconv.h>
 #include <frams/model/model.h>
-
-struct F1Props
-{
-	double length, curvedness, weight, friction, muscle_power, assimilation, stamina, ingestion, twist, energy;
-	double muscle_bend_range;
-	bool muscle_reset_range;
-	double visual_size, cred, cgreen, cblue;
-	void normalizeBiol4();
-};
 
 /**
Index: /cpp/frams/genetics/geneprops.cpp
===================================================================
--- /cpp/frams/genetics/geneprops.cpp	(revision 759)
+++ /cpp/frams/genetics/geneprops.cpp	(revision 759)
@@ -0,0 +1,120 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#include "geneprops.h"
+
+GeneProps GeneProps::standard_values;
+
+GeneProps::GeneProps()
+{
+	length = 1.0;
+	weight = 1.0;
+	friction = 0.4;
+	curvedness = 0.0;
+	twist = 0.0;
+	energy = 1.0;
+
+	muscle_power = 0.25; // "biological" property
+	assimilation = 0.25; // "biological" property
+	stamina = 0.25; // "biological" property
+	ingestion = 0.25; // "biological" property
+
+	muscle_bend_range = 1.0;
+	muscle_reset_range = true;
+
+	visual_size = 0.2;
+	cred = 0.5;
+	cgreen = 0.5;
+	cblue = 0.5;
+
+	normalizeBiol4();
+}
+
+void GeneProps::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;
+	}
+}
+
+int GeneProps::executeModifier(char modif)
+{
+	switch (modif)
+	{
+#ifdef v1f1COMPATIBLE
+	case 'L': length += (3.0 - length)*0.3;
+		length = min(length, Model::getMaxJoint().d.x); break;
+#else
+	case 'L': length += (2.0 - length)*0.3; //2.0 is currently Model::getMaxJoint().d.x so min() does not limit the range
+		length = min(length, Model::getMaxJoint().d.x); break;
+#endif
+	case 'l': length += (0.33 - length)*0.3;
+		length = max(length, Model::getMinJoint().d.x); break;
+
+	case 'W': weight += (2.0 - weight)*0.3;  break;
+	case 'w': weight += (0.5 - weight)*0.3;  break;
+	case 'F': friction += (4 - friction)*0.2;  break;
+	case 'f': friction -= friction*0.2;  break;
+	case 'C': curvedness += (2.0 - curvedness) * 0.25; break;
+	case 'c': curvedness += (-2.0 - curvedness) * 0.25; break;
+	case 'Q': twist += (M_PI_2 - twist)*0.3; break;
+	case 'q': twist += (-M_PI_2 - twist)*0.3; break;
+	case 'E': energy += (10.0 - energy)*0.1;  break;
+	case 'e': energy -= energy*0.1;	 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 'D': cred += (1.0 - cred)*0.25;  break;
+	case 'd': cred += (0.0 - cred)*0.25;  break;
+	case 'G': cgreen += (1.0 - cgreen)*0.25;  break;
+	case 'g': cgreen += (0.0 - cgreen)*0.25;  break;
+	case 'B': cblue += (1.0 - cblue)*0.25;  break;
+	case 'b': cblue += (0.0 - cblue)*0.25;  break;
+	case 'H': visual_size += (0.7 - visual_size)*0.25;  break;
+	case 'h': visual_size += (0.05 - visual_size)*0.25;  break;
+
+	default: return -1;
+	}
+	return 0;
+}
+
+void GeneProps::propagateAlong(bool use_f1_muscle_reset_range)
+{
+	length = 0.5*length + 0.5 * standard_values.length;
+	weight += (standard_values.weight - weight) * 0.5;
+	friction = 0.8 * friction + 0.2 * standard_values.friction;
+	curvedness = 0.66 * curvedness;
+	twist = 0.66 * twist;
+
+	assimilation = 0.8 * assimilation + 0.2 * standard_values.assimilation;
+	ingestion = 0.8 * ingestion + 0.2 * standard_values.ingestion;
+	stamina = 0.8 * stamina + 0.2 * standard_values.stamina;
+	muscle_power = 0.8 * muscle_power + 0.2 * standard_values.muscle_power;
+
+	normalizeBiol4();
+
+	visual_size = 0.5*visual_size + 0.5 * standard_values.visual_size;
+
+	if (use_f1_muscle_reset_range)
+	{
+		if (muscle_reset_range) muscle_bend_range = 1.0; else muscle_reset_range = true;
+	}
+}
Index: /cpp/frams/genetics/geneprops.h
===================================================================
--- /cpp/frams/genetics/geneprops.h	(revision 759)
+++ /cpp/frams/genetics/geneprops.h	(revision 759)
@@ -0,0 +1,77 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#ifndef _GENEPROPS_H
+#define _GENEPROPS_H
+
+#include <common/nonstd_math.h>
+#include <frams/model/model.h>
+
+/**
+ * Contains physical, biological and other properties of
+ * stick, except for rotation. The constructor initializes properties of sticks with
+ * default values. In order to change a property of a stick, the executeModifier() method
+ * should be called. Modification of length, curvedness and twist properties
+ * usually affects further sticks, so new sticks should have properties of
+ * parents (prop) modified with the prop.propagateAlong() method.
+ * "Biological" properties (assimilation, stamina, muscle strength and
+ * ingestion) should be normalized after modification with normalizeBiol4().
+ */
+struct GeneProps
+{
+public:
+	double length;            ///<incremented by L, decremented by l. Physical property, length of stick
+	double curvedness;        ///<incremented by C, decremented by c. Curvedness of sticks
+	double weight;            ///<incremented by W, decremented by w. Physical property, weight of stick (in water environment light sticks swim on the surface)
+	double friction;          ///<incremented by F, decremented by f. Physical property, friction of a stick (sticks will slide on the ground or stick to it)
+
+	double muscle_power;      ///<incremented by M, decremented by m. Biological property, muscle strength (muscle speed). Strong muscles act with bigger force, gain higher speed, can resist bigger stress, and use more energy
+	double assimilation;      ///<incremented by A, decremented by a. Biological property, assimilation, photosynthesis (a vertical stick can assimilate twice as much as horizontal one)
+	double stamina;           ///<incremented by S, decremented by s. Biological property, stamina (increases chance of survival during fights)
+	double ingestion;         ///<incremented by I, decremented by i. Biological property, ingestion (ability to gain energy from food)
+
+	double twist;             ///<incremented by Q, decremented by q. Twist of a stick
+	double energy;            ///<incremented by E, decremented by e. Energy of a creature
+
+	double muscle_bend_range; ///<Used only by conv_f1
+	bool muscle_reset_range;  ///<Used only by conv_f1
+
+	double visual_size;       ///<incremented by H, decremented by h. Part's visual size, only affects appearance
+	double cred;              ///<incremented by D, decremented by d. Part's red color proportion
+	double cgreen;            ///<incremented by B, decremented by b. Part's blue color proportion
+	double cblue;             ///<incremented by G, decremented by g. Part's green color proportion
+
+	static GeneProps standard_values;
+
+	/**
+	 * Constructor initializing all properties with default values.
+	 */
+	GeneProps();
+
+	/**
+	 * Normalizes biological properties (muscle_power,
+	 * assimilation, stamina, and ingestion). This method is called in
+	 * executeModifier() when any of the biological properties is modified. All values
+	 * of those properties sum up to 1.
+	 */
+	void normalizeBiol4();
+
+	/**
+	 * Checks whether the given character is property modifier. If yes, the property
+	 * is modified and properties are normalized when needed.
+	 * @param modif character that might be a property modifier
+	 * @return 0 if the provided character was property modifier, -1 otherwise
+	 */
+	int executeModifier(char modif);
+
+	/**
+	 * Adjusts current properties for the next stick. In order to set
+	 * new properties to the created stick, the copy of the previous stick should be created,
+	 * and propagateAlong() should be used for that copy.
+	 * @param use_reset_range true if this method should modify muscle_bend_range (used in f1 conversion).
+	 */
+	void propagateAlong(bool use_f1_muscle_reset_range);
+};
+
+#endif // _GENEPROPS_H
