From eded2ef345ed3d3c07c915b5ed176756bdc5daa1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 15 Oct 2010 15:13:53 +0000 Subject: [PATCH] - Each IWAD can now define its own config section. Hacx, Harmony and Action Doom2 now do that. - moved IWAD identification data into a lump in zdoom.pk3. - rewrote IWAD checking code SVN r2943 (trunk) --- src/d_iwad.cpp | 682 ++++++++++++++++--------------------- src/d_main.cpp | 16 +- src/d_main.h | 79 +++-- src/gameconfigfile.cpp | 17 +- src/gi.h | 3 +- src/keysections.cpp | 5 +- src/m_misc.cpp | 6 +- src/menu/menu.cpp | 2 +- src/p_udmf.cpp | 2 +- src/sdl/i_system.cpp | 6 +- src/sdl/i_system.h | 3 +- src/stringtable.cpp | 2 +- src/win32/i_main.cpp | 2 +- src/win32/i_system.cpp | 2 +- src/win32/i_system.h | 3 +- wadsrc/static/iwadinfo.txt | 319 +++++++++++++++++ 16 files changed, 683 insertions(+), 466 deletions(-) create mode 100644 wadsrc/static/iwadinfo.txt diff --git a/src/d_iwad.cpp b/src/d_iwad.cpp index 8900bc23f..93ea10837 100644 --- a/src/d_iwad.cpp +++ b/src/d_iwad.cpp @@ -43,6 +43,8 @@ #include "m_argv.h" #include "m_misc.h" #include "c_cvars.h" +#include "sc_man.h" +#include "v_video.h" #include "gameconfigfile.h" #include "resourcefiles/resourcefile.h" @@ -50,99 +52,224 @@ CVAR (Bool, queryiwad, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); CVAR (String, defaultiwad, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG); -EIWADType gameiwad; +//========================================================================== +// +// Clear check list +// +//========================================================================== -// If autoname is NULL, that's either because that game doesn't allow -// loading of external wads or because it's already caught by the -// general game-specific wads section. -const IWADInfo IWADInfos[NUM_IWAD_TYPES] = +void FIWadManager::ClearChecks() { - // banner text, autoname, fg color, bg color - { "Final Doom: TNT - Evilution", "TNT", MAKERGB(168,0,0), MAKERGB(168,168,168), GAME_Doom, "mapinfo/tnt.txt", GI_MAPxx | GI_COMPATSHORTTEX | GI_COMPATSTAIRS }, - { "Final Doom: Plutonia Experiment", "Plutonia", MAKERGB(168,0,0), MAKERGB(168,168,168), GAME_Doom, "mapinfo/plutonia.txt", GI_MAPxx | GI_COMPATSHORTTEX }, - { "Hexen: Beyond Heretic", NULL, MAKERGB(240,240,240), MAKERGB(107,44,24), GAME_Hexen, "mapinfo/hexen.txt", GI_MAPxx | GI_COMPATPOLY1 }, - { "Hexen: Deathkings of the Dark Citadel", "HexenDK", MAKERGB(240,240,240), MAKERGB(139,68,9), GAME_Hexen, "mapinfo/hexdd.txt", GI_MAPxx | GI_COMPATPOLY1 | GI_COMPATPOLY2 }, - { "Hexen: Demo Version", "HexenDemo",MAKERGB(240,240,240), MAKERGB(107,44,24), GAME_Hexen, "mapinfo/hexen.txt", GI_MAPxx | GI_SHAREWARE }, - { "DOOM 2: Hell on Earth", "Doom2", MAKERGB(168,0,0), MAKERGB(168,168,168), GAME_Doom, "mapinfo/doom2.txt", GI_MAPxx | GI_COMPATSHORTTEX }, - { "Heretic Shareware", NULL, MAKERGB(252,252,0), MAKERGB(168,0,0), GAME_Heretic, "mapinfo/hereticsw.txt",GI_SHAREWARE }, - { "Heretic: Shadow of the Serpent Riders", "Heretic1", MAKERGB(252,252,0), MAKERGB(168,0,0), GAME_Heretic, "mapinfo/heretic.txt", GI_MENUHACK_EXTENDED }, - { "Heretic", "Heretic1", MAKERGB(252,252,0), MAKERGB(168,0,0), GAME_Heretic, "mapinfo/heretic.txt" }, - { "DOOM Shareware", NULL, MAKERGB(168,0,0), MAKERGB(168,168,168), GAME_Doom, "mapinfo/doom1.txt", GI_SHAREWARE | GI_COMPATSHORTTEX }, - { "The Ultimate DOOM", "Doom1", MAKERGB(84,84,84), MAKERGB(168,168,168), GAME_Doom, "mapinfo/ultdoom.txt", GI_COMPATSHORTTEX }, - { "DOOM Registered", "Doom1", MAKERGB(84,84,84), MAKERGB(168,168,168), GAME_Doom, "mapinfo/doom1.txt", GI_COMPATSHORTTEX }, - { "Strife: Quest for the Sigil", NULL, MAKERGB(224,173,153), MAKERGB(0,107,101), GAME_Strife, "mapinfo/strife.txt", GI_MAPxx }, - { "Strife: Teaser (Old Version)", NULL, MAKERGB(224,173,153), MAKERGB(0,107,101), GAME_Strife, "mapinfo/strife.txt", GI_MAPxx | GI_SHAREWARE }, - { "Strife: Teaser (New Version)", NULL, MAKERGB(224,173,153), MAKERGB(0,107,101), GAME_Strife, "mapinfo/strife.txt", GI_MAPxx | GI_SHAREWARE | GI_TEASER2 }, - { "Freedoom", "Freedoom", MAKERGB(50,84,67), MAKERGB(198,220,209), GAME_Doom, "mapinfo/doom2.txt", GI_MAPxx }, - { "Ultimate Freedoom", "Freedoom1",MAKERGB(50,84,67), MAKERGB(198,220,209), GAME_Doom, "mapinfo/doom1.txt" }, - { "Freedoom \"Demo\"", NULL, MAKERGB(50,84,67), MAKERGB(198,220,209), GAME_Doom, "mapinfo/doom1.txt" }, - { "FreeDM", "FreeDM", MAKERGB(50,84,67), MAKERGB(198,220,209), GAME_Doom, "mapinfo/doom2.txt", GI_MAPxx }, - { "Blasphemer", "Blasphemer",MAKERGB(115,0,0), MAKERGB(0,0,0), GAME_Heretic, "mapinfo/heretic.txt" }, - { "Chex(R) Quest", "Chex1", MAKERGB(255,255,0), MAKERGB(0,192,0), GAME_Chex, "mapinfo/chex.txt" }, - { "Chex(R) Quest 3", "Chex3", MAKERGB(255,255,0), MAKERGB(0,192,0), GAME_Chex, "mapinfo/chex3.txt", GI_NOTEXTCOLOR }, - { "Action Doom 2: Urban Brawl", "UrbanBrawl",MAKERGB(168,168,0), MAKERGB(168,0,0), GAME_Doom, "mapinfo/urbanbrawl.txt", GI_MAPxx }, - { "Harmony", "Harmony", MAKERGB(110,180,230), MAKERGB(69,79,126), GAME_Doom, "mapinfo/doom2.txt", GI_MAPxx }, - { "Hacx: Twitch n' Kill", "Hacx", MAKERGB(168,0,0), MAKERGB(168,168,168), GAME_Doom, "mapinfo/doom2.txt", GI_MAPxx }, - //{ "ZDoom Engine", NULL, MAKERGB(168,0,0), MAKERGB(168,168,168) }, -}; + mLumpsFound.Resize(mIWads.Size()); + for(unsigned i=0;igametype = GAME_Doom; + else if (sc.Compare("Heretic")) iwad->gametype = GAME_Heretic; + else if (sc.Compare("Hexen")) iwad->gametype = GAME_Hexen; + else if (sc.Compare("Strife")) iwad->gametype = GAME_Strife; + else if (sc.Compare("Chex")) iwad->gametype = GAME_Chex; + else sc.ScriptError(NULL); + } + else if (sc.Compare("Mapinfo")) + { + sc.MustGetStringName("="); + sc.MustGetString(); + iwad->MapInfo = sc.String; + } + else if (sc.Compare("Compatibility")) + { + sc.MustGetStringName("="); + do + { + sc.MustGetString(); + if(sc.Compare("NoTextcolor")) iwad->flags |= GI_NOTEXTCOLOR; + else if(sc.Compare("Poly1")) iwad->flags |= GI_COMPATPOLY1; + else if(sc.Compare("Poly2")) iwad->flags |= GI_COMPATPOLY2; + else if(sc.Compare("Shareware")) iwad->flags |= GI_SHAREWARE; + else if(sc.Compare("Teaser2")) iwad->flags |= GI_TEASER2; + else if(sc.Compare("Extended")) iwad->flags |= GI_MENUHACK_EXTENDED; + else if(sc.Compare("Shorttex")) iwad->flags |= GI_COMPATSHORTTEX; + else if(sc.Compare("Stairs")) iwad->flags |= GI_COMPATSTAIRS; + else sc.ScriptError(NULL); + } + while (sc.CheckString(",")); + } + else if (sc.Compare("MustContain")) + { + sc.MustGetStringName("="); + do + { + sc.MustGetString(); + iwad->Lumps.Push(FString(sc.String)); + } + while (sc.CheckString(",")); + } + else if (sc.Compare("BannerColors")) + { + sc.MustGetStringName("="); + sc.MustGetString(); + iwad->FgColor = V_GetColor(NULL, sc.String); + sc.MustGetStringName(","); + sc.MustGetString(); + iwad->BkColor = V_GetColor(NULL, sc.String); + } + else if (sc.Compare("Load")) + { + sc.MustGetStringName("="); + do + { + sc.MustGetString(); + iwad->Load.Push(FString(sc.String)); + } + while (sc.CheckString(",")); + } + else if (sc.Compare("Required")) + { + sc.MustGetStringName("="); + sc.MustGetString(); + iwad->Required = sc.String; + } + else + { + sc.ScriptError("Unknown keyword '%s'", sc.String); + } + } + } + else if (sc.Compare("NAMES")) + { + sc.MustGetStringName("{"); + mIWadNames.Push(FString()); + while (!sc.CheckString("}")) + { + sc.MustGetString(); + FString wadname = sc.String; +#ifdef _WIN32 + mIWadNames.Push(wadname); +#else + // check for lowercase, uppercased first letter and full uppercase on Linux etc. + wadname.ToLower(); + mIWadNames.Push(wadname); + wadname[0] = toupper(wadname[0]); + mIWadNames.Push(wadname); + wadname.ToUpper(); + mIWadNames.Push(wadname); #endif - NULL -}; + } + } + } +} + +//========================================================================== +// +// Lool for IWAD definition lump +// +//========================================================================== + +void FIWadManager::ParseIWadInfos(const char *fn) +{ + FResourceFile *resfile = FResourceFile::OpenResourceFile(fn, NULL, true); + if (resfile != NULL) + { + DWORD cnt = resfile->LumpCount(); + for(int i=cnt-1; i>=0; i--) + { + FResourceLump *lmp = resfile->GetLump(i); + + if (lmp->Namespace == ns_global && !stricmp(lmp->Name, "IWADINFO")) + { + // Found one! + ParseIWadInfo(resfile->Filename, (const char*)lmp->CacheLump(), lmp->LumpSize); + break; + } + } + delete resfile; + } +} + //========================================================================== // @@ -151,279 +278,30 @@ static const char *IWADNames[] = // Scan the contents of an IWAD to determine which one it is //========================================================================== -static EIWADType ScanIWAD (const char *iwad) +int FIWadManager::ScanIWAD (const char *iwad) { - static const char checklumps[][8] = - { - "AD2LIB", - "E1M1", - "E4M2", - "MAP01", - "MAP40", - "MAP60", - "TITLE", - "REDTNT2", - "CAMO1", - { 'E','X','T','E','N','D','E','D'}, - "ENDSTRF", - "MAP33", - "INVCURS", - { 'F','R','E','E','D','O','O','M' }, - { 'B','L','A','S','P','H','E','M' }, - "W94_1", - { 'P','O','S','S','H','0','M','0' }, - "CYCLA1", - "FLMBA1", - "MAPINFO", - "0HAWK01", - "0CARA3", - "0NOSE1", - "HACX-R", - { 'G','A','M','E','I','N','F','O' }, - "E2M1","E2M2","E2M3","E2M4","E2M5","E2M6","E2M7","E2M8","E2M9", - "E3M1","E3M2","E3M3","E3M4","E3M5","E3M6","E3M7","E3M8","E3M9", - "DPHOOF","BFGGA0","HEADA1","CYBRA1", - { 'S','P','I','D','A','1','D','1' }, - - }; -#define NUM_CHECKLUMPS (countof(checklumps)) - enum - { - Check_ad2lib, - Check_e1m1, - Check_e4m1, - Check_map01, - Check_map40, - Check_map60, - Check_title, - Check_redtnt2, - Check_cam01, - Check_Extended, - Check_endstrf, - Check_map33, - Check_invcurs, - Check_FreeDoom, - Check_Blasphem, - Check_W94_1, - Check_POSSH0M0, - Check_Cycla1, - Check_Flmba1, - Check_Mapinfo, - Check_Hawk, - Check_Car, - Check_Nose, - Check_Hacx, - Check_Gameinfo, - Check_e2m1 - }; - bool lumpsfound[NUM_CHECKLUMPS]; - size_t i; - - memset (lumpsfound, 0, sizeof(lumpsfound)); FResourceFile *iwadfile = FResourceFile::OpenResourceFile(iwad, NULL, true); if (iwadfile != NULL) { + ClearChecks(); for(DWORD ii = 0; ii < iwadfile->LumpCount(); ii++) { FResourceLump *lump = iwadfile->GetLump(ii); - size_t j; - for (j = 0; j < NUM_CHECKLUMPS; j++) + CheckLumpName(lump->Name); + if (lump->FullName != NULL) { - if (!lumpsfound[j]) + if (strnicmp(lump->FullName, "maps/", 5) == 0) { - if (strnicmp (lump->Name, checklumps[j], 8) == 0) - { - lumpsfound[j] = true; - break; - } - // Check for maps inside zips, too. - else if (lump->FullName != NULL) - { - if (checklumps[j][0] == 'E' && checklumps[j][2] == 'M' && checklumps[j][4] == '\0') - { - if (strnicmp(lump->FullName, "maps/", 5) == 0 && - strnicmp(lump->FullName + 5, checklumps[j], 4) == 0 && - stricmp(lump->FullName + 9, ".wad") == 0) - { - lumpsfound[j] = true; - break; - } - } - else if (checklumps[j][0] == 'M' && checklumps[j][1] == 'A' && checklumps[j][2] == 'P' && - checklumps[j][5] == '\0') - { - if (strnicmp(lump->FullName, "maps/", 5) == 0 && - strnicmp(lump->FullName + 5, checklumps[j], 5) == 0 && - stricmp(lump->FullName + 10, ".wad") == 0) - { - lumpsfound[j] = true; - break; - } - } - } + FString mapname(lump->FullName+5, strcspn(lump->FullName+5, ".")); + CheckLumpName(mapname); } } } delete iwadfile; } - - // Always check for custom iwads first. -#if 0 - if (lumpsfound[Check_Gameinfo]) - { - return IWAD_Custom; - } -#endif - if (lumpsfound[Check_title] && lumpsfound[Check_map60]) - { - return IWAD_HexenDK; - } - else if (lumpsfound[Check_map33] && lumpsfound[Check_endstrf]) - { - if (lumpsfound[Check_map01]) - { - return IWAD_Strife; - } - else if (lumpsfound[Check_invcurs]) - { - return IWAD_StrifeTeaser2; // Strife0.wad from 14 Mar 1996 - } - else - { - return IWAD_StrifeTeaser; // Strife0.wad from 22 Feb 1996 - } - } - else if (lumpsfound[Check_map01]) - { - if (lumpsfound[Check_ad2lib]) - { - return IWAD_ActionDoom2; - } - else if (lumpsfound[Check_Hawk] && lumpsfound[Check_Car] && lumpsfound[Check_Nose]) - { - return IWAD_Harmony; - } - else if (lumpsfound[Check_Hacx]) - { - return IWAD_Hacx; - } - else if (lumpsfound[Check_FreeDoom]) - { - // Is there a 100% reliable way to tell FreeDoom and FreeDM - // apart based solely on the lump names? - if (strstr(iwad, "freedm.wad") || strstr(iwad, "FREEDM.WAD")) - { - return IWAD_FreeDM; - } - else - { - return IWAD_FreeDoom; - } - } - else if (lumpsfound[Check_redtnt2]) - { - return IWAD_Doom2TNT; - } - else if (lumpsfound[Check_cam01]) - { - return IWAD_Doom2Plutonia; - } - else - { - if (lumpsfound[Check_title]) - { - if (lumpsfound[Check_map40]) - { - return IWAD_Hexen; - } - else - { - return IWAD_HexenDemo; - } - } - else - { - return IWAD_Doom2; - } - } - } - else if (lumpsfound[Check_e1m1]) - { - if (lumpsfound[Check_title]) - { - if (!lumpsfound[Check_e2m1]) - { - return IWAD_HereticShareware; - } - else - { - if (lumpsfound[Check_Blasphem]) - { - return IWAD_Blasphemer; - } - else if (lumpsfound[Check_Extended]) - { - return IWAD_HereticExtended; - } - else - { - return IWAD_Heretic; - } - } - } - else if (lumpsfound[Check_Cycla1] && lumpsfound[Check_Flmba1]) - { - if (!lumpsfound[Check_Mapinfo]) - { - // The original release won't work without its hacked custom EXE. - //I_FatalError("Found an incompatible version of Chex Quest 3"); - return NUM_IWAD_TYPES; // Can't use it. - } - return IWAD_ChexQuest3; - } - else - { - if (lumpsfound[Check_FreeDoom]) - { - if (!lumpsfound[Check_e2m1]) - { - return IWAD_FreeDoom1; - } - else - { - return IWAD_FreeDoomU; - } - } - for (i = Check_e2m1; i < NUM_CHECKLUMPS; i++) - { - if (!lumpsfound[i]) - { - return IWAD_DoomShareware; - } - } - if (i == NUM_CHECKLUMPS) - { - if (lumpsfound[Check_e4m1]) - { - if (lumpsfound[Check_W94_1] && lumpsfound[Check_POSSH0M0]) - { - return IWAD_ChexQuest; - } - else - { - return IWAD_UltimateDoom; - } - } - else - { - return IWAD_DoomRegistered; - } - } - } - } - return NUM_IWAD_TYPES; // Don't know + return GetIWadInfo(); } //========================================================================== @@ -437,10 +315,9 @@ static EIWADType ScanIWAD (const char *iwad) // //========================================================================== -static int CheckIWAD (const char *doomwaddir, WadStuff *wads) +int FIWadManager::CheckIWAD (const char *doomwaddir, WadStuff *wads) { const char *slash; - int i; int numfound; numfound = 0; @@ -448,20 +325,21 @@ static int CheckIWAD (const char *doomwaddir, WadStuff *wads) slash = (doomwaddir[0] && doomwaddir[strlen (doomwaddir)-1] != '/') ? "/" : ""; // Search for a pre-defined IWAD - for (i = IWADNames[0] ? 0 : 1; IWADNames[i]; i++) + for (unsigned i=0; i< mIWadNames.Size(); i++) { - if (wads[i].Path.IsEmpty()) + if (mIWadNames[i].IsNotEmpty() && wads[i].Path.IsEmpty()) { FString iwad; - iwad.Format ("%s%s%s", doomwaddir, slash, IWADNames[i]); + iwad.Format ("%s%s%s", doomwaddir, slash, mIWadNames[i]); FixPathSeperator (iwad); if (FileExists (iwad)) { wads[i].Type = ScanIWAD (iwad); - if (wads[i].Type != NUM_IWAD_TYPES) + if (wads[i].Type != -1) { wads[i].Path = iwad; + wads[i].Name = mIWads[wads[i].Type].Name; numfound++; } } @@ -492,10 +370,10 @@ static int CheckIWAD (const char *doomwaddir, WadStuff *wads) // //========================================================================== -static EIWADType IdentifyVersion (TArray &wadfiles, const char *iwad, const char *zdoom_wad) +int FIWadManager::IdentifyVersion (TArray &wadfiles, const char *iwad, const char *zdoom_wad) { - WadStuff wads[countof(IWADNames)]; - size_t foundwads[NUM_IWAD_TYPES] = { 0 }; + TArray wads; + TArray foundwads; const char *iwadparm = Args->CheckValue ("-iwad"); size_t numwads; int pickwad; @@ -503,6 +381,11 @@ static EIWADType IdentifyVersion (TArray &wadfiles, const char *iwad, c bool iwadparmfound = false; FString custwad; + ParseIWadInfos(zdoom_wad); + wads.Resize(mIWadNames.Size()); + foundwads.Resize(mIWads.Size()); + memset(&foundwads[0], 0, foundwads.Size() * sizeof(foundwads[0])); + if (iwadparm == NULL && iwad != NULL && *iwad != 0) { iwadparm = iwad; @@ -512,7 +395,7 @@ static EIWADType IdentifyVersion (TArray &wadfiles, const char *iwad, c { custwad = iwadparm; FixPathSeperator (custwad); - if (CheckIWAD (custwad, wads)) + if (CheckIWAD (custwad, &wads[0])) { // -iwad parameter was a directory iwadparm = NULL; } @@ -520,8 +403,8 @@ static EIWADType IdentifyVersion (TArray &wadfiles, const char *iwad, c { DefaultExtension (custwad, ".wad"); iwadparm = custwad; - IWADNames[0] = iwadparm; - CheckIWAD ("", wads); + mIWadNames[0] = custwad; + CheckIWAD ("", &wads[0]); } } @@ -538,7 +421,7 @@ static EIWADType IdentifyVersion (TArray &wadfiles, const char *iwad, c { FString nice = NicePath(value); FixPathSeperator(nice); - CheckIWAD(nice, wads); + CheckIWAD(nice, &wads[0]); } } } @@ -558,7 +441,7 @@ static EIWADType IdentifyVersion (TArray &wadfiles, const char *iwad, c steam_path += "/SteamApps/common/"; for (i = 0; i < countof(steam_dirs); ++i) { - CheckIWAD (steam_path + steam_dirs[i], wads); + CheckIWAD (steam_path + steam_dirs[i], &wads[0]); } } #endif @@ -569,7 +452,7 @@ static EIWADType IdentifyVersion (TArray &wadfiles, const char *iwad, c iwadparmfound = true; } - for (i = numwads = 0; i < countof(IWADNames); i++) + for (i = numwads = 0; i < mIWadNames.Size(); i++) { if (!wads[i].Path.IsEmpty()) { @@ -582,20 +465,42 @@ static EIWADType IdentifyVersion (TArray &wadfiles, const char *iwad, c } } - if (foundwads[IWAD_HexenDK] && !foundwads[IWAD_Hexen]) - { // Cannot play Hexen DK without Hexen - size_t kill = foundwads[IWAD_HexenDK]; - for (i = kill; i < numwads; ++i) + for (unsigned i=0; i kill) + bool found = false; + // needs to be loaded with another IWAD (HexenDK) + for (unsigned j=0; j kill) + { + foundwads[j]--; + } + } + } } } @@ -629,7 +534,7 @@ static EIWADType IdentifyVersion (TArray &wadfiles, const char *iwad, c } } } - pickwad = I_PickIWad (wads, (int)numwads, queryiwad, defiwad); + pickwad = I_PickIWad (&wads[0], (int)numwads, queryiwad, defiwad); if (pickwad >= 0) { // The newly selected IWAD becomes the new default @@ -644,15 +549,14 @@ static EIWADType IdentifyVersion (TArray &wadfiles, const char *iwad, c // zdoom.pk3 must always be the first file loaded and the IWAD second. D_AddFile (wadfiles, zdoom_wad); - if (wads[pickwad].Type == IWAD_HexenDK) - { // load hexen.wad before loading hexdd.wad - D_AddFile (wadfiles, wads[foundwads[IWAD_Hexen]-1].Path); + if (mIWads[wads[pickwad].Type].preload >= 0) + { + D_AddFile (wadfiles, wads[foundwads[mIWads[wads[pickwad].Type].preload]-1].Path); } - D_AddFile (wadfiles, wads[pickwad].Path); - if (wads[pickwad].Type == IWAD_Strife) - { // Try to load voices.wad along with strife1.wad + for (unsigned i=0; i < mIWads[wads[pickwad].Type].Load.Size(); i++) + { long lastslash = wads[pickwad].Path.LastIndexOf ('/'); FString path; @@ -664,25 +568,31 @@ static EIWADType IdentifyVersion (TArray &wadfiles, const char *iwad, c { path = FString (wads[pickwad].Path.GetChars(), lastslash + 1); } - path += "voices.wad"; + path += mIWads[wads[pickwad].Type].Load[i]; D_AddFile (wadfiles, path); - } + } return wads[pickwad].Type; } -const IWADInfo *D_FindIWAD(TArray &wadfiles, const char *iwad, const char *basewad) +//========================================================================== +// +// Find an IWAD to use for this game +// +//========================================================================== + +const FIWADInfo *FIWadManager::FindIWAD(TArray &wadfiles, const char *iwad, const char *basewad) { - EIWADType iwadType = IdentifyVersion(wadfiles, iwad, basewad); - gameiwad = iwadType; - const IWADInfo *iwad_info = &IWADInfos[iwadType]; + int iwadType = IdentifyVersion(wadfiles, iwad, basewad); + //gameiwad = iwadType; + const FIWADInfo *iwad_info = &mIWads[iwadType]; if (DoomStartupInfo.Name.IsEmpty()) DoomStartupInfo.Name = iwad_info->Name; if (DoomStartupInfo.BkColor == 0 && DoomStartupInfo.FgColor == 0) { DoomStartupInfo.BkColor = iwad_info->BkColor; DoomStartupInfo.FgColor = iwad_info->FgColor; } - I_SetIWADInfo(iwad_info); + I_SetIWADInfo(); return iwad_info; } \ No newline at end of file diff --git a/src/d_main.cpp b/src/d_main.cpp index 9c4c6b13b..6138c1607 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -122,7 +122,7 @@ extern void M_SetDefaultMode (); extern void R_ExecuteSetViewSize (); extern void G_NewInit (); extern void SetupPlayerClasses (); -const IWADInfo *D_FindIWAD(TArray &wadfiles, const char *iwad, const char *basewad); +const FIWADInfo *D_FindIWAD(TArray &wadfiles, const char *iwad, const char *basewad); // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- @@ -1873,11 +1873,13 @@ void D_DoomMain (void) GetCmdLineFiles(pwads); FString iwad = CheckGameInfo(pwads); - const IWADInfo *iwad_info = D_FindIWAD(allwads, iwad, basewad); + FIWadManager *iwad_man = new FIWadManager; + const FIWADInfo *iwad_info = iwad_man->FindIWAD(allwads, iwad, basewad); gameinfo.gametype = iwad_info->gametype; gameinfo.flags = iwad_info->flags; + gameinfo.ConfigName = iwad_info->Configname; - GameConfig->DoGameSetup (GameName()); + GameConfig->DoGameSetup (gameinfo.ConfigName); if (!(gameinfo.flags & GI_SHAREWARE) && !Args->CheckParm("-noautoload")) { @@ -1910,7 +1912,7 @@ void D_DoomMain (void) D_AddConfigWads (allwads, "Global.Autoload"); // Add game-specific wads - file = GameName(); + file = gameinfo.ConfigName; file += ".Autoload"; D_AddConfigWads (allwads, file); @@ -1925,7 +1927,7 @@ void D_DoomMain (void) // Run automatically executed files execFiles = new DArgs; - GameConfig->AddAutoexec (execFiles, GameName()); + GameConfig->AddAutoexec (execFiles, gameinfo.ConfigName); D_MultiExec (execFiles, true); // Run .cfg files at the start of the command line. @@ -2145,7 +2147,7 @@ void D_DoomMain (void) StartScreen->Progress (); - Printf ("R_Init: Init %s refresh subsystem.\n", GameName()); + Printf ("R_Init: Init %s refresh subsystem.\n", gameinfo.ConfigName.GetChars()); StartScreen->LoadingStatus ("Loading graphics", 0x3f); R_Init (); @@ -2223,6 +2225,8 @@ void D_DoomMain (void) // about to begin the game. FBaseCVar::EnableNoSet (); + delete iwad_man; // now we won't need this anymore + // [RH] Run any saved commands from the command line or autoexec.cfg now. gamestate = GS_FULLCONSOLE; Net_NewMakeTic (); diff --git a/src/d_main.h b/src/d_main.h index eb49840f1..415a6b943 100644 --- a/src/d_main.h +++ b/src/d_main.h @@ -56,55 +56,31 @@ bool D_AddFile (TArray &wadfiles, const char *file, bool check = true, extern const char *D_DrawIcon; -enum EIWADType -{ - IWAD_Doom2TNT, - IWAD_Doom2Plutonia, - IWAD_Hexen, - IWAD_HexenDK, - IWAD_HexenDemo, - IWAD_Doom2, - IWAD_HereticShareware, - IWAD_HereticExtended, - IWAD_Heretic, - IWAD_DoomShareware, - IWAD_UltimateDoom, - IWAD_DoomRegistered, - IWAD_Strife, - IWAD_StrifeTeaser, - IWAD_StrifeTeaser2, - IWAD_FreeDoom, - IWAD_FreeDoomU, - IWAD_FreeDoom1, - IWAD_FreeDM, - IWAD_Blasphemer, - IWAD_ChexQuest, - IWAD_ChexQuest3, - IWAD_ActionDoom2, - IWAD_Harmony, - IWAD_Hacx, - IWAD_Custom, - - NUM_IWAD_TYPES -}; - struct WadStuff { - WadStuff() : Type(IWAD_Doom2TNT) {} + WadStuff() : Type(0) {} FString Path; - EIWADType Type; + FString Name; + int Type; }; -struct IWADInfo +struct FIWADInfo { - const char *Name; // Title banner text for this IWAD - const char *Autoname; // Name of autoload ini section for this IWAD + FString Name; // Title banner text for this IWAD + FString Autoname; // Name of autoload ini section for this IWAD + FString Configname; // Name of config section for this IWAD + FString Required; // Requires another IWAD DWORD FgColor; // Foreground color for title banner DWORD BkColor; // Background color for title banner EGameType gametype; // which game are we playing? - const char *MapInfo; // Base mapinfo to load + FString MapInfo; // Base mapinfo to load + TArray Load; // Wads to be loaded with this one. + TArray Lumps; // Lump names for identification int flags; + int preload; + + FIWADInfo() { flags = 0; preload = -1; FgColor = 0; BkColor= 0xc0c0c0; gametype = GAME_Doom; } }; struct FStartupInfo @@ -116,7 +92,30 @@ struct FStartupInfo extern FStartupInfo DoomStartupInfo; -extern const IWADInfo IWADInfos[NUM_IWAD_TYPES]; -extern EIWADType gameiwad; +//========================================================================== +// +// IWAD identifier class +// +//========================================================================== + +struct FIWadManager +{ +private: + TArray mIWads; + TArray mIWadNames; + TArray mLumpsFound; + + void ParseIWadInfo(const char *fn, const char *data, int datasize); + void ParseIWadInfos(const char *fn); + void ClearChecks(); + void CheckLumpName(const char *name); + int GetIWadInfo(); + int ScanIWAD (const char *iwad); + int CheckIWAD (const char *doomwaddir, WadStuff *wads); + int IdentifyVersion (TArray &wadfiles, const char *iwad, const char *zdoom_wad); +public: + const FIWADInfo *FindIWAD(TArray &wadfiles, const char *iwad, const char *basewad); +}; + #endif diff --git a/src/gameconfigfile.cpp b/src/gameconfigfile.cpp index 64ddaa4b8..53b30e02a 100644 --- a/src/gameconfigfile.cpp +++ b/src/gameconfigfile.cpp @@ -62,6 +62,7 @@ extern HWND Window; #include "a_pickups.h" #include "doomstat.h" #include "i_system.h" +#include "gi.h" EXTERN_CVAR (Bool, con_centernotify) EXTERN_CVAR (Int, msg0color) @@ -347,18 +348,6 @@ void FGameConfigFile::DoGameSetup (const char *gamename) { const char *key; const char *value; - enum { Doom, Heretic, Hexen, Strife, Chex } game; - - if (strcmp (gamename, "Heretic") == 0) - game = Heretic; - else if (strcmp (gamename, "Hexen") == 0) - game = Hexen; - else if (strcmp (gamename, "Strife") == 0) - game = Strife; - else if (strcmp (gamename, "Chex") == 0) - game = Chex; - else - game = Doom; if (bMigrating) { @@ -380,9 +369,9 @@ void FGameConfigFile::DoGameSetup (const char *gamename) ReadCVars (0); } - if (game == Heretic || game == Hexen) + if (gameinfo.gametype & GAME_Raven) { - SetRavenDefaults (game == Hexen); + SetRavenDefaults (gameinfo.gametype == GAME_Hexen); } // The NetServerInfo section will be read when it's determined that diff --git a/src/gi.h b/src/gi.h index b65926881..7559a2c4b 100644 --- a/src/gi.h +++ b/src/gi.h @@ -70,6 +70,7 @@ struct gameinfo_t { int flags; EGameType gametype; + FString ConfigName; char titlePage[9]; bool drawreadthis; @@ -135,7 +136,7 @@ struct gameinfo_t extern gameinfo_t gameinfo; -inline const char *GameName() +inline const char *GameTypeName() { return GameNames[gameinfo.gametype]; } diff --git a/src/keysections.cpp b/src/keysections.cpp index 5f8f12ea7..60afce21b 100644 --- a/src/keysections.cpp +++ b/src/keysections.cpp @@ -48,10 +48,7 @@ static void LoadKeys (const char *modname, bool dbl) { char section[64]; - if (GameName() == NULL) - return; - - mysnprintf (section, countof(section), "%s.%s%sBindings", GameName(), modname, + mysnprintf (section, countof(section), "%s.%s%sBindings", gameinfo.ConfigName, modname, dbl ? ".Double" : "."); FKeyBindings *bindings = dbl? &DoubleBindings : &Bindings; diff --git a/src/m_misc.cpp b/src/m_misc.cpp index 3762691b1..924f45e7c 100644 --- a/src/m_misc.cpp +++ b/src/m_misc.cpp @@ -375,9 +375,9 @@ bool M_SaveDefaults (const char *filename) GameConfig->ChangePathName (filename); } GameConfig->ArchiveGlobalData (); - if (GameName() != NULL) + if (gameinfo.ConfigName.IsNotEmpty()) { - GameConfig->ArchiveGameData (GameName()); + GameConfig->ArchiveGameData (gameinfo.ConfigName); } success = GameConfig->WriteConfigFile (); if (filename != NULL) @@ -619,7 +619,7 @@ static bool FindFreeName (FString &fullname, const char *extension) for (i = 0; i <= 9999; i++) { - const char *gamename = GameName(); + const char *gamename = gameinfo.ConfigName; time_t now; tm *tm; diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index 1d6184437..b4e64b6a9 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -960,6 +960,6 @@ CCMD(reset2defaults) CCMD(reset2saved) { GameConfig->DoGlobalSetup (); - GameConfig->DoGameSetup (GameName()); + GameConfig->DoGameSetup (gameinfo.ConfigName); R_SetViewSize (screenblocks); } diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 263022501..8ae9403b2 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -1449,7 +1449,7 @@ public: floordrop = true; break; default: - Printf("Unknown namespace %s. Using defaults for %s\n", sc.String, GameName()); + Printf("Unknown namespace %s. Using defaults for %s\n", sc.String, GameTypeName()); switch (gameinfo.gametype) { default: // Shh, GCC diff --git a/src/sdl/i_system.cpp b/src/sdl/i_system.cpp index ff15b1e88..1a681fd65 100644 --- a/src/sdl/i_system.cpp +++ b/src/sdl/i_system.cpp @@ -414,7 +414,7 @@ void STACK_ARGS I_Error (const char *error, ...) throw CRecoverableError (errortext); } -void I_SetIWADInfo (const IWADInfo *info) +void I_SetIWADInfo () { } @@ -511,7 +511,7 @@ int I_PickIWad_Gtk (WadStuff *wads, int numwads, bool showwin, int defaultiwad) gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, 0, filepart, - 1, IWADInfos[wads[i].Type].Name, + 1, wads[i].Name, 2, i, -1); if (i == defaultiwad) @@ -625,7 +625,7 @@ int I_PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad) filepart = wads[i].Path; else filepart++; - printf ("%d. %s (%s)\n", i+1, IWADInfos[wads[i].Type].Name, filepart); + printf ("%d. %s (%s)\n", i+1, wads[i].Name, filepart); } printf ("Which one? "); scanf ("%d", &i); diff --git a/src/sdl/i_system.h b/src/sdl/i_system.h index acdae0167..a3341f4c5 100644 --- a/src/sdl/i_system.h +++ b/src/sdl/i_system.h @@ -115,8 +115,7 @@ void popterm (); void I_PrintStr (const char *str); // Set the title string of the startup window -struct IWADInfo; -void I_SetIWADInfo (const IWADInfo *info); +void I_SetIWADInfo (); // Pick from multiple IWADs to use int I_PickIWad (WadStuff *wads, int numwads, bool queryiwad, int defaultiwad); diff --git a/src/stringtable.cpp b/src/stringtable.cpp index 1746a29d8..5453cead8 100644 --- a/src/stringtable.cpp +++ b/src/stringtable.cpp @@ -231,7 +231,7 @@ void FStringTable::LoadLanguage (int lumpnum, DWORD code, bool exactMatch, int p sc.MustGetStringName("ifgame"); sc.MustGetStringName("("); sc.MustGetString(); - skip |= !sc.Compare(GameName()); + skip |= !sc.Compare(GameTypeName()); sc.MustGetStringName(")"); sc.MustGetString(); diff --git a/src/win32/i_main.cpp b/src/win32/i_main.cpp index 782f9fa5f..87c50da99 100644 --- a/src/win32/i_main.cpp +++ b/src/win32/i_main.cpp @@ -406,7 +406,7 @@ void LayoutMainWindow (HWND hWnd, HWND pane) // //========================================================================== -void I_SetIWADInfo(const IWADInfo *info) +void I_SetIWADInfo() { // Make the startup banner show itself LayoutMainWindow(Window, NULL); diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index 095ef1ee5..b585be71a 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -1107,7 +1107,7 @@ BOOL CALLBACK IWADBoxCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lPa filepart = WadList[i].Path; else filepart++; - work.Format("%s (%s)", IWADInfos[WadList[i].Type].Name, filepart); + work.Format("%s (%s)", WadList[i].Name, filepart); SendMessage(ctrl, LB_ADDSTRING, 0, (LPARAM)work.GetChars()); SendMessage(ctrl, LB_SETITEMDATA, i, (LPARAM)i); } diff --git a/src/win32/i_system.h b/src/win32/i_system.h index d7af1b4b1..6bafdc01c 100644 --- a/src/win32/i_system.h +++ b/src/win32/i_system.h @@ -125,8 +125,7 @@ void I_PaintConsole (void); void I_PrintStr (const char *cp); // Set the title string of the startup window -struct IWADInfo; -void I_SetIWADInfo (const IWADInfo *title); +void I_SetIWADInfo (); // Pick from multiple IWADs to use int I_PickIWad (WadStuff *wads, int numwads, bool queryiwad, int defaultiwad); diff --git a/wadsrc/static/iwadinfo.txt b/wadsrc/static/iwadinfo.txt new file mode 100644 index 000000000..0ee148b17 --- /dev/null +++ b/wadsrc/static/iwadinfo.txt @@ -0,0 +1,319 @@ +// Must be sorted in identification order (easiest to recognize first!) + +IWad +{ + Name = "Harmony" + Game = "Doom" + Config = "Harmony" + Mapinfo = "mapinfo/doom2.txt" + MustContain = "MAP01", "0HAWK01", "0CARA3", "0NOSE1" + BannerColors = "6e b4 d6", "45 4f 7e" +} + +IWad +{ + Name = "Hacx: Twitch'n Kill" + Game = "Doom" + Config = "Hacx" + Mapinfo = "mapinfo/doom2.txt" + MustContain = "MAP01", "HACX-R" + BannerColors = "00 00 a8", "a8 a8 a8" +} + +IWad +{ + Name = "Action Doom 2: Urban Brawl" + Game = "Doom" + Config = "UrbanBrawl" + Mapinfo = "mapinfo/doom2.txt" + MustContain = "MAP01", "AD2LIB" + BannerColors = "a8 a8 00", "a8 00 00" +} + +IWad +{ + Name = "Chex(R) Quest 3" + Autoname = "Chex3" + Game = "Chex" + Config = "Chex" + Mapinfo = "mapinfo/chex.txt" + Compatibility = "NoTextcolor" + MustContain = "E1M1", "CYCLA1", "FLMBA1", "MAPINFO" + BannerColors = "ff ff 00", "00 c0 00" +} + +IWad +{ + Name = "Chex(R) Quest" + Autoname = "Chex1" + Game = "Chex" + Config = "Chex" + Mapinfo = "mapinfo/chex.txt" + MustContain = "E1M1", "E4M1", "W94_1", "POSSH0M0" + BannerColors = "ff ff 00", "00 c0 00" +} + +IWad +{ + Name = "Strife: Quest for the Sigil" + Game = "Strife" + Config = "Strife" + Mapinfo = "mapinfo/strife.txt" + MustContain = "MAP01", "MAP33", "ENDSTRF" + BannerColors = "d0 ad 99", "00 6b 65" + Load = "voices.wad" +} + +IWad +{ + Name = "Strife: Teaser (New Version)" + Game = "Strife" + Config = "Strife" + Mapinfo = "mapinfo/strife.txt" + Compatibility = "Shareware", "Teaser2" + MustContain = "MAP33", "ENDSTRF", "INVCURS" + BannerColors = "d0 ad 99", "00 6b 65" +} + +IWad +{ + Name = "Strife: Teaser (Old Version)" + Game = "Strife" + Config = "Strife" + Mapinfo = "mapinfo/strife.txt" + Compatibility = "Shareware" + MustContain = "MAP33", "ENDSTRF" + BannerColors = "d0 ad 99", "00 6b 65" +} + +IWad +{ + Name = "Hexen: Beyond Heretic" + Game = "Hexen" + Config = "Hexen" + Mapinfo = "mapinfo/doom2.txt" + Compatibility = "Poly1" + MustContain = "TITLE", "MAP01", "MAP40", "WINNOWR" + BannerColors = "f0 f0 f0", "6b 3c 18" +} + +IWad +{ + Name = "Hexen: Deathkings of the Dark Citadel" + Autoname = "HexenDK" + Game = "Hexen" + Config = "Hexen" + Mapinfo = "mapinfo/hexen.txt" + Compatibility = "Poly1", "Poly2" + MustContain = "TITLE", "MAP60", "CLUS1MSG" + BannerColors = "f0 f0 f0", "6b 3c 18" + Required = "Hexen: Beyond Heretic" +} + +IWad +{ + Name = "Hexen: Demo Version" + Game = "Hexen" + Config = "Hexen" + Mapinfo = "mapinfo/doom2.txt" + Compatibility = "Shareware" + MustContain = "TITLE", "MAP01", "WINNOWR" + BannerColors = "f0 f0 f0", "6b 3c 18" +} + +IWad +{ + Name = "Blasphemer" + Autoname = "Blasphemer" + Game = "Heretic" + Config = "Heretic" + Mapinfo = "mapinfo/heretic.txt" + MustContain = "E1M1", "E2M1", "TITLE", "BLASPHEM" + BannerColors = "73 00 00", "00 00 00" +} + +IWad +{ + Name = "Heretic: Shadow of the Serpent Riders" + Autoname = "Heretic1" + Game = "Heretic" + Config = "Heretic" + Mapinfo = "mapinfo/heretic.txt" + Compatibility = "Extended" + MustContain = "E1M1", "E2M1", "TITLE", "MUS_E1M1", "EXTENDED" + BannerColors = "fc fc 00", "a8 00 00" +} + +IWad +{ + Name = "Heretic" + Autoname = "Heretic1" + Game = "Heretic" + Config = "Heretic" + Mapinfo = "mapinfo/heretic.txt" + MustContain = "E1M1", "E2M1", "TITLE", "MUS_E1M1" + BannerColors = "fc fc 00", "a8 00 00" +} + +IWad +{ + Name = "Heretic Shareware" + Game = "Heretic" + Config = "Heretic" + Mapinfo = "mapinfo/hereticsw.txt" + Compatibility = "Shareware" + MustContain = "E1M1", "TITLE", "MUS_E1M1" + BannerColors = "fc fc 00", "a8 00 00" +} + +IWad +{ + Name = "FreeDM" + Autoname = "FreeDM" + Game = "Doom" + Config = "Doom" + Mapinfo = "mapinfo/doom2.txt" + MustContain = "MAP01", "FREEDM" + BannerColors = "32 54 43", "c6 dc d1" +} + +IWad +{ + Name = "Freedoom" + Autoname = "Freedoom" + Game = "Doom" + Config = "Doom" + Mapinfo = "mapinfo/doom2.txt" + MustContain = "MAP01", "FREEDOOM" + BannerColors = "32 54 43", "c6 dc d1" +} + +IWad +{ + Name = "Ultimate Freedoom" + Autoname = "Freedoom1" + Game = "Doom" + Config = "Doom" + Mapinfo = "mapinfo/doom1.txt" + MustContain = "E1M1", "E2M1", "E3M1", "FREEDOOM" + BannerColors = "32 54 43", "c6 dc d1" +} + +IWad +{ + Name = "Freedoom 'Demo'" + Autoname = "Freedoom1" + Game = "Doom" + Config = "Doom" + Mapinfo = "mapinfo/doom2.txt" + MustContain = "E1M1", "FREEDOOM" + BannerColors = "32 54 43", "c6 dc d1" +} + +IWad +{ + Name = "The Ultimate DOOM" + Autoname = "Doom1" + Game = "Doom" + Config = "Doom" + Mapinfo = "mapinfo/doom1.txt" + Compatibility = "Shorttex" + MustContain = "E1M1","E2M1","E2M2","E2M3","E2M4","E2M5","E2M6","E2M7","E2M8","E2M9", + "E3M1","E3M2","E3M3","E3M4","E3M5","E3M6","E3M7","E3M8","E3M9", + "DPHOOF","BFGGA0","HEADA1","CYBRA1","SPIDA1D1", "E4M2" + BannerColors = "54 54 54", "a8 a8 a8" +} + +IWad +{ + Name = "DOOM Registered" + Autoname = "Doom1" + Game = "Doom" + Config = "Doom" + Mapinfo = "mapinfo/doom1.txt" + Compatibility = "Shorttex" + MustContain = "E1M1","E2M1","E2M2","E2M3","E2M4","E2M5","E2M6","E2M7","E2M8","E2M9", + "E3M1","E3M2","E3M3","E3M4","E3M5","E3M6","E3M7","E3M8","E3M9", + "DPHOOF","BFGGA0","HEADA1","CYBRA1","SPIDA1D1" + BannerColors = "54 54 54", "a8 a8 a8" +} + +IWad +{ + Name = "DOOM Shareware" + Game = "Doom" + Config = "Doom" + Mapinfo = "mapinfo/doom1.txt" + Compatibility = "Shareware", "Shorttex" + MustContain = "E1M1" + BannerColors = "54 54 54", "a8 a8 a8" +} + +IWad +{ + Name = "Final Doom: TNT - Evilution" + Autoname = "TNT" + Game = "Doom" + Config = "Doom" + Mapinfo = "mapinfo/tnt.txt" + Compatibility = "Shorttex", "Stairs" + MustContain = "MAP01", "REDTNT2" + BannerColors = "a8 00 00", "a8 a8 a8" +} + +IWad +{ + Name = "Final Doom: Plutonia Experiment" + Autoname = "Plutonia" + Game = "Doom" + Config = "Doom" + Mapinfo = "mapinfo/plutonia.txt" + Compatibility = "Shorttex" + MustContain = "MAP01", "CAMO1" + BannerColors = "a8 00 00", "a8 a8 a8" +} + +// Doom 2 must be last to be checked becaude MAP01 is its only requirement +IWad +{ + Name = "DOOM 2: Hell on Earth" + Autoname = "Doom2" + Game = "Doom" + Config = "Doom" + Mapinfo = "mapinfo/doom2.txt" + Compatibility = "Shorttex" + MustContain = "MAP01" + BannerColors = "a8 00 00", "a8 a8 a8" +} + + + +Names +{ + "doom2f.wad" + "doom2.wad" + "plutonia.wad" + "tnt.wad" + "doomu.wad" + "doom.wad" + "doom1.wad" + "heretic.wad" + "heretic1.wad" + "hexen.wad" + "hexdd.wad" + "hexendemo.wad" + "hexdemo.wad" + "strife1.wad" + "strife0.wad" + "freedoom.wad" + "freedoom1.wad" + "freedoomu.wad" + "freedm.wad" + "blasphem.wad" + "blasphemer.wad" + "chex.wad" + "chex3.wad" + "action2.wad" + "harm1.wad" + "hacx.wad" +}