]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/doom/d_main.c
6f1e8621545e224ade980acf47397386b62749b1
[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         I_UpdateSound ();
330         return;
331     }
332     
333     // wipe update
334     wipe_EndScreen(0, 0, SCREENWIDTH, SCREENHEIGHT);
335
336     wipestart = I_GetTime () - 1;
337
338     do
339     {
340         do
341         {
342             nowtime = I_GetTime ();
343             tics = nowtime - wipestart;
344         } while (!tics);
345         wipestart = nowtime;
346         done = wipe_ScreenWipe(wipe_Melt
347                                , 0, 0, SCREENWIDTH, SCREENHEIGHT, tics);
348         I_UpdateNoBlit ();
349         M_Drawer ();                            // menu is drawn even on top of wipes
350         I_FinishUpdate ();                      // page flip or blit buffer
351         if (!done)
352                 I_UpdateSound ();
353     } while (!done);
354 }
355
356
357
358 //
359 //  D_DoomLoop
360 //
361 extern  boolean         demorecording;
362
363 void D_DoomLoop (void)
364 {
365     if (demorecording)
366         G_BeginRecording ();
367                 
368     if (M_CheckParm ("-debugfile"))
369     {
370         char    filename[20];
371         sprintf (filename,"debug%i.txt",consoleplayer);
372         printf ("debug output to: %s\n",filename);
373         debugfile = fopen (filename,"w");
374     }
375         
376     for(;;)
377     {
378         // frame syncronous IO operations
379         // I_StartFrame ();                
380         
381         // process one or more tics
382         if (singletics)
383         {
384             I_StartTic ();
385             D_ProcessEvents ();
386             G_BuildTiccmd (&netcmds[consoleplayer][maketic%BACKUPTICS]);
387             if (advancedemo)
388                 D_DoAdvanceDemo ();
389             M_Ticker ();
390             G_Ticker ();
391             gametic++;
392             maketic++;
393         }
394         else
395         {
396             TryRunTics (); // will run at least one tic
397         }
398                 
399         S_UpdateSounds (players[consoleplayer].mo);// move positional sounds
400
401         // Update display, next frame, with current state.
402         D_Display ();
403     }
404 }
405
406
407
408 //
409 //  DEMO LOOP
410 //
411 int             demosequence;
412 int             pagetic;
413 char                    *pagename;
414
415
416 //
417 // D_PageTicker
418 // Handles timing for warped projection
419 //
420 void D_PageTicker (void)
421 {
422     if (--pagetic < 0)
423         D_AdvanceDemo ();
424 }
425
426
427
428 //
429 // D_PageDrawer
430 //
431 void D_PageDrawer (void)
432 {
433     V_DrawPatch (0,0, 0, W_CacheLumpName(pagename, PU_CACHE));
434 }
435
436
437 //
438 // D_AdvanceDemo
439 // Called after each demo or intro demosequence finishes
440 //
441 void D_AdvanceDemo (void)
442 {
443     advancedemo = true;
444 }
445
446
447 //
448 // This cycles through the demo sequences.
449 // FIXME - version dependend demo numbers?
450 //
451 void D_DoAdvanceDemo (void)
452 {
453     players[consoleplayer].playerstate = PST_LIVE;  // not reborn
454     advancedemo = false;
455     usergame = false;               // no save / end game here
456     paused = false;
457     gameaction = ga_nothing;
458
459     if ( gamemode == retail )
460       demosequence = (demosequence+1)%7;
461     else
462       demosequence = (demosequence+1)%6;
463     
464     switch (demosequence)
465     {
466       case 0:
467         if ( gamemode == commercial )
468             pagetic = 35 * 11;
469         else
470             pagetic = 170;
471         gamestate = GS_DEMOSCREEN;
472         pagename = "TITLEPIC";
473         if ( gamemode == commercial )
474           S_StartMusic(mus_dm2ttl);
475         else
476           S_StartMusic (mus_intro);
477         break;
478       case 1:
479         G_DeferedPlayDemo ("demo1");
480         break;
481       case 2:
482         pagetic = 200;
483         gamestate = GS_DEMOSCREEN;
484         pagename = "CREDIT";
485         break;
486       case 3:
487         G_DeferedPlayDemo ("demo2");
488         break;
489       case 4:
490         gamestate = GS_DEMOSCREEN;
491         if ( gamemode == commercial)
492         {
493             pagetic = 35 * 11;
494             pagename = "TITLEPIC";
495             S_StartMusic(mus_dm2ttl);
496         }
497         else
498         {
499             pagetic = 200;
500
501             if ( gamemode == retail )
502               pagename = "CREDIT";
503             else
504               pagename = "HELP2";
505         }
506         break;
507       case 5:
508         G_DeferedPlayDemo ("demo3");
509         break;
510         // THE DEFINITIVE DOOM Special Edition demo
511       case 6:
512         G_DeferedPlayDemo ("demo4");
513         break;
514     }
515 }
516
517
518
519 //
520 // D_StartTitle
521 //
522 void D_StartTitle (void)
523 {
524     gameaction = ga_nothing;
525     demosequence = -1;
526     D_AdvanceDemo ();
527 }
528
529
530
531
532 //      print title for every printed line
533 char            title[128];
534
535
536
537 //
538 // D_AddFile
539 //
540 void D_AddFile (char *file)
541 {
542     int     numwadfiles;
543     char    *newfile;
544         
545     for (numwadfiles = 0 ; wadfiles[numwadfiles] ; numwadfiles++)
546         ;
547
548     newfile = malloc (strlen(file)+1);
549     strcpy (newfile, file);
550         
551     wadfiles[numwadfiles] = newfile;
552 }
553
554
555 //
556 // IdentifyVersion
557 // Checks availability of IWAD files by name,
558 // to determine whether registered/commercial features
559 // should be executed (notably loading PWAD's).
560 //
561 void IdentifyVersion (void)
562 {
563         char *wadfile, *slash;
564
565         if (M_CheckParm ("-shdev"))
566         {
567                 I_Error("PORTME d_main.c IdentifyVersion -shdev");
568 /*
569                 gamemode = shareware;
570                 devparm = true;
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");
575                 return;
576 */
577         }
578
579         if (M_CheckParm ("-regdev"))
580         {
581                 I_Error("PORTME d_main.c IdentifyVersion -regdev");
582 /*
583                 gamemode = registered;
584                 devparm = true;
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");
590                 return;
591 */
592         }
593
594         if (M_CheckParm ("-comdev"))
595         {
596                 I_Error("PORTME d_main.c IdentifyVersion -comdev");
597 /*
598                 gamemode = commercial;
599                 devparm = true;
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");
604                 return;
605 */
606         }
607
608         if ( (wadfile = I_IdentifyWAD("doom2f.wad")) ) {
609                 gamemode = commercial;
610                 // C'est ridicule!
611                 // Let's handle languages in config files, okay?
612                 language = french;
613                 printf("French version\n");
614                 D_AddFile (wadfile);
615         } else if ( (wadfile = I_IdentifyWAD("doom2.wad")) ) {
616                 gamemode = commercial;
617                 D_AddFile (wadfile);
618         } else if ( (wadfile = I_IdentifyWAD("plutonia.wad")) ) {
619                 gamemode = commercial;
620                 D_AddFile (wadfile);
621         } else if ( (wadfile = I_IdentifyWAD("tnt.wad")) ) {
622                 gamemode = commercial;
623                 D_AddFile (wadfile);
624         } else if ( (wadfile = I_IdentifyWAD("doomu.wad")) ) {
625                 gamemode = retail;
626                 D_AddFile (wadfile);
627         } else if ( (wadfile = I_IdentifyWAD("doom.wad")) ) {
628                 gamemode = registered;
629                 D_AddFile (wadfile);
630         } else if ( (wadfile = I_IdentifyWAD("doom1.wad")) ) {
631                 gamemode = shareware;
632                 D_AddFile (wadfile);
633         } else {
634                 printf("Game mode indeterminate.\n");
635                 gamemode = indetermined;
636                 return;
637         }
638         strncpy(basedefault, wadfile, sizeof(basedefault)-5);
639         basedefault[sizeof(basedefault)-5] = '\0';
640         slash = strrchr(basedefault, '/');
641         if (slash++ == 0)
642                 slash = basedefault;
643         strcpy(slash, "cfg");
644 }
645
646 //
647 // Find a Response File
648 //
649 void FindResponseFile (void)
650 {
651     int             i;
652 #define MAXARGVS        100
653         
654     for (i = 1;i < myargc;i++)
655         if (myargv[i][0] == '@')
656         {
657             FILE *          handle;
658             int             size;
659             int             k;
660             int             index;
661             int             indexinfile;
662             char    *infile;
663             char    *file;
664             char    *moreargs[20];
665             char    *firstargv;
666                         
667             // READ THE RESPONSE FILE INTO MEMORY
668             handle = fopen (&myargv[i][1],"rb");
669             if (!handle)
670             {
671                 fprint(2, "No such response file!\n");
672                 exits("open");
673             }
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);
680             fclose (handle);
681                         
682             // KEEP ALL CMDLINE ARGS FOLLOWING @RESPONSEFILE ARG
683             for (index = 0,k = i+1; k < myargc; k++)
684                 moreargs[index++] = myargv[k];
685                         
686             firstargv = myargv[0];
687             myargv = malloc(sizeof(char *)*MAXARGVS);
688             memset(myargv,0,sizeof(char *)*MAXARGVS);
689             myargv[0] = firstargv;
690                         
691             infile = file;
692             indexinfile = k = 0;
693             indexinfile++;  // SKIP PAST ARGV[0] (KEEP IT)
694             do
695             {
696                 myargv[indexinfile++] = infile+k;
697                 while(k < size &&
698                       ((*(infile+k)>= ' '+1) && (*(infile+k)<='z')))
699                     k++;
700                 *(infile+k) = 0;
701                 while(k < size &&
702                       ((*(infile+k)<= ' ') || (*(infile+k)>'z')))
703                     k++;
704             } while(k < size);
705                         
706             for (k = 0;k < index;k++)
707                 myargv[indexinfile++] = moreargs[k];
708             myargc = indexinfile;
709         
710             // DISPLAY ARGS
711             printf("%d command-line args:\n",myargc);
712             for (k=1;k<myargc;k++)
713                 printf("%s\n",myargv[k]);
714
715             break;
716         }
717 }
718
719
720 //
721 // D_DoomMain
722 //
723 void D_DoomMain (void)
724 {
725     int         p;
726     char        file[256];
727
728     FindResponseFile ();
729         
730     IdentifyVersion ();
731         
732     setbuf (stdout, NULL);
733     modifiedgame = false;
734         
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)
740         noztele = 1;
741     if (M_CheckParm ("-nobounce") && (gamemode == commercial || gamemode == registered))
742         nobounce = 1;
743     if (M_CheckParm ("-altdeath"))
744         deathmatch = 2;
745     else if (M_CheckParm ("-deathmatch"))
746         deathmatch = 1;
747
748     switch ( gamemode )
749     {
750       case retail:
751         sprintf (title,
752                  "                         "
753                  "The Ultimate DOOM Startup v%i.%i"
754                  "                           ",
755                  VERSION/100,VERSION%100);
756         break;
757       case shareware:
758         sprintf (title,
759                  "                            "
760                  "DOOM Shareware Startup v%i.%i"
761                  "                           ",
762                  VERSION/100,VERSION%100);
763         break;
764       case registered:
765         sprintf (title,
766                  "                            "
767                  "DOOM Registered Startup v%i.%i"
768                  "                           ",
769                  VERSION/100,VERSION%100);
770         break;
771       case commercial:
772         sprintf (title,
773                  "                         "
774                  "DOOM 2: Hell on Earth v%i.%i"
775                  "                           ",
776                  VERSION/100,VERSION%100);
777         break;
778 /*FIXME
779        case pack_plut:
780         sprintf (title,
781                  "                   "
782                  "DOOM 2: Plutonia Experiment v%i.%i"
783                  "                           ",
784                  VERSION/100,VERSION%100);
785         break;
786       case pack_tnt:
787         sprintf (title,
788                  "                     "
789                  "DOOM 2: TNT - Evilution v%i.%i"
790                  "                           ",
791                  VERSION/100,VERSION%100);
792         break;
793 */
794       default:
795         sprintf (title,
796                  "                     "
797                  "Public DOOM - v%i.%i"
798                  "                           ",
799                  VERSION/100,VERSION%100);
800         break;
801     }
802     
803     printf ("%s\n",title);
804
805     if (devparm)
806         printf(D_DEVSTR);
807     
808     // turbo option
809     if ( (p=M_CheckParm ("-turbo")) )
810     {
811         int     scale = 200;
812         extern int forwardmove[2];
813         extern int sidemove[2];
814         
815         if (p<myargc-1)
816             scale = atoi (myargv[p+1]);
817         if (scale < 10)
818             scale = 10;
819         if (scale > 400)
820             scale = 400;
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;
826     }
827     
828     // add any files specified on the command line with -file wadfile
829     // to the wad list
830     //
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");
834     if (p)
835     {
836         myargv[p][4] = 'p';     // big hack, change to -warp
837
838         // Map name handling.
839         switch (gamemode )
840         {
841           case shareware:
842           case retail:
843           case registered:
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]);
848             break;
849             
850           case commercial:
851           default:
852             p = atoi (myargv[p+1]);
853             if (p<10)
854               sprintf (file,"~"DEVMAPS"cdata/map0%i.wad", p);
855             else
856               sprintf (file,"~"DEVMAPS"cdata/map%i.wad", p);
857             break;
858         }
859         D_AddFile (file);
860     }
861         
862     p = M_CheckParm ("-file");
863     if (p)
864     {
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]);
870     }
871
872     p = M_CheckParm ("-playdemo");
873
874     if (!p)
875         p = M_CheckParm ("-timedemo");
876
877     if (p && p < myargc-1)
878     {
879         sprintf (file,"%s.lmp", myargv[p+1]);
880         D_AddFile (file);
881         printf("Playing demo %s.lmp.\n",myargv[p+1]);
882     }
883     
884     // get skill / episode / map from parms
885     startskill = sk_medium;
886     startepisode = 1;
887     startmap = 1;
888     autostart = false;
889
890                 
891     p = M_CheckParm ("-skill");
892     if (p && p < myargc-1)
893     {
894         startskill = myargv[p+1][0]-'1';
895         autostart = true;
896     }
897
898     p = M_CheckParm ("-episode");
899     if (p && p < myargc-1)
900     {
901         startepisode = myargv[p+1][0]-'0';
902         startmap = 1;
903         autostart = true;
904     }
905         
906     p = M_CheckParm ("-timer");
907     if (p && p < myargc-1 && deathmatch)
908     {
909         int     time;
910         time = atoi(myargv[p+1]);
911         printf("Levels will end after %d minute",time);
912         if (time>1)
913             printf("s");
914         printf(".\n");
915     }
916
917     p = M_CheckParm ("-avg");
918     if (p && p < myargc-1 && deathmatch)
919         printf("Austin Virtual Gaming: Levels will end after 20 minutes\n");
920
921     p = M_CheckParm ("-warp");
922     if (p && p < myargc-1)
923     {
924         startmap = atoi (myargv[p+1]);
925         if (gamemode != commercial){
926             startepisode = startmap / 10;
927             startmap %= 10;
928         }
929         autostart = true;
930     }
931     
932     // init subsystems
933     printf ("V_Init: allocate screens.\n");
934     V_Init ();
935
936     printf ("M_LoadDefaults: Load system defaults.\n");
937     M_LoadDefaults ();              // load before initing other systems
938
939     printf ("Z_Init: Init zone memory allocation daemon. \n");
940     Z_Init ();
941
942     printf ("W_Init: Init WADfiles.\n");
943     W_InitMultipleFiles (wadfiles);
944     
945
946     // Check for -file in shareware
947     if (modifiedgame)
948     {
949         // These are the lumps that will be checked in IWAD,
950         // if any one is not present, execution will be aborted.
951         char name[23][8]=
952         {
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"
956         };
957         int i;
958         
959         if ( gamemode == shareware)
960             I_Error("\nYou cannot -file with the shareware "
961                     "version. Register!");
962
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.");
969     }
970     
971     // Iff additonal PWAD files are used, print modified banner
972     if (modifiedgame)
973     {
974         /*m*/printf (
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"
981             );
982         USED( getchar () );
983     }
984         
985
986     // Check and print which version is executed.
987     switch ( gamemode )
988     {
989       case shareware:
990       case indetermined:
991         printf (
992             "===========================================================================\n"
993             "                                Shareware!\n"
994             "===========================================================================\n"
995         );
996         break;
997       case registered:
998       case retail:
999       case commercial:
1000         printf (
1001             "===========================================================================\n"
1002             "                 Commercial product - do not distribute!\n"
1003             "         Please report software piracy to the SPA: 1-800-388-PIR8\n"
1004             "===========================================================================\n"
1005         );
1006         break;
1007         
1008       default:
1009         // Ouch.
1010         break;
1011     }
1012
1013     printf ("M_Init: Init miscellaneous info.\n");
1014     M_Init ();
1015
1016     printf ("R_Init: Init DOOM refresh daemon - ");
1017     R_Init ();
1018
1019     printf ("\nP_Init: Init Playloop state.\n");
1020     P_Init ();
1021
1022     printf ("I_Init: Setting up machine state.\n");
1023     I_Init ();
1024
1025     printf ("D_CheckNetGame: Checking network game status.\n");
1026     D_CheckNetGame ();
1027
1028     printf ("S_Init: Setting up sound.\n");
1029     S_Init (snd_SfxVolume /* *8 */, snd_MusicVolume /* *8*/ );
1030
1031     printf ("HU_Init: Setting up heads up display.\n");
1032     HU_Init ();
1033
1034     printf ("ST_Init: Init status bar.\n");
1035     ST_Init ();
1036
1037     // check for a driver that wants intermission stats
1038     p = M_CheckParm ("-statcopy");
1039     if (p && p<myargc-1)
1040     {
1041         // for statistics driver
1042         extern  void*   statcopy;                            
1043
1044         statcopy = (void*)atoi(myargv[p+1]);
1045         printf ("External statistics registered.\n");
1046     }
1047     
1048     // start the apropriate game based on parms
1049     p = M_CheckParm ("-record");
1050
1051     if (p && p < myargc-1)
1052     {
1053         G_RecordDemo (myargv[p+1]);
1054         autostart = true;
1055     }
1056         
1057     p = M_CheckParm ("-playdemo");
1058     if (p && p < myargc-1)
1059     {
1060         singledemo = true;              // quit after one demo
1061         G_DeferedPlayDemo (myargv[p+1]);
1062         D_DoomLoop ();  // never returns
1063     }
1064         
1065     p = M_CheckParm ("-timedemo");
1066     if (p && p < myargc-1)
1067     {
1068         G_TimeDemo (myargv[p+1]);
1069         D_DoomLoop ();  // never returns
1070     }
1071         
1072     p = M_CheckParm ("-loadgame");
1073     if (p && p < myargc-1)
1074     {
1075         sprintf(file, SAVEGAMENAME"%c.dsg",myargv[p+1][0]);
1076         G_LoadGame (file);
1077     }
1078         
1079
1080     if ( gameaction != ga_loadgame )
1081     {
1082         if (autostart || netgame)
1083             G_InitNew (startskill, startepisode, startmap);
1084         else
1085             D_StartTitle ();                // start up intro loop
1086
1087     }
1088
1089     D_DoomLoop ();  // never returns
1090 }