Index: /Daodan/src/Daodan.c
===================================================================
--- /Daodan/src/Daodan.c	(revision 346)
+++ /Daodan/src/Daodan.c	(revision 347)
@@ -21,4 +21,22 @@
 HMODULE DDrONiModule;
 
+bool patch_fonttexturecache = true;
+bool patch_largetextures = true;
+bool patch_pathfinding = true;
+bool patch_projaware = true;
+bool patch_wpfadetime = true;
+bool patch_kickguns = false;
+bool patch_cooldowntimer = true;
+bool patch_throwtest = false;
+bool patch_alttab = true;
+bool patch_particledisablebit = false;
+bool patch_multibyte = true;
+bool patch_cheattable = true;
+
+bool patch_safeprintf = true;
+bool patch_daodandisplayenum = true;
+bool patch_usegettickcount = true;
+bool patch_usedaodangl = false;
+
 bool DDrPatch_Init()
 {
@@ -26,9 +44,13 @@
 	
 	// Font texture cache doubled
-	DDrPatch_Byte  (OniExe + 0x00020ea7, 0x20);
-	DDrPatch_Byte  (OniExe + 0x00020f4a, 0x40);
+	if (patch_fonttexturecache)
+	{
+		DDrPatch_Byte  (OniExe + 0x00020ea7, 0x20);
+		DDrPatch_Byte  (OniExe + 0x00020f4a, 0x40);
+	}
 	
 	// Now supports textures up to 512x512
-	DDrPatch_Byte  (OniExe + 0x00005251, 0x10);
+	if (patch_largetextures)
+		DDrPatch_Byte  (OniExe + 0x00005251, 0x10);
 	
 	// Non-"_Final" levels are now valid
@@ -36,69 +58,97 @@
 	
 	// Pathfinding grid cache size x8
-	DDrPatch_Byte  (OniExe + 0x0010b03b, 0x20);
-	DDrPatch_Byte  (OniExe + 0x0010b04c, 0x20);
+	if (patch_pathfinding)
+	{
+		DDrPatch_Byte  (OniExe + 0x0010b03b, 0x20);
+		DDrPatch_Byte  (OniExe + 0x0010b04c, 0x20);
+	}
 	
 	// Projectile awareness fixed
-	DDrPatch_Byte  (OniExe + 0x0009c07c, 0x6c);
-	DDrPatch_Byte  (OniExe + 0x0009c080, 0x70);
-	DDrPatch_Byte  (OniExe + 0x0009c084, 0x74);
-	DDrPatch_Byte  (OniExe + 0x0009c110, 0x6c);
+	if (patch_projaware)
+	{
+		DDrPatch_Byte  (OniExe + 0x0009c07c, 0x6c);
+		DDrPatch_Byte  (OniExe + 0x0009c080, 0x70);
+		DDrPatch_Byte  (OniExe + 0x0009c084, 0x74);
+		DDrPatch_Byte  (OniExe + 0x0009c110, 0x6c);
+	}
 	
 	// Forced DirectInput (for Windows NT)
 	DDrPatch_Byte  (OniExe + 0x00002e6d, 0xeb);
 	
-	// Makes wp_fadetime actually have a function
-	const char fadetime_patch[] = { 0x66, 0x8B, 0x1D, 0xC4, 0x7D, 0x62, 0x00, 0x66, 0x89, 0x5E, 0x46, 0x5B, 0x5E, 0x83, 0xC4, 0x14, 0xC3 };
-	DDrPatch_Const (OniExe + 0x0011a889, fadetime_patch);
-	DDrPatch_Byte  (OniExe + 0x0011a560, 0x31);
-	
-	// Sets the fadetime to 4800 by default
-	DDrPatch_Int16 (OniExe + 0x0011ab0e, 0x12c0);
+	if (patch_wpfadetime)
+	{
+		// Makes wp_fadetime actually have a function
+		const char fadetime_patch[] = { 0x66, 0x8B, 0x1D, 0xC4, 0x7D, 0x62, 0x00, 0x66, 0x89, 0x5E, 0x46, 0x5B, 0x5E, 0x83, 0xC4, 0x14, 0xC3 };
+		DDrPatch_Const (OniExe + 0x0011a889, fadetime_patch);
+		DDrPatch_Byte  (OniExe + 0x0011a560, 0x31);
+		
+		// Sets the fadetime to 4800 by default
+		DDrPatch_Int16 (OniExe + 0x0011ab0e, 0x12c0);
+	}
 	
 	
 	// Hackish fix for Konoko not kicking guns
-//	const char kickgun_patch[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0xC7, 0x05, 0x1C, 0xC9, 0x5E, 0x00, 0x70, 0xB8, 0x43, 0x00, 0xC7, 0x05, 0x20, 0xC9, 0x5E, 0x00, 0x20, 0xBE, 0x43 };
-//	DDrPatch_Const (OniExe + 0x000dc420, kickgun_patch);
+	if (patch_kickguns)
+	{
+		const char kickgun_patch[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0xC7, 0x05, 0x1C, 0xC9, 0x5E, 0x00, 0x70, 0xB8, 0x43, 0x00, 0xC7, 0x05, 0x20, 0xC9, 0x5E, 0x00, 0x20, 0xBE, 0x43 };
+		DDrPatch_Const (OniExe + 0x000dc420, kickgun_patch);
+	}
 	
 	// Cooldown timer exploit fix ^_^
-	const char cooldown_patch[] = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 };
-	DDrPatch_Const (OniExe + 0x0011a825, cooldown_patch);
-	
-//	const char throwtest_patch[] = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 };
-//	DDrPatch_Const(OniExe + 0x000dc190, throwtest_patch);
+	if (patch_cooldowntimer)
+	{
+		const char cooldown_patch[] = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 };
+		DDrPatch_Const (OniExe + 0x0011a825, cooldown_patch);
+	}
+	
+	if (patch_throwtest)
+	{
+		const char throwtest_patch[] = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 };
+		DDrPatch_Const(OniExe + 0x000dc190, throwtest_patch);
+	}
 	
 	// Disable UUrPlatform_Initalize/Terminate, this enables the Alt-Tab and the Windows key but has the possible side effect of allowing the screensaver to enable itself in-game.
