/* Emacs style mode select -*- C++ -*- *----------------------------------------------------------------------------- * * * PrBoom: a Doom port merged with LxDoom and LSDLDoom * based on BOOM, a modified and improved DOOM engine * Copyright (C) 1999 by * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman * Copyright (C) 1999-2004 by * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze * Copyright 2005, 2006 by * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * 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 _MSC_VER #define F_OK 0 /* Check for file existence */ #define W_OK 2 /* Check for write permission */ #define R_OK 4 /* Check for read permission */ #include #include #else #include #endif #include #include #include #include "doomdef.h" #include "doomtype.h" #include "doomstat.h" #include "d_net.h" #include "dstrings.h" #include "sounds.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 "p_checksum.h" #include "i_main.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_draw.h" #include "r_main.h" #include "r_fps.h" #include "d_main.h" #include "d_deh.h" // Ty 04/08/98 - Externalizations #include "lprintf.h" // jff 08/03/98 - declaration of lprintf #include "am_map.h" void GetFirstMap(int *ep, int *map); // Ty 08/29/98 - add "-warp x" functionality static void D_PageDrawer(void); // CPhipps - removed wadfiles[] stuff boolean devparm; // started game with -devparm // jff 1/24/98 add new versions of these variables to remember command line boolean clnomonsters; // checkparm of -nomonsters boolean clrespawnparm; // checkparm of -respawn boolean clfastparm; // checkparm of -fast // jff 1/24/98 end definition of command line version of play mode switches boolean nomonsters; // working -nomonsters boolean respawnparm; // working -respawn boolean fastparm; // working -fast boolean singletics = false; // debug flag to cancel adaptiveness //jff 1/22/98 parms for disabling music and sound boolean nosfxparm; boolean nomusicparm; //jff 4/18/98 extern boolean inhelpscreens; skill_t startskill; int startepisode; int startmap; boolean autostart; FILE *debugfile; int ffmap; boolean advancedemo; char wadfile[PATH_MAX+1]; // primary wad file char mapdir[PATH_MAX+1]; // directory of development maps char baseiwad[PATH_MAX+1]; // jff 3/23/98: iwad directory char basesavegame[PATH_MAX+1]; // killough 2/16/98: savegame directory //jff 4/19/98 list of standard IWAD names const char *const standard_iwads[]= { "doom2f.wad", "doom2.wad", "plutonia.wad", "tnt.wad", "doom.wad", "doom1.wad", "doomu.wad", /* CPhipps - alow doomu.wad */ "freedoom.wad", /* wart@kobold.org: added freedoom for Fedora Extras */ }; static const int nstandard_iwads = sizeof standard_iwads/sizeof*standard_iwads; /* * D_PostEvent - Event handling * * Called by I/O functions when an event is received. * Try event handlers for each code area in turn. * cph - in the true spirit of the Boom source, let the * short ciruit operator madness begin! */ void D_PostEvent(event_t *ev) { /* cph - suppress all input events at game start * FIXME: This is a lousy kludge */ if (gametic < 3) return; M_Responder(ev) || (gamestate == GS_LEVEL && ( HU_Responder(ev) || ST_Responder(ev) || AM_Responder(ev) ) ) || G_Responder(ev); } // // D_Wipe // // CPhipps - moved the screen wipe code from D_Display to here // The screens to wipe between are already stored, this just does the timing // and screen updating static void D_Wipe(void) { boolean done; int wipestart = I_GetTime () - 1; do { int nowtime, tics; do { I_uSleep(5000); // CPhipps - don't thrash cpu in this loop nowtime = I_GetTime(); tics = nowtime - wipestart; } while (!tics); wipestart = nowtime; done = wipe_ScreenWipe(tics); I_UpdateNoBlit(); M_Drawer(); // menu is drawn even on top of wipes I_FinishUpdate(); // page flip or blit buffer } while (!done); } // // 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 boolean setsizeneeded; extern int showMessages; void D_Display (void) { static boolean inhelpscreensstate = false; static boolean isborderstate = false; static boolean borderwillneedredraw = false; static gamestate_t oldgamestate = -1; boolean wipe; boolean viewactive = false, isborder = false; if (nodrawers) // for comparative timing / profiling return; if (!I_StartDisplay()) return; // save the current screen if about to wipe if ((wipe = gamestate != wipegamestate) && (V_GetMode() != VID_MODEGL)) wipe_StartScreen(); if (gamestate != GS_LEVEL) { // Not a level switch (oldgamestate) { case -1: case GS_LEVEL: V_SetPalette(0); // cph - use default (basic) palette default: break; } switch (gamestate) { case GS_INTERMISSION: WI_Drawer(); break; case GS_FINALE: F_Drawer(); break; case GS_DEMOSCREEN: D_PageDrawer(); break; default: break; } } else if (gametic != basetic) { // In a level boolean redrawborderstuff; HU_Erase(); if (setsizeneeded) { // change the view size if needed R_ExecuteSetViewSize(); oldgamestate = -1; // force background redraw } // Work out if the player view is visible, and if there is a border viewactive = (!(automapmode & am_active) || (automapmode & am_overlay)) && !inhelpscreens; isborder = viewactive ? (viewheight != SCREENHEIGHT) : (!inhelpscreens && (automapmode & am_active)); if (oldgamestate != GS_LEVEL) { R_FillBackScreen (); // draw the pattern into the back screen redrawborderstuff = isborder; } else { // CPhipps - // If there is a border, and either there was no border last time, // or the border might need refreshing, then redraw it. redrawborderstuff = isborder && (!isborderstate || borderwillneedredraw); // The border may need redrawing next time if the border surrounds the screen, // and there is a menu being displayed borderwillneedredraw = menuactive && isborder && viewactive && (viewwidth != SCREENWIDTH); } if (redrawborderstuff || (V_GetMode() == VID_MODEGL)) R_DrawViewBorder(); // Now do the drawing if (viewactive) R_RenderPlayerView (&players[displayplayer]); if (automapmode & am_active) AM_Drawer(); ST_Drawer((viewheight != SCREENHEIGHT) || ((automapmode & am_active) && !(automapmode & am_overlay)), redrawborderstuff); if (V_GetMode() != VID_MODEGL) R_DrawViewBorder(); HU_Drawer(); } inhelpscreensstate = inhelpscreens; isborderstate = isborder; oldgamestate = wipegamestate = gamestate; // draw pause pic if (paused) { // Simplified the "logic" here and no need for x-coord caching - POPE V_DrawNamePatch((320 - V_NamePatchWidth("M_PAUSE"))/2, 4, 0, "M_PAUSE", CR_DEFAULT, VPT_STRETCH); } // menus go directly to the screen M_Drawer(); // menu is drawn even on top of everything #ifdef HAVE_NET NetUpdate(); // send out any new accumulation #else D_BuildNewTiccmds(); #endif // normal update if (!wipe || (V_GetMode() == VID_MODEGL)) I_FinishUpdate (); // page flip or blit buffer else { // wipe update wipe_EndScreen(); D_Wipe(); } I_EndDisplay(); //e6y: don't thrash cpu during pausing if (paused) { I_uSleep(1000); } } // CPhipps - Auto screenshot Variables static int auto_shot_count, auto_shot_time; static const char *auto_shot_fname; // // 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 // static void D_DoomLoop(void) { for (;;) { WasRenderedInTryRunTics = false; // frame syncronous IO operations I_StartFrame (); if (ffmap == gamemap) ffmap = 0; // process one or more tics if (singletics) { I_StartTic (); G_BuildTiccmd (&netcmds[consoleplayer][maketic%BACKUPTICS]); if (advancedemo) D_DoAdvanceDemo (); M_Ticker (); G_Ticker (); P_Checksum(gametic); gametic++; maketic++; } else TryRunTics (); // will run at least one tic // killough 3/16/98: change consoleplayer to displayplayer if (players[displayplayer].mo) // cph 2002/08/10 S_UpdateSounds(players[displayplayer].mo);// move positional sounds if (V_GetMode() == VID_MODEGL ? !movement_smooth || !WasRenderedInTryRunTics : !movement_smooth || !WasRenderedInTryRunTics || gamestate != wipegamestate ) { // Update display, next frame, with current state. D_Display(); } // CPhipps - auto screenshot if (auto_shot_fname && !--auto_shot_count) { auto_shot_count = auto_shot_time; M_DoScreenShot(auto_shot_fname); } } } // // DEMO LOOP // static int demosequence; // killough 5/2/98: made static static int pagetic; static const char *pagename; // CPhipps - const // // D_PageTicker // Handles timing for warped projection // void D_PageTicker(void) { if (--pagetic < 0) D_AdvanceDemo(); } // // D_PageDrawer // static void D_PageDrawer(void) { // proff/nicolas 09/14/98 -- now stretchs bitmaps to fullscreen! // CPhipps - updated for new patch drawing // proff - added M_DrawCredits if (pagename) { V_DrawNamePatch(0, 0, 0, pagename, CR_DEFAULT, VPT_STRETCH); } else M_DrawCredits(); } // // D_AdvanceDemo // Called after each demo or intro demosequence finishes // void D_AdvanceDemo (void) { advancedemo = true; } /* killough 11/98: functions to perform demo sequences * cphipps 10/99: constness fixes */ static void D_SetPageName(const char *name) { pagename = name; } static void D_DrawTitle1(const char *name) { S_StartMusic(mus_intro); pagetic = (TICRATE*170)/35; D_SetPageName(name); } static void D_DrawTitle2(const char *name) { S_StartMusic(mus_dm2ttl); D_SetPageName(name); } /* killough 11/98: tabulate demo sequences */ static struct { void (*func)(const char *); const char *name; } const demostates[][4] = { { {D_DrawTitle1, "TITLEPIC"}, {D_DrawTitle1, "TITLEPIC"}, {D_DrawTitle2, "TITLEPIC"}, {D_DrawTitle1, "TITLEPIC"}, }, { {G_DeferedPlayDemo, "demo1"}, {G_DeferedPlayDemo, "demo1"}, {G_DeferedPlayDemo, "demo1"}, {G_DeferedPlayDemo, "demo1"}, }, { {D_SetPageName, NULL}, {D_SetPageName, NULL}, {D_SetPageName, NULL}, {D_SetPageName, NULL}, }, { {G_DeferedPlayDemo, "demo2"}, {G_DeferedPlayDemo, "demo2"}, {G_DeferedPlayDemo, "demo2"}, {G_DeferedPlayDemo, "demo2"}, }, { {D_SetPageName, "HELP2"}, {D_SetPageName, "HELP2"}, {D_SetPageName, "CREDIT"}, {D_DrawTitle1, "TITLEPIC"}, }, { {G_DeferedPlayDemo, "demo3"}, {G_DeferedPlayDemo, "demo3"}, {G_DeferedPlayDemo, "demo3"}, {G_DeferedPlayDemo, "demo3"}, }, { {NULL}, {NULL}, {NULL}, {D_SetPageName, "CREDIT"}, }, { {NULL}, {NULL}, {NULL}, {G_DeferedPlayDemo, "demo4"}, }, { {NULL}, {NULL}, {NULL}, {NULL}, } }; /* * This cycles through the demo sequences. * killough 11/98: made table-driven */ void D_DoAdvanceDemo(void) { players[consoleplayer].playerstate = PST_LIVE; /* not reborn */ advancedemo = usergame = paused = false; gameaction = ga_nothing; pagetic = TICRATE * 11; /* killough 11/98: default behavior */ gamestate = GS_DEMOSCREEN; if (netgame && !demoplayback) { demosequence = 0; } else if (!demostates[++demosequence][gamemode].func) demosequence = 0; demostates[demosequence][gamemode].func (demostates[demosequence][gamemode].name); } // // D_StartTitle // void D_StartTitle (void) { gameaction = ga_nothing; demosequence = -1; D_AdvanceDemo(); } // // D_AddFile // // Rewritten by Lee Killough // // Ty 08/29/98 - add source parm to indicate where this came from // CPhipps - static, const char* parameter // - source is an enum // - modified to allocate & use new wadfiles array void D_AddFile (const char *file, wad_source_t source) { char *gwa_filename=NULL; wadfiles = realloc(wadfiles, sizeof(*wadfiles)*(numwadfiles+1)); wadfiles[numwadfiles].name = AddDefaultExtension(strcpy(malloc(strlen(file)+5), file), ".wad"); wadfiles[numwadfiles].src = source; // Ty 08/29/98 numwadfiles++; // proff: automatically try to add the gwa files // proff - moved from w_wad.c gwa_filename=AddDefaultExtension(strcpy(malloc(strlen(file)+5), file), ".wad"); if (strlen(gwa_filename)>4) if (!strcasecmp(gwa_filename+(strlen(gwa_filename)-4),".wad")) { char *ext; ext = &gwa_filename[strlen(gwa_filename)-4]; ext[1] = 'g'; ext[2] = 'w'; ext[3] = 'a'; wadfiles = realloc(wadfiles, sizeof(*wadfiles)*(numwadfiles+1)); wadfiles[numwadfiles].name = gwa_filename; wadfiles[numwadfiles].src = source; // Ty 08/29/98 numwadfiles++; } } // killough 10/98: support -dehout filename // cph - made const, don't cache results static const char *D_dehout(void) { int p = M_CheckParm("-dehout"); if (!p) p = M_CheckParm("-bexout"); return (p && ++p < myargc ? myargv[p] : NULL); } // // CheckIWAD // // Verify a file is indeed tagged as an IWAD // Scan its lumps for levelnames and return gamemode as indicated // Detect missing wolf levels in DOOM II // // The filename to check is passed in iwadname, the gamemode detected is // returned in gmode, hassec returns the presence of secret levels // // jff 4/19/98 Add routine to test IWAD for validity and determine // the gamemode from it. Also note if DOOM II, whether secret levels exist // CPhipps - const char* for iwadname, made static static void CheckIWAD(const char *iwadname,GameMode_t *gmode,boolean *hassec) { if ( !access (iwadname,R_OK) ) { int ud=0,rg=0,sw=0,cm=0,sc=0; FILE* fp; // Identify IWAD correctly if ((fp = fopen(iwadname, "rb"))) { wadinfo_t header; // read IWAD header if (fread(&header, sizeof(header), 1, fp) == 1 && !strncmp(header.identification, "IWAD", 4)) { size_t length; filelump_t *fileinfo; // read IWAD directory header.numlumps = LONG(header.numlumps); header.infotableofs = LONG(header.infotableofs); length = header.numlumps; fileinfo = malloc(length*sizeof(filelump_t)); if (fseek (fp, header.infotableofs, SEEK_SET) || fread (fileinfo, sizeof(filelump_t), length, fp) != length || fclose(fp)) I_Error("CheckIWAD: failed to read directory %s",iwadname); // scan directory for levelname lumps while (length--) if (fileinfo[length].name[0] == 'E' && fileinfo[length].name[2] == 'M' && fileinfo[length].name[4] == 0) { if (fileinfo[length].name[1] == '4') ++ud; else if (fileinfo[length].name[1] == '3') ++rg; else if (fileinfo[length].name[1] == '2') ++rg; else if (fileinfo[length].name[1] == '1') ++sw; } else if (fileinfo[length].name[0] == 'M' && fileinfo[length].name[1] == 'A' && fileinfo[length].name[2] == 'P' && fileinfo[length].name[5] == 0) { ++cm; if (fileinfo[length].name[3] == '3') if (fileinfo[length].name[4] == '1' || fileinfo[length].name[4] == '2') ++sc; } free(fileinfo); } else // missing IWAD tag in header I_Error("CheckIWAD: IWAD tag %s not present", iwadname); } else // error from open call I_Error("CheckIWAD: Can't open IWAD %s", iwadname); // Determine game mode from levels present // Must be a full set for whichever mode is present // Lack of wolf-3d levels also detected here *gmode = indetermined; *hassec = false; if (cm>=30) { *gmode = commercial; *hassec = sc>=2; } else if (ud>=9) *gmode = retail; else if (rg>=18) *gmode = registered; else if (sw>=9) *gmode = shareware; } else // error from access call I_Error("CheckIWAD: IWAD %s not readable", iwadname); } // NormalizeSlashes // // Remove trailing slashes, translate backslashes to slashes // The string to normalize is passed and returned in str // // jff 4/19/98 Make killoughs slash fixer a subroutine // static void NormalizeSlashes(char *str) { int l; // killough 1/18/98: Neater / \ handling. // Remove trailing / or \ to prevent // /\ \/ \\, and change \ to / if (!str || !(l = strlen(str))) return; if (str[--l]=='/' || str[l]=='\\') // killough 1/18/98 str[l]=0; while (l--) if (str[l]=='\\') str[l]='/'; } /* * FindIWADFIle * * Search for one of the standard IWADs * CPhipps - static, proper prototype * - 12/1999 - rewritten to use I_FindFile */ static char *FindIWADFile(void) { int i; char * iwad = NULL; i = M_CheckParm("-iwad"); if (i && (++i < myargc)) { iwad = I_FindFile(myargv[i], ".wad"); } else { for (i=0; !iwad && i PATH_MAX-12) p = NULL; strcpy(basesavegame,(p == NULL) ? I_DoomExeDir() : p); } if ((i=M_CheckParm("-save")) && i=10 && !strnicmp(iwad+i-10,"doom2f.wad",10)) language=french; else if (i>=7 && !strnicmp(iwad+i-7,"tnt.wad",7)) gamemission = pack_tnt; else if (i>=12 && !strnicmp(iwad+i-12,"plutonia.wad",12)) gamemission = pack_plut; break; default: gamemission = none; break; } if (gamemode == indetermined) //jff 9/3/98 use logical output routine lprintf(LO_WARN,"Unknown Game Version, may not work\n"); D_AddFile(iwad,source_iwad); free(iwad); } else I_Error("IdentifyVersion: IWAD not found\n"); } // killough 5/3/98: old code removed // // Find a Response File // #define MAXARGVS 100 static void FindResponseFile (void) { int i; for (i = 1;i < myargc;i++) if (myargv[i][0] == '@') { int size; int index; int indexinfile; byte *file = NULL; const char **moreargs = malloc(myargc * sizeof(const char*)); const char **newargv; // proff 04/05/2000: Added for searching responsefile char fname[PATH_MAX+1]; strcpy(fname,&myargv[i][1]); AddDefaultExtension(fname,".rsp"); // READ THE RESPONSE FILE INTO MEMORY // proff 04/05/2000: changed for searching responsefile // cph 2002/08/09 - use M_ReadFile for simplicity size = M_ReadFile(fname, &file); // proff 04/05/2000: Added for searching responsefile if (size < 0) { strcat(strcpy(fname,I_DoomExeDir()),&myargv[i][1]); AddDefaultExtension(fname,".rsp"); size = M_ReadFile(fname, &file); } if (size < 0) { /* proff 04/05/2000: Changed from LO_FATAL * proff 04/05/2000: Simply removed the exit(1); * cph - made fatal, don't drop through and SEGV */ I_Error("No such response file: %s",fname); } //jff 9/3/98 use logical output routine lprintf(LO_CONFIRM,"Found response file %s\n",fname); // proff 04/05/2000: Added check for empty rsp file if (size<=0) { int k; lprintf(LO_ERROR,"\nResponse file empty!\n"); newargv = calloc(sizeof(char *),MAXARGVS); newargv[0] = myargv[0]; for (k = 1,index = 1;k < myargc;k++) { if (i!=k) newargv[index++] = myargv[k]; } myargc = index; myargv = newargv; return; } // KEEP ALL CMDLINE ARGS FOLLOWING @RESPONSEFILE ARG memcpy((void *)moreargs,&myargv[i+1],(index = myargc - i - 1) * sizeof(myargv[0])); { const char *firstargv = myargv[0]; newargv = calloc(sizeof(char *),MAXARGVS); newargv[0] = firstargv; } { byte *infile = file; indexinfile = 0; indexinfile++; // SKIP PAST ARGV[0] (KEEP IT) do { while (size > 0 && isspace(*infile)) { infile++; size--; } if (size > 0) { char *s = malloc(size+1); char *p = s; int quoted = 0; while (size > 0) { // Whitespace terminates the token unless quoted if (!quoted && isspace(*infile)) break; if (*infile == '\"') { // Quotes are removed but remembered infile++; size--; quoted ^= 1; } else { *p++ = *infile++; size--; } } if (quoted) I_Error("Runaway quoted string in response file"); // Terminate string, realloc and add to argv *p = 0; newargv[indexinfile++] = realloc(s,strlen(s)+1); } } while(size > 0); } free(file); memcpy((void *)&newargv[indexinfile],moreargs,index*sizeof(moreargs[0])); free((void *)moreargs); myargc = indexinfile+index; myargv = newargv; // DISPLAY ARGS //jff 9/3/98 use logical output routine lprintf(LO_CONFIRM,"%d command-line args:\n",myargc); for (index=1;index 0) { tmyargv[tmyargc++] = strdup("-file"); // put the switch in for (i=0;i 0) { tmyargv[tmyargc++] = strdup("-deh"); for (i=0;i 0) { tmyargv[tmyargc++] = strdup("-playdemo"); for (i=0;i 400) scale = 400; //jff 9/3/98 use logical output routine lprintf (LO_CONFIRM,"turbo scale: %i%%\n",scale); forwardmove[0] = forwardmove[0]*scale/100; forwardmove[1] = forwardmove[1]*scale/100; sidemove[0] = sidemove[0]*scale/100; sidemove[1] = sidemove[1]*scale/100; } modifiedgame = false; // get skill / episode / map from parms startskill = sk_none; // jff 3/24/98 was sk_medium, just note not picked startepisode = 1; startmap = 1; autostart = false; if ((p = M_CheckParm ("-skill")) && p < myargc-1) { startskill = myargv[p+1][0]-'1'; autostart = true; } if ((p = M_CheckParm ("-episode")) && p < myargc-1) { startepisode = myargv[p+1][0]-'0'; startmap = 1; autostart = true; } if ((p = M_CheckParm ("-timer")) && p < myargc-1 && deathmatch) { int time = atoi(myargv[p+1]); //jff 9/3/98 use logical output routine lprintf(LO_CONFIRM,"Levels will end after %d minute%s.\n", time, time>1 ? "s" : ""); } if ((p = M_CheckParm ("-avg")) && p < myargc-1 && deathmatch) //jff 9/3/98 use logical output routine lprintf(LO_CONFIRM,"Austin Virtual Gaming: Levels will end after 20 minutes\n"); if ((p = M_CheckParm ("-warp")) || // killough 5/2/98 (p = M_CheckParm ("-wart"))) // Ty 08/29/98 - moved this check later so we can have -warp alone: && p < myargc-1) { startmap = 0; // Ty 08/29/98 - allow "-warp x" to go to first map in wad(s) autostart = true; // Ty 08/29/98 - move outside the decision tree if (gamemode == commercial) { if (p < myargc-1) startmap = atoi(myargv[p+1]); // Ty 08/29/98 - add test if last parm } else // 1/25/98 killough: fix -warp xxx from crashing Doom 1 / UD { if (p < myargc-2) { startepisode = atoi(myargv[++p]); startmap = atoi(myargv[p+1]); } } } // Ty 08/29/98 - later we'll check for startmap=0 and autostart=true // as a special case that -warp * was used. Actually -warp with any // non-numeric will do that but we'll only document "*" //jff 1/22/98 add command line parms to disable sound and music { int nosound = M_CheckParm("-nosound"); nomusicparm = nosound || M_CheckParm("-nomusic"); nosfxparm = nosound || M_CheckParm("-nosfx"); } //jff end of sound/music command line parms // killough 3/2/98: allow -nodraw -noblit generally nodrawers = M_CheckParm ("-nodraw"); noblit = M_CheckParm ("-noblit"); //proff 11/22/98: Added setting of viewangleoffset p = M_CheckParm("-viewangle"); if (p) { viewangleoffset = atoi(myargv[p+1]); viewangleoffset = viewangleoffset<0 ? 0 : (viewangleoffset>7 ? 7 : viewangleoffset); viewangleoffset = (8-viewangleoffset) * ANG45; } // init subsystems G_ReloadDefaults(); // killough 3/4/98: set defaults just loaded. // jff 3/24/98 this sets startskill if it was -1 // Video stuff if ((p = M_CheckParm("-width"))) if (myargv[p+1]) desired_screenwidth = atoi(myargv[p+1]); if ((p = M_CheckParm("-height"))) if (myargv[p+1]) desired_screenheight = atoi(myargv[p+1]); if ((p = M_CheckParm("-fullscreen"))) use_fullscreen = 1; if ((p = M_CheckParm("-nofullscreen"))) use_fullscreen = 0; // e6y // New command-line options for setting a window (-window) // or fullscreen (-nowindow) mode temporarily which is not saved in cfg. // It works like "-geom" switch desired_fullscreen = use_fullscreen; if ((p = M_CheckParm("-window"))) desired_fullscreen = 0; if ((p = M_CheckParm("-nowindow"))) desired_fullscreen = 1; { // -geometry handling, change screen size for this session only // e6y: new code by me int w, h; if (!(p = M_CheckParm("-geom"))) p = M_CheckParm("-geometry"); if (!(p && (p+1= MAXLOADFILES) ProcessDehFile(fpath, D_dehout(), 0); else { D_AddFile(fpath,source_auto_load); } modifiedgame = true; free(fpath); } } } // e6y: DEH files preloaded in wrong order // http://sourceforge.net/tracker/index.php?func=detail&aid=1418158&group_id=148658&atid=772943 // The dachaked stuff has been moved from above // ty 03/09/98 do dehacked stuff // Note: do this before any other since it is expected by // the deh patch author that this is actually part of the EXE itself // Using -deh in BOOM, others use -dehacked. // Ty 03/18/98 also allow .bex extension. .bex overrides if both exist. D_BuildBEXTables(); // haleyjd p = M_CheckParm ("-deh"); if (p) { char file[PATH_MAX+1]; // cph - localised // the parms after p are deh/bex file names, // until end of parms or another - preceded parm // Ty 04/11/98 - Allow multiple -deh files in a row while (++p != myargc && *myargv[p] != '-') { AddDefaultExtension(strcpy(file, myargv[p]), ".bex"); if (access(file, F_OK)) // nope { AddDefaultExtension(strcpy(file, myargv[p]), ".deh"); if (access(file, F_OK)) // still nope I_Error("D_DoomMainSetup: Cannot find .deh or .bex file named %s",myargv[p]); } // during the beta we have debug output to dehout.txt ProcessDehFile(file,D_dehout(),0); } } // ty 03/09/98 end of do dehacked stuff // add any files specified on the command line with -file wadfile // to the wad list // killough 1/31/98, 5/2/98: reload hack removed, -wart same as -warp now. if ((p = M_CheckParm ("-file"))) { // 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] != '-') D_AddFile(myargv[p],source_pwad); } if (!(p = M_CheckParm("-playdemo")) || p >= myargc-1) { /* killough */ if ((p = M_CheckParm ("-fastdemo")) && p < myargc-1) /* killough */ fastdemo = true; // run at fastest speed possible else p = M_CheckParm ("-timedemo"); } if (p && p < myargc-1) { char file[PATH_MAX+1]; // cph - localised strcpy(file,myargv[p+1]); AddDefaultExtension(file,".lmp"); // killough D_AddFile (file,source_lmp); //jff 9/3/98 use logical output routine lprintf(LO_CONFIRM,"Playing demo %s\n",file); if ((p = M_CheckParm ("-ffmap")) && p < myargc-1) { ffmap = atoi(myargv[p+1]); } } // internal translucency set to config file value // phares general_translucency = default_translucency; // phares // 1/18/98 killough: Z_Init() call moved to i_main.c // CPhipps - move up netgame init //jff 9/3/98 use logical output routine lprintf(LO_INFO,"D_InitNetGame: Checking for network game.\n"); D_InitNetGame(); //jff 9/3/98 use logical output routine lprintf(LO_INFO,"W_Init: Init WADfiles.\n"); W_Init(); // CPhipps - handling of wadfiles init changed lprintf(LO_INFO,"\n"); // killough 3/6/98: add a newline, by popular demand :) // e6y // option to disable automatic loading of dehacked-in-wad lump if (!M_CheckParm ("-nodeh")) if ((p = W_CheckNumForName("DEHACKED")) != -1) // cph - add dehacked-in-a-wad support ProcessDehFile(NULL, D_dehout(), p); V_InitColorTranslation(); //jff 4/24/98 load color translation lumps // killough 2/22/98: copyright / "modified game" / SPA banners removed // Ty 04/08/98 - Add 5 lines of misc. data, only if nonblank // The expectation is that these will be set in a .bex file //jff 9/3/98 use logical output routine if (*startup1) lprintf(LO_INFO,"%s",startup1); if (*startup2) lprintf(LO_INFO,"%s",startup2); if (*startup3) lprintf(LO_INFO,"%s",startup3); if (*startup4) lprintf(LO_INFO,"%s",startup4); if (*startup5) lprintf(LO_INFO,"%s",startup5); // End new startup strings //jff 9/3/98 use logical output routine lprintf(LO_INFO,"M_Init: Init miscellaneous info.\n"); M_Init(); #ifdef HAVE_NET // CPhipps - now wait for netgame start D_CheckNetGame(); #endif //jff 9/3/98 use logical output routine lprintf(LO_INFO,"R_Init: Init DOOM refresh daemon - "); R_Init(); //jff 9/3/98 use logical output routine lprintf(LO_INFO,"\nP_Init: Init Playloop state.\n"); P_Init(); //jff 9/3/98 use logical output routine lprintf(LO_INFO,"I_Init: Setting up machine state.\n"); I_Init(); //jff 9/3/98 use logical output routine lprintf(LO_INFO,"S_Init: Setting up sound.\n"); S_Init(snd_SfxVolume /* *8 */, snd_MusicVolume /* *8*/ ); //jff 9/3/98 use logical output routine lprintf(LO_INFO,"HU_Init: Setting up heads up display.\n"); HU_Init(); if (!(M_CheckParm("-nodraw") && M_CheckParm("-nosound"))) I_InitGraphics(); //jff 9/3/98 use logical output routine lprintf(LO_INFO,"ST_Init: Init status bar.\n"); ST_Init(); idmusnum = -1; //jff 3/17/98 insure idmus number is blank // CPhipps - auto screenshots if ((p = M_CheckParm("-autoshot")) && (p < myargc-2)) if ((auto_shot_count = auto_shot_time = atoi(myargv[p+1]))) auto_shot_fname = myargv[p+2]; // start the apropriate game based on parms // killough 12/98: // Support -loadgame with -record and reimplement -recordfrom. if ((slot = M_CheckParm("-recordfrom")) && (p = slot+2) < myargc) G_RecordDemo(myargv[p]); else { slot = M_CheckParm("-loadgame"); if ((p = M_CheckParm("-record")) && ++p < myargc) { autostart = true; G_RecordDemo(myargv[p]); } } if ((p = M_CheckParm ("-checksum")) && ++p < myargc) { P_RecordChecksum (myargv[p]); } if ((p = M_CheckParm ("-fastdemo")) && ++p < myargc) { // killough fastdemo = true; // run at fastest speed possible timingdemo = true; // show stats after quit G_DeferedPlayDemo(myargv[p]); singledemo = true; // quit after one demo } else if ((p = M_CheckParm("-timedemo")) && ++p < myargc) { singletics = true; timingdemo = true; // show stats after quit G_DeferedPlayDemo(myargv[p]); singledemo = true; // quit after one demo } else if ((p = M_CheckParm("-playdemo")) && ++p < myargc) { G_DeferedPlayDemo(myargv[p]); singledemo = true; // quit after one demo } if (slot && ++slot < myargc) { slot = atoi(myargv[slot]); // killough 3/16/98: add slot info G_LoadGame(slot, true); // killough 5/15/98: add command flag // cph - no filename } else if (!singledemo) { /* killough 12/98 */ if (autostart || netgame) { G_InitNew(startskill, startepisode, startmap); if (demorecording) G_BeginRecording(); } else D_StartTitle(); // start up intro loop } } // // D_DoomMain // void D_DoomMain(void) { D_DoomMainSetup(); // CPhipps - setup out of main execution stack D_DoomLoop (); // never returns } // // GetFirstMap // // Ty 08/29/98 - determine first available map from the loaded wads and run it // void GetFirstMap(int *ep, int *map) { int i,j; // used to generate map name boolean done = false; // Ty 09/13/98 - to exit inner loops char test[6]; // MAPxx or ExMx plus terminator for testing char name[6]; // MAPxx or ExMx plus terminator for display boolean newlevel = false; // Ty 10/04/98 - to test for new level int ix; // index for lookup strcpy(name,""); // initialize if (*map == 0) // unknown so go search for first changed one { *ep = 1; *map = 1; // default E1M1 or MAP01 if (gamemode == commercial) { for (i=1;!done && i<33;i++) // Ty 09/13/98 - add use of !done { sprintf(test,"MAP%02d",i); ix = W_CheckNumForName(test); if (ix != -1) // Ty 10/04/98 avoid -1 subscript { if (lumpinfo[ix].source == source_pwad) { *map = i; strcpy(name,test); // Ty 10/04/98 done = true; // Ty 09/13/98 newlevel = true; // Ty 10/04/98 } else { if (!*name) // found one, not pwad. First default. strcpy(name,test); } } } } else // one of the others { strcpy(name,"E1M1"); // Ty 10/04/98 - default for display for (i=1;!done && i<5;i++) // Ty 09/13/98 - add use of !done { for (j=1;!done && j<10;j++) // Ty 09/13/98 - add use of !done { sprintf(test,"E%dM%d",i,j); ix = W_CheckNumForName(test); if (ix != -1) // Ty 10/04/98 avoid -1 subscript { if (lumpinfo[ix].source == source_pwad) { *ep = i; *map = j; strcpy(name,test); // Ty 10/04/98 done = true; // Ty 09/13/98 newlevel = true; // Ty 10/04/98 } else { if (!*name) // found one, not pwad. First default. strcpy(name,test); } } } } } //jff 9/3/98 use logical output routine lprintf(LO_CONFIRM,"Auto-warping to first %slevel: %s\n", newlevel ? "new " : "", name); // Ty 10/04/98 - new level test } }