Changed frontlib to use the existing ini file formats of the QtFrontend
authorMedo <smaxein@googlemail.com>
Fri, 15 Jun 2012 19:57:25 +0200
changeset 7230 240620f46dd7
parent 7227 1c859f572d72
child 7234 613998625a3c
Changed frontlib to use the existing ini file formats of the QtFrontend
project_files/frontlib/hwconsts.h
project_files/frontlib/ipc/gameconn.c
project_files/frontlib/ipc/gameconn.h
project_files/frontlib/ipc/ipcprotocol.c
project_files/frontlib/ipc/ipcprotocol.h
project_files/frontlib/model/cfg.c
project_files/frontlib/model/cfg.h
project_files/frontlib/model/map.c
project_files/frontlib/model/map.h
project_files/frontlib/model/schemelist.c
project_files/frontlib/model/schemelist.h
project_files/frontlib/model/team.c
project_files/frontlib/model/team.h
project_files/frontlib/model/weapon.c
project_files/frontlib/model/weapon.h
project_files/frontlib/resources/metasettings.ini
project_files/frontlib/test.c
project_files/frontlib/util/inihelper.c
project_files/frontlib/util/refcounter.h
project_files/frontlib/util/util.c
project_files/frontlib/util/util.h
--- a/project_files/frontlib/hwconsts.h	Tue Jun 12 21:10:11 2012 +0200
+++ b/project_files/frontlib/hwconsts.h	Fri Jun 15 19:57:25 2012 +0200
@@ -13,9 +13,5 @@
 #define GAMEMOD_SHAREDAMMO_MASKBIT 16
 
 #define WEAPONS_COUNT 55
-#define AMMOLINE_DEFAULT_QT     "9391929422199121032235111001201000000211110101011111011"
-#define AMMOLINE_DEFAULT_PROB   "0405040541600655546554464776576666666155510101115411011"
-#define AMMOLINE_DEFAULT_DELAY  "0000000000000205500000040007004000000000220000000600000"
-#define AMMOLINE_DEFAULT_CRATE  "1311110312111111123114111111111111111211111101111111010"
 
 #endif
--- a/project_files/frontlib/ipc/gameconn.c	Tue Jun 12 21:10:11 2012 +0200
+++ b/project_files/frontlib/ipc/gameconn.c	Fri Jun 15 19:57:25 2012 +0200
@@ -63,43 +63,6 @@
 	conn->onNetMessageCb = &defaultCallback_onNetMessage;
 }
 
-static bool getGameMod(flib_cfg_meta *meta, flib_cfg *conf, int maskbit) {
-	for(int i=0; i<meta->modCount; i++) {
-		if(meta->mods[i].bitmaskIndex == maskbit) {
-			return conf->mods[i];
-		}
-	}
-	flib_log_e("Unable to find game mod with mask bit %i", maskbit);
-	return false;
-}
-
-static int fillConfigBuffer(flib_vector *configBuffer, const char *playerName, flib_cfg_meta *metaconf, flib_gamesetup *setup, bool netgame) {
-	bool error = false;
-	bool perHogAmmo = false;
-	bool sharedAmmo = false;
-
-	error |= flib_ipc_append_message(configBuffer, netgame ? "TN" : "TL");
-	error |= flib_ipc_append_seed(configBuffer, setup->seed);
-	if(setup->map) {
-		error |= flib_ipc_append_mapconf(configBuffer, setup->map, false);
-	}
-	if(setup->script) {
-		error |= flib_ipc_append_message(configBuffer, "escript %s", setup->script);
-	}
-	if(setup->gamescheme) {
-		error |= flib_ipc_append_gamescheme(configBuffer, setup->gamescheme, metaconf);
-		perHogAmmo = getGameMod(metaconf, setup->gamescheme, GAMEMOD_PERHOGAMMO_MASKBIT);
-		sharedAmmo = getGameMod(metaconf, setup->gamescheme, GAMEMOD_SHAREDAMMO_MASKBIT);
-	}
-	if(setup->teams) {
-		for(int i=0; i<setup->teamcount; i++) {
-			error |= flib_ipc_append_addteam(configBuffer, setup->teams[i], perHogAmmo, sharedAmmo);
-		}
-	}
-	error |= flib_ipc_append_message(configBuffer, "!");
-	return error ? -1 : 0;
-}
-
 static flib_gameconn *flib_gameconn_create_partial(bool record, const char *playerName, bool netGame) {
 	flib_gameconn *result = NULL;
 	flib_gameconn *tempConn = flib_calloc(1, sizeof(flib_gameconn));
@@ -122,11 +85,11 @@
 	return result;
 }
 