-	DDrPatch_Byte  ((void*)UUrPlatform_Initialize, 0xC3);
-	DDrPatch_Byte  ((void*)UUrPlatform_Terminate, 0xC3);
+	if (patch_alttab)
+	{
+		DDrPatch_Byte  ((void*)UUrPlatform_Initialize, 0xC3);
+		DDrPatch_Byte  ((void*)UUrPlatform_Terminate, 0xC3);
+	}
 	
 	// Unlocks particle action disabling/enabling bits for all events. (Will be controlled by a command line switch when I figure out how to do that without Win32 hacks.)
-	//DDrPatch_Int16 (OniExe + 0x001b184, 0x9090);
+	if (patch_particledisablebit)
+		DDrPatch_Int16 (OniExe + 0x001b184, 0x9090);
 	
 	// Multi-byte patch (multiple language support)
-	DDrPatch_Byte  (OniExe + 0x0002d8f8, 0xeb);
-	DDrPatch_Byte  (OniExe + 0x0002d9ad, 0xeb);
-	DDrPatch_Byte  (OniExe + 0x0002dbe2, 0xeb);
-	DDrPatch_Byte  (OniExe + 0x0002dec3, 0xeb);
-	DDrPatch_Byte  (OniExe + 0x0002e2ab, 0xeb);
-	DDrPatch_Byte  (OniExe + 0x0002e2c4, 0xeb);
-	DDrPatch_Byte  (OniExe + 0x0002e379, 0xeb);
-	DDrPatch_Byte  (OniExe + 0x0002e48c, 0xeb);
-	DDrPatch_Byte  (OniExe + 0x0002e4d0, 0xeb);
-	DDrPatch_Byte  (OniExe + 0x0002e4f4, 0xeb);
-	DDrPatch_Byte  (OniExe + 0x0002e646, 0xeb);
-	DDrPatch_Byte  (OniExe + 0x0002e695, 0xeb);
-	DDrPatch_Byte  (OniExe + 0x0002e944, 0xeb);
-	DDrPatch_Byte  (OniExe + 0x0002e95d, 0xeb);
-	DDrPatch_Byte  (OniExe + 0x0002e98e, 0xeb);
-	DDrPatch_Byte  (OniExe + 0x0002e9dc, 0xeb);
+	if (patch_multibyte)
+	{
+		DDrPatch_Byte  (OniExe + 0x0002d8f8, 0xeb);
+		DDrPatch_Byte  (OniExe + 0x0002d9ad, 0xeb);
+		DDrPatch_Byte  (OniExe + 0x0002dbe2, 0xeb);
+		DDrPatch_Byte  (OniExe + 0x0002dec3, 0xeb);
+		DDrPatch_Byte  (OniExe + 0x0002e2ab, 0xeb);
+		DDrPatch_Byte  (OniExe + 0x0002e2c4, 0xeb);
+		DDrPatch_Byte  (OniExe + 0x0002e379, 0xeb);
+		DDrPatch_Byte  (OniExe + 0x0002e48c, 0xeb);
+		DDrPatch_Byte  (OniExe + 0x0002e4d0, 0xeb);
+		DDrPatch_Byte  (OniExe + 0x0002e4f4, 0xeb);
+		DDrPatch_Byte  (OniExe + 0x0002e646, 0xeb);
+		DDrPatch_Byte  (OniExe + 0x0002e695, 0xeb);
+		DDrPatch_Byte  (OniExe + 0x0002e944, 0xeb);
+		DDrPatch_Byte  (OniExe + 0x0002e95d, 0xeb);
+		DDrPatch_Byte  (OniExe + 0x0002e98e, 0xeb);
+		DDrPatch_Byte  (OniExe + 0x0002e9dc, 0xeb);
+	}
 	
 	// Cheat table patch
