]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/doom/d_main.c
369d67650b71d1f8631a60500da607e6cf540922
[plan9front.git] / sys / src / games / doom / d_main.c
1 // Emacs style mode select   -*- C++ -*- 
2 //-----------------------------------------------------------------------------
3 //
4 // $Id:$
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 //
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.
11 //
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
15 // for more details.
16 //
17 // $Log:$
18 //
19 // DESCRIPTION:
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.
24 //
25 //-----------------------------------------------------------------------------
26
27
28 static const char rcsid[] = "$Id: d_main.c,v 1.8 1997/02/03 22:45:09 b1 Exp $";
29
30 #define BGCOLOR         7
31 #define FGCOLOR         8
32
33 #include "doomdef.h"
34 #include "doomstat.h"
35
36 #include "dstrings.h"
37 #include "sounds.h"
38
39
40 #include "z_zone.h"
41 #include "w_wad.h"
42 #include "s_sound.h"
43 #include "v_video.h"
44
45 #include "f_finale.h"
46 #include "f_wipe.h"
47
48 #include "m_argv.h"
49 #include "m_misc.h"
50 #include "m_menu.h"
51
52 #include "i_system.h"
53 #include "i_sound.h"
54 #include "i_video.h"
55
56 #include "g_game.h"
57
58 #include "hu_stuff.h"
59 #include "wi_stuff.h"
60 #include "st_stuff.h"
61 #include "am_map.h"
62
63 #include "p_setup.h"
64 #include "r_local.h"
65
66
67 #include "d_main.h"
68
69 //
70 // D-DoomLoop()
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
77 //
78 void D_DoomLoop (void);
79
80
81 char*           wadfiles[MAXWADFILES];
82
83
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
88
89 boolean         drone;
90
91 boolean         singletics = false; // debug flag to cancel adaptiveness
92
93 /* bug compatibility with various versions of doom */
94 boolean         noztele;
95 boolean         nobounce;
96
97
98 //extern int soundVolume;
99 //extern  int   sfxVolume;
100 //extern  int   musicVolume;
101
102 extern  boolean inhelpscreens;
103
104 skill_t         startskill;
105 int             startepisode;
106 int             startmap;
107 boolean         autostart;
108
109 FILE*           debugfile;
110
111 boolean         advancedemo;
112
113
114
115
116 char            wadfile[1024];          // primary wad file
117 char            mapdir[1024];           // directory of development maps
118 char            basedefault[1024];      // default file
119
120
121 void D_CheckNetGame (void);
122 void D_ProcessEvents (void);
123 void G_BuildTiccmd (ticcmd_t* cmd);
124 void D_DoAdvanceDemo (void);
125
126
127 //
128 // EVENT HANDLING
129 //
130 // Events are asynchronous inputs generally generated by the game user.
131 // Events can be discarded if no responder claims them
132 //
133 event_t         events[MAXEVENTS];
134 int             eventhead;
135 int             eventtail;
136 QLock           eventlock;
137
138
139 //
140 // D_PostEvent
141 // Called by the I/O functions when input is detected
142 //
143 void D_PostEvent (event_t* ev)
144 {
145     int next;
146
147 retry:
148     qlock(&eventlock);
149     next = (eventhead+1)&(MAXEVENTS-1);
150     if(next == eventtail){
151         qunlock(&eventlock);
152         if(ev->type != ev_keydown && ev->type != ev_keyup)
153             return;
154         sleep(1);
155         goto retry;
156     }
157     events[eventhead] = *ev;
158     eventhead = next;
159     qunlock(&eventlock);
160 }
161
162
163 //
164 // D_ProcessEvents
165 // Send all the events of the given timestamp down the responder chain
166 //
167 void D_ProcessEvents (void)
168 {
169     event_t*    ev;
170         
171     // IF STORE DEMO, DO NOT ACCEPT INPUT
172     if ( ( gamemode == commercial )
173          && (W_CheckNumForName("map01")<0) )
174       return;
175         
176     for ( ; eventtail != eventhead ; eventtail = (eventtail+1)&(MAXEVENTS-1))
177     {
178         ev = &events[eventtail];
179         if (M_Responder (ev))
180             continue;               // menu ate the event
181         G_Responder (ev);
182     }
183 }
184
185
186
187
188 //
189 // D_Display
190 //  draw current display, possibly wiping it from the previous
191 //
192
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);
198
199 void D_Display (void)
200 {
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;
207     int                         nowtime;
208     int                         tics;
209     int                         wipestart;
210     int                         y;
211     boolean                     done;
212     boolean                     wipe;
213     boolean                     redrawsbar;
214
215     if (nodrawers)
216         return;                    // for comparative timing / profiling
217                 
218     redrawsbar = false;
219     
220     // change the view size if needed
221     if (setsizeneeded)
222     {
223         R_ExecuteSetViewSize ();
224         oldgamestate = -1;                      // force background redraw
225         borderdrawcount = 3;
226     }
227
228     // save the current screen if about to wipe
229     if (gamestate != wipegamestate)
230     {
231         wipe = true;
232         wipe_StartScreen(0, 0, SCREENWIDTH, SCREENHEIGHT);
233     }
234     else
235         wipe = false;
236
237     if (gamestate == GS_LEVEL && gametic)
238         HU_Erase();
239     
240     // do buffered drawing
241     switch (gamestate)
242     {
243       case GS_LEVEL:
244         if (!gametic)
245             break;
246         if (automapactive)
247             AM_Drawer ();
248         if (wipe || (viewheight != 200 && fullscreen) )
249             redrawsbar = true;
250         if (inhelpscreensstate && !inhelpscreens)
251             redrawsbar = true;              // just put away the help screen
252         ST_Drawer (viewheight == 200, redrawsbar );
253         fullscreen = viewheight == 200;
254         break;
255
256       case GS_INTERMISSION:
257         WI_Drawer ();
258         break;
259
260       case GS_FINALE:
261         F_Drawer ();
262         break;
263
264       case GS_DEMOSCREEN:
265         D_PageDrawer ();
266         break;
267     }
268     
269     // draw buffered stuff to screen
270     I_UpdateNoBlit ();
271     
272     // draw the view directly
273     if (gamestate == GS_LEVEL && !automapactive && gametic)
274         R_RenderPlayerView (&players[displayplayer]);
275
276     if (gamestate == GS_LEVEL && gametic)
277         HU_Drawer ();
278     
279     // clean up border stuff
280     if (gamestate != oldgamestate && gamestate != GS_LEVEL)
281         I_SetPalette (W_CacheLumpName ("PLAYPAL",PU_CACHE));
282
283     // see if the border needs to be initially drawn
284     if (gamestate == GS_LEVEL && oldgamestate != GS_LEVEL)
285     {
286         viewactivestate = false;        // view was not active
287         R_FillBackScreen ();    // draw the pattern into the back screen
288     }
289
290     // see if the border needs to be updated to the screen
291     if (gamestate == GS_LEVEL && !automapactive && scaledviewwidth != 320)
292     {
293         if (menuactive || menuactivestate || !viewactivestate)
294             borderdrawcount = 3;
295         if (borderdrawcount)
296         {
297             R_DrawViewBorder ();    // erase old menu stuff
298             borderdrawcount--;
299         }
300
301     }
302
303     menuactivestate = menuactive;
304     viewactivestate = viewactive;
305     inhelpscreensstate = inhelpscreens;
306     oldgamestate = wipegamestate = gamestate;
307     
308     // draw pause pic
309     if (paused)
310     {
311         if (automapactive)
312             y = 4;
313         else
314             y = viewwindowy+4;
315         V_DrawPatchDirect(viewwindowx+(scaledviewwidth-68)/2,
316                           y,0,W_CacheLumpName ("M_PAUSE", PU_CACHE));
317     }
318
319
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
323
324
325     // normal update
326     if (!wipe)
327     {
328         I_FinishUpdate ();              // page flip or blit buffer
329         return;
330     }
331     
332     // wipe update
333     wipe_EndScreen(0, 0, SCREENWIDTH, SCREENHEIGHT);
334
335     wipestart = I_GetTime () - 1;
336
337     do
338     {
339         do
340         {
341             nowtime = I_GetTime ();
342             tics = nowtime - wipestart;
343         } while (!tics);
344         wipestart = nowtime;
345         done = wipe_ScreenWipe(wipe_Melt
346                                , 0, 0, SCREENWIDTH, SCREENHEIGHT, tics);
347         I_UpdateNoBlit ();
348         M_Drawer ();                            // menu is drawn even on top of wipes
349         I_FinishUpdate ();                      // page flip or blit buffer
350     } while (!done);
351 }
352
353
354
355 //
356 //  D_DoomLoop
357 //
358 extern  boolean         demorecording;
359
360 void D_DoomLoop (void)
361 {
362     if (demorecording)
363         G_BeginRecording ();
364                 
365     if (M_CheckParm ("-debugfile"))
366     {
367         char    filename[20];
368         sprintf (filename,"debug%i.txt",consoleplayer);
369         printf ("debug output to: %s\n",filename);
370         debugfile = fopen (filename,"w");
371     }
372         
373     for(;;)
374     {
375         // frame syncronous IO operations
376         // I_StartFrame ();                
377         
378         // process one or more tics
379         if (singletics)
380         {
381             I_StartTic ();
382             D_ProcessEvents ();
383             G_BuildTiccmd (&netcmds[consoleplayer][maketic%BACKUPTICS]);
384             if (advancedemo)
385                 D_DoAdvanceDemo ();
386             M_Ticker ();
387             G_Ticker ();
388             gametic++;
389             maketic++;
390         }
391         else
392         {
393             TryRunTics (); // will run at least one tic
394         }
395                 
396         S_UpdateSounds (players[consoleplayer].mo);// move positional sounds
397
398         // Update display, next frame, with current state.
399         D_Display ();
400
401         // Sound mixing for the buffer is snychronous.
402         I_UpdateSound();
403
404         // Update sound output.
405         I_SubmitSound();
406     }
407 }
408
409
410
411 //
412 //  DEMO LOOP
413 //
414 int             demosequence;
415 int             pagetic;
416 char                    *pagename;
417
418
419 //
420 // D_PageTicker
421 // Handles timing for warped projection
422 //
423 void D_PageTicker (void)
424 {
425     if (--pagetic < 0)
426         D_AdvanceDemo ();
427 }
428
429
430
431 //
432 // D_PageDrawer
433 //
434 void D_PageDrawer (void)
435 {
436     V_DrawPatch (0,0, 0, W_CacheLumpName(pagename, PU_CACHE));
437 }
438
439
440 //
441 // D_AdvanceDemo
442 // Called after each demo or intro demosequence finishes
443 //
444 void D_AdvanceDemo (void)
445 {
446     advancedemo = true;
447 }
448
449
450 //
451 // This cycles through the demo sequences.
452 // FIXME - version dependend demo numbers?
453 //
454 void D_DoAdvanceDemo (void)
455 {
456     players[consoleplayer].playerstate = PST_LIVE;  // not reborn
457     advancedemo = false;
458     usergame = false;               // no save / end game here
459     paused = false;
460     gameaction = ga_nothing;
461
462     if ( gamemode == retail )
463       demosequence = (demosequence+1)%7;
464     else
465       demosequence = (demosequence+1)%6;
466     
467     switch (demosequence)
468     {
469       case 0:
470         if ( gamemode == commercial )
471             pagetic = 35 * 11;
472         else
473             pagetic = 170;
474         gamestate = GS_DEMOSCREEN;
475         pagename = "TITLEPIC";
476         if ( gamemode == commercial )
477           S_StartMusic(mus_dm2ttl);
478         else
479           S_StartMusic (mus_intro);
480         break;
481       case 1:
482         G_DeferedPlayDemo ("demo1");
483         break;
484       case 2:
485         pagetic = 200;
486         gamestate = GS_DEMOSCREEN;
487         pagename = "CREDIT";
488         break;
489       case 3:
490         G_DeferedPlayDemo ("demo2");
491         break;
492       case 4:
493         gamestate = GS_DEMOSCREEN;
494         if ( gamemode == commercial)
495         {
496             pagetic = 35 * 11;
497             pagename = "TITLEPIC";
498             S_StartMusic(mus_dm2ttl);
499         }
500         else
501         {
502             pagetic = 200;
503
504             if ( gamemode == retail )
505               pagename = "CREDIT";
506             else
507               pagename = "HELP2";
508         }
509         break;
510       case 5:
511         G_DeferedPlayDemo ("demo3");
512         break;
513         // THE DEFINITIVE DOOM Special Edition demo
514       case 6:
515         G_DeferedPlayDemo ("demo4");
516         break;
517     }
518 }
519
520
521
522 //
523 // D_StartTitle
524 //
525 void D_StartTitle (void)
526 {
527     gameaction = ga_nothing;
528     demosequence = -1;
529     D_AdvanceDemo ();
530 }
531
532
533
534
535 //      print title for every printed line
536 char            title[128];
537
538
539
540 //
541 // D_AddFile
542 //
543 void D_AddFile (char *file)
544 {
545     int     numwadfiles;
546     char    *newfile;
547         
548     for (numwadfiles = 0 ; wadfiles[numwadfiles] ; numwadfiles++)
549         ;
550
551     newfile = malloc (strlen(file)+1);
552     strcpy (newfile, file);
553         
554     wadfiles[numwadfiles] = newfile;
555 }
556
557
558 //
559 // IdentifyVersion
560 // Checks availability of IWAD files by name,
561 // to determine whether registered/commercial features
562 // should be executed (notably loading PWAD's).
563 //
564 void IdentifyVersion (void)
565 {
566         char *wadfile;
567
568         if (M_CheckParm ("-shdev"))
569         {
570                 I_Error("PORTME d_main.c IdentifyVersion -shdev");
571 /*
572                 gamemode = shareware;
573                 devparm = true;
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");
578                 return;
579 */
580         }
581
582         if (M_CheckParm ("-regdev"))
583         {
584                 I_Error("PORTME d_main.c IdentifyVersion -regdev");
585 /*
586                 gamemode = registered;
587                 devparm = true;
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");
593                 return;
594 */
595         }
596
597         if (M_CheckParm ("-comdev"))
598         {
599                 I_Error("PORTME d_main.c IdentifyVersion -comdev");
600 /*
601                 gamemode = commercial;
602                 devparm = true;
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");
607                 return;
608 */
609         }
610
611         if ( (wadfile = I_IdentifyWAD("doom2f.wad")) ) {
612                 gamemode = commercial;
613                 // C'est ridicule!
614                 // Let's handle languages in config files, okay?
615                 language = french;
616                 printf("French version\n");
617                 D_AddFile (wadfile);
618                 return;
619         } else if ( (wadfile = I_IdentifyWAD("doom2.wad")) ) {
620                 gamemode = commercial;
621                 D_AddFile (wadfile);
622                 return;
623         } else if ( (wadfile = I_IdentifyWAD("plutonia.wad")) ) {
624                 gamemode = commercial;
625                 D_AddFile (wadfile);
626                 return;
627         } else if ( (wadfile = I_IdentifyWAD("tnt.wad")) ) {
628                 gamemode = commercial;
629                 D_AddFile (wadfile);
630                 return;
631         } else if ( (wadfile = I_IdentifyWAD("doomu.wad")) ) {
632                 gamemode = retail;
633                 D_AddFile (wadfile);
634                 return;
635         } else if ( (wadfile = I_IdentifyWAD("doom.wad")) ) {
636                 gamemode = registered;
637                 D_AddFile (wadfile);
638                 return;
639         } else if ( (wadfile = I_IdentifyWAD("doom1.wad")) ) {
640                 gamemode = shareware;
641                 D_AddFile (wadfile);
642                 return;
643         } else {
644                 printf("Game mode indeterminate.\n");
645                 gamemode = indetermined;
646         }
647 }
648
649 //
650 // Find a Response File
651 //
652 void FindResponseFile (void)
653 {
654     int             i;
655 #define MAXARGVS        100
656         
657     for (i = 1;i < myargc;i++)
658         if (myargv[i][0] == '@')
659         {
660             FILE *          handle;
661             int             size;
662             int             k;
663             int             index;
664             int             indexinfile;
665             char    *infile;
666             char    *file;
667             char    *moreargs[20];
668             char    *firstargv;
669                         
670             // READ THE RESPONSE FILE INTO MEMORY
671             handle = fopen (&myargv[i][1],"rb");
672             if (!handle)
673             {
674                 fprint(2, "No such response file!\n");
675                 exits("open");
676             }
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);
683             fclose (handle);
684                         
685             // KEEP ALL CMDLINE ARGS FOLLOWING @RESPONSEFILE ARG
686             for (index = 0,k = i+1; k < myargc; k++)
687                 moreargs[index++] = myargv[k];
688                         
689             firstargv = myargv[0];
690             myargv = malloc(sizeof(char *)*MAXARGVS);
691             memset(myargv,0,sizeof(char *)*MAXARGVS);
692             myargv[0] = firstargv;
693                         
694             infile = file;
695             indexinfile = k = 0;
696             indexinfile++;  // SKIP PAST ARGV[0] (KEEP IT)
697             do
698             {
699                 myargv[indexinfile++] = infile+k;
700                 while(k < size &&
701                       ((*(infile+k)>= ' '+1) && (*(infile+k)<='z')))
702                     k++;
703                 *(infile+k) = 0;
704                 while(k < size &&
705                       ((*(infile+k)<= ' ') || (*(infile+k)>'z')))
706                     k++;
707             } while(k < size);
708                         
709             for (k = 0;k < index;k++)
710                 myargv[indexinfile++] = moreargs[k];
711             myargc = indexinfile;
712         
713             // DISPLAY ARGS
714             printf("%d command-line args:\n",myargc);
715             for (k=1;k<myargc;k++)
716                 printf("%s\n",myargv[k]);
717
718             break;
719         }
720 }
721
722
723 //
724 // D_DoomMain
725 //
726 void D_DoomMain (void)
727 {
728     int         p;
729     char        file[256];
730
731     FindResponseFile ();
732         
733     IdentifyVersion ();
734         
735     setbuf (stdout, NULL);
736     modifiedgame = false;
737         
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)
743         noztele = 1;
744     if (M_CheckParm ("-nobounce") && (gamemode == commercial || gamemode == registered))
745         nobounce = 1;
746     if (M_CheckParm ("-altdeath"))
747         deathmatch = 2;
748     else if (M_CheckParm ("-deathmatch"))
749         deathmatch = 1;
750
751     switch ( gamemode )
752     {
753       case retail:
754         sprintf (title,
755                  "                         "
756                  "The Ultimate DOOM Startup v%i.%i"
757                  "                           ",
758                  VERSION/100,VERSION%100);
759         break;
760       case shareware:
761         sprintf (title,
762                  "                            "
763                  "DOOM Shareware Startup v%i.%i"
764                  "                           ",
765                  VERSION/100,VERSION%100);
766         break;
767       case registered:
768         sprintf (title,
769                  "                            "
770                  "DOOM Registered Startup v%i.%i"
771                  "                           ",
772                  VERSION/100,VERSION%100);
773         break;
774       case commercial:
775         sprintf (title,
776                  "                         "
777                  "DOOM 2: Hell on Earth v%i.%i"
778                  "                           ",
779                  VERSION/100,VERSION%100);
780         break;
781 /*FIXME
782        case pack_plut:
783         sprintf (title,
784                  "                   "
785                  "DOOM 2: Plutonia Experiment v%i.%i"
786                  "                           ",
787                  VERSION/100,VERSION%100);
788         break;
789       case pack_tnt:
790         sprintf (title,
791                  "                     "
792                  "DOOM 2: TNT - Evilution v%i.%i"
793                  "                           ",
794                  VERSION/100,VERSION%100);
795         break;
796 */
797       default:
798         sprintf (title,
799                  "                     "
800                  "Public DOOM - v%i.%i"
801                  "                           ",
802                  VERSION/100,VERSION%100);
803         break;
804     }
805     
806     printf ("%s\n",title);
807
808     if (devparm)
809         printf(D_DEVSTR);
810     
811     // turbo option
812     if ( (p=M_CheckParm ("-turbo")) )
813     {
814         int     scale = 200;
815         extern int forwardmove[2];
816         extern int sidemove[2];
817         
818         if (p<myargc-1)
819             scale = atoi (myargv[p+1]);
820         if (scale < 10)
821             scale = 10;
822         if (scale > 400)
823             scale = 400;
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;
829     }
830     
831     // add any files specified on the command line with -file wadfile
832     // to the wad list
833     //
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");
837     if (p)
838     {
839         myargv[p][4] = 'p';     // big hack, change to -warp
840
841         // Map name handling.
842         switch (gamemode )
843         {
844           case shareware:
845           case retail:
846           case registered:
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]);
851             break;
852             
853           case commercial:
854           default:
855             p = atoi (myargv[p+1]);
856             if (p<10)
857               sprintf (file,"~"DEVMAPS"cdata/map0%i.wad", p);
858             else
859               sprintf (file,"~"DEVMAPS"cdata/map%i.wad", p);
860             break;
861         }
862         D_AddFile (file);
863     }
864         
865     p = M_CheckParm ("-file");
866     if (p)
867     {
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]);
873     }
874
875     p = M_CheckParm ("-playdemo");
876
877     if (!p)
878         p = M_CheckParm ("-timedemo");
879
880     if (p && p < myargc-1)
881     {
882         sprintf (file,"%s.lmp", myargv[p+1]);
883         D_AddFile (file);
884         printf("Playing demo %s.lmp.\n",myargv[p+1]);
885     }
886     
887     // get skill / episode / map from parms
888     startskill = sk_medium;
889     startepisode = 1;
890     startmap = 1;
891     autostart = false;
892
893                 
894     p = M_CheckParm ("-skill");
895     if (p && p < myargc-1)
896     {
897         startskill = myargv[p+1][0]-'1';
898         autostart = true;
899     }
900
901     p = M_CheckParm ("-episode");
902     if (p && p < myargc-1)
903     {
904         startepisode = myargv[p+1][0]-'0';
905         startmap = 1;
906         autostart = true;
907     }
908         
909     p = M_CheckParm ("-timer");
910     if (p && p < myargc-1 && deathmatch)
911     {
912         int     time;
913         time = atoi(myargv[p+1]);
914         printf("Levels will end after %d minute",time);
915         if (time>1)
916             printf("s");
917         printf(".\n");
918     }
919
920     p = M_CheckParm ("-avg");
921     if (p && p < myargc-1 && deathmatch)
922         printf("Austin Virtual Gaming: Levels will end after 20 minutes\n");
923
924     p = M_CheckParm ("-warp");
925     if (p && p < myargc-1)
926     {
927         startmap = atoi (myargv[p+1]);
928         if (gamemode != commercial){
929             startepisode = startmap / 10;
930             startmap %= 10;
931         }
932         autostart = true;
933     }
934     
935     // init subsystems
936     printf ("V_Init: allocate screens.\n");
937     V_Init ();
938
939     printf ("M_LoadDefaults: Load system defaults.\n");
940     M_LoadDefaults ();              // load before initing other systems
941
942     printf ("Z_Init: Init zone memory allocation daemon. \n");
943     Z_Init ();
944
945     printf ("W_Init: Init WADfiles.\n");
946     W_InitMultipleFiles (wadfiles);
947     
948
949     // Check for -file in shareware
950     if (modifiedgame)
951     {
952         // These are the lumps that will be checked in IWAD,
953         // if any one is not present, execution will be aborted.
954         char name[23][8]=
955         {
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"
959         };
960         int i;
961         
962         if ( gamemode == shareware)
963             I_Error("\nYou cannot -file with the shareware "
964                     "version. Register!");
965
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.");
972     }
973     
974     // Iff additonal PWAD files are used, print modified banner
975     if (modifiedgame)
976     {
977         /*m*/printf (
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"
984             );
985         USED( getchar () );
986     }
987         
988
989     // Check and print which version is executed.
990     switch ( gamemode )
991     {
992       case shareware:
993       case indetermined:
994         printf (
995             "===========================================================================\n"
996             "                                Shareware!\n"
997             "===========================================================================\n"
998         );
999         break;
1000       case registered:
1001       case retail:
1002       case commercial:
1003         printf (
1004             "===========================================================================\n"
1005             "                 Commercial product - do not distribute!\n"
1006             "         Please report software piracy to the SPA: 1-800-388-PIR8\n"
1007             "===========================================================================\n"
1008         );
1009         break;
1010         
1011       default:
1012         // Ouch.
1013         break;
1014     }
1015
1016     printf ("M_Init: Init miscellaneous info.\n");
1017     M_Init ();
1018
1019     printf ("R_Init: Init DOOM refresh daemon - ");
1020     R_Init ();
1021
1022     printf ("\nP_Init: Init Playloop state.\n");
1023     P_Init ();
1024
1025     printf ("I_Init: Setting up machine state.\n");
1026     I_Init ();
1027
1028     printf ("D_CheckNetGame: Checking network game status.\n");
1029     D_CheckNetGame ();
1030
1031     printf ("S_Init: Setting up sound.\n");
1032     S_Init (snd_SfxVolume /* *8 */, snd_MusicVolume /* *8*/ );
1033
1034     printf ("HU_Init: Setting up heads up display.\n");
1035     HU_Init ();
1036
1037     printf ("ST_Init: Init status bar.\n");
1038     ST_Init ();
1039
1040     // check for a driver that wants intermission stats
1041     p = M_CheckParm ("-statcopy");
1042     if (p && p<myargc-1)
1043     {
1044         // for statistics driver
1045         extern  void*   statcopy;                            
1046
1047         statcopy = (void*)atoi(myargv[p+1]);
1048         printf ("External statistics registered.\n");
1049     }
1050     
1051     // start the apropriate game based on parms
1052     p = M_CheckParm ("-record");
1053
1054     if (p && p < myargc-1)
1055     {
1056         G_RecordDemo (myargv[p+1]);
1057         autostart = true;
1058     }
1059         
1060     p = M_CheckParm ("-playdemo");
1061     if (p && p < myargc-1)
1062     {
1063         singledemo = true;              // quit after one demo
1064         G_DeferedPlayDemo (myargv[p+1]);
1065         D_DoomLoop ();  // never returns
1066     }
1067         
1068     p = M_CheckParm ("-timedemo");
1069     if (p && p < myargc-1)
1070     {
1071         G_TimeDemo (myargv[p+1]);
1072         D_DoomLoop ();  // never returns
1073     }
1074         
1075     p = M_CheckParm ("-loadgame");
1076     if (p && p < myargc-1)
1077     {
1078         sprintf(file, SAVEGAMENAME"%c.dsg",myargv[p+1][0]);
1079         G_LoadGame (file);
1080     }
1081         
1082
1083     if ( gameaction != ga_loadgame )
1084     {
1085         if (autostart || netgame)
1086             G_InitNew (startskill, startepisode, startmap);
1087         else
1088             D_StartTitle ();                // start up intro loop
1089
1090     }
1091
1092     D_DoomLoop ();  // never returns
1093 }