Index: /cpp/frams/Makefile-SDK-files
===================================================================
--- /cpp/frams/Makefile-SDK-files	(revision 731)
+++ /cpp/frams/Makefile-SDK-files	(revision 732)
@@ -25,5 +25,5 @@
 STDOUT_LOGGER_OBJS=common/virtfile/virtfile.o common/loggers/loggertostdout.o common/console.o 
 
-GENOTYPE_LOADER_OBJS=frams/_demos/genotypeloader.o frams/param/multiparamload.o
+GENOTYPE_LOADER_OBJS=frams/_demos/genotypeloader.o frams/_demos/genotypemini.o frams/param/multiparamload.o
 SDK_LIB_OBJS= $(STDOUT_LOGGER_OBJS) $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GENMAN_SDK_OBJS) $(GEOMETRY_OBJS) $(GENOTYPE_LOADER_OBJS) common/virtfile/stdiofile.o
 
@@ -36,9 +36,9 @@
 F0_VARIANTS_OBJS=frams/_demos/f0_variants_test.o $(STDOUT_LOGGER_OBJS) $(SDK_OBJS) $(GENOCONV_SDK_OBJS)
 
-LOADER_TEST_OBJS=frams/_demos/genotypeloader.o frams/_demos/loader_test_geno.o common/virtfile/virtfile.o frams/param/multiparamload.o common/virtfile/stdiofile.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS)
+LOADER_TEST_OBJS=frams/_demos/genotypeloader.o frams/_demos/genotypemini.o frams/_demos/loader_test_geno.o common/virtfile/virtfile.o frams/param/multiparamload.o common/virtfile/stdiofile.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS)
 
 LOADER_TEST_PARAM_OBJS=frams/_demos/loader_test_param.o frams/param/multiparamload.o common/virtfile/stdiofile.o $(STDOUT_LOGGER_OBJS) $(SDK_OBJS)
 
-SAVER_TEST_OBJS=frams/_demos/genotypeloader.o frams/_demos/saver_test_geno.o common/virtfile/virtfile.o frams/param/multiparamload.o common/virtfile/stdiofile.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS)
+SAVER_TEST_OBJS=frams/_demos/genotypeloader.o frams/_demos/genotypemini.o frams/_demos/saver_test_geno.o common/virtfile/virtfile.o frams/param/multiparamload.o common/virtfile/stdiofile.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS)
 
 GENOCONV_TEST_OBJS= frams/_demos/genoconv_test.o frams/_demos/printconvmap.o $(STDOUT_LOGGER_OBJS) $(SDK_OBJS) $(GENOCONV_SDK_OBJS)
@@ -64,14 +64,14 @@
 NEURO_LAYOUT_TEST_OBJS= frams/_demos/neuro_layout_test.o $(STDOUT_LOGGER_OBJS) $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GENMAN_SDK_OBJS) frams/canvas/nn_layout_model.o frams/canvas/nn_simple_layout.o frams/canvas/nn_smart_layout.o
 
-GEOMETRY_INFO_TEST_OBJS=frams/_demos/geometry/info_test.o frams/_demos/geometry/geometrytestutils.o frams/_demos/genotypeloader.o frams/param/multiparamload.o common/virtfile/stdiofile.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GEOMETRY_OBJS) $(GENMAN_SDK_OBJS) $(STDOUT_LOGGER_OBJS)
+GEOMETRY_INFO_TEST_OBJS=frams/_demos/geometry/info_test.o frams/_demos/geometry/geometrytestutils.o frams/_demos/genotypeloader.o frams/_demos/genotypemini.o frams/param/multiparamload.o common/virtfile/stdiofile.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GEOMETRY_OBJS) $(GENMAN_SDK_OBJS) $(STDOUT_LOGGER_OBJS)
 
-GEOMETRY_SURFACE_TEST_OBJS=frams/_demos/geometry/surface_test.o frams/_demos/geometry/geometrytestutils.o frams/_demos/genotypeloader.o frams/param/multiparamload.o common/virtfile/stdiofile.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GEOMETRY_OBJS) $(GENMAN_SDK_OBJS) $(STDOUT_LOGGER_OBJS)
+GEOMETRY_SURFACE_TEST_OBJS=frams/_demos/geometry/surface_test.o frams/_demos/geometry/geometrytestutils.o frams/_demos/genotypeloader.o frams/_demos/genotypemini.o frams/param/multiparamload.o common/virtfile/stdiofile.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GEOMETRY_OBJS) $(GENMAN_SDK_OBJS) $(STDOUT_LOGGER_OBJS)
 
-GEOMETRY_VOLUME_TEST_OBJS=frams/_demos/geometry/volume_test.o frams/_demos/geometry/geometrytestutils.o frams/_demos/genotypeloader.o frams/param/multiparamload.o common/virtfile/stdiofile.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GEOMETRY_OBJS) $(GENMAN_SDK_OBJS) $(STDOUT_LOGGER_OBJS)
+GEOMETRY_VOLUME_TEST_OBJS=frams/_demos/geometry/volume_test.o frams/_demos/geometry/geometrytestutils.o frams/_demos/genotypeloader.o frams/_demos/genotypemini.o frams/param/multiparamload.o common/virtfile/stdiofile.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GEOMETRY_OBJS) $(GENMAN_SDK_OBJS) $(STDOUT_LOGGER_OBJS)
 
-GEOMETRY_APICES_TEST_OBJS=frams/_demos/geometry/apices_test.o frams/_demos/geometry/geometrytestutils.o frams/_demos/genotypeloader.o frams/param/multiparamload.o common/virtfile/stdiofile.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GEOMETRY_OBJS) $(GENMAN_SDK_OBJS) $(STDOUT_LOGGER_OBJS)
+GEOMETRY_APICES_TEST_OBJS=frams/_demos/geometry/apices_test.o frams/_demos/geometry/geometrytestutils.o frams/_demos/genotypeloader.o frams/_demos/genotypemini.o frams/param/multiparamload.o common/virtfile/stdiofile.o $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GEOMETRY_OBJS) $(GENMAN_SDK_OBJS) $(STDOUT_LOGGER_OBJS)
 
 SIMIL_TEST_OBJS=frams/_demos/simil_test.o frams/model/similarity/SVD/lapack.o frams/model/similarity/SVD/matrix_tools.o frams/model/similarity/simil_match.o frams/model/similarity/simil_model.o  \
-     frams/_demos/genotypeloader.o frams/param/multiparamload.o common/virtfile/stdiofile.o $(STDOUT_LOGGER_OBJS) $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GENMAN_SDK_OBJS)
+     frams/_demos/genotypeloader.o frams/_demos/genotypemini.o frams/param/multiparamload.o common/virtfile/stdiofile.o $(STDOUT_LOGGER_OBJS) $(SDK_OBJS) $(GENOCONV_SDK_OBJS) $(GENMAN_SDK_OBJS)
 
 SIMIL_UNITTESTS_OBJS=frams/_demos/simil_unittests.o frams/model/similarity/simil_match.o
Index: /cpp/frams/_demos/genoconv_test.cpp
===================================================================
--- /cpp/frams/_demos/genoconv_test.cpp	(revision 731)
+++ /cpp/frams/_demos/genoconv_test.cpp	(revision 732)
@@ -27,5 +27,5 @@
 		in_format = 'x';
 	}
-	SString convert(SString &i, MultiMap *map) { return SString("after conversion..."); }
+	SString convert(SString &i, MultiMap *map, bool using_checkpoints) { return SString("after conversion..."); }
 	~GenoConv_Test() {}
 };
@@ -42,5 +42,5 @@
 	}
 
-	SString convert(SString &i, MultiMap *map)
+	SString convert(SString &i, MultiMap *map, bool using_checkpoints)
 	{
 		Model mod;
@@ -53,5 +53,5 @@
 		return mod.getF0Geno().getGenes();
 	}
-	
+
 	~GenoConv_Test2() {}
 };
@@ -70,10 +70,10 @@
 		mapsupport = 1;
 	}
-	SString convert(SString &in, MultiMap *map);
+	SString convert(SString &in, MultiMap *map, bool using_checkpoints);
 	~GenoConv_Test3() {}
 };
 
 /** main converting routine - most important: direct conversion map example */
-SString GenoConv_Test3::convert(SString &in, MultiMap *map)
+SString GenoConv_Test3::convert(SString &in, MultiMap *map, bool using_checkpoints)
 {
 	SString dst;
@@ -116,4 +116,8 @@
 }
 
+// arguments:
+//     genotype (or - meaning "read from stdin") [default: X]
+//     target format [default: 0]
+//     "checkpoints" (just write this exact word) [default: not using checkpoints]
 int main(int argc, char *argv[])
 {
@@ -146,4 +150,5 @@
 		src = "X";
 	char dst = (argc > 2) ? *argv[2] : '0';
+	bool using_checkpoints = (argc > 3) ? (strcmp(argv[3], "checkpoints") == 0) : false;
 
 	printf("*** Source genotype:\n");
@@ -151,29 +156,51 @@
 	printGen(g1);
 	MultiMap m;
-	Geno g2 = g1.getConverted(dst, &m);
+	Geno g2 = g1.getConverted(dst, &m, using_checkpoints);
 	printf("*** Converted to f%c:\n", dst);
 	printGen(g2);
-	if (m.isEmpty())
-		printf("(conversion map not available)\n");
+
+	if (using_checkpoints)
+	{ // using Model with checkpoints
+		Model m1(g2, false, true);//true=using_checkpoints
+		printf("\nModel built from the converted f%c genotype has %d checkpoints\n", g2.getFormat(), m1.getCheckpointCount());
+		Model m2(g1, false, true);//true=using_checkpoints
+		printf("Model built from the source f%c genotype has %d checkpoints\n", g1.getFormat(), m2.getCheckpointCount());
+		// accessing individual checkpoint models (if available)
+		if (m1.getCheckpointCount() > 0)
+		{
+			int c = m1.getCheckpointCount() / 2;
+			Model *cm = m1.getCheckpoint(c);
+			printf("Checkpoint #%d (%d parts, %d joint, %d neurons)\n%s", c, cm->getPartCount(), cm->getJointCount(), cm->getNeuroCount(), cm->getF0Geno().getGenesAndFormat().c_str());
+		}
+	}
 	else
-	{
-		printf("Conversion map:\n");
-		m.print();
-		printConvMap(g1.getGenes(), g2.getGenes(), m);
-		printf("Reverse conversion map:\n");
-		MultiMap rm;
-		rm.addReversed(m);
-		rm.print();
-		printConvMap(g2.getGenes(), g1.getGenes(), rm);
-	}
-
-	Model mod1(g1, 1);
-	printf("\nModel map for f%c genotype:\n", g1.getFormat());
-	printModelMap(g1.getGenes(), mod1.getMap());
-	mod1.getMap().print();
-	Model mod2(g2, 1);
-	printf("\nModel map for f%c genotype:\n", g2.getFormat());
-	printModelMap(g2.getGenes(), mod2.getMap());
-	mod2.getMap().print();
+	{ // there is no mapping for checkpoints so it's nothing interesting to see here in the checkpoints mode
+		if (m.isEmpty())
+			printf("(conversion map not available)\n");
+		else
+		{
+			printf("Conversion map:\n");
+			m.print();
+			printConvMap(g1.getGenes(), g2.getGenes(), m);
+			printf("Reverse conversion map:\n");
+			MultiMap rm;
+			rm.addReversed(m);
+			rm.print();
+			printConvMap(g2.getGenes(), g1.getGenes(), rm);
+		}
+
+		Model mod1(g1, 1);
+		printf("\nModel map for f%c genotype:\n", g1.getFormat());
+		printModelMap(g1.getGenes(), mod1.getMap());
+		MultiMap mod1combined;
+		mod1combined.addCombined(mod1.getMap(), getModelDisplayMap());
+		mod1combined.print();
+		Model mod2(g2, 1);
+		printf("\nModel map for f%c genotype:\n", g2.getFormat());
+		printModelMap(g2.getGenes(), mod2.getMap());
+		MultiMap mod2combined;
+		mod2combined.addCombined(mod2.getMap(), getModelDisplayMap());
+		mod2combined.print();
+	}
 	return 0;
 }
Index: /cpp/frams/_demos/genotypeloader.cpp
===================================================================
--- /cpp/frams/_demos/genotypeloader.cpp	(revision 731)
+++ /cpp/frams/_demos/genotypeloader.cpp	(revision 732)
@@ -5,59 +5,10 @@
 #include "genotypeloader.h"
 
