Index: cpp/frams/_demos/f0_variants_test.cpp
===================================================================
--- cpp/frams/_demos/f0_variants_test.cpp	(revision 719)
+++ cpp/frams/_demos/f0_variants_test.cpp	(revision 720)
@@ -30,5 +30,5 @@
 modelparam.select(&m);
 gen+="m:";
-modelparam.save2(gen,omit_default_values ? &defaultmodel : NULL);
+modelparam.saveSingleLine(gen,omit_default_values ? &defaultmodel : NULL);
 
 Part *p;
@@ -40,5 +40,5 @@
 	partparam.select(p);
 	gen+="p:";
-	partparam.save2(gen,omit_default_values ? &defaultpart : NULL);
+	partparam.saveSingleLine(gen,omit_default_values ? &defaultpart : NULL);
 	}
 for (int i=0;j=(Joint*)m.getJoint(i);i++)
@@ -47,5 +47,5 @@
 	jointparam.setParamTab(j->usedelta?f0_joint_paramtab:f0_nodeltajoint_paramtab);
 	gen+="j:";
-	jointparam.save2(gen,omit_default_values ? &defaultjoint : NULL);
+	jointparam.saveSingleLine(gen,omit_default_values ? &defaultjoint : NULL);
 	}
 for (int i=0;n=(Neuro*)m.getNeuro(i);i++)
@@ -53,5 +53,5 @@
 	neuroparam.select(n);
 	gen+="n:";
-	neuroparam.save2(gen,omit_default_values ? &defaultneuro : NULL);
+	neuroparam.saveSingleLine(gen,omit_default_values ? &defaultneuro : NULL);
 	}
 for (int a=0;n=(Neuro*)m.getNeuro(a);a++)
@@ -67,5 +67,5 @@
 		connparam.select(&nc);
 		gen+="c:";
-		connparam.save2(gen,omit_default_values ? &defaultconn : NULL);
+		connparam.saveSingleLine(gen,omit_default_values ? &defaultconn : NULL);
 		}
 	}
@@ -106,5 +106,5 @@
 	}
 
-printf("\nthis example shows how to save a f0 genotype using low-level ParamInterface::save2() calls\n");
+printf("\nthis example shows how to save a f0 genotype using low-level ParamInterface::saveSingleLine() calls\n");
 
 SString f0_skipping_defaults;
@@ -125,5 +125,5 @@
                   ( format 1 )
 
-this example shows how to save a f0 genotype using low-level ParamInterface::save2() calls
+this example shows how to save a f0 genotype using low-level ParamInterface::saveSingleLine() calls
 
 ==== with defdata (skips default values) ======
Index: cpp/frams/genetics/fF/fF_genotype.h
===================================================================
--- cpp/frams/genetics/fF/fF_genotype.h	(revision 719)
+++ cpp/frams/genetics/fF/fF_genotype.h	(revision 720)
@@ -36,6 +36,6 @@
 	{
 		SString s = serialized;
-		int p = 0; //position in string
-		return ((param.load2(s, p) == param.getPropCount()) && (p == s.len()));
+		ParamInterface::LoadOptions opts;
+		return ((param.load(ParamInterface::FormatSingleLine, s, &opts) == param.getPropCount()) && (opts.offset == s.len()));
 	}
 
@@ -43,5 +43,5 @@
 	{
 		SString tmp;
-		param.save2(tmp, NULL/*object containing default values for comparison*/, false/*add CR*/, false/*force field names*/);
+		param.saveSingleLine(tmp, NULL/*object containing default values for comparison*/, false/*add CR*/, false/*force field names*/);
 		return string(tmp.c_str());
 	}
Index: cpp/frams/model/model.cpp
===================================================================
--- cpp/frams/model/model.cpp	(revision 719)
+++ cpp/frams/model/model.cpp	(revision 720)
@@ -407,5 +407,5 @@
 	SString mod_props;
 	modelparam.select(this);
