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
333 wipe_EndScreen(0, 0, SCREENWIDTH, SCREENHEIGHT);
335 wipestart = I_GetTime () - 1;
341 nowtime = I_GetTime ();
342 tics = nowtime - wipestart;
345 done = wipe_ScreenWipe(wipe_Melt
346 , 0, 0, SCREENWIDTH, SCREENHEIGHT, tics);
348 M_Drawer (); // menu is drawn even on top of wipes
349 I_FinishUpdate (); // page flip or blit buffer
358 extern boolean demorecording;
360 void D_DoomLoop (void)
365 if (M_CheckParm ("-debugfile"))
368 sprintf (filename,"debug%i.txt",consoleplayer);
369 printf ("debug output to: %s\n",filename);
370 debugfile = fopen (filename,"w");
375 // frame syncronous IO operations
378 // process one or more tics
383 G_BuildTiccmd (&netcmds[consoleplayer][maketic%BACKUPTICS]);
393 TryRunTics (); // will run at least one tic
396 S_UpdateSounds (players[consoleplayer].mo);// move positional sounds
398 // Update display, next frame, with current state.
401 // Sound mixing for the buffer is snychronous.
404 // Update sound output.
421 // Handles timing for warped projection
423 void D_PageTicker (void)
434 void D_PageDrawer (void)
436 V_DrawPatch (0,0, 0, W_CacheLumpName(pagename, PU_CACHE));
442 // Called after each demo or intro demosequence finishes
444 void D_AdvanceDemo (void)
451 // This cycles through the demo sequences.
452 // FIXME - version dependend demo numbers?
454 void D_DoAdvanceDemo (void)
456 players[consoleplayer].playerstate = PST_LIVE; // not reborn
458 usergame = false; // no save / end game here
460 gameaction = ga_nothing;
462 if ( gamemode == retail )
463 demosequence = (demosequence+1)%7;
465 demosequence = (demosequence+1)%6;
467 switch (demosequence)
470 if ( gamemode == commercial )
474 gamestate = GS_DEMOSCREEN;
475 pagename = "TITLEPIC";
476 if ( gamemode == commercial )
477 S_StartMusic(mus_dm2ttl);
479 S_StartMusic (mus_intro);
482 G_DeferedPlayDemo ("demo1");
486 gamestate = GS_DEMOSCREEN;
490 G_DeferedPlayDemo ("demo2");
493 gamestate = GS_DEMOSCREEN;
494 if ( gamemode == commercial)
497 pagename = "TITLEPIC";
498 S_StartMusic(mus_dm2ttl);
504 if ( gamemode == retail )
511 G_DeferedPlayDemo ("demo3");
513 // THE DEFINITIVE DOOM Special Edition demo
515 G_DeferedPlayDemo ("demo4");
525 void D_StartTitle (void)
527 gameaction = ga_nothing;
535 // print title for every printed line
543 void D_AddFile (char *file)
548 for (numwadfiles = 0 ; wadfiles[numwadfiles] ; numwadfiles++)
551 newfile = malloc (strlen(file)+1);
552 strcpy (newfile, file);
554 wadfiles[numwadfiles] = newfile;
560 // Checks availability of IWAD files by name,
561 // to determine whether registered/commercial features
562 // should be executed (notably loading PWAD's).
564 void IdentifyVersion (void)
568 if (M_CheckParm ("-shdev"))
570 I_Error("PORTME d_main.c IdentifyVersion -shdev");
572 gamemode = shareware;
574 D_AddFile (DEVDATA"doom1.wad");
575 D_AddFile (DEVMAPS"data_se/texture1.lmp");
576 D_AddFile (DEVMAPS"data_se/pnames.lmp");
577 strcpy (basedefault,DEVDATA"default.cfg");
582 if (M_CheckParm ("-regdev"))
584 I_Error("PORTME d_main.c IdentifyVersion -regdev");
586 gamemode = registered;
588 D_AddFile (DEVDATA"doom.wad");
589 D_AddFile (DEVMAPS"data_se/texture1.lmp");
590 D_AddFile (DEVMAPS"data_se/texture2.lmp");
591 D_AddFile (DEVMAPS"data_se/pnames.lmp");
592 strcpy (basedefault,DEVDATA"default.cfg");
597 if (M_CheckParm ("-comdev"))
599 I_Error("PORTME d_main.c IdentifyVersion -comdev");
601 gamemode = commercial;
603 D_AddFile (DEVDATA"doom2.wad");
604 D_AddFile (DEVMAPS"cdata/texture1.lmp");
605 D_AddFile (DEVMAPS"cdata/pnames.lmp");
606 strcpy (basedefault,DEVDATA"default.cfg");
611 if ( (wadfile = I_IdentifyWAD("doom2f.wad")) ) {
612 gamemode = commercial;
614 // Let's handle languages in config files, okay?
616 printf("French version\n");
619 } else if ( (wadfile = I_IdentifyWAD("doom2.wad")) ) {
620 gamemode = commercial;
623 } else if ( (wadfile = I_IdentifyWAD("plutonia.wad")) ) {
624 gamemode = commercial;
627 } else if ( (wadfile = I_IdentifyWAD("tnt.wad")) ) {
628 gamemode = commercial;
631 } else if ( (wadfile = I_IdentifyWAD("doomu.wad")) ) {
635 } else if ( (wadfile = I_IdentifyWAD("doom.wad")) ) {
636 gamemode = registered;
639 } else if ( (wadfile = I_IdentifyWAD("doom1.wad")) ) {
640 gamemode = shareware;
644 printf("Game mode indeterminate.\n");
645 gamemode = indetermined;
650 // Find a Response File
652 void FindResponseFile (void)
657 for (i = 1;i < myargc;i++)
658 if (myargv[i][0] == '@')
670 // READ THE RESPONSE FILE INTO MEMORY
671 handle = fopen (&myargv[i][1],"rb");
674 fprint(2, "No such response file!\n");
677 printf("Found response file %s!\n",&myargv[i][1]);
678 fseek (handle,0,SEEK_END);
679 size = ftell(handle);
680 fseek (handle,0,SEEK_SET);
681 file = malloc (size);
682 fread (file,size,1,handle);
685 // KEEP ALL CMDLINE ARGS FOLLOWING @RESPONSEFILE ARG
686 for (index = 0,k = i+1; k < myargc; k++)
687 moreargs[index++] = myargv[k];
689 firstargv = myargv[0];
690 myargv = malloc(sizeof(char *)*MAXARGVS);
691 memset(myargv,0,sizeof(char *)*MAXARGVS);
692 myargv[0] = firstargv;
696 indexinfile++; // SKIP PAST ARGV[0] (KEEP IT)
699 myargv[indexinfile++] = infile+k;
701 ((*(infile+k)>= ' '+1) && (*(infile+k)<='z')))
705 ((*(infile+k)<= ' ') || (*(infile+k)>'z')))
709 for (k = 0;k < index;k++)
710 myargv[indexinfile++] = moreargs[k];
711 myargc = indexinfile;
714 printf("%d command-line args:\n",myargc);
715 for (k=1;k<myargc;k++)
716 printf("%s\n",myargv[k]);
726 void D_DoomMain (void)
735 setbuf (stdout, NULL);
736 modifiedgame = false;
738 nomonsters = M_CheckParm ("-nomonsters");
739 respawnparm = M_CheckParm ("-respawn");
740 fastparm = M_CheckParm ("-fast");
741 devparm = M_CheckParm ("-devparm");
742 if (M_CheckParm ("-noztele") && gamemode == commercial)
744 if (M_CheckParm ("-nobounce") && (gamemode == commercial || gamemode == registered))
746 if (M_CheckParm ("-altdeath"))
748 else if (M_CheckParm ("-deathmatch"))
756 "The Ultimate DOOM Startup v%i.%i"
758 VERSION/100,VERSION%100);
763 "DOOM Shareware Startup v%i.%i"
765 VERSION/100,VERSION%100);
770 "DOOM Registered Startup v%i.%i"
772 VERSION/100,VERSION%100);
777 "DOOM 2: Hell on Earth v%i.%i"
779 VERSION/100,VERSION%100);
785 "DOOM 2: Plutonia Experiment v%i.%i"
787 VERSION/100,VERSION%100);
792 "DOOM 2: TNT - Evilution v%i.%i"
794 VERSION/100,VERSION%100);
800 "Public DOOM - v%i.%i"
802 VERSION/100,VERSION%100);
806 printf ("%s\n",title);
812 if ( (p=M_CheckParm ("-turbo")) )
815 extern int forwardmove[2];
816 extern int sidemove[2];
819 scale = atoi (myargv[p+1]);
824 printf ("turbo scale: %i%%\n",scale);
825 forwardmove[0] = forwardmove[0]*scale/100;
826 forwardmove[1] = forwardmove[1]*scale/100;
827 sidemove[0] = sidemove[0]*scale/100;
828 sidemove[1] = sidemove[1]*scale/100;
831 // add any files specified on the command line with -file wadfile
834 // convenience hack to allow -wart e m to add a wad file
835 // prepend a tilde to the filename so wadfile will be reloadable
836 p = M_CheckParm ("-wart");
839 myargv[p][4] = 'p'; // big hack, change to -warp
841 // Map name handling.
847 sprintf (file,"~"DEVMAPS"E%cM%c.wad",
848 myargv[p+1][0], myargv[p+2][0]);
849 printf("Warping to Episode %s, Map %s.\n",
850 myargv[p+1],myargv[p+2]);
855 p = atoi (myargv[p+1]);
857 sprintf (file,"~"DEVMAPS"cdata/map0%i.wad", p);
859 sprintf (file,"~"DEVMAPS"cdata/map%i.wad", p);
865 p = M_CheckParm ("-file");
868 // the parms after p are wadfile/lump names,
869 // until end of parms or another - preceded parm
870 modifiedgame = true; // homebrew levels
871 while (++p != myargc && myargv[p][0] != '-')
872 D_AddFile (myargv[p]);
875 p = M_CheckParm ("-playdemo");
878 p = M_CheckParm ("-timedemo");
880 if (p && p < myargc-1)
882 sprintf (file,"%s.lmp", myargv[p+1]);
884 printf("Playing demo %s.lmp.\n",myargv[p+1]);
887 // get skill / episode / map from parms
888 startskill = sk_medium;
894 p = M_CheckParm ("-skill");
895 if (p && p < myargc-1)
897 startskill = myargv[p+1][0]-'1';
901 p = M_CheckParm ("-episode");
902 if (p && p < myargc-1)
904 startepisode = myargv[p+1][0]-'0';
909 p = M_CheckParm ("-timer");
910 if (p && p < myargc-1 && deathmatch)
913 time = atoi(myargv[p+1]);
914 printf("Levels will end after %d minute",time);
920 p = M_CheckParm ("-avg");
921 if (p && p < myargc-1 && deathmatch)
922 printf("Austin Virtual Gaming: Levels will end after 20 minutes\n");
924 p = M_CheckParm ("-warp");
925 if (p && p < myargc-1)
927 startmap = atoi (myargv[p+1]);
928 if (gamemode != commercial){
929 startepisode = startmap / 10;
936 printf ("V_Init: allocate screens.\n");
939 printf ("M_LoadDefaults: Load system defaults.\n");
940 M_LoadDefaults (); // load before initing other systems
942 printf ("Z_Init: Init zone memory allocation daemon. \n");
945 printf ("W_Init: Init WADfiles.\n");
946 W_InitMultipleFiles (wadfiles);
949 // Check for -file in shareware
952 // These are the lumps that will be checked in IWAD,
953 // if any one is not present, execution will be aborted.
956 "e2m1","e2m2","e2m3","e2m4","e2m5","e2m6","e2m7","e2m8","e2m9",
957 "e3m1","e3m3","e3m3","e3m4","e3m5","e3m6","e3m7","e3m8","e3m9",
958 "dphoof","bfgga0","heada1","cybra1","spida1d1"
962 if ( gamemode == shareware)
963 I_Error("\nYou cannot -file with the shareware "
964 "version. Register!");
966 // Check for fake IWAD with right name,
967 // but w/o all the lumps of the registered version.
968 if (gamemode == registered)
969 for (i = 0;i < 23; i++)
970 if (W_CheckNumForName(name[i])<0)
971 I_Error("\nThis is not the registered version.");
974 // Iff additonal PWAD files are used, print modified banner
978 "===========================================================================\n"
979 "ATTENTION: This version of DOOM has been modified. If you would like to\n"
980 "get a copy of the original game, call 1-800-IDGAMES or see the readme file.\n"
981 " You will not receive technical support for modified games.\n"
982 " press enter to continue\n"
983 "===========================================================================\n"
989 // Check and print which version is executed.
995 "===========================================================================\n"
997 "===========================================================================\n"
1004 "===========================================================================\n"
1005 " Commercial product - do not distribute!\n"
1006 " Please report software piracy to the SPA: 1-800-388-PIR8\n"
1007 "===========================================================================\n"
1016 printf ("M_Init: Init miscellaneous info.\n");
1019 printf ("R_Init: Init DOOM refresh daemon - ");
1022 printf ("\nP_Init: Init Playloop state.\n");
1025 printf ("I_Init: Setting up machine state.\n");
1028 printf ("D_CheckNetGame: Checking network game status.\n");
1031 printf ("S_Init: Setting up sound.\n");
1032 S_Init (snd_SfxVolume /* *8 */, snd_MusicVolume /* *8*/ );
1034 printf ("HU_Init: Setting up heads up display.\n");
1037 printf ("ST_Init: Init status bar.\n");
1040 // check for a driver that wants intermission stats
1041 p = M_CheckParm ("-statcopy");
1042 if (p && p<myargc-1)
1044 // for statistics driver
1045 extern void* statcopy;
1047 statcopy = (void*)atoi(myargv[p+1]);
1048 printf ("External statistics registered.\n");
1051 // start the apropriate game based on parms
1052 p = M_CheckParm ("-record");
1054 if (p && p < myargc-1)
1056 G_RecordDemo (myargv[p+1]);
1060 p = M_CheckParm ("-playdemo");
1061 if (p && p < myargc-1)
1063 singledemo = true; // quit after one demo
1064 G_DeferedPlayDemo (myargv[p+1]);
1065 D_DoomLoop (); // never returns
1068 p = M_CheckParm ("-timedemo");
1069 if (p && p < myargc-1)
1071 G_TimeDemo (myargv[p+1]);
1072 D_DoomLoop (); // never returns
1075 p = M_CheckParm ("-loadgame");
1076 if (p && p < myargc-1)
1078 sprintf(file, SAVEGAMENAME"%c.dsg",myargv[p+1][0]);
1083 if ( gameaction != ga_loadgame )
1085 if (autostart || netgame)
1086 G_InitNew (startskill, startepisode, startmap);
1088 D_StartTitle (); // start up intro loop
1092 D_DoomLoop (); // never returns