-#define FIELDSTRUCT MiniGenotype
-ParamEntry minigenotype_paramtab[] =
-{
-	{ "Genotype", 1, 29, "org", },
 
-	{ "name", 0, 0, "Name", "s 0 40", FIELD(name), },
-	{ "genotype", 0, 0, "Genotype", "s 1", FIELD(genotype), "Genes as a string of characters.", },
+GenotypeMiniLoader::GenotypeMiniLoader() :genotype_param(genotypemini_paramtab, &genotype_object) { init(); }
+GenotypeMiniLoader::GenotypeMiniLoader(VirtFILE *f) : MultiParamLoader(f), genotype_param(genotypemini_paramtab, &genotype_object) { init(); }
+GenotypeMiniLoader::GenotypeMiniLoader(const char* filename) : MultiParamLoader(filename), genotype_param(genotypemini_paramtab, &genotype_object) { init(); }
 
-	{ "info_timestamp", 1, 0, "Last modified", "ft 0 -1 0", FIELD(info_timestamp), },
-	{ "info_author", 1, 0, "Author name", "s 0 100", FIELD(info_author), },
-	{ "info_author_ispublic", 1, 0, "Author name is public", "d 0 1 1", FIELD(info_author_ispublic), },
-	{ "info_email", 1, 0, "Author email", "s 0 100", FIELD(info_email), },
-	{ "info_email_ispublic", 1, 0, "Author email is public", "d 0 1 0", FIELD(info_email_ispublic), },
-	{ "info", 1, 0, "Description", "s 1 1000", FIELD(info), "Short description of key features of this creature.", },
-	{ "info_origin", 1, 0, "Origin", "d 0 4 0 ~Unspecified~Designed~Designed and evolved~Evolved under various conditions~Evolved using single, constant setup", FIELD(info_origin), "Declaration of how this genotype originated." },
-	{ "info_how_created", 1, 0, "How created", "s 1 1000", FIELD(info_how_created), "Description of the process of designing and/or evolving this genotype." },
-	{ "info_performance", 1, 0, "Performance notes", "s 1 1000", FIELD(info_performance), "Description of why this genotype is special/interesting and how it performs." }, 
-
-	{ "energy0", 0, 0, "Starting energy", "f 0 -1 0", FIELD(energy0), },
-	{ "numparts", 0, 0, "Body parts", "d", FIELD(numparts), },
-	{ "numjoints", 0, 0, "Body joints", "d", FIELD(numjoints), },
-	{ "numneurons", 0, 0, "Brain size", "d", FIELD(numneurons), },
-	{ "numconnections", 0, 0, "Brain connections", "d", FIELD(numconnections), },
-
-	{ "num", 0, 0, "Ordinal number", "d", FIELD(ordnumber), },
-	{ "gnum", 0, 0, "Generation", "d", FIELD(generation), },
-
-	{ "instances", 0, 0, "Instances", "d", FIELD(instances), "Copies of this genotype", },
-
-	{ "lifespan", 0, 0, "Life span", "f", FIELD(lifespan), "Average life span", },
-	{ "velocity", 0, 0, "Velocity", "f", FIELD(velocity), "Average velocity", },
-	{ "distance", 0, 0, "Distance", "f", FIELD(distance), },
-	{ "vertvel", 0, 0, "Vertical velocity", "f", FIELD(vertvel), },
-	{ "vertpos", 0, 0, "Vertical position", "f", FIELD(vertpos), },
-
-	{ "user1", 0, 0, "User field 1", "x", FIELD(user1), },
-	{ "user2", 0, 0, "User field 2", "x", FIELD(user2), },
-	{ "user3", 0, 0, "User field 3", "x", FIELD(user3), },
-
-	{ "is_valid", 0, 0, "Validity", "d -1 1 -1", FIELD(is_valid),
-	"0 = invalid genotype\n"
-	"1 = valid genotype\n"
-	"-1 = validity is not known." },
-
-	{ "uid", 0, 0, "#", "s", FIELD(uid), "Unique identifier" },
-
-	{ 0, 0, 0, },
-};
-#undef FIELDSTRUCT
-
-MiniGenotypeLoader::MiniGenotypeLoader() :genotype_param(minigenotype_paramtab, &genotype_object) { init(); }
-MiniGenotypeLoader::MiniGenotypeLoader(VirtFILE *f) : MultiParamLoader(f), genotype_param(minigenotype_paramtab, &genotype_object) { init(); }
-MiniGenotypeLoader::MiniGenotypeLoader(const char* filename) : MultiParamLoader(filename), genotype_param(minigenotype_paramtab, &genotype_object) { init(); }
-
-void MiniGenotypeLoader::init()
+void GenotypeMiniLoader::init()
 {
 	addObject(&genotype_param);
@@ -65,5 +16,5 @@
 }
 
