Index: Daodan/src/Daodan.c
===================================================================
--- Daodan/src/Daodan.c	(revision 992)
+++ Daodan/src/Daodan.c	(revision 993)
@@ -27,13 +27,13 @@
 	time(&rawtime);
 	timeinfo = localtime(&rawtime);
-	strftime(buffer, 80, "Daodan: %Y-%m-%d %H:%M:%S", timeinfo);
+	strftime(buffer, 80, "%Y-%m-%d %H:%M:%S", timeinfo);
 
-	DDrStartupMessage("Daodan: Daodan v."DAODAN_VERSION_STRING" attached!");
-	DDrStartupMessage(buffer);
+	STARTUPMESSAGE("Daodan v."DAODAN_VERSION_STRING" attached!", 0);
+	STARTUPMESSAGE("%s", buffer);
 	
 	DDrConfig(argc, argv);
 
 	if(GetKeyState(VK_SHIFT) & 0x8000) {
-		DDrStartupMessage("Daodan: Shift");
+		STARTUPMESSAGE("Shift", 0);
 		guitest(DDrONiModule);
 	}
Index: Daodan/src/Daodan_BSL.c
===================================================================
--- Daodan/src/Daodan_BSL.c	(revision 992)
+++ Daodan/src/Daodan_BSL.c	(revision 993)
@@ -726,5 +726,5 @@
 		
 		if (!*type)
-			DDrStartupMessage("Daodan: Badly formed bsl definition for \"%s\"", name);
+			STARTUPMESSAGE("Badly formed bsl definition for \"%s\"", name);
 		
 		if (!strcmp(type, "int"))
@@ -738,5 +738,5 @@
 		else
 		{
-			DDrStartupMessage("Daodan: Unknown type in bsl definition for \"%s\"", name);
+			STARTUPMESSAGE("Unknown type in bsl definition for \"%s\"", name);
 			return true;
 		}
@@ -783,7 +783,7 @@
 void SLrConfig()
 {
-	DDrStartupMessage("Daodan: Re-parsing daodan.ini for bsl...");
+	STARTUPMESSAGE("Re-parsing daodan.ini for bsl...", 0);
 	inifile_read("daodan.ini", SLrIniCallback);
-	DDrStartupMessage("Daodan: Finished parsing");
+	STARTUPMESSAGE("Finished parsing", 0);
 }
 */
@@ -797,8 +797,8 @@
 		if(errornum)
 		{
-			DDrStartupMessage("Daodan: Registration of script command %s failed with error %i", name, errornum);
+			STARTUPMESSAGE("Registration of script command %s failed with error %i", name, errornum);
 		}
 	} else {
-		DDrStartupMessage("Daodan: Registration of script command %s failed because of a too long argfmt", name);
+		STARTUPMESSAGE("Registration of script command %s failed because of a too long argfmt", name);
 	}
 }
Index: Daodan/src/Daodan_Cheater.c
===================================================================
--- Daodan/src/Daodan_Cheater.c	(revision 992)
+++ Daodan/src/Daodan_Cheater.c	(revision 993)
@@ -8,4 +8,5 @@
 
 #include "Daodan.h"
+#include "Daodan_Config.h"
 #include "Daodan_Cheater.h"
 
@@ -97,5 +98,5 @@
 float cheat_oldheight2 = 135;
 bool inc_fallingframes = true;
