1 /* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
5 * PrBoom a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
28 * DOOM main program (D_DoomMain) and game loop (D_DoomLoop),
29 * plus functions to determine game mode (shareware, registered),
30 * parse command line parameters, configure game parameters (turbo),
31 * and call the startup functions.
33 *-----------------------------------------------------------------------------
37 #include "rockmacros.h"
65 #include "d_deh.h" // Ty 04/08/98 - Externalizations
68 // DEHacked support - Ty 03/09/97 // CPhipps - const char*'s
69 void ProcessDehFile(const char *filename
, const char *outfilename
, int lumpnum
);
71 // CPhipps - removed wadfiles[] stuff
73 boolean devparm
; // started game with -devparm
75 // jff 1/24/98 add new versions of these variables to remember command line
76 boolean clnomonsters
; // checkparm of -nomonsters
77 boolean clrespawnparm
; // checkparm of -respawn
78 boolean clfastparm
; // checkparm of -fast
79 // jff 1/24/98 end definition of command line version of play mode switches
81 boolean nomonsters
; // working -nomonsters
82 boolean respawnparm
; // working -respawn
83 boolean fastparm
; // working -fast
86 boolean singletics
= false; // debug flag to cancel adaptiveness
90 //jff 1/22/98 parms for disabling music and sound
91 boolean nomusicparm
=0;
94 extern boolean inhelpscreens
;
105 extern boolean timingdemo
, singledemo
, demoplayback
, fastdemo
; // killough
109 void D_DoAdvanceDemo (void);
112 * D_PostEvent - Event handling
114 * Called by I/O functions when an event is received.
115 * Try event handlers for each code area in turn.
118 void D_PostEvent(event_t
*ev
)
120 /* cph - suppress all input events at game start
121 * FIXME: This is a lousy kludge */
125 if(!M_Responder(ev
)) {
126 if(gamestate
== GS_LEVEL
&& (
140 // CPhipps - moved the screen wipe code from D_Display to here
141 // The screens to wipe between are already stored, this just does the timing
142 // and screen updating
144 static void D_Wipe(void)
147 int wipestart
= I_GetTime () - 1;
154 //I_uSleep(5000); // CPhipps - don't thrash cpu in this loop
155 nowtime
= I_GetTime();
156 tics
= nowtime
- wipestart
;
161 done
= wipe_ScreenWipe(0,0,SCREENWIDTH
,SCREENHEIGHT
,tics
);
162 M_Drawer(); // menu is drawn even on top of wipes
163 I_FinishUpdate(); // page flip or blit buffer
170 // draw current display, possibly wiping it from the previous
173 // wipegamestate can be set to -1 to force a wipe on the next draw
174 gamestate_t wipegamestate
= GS_DEMOSCREEN
;
175 extern boolean setsizeneeded
;
176 extern int showMessages
;
178 void D_Display (void)
180 static boolean isborderstate IDATA_ATTR
= false;
181 static boolean borderwillneedredraw IDATA_ATTR
= false;
182 static gamestate_t oldgamestate IDATA_ATTR
= -1;
184 boolean viewactive
= false, isborder
= false;
186 if (nodrawers
) // for comparative timing / profiling
189 // save the current screen if about to wipe
190 if ((wipe
= gamestate
!= wipegamestate
))
191 wipe_StartScreen(0, 0, SCREENWIDTH
, SCREENHEIGHT
);
193 if (gamestate
!= GS_LEVEL
) { // Not a level
194 switch (oldgamestate
) {
195 case (gamestate_t
)-1:
197 V_SetPalette(0); // cph - use default (basic) palette
203 case GS_INTERMISSION
:
215 } else if (gametic
!= basetic
) { // In a level
216 boolean redrawborderstuff
;
220 if (setsizeneeded
) { // change the view size if needed
221 R_ExecuteSetViewSize();
222 oldgamestate
= -1; // force background redraw
225 // Work out if the player view is visible, and if there is a border
226 viewactive
= (!(automapmode
& am_active
) || (automapmode
& am_overlay
)) && !inhelpscreens
;
227 isborder
= viewactive
? (viewheight
!= SCREENHEIGHT
) : (!inhelpscreens
&& (automapmode
& am_active
));
229 if (oldgamestate
!= GS_LEVEL
) {
230 R_FillBackScreen (); // draw the pattern into the back screen
231 redrawborderstuff
= isborder
;
234 // If there is a border, and either there was no border last time,
235 // or the border might need refreshing, then redraw it.
236 redrawborderstuff
= isborder
&& (!isborderstate
|| borderwillneedredraw
);
237 // The border may need redrawing next time if the border surrounds the screen,
238 // and there is a menu being displayed
239 borderwillneedredraw
= menuactive
&& isborder
&& viewactive
&& (viewwidth
!= SCREENWIDTH
);
242 if (redrawborderstuff
)
245 // Now do the drawing
247 R_RenderPlayerView (&players
[displayplayer
]);
248 if (automapmode
& am_active
)
250 ST_Drawer((viewheight
!= SCREENHEIGHT
) || ((automapmode
& am_active
) && !(automapmode
& am_overlay
)), redrawborderstuff
);
256 isborderstate
= isborder
;
257 oldgamestate
= wipegamestate
= gamestate
;
263 if (!x
) { // Cache results of x pos calc
264 int lump
= W_GetNumForName("M_PAUSE");
265 const patch_t
* p
= W_CacheLumpNum(lump
);
266 x
= (320 - SHORT(p
->width
))/2;
267 W_UnlockLumpNum(lump
);
270 // CPhipps - updated for new patch drawing
271 V_DrawNamePatch(x
, (!(automapmode
& am_active
) || (automapmode
& am_overlay
))
272 ? 4+(viewwindowy
*200/SCREENHEIGHT
) : 4, // cph - Must un-stretch viewwindowy
273 0, "M_PAUSE", CR_DEFAULT
, VPT_STRETCH
);
276 // menus go directly to the screen
277 M_Drawer(); // menu is drawn even on top of everything
282 I_FinishUpdate (); // page flip or blit buffer
285 wipe_EndScreen(0, 0, SCREENWIDTH
, SCREENHEIGHT
);
293 // Not a globally visible function,
294 // just included for source reference,
295 // called by D_DoomMain, never exits.
296 // Manages timing and IO,
297 // calls all ?_Responder, ?_Ticker, and ?_Drawer,
298 // calls I_GetTime, I_StartFrame, and I_StartTic
301 extern boolean demorecording
;
303 static void D_DoomLoop (void)
311 // process one or more tics
315 G_BuildTiccmd (&netcmds
[consoleplayer
][maketic
%BACKUPTICS
]);
324 TryRunTics (); // will run at least one tic
326 // killough 3/16/98: change consoleplayer to displayplayer
327 if (players
[displayplayer
].mo
) // cph 2002/08/10
328 S_UpdateSounds(players
[displayplayer
].mo
);// move positional sounds
330 // Update display, next frame, with current state.
333 // Give the system some time
342 static int demosequence
; // killough 5/2/98: made static
344 static const char *pagename
; // CPhipps - const
348 // Handles timing for warped projection
350 void D_PageTicker(void)
359 void D_PageDrawer(void)
361 // CPhipps - updated for new patch drawing
362 V_DrawNamePatch(0, 0, 0, pagename
, CR_DEFAULT
, VPT_STRETCH
);
367 // Called after each demo or intro demosequence finishes
369 void D_AdvanceDemo (void)
374 /* killough 11/98: functions to perform demo sequences
375 * cphipps 10/99: constness fixes
378 static void D_SetPageName(const char *name
)
383 static void D_DrawTitle1(const char *name
)
385 S_StartMusic(mus_intro
);
386 pagetic
= (TICRATE
*170)/35;
390 static void D_DrawTitle2(const char *name
)
392 S_StartMusic(mus_dm2ttl
);
396 /* killough 11/98: tabulate demo sequences
401 void (*func
)(const char *);
403 } const demostates
[][4] =
406 {D_DrawTitle1
, "TITLEPIC"},
407 {D_DrawTitle1
, "TITLEPIC"},
408 {D_DrawTitle2
, "TITLEPIC"},
409 {D_DrawTitle1
, "TITLEPIC"},
413 {G_DeferedPlayDemo
, "demo1"},
414 {G_DeferedPlayDemo
, "demo1"},
415 {G_DeferedPlayDemo
, "demo1"},
416 {G_DeferedPlayDemo
, "demo1"},
419 {D_SetPageName
, "CREDIT"},
420 {D_SetPageName
, "CREDIT"},
421 {D_SetPageName
, "CREDIT"},
422 {D_SetPageName
, "CREDIT"},
426 {G_DeferedPlayDemo
, "demo2"},
427 {G_DeferedPlayDemo
, "demo2"},
428 {G_DeferedPlayDemo
, "demo2"},
429 {G_DeferedPlayDemo
, "demo2"},
433 {D_SetPageName
, "HELP2"},
434 {D_SetPageName
, "HELP2"},
435 {D_SetPageName
, "CREDIT"},
436 {D_DrawTitle1
, "TITLEPIC"},
440 {G_DeferedPlayDemo
, "demo3"},
441 {G_DeferedPlayDemo
, "demo3"},
442 {G_DeferedPlayDemo
, "demo3"},
443 {G_DeferedPlayDemo
, "demo3"},
450 {D_SetPageName
, "CREDIT"},
457 {G_DeferedPlayDemo
, "demo4"},
469 * This cycles through the demo sequences.
470 * killough 11/98: made table-driven
473 void D_DoAdvanceDemo(void)
475 players
[consoleplayer
].playerstate
= PST_LIVE
; /* not reborn */
476 advancedemo
= usergame
= paused
= false;
477 gameaction
= ga_nothing
;
479 pagetic
= TICRATE
* 11; /* killough 11/98: default behavior */
480 gamestate
= GS_DEMOSCREEN
;
482 if (netgame
&& !demoplayback
) {
485 if (!demostates
[++demosequence
][gamemode
].func
)
487 demostates
[demosequence
][gamemode
].func(demostates
[demosequence
][gamemode
].name
);
493 void D_StartTitle (void)
495 gameaction
= ga_nothing
;
503 // Rewritten by Lee Killough
505 // Ty 08/29/98 - add source parm to indicate where this came from
506 // CPhipps - static, const char* parameter
507 // - source is an enum
508 // - modified to allocate & use new wadfiles array
509 void D_AddFile (const char *file
, wad_source_t source
)
511 wadfiles
= realloc(wadfiles
, sizeof(*wadfiles
)*(numwadfiles
+1));
512 wadfiles
[numwadfiles
].name
=
513 AddDefaultExtension(strcpy(malloc(strlen(file
)+5), file
), ".wad");
514 wadfiles
[numwadfiles
].src
= source
; // Ty 08/29/98
521 // Verify a file is indeed tagged as an IWAD
522 // Scan its lumps for levelnames and return gamemode as indicated
523 // Detect missing wolf levels in DOOM II
525 // The filename to check is passed in iwadname, the gamemode detected is
526 // returned in gmode, hassec returns the presence of secret levels
528 // jff 4/19/98 Add routine to test IWAD for validity and determine
529 // the gamemode from it. Also note if DOOM II, whether secret levels exist
530 // CPhipps - const char* for iwadname, made static
532 static void CheckIWAD(const char *iwadname
,GameMode_t
*gmode
,boolean
*hassec
)
534 if ( !fileexists (iwadname
) )
536 int ud
=0,rg
=0,sw
=0,cm
=0,sc
=0;
539 // Identify IWAD correctly
540 if ( (handle
= open (iwadname
,O_RDONLY
)) != -1)
545 read (handle
, &header
, sizeof(header
));
546 if (!strncmp(header
.identification
,"IWAD",4))
549 filelump_t
*fileinfo
;
551 // read IWAD directory
552 header
.numlumps
= LONG(header
.numlumps
);
553 header
.infotableofs
= LONG(header
.infotableofs
);
554 length
= header
.numlumps
;
555 fileinfo
= malloc(length
*sizeof(filelump_t
));
556 lseek (handle
, header
.infotableofs
, SEEK_SET
);
557 read (handle
, fileinfo
, length
*sizeof(filelump_t
));
560 // scan directory for levelname lumps
562 if (fileinfo
[length
].name
[0] == 'E' &&
563 fileinfo
[length
].name
[2] == 'M' &&
564 fileinfo
[length
].name
[4] == 0)
566 if (fileinfo
[length
].name
[1] == '4')
568 else if (fileinfo
[length
].name
[1] == '3')
570 else if (fileinfo
[length
].name
[1] == '2')
572 else if (fileinfo
[length
].name
[1] == '1')
575 else if (fileinfo
[length
].name
[0] == 'M' &&
576 fileinfo
[length
].name
[1] == 'A' &&
577 fileinfo
[length
].name
[2] == 'P' &&
578 fileinfo
[length
].name
[5] == 0)
581 if (fileinfo
[length
].name
[3] == '3')
582 if (fileinfo
[length
].name
[4] == '1' ||
583 fileinfo
[length
].name
[4] == '2')
589 else // missing IWAD tag in header
590 I_Error("CheckIWAD: IWAD tag %s not present", iwadname
);
592 else // error from open call
593 I_Error("CheckIWAD: Can't open IWAD %s", iwadname
);
595 // Determine game mode from levels present
596 // Must be a full set for whichever mode is present
597 // Lack of wolf-3d levels also detected here
599 *gmode
= indetermined
;
613 else // error from access call
614 I_Error("CheckIWAD: IWAD %s not readable", iwadname
);
617 void D_DoomMainSetup(void)
621 nomonsters
= M_CheckParm ("-nomonsters");
622 respawnparm
= M_CheckParm ("-respawn");
623 fastparm
= M_CheckParm ("-fast");
624 devparm
= M_CheckParm ("-devparm");
625 if (M_CheckParm ("-altdeath"))
627 else if (M_CheckParm ("-deathmatch"))
630 printf("Welcome to Rockdoom\n");
635 printf ("The Ultimate DOOM Startup v%d.%d\n",DVERSION
/100,DVERSION
%100);
638 printf ("DOOM Shareware Startup v%d.%d\n",DVERSION
/100,DVERSION
%100);
641 printf ("DOOM Registered Startup v%d.%d\n",DVERSION
/100,DVERSION
%100);
647 printf ("DOOM 2: Plutonia Experiment v%d.%d\n",DVERSION
/100,DVERSION
%100);
650 printf ("DOOM 2: TNT - Evilution v%d.%d\n",DVERSION
/100,DVERSION
%100);
653 printf ("DOOM 2: Hell on Earth v%d.%d\n",DVERSION
/100,DVERSION
%100);
658 printf ("Public DOOM v%d.%d\n",DVERSION
/100,DVERSION
%100);
666 if ((p
=M_CheckParm ("-turbo")))
669 extern int forwardmove
[2];
670 extern int sidemove
[2];
673 scale
= atoi (myargv
[p
+1]);
678 printf ("turbo scale: %d%%\n",scale
);
679 forwardmove
[0] = forwardmove
[0]*scale
/100;
680 forwardmove
[1] = forwardmove
[1]*scale
/100;
681 sidemove
[0] = sidemove
[0]*scale
/100;
682 sidemove
[1] = sidemove
[1]*scale
/100;
685 // get skill / episode / map from parms
686 startskill
= sk_medium
;
691 p
= M_CheckParm ("-skill");
692 if (p
&& p
< myargc
-1)
694 startskill
= myargv
[p
+1][0]-'1';
698 p
= M_CheckParm ("-episode");
699 if (p
&& p
< myargc
-1)
701 startepisode
= myargv
[p
+1][0]-'0';
706 p
= M_CheckParm ("-warp");
707 if (p
&& p
< myargc
-1)
709 if (gamemode
== commercial
)
710 startmap
= atoi (myargv
[p
+1]);
713 startepisode
= myargv
[p
+1][0]-'0';
714 startmap
= myargv
[p
+2][0]-'0';
719 // CPhipps - move up netgame init
720 printf("D_InitNetGame: Checking for network game.\n");
724 printf ("V_Init: allocate screens.\n");
727 printf ("W_Init: Init WADfiles.\n");
730 if ((p
= W_CheckNumForName("DEHACKED")) != -1) // cph - add dehacked-in-a-wad support
731 ProcessDehFile(NULL
, dehout
? "/dehlog.txt" : NULL
, p
);
733 V_InitColorTranslation(); //jff 4/24/98 load color translation lumps
735 // Check for -file in shareware
738 // These are the lumps that will be checked in IWAD,
739 // if any one is not present, execution will be aborted.
740 const char name
[23][8]=
742 "e2m1","e2m2","e2m3","e2m4","e2m5","e2m6","e2m7","e2m8","e2m9",
743 "e3m1","e3m3","e3m3","e3m4","e3m5","e3m6","e3m7","e3m8","e3m9",
744 "dphoof","bfgga0","heada1","cybra1","spida1d1"
748 if ( gamemode
== shareware
)
749 I_Error("\nYou cannot -file with the shareware version. Register!\n");
751 // Check for fake IWAD with right name,
752 // but w/o all the lumps of the registered version.
753 if (gamemode
== registered
)
754 for (i
= 0;i
< 23; i
++)
755 if (W_CheckNumForName(name
[i
])<0)
756 I_Error("This is not the registered version.\n");
759 // Iff additonal PWAD files are used, print modified banner
761 printf ("ATTENTION: This version of DOOM has been modified.\n");
763 // Check and print which version is executed.
768 printf ("Shareware!\n");
773 printf ("Commercial product - do not distribute!\n");
780 printf ("M_Init: Init miscellaneous info.\n");
783 printf ("R_Init: Init DOOM refresh daemon - ");
786 printf ("P_Init: Init Playloop state.\n");
789 printf ("I_Init: Setting up machine state.\n");
792 printf ("S_Init: Setting up sound.\n");
793 S_Init (snd_SfxVolume
/* *8 */, snd_MusicVolume
/* *8*/ );
795 printf ("HU_Init: Setting up heads up display.\n");
800 printf ("ST_Init: Init status bar.\n");
803 // check for a driver that wants intermission stats
804 p
= M_CheckParm ("-statcopy");
807 // for statistics driver
808 extern void* statcopy
;
810 statcopy
= (void*)(long)atoi(myargv
[p
+1]);
811 printf ("External statistics registered.\n");
814 // start the apropriate game based on parms
815 p
= M_CheckParm ("-record");
816 if (p
&& p
< myargc
-1)
818 G_RecordDemo (myargv
[p
+1]);
822 p
= M_CheckParm ("-loadgame");
823 if (p
&& p
< myargc
-1)
824 G_LoadGame (atoi(myargv
[p
+1]), false);
826 if ( gameaction
!= ga_loadgame
)
828 if (!singledemo
) { /* killough 12/98 */
829 if (autostart
|| netgame
)
830 G_InitNew (startskill
, startepisode
, startmap
);
832 D_StartTitle (); // start up intro loop
840 void D_DoomMain (void)
842 D_DoomMainSetup(); // get this crap off the stack
844 D_DoomLoop (); // never returns