-MiniGenotype* MiniGenotypeLoader::loadNextGenotype()
+GenotypeMini* GenotypeMiniLoader::loadNextGenotype()
 {
 	genotype_object.clear();
Index: /cpp/frams/_demos/genotypeloader.h
===================================================================
--- /cpp/frams/_demos/genotypeloader.h	(revision 731)
+++ /cpp/frams/_demos/genotypeloader.h	(revision 732)
@@ -8,28 +8,5 @@
 #include <frams/util/sstring.h>
 #include <frams/param/multiparamload.h>
-
-/** Defines the association between "org:" object (found in genotype files)
-	and the MiniGenotype fields. MiniGenotypeLoader uses this definition
-	but you can also use it to make MultiParamLoader load genotype
-	*/
-extern ParamEntry minigenotype_paramtab[];
-
-/** Helper class, mostly useful with MultiParamLoader
-	or its specialized version: MiniGenotypeLoader.
-	MiniGenotype stores the subset of Genotype fields (the ones normally saved in .gen files)
-	*/
-class MiniGenotype
-{
-public:
-	SString name, genotype, info, uid;
-	double info_timestamp;
-	SString info_author, info_email;
-	paInt info_author_ispublic, info_email_ispublic, info_origin;
-	SString info_how_created, info_performance;
-	double energy0, lifespan, velocity, distance, vertvel, vertpos;
-	paInt numparts, numjoints, numneurons, numconnections, ordnumber, generation, instances, is_valid;
-	ExtValue user1, user2, user3;
-	void clear() { Param p(minigenotype_paramtab, this); p.setDefault(); }
-};
+#include "genotypemini.h"
 
 /** In most simple cases this is the class you would use to load a series of genotypes from
@@ -48,20 +25,20 @@
 	methods, or you can use it as a guide for creating your own specialized class.
 	*/
-class MiniGenotypeLoader : public MultiParamLoader
+class GenotypeMiniLoader : public MultiParamLoader
 {
-	MiniGenotype genotype_object;
+	GenotypeMini genotype_object;
 	Param genotype_param;
 	bool initialized;
 	void init();
 public:
-	MiniGenotypeLoader();
-	MiniGenotypeLoader(VirtFILE *f);
-	MiniGenotypeLoader(const char* filename);
+	GenotypeMiniLoader();
+	GenotypeMiniLoader(VirtFILE *f);
+	GenotypeMiniLoader(const char* filename);
 
 	/** @returns genotype object if one was loaded or NULL otherwise.
 
-		Returned MiniGenotype pointer always references the the same object (MiniGenotypeLoader::genotype_object)
+		Returned GenotypeMini pointer always references the the same object (GenotypeMiniLoader::genotype_object)
 		which means you may need to copy the data from it before calling loadNextGenotype() again.
-		In the default configuration (simple MiniGenotypeLoader) NULL is always final and should be used
+		In the default configuration (simple GenotypeMiniLoader) NULL is always final and should be used
 		to finish processing.
 
@@ -70,5 +47,5 @@
 		MultiParamLoader::finished() and other methods to determine the real cause of NULL.
 		*/
-	MiniGenotype* loadNextGenotype();
+	GenotypeMini* loadNextGenotype();
 };
 
Index: /cpp/frams/_demos/genotypemini.cpp
===================================================================
--- /cpp/frams/_demos/genotypemini.cpp	(revision 732)
+++ /cpp/frams/_demos/genotypemini.cpp	(revision 732)
@@ -0,0 +1,108 @@
+#include "genotypemini.h"
+#include <frams/vm/classes/collectionobj.h>
+#include <common/log.h>
+
+#define FIELDSTRUCT GenotypeMini
+ParamEntry genotypemini_paramtab[] =
+{
+	{ "Genotype", 1, 31, "org", },
+
+	{ "name", 0, 0, "Name", "s 0 40", FIELD(name), },
+	{ "genotype", 0, 0, "Genotype", "s 1", FIELD(genotype), "Genes as a string of characters.", },
+
+	{ "info_timestamp", 1, 0, "Last modified", "ft 0 -1 0", FIELD(info_timestamp), },
+	{ "info_author", 1, 0, "Author name", "s 0 100", FIELD(info_author), },
+	{ "info_author_ispublic", 1, 0, "Author name is public", "d 0 1 1", FIELD(info_author_ispublic), },
+	{ "info_email", 1, 0, "Author email", "s 0 100", FIELD(info_email), },
+	{ "info_email_ispublic", 1, 0, "Author email is public", "d 0 1 0", FIELD(info_email_ispublic), },
+	{ "info", 1, 0, "Description", "s 1 1000", FIELD(info), "Short description of key features of this creature.", },
+	{ "info_origin", 1, 0, "Origin", "d 0 4 0 ~Unspecified~Designed~Designed and evolved~Evolved under various conditions~Evolved using single, constant setup", FIELD(info_origin), "Declaration of how this genotype originated." },
+	{ "info_how_created", 1, 0, "How created", "s 1 1000", FIELD(info_how_created), "Description of the process of designing and/or evolving this genotype." },
+	{ "info_performance", 1, 0, "Performance notes", "s 1 1000", FIELD(info_performance), "Description of why this genotype is special/interesting and how it performs." },
+
+	{ "energy0", 0, 0, "Starting energy", "f 0 -1 0", FIELD(energy0), },
+	{ "numparts", 0, 0, "Body parts", "d", FIELD(numparts), },
+	{ "numjoints", 0, 0, "Body joints", "d", FIELD(numjoints), },
+	{ "numneurons", 0, 0, "Brain size", "d", FIELD(numneurons), },
+	{ "numconnections", 0, 0, "Brain connections", "d", FIELD(numconnections), },
+
+	{ "num", 0, 0, "Ordinal number", "d", FIELD(ordnumber), },
+	{ "gnum", 0, 0, "Generation", "d", FIELD(generation), },
+
+	{ "instances", 0, 0, "Instances", "d", FIELD(instances), "Copies of this genotype", },
+
+	{ "lifespan", 0, 0, "Life span", "f", FIELD(lifespan), "Average life span", },
+	{ "velocity", 0, 0, "Velocity", "f", FIELD(velocity), "Average velocity", },
+	{ "distance", 0, 0, "Distance", "f", FIELD(distance), },
+	{ "vertvel", 0, 0, "Vertical velocity", "f", FIELD(vertvel), },
+	{ "vertpos", 0, 0, "Vertical position", "f", FIELD(vertpos), },
+
+	{ "user1", 0, 0, "User field 1", "x", FIELD(user1), },
+	{ "user2", 0, 0, "User field 2", "x", FIELD(user2), },
+	{ "user3", 0, 0, "User field 3", "x", FIELD(user3), },
+	{ "data", 3, PARAM_OBJECTSET, "Custom fields dictionary", "oDictionary", FIELD(data), },
+
+	{ "is_valid", 0, 0, "Validity", "d -1 1 -1", FIELD(is_valid),
+	"0 = invalid genotype\n"
+	"1 = valid genotype\n"
+	"-1 = validity is not known." },
+
+	{ "uid", 0, 0, "#", "s", FIELD(uid), "Unique identifier" },
+
+	{ "mutate", 0, 0, "Mutate", "p()", PROCEDURE(p_mutate), },
+
+	{ 0, 0, 0, },
+};
+#undef FIELDSTRUCT
+
+void GenotypeMini::initData()
+{
+	DictionaryObject *d = new DictionaryObject;
+	data = d->makeObject();
+}
+
+GenotypeMini::GenotypeMini()
+{
+	initData();
+}
+
+GenotypeMini::GenotypeMini(const GenotypeMini &src)
+{
+	initData();
+	name = src.name; genotype = src.genotype; info = src.info; uid = src.uid; info_timestamp = src.info_timestamp; info_author = src.info_author; info_email = src.info_email; info_author_ispublic = src.info_author_ispublic; info_email_ispublic = src.info_email_ispublic; info_origin = src.info_origin; info_how_created = src.info_how_created; info_performance = src.info_performance; energy0 = src.energy0; lifespan = src.lifespan; velocity = src.velocity; distance = src.distance; vertvel = src.vertvel; vertpos = src.vertpos; numparts = src.numparts; numjoints = src.numjoints; numneurons = src.numneurons; numconnections = src.numconnections; ordnumber = src.ordnumber; generation = src.generation; instances = src.instances; is_valid = src.is_valid; user1 = src.user1; user2 = src.user2; user3 = src.user3;
+
+	// special case for 'data' (Dictionary inside an ExtObject)
+	// 'data=src.data' would copy the Dictionary object reference (very wrong!)
+	// performing a shallow copy instead:
+	DictionaryObject *d = DictionaryObject::fromObject(data);
+	DictionaryObject *src_d = DictionaryObject::fromObject(src.data);
+	d->copyFrom(src_d);
+}
+
+void GenotypeMini::clear()
+{
+	Param p(genotypemini_paramtab, this);
+	p.setDefault();
+}
+
+static std::function<Geno(const Geno&)> genman_mutate;
+
+void GenotypeMini::useGenManMutate(std::function<Geno(const Geno&)> gmm)
+{
+	genman_mutate = gmm;
+}
+
+void GenotypeMini::p_mutate(ExtValue *args, ExtValue *ret)
+{
+	if (ret != NULL) ret->setEmpty();
+	if (!genman_mutate)
+	{
+		logPrintf("GenotypeMini", "mutate", LOG_ERROR, "No function for mutation provided. See GENOTYPEMINI_USE_GENMAN().");
+		return;
+	}
+	Geno in(genotype.c_str(), -1, name.c_str(), info.c_str());
+	Geno out = genman_mutate(in);
+	genotype = out.getGenesAndFormat();
+	name = out.getName();
+	info = out.getComment();
+}
Index: /cpp/frams/_demos/genotypemini.h
===================================================================
--- /cpp/frams/_demos/genotypemini.h	(revision 732)
+++ /cpp/frams/_demos/genotypemini.h	(revision 732)
@@ -0,0 +1,48 @@
+#ifndef _GENOTYPEMINI_H_
+#define _GENOTYPEMINI_H_
+
+#include <frams/param/param.h>
+#include <frams/util/extvalue.h>
+#include <frams/genetics/geno.h>
+#include <functional>
+
+/** Defines the association between "org:" object (found in genotype files)
+	and the GenotypeMini fields. GenotypeMiniLoader uses this definition
+	but you can also use it to make MultiParamLoader load genotype
+	*/
+extern ParamEntry genotypemini_paramtab[];
+
+/** Helper class, mostly useful with MultiParamLoader
+	or its specialized version: MiniGenotypeLoader.
+	GenotypeMini stores the subset of Genotype fields (the ones normally saved in .gen files)
+	*/
+class GenotypeMini
+{
+public:
+	SString name, genotype, info, uid;
+	double info_timestamp;
+	SString info_author, info_email;
+	paInt info_author_ispublic, info_email_ispublic, info_origin;
+	SString info_how_created, info_performance;
+	double energy0, lifespan, velocity, distance, vertvel, vertpos;
+	paInt numparts, numjoints, numneurons, numconnections, ordnumber, generation, instances, is_valid;
+	ExtValue user1, user2, user3;
+	ExtObject data;
+	void clear();
+
+	GenotypeMini();
+	GenotypeMini(const GenotypeMini &src);
+	void initData();
+
+#define GENOTYPEMINI_USE_GENMAN(gm) GenotypeMini::useGenManMutate(std::bind(&GenMan::mutate,&(gm),std::placeholders::_1))
+	static void useGenManMutate(std::function<Geno(const Geno&)> gmm);
+	/** GenMan object must be provided before using the 'mutate()' operation, like this:
+		GENOTYPEMINI_USE_GENMAN(genetics.genman);
+		*/
+
+#define STATRICKCLASS GenotypeMini
+	PARAMPROCDEF(p_mutate);
+#undef STATRICKCLASS
+};
+
+#endif
Index: /cpp/frams/_demos/geometry/geometrytestutils.cpp
===================================================================
--- /cpp/frams/_demos/geometry/geometrytestutils.cpp	(revision 731)
+++ /cpp/frams/_demos/geometry/geometrytestutils.cpp	(revision 732)
@@ -18,17 +18,17 @@
 	long count = 0;
 	long totalSize = 0;
-	MiniGenotypeLoader loader(file);
-	MiniGenotype *genotype;
-	
+	GenotypeMiniLoader loader(file);
+	GenotypeMini *genotype;
+
 	while (genotype = loader.loadNextGenotype())
 	{
 		count++;
 		totalSize += genotype->genotype.len();
-		
+
 		fprintf(stderr, "%d. (%6d chars) %s\n", count, genotype->genotype.len(),
 			genotype->name.c_str());
 	}
-	
-	if (loader.getStatus() == MiniGenotypeLoader::OnError)
+
+	if (loader.getStatus() == GenotypeMiniLoader::OnError)
 	{
 		fprintf(stderr, "Error: %s\n", loader.getError().c_str());
@@ -44,6 +44,6 @@
 class TestInvoker
 {
-	public:
-		virtual void operator()(Model &model) = 0;
+public:
+	virtual void operator()(Model &model) = 0;
 };
 
@@ -53,15 +53,15 @@
 	const int genoIndex = isdigit(genoId[0]) ? atol(genoId) : 0;
 	long count = 0;
-	MiniGenotypeLoader loader(file);
-	MiniGenotype *genotype;
-	
+	GenotypeMiniLoader loader(file);
+	GenotypeMini *genotype;
+
 	while (genotype = loader.loadNextGenotype())
 	{
 		count++;
-		
+
 		if ((genoIndex == count) || (strcmp(genotype->name.c_str(), genoName) == 0))
 		{
 			Model model(genotype->genotype);
-			
+
 			if (!model.isValid())
 			{
@@ -74,6 +74,6 @@
 		}
 	}
-	
-	if (loader.getStatus() == MiniGenotypeLoader::OnError)
+
+	if (loader.getStatus() == GenotypeMiniLoader::OnError)
 	{
 		fprintf(stderr, "Error: %s\n", loader.getError().c_str());
@@ -94,5 +94,5 @@
 	if ((shape < 1) || (shape > 3))
 	{
-		shape = (rand()%3) + 1;
+		shape = (rand() % 3) + 1;
 	}
 
@@ -106,24 +106,24 @@
 }
 
-class ModelBasedTestInvoker: public TestInvoker
-{
-	private:
-		void (*test)(Model &);
-	public:
-		ModelBasedTestInvoker(void (*_test)(Model &)):
-			test(_test)
-		{}
-		void operator()(Model &model)
-		{
-			test(model);
-		}
+class ModelBasedTestInvoker : public TestInvoker
+{
+private:
+	void(*test)(Model &);
+public:
+	ModelBasedTestInvoker(void(*_test)(Model &)) :
+		test(_test)
+	{}
+	void operator()(Model &model)
+	{
+		test(model);
+	}
 };
 
-int GeometryTestUtils::execute(const SString header, int argc, char *argv[], void (*test)(Model &))
+int GeometryTestUtils::execute(const SString header, int argc, char *argv[], void(*test)(Model &))
 {
 	LoggerToStdout messages_to_stdout(LoggerBase::Enable); //comment this object out to mute error/warning messages
 	StdioFileSystem_autoselect stdiofilesys;
 	PreconfiguredGenetics genetics;
-	
+
 	srand(time(NULL));
 
@@ -132,5 +132,5 @@
 		return printGenotypesList(argv[2]);
 	}
-	
+
 	if ((argc == 4) && (strcmp("-l", argv[1]) == 0))
 	{
@@ -138,5 +138,5 @@
 		return executeTestUsingLoadedModel(argv[2], argv[3], invoker);
 	}
-	
+
 	if ((argc == 2) && (strcmp("-c", argv[1]) == 0))
 	{
@@ -144,5 +144,5 @@
 		return executeTestUsingRandomModel(-1, invoker);
 	}
-	
+
 	if ((argc == 3) && (strcmp("-c", argv[1]) == 0) && isdigit(argv[2][0]))
 	{
@@ -151,5 +151,5 @@
 		return executeTestUsingRandomModel(shape, invoker);
 	}
-	
+
 	fprintf(stderr,
 		"%s\n\n"
@@ -165,28 +165,28 @@
 }
 
-class ModelAndDensityBasedTestInvoker: public TestInvoker
-{
-	private:
-		void (*test)(Model &, const double);
-		double density;
-	public:
-		ModelAndDensityBasedTestInvoker(void (*_test)(Model &, const double), double _density):
-			test(_test),
-			density(_density)
-		{}
-		
-		void operator()(Model &model)
-		{
-			test(model, density);
-		}
+class ModelAndDensityBasedTestInvoker : public TestInvoker
+{
+private:
+	void(*test)(Model &, const double);
+	double density;
+public:
+	ModelAndDensityBasedTestInvoker(void(*_test)(Model &, const double), double _density) :
+		test(_test),
+		density(_density)
+	{}
+
+	void operator()(Model &model)
+	{
+		test(model, density);
+	}
 };
 
 int GeometryTestUtils::execute(const SString header, int argc, char *argv[],
-	void (*test)(Model &, const double))
+	void(*test)(Model &, const double))
 {
 	LoggerToStdout messages_to_stdout(LoggerBase::Enable); //comment this object out to mute error/warning messages
 	StdioFileSystem_autoselect stdiofilesys;
 	PreconfiguredGenetics genetics;
-	
+
 	srand(time(NULL));
 
@@ -202,5 +202,5 @@
 		return executeTestUsingLoadedModel(argv[2], argv[3], invoker);
 	}
-	
+
 	if ((argc == 3) && (strcmp("-c", argv[1]) == 0) && isdigit(argv[2][0]))
 	{
@@ -209,5 +209,5 @@
 		return executeTestUsingRandomModel(-1, invoker);
 	}
-	
+
 	if ((argc == 4) && (strcmp("-c", argv[1]) == 0) && isdigit(argv[2][0]) && isdigit(argv[3][0]))
 	{
@@ -217,5 +217,5 @@
 		return executeTestUsingRandomModel(shape, invoker);
 	}
-	
+
 	fprintf(stderr,
 		"%s\n\n"
@@ -235,9 +235,9 @@
 {
 	Part *part = model.addNewPart(Part::SHAPE_ELLIPSOID);
-	
+
 	part->p = Pt3D(0);
 	part->scale = Pt3D(0.1);
 	part->vcolor = Pt3D(1.0, 0.0, 1.0);
-	
+
 	addAxesToModel(Pt3D(0.5), Orient(Orient_1), Pt3D(0.0), model);
 }
@@ -247,9 +247,9 @@
 	Part *anchor = model.getPart(0);
 	Part *part = model.addNewPart(Part::SHAPE_ELLIPSOID);
-	
+
 	part->p = Pt3D(markerLocation);
 	part->scale = Pt3D(0.05);
 	part->vcolor = Pt3D(1.0, 1.0, 0.0);
-	
+
 	model.addNewJoint(anchor, part, Joint::SHAPE_FIXED);
 }
@@ -260,5 +260,5 @@
 	Part *anchor = model.getPart(0);
 	Part *part;
-	
+
 	part = model.addNewPart(Part::SHAPE_CUBOID);
 	part->scale = Pt3D(sizes.x, 0.05, 0.05);
@@ -267,5 +267,5 @@
 	part->vcolor = Pt3D(1.0, 0.0, 0.0);
 	model.addNewJoint(anchor, part, Joint::SHAPE_FIXED);
-	
+
 	part = model.addNewPart(Part::SHAPE_CUBOID);
 	part->scale = Pt3D(0.05, sizes.y, 0.05);
@@ -274,5 +274,5 @@
 	part->vcolor = Pt3D(0.0, 1.0, 0.0);
 	model.addNewJoint(anchor, part, Joint::SHAPE_FIXED);
-	
+
 	part = model.addNewPart(Part::SHAPE_CUBOID);
 	part->scale = Pt3D(0.05, 0.05, sizes.z);
@@ -287,7 +287,7 @@
 	Part *targetAnchor = target.getPart(0);
 	Part *sourceAnchor = source.getPart(0);
-	
+
 	target.moveElementsFrom(source);
-	
+
 	target.addNewJoint(targetAnchor, sourceAnchor, Joint::SHAPE_FIXED);
 }
@@ -295,5 +295,5 @@
 double frand(double from, double width)
 {
-	return from + width * ((rand()%10000) / 10000.0);
+	return from + width * ((rand() % 10000) / 10000.0);
 }
 
Index: /cpp/frams/_demos/loader_test_geno.cpp
===================================================================
--- /cpp/frams/_demos/loader_test_geno.cpp	(revision 731)
+++ /cpp/frams/_demos/loader_test_geno.cpp	(revision 732)
@@ -26,10 +26,10 @@
 	long count = 0, totalsize = 0;
 	StdioFileSystem_autoselect stdiofilesys;
-	MiniGenotypeLoader loader(argv[1]);
+	GenotypeMiniLoader loader(argv[1]);
 	const char* selected = (argc < 3) ? NULL : argv[2];
 	const char* field_name = (argc < 4) ? NULL : argv[3];
 	int selected_index = (selected&&isdigit(selected[0])) ? atol(selected) : 0;
 	// using char* constructor (passing the file name to open)
-	MiniGenotype *loaded;
+	GenotypeMini *loaded;
 	while (loaded = loader.loadNextGenotype())
 	{ // if loaded != NULL then the "org:" object data was
@@ -51,5 +51,5 @@
 			if (field_name)
 			{
-				Param p(minigenotype_paramtab, loaded);
+				Param p(genotypemini_paramtab, loaded);
 				int field_index = p.findId(field_name);
 				if (field_index < 0)
@@ -68,5 +68,5 @@
 	}
 	// the loop repeats until loaded==NULL, which could be beacause of error
-	if (loader.getStatus() == MiniGenotypeLoader::OnError)
+	if (loader.getStatus() == GenotypeMiniLoader::OnError)
 		fprintf(stderr, "Error: %s", loader.getError().c_str());
 	// (otherwise it was the end of the file)
Index: /cpp/frams/_demos/paramtree_paramlist_test.cpp
===================================================================
--- /cpp/frams/_demos/paramtree_paramlist_test.cpp	(revision 731)
+++ /cpp/frams/_demos/paramtree_paramlist_test.cpp	(revision 732)
@@ -22,5 +22,5 @@
 	PreconfiguredGenetics genetics;
 
-	Param minigenotype_param(minigenotype_paramtab);
+	Param genotypemini_param(genotypemini_paramtab);
 	NeuroFactory neurofac;
 	neurofac.setStandardImplementation();
@@ -36,5 +36,5 @@
 	combined += &Pt3D_Ext::getStaticParam();
 	combined += &Orient_Ext::getStaticParam();
-	combined += &minigenotype_param;
+	combined += &genotypemini_param;
 	combined += &nn_config.par;
 	combined += &modelgeo.par;
Index: /cpp/frams/_demos/printconvmap.cpp
===================================================================
--- /cpp/frams/_demos/printconvmap.cpp	(revision 731)
+++ /cpp/frams/_demos/printconvmap.cpp	(revision 732)
@@ -1,4 +1,4 @@
 // This file is a part of Framsticks SDK.  http://www.framsticks.com/
-// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
+// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
 // See LICENSE.txt for details.
 
@@ -6,91 +6,109 @@
 #include <stdio.h>
 #include <frams/util/multimap.h>
+#include <frams/model/model.h>
 
 #define GEN1MAX 15
 
-void printN(const char* t,int maxlen)
+void printN(const char* t, int maxlen)
 {
-while(maxlen-- > 0)
-	if (*t) putchar(*(t++));
-	else putchar(' ');
+	while (maxlen-- > 0)
+		if (*t) putchar(*(t++));
+		else putchar(' ');
 }
 
-void printN(char t,int maxlen)
+void printN(char t, int maxlen)
 {
-while(maxlen-- > 0) putchar(t);
+	while (maxlen-- > 0) putchar(t);
 }
 
-void printmapping(const char* gen1, int len1,const MultiRange &mr,const char* gen2,int len2)
+void printmapping(const char* gen1, int len1, const MultiRange &mr, const char* gen2, int len2)
 {
-printN(' ',GEN1MAX-len1);
-printN(gen1,len1);
-printf(" : ");
-int i;
-for(i=0;i<len2;i++)
-	if (mr.contains(i))
-		putchar(gen2[i]);
-	else
-		putchar('.');
-putchar('\n');
+	printN(' ', GEN1MAX - len1);
+	printN(gen1, len1);
+	printf(" : ");
+	int i;
+	for (i = 0; i < len2; i++)
+		if (mr.contains(i))
+			putchar(gen2[i]);
+		else
+			putchar('.');
+	putchar('\n');
 }
 
 void stripstring(SString &str)
 {
-char *t=str.directWrite();
-for(;*t;t++)
-	if (strchr("\n\r\t",*t)) *t=' ';
+	char *t = str.directWrite();
+	for (; *t; t++)
+		if (strchr("\n\r\t", *t)) *t = ' ';
 }
 
-void printConvMap(const SString& gen1,const SString& gen2,const MultiMap& map)
+void printConvMap(const SString& gen1, const SString& gen2, const MultiMap& map)
 {
-int y,y2,len1;
-int id=0;
-if (map.isEmpty())
+	int y, y2, len1;
+	int id = 0;
+	if (map.isEmpty())
 	{
-	printf("{ empty }\n");
-	return;
+		printf("{ empty }\n");
+		return;
 	}
-len1=gen1.len();
-SString g1=gen1;
-stripstring(g1);
-SString g2=gen2;
-stripstring(g2);
-const char* g=g1.c_str();
-y=0;
-MultiRange *mr;
-MultiRange emptyrange;
-printN(' ',GEN1MAX);
-printf("   %s\n",g2.c_str());
-int begin=map.getBegin();
-int end=map.getEnd();
-while(y<len1)
+	len1 = gen1.len();
+	SString g1 = gen1;
+	stripstring(g1);
+	SString g2 = gen2;
+	stripstring(g2);
+	const char* g = g1.c_str();
+	y = 0;
+	MultiRange *mr;
+	MultiRange emptyrange;
+	printN(' ', GEN1MAX);
+	printf("   %s\n", g2.c_str());
+	int begin = map.getBegin();
+	int end = map.getEnd();
+	while (y < len1)
 	{
-	if (y<begin)
+		if (y < begin)
 		{
-		mr=&emptyrange;
-		y2=begin;
+			mr = &emptyrange;
+			y2 = begin;
 		}
-	else if (y>end)
+		else if (y > end)
 		{
-		mr=&emptyrange;
-		y2=len1;
+			mr = &emptyrange;
+			y2 = len1;
 		}
-	else	{
-		id=map.findMappingId(y);
-		mr=&map.getMapping(id)->to;
-		y2=map.getMapping(id+1)->begin;
+		else	{
+			id = map.findMappingId(y);
+			mr = &map.getMapping(id)->to;
+			y2 = map.getMapping(id + 1)->begin;
 		}
-	if ((y2-y) > GEN1MAX) y2=y+GEN1MAX;
-	if (y2>(y+len1)) y2=y+len1;
-	printmapping(g+y,y2-y,*mr,g2.c_str(),g2.len());
-	y=y2;
+		if ((y2 - y) > GEN1MAX) y2 = y + GEN1MAX;
+		if (y2 > (y + len1)) y2 = y + len1;
+		printmapping(g + y, y2 - y, *mr, g2.c_str(), g2.len());
+		y = y2;
 	}
 }
 
-void printModelMap(const SString& gen1,const MultiMap& map)
+const MultiMap & getModelDisplayMap()
 {
-SString g2("012345678901234567890123456789");
-printN(' ',GEN1MAX);
-printf("   Parts     Joints    Neurons\n");
-printConvMap(gen1,g2,map);
+	static MultiMap display_map;
+	if (display_map.isEmpty())
+	{
+		for (int i = 0; i < 10; i++)
+		{
+			display_map.add(Model::partToMap(i), Model::partToMap(i), i, i);
+			display_map.add(Model::jointToMap(i), Model::jointToMap(i), 10 + i, 10 + i);
+			display_map.add(Model::neuroToMap(i), Model::neuroToMap(i), 20 + i, 20 + i);
+		}
+	}
+	return display_map;
 }
+
+void printModelMap(const SString& gen1, const MultiMap& map)
+{
+	MultiMap combined_map;
+	combined_map.addCombined(map, getModelDisplayMap());
+	SString g2("012345678901234567890123456789");
+	printN(' ', GEN1MAX);
+	printf("   Parts     Joints    Neurons\n");
+	printConvMap(gen1, g2, combined_map);
+}
Index: /cpp/frams/_demos/printconvmap.h
===================================================================
--- /cpp/frams/_demos/printconvmap.h	(revision 731)
+++ /cpp/frams/_demos/printconvmap.h	(revision 732)
@@ -1,4 +1,4 @@
 // This file is a part of Framsticks SDK.  http://www.framsticks.com/
-// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
+// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
 // See LICENSE.txt for details.
 
@@ -10,6 +10,7 @@
 class MultiMap;
 
-void printConvMap(const SString& gen1,const SString& gen2,const MultiMap& map);
-void printModelMap(const SString& gen1,const MultiMap& map);
+void printConvMap(const SString& gen1, const SString& gen2, const MultiMap& map);
+void printModelMap(const SString& gen1, const MultiMap& map); //automaticaly combines the map with the ModelDisplayMap
+const MultiMap & getModelDisplayMap(); // mapping: true model -> display (so the regular map printing/debugging tools can be used for model maps, avoiding invonveniently huge numbers)
 
 #endif
Index: /cpp/frams/_demos/saver_test_geno.cpp
===================================================================
--- /cpp/frams/_demos/saver_test_geno.cpp	(revision 731)
+++ /cpp/frams/_demos/saver_test_geno.cpp	(revision 732)
@@ -28,6 +28,6 @@
 	{
 		int N = atoi(argv[2]);
-		MiniGenotype g;
-		Param p(minigenotype_paramtab, &g);
+		GenotypeMini g;
+		Param p(genotypemini_paramtab, &g);
 		g.clear();
 		printf("Saving %d genotypes to %s\n", N, argv[1]);
Index: /cpp/frams/_demos/simil_test.cpp
===================================================================
--- /cpp/frams/_demos/simil_test.cpp	(revision 731)
+++ /cpp/frams/_demos/simil_test.cpp	(revision 732)
@@ -125,6 +125,6 @@
 
 	long count = 0, totalsize = 0;
-	MiniGenotypeLoader loader(szFileName);
-	MiniGenotype *loaded;
+	GenotypeMiniLoader loader(szFileName);
+	GenotypeMini *loaded;
 	while (loaded = loader.loadNextGenotype())
 	{
@@ -147,5 +147,5 @@
 		}
 	}
-	if (loader.getStatus() == MiniGenotypeLoader::OnError)
+	if (loader.getStatus() == GenotypeMiniLoader::OnError)
 	{
 		printf("Error: %s", loader.getError().c_str());
Index: /cpp/frams/config/f0-SDK.def
===================================================================
--- /cpp/frams/config/f0-SDK.def	(revision 731)
+++ /cpp/frams/config/f0-SDK.def	(revision 732)
@@ -89,5 +89,5 @@
 PROP(getInputNeuroIndex,0,1+2,`get input neuron index',p d(d),,,,p_getInputNeuroIndex,PROCEDURE)
 PROP(getInputWeight,0,1+2,`get input weight',p f(d),,,,p_getInputWeight,PROCEDURE)
-PROP(classObject,0,1+2,`neuron class',o NeuroClass,,,,classObject,GETONLY)
+PROP(classObject,0,1+2,`neuron class',oNeuroClass,,,,classObject,GETONLY)
 ENDCLASS
 
Index: /cpp/frams/config/f0.def
===================================================================
--- /cpp/frams/config/f0.def	(revision 731)
+++ /cpp/frams/config/f0.def	(revision 732)
@@ -89,5 +89,5 @@
 PROP(getInputNeuroIndex,0,0,`get input neuron index',p d(d),,,,p_getInputNeuroIndex,PROCEDURE)
 PROP(getInputWeight,0,0,`get input weight',p f(d),,,,p_getInputWeight,PROCEDURE)
-PROP(classObject,0,1+2,`neuron class',o NeuroClass,,,,classObject,GETONLY)
+PROP(classObject,0,1+2,`neuron class',oNeuroClass,,,,classObject,GETONLY)
 ENDCLASS
 
Index: /cpp/frams/config/sdk_build_config.h
===================================================================
--- /cpp/frams/config/sdk_build_config.h	(revision 731)
+++ /cpp/frams/config/sdk_build_config.h	(revision 732)
@@ -1,4 +1,4 @@
 // This file is a part of Framsticks SDK.  http://www.framsticks.com/
-// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
+// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
 // See LICENSE.txt for details.
 
@@ -15,5 +15,4 @@
 
 #define NOCREATUREOBJECT
-#define EASYMAPDEBUG
 #define SDK_WITHOUT_FRAMS
 #define NO_BARRIER
Index: /cpp/frams/genetics/f1/conv_f1.cpp
===================================================================
--- /cpp/frams/genetics/f1/conv_f1.cpp	(revision 731)
+++ /cpp/frams/genetics/f1/conv_f1.cpp	(revision 732)
@@ -1,4 +1,4 @@
 // 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.
 
@@ -14,5 +14,5 @@
 
 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 };
+0.2, 0.5, 0.5, 0.5 };
 
 class Builder
@@ -106,9 +106,9 @@
 
 /** main conversion function - with conversion map support */
-SString GenoConv_f1::convert(SString &i, MultiMap *map)
+SString GenoConv_f1::convert(SString &i, MultiMap *map, bool using_checkpoints)
 {
 	const char* g = i.c_str();
 	Builder builder(g, map ? 1 : 0);
-	builder.model.open();
+	builder.model.open(using_checkpoints);
 	builder.grow(-1, g, Pt3D_0, stdprops, -1); // uses Model::addFromString() to create model elements
 	if (builder.invalid) return SString();
@@ -242,4 +242,5 @@
 
 			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;
Index: /cpp/frams/genetics/f1/conv_f1.h
===================================================================
--- /cpp/frams/genetics/f1/conv_f1.h	(revision 731)
+++ /cpp/frams/genetics/f1/conv_f1.h	(revision 732)
@@ -1,4 +1,4 @@
 // 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.
 
@@ -69,5 +69,5 @@
 		mapsupport = 1;
 	}
-	SString convert(SString &i, MultiMap *map);
+	SString convert(SString &i, MultiMap *map, bool using_checkpoints);
 	~GenoConv_f1() {}
 };
Index: /cpp/frams/genetics/geno.cpp
===================================================================
--- /cpp/frams/genetics/geno.cpp	(revision 731)
+++ /cpp/frams/genetics/geno.cpp	(revision 732)
@@ -1,4 +1,4 @@
 // This file is a part of Framsticks SDK.  http://www.framsticks.com/
-// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
+// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
 // See LICENSE.txt for details.
 
@@ -32,5 +32,5 @@
 	name = genname;
 	txt = comment;
-	setGenesAndFormat(genstring,genformat);
+	setGenesAndFormat(genstring, genformat);
 }
 
@@ -54,5 +54,5 @@
 					mapinshift = end + 1;
 					gencopy = genstring.substr(end + 1);
-					if ((end>0) && (genstring[end-1]=='\r')) end--;
+					if ((end > 0) && (genstring[end - 1] == '\r')) end--;
 					error_end = end;
 					if (end != 3) genformat = INVALID_FORMAT;
@@ -82,5 +82,5 @@
 				break;
 			}
-			if (!isalnum(genformat)) genformat=INVALID_FORMAT;
+			if (!isalnum(genformat)) genformat = INVALID_FORMAT;
 			if (genformat == INVALID_FORMAT)
 			{
@@ -93,5 +93,5 @@
 					cut = genstring.substr(0, error_end);
 				int lf = cut.indexOf('\n');
-				if (lf >= 0) { if ((lf>0)&&(cut[lf-1]=='\r')) lf--; cut = cut.substr(0, lf); }
+				if (lf >= 0) { if ((lf > 0) && (cut[lf - 1] == '\r')) lf--; cut = cut.substr(0, lf); }
 				sstringQuote(cut);
 				logPrintf("Geno", "init", LOG_ERROR, "Invalid genotype format declaration: '%s'%s", cut.c_str(), name.len() ? SString::sprintf(" in '%s'", name.c_str()).c_str() : "");
@@ -226,5 +226,5 @@
 	{
 		bool converter_missing;
-		Geno f0geno = g.getConverted('0', NULL, &converter_missing);
+		Geno f0geno = g.getConverted('0', NULL, false, &converter_missing);
 		if (converter_missing)
 			return -1;//no result
@@ -295,5 +295,5 @@
 }
 
-Geno Geno::getConverted(char otherformat, MultiMap *m, bool *converter_missing)
+Geno Geno::getConverted(char otherformat, MultiMap *m, bool using_checkpoints, bool *converter_missing)
 {
 	if (otherformat == getFormat()) { if (converter_missing) *converter_missing = false; return *this; }
@@ -302,8 +302,8 @@
 	if (converters)
 	{
-		if ((otherformat == '0') && (!m))
+		if ((otherformat == '0') && (!m) && (!using_checkpoints))
 		{
 			if (!f0gen)
-				f0gen = new Geno(converters->convert(*this, otherformat, NULL, converter_missing));
+				f0gen = new Geno(converters->convert(*this, otherformat, NULL, using_checkpoints, converter_missing));
 			else
 			{
@@ -313,5 +313,5 @@
 		}
 		else
-			return converters->convert(*this, otherformat, m, converter_missing);
+			return converters->convert(*this, otherformat, m, using_checkpoints, converter_missing);
 	}
 #endif
Index: /cpp/frams/genetics/geno.h
===================================================================
--- /cpp/frams/genetics/geno.h	(revision 731)
+++ /cpp/frams/genetics/geno.h	(revision 732)
@@ -1,4 +1,4 @@
 // This file is a part of Framsticks SDK.  http://www.framsticks.com/
-// Copyright (C) 1999-2016  Maciej Komosinski and Szymon Ulatowski.
+// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
 // See LICENSE.txt for details.
 
@@ -90,5 +90,5 @@
 
 	/** @param genformat=-1 -> detect genotype format from genstring comment (like the constructor does), else specify the valid format in genformat and pure genes in genstring. */
-	void setGenesAndFormat(const SString& genstring, char genformat=-1);
+	void setGenesAndFormat(const SString& genstring, char genformat = -1);
 	/** g must be pure genes, without format. For the standard behavior use setGenesAndFormat() */
 	void setGenesAssumingSameFormat(const SString& g);
@@ -107,5 +107,5 @@
 	/// make converted version of the genotype.
 	/// @param converter_missing optional output parameter (ignored when NULL). Receives true if the conversion fails because of the lack of appropriate converter(s) (the returned Geno is always invalid in this case). Receives false if the genotype was converted by a converter or a converter chain (the returned Geno can be valid or invalid, depending on the converter's decision).
-	Geno getConverted(char otherformat, MultiMap *m = 0, bool *converter_missing = NULL);
+	Geno getConverted(char otherformat, MultiMap *m = 0, bool using_checkpoints = false, bool *converter_missing = NULL);
 
 	/// @return -1 = before first char in the string
Index: /cpp/frams/genetics/genoconv.cpp
===================================================================
--- /cpp/frams/genetics/genoconv.cpp	(revision 731)
+++ /cpp/frams/genetics/genoconv.cpp	(revision 732)
@@ -1,4 +1,4 @@
 // This file is a part of Framsticks SDK.  http://www.framsticks.com/
-// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
+// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
 // See LICENSE.txt for details.
 
@@ -81,5 +81,5 @@
 
 GenoConvManager::GenoConvManager()
-:param(this)
+	:param(this)
 {
 }
@@ -166,5 +166,5 @@
 }
 
-Geno GenoConvManager::convert(Geno &in, char format, MultiMap *map, bool *converter_missing)
+Geno GenoConvManager::convert(Geno &in, char format, MultiMap *map, bool using_checkpoints, bool *converter_missing)
 {
 	if (in.getFormat() == format) { if (converter_missing) *converter_missing = false; return in; }
@@ -187,8 +187,8 @@
 	{
 		GenoConverter *gk = (GenoConverter*)converters(*t);
-		tmp = gk->convert(tmp, mapavail ? &tmpmap : 0);
+		tmp = gk->convert(tmp, mapavail ? &tmpmap : 0, using_checkpoints);
 		if (!tmp.len())
 		{
-			string t=ssprintf("f%c->f%c conversion failed (%s)", gk->in_format, gk->out_format, gk->name);
+			string t = ssprintf("f%c->f%c conversion failed (%s)", gk->in_format, gk->out_format, gk->name);
 			return Geno(0, 0, 0, t.c_str());
 		}
Index: /cpp/frams/genetics/genoconv.h
===================================================================
--- /cpp/frams/genetics/genoconv.h	(revision 731)
+++ /cpp/frams/genetics/genoconv.h	(revision 732)
@@ -1,4 +1,4 @@
 // This file is a part of Framsticks SDK.  http://www.framsticks.com/
-// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
+// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
 // See LICENSE.txt for details.
 
@@ -53,5 +53,5 @@
 	/// Any other return value is assumed to be output genotype.
 	/// @param map if not null, mapping informaton is requested, converter should add conversion map to this object
-	virtual SString convert(SString &i, MultiMap *map) { return SString(); }
+	virtual SString convert(SString &i, MultiMap *map, bool using_checkpoints) { return SString(); }
 
 	virtual ~GenoConverter() {}
@@ -78,5 +78,5 @@
 	/// make a genotype in other format. genotype will be invalid
 	/// if GenoConvManager cannot convert it.
-	Geno convert(Geno &in, char format, MultiMap *map = 0, bool *converter_missing = NULL);
+	Geno convert(Geno &in, char format, MultiMap *map = 0, bool using_checkpoints = false, bool *converter_missing = NULL);
 	/// register GenoConverter, the added object will be automatically deleted when GenoConvManager is destructed (call removeConverter() if this is not desirable)
 	void addConverter(GenoConverter *conv);
Index: /cpp/frams/model/defassign-f0-SDK.h
===================================================================
--- /cpp/frams/model/defassign-f0-SDK.h	(revision 731)
+++ /cpp/frams/model/defassign-f0-SDK.h	(revision 732)
@@ -1,4 +1,4 @@
 // This file is a part of Framsticks SDK.  http://www.framsticks.com/
-// Copyright (C) 1999-2016  Maciej Komosinski and Szymon Ulatowski.
+// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
 // See LICENSE.txt for details.
 
Index: /cpp/frams/model/f0-SDK-classes.h
===================================================================
--- /cpp/frams/model/f0-SDK-classes.h	(revision 731)
+++ /cpp/frams/model/f0-SDK-classes.h	(revision 732)
@@ -155,5 +155,5 @@
  {"getInputNeuroIndex",0,1+2,"get input neuron index","p d(d)",PROCEDURE(p_getInputNeuroIndex),},
  {"getInputWeight",0,1+2,"get input weight","p f(d)",PROCEDURE(p_getInputWeight),},
- {"classObject",0,1+2,"neuron class","o NeuroClass",GETONLY(classObject),},
+ {"classObject",0,1+2,"neuron class","oNeuroClass",GETONLY(classObject),},
  {0,0,0,}
 };
Index: /cpp/frams/model/model.cpp
===================================================================
--- /cpp/frams/model/model.cpp	(revision 731)
+++ /cpp/frams/model/model.cpp	(revision 732)
@@ -1,4 +1,4 @@
 // 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.
 
@@ -9,4 +9,6 @@
 #include <common/loggers/loggers.h>
 
+#define F0_CHECKPOINT_LINE "checkpoint:"
+
 Model::Model()
 {
@@ -18,4 +20,6 @@
 {
 	partmappingchanged = 0;
+	using_checkpoints = false;
+	is_checkpoint = false;
 	buildstatus = empty;
 	modelfromgenotype = 0;
@@ -47,10 +51,8 @@
 	f0genoknown = 0;
 	startenergy = mod.startenergy;
-	if (mod.getStatus() == valid)
-	{
-		modelfromgenotype = mod.modelfromgenotype;
-		{for (int i = 0; i < mod.getPartCount(); i++)
-			addPart(new Part(*mod.getPart(i))); }
-	{for (int i = 0; i < mod.getJointCount(); i++)
+	modelfromgenotype = mod.modelfromgenotype;
+	for (int i = 0; i < mod.getPartCount(); i++)
+		addPart(new Part(*mod.getPart(i)));
+	for (int i = 0; i < mod.getJointCount(); i++)
 	{
 		Joint *oldj = mod.getJoint(i);
@@ -58,6 +60,6 @@
 		addJoint(j);
 		j->attachToParts(oldj->part1->refno, oldj->part2->refno);
-	}}
-	{for (int i = 0; i < mod.getNeuroCount(); i++)
+	}
+	for (int i = 0; i < mod.getNeuroCount(); i++)
 	{
 		Neuro *oldn = mod.getNeuro(i);
@@ -66,25 +68,32 @@
 		if (oldn->part_refno >= 0) n->attachToPart(oldn->part_refno);
 		else n->attachToJoint(oldn->joint_refno);
-	}}
-		for (int i = 0; i < mod.getNeuroCount(); i++)
-		{
-			Neuro *oldn = mod.getNeuro(i);
-			Neuro *n = getNeuro(i);
-			for (int ni = 0; ni < oldn->getInputCount(); ni++)
-			{
-				double w;
-				Neuro *oldinput = oldn->getInput(ni, w);
-				SString info = n->getInputInfo(ni);
-				n->addInput(getNeuro(oldinput->refno), w, &info);
-			}
-		}
-	}
-}
-
-
-Model::Model(const Geno &src, bool buildmaps)
+	}
+	for (int i = 0; i < mod.getNeuroCount(); i++)
+	{
+		Neuro *oldn = mod.getNeuro(i);
+		Neuro *n = getNeuro(i);
+		for (int ni = 0; ni < oldn->getInputCount(); ni++)
+		{
+			double w;
+			Neuro *oldinput = oldn->getInput(ni, w);
+			SString info = n->getInputInfo(ni);
+			n->addInput(getNeuro(oldinput->refno), w, &info);
+		}
+	}
+	updateRefno();
+	if (using_checkpoints)
+		for (vector<Model*>::const_iterator it = mod.checkpoints.begin(); it != mod.checkpoints.end(); it++)
+		{
+		Model *m = *it;
+		Model *n = new Model(*m, m->autobuildmaps, false, true);
+		checkpoints.push_back(n);
+		}
+}
+
+
+Model::Model(const Geno &src, bool buildmaps, bool _using_checkpoints, bool _is_checkpoint)
 	:autobuildmaps(buildmaps)
 {
-	init(src);
+	init(src, _using_checkpoints, _is_checkpoint);
 }
 
@@ -92,21 +101,30 @@
 {
 	clear();
-	open();
+	open(mod.isUsingCheckpoints(), mod.isCheckpoint());
 	internalCopy(mod);
 	buildstatus = mod.buildstatus;
 }
 
-Model::Model(const Model &mod, bool buildmaps)
+Model::Model(const Model &mod, bool buildmaps, bool _using_checkpoints, bool _is_checkpoint)
 	:autobuildmaps(buildmaps)
 {
 	init();
-	open();
+	open(_using_checkpoints, _is_checkpoint);
 	internalCopy(mod);
-	buildstatus = mod.buildstatus;
-}
-
-void Model::init(const Geno &src)
+	if (is_checkpoint)
+		close();
+	else
+		buildstatus = mod.buildstatus;
+	if (mod.map)
+		map = new MultiMap(*mod.map);
+	if (mod.f0map)
+		f0map = new MultiMap(*mod.f0map);
+}
+
+void Model::init(const Geno &src, bool _using_checkpoints, bool _is_checkpoint)
 {
 	init();
+	using_checkpoints = _using_checkpoints;
+	is_checkpoint = _is_checkpoint;
 	modelfromgenotype = 1;
 	geno = src;
@@ -146,4 +164,7 @@
 	geno = Geno();
 	f0geno = Geno();
+	for (vector<Model*>::iterator it = checkpoints.begin(); it != checkpoints.end(); it++)
+		delete *it;
+	checkpoints.clear();
 }
 
@@ -293,15 +314,15 @@
 Model::ItemType Model::itemTypeFromLinePrefix(const char* line)
 {
-struct PrefixAndItem { const char* prefix; ItemType type; };
-static const PrefixAndItem types[]={ {"m:",ModelType},{"p:",PartType},{"j:",JointType},{"n:",NeuronType},{"c:",NeuronConnectionType},{NULL} };
-for(const PrefixAndItem *t=types;t->prefix!=NULL;t++)
-	{
-	const char* in=line;
-	const char* pattern=t->prefix;
-	for(;*in==*pattern;in++,pattern++)
-		if (*pattern==':')
-			return t->type;
-	}
-return UnknownType;
+	struct PrefixAndItem { const char* prefix; ItemType type; };
+	static const PrefixAndItem types[] = { { "m:", ModelType }, { "p:", PartType }, { "j:", JointType }, { "n:", NeuronType }, { "c:", NeuronConnectionType }, { F0_CHECKPOINT_LINE, CheckpointType }, { NULL } };
+	for (const PrefixAndItem *t = types; t->prefix != NULL; t++)
+	{
+		const char* in = line;
+		const char* pattern = t->prefix;
+		for (; *in == *pattern; in++, pattern++)
+			if (*pattern == ':')
+				return t->type;
+	}
+	return UnknownType;
 }
 
@@ -311,5 +332,5 @@
 	f0warnposition = -1;
 	MultiMap *convmap = autobuildmaps ? new MultiMap() : NULL;
-	f0geno = (geno.getFormat() == '0') ? geno : geno.getConverted('0', convmap);
+	f0geno = (geno.getFormat() == '0') ? geno : geno.getConverted('0', convmap, using_checkpoints);
 	f0genoknown = 1;
 	if (f0geno.isInvalid())
@@ -331,7 +352,8 @@
 	MultiRange frommap;
 	LoggerToMemory mh(LoggerBase::Enable | LoggerBase::DontBlock);
+	Model *current_model = this;
 	for (; f0txt.getNextToken(pos, line, '\n'); lnum++)
 	{
-		const char* line_ptr=line.c_str();
+		const char* line_ptr = line.c_str();
 		for (; *line_ptr; line_ptr++)
 			if (!strchr(" \r\t", *line_ptr)) break;
@@ -339,16 +361,16 @@
 		if (!*line_ptr) continue;
 
-		const char* colon=strchr(line_ptr,':');
-		ItemType type=UnknownType;
+		const char* colon = strchr(line_ptr, ':');
+		ItemType type = UnknownType;
 		SString excluding_prefix;
-		if (colon!=NULL)
-			{
+		if (colon != NULL)
+		{
 			colon++;
-			type=itemTypeFromLinePrefix(line_ptr);
+			type = itemTypeFromLinePrefix(line_ptr);
 			for (; *colon; colon++)
 				if (!strchr(" \r\t", *colon)) break;
-			excluding_prefix=colon;
-			}
-		
+			excluding_prefix = colon;
+		}
+
 		if (autobuildmaps)
 		{
@@ -357,5 +379,12 @@
 		}
 		mh.reset();
-		if (addFromString(type, excluding_prefix, lnum, autobuildmaps ? (&frommap) : 0) == -1)
+		if (type == CheckpointType)
+		{
+			current_model->close();
+			current_model = new Model;
+			current_model->open(false, true);
+			checkpoints.push_back(current_model);
+		}
+		else if (current_model->addFromString(type, excluding_prefix, lnum, autobuildmaps ? (&frommap) : 0) == -1)
 		{
 			buildstatus = invalid;
@@ -371,5 +400,5 @@
 	}
 	mh.disable();
-	close();
+	current_model->close();
 	if (convmap)
 	{
@@ -503,4 +532,12 @@
 		}
 	}
+
+	for (vector<Model*>::const_iterator it = checkpoints.begin(); it != checkpoints.end(); it++)
+	{
+		Geno g = (*it)->getF0Geno();
+		gen += F0_CHECKPOINT_LINE "\n";
+		gen += g.getGenes();
+	}
+
 	g = Geno(gen.c_str(), '0');
 }
@@ -508,7 +545,9 @@
 //////////////
 
-void Model::open()
+void Model::open(bool _using_checkpoints, bool _is_checkpoint)
 {
 	if (buildstatus == building) return;
+	using_checkpoints = _using_checkpoints;
+	is_checkpoint = _is_checkpoint;
 	buildstatus = building;
 	modelfromgenotype = 0;
@@ -518,6 +557,21 @@
 }
 
+int Model::getCheckpointCount()
+{
+	return checkpoints.size();
+}
+
+Model* Model::getCheckpoint(int i)
+{
+	return checkpoints[i];
+}
+
 void Model::checkpoint()
-{}
+{
+	if (!using_checkpoints) return;
+	updateRefno();
+	Model *m = new Model(*this, false, false, true);
+	checkpoints.push_back(m);
+}
 
 void Model::setGeno(const Geno& newgeno)
@@ -544,5 +598,5 @@
 	if (buildstatus != building)
 		logPrintf("Model", "close", LOG_WARN, "Unexpected close() - no open()");
-	if (internalcheck(building_live_model ? LIVE_CHECK : FINAL_CHECK) > 0)
+	if (internalcheck(is_checkpoint ? CHECKPOINT_CHECK : (building_live_model ? LIVE_CHECK : FINAL_CHECK)) > 0)
 	{
 		buildstatus = valid;
@@ -589,5 +643,5 @@
 int Model::addFromString(ItemType item_type, const SString &singleline, const MultiRange* srcrange)
 {
-	return addFromString(item_type,singleline, 0, srcrange);
+	return addFromString(item_type, singleline, 0, srcrange);
 }
 
@@ -612,8 +666,8 @@
 	error_message = SString::empty();
 	ParamInterface::LoadOptions opts;
-	switch(item_type)
-		{
-		case PartType:
-		{
+	switch (item_type)
+	{
+	case PartType:
+	{
 		Param partparam(f0_part_paramtab);
 		Part *p = new Part();
@@ -626,8 +680,8 @@
 		if (srcrange) p->setMapping(*srcrange);
 		return getPartCount() - 1;
-		}
-
-		case ModelType:
-		{
+	}
+
+	case ModelType:
+	{
 		Param modelparam(f0_model_paramtab);
 		modelparam.select(this);
@@ -635,8 +689,8 @@
 		if (opts.parse_failed) { error_message = "Invalid 'm:'"; return -1; }
 		return 0;
-		}
-
-		case JointType:
-		{
+	}
+
+	case JointType:
+	{
 		Param jointparam(f0_joint_paramtab);
 		Joint *j = new Joint();
@@ -665,8 +719,8 @@
 			return -1;
 		}
-		}
-
-		case NeuronType:
-		{
+	}
+
+	case NeuronType:
+	{
 		Param neuroparam(f0_neuro_paramtab);
 		Neuro *nu = new Neuro();
@@ -714,8 +768,8 @@
 			return neurons.size() - 1;
 		}
-		}
-
-		case NeuronConnectionType:			
-		{
+	}
+
+	case NeuronConnectionType:
+	{
 		Param ncparam(f0_neuroconn_paramtab);
 		NeuroConn c;
@@ -736,9 +790,9 @@
 		error_message = SString::sprintf("Invalid reference to Neuro #%d", n1_ok ? c.n2_refno : c.n1_refno);
 		return -1;
-		}
-
-		case UnknownType: //handled by addFromString for uniform error handling
-			return -1;
-		}
+	}
+
+	case CheckpointType: case UnknownType: //handled by addFromString for uniform error handling
+		return -1;
+	}
 	return -1;
 }
@@ -747,24 +801,20 @@
 /////////////
 
-/** change the sequence of neuro units
-	and fix references in "-" objects (n-n connections)  */
-void Model::moveNeuro(int oldpos, int newpos)
-{
-	if (oldpos == newpos) return; // nop!
-	Neuro *n = getNeuro(oldpos);
-	neurons -= oldpos;
-	neurons.insert(newpos, n);
-	// conn_refno could be broken -> fix it
-}
-
-////////////
-
-void Model::updateNeuroRefno()
-{
+void Model::updateRefno()
+{
+	for (int i = 0; i < parts.size(); i++)
+		getPart(i)->refno = i;
+	for (int i = 0; i < joints.size(); i++)
+	{
+		Joint *j = getJoint(i);
+		j->refno = i;
+		if (j->part1 && j->part2 && (j->part1 != j->part2))
+		{
+			j->p1_refno = j->part1->refno;
+			j->p2_refno = j->part2->refno;
+		}
+	}
 	for (int i = 0; i < neurons.size(); i++)
-	{
-		Neuro* n = (Neuro*)neurons(i);
-		n->refno = i;
-	}
+		getNeuro(i)->refno = i;
 }
 
@@ -779,12 +829,4 @@
 #define LINKFLAG 0x8000000
 
-void Model::updateRefno()
-{
-	int i;
-	for (i = 0; i < getPartCount(); i++) getPart(i)->refno = i;
-	for (i = 0; i < getJointCount(); i++) getJoint(i)->refno = i;
-	for (i = 0; i < getNeuroCount(); i++) getNeuro(i)->refno = i;
-}
-
 SString Model::nameForErrors() const
 {
@@ -802,4 +844,5 @@
 	int ret = 1;
 	shape = SHAPE_UNKNOWN;
+	updateRefno();
 	if ((parts.size() == 0) && (neurons.size() == 0)) return 0;
 	if (parts.size() == 0)
@@ -812,5 +855,4 @@
 			p = (Part*)parts(i);
 			p->owner = this;
-			p->refno = i;
 			if (checklevel > 0)
 				p->mass = 0.0;
@@ -907,5 +949,5 @@
 					}
 				}
-				if (check != LIVE_CHECK)
+				if ((check != LIVE_CHECK) && (check != CHECKPOINT_CHECK))
 				{
 					if (j->shape != Joint::SHAPE_FIXED)
@@ -935,6 +977,4 @@
 	}
 
-	updateNeuroRefno(); // valid refno is important for n-n connections check (later)
-
 	for (i = 0; i < neurons.size(); i++)
 	{
@@ -944,73 +984,78 @@
 	}
 
-	if (parts.size() && (checklevel > 0))
-	{
-		for (i = 0; i < parts.size(); i++)
-		{
-			p = (Part*)parts(i);
-			if (p->mass <= 0.001)
-				p->mass = 1.0;
-			p->flags &= ~LINKFLAG;
-		}
-		getPart(0)->flags |= LINKFLAG;
-		int change = 1;
-		while (change)
-		{
-			change = 0;
-			for (i = 0; i < joints.size(); i++)
-			{
-				j = (Joint*)joints(i);
-				if (j->part1->flags&LINKFLAG)
+	if (check != CHECKPOINT_CHECK)
+	{
+
+		if (parts.size() && (checklevel > 0))
+		{
+			for (i = 0; i < parts.size(); i++)
+			{
+				p = (Part*)parts(i);
+				if (p->mass <= 0.001)
+					p->mass = 1.0;
+				p->flags &= ~LINKFLAG;
+			}
+			getPart(0)->flags |= LINKFLAG;
+			int change = 1;
+			while (change)
+			{
+				change = 0;
+				for (i = 0; i < joints.size(); i++)
 				{
-					if (!(j->part2->flags&LINKFLAG))
+					j = (Joint*)joints(i);
+					if (j->part1->flags&LINKFLAG)
 					{
-						change = 1;
-						j->part2->flags |= LINKFLAG;
+						if (!(j->part2->flags&LINKFLAG))
+						{
+							change = 1;
+							j->part2->flags |= LINKFLAG;
+						}
 					}
+					else
+						if (j->part2->flags&LINKFLAG)
+						{
+						if (!(j->part1->flags&LINKFLAG))
+						{
+							change = 1;
+							j->part1->flags |= LINKFLAG;
+						}
+						}
 				}
-				else
-					if (j->part2->flags&LINKFLAG)
-					{
-					if (!(j->part1->flags&LINKFLAG))
-					{
-						change = 1;
-						j->part1->flags |= LINKFLAG;
-					}
-					}
-			}
-		}
-		for (i = 0; i < parts.size(); i++)
-		{
-			p = (Part*)parts(i);
-			if (!(p->flags&LINKFLAG))
-			{
-				logPrintf("Model", "internalCheck", LOG_ERROR, "Not all parts connected (eg. Part #0 and Part #%d)%s", i, nameForErrors().c_str());
+			}
+			for (i = 0; i < parts.size(); i++)
+			{
+				p = (Part*)parts(i);
+				if (!(p->flags&LINKFLAG))
+				{
+					logPrintf("Model", "internalCheck", LOG_ERROR, "Not all parts connected (eg. Part #0 and Part #%d)%s", i, nameForErrors().c_str());
+					ret = 0;
+					break;
+				}
+			}
+		}
+
+		for (i = 0; i < joints.size(); i++)
+		{
+			j = (Joint*)joints(i);
+			if (j->p1_refno == j->p2_refno)
+			{
+				logPrintf("Model", "internalCheck", LOG_ERROR, "Illegal self connection, Joint #%d%s", i, nameForErrors().c_str());
 				ret = 0;
 				break;
 			}
-		}
-	}
-
-	for (i = 0; i < joints.size(); i++)
-	{
-		j = (Joint*)joints(i);
-		if (j->p1_refno == j->p2_refno)
-		{
-			logPrintf("Model", "internalCheck", LOG_ERROR, "Illegal self connection, Joint #%d%s", i, nameForErrors().c_str());
-			ret = 0;
-			break;
-		}
-		for (k = i + 1; k < joints.size(); k++)
-		{
-			Joint* j2 = (Joint*)joints(k);
-			if (((j->p1_refno == j2->p1_refno) && (j->p2_refno == j2->p2_refno))
-				|| ((j->p1_refno == j2->p2_refno) && (j->p2_refno == j2->p1_refno)))
-			{
-				logPrintf("Model", "internalCheck", LOG_ERROR, "Illegal duplicate Joint #%d and Joint #%d%s", i, k, nameForErrors().c_str());
-				ret = 0;
-				break;
-			}
-		}
-	}
+			for (k = i + 1; k < joints.size(); k++)
+			{
+				Joint* j2 = (Joint*)joints(k);
+				if (((j->p1_refno == j2->p1_refno) && (j->p2_refno == j2->p2_refno))
+					|| ((j->p1_refno == j2->p2_refno) && (j->p2_refno == j2->p1_refno)))
+				{
+					logPrintf("Model", "internalCheck", LOG_ERROR, "Illegal duplicate Joint #%d and Joint #%d%s", i, k, nameForErrors().c_str());
+					ret = 0;
+					break;
+				}
+			}
+		}
+	}
+
 	if (shape == SHAPE_ILLEGAL)
 		ret = 0;
@@ -1250,4 +1295,36 @@
 //////////////////////
 
+int Model::elementToMap(ItemType type, int index)
+{
+	switch (type)
+	{
+	case PartType: return partToMap(index);
+	case JointType: return jointToMap(index);
+	case NeuronType: return neuroToMap(index);
+	default: return -1;
+	}
+}
+
+Model::TypeAndIndex Model::mapToElement(int map_index)
+{
+	if ((map_index >= 0) && (map_index < MODEL_MAPPING_OFFSET))
+		return TypeAndIndex(PartType, mapToPart(map_index));
+	if ((map_index >= MODEL_MAPPING_OFFSET) && (map_index < 2 * MODEL_MAPPING_OFFSET))
+		return TypeAndIndex(JointType, mapToJoint(map_index));
+	if ((map_index >= 2 * MODEL_MAPPING_OFFSET) && (map_index < 3 * MODEL_MAPPING_OFFSET))
+		return TypeAndIndex(NeuronType, mapToNeuro(map_index));
+	return TypeAndIndex();
+}
+
+int Model::partToMap(int i) { return MODEL_MAPPING_OFFSET + i; }
+int Model::jointToMap(int i) { return 2 * MODEL_MAPPING_OFFSET + i; }
+int Model::neuroToMap(int i) { return 3 * MODEL_MAPPING_OFFSET + i; }
+int Model::mapToPart(int i) { return i - MODEL_MAPPING_OFFSET; }
+int Model::mapToJoint(int i) { return i - 2 * MODEL_MAPPING_OFFSET; }
+int Model::mapToNeuro(int i) { return i - 3 * MODEL_MAPPING_OFFSET; }
+
+
+//////////////////////
+
 class MinPart : public Part { public: MinPart() { Param par(f0_part_paramtab, this); par.setMin(); } };
 class MaxPart : public Part { public: MaxPart() { Param par(f0_part_paramtab, this); par.setMax(); } };
Index: /cpp/frams/model/model.h
===================================================================
--- /cpp/frams/model/model.h	(revision 731)
+++ /cpp/frams/model/model.h	(revision 732)
@@ -1,4 +1,4 @@
 // This file is a part of Framsticks SDK.  http://www.framsticks.com/
-// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
+// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
 // See LICENSE.txt for details.
 
@@ -15,6 +15,4 @@
 
 extern ParamEntry f0_model_paramtab[];
-
-//#define EASYMAPDEBUG
 
 enum ModelBuildStatus { empty, building, invalid, valid };
@@ -64,4 +62,8 @@
 	/// make model map in build()
 	bool autobuildmaps;
+	/// supports adding checkpoints
+	bool using_checkpoints;
+	/// means less strict validation
+	bool is_checkpoint;
 	/// valid if build from f0 genotype
 	int f0errorposition;
@@ -75,4 +77,5 @@
 	SList parts, joints, neurons;
 	char partmappingchanged;
+	vector<Model*> checkpoints;
 
 	void internalCopy(const Model &mod);
@@ -95,16 +98,14 @@
 		EDITING_CHECK, ///< Used in Model::validate(). Default validation - does not modify elements of the Model.
 		FINAL_CHECK,   ///< Used in Model::close() when a Model is built from a genotype. Like EDITING_CHECK, but also calculates Joint::d and Joint::rot.
-		LIVE_CHECK     ///< used in Model::close() when a Model is built from a Creature. Like FINAL_CHECK but does not limit joint length which could make some liveModels invalid.
+		LIVE_CHECK,     ///< used in Model::close() when a Model is built from a Creature. Like FINAL_CHECK but does not limit joint length which could make some liveModels invalid.
+		CHECKPOINT_CHECK     ///< used when storing checkpoint models. Like LIVE_CHECK, excluding consistency check (disjoint parts are acceptable)
 	};
 protected:
 	ShapeType shape;
 
-	void updateNeuroRefno(); // set Neuro::refno for all neurons
 	SString nameForErrors() const;
 	int internalcheck(CheckType check);
 
-	void moveNeuro(int oldpos, int newpos);
-
-	void init(const Geno &srcgen);
+	void init(const Geno &srcgen, bool _using_checkpoints, bool _is_checkpoint);
 	void init();
 
@@ -134,6 +135,11 @@
 	int getErrorPosition(bool includingwarnings = false);
 	ShapeType getShapeType() const { return shape; }
+	bool isUsingCheckpoints() const { return using_checkpoints; }
+	bool isCheckpoint() const { return is_checkpoint; }
 
 	void updateRefno(); // set ::refno for all elements
+
+	int getCheckpointCount();
+	Model* getCheckpoint(int i);
 
 	/// The bounding box size. Valid if the model is valid. Read only.
@@ -153,6 +159,6 @@
 	   @see getMap()
 	   */
-	Model(const Geno &src, bool buildmaps = false);
-	Model(const Model &mod, bool buildmaps = false);
+	Model(const Geno &src, bool buildmaps = false, bool _using_checkpoints = false, bool _is_checkpoint = false);
+	Model(const Model &mod, bool buildmaps = false, bool _using_checkpoints = false, bool _is_checkpoint = false);
 	/** duplicate the model.
 		the resulting object's status is 'building' (opened).
@@ -255,5 +261,5 @@
 	void clear();
 
-	enum ItemType { UnknownType,ModelType,PartType,JointType,NeuronType,NeuronConnectionType };
+	enum ItemType { UnknownType, ModelType, PartType, JointType, NeuronType, NeuronConnectionType, CheckpointType };
 	static ItemType itemTypeFromLinePrefix(const char* line);
 	/** Execute single line of <B>f0</B> genotype.
@@ -264,9 +270,9 @@
 		@param srcrange source genotype range which will be mapped to this element
 		*/
-	int addFromString(ItemType item_type,const SString &singleline, int line_num, const MultiRange* srcrange = NULL);
+	int addFromString(ItemType item_type, const SString &singleline, int line_num, const MultiRange* srcrange = NULL);
 	/** Execute single line of <B>f0</B> genotype - compatiblity variant */
-	int addFromString(ItemType item_type,const SString &singleline, const MultiRange* srcrange = NULL);
+	int addFromString(ItemType item_type, const SString &singleline, const MultiRange* srcrange = NULL);
 	/** Execute single line of <B>f0</B> genotype - low level variant, used by Model::build(), error messages returned as string instead of calling logger */
-	int addFromStringNoLog(ItemType item_type,const SString &singleline, SString& error_message, const MultiRange* srcrange = 0);
+	int addFromStringNoLog(ItemType item_type, const SString &singleline, SString& error_message, const MultiRange* srcrange = 0);
 
 	/// separate build stages (for future use)
@@ -289,5 +295,5 @@
 	/// or modify the model created from the genotype.
 	/// Between open() and close() the model is not fully usable.
-	void open();
+	void open(bool _using_checkpoints = false, bool _is_checkpoint = false);
 
 	/// Current model written as f0 genotype while building
@@ -379,19 +385,21 @@
 	void buildUsingSolidShapeTypes(const Model& src_ballandstick_shapes, Part::Shape use_shape = Part::SHAPE_CYLINDER, float thickness = 0.2);
 
-#ifdef EASYMAPDEBUG
-	static int partToMap(int i) {return 0+i;}
-	static int jointToMap(int i) {return 10+i;}
-	static int neuroToMap(int i) {return 20+i;}
-	static int mapToPart(int i) {return i-0;}
-	static int mapToJoint(int i) {return i-10;}
-	static int mapToNeuro(int i) {return i-20;}
-#else
-	static int partToMap(int i) { return 0x10000000 + i; }
-	static int jointToMap(int i) { return 0x20000000 + i; }
-	static int neuroToMap(int i) { return 0x30000000 + i; }
-	static int mapToPart(int i) { return i - 0x10000000; }
-	static int mapToJoint(int i) { return i - 0x20000000; }
-	static int mapToNeuro(int i) { return i - 0x30000000; }
-#endif
+protected:
+	static const int MODEL_MAPPING_OFFSET = 0x10000000;
+public:
+	static int elementToMap(ItemType t, int i);
+	struct TypeAndIndex
+	{
+		ItemType type; int index;
+		TypeAndIndex() :type(UnknownType), index(0) {}
+		TypeAndIndex(ItemType _type, int _index) :type(_type), index(_index) {}
+	};
+	static TypeAndIndex mapToElement(int i);
+	static int partToMap(int i);
+	static int jointToMap(int i);
+	static int neuroToMap(int i);
+	static int mapToPart(int i);
+	static int mapToJoint(int i);
+	static int mapToNeuro(int i);
 
 	static void makeGenToGenMap(MultiMap& result, const MultiMap& gen1tomodel, const MultiMap& gen2tomodel);
Index: /cpp/frams/model/modelobj.cpp
===================================================================
--- /cpp/frams/model/modelobj.cpp	(revision 731)
+++ /cpp/frams/model/modelobj.cpp	(revision 732)
@@ -7,16 +7,17 @@
 ParamEntry modelobj_paramtab[] =
 {
-	{ "Model", 1, 16, "Model", },
+	{ "Model", 1, 21, "Model", },
 	{ "se", 0, PARAM_NOSTATIC, "startenergy", "f", FIELD(startenergy), },
 	{ "Vstyle", 0, PARAM_NOSTATIC, "vis_style", "s", FIELD(vis_style), },
 
-	{ "geno", 0, PARAM_NOSTATIC | PARAM_READONLY, "geno", "o Geno", GETONLY(geno), },
-	{ "newFromString", 0, 0, "create new object", "p oModel(s genotype)", PROCEDURE(p_newfromstring), },
-	{ "newFromGeno", 0, 0, "create new object", "p oModel(oGeno)", PROCEDURE(p_newfromgeno), },
+	{ "geno", 0, PARAM_NOSTATIC | PARAM_READONLY, "Geno", "oGeno", GETONLY(geno), },
+	{ "newFromString", 0, 0, "Create a new object", "p oModel(s genotype)", PROCEDURE(p_newfromstring), },
+	{ "newFromGeno", 0, 0, "Create a new object", "p oModel(oGeno)", PROCEDURE(p_newfromgeno), },
+	{ "newWithCheckpoints", 0, 0, "Create a new object", "p oModel(x Geno object or string genotype)", PROCEDURE(p_newwithcheckpoints), "Creates a Model with the \"Checkpoints\" option enabled. Genotype converters supporting Checkpoints provide a sequence of Models that reflects development stages of the creature (this sequence is used purely for debugging and visualization of phenotype growth/development). Checkpoint Models can be accessed using getCheckpoint(i) for i ranging from 0 to numcheckpoints-1. Models created without the Checkpoint option and Models coming from unsupported converters have numcheckpoints=0." },
 
-	{ "numparts", 0, PARAM_DONTSAVE | PARAM_NOSTATIC | PARAM_READONLY, "number of parts", "d", GETONLY(numparts), },
-	{ "numjoints", 0, PARAM_DONTSAVE | PARAM_NOSTATIC | PARAM_READONLY, "number of joints", "d", GETONLY(numjoints), },
-	{ "numneurons", 0, PARAM_DONTSAVE | PARAM_NOSTATIC | PARAM_READONLY, "number of neurons", "d", GETONLY(numneurons), },
-	{ "numconnections", 0, PARAM_DONTSAVE | PARAM_NOSTATIC | PARAM_READONLY, "number of neuron connections", "d", GETONLY(numconnections), },
+	{ "numparts", 0, PARAM_DONTSAVE | PARAM_NOSTATIC | PARAM_READONLY, "Number of parts", "d", GETONLY(numparts), },
+	{ "numjoints", 0, PARAM_DONTSAVE | PARAM_NOSTATIC | PARAM_READONLY, "Number of joints", "d", GETONLY(numjoints), },
+	{ "numneurons", 0, PARAM_DONTSAVE | PARAM_NOSTATIC | PARAM_READONLY, "Number of neurons", "d", GETONLY(numneurons), },
+	{ "numconnections", 0, PARAM_DONTSAVE | PARAM_NOSTATIC | PARAM_READONLY, "Number of neuron connections", "d", GETONLY(numconnections), },
 
 	{ "getPart", 0, PARAM_USERHIDDEN | PARAM_NOSTATIC, "getPart (static model information)", "p oPart(d index)", PROCEDURE(p_getpart), },
@@ -24,8 +25,20 @@
 	{ "getNeuroDef", 0, PARAM_USERHIDDEN | PARAM_NOSTATIC, "getNeuroDef", "p oNeuroDef(d index)", PROCEDURE(p_getneuro), },
 
-	{ "size_x", 0, PARAM_READONLY | PARAM_NOSTATIC | PARAM_DEPRECATED, "bounding box x size", "f", FIELD(size.x), "(size_x,size_y,size_z) are dimensions of the axis-aligned bounding box of the creature, including imaginary Part sizes (Part.s, usually 1.0). A creature consisting of a single default part has the size of (2.0,2.0,2.0) - twice the Part.s value (like a sphere diameter is twice its radius).\nSee also: Creature.moveAbs" },
-	{ "size_y", 0, PARAM_READONLY | PARAM_NOSTATIC | PARAM_DEPRECATED, "bounding box y size", "f", FIELD(size.y), "See Model.size_x" },
-	{ "size_z", 0, PARAM_READONLY | PARAM_NOSTATIC | PARAM_DEPRECATED, "bounding box z size", "f", FIELD(size.z), "See Model.size_x" },
+	{ "size_x", 0, PARAM_READONLY | PARAM_NOSTATIC | PARAM_DEPRECATED, "Bounding box x size", "f", FIELD(size.x), "(size_x,size_y,size_z) are dimensions of the axis-aligned bounding box of the creature, including imaginary Part sizes (Part.s, usually 1.0). A creature consisting of a single default part has the size of (2.0,2.0,2.0) - twice the Part.s value (like a sphere diameter is twice its radius).\nSee also: Creature.moveAbs" },
+	{ "size_y", 0, PARAM_READONLY | PARAM_NOSTATIC | PARAM_DEPRECATED, "Bounding box y size", "f", FIELD(size.y), "See Model.size_x" },
+	{ "size_z", 0, PARAM_READONLY | PARAM_NOSTATIC | PARAM_DEPRECATED, "Bounding box z size", "f", FIELD(size.z), "See Model.size_x" },
 	{ "bboxSize", 0, PARAM_READONLY | PARAM_NOSTATIC, "Bounding box size", "oXYZ", GETONLY(bboxsize) },
+	{ "numcheckpoints", 0, PARAM_DONTSAVE | PARAM_READONLY | PARAM_NOSTATIC, "Number of checkpoints", "d", GETONLY(numcheckpoints) },
+	{ "getCheckpoint", 0, PARAM_USERHIDDEN | PARAM_NOSTATIC, "getCheckpoint", "p oModel(d index)", PROCEDURE(p_getcheckpoint),
+	"Checkpoint Model objects are only valid as long as the parent Model object exists.\n"
+	"See also: Model.newWithCheckpoints()\n\n"
+	"// incorrect usage - calling getCheckpoint() on a temporary object:\n"
+	"var c=Model.newWithCheckpoints(\"XXX\").getCheckpoint(1).genotype.geno;\n\n"
+	"// correct usage - keeping the parent Model reference in 'm':\n"
+	"var m=Model.newWithCheckpoints(\"XXX\");\n"
+	"var c=m.getCheckpoint(1).genotype.geno;\n"
+	},
+	{ "shape_type", 0, PARAM_DONTSAVE | PARAM_NOSTATIC | PARAM_READONLY, "Shape type", "d 0 3 ~Unknown~Illegal~Ball-and-stick~Solids", GETONLY(shape_type) },
+	{ "solid_model", 0, PARAM_DONTSAVE | PARAM_NOSTATIC | PARAM_READONLY, "Solid shapes model", "oModel", GETONLY(solid_model), "Conversion of this Model to solid shapes. Note! Only available when this Model has shape_type==2 (Ball-and-stick)." },
 
 	{ 0, 0, 0, },
@@ -57,9 +70,29 @@
 }
 
+void ModelObj::p_newwithcheckpoints(ExtValue *args, ExtValue *ret)
+{
+	Model *m = NULL;
+	if (args[0].getType() == TString)
+		m = new Model(Geno(args[0].getString()), false, true);
+	else
+	{
+		Geno *g = GenoObj::fromObject(args[0].getObject(), false);
+		if (g)
+			m = new Model(*g, false, true);
+		else
+			logPrintf("Model", "newWithCheckpoints", LOG_ERROR, "Geno or string expected, %s found", args[0].typeDescription().c_str());
+	}
+
+	if (m != NULL)
+		*ret = makeDynamicObject(m);
+	else
+		ret->setEmpty();
+}
+
 Param& ModelObj::getStaticParam()
 {
 #ifdef __CODEGUARD__
 	static ModelObj static_modelobj;
-	static Param static_modelparam(modelobj_paramtab,&static_modelobj);
+	static Param static_modelparam(modelobj_paramtab, &static_modelobj);
 #else
 	static Param static_modelparam(modelobj_paramtab);
@@ -131,2 +164,29 @@
 	*ret = Pt3D_Ext::makeDynamicObject(new Pt3D_Ext(size));
 }
+
+void ModelObj::p_getcheckpoint(PARAMPROCARGS)
+{
+	int i = args->getInt();
+	if ((i < 0) || (i >= getCheckpointCount()))
+	{
+		ret->setEmpty();
+		return;
+	}
+	ret->setObject(makeStaticObject(getCheckpoint(i)));
+}
+
+void ModelObj::get_solid_model(ExtValue *ret)
+{
+	if (getShapeType() != Model::SHAPE_BALL_AND_STICK)
+		ret->setEmpty();
+	Model *m = new Model;
+	m->open();
+	m->buildUsingSolidShapeTypes(*this);
+	m->close();
+	*ret = makeDynamicObject(m);
+}
+
+void ModelObj::get_shape_type(ExtValue *ret)
+{
+	ret->setInt(getShapeType());
+}
Index: /cpp/frams/model/modelobj.h
===================================================================
--- /cpp/frams/model/modelobj.h	(revision 731)
+++ /cpp/frams/model/modelobj.h	(revision 732)
@@ -14,4 +14,5 @@
 	PARAMPROCDEF(p_newfromstring);
 	PARAMPROCDEF(p_newfromgeno);
+	PARAMPROCDEF(p_newwithcheckpoints);
 
 #define GETDELEGATE(name,type,value) PARAMGETDEF(name) {arg1->set ## type (value);}
@@ -20,4 +21,5 @@
 	GETDELEGATE(numneurons, Int, getNeuroCount())
 	GETDELEGATE(numconnections, Int, getConnectionCount())
+	GETDELEGATE(numcheckpoints, Int, getCheckpointCount())
 #undef GETDELEGATE
 
@@ -26,4 +28,7 @@
 	PARAMPROCDEF(p_getneuro);
 	PARAMGETDEF(bboxsize);
+	PARAMPROCDEF(p_getcheckpoint);
+	PARAMGETDEF(shape_type);
+	PARAMGETDEF(solid_model);
 
 #undef STATRICKCLASS
Index: /cpp/frams/neuro/neuroimpl.cpp
===================================================================
--- /cpp/frams/neuro/neuroimpl.cpp	(revision 731)
+++ /cpp/frams/neuro/neuroimpl.cpp	(revision 732)
@@ -324,8 +324,8 @@
 	{ "position_y", 0, PARAM_READONLY, "Position y", "f", GETONLY(position_y), },
 	{ "position_z", 0, PARAM_READONLY, "Position z", "f", GETONLY(position_z), },
-	{ "creature", 0, PARAM_READONLY, "Gets owner creature", "o Creature", GETONLY(creature), },
-	{ "part", 0, PARAM_READONLY, "The Part object where this neuron is located", "o MechPart", GETONLY(part), },
-	{ "joint", 0, PARAM_READONLY, "The Joint object where this neuron is located", "o MechJoint", GETONLY(joint), },
-	{ "neuroproperties", 0, PARAM_READONLY, "Custom neuron fields", "o NeuroProperties", GETONLY(fields),
+	{ "creature", 0, PARAM_READONLY, "Gets owner creature", "oCreature", GETONLY(creature), },
+	{ "part", 0, PARAM_READONLY, "The Part object where this neuron is located", "oMechPart", GETONLY(part), },
+	{ "joint", 0, PARAM_READONLY, "The Joint object where this neuron is located", "oMechJoint", GETONLY(joint), },
+	{ "neuroproperties", 0, PARAM_READONLY, "Custom neuron fields", "oNeuroProperties", GETONLY(fields),
 	"Neurons can have different fields depending on their class. Script neurons have their fields defined using the \"property:\" syntax. If you develop a custom neuron script you should use the NeuroProperties object for accessing your own neuron fields. The Neuro.neuroproperties property is meant for accessing the neuron fields from the outside script.\n"
 	"Examples:\n"
@@ -341,8 +341,8 @@
 	"for(i=0;i<iobj.size;i++)\n"
 	" Simulator.print(iobj.getId(i)+\" (\"+iobj.getName(i)+\")\");", },
-	{ "def", 0, PARAM_READONLY, "Neuron definition from which this live neuron was built", "o NeuroDef", GETONLY(neurodef), },
-	{ "classObject", 0, PARAM_READONLY, "Neuron class for this neuron", "o NeuroClass", GETONLY(classObject), },
+	{ "def", 0, PARAM_READONLY, "Neuron definition from which this live neuron was built", "oNeuroDef", GETONLY(neurodef), },
+	{ "classObject", 0, PARAM_READONLY, "Neuron class for this neuron", "oNeuroClass", GETONLY(classObject), },
 #ifdef NEURO_SIGNALS
-	{ "signals", 0, PARAM_READONLY, "Signals", "o NeuroSignals", FIELD(sigs_obj), },
+	{ "signals", 0, PARAM_READONLY, "Signals", "oNeuroSignals", FIELD(sigs_obj), },
 #endif
 
Index: /cpp/frams/param/param.cpp
===================================================================
--- /cpp/frams/param/param.cpp	(revision 731)
+++ /cpp/frams/param/param.cpp	(revision 732)
@@ -853,4 +853,8 @@
 	else
 	{
+		if ((t[0] == 'o') && (t[1] == ' '))
+		{
+			err = "space after 'o'";
+		}
 		if (!(pe->flags & (PARAM_READONLY | PARAM_DONTSAVE | PARAM_USERREADONLY | PARAM_CONST | PARAM_DONTLOAD | PARAM_LINECOMMENT | PARAM_OBJECTSET)))
 		{ //write access
@@ -1287,5 +1291,5 @@
 		if (i >= 0) i++;
 #ifdef __CODEGUARD__ 
-		if (next_field<end-1) t=next_field+1; else return fields_loaded;
+		if (next_field < end - 1) t = next_field + 1; else return fields_loaded;
 #else
 		t = next_field + 1;
Index: /cpp/frams/vm/classes/genoobj.cpp
===================================================================
--- /cpp/frams/vm/classes/genoobj.cpp	(revision 731)
+++ /cpp/frams/vm/classes/genoobj.cpp	(revision 732)
@@ -1,4 +1,4 @@
 // This file is a part of Framsticks SDK.  http://www.framsticks.com/
-// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
+// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
 // See LICENSE.txt for details.
 
@@ -11,5 +11,5 @@
 ParamEntry geno_paramtab[] =
 {
-	{ "Geno", 1, 15, "Geno", "All information about a single genotype.\nThis is a genetics-only object which does not contain any performance data. See also: Genotype class" },
+	{ "Geno", 1, 16, "Geno", "All information about a single genotype.\nThis is a genetics-only object which does not contain any performance data. See also: Genotype class" },
 	{ "name", 0, PARAM_NOSTATIC, "Name", "s 0 40", GETSET(name), },
 	{ "rawgenotype", 0, PARAM_NOSTATIC | PARAM_READONLY, "Raw genotype", "s 1", GETONLY(genotype), "Genotype, excluding the format specifier" },
@@ -23,5 +23,6 @@
 	"-1 = validity is not known. This is a transient state. The value of \"is_valid\" will never be -1 when read. It is safe to treat is_valid as boolean in statements like \"if (g.is_valid) ...\". Setting \"is_valid=-1\" will make it 0 or 1 again. This third state (-1) is only needed for loading Genotype objects from files where the \"is_valid\" field might not be present."
 	},
-	{ "getConverted", 0, PARAM_NOSTATIC, "get converted genotype", "p oGeno(s format)", PROCEDURE(p_getconvert), },
+	{ "getConverted", 0, PARAM_NOSTATIC, "Get converted genotype", "p oGeno(s format)", PROCEDURE(p_getconvert), },
+	{ "getConvertedWithCheckpoints", 0, PARAM_NOSTATIC, "Get converted genotype", "p oGeno(s format)", PROCEDURE(p_getconvert_ch), "See also Model.newWithCheckpoints()" },
 	{ "f0genotype", 0, PARAM_NOSTATIC | PARAM_READONLY, "f0 genotype", "s 1", GETONLY(f0genotype), "converted to f0 genotype", },
 	{ "new", 0, 0, "create new empty object", "p oGeno()", PROCEDURE(p_new), },
@@ -85,5 +86,5 @@
 void GenoObj::get_format(ExtValue *ret)
 {
-	char format_as_string[2]={getFormat(),0};
+	char format_as_string[2] = { getFormat(), 0 };
 	ret->setString(format_as_string);
 }
@@ -102,13 +103,13 @@
 char GenoObj::formatFromExtValue(ExtValue& v)
 {
-if (v.getType()==TInt)
-	return v.getInt();
-if (v.getType()==TString)
+	if (v.getType() == TInt)
+		return v.getInt();
+	if (v.getType() == TString)
 	{
-	SString s=v.getString();
-	if (s.len()==1)
-		return s.charAt(0);
+		SString s = v.getString();
+		if (s.len() == 1)
+			return s.charAt(0);
 	}
-return Geno::INVALID_FORMAT;
+	return Geno::INVALID_FORMAT;
 }
 
@@ -116,4 +117,9 @@
 {
 	*ret = makeDynamicObjectAndDecRef(new Geno(getConverted(formatFromExtValue(args[0]))));
+}
+
+void GenoObj::p_getconvert_ch(ExtValue *args, ExtValue *ret)
+{
+	*ret = makeDynamicObjectAndDecRef(new Geno(getConverted(formatFromExtValue(args[0]), NULL, true)));
 }
 
Index: /cpp/frams/vm/classes/genoobj.h
===================================================================
--- /cpp/frams/vm/classes/genoobj.h	(revision 731)
+++ /cpp/frams/vm/classes/genoobj.h	(revision 732)
@@ -1,4 +1,4 @@
 // This file is a part of Framsticks SDK.  http://www.framsticks.com/
-// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
+// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
 // See LICENSE.txt for details.
 
@@ -25,4 +25,5 @@
 	PARAMGETDEF(string);
 	PARAMPROCDEF(p_getconvert);
+	PARAMPROCDEF(p_getconvert_ch);
 	PARAMGETDEF(f0genotype);
 	PARAMPROCDEF(p_new);
