1 /*
2 ** gameconfigfile.cpp
3 ** An .ini parser specifically for zdoom.ini
4 **
5 **---------------------------------------------------------------------------
6 ** Copyright 1998-2008 Randy Heit
7 ** All rights reserved.
8 **
9 ** Redistribution and use in source and binary forms, with or without
10 ** modification, are permitted provided that the following conditions
11 ** are met:
12 **
13 ** 1. Redistributions of source code must retain the above copyright
14 ** notice, this list of conditions and the following disclaimer.
15 ** 2. Redistributions in binary form must reproduce the above copyright
16 ** notice, this list of conditions and the following disclaimer in the
17 ** documentation and/or other materials provided with the distribution.
18 ** 3. The name of the author may not be used to endorse or promote products
19 ** derived from this software without specific prior written permission.
20 **
21 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OFf
30 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 **---------------------------------------------------------------------------
32 **
33 */
34
35 #include <stdio.h>
36 #include <time.h>
37
38 #ifdef __APPLE__
39 #include <CoreServices/CoreServices.h>
40 #endif
41
42 #ifdef _WIN32
43 #define WIN32_LEAN_AND_MEAN
44 #include <windows.h>
45 extern HWND Window;
46 #define USE_WINDOWS_DWORD
47 #endif
48
49 #include "doomdef.h"
50 #include "gameconfigfile.h"
51 #include "c_cvars.h"
52 #include "c_dispatch.h"
53 #include "c_bind.h"
54 #include "gstrings.h"
55 #include "m_argv.h"
56 #include "cmdlib.h"
57 #include "version.h"
58 #include "m_misc.h"
59 #include "v_font.h"
60 #include "a_pickups.h"
61 #include "doomstat.h"
62 #include "i_system.h"
63 #include "gi.h"
64 #include "d_main.h"
65
EXTERN_CVAR(Bool,con_centernotify)66 EXTERN_CVAR (Bool, con_centernotify)
67 EXTERN_CVAR (Int, msg0color)
68 EXTERN_CVAR (Color, color)
69 EXTERN_CVAR (Float, dimamount)
70 EXTERN_CVAR (Int, msgmidcolor)
71 EXTERN_CVAR (Int, msgmidcolor2)
72 EXTERN_CVAR (Bool, snd_pitched)
73 EXTERN_CVAR (Color, am_wallcolor)
74 EXTERN_CVAR (Color, am_fdwallcolor)
75 EXTERN_CVAR (Color, am_cdwallcolor)
76 EXTERN_CVAR (Float, spc_amp)
77 EXTERN_CVAR (Bool, wi_percents)
78
79 FGameConfigFile::FGameConfigFile ()
80 {
81 #ifdef __APPLE__
82 FString user_docs, user_app_support, local_app_support;
83 #endif
84 FString pathname;
85
86 OkayToWrite = false; // Do not allow saving of the config before DoGameSetup()
87 bModSetup = false;
88 pathname = GetConfigPath (true);
89 ChangePathName (pathname);
90 LoadConfigFile ();
91
92 // If zdoom.ini was read from the program directory, switch
93 // to the user directory now. If it was read from the user
94 // directory, this effectively does nothing.
95 pathname = GetConfigPath (false);
96 ChangePathName (pathname);
97
98 // Set default IWAD search paths if none present
99 if (!SetSection ("IWADSearch.Directories"))
100 {
101 SetSection ("IWADSearch.Directories", true);
102 SetValueForKey ("Path", ".", true);
103 SetValueForKey ("Path", "$DOOMWADDIR", true);
104 #ifdef __APPLE__
105 char cpath[PATH_MAX];
106 FSRef folder;
107
108 if (noErr == FSFindFolder(kUserDomain, kDocumentsFolderType, kCreateFolder, &folder) &&
109 noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX))
110 {
111 user_docs << cpath << "/" GAME_DIR;
112 SetValueForKey("Path", user_docs, true);
113 }
114 else
115 {
116 SetValueForKey("Path", "~/" GAME_DIR, true);
117 }
118 if (noErr == FSFindFolder(kUserDomain, kApplicationSupportFolderType, kCreateFolder, &folder) &&
119 noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX))
120 {
121 user_app_support << cpath << "/" GAME_DIR;
122 SetValueForKey("Path", user_app_support, true);
123 }
124 SetValueForKey ("Path", "$PROGDIR", true);
125 if (noErr == FSFindFolder(kLocalDomain, kApplicationSupportFolderType, kCreateFolder, &folder) &&
126 noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX))
127 {
128 local_app_support << cpath << "/" GAME_DIR;
129 SetValueForKey("Path", local_app_support, true);
130 }
131 #elif !defined(__unix__)
132 SetValueForKey ("Path", "$HOME", true);
133 SetValueForKey ("Path", "$PROGDIR", true);
134 #else
135 SetValueForKey ("Path", "~/" GAME_DIR, true);
136 // Arch Linux likes them in /usr/share/doom
137 // Debian likes them in /usr/share/games/doom
138 // I assume other distributions don't do anything radically different
139 SetValueForKey ("Path", "/usr/local/share/doom", true);
140 SetValueForKey ("Path", "/usr/local/share/games/doom", true);
141 SetValueForKey ("Path", "/usr/share/doom", true);
142 SetValueForKey ("Path", "/usr/share/games/doom", true);
143 #endif
144 }
145
146 // Set default search paths if none present
147 if (!SetSection ("FileSearch.Directories"))
148 {
149 SetSection ("FileSearch.Directories", true);
150 #ifdef __APPLE__
151 SetValueForKey ("Path", user_docs, true);
152 SetValueForKey ("Path", user_app_support, true);
153 SetValueForKey ("Path", "$PROGDIR", true);
154 SetValueForKey ("Path", local_app_support, true);
155 #elif !defined(__unix__)
156 SetValueForKey ("Path", "$PROGDIR", true);
157 #else
158 SetValueForKey ("Path", "~/" GAME_DIR, true);
159 SetValueForKey ("Path", SHARE_DIR, true);
160 #endif
161 SetValueForKey ("Path", "$DOOMWADDIR", true);
162 }
163
164 // Add some self-documentation.
165 SetSectionNote("IWADSearch.Directories",
166 "# These are the directories to automatically search for IWADs.\n"
167 "# Each directory should be on a separate line, preceded by Path=\n");
168 SetSectionNote("FileSearch.Directories",
169 "# These are the directories to search for wads added with the -file\n"
170 "# command line parameter, if they cannot be found with the path\n"
171 "# as-is. Layout is the same as for IWADSearch.Directories\n");
172 }
173
~FGameConfigFile()174 FGameConfigFile::~FGameConfigFile ()
175 {
176 }
177
WriteCommentHeader(FILE * file) const178 void FGameConfigFile::WriteCommentHeader (FILE *file) const
179 {
180 fprintf (file, "# This file was generated by " GAMENAME " %s on %s\n", GetVersionString(), myasctime());
181 }
182
DoAutoloadSetup(FIWadManager * iwad_man)183 void FGameConfigFile::DoAutoloadSetup (FIWadManager *iwad_man)
184 {
185 // Create auto-load sections, so users know what's available.
186 // Note that this totem pole is the reverse of the order that
187 // they will appear in the file.
188
189 double last = 0;
190 if (SetSection ("LastRun"))
191 {
192 const char *lastver = GetValueForKey ("Version");
193 if (lastver != NULL) last = atof(lastver);
194 }
195
196 if (last < 211)
197 {
198 RenameSection("Chex3.Autoload", "chex.chex3.Autoload");
199 RenameSection("Chex1.Autoload", "chex.chex1.Autoload");
200 RenameSection("HexenDK.Autoload", "hexen.deathkings.Autoload");
201 RenameSection("HereticSR.Autoload", "heretic.shadow.Autoload");
202 RenameSection("FreeDM.Autoload", "doom.freedoom.freedm.Autoload");
203 RenameSection("Freedoom2.Autoload", "doom.freedoom.phase2.Autoload");
204 RenameSection("Freedoom1.Autoload", "doom.freedoom.phase1.Autoload");
205 RenameSection("Freedoom.Autoload", "doom.freedoom.Autoload");
206 RenameSection("DoomBFG.Autoload", "doom.doom1.bfg.Autoload");
207 RenameSection("DoomU.Autoload", "doom.doom1.ultimate.Autoload");
208 RenameSection("Doom1.Autoload", "doom.doom1.registered.Autoload");
209 RenameSection("TNT.Autoload", "doom.doom2.tnt.Autoload");
210 RenameSection("Plutonia.Autoload", "doom.doom2.plutonia.Autoload");
211 RenameSection("Doom2BFG.Autoload", "doom.doom2.bfg.Autoload");
212 RenameSection("Doom2.Autoload", "doom.doom2.commercial.Autoload");
213 }
214 const FString *pAuto;
215 for (int num = 0; (pAuto = iwad_man->GetAutoname(num)) != NULL; num++)
216 {
217 if (!(iwad_man->GetIWadFlags(num) & GI_SHAREWARE)) // we do not want autoload sections for shareware IWADs (which may have an autoname for resource filtering)
218 {
219 FString workname = *pAuto;
220
221 while (workname.IsNotEmpty())
222 {
223 FString section = workname + ".Autoload";
224 CreateSectionAtStart(section.GetChars());
225 long dotpos = workname.LastIndexOf('.');
226 if (dotpos < 0) break;
227 workname.Truncate(dotpos);
228 }
229 }
230 }
231 CreateSectionAtStart("Global.Autoload");
232
233 // The same goes for auto-exec files.
234 CreateStandardAutoExec("Chex.AutoExec", true);
235 CreateStandardAutoExec("Strife.AutoExec", true);
236 CreateStandardAutoExec("Hexen.AutoExec", true);
237 CreateStandardAutoExec("Heretic.AutoExec", true);
238 CreateStandardAutoExec("Doom.AutoExec", true);
239
240 // Move search paths back to the top.
241 MoveSectionToStart("FileSearch.Directories");
242 MoveSectionToStart("IWADSearch.Directories");
243
244 SetSectionNote("Doom.AutoExec",
245 "# Files to automatically execute when running the corresponding game.\n"
246 "# Each file should be on its own line, preceded by Path=\n\n");
247 SetSectionNote("Global.Autoload",
248 "# WAD files to always load. These are loaded after the IWAD but before\n"
249 "# any files added with -file. Place each file on its own line, preceded\n"
250 "# by Path=\n");
251 SetSectionNote("Doom.Autoload",
252 "# Wad files to automatically load depending on the game and IWAD you are\n"
253 "# playing. You may have have files that are loaded for all similar IWADs\n"
254 "# (the game) and files that are only loaded for particular IWADs. For example,\n"
255 "# any files listed under 'doom.Autoload' will be loaded for any version of Doom,\n"
256 "# but files listed under 'doom.doom2.Autoload' will only load when you are\n"
257 "# playing a Doom 2 based game (doom2.wad, tnt.wad or plutonia.wad), and files listed under\n"
258 "# 'doom.doom2.commercial.Autoload' only when playing doom2.wad.\n\n");
259 }
260
DoGlobalSetup()261 void FGameConfigFile::DoGlobalSetup ()
262 {
263 if (SetSection ("GlobalSettings.Unknown"))
264 {
265 ReadCVars (CVAR_GLOBALCONFIG);
266 }
267 if (SetSection ("GlobalSettings"))
268 {
269 ReadCVars (CVAR_GLOBALCONFIG);
270 }
271 if (SetSection ("LastRun"))
272 {
273 const char *lastver = GetValueForKey ("Version");
274 if (lastver != NULL)
275 {
276 double last = atof (lastver);
277 if (last < 123.1)
278 {
279 FBaseCVar *noblitter = FindCVar ("vid_noblitter", NULL);
280 if (noblitter != NULL)
281 {
282 noblitter->ResetToDefault ();
283 }
284 }
285 if (last < 202)
286 {
287 // Make sure the Hexen hotkeys are accessible by default.
288 if (SetSection ("Hexen.Bindings"))
289 {
290 SetValueForKey ("\\", "use ArtiHealth");
291 SetValueForKey ("scroll", "+showscores");
292 SetValueForKey ("0", "useflechette");
293 SetValueForKey ("9", "use ArtiBlastRadius");
294 SetValueForKey ("8", "use ArtiTeleport");
295 SetValueForKey ("7", "use ArtiTeleportOther");
296 SetValueForKey ("6", "use ArtiPork");
297 SetValueForKey ("5", "use ArtiInvulnerability2");
298 }
299 }
300 if (last < 204)
301 { // The old default for vsync was true, but with an unlimited framerate
302 // now, false is a better default.
303 FBaseCVar *vsync = FindCVar ("vid_vsync", NULL);
304 if (vsync != NULL)
305 {
306 vsync->ResetToDefault ();
307 }
308 }
309 if (last < 206)
310 { // spc_amp is now a float, not an int.
311 if (spc_amp > 16)
312 {
313 spc_amp = spc_amp / 16.f;
314 }
315 }
316 if (last < 207)
317 { // Now that snd_midiprecache works again, you probably don't want it on.
318 FBaseCVar *precache = FindCVar ("snd_midiprecache", NULL);
319 if (precache != NULL)
320 {
321 precache->ResetToDefault();
322 }
323 }
324 if (last < 208)
325 { // Weapon sections are no longer used, so tidy up the config by deleting them.
326 const char *name;
327 size_t namelen;
328 bool more;
329
330 more = SetFirstSection();
331 while (more)
332 {
333 name = GetCurrentSection();
334 if (name != NULL &&
335 (namelen = strlen(name)) > 12 &&
336 strcmp(name + namelen - 12, ".WeaponSlots") == 0)
337 {
338 more = DeleteCurrentSection();
339 }
340 else
341 {
342 more = SetNextSection();
343 }
344 }
345 }
346 if (last < 209)
347 {
348 // menu dimming is now a gameinfo option so switch user override off
349 FBaseCVar *dim = FindCVar ("dimamount", NULL);
350 if (dim != NULL)
351 {
352 dim->ResetToDefault ();
353 }
354 }
355 if (last < 210)
356 {
357 if (SetSection ("Hexen.Bindings"))
358 {
359 // These 2 were misnamed in earlier versions
360 SetValueForKey ("6", "use ArtiPork");
361 SetValueForKey ("5", "use ArtiInvulnerability2");
362 }
363 }
364 }
365 }
366 }
367
DoGameSetup(const char * gamename)368 void FGameConfigFile::DoGameSetup (const char *gamename)
369 {
370 const char *key;
371 const char *value;
372
373 sublen = countof(section) - 1 - mysnprintf (section, countof(section), "%s.", gamename);
374 subsection = section + countof(section) - sublen - 1;
375 section[countof(section) - 1] = '\0';
376
377 strncpy (subsection, "UnknownConsoleVariables", sublen);
378 if (SetSection (section))
379 {
380 ReadCVars (0);
381 }
382
383 strncpy (subsection, "ConsoleVariables", sublen);
384 if (SetSection (section))
385 {
386 ReadCVars (0);
387 }
388
389 if (gameinfo.gametype & GAME_Raven)
390 {
391 SetRavenDefaults (gameinfo.gametype == GAME_Hexen);
392 }
393
394 // The NetServerInfo section will be read and override anything loaded
395 // here when it's determined that a netgame is being played.
396 strncpy (subsection, "LocalServerInfo", sublen);
397 if (SetSection (section))
398 {
399 ReadCVars (0);
400 }
401
402 strncpy (subsection, "Player", sublen);
403 if (SetSection (section))
404 {
405 ReadCVars (0);
406 }
407
408 strncpy (subsection, "ConsoleAliases", sublen);
409 if (SetSection (section))
410 {
411 const char *name = NULL;
412 while (NextInSection (key, value))
413 {
414 if (stricmp (key, "Name") == 0)
415 {
416 name = value;
417 }
418 else if (stricmp (key, "Command") == 0 && name != NULL)
419 {
420 C_SetAlias (name, value);
421 name = NULL;
422 }
423 }
424 }
425 OkayToWrite = true;
426 }
427
428 // Moved from DoGameSetup so that it can happen after wads are loaded
DoKeySetup(const char * gamename)429 void FGameConfigFile::DoKeySetup(const char *gamename)
430 {
431 static const struct { const char *label; FKeyBindings *bindings; } binders[] =
432 {
433 { "Bindings", &Bindings },
434 { "DoubleBindings", &DoubleBindings },
435 { "AutomapBindings", &AutomapBindings },
436 { NULL, NULL }
437 };
438 const char *key, *value;
439
440 sublen = countof(section) - 1 - mysnprintf(section, countof(section), "%s.", gamename);
441 subsection = section + countof(section) - sublen - 1;
442 section[countof(section) - 1] = '\0';
443
444 C_SetDefaultBindings ();
445
446 for (int i = 0; binders[i].label != NULL; ++i)
447 {
448 strncpy(subsection, binders[i].label, sublen);
449 if (SetSection(section))
450 {
451 FKeyBindings *bindings = binders[i].bindings;
452 bindings->UnbindAll();
453 while (NextInSection(key, value))
454 {
455 bindings->DoBind(key, value);
456 }
457 }
458 }
459 }
460
461 // Like DoGameSetup(), but for mod-specific cvars.
462 // Called after CVARINFO has been parsed.
DoModSetup(const char * gamename)463 void FGameConfigFile::DoModSetup(const char *gamename)
464 {
465 mysnprintf(section, countof(section), "%s.Player.Mod", gamename);
466 if (SetSection(section))
467 {
468 ReadCVars(CVAR_MOD|CVAR_USERINFO|CVAR_IGNORE);
469 }
470 mysnprintf(section, countof(section), "%s.LocalServerInfo.Mod", gamename);
471 if (SetSection (section))
472 {
473 ReadCVars (CVAR_MOD|CVAR_SERVERINFO|CVAR_IGNORE);
474 }
475 // Signal that these sections should be rewritten when saving the config.
476 bModSetup = true;
477 }
478
ReadNetVars()479 void FGameConfigFile::ReadNetVars ()
480 {
481 strncpy (subsection, "NetServerInfo", sublen);
482 if (SetSection (section))
483 {
484 ReadCVars (0);
485 }
486 if (bModSetup)
487 {
488 mysnprintf(subsection, sublen, "NetServerInfo.Mod");
489 if (SetSection(section))
490 {
491 ReadCVars(CVAR_MOD|CVAR_SERVERINFO|CVAR_IGNORE);
492 }
493 }
494 }
495
496 // Read cvars from a cvar section of the ini. Flags are the flags to give
497 // to newly-created cvars that were not already defined.
ReadCVars(DWORD flags)498 void FGameConfigFile::ReadCVars (DWORD flags)
499 {
500 const char *key, *value;
501 FBaseCVar *cvar;
502 UCVarValue val;
503
504 flags |= CVAR_ARCHIVE|CVAR_UNSETTABLE|CVAR_AUTO;
505 while (NextInSection (key, value))
506 {
507 cvar = FindCVar (key, NULL);
508 if (cvar == NULL)
509 {
510 cvar = new FStringCVar (key, NULL, flags);
511 }
512 val.String = const_cast<char *>(value);
513 cvar->SetGenericRep (val, CVAR_String);
514 }
515 }
516
ArchiveGameData(const char * gamename)517 void FGameConfigFile::ArchiveGameData (const char *gamename)
518 {
519 char section[32*3], *subsection;
520
521 sublen = countof(section) - 1 - mysnprintf (section, countof(section), "%s.", gamename);
522 subsection = section + countof(section) - 1 - sublen;
523
524 strncpy (subsection, "Player", sublen);
525 SetSection (section, true);
526 ClearCurrentSection ();
527 C_ArchiveCVars (this, CVAR_ARCHIVE|CVAR_USERINFO);
528
529 if (bModSetup)
530 {
531 strncpy (subsection + 6, ".Mod", sublen - 6);
532 SetSection (section, true);
533 ClearCurrentSection ();
534 C_ArchiveCVars (this, CVAR_MOD|CVAR_ARCHIVE|CVAR_AUTO|CVAR_USERINFO);
535 }
536
537 strncpy (subsection, "ConsoleVariables", sublen);
538 SetSection (section, true);
539 ClearCurrentSection ();
540 C_ArchiveCVars (this, CVAR_ARCHIVE);
541
542 // Do not overwrite the serverinfo section if playing a netgame, and
543 // this machine was not the initial host.
544 if (!netgame || consoleplayer == 0)
545 {
546 strncpy (subsection, netgame ? "NetServerInfo" : "LocalServerInfo", sublen);
547 SetSection (section, true);
548 ClearCurrentSection ();
549 C_ArchiveCVars (this, CVAR_ARCHIVE|CVAR_SERVERINFO);
550
551 if (bModSetup)
552 {
553 strncpy (subsection, netgame ? "NetServerInfo.Mod" : "LocalServerInfo.Mod", sublen);
554 SetSection (section, true);
555 ClearCurrentSection ();
556 C_ArchiveCVars (this, CVAR_MOD|CVAR_ARCHIVE|CVAR_AUTO|CVAR_SERVERINFO);
557 }
558 }
559
560 strncpy (subsection, "UnknownConsoleVariables", sublen);
561 SetSection (section, true);
562 ClearCurrentSection ();
563 C_ArchiveCVars (this, CVAR_ARCHIVE|CVAR_AUTO);
564
565 strncpy (subsection, "ConsoleAliases", sublen);
566 SetSection (section, true);
567 ClearCurrentSection ();
568 C_ArchiveAliases (this);
569
570 M_SaveCustomKeys (this, section, subsection, sublen);
571
572 strcpy (subsection, "Bindings");
573 SetSection (section, true);
574 Bindings.ArchiveBindings (this);
575
576 strncpy (subsection, "DoubleBindings", sublen);
577 SetSection (section, true);
578 DoubleBindings.ArchiveBindings (this);
579
580 strncpy (subsection, "AutomapBindings", sublen);
581 SetSection (section, true);
582 AutomapBindings.ArchiveBindings (this);
583 }
584
ArchiveGlobalData()585 void FGameConfigFile::ArchiveGlobalData ()
586 {
587 SetSection ("LastRun", true);
588 ClearCurrentSection ();
589 SetValueForKey ("Version", LASTRUNVERSION);
590
591 SetSection ("GlobalSettings", true);
592 ClearCurrentSection ();
593 C_ArchiveCVars (this, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
594
595 SetSection ("GlobalSettings.Unknown", true);
596 ClearCurrentSection ();
597 C_ArchiveCVars (this, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_AUTO);
598 }
599
GetConfigPath(bool tryProg)600 FString FGameConfigFile::GetConfigPath (bool tryProg)
601 {
602 const char *pathval;
603
604 pathval = Args->CheckValue ("-config");
605 if (pathval != NULL)
606 {
607 return FString(pathval);
608 }
609 return M_GetConfigPath(tryProg);
610 }
611
CreateStandardAutoExec(const char * section,bool start)612 void FGameConfigFile::CreateStandardAutoExec(const char *section, bool start)
613 {
614 if (!SetSection(section))
615 {
616 FString path = M_GetAutoexecPath();
617 SetSection (section, true);
618 SetValueForKey ("Path", path.GetChars());
619 }
620 if (start)
621 {
622 MoveSectionToStart(section);
623 }
624 }
625
AddAutoexec(DArgs * list,const char * game)626 void FGameConfigFile::AddAutoexec (DArgs *list, const char *game)
627 {
628 char section[64];
629 const char *key;
630 const char *value;
631
632 mysnprintf (section, countof(section), "%s.AutoExec", game);
633
634 // If <game>.AutoExec section does not exist, create it
635 // with a default autoexec.cfg file present.
636 CreateStandardAutoExec(section, false);
637 // Run any files listed in the <game>.AutoExec section
638 if (!SectionIsEmpty())
639 {
640 while (NextInSection (key, value))
641 {
642 if (stricmp (key, "Path") == 0 && *value != '\0')
643 {
644 FString expanded_path = ExpandEnvVars(value);
645 if (FileExists(expanded_path))
646 {
647 list->AppendArg (ExpandEnvVars(value));
648 }
649 }
650 }
651 }
652 }
653
SetRavenDefaults(bool isHexen)654 void FGameConfigFile::SetRavenDefaults (bool isHexen)
655 {
656 UCVarValue val;
657
658 val.Bool = false;
659 wi_percents.SetGenericRepDefault (val, CVAR_Bool);
660 val.Bool = true;
661 con_centernotify.SetGenericRepDefault (val, CVAR_Bool);
662 snd_pitched.SetGenericRepDefault (val, CVAR_Bool);
663 val.Int = 9;
664 msg0color.SetGenericRepDefault (val, CVAR_Int);
665 val.Int = CR_WHITE;
666 msgmidcolor.SetGenericRepDefault (val, CVAR_Int);
667 val.Int = CR_YELLOW;
668 msgmidcolor2.SetGenericRepDefault (val, CVAR_Int);
669
670 val.Int = 0x543b17;
671 am_wallcolor.SetGenericRepDefault (val, CVAR_Int);
672 val.Int = 0xd0b085;
673 am_fdwallcolor.SetGenericRepDefault (val, CVAR_Int);
674 val.Int = 0x734323;
675 am_cdwallcolor.SetGenericRepDefault (val, CVAR_Int);
676
677 // Fix the Heretic/Hexen automap colors so they are correct.
678 // (They were wrong on older versions.)
679 if (*am_wallcolor == 0x2c1808 && *am_fdwallcolor == 0x887058 && *am_cdwallcolor == 0x4c3820)
680 {
681 am_wallcolor.ResetToDefault ();
682 am_fdwallcolor.ResetToDefault ();
683 am_cdwallcolor.ResetToDefault ();
684 }
685
686 if (!isHexen)
687 {
688 val.Int = 0x3f6040;
689 color.SetGenericRepDefault (val, CVAR_Int);
690 }
691 }
692
CCMD(whereisini)693 CCMD (whereisini)
694 {
695 FString path = M_GetConfigPath(false);
696 Printf ("%s\n", path.GetChars());
697 }
698