-	modelparam.save2(mod_props, handle_defaults ? &defaultmodel : NULL, true, !handle_defaults);
+	modelparam.saveSingleLine(mod_props, handle_defaults ? &defaultmodel : NULL, true, !handle_defaults);
 	if (mod_props.len() > 1) //are there any non-default values? ("\n" is empty)
 	{
@@ -419,5 +419,5 @@
 		len = gen.len();
 		gen += "p:";
-		partparam.save2(gen, handle_defaults ? &defaultpart : NULL, true, !handle_defaults);
+		partparam.saveSingleLine(gen, handle_defaults ? &defaultpart : NULL, true, !handle_defaults);
 		if (map)
 			map->add(len, gen.len() - 1, partToMap(i));
@@ -429,5 +429,5 @@
 		jointparam.setParamTab(j->usedelta ? f0_joint_paramtab : f0_nodeltajoint_paramtab);
 		gen += "j:";
-		jointparam.save2(gen, handle_defaults ? &defaultjoint : NULL, true, !handle_defaults);
+		jointparam.saveSingleLine(gen, handle_defaults ? &defaultjoint : NULL, true, !handle_defaults);
 		if (map)
 			map->add(len, gen.len() - 1, jointToMap(i));
@@ -438,5 +438,5 @@
 		len = gen.len();
 		gen += "n:";
-		neuroparam.save2(gen, handle_defaults ? &defaultneuro : NULL, true, !handle_defaults);
+		neuroparam.saveSingleLine(gen, handle_defaults ? &defaultneuro : NULL, true, !handle_defaults);
 		if (map)
 			map->add(len, gen.len() - 1, neuroToMap(i));
@@ -469,5 +469,5 @@
 			len = gen.len();
 			gen += "c:";
-			connparam.save2(gen, handle_defaults ? &defaultconn : NULL, true, !handle_defaults);
+			connparam.saveSingleLine(gen, handle_defaults ? &defaultconn : NULL, true, !handle_defaults);
 			if (map)
 				map->add(len, gen.len() - 1, neuroToMap(n->refno));
@@ -582,6 +582,7 @@
 {
 	error_message = SString::empty();
-	int pos = 0; const char*t = line.c_str();
-	for (; *t; t++, pos++)
+	const char*t = line.c_str();
+	ParamInterface::LoadOptions opts;
+	for (; *t; t++, opts.offset++)
 		if (!strchr(" \r\t", *t)) break;
 	if (*t == '#') return 0;
@@ -592,6 +593,7 @@
 		Part *p = new Part();
 		partparam.select(p);
-		pos += 2;
-		if (partparam.load2(line, pos) & ParamInterface::LOAD2_PARSE_FAILED) { delete p; error_message = "Invalid 'p:'"; return -1; }
+		opts.offset += 2;
+		partparam.load(ParamInterface::FormatSingleLine, line, &opts);
+		if (opts.parse_failed) { delete p; error_message = "Invalid 'p:'"; return -1; }
 		p->o.rotate(p->rot);
 		parts += p;
@@ -604,6 +606,7 @@
 		Param modelparam(f0_model_paramtab);
 		modelparam.select(this);
-		pos += 2;
-		if (modelparam.load2(line, pos) & ParamInterface::LOAD2_PARSE_FAILED) { error_message = "Invalid 'm:'"; return -1; }
+		opts.offset += 2;
+		modelparam.load(ParamInterface::FormatSingleLine, line, &opts);
+		if (opts.parse_failed) { error_message = "Invalid 'm:'"; return -1; }
 		return 0;
 	}
@@ -613,7 +616,8 @@
 		Joint *j = new Joint();
 		jointparam.select(j);
-		pos += 2;
+		opts.offset += 2;
 		j->owner = this;
-		if (jointparam.load2(line, pos) & ParamInterface::LOAD2_PARSE_FAILED) { delete j; error_message = "Invalid 'j:'"; return -1; }
+		jointparam.load(ParamInterface::FormatSingleLine, line, &opts);
+		if (opts.parse_failed) { delete j; error_message = "Invalid 'j:'"; return -1; }
 		bool p1_ok = false, p2_ok = false;
 		if ((p1_ok = ((j->p1_refno >= 0) && (j->p1_refno < getPartCount()))) &&
@@ -642,6 +646,7 @@
 		Neuro *nu = new Neuro();
 		neuroparam.select(nu);
-		pos += 2;
-		if (neuroparam.load2(line, pos) & ParamInterface::LOAD2_PARSE_FAILED) { delete nu; error_message = "Invalid 'n:'"; return -1; }
+		opts.offset += 2;
+		neuroparam.load(ParamInterface::FormatSingleLine, line, &opts);
+		if (opts.parse_failed) { delete nu; error_message = "Invalid 'n:'"; return -1; }
 #ifdef MODEL_V1_COMPATIBLE
 		if (nu->neuro_refno>=0) // parent specified...
@@ -718,6 +723,7 @@
 		NeuroConn c;
 		ncparam.select(&c);
-		pos += 2;
-		if (ncparam.load2(line, pos) & ParamInterface::LOAD2_PARSE_FAILED) { error_message = "Invalid 'c:'"; return -1; }
+		opts.offset += 2;
+		ncparam.load(ParamInterface::FormatSingleLine, line, &opts);
+		if (opts.parse_failed) { error_message = "Invalid 'c:'"; return -1; }
 		bool n1_ok = false, n2_ok = false;
 		if ((n1_ok = ((c.n1_refno >= 0) && (c.n1_refno < getNeuroCount())))
@@ -741,6 +747,7 @@
 		Neuro *nu=new Neuro();
 		neuroitemparam.select(nu);
-		pos+=3;
-		if (neuroitemparam.load2(line,pos) & ParamInterface::LOAD2_PARSE_FAILED) {delete nu; return -1;}
+		opts.offset+=3;
+		neuroitemparam.loadSingleLine(line,opts);
+		if (opts.parse_failed) {delete nu; return -1;}
 		// illegal parent?
 		if ((nu->neuro_refno<0)||(nu->neuro_refno>=old_getNeuroCount()))
Index: cpp/frams/neuro/neuroimpl.cpp
===================================================================
--- cpp/frams/neuro/neuroimpl.cpp	(revision 719)
+++ cpp/frams/neuro/neuroimpl.cpp	(revision 720)
@@ -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.
 
@@ -14,28 +14,28 @@
 #endif
 
-const int NeuroImpl::ENDDRAWING=-9999;
-const int NeuroImpl::MAXDRAWINGXY=0xffff;
-
-int NeuroNetImpl::mytags_id=0;
+const int NeuroImpl::ENDDRAWING = -9999;
+const int NeuroImpl::MAXDRAWINGXY = 0xffff;
+
+int NeuroNetImpl::mytags_id = 0;
 
 /////////////////////////////////////////////////////////
 
 #define FIELDSTRUCT NeuroNetConfig
-static ParamEntry nncfg_paramtab[]=
-{
-{"Creature: Neurons",1,3,"nnsim",},
-{"randinit",1,0,"Random initialization","f 0 10 0.01",FIELD(randominit),"Allowed range for initializing all neuron states with uniform distribution random numbers and zero mean. Set to 0 for deterministic initialization."},
-{"nnoise",1,0,"Noise","f 0 1 0",FIELD(nnoise),"Gaussian neural noise: a random value is added to each neural output in each simulation step. Set standard deviation here to add random noise, or 0 for deterministic simulation."},
-{"touchrange",1,0,"T receptor range","f 0 100 1",FIELD(touchrange),},
-{0,0,0,},
-}; 
+static ParamEntry nncfg_paramtab[] =
+{
+	{ "Creature: Neurons", 1, 3, "nnsim", },
+	{ "randinit", 1, 0, "Random initialization", "f 0 10 0.01", FIELD(randominit), "Allowed range for initializing all neuron states with uniform distribution random numbers and zero mean. Set to 0 for deterministic initialization." },
+	{ "nnoise", 1, 0, "Noise", "f 0 1 0", FIELD(nnoise), "Gaussian neural noise: a random value is added to each neural output in each simulation step. Set standard deviation here to add random noise, or 0 for deterministic simulation." },
+	{ "touchrange", 1, 0, "T receptor range", "f 0 100 1", FIELD(touchrange), },
+	{ 0, 0, 0, },
+};
 #undef FIELDSTRUCT
 
 NeuroNetConfig::NeuroNetConfig(NeuroFactory *fac)
-	:par(nncfg_paramtab,this),
-	 randominit(0.01),
-	 nnoise(0),
-	 touchrange(1),
-	 factory(fac)
+	:par(nncfg_paramtab, this),
+	randominit(0.01),
+	nnoise(0),
+	touchrange(1),
+	factory(fac)
 {}
 
@@ -44,105 +44,111 @@
 NeuroNetImpl::NeuroNetImpl(Model& model, NeuroNetConfig& conf
 #ifdef NEURO_SIGNALS
-, ChannelSpace *ch
-#endif
-)
-	:mod(model),config(conf),
-	 isbuilt(1),errorcount(0)
+	, ChannelSpace *ch
+#endif
+	)
+	:mod(model), config(conf),
+	isbuilt(1), errorcount(0)
 #ifdef NEURO_SIGNALS
-,channels(ch)
-#endif
-{
-if (!mytags_id) mytags_id=mod.userdata.newID();
-
-Neuro *n;
-NeuroImpl *ni;
-Joint *j;
-int i;
-DB(printf("makeNeuroNet(%p)\n",&mod));
-
-minorder=3; maxorder=0;
-errorcount=0;
-
-for (i=0;j=mod.getJoint(i);i++)
-	j->flags&=~(4+8); // todo: !!!neuroitems shouldn't use model fields!!!
-
-for (i=0;n=mod.getNeuro(i);i++)
-	{
-	ni=conf.factory->createNeuroImpl(n);
-	n->userdata[mytags_id]=ni;
-	if (!ni) { errorcount++;
-		logPrintf("NeuroNetImpl","create",LOG_WARN,"neuron #%d (%s) implementation not available",
-			 i,n->getClassName().c_str());
-		continue; } // implementation not available?!
-	ni->owner=this;
-	ni->neuro=n;
-	ni->readParam();
-	}
-
-for (i=0;n=mod.getNeuro(i);i++)
-	{
-	n->state+=(rnd01-0.5)*config.randominit;
-	ni=(NeuroImpl*)n->userdata[mytags_id];
-	if (!ni) continue;
-	if (!ni->lateinit())
-		{ ni->status=NeuroImpl::InitError; errorcount++;
-		logPrintf("NeuroNetImpl","create",LOG_WARN,"neuron #%d (%s) initialization failed",
-			 i,n->getClassName().c_str());
-		continue; }
-	ni->status=NeuroImpl::InitOk;
-	int order=ni->getSimOrder();
-	if (order<0) order=0; else if (order>2) order=2;
-	if (order<minorder) minorder=order;
-	if (order>maxorder) maxorder=order;
-	neurons[order]+=ni;
-	if (ni->getNeedPhysics())
-		neurons[3]+=ni;
-	}
-cnode=mod.delmodel_list.add(STATRICKCALLBACK(this,&NeuroNetImpl::destroyNN,0));
+	, channels(ch)
+#endif
+{
+	if (!mytags_id) mytags_id = mod.userdata.newID();
+
+	Neuro *n;
+	NeuroImpl *ni;
+	Joint *j;
+	int i;
+	DB(printf("makeNeuroNet(%p)\n", &mod));
+
+	minorder = 3; maxorder = 0;
+	errorcount = 0;
+
+	for (i = 0; j = mod.getJoint(i); i++)
+		j->flags &= ~(4 + 8); // todo: !!!neuroitems shouldn't use model fields!!!
+
+	for (i = 0; n = mod.getNeuro(i); i++)
+	{
+		ni = conf.factory->createNeuroImpl(n);
+		n->userdata[mytags_id] = ni;
+		if (!ni)
+		{
+			errorcount++;
+			logPrintf("NeuroNetImpl", "create", LOG_WARN, "neuron #%d (%s) implementation not available",
+				i, n->getClassName().c_str());
+			continue;
+		} // implementation not available?!
+		ni->owner = this;
+		ni->neuro = n;
+		ni->readParam();
+	}
+
+	for (i = 0; n = mod.getNeuro(i); i++)
+	{
+		n->state += (rnd01 - 0.5)*config.randominit;
+		ni = (NeuroImpl*)n->userdata[mytags_id];
+		if (!ni) continue;
+		if (!ni->lateinit())
+		{
+			ni->status = NeuroImpl::InitError;
+			errorcount++;
+			logPrintf("NeuroNetImpl", "create", LOG_WARN, "neuron #%d (%s) initialization failed",
+				i, n->getClassName().c_str());
+			continue;
+		}
+		ni->status = NeuroImpl::InitOk;
+		int order = ni->getSimOrder();
+		if (order < 0) order = 0; else if (order>2) order = 2;
+		if (order < minorder) minorder = order;
+		if (order > maxorder) maxorder = order;
+		neurons[order] += ni;
+		if (ni->getNeedPhysics())
+			neurons[3] += ni;
+	}
+	cnode = mod.delmodel_list.add(STATRICKCALLBACK(this, &NeuroNetImpl::destroyNN, 0));
 }
 
 void NeuroNetImpl::destroyNN(CALLBACKARGS)
 {
-if (!isbuilt) return;
-DB(printf("destroyNeuroNet(%p)\n",&mod));
-NeuroImpl *ni;
-Neuro *n;
-for (int i=0;n=mod.getNeuro(i);i++)
-	{
-	ni=(NeuroImpl*)n->userdata[mytags_id];
-	delete ni;
-	n->userdata[mytags_id]=0;
-	}
-mod.delmodel_list.remove(cnode);
-isbuilt=0; errorcount=0;
-delete this;
+	if (!isbuilt) return;
+	DB(printf("destroyNeuroNet(%p)\n", &mod));
+	NeuroImpl *ni;
+	Neuro *n;
+	for (int i = 0; n = mod.getNeuro(i); i++)
+	{
+		ni = (NeuroImpl*)n->userdata[mytags_id];
+		delete ni;
+		n->userdata[mytags_id] = 0;
+	}
+	mod.delmodel_list.remove(cnode);
+	isbuilt = 0; errorcount = 0;
+	delete this;
 }
 
 NeuroNetImpl::~NeuroNetImpl()
 {
-destroyNN(0,0);
+	destroyNN(0, 0);
 }
 
 void NeuroNetImpl::simulateNeuroNet()
 {
-NeuroImpl *ni;
-for (int order=minorder;order<=maxorder;order++)
-	{
+	NeuroImpl *ni;
+	for (int order = minorder; order <= maxorder; order++)
+	{
+		int i;
+		SList &nlist = neurons[order];
+		for (i = 0; ni = (NeuroImpl*)nlist(i); i++)
+			ni->go();
+		for (i = 0; ni = (NeuroImpl*)nlist(i); i++)
+			ni->commit();
+	}
+}
+
+void NeuroNetImpl::simulateNeuroPhysics()
+{
+	NeuroImpl *ni;
 	int i;
-	SList &nlist=neurons[order];
-	for (i=0;ni=(NeuroImpl*)nlist(i);i++)
-		ni->go();
-	for (i=0;ni=(NeuroImpl*)nlist(i);i++)
-		ni->commit();
-	}
-}
-
-void NeuroNetImpl::simulateNeuroPhysics()
-{
-NeuroImpl *ni;
-int i;
-SList &nlist=neurons[3];
-for (i=0;ni=(NeuroImpl*)nlist(i);i++)
-	ni->goPhysics();
+	SList &nlist = neurons[3];
+	for (i = 0; ni = (NeuroImpl*)nlist(i); i++)
+		ni->goPhysics();
 }
 
@@ -151,59 +157,62 @@
 void NeuroImpl::setChannelCount(int c)
 {
-if (c<1) c=1;
-if (c==channels) return;
-if (c<channels) {channels=c; chstate.trim(c-1); chnewstate.trim(c-1); return;}
-double s=getState(channels-1);
-chnewstate.setSize(c-1);
-chstate.setSize(c-1);
-for(int i=channels;i<c;i++)
-	{chstate(i-1)=s; chnewstate(i-1)=s;}
-channels=c;
-}
-
-void NeuroImpl::setState(double st,int channel)
-{
-validateNeuroState(st);
-if (channel>=channels) channel=channels-1;
-if (channel<=0) {newstate=st;return;}
-chnewstate(channel-1)=st;
-}
-
-void NeuroImpl::setCurrentState(double st,int channel)
-{
-validateNeuroState(st);
-if (channel>=channels) channel=channels-1;
-if (channel<=0) {neuro->state=st; return;}
-chstate(channel-1)=st;
+	if (c < 1) c = 1;
+	if (c == channels) return;
+	if (c < channels) { channels = c; chstate.trim(c - 1); chnewstate.trim(c - 1); return; }
+	double s = getState(channels - 1);
+	chnewstate.setSize(c - 1);
+	chstate.setSize(c - 1);
+	for (int i = channels; i < c; i++)
+	{
+		chstate(i - 1) = s;
+		chnewstate(i - 1) = s;
+	}
+	channels = c;
+}
+
+void NeuroImpl::setState(double st, int channel)
+{
+	validateNeuroState(st);
+	if (channel >= channels) channel = channels - 1;
+	if (channel <= 0) { newstate = st; return; }
+	chnewstate(channel - 1) = st;
+}
+
+void NeuroImpl::setCurrentState(double st, int channel)
+{
+	validateNeuroState(st);
+	if (channel >= channels) channel = channels - 1;
+	if (channel <= 0) { neuro->state = st; return; }
+	chstate(channel - 1) = st;
 }
 
 double NeuroImpl::getNewState(int channel)
 {
-if (neuro->flags&Neuro::HoldState) return getState(channel);
-if (channel>=channels) channel=channels-1;
-if (channel<=0) {return newstate;}
-return chnewstate(channel-1);
+	if (neuro->flags&Neuro::HoldState) return getState(channel);
+	if (channel >= channels) channel = channels - 1;
+	if (channel <= 0) { return newstate; }
+	return chnewstate(channel - 1);
 }
 
 double NeuroImpl::getState(int channel)
 {
-if (channel>=channels) channel=channels-1;
-if (channel<=0) return neuro->state;
-return chstate(channel-1);
+	if (channel >= channels) channel = channels - 1;
+	if (channel <= 0) return neuro->state;
+	return chstate(channel - 1);
 }
 
 void NeuroImpl::commit()
 {
-if (!(neuro->flags&Neuro::HoldState))
-	{
-	if (channels>1)
-		chstate=chnewstate;
-	neuro->state=newstate;
-	if (owner->getConfig().nnoise>0.0)
+	if (!(neuro->flags&Neuro::HoldState))
+	{
+		if (channels > 1)
+			chstate = chnewstate;
+		neuro->state = newstate;
+		if (owner->getConfig().nnoise > 0.0)
 		{
-		neuro->state+=RndGen.GaussStd()*owner->getConfig().nnoise;
-		if (channels>1)
-			for(int i=0;i<chstate.size();i++)
-				chstate(0)+=RndGen.GaussStd()*owner->getConfig().nnoise;
+			neuro->state += RndGen.GaussStd()*owner->getConfig().nnoise;
+			if (channels > 1)
+				for (int i = 0; i < chstate.size(); i++)
+					chstate(0) += RndGen.GaussStd()*owner->getConfig().nnoise;
 		}
 	}
@@ -212,72 +221,71 @@
 int NeuroImpl::getInputChannelCount(int i)
 {
-if ((i<0)||(i >= neuro->getInputCount())) return 1;
-Neuro *nu=neuro->getInput(i);
-NeuroImpl *ni=NeuroNetImpl::getImpl(nu);
-if (!ni) return 1;
-return ni->channels;
-}
-
-double NeuroImpl::getInputState(int i,int channel)
-{
-if ((i<0)||(i >= neuro->getInputCount())) return 0;
-Neuro *nu=neuro->getInput(i);
-if (channel<=0) return nu->state;
-NeuroImpl *ni=NeuroNetImpl::getImpl(nu);
-if (!ni) return nu->state;
-if (channel>=ni->channels) channel=ni->channels-1;
-if (!channel) return nu->state;
-return ni->chstate(channel-1);
+	if ((i < 0) || (i >= neuro->getInputCount())) return 1;
+	Neuro *nu = neuro->getInput(i);
+	NeuroImpl *ni = NeuroNetImpl::getImpl(nu);
+	if (!ni) return 1;
+	return ni->channels;
+}
+
+double NeuroImpl::getInputState(int i, int channel)
+{
+	if ((i < 0) || (i >= neuro->getInputCount())) return 0;
+	Neuro *nu = neuro->getInput(i);
+	if (channel <= 0) return nu->state;
+	NeuroImpl *ni = NeuroNetImpl::getImpl(nu);
+	if (!ni) return nu->state;
+	if (channel >= ni->channels) channel = ni->channels - 1;
+	if (!channel) return nu->state;
+	return ni->chstate(channel - 1);
 }
 
 double NeuroImpl::getWeightedInputState(int i, int channel)
 {
-if ((i<0)||(i >= neuro->getInputCount())) return 0;
-double w;
-Neuro *nu=neuro->getInput(i,w);
-if (channel<=0) return nu->state * w;
-NeuroImpl *ni=NeuroNetImpl::getImpl(nu);
-if (!ni) return nu->state * w;
-if (channel>=ni->channels) channel=ni->channels-1;
-if (!channel) return w * nu->state;
-return w * ni->chstate(channel-1);
+	if ((i < 0) || (i >= neuro->getInputCount())) return 0;
+	double w;
+	Neuro *nu = neuro->getInput(i, w);
+	if (channel <= 0) return nu->state * w;
+	NeuroImpl *ni = NeuroNetImpl::getImpl(nu);
+	if (!ni) return nu->state * w;
+	if (channel >= ni->channels) channel = ni->channels - 1;
+	if (!channel) return w * nu->state;
+	return w * ni->chstate(channel - 1);
 }
 
 double NeuroImpl::getInputSum(int startwith)
 {
-if (startwith<0) return 0;
-Neuro *inp;
-double sum=0.0;
-while(inp=neuro->getInput(startwith++))
-	sum+=inp->state;
-return sum;
+	if (startwith < 0) return 0;
+	Neuro *inp;
+	double sum = 0.0;
+	while (inp = neuro->getInput(startwith++))
+		sum += inp->state;
+	return sum;
 }
 
 double NeuroImpl::getWeightedInputSum(int startwith)
 {
-if (startwith<0) return 0;
-Neuro *inp;
-double sum=0.0;
-double w;
-while(inp=neuro->getInput(startwith++,w))
-	sum+=inp->state*w;
-return sum;
+	if (startwith < 0) return 0;
+	Neuro *inp;
+	double sum = 0.0;
+	double w;
+	while (inp = neuro->getInput(startwith++, w))
+		sum += inp->state*w;
+	return sum;
 }
 
 void NeuroImpl::readParam()
 {
-Param par;
-if (!paramentries) return;
-par.setParamTab(paramentries);
-par.select(this);
-par.setDefault();
-int zero=0;
-par.load2(neuro->getClassParams(),zero);
+	Param par;
+	if (!paramentries) return;
+	par.setParamTab(paramentries);
+	par.select(this);
+	par.setDefault();
+	par.load(ParamInterface::FormatSingleLine, neuro->getClassParams());
 }
 
 Param& NeuroImpl::getStaticParam()
 {
-static Param p(neuroimpl_tab,0,"Neuro");
-return p;
+	static Param p(neuroimpl_tab, 0, "Neuro");
+	return p;
 }
 
@@ -291,168 +299,168 @@
 
 #define FIELDSTRUCT NeuroImpl
-ParamEntry neuroimpl_tab[]=
-{
-{"Neuro",1,27+NEUROIMPL_SIGNAL_PROPS,"Neuro","Live Neuron object."},
-
-{"getInputState",0,0,"Get input signal","p f(d input)",PROCEDURE(p_get),},
-{"getInputWeight",0,0,"Get input weight","p f(d input)",PROCEDURE(p_getweight),},
-{"getWeightedInputState",0,0,"Get weighted input signal","p f(d input)",PROCEDURE(p_getw),},
-{"getInputSum",0,0,"Get signal sum","p f(d input)",PROCEDURE(p_getsum),},
-{"getWeightedInputSum",0,0,"Get weighted signal sum","p f(d input)",PROCEDURE(p_getwsum),"Uses any number of inputs starting with the specified input. getWeightedInputSum(0)=weightedInputSum"},
-{"getInputCount",0,PARAM_READONLY,"Get input count","d",GETONLY(count),},
-{"inputSum",0,PARAM_READONLY,"Full signal sum","f",GETONLY(sum),},
-{"weightedInputSum",0,PARAM_READONLY,"Full weighted signal sum","f",GETONLY(wsum),},
-{"getInputChannelCount",0,0,"Get channel count for input","p d(d input)",PROCEDURE(p_getchancount),},
-{"getInputStateChannel",0,0,"Get input signal from channel","p f(d input,d channel)",PROCEDURE(p_getchan),},
-{"getWeightedInputStateChannel",0,0,"Get weighted input signal from channel","p f(d input,d channel)",PROCEDURE(p_getwchan),},
-{"state",0,0,"Neuron state (channel 0)","f",GETSET(state),"When read, returns the current neuron state.\nWhen written, sets the 'internal' neuron state that will become current in the next step.\nTypically you should use this field, and not currState."},
-{"channelCount",0,0,"Number of output channels","d",GETSET(channels),},
-{"getStateChannel",0,0,"Get state for channel","p f(d channel)",PROCEDURE(p_getstate),},
-{"setStateChannel",0,0,"Set state for channel","p(d channel,f value)",PROCEDURE(p_setstate),},
-{"hold",0,0,"Hold state","d 0 1",GETSET(hold),"\"Holding\" means keeping the neuron state as is, blocking the regular neuron operation. This is useful when your script needs to inject some control signals into the NN. Without \"holding\", live neurons would be constantly overwriting your changes, and the rest of the NN could see inconsistent states, depending on the connections. Setting hold=1 ensures the neuron state will be only set by you, and not by the neuron. The enforced signal value can be set using Neuro.currState before or after setting hold=1. Set hold=0 to resume normal operation.",},
-{"currState",0,0,"Current neuron state (channel 0)","f",GETSET(cstate),"When read, it behaves just like the 'state' field.\nWhen written, changes the current neuron state immediately, which disturbs the regular synchronous NN operation.\nThis feature should only be used while controlling the neuron 'from outside' (like a neuro probe) and not in the neuron definition. See also: Neuro.hold",},
-{"setCurrStateChannel",0,0,"Set current neuron state for channel","p(d channel,f value)",PROCEDURE(p_setcstate),"Analogous to \"currState\"."},
-{"position_x",0,PARAM_READONLY,"Position x","f",GETONLY(position_x),},
-{"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),
-"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"
-"var c=Populations.createFromString(\"X[N]\");\n"
-"Simulator.print(\"standard neuron inertia=\"+c.getNeuro(0).neuroproperties.in);\n"
-"c=Populations.createFromString(\"X[Nn,e:0.1]\");\n"
-"Simulator.print(\"noisy neuron error rate=\"+c.getNeuro(0).neuroproperties.e);\n"
-"\n"
-"The Interface object can be used to discover which fields are available for a certain neuron object:\n"
-"c=Populations.createFromString(\"X[N]\");\n"
-"var iobj=Interface.makeFrom(c.getNeuro(0).neuroproperties);\n"
-"var i;\n"
-"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),},
+ParamEntry neuroimpl_tab[] =
+{
+	{ "Neuro", 1, 27 + NEUROIMPL_SIGNAL_PROPS, "Neuro", "Live Neuron object." },
+
+	{ "getInputState", 0, 0, "Get input signal", "p f(d input)", PROCEDURE(p_get), },
+	{ "getInputWeight", 0, 0, "Get input weight", "p f(d input)", PROCEDURE(p_getweight), },
+	{ "getWeightedInputState", 0, 0, "Get weighted input signal", "p f(d input)", PROCEDURE(p_getw), },
+	{ "getInputSum", 0, 0, "Get signal sum", "p f(d input)", PROCEDURE(p_getsum), },
+	{ "getWeightedInputSum", 0, 0, "Get weighted signal sum", "p f(d input)", PROCEDURE(p_getwsum), "Uses any number of inputs starting with the specified input. getWeightedInputSum(0)=weightedInputSum" },
+	{ "getInputCount", 0, PARAM_READONLY, "Get input count", "d", GETONLY(count), },
+	{ "inputSum", 0, PARAM_READONLY, "Full signal sum", "f", GETONLY(sum), },
+	{ "weightedInputSum", 0, PARAM_READONLY, "Full weighted signal sum", "f", GETONLY(wsum), },
+	{ "getInputChannelCount", 0, 0, "Get channel count for input", "p d(d input)", PROCEDURE(p_getchancount), },
+	{ "getInputStateChannel", 0, 0, "Get input signal from channel", "p f(d input,d channel)", PROCEDURE(p_getchan), },
+	{ "getWeightedInputStateChannel", 0, 0, "Get weighted input signal from channel", "p f(d input,d channel)", PROCEDURE(p_getwchan), },
+	{ "state", 0, 0, "Neuron state (channel 0)", "f", GETSET(state), "When read, returns the current neuron state.\nWhen written, sets the 'internal' neuron state that will become current in the next step.\nTypically you should use this field, and not currState." },
+	{ "channelCount", 0, 0, "Number of output channels", "d", GETSET(channels), },
+	{ "getStateChannel", 0, 0, "Get state for channel", "p f(d channel)", PROCEDURE(p_getstate), },
+	{ "setStateChannel", 0, 0, "Set state for channel", "p(d channel,f value)", PROCEDURE(p_setstate), },
+	{ "hold", 0, 0, "Hold state", "d 0 1", GETSET(hold), "\"Holding\" means keeping the neuron state as is, blocking the regular neuron operation. This is useful when your script needs to inject some control signals into the NN. Without \"holding\", live neurons would be constantly overwriting your changes, and the rest of the NN could see inconsistent states, depending on the connections. Setting hold=1 ensures the neuron state will be only set by you, and not by the neuron. The enforced signal value can be set using Neuro.currState before or after setting hold=1. Set hold=0 to resume normal operation.", },
+	{ "currState", 0, 0, "Current neuron state (channel 0)", "f", GETSET(cstate), "When read, it behaves just like the 'state' field.\nWhen written, changes the current neuron state immediately, which disturbs the regular synchronous NN operation.\nThis feature should only be used while controlling the neuron 'from outside' (like a neuro probe) and not in the neuron definition. See also: Neuro.hold", },
+	{ "setCurrStateChannel", 0, 0, "Set current neuron state for channel", "p(d channel,f value)", PROCEDURE(p_setcstate), "Analogous to \"currState\"." },
+	{ "position_x", 0, PARAM_READONLY, "Position x", "f", GETONLY(position_x), },
+	{ "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),
+	"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"
+	"var c=Populations.createFromString(\"X[N]\");\n"
+	"Simulator.print(\"standard neuron inertia=\"+c.getNeuro(0).neuroproperties.in);\n"
+	"c=Populations.createFromString(\"X[Nn,e:0.1]\");\n"
+	"Simulator.print(\"noisy neuron error rate=\"+c.getNeuro(0).neuroproperties.e);\n"
+	"\n"
+	"The Interface object can be used to discover which fields are available for a certain neuron object:\n"
+	"c=Populations.createFromString(\"X[N]\");\n"
+	"var iobj=Interface.makeFrom(c.getNeuro(0).neuroproperties);\n"
+	"var i;\n"
+	"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), },
 #ifdef NEURO_SIGNALS
-{"signals",0,PARAM_READONLY,"Signals","o NeuroSignals",FIELD(sigs_obj),},
-#endif
-
-{0,0,0,},
+	{ "signals", 0, PARAM_READONLY, "Signals", "o NeuroSignals", FIELD(sigs_obj), },
+#endif
+
+	{ 0, 0, 0, },
 };
 #undef FIELDSTRUCT
 
 #ifdef NEURO_SIGNALS
-ParamEntry neurosignals_paramtab[]=
- {
-{"NeuroSignals",1,8,"NeuroSignals","Signals attached to a neuron.\nSee also: Signal, WorldSignals, CreatureSignals.\nscripts/light.neuro and scripts/seelight.neuro are simple custom neuron examples demonstrating how to send/receive signals between creatures.",},
+ParamEntry neurosignals_paramtab[] =
+{
+	{ "NeuroSignals", 1, 8, "NeuroSignals", "Signals attached to a neuron.\nSee also: Signal, WorldSignals, CreatureSignals.\nscripts/light.neuro and scripts/seelight.neuro are simple custom neuron examples demonstrating how to send/receive signals between creatures.", },
 
 #define FIELDSTRUCT NeuroSignals
-SIGNPAR_ADD(""),
-SIGNPAR_RECEIVE(""),
-SIGNPAR_RECEIVESET(""),
-SIGNPAR_RECEIVEFILTER(""),
-SIGNPAR_RECEIVESINGLE(""),
+	SIGNPAR_ADD(""),
+	SIGNPAR_RECEIVE(""),
+	SIGNPAR_RECEIVESET(""),
+	SIGNPAR_RECEIVEFILTER(""),
+	SIGNPAR_RECEIVESINGLE(""),
 #undef FIELDSTRUCT
 
 #define FIELDSTRUCT SignalSet
-SIGNSETPAR_GET,
-SIGNSETPAR_SIZE,
-SIGNSETPAR_CLEAR,
+	SIGNSETPAR_GET,
+	SIGNSETPAR_SIZE,
+	SIGNSETPAR_CLEAR,
 #undef FIELDSTRUCT
-{0,0,0,},
- }; 
+	{ 0, 0, 0, },
+};
 
 Param& NeuroSignals::getStaticParam()
 {
-static Param p(neurosignals_paramtab,0);
-return p;
+	static Param p(neurosignals_paramtab, 0);
+	return p;
 }
 #endif
 
 #ifdef NEURO_SIGNALS
-class NeuroSigSource: public SigSource
-{
-  protected:
-NeuroImpl* owner;
-  public:
-NeuroSigSource(NeuroImpl *n,Creature *c):SigSource(0,c),owner(n) {}
-bool update();
+class NeuroSigSource : public SigSource
+{
+protected:
+	NeuroImpl* owner;
+public:
+	NeuroSigSource(NeuroImpl *n, Creature *c) :SigSource(0, c), owner(n) {}
+	bool update();
 };
 
 bool NeuroSigSource::update()
 {
-Pt3D p;
-if (owner->getPosition(p))
-	{
-	setLocation(p);
-	return true;
-	}
-return false;
+	Pt3D p;
+	if (owner->getPosition(p))
+	{
+		setLocation(p);
+		return true;
+	}
+	return false;
 }
 
 Creature *NeuroSignals::getCreature()
 {
-if (!cr)
-	{
-	cr=owner->getCreature();
-	}
-return cr;
+	if (!cr)
+	{
+		cr = owner->getCreature();
+	}
+	return cr;
 }
 
 void NeuroSignals::p_add(PARAMPROCARGS)
 {
-SigSource *s=new NeuroSigSource(owner,getCreature());
-if (owner->owner->channels)
-	{
-	SigChannel *ch=owner->owner->channels->getChannel(args->getString(),true);
-	ch->addSource(s);
-	}
-else
-	SigChannel::dummy_channel.addSource(s);
-sigs+=s;
-s->setupObject(ret);
+	SigSource *s = new NeuroSigSource(owner, getCreature());
+	if (owner->owner->channels)
+	{
+		SigChannel *ch = owner->owner->channels->getChannel(args->getString(), true);
+		ch->addSource(s);
+	}
+	else
+		SigChannel::dummy_channel.addSource(s);
+	sigs += s;
+	s->setupObject(ret);
 }
 
 void NeuroSignals::p_receive(PARAMPROCARGS)
 {
-SigChannel *ch; Pt3D p;
-if (owner->owner->channels && (ch=owner->owner->channels->getChannel(args->getString(),false)) && owner->getPosition(p))
-	ret->setDouble(ch->receive(&p,getCreature()));
-else
-	ret->setDouble(0);
+	SigChannel *ch; Pt3D p;
+	if (owner->owner->channels && (ch = owner->owner->channels->getChannel(args->getString(), false)) && owner->getPosition(p))
+		ret->setDouble(ch->receive(&p, getCreature()));
+	else
+		ret->setDouble(0);
 }
 
 void NeuroSignals::p_receiveFilter(PARAMPROCARGS)
 {
-SigChannel *ch; Pt3D p;
-if (owner->owner->channels && (ch=owner->owner->channels->getChannel(args[3].getString(),false)) && owner->getPosition(p))
-	ret->setDouble(ch->receive(&p,getCreature(),args[2].getDouble(),args[1].getDouble(),args[0].getDouble()));
-else
-	ret->setDouble(0);
+	SigChannel *ch; Pt3D p;
+	if (owner->owner->channels && (ch = owner->owner->channels->getChannel(args[3].getString(), false)) && owner->getPosition(p))
+		ret->setDouble(ch->receive(&p, getCreature(), args[2].getDouble(), args[1].getDouble(), args[0].getDouble()));
+	else
+		ret->setDouble(0);
 }
 
 void NeuroSignals::p_receiveSet(PARAMPROCARGS)
 {
-SigChannel *ch; Pt3D p;
-SigVector *vec=new SigVector();
-if (owner->owner->channels && (ch=owner->owner->channels->getChannel(args[1].getString(),false)) && owner->getPosition(p))
-	ch->receiveSet(vec,&p,getCreature(),args[0].getDouble());
-ret->setObject(vec->makeObject());
+	SigChannel *ch; Pt3D p;
+	SigVector *vec = new SigVector();
+	if (owner->owner->channels && (ch = owner->owner->channels->getChannel(args[1].getString(), false)) && owner->getPosition(p))
+		ch->receiveSet(vec, &p, getCreature(), args[0].getDouble());
+	ret->setObject(vec->makeObject());
 }
 
 void NeuroSignals::p_receiveSingle(PARAMPROCARGS)
 {
-SigChannel *ch; Pt3D p;
-if (owner->owner->channels && (ch=owner->owner->channels->getChannel(args[1].getString(),false)) && owner->getPosition(p))
-	{
-	SigSource *src=ch->receiveSingle(&p,getCreature(),args[0].getDouble(),0,1e99);
-	if (src)
+	SigChannel *ch; Pt3D p;
+	if (owner->owner->channels && (ch = owner->owner->channels->getChannel(args[1].getString(), false)) && owner->getPosition(p))
+	{
+		SigSource *src = ch->receiveSingle(&p, getCreature(), args[0].getDouble(), 0, 1e99);
+		if (src)
 		{
-		src->setupObject(ret);
-		return;
+			src->setupObject(ret);
+			return;
 		}
 	}
-ret->setEmpty();
+	ret->setEmpty();
 }
 #endif
@@ -460,5 +468,5 @@
 #ifndef SDK_WITHOUT_FRAMS
 extern ParamEntry creature_paramtab[];
-static Param creature_param(creature_paramtab,0);
+static Param creature_param(creature_paramtab, 0);
 #endif
 
@@ -466,8 +474,8 @@
 {
 #ifndef SDK_WITHOUT_FRAMS
-CreatMechObject *cmo=(CreatMechObject *)neuro->owner->userdata[CreatMechObject::modeltags_id];
-return cmo->creature;
+	CreatMechObject *cmo = (CreatMechObject *)neuro->owner->userdata[CreatMechObject::modeltags_id];
+	return cmo->creature;
 #else
-return 0;
+	return 0;
 #endif
 }
@@ -476,5 +484,5 @@
 {
 #ifndef SDK_WITHOUT_FRAMS
-ret->setObject(ExtObject(&creature_param,getCreature()));
+	ret->setObject(ExtObject(&creature_param, getCreature()));
 #endif
 }
@@ -483,9 +491,9 @@
 {
 #ifndef SDK_WITHOUT_FRAMS
-Part *pa;
-if (pa=neuro->getPart())
-	ret->setObject(ExtObject(&MechPart::getStaticParam(),((MechPart *)pa->userdata[CreatMechObject::modeltags_id])));
-else
-	ret->setEmpty();
+	Part *pa;
+	if (pa = neuro->getPart())
+		ret->setObject(ExtObject(&MechPart::getStaticParam(), ((MechPart *)pa->userdata[CreatMechObject::modeltags_id])));
+	else
+		ret->setEmpty();
 #endif
 }
@@ -494,9 +502,9 @@
 {
 #ifndef SDK_WITHOUT_FRAMS
-Joint *jo;
-if (jo=neuro->getJoint())
-	ret->setObject(ExtObject(&MechJoint::getStaticParam(),((MechJoint*)jo->userdata[CreatMechObject::modeltags_id])));
-else
-	ret->setEmpty();
+	Joint *jo;
+	if (jo = neuro->getJoint())
+		ret->setObject(ExtObject(&MechJoint::getStaticParam(), ((MechJoint*)jo->userdata[CreatMechObject::modeltags_id])));
+	else
+		ret->setEmpty();
 #endif
 }
@@ -505,45 +513,57 @@
 {
 #ifndef SDK_WITHOUT_FRAMS
-Part *pa; Joint *jo;
-if (pa=neuro->getPart())
-	{pos=((MechPart *)pa->userdata[CreatMechObject::modeltags_id])->p; return true;}
-if (jo=neuro->getJoint())
-	{
-	if (neuro->getClass()->getVisualHints() & NeuroClass::AtFirstPart)
-		pos=((MechPart*)jo->part1->userdata[CreatMechObject::modeltags_id])->p;
-	else if (neuro->getClass()->getVisualHints() & NeuroClass::AtSecondPart)
-		pos=((MechPart*)jo->part2->userdata[CreatMechObject::modeltags_id])->p;
-	else pos=(((MechPart*)jo->part1->userdata[CreatMechObject::modeltags_id])->p
-		   +((MechPart*)jo->part2->userdata[CreatMechObject::modeltags_id])->p)/2;
-	return true;
-	}
-#endif
-return false;
+	Part *pa; Joint *jo;
+	if (pa = neuro->getPart())
+	{
+		pos = ((MechPart *)pa->userdata[CreatMechObject::modeltags_id])->p;
+		return true;
+	}
+	if (jo = neuro->getJoint())
+	{
+		if (neuro->getClass()->getVisualHints() & NeuroClass::AtFirstPart)
+			pos = ((MechPart*)jo->part1->userdata[CreatMechObject::modeltags_id])->p;
+		else if (neuro->getClass()->getVisualHints() & NeuroClass::AtSecondPart)
+			pos = ((MechPart*)jo->part2->userdata[CreatMechObject::modeltags_id])->p;
+		else pos = (((MechPart*)jo->part1->userdata[CreatMechObject::modeltags_id])->p
+			+ ((MechPart*)jo->part2->userdata[CreatMechObject::modeltags_id])->p) / 2;
+		return true;
+	}
+#endif
+	return false;
 }
 
 void NeuroImpl::get_position_x(ExtValue *ret)
-{Pt3D pos; if (getPosition(pos)) ret->setDouble(pos.x); else ret->setEmpty();}
+{
+	Pt3D pos;
+	if (getPosition(pos)) ret->setDouble(pos.x); else ret->setEmpty();
+}
 void NeuroImpl::get_position_y(ExtValue *ret)
-{Pt3D pos; if (getPosition(pos)) ret->setDouble(pos.y); else ret->setEmpty();}
+{
+	Pt3D pos;
+	if (getPosition(pos)) ret->setDouble(pos.y); else ret->setEmpty();
+}
 void NeuroImpl::get_position_z(ExtValue *ret)
-{Pt3D pos; if (getPosition(pos)) ret->setDouble(pos.z); else ret->setEmpty();}
+{
+	Pt3D pos;
+	if (getPosition(pos)) ret->setDouble(pos.z); else ret->setEmpty();
+}
 
 
 void NeuroImpl::createFieldsObject()
 {
-fields_param=new Param(paramentries?paramentries:(ParamEntry*)&empty_paramtab,this,"NeuroProperties");
-fields_object=new ExtObject(fields_param);
+	fields_param = new Param(paramentries ? paramentries : (ParamEntry*)&empty_paramtab, this, "NeuroProperties");
+	fields_object = new ExtObject(fields_param);
 }
 
 void NeuroImpl::get_fields(ExtValue *ret)
 {
-if (!fields_object)
-	createFieldsObject();
-ret->setObject(*fields_object);
+	if (!fields_object)
+		createFieldsObject();
+	ret->setObject(*fields_object);
 }
 
 void NeuroImpl::get_neurodef(ExtValue *ret)
 {
-ret->setObject(ExtObject(&Neuro::getStaticParam(),neuro));
+	ret->setObject(ExtObject(&Neuro::getStaticParam(), neuro));
 }
 
@@ -551,5 +571,5 @@
 {
 #ifndef SDK_WITHOUT_FRAMS
-NeuroClassExt::makeStaticObject(ret,neuroclass);
+	NeuroClassExt::makeStaticObject(ret, neuroclass);
 #endif
 }
@@ -557,8 +577,8 @@
 NeuroImpl::~NeuroImpl()
 {
-if (fields_param)
-	{
-	delete fields_param;
-	delete fields_object;
-	}
-}
+	if (fields_param)
+	{
+		delete fields_param;
+		delete fields_object;
+	}
+}
Index: cpp/frams/param/multiparamload.cpp
===================================================================
--- cpp/frams/param/multiparamload.cpp	(revision 719)
+++ cpp/frams/param/multiparamload.cpp	(revision 720)
@@ -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,33 +10,33 @@
 void MultiParamLoader::init()
 {
-file=0; ownfile=0;
-status=0;
-reset();
+	file = 0; ownfile = 0;
+	status = 0;
+	reset();
 }
 
 void MultiParamLoader::reset()
 {
-status=0;
-breakcond=OnError;
-aborting=false;
-emptyparam.setParamTab(empty_paramtab);
-linenum=0;
+	status = 0;
+	breakcond = OnError;
+	aborting = false;
+	emptyparam.setParamTab(empty_paramtab);
+	linenum = 0;
 }
 
 int MultiParamLoader::findObject(const ExtObject &o)
 {
-for(int i=0;i<objects.size();i++)
-	if ((*objects(i))==o)
-		return i;
-return -1;
+	for (int i = 0; i < objects.size(); i++)
+		if ((*objects(i)) == o)
+			return i;
+	return -1;
 }
 
 void MultiParamLoader::removeObject(const ExtObject &o)
 {
-int i=findObject(o);
-if (i>=0)
-	{
-	delete objects(i);
-	objects-=i;
+	int i = findObject(o);
+	if (i >= 0)
+	{
+		delete objects(i);
+		objects -= i;
 	}
 }
@@ -44,204 +44,208 @@
 void MultiParamLoader::clearObjects()
 {
-FOREACH(ExtObject*,o,objects)
-	delete o;
-objects.clear();
+	FOREACH(ExtObject*, o, objects)
+		delete o;
+	objects.clear();
 }
 
 void MultiParamLoader::load()
 {
-clearstack();
-if (!file)
-	{
-	lasterror="can't open file";
-	status=OnError;
-	return;
-	}
-status=Loading;
-aborting=false;
+	clearstack();
+	if (!file)
+	{
+		lasterror = "can't open file";
+		status = OnError;
+		return;
+	}
+	status = Loading;
+	aborting = false;
 }
 
 void MultiParamLoader::abort()
 {
-if (file && ownfile)
-	{
-	delete file;
-	file=0;
-	}
-clearstack();
-status=Finished;
-aborting=true;
+	if (file && ownfile)
+	{
+		delete file;
+		file = 0;
+	}
+	clearstack();
+	status = Finished;
+	aborting = true;
 }
 
 void MultiParamLoader::load(VirtFILE *f)
 {
-abort();
-ownfile=0;
-file=f;
-load();
+	abort();
+	ownfile = 0;
+	file = f;
+	load();
 }
 
 void MultiParamLoader::load(const char* filename)
 {
-abort();
-ownfile=1;
-file=Vfopen(filename,FOPEN_READ_BINARY);
-load();
+	abort();
+	ownfile = 1;
+	file = Vfopen(filename, FOPEN_READ_BINARY);
+	load();
 }
 
 int MultiParamLoader::go()
 {
-SString buf;
-if (status==OnError) return status;
-int unexpected_line = 0;
-while (!finished())
-	{
-	if ((status==BeforeObject) || ((status==BeforeUnknown) && !lastobject.isEmpty()))
-		{
-		Param tmp_param;
-		ParamInterface *pi=lastobject.getParamInterface(tmp_param);
-		pi->load(file,true,&aborting,&linenum);
-		if ((status!=Finished) && maybeBreak(AfterObject))
-			break;
-		unexpected_line = 0;
-		continue;
-		}
-	else if (status==BeforeUnknown)
-		{
-		logPrintf("MultiParamLoader","go",LOG_WARN,"Skipping object '%s'",lastunknown.c_str());
-		loadObjectNow(&emptyparam,false);
-		continue;
-		}
-	if (!loadSStringLine(file,buf))
-		{
-		unexpected_line = 0;
-		if (!returnFromIncluded())
-			{
-			abort();
-			break;
-			}
-		else
+	SString buf;
+	if (status == OnError) return status;
+	int unexpected_line = 0;
+	while (!finished())
+	{
+		if ((status == BeforeObject) || ((status == BeforeUnknown) && !lastobject.isEmpty()))
+		{
+			Param tmp_param;
+			ParamInterface *pi = lastobject.getParamInterface(tmp_param);
+			ParamInterface::LoadOptions opts;
+			opts.abortable = &aborting;
+			opts.warn_unknown_fields = true;
+			opts.linenum = &linenum;
+			pi->load(ParamInterface::FormatMultiLine, file, &opts);
+			if ((status != Finished) && maybeBreak(AfterObject))
+				break;
+			unexpected_line = 0;
 			continue;
 		}
-	linenum++;
-	if (buf[0]=='#')
-		{
-		unexpected_line = 0;
-		if (buf.startsWith("#include"))
-			{
-			const char* t=strchr(buf.c_str(),'\"'),*t2=0;
-			if (t)
-				t2=strchr(t+1,'\"');
-			if (t2)
+		else if (status == BeforeUnknown)
+		{
+			logPrintf("MultiParamLoader", "go", LOG_WARN, "Skipping object '%s'", lastunknown.c_str());
+			loadObjectNow(&emptyparam, false);
+			continue;
+		}
+		if (!loadSStringLine(file, buf))
+		{
+			unexpected_line = 0;
+			if (!returnFromIncluded())
+			{
+				abort();
+				break;
+			}
+			else
+				continue;
+		}
+		linenum++;
+		if (buf[0] == '#')
+		{
+			unexpected_line = 0;
+			if (buf.startsWith("#include"))
+			{
+				const char* t = strchr(buf.c_str(), '\"'), *t2 = 0;
+				if (t)
+					t2 = strchr(t + 1, '\"');
+				if (t2)
 				{
-				SString filename(t+1,t2-t-1);
-				includeFile(filename);
+					SString filename(t + 1, t2 - t - 1);
+					includeFile(filename);
 				}
-			else
+				else
 				{
-				const char* thisfilename=file->VgetPath();
-				logPrintf("MultiParamLoader","go",LOG_WARN,"invalid \"%s\"%s%s",buf.c_str(),
-					 (thisfilename?" in ":""),(thisfilename?thisfilename:""));
+					const char* thisfilename = file->VgetPath();
+					logPrintf("MultiParamLoader", "go", LOG_WARN, "invalid \"%s\"%s%s", buf.c_str(),
+						(thisfilename ? " in " : ""), (thisfilename ? thisfilename : ""));
 				}
+				continue;
+			}
+			else if ((status != Finished) && maybeBreak(OnComment))
+			{
+				lastcomment = buf.substr(1);
+				break;
+			}
 			continue;
-			}
-		else if ((status!=Finished) && maybeBreak(OnComment))
-			{
-			lastcomment=buf.substr(1);
-			break;
-			}
-		continue;
-		}
-	buf=trim(buf);
-	if (buf.len()==0)
-		unexpected_line = 0;
-	else if ((buf.len()>1)&&(buf[buf.len()-1]==':'))
-		{
-		unexpected_line = 0;
-		lastunknown=0;
-		lastunknown=buf.substr(0,buf.len()-1);
-		lastobject.setEmpty();
-		FOREACH(ExtObject*,o,objects)
-			{
-			if (!strcmp(o->interfaceName(),lastunknown.c_str())) {lastobject=*o; break;}
+		}
+		buf = trim(buf);
+		if (buf.len() == 0)
+			unexpected_line = 0;
+		else if ((buf.len() > 1) && (buf[buf.len() - 1] == ':'))
+		{
+			unexpected_line = 0;
+			lastunknown = 0;
+			lastunknown = buf.substr(0, buf.len() - 1);
+			lastobject.setEmpty();
+			FOREACH(ExtObject*, o, objects)
+			{
+				if (!strcmp(o->interfaceName(), lastunknown.c_str())) { lastobject = *o; break; }
 			}
 			if (!lastobject.isEmpty())
-				{
+			{
 				if (maybeBreak(BeforeObject))
 					break;
-				}
+			}
 			else
-				{
+			{
 				if (maybeBreak(BeforeUnknown))
 					break;
-				}
-		
-		}
+			}
+
+		}
+		else
+		{
+			switch (unexpected_line)
+			{
+			case 0:
+			{
+				const char* thisfilename = file->VgetPath();
+				logPrintf("MultiParamLoader", "go", LOG_WARN, "Ignored unexpected line %d%s",
+					linenum,
+					thisfilename ? SString::sprintf(" while reading '%s'", thisfilename).c_str() : "");
+			}
+				break;
+
+			case 1:
+				logPrintf("MultiParamLoader", "go", LOG_WARN, "The following line(s) were also unexpected and were ignored");
+				break;
+			}
+			unexpected_line++;
+		}
+	}
+	return status;
+}
+
+bool MultiParamLoader::alreadyIncluded(const char* filename)
+{
+	int i;
+	const char* t;
+	for (i = 0; i < filestack.size(); i++)
+	{
+		t = filestack(i)->VgetPath();
+		if (!t) continue;
+		if (!strcmp(filename, t)) return true;
+	}
+	return false;
+}
+
+void MultiParamLoader::includeFile(SString& filename)
+{
+	const char* thisfilename = file->VgetPath();
+	SString newfilename;
+	const char* t = thisfilename ? strrchr(thisfilename, PATH_SEPARATOR_CHAR) : 0;
+
+	if (thisfilename && t)
+	{
+		newfilename.append(thisfilename, t - thisfilename + 1);
+		newfilename += filename;
+	}
 	else
-		{
-		switch(unexpected_line)
-			{
-			case 0:
-			{
-			const char* thisfilename=file->VgetPath();
-			logPrintf("MultiParamLoader","go", LOG_WARN, "Ignored unexpected line %d%s", 
-				  linenum,
-				  thisfilename ? SString::sprintf(" while reading '%s'",thisfilename).c_str():"");
-			}
-			break;
-
-			case 1:
-			logPrintf("MultiParamLoader","go", LOG_WARN, "The following line(s) were also unexpected and were ignored");
-			break;
-			}
-		unexpected_line++;
-		}
-	}
-return status;
-}
-
-bool MultiParamLoader::alreadyIncluded(const char* filename)
-{
-int i;
-const char* t;
-for(i=0;i<filestack.size();i++)
-	{
-	t=filestack(i)->VgetPath();
-	if (!t) continue;
-	if (!strcmp(filename,t)) return true;
-	}
-return false;
-}
-
-void MultiParamLoader::includeFile(SString& filename)
-{
-const char* thisfilename=file->VgetPath();
-SString newfilename;
-const char* t=thisfilename?strrchr(thisfilename,PATH_SEPARATOR_CHAR):0;
-
-if (thisfilename && t)
-	{
-	newfilename.append(thisfilename,t-thisfilename+1);
-	newfilename+=filename;
-	}
-else
-	newfilename=filename;
-
-if (alreadyIncluded(newfilename.c_str()))
-	{
-	logPrintf("MultiParamLoader","include",LOG_WARN,"circular reference ignored (\"%s\")",
-		    filename.c_str());
-	return;
-	}
-
-VirtFILE *f=Vfopen(newfilename.c_str(),FOPEN_READ_BINARY);
-if (!f)
-	{
-	logPrintf("MultiParamLoader","include",LOG_WARN,"\"%s\" not found",newfilename.c_str());
-	}
-else
-	{
-	filestack+=file;
-	file=f;
+		newfilename = filename;
+
+	if (alreadyIncluded(newfilename.c_str()))
+	{
+		logPrintf("MultiParamLoader", "include", LOG_WARN, "circular reference ignored (\"%s\")",
+			filename.c_str());
+		return;
+	}
+
+	VirtFILE *f = Vfopen(newfilename.c_str(), FOPEN_READ_BINARY);
+	if (!f)
+	{
+		logPrintf("MultiParamLoader", "include", LOG_WARN, "\"%s\" not found", newfilename.c_str());
+	}
+	else
+	{
+		filestack += file;
+		file = f;
 	}
 }
@@ -249,51 +253,55 @@
 VirtFILE* MultiParamLoader::popstack()
 {
-if (!filestack.size()) return 0;
-VirtFILE* f=filestack(filestack.size()-1);
-filestack.remove(filestack.size()-1);
-return f;
+	if (!filestack.size()) return 0;
+	VirtFILE* f = filestack(filestack.size() - 1);
+	filestack.remove(filestack.size() - 1);
+	return f;
 }
 
 void MultiParamLoader::clearstack()
 {
-VirtFILE *f;
-while(f=popstack()) delete f;
+	VirtFILE *f;
+	while (f = popstack()) delete f;
 }
 
 bool MultiParamLoader::returnFromIncluded()
 {
-if (!filestack.size()) return false;
-if (file) delete file;
-file=popstack();
-return true;
-}
-
-int MultiParamLoader::loadObjectNow(const ExtObject& o,bool warn_unknown_fields)
-{
-Param tmp_param;
-ParamInterface *pi=o.getParamInterface(tmp_param);
-pi->load(file,warn_unknown_fields,&aborting,&linenum);
-status=AfterObject;
-return 0;
+	if (!filestack.size()) return false;
+	if (file) delete file;
+	file = popstack();
+	return true;
+}
+
+int MultiParamLoader::loadObjectNow(const ExtObject& o, bool warn_unknown_fields)
+{
+	Param tmp_param;
+	ParamInterface *pi = o.getParamInterface(tmp_param);
+	ParamInterface::LoadOptions opts;
+	opts.abortable = &aborting;
+	opts.warn_unknown_fields = warn_unknown_fields;
+	opts.linenum = &linenum;
+	pi->load(ParamInterface::FormatMultiLine, file, &opts);
+	status = AfterObject;
+	return 0;
 }
 
 int MultiParamLoader::run()
 {
-int stat;
-breakOn(OnError);
-while(stat=go())
-	if (stat==OnError)
+	int stat;
+	breakOn(OnError);
+	while (stat = go())
+		if (stat == OnError)
 		{
 		abort();
 		return 0;
 		}
-return 1;
+	return 1;
 }
 
 SString MultiParamLoader::currentFilePathForErrorMessage()
 {
-const char* filename=getFile()->VgetPath();
-if (filename)
-	return SString::sprintf(" in '%s'",filename);
-return SString::empty();
-}
+	const char* filename = getFile()->VgetPath();
+	if (filename)
+		return SString::sprintf(" in '%s'", filename);
+	return SString::empty();
+}
Index: cpp/frams/param/param.cpp
===================================================================
--- cpp/frams/param/param.cpp	(revision 719)
+++ cpp/frams/param/param.cpp	(revision 720)
@@ -10,4 +10,5 @@
 #include "common/log.h"
 #include <frams/util/sstringutils.h>
+#include <common/virtfile/stringfile.h>
 
 //#define SAVE_ALL_NAMES
@@ -356,5 +357,5 @@
 }
 
-void SimpleAbstractParam::save2(SString& f, void *defdata, bool addcr, bool all_names)
+void SimpleAbstractParam::saveSingleLine(SString& f, void *defdata, bool addcr, bool all_names)
 { // defdata!=NULL -> does not save default values
 	const char *p;
@@ -421,5 +422,55 @@
 }
 
-int ParamInterface::load(VirtFILE* f, bool warn_unknown_fields, bool *abortable, int *linenum)
+int ParamInterface::load(FileFormat format, VirtFILE* f, LoadOptions *options)
+{
+	LoadOptions default_options;
+	if (options == NULL)
+		options = &default_options;
+	switch (format)
+	{
+	case FormatMultiLine:
+		return loadMultiLine(f, *options);
+
+	case FormatSingleLine:
+	{
+		StringFILE *sf = dynamic_cast<StringFILE*>(f);
+		SString s;
+		if (sf)
+		{
+			s = sf->getString().c_str();
+			options->offset += sf->Vtell();
+		}
+		else
+		{
+			if (!loadSStringLine(f, s))
+				return -1;
+		}
+		return loadSingleLine(s, *options);
+	}
+	}
+	return -1;
+}
+
+int ParamInterface::load(FileFormat format, const SString &s, LoadOptions *options)
+{
+	LoadOptions default_options;
+	if (options == NULL)
+		options = &default_options;
+	switch (format)
+	{
+	case FormatMultiLine:
+	{
+		string std_string(s.c_str());
+		StringFILE f(std_string);
+		return loadMultiLine(&f, *options);
+	}
+
+	case FormatSingleLine:
+		return loadSingleLine(s, *options);
+	}
+	return -1;
+}
+
+int ParamInterface::loadMultiLine(VirtFILE* f, LoadOptions &options)
 {
 	SString buf;
@@ -434,7 +485,7 @@
 	if ((i = findId("beforeLoad")) >= 0)
 		call(i, NULL, NULL);
-	while (((!abortable) || (!*abortable)) && loadSStringLine(f, buf))
-	{
-		if (linenum) (*linenum)++;
+	while (((!options.abortable) || (!*options.abortable)) && loadSStringLine(f, buf))
+	{
+		if (options.linenum) (*options.linenum)++;
 		const char* t = buf.c_str();
 		p0 = t; while (isblank(*p0)) p0++;
@@ -448,6 +499,6 @@
 			case 0:
 				logPrintf("ParamInterface", "load", LOG_WARN, "Ignored unexpected line %s while reading object '%s'",
-					linenum ?
-					SString::sprintf("%d", *linenum).c_str()
+					options.linenum ?
+					SString::sprintf("%d", *options.linenum).c_str()
 					: SString::sprintf("'%s'", p0).c_str(),
 					getName());
@@ -472,6 +523,6 @@
 				{
 					fileinfo = SString::sprintf(" while reading from '%s'", fname);
-					if (linenum)
-						fileinfo += SString::sprintf(" (line %d)", *linenum);
+					if (options.linenum)
+						fileinfo += SString::sprintf(" (line %d)", *options.linenum);
 				}
 				logPrintf("ParamInterface", "load", LOG_WARN, "Multiple '%s.%s' fields found%s", getName(), id(i), fileinfo.c_str());
@@ -496,9 +547,9 @@
 					int ch; while ((ch = f->Vgetc()) != EOF) if (ch == '\n') break;
 					unquoteTilde(s);
-					if (linenum && (flags(i)&PARAM_LINECOMMENT))
-						s = SString::sprintf("@file %s\n@line %d\n", f->VgetPath(), *linenum + 1) + s;
+					if (options.linenum && (flags(i)&PARAM_LINECOMMENT))
+						s = SString::sprintf("@file %s\n@line %d\n", f->VgetPath(), *options.linenum + 1) + s;
 					set(i, s.c_str());
-					if (linenum)
-						(*linenum) += lfcount;
+					if (options.linenum)
+						(*options.linenum) += lfcount;
 				}
 				else
@@ -510,5 +561,5 @@
 			}
 		}
-		else if (warn_unknown_fields)
+		else if (options.warn_unknown_fields)
 		{
 			SString name(p0, p_len);
@@ -521,5 +572,5 @@
 			if (!readUntilTilde(f, s))
 				closingTildeError(this, f, -1);
-			if (linenum)
+			if (options.linenum)
 			{
 				const char* tmp = s.c_str();
@@ -530,5 +581,5 @@
 					lfcount++; tmp++;
 					}
-				(*linenum) += lfcount;
+				(*options.linenum) += lfcount;
 			}
 			int ch; while ((ch = f->Vgetc()) != EOF) if (ch == '\n') break;
@@ -705,5 +756,5 @@
 {
 	const char *t;
-	if (((*(t = type(i))) == 'd') && (strchr(t, '~')!=NULL)) //type is int and contains enum labels
+	if (((*(t = type(i))) == 'd') && (strchr(t, '~') != NULL)) //type is int and contains enum labels
 	{
 		paInt mn, mx, def;
@@ -1131,5 +1182,5 @@
 }
 
-int ParamInterface::load2(const SString &s, int &poz)
+int ParamInterface::loadSingleLine(const SString &s, LoadOptions &options)
 {
 	int i; // the index number of the parameter
@@ -1145,8 +1196,8 @@
 	SString tmpvalue;
 	bool parse_failed = false;
-	if (poz >= s.len()) return fields_loaded;
-	t = s.c_str() + poz;
-
-	lin = getline(s, poz, len); // all fields must be encoded in a single line
+	if (options.offset >= s.len()) return fields_loaded;
+	t = s.c_str() + options.offset;
+
+	lin = getline(s, options.offset, len); // all fields must be encoded in a single line
 	if (!len) return fields_loaded; // empty line = end
 	i = 0;
@@ -1241,5 +1292,6 @@
 #endif
 	}
-	return fields_loaded | (parse_failed ? LOAD2_PARSE_FAILED : 0);
+	if (parse_failed) options.parse_failed = true;
+	return fields_loaded;
 }
 
Index: cpp/frams/param/param.h
===================================================================
--- cpp/frams/param/param.h	(revision 719)
+++ cpp/frams/param/param.h	(revision 720)
@@ -28,5 +28,5 @@
 #define PARAM_NOSTATIC  256     //< (FramScript) don't access this member in a static object (ClassName.field)
 #define PARAM_CONST     512     //< (FramScript) constant value
-#define PARAM_CANOMITNAME 1024  //< affects Param::save2()/load2() - for example one-liners in f0 genetic encoding
+#define PARAM_CANOMITNAME 1024  //< affects Param::saveSingleLine()/loadSingleLine() - for example one-liners in f0 genetic encoding
 #define PARAM_DONTLOAD	  2048  //< Param::load() skips this field
 #define PARAM_NOISOLATION 4096  //< don't use proxy object in master/slave interactions
@@ -170,12 +170,21 @@
 	void quickCopyFrom(ParamInterface *src);
 
+	enum FileFormat { FormatMultiLine, FormatSingleLine }; // FormatJSON in the future?
+	struct LoadOptions {
+		bool warn_unknown_fields; bool *abortable; int *linenum; int offset; bool parse_failed;
+		LoadOptions() : warn_unknown_fields(false), abortable(NULL), linenum(NULL), offset(0), parse_failed(false) {}
+	};
+
 	int save(VirtFILE*, const char* altname = NULL, bool force = 0);
 	int saveprop(VirtFILE*, int i, const char* p, bool force = 0);
-	int load(VirtFILE*, bool warn_unknown_fields = true, bool *abortable = NULL, int *linenum = NULL);///< @return the number of fields loaded
-	int load2(const SString &, int &);///< @return the number of fields loaded (or'ed with LOAD2_PARSE_FAILED if a parsing error was detected)
+
+	int load(FileFormat format, VirtFILE*, LoadOptions *load_options = NULL);///< @return the number of fields loaded
+	int load(FileFormat format, const SString &, LoadOptions *load_options = NULL);///< @return the number of fields loaded
+protected:
+	int loadMultiLine(VirtFILE*, LoadOptions &options);///< @return the number of fields loaded
+	int loadSingleLine(const SString &, LoadOptions &options);///< @return the number of fields loaded
+public:
 
 	static const char* SERIALIZATION_PREFIX;
-	static const int LOAD2_PARSE_FAILED = (1 << 30); ///< this bit is set in return value from load2 if a parse error was detected while loading. usage: if (load2(...) & LOAD2_PARSE_FAILED) ...
-	static const int LOAD2_IGNORE_PARSE_FAILED = (~LOAD2_PARSE_FAILED); ///< bitmask to be used if the parsing error is to be ignored. usage: int number_of_loaded_fields=load2(...) & LOAD2_IGNORE_PARSE_FAILED;
 
 	static bool isValidTypeDescription(const char* t);
@@ -299,5 +308,5 @@
 
 	int isequal(int i, void* defdata);
-	void save2(SString&, void *defdata, bool addcr = true, bool all_names = true);
+	void saveSingleLine(SString&, void *defdata, bool addcr = true, bool all_names = true);
 
 	virtual void setDefault();
Index: cpp/frams/param/syntparam.cpp
===================================================================
--- cpp/frams/param/syntparam.cpp	(revision 719)
+++ cpp/frams/param/syntparam.cpp	(revision 720)
@@ -8,60 +8,54 @@
 #include <math.h>
 
-SyntParam::SyntParam(ParamEntry *init_pe,SString* autostr,bool handle_defaults_when_saving)
+SyntParam::SyntParam(ParamEntry *init_pe, SString* autostr, bool handle_defaults_when_saving)
 	:autostring(autostr)
 {
-Param::setParamTab(init_pe);
-pe=ParamObject::makeParamTab(this);
-Param::setParamTab(pe);
-if (handle_defaults_when_saving)
+	Param::setParamTab(init_pe);
+	pe = ParamObject::makeParamTab(this);
+	Param::setParamTab(pe);
+	if (handle_defaults_when_saving)
 	{
-	def_obj=ParamObject::makeObject(pe);
-	Param::select(def_obj);
+		def_obj = ParamObject::makeObject(pe);
+		Param::select(def_obj);
+		Param::setDefault();
+	}
+	else
+		def_obj = NULL;
+	obj = ParamObject::makeObject(pe);
+	Param::select(obj);
 	Param::setDefault();
-	}
-else
-	def_obj=NULL;
-obj=ParamObject::makeObject(pe);
-Param::select(obj);
-Param::setDefault();
-revert();
+	revert();
 }
 
 SyntParam::SyntParam(const SyntParam& src)
-	:Param(),autostring(src.autostring)
+	:Param(), autostring(src.autostring)
 {
-Param::setParamTab(src.pe);
-pe=ParamObject::makeParamTab(this);
-Param::setParamTab(pe);
-obj=ParamObject::dupObject(src.obj);
-def_obj=src.def_obj ? ParamObject::dupObject(src.def_obj) : NULL;
-Param::select(obj);
+	Param::setParamTab(src.pe);
+	pe = ParamObject::makeParamTab(this);
+	Param::setParamTab(pe);
+	obj = ParamObject::dupObject(src.obj);
+	def_obj = src.def_obj ? ParamObject::dupObject(src.def_obj) : NULL;
+	Param::select(obj);
 }
 
 SyntParam::~SyntParam()
 {
-update();
-ParamObject::freeParamTab(pe);
-ParamObject::freeObject(obj);
-ParamObject::freeObject(def_obj);
+	update();
+	ParamObject::freeParamTab(pe);
+	ParamObject::freeObject(obj);
+	ParamObject::freeObject(def_obj);
 }
 
 void SyntParam::update(SString *s)
 {
-if (!s) s=autostring;
-if (s) {*s=""; Param::save2(*s,def_obj,0);}
+	if (!s) s = autostring;
+	if (s) { *s = ""; Param::saveSingleLine(*s, def_obj, 0); }
 }
 
 void SyntParam::revert(SString *s)
 {
-if (!s) s=autostring;
-if (s)	{
-	int p=0;
-	Param::load2(*s,p);
+	if (!s) s = autostring;
+	if (s)	{
+		Param::load(ParamInterface::FormatSingleLine, *s);
 	}
 }
-
-
-
-
-
