Update the discussion of themeing in the manual, and put a note in the wps tags appen...
[kugel-rb.git] / apps / plugins / doom / d_main.c
blobf58d1aae4a5f80d065cb6277c55f6995b04a228b
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
25 * 02111-1307, USA.
27 * DESCRIPTION:
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"
39 #include "doomdef.h"
40 #include "doomtype.h"
41 #include "doomstat.h"
42 #include "dstrings.h"
43 #include "sounds.h"
44 #include "z_zone.h"
45 #include "w_wad.h"
46 #include "s_sound.h"
47 #include "v_video.h"
48 #include "f_finale.h"
49 #include "f_wipe.h"
50 #include "m_argv.h"
51 #include "m_misc.h"
52 #include "m_menu.h"
53 #include "i_system.h"
54 #include "i_sound.h"
55 #include "i_video.h"
56 #include "g_game.h"
57 #include "hu_stuff.h"
58 #include "wi_stuff.h"
59 #include "st_stuff.h"
60 #include "am_map.h"
61 #include "p_setup.h"
62 #include "r_draw.h"
63 #include "r_main.h"
64 #include "d_main.h"
65 #include "d_deh.h" // Ty 04/08/98 - Externalizations
66 #include "am_map.h"
67 #include "m_swap.h"
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
85 boolean dehout=true;
87 boolean singletics = false; // debug flag to cancel adaptiveness
89 bool doomexit;
91 //jff 1/22/98 parms for disabling music and sound
92 boolean nomusicparm=0;
94 //jff 4/18/98
95 extern boolean inhelpscreens;
97 skill_t startskill;
98 int startepisode;
99 int startmap;
100 boolean autostart;
101 int debugfile;
102 int ffmap;
104 boolean advancedemo;
106 extern boolean timingdemo, singledemo, demoplayback, fastdemo; // killough
108 int basetic;
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 */
123 if (gametic < 3)
124 return;
126 if(!M_Responder(ev)) {
127 if(gamestate == GS_LEVEL && (
128 HU_Responder(ev) ||
129 ST_Responder(ev) ||
130 AM_Responder(ev)
132 return;
133 else
134 G_Responder(ev);
139 // D_Wipe
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)
147 boolean done;
148 int wipestart = I_GetTime () - 1;
152 int nowtime, tics;
155 //I_uSleep(5000); // CPhipps - don't thrash cpu in this loop
156 nowtime = I_GetTime();
157 tics = nowtime - wipestart;
159 while (!tics);
160 wipestart = nowtime;
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
166 while (!done);
170 // D_Display
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;
185 boolean wipe;
186 boolean viewactive = false, isborder = false;
188 if (nodrawers) // for comparative timing / profiling
189 return;
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) {
197 case (gamestate_t)-1:
198 case GS_LEVEL:
199 V_SetPalette(0); // cph - use default (basic) palette
200 default:
201 break;
204 switch (gamestate) {
205 case GS_INTERMISSION:
206 WI_Drawer();
207 break;
208 case GS_FINALE:
209 F_Drawer();
210 break;
211 case GS_DEMOSCREEN:
212 D_PageDrawer();
213 break;
214 default:
215 break;
217 } else if (gametic != basetic) { // In a level
218 boolean redrawborderstuff;
220 HU_Erase();
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;
234 } else {
235 // CPhipps -
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)
245 R_DrawViewBorder();
247 // Now do the drawing
248 if (viewactive)
249 R_RenderPlayerView (&players[displayplayer]);
250 if (automapmode & am_active)
251 AM_Drawer();
252 ST_Drawer((viewheight != SCREENHEIGHT) || ((automapmode & am_active) && !(automapmode & am_overlay)), redrawborderstuff);
253 R_DrawViewBorder();
255 HU_Drawer();
258 inhelpscreensstate = inhelpscreens;
259 isborderstate = isborder;
260 oldgamestate = wipegamestate = gamestate;
262 // draw pause pic
263 if (paused) {
264 static int x;
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
281 D_BuildNewTiccmds();
283 // normal update
284 if (!wipe)
285 I_FinishUpdate (); // page flip or blit buffer
286 else {
287 // wipe update
288 wipe_EndScreen(0, 0, SCREENWIDTH, SCREENHEIGHT);
289 D_Wipe();
294 // D_DoomLoop()
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)
308 basetic = gametic;
310 I_SubmitSound();
312 while (!doomexit)
314 // process one or more tics
315 if (singletics)
317 I_StartTic ();
318 G_BuildTiccmd (&netcmds[consoleplayer][maketic%BACKUPTICS]);
319 if (advancedemo)
320 D_DoAdvanceDemo ();
321 M_Ticker ();
322 G_Ticker ();
323 gametic++;
324 maketic++;
326 else
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.
334 D_Display();
336 // Give the system some time
337 rb->yield();
342 // DEMO LOOP
345 static int demosequence; // killough 5/2/98: made static
346 static int pagetic;
347 static const char *pagename; // CPhipps - const
350 // D_PageTicker
351 // Handles timing for warped projection
353 void D_PageTicker(void)
355 if (--pagetic < 0)
356 D_AdvanceDemo();
360 // D_PageDrawer
362 void D_PageDrawer(void)
364 // CPhipps - updated for new patch drawing
365 V_DrawNamePatch(0, 0, 0, pagename, CR_DEFAULT, VPT_STRETCH);
369 // D_AdvanceDemo
370 // Called after each demo or intro demosequence finishes
372 void D_AdvanceDemo (void)
374 advancedemo = true;
377 /* killough 11/98: functions to perform demo sequences
378 * cphipps 10/99: constness fixes
381 static void D_SetPageName(const char *name)
383 pagename = name;
386 static void D_DrawTitle1(const char *name)
388 S_StartMusic(mus_intro);
389 pagetic = (TICRATE*170)/35;
390 D_SetPageName(name);
393 static void D_DrawTitle2(const char *name)
395 S_StartMusic(mus_dm2ttl);
396 D_SetPageName(name);
399 /* killough 11/98: tabulate demo sequences
402 static struct
404 void (*func)(const char *);
405 const char *name;
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"},
450 {NULL,0},
451 {NULL,0},
452 {NULL,0},
453 {D_SetPageName, "CREDIT"},
457 {NULL,0},
458 {NULL,0},
459 {NULL,0},
460 {G_DeferedPlayDemo, "demo4"},
464 {NULL,0},
465 {NULL,0},
466 {NULL,0},
467 {NULL,0},
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) {
486 demosequence = 0;
487 } else
488 if (!demostates[++demosequence][gamemode].func)
489 demosequence = 0;
490 demostates[demosequence][gamemode].func(demostates[demosequence][gamemode].name);
494 // D_StartTitle
496 void D_StartTitle (void)
498 gameaction = ga_nothing;
499 demosequence = -1;
500 D_AdvanceDemo();
504 // D_AddFile
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
518 numwadfiles++;
522 // CheckIWAD
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
534 #if 0
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;
540 int handle;
542 // Identify IWAD correctly
543 if ( (handle = open (iwadname,O_RDONLY)) != -1)
545 wadinfo_t header;
547 // read IWAD header
548 read (handle, &header, sizeof(header));
549 if (!strncmp(header.identification,"IWAD",4))
551 size_t length;
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));
561 close(handle);
563 // scan directory for levelname lumps
564 while (length--)
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')
570 ++ud;
571 else if (fileinfo[length].name[1] == '3')
572 ++rg;
573 else if (fileinfo[length].name[1] == '2')
574 ++rg;
575 else if (fileinfo[length].name[1] == '1')
576 ++sw;
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)
583 ++cm;
584 if (fileinfo[length].name[3] == '3')
585 if (fileinfo[length].name[4] == '1' ||
586 fileinfo[length].name[4] == '2')
587 ++sc;
590 free(fileinfo);
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;
603 *hassec = false;
604 if (cm>=30)
606 *gmode = commercial;
607 *hassec = sc>=2;
609 else if (ud>=9)
610 *gmode = retail;
611 else if (rg>=18)
612 *gmode = registered;
613 else if (sw>=9)
614 *gmode = shareware;
616 else // error from access call
617 I_Error("CheckIWAD: IWAD %s not readable", iwadname);
619 #endif
620 void D_DoomMainSetup(void)
622 int p;
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"))
629 deathmatch = 2;
630 else if (M_CheckParm ("-deathmatch"))
631 deathmatch = 1;
633 printf("Welcome to Rockdoom\n");
635 switch ( gamemode )
637 case retail:
638 printf ("The Ultimate DOOM Startup v%d.%d\n",DVERSION/100,DVERSION%100);
639 break;
640 case shareware:
641 printf ("DOOM Shareware Startup v%d.%d\n",DVERSION/100,DVERSION%100);
642 break;
643 case registered:
644 printf ("DOOM Registered Startup v%d.%d\n",DVERSION/100,DVERSION%100);
645 break;
646 case commercial:
647 switch (gamemission)
649 case pack_plut:
650 printf ("DOOM 2: Plutonia Experiment v%d.%d\n",DVERSION/100,DVERSION%100);
651 break;
652 case pack_tnt:
653 printf ("DOOM 2: TNT - Evilution v%d.%d\n",DVERSION/100,DVERSION%100);
654 break;
655 default:
656 printf ("DOOM 2: Hell on Earth v%d.%d\n",DVERSION/100,DVERSION%100);
657 break;
659 break;
660 default:
661 printf ("Public DOOM v%d.%d\n",DVERSION/100,DVERSION%100);
662 break;
665 if (devparm)
666 printf(D_DEVSTR);
668 // turbo option
669 if ((p=M_CheckParm ("-turbo")))
671 int scale = 200;
672 extern int forwardmove[2];
673 extern int sidemove[2];
675 if (p<myargc-1)
676 scale = atoi (myargv[p+1]);
677 if (scale < 10)
678 scale = 10;
679 if (scale > 400)
680 scale = 400;
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;
690 startepisode = 1;
691 startmap = 1;
692 autostart = false;
694 p = M_CheckParm ("-skill");
695 if (p && p < myargc-1)
697 startskill = myargv[p+1][0]-'1';
698 autostart = true;
701 p = M_CheckParm ("-episode");
702 if (p && p < myargc-1)
704 startepisode = myargv[p+1][0]-'0';
705 startmap = 1;
706 autostart = true;
709 p = M_CheckParm ("-warp");
710 if (p && p < myargc-1)
712 if (gamemode == commercial)
713 startmap = atoi (myargv[p+1]);
714 else
716 startepisode = myargv[p+1][0]-'0';
717 startmap = myargv[p+2][0]-'0';
719 autostart = true;
722 // CPhipps - move up netgame init
723 printf("D_InitNetGame: Checking for network game.\n");
724 D_InitNetGame();
726 // init subsystems
727 printf ("V_Init: allocate screens.\n");
728 V_Init ();
730 printf ("W_Init: Init WADfiles.\n");
731 W_Init();
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
739 if (modifiedgame)
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"
749 int i;
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
763 if (modifiedgame)
764 printf ("ATTENTION: This version of DOOM has been modified.\n");
766 // Check and print which version is executed.
767 switch ( gamemode )
769 case shareware:
770 case indetermined:
771 printf ("Shareware!\n");
772 break;
773 case registered:
774 case retail:
775 case commercial:
776 printf ("Commercial product - do not distribute!\n");
777 break;
778 default:
779 // Ouch.
780 break;
783 printf ("M_Init: Init miscellaneous info.\n");
784 M_Init ();
786 printf ("R_Init: Init DOOM refresh daemon - ");
787 R_Init ();
789 printf ("P_Init: Init Playloop state.\n");
790 P_Init ();
792 printf ("I_Init: Setting up machine state.\n");
793 I_Init ();
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");
799 HU_Init ();
801 I_InitGraphics ();
803 printf ("ST_Init: Init status bar.\n");
804 ST_Init ();
806 // check for a driver that wants intermission stats
807 p = M_CheckParm ("-statcopy");
808 if (p && p<myargc-1)
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]);
822 autostart = true;
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);
834 else
835 D_StartTitle (); // start up intro loop
841 // D_DoomMain
843 void D_DoomMain (void)
845 D_DoomMainSetup(); // get this crap off the stack
847 D_DoomLoop (); // never returns