-flib_gameconn *flib_gameconn_create(const char *playerName, flib_cfg_meta *metaconf, flib_gamesetup *setup, bool netgame) {
+flib_gameconn *flib_gameconn_create(const char *playerName, flib_gamesetup *setup, bool netgame) {
 	flib_gameconn *result = NULL;
 	flib_gameconn *tempConn = flib_gameconn_create_partial(true, playerName, netgame);
 	if(tempConn) {
-		if(fillConfigBuffer(tempConn->configBuffer, playerName, metaconf, setup, netgame) == 0) {
+		if(!flib_ipc_append_fullconfig(tempConn->configBuffer, setup, netgame)) {
 			result = tempConn;
 			tempConn = NULL;
 		}
--- a/project_files/frontlib/ipc/gameconn.h	Tue Jun 12 21:10:11 2012 +0200
+++ b/project_files/frontlib/ipc/gameconn.h	Fri Jun 15 19:57:25 2012 +0200
@@ -16,7 +16,7 @@
 struct _flib_gameconn;
 typedef struct _flib_gameconn flib_gameconn;
 
-flib_gameconn *flib_gameconn_create(const char *playerName, flib_cfg_meta *metaconf, flib_gamesetup *setup, bool netgame);
+flib_gameconn *flib_gameconn_create(const char *playerName, flib_gamesetup *setup, bool netgame);
 flib_gameconn *flib_gameconn_create_playdemo(const uint8_t *demo, int size);
 flib_gameconn *flib_gameconn_create_loadgame(const char *playerName, const uint8_t *save, int size);
 void flib_gameconn_destroy(flib_gameconn *conn);
@@ -75,4 +75,6 @@
  */
 void flib_gameconn_onNetMessage(flib_gameconn *conn, void (*callback)(void *context, const uint8_t *em, int size), void* context);
 
+// TODO efinish
+
 #endif
--- a/project_files/frontlib/ipc/ipcprotocol.c	Tue Jun 12 21:10:11 2012 +0200
+++ b/project_files/frontlib/ipc/ipcprotocol.c	Fri Jun 15 19:57:25 2012 +0200
@@ -6,6 +6,7 @@
 #include <stdbool.h>
 #include <string.h>
 #include <inttypes.h>
+#include <stdlib.h>
 
 int flib_ipc_append_message(flib_vector *vec, const char *fmt, ...) {
 	int result = -1;
@@ -38,7 +39,7 @@
 	return result;
 }
 
-int flib_ipc_append_mapconf(flib_vector *vec, flib_map *map, bool mappreview) {
+int flib_ipc_append_mapconf(flib_vector *vec, const flib_map *map, bool mappreview) {
 	int result = -1;
 	flib_vector *tempvector = flib_vector_create();
 	if(!vec || !map) {
@@ -96,12 +97,13 @@
 	}
 }
 
-int flib_ipc_append_gamescheme(flib_vector *vec, flib_cfg *scheme, flib_cfg_meta *meta) {
+int flib_ipc_append_gamescheme(flib_vector *vec, const flib_cfg *scheme) {
 	int result = -1;
 	flib_vector *tempvector = flib_vector_create();
-	if(!vec || !scheme || !meta) {
+	if(!vec || !scheme) {
 		flib_log_e("null parameter in flib_ipc_append_gamescheme");
 	} else if(tempvector) {
+		const flib_cfg_meta *meta = scheme->meta;
 		bool error = false;
 		uint32_t gamemods = 0;
 		for(int i=0; i<meta->modCount; i++) {
@@ -112,8 +114,8 @@
 		error |= flib_ipc_append_message(tempvector, "e$gmflags %"PRIu32, gamemods);
 		for(int i=0; i<meta->settingCount; i++) {
 			int value = scheme->settings[i];
-			if(meta->settings[i].checkOverMax) {
-				value = value>meta->settings[i].max ? meta->settings[i].max : value;
+			if(meta->settings[i].maxMeansInfinity) {
+				value = value>=meta->settings[i].max ? 9999 : value;
 			}
 			if(meta->settings[i].times1000) {
 				value *= 1000;
@@ -133,19 +135,23 @@
 	return result;
 }
 
-// FIXME shared ammo will break per-team ammo
-int flib_ipc_append_addteam(flib_vector *vec, flib_team *team, bool perHogAmmo, bool sharedAmmo) {
+static int appendWeaponSet(flib_vector *vec, flib_weaponset *set) {
+	return flib_ipc_append_message(vec, "eammloadt %s", set->loadout)
+		|| flib_ipc_append_message(vec, "eammprob %s", set->crateprob)
+		|| flib_ipc_append_message(vec, "eammdelay %s", set->delay)
+		|| flib_ipc_append_message(vec, "eammreinf %s", set->crateammo);
+}
+
+int flib_ipc_append_addteam(flib_vector *vec, const flib_team *team, bool perHogAmmo, bool noAmmoStore) {
 	int result = -1;
 	flib_vector *tempvector = flib_vector_create();
-	if(!vec || !team || !team->weaponset) {
+	if(!vec || !team) {
 		flib_log_e("invalid parameter in flib_ipc_append_addteam");
 	} else if(tempvector) {
 		bool error = false;
-		error |= flib_ipc_append_message(tempvector, "eammloadt %s", team->weaponset->loadout);
-		error |= flib_ipc_append_message(tempvector, "eammprob %s", team->weaponset->crateprob);
-		error |= flib_ipc_append_message(tempvector, "eammdelay %s", team->weaponset->delay);
-		error |= flib_ipc_append_message(tempvector, "eammreinf %s", team->weaponset->crateammo);
-		if(!perHogAmmo) {
+
+		if(!perHogAmmo && !noAmmoStore) {
+			error |= appendWeaponSet(tempvector, team->hogs[0].weaponset);
 			error |= flib_ipc_append_message(tempvector, "eammstore");
 		}
 
@@ -166,6 +172,9 @@
 		}
 
 		for(int i=0; i<team->hogsInGame; i++) {
+			if(perHogAmmo && !noAmmoStore) {
+				error |= appendWeaponSet(tempvector, team->hogs[i].weaponset);
+			}
 			error |= flib_ipc_append_message(tempvector, "eaddhh %i %i %s", team->hogs[i].difficulty, team->hogs[i].initialHealth, team->hogs[i].name);
 			error |= flib_ipc_append_message(tempvector, "ehat %s", team->hogs[i].hat);
 		}
@@ -181,3 +190,80 @@
 	flib_vector_destroy(tempvector);
 	return result;
 }
+
+static bool getGameMod(const flib_cfg *conf, int maskbit) {
+	for(int i=0; i<conf->meta->modCount; i++) {
+		if(conf->meta->mods[i].bitmaskIndex == maskbit) {
+			return conf->mods[i];
+		}
+	}
+	flib_log_e("Unable to find game mod with mask bit %i", maskbit);
+	return false;
+}
+
+int flib_ipc_append_fullconfig(flib_vector *vec, const flib_gamesetup *setup, bool netgame) {
+	int result = -1;
+	flib_vector *tempvector = flib_vector_create();
+	if(!vec || !setup) {
+		flib_log_e("null parameter in flib_ipc_append_fullconfig");
+	} else if(tempvector) {
+		bool error = false;
+		bool perHogAmmo = false;
+		bool sharedAmmo = false;
+
+		error |= flib_ipc_append_message(vec, netgame ? "TN" : "TL");
+		error |= flib_ipc_append_seed(vec, setup->seed);
+		if(setup->map) {
+			error |= flib_ipc_append_mapconf(tempvector, setup->map, false);
+		}
+		if(setup->script) {
+			error |= flib_ipc_append_message(tempvector, "escript %s", setup->script);
+		}
+		if(setup->gamescheme) {
+			error |= flib_ipc_append_gamescheme(tempvector, setup->gamescheme);
+			sharedAmmo = getGameMod(setup->gamescheme, GAMEMOD_SHAREDAMMO_MASKBIT);
+			// Shared ammo has priority over per-hog ammo
+			perHogAmmo = !sharedAmmo && getGameMod(setup->gamescheme, GAMEMOD_PERHOGAMMO_MASKBIT);
+		}
+		if(setup->teams && setup->teamcount>0) {
+			uint32_t *clanColors = flib_calloc(setup->teamcount, sizeof(uint32_t));
+			if(!clanColors) {
+				error = true;
+			} else {
+				int clanCount = 0;
+				for(int i=0; i<setup->teamcount; i++) {
+					flib_team *team = setup->teams[i];
+					bool newClan = false;
+
+					// Find the clan index of this team (clans are identified by color).
+					// The upper 8 bits (alpha) are ignored in the engine as well.
+					uint32_t color = team->color&UINT32_C(0x00ffffff);
+					int clan = 0;
+					while(clan<clanCount && clanColors[clan] != color) {
+						clan++;
+					}
+					if(clan==clanCount) {
+						newClan = true;
+						clanCount++;
+						clanColors[clan] = color;
+					}
+
+					// If shared ammo is active, only add an ammo store for the first team in each clan.
+					bool noAmmoStore = sharedAmmo&&!newClan;
+					error |= flib_ipc_append_addteam(tempvector, setup->teams[i], perHogAmmo, noAmmoStore);
+				}
+			}
+			free(clanColors);
+		}
+		error |= flib_ipc_append_message(tempvector, "!");
+
+		if(!error) {
+			// Message created, now we can copy everything.
+			flib_constbuffer constbuf = flib_vector_as_constbuffer(tempvector);
+			if(flib_vector_append(vec, constbuf.data, constbuf.size) == constbuf.size) {
+				result = 0;
+			}
+		}
+	}
+	return result;
+}
--- a/project_files/frontlib/ipc/ipcprotocol.h	Tue Jun 12 21:10:11 2012 +0200
+++ b/project_files/frontlib/ipc/ipcprotocol.h	Fri Jun 15 19:57:25 2012 +0200
@@ -5,6 +5,7 @@
 #include "../model/map.h"
 #include "../model/team.h"
 #include "../model/cfg.h"
+#include "../model/gamesetup.h"
 
 #include <stdbool.h>
 
@@ -27,7 +28,7 @@
  * Returns nonzero if something goes wrong. In that case the buffer
  * contents are unaffected.
  */
-int flib_ipc_append_mapconf(flib_vector *vec, flib_map *map, bool mappreview);
+int flib_ipc_append_mapconf(flib_vector *vec, const flib_map *map, bool mappreview);
 
 /**
  * Append a seed message to the buffer.
@@ -43,8 +44,10 @@
  * Returns nonzero if something goes wrong. In that case the buffer
  * contents are unaffected.
  */
-int flib_ipc_append_gamescheme(flib_vector *vec, flib_cfg *seed, flib_cfg_meta *meta);
+int flib_ipc_append_gamescheme(flib_vector *vec, const flib_cfg *cfg);
 
-int flib_ipc_append_addteam(flib_vector *vec, flib_team *team, bool perHogAmmo, bool sharedAmmo);
+int flib_ipc_append_addteam(flib_vector *vec, const flib_team *team, bool perHogAmmo, bool noAmmoStore);
+
+int flib_ipc_append_fullconfig(flib_vector *vec, const flib_gamesetup *setup, bool netgame);
 
 #endif /* IPCPROTOCOL_H_ */
--- a/project_files/frontlib/model/cfg.c	Tue Jun 12 21:10:11 2012 +0200
+++ b/project_files/frontlib/model/cfg.c	Fri Jun 15 19:57:25 2012 +0200
@@ -3,96 +3,25 @@
 #include "../util/inihelper.h"
 #include "../util/logging.h"
 #include "../util/util.h"
+#include "../util/refcounter.h"
 
 #include <stdio.h>
 #include <stdlib.h>
-
-static flib_cfg_meta *flib_cfg_meta_from_ini_handleError(flib_cfg_meta *result, flib_ini *settingfile, flib_ini *modfile) {
-	flib_cfg_meta_destroy(result);
-	flib_ini_destroy(settingfile);
-	flib_ini_destroy(modfile);
-	return NULL;
-}
-
-flib_cfg_meta *flib_cfg_meta_from_ini(const char *settingpath, const char *modpath) {
-	if(!settingpath || !modpath) {
-		flib_log_e("null parameter in flib_cfg_meta_from_ini");
-		return NULL;
-	}
-	flib_cfg_meta *result = flib_calloc(1, sizeof(flib_cfg_meta));
-	flib_ini *settingfile = flib_ini_load(settingpath);
-	flib_ini *modfile = flib_ini_load(modpath);
-
-	if(!result || !settingfile || !modfile) {
-		return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile);
-	}
-
-	result->settingCount = flib_ini_get_sectioncount(settingfile);
-	result->modCount = flib_ini_get_sectioncount(modfile);
-	result->settings = flib_calloc(result->settingCount, sizeof(flib_cfg_setting_meta));
-	result->mods = flib_calloc(result->modCount, sizeof(flib_cfg_mod_meta));
-
-	if(!result->settings || !result->mods) {
-		return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile);
-	}
-
-	for(int i=0; i<result->settingCount; i++) {
-		result->settings[i].iniName = flib_ini_get_sectionname(settingfile, i);
-		if(!result->settings[i].iniName) {
-			return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile);
-		}
+#include <limits.h>
+#include <string.h>
 
-		bool error = false;
-		error |= flib_ini_enter_section(settingfile, result->settings[i].iniName);
-		error |= flib_ini_get_str(settingfile, &result->settings[i].title, "title");
-		error |= flib_ini_get_str(settingfile, &result->settings[i].engineCommand, "command");
-		error |= flib_ini_get_str(settingfile, &result->settings[i].image, "image");
-		error |= flib_ini_get_bool(settingfile, &result->settings[i].checkOverMax, "checkOverMax");
-		error |= flib_ini_get_bool(settingfile, &result->settings[i].times1000, "times1000");
-		error |= flib_ini_get_int(settingfile, &result->settings[i].min, "min");
-		error |= flib_ini_get_int(settingfile, &result->settings[i].max, "max");
-		error |= flib_ini_get_int(settingfile, &result->settings[i].def, "default");
-
-		if(error) {
-			flib_log_e("Missing or malformed ini parameter in file %s, section %s", settingpath, result->settings[i].iniName);
-			return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile);
-		}
-	}
-
-	for(int i=0; i<result->modCount; i++) {
-		result->mods[i].iniName = flib_ini_get_sectionname(modfile, i);
-		if(!result->mods[i].iniName) {
-			return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile);
-		}
-
-		bool error = false;
-		error |= flib_ini_enter_section(modfile, result->mods[i].iniName);
-		error |= flib_ini_get_int(modfile, &result->mods[i].bitmaskIndex, "bitmaskIndex");
-		if(error) {
-			flib_log_e("Missing or malformed ini parameter in file %s, section %s", modpath, result->mods[i].iniName);
-			return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile);
-		}
-	}
-
-	flib_ini_destroy(settingfile);
-	flib_ini_destroy(modfile);
-	return result;
-}
-
-void flib_cfg_meta_destroy(flib_cfg_meta *cfg) {
+static void flib_cfg_meta_destroy(flib_cfg_meta *cfg) {
 	if(cfg) {
 		if(cfg->settings) {
 			for(int i=0; i<cfg->settingCount; i++) {
-				free(cfg->settings[i].iniName);
-				free(cfg->settings[i].title);
+				free(cfg->settings[i].name);
 				free(cfg->settings[i].engineCommand);
-				free(cfg->settings[i].image);
 			}
 			free(cfg->settings);
 		}
 		if(cfg->mods) {
 			for(int i=0; i<cfg->modCount; i++) {
-				free(cfg->mods[i].iniName);
+				free(cfg->mods[i].name);
 			}
 			free(cfg->mods);
 		}
@@ -100,15 +29,132 @@
 	}
 }
 
-flib_cfg *flib_cfg_create(const flib_cfg_meta *meta, const char *schemeName) {
-	flib_cfg *result = flib_calloc(1, sizeof(flib_cfg));
+static void flib_cfg_destroy(flib_cfg* cfg) {
+	if(cfg) {
+		flib_cfg_meta_release(cfg->meta);
+		free(cfg->mods);
+		free(cfg->settings);
+		free(cfg->schemeName);
+		free(cfg);
+	}
+}
+
+static flib_cfg_meta *flib_cfg_meta_from_ini_handleError(flib_cfg_meta *result, flib_ini *ini) {
+	flib_cfg_meta_destroy(result);
+	flib_ini_destroy(ini);
+	return NULL;
+}
+
+static int readMetaSettingSections(flib_ini *ini, flib_cfg_meta *result, int limit) {
+	while(result->settingCount<limit) {
+		char sectionName[32];
+		if(snprintf(sectionName, sizeof(sectionName), "setting%i", result->settingCount) <= 0) {
+			return -1;
+		}
+		if(!flib_ini_enter_section(ini, sectionName)) {
+			flib_cfg_setting_meta *metasetting = &result->settings[result->settingCount];
+			result->settingCount++;
+
+			bool error = false;
+			error |= flib_ini_get_str(ini, &metasetting->name, "name");
+			error |= flib_ini_get_str_opt(ini, &metasetting->engineCommand, "command", NULL);
+			error |= flib_ini_get_bool(ini, &metasetting->times1000, "times1000");
+			error |= flib_ini_get_bool(ini, &metasetting->maxMeansInfinity, "maxmeansinfinity");
+			error |= flib_ini_get_int(ini, &metasetting->min, "min");
+			error |= flib_ini_get_int(ini, &metasetting->max, "max");
+			error |= flib_ini_get_int(ini, &metasetting->def, "default");
+			if(error) {
+				flib_log_e("Missing or malformed ini parameter in metaconfig, section %s", sectionName);
+				return -1;
+			}
+		} else {
+			return 0;
+		}
+	}
+	return 0;
+}
+
+static int readMetaModSections(flib_ini *ini, flib_cfg_meta *result, int limit) {
+	while(result->modCount<limit) {
+		char sectionName[32];
+		if(snprintf(sectionName, sizeof(sectionName), "mod%i", result->modCount) <= 0) {
+			return -1;
+		}
+		if(!flib_ini_enter_section(ini, sectionName)) {
+			flib_cfg_mod_meta *metamod = &result->mods[result->modCount];
+			result->modCount++;
+
+			bool error = false;
+			error |= flib_ini_get_str(ini, &metamod->name, "name");
+			error |= flib_ini_get_int(ini, &metamod->bitmaskIndex, "bitmaskIndex");
+			if(error) {
+				flib_log_e("Missing or malformed ini parameter in metaconfig, section %s", sectionName);
+				return -1;
+			}
+		} else {
+			return 0;
+		}
+	}
+	return 0;
+}
+
+flib_cfg_meta *flib_cfg_meta_from_ini(const char *filename) {
+	if(!filename) {
+		flib_log_e("null parameter in flib_cfg_meta_from_ini");
+		return NULL;
+	}
+	flib_cfg_meta *result = flib_cfg_meta_retain(flib_calloc(1, sizeof(flib_cfg_meta)));
+	flib_ini *ini = flib_ini_load(filename);
+
+	if(!result || !ini) {
+		return flib_cfg_meta_from_ini_handleError(result, ini);
+	}
+
+	// We're overallocating here for simplicity
+	int sectionCount = flib_ini_get_sectioncount(ini);
+	result->settingCount = 0;
+	result->modCount = 0;
+	result->settings = flib_calloc(sectionCount, sizeof(flib_cfg_setting_meta));
+	result->mods = flib_calloc(sectionCount, sizeof(flib_cfg_mod_meta));
+
+	if(!result->settings || !result->mods) {
+		return flib_cfg_meta_from_ini_handleError(result, ini);
+	}
+
+	if(readMetaSettingSections(ini, result, sectionCount) || readMetaModSections(ini, result, sectionCount)) {
+		return flib_cfg_meta_from_ini_handleError(result, ini);
+	}
+
+	if(result->settingCount+result->modCount != sectionCount) {
+		flib_log_e("Unknown or non-contiguous sections headers in metaconfig.");
+		return flib_cfg_meta_from_ini_handleError(result, ini);
+	}
+
+	flib_ini_destroy(ini);
+	return result;
+}
+
+flib_cfg_meta *flib_cfg_meta_retain(flib_cfg_meta *metainfo) {
+	if(metainfo) {
+		flib_retain(&metainfo->_referenceCount, "flib_cfg_meta");
+	}
+	return metainfo;
+}
+
+void flib_cfg_meta_release(flib_cfg_meta *cfg) {
+	if(cfg && flib_release(&cfg->_referenceCount, "flib_cfg_meta")) {
+		flib_cfg_meta_destroy(cfg);
+	}
+}
+
+flib_cfg *flib_cfg_create(flib_cfg_meta *meta, const char *schemeName) {
+	flib_cfg *result = flib_cfg_retain(flib_calloc(1, sizeof(flib_cfg)));
 	if(!meta || !result || !schemeName) {
 		flib_log_e("null parameter in flib_cfg_create");
 		return NULL;
 	}
 
-	result->modCount = meta->modCount;
-	result->settingCount = meta->settingCount;
+	result->meta = flib_cfg_meta_retain(meta);
 	result->schemeName = flib_strdupnull(schemeName);
 	result->mods = flib_calloc(meta->modCount, sizeof(*result->mods));
 	result->settings = flib_calloc(meta->settingCount, sizeof(*result->settings));
@@ -124,103 +170,27 @@
 	return result;
 }
 
-flib_cfg *flib_cfg_from_ini_handleError(flib_cfg *result, flib_ini *settingfile) {
-	flib_ini_destroy(settingfile);
-	flib_cfg_destroy(result);
-	return NULL;
-}
-
-flib_cfg *flib_cfg_from_ini(const flib_cfg_meta *meta, const char *filename) {
-	if(!meta || !filename) {
-		flib_log_e("null parameter in flib_cfg_from_ini");
-		return NULL;
-	}
-	flib_ini *settingfile = flib_ini_load(filename);
-	if(!settingfile) {
-		return NULL;
-	}
-
-	char *schemename = NULL;
-	if(flib_ini_enter_section(settingfile, "Scheme")) {
-		flib_log_e("Missing section \"Scheme\" in config file %s.", filename);
-		return flib_cfg_from_ini_handleError(NULL, settingfile);
-	}
-	if(flib_ini_get_str(settingfile, &schemename, "name")) {
-		flib_log_e("Missing scheme name in config file %s.", filename);
-		return flib_cfg_from_ini_handleError(NULL, settingfile);
-	}
-
-	flib_cfg *result = flib_cfg_create(meta, schemename);
-
-	if(flib_ini_enter_section(settingfile, "BasicSettings")) {
-		flib_log_w("Missing section \"BasicSettings\" in config file %s, using defaults.", filename);
-	} else {
-		for(int i=0; i<meta->settingCount; i++) {
-			if(flib_ini_get_int_opt(settingfile, &result->settings[i], meta->settings[i].iniName, meta->settings[i].def)) {
-				flib_log_e("Error reading BasicSetting %s in config file %s.", meta->settings[i].iniName, filename);
-				return flib_cfg_from_ini_handleError(result, settingfile);
-			}
+flib_cfg *flib_cfg_copy(flib_cfg *cfg) {
+	flib_cfg *result = NULL;
+	if(cfg) {
+		result = flib_cfg_create(cfg->meta, cfg->schemeName);
+		if(result) {
+			memcpy(result->mods, cfg->mods, cfg->meta->modCount * sizeof(*cfg->mods));
+			memcpy(result->settings, cfg->settings, cfg->meta->settingCount * sizeof(*cfg->settings));
 		}
 	}
-
-	if(flib_ini_enter_section(settingfile, "GameMods")) {
-		flib_log_w("Missing section \"GameMods\" in config file %s, using defaults.", filename);
-	} else {
-		for(int i=0; i<meta->modCount; i++) {
-			if(flib_ini_get_bool_opt(settingfile, &result->mods[i], meta->mods[i].iniName, false)) {
-				flib_log_e("Error reading GameMod %s in config file %s.", meta->mods[i].iniName, filename);
-				return flib_cfg_from_ini_handleError(result, settingfile);
-			}
-		}
-	}
-	flib_ini_destroy(settingfile);
-	return result;
-}
-
-int flib_cfg_to_ini(const flib_cfg_meta *meta, const char *filename, const flib_cfg *config) {
-	int result = -1;
-	if(!meta || !filename || !config || config->modCount!=meta->modCount || config->settingCount!=meta->settingCount) {
-		flib_log_e("Invalid parameter in flib_cfg_to_ini");
-	} else {
-		flib_ini *ini = flib_ini_create(filename);
-		if(ini) {
-			bool error = false;
-
-			// Add the values
-			error |= flib_ini_create_section(ini, "Scheme");
-			if(!error) {
-				error |= flib_ini_set_str(ini, "name", config->schemeName);
-			}
-
-
-			error |= flib_ini_create_section(ini, "BasicSettings");
-			if(!error) {
-				for(int i=0; i<config->settingCount; i++) {
-					error |= flib_ini_set_int(ini, meta->settings[i].iniName, config->settings[i]);
-				}
-			}
-
-			error |= flib_ini_create_section(ini, "GameMods");
-			if(!error) {
-				for(int i=0; i<config->modCount; i++) {
-					error |= flib_ini_set_bool(ini, meta->mods[i].iniName, config->mods[i]);
-				}
-			}
-
-			if(!error) {
-				result = flib_ini_save(ini, filename);
-			}
-		}
-		flib_ini_destroy(ini);
-	}
 	return result;
 }
 
-void flib_cfg_destroy(flib_cfg* cfg) {
+flib_cfg *flib_cfg_retain(flib_cfg *cfg) {
 	if(cfg) {
-		free(cfg->mods);
-		free(cfg->settings);
-		free(cfg->schemeName);
-		free(cfg);
+		flib_retain(&cfg->_referenceCount, "flib_cfg");
+	}
+	return cfg;
+}
+
+void flib_cfg_release(flib_cfg *cfg) {
+	if(cfg && flib_release(&cfg->_referenceCount, "flib_cfg")) {
+		flib_cfg_destroy(cfg);
 	}
 }
--- a/project_files/frontlib/model/cfg.h	Tue Jun 12 21:10:11 2012 +0200
+++ b/project_files/frontlib/model/cfg.h	Fri Jun 15 19:57:25 2012 +0200
@@ -1,9 +1,5 @@
 /**
  * Data structures for game scheme information.
- *
- * Important conventions:
- * - All data structures own what they point to.
- * - Strings are never null pointers.
  */
 
 #ifndef CFG_H_
@@ -11,66 +7,79 @@
 
 #include <stdbool.h>
 
+// TODO: cfg/config -> scheme
+
 typedef struct {
-    char *iniName;
-    char *title;
+    char *name;
     char *engineCommand;
-    char *image;
-    int netplayIndex;
-    bool checkOverMax;
+    bool maxMeansInfinity;
     bool times1000;
-    int def;
     int min;
     int max;
+    int def;
 } flib_cfg_setting_meta;
 
 typedef struct {
-    char *iniName;
+    char *name;
     int bitmaskIndex;
 } flib_cfg_mod_meta;
 
 typedef struct {
-    int settingCount;
-    int modCount;
+	int _referenceCount;
+	int settingCount;
+	int modCount;
     flib_cfg_setting_meta *settings;
     flib_cfg_mod_meta *mods;
 } flib_cfg_meta;
 
 typedef struct {
-    int settingCount;
-    int modCount;
+	int _referenceCount;
+    flib_cfg_meta *meta;
+
     char *schemeName;
     int *settings;
     bool *mods;
 } flib_cfg;
 
 /**
- * Read the meta-configuration from the relevant .ini files (e.g. which settings exist,
+ * Read the meta-configuration from a .ini file (e.g. which settings exist,
  * what are their defaults etc.)
  *
- * Returns the meta-configuration or NULL. Destroy the meta-configuration with
- * flib_cfg_meta_destroy.
+ * Returns the meta-configuration or NULL.
  */
-flib_cfg_meta *flib_cfg_meta_from_ini(const char *settingpath, const char *modpath);
-void flib_cfg_meta_destroy(flib_cfg_meta *metainfo);
+flib_cfg_meta *flib_cfg_meta_from_ini(const char *filename);
 
 /**
- * Create a new configuration with default settings.
+ * Increase the reference count of the object. Call this if you store a pointer to it somewhere.
+ * Returns the parameter.
+ */
+flib_cfg_meta *flib_cfg_meta_retain(flib_cfg_meta *metainfo);
+
+/**
+ * Decrease the reference count of the object and free it if this was the last reference.
+ */
+void flib_cfg_meta_release(flib_cfg_meta *metainfo);
+
+/**
+ * Create a new configuration with everything set to default or false
  * Returns NULL on error.
  */
-flib_cfg *flib_cfg_create(const flib_cfg_meta *meta, const char *schemeName);
+flib_cfg *flib_cfg_create(flib_cfg_meta *meta, const char *schemeName);
+
+/**
+ * Create a copy of the scheme. Returns NULL on error or if NULL was passed.
+ */
+flib_cfg *flib_cfg_copy(flib_cfg *cfg);
 
 /**
- * Load a configuration from the ini file.
- * Returns NULL on error.
+ * Increase the reference count of the object. Call this if you store a pointer to it somewhere.
+ * Returns the parameter.
  */
-flib_cfg *flib_cfg_from_ini(const flib_cfg_meta *meta, const char *filename);
+flib_cfg *flib_cfg_retain(flib_cfg *cfg);
 
 /**
- * Store the configuration to an ini file.
- * Returns NULL on error.
+ * Decrease the reference count of the object and free it if this was the last reference.
  */
-int flib_cfg_to_ini(const flib_cfg_meta *meta, const char *filename, const flib_cfg *config);
-void flib_cfg_destroy(flib_cfg* cfg);
+void flib_cfg_release(flib_cfg* cfg);
 
 #endif /* CFG_H_ */
--- a/project_files/frontlib/model/map.c	Tue Jun 12 21:10:11 2012 +0200
+++ b/project_files/frontlib/model/map.c	Fri Jun 15 19:57:25 2012 +0200
@@ -3,9 +3,19 @@
 #include "../util/inihelper.h"
 #include "../util/util.h"
 #include "../util/logging.h"
+#include "../util/refcounter.h"
 
 #include <stdlib.h>
 
+static void flib_map_destroy(flib_map *map) {
+	if(map) {
+		free(map->drawData);
+		free(map->name);
+		free(map->theme);
+		free(map);
+	}
+}
+
 flib_map *flib_map_create_regular(const char *theme, int templateFilter) {
 	flib_map *result = NULL;
 	if(!theme) {
@@ -13,6 +23,7 @@
 	} else {
 		flib_map *newmap = flib_calloc(1, sizeof(flib_map));
 		if(newmap) {
+			newmap->_referenceCount = 1;
 			newmap->mapgen = MAPGEN_REGULAR;
 			newmap->templateFilter = templateFilter;
 			newmap->theme = flib_strdupnull(theme);
@@ -33,6 +44,7 @@
 	} else {
 		flib_map *newmap = flib_calloc(1, sizeof(flib_map));
 		if(newmap) {
+			newmap->_referenceCount = 1;
 			newmap->mapgen = MAPGEN_MAZE;
 			newmap->mazeSize = mazeSize;
 			newmap->theme = flib_strdupnull(theme);
@@ -53,6 +65,7 @@
 	} else {
 		flib_map *newmap = flib_calloc(1, sizeof(flib_map));
 		if(newmap) {
+			newmap->_referenceCount = 1;
 			newmap->mapgen = MAPGEN_NAMED;
 			newmap->name = flib_strdupnull(name);
 			if(newmap->name) {
@@ -72,6 +85,7 @@
 	} else {
 		flib_map *newmap = flib_calloc(1, sizeof(flib_map));
 		if(newmap) {
+			newmap->_referenceCount = 1;
 			newmap->mapgen = MAPGEN_DRAWN;
 			newmap->drawData = flib_bufdupnull(drawData, drawDataSize);
 			newmap->drawDataSize = drawDataSize;
@@ -85,11 +99,15 @@
 	return result;
 }
 
-void flib_map_destroy(flib_map *map) {
+flib_map *flib_map_retain(flib_map *map) {
 	if(map) {
-		free(map->drawData);
-		free(map->name);
-		free(map->theme);
-		free(map);
+		flib_retain(&map->_referenceCount, "flib_map");
+	}
+	return map;
+}
+
+void flib_map_release(flib_map *map) {
+	if(map && flib_release(&map->_referenceCount, "flib_map")) {
+		flib_map_destroy(map);
 	}
 }
--- a/project_files/frontlib/model/map.h	Tue Jun 12 21:10:11 2012 +0200
+++ b/project_files/frontlib/model/map.h	Fri Jun 15 19:57:25 2012 +0200
@@ -30,6 +30,7 @@
 #define MAZE_SIZE_LARGE_ISLANDS 5
 
 typedef struct {
+	int _referenceCount;
 	int mapgen;				// Always one of the MAPGEN_ constants
 	char *theme;			// Used for all except MAPGEN_NAMED
 	char *name;				// Used for MAPGEN_NAMED
@@ -79,9 +80,15 @@
 flib_map *flib_map_create_drawn(const char *theme, const uint8_t *drawData, int drawDataSize);
 
 /**
- * Free the memory taken up by the map. Passing NULL is allowed and does nothing.
+ * Increase the reference count of the object. Call this if you store a pointer to it somewhere.
+ * Returns the parameter.
  */
-void flib_map_destroy(flib_map *map);
+flib_map *flib_map_retain(flib_map *map);
+
+/**
+ * Decrease the reference count of the object and free it if this was the last reference.
+ */
+void flib_map_release(flib_map *map);
 
 
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/model/schemelist.c	Fri Jun 15 19:57:25 2012 +0200
@@ -0,0 +1,229 @@
+#include "schemelist.h"
+
+#include "../util/inihelper.h"
+#include "../util/logging.h"
+#include "../util/util.h"
+#include "../util/refcounter.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+
+static void flib_schemelist_destroy(flib_schemelist *list) {
+	if(list) {
+		for(int i=0; i<list->schemeCount; i++) {
+			flib_cfg_release(list->schemes[i]);
+		}
+		free(list);
+	}
+}
+
+static char *makePrefixedName(int schemeIndex, const char *settingName) {
+	return flib_asprintf("%i\\%s", schemeIndex, settingName);
+}
+
+static int readSettingsFromIni(flib_ini *ini, flib_cfg *scheme, int index) {
+	flib_cfg_meta *meta = scheme->meta;
+	bool error = false;
+	for(int i=0; i<meta->settingCount && !error; i++) {
+		char *key = makePrefixedName(index, meta->settings[i].name);
+		if(!key) {
+			error = true;
+		} else if(flib_ini_get_int_opt(ini, &scheme->settings[i], key, meta->settings[i].def)) {
+			flib_log_e("Error reading setting %s in schemes file.", key);
+			error = true;
+		}
+		free(key);
+	}
+	return error;
+}
+
+static int readModsFromIni(flib_ini *ini, flib_cfg *scheme, int index) {
+	flib_cfg_meta *meta = scheme->meta;
+	bool error = false;
+	for(int i=0; i<meta->modCount && !error; i++) {
+		char *key = makePrefixedName(index, meta->mods[i].name);
+		if(!key) {
+			error = true;
+		} else if(flib_ini_get_bool_opt(ini, &scheme->mods[i], key, false)) {
+			flib_log_e("Error reading mod %s in schemes file.", key);
+			error = true;
+		}
+		free(key);
+	}
+	return error;
+}
+
+static flib_cfg *readSchemeFromIni(flib_cfg_meta *meta, flib_ini *ini, int index) {
+	flib_cfg *result = NULL;
+	char *schemeNameKey = makePrefixedName(index+1, "name");
+	if(schemeNameKey) {
+		char *schemeName = NULL;
+		if(!flib_ini_get_str_opt(ini, &schemeName, schemeNameKey, "Unnamed")) {
+			flib_cfg *scheme = flib_cfg_create(meta, schemeName);
+			if(scheme) {
+				if(!readSettingsFromIni(ini, scheme, index) && !readModsFromIni(ini, scheme, index)) {
+					result = flib_cfg_retain(scheme);
+				}
+			}
+			flib_cfg_release(scheme);
+		}
+		free(schemeName);
+	}
+	free(schemeNameKey);
+	return result;
+}
+
+static flib_schemelist *fromIniHandleError(flib_schemelist *result, flib_ini *ini) {
+	flib_ini_destroy(ini);
+	flib_schemelist_destroy(result);
+	return NULL;
+}
+
+flib_schemelist *flib_schemelist_from_ini(flib_cfg_meta *meta, const char *filename) {
+	flib_schemelist *list = NULL;
+	if(!meta || !filename) {
+		flib_log_e("null parameter in flib_schemelist_from_ini");
+		return NULL;
+	}
+	flib_ini *ini = flib_ini_load(filename);
+	if(!ini || flib_ini_enter_section(ini, "schemes")) {
+		flib_log_e("Missing file or missing section \"schemes\" in file %s.", filename);
+		return fromIniHandleError(list, ini);
+	}
+
+	list = flib_schemelist_create();
+	if(!list) {
+		return fromIniHandleError(list, ini);
+	}
+
+	int schemeCount = 0;
+	if(flib_ini_get_int(ini, &schemeCount, "size")) {
+		flib_log_e("Missing or malformed scheme count in config file %s.", filename);
+		return fromIniHandleError(list, ini);
+	}
+
+	for(int i=0; i<schemeCount; i++) {
+		flib_cfg *scheme = readSchemeFromIni(meta, ini, i);
+		if(!scheme || flib_schemelist_insert(list, scheme, i)) {
+			flib_cfg_release(scheme);
+			flib_log_e("Error reading scheme %i from config file %s.", i, filename);
+			return fromIniHandleError(list, ini);
+		}
+		flib_cfg_release(scheme);
+	}
+
+
+	flib_ini_destroy(ini);
+	return list;
+}
+
+static int writeSchemeToIni(flib_cfg *scheme, flib_ini *ini, int index) {
+	flib_cfg_meta *meta = scheme->meta;
+	bool error = false;
+
+	char *key = makePrefixedName(index+1, "name");
+	error |= !key || flib_ini_set_str(ini, key, scheme->schemeName);
+	free(key);
+
+	for(int i=0; i<meta->modCount && !error; i++) {
+		char *key = makePrefixedName(index+1, meta->mods[i].name);
+		error |= !key || flib_ini_set_bool(ini, key, scheme->mods[i]);
+		free(key);
+	}
+
+	for(int i=0; i<meta->settingCount && !error; i++) {
+		char *key = makePrefixedName(index+1, meta->settings[i].name);
+		error |= !key || flib_ini_set_int(ini, key, scheme->settings[i]);
+		free(key);
+	}
+	return error;
+}
+
+int flib_schemelist_to_ini(const char *filename, const flib_schemelist *schemes) {
+	int result = -1;
+	if(!filename || !schemes) {
+		flib_log_e("null parameter in flib_schemelist_to_ini");
+	} else {
+		flib_ini *ini = flib_ini_create(NULL);
+		if(ini && !flib_ini_create_section(ini, "schemes")) {
+			bool error = false;
+			error |= flib_ini_set_int(ini, "size", schemes->schemeCount);
+			for(int i=0; i<schemes->schemeCount && !error; i++) {
+				error |= writeSchemeToIni(schemes->schemes[i], ini, i);
+			}
+
+			if(!error) {
+				result = flib_ini_save(ini, filename);
+			}
+		}
+		flib_ini_destroy(ini);
+	}
+	return result;
+}
+
+flib_schemelist *flib_schemelist_create() {
+	return flib_schemelist_retain(flib_calloc(1, sizeof(flib_schemelist)));
+}
+
+flib_schemelist *flib_schemelist_retain(flib_schemelist *list) {
+	if(list) {
+		flib_retain(&list->_referenceCount, "flib_schemelist");
+	}
+	return list;
+}
+
+void flib_schemelist_release(flib_schemelist *list) {
+	if(list && flib_release(&list->_referenceCount, "flib_schemelist")) {
+		flib_schemelist_destroy(list);
+	}
+}
+
+flib_cfg *flib_schemelist_find(flib_schemelist *list, const char *name) {
+	if(list && name) {
+		for(int i=0; i<list->schemeCount; i++) {
+			if(!strcmp(name, list->schemes[i]->schemeName)) {
+				return list->schemes[i];
+			}
+		}
+	}
+	return NULL;
+}
+
+int flib_schemelist_insert(flib_schemelist *list, flib_cfg *cfg, int pos) {
+	int result = -1;
+	if(!list || !cfg || pos < 0 || pos > list->schemeCount) {
+		flib_log_e("Invalid parameter in flib_schemelist_insert");
+	} else {
+		flib_cfg **newSchemes = flib_realloc(list->schemes, (list->schemeCount+1)*sizeof(*list->schemes));
+		if(newSchemes) {
+			list->schemes = newSchemes;
+			memmove(list->schemes+pos+1, list->schemes+pos, (list->schemeCount-pos)*sizeof(*list->schemes));
+			list->schemes[pos] = flib_cfg_retain(cfg);
+			list->schemeCount++;
+			result = 0;
+		}
+	}
+	return result;
+}
+
+int flib_schemelist_delete(flib_schemelist *list, int pos) {
+	int result = -1;
+	if(!list || pos < 0 || pos >= list->schemeCount) {
+		flib_log_e("Invalid parameter in flib_schemelist_delete");
+	} else {
+		flib_cfg_release(list->schemes[pos]);
+		memmove(list->schemes+pos, list->schemes+pos+1, (list->schemeCount-(pos+1))*sizeof(*list->schemes));
+		list->schemes[list->schemeCount-1] = NULL;
+		list->schemeCount--;
+
+		// If the realloc fails, just keep using the old buffer...
+		flib_cfg **newSchemes = flib_realloc(list->schemes, list->schemeCount*sizeof(*list->schemes));
+		if(newSchemes || list->schemeCount==1) {
+			list->schemes = newSchemes;
+		}
+		result = 0;
+	}
+	return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/model/schemelist.h	Fri Jun 15 19:57:25 2012 +0200
@@ -0,0 +1,67 @@
+/**
+ * Functions for managing a list of schemes.
+ * This is in here because the scheme config file of the QtFrontend (which we are staying compatble with) contains
+ * all the schemes at once, so we need functions to work with a list like that.
+ */
+
+#ifndef SCHEMELIST_H_
+#define SCHEMELIST_H_
+
+#include "cfg.h"
+
+typedef struct {
+	int _referenceCount;
+	int schemeCount;
+	flib_cfg **schemes;
+} flib_schemelist;
+
+/**
+ * Load a list of configurations from the ini file.
+ * Returns NULL on error.
+ */
+flib_schemelist *flib_schemelist_from_ini(flib_cfg_meta *meta, const char *filename);
+
+/**
+ * Store the list of configurations to an ini file.
+ * Returns NULL on error.
+ */
+int flib_schemelist_to_ini(const char *filename, const flib_schemelist *config);
+
+/**
+ * Create an empty scheme list. Returns NULL on error.
+ */
+flib_schemelist *flib_schemelist_create();
+
+/**
+ * Insert a new scheme into the list at position pos, moving all higher schemes to make place.
+ * pos must be at least 0 (insert at the start) and at most list->schemeCount (insert at the end).
+ * The scheme is retained automatically.
+ * Returns 0 on success.
+ */
+int flib_schemelist_insert(flib_schemelist *list, flib_cfg *cfg, int pos);
+
+/**
+ * Delete a cfg from the list at position pos, moving down all higher schemes.
+ * The scheme is released automatically.
+ * Returns 0 on success.
+ */
+int flib_schemelist_delete(flib_schemelist *list, int pos);
+
+/**
+ * Find the scheme with a specific name
+ */
+flib_cfg *flib_schemelist_find(flib_schemelist *list, const char *name);
+
+/**
+ * Increase the reference count of the object. Call this if you store a pointer to it somewhere.
+ * Returns the parameter.
+ */
+flib_schemelist *flib_schemelist_retain(flib_schemelist *list);
+
+/**
+ * Decrease the reference count of the object and free it if this was the last reference.
+ */
+void flib_schemelist_release(flib_schemelist *list);
+
+
+#endif /* SCHEMELIST_H_ */
--- a/project_files/frontlib/model/team.c	Tue Jun 12 21:10:11 2012 +0200
+++ b/project_files/frontlib/model/team.c	Fri Jun 15 19:57:25 2012 +0200
@@ -194,6 +194,7 @@
 		for(int i=0; i<HEDGEHOGS_PER_TEAM; i++) {
 			free(team->hogs[i].name);
 			free(team->hogs[i].hat);
+			flib_weaponset_release(team->hogs[i].weaponset);
 		}
 		free(team->name);
 		free(team->grave);
@@ -208,7 +209,15 @@
 		}
 		free(team->bindings);
 		free(team->hash);
-		flib_weaponset_destroy(team->weaponset);
 		free(team);
 	}
 }
+
+void flib_team_set_weaponset(flib_team *team, flib_weaponset *set) {
+	if(team) {
+		for(int i=0; i<HEDGEHOGS_PER_TEAM; i++) {
+			flib_weaponset_release(team->hogs[i].weaponset);
+			team->hogs[i].weaponset = flib_weaponset_retain(set);
+		}
+	}
+}
--- a/project_files/frontlib/model/team.h	Tue Jun 12 21:10:11 2012 +0200
+++ b/project_files/frontlib/model/team.h	Fri Jun 15 19:57:25 2012 +0200
@@ -34,6 +34,7 @@
 
 	// Transient setting used in game setup
 	int initialHealth;
+	flib_weaponset *weaponset;
 } flib_hog;
 
 typedef struct {
@@ -57,9 +58,7 @@
 	uint32_t color;
 	int hogsInGame;
 	bool remoteDriven;
-	char *hash; // TODO calculate
-
-	flib_weaponset *weaponset;
+	char *hash; // TODO calculate at the appropriate time... i.e. before trying to send the config to the engine
 } flib_team;
 
 /**
@@ -85,6 +84,12 @@
  * first hog is used for the entire team when writing.
  */
 int flib_team_to_ini(const char *filename, const flib_team *team);
+
+/**
+ * Set the same weaponset for every hog in the team
+ */
+void flib_team_set_weaponset(flib_team *team, flib_weaponset *set);
+
 void flib_team_destroy(flib_team *team);
 
 #endif /* TEAM_H_ */
--- a/project_files/frontlib/model/weapon.c	Tue Jun 12 21:10:11 2012 +0200
+++ b/project_files/frontlib/model/weapon.c	Fri Jun 15 19:57:25 2012 +0200
@@ -3,118 +3,177 @@
 #include "../util/inihelper.h"
 #include "../util/logging.h"
 #include "../util/util.h"
+#include "../util/refcounter.h"
 
 #include <stdlib.h>
 #include <ctype.h>
-
-int set_field(char field[WEAPONS_COUNT+1], const char *line, bool no9) {
-	// Validate the new string
-	for(int i=0; i<WEAPONS_COUNT && line[i]; i++) {
-		if(line[i] < '0' || line[i] > '9' || (no9 && line[i] == '9')) {
-			flib_log_e("Invalid character in weapon config string \"%.*s\", position %i", WEAPONS_COUNT, line, i);
-			return -1;
-		}
-	}
-
-	bool lineEnded = false;
-	for(int i=0; i<WEAPONS_COUNT; i++) {
-		if(!lineEnded && !line[i]) {
-			flib_log_w("Incomplete weapon config line \"%s\", filling with zeroes.", line);
-			lineEnded = true;
-		}
-		if(lineEnded) {
-			field[i] = '0';
-		} else {
-			field[i] = line[i];
-		}
-	}
-	field[WEAPONS_COUNT] = 0;
-	return 0;
-}
+#include <string.h>
 
-static flib_weaponset *flib_weaponset_create_str(const char *name, const char *loadoutStr, const char *crateProbStr, const char *crateAmmoStr, const char *delayStr) {
-	flib_weaponset *result = NULL;
-	if(!name || !loadoutStr || !crateProbStr || !crateAmmoStr || !delayStr) {
-		flib_log_e("null parameter in flib_weaponset_create_str");
-	} else {
-		flib_weaponset *newSet = flib_calloc(1, sizeof(flib_weaponset));
-		char *nameCopy = flib_strdupnull(name);
-		if(newSet && nameCopy) {
-			newSet->name = nameCopy;
-			nameCopy = NULL;
-			bool error = false;
-			error |= set_field(newSet->loadout, loadoutStr, false);
-			error |= set_field(newSet->crateprob, crateProbStr, false);
-			error |= set_field(newSet->crateammo, crateAmmoStr, false);
-			error |= set_field(newSet->delay, delayStr, false);
-			if(!error) {
-				result = newSet;
-				newSet = NULL;
-			}
-		}
-		free(nameCopy);
-		flib_weaponset_destroy(newSet);
-	}
-	return result;
-}
-
-void flib_weaponset_destroy(flib_weaponset *cfg) {
+static void flib_weaponset_destroy(flib_weaponset *cfg) {
 	if(cfg) {
 		free(cfg->name);
 		free(cfg);
 	}
 }
 
+static void setField(char field[WEAPONS_COUNT+1], const char *line, int lineLen, bool no9) {
+	if(lineLen>WEAPONS_COUNT) {
+		lineLen = WEAPONS_COUNT;
+	}
+
+	char min = '0';
+	char max = no9 ? '8' : '9';
+	for(int i=0; i<lineLen; i++) {
+		if(line[i] >= min && line[i] <= max) {
+			field[i] = line[i];
+		} else {
+			flib_log_w("Invalid character in weapon config string \"%.*s\", position %i", lineLen, line, i);
+			field[i] = '0';
+		}
+	}
+	for(int i=lineLen; i<WEAPONS_COUNT; i++) {
+		field[i] = '0';
+	}
+	field[WEAPONS_COUNT] = 0;
+}
+
 flib_weaponset *flib_weaponset_create(const char *name) {
-	return flib_weaponset_create_str(name, AMMOLINE_DEFAULT_QT, AMMOLINE_DEFAULT_PROB, AMMOLINE_DEFAULT_CRATE, AMMOLINE_DEFAULT_DELAY);
+	flib_weaponset *result = NULL;
+	if(!name) {
+		flib_log_e("null parameter in flib_weaponset_create_str");
+	} else {
+		flib_weaponset *newSet = flib_weaponset_retain(flib_calloc(1, sizeof(flib_weaponset)));
+		if(newSet) {
+			newSet->name = flib_strdupnull(name);
+			if(newSet->name) {
+				setField(newSet->loadout, "", 0, false);
+				setField(newSet->crateprob, "", 0, false);
+				setField(newSet->crateammo, "", 0, false);
+				setField(newSet->delay, "", 0, false);
+				result = flib_weaponset_retain(newSet);
+			}
+		}
+		flib_weaponset_release(newSet);
+	}
+	return result;
+}
+
+flib_weaponset *flib_weaponset_retain(flib_weaponset *weaponset) {
+	if(weaponset) {
+		flib_retain(&weaponset->_referenceCount, "flib_weaponset");
+	}
+	return weaponset;
 }
 
-flib_weaponset *flib_weaponset_from_ini(const char *filename) {
-	flib_weaponset *result = NULL;
+void flib_weaponset_release(flib_weaponset *weaponset) {
+	if(weaponset && flib_release(&weaponset->_referenceCount, "flib_weaponset")) {
+		flib_weaponset_destroy(weaponset);
+	}
+}
+
+static void flib_weaponsetlist_destroy(flib_weaponsetlist *list) {
+	if(list) {
+		for(int i=0; i<list->weaponsetCount; i++) {
+			flib_weaponset_release(list->weaponsets[i]);
+		}
+		free(list);
+	}
+}
+
+static int fillWeaponsetFromIni(flib_weaponsetlist *list, flib_ini *ini, int index) {
+	int result = -1;
+	char *keyname = flib_ini_get_keyname(ini, index);
+	char *decodedKeyname = flib_urldecode(keyname);
+
+	if(decodedKeyname) {
+		flib_weaponset *set = flib_weaponset_create(decodedKeyname);
+		if(set) {
+			char *value = NULL;
+			if(!flib_ini_get_str(ini, &value, keyname)) {
+				int fieldlen = strlen(value)/4;
+				setField(set->loadout, value, fieldlen, false);
+				setField(set->crateprob, value+1*fieldlen, fieldlen, true);
+				setField(set->delay, value+2*fieldlen, fieldlen, true);
+				setField(set->crateammo, value+3*fieldlen, fieldlen, true);
+				result = flib_weaponsetlist_insert(list, set, list->weaponsetCount);
+			}
+			free(value);
+		}
+		flib_weaponset_release(set);
+	}
+
+	free(keyname);
+	free(decodedKeyname);
+	return result;
+}
+
+static int fillWeaponsetsFromIni(flib_weaponsetlist *list, flib_ini *ini) {
+	bool error = false;
+	int weaponsets = flib_ini_get_keycount(ini);
+
+	for(int i=0; i<weaponsets && !error; i++) {
+		error |= fillWeaponsetFromIni(list, ini, i);
+	}
+	return error;
+}
+
+flib_weaponsetlist *flib_weaponsetlist_from_ini(const char *filename) {
+	flib_weaponsetlist *result = NULL;
 	if(!filename) {
-		flib_log_e("null parameter in flib_weaponset_from_ini");
+		flib_log_e("null parameter in flib_weaponsetlist_from_ini");
 	} else {
 		flib_ini *ini = flib_ini_load(filename);
 		if(!ini) {
-			flib_log_e("Error loading weapon scheme file %s", filename);
-		} else if(!flib_ini_enter_section(ini, "weaponset")) {
-			bool error = false;
-			char *name = NULL, *loadout = NULL, *crateprob = NULL, *crateammo = NULL, *delay = NULL;
-			error |= flib_ini_get_str(ini, &name, "name");
-			error |= flib_ini_get_str(ini, &loadout, "loadout");
-			error |= flib_ini_get_str(ini, &crateprob, "crateprob");
-			error |= flib_ini_get_str(ini, &crateammo, "crateammo");
-			error |= flib_ini_get_str(ini, &delay, "delay");
-
-			if(error) {
-				flib_log_e("Missing key in weapon scheme file %s", filename);
-			} else {
-				result = flib_weaponset_create_str(name, loadout, crateprob, crateammo, delay);
+			flib_log_e("Missing file %s.", filename);
+		} else if(flib_ini_enter_section(ini, "General")) {
+			flib_log_e("Missing section \"General\" in file %s.", filename);
+		} else {
+			flib_weaponsetlist *list = flib_weaponsetlist_create();
+			if(list) {
+				if(!fillWeaponsetsFromIni(list, ini)) {
+					result = flib_weaponsetlist_retain(list);
+				}
 			}
-			free(name);
-			free(loadout);
-			free(crateprob);
-			free(crateammo);
-			free(delay);
+			flib_weaponsetlist_release(list);
 		}
 		flib_ini_destroy(ini);
 	}
 	return result;
 }
 
-int flib_weaponset_to_ini(const char *filename, const flib_weaponset *set) {
+static bool needsEscape(char c) {
+	return !((c>='0' && c<='9') || (c>='a' && c <='z'));
+}
+
+
+static int writeWeaponsetToIni(flib_ini *ini, flib_weaponset *set) {
 	int result = -1;
-	if(!filename || !set) {
-		flib_log_e("null parameter in flib_weaponset_to_ini");
+	char weaponstring[WEAPONS_COUNT*4+1];
+	strcpy(weaponstring, set->loadout);
+	strcat(weaponstring, set->crateprob);
+	strcat(weaponstring, set->delay);
+	strcat(weaponstring, set->crateammo);
+
+	char *escapedname = flib_urlencode_pred(set->name, needsEscape);
+	if(escapedname) {
+		result = flib_ini_set_str(ini, escapedname, weaponstring);
+	}
+	free(escapedname);
+	return result;
+}
+
+int flib_weaponsetlist_to_ini(const char *filename, const flib_weaponsetlist *list) {
+	int result = -1;
+	if(!filename || !list) {
+		flib_log_e("null parameter in flib_weaponsetlist_to_ini");
 	} else {
-		flib_ini *ini = flib_ini_create(filename);
-		if(!flib_ini_create_section(ini, "weaponset")) {
+		flib_ini *ini = flib_ini_create(NULL);
+		if(ini && !flib_ini_create_section(ini, "General")) {
 			bool error = false;
-			error |= flib_ini_set_str(ini, "name", set->name);
-			error |= flib_ini_set_str(ini, "loadout", set->loadout);
-			error |= flib_ini_set_str(ini, "crateprob", set->crateprob);
-			error |= flib_ini_set_str(ini, "crateammo", set->crateammo);
-			error |= flib_ini_set_str(ini, "delay", set->delay);
+			for(int i=0; i<list->weaponsetCount && !error; i++) {
+				error |= writeWeaponsetToIni(ini, list->weaponsets[i]);
+			}
+
 			if(!error) {
 				result = flib_ini_save(ini, filename);
 			}
@@ -123,3 +182,57 @@
 	}
 	return result;
 }
+
+flib_weaponsetlist *flib_weaponsetlist_create() {
+	return flib_weaponsetlist_retain(flib_calloc(1, sizeof(flib_weaponsetlist)));
+}
+
+int flib_weaponsetlist_insert(flib_weaponsetlist *list, flib_weaponset *weaponset, int pos) {
+	int result = -1;
+	if(!list || !weaponset || pos < 0 || pos > list->weaponsetCount) {
+		flib_log_e("Invalid parameter in flib_weaponsetlist_insert");
+	} else {
+		flib_weaponset **newSets = flib_realloc(list->weaponsets, (list->weaponsetCount+1)*sizeof(*list->weaponsets));
+		if(newSets) {
+			list->weaponsets = newSets;
+			memmove(list->weaponsets+pos+1, list->weaponsets+pos, (list->weaponsetCount-pos)*sizeof(*list->weaponsets));
+			list->weaponsets[pos] = flib_weaponset_retain(weaponset);
+			list->weaponsetCount++;
+			result = 0;
+		}
+	}
+	return result;
+}
+
+int flib_weaponsetlist_delete(flib_weaponsetlist *list, int pos) {
+	int result = -1;
+	if(!list || pos < 0 || pos >= list->weaponsetCount) {
+		flib_log_e("Invalid parameter in flib_weaponsetlist_delete");
+	} else {
+		flib_weaponset_release(list->weaponsets[pos]);
+		memmove(list->weaponsets+pos, list->weaponsets+pos+1, (list->weaponsetCount-(pos+1))*sizeof(*list->weaponsets));
+		list->weaponsets[list->weaponsetCount-1] = NULL;
+		list->weaponsetCount--;
+
+		// If the realloc fails, just keep using the old buffer...
+		flib_weaponset **newSets = flib_realloc(list->weaponsets, list->weaponsetCount*sizeof(*list->weaponsets));
+		if(newSets || list->weaponsetCount==1) {
+			list->weaponsets = newSets;
+		}
+		result = 0;
+	}
+	return result;
+}
+
+flib_weaponsetlist *flib_weaponsetlist_retain(flib_weaponsetlist *list) {
+	if(list) {
+		flib_retain(&list->_referenceCount, "flib_weaponsetlist");
+	}
+	return list;
+}
+
+void flib_weaponsetlist_release(flib_weaponsetlist *list) {
+	if(list && flib_release(&list->_referenceCount, "flib_weaponsetlist")) {
+		flib_weaponsetlist_destroy(list);
+	}
+}
--- a/project_files/frontlib/model/weapon.h	Tue Jun 12 21:10:11 2012 +0200
+++ b/project_files/frontlib/model/weapon.h	Fri Jun 15 19:57:25 2012 +0200
@@ -10,6 +10,7 @@
  * For the other setting, 9 is invalid.
  */
 typedef struct {
+	int _referenceCount;
 	char loadout[WEAPONS_COUNT+1];
 	char crateprob[WEAPONS_COUNT+1];
 	char crateammo[WEAPONS_COUNT+1];
@@ -17,6 +18,12 @@
 	char *name;
 } flib_weaponset;
 
+typedef struct {
+	int _referenceCount;
+	int weaponsetCount;
+	flib_weaponset **weaponsets;
+} flib_weaponsetlist;
+
 /**
  * Returns a new weapon set, or NULL on error.
  * name must not be NULL.
@@ -27,15 +34,57 @@
 flib_weaponset *flib_weaponset_create(const char *name);
 
 /**
- * Loads a weapon set, returns NULL on error.
+ * Increase the reference count of the object. Call this if you store a pointer to it somewhere.
+ * Returns the parameter.
+ */
+flib_weaponset *flib_weaponset_retain(flib_weaponset *weaponset);
+
+/**
+ * Decrease the reference count of the object and free it if this was the last reference.
  */
-flib_weaponset *flib_weaponset_from_ini(const char *filename);
+void flib_weaponset_release(flib_weaponset *weaponset);
+
+/**
+ * Load a list of weaponsets from the ini file.
+ * Returns NULL on error.
+ */
+flib_weaponsetlist *flib_weaponsetlist_from_ini(const char *filename);
+
+/**
+ * Store the list of weaponsets to an ini file.
+ * Returns NULL on error.
+ */
+int flib_weaponsetlist_to_ini(const char *filename, const flib_weaponsetlist *weaponsets);
 
 /**
- * Write the weapon set to an ini file. Attempts to
- * retain extra ini settings that were already present.
+ * Create an empty weaponset list. Returns NULL on error.
+ */
+flib_weaponsetlist *flib_weaponsetlist_create();
+
+/**
+ * Insert a new weaponset into the list at position pos, moving all higher weaponsets to make place.
+ * pos must be at least 0 (insert at the start) and at most list->weaponsetCount (insert at the end).
+ * The weaponset is retained automatically.
+ * Returns 0 on success.
  */
-int flib_weaponset_to_ini(const char *filename, const flib_weaponset *set);
-void flib_weaponset_destroy(flib_weaponset *set);
+int flib_weaponsetlist_insert(flib_weaponsetlist *list, flib_weaponset *weaponset, int pos);
+
+/**
+ * Delete a weaponset from the list at position pos, moving down all higher weaponsets.
+ * The weaponset is released automatically.
+ * Returns 0 on success.
+ */
+int flib_weaponsetlist_delete(flib_weaponsetlist *list, int pos);
+
+/**
+ * Increase the reference count of the object. Call this if you store a pointer to it somewhere.
+ * Returns the parameter.
+ */
+flib_weaponsetlist *flib_weaponsetlist_retain(flib_weaponsetlist *list);
+
+/**
+ * Decrease the reference count of the object and free it if this was the last reference.
+ */
+void flib_weaponsetlist_release(flib_weaponsetlist *list);
 
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/resources/metasettings.ini	Fri Jun 15 19:57:25 2012 +0200
@@ -0,0 +1,234 @@
+[mod0]
+name=fortsmode
+bitmaskindex=12
+
+[mod1]
+name=divteams
+bitmaskindex=4
+
+[mod2]
+name=solidland
+bitmaskindex=2
+
+[mod3]
+name=border
+bitmaskindex=3
+
+[mod4]
+name=lowgrav
+bitmaskindex=5
+
+[mod5]
+name=laser
+bitmaskindex=6
+
+[mod6]
+name=invulnerability
+bitmaskindex=7
+
+[mod7]
+name=resethealth
+bitmaskindex=8
+
+[mod8]
+name=vampiric
+bitmaskindex=9
+
+[mod9]
+name=karma
+bitmaskindex=10
+
+[mod10]
+name=artillery
+bitmaskindex=11
+
+[mod11]
+name=randomorder
+bitmaskindex=13
+
+[mod12]
+name=king
+bitmaskindex=14
+
+[mod13]
+name=placehog
+bitmaskindex=15
+
+[mod14]
+name=sharedammo
+bitmaskindex=16
+
+[mod15]
+name=disablegirders
+bitmaskindex=17
+
+[mod16]
+name=disablelandobjects
+bitmaskindex=18
+
+[mod17]
+name=aisurvival
+bitmaskindex=19
+
+[mod18]
+name=infattack
+bitmaskindex=20
+
+[mod19]
+name=resetweps
+bitmaskindex=21
+
+[mod20]
+name=perhogammo
+bitmaskindex=22
+
+[mod21]
+name=disablewind
+bitmaskindex=23
+
+[mod22]
+name=morewind
+bitmaskindex=24
+
+[mod23]
+name=tagteam
+bitmaskindex=25
+
+[mod24]
+name=bottomborder
+bitmaskindex=26
+
+
+[setting0]
+name=damagefactor
+times1000=false
+command=e$damagepct
+maxmeansinfinity=false
+min=10
+max=300
+default=100
+
+[setting1]
+name=turntime
+times1000=true
+command=e$turntime
+maxmeansinfinity=true
+min=1
+max=9999
+default=45
+
+[setting2]
+name=health
+times1000=false
+maxmeansinfinity=false
+min=50
+max=200
+default=100
+
+[setting3]
+name=suddendeath
+times1000=false
+command=e$sd_turns
+maxmeansinfinity=true
+min=0
+max=50
+default=15
+
+[setting4]
+name=caseprobability
+times1000=false
+command=e$casefreq
+maxmeansinfinity=false
+min=0
+max=9
+default=5
+
+[setting5]
+name=minestime
+times1000=true
+command=e$minestime
+maxmeansinfinity=false
+min=-1
+max=5
+default=3
+
+[setting6]
+name=minesnum
+times1000=false
+command=e$minesnum
+maxmeansinfinity=false
+min=0
+max=80
+default=4
+
+[setting7]
+name=minedudpct
+times1000=false
+command=e$minedudpct
+maxmeansinfinity=false
+min=0
+max=100
+default=0
+
+[setting8]
+name=explosives
+times1000=false
+command=e$explosives
+maxmeansinfinity=false
+min=0
+max=40
+default=2
+
+[setting9]
+name=healthprobability
+times1000=false
+command=e$healthprob
+maxmeansinfinity=false
+min=0
+max=100
+default=35
+
+[setting10]
+name=healthcaseamount
+times1000=false
+command=e$hcaseamount
+maxmeansinfinity=false
+min=0
+max=200
+default=25
+
+[setting11]
+name=waterrise
+times1000=false
+command=e$waterrise
+maxmeansinfinity=false
+min=0
+max=100
+default=47
+
+[setting12]
+name=healthdecrease
+times1000=false
+command=e$healthdec
+maxmeansinfinity=false
+min=0
+max=100
+default=5
+
+[setting13]
+name=ropepct
+times1000=false
+command=e$ropepct
+maxmeansinfinity=false
+min=25
+max=999
+default=100
+
+[setting14]
+name=getawaytime
+times1000=false
+command=e$getawaytime
+maxmeansinfinity=false
+min=0
+max=999
+default=100
--- a/project_files/frontlib/test.c	Tue Jun 12 21:10:11 2012 +0200
+++ b/project_files/frontlib/test.c	Fri Jun 15 19:57:25 2012 +0200
@@ -1,6 +1,8 @@
 #include "frontlib.h"
 #include "util/logging.h"
 #include "model/map.h"
+#include "model/weapon.h"
+#include "model/schemelist.h"
 #include "ipc/mapconn.h"
 #include "ipc/gameconn.h"
 
@@ -80,7 +82,7 @@
 	assert(mapConnection);
 
 	// We don't need the map description anymore
-	flib_map_destroy(map);
+	flib_map_release(map);
 	map = NULL;
 
 	// Register the callback functions
@@ -99,10 +101,13 @@
 }
 
 void testGame() {
-	flib_cfg_meta *metaconf = flib_cfg_meta_from_ini("basicsettings.ini", "gamemods.ini");
+	flib_cfg_meta *metaconf = flib_cfg_meta_from_ini("metasettings.ini");
 	assert(metaconf);
+	flib_weaponset *weapons = flib_weaponset_create("Defaultweaps");
+	flib_schemelist *schemelist = flib_schemelist_from_ini(metaconf, "schemes.ini");
+
 	flib_gamesetup setup;
-	setup.gamescheme = flib_cfg_from_ini(metaconf, "scheme_shoppa.ini");
+	setup.gamescheme = flib_schemelist_find(schemelist, "Default");
 	setup.map = flib_map_create_maze("Jungle", MAZE_SIZE_MEDIUM_TUNNELS);
 	setup.seed = "asparagus";
 	setup.script = NULL;
@@ -116,7 +121,6 @@
 	setup.teams[0]->hogsInGame = 2;
 	setup.teams[0]->name = "Team Awesome";
 	setup.teams[0]->voicepack = "British";
-	setup.teams[0]->weaponset = flib_weaponset_create("Defaultweaps");
 	setup.teams[0]->hogs[0].difficulty = 2;
 	setup.teams[0]->hogs[0].hat = "NoHat";
 	setup.teams[0]->hogs[0].initialHealth = 100;
@@ -126,15 +130,17 @@
 	setup.teams[0]->hogs[1].initialHealth = 100;
 	setup.teams[0]->hogs[1].name = "Chefkoch";
 	setup.teams[1] = flib_team_from_ini("Cave Dwellers.hwt");
-	setup.teams[1]->color = 0xff0000ff;
+	setup.teams[1]->color = 0xFF0000F0;
 	setup.teams[1]->hogsInGame = 8;
-	setup.teams[1]->weaponset = flib_weaponset_create("Defaultweaps");
+	flib_team_set_weaponset(setup.teams[0], weapons);
+	flib_team_set_weaponset(setup.teams[1], weapons);
+	flib_weaponset_release(weapons);
 
-	flib_gameconn *gameconn = flib_gameconn_create("Medo42", metaconf, &setup, false);
+	flib_gameconn *gameconn = flib_gameconn_create("Medo42", &setup, false);
 	assert(gameconn);
 
 	flib_gameconn_onDisconnect(gameconn, &onDisconnect, &gameconn);
-	flib_gameconn_onGameRecorded(gameconn, &onGameRecorded, &gameconn);
+	//flib_gameconn_onGameRecorded(gameconn, &onGameRecorded, &gameconn);
 
 	startEngineGame(flib_gameconn_getport(gameconn));
 
@@ -196,7 +202,20 @@
 	//testMapPreview();
 	//testDemo();
 	//testSave();
-	testGame();
+	//testGame();
+
+	flib_cfg_meta *meta = flib_cfg_meta_from_ini("metasettings.ini");
+	assert(meta);
+	flib_schemelist *schemelist = flib_schemelist_from_ini(meta, "schemes.ini");
+	assert(schemelist);
+
+	flib_schemelist_to_ini("Copy of Schemelist.ini", schemelist);
+	flib_schemelist_release(schemelist);
+	flib_cfg_meta_release(meta);
+
+	flib_weaponsetlist *weaponsets = flib_weaponsetlist_from_ini("weapons.ini");
+	assert(!flib_weaponsetlist_to_ini("copy of weapons.ini", weaponsets));
+	flib_weaponsetlist_release(weaponsets);
 
 	flib_quit();
 	return 0;
--- a/project_files/frontlib/util/inihelper.c	Tue Jun 12 21:10:11 2012 +0200
+++ b/project_files/frontlib/util/inihelper.c	Fri Jun 15 19:57:25 2012 +0200
@@ -179,7 +179,7 @@
 			value = def;
 		}
 		char *valueDup = flib_strdupnull(value);
-		if(valueDup) {
+		if(valueDup || !def) {
 			*outVar = valueDup;
 			result = 0;
 		}
@@ -209,7 +209,7 @@
 	int result = flib_ini_get_int(ini, &tmpValue, key);
 	if(result == 0) {
 		*outVar = tmpValue;
-	} else if(result == INI_ERROR_NOTFOUND) {
+	} else if(result == INI_ERROR_NOTFOUND || result == INI_ERROR_FORMAT) {
 		*outVar = def;
 		result = 0;
 	}
@@ -238,7 +238,7 @@
 	int result = flib_ini_get_bool(ini, &tmpValue, key);
 	if(result == 0) {
 		*outVar = tmpValue;
-	} else if(result == INI_ERROR_NOTFOUND) {
+	} else if(result == INI_ERROR_NOTFOUND || result == INI_ERROR_FORMAT) {
 		*outVar = def;
 		result = 0;
 	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/util/refcounter.h	Fri Jun 15 19:57:25 2012 +0200
@@ -0,0 +1,51 @@
+/**
+ * Helper functions for reference counted structs.
+ *
+ * We don't have enough of them to justify going crazy with macros, but I still prefer
+ * to have the logic in one place.
+ *
+ * In particular, these functions handle counter overflow in a sensible way
+ * (log and leak).
+ */
+
+#ifndef REFCOUNTER_H_
+#define REFCOUNTER_H_
+
+#include "logging.h"
+#include <stdbool.h>
+
+static inline void flib_retain(int *referenceCountPtr, const char *objName) {
+	if(!referenceCountPtr || !objName) {
+		flib_log_e("null parameter to flib_retain");
+	} else {
+		if((*referenceCountPtr)  >= 0) {
+			(*referenceCountPtr)++;
+			flib_log_d("retaining %s, now %i references", objName, (*referenceCountPtr));
+		}
+		if((*referenceCountPtr) < 0) {
+			flib_log_e("Memory leak: Reference count overflow in %s object!", objName);
+		}
+	}
+}
+
+/**
+ * Returns true if the struct should be freed.
+ */
+static inline bool flib_release(int *referenceCountPtr, const char *objName) {
+	bool result = false;
+	if(!referenceCountPtr) {
+		flib_log_e("null parameter to flib_release");
+	} else if((*referenceCountPtr) > 0) {
+		if(--(*referenceCountPtr) == 0) {
+			flib_log_d("releasing and destroying %s", objName);
+			result = true;
+		} else {
+			flib_log_d("releasing %s, now %i references", objName, (*referenceCountPtr));
+		}
+	} else if((*referenceCountPtr) == 0) {
+		flib_log_e("Attempt to release a %s with zero references!", objName);
+	}
+	return result;
+}
+
+#endif /* REFCOUNTER_H_ */
--- a/project_files/frontlib/util/util.c	Tue Jun 12 21:10:11 2012 +0200
+++ b/project_files/frontlib/util/util.c	Fri Jun 15 19:57:25 2012 +0200
@@ -56,7 +56,7 @@
 
 void *flib_malloc(size_t size) {
 	void *result = malloc(size);
-	if(!result) {
+	if(!result && size>0) {
 		flib_log_e("Out of memory trying to malloc %zu bytes.", size);
 	}
 	return result;
@@ -64,17 +64,29 @@
 
 void *flib_calloc(size_t count, size_t elementsize) {
 	void *result = calloc(count, elementsize);
-	if(!result) {
+	if(!result && count>0 && elementsize>0) {
 		flib_log_e("Out of memory trying to calloc %zu objects of %zu bytes each.", count, elementsize);
 	}
 	return result;
 }
 
+void *flib_realloc(void *ptr, size_t size) {
+	void *result = realloc(ptr, size);
+	if(!result && size>0) {
+		flib_log_e("Out of memory trying to realloc %zu bytes.", size);
+	}
+	return result;
+}
+
 static bool isAsciiAlnum(char c) {
 	return (c>='0' && c<='9') || (c>='a' && c <='z') || (c>='A' && c <='Z');
 }
 
 char *flib_urlencode(const char *inbuf) {
+	return flib_urlencode_pred(inbuf, isAsciiAlnum);
+}
+
+char *flib_urlencode_pred(const char *inbuf, bool (*needsEscaping)(char c)) {
 	if(!inbuf) {
 		return NULL;
 	}
@@ -91,7 +103,7 @@
 
     size_t inpos = 0, outpos = 0;
     while(inbuf[inpos]) {
-        if(isAsciiAlnum(inbuf[inpos])) {
+        if(!needsEscaping(inbuf[inpos])) {
         	outbuf[outpos++] = inbuf[inpos++];
         } else {
             if(snprintf(outbuf+outpos, 4, "%%%02X", (unsigned)((uint8_t*)inbuf)[inpos])<0) {
--- a/project_files/frontlib/util/util.h	Tue Jun 12 21:10:11 2012 +0200
+++ b/project_files/frontlib/util/util.h	Fri Jun 15 19:57:25 2012 +0200
@@ -3,6 +3,7 @@
 
 #include <stddef.h>
 #include <stdarg.h>
+#include <stdbool.h>
 
 /**
  * Prints a format string to a newly allocated buffer of the required size.
@@ -46,6 +47,12 @@
 void *flib_calloc(size_t count, size_t elementsize);
 
 /**
+ * Simple realloc wrapper that automatically logs an error if no memory
+ * is available. Otherwise behaves exactly like realloc.
+ */
+void *flib_realloc(void *ptr, size_t size);
+
+/**
  * Replace all non-alphanumeric and non-ascii bytes with escape
  * sequences in the form %XX. Does not modify the original string,
  * but returns a newly allocated one that must be free()d. Returns
@@ -56,6 +63,17 @@
 char *flib_urlencode(const char *str);
 
 /**
+ * Replace some bytes with escape sequences in the form %XX.
+ * Does not modify the original string, but returns a newly allocated
+ * one that must be free()d.
+ *
+ * All bytes for which the predicate function returns true are escaped.
+ *
+ * Returns null on failure or if null was passed as argument.
+ */
+char *flib_urlencode_pred(const char *str, bool (*needsEscaping)(char c));
+
+/**
  * Replace escape sequences of the form %XX with their byte values.
  * Does not modify the original string, but returns a newly allocated
  * one that must be free()d. Returns null on failure or if null was