-extern bool patch_bsl;
+
 uint8_t ONICALL DDrCheater(uint32_t cheat)
 {
@@ -252,5 +253,7 @@
 		case cheat_elderrune:
 		{
-			if(patch_bsl) {
+			ConfigOption_t* co = DDrConfig_GetOptOfType("patch.bsl", C_BOOL);
+			if (co->value.intBoolVal)
+			{
 				int* Regeneration = &ONgGameState->PlayerCharacter->RegenHax;
 				if(*Regeneration)
Index: Daodan/src/Daodan_Config.c
===================================================================
--- Daodan/src/Daodan_Config.c	(revision 992)
+++ Daodan/src/Daodan_Config.c	(revision 993)
@@ -11,171 +11,436 @@
 #include "Inifile_Reader.h"
 
-bool patch_alttab = true;
-bool patch_argb8888 = true;
-bool patch_binkplay = true;
-bool patch_bsl = true;
-bool patch_cheater = true;
-bool patch_cheatsenabled = true;
-bool patch_cheattable = true;
-bool patch_clipcursor = true;
-bool patch_cooldowntimer = true;
-bool patch_daodandisplayenum = true;
-bool patch_directinput = true;
-bool patch_disablecmdline = true;
-bool patch_flatline = true;
-bool patch_fonttexturecache = true;
-bool patch_getcmdline = true;
-bool patch_hdscreens_lowres = true;
-bool patch_highres_console = true;
-bool patch_kickguns = false;
-bool patch_killvtune = true;
-bool patch_largetextures = true;
-bool patch_levelplugins = true;
-bool patch_newweapon = true;
-bool patch_nomultibyte = true;
-bool patch_optionsvisible = true;
-bool patch_particledisablebit = false;
-bool patch_pathfinding = true;
-bool patch_projaware = true;
-bool patch_safeprintf = true;
-bool patch_showalllasersights = false;
-bool patch_showtriggervolumes = true;
-bool patch_throwtest = false;
-bool patch_usedaodangl = true;
-bool patch_usegettickcount = true;
-bool patch_wpfadetime = true;
-
-bool opt_border = true;
-bool opt_gamma = true;
-bool opt_topmost = false;
-bool opt_usedaodanbsl = true;
-
-bool patch_chinese = true;
-
-
-enum {s_unknown, s_options, s_patch, s_bsl, s_language} ini_section;
-
-bool DDrIniCallback(char* section, bool newsection, char* name, char* value)
-{
-	if (newsection)
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
+
+static const char* iniName = "daodan.ini";
+
+ConfigSection_t config[] = {
+	{ "patches", "Patches", {
+		{ "alttab",
+			"Allows user to switch applications while in Oni (Alt-Tab) and use Windows key, however it may enable the screensaver as well.",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "argb8888",
+			"Textures using ARGB8888 can be used.",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "binkplay",
+			"Fix binkplay calls to use GDI and outro same mode as intro.",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "bsl",
+			"Enables d_regen (unfinished) and prevents fly-in portraits from being stretched when playing in widescreen resolutions.",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "cheater",
+			"Adds new cheat codes (see section below).",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "cheatsenabled",
+			"Enables cheats without having to beat the game first.",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "cheattable",
+			"Replaces Oni's cheat table with table that includes new cheats (see section below).",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "chinese",
+			"Allow for chinese fonts to be shown.",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "clipcursor",
+			"Limit cursor to Oni's window.",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "cooldowntimer",
+			"Disables weapon cooldown exploit.",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "daodandisplayenum",
+			"Offers more display modes in the Options menu.",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "directinput",
+			"Forces on DirectInput.",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "disablecmdline",
+			"Replaces existing command line parser with Daodan's in order to add new commands. Meant to be used with getcmdline.",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "fonttexturecache",
+			"Doubles size of font texture cache.",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "getcmdline",
+			"Replaces existing command line parser with Daodan's in order to add new commands. Meant to be used with disablecmdline.",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "hdscreens_lowres",
+			"???",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "highres_console",
+			"Fixes bug where console line becomes invisible at higher resolutions.",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "kickguns",
+			"Unfinished, do not use.",
+			C_BOOL,
+			{.intBoolVal = false},
+			{.intBoolVal = false} },
+		{ "largetextures",
+			"Textures up to 512x512 can be used.",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "levelplugins",
+			"Allows level files to be loaded from the GDF which do not end in \"_Final\".",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "newweap",
+			"Picking up a weapon displays a message containing the weapon name and amount of ammo.",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "nomultibyte",
+			"Enables languages which use multibyte coding (such as Chinese).",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "optionsvisible",
+			"Always show options button in main menu, even when pausing from a game.",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "particledisablebit",
+			"Unlocks particle action disabling/enabling bits for all events so that a particle event can occur multiple times.",
+			C_BOOL,
+			{.intBoolVal = false},
+			{.intBoolVal = false} },
+		{ "pathfinding",
+			"Multiplies size of pathfinding grid cache by eight in order to prevent crashes in large levels.",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "projaware",
+			"Allows AI to dodge incoming gunfire properly.",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "safeprintf",
+			"Replaces Oni's function that prints to startup.txt with a safer one.",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "showalllasersights",
+			"Show all (also enemies') weapon lasersights.",
+			C_BOOL,
+			{.intBoolVal = false},
+			{.intBoolVal = false} },
+		{ "showtriggervolumes",
+			"Allows BSL variable \"show_triggervolumes\" to work when set to 1.",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "throwtest",
+			"Not recommended for use; experiment with allowing enemies to be thrown over railings.",
+			C_BOOL,
+			{.intBoolVal = false},
+			{.intBoolVal = false} },
+		{ "usedaodangl",
+			"Provides an improved windowed mode (-noswitch); this patch is known to break the hiding of the Windows taskbar in fullscreen mode.",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "usegettickcount",
+			"Replaces Oni's timing functions with more accurate ones.",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "wpfadetime",
+			"Adds working function for existing BSL command wp_fadetime, sets fade time to 4800.",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ 0, 0, 0, {0}, {0} }
+	} },
+	{ "options", "Options", {
+		{ "border",
+			"If \"windowhack\" patch is active, make sure game window has border in windowed mode.",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "debug",
+			"???",
+			EXT_BOOL,
+			{.intBoolVal = false },
+			{.extBoolVal = &AKgDebug_DebugMaps } },
+		{ "debugfiles",
+			"???",
+			EXT_BOOL,
+			{.intBoolVal = false },
+			{.extBoolVal = &BFgDebugFileEnable } },
+		{ "findsounds",
+			"???",
+			EXT_BOOL,
+			{.intBoolVal = false },
+			{.extBoolVal = &SSgSearchOnDisk } },
+		{ "gamma",
+			"Enable gamma slider in fullscreen.",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "ignore_private_data",
+			"???",
+			EXT_BOOL,
+			{.intBoolVal = false },
+			{.extBoolVal = &opt_ignore_private_data } },
+		{ "sound",
+			"???",
+			EXT_BOOL,
+			{.intBoolVal = true },
+			{.extBoolVal = &opt_sound } },
+		{ "switch",
+			"Always switch screen to resolution on Oni's Options screen, making the game fullscreen; opposite of Oni's built-in argument \"noswitch\".",
+			EXT_BOOL,
+			{.intBoolVal = true},
+			{.extBoolVal = &M3gResolutionSwitch} },
+		{ "topmost",
+			"Keep game window on top in windowed mode, even when switching applications.",
+			C_BOOL,
+			{.intBoolVal = false},
+			{.intBoolVal = false} },
+		{ "usedaodanbsl",
+			"Adds new BSL commands (see below).",
+			C_BOOL,
+			{.intBoolVal = true},
+			{.intBoolVal = true} },
+		{ "language",
+			"Localization for hardcoded strings (e.g. \"Savepoints\").",
+			C_STRING,
+			{.stringVal = "en"},
+			{.stringVal = "en"} },
+		{ 0, 0, 0, {0}, {0} }
+	} }
+};
+
+
+void DDrConfig_Print()
+{
+	for (unsigned int s = 0; s < ARRAY_SIZE(config); s++) {
+		for (ConfigOption_t* co = config[s].options; co->name != 0; co++) {
+			switch (co->type) {
+				case C_STRING:
+					STARTUPMESSAGE("Option %s.%s = %s (def %s)", config[s].name, co->name, co->value.stringVal, co->defaultValue.stringVal);
+					break;
+				case EXT_BOOL:
+					STARTUPMESSAGE("Option %s.%s = %d (def %d)", config[s].name, co->name, *co->value.extBoolVal, co->defaultValue.intBoolVal);
+					break;
+				default:
+					STARTUPMESSAGE("Option %s.%s = %d (def %d)", config[s].name, co->name, co->value.intBoolVal, co->defaultValue.intBoolVal);
+			}
+		}
+	}
+}
+
+const char* DDrConfig_GetOptionTypeName(OptionType_t type)
+{
+	switch (type) {
+		case C_INT:
+			return "Int";
+		case C_BOOL:
+			return "Bool";
+		case C_STRING:
+			return "String";
+		case EXT_BOOL:
+			return "pBool";
+		default:
+			return "unknown";
+	}
+}
+
+static ConfigOption_t* DDrConfig_GetOption(const char* fullOptName)
+{
+	char section[50];
+	strcpy(section, fullOptName);
+
+	char* option = strchr(section, '.');
+	if (option == 0) {
+		STARTUPMESSAGE("Could not find option separator in \"%s\"", fullOptName);
+		return 0;
+	}
+	*option++ = 0;
+
+	for (unsigned int s = 0; s < ARRAY_SIZE(config); s++) {
+		if (!_stricmp(config[s].name, section)) {
+			for (ConfigOption_t* co = config[s].options; co->name != 0; co++) {
+				if (!_stricmp(co->name, option)) {
+					return co;
+				}
+			}
+			STARTUPMESSAGE("Could not find option \"%s\" in section \"%s\"", option, section);
+			return 0;
+		}
+	}
+	STARTUPMESSAGE("Could not find section \"%s\" for option \"%s\"", section, option);
+	return 0;
+}
+
+
+
+ConfigOption_t* DDrConfig_GetOptOfType(const char* fullOptName, OptionType_t type)
+{
+	ConfigOption_t* co = DDrConfig_GetOption(fullOptName);
+	if (co == 0)
+		return 0;
+
+	if (co->type != type) {
+		STARTUPMESSAGE("Option \"%s\" is not of type %s", fullOptName, DDrConfig_GetOptionTypeName(type));
+		return 0;
+	}
+	return co;
+}
+
+
+void DDrConfig_InitExtBools()
+{
+	for (unsigned int s = 0; s < ARRAY_SIZE(config); s++) {
+		for (ConfigOption_t* co = config[s].options; co->name != 0; co++) {
+			if (co->type == EXT_BOOL) {
+				*co->value.extBoolVal = co->defaultValue.intBoolVal;
+			}
+		}
+	}
+}
+
+
+
+void DDrIniCallback(char* section, char* name, char* value)
+{
+	static char curSection[20];
+	char fullOptName[50];
+
+	if (!_stricmp(section, "patch"))
+		section = "patches";
+
+	strcpy(curSection, section);
+
+	strcpy(fullOptName, curSection);
+	fullOptName[strlen(curSection)] = '.';
+	strcpy(fullOptName+strlen(curSection)+1, name);
+
+	ConfigOption_t* co = DDrConfig_GetOption(fullOptName);
+
+	if (co)
 	{
-		if (!_stricmp(section, "options"))
-			ini_section = s_options;
-		else if (!_stricmp(section, "patch") || !_stricmp(section, "patches"))
-			ini_section = s_patch;
-		else if (!_stricmp(section, "bsl"))
-			ini_section = s_bsl;
-		else if (!_stricmp(section, "language"))
-			ini_section = s_language;
+		switch (co->type) {
+			case C_INT:
+				co->value.intBoolVal = strtol(value, NULL, 0);
+				break;
+			case C_BOOL:
+				co->value.intBoolVal = !_stricmp(value, "true");
+				break;
+			case C_STRING:
+				co->value.stringVal = value;
+				break;
+			case EXT_BOOL:
+				*(co->value.extBoolVal) = !_stricmp(value, "true");
+				break;
+			default:
+				STARTUPMESSAGE("Config value type unknown: %d", co->type);
+		}
+	}
+}
+
+void DDrConfig_WriteTemplateIni()
+{
+	FILE* fp;
+	STARTUPMESSAGE("%s doesn't exist, creating", iniName);
+	fp = fopen(iniName, "w");
+	if (fp)
+	{
+		for (unsigned int s = 0; s < ARRAY_SIZE(config); s++) {
+			fprintf(fp, "[%s]\n", config[s].name);
+		}
+		fclose(fp);
+	}
+}
+
+
+void DDrConfig(int argc, char* argv[])
+{
+	int i;
+	char* section;
+	char* option;
+	bool falseoption;
+
+	DDrConfig_InitExtBools();
+
+	if (GetFileAttributes(iniName) == INVALID_FILE_ATTRIBUTES)
+		DDrConfig_WriteTemplateIni();
+	
+	STARTUPMESSAGE("Parsing daodan.ini...", 0);
+	if (!Inifile_Read(iniName, DDrIniCallback))
+		STARTUPMESSAGE("Error reading daodan.ini, check your syntax!", 0);
+	STARTUPMESSAGE("Finished parsing", 0);
+
+
+
+	STARTUPMESSAGE("Parsing command line...", 0);
+	for (i = 1; i < argc; i ++)
+	{
+		if (argv[i][0] == '-')
+		{
+			section = argv[i] + 1;
+			if ((option = strchr(argv[i], '.')))
+			{
+				*option = '\0';
+				falseoption = (option[1] == 'n' || option[1] == 'N') && (option[2] == 'o' || option[2] == 'O');
+				if (i < (argc - 1) && argv[i + 1][0] != '-')
+					DDrIniCallback(section, option + 1, argv[++i]);
+				else
+					DDrIniCallback(section, option + (falseoption ? 3 : 1), (falseoption ? "false" : "true"));
+				*option = '.';
+			}
+			else
+			{
+				falseoption = (section[0] == 'n' || section[0] == 'N') && (section[1] == 'o' || section[1] == 'O');
+				if (i < (argc - 1) && argv[i + 1][0] != '-')
+					DDrIniCallback("options", section, argv[++i]);
+				else
+					DDrIniCallback("options", section + (falseoption ? 2 : 0), (falseoption ? "false" : "true"));
+			}
+		}
 		else
 		{
-			ini_section = s_unknown;
-			DDrStartupMessage("Daodan: Unrecognised ini section \"%s\"", section);
-		}
-	}
-	
-	switch (ini_section)
-	{
-		case s_options:
-			if (!_stricmp(name, "border"))
-				opt_border = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "debug"))
-				AKgDebug_DebugMaps = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "debugfiles"))
-				BFgDebugFileEnable = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "findsounds"))
-				SSgSearchOnDisk = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "gamma"))
-				opt_gamma = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "ignore_private_data"))
-				opt_ignore_private_data = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "nomultibyte"))
-				patch_nomultibyte = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "sound"))
-				opt_sound = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "switch"))
-				M3gResolutionSwitch = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "topmost"))
-				opt_topmost = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "usedaodanbsl"))
-				opt_usedaodanbsl = !_stricmp(inifile_cleanstr(value), "true");
-			else
-				DDrStartupMessage("Daodan: Unrecognised ini option \"%s\"", name);
+			STARTUPMESSAGE("Parse error \"%s\"", argv[i]);
 			break;
