// D_main.c #ifdef __WATCOMC__ #include #include #include #endif #ifdef __NeXT__ #include #endif #ifdef NORMALUNIX #include #include #include #endif #include "doomdef.h" #include "dutils.h" void mprintf(char *string); boolean shareware; // true if only episode 1 present boolean registered; // true if complete version boolean commercial; // true if DOOM II: Hell On Earth boolean french; boolean devparm; // started game with -devparm boolean nomonsters; // checkparm of -nomonsters boolean respawnparm; // checkparm of -respawn boolean fastparm; // checkparm of -fast boolean drone; boolean singletics = false; // debug flag to cancel adaptiveness boolean modifiedgame; // set if homebrew stuff has been added //extern int soundVolume; extern int sfxVolume; extern int musicVolume; extern boolean inhelpscreens; skill_t startskill; int startepisode, startmap; boolean autostart; FILE *debugfile; boolean advancedemo; #define MAXWADFILES 20 char wadfile[1024]; // primary wad file char mapdir[1024]; // directory of development maps char basedefault[1024]; // default file char *wadfiles[MAXWADFILES]; void D_CheckNetGame (void); void D_ProcessEvents (void); void G_BuildTiccmd (ticcmd_t *cmd); void D_DoAdvanceDemo (void); /* =============================================================================== EVENT HANDLING Events are asyncronous inputs generally generated by the game user. Events can be discarded if no responder claims them =============================================================================== */ event_t events[MAXEVENTS]; int eventhead, eventtail; /* ==================== = = D_PostEvent = = Called by the I/O functions when input is detected ==================== */ void D_PostEvent (event_t *ev) { events[eventhead] = *ev; eventhead = (++eventhead)&(MAXEVENTS-1); } /* ==================== = = D_ProcessEvents = = Send all the events of the given timestamp down the responder chain ==================== */ void D_ProcessEvents (void) { event_t *ev; // IF STORE DEMO, DON'T ACCEPT INPUT if (commercial && (W_CheckNumForName("map01")<0)) return; for ( ; eventtail != eventhead ; eventtail = (++eventtail)&(MAXEVENTS-1) ) { ev = &events[eventtail]; if (M_Responder (ev)) continue; // menu ate the event G_Responder (ev); } } //============================================================================= fixed_t FixedDiv (fixed_t a, fixed_t b) { if ( (abs(a)>>14) >= abs(b)) return (a^b)<0 ? MININT : MAXINT; return FixedDiv2 (a,b); } //============================================================================= /* ============= = = 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 R_ExecuteSetViewSize (void); void D_Display (void) { static boolean viewactivestate = false; static boolean menuactivestate = false; static boolean inhelpscreensstate = false; static boolean fullscreen = false; static gamestate_t oldgamestate = -1; static int borderdrawcount; int nowtime, tics; int wipestart, y; boolean done, wipe, redrawsbar; if (nodrawers) return; // for comparative timing / profiling redrawsbar = false; // // change the view size if needed // if (setsizeneeded) { R_ExecuteSetViewSize (); oldgamestate = -1; // force background redraw borderdrawcount = 3; } // // save the current screen if about to wipe // if (gamestate != wipegamestate) { wipe = true; wipe_StartScreen(0, 0, SCREENWIDTH, SCREENHEIGHT); } else wipe = false; if (gamestate == GS_LEVEL && gametic) HU_Erase(); // // do buffered drawing // switch (gamestate) { case GS_LEVEL: if (!gametic) break; if (automapactive) AM_Drawer (); if (wipe || (viewheight != 200 && fullscreen) ) redrawsbar = true; if (inhelpscreensstate && !inhelpscreens) redrawsbar = true; // just put away the help screen ST_Drawer (viewheight == 200, redrawsbar ); fullscreen = viewheight == 200; break; case GS_INTERMISSION: WI_Drawer (); break; case GS_FINALE: F_Drawer (); break; case GS_DEMOSCREEN: D_PageDrawer (); break; } // // draw buffered stuff to screen // I_UpdateNoBlit (); // // draw the view directly // if (gamestate == GS_LEVEL && !automapactive && gametic) R_RenderPlayerView (&players[displayplayer]); if (gamestate == GS_LEVEL && gametic) HU_Drawer (); // // clean up border stuff // if (gamestate != oldgamestate && gamestate != GS_LEVEL) I_SetPalette (W_CacheLumpName ("PLAYPAL",PU_CACHE)); // see if the border needs to be initially drawn if (gamestate == GS_LEVEL && oldgamestate != GS_LEVEL) { viewactivestate = false; // view wasn't active R_FillBackScreen (); // draw the pattern into the back screen } // see if the border needs to be updated to the screen if (gamestate == GS_LEVEL && !automapactive && scaledviewwidth != 320) { if (menuactive || menuactivestate || !viewactivestate) borderdrawcount = 3; if (borderdrawcount) { R_DrawViewBorder (); // erase old menu stuff borderdrawcount--; } } menuactivestate = menuactive; viewactivestate = viewactive; inhelpscreensstate = inhelpscreens; oldgamestate = wipegamestate = gamestate; // // draw pause pic // if (paused) { if (automapactive) y = 4; else y = viewwindowy+4; V_DrawPatchDirect (viewwindowx+ (scaledviewwidth-68)/2,y,0 ,W_CacheLumpName ("M_PAUSE", PU_CACHE)); } // // menus go directly to the screen // M_Drawer (); // menu is drawn even on top of everything NetUpdate (); // send out any new accumulation // normal update if (!wipe) { I_FinishUpdate (); // page flip or blit buffer return; } // // wipe update // wipe_EndScreen(0, 0, SCREENWIDTH, SCREENHEIGHT); wipestart = I_GetTime () - 1; do { do { nowtime = I_GetTime (); tics = nowtime - wipestart; } while (!tics); wipestart = nowtime; done = wipe_ScreenWipe(wipe_Melt , 0, 0, SCREENWIDTH, SCREENHEIGHT, tics); I_UpdateNoBlit (); M_Drawer (); // menu is drawn even on top of wipes I_FinishUpdate (); // page flip or blit buffer } while (!done); } /* =============================================================================== = = D_DoomLoop = =============================================================================== */ extern boolean demorecording; void D_DoomLoop (void) { if (demorecording) G_BeginRecording (); if (M_CheckParm ("-debugfile")) { char filename[20]; sprintf (filename,"debug%i.txt",consoleplayer); printf ("debug output to: %s\n",filename); debugfile = fopen (filename,"w"); } I_InitGraphics (); while (1) { I_StartFrame (); // frame syncronous IO operations // // process one or more tics // if (singletics) { I_StartTic (); D_ProcessEvents (); G_BuildTiccmd (&netcmds[consoleplayer][maketic%BACKUPTICS]); if (advancedemo) D_DoAdvanceDemo (); M_Ticker (); G_Ticker (); gametic++; maketic++; } else { TryRunTics (); // will run at least one tic } S_UpdateSounds (players[consoleplayer].mo);// move positional sounds 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_DrawPatch (0,0, 0, W_CacheLumpName(pagename, PU_CACHE)); } /* ================= = = D_AdvanceDemo = = Called after each demo or intro demosequence finishes ================= */ void D_AdvanceDemo (void) { advancedemo = true; } void D_DoAdvanceDemo (void) { players[consoleplayer].playerstate = PST_LIVE; // don't reborn advancedemo = false; usergame = false; // can't save / end game here paused = false; gameaction = ga_nothing; demosequence = (demosequence+1)%6; switch (demosequence) { case 0: if (commercial) pagetic = 35 * 11; else pagetic = 170; gamestate = GS_DEMOSCREEN; pagename = "TITLEPIC"; commercial ? S_StartMusic(mus_dm2ttl):S_StartMusic (mus_intro); break; case 1: G_DeferedPlayDemo ("demo1"); break; case 2: pagetic = 200; gamestate = GS_DEMOSCREEN; pagename = "CREDIT"; break; case 3: G_DeferedPlayDemo ("demo2"); break; case 4: gamestate = GS_DEMOSCREEN; if (commercial) { pagetic = 35 * 11; pagename = "TITLEPIC"; S_StartMusic(mus_dm2ttl); } else { pagetic = 200; pagename = "HELP2"; } break; case 5: G_DeferedPlayDemo ("demo3"); break; } } /* ================= = = D_StartTitle = ================= */ void D_StartTitle (void) { gameaction = ga_nothing; demosequence = -1; D_AdvanceDemo (); } #ifdef __WATCOMC__ //==================================================== // // Print (in color) a string // //==================================================== int getx(void) { union REGS r; r.h.ah = 3; r.h.bh = 0; int386(0x10,&r,&r); return r.h.dl; } int gety(void) { union REGS r; r.h.ah = 3; r.h.bh = 0; int386(0x10,&r,&r); return r.h.dh; } void setxy(int x,int y) { union REGS r; r.h.ah = 2; r.h.bh = 0; r.h.dh = y; r.h.dl = x; int386(0x10,&r,&r); } void dprint(char *string,int fg,int bg) { union REGS r; int i,x,y; char color; color = (bg << 4) | fg; x = getx(); y = gety(); for (i = 0; i < strlen(string); i++) { r.h.ah = 9; r.h.al = string[i]; r.h.bh = 0; r.h.bl = color; r.w.cx = 1; int386(0x10,&r,&r); x++; if (x > 79) x = 0; setxy(x,y); } } #endif // // print title for every printed line // char title[128]; void mprintf(char *string) { #ifdef __WATCOMC__ int x; int y; #endif printf(string); #ifdef __WATCOMC__ x = getx(); y = gety(); setxy(0,0); dprint (title,4,7); setxy(x,y); #endif } /* ============== = = D_AddFile = ============== */ void D_AddFile (char *file) { int numwadfiles; char *newfile; for (numwadfiles = 0 ; wadfiles[numwadfiles] ; numwadfiles++) ; newfile = malloc (strlen(file)+1); strcpy (newfile, file); wadfiles[numwadfiles] = newfile; } /* ============= = = IdentifyVersion = ============= */ void IdentifyVersion (void) { char *doom1wad, *doomwad, *doom2wad, *doom2fwad; #ifdef NORMALUNIX char *home; char *doomwaddir; doomwaddir = getenv("DOOMWADDIR"); if (!doomwaddir) doomwaddir = "."; doom1wad = malloc(strlen(doomwaddir)+1+9+1); sprintf(doom1wad, "%s/doom1.wad", doomwaddir); doom2fwad = malloc(strlen(doomwaddir)+1+10+1); sprintf(doom2fwad, "%s/doom2f.wad", doomwaddir); doom2wad = malloc(strlen(doomwaddir)+1+9+1); sprintf(doom2wad, "%s/doom2.wad", doomwaddir); doomwad = malloc(strlen(doomwaddir)+1+8+1); sprintf(doomwad, "%s/doom.wad", doomwaddir); home = getenv("HOME"); if (!home) I_Error("Please set $HOME to your home directory"); sprintf(basedefault, "%s/.doomrc", home); #else strcpy (basedefault,"default.cfg"); doom1wad = "doom1.wad"; doom2fwad = "doom2f.wad"; doom2wad = "doom2.wad"; doomwad = "doom.wad"; #endif if (M_CheckParm ("-shdev")) { registered = false; shareware = true; devparm = true; D_AddFile (DEVDATA"doom1.wad"); D_AddFile (DEVMAPS"data/texture1.lmp"); D_AddFile (DEVMAPS"data/pnames.lmp"); strcpy (basedefault,DEVDATA"default.cfg"); return; } if (M_CheckParm ("-regdev")) { registered = true; devparm = true; D_AddFile (DEVDATA"doom.wad"); D_AddFile (DEVMAPS"data/texture1.lmp"); D_AddFile (DEVMAPS"data/texture2.lmp"); D_AddFile (DEVMAPS"data/pnames.lmp"); strcpy (basedefault,DEVDATA"default.cfg"); return; } if (M_CheckParm ("-comdev")) { commercial = true; devparm = true; D_AddFile (DEVDATA"doom2.wad"); D_AddFile (DEVMAPS"cdata/texture1.lmp"); D_AddFile (DEVMAPS"cdata/pnames.lmp"); strcpy (basedefault,DEVDATA"default.cfg"); return; } if ( !access (doom2fwad,R_OK) ) { commercial = true; french = true; printf("French version\n"); D_AddFile (doom2fwad); return; } if ( !access (doom2wad,R_OK) ) { commercial = true; D_AddFile (doom2wad); return; } if (! access (doomwad,R_OK) ) { registered = true; D_AddFile (doomwad); return; } if ( !access (doom1wad,R_OK) ) { shareware = true; D_AddFile (doom1wad); return; } printf("Game mode indeterminate.\n"); exit(1); // I_Error ("Game mode indeterminate\n"); } /* ============= = = CheckBetaTest = ============= */ void CheckBetaTest (void) { #ifdef BETATEST // // check password and date stamp for bad beta testers // struct dosdate_t d; char *p, *check; p = check = W_CacheLumpName ("bpas",PU_CACHE); while (*check > ' ') check++; *check = 0; if (!M_CheckParm (p)) I_Error ("Corrupt wadfile"); _dos_getdate(&d); if (d.year > 1993 || d.day > 20) I_Error ("Bad wadfile"); #endif } //======================================================== // // Find a Response File // //======================================================== void FindResponseFile (void) { int i; #define MAXARGVS 100 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) { printf ("\nNo such response file!"); exit(1); } printf("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("%d command-line args:\n",myargc); for (k=1;k 400) scale = 400; printf ("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; } // // add any files specified on the command line with -file wadfile to // the wad list // // convenience hack to allow -wart e m to add a wad file // prepend a tilde to the filename so wadfile will be reloadable p = M_CheckParm ("-wart"); if (p) { myargv[p][4] = 'p'; // big hack, change to -warp if (commercial) { p = atoi (myargv[p+1]); if (p<10) sprintf (file,"~"DEVMAPS"cdata/map0%i.wad", p); else sprintf (file,"~"DEVMAPS"cdata/map%i.wad", p); } else { sprintf (file,"~"DEVMAPS"E%cM%c.wad", myargv[p+1][0], myargv[p+2][0]); printf("Warping to Episode %s, Map %s.\n",myargv[p+1],myargv[p+2]); } D_AddFile (file); } 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] != '-') D_AddFile (myargv[p]); } p = M_CheckParm ("-playdemo"); if (!p) p = M_CheckParm ("-timedemo"); if (p && p < myargc-1) { sprintf (file,"%s.lmp", myargv[p+1]); D_AddFile (file); printf("Playing demo %s.lmp.\n",myargv[p+1]); } // // get skill / episode / map from parms // startskill = sk_medium; startepisode = 1; startmap = 1; autostart = false; p = M_CheckParm ("-skill"); if (p && p < myargc-1) { startskill = myargv[p+1][0]-'1'; autostart = true; } p = M_CheckParm ("-episode"); if (p && p < myargc-1) { startepisode = myargv[p+1][0]-'0'; startmap = 1; autostart = true; } p = M_CheckParm ("-timer"); if (p && p < myargc-1 && deathmatch) { int time; time = atoi(myargv[p+1]); printf("Levels will end after %d minute",time); if (time>1) printf("s"); printf(".\n"); } p = M_CheckParm ("-avg"); if (p && p < myargc-1 && deathmatch) printf("Austin Virtual Gaming: Levels will end after 20 minutes\n"); p = M_CheckParm ("-warp"); if (p && p < myargc-1) { if (commercial) startmap = atoi (myargv[p+1]); else { startepisode = myargv[p+1][0]-'0'; startmap = myargv[p+2][0]-'0'; } autostart = true; } // // init subsystems // printf ("V_Init: allocate screens.\n"); V_Init (); printf ("M_LoadDefaults: Load system defaults.\n"); M_LoadDefaults (); // load before initing other systems printf ("Z_Init: Init zone memory allocation daemon. \n"); Z_Init (); printf ("W_Init: Init WADfiles.\n"); W_InitMultipleFiles (wadfiles); // // Check for -file in shareware // if (modifiedgame) { char name[23][8]= { "e2m1","e2m2","e2m3","e2m4","e2m5","e2m6","e2m7","e2m8","e2m9", "e3m1","e3m3","e3m3","e3m4","e3m5","e3m6","e3m7","e3m8","e3m9", "dphoof","bfgga0","heada1","cybra1","spida1d1" }; int i; if (shareware) I_Error("\nYou cannot -file with the shareware " "version. Register!"); if (registered) for (i = 0;i < 23; i++) if (W_CheckNumForName(name[i])<0) I_Error("\nThis is not the registered version."); } // // print modified banner // if (modifiedgame) { printf ( "===========================================================================\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" " press enter to continue\n" "===========================================================================\n" ); getchar (); } // // check which version // if (registered) { mprintf (" registered version.\n"); mprintf ( "===========================================================================\n" " This version is NOT SHAREWARE, do not distribute!\n" " Please report software piracy to the SPA: 1-800-388-PIR8\n" "===========================================================================\n" ); } if (shareware) mprintf (" shareware version.\n"); if (commercial) { mprintf (" commercial version.\n"); mprintf ( "===========================================================================\n" " Do not distribute!\n" " Please report software piracy to the SPA: 1-800-388-PIR8\n" "===========================================================================\n" ); // shareware = false; } mprintf ("M_Init: Init miscellaneous info.\n"); M_Init (); mprintf ("R_Init: Init DOOM refresh daemon - "); R_Init (); mprintf ("\nP_Init: Init Playloop state.\n"); P_Init (); mprintf ("I_Init: Setting up machine state.\n"); I_Init (); mprintf ("D_CheckNetGame: Checking network game status.\n"); D_CheckNetGame (); mprintf ("S_Init: Setting up sound.\n"); S_Init (sfxVolume*8,musicVolume*8); mprintf ("HU_Init: Setting up heads up display.\n"); HU_Init (); mprintf ("ST_Init: Init status bar.\n"); ST_Init (); CheckBetaTest (); // // check for a driver that wants intermission stats // p = M_CheckParm ("-statcopy"); if (p && p