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
69 // DEHacked support - Ty 03/09/97 // CPhipps - const char*'s
70 void ProcessDehFile(const char *filename
, const char *outfilename
, int lumpnum
);
72 // CPhipps - removed wadfiles[] stuff
74 boolean devparm
; // started game with -devparm
76 // jff 1/24/98 add new versions of these variables to remember command line
77 boolean clnomonsters
; // checkparm of -nomonsters
78 boolean clrespawnparm
; // checkparm of -respawn
79 boolean clfastparm
; // checkparm of -fast
80 // jff 1/24/98 end definition of command line version of play mode switches
82 boolean nomonsters
; // working -nomonsters
83 boolean respawnparm
; // working -respawn
84 boolean fastparm
; // working -fast
87 boolean singletics
= false; // debug flag to cancel adaptiveness
91 //jff 1/22/98 parms for disabling music and sound
92 boolean nomusicparm
=0;
95 extern boolean inhelpscreens
;
106 extern boolean timingdemo
, singledemo
, demoplayback
, fastdemo
; // killough
110 void D_DoAdvanceDemo (void);
113 * D_PostEvent - Event handling
115 * Called by I/O functions when an event is received.
116 * Try event handlers for each code area in turn.
119 void D_PostEvent(event_t
*ev
)
121 /* cph - suppress all input events at game start
122 * FIXME: This is a lousy kludge */
126 if(!M_Responder(ev
)) {
127 if(gamestate
== GS_LEVEL
&& (
141 // CPhipps - moved the screen wipe code from D_Display to here
142 // The screens to wipe between are already stored, this just does the timing
143 // and screen updating
145 static void D_Wipe(void)
148 int wipestart
= I_GetTime () - 1;
155 //I_uSleep(5000); // CPhipps - don't thrash cpu in this loop
156 nowtime
= I_GetTime();
157 tics
= nowtime
- wipestart
;
162 done
= wipe_ScreenWipe(0,0,SCREENWIDTH
,SCREENHEIGHT
,tics
);
163 M_Drawer(); // menu is drawn even on top of wipes
164 I_FinishUpdate(); // page flip or blit buffer
171 // draw current display, possibly wiping it from the previous
174 // wipegamestate can be set to -1 to force a wipe on the next draw
175 gamestate_t wipegamestate
= GS_DEMOSCREEN
;
176 extern boolean setsizeneeded
;
177 extern int showMessages
;
179 void D_Display (void)
181 static boolean isborderstate IDATA_ATTR
= false;
182 static boolean borderwillneedredraw IDATA_ATTR
= false;
183 static boolean inhelpscreensstate IDATA_ATTR
= false;
184 static gamestate_t oldgamestate IDATA_ATTR
= -1;
186 boolean viewactive
= false, isborder
= false;
188 if (nodrawers
) // for comparative timing / profiling
191 // save the current screen if about to wipe
192 if ((wipe
= gamestate
!= wipegamestate
))
193 wipe_StartScreen(0, 0, SCREENWIDTH
, SCREENHEIGHT
);
195 if (gamestate
!= GS_LEVEL
) { // Not a level
196 switch (oldgamestate
) {
199 V_SetPalette(0); // cph - use default (basic) palette
205 case GS_INTERMISSION
:
217 } else if (gametic
!= basetic
) { // In a level
218 boolean redrawborderstuff
;
222 if (setsizeneeded
) { // change the view size if needed
223 R_ExecuteSetViewSize();
224 oldgamestate
= -1; // force background redraw
227 // Work out if the player view is visible, and if there is a border
228 viewactive
= (!(automapmode
& am_active
) || (automapmode
& am_overlay
)) && !inhelpscreens
;
229 isborder
= viewactive
? (viewheight
!= SCREENHEIGHT
) : (!inhelpscreens
&& (automapmode
& am_active
));
231 if (oldgamestate
!= GS_LEVEL
) {
232 R_FillBackScreen (); // draw the pattern into the back screen
233 redrawborderstuff
= isborder
;
236 // If there is a border, and either there was no border last time,
237 // or the border might need refreshing, then redraw it.
238 redrawborderstuff
= isborder
&& (!isborderstate
|| borderwillneedredraw
);
239 // The border may need redrawing next time if the border surrounds the screen,
240 // and there is a menu being displayed
241 borderwillneedredraw
= menuactive
&& isborder
&& viewactive
&& (viewwidth
!= SCREENWIDTH
);
244 if (redrawborderstuff
)
247 // Now do the drawing
249 R_RenderPlayerView (&players
[displayplayer
]);
250 if (automapmode
& am_active
)
252 ST_Drawer((viewheight
!= SCREENHEIGHT
) || ((automapmode
& am_active
) && !(automapmode
& am_overlay
)), redrawborderstuff
);
258 inhelpscreensstate
= inhelpscreens
;
259 isborderstate
= isborder
;
260 oldgamestate
= wipegamestate
= gamestate
;
266 if (!x
) { // Cache results of x pos calc
267 int lump
= W_GetNumForName("M_PAUSE");
268 const patch_t
* p
= W_CacheLumpNum(lump
);
269 x
= (320 - SHORT(p
->width
))/2;
270 W_UnlockLumpNum(lump
);
273 // CPhipps - updated for new patch drawing
274 V_DrawNamePatch(x
, (!(automapmode
& am_active
) || (automapmode
& am_overlay
))
275 ? 4+(viewwindowy
*200/SCREENHEIGHT
) : 4, // cph - Must un-stretch viewwindowy
276 0, "M_PAUSE", CR_DEFAULT
, VPT_STRETCH
);
279 // menus go directly to the screen
280 M_Drawer(); // menu is drawn even on top of everything
285 I_FinishUpdate (); // page flip or blit buffer
288 wipe_EndScreen(0, 0, SCREENWIDTH
, SCREENHEIGHT
);
296 // Not a globally visible function,
297 // just included for source reference,
298 // called by D_DoomMain, never exits.
299 // Manages timing and IO,
300 // calls all ?_Responder, ?_Ticker, and ?_Drawer,
301 // calls I_GetTime, I_StartFrame, and I_StartTic
304 extern boolean demorecording
;
306 static void D_DoomLoop (void)
314 // process one or more tics
318 G_BuildTiccmd (&netcmds
[consoleplayer
][maketic
%BACKUPTICS
]);
327 TryRunTics (); // will run at least one tic
329 // killough 3/16/98: change consoleplayer to displayplayer
330 if (players
[displayplayer
].mo
) // cph 2002/08/10
331 S_UpdateSounds(players
[displayplayer
].mo
);// move positional sounds
333 // Update display, next frame, with current state.
336 // Give the system some time
345 static int demosequence
; // killough 5/2/98: made static
347 static const char *pagename
; // CPhipps - const
351 // Handles timing for warped projection
353 void D_PageTicker(void)
362 void D_PageDrawer(void)
364 // CPhipps - updated for new patch drawing
365 V_DrawNamePatch(0, 0, 0, pagename
, CR_DEFAULT
, VPT_STRETCH
);
370 // Called after each demo or intro demosequence finishes
372 void D_AdvanceDemo (void)
377 /* killough 11/98: functions to perform demo sequences
378 * cphipps 10/99: constness fixes
381 static void D_SetPageName(const char *name
)
386 static void D_DrawTitle1(const char *name
)
388 S_StartMusic(mus_intro
);
389 pagetic
= (TICRATE
*170)/35;
393 static void D_DrawTitle2(const char *name
)
395 S_StartMusic(mus_dm2ttl
);
399 /* killough 11/98: tabulate demo sequences
404 void (*func
)(const char *);
406 } const demostates
[][4] =
409 {D_DrawTitle1
, "TITLEPIC"},
410 {D_DrawTitle1
, "TITLEPIC"},
411 {D_DrawTitle2
, "TITLEPIC"},
412 {D_DrawTitle1
, "TITLEPIC"},
416 {G_DeferedPlayDemo
, "demo1"},
417 {G_DeferedPlayDemo
, "demo1"},
418 {G_DeferedPlayDemo
, "demo1"},
419 {G_DeferedPlayDemo
, "demo1"},
422 {D_SetPageName
, "CREDIT"},
423 {D_SetPageName
, "CREDIT"},
424 {D_SetPageName
, "CREDIT"},
425 {D_SetPageName
, "CREDIT"},
429 {G_DeferedPlayDemo
, "demo2"},
430 {G_DeferedPlayDemo
, "demo2"},
431 {G_DeferedPlayDemo
, "demo2"},
432 {G_DeferedPlayDemo
, "demo2"},
436 {D_SetPageName
, "HELP2"},
437 {D_SetPageName
, "HELP2"},
438 {D_SetPageName
, "CREDIT"},
439 {D_DrawTitle1
, "TITLEPIC"},
443 {G_DeferedPlayDemo
, "demo3"},
444 {G_DeferedPlayDemo
, "demo3"},
445 {G_DeferedPlayDemo
, "demo3"},
446 {G_DeferedPlayDemo
, "demo3"},
453 {D_SetPageName
, "CREDIT"},
460 {G_DeferedPlayDemo
, "demo4"},
472 * This cycles through the demo sequences.
473 * killough 11/98: made table-driven
476 void D_DoAdvanceDemo(void)
478 players
[consoleplayer
].playerstate
= PST_LIVE
; /* not reborn */
479 advancedemo
= usergame
= paused
= false;
480 gameaction
= ga_nothing
;
482 pagetic
= TICRATE
* 11; /* killough 11/98: default behavior */
483 gamestate
= GS_DEMOSCREEN
;
485 if (netgame
&& !demoplayback
) {
488 if (!demostates
[++demosequence
][gamemode
].func
)
490 demostates
[demosequence
][gamemode
].func(demostates
[demosequence
][gamemode
].name
);
496 void D_StartTitle (void)
498 gameaction
= ga_nothing
;
506 // Rewritten by Lee Killough
508 // Ty 08/29/98 - add source parm to indicate where this came from
509 // CPhipps - static, const char* parameter
510 // - source is an enum
511 // - modified to allocate & use new wadfiles array
512 void D_AddFile (const char *file
, wad_source_t source
)
514 wadfiles
= realloc(wadfiles
, sizeof(*wadfiles
)*(numwadfiles
+1));
515 wadfiles
[numwadfiles
].name
=
516 AddDefaultExtension(strcpy(malloc(strlen(file
)+5), file
), ".wad");
517 wadfiles
[numwadfiles
].src
= source
; // Ty 08/29/98
524 // Verify a file is indeed tagged as an IWAD
525 // Scan its lumps for levelnames and return gamemode as indicated
526 // Detect missing wolf levels in DOOM II
528 // The filename to check is passed in iwadname, the gamemode detected is
529 // returned in gmode, hassec returns the presence of secret levels
531 // jff 4/19/98 Add routine to test IWAD for validity and determine
532 // the gamemode from it. Also note if DOOM II, whether secret levels exist
533 // CPhipps - const char* for iwadname, made static
535 static void CheckIWAD(const char *iwadname
,GameMode_t
*gmode
,boolean
*hassec
)
537 if ( !fileexists (iwadname
) )
539 int ud
=0,rg
=0,sw
=0,cm
=0,sc
=0;
542 // Identify IWAD correctly
543 if ( (handle
= open (iwadname
,O_RDONLY
)) != -1)
548 read (handle
, &header
, sizeof(header
));
549 if (!strncmp(header
.identification
,"IWAD",4))
552 filelump_t
*fileinfo
;
554 // read IWAD directory
555 header
.numlumps
= LONG(header
.numlumps
);
556 header
.infotableofs
= LONG(header
.infotableofs
);
557 length
= header
.numlumps
;
558 fileinfo
= malloc(length
*sizeof(filelump_t
));
559 lseek (handle
, header
.infotableofs
, SEEK_SET
);
560 read (handle
, fileinfo
, length
*sizeof(filelump_t
));
563 // scan directory for levelname lumps
565 if (fileinfo
[length
].name
[0] == 'E' &&
566 fileinfo
[length
].name
[2] == 'M' &&
567 fileinfo
[length
].name
[4] == 0)
569 if (fileinfo
[length
].name
[1] == '4')
571 else if (fileinfo
[length
].name
[1] == '3')
573 else if (fileinfo
[length
].name
[1] == '2')
575 else if (fileinfo
[length
].name
[1] == '1')
578 else if (fileinfo
[length
].name
[0] == 'M' &&
579 fileinfo
[length
].name
[1] == 'A' &&
580 fileinfo
[length
].name
[2] == 'P' &&
581 fileinfo
[length
].name
[5] == 0)
584 if (fileinfo
[length
].name
[3] == '3')
585 if (fileinfo
[length
].name
[4] == '1' ||
586 fileinfo
[length
].name
[4] == '2')
592 else // missing IWAD tag in header
593 I_Error("CheckIWAD: IWAD tag %s not present", iwadname
);
595 else // error from open call
596 I_Error("CheckIWAD: Can't open IWAD %s", iwadname
);
598 // Determine game mode from levels present
599 // Must be a full set for whichever mode is present
600 // Lack of wolf-3d levels also detected here
602 *gmode
= indetermined
;
616 else // error from access call
617 I_Error("CheckIWAD: IWAD %s not readable", iwadname
);
620 void D_DoomMainSetup(void)
624 nomonsters
= M_CheckParm ("-nomonsters");
625 respawnparm
= M_CheckParm ("-respawn");
626 fastparm
= M_CheckParm ("-fast");
627 devparm
= M_CheckParm ("-devparm");
628 if (M_CheckParm ("-altdeath"))
630 else if (M_CheckParm ("-deathmatch"))
633 printf("Welcome to Rockdoom\n");
638 printf ("The Ultimate DOOM Startup v%d.%d\n",DVERSION
/100,DVERSION
%100);
641 printf ("DOOM Shareware Startup v%d.%d\n",DVERSION
/100,DVERSION
%100);
644 printf ("DOOM Registered Startup v%d.%d\n",DVERSION
/100,DVERSION
%100);
650 printf ("DOOM 2: Plutonia Experiment v%d.%d\n",DVERSION
/100,DVERSION
%100);
653 printf ("DOOM 2: TNT - Evilution v%d.%d\n",DVERSION
/100,DVERSION
%100);
656 printf ("DOOM 2: Hell on Earth v%d.%d\n",DVERSION
/100,DVERSION
%100);
661 printf ("Public DOOM v%d.%d\n",DVERSION
/100,DVERSION
%100);
669 if ((p
=M_CheckParm ("-turbo")))
672 extern int forwardmove
[2];
673 extern int sidemove
[2];
676 scale
= atoi (myargv
[p
+1]);
681 printf ("turbo scale: %d%%\n",scale
);
682 forwardmove
[0] = forwardmove
[0]*scale
/100;
683 forwardmove
[1] = forwardmove
[1]*scale
/100;
684 sidemove
[0] = sidemove
[0]*scale
/100;
685 sidemove
[1] = sidemove
[1]*scale
/100;
688 // get skill / episode / map from parms
689 startskill
= sk_medium
;
694 p
= M_CheckParm ("-skill");
695 if (p
&& p
< myargc
-1)
697 startskill
= myargv
[p
+1][0]-'1';
701 p
= M_CheckParm ("-episode");
702 if (p
&& p
< myargc
-1)
704 startepisode
= myargv
[p
+1][0]-'0';
709 p
= M_CheckParm ("-warp");
710 if (p
&& p
< myargc
-1)
712 if (gamemode
== commercial
)
713 startmap
= atoi (myargv
[p
+1]);
716 startepisode
= myargv
[p
+1][0]-'0';
717 startmap
= myargv
[p
+2][0]-'0';
722 // CPhipps - move up netgame init
723 printf("D_InitNetGame: Checking for network game.\n");
727 printf ("V_Init: allocate screens.\n");
730 printf ("W_Init: Init WADfiles.\n");
733 if ((p
= W_CheckNumForName("DEHACKED")) != -1) // cph - add dehacked-in-a-wad support
734 ProcessDehFile(NULL
, dehout
? "/dehlog.txt" : NULL
, p
);
736 V_InitColorTranslation(); //jff 4/24/98 load color translation lumps
738 // Check for -file in shareware
741 // These are the lumps that will be checked in IWAD,
742 // if any one is not present, execution will be aborted.
743 const char name
[23][8]=
745 "e2m1","e2m2","e2m3","e2m4","e2m5","e2m6","e2m7","e2m8","e2m9",
746 "e3m1","e3m3","e3m3","e3m4","e3m5","e3m6","e3m7","e3m8","e3m9",
747 "dphoof","bfgga0","heada1","cybra1","spida1d1"
751 if ( gamemode
== shareware
)
752 I_Error("\nYou cannot -file with the shareware version. Register!\n");
754 // Check for fake IWAD with right name,
755 // but w/o all the lumps of the registered version.
756 if (gamemode
== registered
)
757 for (i
= 0;i
< 23; i
++)
758 if (W_CheckNumForName(name
[i
])<0)
759 I_Error("This is not the registered version.\n");
762 // Iff additonal PWAD files are used, print modified banner
764 printf ("ATTENTION: This version of DOOM has been modified.\n");
766 // Check and print which version is executed.
771 printf ("Shareware!\n");
776 printf ("Commercial product - do not distribute!\n");
783 printf ("M_Init: Init miscellaneous info.\n");
786 printf ("R_Init: Init DOOM refresh daemon - ");
789 printf ("P_Init: Init Playloop state.\n");
792 printf ("I_Init: Setting up machine state.\n");
795 printf ("S_Init: Setting up sound.\n");
796 S_Init (snd_SfxVolume
/* *8 */, snd_MusicVolume
/* *8*/ );
798 printf ("HU_Init: Setting up heads up display.\n");
803 printf ("ST_Init: Init status bar.\n");
806 // check for a driver that wants intermission stats
807 p
= M_CheckParm ("-statcopy");
810 // for statistics driver
811 extern void* statcopy
;
813 statcopy
= (void*)(long)atoi(myargv
[p
+1]);
814 printf ("External statistics registered.\n");
817 // start the apropriate game based on parms
818 p
= M_CheckParm ("-record");
819 if (p
&& p
< myargc
-1)
821 G_RecordDemo (myargv
[p
+1]);
825 p
= M_CheckParm ("-loadgame");
826 if (p
&& p
< myargc
-1)
827 G_LoadGame (atoi(myargv
[p
+1]), false);
829 if ( gameaction
!= ga_loadgame
)
831 if (!singledemo
) { /* killough 12/98 */
832 if (autostart
|| netgame
)
833 G_InitNew (startskill
, startepisode
, startmap
);
835 D_StartTitle (); // start up intro loop
843 void D_DoomMain (void)
845 D_DoomMainSetup(); // get this crap off the stack
847 D_DoomLoop (); // never returns