-		case s_patch:
-			if (!_stricmp(name, "alttab"))
-				patch_alttab = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "argb8888"))
-				patch_argb8888 = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "binkplay"))
-				patch_binkplay = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "bsl"))
-				patch_bsl = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "cheater"))
-				patch_cheater = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "cheatsenabled"))
-				patch_cheatsenabled = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "cheattable"))
-				patch_cheattable = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "clipcursor"))
-				patch_clipcursor = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "cooldowntimer"))
-				patch_cooldowntimer = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "daodandisplayenum"))
-				patch_daodandisplayenum = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "directinput"))
-				patch_directinput = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "disablecmdline"))
-				patch_disablecmdline = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "flatline"))
-				patch_flatline = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "fonttexturecache"))
-				patch_fonttexturecache = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "getcmdline"))
-				patch_getcmdline = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "hdscreens_lowres"))
-				patch_hdscreens_lowres = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "highres_console"))
-				patch_highres_console = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "kickguns"))
-				patch_kickguns = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "killvtune"))
-				patch_killvtune = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "largetextures"))
-				patch_largetextures = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "levelplugins"))
-				patch_levelplugins = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "nomultibyte"))
-				patch_nomultibyte = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "newweap"))
-				patch_newweapon = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "optionsvisible"))
-				patch_optionsvisible = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "particledisablebit"))
-				patch_particledisablebit = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "pathfinding"))
-				patch_pathfinding = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "projaware"))
-				patch_projaware = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "safeprintf"))
-				patch_safeprintf = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "showalllasersights"))
-				patch_showalllasersights = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "showtriggervolumes"))
-				patch_showtriggervolumes = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "throwtest"))
-				patch_throwtest = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "usedaodangl"))
-				patch_usedaodangl = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "usegettickcount"))
-				patch_usegettickcount = !_stricmp(inifile_cleanstr(value), "true");
-			else if (!_stricmp(name, "wpfadetime"))
-				patch_wpfadetime = !_stricmp(inifile_cleanstr(value), "true");
-			else
-				DDrStartupMessage("Daodan: Unrecognised ini patch \"%s\"", name);
-			break;
+		}
+	}
+	STARTUPMESSAGE("Finished parsing", 0);
+}
+
+
+/*
 		case s_language:
-			if (!_stricmp(name, "chinese"))
-				patch_chinese = !_stricmp(inifile_cleanstr(value), "true");
 			else if (!_stricmp(name, "blam"))
 				DDrPatch__strdup((int*)(OniExe + 0x0010fb73), value);
@@ -282,85 +547,4 @@
 			else if (!_stricmp(name, "carousel_off"))
 				DDr_CheatTable[21].message_off = _strdup(value);
-			else
-				DDrStartupMessage("Daodan: Unrecognised ini language item \"%s\"", name);
-			break;
-		case s_bsl:
-		default:
-			break;
-	}
-	
-	return true;
-}
-
-void DDrConfig(int argc, char* argv[])
-{
-	int i;
-	char* section;
-	char* option;
-	bool falseoption;
-
-
-	// Tell Oni to not load non levelX_final-files by default:
-	opt_ignore_private_data = false;
-
-	// Enable sound by default:
-	opt_sound = true;
-
-
-	if (GetFileAttributes("daodan.ini") == INVALID_FILE_ATTRIBUTES)
-	{
-		FILE* fp;
-		DDrStartupMessage("Daodan: daodan.ini doesn't exist, creating");
-		fp = fopen("daodan.ini", "w");
-		if (fp)
-		{
-			fputs("[Options]\n", fp);
-			fputs("[Patch]\n", fp);
-			fputs("[BSL]\n", fp);
-			fputs("[Language]\n", fp);
-			fclose(fp);
-		}
-	}
-	
-	DDrStartupMessage("Daodan: Parsing daodan.ini...");
-	if (!inifile_read("daodan.ini", DDrIniCallback))
-		DDrStartupMessage("Daodan: Error reading daodan.ini, check your syntax!");
-	DDrStartupMessage("Daodan: Finished parsing");
-
-
-
-	DDrStartupMessage("Daodan: Parsing command line...");
-	for (i = 1; i < argc; i ++)
-	{
-		if (argv[i][0] == '-')
-		{
-			section = argv[i] + 1;
-			if ((option = strchr(argv[i], '.')))
-			{
-				*option = '\0';
-				falseoption = (option[1] == 'n' || option[1] == 'N') && (option[2] == 'o' || option[2] == 'O');
-				if (i < (argc - 1) && argv[i + 1][0] != '-')
-					DDrIniCallback(section, true, option + 1, argv[++i]);
-				else
-					DDrIniCallback(section, true, option + (falseoption ? 3 : 1), (falseoption ? "false" : "true"));
-				*option = '.';
-			}
-			else
-			{
-				falseoption = (section[0] == 'n' || section[0] == 'N') && (section[1] == 'o' || section[1] == 'O');
-				ini_section = s_options;
-				if (i < (argc - 1) && argv[i + 1][0] != '-')
-					DDrIniCallback(NULL, false, section, argv[++i]);
-				else
-					DDrIniCallback(NULL, false, section + (falseoption ? 2 : 0), (falseoption ? "false" : "true"));
-			}
-		}
-		else
-		{
-			DDrStartupMessage("Daodan: Parse error \"%s\"", argv[i]);
-			break;
-		}
-	}
-	DDrStartupMessage("Daodan: Finished parsing");
-}
-
+*/	
+
Index: Daodan/src/Daodan_Config.h
===================================================================
--- Daodan/src/Daodan_Config.h	(revision 992)
+++ Daodan/src/Daodan_Config.h	(revision 993)
@@ -4,47 +4,36 @@
 #include "stdint.h"
 
