// Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // // $Id:$ // // Copyright (C) 1993-1996 by id Software, Inc. // // This source is available for distribution and/or modification // only under the terms of the DOOM Source Code License as // published by id Software. All rights reserved. // // The source is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License // for more details. // // $Log:$ // // DESCRIPTION: // DOOM main program (D_DoomMain) and game loop (D_DoomLoop), // plus functions to determine game mode (shareware, registered), // parse command line parameters, configure game parameters (turbo), // and call the startup functions. // //----------------------------------------------------------------------------- #ifdef _WIN32 #include #define mkdir(a,b) mkdir (a) #else #include #endif #include "m_alloc.h" #include "minilzo.h" #include "doomdef.h" #include "doomstat.h" #include "dstrings.h" #include "z_zone.h" #include "w_wad.h" #include "s_sound.h" #include "v_video.h" #include "f_finale.h" #include "f_wipe.h" #include "m_argv.h" #include "m_misc.h" #include "m_menu.h" #include "c_consol.h" #include "c_cmds.h" #include "c_dispch.h" #include "i_system.h" #include "i_sound.h" #include "i_video.h" #include "g_game.h" #include "hu_stuff.h" #include "wi_stuff.h" #include "st_stuff.h" #include "am_map.h" #include "p_setup.h" #include "r_local.h" #include "r_sky.h" #include "d_main.h" #include "d_dehack.h" #include "cmdlib.h" #include "s_sound.h" #include "m_swap.h" cvar_t *fraglimit; cvar_t *timelimit; cvar_t *turbo; extern void TurboCallback (cvar_t *); // // D-DoomLoop() // Not a globally visible function, // just included for source reference, // called by D_DoomMain, never exits. // Manages timing and IO, // calls all ?_Responder, ?_Ticker, and ?_Drawer, // calls I_GetTime, I_StartFrame, and I_StartTic // void D_DoomLoop (void); wadlist_t *wadfiles; // [RH] remove limit on # of loaded wads wadlist_t **wadtail = &wadfiles; BOOL devparm; // started game with -devparm int NoWipe; // [RH] Allow wipe? (Needs to be set each time) BOOL drone; BOOL singletics = false; // debug flag to cancel adaptiveness char *D_DrawIcon; // [RH] Patch name of icon to draw on next refresh extern BOOL inhelpscreens; char startmap[8]; BOOL autostart; FILE* debugfile; BOOL advancedemo; char wadfile[1024]; // primary wad file void D_CheckNetGame (void); void D_ProcessEvents (void); void G_BuildTiccmd (ticcmd_t* cmd); void D_DoAdvanceDemo (void); // // EVENT HANDLING // // Events are asynchronous inputs generally generated by the game user. // Events can be discarded if no responder claims them // event_t events[MAXEVENTS]; int eventhead; int eventtail; // // D_PostEvent // Called by the I/O functions when input is detected // void D_PostEvent (const event_t* ev) { events[eventhead] = *ev; eventhead = (++eventhead)&(MAXEVENTS-1); } // // D_ProcessEvents // Send all the events of the given timestamp down the responder chain // // [RH] Stuff for screenmode testing extern int testingmode; extern void M_RestoreMode (void); void D_ProcessEvents (void) { event_t *ev; // [RH] If testing mode, do not accept input until test is over if (testingmode) { if (testingmode <= I_GetTime()) { M_RestoreMode (); } return; } for ( ; eventtail != eventhead ; eventtail = (++eventtail)&(MAXEVENTS-1) ) { ev = &events[eventtail]; if (C_Responder (ev)) continue; // console ate the event if (M_Responder (ev)) continue; // menu ate the event G_Responder (ev); } } // [RH] Each time dmflags is changed, this function is called and // transforms it into an integer so that we don't need to make // the conversion each time we check its value. void DMFlagsCallback (cvar_t *var) { dmflags = (int)var->value; // In case DF_NO_FREELOOK was changed, reinitialize the sky // map. (If no freelook, then no need to stretch the sky.) if (textureheight) R_InitSkyMap (r_stretchsky); if (dmflags & DF_NO_FREELOOK) AddCommandString ("centerview"); } // // D_Display // draw current display, possibly wiping it from the previous // // wipegamestate can be set to -1 to force a wipe on the next draw gamestate_t wipegamestate = GS_DEMOSCREEN; extern BOOL setsizeneeded, setmodeneeded; extern int NewWidth, NewHeight, NewID, DisplayID; extern cvar_t *st_scale; void R_ExecuteSetViewSize (void); void D_Display (void) { BOOL wipe; if (nodrawers) return; // for comparative timing / profiling // [RH] change the screen mode if needed if (setmodeneeded) { int oldwidth = screen.width; int oldheight = screen.height; int oldid = DisplayID; // Change screen mode. if (!V_SetResolution (NewWidth, NewHeight, NewID)) if (!V_SetResolution (oldwidth, oldheight, oldid)) I_FatalError ("Could not change screen mode"); // Recalculate various view parameters. setsizeneeded = true; // Trick status bar into rethinking its position SetCVarFloat (st_scale, st_scale->value); SB_state = -1; // Refresh the console. C_NewModeAdjust (); } // change the view size if needed if (setsizeneeded) { R_ExecuteSetViewSize (); setmodeneeded = false; } I_BeginUpdate (); // [RH] Allow temporarily disabling wipes if (NoWipe) { BorderNeedRefresh = true; NoWipe--; wipe = false; wipegamestate = gamestate; } else if (gamestate != wipegamestate && gamestate != GS_FULLCONSOLE) { // save the current screen if about to wipe BorderNeedRefresh = true; wipe = true; wipe_StartScreen(0, 0, screen.width, screen.height); wipegamestate = gamestate; } else { wipe = false; } switch (gamestate) { case GS_FULLCONSOLE: C_DrawConsole (); M_Drawer (); I_FinishUpdate (); return; case GS_LEVEL: if (!gametic) break; if (viewactive) R_RenderPlayerView (&players[consoleplayer]); if (automapactive) AM_Drawer (); C_DrawMid (); ST_Drawer (); CT_Drawer (); break; case GS_INTERMISSION: WI_Drawer (); break; case GS_FINALE: F_Drawer (); break; case GS_DEMOSCREEN: D_PageDrawer (); break; } // draw pause pic if (paused && !menuactive) { patch_t *pause = W_CacheLumpName ("M_PAUSE", PU_CACHE); int y; y = (automapactive && !viewactive) ? 4 : viewwindowy + 4; V_DrawPatchCleanNoMove((screen.width-(pause->width)*CleanXfac)/2,y,&screen,pause); } // [RH] Draw icon, if any if (D_DrawIcon) { int lump = W_CheckNumForName (D_DrawIcon); D_DrawIcon = NULL; if (lump >= 0) { patch_t *p = W_CacheLumpNum (lump, PU_CACHE); V_DrawPatchIndirect (160-SHORT(p->width)/2, 100-SHORT(p->height)/2, &screen, p); } NoWipe = 10; } NetUpdate (); // send out any new accumulation if (!wipe) { // normal update C_DrawConsole (); // draw console M_Drawer (); // menu is drawn even on top of everything I_FinishUpdate (); // page flip or blit buffer } else { // wipe update int wipestart, nowtime, tics; BOOL done; wipe_EndScreen(0, 0, screen.width, screen.height); I_FinishUpdateNoBlit (); wipestart = I_GetTime () - 1; do { do { nowtime = I_GetTime (); tics = nowtime - wipestart; } while (!tics); wipestart = nowtime; I_BeginUpdate (); done = wipe_ScreenWipe(wipe_Melt, 0, 0, screen.width, screen.height, tics); C_DrawConsole (); M_Drawer (); // menu is drawn even on top of wipes I_FinishUpdate (); // page flip or blit buffer } while (!done); } } // // [RH] D_ErrorLoop // char errortext[2048]; jmp_buf errorjmp; BOOL errorjmpable; extern BOOL gameisdead; static void STACK_ARGS godead (void) { gameisdead = true; } void D_ErrorLoop (void) { int i; if (gameaction != ga_nothing) { gamestate = GS_FULLCONSOLE; C_FullConsole (); } atexit (godead); while (1) { if (setjmp (errorjmp)) { errorjmpable = false; if (errortext[0]) { Printf (PRINT_HIGH, "%s\n", errortext); errortext[0] = 0; D_QuitNetGame (); netgame = false; singletics = false; if (demorecording || demoplayback) G_CheckDemoStatus (); for (i = 1; i < MAXPLAYERS; i++) playeringame[i] = 0; consoleplayer = 0; playeringame[0] = 1; players[0].playerstate = PST_LIVE; gameaction = ga_fullconsole; } } errorjmpable = true; D_DoomLoop (); // never returns } } // // D_DoomLoop // extern BOOL demorecording; void D_DoomLoop (void) { while (1) { // frame syncronous IO operations I_StartFrame (); // process one or more tics if (singletics) { I_StartTic (); D_ProcessEvents (); G_BuildTiccmd (&netcmds[consoleplayer][maketic%BACKUPTICS]); if (advancedemo) D_DoAdvanceDemo (); C_Ticker (); M_Ticker (); G_Ticker (); gametic++; maketic++; Net_NewMakeTic (); } else { TryRunTics (); // will run at least one tic } // [RH] Use the consoleplayer's camera to update sounds S_UpdateSounds (players[consoleplayer].camera); // move positional sounds // Update display, next frame, with current state. D_Display (); } } // // DEMO LOOP // int demosequence; int pagetic; char *pagename; // // D_PageTicker // Handles timing for warped projection // void D_PageTicker (void) { if (--pagetic < 0) D_AdvanceDemo (); } // // D_PageDrawer // void D_PageDrawer (void) { V_DrawPatchIndirect (0,0, &screen, W_CacheLumpName(pagename, PU_CACHE)); } // // D_AdvanceDemo // Called after each demo or intro demosequence finishes // void D_AdvanceDemo (void) { advancedemo = true; } // // This cycles through the demo sequences. // FIXME - version dependend demo numbers? // // [RH] If M_DemoNoPlay is true, then any // demos are skipped. extern BOOL M_DemoNoPlay; void D_DoAdvanceDemo (void) { static char *pages[2][3] = { { "CREDIT", "TITLEPIC", "HELP2" }, { "CREDIT", "TITLEPIC", "CREDIT" } }; static char demoname[8] = "DEMO1"; static int democount = 0; static int pagecount; char **page; players[consoleplayer].playerstate = PST_LIVE; // not reborn advancedemo = false; usergame = false; // no save / end game here paused = false; gameaction = ga_nothing; if (gamemode == retail || gamemode == commercial) { page = pages[1]; } else { page = pages[0]; } switch (demosequence) { case 1: if (!M_DemoNoPlay) { BorderNeedRefresh = true; democount++; sprintf (demoname + 4, "%d", democount); if (W_CheckNumForName (demoname) < 0) { demosequence = 0; democount = 1; // falls through to case 0 below } else { G_DeferedPlayDemo (demoname); demosequence = 2; break; } } default: case 0: gamestate = GS_DEMOSCREEN; pagename = "TITLEPIC"; if (gamemode == commercial) { pagetic = TICRATE * 11; if (HexenHack) { // [RH] :-) S_StartMusic ("hexen"); } else { S_StartMusic ("D_DM2TTL"); } } else { pagetic = TICRATE * 5; S_StartMusic ("D_INTRO"); } demosequence = 1; pagecount = 0; C_HideConsole (); break; case 2: pagetic = (TICRATE * 200) / 35; gamestate = GS_DEMOSCREEN; pagename = page[pagecount]; pagecount = (pagecount+1) % 3; demosequence = 1; break; } } // // D_StartTitle // void D_StartTitle (void) { gameaction = ga_nothing; demosequence = -1; D_AdvanceDemo (); } // // [RH] Quit the current game and go to fullscreen console // void Cmd_Endgame (player_t *plyr, int argc, char **argv) { if (!netgame) { gameaction = ga_fullconsole; demosequence = -1; } } // // D_AddFile // void D_AddFile (char *file) { wadlist_t *wad = Z_Malloc (sizeof(*wad) + strlen(file), PU_STATIC, 0); *wadtail = wad; wad->next = NULL; strcpy (wad->name, file); wadtail = &wad->next; } // // IdentifyVersion // Checks availability of IWAD files by name, // to determine whether registered/commercial features // should be executed (notably loading PWAD's). // [RH] Rewritten to recognize the IWAD by its contents, not its name. // static const char *IdentifyVersion (void) { const char *titlestring = "Public DOOM - "; static const char doomwadnames[][13] = { "doom2f.wad", "doom2.wad", "plutonia.wad", "tnt.wad", "doomu.wad", // Hack from original Linux version. Not necessary, but I threw it in anyway. "doom.wad", "doom1.wad", "" }; int i; char *doomwaddir; char iwad[256]; int iwadindex; doomwaddir = progdir; // Search for a pre-defined IWAD from the list above for (i = 0; doomwadnames[i][0]; i++) { sprintf (iwad, "%s%s", doomwaddir, doomwadnames[i]); if (FileExists (iwad)) break; } if (!doomwadnames[i][0]) iwad[0] = 0; // See if the user wants to use a different iwad instead iwadindex = M_CheckParm ("-iwad"); if (iwadindex && iwadindex < myargc - 1) { char *custwad = Z_Malloc(strlen(myargv[++iwadindex]) + 5, PU_STATIC, 0); strcpy (custwad, myargv[iwadindex]); FixPathSeperator (custwad); DefaultExtension (custwad, ".wad"); if (FileExists (custwad)) strcpy (iwad, custwad); Z_Free (custwad); } // Now scan the contents of the IWAD to determine which one it is if (iwad[0]) { static const char checklumps[8][8] = { "E1M1", "E2M1", "E4M1", "MAP01", "ANIMDEFS", "FINAL2", "REDTNT2", "CAMO1" }; int lumpsfound[8]; wadinfo_t header; FILE *f; memset (lumpsfound, 0, sizeof(lumpsfound)); if ( (f = fopen (iwad, "rb")) ) { fread (&header, sizeof(header), 1, f); if (header.identification == IWAD_ID || header.identification == PWAD_ID) { header.numlumps = LONG(header.numlumps); if (0 == fseek (f, LONG(header.infotableofs), SEEK_SET)) { for (i = 0; i < header.numlumps; i++) { filelump_t lump; int j; if (0 == fread (&lump, sizeof(lump), 1, f)) break; for (j = 0; j < 8; j++) if (!strnicmp (lump.name, checklumps[j], 8)) lumpsfound[j]++; } } } fclose (f); } gamemode = undetermined; if (lumpsfound[3]) { gamemode = commercial; if (lumpsfound[6]) { gamemission = pack_tnt; titlestring = "DOOM 2: TNT - Evilution"; } else if (lumpsfound[7]) { gamemission = pack_plut; titlestring = "DOOM 2: Plutonia Experiment"; } else { gamemission = doom2; if (lumpsfound[4]) titlestring = "Hexen (But It Won't Work)"; else titlestring = "DOOM 2: Hell on Earth"; } } else if (lumpsfound[0]) { gamemission = doom; if (lumpsfound[1]) { if (lumpsfound[2]) { gamemode = retail; titlestring = "The Ultimate DOOM"; } else { gamemode = registered; titlestring = "DOOM Registered"; } } else { gamemode = shareware; titlestring = "DOOM Shareware"; } if (lumpsfound[5]) titlestring = "Heretic (But It Won't Work)"; } } if (gamemode == undetermined) Printf (PRINT_HIGH, "Game mode indeterminate.\n"); if (iwad[0]) D_AddFile (iwad); return titlestring; } // // Find a Response File // void FindResponseFile (void) { #define MAXARGVS 100 int i; for (i = 1; i < myargc; i++) if (myargv[i][0] == '@') { FILE * handle; int size; int k; int index; int indexinfile; char *infile; char *file; char *moreargs[20]; char *firstargv; // READ THE RESPONSE FILE INTO MEMORY handle = fopen (&myargv[i][1],"rb"); if (!handle) I_FatalError ("\nNo such response file!"); Printf (PRINT_HIGH, "Found response file %s!\n", &myargv[i][1]); fseek (handle,0,SEEK_END); size = ftell(handle); fseek (handle,0,SEEK_SET); file = Malloc (size); fread (file,size,1,handle); fclose (handle); // KEEP ALL CMDLINE ARGS FOLLOWING @RESPONSEFILE ARG for (index = 0,k = i+1; k < myargc; k++) moreargs[index++] = myargv[k]; firstargv = myargv[0]; myargv = Malloc(sizeof(char *)*MAXARGVS); memset(myargv,0,sizeof(char *)*MAXARGVS); myargv[0] = firstargv; infile = file; indexinfile = k = 0; indexinfile++; // SKIP PAST ARGV[0] (KEEP IT) do { myargv[indexinfile++] = infile+k; while(k < size && ((*(infile+k)>= ' '+1) && (*(infile+k)<='z'))) k++; *(infile+k) = 0; while(k < size && ((*(infile+k)<= ' ') || (*(infile+k)>'z'))) k++; } while(k < size); for (k = 0;k < index;k++) myargv[indexinfile++] = moreargs[k]; myargc = indexinfile; // DISPLAY ARGS Printf (PRINT_HIGH, "%d command-line args:\n",myargc); for (k = 1; k < myargc; k++) Printf (PRINT_HIGH, "%s\n",myargv[k]); break; } } // [RH] Copied this from BOOM 2.02: // // DoLooseFiles // // Take any file names on the command line before the first switch parm // and insert the appropriate -file, -deh or -playdemo switch in front // of them. // // Note that more than one -file, etc. entry on the command line won't // work, so we have to go get all the valid ones if any that show up // after the loose ones. This means that boom fred.wad -file wilma // will still load fred.wad and wilma.wad, in that order. // The response file code kludges up its own version of myargv[] and // unfortunately we have to do the same here because that kludge only // happens if there _is_ a response file. Truth is, it's more likely // that there will be a need to do one or the other so it probably // isn't important. We'll point off to the original argv[], or the // area allocated in FindResponseFile, or our own areas from copystrings. // static void DoLooseFiles (void) { char *wads[MAXARGVS]; // store the respective loose filenames char *lmps[MAXARGVS]; char *dehs[MAXARGVS]; int wadcount = 0; // count the loose filenames int lmpcount = 0; int dehcount = 0; int i,j,p; char **tmyargv; // use these to recreate the argv array int tmyargc; for (i=1; i < myargc; i++) { if (*myargv[i] == '-' || *myargv[i] == '+') break; // quit at first switch // so now we must have a loose file. Find out what kind and store it. j = strlen(myargv[i]); if (!stricmp(&myargv[i][j-4], ".wad")) wads[wadcount++] = copystring (myargv[i]); if (!stricmp(&myargv[i][j-4], ".lmp")) lmps[lmpcount++] = copystring (myargv[i]); if (!stricmp(&myargv[i][j-4], ".deh")) dehs[dehcount++] = copystring (myargv[i]); if (!stricmp(&myargv[i][j-4], ".bex")) dehs[dehcount++] = copystring (myargv[i]); if (myargv[i][j-4] != '.') // assume wad if no extension wads[wadcount++] = copystring (myargv[i]); *myargv[i] = '\0'; // nuke that entry so it won't repeat later } // Now, if we didn't find any loose files, we can just leave. if (wadcount + lmpcount + dehcount == 0) return; // ******* early return **** if ((p = M_CheckParm ("-file"))) { *myargv[p] = '\0'; // nuke the entry while (++p != myargc && *myargv[p] != '-' && *myargv[p] != '+') { wads[wadcount++] = copystring (myargv[p]); *myargv[p] = '\0'; // null any we find and save } } if ((p = M_CheckParm ("-deh"))) { *myargv[p] = '\0'; // nuke the entry while (++p != myargc && *myargv[p] != '-' && *myargv[p] != '+') { dehs[dehcount++] = copystring (myargv[p]); *myargv[p] = '\0'; // null any we find and save } } if ((p = M_CheckParm ("-playdemo"))) { *myargv[p] = '\0'; // nuke the entry while (++p != myargc && *myargv[p] != '-' && *myargv[p] != '+') { lmps[lmpcount++] = copystring (myargv[p]); *myargv[p] = '\0'; // null any we find and save } } // Now go back and redo the whole myargv array with our stuff in it. // First, create a new myargv array to copy into tmyargv = calloc(sizeof(char *), MAXARGVS); tmyargv[0] = myargv[0]; // invocation tmyargc = 1; // put our stuff into it if (wadcount > 0) { tmyargv[tmyargc++] = copystring ("-file"); // put the switch in for (i=0;i 0) { tmyargv[tmyargc++] = copystring ("-deh"); for (i=0;i 0) { tmyargv[tmyargc++] = copystring ("-playdemo"); for (i=0;ivalue < 0.25) { SetCVarFloat (var, 0.25); } else if (var->value > 1) { SetCVarFloat (var, 1); } else { floop = ((int)(var->value * 4) << MF_TRANSLUCSHIFT) & MF_TRANSLUCBITS; mobjinfo[MT_SKULL].flags = (mobjinfo[MT_SKULL].flags & ~MF_TRANSLUCBITS) | floop; // Find all the lost souls in the world and change them, also. currentthinker = thinkercap.next; if (!currentthinker) return; while (currentthinker != &thinkercap) { if ( (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker) && ((mobj_t *)currentthinker)->type == MT_SKULL ) ((mobj_t *)currentthinker)->flags = (((mobj_t *)currentthinker)->flags & ~MF_TRANSLUCBITS) | floop; currentthinker = currentthinker->next; } } } // // D_DoomMain // void D_DoomMain (void) { int p, flags; char file[256]; gamestate = GS_STARTUP; // [RH] Initialize the minilzo package. if (lzo_init () != LZO_E_OK) I_FatalError ("Could not initialize LZO routines"); C_InstallCommands (); M_LoadDefaults (); // load before initing other systems // [RH] do all +set commands on the command line C_ExecCmdLineParams (true); // [RH] Set default cvar values. These will // be overridden by the configfile. C_SetCVars (); { cvar_t *var = cvar ("transsouls", "0.75", CVAR_ARCHIVE|CVAR_CALLBACK); var->u.callback = TransSoulsCallback; TransSoulsCallback (var); } FindResponseFile (); DoLooseFiles(); // Ty 08/29/98 - handle "loose" files on command line { // [RH] Make sure zdoom.wad is always loaded, // as it contains stuff we need. char *zdoomwad = Z_Malloc (strlen (progdir) + 10, PU_STATIC, 0); sprintf (zdoomwad, "%szdoom.wad", progdir); D_AddFile (zdoomwad); sprintf (zdoomwad, "%szvox.wad", progdir); D_AddFile (zdoomwad); Z_Free (zdoomwad); } I_SetTitleString (IdentifyVersion ()); // [RH] Add any .wad files in the skins directory { char skinname[256]; findstate_t findstate; long handle; int stuffstart; stuffstart = sprintf (skinname, "%sskins/", progdir); strcpy (skinname + stuffstart, "*.wad"); if ((handle = I_FindFirst (skinname, &findstate)) != -1) { do { if (!(I_FindAttr (&findstate) & FA_DIREC)) { strcpy (skinname + stuffstart, I_FindName (&findstate)); D_AddFile (skinname); } } while (I_FindNext (handle, &findstate) == 0); I_FindClose (handle); } } modifiedgame = false; p = M_CheckParm ("-file"); if (p) { // the parms after p are wadfile/lump names, // until end of parms or another - preceded parm modifiedgame = true; // homebrew levels while (++p != myargc && myargv[p][0] != '-' && myargv[p][0] != '+') D_AddFile (myargv[p]); } if (!(p = M_CheckParm ("-playdemo")) ) if (!(p = M_CheckParm ("-timedemo")) ) { if ( (p = M_CheckParm ("-fastdemo")) ) fastdemo = true; } W_InitMultipleFiles (&wadfiles); // [RH] Moved these up here so that we can do most of our // startup output in a fullscreen console. CT_Init (); I_Init (); I_InitGraphics (); V_Init (); // [RH] Initialize configurable strings. D_InitStrings (); // [RH] Apply any DeHackEd patch { int hack; cvar_t *autopatch; hack = M_CheckParm ("-deh"); if (hack && hack < myargc - 1) // Use patch from command line DoDehPatch (myargv[hack + 1], false); else { autopatch = cvar ("def_patch", "", CVAR_ARCHIVE); if (FileExists (autopatch->string)) // Use patch specified by def_patch. // (Any patches in a PWAD take precedence.) DoDehPatch (autopatch->string, true); else DoDehPatch (NULL, true); // See if there's a patch in a PWAD } } // [RH] User-configurable startup strings. Because BOOM does. if (STARTUP1[0]) Printf (PRINT_HIGH, "%s\n", STARTUP1); if (STARTUP2[0]) Printf (PRINT_HIGH, "%s\n", STARTUP2); if (STARTUP3[0]) Printf (PRINT_HIGH, "%s\n", STARTUP3); if (STARTUP4[0]) Printf (PRINT_HIGH, "%s\n", STARTUP4); if (STARTUP5[0]) Printf (PRINT_HIGH, "%s\n", STARTUP5); flags = (int)dmflagsvar->value; dmflagsvar->u.callback = DMFlagsCallback; if (M_CheckParm ("-nomonsters")) flags |= DF_NO_MONSTERS; if (M_CheckParm ("-respawn")) flags |= DF_MONSTERS_RESPAWN; if (M_CheckParm ("-fast")) flags |= DF_FAST_MONSTERS; devparm = M_CheckParm ("-devparm"); if (M_CheckParm ("-altdeath")) { SetCVarFloat (deathmatch, 1.0f); flags |= DF_ITEMS_RESPAWN; } else if (M_CheckParm ("-deathmatch")) { SetCVarFloat (deathmatch, 1.0f); flags |= DF_WEAPONS_STAY; } SetCVarFloat (dmflagsvar, (float)flags); // get skill / episode / map from parms strcpy (startmap, gamemode == commercial ? "MAP01" : "E1M1"); autostart = false; p = M_CheckParm ("-skill"); if (p && p < myargc-1) { SetCVarFloat (gameskill, (float)(myargv[p+1][0]-'1')); autostart = true; } p = M_CheckParm ("-warp"); if (p && p < myargc-1) { int ep, map; if (gamemode == commercial) { ep = 1; map = atoi (myargv[p+1]); } else { ep = myargv[p+1][0]-'0'; map = myargv[p+2][0]-'0'; } strncpy (startmap, CalcMapName (ep, map), 8); autostart = true; } // [RH] Hack to handle +map p = M_CheckParm ("+map"); if (p && p < myargc-1) { strncpy (startmap, myargv[p+1], 8); myargv[p][0] = '-'; autostart = true; } if (devparm) Printf (PRINT_HIGH, Strings[0].builtin); // D_DEVSTR if (M_CheckParm("-cdrom")) { Printf (PRINT_HIGH, Strings[1].builtin); // D_CDROM mkdir ("c:\\zdoomdat", 0); } // turbo option // [RH] (Also exists as a cvar now.) { cvar_t *turbo = cvar ("turbo", "0", CVAR_CALLBACK); float tval; turbo->u.callback = TurboCallback; if ( (p=M_CheckParm ("-turbo")) ) { if (p < myargc - 1) tval = (float)atof (myargv[p+1]); else tval = 200.0f; Printf (PRINT_HIGH, "turbo scale: %g%%\n", tval); } else { tval = 100.0f; } SetCVarFloat (turbo, tval); } p = M_CheckParm ("-timer"); if (p && p < myargc-1) { double time = atof (myargv[p+1]); Printf (PRINT_HIGH, "Levels will end after %g minute%s.\n", time, time > 1 ? "s" : ""); SetCVarFloat (timelimit, (float)time); } p = M_CheckParm ("-avg"); if (p && p < myargc-1) { Printf (PRINT_HIGH, "Austin Virtual Gaming: Levels will end after 20 minutes\n"); SetCVarFloat (timelimit, 20); } // [RH] Now that all text strings are set up, // insert them into the level and cluster data. G_SetLevelStrings (); // [RH] Parse through all loaded mapinfo lumps G_ParseMapInfo (); // [RH] Parse any SNDINFO lumps S_ParseSndInfo(); // Check for -file in shareware // [RH] Don't check for a bunch of lumps not found in shareware. if (modifiedgame && gamemode == shareware) I_Error("\nYou cannot -file with the shareware version. Register!"); #if 0 // Iff additonal PWAD files are used, print modified banner if (modifiedgame) { /*m*/Printf (PRINT_HIGH, "===========================================================================\n" "ATTENTION: This version of DOOM has been modified. If you would like to\n" "get a copy of the original game, call 1-800-IDGAMES or see the readme file.\n" " You will not receive technical support for modified games.\n" "===========================================================================\n" ); } // Check and print which version is executed. switch ( gamemode ) { case shareware: case undetermined: Printf (PRINT_HIGH, "===========================================================================\n" " Shareware!\n" "===========================================================================\n" ); break; case registered: case retail: case commercial: Printf (PRINT_HIGH, "===========================================================================\n" " Commercial product - do not distribute!\n" " Please report software piracy to the SPA: 1-800-388-PIR8\n" "===========================================================================\n" ); break; default: // Ouch. break; } #endif Printf (PRINT_HIGH, "M_Init: Init miscellaneous info.\n"); M_Init (); Printf (PRINT_HIGH, "R_Init: Init DOOM refresh daemon"); R_Init (); Printf (PRINT_HIGH, "\nP_Init: Init Playloop state."); P_Init (); Printf (PRINT_HIGH, "\nS_Init: Setting up sound.\n"); S_Init ((int)snd_SfxVolume->value /* *8 */, snd_MusicVolume->value /* *8*/ ); Printf (PRINT_HIGH, "D_CheckNetGame: Checking network game status.\n"); D_CheckNetGame (); Printf (PRINT_HIGH, "ST_Init: Init status bar.\n"); ST_Init (); // start the apropriate game based on parms p = M_CheckParm ("-record"); if (p && p < myargc-1) { G_RecordDemo (myargv[p+1]); autostart = true; } p = M_CheckParm ("-playdemo"); if (p && p < myargc-1) { char blah[256]; singledemo = true; // quit after one demo strcpy (blah, myargv[p+1]); FixPathSeperator (blah); ExtractFileBase (blah, file); G_DeferedPlayDemo (file); D_ErrorLoop (); // never returns } p = M_CheckParm ("-fastdemo"); if (p && p < myargc-1) { extern BOOL timingdemo; singledemo = true; // quit after one demo timingdemo = true; // show stats after quit G_DeferedPlayDemo(myargv[p+1]); D_ErrorLoop(); // never returns } p = M_CheckParm ("-timedemo"); if (p && p < myargc-1) { G_TimeDemo (myargv[p+1]); D_ErrorLoop (); // never returns } p = M_CheckParm ("-loadgame"); if (p && p < myargc-1) { G_BuildSaveName (file, myargv[p+1][0] - '0'); G_LoadGame (file); } // [RH] Initialize items. Still only used for the give command. :-( InitItems (); // [RH] Lock any cvars that should be locked now that we're // about to begin the game. C_EnableNoSet (); // [RH] Now that all game subsystems have been initialized, // do all commands on the command line other than +set C_ExecCmdLineParams (false); if (gameaction != ga_loadgame) { BorderNeedRefresh = true; if (autostart || netgame) { G_InitNew (startmap); } else { D_StartTitle (); // start up intro loop } } if (demorecording) G_BeginRecording (); if (M_CheckParm ("-debugfile")) { char filename[20]; sprintf (filename,"debug%i.txt",consoleplayer); Printf (PRINT_HIGH, "debug output to: %s\n",filename); debugfile = fopen (filename,"w"); } atexit (D_QuitNetGame); // killough D_ErrorLoop (); // [RH] Wrap D_DoomLoop inside another function }