source: Daodan/src/Daodan_Config.c@ 1015

Last change on this file since 1015 was 1008, checked in by alloc, 10 years ago

Daodan 3.9: Added AI awareness patch (fixes #36)

File size: 17.1 KB
Line 
1#include <windows.h>
2#include <string.h>
3#include <time.h>
4
5#include "Daodan_Config.h"
6#include "Daodan_Patch.h"
7#include "Patches/Utility.h"
8
9#include "Oni/Oni.h"
10#include "_Version.h"
11
12#include "Inifile_Reader.h"
13
14#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
15
16static const char* iniName = "daodan.ini";
17static const char* helpFile = "daodan_help.txt";
18
19static const char* defaultSection = "options";
20
21static char invalidCurParamaters[2000] = "";
22static char invalidTotalParamaters[4000] = "";
23
24void DDrConfig_PrintHelp();
25
26
27ConfigSection_t config[] = {
28 { "", "Command line only", {
29 { "help",
30 "Generates this help file.",
31 C_CMD,
32 {.intBoolVal = 0},
33 {.callback = DDrConfig_PrintHelp} },
34 { 0, 0, 0, {0}, {0} }
35 } },
36 { "devmode", "Developer Mode", {
37 { "highres_console",
38 "Fixes bug where console line becomes invisible at higher resolutions.",
39 C_BOOL,
40 {.intBoolVal = true},
41 {.intBoolVal = true} },
42 { "showtriggervolumes",
43 "Allows BSL variable \"show_triggervolumes\" and Ctrl+Shift+X (in devmode) to work.",
44 C_BOOL,
45 {.intBoolVal = true},
46 {.intBoolVal = true} },
47 { 0, 0, 0, {0}, {0} }
48 } },
49 { "gameplay", "Gameplay", {
50 { "characterawareness",
51 "Makes AI remember the player.",
52 C_BOOL,
53 {.intBoolVal = true},
54 {.intBoolVal = true} },
55 { "cheatsenabled",
56 "Enables cheats without having to beat the game first.",
57 C_BOOL,
58 {.intBoolVal = true},
59 {.intBoolVal = true} },
60 { "cheattable",
61 "Replaces Oni's cheat table with table that includes new cheats including devmode.",
62 C_BOOL,
63 {.intBoolVal = true},
64 {.intBoolVal = true} },
65 { "cooldowntimer",
66 "Disables weapon cooldown exploit.",
67 C_BOOL,
68 {.intBoolVal = true},
69 {.intBoolVal = true} },
70 { "kickguns",
71 "EXPERIMENTAL! Unfinished, do not use.",
72 C_BOOL,
73 {.intBoolVal = false},
74 {.intBoolVal = false} },
75 { "pathfinding",
76 "Size of pathfinding grid cache increased by eight times in order to prevent crashes in large levels.",
77 C_BOOL,
78 {.intBoolVal = true},
79 {.intBoolVal = true} },
80 { "projaware",
81 "Allows AI to dodge incoming gunfire properly.",
82 C_BOOL,
83 {.intBoolVal = true},
84 {.intBoolVal = true} },
85 { "throwtest",
86 "EXPERIMENTAL! Experiment with allowing enemies to be thrown over railings.",
87 C_BOOL,
88 {.intBoolVal = false},
89 {.intBoolVal = false} },
90 { "wpfadetime",
91 "Adds working function for existing BSL command wp_fadetime, sets fade time to 4800.",
92 C_BOOL,
93 {.intBoolVal = true},
94 {.intBoolVal = true} },
95 { 0, 0, 0, {0}, {0} }
96 } },
97 { "graphics", "Graphics", {
98 { "binkplay",
99 "Fix binkplay calls to use GDI and outro same mode as intro.",
100 C_BOOL,
101 {.intBoolVal = true},
102 {.intBoolVal = true} },
103 { "daodangl",
104 "Provides an improved windowed mode (-noswitch).",
105 C_BOOL,
106 {.intBoolVal = true},
107 {.intBoolVal = true} },
108 { "displayenum",
109 "Offers a more accurate list of available display modes in the Options menu.",
110 C_BOOL,
111 {.intBoolVal = true},
112 {.intBoolVal = true} },
113 { "gamma",
114 "Enable gamma slider in fullscreen, disable in windowed mode.",
115 C_BOOL,
116 {.intBoolVal = true},
117 {.intBoolVal = true} },
118 { "newweap",
119 "Standing above a weapon displays a message containing the weapon name and amount of ammo.",
120 C_BOOL,
121 {.intBoolVal = true},
122 {.intBoolVal = true} },
123 { "optionsvisible",
124 "Always show options button in main menu, even when pausing from a game.",
125 C_BOOL,
126 {.intBoolVal = true},
127 {.intBoolVal = true} },
128 { "showalllasersights",
129 "Show all (also enemies') weapon lasersights.",
130 C_BOOL,
131 {.intBoolVal = false},
132 {.intBoolVal = false} },
133 { "widescreenportraits",
134 "Prevents fly-in portraits from being stretched when playing in widescreen resolutions.",
135 C_BOOL,
136 {.intBoolVal = true},
137 {.intBoolVal = true} },
138 { 0, 0, 0, {0}, {0} }
139 } },
140 { "language", "Language", {
141 { "chinese",
142 "Allow for chinese fonts to be shown if the required DLL is available.",
143 C_BOOL,
144 {.intBoolVal = true},
145 {.intBoolVal = true} },
146 { "fonttexturecache",
147 "Doubles size of font texture cache.",
148 C_BOOL,
149 {.intBoolVal = true},
150 {.intBoolVal = true} },
151 { "language",
152 "Localization for hardcoded strings (e.g. \"Savepoints\").",
153 C_STRING,
154 {.stringVal = "en"},
155 {.stringVal = "en"} },
156 { "nomultibyte",
157 "Enables languages which use multibyte coding (such as Chinese).",
158 C_BOOL,
159 {.intBoolVal = true},
160 {.intBoolVal = true} },
161 { 0, 0, 0, {0}, {0} }
162 } },
163 { "modding", "Modding", {
164 { "argb8888",
165 "Allows using textures with ARGB8888.",
166 C_BOOL,
167 {.intBoolVal = true},
168 {.intBoolVal = true} },
169 { "d_regen",
170 "Enables script command d_regen (query/set regeneration for any character).",
171 C_BOOL,
172 {.intBoolVal = true},
173 {.intBoolVal = true} },
174 { "daodanbsl",
175 "Adds new BSL commands.",
176 C_BOOL,
177 {.intBoolVal = true},
178 {.intBoolVal = true} },
179 { "hdscreens_lowres",
180 "Allow HD intro/ending screens on game resolutions smaller than 1024x768.",
181 C_BOOL,
182 {.intBoolVal = true},
183 {.intBoolVal = true} },
184 { "largetextures",
185 "Textures up to 512x512 can be used.",
186 C_BOOL,
187 {.intBoolVal = true},
188 {.intBoolVal = true} },
189 { "levelplugins",
190 "Allows level files to be loaded which do not end in \"_Final\".",
191 C_BOOL,
192 {.intBoolVal = true},
193 {.intBoolVal = true} },
194 { 0, 0, 0, {0}, {0} }
195 } },
196 { "oni", "Original Oni Options", {
197 { "debug",
198 "Not useful, probably does nothing.",
199 EXT_BOOL,
200 {.intBoolVal = false },
201 {.extBoolVal = &AKgDebug_DebugMaps } },
202 { "debugfiles",
203 "Logs called BSL functions to script_debug.txt.",
204 EXT_BOOL,
205 {.intBoolVal = false },
206 {.extBoolVal = &BFgDebugFileEnable } },
207 { "findsounds",
208 "Not useful, extends output of sound_list_broken_links.",
209 EXT_BOOL,
210 {.intBoolVal = false },
211 {.extBoolVal = &SSgSearchOnDisk } },
212 { "ignore_private_data",
213 "Not useful, probably does nothing.",
214 EXT_BOOL,
215 {.intBoolVal = false },
216 {.extBoolVal = &opt_ignore_private_data } },
217 { "sound",
218 "Enable sound.",
219 EXT_BOOL,
220 {.intBoolVal = true },
221 {.extBoolVal = &opt_sound } },
222 { "switch",
223 "Switch to fullscreen instead of staying in a window.",
224 EXT_BOOL,
225 {.intBoolVal = true},
226 {.extBoolVal = &M3gResolutionSwitch} },
227 { 0, 0, 0, {0}, {0} }
228 } },
229 { "windows", "Windows", {
230 { "alttab",
231 "Allows to Alt-Tab out of Oni and use Windows key. May enable the screensaver as well.",
232 C_BOOL,
233 {.intBoolVal = true},
234 {.intBoolVal = true} },
235 { "border",
236 "Add a border if in windowed mode and \"usedaodangl\" patch is active.",
237 C_BOOL,
238 {.intBoolVal = true},
239 {.intBoolVal = true} },
240 { "clipcursor",
241 "Limit cursor to Oni's window.",
242 C_BOOL,
243 {.intBoolVal = true},
244 {.intBoolVal = true} },
245 { "directinput",
246 "Enforces the usage of DirectInput on every system. Should be off for Linux/Wine.",
247 C_BOOL,
248 {.intBoolVal = true},
249 {.intBoolVal = true} },
250 { "disablecmdline",
251 "Disables Oni's existing command line parser as Daodan has its own.",
252 C_BOOL,
253 {.intBoolVal = true},
254 {.intBoolVal = true} },
255 { "killvtune",
256 "Prevent loading of vtuneapi.dll.",
257 C_BOOL,
258 {.intBoolVal = false},
259 {.intBoolVal = false} },
260 { "safeprintf",
261 "Replaces Oni's function that prints to startup.txt with a safer one.",
262 C_BOOL,
263 {.intBoolVal = true},
264 {.intBoolVal = true} },
265 { "topmost",
266 "Keep game window on top in windowed mode, even when switching applications.",
267 C_BOOL,
268 {.intBoolVal = false},
269 {.intBoolVal = false} },
270 { "usegettickcount",
271 "Replaces Oni's timing functions with more accurate ones.",
272 C_BOOL,
273 {.intBoolVal = true},
274 {.intBoolVal = true} },
275 { 0, 0, 0, {0}, {0} }
276 } }
277};
278
279
280void DDrConfig_Print()
281{
282 for (unsigned int s = 0; s < ARRAY_SIZE(config); s++) {
283 for (ConfigOption_t* co = config[s].options; co->name != 0; co++) {
284 switch (co->type) {
285 case C_STRING:
286 STARTUPMESSAGE("Option %s.%s = %s (def %s)", config[s].name, co->name, co->value.stringVal, co->defaultValue.stringVal);
287 break;
288 case EXT_BOOL:
289 STARTUPMESSAGE("Option %s.%s = %d (def %d)", config[s].name, co->name, *co->value.extBoolVal, co->defaultValue.intBoolVal);
290 break;
291 case C_CMD:
292 break;
293 default:
294 STARTUPMESSAGE("Option %s.%s = %d (def %d)", config[s].name, co->name, co->value.intBoolVal, co->defaultValue.intBoolVal);
295 }
296 }
297 }
298}
299
300void DDrConfig_PrintHelp()
301{
302 STARTUPMESSAGE("Writing Daodan help file (%s)", helpFile);
303
304 FILE* fp;
305 remove(helpFile);
306 fp = fopen(helpFile, "w");
307 if (fp)
308 {
309 time_t rawtime;
310 struct tm* timeinfo;
311 char buffer[80];
312 time(&rawtime);
313 timeinfo = localtime(&rawtime);
314 strftime(buffer, 80, "%Y-%m-%d %H:%M:%S", timeinfo);
315
316 fprintf(fp, "Daodan help - generated on %s for Daodan v."DAODAN_VERSION_STRING"\n\n", buffer);
317 fprintf(fp, "List of Daodan configuration parameters:\n");
318 for (unsigned int s = 0; s < ARRAY_SIZE(config); s++) {
319 fprintf(fp, " %s - %s:\n", config[s].name, config[s].description);
320 for (ConfigOption_t* co = config[s].options; co->name != 0; co++) {
321 char* name = co->name;
322 char* desc = co->description;
323 const char* tName = DDrConfig_GetOptionTypeName(co->type);
324 const char* val = DDrConfig_GetOptionValueString(co, 1);
325 if (!val)
326 val = "";
327 fprintf(fp, " %-22s %6s=%-5s %s\n", name, tName, val, desc);
328 }
329 fprintf(fp, "\n");
330 }
331 fprintf(fp, "\nConfiguration parameters can be either set in daodan.ini or passed on command line.\n\n");
332 fprintf(fp, "In daodan.ini each section of parameters has its own section in the ini file started by [section name]. Parameters are given within that section by their name only, followed by an equals sign and the desired value. Example:\n");
333 fprintf(fp, " [sectionX]\n parameterName = false\n");
334 fprintf(fp, "\nTo pass the parameter on the command line:\n");
335 fprintf(fp, " Oni.exe -parameterName false\n");
336 fprintf(fp, "For bool parameters the value can be ommitted so it is regarded as \"true\":\n");
337 fprintf(fp, " Oni.exe -parameterName\n");
338 fprintf(fp, "To disable a bool parameter you can prefix \"no\" to the parameter name like this:\n");
339 fprintf(fp, " Oni.exe -noparameterName\n");
340
341 fclose(fp);
342 }
343 else
344 {
345 STARTUPMESSAGE("Writing Daodan help file failed", 0);
346 }
347}
348
349const char* DDrConfig_GetOptionTypeName(OptionType_t type)
350{
351 switch (type) {
352 case C_INT:
353 return "Int";
354 case C_BOOL:
355 return "Bool";
356 case C_STRING:
357 return "String";
358 case C_CMD:
359 return "Cmd";
360 case EXT_BOOL:
361 return "pBool";
362 default:
363 return "unknown";
364 }
365}
366
367const char* DDrConfig_GetOptionValueString(ConfigOption_t* opt, char printdefault)
368{
369 OptionValue_t* optVal = (printdefault ? &opt->defaultValue : &opt->value);
370 int boolV = optVal->intBoolVal;
371 char* val = 0;
372 switch (opt->type) {
373 case C_STRING:
374 return optVal->stringVal;
375 case EXT_BOOL:
376 if (printdefault)
377 return (boolV ? "true" : "false");
378 else
379 return (*optVal->extBoolVal ? "true" : "false");
380 case C_BOOL:
381 return (boolV ? "true" : "false");
382 case C_CMD:
383 return 0;
384 default:
385 val = malloc(20);
386 sprintf(val, "%d", boolV);
387 return val;
388 }
389}
390
391char DDrConfig_NonDefaultOptionValue(ConfigOption_t* opt)
392{
393 switch (opt->type) {
394 case C_STRING:
395 return _stricmp(opt->defaultValue.stringVal, opt->value.stringVal);
396 case EXT_BOOL:
397 return !opt->defaultValue.intBoolVal != !*opt->value.extBoolVal;
398 case C_BOOL:
399 return !opt->defaultValue.intBoolVal != !opt->value.intBoolVal;
400 case C_CMD:
401 return 0;
402 case C_INT:
403 return opt->defaultValue.intBoolVal != opt->value.intBoolVal;
404 }
405 return 0;
406}
407
408static ConfigOption_t* DDrConfig_GetOption(const char* fullOptName)
409{
410 char section[50];
411 strcpy(section, fullOptName);
412
413 char* option = strchr(section, '.');
414 if (option == 0) {
415 STARTUPMESSAGE("Could not find option separator in \"%s\"", fullOptName);
416 return 0;
417 }
418 *option++ = 0;
419
420 char isWildcardSection = !_stricmp(section, "*");
421
422 for (unsigned int s = 0; s < ARRAY_SIZE(config); s++) {
423 if (isWildcardSection || !_stricmp(config[s].name, section)) {
424 for (ConfigOption_t* co = config[s].options; co->name != 0; co++) {
425 if (!_stricmp(co->name, option)) {
426 return co;
427 }
428 }
429 if (!isWildcardSection) {
430 STARTUPMESSAGE("Could not find option \"%s\" in section \"%s\"", option, section);
431 return 0;
432 }
433 }
434 }
435 if (!isWildcardSection)
436 STARTUPMESSAGE("Could not find section \"%s\" for option \"%s\"", section, option);
437 else
438 STARTUPMESSAGE("Could not find option \"%s\"", option);
439 return 0;
440}
441
442
443
444ConfigOption_t* DDrConfig_GetOptOfType(const char* fullOptName, OptionType_t type)
445{
446 ConfigOption_t* co = DDrConfig_GetOption(fullOptName);
447 if (co == 0)
448 return 0;
449
450 if (co->type != type) {
451 STARTUPMESSAGE("Option \"%s\" is not of type %s", fullOptName, DDrConfig_GetOptionTypeName(type));
452 return 0;
453 }
454 return co;
455}
456
457
458
459void DDrConfig_InitExtBools()
460{
461 for (unsigned int s = 0; s < ARRAY_SIZE(config); s++) {
462 for (ConfigOption_t* co = config[s].options; co->name != 0; co++) {
463 if (co->type == EXT_BOOL) {
464 *co->value.extBoolVal = co->defaultValue.intBoolVal;
465 }
466 }
467 }
468}
469
470
471
472void DDrConfig_WriteIni()
473{
474 FILE* fp;
475 STARTUPMESSAGE("%s doesn't exist, creating", iniName);
476 fp = fopen(iniName, "w");
477 if (fp)
478 {
479 for (unsigned int s = 0; s < ARRAY_SIZE(config); s++) {
480 if (strlen(config[s].name)) {
481 fprintf(fp, "[%s]\n", config[s].name);
482 for (ConfigOption_t* co = config[s].options; co->name != 0; co++) {
483 char* name = co->name;
484 const char* val = DDrConfig_GetOptionValueString(co, 0);
485 if (val && DDrConfig_NonDefaultOptionValue(co))
486 fprintf(fp, "%s = %s\n", name, val);
487 }
488 fprintf(fp, "\n");
489 }
490 }
491 fclose(fp);
492 }
493 else
494 {
495 STARTUPMESSAGE("Writing %s template file failed", iniName);
496 }
497}
498
499
500void DDrIniCallback(const char* section, const char* name, const char* value)
501{
502 char fullOptName[50];
503
504 if (!_stricmp(section, "patch"))
505 section = "patches";
506
507 strcpy(fullOptName, section);
508 fullOptName[strlen(section)] = '.';
509 strcpy(fullOptName+strlen(section)+1, name);
510
511 ConfigOption_t* co = DDrConfig_GetOption(fullOptName);
512
513 if (co)
514 {
515 char* buf = 0;
516 switch (co->type) {
517 case C_INT:
518 co->value.intBoolVal = strtol(value, NULL, 0);
519 break;
520 case C_BOOL:
521 co->value.intBoolVal = !_stricmp(value, "true");
522 break;
523 case C_STRING:
524 buf = malloc(strlen(value)+1);
525 strcpy(buf, value);
526 co->value.stringVal = buf;
527 break;
528 case C_CMD:
529 co->value.callback();
530 break;
531 case EXT_BOOL:
532 *(co->value.extBoolVal) = !_stricmp(value, "true");
533 break;
534 default:
535 STARTUPMESSAGE("Config value type unknown: %d", co->type);
536 }
537 } else {
538 char buf[100];
539 if (!_stricmp(section, "*"))
540 sprintf(buf, " %s\n", name);
541 else
542 sprintf(buf, " %s.%s\n", section, name);
543 if (strlen(buf) + strlen(invalidCurParamaters) < sizeof(invalidCurParamaters) - 1) {
544 strcpy(invalidCurParamaters + strlen(invalidCurParamaters), buf);
545 }
546 }
547}
548
549
550bool DDrConfig_ParseCommandLine(int argc, char* argv[])
551{
552 for (int i = 1; i < argc; i ++)
553 {
554 if (argv[i][0] == '-')
555 {
556 char* option;
557 bool invertedOption;
558
559 option = argv[i]+1;
560
561 invertedOption = (option[0] == 'n' || option[0] == 'N') && (option[1] == 'o' || option[1] == 'O');
562 if (invertedOption)
563 option += 2;
564
565 if (i < (argc - 1) && argv[i+1][0] != '-')
566 // Has value in next field
567 {
568 DDrIniCallback("*", option, argv[++i]);
569 }
570 else
571 // Implicit value
572 {
573 DDrIniCallback("*", option, (invertedOption ? "false" : "true"));
574 }
575 }
576 else
577 {
578 STARTUPMESSAGE("Parse error \"%s\"", argv[i]);
579 return false;
580 }
581 }
582 return true;
583}
584
585void DDrConfig(int argc, char* argv[])
586{
587 STARTUPMESSAGE("Initializing standard booleans", 0);
588 DDrConfig_InitExtBools();
589
590 if (GetFileAttributes(iniName) == INVALID_FILE_ATTRIBUTES)
591 DDrConfig_WriteIni();
592
593 STARTUPMESSAGE("Parsing daodan.ini...", 0);
594 if (!Inifile_Read(iniName, DDrIniCallback))
595 STARTUPMESSAGE("Error reading daodan.ini, check your syntax!", 0);
596 STARTUPMESSAGE("Finished parsing", 0);
597
598 if (strlen(invalidCurParamaters) > 0)
599 {
600 sprintf(invalidTotalParamaters, "In %s:\n%s\n", iniName, invalidCurParamaters);
601 invalidCurParamaters[0] = 0;
602 }
603
604 STARTUPMESSAGE("Parsing command line...", 0);
605 DDrConfig_ParseCommandLine(argc, argv);
606 STARTUPMESSAGE("Finished parsing", 0);
607
608 if (strlen(invalidCurParamaters) > 0)
609 {
610 sprintf(invalidTotalParamaters, "%sOn command line:\n%s\n", invalidTotalParamaters, invalidCurParamaters);
611 }
612
613 if (strlen(invalidTotalParamaters) > 0)
614 {
615 char msg[4096];
616 sprintf(msg, "Invalid parameters given:\n%sContinue launching Oni?", invalidTotalParamaters);
617 int res = MessageBox(NULL, msg, "Parameters invalid", MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON1);
618 if (res == IDNO) {
619 exit(0);
620 }
621 }
622
623 DDrConfig_WriteIni();
624
625// DDrConfig_Print();
626}
627
Note: See TracBrowser for help on using the repository browser.