+typedef enum {
+	C_BOOL,
+	C_INT,
+	C_STRING,
+	EXT_BOOL
+} OptionType_t;
+
+typedef union {
+	int intBoolVal;
+	uint8_t* extBoolVal;
+	char* stringVal;
+} OptionValue_t;
+
+typedef struct {
+	char* name;
+	char* description;
+	OptionType_t type;
+	OptionValue_t defaultValue;
+	OptionValue_t value;
+} ConfigOption_t;
+
+typedef struct {
+	char* name;
+	char* description;
+	ConfigOption_t options[50];
+} ConfigSection_t;
+
+
 void DDrConfig(int argc, char* argv[]);
 
-extern bool patch_alttab;
-extern bool patch_argb8888;
-extern bool patch_binkplay;
-extern bool patch_bsl;
-extern bool patch_cheater;
-extern bool patch_cheatsenabled;
-extern bool patch_cheattable;
-extern bool patch_clipcursor;
-extern bool patch_cooldowntimer;
-extern bool patch_daodandisplayenum;
-extern bool patch_directinput;
-extern bool patch_disablecmdline;
-extern bool patch_flatline;
-extern bool patch_fonttexturecache;
-extern bool patch_getcmdline;
-extern bool patch_hdscreens_lowres;
-extern bool patch_highres_console;
-extern bool patch_kickguns;
-extern bool patch_killvtune;
-extern bool patch_largetextures;
-extern bool patch_levelplugins;
-extern bool patch_newweapon;
-extern bool patch_nomultibyte;
-extern bool patch_optionsvisible;
-extern bool patch_particledisablebit;
-extern bool patch_pathfinding;
-extern bool patch_projaware;
-extern bool patch_safeprintf;
-extern bool patch_showalllasersights;
-extern bool patch_showtriggervolumes;
-extern bool patch_throwtest;
-extern bool patch_usedaodangl;
-extern bool patch_usegettickcount;
-extern bool patch_wpfadetime;
-
-extern bool opt_border;
-extern bool opt_gamma;
-extern bool opt_topmost;
-extern bool opt_usedaodanbsl;
-
-extern bool patch_chinese;
+ConfigOption_t* DDrConfig_GetOptOfType(const char* fullOptName, OptionType_t type);
+const char* DDrConfig_GetOptionTypeName(OptionType_t type);
 
 #endif
Index: Daodan/src/Daodan_GL.c
===================================================================
--- Daodan/src/Daodan_GL.c	(revision 992)
+++ Daodan/src/Daodan_GL.c	(revision 993)
@@ -67,5 +67,5 @@
 	signed int j;
 	
-	DDrStartupMessage("Daodan: Listing display modes");
+	STARTUPMESSAGE("Listing display modes", 0);
 
 	memset(modes, 0, sizeof(M3tDisplayMode) * DD_MAX_MODES);
@@ -170,7 +170,7 @@
 	}
 
-	DDrStartupMessage("Daodan: %u modes available:", vmodes);
+	STARTUPMESSAGE("%u modes available:", vmodes);
 	for (i = 0; i < vmodes; ++i)
-		DDrStartupMessage("Daodan:   %ux%ux%u", modes[i].Width, modes[i].Height, modes[i].Depth);
+		STARTUPMESSAGE("   %ux%ux%u", modes[i].Width, modes[i].Height, modes[i].Depth);
 
 	return vmodes;
