diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index 74968404d..a40f1f1a2 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -450,11 +450,10 @@ CCMD (exec) for (int i = 1; i < argv.argc(); ++i) { - switch (C_ExecFile (argv[i], gamestate == GS_STARTUP)) + if (!C_ExecFile(argv[i])) { - case 1: Printf ("Could not open \"%s\"\n", argv[1]); break; - case 2: Printf ("Error parsing \"%s\"\n", argv[1]); break; - default: break; + Printf ("Could not exec \"%s\"\n", argv[i]); + break; } } } diff --git a/src/c_dispatch.cpp b/src/c_dispatch.cpp index 6a526a661..d72993cb7 100644 --- a/src/c_dispatch.cpp +++ b/src/c_dispatch.cpp @@ -185,9 +185,6 @@ static const char *KeyConfCommands[] = "clearplayerclasses" }; -static TArray StoredStartupSets; -static bool RunningStoredStartups; - // CODE -------------------------------------------------------------------- IMPLEMENT_CLASS (DWaitingCommand) @@ -540,18 +537,6 @@ void ResetButtonStates () } } -void C_ExecStoredSets() -{ - assert(!RunningStoredStartups); - RunningStoredStartups = true; - for (unsigned i = 0; i < StoredStartupSets.Size(); ++i) - { - C_DoCommand(StoredStartupSets[i]); - } - StoredStartupSets.Clear(); - RunningStoredStartups = false; -} - void C_DoCommand (const char *cmd, int keynum) { FConsoleCommand *com; @@ -627,22 +612,7 @@ void C_DoCommand (const char *cmd, int keynum) if ( (com = FindNameInHashTable (Commands, beg, len)) ) { - if (gamestate == GS_STARTUP && !RunningStoredStartups && - len == 3 && strnicmp(beg, "set", 3) == 0) - { - // Save setting of unknown cvars for later, in case a loaded wad has a - // CVARINFO that defines it. - FCommandLine args(beg); - if (args.argc() > 1 && FindCVar(args[1], NULL) == NULL) - { - StoredStartupSets.Push(beg); - } - else - { - com->Run(args, players[consoleplayer].mo, keynum); - } - } - else if (gamestate != GS_STARTUP || ParsingKeyConf || + if (gamestate != GS_STARTUP || ParsingKeyConf || (len == 3 && strnicmp (beg, "set", 3) == 0) || (len == 7 && strnicmp (beg, "logfile", 7) == 0) || (len == 9 && strnicmp (beg, "unbindall", 9) == 0) || @@ -687,15 +657,7 @@ void C_DoCommand (const char *cmd, int keynum) } else { // We don't know how to handle this command - if (gamestate == GS_STARTUP && !RunningStoredStartups) - { - // Save it for later, in case a CVARINFO defines it. - StoredStartupSets.Push(beg); - } - else - { - Printf ("Unknown command \"%.*s\"\n", (int)len, beg); - } + Printf ("Unknown command \"%.*s\"\n", (int)len, beg); } } } @@ -1368,7 +1330,7 @@ CCMD (key) // Execute any console commands specified on the command line. // These all begin with '+' as opposed to '-'. -void C_ExecCmdLineParams () +FExecList *C_ParseCmdLineParams(FExecList *exec) { for (int currArg = 1; currArg < Args->NumArgs(); ) { @@ -1389,10 +1351,15 @@ void C_ExecCmdLineParams () cmdString = BuildString (cmdlen, Args->GetArgList (argstart)); if (!cmdString.IsEmpty()) { - C_DoCommand (&cmdString[1]); + if (exec == NULL) + { + exec = new FExecList; + } + exec->AddCommand(&cmdString[1]); } } } + return exec; } bool FConsoleCommand::IsAlias () @@ -1469,28 +1436,60 @@ void FConsoleAlias::SafeDelete () } } -static BYTE PullinBad = 2; -static const char *PullinFile; -extern TArray allwads; +void FExecList::AddCommand(const char *cmd, const char *file) +{ + // Pullins are special and need to be separated from general commands. + // They also turned out to be a really bad idea, since they make things + // more complicated. :( + if (file != NULL && strnicmp(cmd, "pullin", 6) == 0 && isspace(cmd[6])) + { + FCommandLine line(cmd); + C_SearchForPullins(this, file, line); + } + // Recursive exec: Parse this file now. + else if (strnicmp(cmd, "exec", 4) == 0 && isspace(cmd[4])) + { + FCommandLine argv(cmd); + for (int i = 1; i < argv.argc(); ++i) + { + C_ParseExecFile(argv[i], this); + } + } + else + { + Commands.Push(cmd); + } +} -int C_ExecFile (const char *file, bool usePullin) +void FExecList::ExecCommands() const +{ + for (unsigned i = 0; i < Commands.Size(); ++i) + { + AddCommandString(Commands[i].LockBuffer()); + Commands[i].UnlockBuffer(); + } +} + +void FExecList::AddPullins(TArray &wads) const +{ + for (unsigned i = 0; i < Pullins.Size(); ++i) + { + D_AddFile(wads, Pullins[i]); + } +} + +FExecList *C_ParseExecFile(const char *file, FExecList *exec) { FILE *f; char cmd[4096]; int retval = 0; - BYTE pullinSaved = PullinBad; - const char *fileSaved = PullinFile; - if ( (f = fopen (file, "r")) ) { - PullinBad = 1-usePullin; - PullinFile = file; - - while (fgets (cmd, 4095, f)) + while (fgets(cmd, countof(cmd)-1, f)) { // Comments begin with // - char *stop = cmd + strlen (cmd) - 1; + char *stop = cmd + strlen(cmd) - 1; char *comment = cmd; int inQuote = 0; @@ -1517,88 +1516,78 @@ int C_ExecFile (const char *file, bool usePullin) { // Comment in middle of line *comment = 0; } - - AddCommandString (cmd); + if (exec == NULL) + { + exec = new FExecList; + } + exec->AddCommand(cmd, file); } - if (!feof (f)) + if (!feof(f)) { - retval = 2; + Printf("Error parsing \"%s\"\n", file); } - fclose (f); + fclose(f); } else { - retval = 1; + Printf ("Could not open \"%s\"\n", file); + } + return exec; +} + +bool C_ExecFile (const char *file) +{ + FExecList *exec = C_ParseExecFile(file, NULL); + if (exec != NULL) + { + exec->ExecCommands(); + if (exec->Pullins.Size() > 0) + { + Printf(TEXTCOLOR_BOLD "Notice: Pullin files were ignored.\n"); + } + delete exec; + } + return exec != NULL; +} + +void C_SearchForPullins(FExecList *exec, const char *file, FCommandLine &argv) +{ + const char *lastSlash; + + assert(exec != NULL); + assert(file != NULL); +#ifdef __unix__ + lastSlash = strrchr(file, '/'); +#else + const char *lastSlash1, *lastSlash2; + + lastSlash1 = strrchr(file, '/'); + lastSlash2 = strrchr(file, '\\'); + lastSlash = MAX(lastSlash1, lastSlash2); +#endif + + for (int i = 1; i < argv.argc(); ++i) + { + // Try looking for the wad in the same directory as the .cfg + // before looking for it in the current directory. + if (lastSlash != NULL) + { + FString path(file, (lastSlash - file) + 1); + path += argv[i]; + if (FileExists(path)) + { + exec->Pullins.Push(path); + continue; + } + } + exec->Pullins.Push(argv[i]); } - PullinBad = pullinSaved; - PullinFile = fileSaved; - return retval; } CCMD (pullin) { - if (PullinBad == 2) - { - Printf ("This command is only valid from .cfg\n" - "files and only when used at startup.\n"); - } - else if (argv.argc() > 1) - { - const char *lastSlash; - -#ifdef __unix__ - lastSlash = strrchr (PullinFile, '/'); -#else - const char *lastSlash1, *lastSlash2; - - lastSlash1 = strrchr (PullinFile, '/'); - lastSlash2 = strrchr (PullinFile, '\\'); - lastSlash = MAX (lastSlash1, lastSlash2); -#endif - - if (PullinBad) - { - Printf ("Not loading:"); - } - for (int i = 1; i < argv.argc(); ++i) - { - if (PullinBad) - { - Printf (" %s", argv[i]); - } - else - { - // Try looking for the wad in the same directory as the .cfg - // before looking for it in the current directory. - char *path = argv[i]; - - if (lastSlash != NULL) - { - size_t pathlen = lastSlash - PullinFile + strlen (argv[i]) + 2; - path = new char[pathlen]; - strncpy (path, PullinFile, (lastSlash - PullinFile) + 1); - strcpy (path + (lastSlash - PullinFile) + 1, argv[i]); - if (!FileExists (path)) - { - delete[] path; - path = argv[i]; - } - else - { - FixPathSeperator (path); - } - } - D_AddFile (allwads, path); - if (path != argv[i]) - { - delete[] path; - } - } - } - if (PullinBad) - { - Printf ("\n"); - } - } + // Actual handling for pullin is now completely special-cased above + Printf (TEXTCOLOR_BOLD "Pullin" TEXTCOLOR_NORMAL " is only valid from .cfg\n" + "files and only when used at startup.\n"); } diff --git a/src/c_dispatch.h b/src/c_dispatch.h index b494005c7..f9aeb0dc3 100644 --- a/src/c_dispatch.h +++ b/src/c_dispatch.h @@ -39,31 +39,6 @@ class FConfigFile; class APlayerPawn; -extern bool CheckCheatmode (bool printmsg = true); - -void C_ExecCmdLineParams (); -void C_ExecStoredSets(); - -// Add commands to the console as if they were typed in. Can handle wait -// and semicolon-separated commands. This function may modify the source -// string, but the string will be restored to its original state before -// returning. Therefore, commands passed must not be in read-only memory. -void AddCommandString (char *text, int keynum=0); - -// Process a single console command. Does not handle wait. -void C_DoCommand (const char *cmd, int keynum=0); - -int C_ExecFile (const char *cmd, bool usePullin); - -// Write out alias commands to a file for all current aliases. -void C_ArchiveAliases (FConfigFile *f); - -void C_SetAlias (const char *name, const char *cmd); -void C_ClearAliases (); - -// build a single string out of multiple strings -FString BuildString (int argc, FString *argv); - // Class that can parse command lines class FCommandLine { @@ -83,6 +58,44 @@ private: bool noescapes; }; +// Contains the contents of an exec'ed file +struct FExecList +{ + TArray Commands; + TArray Pullins; + + void AddCommand(const char *cmd, const char *file = NULL); + void ExecCommands() const; + void AddPullins(TArray &wads) const; +}; + + +extern bool CheckCheatmode (bool printmsg = true); + +FExecList *C_ParseCmdLineParams(FExecList *exec); + +// Add commands to the console as if they were typed in. Can handle wait +// and semicolon-separated commands. This function may modify the source +// string, but the string will be restored to its original state before +// returning. Therefore, commands passed must not be in read-only memory. +void AddCommandString (char *text, int keynum=0); + +// Process a single console command. Does not handle wait. +void C_DoCommand (const char *cmd, int keynum=0); + +FExecList *C_ParseExecFile(const char *file, FExecList *source); +void C_SearchForPullins(FExecList *exec, const char *file, class FCommandLine &args); +bool C_ExecFile(const char *file); + +// Write out alias commands to a file for all current aliases. +void C_ArchiveAliases (FConfigFile *f); + +void C_SetAlias (const char *name, const char *cmd); +void C_ClearAliases (); + +// build a single string out of multiple strings +FString BuildString (int argc, FString *argv); + typedef void (*CCmdRun) (FCommandLine &argv, APlayerPawn *instigator, int key); class FConsoleCommand diff --git a/src/d_iwad.cpp b/src/d_iwad.cpp index 7574347bc..3fc365e8c 100644 --- a/src/d_iwad.cpp +++ b/src/d_iwad.cpp @@ -219,6 +219,11 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize) sc.ScriptError("Unknown keyword '%s'", sc.String); } } + if (iwad->MapInfo.IsEmpty()) + { + // We must at least load the minimum defaults to allow the engine to run. + iwad->MapInfo = "mapinfo/mindefaults.txt"; + } } else if (sc.Compare("NAMES")) { diff --git a/src/d_main.cpp b/src/d_main.cpp index 1244cc88f..9b46d42c2 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1723,12 +1723,13 @@ bool ConsiderPatches (const char *arg) // //========================================================================== -void D_MultiExec (DArgs *list, bool usePullin) +FExecList *D_MultiExec (DArgs *list, FExecList *exec) { for (int i = 0; i < list->NumArgs(); ++i) { - C_ExecFile (list->GetArg (i), usePullin); + exec = C_ParseExecFile(list->GetArg(i), exec); } + return exec; } static void GetCmdLineFiles(TArray &wadfiles) @@ -2291,18 +2292,24 @@ void D_DoomMain (void) AddAutoloadFiles(iwad_info->Autoname); - // Run automatically executed files + // Process automatically executed files + FExecList *exec; execFiles = new DArgs; - GameConfig->AddAutoexec (execFiles, gameinfo.ConfigName); - D_MultiExec (execFiles, true); + GameConfig->AddAutoexec(execFiles, gameinfo.ConfigName); + exec = D_MultiExec(execFiles, NULL); - // Run .cfg files at the start of the command line. + // Process .cfg files at the start of the command line. execFiles = Args->GatherFiles ("-exec"); - D_MultiExec (execFiles, true); + exec = D_MultiExec(execFiles, exec); - C_ExecCmdLineParams (); // [RH] do all +set commands on the command line + // [RH] process all + commands on the command line + exec = C_ParseCmdLineParams(exec); CopyFiles(allwads, pwads); + if (exec != NULL) + { + exec->AddPullins(allwads); + } // Since this function will never leave we must delete this array here manually. pwads.Clear(); @@ -2310,7 +2317,7 @@ void D_DoomMain (void) if (hashfile) { - Printf("Notice: File hashing is incredibly verbose. Expect loading files to take much longer then usual.\n"); + Printf("Notice: File hashing is incredibly verbose. Expect loading files to take much longer than usual.\n"); } Printf ("W_Init: Init WADfiles.\n"); @@ -2324,8 +2331,13 @@ void D_DoomMain (void) // Now that wads are loaded, define mod-specific cvars. ParseCVarInfo(); - // Try setting previously unknown cvars again, as a CVARINFO may have made them known. - C_ExecStoredSets(); + // Actually exec command line commands and exec files. + if (exec != NULL) + { + exec->ExecCommands(); + delete exec; + exec = NULL; + } // [RH] Initialize localizable strings. GStrings.LoadStrings (false); diff --git a/src/g_doomedmap.cpp b/src/g_doomedmap.cpp index 131ddd076..c9deb7256 100644 --- a/src/g_doomedmap.cpp +++ b/src/g_doomedmap.cpp @@ -80,7 +80,8 @@ const char *SpecialMapthingNames[] = { struct MapinfoEdMapItem { FName classname; // DECORATE is read after MAPINFO so we do not have the actual classes available here yet. - int special; + short special; + bool argsdefined; int args[5]; // These are for error reporting. We must store the file information because it's no longer available when these items get resolved. FString filename; @@ -180,14 +181,15 @@ void FMapInfoParser::ParseDoomEdNums() editem.special = -1; } memset(editem.args, 0, sizeof(editem.args)); + editem.argsdefined = false; int minargs = 0; int maxargs = 5; FString specialname; if (sc.CheckString(",")) { - // todo: parse a special or args - if (editem.special < 0) editem.special = 0; // mark args as used - if this is done we need to prevent assignment of map args in P_SpawnMapThing. + editem.argsdefined = true; // mark args as used - if this is done we need to prevent assignment of map args in P_SpawnMapThing. + if (editem.special < 0) editem.special = 0; if (!sc.CheckNumber()) { sc.MustGetString(); @@ -264,6 +266,7 @@ void InitActorNumsFromMapinfo() FDoomEdEntry ent; ent.Type = cls; ent.Special = pair->Value.special; + ent.ArgsDefined = pair->Value.argsdefined; memcpy(ent.Args, pair->Value.args, sizeof(ent.Args)); DoomEdMap.Insert(pair->Key, ent); } diff --git a/src/info.h b/src/info.h index 8eed93e48..bdbb69940 100644 --- a/src/info.h +++ b/src/info.h @@ -282,7 +282,8 @@ struct FActorInfo struct FDoomEdEntry { const PClass *Type; - int Special; + short Special; + bool ArgsDefined; int Args[5]; }; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index e3317e1a2..2571413c8 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4617,9 +4617,9 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) } // copy args to mapthing so that we have them in one place for the rest of this function - if (mentry->Type != NULL && mentry->Special >= 0) + if (mentry->ArgsDefined) { - mthing->special = mentry->Special; + if (mentry->Type!= NULL) mthing->special = mentry->Special; memcpy(mthing->args, mentry->Args, sizeof(mthing->args)); } diff --git a/wadsrc/static/iwadinfo.txt b/wadsrc/static/iwadinfo.txt index a274a1f2f..6c958ddfa 100644 --- a/wadsrc/static/iwadinfo.txt +++ b/wadsrc/static/iwadinfo.txt @@ -6,6 +6,7 @@ IWad Autoname = "square.square" Game = "Doom" Config = "Square" + Mapinfo = "mapinfo/mindefaults.txt" MustContain = "SQU-IWAD", "E1A1" BannerColors = "ff ff ff", "80 00 80" } @@ -16,6 +17,7 @@ IWad Autoname = "square.squareware" Game = "Doom" Config = "Square" + Mapinfo = "mapinfo/mindefaults.txt" MustContain = "SQU-SWE1", "E1A1" BannerColors = "ff ff ff", "80 00 80" } diff --git a/wadsrc/static/mapinfo/mindefaults.txt b/wadsrc/static/mapinfo/mindefaults.txt new file mode 100644 index 000000000..cbb3fa06b --- /dev/null +++ b/wadsrc/static/mapinfo/mindefaults.txt @@ -0,0 +1,59 @@ +// defines the minimum needed entries to let an unknown IWAD run + +gameinfo +{ + titlepage = "-NOFLAT-" + titletime = 999 + infopage = "-NOFLAT-" + titlemusic = "" + advisorytime = 0 + chatsound = "" + finalemusic = "" + finaleflat = "-NOFLAT-" + finalepage = "-NOFLAT-" + quitsound = "" + borderflat = "-NOFLAT-" + border = DoomBorder + telefogheight = 0 + defkickback = 100 + skyflatname = "F_SKY1" + translator = "xlat/doom.txt" + defaultbloodcolor = "68 00 00" + defaultbloodparticlecolor = "ff 00 00" + backpacktype = "Backpack" + armoricons = "AICNA0", 0.75, "AICNC0" + statusbar = "sbarinfo/doom.txt" + intermissionmusic = "" + intermissioncounter = true + dimcolor = "6f 00 6b" + dimamount = 0.8 + definventorymaxamount = 25 + defaultrespawntime = 12 + defaultdropstyle = 1 + endoom = "ENDOOM" + player5start = 4001 + pickupcolor = "c0 c0 c0" + quitmessages = "Do you want to quit?" + + menufontcolor_title = "purple" + menufontcolor_label = "default" + menufontcolor_value = "gray" + menufontcolor_action = "gray" + menufontcolor_header = "blue" + menufontcolor_highlight = "lightblue" + menufontcolor_selection = "purple" + menubackbutton = "M_BACK_D" + playerclasses = "DoomPlayer" + pausesign = "-NOFLAT-" + gibfactor = 1 + cursorpic = "doomcurs" + textscreenx = 10 + textscreeny = 10 + defaultendsequence = "Inter_Cast" + maparrow = "maparrows/arrow.txt", "maparrows/ddtarrow.txt" + statscreen_mapnamefont = "BigFont" + statscreen_finishedpatch = "WIF" + statscreen_enteringpatch = "WIENTER" +} + +include "mapinfo/common.txt"