1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
6 // Copyright (C) 1993-1996 by id Software, Inc.
8 // This source is available for distribution and/or modification
9 // only under the terms of the DOOM Source Code License as
10 // published by id Software. All rights reserved.
12 // The source is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
20 // DOOM main program (D_DoomMain) and game loop (D_DoomLoop),
21 // plus functions to determine game mode (shareware, registered),
22 // parse command line parameters, configure game parameters (turbo),
23 // and call the startup functions.
25 //-----------------------------------------------------------------------------
28 static const char rcsid[] = "$Id: d_main.c,v 1.8 1997/02/03 22:45:09 b1 Exp $";
71 // Not a globally visible function,
72 // just included for source reference,
73 // called by D_DoomMain, never exits.
74 // Manages timing and IO,
75 // calls all ?_Responder, ?_Ticker, and ?_Drawer,
76 // calls I_GetTime, I_StartFrame, and I_StartTic
78 void D_DoomLoop (void);
81 char* wadfiles[MAXWADFILES];
84 boolean devparm; // started game with -devparm
85 boolean nomonsters; // checkparm of -nomonsters
86 boolean respawnparm; // checkparm of -respawn
87 boolean fastparm; // checkparm of -fast
91 boolean singletics = false; // debug flag to cancel adaptiveness
93 /* bug compatibility with various versions of doom */
98 //extern int soundVolume;
99 //extern int sfxVolume;
100 //extern int musicVolume;
102 extern boolean inhelpscreens;
116 char wadfile[1024]; // primary wad file
117 char mapdir[1024]; // directory of development maps
118 char basedefault[1024]; // default file
121 void D_CheckNetGame (void);
122 void D_ProcessEvents (void);
123 void G_BuildTiccmd (ticcmd_t* cmd);
124 void D_DoAdvanceDemo (void);
130 // Events are asynchronous inputs generally generated by the game user.
131 // Events can be discarded if no responder claims them
133 event_t events[MAXEVENTS];
141 // Called by the I/O functions when input is detected
143 void D_PostEvent (event_t* ev)
149 next = (eventhead+1)&(MAXEVENTS-1);
150 if(next == eventtail){
152 if(ev->type != ev_keydown && ev->type != ev_keyup)
157 events[eventhead] = *ev;
165 // Send all the events of the given timestamp down the responder chain
167 void D_ProcessEvents (void)
171 // IF STORE DEMO, DO NOT ACCEPT INPUT
172 if ( ( gamemode == commercial )
173 && (W_CheckNumForName("map01")<0) )
176 for ( ; eventtail != eventhead ; eventtail = (eventtail+1)&(MAXEVENTS-1))
178 ev = &events[eventtail];
179 if (M_Responder (ev))
180 continue; // menu ate the event
190 // draw current display, possibly wiping it from the previous
193 // wipegamestate can be set to -1 to force a wipe on the next draw
194 gamestate_t wipegamestate = GS_DEMOSCREEN;
195 extern boolean setsizeneeded;
196 extern int showMessages;
197 void R_ExecuteSetViewSize (void);
199 void D_Display (void)
201 static boolean viewactivestate = false;
202 static boolean menuactivestate = false;
203 static boolean inhelpscreensstate = false;
204 static boolean fullscreen = false;
205 static gamestate_t oldgamestate = -1;
206 static int borderdrawcount;
216 return; // for comparative timing / profiling
220 // change the view size if needed
223 R_ExecuteSetViewSize ();
224 oldgamestate = -1; // force background redraw
228 // save the current screen if about to wipe
229 if (gamestate != wipegamestate)
232 wipe_StartScreen(0, 0, SCREENWIDTH, SCREENHEIGHT);
237 if (gamestate == GS_LEVEL && gametic)
240 // do buffered drawing
248 if (wipe || (viewheight != 200 && fullscreen) )
250 if (inhelpscreensstate && !inhelpscreens)
251 redrawsbar = true; // just put away the help screen
252 ST_Drawer (viewheight == 200, redrawsbar );
253 fullscreen = viewheight == 200;
256 case GS_INTERMISSION:
269 // draw buffered stuff to screen
272 // draw the view directly
273 if (gamestate == GS_LEVEL && !automapactive && gametic)
274 R_RenderPlayerView (&players[displayplayer]);
276 if (gamestate == GS_LEVEL && gametic)
279 // clean up border stuff
280 if (gamestate != oldgamestate && gamestate != GS_LEVEL)
281 I_SetPalette (W_CacheLumpName ("PLAYPAL",PU_CACHE));
283 // see if the border needs to be initially drawn
284 if (gamestate == GS_LEVEL && oldgamestate != GS_LEVEL)
286 viewactivestate = false; // view was not active
287 R_FillBackScreen (); // draw the pattern into the back screen
290 // see if the border needs to be updated to the screen
291 if (gamestate == GS_LEVEL && !automapactive && scaledviewwidth != 320)
293 if (menuactive || menuactivestate || !viewactivestate)
297 R_DrawViewBorder (); // erase old menu stuff
303 menuactivestate = menuactive;
304 viewactivestate = viewactive;
305 inhelpscreensstate = inhelpscreens;
306 oldgamestate = wipegamestate = gamestate;
315 V_DrawPatchDirect(viewwindowx+(scaledviewwidth-68)/2,
316 y,0,W_CacheLumpName ("M_PAUSE", PU_CACHE));
320 // menus go directly to the screen
321 M_Drawer (); // menu is drawn even on top of everything
322 NetUpdate (); // send out any new accumulation
328 I_FinishUpdate (); // page flip or blit buffer
334 wipe_EndScreen(0, 0, SCREENWIDTH, SCREENHEIGHT);
336 wipestart = I_GetTime () - 1;
342 nowtime = I_GetTime ();
343 tics = nowtime - wipestart;
346 done = wipe_ScreenWipe(wipe_Melt
347 , 0, 0, SCREENWIDTH, SCREENHEIGHT, tics);
349 M_Drawer (); // menu is drawn even on top of wipes
350 I_FinishUpdate (); // page flip or blit buffer
361 extern boolean demorecording;
363 void D_DoomLoop (void)
368 if (M_CheckParm ("-debugfile"))
371 sprintf (filename,"debug%i.txt",consoleplayer);
372 printf ("debug output to: %s\n",filename);
373 debugfile = fopen (filename,"w");
378 // frame syncronous IO operations
381 // process one or more tics
386 G_BuildTiccmd (&netcmds[consoleplayer][maketic%BACKUPTICS]);
396 TryRunTics (); // will run at least one tic
399 S_UpdateSounds (players[consoleplayer].mo);// move positional sounds
401 // Update display, next frame, with current state.
418 // Handles timing for warped projection
420 void D_PageTicker (void)
431 void D_PageDrawer (void)
433 V_DrawPatch (0,0, 0, W_CacheLumpName(pagename, PU_CACHE));
439 // Called after each demo or intro demosequence finishes
441 void D_AdvanceDemo (void)
448 // This cycles through the demo sequences.
449 // FIXME - version dependend demo numbers?
451 void D_DoAdvanceDemo (void)
453 players[consoleplayer].playerstate = PST_LIVE; // not reborn
455 usergame = false; // no save / end game here
457 gameaction = ga_nothing;
459 if ( gamemode == retail )
460 demosequence = (demosequence+1)%7;
462 demosequence = (demosequence+1)%6;
464 switch (demosequence)
467 if ( gamemode == commercial )
471 gamestate = GS_DEMOSCREEN;
472 pagename = "TITLEPIC";
473 if ( gamemode == commercial )
474 S_StartMusic(mus_dm2ttl);
476 S_StartMusic (mus_intro);
479 G_DeferedPlayDemo ("demo1");
483 gamestate = GS_DEMOSCREEN;
487 G_DeferedPlayDemo ("demo2");
490 gamestate = GS_DEMOSCREEN;
491 if ( gamemode == commercial)
494 pagename = "TITLEPIC";
495 S_StartMusic(mus_dm2ttl);
501 if ( gamemode == retail )
508 G_DeferedPlayDemo ("demo3");
510 // THE DEFINITIVE DOOM Special Edition demo
512 G_DeferedPlayDemo ("demo4");
522 void D_StartTitle (void)
524 gameaction = ga_nothing;
532 // print title for every printed line
540 void D_AddFile (char *file)
545 for (numwadfiles = 0 ; wadfiles[numwadfiles] ; numwadfiles++)
548 newfile = malloc (strlen(file)+1);
549 strcpy (newfile, file);
551 wadfiles[numwadfiles] = newfile;
557 // Checks availability of IWAD files by name,
558 // to determine whether registered/commercial features
559 // should be executed (notably loading PWAD's).
561 void IdentifyVersion (void)
563 char *wadfile, *slash;
565 if (M_CheckParm ("-shdev"))
567 I_Error("PORTME d_main.c IdentifyVersion -shdev");
569 gamemode = shareware;
571 D_AddFile (DEVDATA"doom1.wad");
572 D_AddFile (DEVMAPS"data_se/texture1.lmp");
573 D_AddFile (DEVMAPS"data_se/pnames.lmp");
574 strcpy (basedefault,DEVDATA"default.cfg");
579 if (M_CheckParm ("-regdev"))
581 I_Error("PORTME d_main.c IdentifyVersion -regdev");
583 gamemode = registered;
585 D_AddFile (DEVDATA"doom.wad");
586 D_AddFile (DEVMAPS"data_se/texture1.lmp");
587 D_AddFile (DEVMAPS"data_se/texture2.lmp");
588 D_AddFile (DEVMAPS"data_se/pnames.lmp");
589 strcpy (basedefault,DEVDATA"default.cfg");
594 if (M_CheckParm ("-comdev"))
596 I_Error("PORTME d_main.c IdentifyVersion -comdev");
598 gamemode = commercial;
600 D_AddFile (DEVDATA"doom2.wad");
601 D_AddFile (DEVMAPS"cdata/texture1.lmp");
602 D_AddFile (DEVMAPS"cdata/pnames.lmp");
603 strcpy (basedefault,DEVDATA"default.cfg");
608 if ( (wadfile = I_IdentifyWAD("doom2f.wad")) ) {
609 gamemode = commercial;
611 // Let's handle languages in config files, okay?
613 printf("French version\n");
615 } else if ( (wadfile = I_IdentifyWAD("doom2.wad")) ) {
616 gamemode = commercial;
618 } else if ( (wadfile = I_IdentifyWAD("plutonia.wad")) ) {
619 gamemode = commercial;
621 } else if ( (wadfile = I_IdentifyWAD("tnt.wad")) ) {
622 gamemode = commercial;
624 } else if ( (wadfile = I_IdentifyWAD("doomu.wad")) ) {
627 } else if ( (wadfile = I_IdentifyWAD("doom.wad")) ) {
628 gamemode = registered;
630 } else if ( (wadfile = I_IdentifyWAD("doom1.wad")) ) {
631 gamemode = shareware;
634 printf("Game mode indeterminate.\n");
635 gamemode = indetermined;
638 strncpy(basedefault, wadfile, sizeof(basedefault)-5);
639 basedefault[sizeof(basedefault)-5] = '\0';
640 slash = strrchr(basedefault, '/');
643 strcpy(slash, "cfg");
647 // Find a Response File
649 void FindResponseFile (void)
654 for (i = 1;i < myargc;i++)
655 if (myargv[i][0] == '@')
667 // READ THE RESPONSE FILE INTO MEMORY
668 handle = fopen (&myargv[i][1],"rb");
671 fprint(2, "No such response file!\n");
674 printf("Found response file %s!\n",&myargv[i][1]);
675 fseek (handle,0,SEEK_END);
676 size = ftell(handle);
677 fseek (handle,0,SEEK_SET);
678 file = malloc (size);
679 fread (file,size,1,handle);
682 // KEEP ALL CMDLINE ARGS FOLLOWING @RESPONSEFILE ARG
683 for (index = 0,k = i+1; k < myargc; k++)
684 moreargs[index++] = myargv[k];
686 firstargv = myargv[0];
687 myargv = malloc(sizeof(char *)*MAXARGVS);
688 memset(myargv,0,sizeof(char *)*MAXARGVS);
689 myargv[0] = firstargv;
693 indexinfile++; // SKIP PAST ARGV[0] (KEEP IT)
696 myargv[indexinfile++] = infile+k;
698 ((*(infile+k)>= ' '+1) && (*(infile+k)<='z')))
702 ((*(infile+k)<= ' ') || (*(infile+k)>'z')))
706 for (k = 0;k < index;k++)
707 myargv[indexinfile++] = moreargs[k];
708 myargc = indexinfile;
711 printf("%d command-line args:\n",myargc);
712 for (k=1;k<myargc;k++)
713 printf("%s\n",myargv[k]);
723 void D_DoomMain (void)
732 setbuf (stdout, NULL);
733 modifiedgame = false;
735 nomonsters = M_CheckParm ("-nomonsters");
736 respawnparm = M_CheckParm ("-respawn");
737 fastparm = M_CheckParm ("-fast");
738 devparm = M_CheckParm ("-devparm");
739 if (M_CheckParm ("-noztele") && gamemode == commercial)
741 if (M_CheckParm ("-nobounce") && (gamemode == commercial || gamemode == registered))
743 if (M_CheckParm ("-altdeath"))
745 else if (M_CheckParm ("-deathmatch"))
753 "The Ultimate DOOM Startup v%i.%i"
755 VERSION/100,VERSION%100);
760 "DOOM Shareware Startup v%i.%i"
762 VERSION/100,VERSION%100);
767 "DOOM Registered Startup v%i.%i"
769 VERSION/100,VERSION%100);
774 "DOOM 2: Hell on Earth v%i.%i"
776 VERSION/100,VERSION%100);
782 "DOOM 2: Plutonia Experiment v%i.%i"
784 VERSION/100,VERSION%100);
789 "DOOM 2: TNT - Evilution v%i.%i"
791 VERSION/100,VERSION%100);
797 "Public DOOM - v%i.%i"
799 VERSION/100,VERSION%100);
803 printf ("%s\n",title);
809 if ( (p=M_CheckParm ("-turbo")) )
812 extern int forwardmove[2];
813 extern int sidemove[2];
816 scale = atoi (myargv[p+1]);
821 printf ("turbo scale: %i%%\n",scale);
822 forwardmove[0] = forwardmove[0]*scale/100;
823 forwardmove[1] = forwardmove[1]*scale/100;
824 sidemove[0] = sidemove[0]*scale/100;
825 sidemove[1] = sidemove[1]*scale/100;
828 // add any files specified on the command line with -file wadfile
831 // convenience hack to allow -wart e m to add a wad file
832 // prepend a tilde to the filename so wadfile will be reloadable
833 p = M_CheckParm ("-wart");
836 myargv[p][4] = 'p'; // big hack, change to -warp
838 // Map name handling.
844 sprintf (file,"~"DEVMAPS"E%cM%c.wad",
845 myargv[p+1][0], myargv[p+2][0]);
846 printf("Warping to Episode %s, Map %s.\n",
847 myargv[p+1],myargv[p+2]);
852 p = atoi (myargv[p+1]);
854 sprintf (file,"~"DEVMAPS"cdata/map0%i.wad", p);
856 sprintf (file,"~"DEVMAPS"cdata/map%i.wad", p);
862 p = M_CheckParm ("-file");
865 // the parms after p are wadfile/lump names,
866 // until end of parms or another - preceded parm
867 modifiedgame = true; // homebrew levels
868 while (++p != myargc && myargv[p][0] != '-')
869 D_AddFile (myargv[p]);
872 p = M_CheckParm ("-playdemo");
875 p = M_CheckParm ("-timedemo");
877 if (p && p < myargc-1)
879 sprintf (file,"%s.lmp", myargv[p+1]);
881 printf("Playing demo %s.lmp.\n",myargv[p+1]);
884 // get skill / episode / map from parms
885 startskill = sk_medium;
891 p = M_CheckParm ("-skill");
892 if (p && p < myargc-1)
894 startskill = myargv[p+1][0]-'1';
898 p = M_CheckParm ("-episode");
899 if (p && p < myargc-1)
901 startepisode = myargv[p+1][0]-'0';
906 p = M_CheckParm ("-timer");
907 if (p && p < myargc-1 && deathmatch)
910 time = atoi(myargv[p+1]);
911 printf("Levels will end after %d minute",time);
917 p = M_CheckParm ("-avg");
918 if (p && p < myargc-1 && deathmatch)
919 printf("Austin Virtual Gaming: Levels will end after 20 minutes\n");
921 p = M_CheckParm ("-warp");
922 if (p && p < myargc-1)
924 startmap = atoi (myargv[p+1]);
925 if (gamemode != commercial){
926 startepisode = startmap / 10;
933 printf ("V_Init: allocate screens.\n");
936 printf ("M_LoadDefaults: Load system defaults.\n");
937 M_LoadDefaults (); // load before initing other systems
939 printf ("Z_Init: Init zone memory allocation daemon. \n");
942 printf ("W_Init: Init WADfiles.\n");
943 W_InitMultipleFiles (wadfiles);
946 // Check for -file in shareware
949 // These are the lumps that will be checked in IWAD,
950 // if any one is not present, execution will be aborted.
953 "e2m1","e2m2","e2m3","e2m4","e2m5","e2m6","e2m7","e2m8","e2m9",
954 "e3m1","e3m3","e3m3","e3m4","e3m5","e3m6","e3m7","e3m8","e3m9",
955 "dphoof","bfgga0","heada1","cybra1","spida1d1"
959 if ( gamemode == shareware)
960 I_Error("\nYou cannot -file with the shareware "
961 "version. Register!");
963 // Check for fake IWAD with right name,
964 // but w/o all the lumps of the registered version.
965 if (gamemode == registered)
966 for (i = 0;i < 23; i++)
967 if (W_CheckNumForName(name[i])<0)
968 I_Error("\nThis is not the registered version.");
971 // Iff additonal PWAD files are used, print modified banner
975 "===========================================================================\n"
976 "ATTENTION: This version of DOOM has been modified. If you would like to\n"
977 "get a copy of the original game, call 1-800-IDGAMES or see the readme file.\n"
978 " You will not receive technical support for modified games.\n"
979 " press enter to continue\n"
980 "===========================================================================\n"
986 // Check and print which version is executed.
992 "===========================================================================\n"
994 "===========================================================================\n"
1001 "===========================================================================\n"
1002 " Commercial product - do not distribute!\n"
1003 " Please report software piracy to the SPA: 1-800-388-PIR8\n"
1004 "===========================================================================\n"
1013 printf ("M_Init: Init miscellaneous info.\n");
1016 printf ("R_Init: Init DOOM refresh daemon - ");
1019 printf ("\nP_Init: Init Playloop state.\n");
1022 printf ("I_Init: Setting up machine state.\n");
1025 printf ("D_CheckNetGame: Checking network game status.\n");
1028 printf ("S_Init: Setting up sound.\n");
1029 S_Init (snd_SfxVolume /* *8 */, snd_MusicVolume /* *8*/ );
1031 printf ("HU_Init: Setting up heads up display.\n");
1034 printf ("ST_Init: Init status bar.\n");
1037 // check for a driver that wants intermission stats
1038 p = M_CheckParm ("-statcopy");
1039 if (p && p<myargc-1)
1041 // for statistics driver
1042 extern void* statcopy;
1044 statcopy = (void*)atoi(myargv[p+1]);
1045 printf ("External statistics registered.\n");
1048 // start the apropriate game based on parms
1049 p = M_CheckParm ("-record");
1051 if (p && p < myargc-1)
1053 G_RecordDemo (myargv[p+1]);
1057 p = M_CheckParm ("-playdemo");
1058 if (p && p < myargc-1)
1060 singledemo = true; // quit after one demo
1061 G_DeferedPlayDemo (myargv[p+1]);
1062 D_DoomLoop (); // never returns
1065 p = M_CheckParm ("-timedemo");
1066 if (p && p < myargc-1)
1068 G_TimeDemo (myargv[p+1]);
1069 D_DoomLoop (); // never returns
1072 p = M_CheckParm ("-loadgame");
1073 if (p && p < myargc-1)
1075 sprintf(file, SAVEGAMENAME"%c.dsg",myargv[p+1][0]);
1080 if ( gameaction != ga_loadgame )
1082 if (autostart || netgame)
1083 G_InitNew (startskill, startepisode, startmap);
1085 D_StartTitle (); // start up intro loop
1089 D_DoomLoop (); // never returns