@@ -254,5 +254,6 @@
 		else
 		{
-			if (opt_border)
+			ConfigOption_t* co = DDrConfig_GetOptOfType("options.border", C_BOOL);
+			if (co && co->value.intBoolVal)
 			{
 				pt.x = rc.left;
@@ -317,5 +318,6 @@
 static void ONICALL DD_GLiGamma_Restore(void)
 {
-	if (opt_gamma)
+	ConfigOption_t* co = DDrConfig_GetOptOfType("options.gamma", C_BOOL);
+	if (co->value.intBoolVal)
 	{
 		if (gl_api->wglSetDeviceGammaRamp3DFX)
@@ -328,5 +330,6 @@
 static void ONICALL DD_GLiGamma_Initialize(void)
 {
-	if (opt_gamma)
+	ConfigOption_t* co = DDrConfig_GetOptOfType("options.gamma", C_BOOL);
+	if (co->value.intBoolVal)
 	{
 		if (gl_api->wglSetDeviceGammaRamp3DFX)
@@ -399,8 +402,9 @@
 	}
 
-	if (!M3gResolutionSwitch && opt_gamma)
+	ConfigOption_t* co = DDrConfig_GetOptOfType("options.gamma", C_BOOL);
+	if (!M3gResolutionSwitch && co->value.intBoolVal)
 	{
 		UUrStartupMessage("Daodan: Ignoring gamma setting due to windowed mode");
-		opt_gamma = false;
+		co->value.intBoolVal = false;
 	}
 
Index: Daodan/src/Daodan_Patch.c
===================================================================
--- Daodan/src/Daodan_Patch.c	(revision 992)
+++ Daodan/src/Daodan_Patch.c	(revision 993)
@@ -45,21 +45,21 @@
     DISASM MyDisasm;
     int i = 0;
-    DDrStartupMessage("");
-    DDrStartupMessage("");
+    STARTUPMESSAGE("", 0);
+    STARTUPMESSAGE("", 0);
 
     memset (&MyDisasm, 0, sizeof(DISASM));
     MyDisasm.EIP = (UIntPtr) from;
     i = 0;
-    DDrStartupMessage("Orig before @ 0x%06x", from);
+    STARTUPMESSAGE("Orig before @ 0x%06x", from);
     while (i<10){
         len = Disasm(&MyDisasm);
         if (len != UNKNOWN_OPCODE) {
-			DDrStartupMessage("%s, Opcode: 0x%x, len: %d, branch: %d, to: 0x%06x", MyDisasm.CompleteInstr, MyDisasm.Instruction.Opcode, len, MyDisasm.Instruction.BranchType, MyDisasm.Instruction.AddrValue);
-			DDrStartupMessage("    Cat: 0x%04x, prefix count: %d", MyDisasm.Instruction.Category & 0xffff, MyDisasm.Prefix.Number );
+			STARTUPMESSAGE("%s, Opcode: 0x%x, len: %d, branch: %d, to: 0x%06x", MyDisasm.CompleteInstr, MyDisasm.Instruction.Opcode, len, MyDisasm.Instruction.BranchType, MyDisasm.Instruction.AddrValue);
+			STARTUPMESSAGE("    Cat: 0x%04x, prefix count: %d", MyDisasm.Instruction.Category & 0xffff, MyDisasm.Prefix.Number );
             MyDisasm.EIP += (UIntPtr)len;
             i++;
         }
     };
-    DDrStartupMessage("");
+    STARTUPMESSAGE("", 0);
 */
 
@@ -78,5 +78,5 @@
 			if ((disasm.Instruction.Category & 0xffff) == CONTROL_TRANSFER) {
 				if (disasm.Prefix.Number > 0) {
-						DDrStartupMessage("Daodan: Detour: Branch in trampoline area from address 0x%08x with prefixes", from);
+						STARTUPMESSAGE("Detour: Branch in trampoline area from address 0x%08x with prefixes", from);
 						return (void*)-1;
 				}
@@ -145,5 +145,5 @@
 						break;
 					default:
-						DDrStartupMessage("Daodan: Detour: Unknown branch in trampoline area from address 0x%08x", from);
+						STARTUPMESSAGE("Detour: Unknown branch in trampoline area from address 0x%08x", from);
 						return (void*)-1;
 				}
@@ -155,5 +155,5 @@
 		}
 		else {
-			DDrStartupMessage("Daodan: Detour: Unknown opcode in trampoline area from address 0x%08x", from);
+			STARTUPMESSAGE("Detour: Unknown opcode in trampoline area from address 0x%08x", from);
 			return (void*)-1;
 		}
@@ -161,5 +161,5 @@
 
 	if (branches > 1) {
-		DDrStartupMessage("Daodan: Detour: Too many branches in trampoline'd code from address 0x%08x: %d", from, branches);
+		STARTUPMESSAGE("Detour: Too many branches in trampoline'd code from address 0x%08x: %d", from, branches);
 		return (void*)-1;
 	}
@@ -171,5 +171,5 @@
 	DWORD oldp;
 	if (!VirtualProtect(trampoline, 40, PAGE_EXECUTE_READWRITE, &oldp)) {
-		DDrStartupMessage("Daodan: Detour: Could not mark page for trampoline as executable: from address 0x%08x", from);
+		STARTUPMESSAGE("Detour: Could not mark page for trampoline as executable: from address 0x%08x", from);
 		return (void*)-1;
 	}
@@ -179,44 +179,44 @@
     MyDisasm.EIP = (UIntPtr) trampoline;
     i = 0;
-    DDrStartupMessage("Trampoline @ 0x%06x", trampoline);
+    STARTUPMESSAGE("Trampoline @ 0x%06x", trampoline);
     while (i<10){
         len = Disasm(&MyDisasm);
         if (len != UNKNOWN_OPCODE) {
-            DDrStartupMessage(MyDisasm.CompleteInstr);
+            STARTUPMESSAGE("%s", MyDisasm.CompleteInstr);
             MyDisasm.EIP += (UIntPtr)len;
             i++;
         }
     };
-    DDrStartupMessage("");
+    STARTUPMESSAGE("", 0);
      
     memset (&MyDisasm, 0, sizeof(DISASM));
     MyDisasm.EIP = disasm.EIP;
     i = 0;
-    DDrStartupMessage("Orig after @ 0x%06x", disasm.EIP);
+    STARTUPMESSAGE("Orig after @ 0x%06x", disasm.EIP);
     while (i<7){
         len = Disasm(&MyDisasm);
         if (len != UNKNOWN_OPCODE) {
-            DDrStartupMessage(MyDisasm.CompleteInstr);
+            STARTUPMESSAGE("%s", MyDisasm.CompleteInstr);
             MyDisasm.EIP += (UIntPtr)len;
             i++;
         }
     };
-    DDrStartupMessage("");
+    STARTUPMESSAGE("", 0);
 
     memset (&MyDisasm, 0, sizeof(DISASM));
     MyDisasm.EIP = (UIntPtr) from;
     i = 0;
-    DDrStartupMessage("Orig start after @ 0x%06x", from);
+    STARTUPMESSAGE("Orig start after @ 0x%06x", from);
     while (i<3){
         len = Disasm(&MyDisasm);
         if (len != UNKNOWN_OPCODE) {
-            DDrStartupMessage(MyDisasm.CompleteInstr);
+            STARTUPMESSAGE("%s", MyDisasm.CompleteInstr);
             MyDisasm.EIP += (UIntPtr)len;
             i++;
         }
     };
-    DDrStartupMessage("");
-    DDrStartupMessage("");
-    DDrStartupMessage("");
+    STARTUPMESSAGE("", 0);
+    STARTUPMESSAGE("", 0);
+    STARTUPMESSAGE("", 0);
 */
 
Index: Daodan/src/Daodan_Utility.h
===================================================================
--- Daodan/src/Daodan_Utility.h	(revision 992)
+++ Daodan/src/Daodan_Utility.h	(revision 993)
@@ -3,4 +3,10 @@
 
 #include "Daodan.h"
+
+#define WHERESTR  "Daodan [%-22s:%4d ]: "
+#define WHEREARG  __FILE__, __LINE__
+#define DEBUGPRINT2(...)       DDrStartupMessage(__VA_ARGS__)
+#define STARTUPMESSAGE(_fmt, ...)  DEBUGPRINT2(WHERESTR _fmt, WHEREARG, __VA_ARGS__)
+
 
 void __cdecl DDrStartupMessage(const char* fmt, ...);
Index: Daodan/src/Daodan_Win32.c
===================================================================
--- Daodan/src/Daodan_Win32.c	(revision 992)
+++ Daodan/src/Daodan_Win32.c	(revision 993)
@@ -153,4 +153,13 @@
 	else
 	{
+		ConfigOption_t* co = DDrConfig_GetOptOfType("options.border", C_BOOL);
+		int opt_border = 0;
+		if (co && co->value.intBoolVal)
+			opt_border = 1;
+		co = DDrConfig_GetOptOfType("options.topmost", C_BOOL);
+		int opt_topmost = 0;
+		if (co && co->value.intBoolVal)
+			opt_topmost = 1;
+
 		window_style    = (opt_border) ? WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_DLGFRAME | WS_MINIMIZEBOX : WS_POPUP;
 		window_style_ex = (opt_topmost) ? WS_EX_TOPMOST : 0;
Index: Daodan/src/Inifile_Reader.c
===================================================================
--- Daodan/src/Inifile_Reader.c	(revision 992)
+++ Daodan/src/Inifile_Reader.c	(revision 993)
@@ -7,85 +7,50 @@
 #include "Inifile_Reader.h"
 
-char* inifile_cleanstr(char* str)
+static char* strtrim(char* string)
 {
-	int i;
-	for (i = strlen(str) - 1; i >= 0; i --)
-		if (isspace(str[i]))
-			str[i] = '\0';
+	while (isspace(*string))
+		string++;
+	for (int i = strlen(string) - 1; i >= 0; i--)
+	{
+		if (isspace(string[i]))
+		{
+			string[i] = 0;
+		}
 		else
+		{
 			break;
-	
-	while (isspace(*str))
-		str++;
-	
-	return str;
+		}
+	}
+	return string;
 }
 
-int64_t inifile_parseint(const char* str, bool issigned)
+static char* newlines(char* string)
 {
-	int64_t ret = 0;
-	bool neg = false;
-	if (str[0] == '0' && str[1] == 'x')
+	for (char* i = string + strlen(string) - 1; i >= string; i--)
 	{
-		int i;
-		if (str[2] == '\0')
-			return 0x100000000LL;
-		
-		for (i = 0, str += 2; *str; i++, str++)
+		if ((*i == '\\') && (*(i+1) == 'n'))
 		{
-			if (i == 8)
-				return 0x100000000LL;
-			
-			ret <<= 4;
-			if (*str >= '0' && *str <= '9')
-				ret |= *str - '0';
-			else if (*str >= 'a' && *str <= 'f')
-				ret |= *str - 'a' + 10;
-			else if (*str >= 'A' && *str <= 'F')
-				ret |= *str - 'A' + 10;
-			else
-				return 0x100000000LL;
+			*i = '\n';
+			memmove(i+1, i+2, strlen(i+1));
 		}
-		return ret;
 	}
-	else if ((*str >= '0' && *str <= '9') || (neg = (*str == '-')))
-	{
-		int i;
-		if (neg)
-			str++;
-		for (i = 0; *str; i++, str++)
-		{
-			if (i == 10)
-				return 0x100000000LL;
-			else if (i == 9 && !issigned && (ret > 429496729LL || (ret == 429496729LL && *str > '5')))
-				return 0x100000000LL;
-			else if (i == 9 && issigned && (ret > 214748364LL || (ret == 214748364LL && *str > (neg ? '8' : '7'))))
-				return 0x100000000LL;
-			
-			ret *= 10;
-			if (*str >= '0' && *str <= '9')
-				ret += *str - '0';
-			else
-				return 0x100000000LL;
-		}
-		if (neg)
-			ret *= -1;
-		return ret;
-	}
-	else
-		return 0x100000000LL;
+	return string;
 }
 
-bool inifile_read(const char* filename, inifile_callback callback)
+bool Inifile_Read(const char* filename, inifile_callback callback)
 {
 	FILE* fp = fopen(filename, "r");
-	char* inisection = "";
+
+	char inisection[30] = "";
+	char option[30] = "";
+	char value[200] = "";
+
 	char readbuf[4096] = "";
 	char* readptr;
+
 	bool success = true;
-	bool newsection = false;
 	
 	if (!fp)
-		return inifile_cantread;
+		return false;
 	
 	while ((readptr = fgets(readbuf, sizeof(readbuf), fp))) // Loop through each line.
@@ -93,57 +58,23 @@
 		while (isspace(readptr[0])) // Skip whitespace.
 			readptr++;
-		
+
 		if (readptr[0] == '\0' || readptr[0] == '#' || readptr[0] == '!') // Skip empty lines and comments.
 			continue;
-		else if (readptr[0] == '[' && readptr[1] != ']') // It's a section header.
+
+		if (sscanf(readptr, "[%[^]]]", inisection) == 1)
 		{
-			int i;
-			for (i = 2; readptr[i]; i ++) // Look for the ]
-				if (readptr[i] == ']')
-					break;
-			
-			if (readptr[i]) // Replace with a null or crash with error.
-				readptr[i] = '\0';
-			else
-			{
-				success = false;
-				break;
-			}
-			
-			if (inisection[0])
-				free(inisection);
-			inisection = _strdup(readptr + 1); // Skip the first [
-			newsection = true;
 		}
-		else // It's a value.
+		else if (sscanf(readptr, "%[^=]=%[^\n]", option, value) == 2)
 		{
-			int i;
-			int equals = 0;
-			for (i = 0; readptr[i]; i ++) // Find the =
-				if (readptr[i] == '=')
-					equals = i;
-			
-			if (readptr[i - 1] == '\n')
-				readptr[i - 1] = '\0'; // Remove the trailing newline.
-			
-			if (equals)
-			{
-				readptr[equals] = '\0';
-				if (!callback(inisection, newsection, readptr, readptr + equals + 1)) // If the callback is false, exit.
-					break;
-				newsection = false;
-			}
-			else // If there's no equals, crash with error.
-			{
-				success = false;
-				break;
-			}
+			callback(inisection, strtrim(option), newlines(strtrim(value)));
+		}
+		else
+		{
+			success = false;
 		}
 	}
-	
-	if (inisection[0])
-		free(inisection);
 	
 	fclose(fp);
 	return success;
 }
+
Index: Daodan/src/Inifile_Reader.h
===================================================================
--- Daodan/src/Inifile_Reader.h	(revision 992)
+++ Daodan/src/Inifile_Reader.h	(revision 993)
@@ -4,13 +4,7 @@
 #include "stdint.h"
 
-enum {
-	inifile_cantread = -20
-};
+typedef void (*inifile_callback)(char* section, char* name, char* value);
 
-typedef bool (*inifile_callback)(char* section, bool newsection, char* name, char* value);
-
-char* inifile_cleanstr(char* str);
-int64_t inifile_parseint(const char* str, bool issigned);
-bool inifile_read(const char* filename, inifile_callback callback);
+bool Inifile_Read(const char* filename, inifile_callback callback);
 
 #endif
Index: Daodan/src/Oni/Symbols_Var.h
===================================================================
--- Daodan/src/Oni/Symbols_Var.h	(revision 992)
+++ Daodan/src/Oni/Symbols_Var.h	(revision 993)
@@ -12,8 +12,8 @@
 
 // Option "debug" ... but what does it do?
-#define AKgDebug_DebugMaps	(*((char*)0x002b2204))
+#define AKgDebug_DebugMaps	(*((onibool*)0x002b2204))
 
 // Option "debugfiles" ... but what does it do?
-#define BFgDebugFileEnable	(*((bool*)0x0055c8d0))
+#define BFgDebugFileEnable	(*((onibool*)0x0055c8d0))
 
 // Command line instance
@@ -57,5 +57,5 @@
 // False to prevent Oni from changing display settings (however Bink
 // player does not respect this setting).
-#define M3gResolutionSwitch	(*((char*)0x00531634))
+#define M3gResolutionSwitch	(*((onibool*)0x00531634))
 
 // Startup.txt file handle
@@ -69,11 +69,11 @@
 
 // Load non levelX_final-files yes/no
-#define opt_ignore_private_data	(*((char*)0x006370f0))
+#define opt_ignore_private_data	(*((onibool*)0x006370f0))
 
 // Play sound yes/no
-#define opt_sound			(*((char*)0x006370fc))
+#define opt_sound			(*((onibool*)0x006370fc))
 
 // Option "findsounds" ... but what does it do?
-#define SSgSearchOnDisk		(*((bool*)0x005eb758))
+#define SSgSearchOnDisk		(*((onibool*)0x005eb758))
 
 // OBJgTriggerVolume_Visible - bsl var to show trigger volumes
Index: Daodan/src/bink-proxy.c
===================================================================
--- Daodan/src/bink-proxy.c	(revision 992)
+++ Daodan/src/bink-proxy.c	(revision 993)
@@ -54,5 +54,5 @@
 		DWORD err;
 
- 		DDrStartupMessage("Daodan: Loading real Bink DLL");
+ 		STARTUPMESSAGE("Loading real Bink DLL", 0);
 		realbink = LoadLibrary("realbink.dll");
 		err = GetLastError();
@@ -63,5 +63,5 @@
 			if(!BinkBufferBlit)
 			{
-				DDrStartupMessage("Daodan: Retrieving function address from real Bink DLL failed for: BinkBufferBlit");
+				STARTUPMESSAGE("Retrieving function address from real Bink DLL failed for: BinkBufferBlit", 0);
 				goto exit_err;
 			}
@@ -69,5 +69,5 @@
 			if(!BinkBufferClose)
 			{
-				DDrStartupMessage("Daodan: Retrieving function address from real Bink DLL failed for: BinkBufferClose");
+				STARTUPMESSAGE("Retrieving function address from real Bink DLL failed for: BinkBufferClose", 0);
 				goto exit_err;
 			}
@@ -75,5 +75,5 @@
 			if(!BinkBufferLock)
 			{
-				DDrStartupMessage("Daodan: Retrieving function address from real Bink DLL failed for: BinkBufferLock");
+				STARTUPMESSAGE("Retrieving function address from real Bink DLL failed for: BinkBufferLock", 0);
 				goto exit_err;
 			}
@@ -81,5 +81,5 @@
 			if(!BinkBufferOpen)
 			{
-				DDrStartupMessage("Daodan: Retrieving function address from real Bink DLL failed for: BinkBufferOpen");
+				STARTUPMESSAGE("Retrieving function address from real Bink DLL failed for: BinkBufferOpen", 0);
 				goto exit_err;
 			}
@@ -87,5 +87,5 @@
 			if(!BinkBufferSetOffset)
 			{
-				DDrStartupMessage("Daodan: Retrieving function address from real Bink DLL failed for: BinkBufferSetOffset");
+				STARTUPMESSAGE("Retrieving function address from real Bink DLL failed for: BinkBufferSetOffset", 0);
 				goto exit_err;
 			}
@@ -93,5 +93,5 @@
 			if(!BinkBufferUnlock)
 			{
-				DDrStartupMessage("Daodan: Retrieving function address from real Bink DLL failed for: BinkBufferUnlock");
+				STARTUPMESSAGE("Retrieving function address from real Bink DLL failed for: BinkBufferUnlock", 0);
 				goto exit_err;
 			}
@@ -99,5 +99,5 @@
 			if(!BinkClose)
 			{
-				DDrStartupMessage("Daodan: Retrieving function address from real Bink DLL failed for: BinkClose");
+				STARTUPMESSAGE("Retrieving function address from real Bink DLL failed for: BinkClose", 0);
 				goto exit_err;
 			}
@@ -105,5 +105,5 @@
 			if(!BinkCopyToBuffer)
 			{
-				DDrStartupMessage("Daodan: Retrieving function address from real Bink DLL failed for: BinkCopyToBuffer");
+				STARTUPMESSAGE("Retrieving function address from real Bink DLL failed for: BinkCopyToBuffer", 0);
 				goto exit_err;
 			}
@@ -111,5 +111,5 @@
 			if(!BinkDoFrame)
 			{
-				DDrStartupMessage("Daodan: Retrieving function address from real Bink DLL failed for: BinkDoFrame");
+				STARTUPMESSAGE("Retrieving function address from real Bink DLL failed for: BinkDoFrame", 0);
 				goto exit_err;
 			}
@@ -117,5 +117,5 @@
 			if(!BinkGetRects)
 			{
-				DDrStartupMessage("Daodan: Retrieving function address from real Bink DLL failed for: BinkGetRects");
+				STARTUPMESSAGE("Retrieving function address from real Bink DLL failed for: BinkGetRects", 0);
 				goto exit_err;
 			}
@@ -123,5 +123,5 @@
 			if(!BinkNextFrame)
 			{
-				DDrStartupMessage("Daodan: Retrieving function address from real Bink DLL failed for: BinkNextFrame");
+				STARTUPMESSAGE("Retrieving function address from real Bink DLL failed for: BinkNextFrame", 0);
 				goto exit_err;
 			}
@@ -129,5 +129,5 @@
 			if(!BinkOpen)
 			{
-				DDrStartupMessage("Daodan: Retrieving function address from real Bink DLL failed for: BinkOpen");
+				STARTUPMESSAGE("Retrieving function address from real Bink DLL failed for: BinkOpen", 0);
 				goto exit_err;
 			}
@@ -135,5 +135,5 @@
 			if(!BinkOpenDirectSound)
 			{
-				DDrStartupMessage("Daodan: Retrieving function address from real Bink DLL failed for: BinkOpenDirectSound");
+				STARTUPMESSAGE("Retrieving function address from real Bink DLL failed for: BinkOpenDirectSound", 0);
 				goto exit_err;
 			}
@@ -141,5 +141,5 @@
 			if(!BinkService)
 			{
-				DDrStartupMessage("Daodan: Retrieving function address from real Bink DLL failed for: BinkService");
+				STARTUPMESSAGE("Retrieving function address from real Bink DLL failed for: BinkService", 0);
 				goto exit_err;
 			}
@@ -147,5 +147,5 @@
 			if(!BinkSetIOSize)
 			{
-				DDrStartupMessage("Daodan: Retrieving function address from real Bink DLL failed for: BinkSetIOSize");
+				STARTUPMESSAGE("Retrieving function address from real Bink DLL failed for: BinkSetIOSize", 0);
 				goto exit_err;
 			}
@@ -153,5 +153,5 @@
 			if(!BinkSetSoundOnOff)
 			{
-				DDrStartupMessage("Daodan: Retrieving function address from real Bink DLL failed for: BinkSetSoundOnOff");
+				STARTUPMESSAGE("Retrieving function address from real Bink DLL failed for: BinkSetSoundOnOff", 0);
 				goto exit_err;
 			}
@@ -159,5 +159,5 @@
 			if(!BinkSetSoundSystem)
 			{
-				DDrStartupMessage("Daodan: Retrieving function address from real Bink DLL failed for: BinkSetSoundSystem");
+				STARTUPMESSAGE("Retrieving function address from real Bink DLL failed for: BinkSetSoundSystem", 0);
 				goto exit_err;
 			}
@@ -165,5 +165,5 @@
 			if(!BinkSetVolume)
 			{
-				DDrStartupMessage("Daodan: Retrieving function address from real Bink DLL failed for: BinkSetVolume");
+				STARTUPMESSAGE("Retrieving function address from real Bink DLL failed for: BinkSetVolume", 0);
 				goto exit_err;
 			}
@@ -171,5 +171,5 @@
 			if(!BinkWait)
 			{
-				DDrStartupMessage("Daodan: Retrieving function address from real Bink DLL failed for: BinkWait");
+				STARTUPMESSAGE("Retrieving function address from real Bink DLL failed for: BinkWait", 0);
 				goto exit_err;
 			}
@@ -178,5 +178,5 @@
 			char msg[100];
 			FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, msg, 100, NULL);
-			DDrStartupMessage("Daodan: Loading real Bink DLL failed with error %i: %s", err, msg);
+			STARTUPMESSAGE("Loading real Bink DLL failed with error %i: %s", err, msg);
 		}
 	}
Index: Daodan/src/patches/Patches.c
===================================================================
--- Daodan/src/patches/Patches.c	(revision 992)
+++ Daodan/src/patches/Patches.c	(revision 993)
@@ -19,5 +19,6 @@
 static void ONICALL DD_ONiOGU_GammaSlider_SetRange(void* window, int min_value, int max_value)
 {
-	WMrWindow_SetEnabled(window, M3gResolutionSwitch && opt_gamma);
+	ConfigOption_t* co = DDrConfig_GetOptOfType("options.gamma", C_BOOL);
+	WMrWindow_SetEnabled(window, M3gResolutionSwitch && co->value.intBoolVal);
 	WMrSlider_SetRange(window, min_value, max_value);
 }
@@ -79,5 +80,6 @@
 void ONICALL DDrGame_Init()
 {
-	if (opt_usedaodanbsl)
+	ConfigOption_t* co = DDrConfig_GetOptOfType("options.usedaodanbsl", C_BOOL);
+	if (co->value.intBoolVal)
 		SLrDaodan_Initialize();
 }
@@ -287,5 +289,5 @@
 		DWORD err;
 
- 		DDrStartupMessage("Daodan: Loading chinese DLL");
+ 		STARTUPMESSAGE("Loading chinese DLL", 0);
 		dll = LoadLibrary("xfhsm_oni.dll");
 		err = GetLastError();
@@ -300,5 +302,5 @@
 			char msg[100];
 			FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, msg, 100, NULL);