-	DDrPatch_Int32 (OniExe + 0x000f616b, (int)&DDr_CheatTable[0].name);
-	DDrPatch_Int32 (OniExe + 0x000f617a, (int)&DDr_CheatTable[0].message_on);
+	if (patch_cheattable)
+	{
+		DDrPatch_Int32 (OniExe + 0x000f616b, (int)&DDr_CheatTable[0].name);
+		DDrPatch_Int32 (OniExe + 0x000f617a, (int)&DDr_CheatTable[0].message_on);
+	}
 	
 	return true;
 }
 
-enum {s_unknown, s_language} ini_section;
+enum {s_unknown, s_patch, s_language} ini_section;
 
 bool DDrIniCallback(char* section, bool newsection, char* name, char* value)
@@ -106,5 +156,7 @@
 	if (newsection)
 	{
-		if (!stricmp(section, "language"))
+		if (!stricmp(section, "patch"))
+			ini_section = s_patch;
+		else if (!stricmp(section, "language"))
 			ini_section = s_language;
 		else
@@ -117,15 +169,55 @@
 	switch (ini_section)
 	{
+		case s_patch:
+			if (!stricmp(name, "fonttexturecache"))
+				patch_fonttexturecache = !stricmp(value, "true");
+			else if (!stricmp(name, "largetextures"))
+				patch_largetextures = !stricmp(value, "true");
+			else if (!stricmp(name, "pathfinding"))
+				patch_pathfinding = !stricmp(value, "true");
+			else if (!stricmp(name, "projaware"))
+				patch_projaware = !stricmp(value, "true");
+			else if (!stricmp(name, "wpfadetime"))
+				patch_wpfadetime = !stricmp(value, "true");
+			else if (!stricmp(name, "kickguns"))
+				patch_kickguns = !stricmp(value, "true");
+			else if (!stricmp(name, "cooldowntimer"))
+				patch_cooldowntimer = !stricmp(value, "true");
+			else if (!stricmp(name, "throwtest"))
+				patch_throwtest = !stricmp(value, "true");
+			else if (!stricmp(name, "alttab"))
+				patch_alttab = !stricmp(value, "true");
+			else if (!stricmp(name, "particledisablebit"))
+				patch_particledisablebit = !stricmp(value, "true");
+			else if (!stricmp(name, "multibyte"))
+				patch_multibyte = !stricmp(value, "true");
+			else if (!stricmp(name, "cheattable"))
+				patch_cheattable = !stricmp(value, "true");
+			else if (!stricmp(name, "safeprintf"))
+				patch_safeprintf = !stricmp(value, "true");
+			else if (!stricmp(name, "daodandisplayenum"))
+				patch_daodandisplayenum = !stricmp(value, "true");
+			else if (!stricmp(name, "usegettickcount"))
+				patch_usegettickcount = !stricmp(value, "true");
+			else if (!stricmp(name, "usedaodangl"))
+				patch_usedaodangl = !stricmp(value, "true");
+			else
+				DDrStartupMessage("unrecognised patch \"%s\"", name);
+			break;
 		case s_language:
 			if (!stricmp(name, "savepoint"))
 			{
-				DDrPatch_StrDup(OniExe + 0x000fd730, value);
-				DDrPatch_StrDup(OniExe + 0x000fd738, value);
+				char* str = strdup(value);
+				DDrPatch_Int32(OniExe + 0x000fd730, (int)str);
+				DDrPatch_Int32(OniExe + 0x000fd738, (int)str);
 			}
 			else if (!stricmp(name, "syndicatewarehouse"))
 			{
-				DDrPatch_StrDup(OniExe + 0x000fd71a, value);
-				DDrPatch_StrDup(OniExe + 0x0010ef75, value);
+				char* str = strdup(value);
+				DDrPatch_Int32(OniExe + 0x000fd71a, (int)str);
+				DDrPatch_Int32(OniExe + 0x0010ef75, (int)str);
 			}
+			else if (!stricmp(name, "damn"))
+				DDrPatch_StrDup(OniExe + 0x0010fb6e, value);
 			else if (!stricmp(name, "blam"))
 				DDrPatch_StrDup(OniExe + 0x0010fb73, value);
@@ -166,13 +258,18 @@
 	
 	// Safe startup message printer
-	DDrPatch_MakeJump(UUrStartupMessage, DDrStartupMessage);
+	if (patch_safeprintf)
+		DDrPatch_MakeJump(UUrStartupMessage, DDrStartupMessage);
 	
 	// Daodan device mode enumeration function
-	DDrPatch_MakeJump(gl_enumerate_valid_display_modes, daodan_enumerate_valid_display_modes);
+	if (patch_daodandisplayenum)
+		DDrPatch_MakeJump(gl_enumerate_valid_display_modes, daodan_enumerate_valid_display_modes);
 	
 	// Performance patch
-	DDrPatch_MakeJump(UUrMachineTime_High, DDrMachineTime_High);
-	DDrPatch_MakeJump(UUrMachineTime_High_Frequency, DDrMachineTime_High_Frequency);
-	DDrPatch_MakeJump(UUrMachineTime_Sixtieths, DDrMachineTime_Sixtieths);
+	if (patch_usegettickcount)
+	{
+		DDrPatch_MakeJump(UUrMachineTime_High, DDrMachineTime_High);
+		DDrPatch_MakeJump(UUrMachineTime_High_Frequency, DDrMachineTime_High_Frequency);
+		DDrPatch_MakeJump(UUrMachineTime_Sixtieths, DDrMachineTime_Sixtieths);
+	}
 	
 	// Cheats always enabled
@@ -180,6 +277,9 @@
 	
 	// Windowed mode
-//	DDrPatch_MakeJump(ONrPlatform_Initialize, DDrPlatform_Initialize);
-//	DDrPatch_MakeJump(gl_platform_initialize, daodangl_platform_initialize);
+	if (patch_usedaodangl)
+	{
+		DDrPatch_MakeJump(ONrPlatform_Initialize, DDrPlatform_Initialize);
+		DDrPatch_MakeJump(gl_platform_initialize, daodangl_platform_initialize);
+	}
 	
 	init_daodan_gl();
