--- Daodan/src/Daodan_Config.c 2013/07/26 10:42:31 893 +++ Daodan/src/Daodan_Config.c 2014/04/06 17:06:02 993 @@ -6,168 +6,442 @@ #include "Daodan_Patch.h" #include "Daodan_Utility.h" -#include "Oni_Symbols.h" +#include "Oni/Oni.h" #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_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_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; +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) -bool patch_chinese = true; +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} } + } } +}; -enum {s_unknown, s_options, s_patch, s_bsl, s_language} ini_section; -bool DDrIniCallback(char* section, bool newsection, char* name, char* value) +void DDrConfig_Print() { - if (newsection) + 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")) - ini_section = s_patch; - else if (!_stricmp(section, "bsl")) - ini_section = s_bsl; - else if (!_stricmp(section, "language")) - ini_section = s_language; - else - { - ini_section = s_unknown; - DDrStartupMessage("Daodan: Unrecognised ini section \"%s\"", section); + 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(); - switch (ini_section) + 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 ++) { - 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); - 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, "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, "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"); + 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 - DDrStartupMessage("Daodan: Unrecognised ini patch \"%s\"", name); + { + 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 + { + STARTUPMESSAGE("Parse error \"%s\"", argv[i]); 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); else if (!_stricmp(name, "damn")) @@ -272,86 +546,5 @@ bool DDrIniCallback(char* section, bool DDr_CheatTable[21].message_on = _strdup(value); 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"); -} +*/