-			DDrStartupMessage("Daodan: Loading DLL failed with error %i: %s", err, msg);
+			STARTUPMESSAGE("Loading DLL failed with error %i: %s", err, msg);
 		}
 	}
@@ -606,58 +608,58 @@
 bool DD_Patch_Init()
 {
-	DDrStartupMessage("Daodan: Patching engine");
-	
-	if (patch_alttab)
+	STARTUPMESSAGE("Patching engine", 0);
+	
+	if (DDrConfig_GetOptOfType("patches.alttab", C_BOOL)->value.intBoolVal)
 		DD_Patch_AltTab();
 	
-	if (patch_argb8888)
+	if (DDrConfig_GetOptOfType("patches.argb8888", C_BOOL)->value.intBoolVal)
 		DD_Patch_ARGB8888();
 
-	if (patch_binkplay)
+	if (DDrConfig_GetOptOfType("patches.binkplay", C_BOOL)->value.intBoolVal)
 		DD_Patch_BinkPlay();
 
-	if (patch_bsl)
+	if (DDrConfig_GetOptOfType("patches.bsl", C_BOOL)->value.intBoolVal)
 		DD_Patch_BSL();
 
-	if (patch_cheater)
+	if (DDrConfig_GetOptOfType("patches.cheater", C_BOOL)->value.intBoolVal)
 		DD_Patch_Cheater();
 
-	if (patch_cheatsenabled)
+	if (DDrConfig_GetOptOfType("patches.cheatsenabled", C_BOOL)->value.intBoolVal)
 		DD_Patch_CheatsEnabled();
 
-	if (patch_cheattable)
+	if (DDrConfig_GetOptOfType("patches.cheattable", C_BOOL)->value.intBoolVal)
 		DD_Patch_CheatTable();
 	
-	if (patch_chinese)
+	if (DDrConfig_GetOptOfType("patches.chinese", C_BOOL)->value.intBoolVal)
 		DD_Patch_Chinese();
 
-	if (patch_clipcursor)
+	if (DDrConfig_GetOptOfType("patches.clipcursor", C_BOOL)->value.intBoolVal)
 		DD_Patch_ClipCursor();
 
-	if (patch_cooldowntimer)
+	if (DDrConfig_GetOptOfType("patches.cooldowntimer", C_BOOL)->value.intBoolVal)
 		DD_Patch_CooldownTimer();
 
-	if (patch_daodandisplayenum)
+	if (DDrConfig_GetOptOfType("patches.daodandisplayenum", C_BOOL)->value.intBoolVal)
 		DD_Patch_DaodanDisplayEnum();
 	
-	if (patch_directinput)
+	if (DDrConfig_GetOptOfType("patches.directinput", C_BOOL)->value.intBoolVal)
 		DD_Patch_DirectInput();
 
-	if (patch_disablecmdline)
+	if (DDrConfig_GetOptOfType("patches.disablecmdline", C_BOOL)->value.intBoolVal)
 		DD_Patch_DisableCmdLine();
 
-	if (patch_fonttexturecache)
+	if (DDrConfig_GetOptOfType("patches.fonttexturecache", C_BOOL)->value.intBoolVal)
 		DD_Patch_FontTextureCache();
 
-	if (patch_getcmdline)
+	if (DDrConfig_GetOptOfType("patches.getcmdline", C_BOOL)->value.intBoolVal)
 		DD_Patch_GetCmdLine();
 
-	if (patch_hdscreens_lowres)
+	if (DDrConfig_GetOptOfType("patches.hdscreens_lowres", C_BOOL)->value.intBoolVal)
 		DD_Patch_HDScreens_LowRes();
 
-	if (patch_highres_console)
+	if (DDrConfig_GetOptOfType("patches.highres_console", C_BOOL)->value.intBoolVal)
 		DD_Patch_HighresConsole();
 	
-	if (patch_kickguns)
+	if (DDrConfig_GetOptOfType("patches.kickguns", C_BOOL)->value.intBoolVal)
 		DD_Patch_KickGuns();
 	
@@ -665,47 +667,47 @@
 	//	DD_Patch_KillVTune();
 
-	if (patch_largetextures)
+	if (DDrConfig_GetOptOfType("patches.largetextures", C_BOOL)->value.intBoolVal)
 		DD_Patch_LargeTextures();
 	
-	if (patch_levelplugins)
+	if (DDrConfig_GetOptOfType("patches.levelplugins", C_BOOL)->value.intBoolVal)
 		DD_Patch_LevelPlugins();
 
-	if (patch_newweapon)
+	if (DDrConfig_GetOptOfType("patches.newweap", C_BOOL)->value.intBoolVal)
 		DD_Patch_NewWeap();
 
-	if (patch_nomultibyte)
+	if (DDrConfig_GetOptOfType("patches.nomultibyte", C_BOOL)->value.intBoolVal)
 		DD_Patch_NoMultiByte();
 
-	if(patch_optionsvisible)
+	if (DDrConfig_GetOptOfType("patches.optionsvisible", C_BOOL)->value.intBoolVal)
 		DD_Patch_OptionsVisible();
 
-	if (patch_particledisablebit)
+	if (DDrConfig_GetOptOfType("patches.particledisablebit", C_BOOL)->value.intBoolVal)
 		DD_Patch_ParticleDisableBit();
 	
-	if (patch_pathfinding)
+	if (DDrConfig_GetOptOfType("patches.pathfinding", C_BOOL)->value.intBoolVal)
 		DD_Patch_PathFinding();
 
-	if (patch_projaware)
+	if (DDrConfig_GetOptOfType("patches.projaware", C_BOOL)->value.intBoolVal)
 		DD_Patch_ProjAware();
 
-	if (patch_safeprintf)
+	if (DDrConfig_GetOptOfType("patches.safeprintf", C_BOOL)->value.intBoolVal)
 		DD_Patch_SafePrintf();
 
-	if (patch_showalllasersights)
+	if (DDrConfig_GetOptOfType("patches.showalllasersights", C_BOOL)->value.intBoolVal)
 		DD_Patch_ShowAllLasersights();
 
-	if (patch_showtriggervolumes)
+	if (DDrConfig_GetOptOfType("patches.showtriggervolumes", C_BOOL)->value.intBoolVal)
 		DD_Patch_ShowTriggerVolumes();
 	
-	if (patch_throwtest)
+	if (DDrConfig_GetOptOfType("patches.throwtest", C_BOOL)->value.intBoolVal)
 		DD_Patch_Throwtest();
 
-	if (patch_usedaodangl)
+	if (DDrConfig_GetOptOfType("patches.usedaodangl", C_BOOL)->value.intBoolVal)
 		DD_Patch_UseDaodanGL();
 
-	if (patch_usegettickcount)
+	if (DDrConfig_GetOptOfType("patches.usegettickcount", C_BOOL)->value.intBoolVal)
 		DD_Patch_UseGetTickCount();
 	
-	if (patch_wpfadetime)
+	if (DDrConfig_GetOptOfType("patches.wpfadetime", C_BOOL)->value.intBoolVal)
 		DD_Patch_WpFadetime();
 
