1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: d_main.c 1567 2020-12-21 02:43:17Z wesleyjohnson $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Copyright (C) 1998-2016 by DooM Legacy Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 //
20 // $Log: d_main.c,v $
21 // Revision 1.66 2005/12/20 14:58:25 darkwolf95
22 // Monster behavior CVAR - Affects how monsters react when they shoot each other
23 //
24 // Revision 1.65 2004/07/27 08:19:34 exl
25 // New fmod, fs functions, bugfix or 2, patrol nodes
26 //
27 // Revision 1.64 2004/04/20 00:34:26 andyp
28 // Linux compilation fixes and string cleanups
29 //
30 // Revision 1.63 2003/11/21 17:52:05 darkwolf95
31 // added "Monsters Infight" for Dehacked patches
32 //
33 // Revision 1.62 2003/07/23 17:20:37 darkwolf95
34 // Initial Chex Quest 1 Support
35 //
36 // Revision 1.61 2003/07/14 21:22:23 hurdler
37 // Revision 1.60 2003/07/13 13:16:15 hurdler
38 //
39 // Revision 1.59 2003/05/04 02:28:34 sburke
40 // Fix for big-endian machines.
41 //
42 // Revision 1.58 2002/12/13 22:34:27 ssntails
43 // MP3/OGG support!
44 //
45 // Revision 1.57 2002/09/27 16:40:08 tonyd
46 // First commit of acbot
47 //
48 // Revision 1.56 2002/09/17 21:20:02 hurdler
49 // Quick hack for hacx freeze
50 //
51 // Revision 1.55 2002/08/24 22:42:02 hurdler
52 // Apply Robert Hogberg patches
53 //
54 // Revision 1.54 2002/07/26 15:21:36 hurdler
55 //
56 // Revision 1.53 2001/12/31 16:56:39 metzgermeister
57 // see Dec 31 log
58 //
59 // Revision 1.52 2001/08/20 20:40:39 metzgermeister
60 //
61 // Revision 1.51 2001/08/12 15:21:03 bpereira
62 // see my log
63 //
64 // Revision 1.50 2001/07/16 22:35:40 bpereira
65 // - fixed crash of e3m8 in heretic
66 // - fixed crosshair not drawed bug
67 //
68 // Revision 1.49 2001/05/27 13:42:47 bpereira
69 // Revision 1.48 2001/05/16 21:21:14 bpereira
70 //
71 // Revision 1.47 2001/05/16 17:12:52 crashrl
72 // Added md5-sum support, removed recursiv wad search
73 //
74 // Revision 1.46 2001/04/27 13:32:13 bpereira
75 //
76 // Revision 1.45 2001/04/17 22:26:07 calumr
77 // Initial Mac add
78 //
79 // Revision 1.44 2001/04/04 20:24:21 judgecutor
80 // Added support for the 3D Sound
81 //
82 // Revision 1.43 2001/04/02 18:54:32 bpereira
83 // Revision 1.42 2001/04/01 17:35:06 bpereira
84 // Revision 1.41 2001/03/30 17:12:49 bpereira
85 //
86 // Revision 1.40 2001/03/19 18:25:02 hurdler
87 // Is there a GOOD reason to check for modified game with shareware version?
88 //
89 // Revision 1.39 2001/03/03 19:43:09 ydario
90 // OS/2 code cleanup
91 //
92 // Revision 1.38 2001/02/24 13:35:19 bpereira
93 // Revision 1.37 2001/02/10 12:27:13 bpereira
94 //
95 // Revision 1.36 2001/01/25 22:15:41 bpereira
96 // added heretic support
97 //
98 // Revision 1.35 2000/11/06 20:52:15 bpereira
99 // Revision 1.34 2000/11/03 03:27:17 stroggonmeth
100 // Revision 1.33 2000/11/02 19:49:35 bpereira
101 //
102 // Revision 1.32 2000/11/02 17:50:06 stroggonmeth
103 // Big 3Dfloors & FraggleScript commit!!
104 //
105 // Revision 1.31 2000/10/21 08:43:28 bpereira
106 // Revision 1.30 2000/10/08 13:29:59 bpereira
107 // Revision 1.29 2000/10/02 18:25:44 bpereira
108 // Revision 1.28 2000/10/01 10:18:16 bpereira
109 // Revision 1.27 2000/09/28 20:57:14 bpereira
110 // Revision 1.26 2000/08/31 14:30:55 bpereira
111 //
112 // Revision 1.25 2000/08/29 15:53:47 hurdler
113 // Remove master server connect timeout on LAN (not connected to Internet)
114 //
115 // Revision 1.24 2000/08/21 21:13:00 metzgermeister
116 // Implementation of I_GetKey() in Linux
117 //
118 // Revision 1.23 2000/08/10 14:50:19 ydario
119 // OS/2 port
120 //
121 // Revision 1.22 2000/05/07 08:27:56 metzgermeister
122 // Revision 1.21 2000/04/30 10:30:10 bpereira
123 //
124 // Revision 1.20 2000/04/25 19:49:46 metzgermeister
125 // support for automatic wad search
126 //
127 // Revision 1.19 2000/04/24 20:24:38 bpereira
128 // Revision 1.18 2000/04/23 16:19:52 bpereira
129 //
130 // Revision 1.17 2000/04/22 20:27:35 metzgermeister
131 // support for immediate fullscreen switching
132 //
133 // Revision 1.16 2000/04/21 20:04:20 hurdler
134 // fix a problem with my last SDL merge
135 //
136 // Revision 1.15 2000/04/19 15:21:02 hurdler
137 // add SDL midi support
138 //
139 // Revision 1.14 2000/04/18 12:55:39 hurdler
140 // Revision 1.13 2000/04/16 18:38:07 bpereira
141 //
142 // Revision 1.12 2000/04/07 23:10:15 metzgermeister
143 // fullscreen support under X in Linux
144 //
145 // Revision 1.11 2000/04/06 20:40:22 hurdler
146 // Mostly remove warnings under windows
147 //
148 // Revision 1.10 2000/04/05 15:47:46 stroggonmeth
149 // Added hack for Dehacked lumps. Transparent sprites are now affected by colormaps.
150 //
151 // Revision 1.9 2000/04/04 00:32:45 stroggonmeth
152 // Initial Boom compatability plus few misc changes all around.
153 //
154 // Revision 1.8 2000/03/29 19:39:48 bpereira
155 //
156 // Revision 1.7 2000/03/28 16:18:41 linuxcub
157 // Added a command to the Linux sound-server which sets a master volume.
158 // Added code to the main parts of doomlegacy which uses this command to
159 // implement volume control for sound effects.
160 //
161 // Added code so the (really cool) cd music works for me. The volume didn't
162 // work for me (with a Teac 532E drive): It always started at max (31) no-
163 // matter what the setting in the config-file was. The added code "jiggles"
164 // the volume-control, and now it works for me :-)
165 // If this code is unacceptable, perhaps another solution is to periodically
166 // compare the cd_volume.value with an actual value _read_ from the drive.
167 // Ie. not trusting that calling the ioctl with the correct value actually
168 // sets the hardware-volume to the requested value. Right now, the ioctl
169 // is assumed to work perfectly, and the value in cd_volume.value is
170 // compared periodically with cdvolume.
171 //
172 // Updated the spec file, so an updated RPM can easily be built, with
173 // a minimum of editing. Where can I upload my pre-built (S)RPMS to ?
174 //
175 // Erling Jacobsen, linuxcub@email.dk
176 //
177 // Revision 1.6 2000/03/23 22:54:00 metzgermeister
178 // added support for HOME/.legacy under Linux
179 //
180 // Revision 1.5 2000/03/06 17:33:36 hurdler
181 // Revision 1.4 2000/03/05 17:10:56 bpereira
182 // Revision 1.3 2000/02/27 00:42:10 hurdler
183 // fix CR+LF problem
184 //
185 //
186 // DESCRIPTION:
187 // DOOM main program (D_DoomMain) and game loop (D_DoomLoop),
188 // plus functions to determine game mode (shareware, doom_registered),
189 // parse command line parameters, configure game parameters (turbo),
190 // and call the startup functions.
191 //
192 //-----------------------------------------------------------------------------
193
194 #include "doomincl.h"
195 // MAX_WADPATH
196
197 #ifdef __WIN32__
198 #include <direct.h>
199 #else
200 #include <unistd.h> // for access
201 #define _MAX_PATH MAX_WADPATH
202 #endif
203
204 // using MAX_WADPATH as buffer limit, so _MAX_PATH must be as long
205 #if _MAX_PATH < MAX_WADPATH
206 #undef _MAX_PATH
207 #define _MAX_PATH MAX_WADPATH
208 #endif
209
210
211 #include "doomstat.h"
212
213 #include "command.h"
214 #include "console.h"
215
216 #include "am_map.h"
217 #include "d_net.h"
218 #include "d_netcmd.h"
219 #include "dehacked.h"
220 #include "dstrings.h"
221
222 #include "f_wipe.h"
223 #include "f_finale.h"
224
225 #include "g_game.h"
226 #include "g_input.h"
227
228 #include "hu_stuff.h"
229
230 #include "i_sound.h"
231 #include "i_system.h"
232 #include "i_video.h"
233
234 #include "m_argv.h"
235 #include "m_menu.h"
236 #include "m_misc.h"
237 #include "m_swap.h"
238
239 #include "p_setup.h"
240 #include "p_fab.h"
241 #include "p_info.h"
242 #include "p_local.h"
243
244 #include "r_main.h"
245 #include "r_local.h"
246
247 #include "s_sound.h"
248 #include "st_stuff.h"
249
250 #include "t_script.h"
251
252 #include "v_video.h"
253
254 #include "wi_stuff.h"
255 #include "w_wad.h"
256
257 #include "z_zone.h"
258 #include "d_main.h"
259 #include "d_netfil.h"
260 #include "m_cheat.h"
261 #include "p_chex.h"
262
263 #ifdef HWRENDER
264 #include "hardware/hw_main.h"
265 // 3D View Rendering
266 #endif
267
268 #include "hardware/hw3sound.h"
269
270 #include "b_game.h"
271 //added by AC for acbot
272
273 #ifdef FRENCH_INLINE
274 #include "d_french.h"
275 #endif
276
277 // Versioning
278 #ifndef SVN_REV
279 #define SVN_REV "1567"
280 #endif
281
282
283 // Version number: major.minor.revision
284 const int VERSION = 148; // major*100 + minor
285 const int REVISION = 8; // for bugfix releases, should not affect compatibility. has nothing to do with svn revisions.
286 static const char VERSIONSTRING[] = "(rev " SVN_REV ")";
287 //static const char VERSIONSTRING[] = "beta (rev " SVN_REV ")";
288 char VERSION_BANNER[80];
289
290 // [WDJ] change this if legacy.wad is changed
291 const short cur_wadversion = 148; // release wadversion
292 // usually allow one version behind cur_wadversion, for easier testing
293 // does not have to be full featured
294 const short min_wadversion = 145;
295
296
297 //
298 // DEMO LOOP
299 //
300 int demosequence;
301 int pagetic;
302 static const char * pagename = "TITLEPIC";
303
304 // PROTOS
305 static void Help(void);
306 static void Clear_SoftError(void);
307 void Heretic_PatchEngine(void);
308 //void Chex1_PatchEngine(void);
309
310 // Null terminated list of files.
311 char * startupwadfiles[MAX_WADFILES+1];
312
313 // command line switches
314 boolean nomonsters; // checkparm of -nomonsters
315
316 boolean singletics = false; // timedemo
317
318 boolean nomusic;
319 boolean nosoundfx; // had clash with WATCOM i86.h nosound() function
320
321 boolean dedicated = false; // dedicated server
322
323 byte verbose = 0;
324 byte devparm = 0;
325 // set by -devparm, plus verbose level.
326 // devparm enables development mode, with CONS messages reporting
327 // on memory usage and other significant events.
328
329 byte demo_ctrl;
330 byte init_sequence = 0;
331 byte fatal_error = 0;
332
333 // name buffer sizes including directory and everything
334 #define FILENAME_SIZE 256
335
336 #if defined SMIF_PC_DOS || defined __WIN32__ || defined __OS2__
337 # define SLASH "\\"
338 #else
339 # define SLASH "/"
340 #endif
341
342 // to make savegamename and directories, in m_menu.c
343 char *legacyhome = NULL;
344 int legacyhome_len;
345
346 char *dirlist[] =
347 { DEFWADS01,
348 #ifdef DEFWADS02
349 DEFWADS02,
350 #endif
351 #ifdef DEFWADS03
352 DEFWADS03,
353 #endif
354 #ifdef DEFWADS04
355 DEFWADS04,
356 #endif
357 #ifdef DEFWADS05
358 DEFWADS05,
359 #endif
360 #ifdef DEFWADS06
361 DEFWADS06,
362 #endif
363 #ifdef DEFWADS07
364 DEFWADS07,
365 #endif
366 #ifdef DEFWADS08
367 DEFWADS08,
368 #endif
369 #ifdef DEFWADS09
370 DEFWADS09,
371 #endif
372 #ifdef DEFWADS10
373 DEFWADS10,
374 #endif
375 #ifdef DEFWADS11
376 DEFWADS11,
377 #endif
378 #ifdef DEFWADS12
379 DEFWADS12,
380 #endif
381 #ifdef DEFWADS13
382 DEFWADS13,
383 #endif
384 #ifdef DEFWADS14
385 DEFWADS14,
386 #endif
387 #ifdef DEFWADS15
388 DEFWADS15,
389 #endif
390 #ifdef DEFWADS16
391 DEFWADS16,
392 #endif
393 #ifdef DEFWADS17
394 DEFWADS17,
395 #endif
396 #ifdef DEFWADS18
397 DEFWADS18,
398 #endif
399 #ifdef DEFWADS19
400 DEFWADS19,
401 #endif
402 #ifdef DEFWADS20
403 DEFWADS20,
404 #endif
405 #ifdef DEFWADS21
406 DEFWADS21,
407 #endif
408 };
409 // Doomwaddir allocation:
410 // [0] = DOOMWADDIR. (ref)
411 // [1] = reserved for dynamic use (ref)
412 // [2] = reserved for dynamic use (ref)
413 #define DOOMWADDIR_DIRLIST 3
414 // [3.. (MAX_NUM_DOOMWADDIR - 3)] = DEFWADSxx (ref or malloc)
415 // [MAX_NUM_DOOMWADDIR-2] = reserved for dynamic use (ref)
416 // [MAX_NUM_DOOMWADDIR-1] = reserved for dynamic use (ref)
417 char * doomwaddir[MAX_NUM_DOOMWADDIR];
418
419 static byte defdir_stat = 0; // when defdir valid
420 static byte defdir_search = 0; // when defdir search is reasonable
421 static char * defdir = NULL; // default dir (malloc)
422 static char * progdir = NULL; // program dir (malloc)
423 static char * progdir_wads = NULL; // program wads directory (malloc)
424
425 #ifdef LAUNCHER
426 consvar_t cv_home = {"home", "", CV_HIDEN, NULL};
427 consvar_t cv_doomwaddir = {"doomwaddir", "", CV_HIDEN, NULL};
428 consvar_t cv_iwad = {"iwad", "", CV_HIDEN, NULL};
429 #endif
430
431
432 #if defined(__APPLE__) && defined(__MACH__)
433 // [WDJ] This is very likely only for a development setup using an .app folder
434 #ifdef EXT_MAC_DIR_SPEC
435 //[segabor]: for Mac specific resources
436 extern char mac_legacy_wad[FILENAME_SIZE]; // legacy.wad in Resources
437 extern char mac_md2_wad[FILENAME_SIZE]; // md2.wad in Resources
438 extern char mac_user_home[FILENAME_SIZE]; // for config and savegames
439 #endif
440 #endif
441
442 // Setup variable doomwaddir for owner usage.
owner_wad_search_order(void)443 void owner_wad_search_order( void )
444 {
445 // Wad search order.
446 defdir_search = 0;
447 if( defdir_stat )
448 {
449 if( ( access( "Desktop", R_OK) == 0 )
450 ||( access( "Pictures", R_OK) == 0 )
451 ||( access( "Music", R_OK) == 0 ) )
452 {
453 if( verbose )
454 GenPrintf( EMSG_ver, "Desktop, Pictures, or Music dir detected, default dir not searched.\n");
455 }
456 else
457 if( defdir
458 &&( !(strcmp( defdir, cv_home.string ) == 0) ) // not home directory
459 &&( !(progdir && (strcmp( defdir, progdir ) == 0)) ) // not program directory
460 &&( !(progdir_wads && (strcmp( defdir, progdir_wads ) == 0)) ) // not wads directory
461 )
462 {
463 defdir_search = 1;
464 // Search current dir near first, for other wad searches.
465 doomwaddir[1] = defdir;
466 }
467 }
468 // Search progdir/wads early, for other wad searches.
469 doomwaddir[2] = progdir_wads;
470 // Search last, for other wad searches.
471 doomwaddir[MAX_NUM_DOOMWADDIR-1] = progdir;
472 }
473
474
475
476 //
477 // EVENT HANDLING
478 //
479 // Events are asynchronous inputs generally generated by the game user.
480 // Events can be discarded if no responder claims them
481 // referenced from i_system.c for I_GetKey()
482
483 event_t events[MAXEVENTS];
484 int eventhead = 0;
485 int eventtail = 0;
486
487 //
488 // D_PostEvent
489 // Called by the I/O functions when input is detected
490 //
D_PostEvent(const event_t * ev)491 void D_PostEvent(const event_t * ev)
492 {
493 events[eventhead] = *ev;
494 eventhead = (eventhead + 1) & (MAXEVENTS - 1);
495 }
496
497 // just for lock this function
498 #ifdef SMIF_PC_DOS
D_PostEvent_end(void)499 void D_PostEvent_end(void)
500 {
501 };
502 #endif
503
504 // Clear the input events before re-enabling play
505 static
D_Clear_Events(void)506 void D_Clear_Events( void )
507 {
508 eventhead = eventtail = 0;
509 mousex = mousey = 0; // clear accumulated motion
510 }
511
512 //
513 // D_Process_Events
514 // Send all the events of the given timestamp down the responder chain
515 //
D_Process_Events(void)516 void D_Process_Events(void)
517 {
518 event_t *ev;
519
520 while (eventtail != eventhead)
521 {
522 ev = &events[eventtail];
523
524 if (M_Responder(ev)) // Menu input
525 ; // menu ate the event
526 else if (CON_Responder(ev)) // console input
527 ;
528 else
529 G_Responder(ev);
530
531 eventtail++;
532 eventtail = eventtail & (MAXEVENTS - 1);
533 }
534 }
535
536 //
537 // D_Display
538 // draw current display, possibly wiping it from the previous
539 //
540
541 // There is a wipe each change of the gamestate.
542 // wipegamestate can be set to GS_FORCEWIPE to force a wipe on the next draw.
543 gamestate_e wipegamestate = GS_DEMOSCREEN;
544
545 CV_PossibleValue_t screenslink_cons_t[] = { {0, "None"}, {wipe_ColorXForm + 1, "Crossfade"}, {wipe_Melt + 1, "Melt"}, {0, NULL} };
546 consvar_t cv_screenslink = { "screenlink", "2", CV_SAVE, screenslink_cons_t };
547
548 // Not called when dedicated.
549 static
D_Display(void)550 void D_Display(void)
551 {
552 // vid : from video setup
553 static boolean menuactivestate = false;
554 static boolean draw_refresh = false;
555 static gamestate_e oldgamestate = GS_FORCEWIPE; // invalid state
556 static int borderdrawcount = 0;
557
558 tic_t nowtime;
559 tic_t tics;
560 tic_t wipestart;
561 int y;
562 boolean wipe_done;
563 boolean wipe;
564 boolean redrawsbar;
565
566 if (nodrawers)
567 return; // for comparative timing / profiling
568
569 wipe = false;
570 redrawsbar = false;
571 wipe_done = false;
572
573 //added:21-01-98: check for change of screen size (video mode)
574 if( setmodeneeded.modetype || drawmode_recalc )
575 {
576 SCR_SetMode( 1 ); // change video mode
577 //added:26-01-98: NOTE! setsizeneeded is set by SCR_Recalc()
578 SCR_Recalc();
579 // setsizeneeded -> redrawsbar
580 // con_recalc, stbar_recalc, am_recalc
581 drawmode_recalc = false;
582 }
583
584 // change the view size if needed
585 if (setsizeneeded)
586 {
587 R_ExecuteSetViewSize(); // set rdraw, view scale, limits, projection
588 oldgamestate = GS_FORCEWIPE; // force background redraw
589 redrawsbar = true;
590 draw_refresh = true;
591 }
592
593 if( rendermode_recalc )
594 {
595 if( gamestate == GS_LEVEL )
596 {
597 // R_FillBackScreen();
598 R_Setup_Drawmode();
599 draw_refresh = true;
600 oldgamestate = GS_FORCEWIPE; // force background redraw
601 #ifdef HWRENDER
602 if( rendermode != render_soft )
603 {
604 // Hardware draw only
605 HWR_SetupLevel();
606 HWR_Preload_Graphics();
607 }
608 #endif
609 }
610 }
611
612 // save the current screen if about to wipe
613 if (gamestate != wipegamestate && rendermode == render_soft)
614 {
615 wipe = true;
616 wipe_StartScreen();
617 }
618
619 // draw buffered stuff to screen
620 // BP: Used only by linux GGI version
621 I_UpdateNoBlit();
622
623 // do buffered drawing
624 switch (gamestate)
625 {
626 case GS_LEVEL:
627 if (!gametic)
628 break;
629
630 // On each gametic
631 HU_Erase();
632 if (automapactive)
633 AM_Drawer();
634
635 if (wipe || menuactivestate
636 #ifdef HWRENDER
637 || rendermode != render_soft
638 #endif
639 || vid.recalc)
640 {
641 redrawsbar = true;
642 }
643 break;
644
645 case GS_INTERMISSION:
646 WI_Drawer();
647 break;
648
649 case GS_FINALE:
650 F_Drawer();
651 break;
652
653 case GS_DEDICATEDSERVER:
654 case GS_DEMOSCREEN:
655 D_PageDrawer(pagename);
656 break;
657
658 case GS_WAITINGPLAYERS:
659 // [WDJ] Because hardware may double buffer, need to overwrite
660 // background. Waiting loop may get alternating backgrounds.
661 D_PageDrawer(pagename); // provide background
662 D_WaitPlayer_Drawer();
663 break;
664
665 case GS_NULL:
666 default:
667 break;
668 }
669
670 if (gamestate == GS_LEVEL)
671 {
672 if (oldgamestate != GS_LEVEL)
673 {
674 // Level map play display initialize
675 R_FillBackScreen(); // draw the pattern into the back screen
676 // the border needs to be initially drawn
677 draw_refresh = true;
678 }
679
680 // Level map play display
681 // draw the view directly
682 if (!automapactive)
683 {
684 // see if the border needs to be updated to the screen
685 if( rdraw_scaledviewwidth != vid.width )
686 {
687 // the menu may draw over parts out of the view window,
688 // which are refreshed only when needed
689 if( menuactive || menuactivestate || draw_refresh )
690 borderdrawcount = 3;
691
692 if( borderdrawcount )
693 {
694 borderdrawcount--;
695 R_DrawViewBorder(); // erase old menu stuff
696 }
697 }
698
699 if (displayplayer_ptr->mo)
700 {
701 #ifdef CLIENTPREDICTION2
702 displayplayer_ptr->mo->flags2 |= MF2_DONTDRAW;
703 #endif
704 #ifdef HWRENDER
705 if (rendermode != render_soft)
706 HWR_RenderPlayerView(0, displayplayer_ptr);
707 else //if (rendermode == render_soft)
708 #endif
709 R_RenderPlayerView(0, displayplayer_ptr);
710 #ifdef CLIENTPREDICTION2
711 displayplayer_ptr->mo->flags2 &= ~MF2_DONTDRAW;
712 #endif
713 }
714
715 // added 16-6-98: render the second screen
716 if ( displayplayer2_ptr && displayplayer2_ptr->mo)
717 {
718 #ifdef CLIENTPREDICTION2
719 displayplayer2_ptr->mo->flags2 |= MF2_DONTDRAW;
720 #endif
721 #ifdef HWRENDER
722 if (rendermode != render_soft)
723 HWR_RenderPlayerView(1, displayplayer2_ptr);
724 else
725 #endif
726 {
727 // Alter the draw tables to draw into second player window
728 //faB: Boris hack :P !!
729 viewwindowy = vid.height / 2;
730 memcpy(ylookup, ylookup2, rdraw_viewheight * sizeof(ylookup[0]));
731
732 R_RenderPlayerView(1, displayplayer2_ptr);
733
734 // Restore first player tables
735 viewwindowy = 0;
736 memcpy(ylookup, ylookup1, rdraw_viewheight * sizeof(ylookup[0]));
737 }
738 #ifdef CLIENTPREDICTION2
739 displayplayer2_ptr->mo->flags2 &= ~MF2_DONTDRAW;
740 #endif
741 }
742 }
743
744 HU_Drawer();
745
746 ST_Drawer(redrawsbar);
747
748 draw_refresh = false;
749 }
750 else
751 {
752 // not GS_LEVEL
753 // change gamma if needed
754 if( gamestate != oldgamestate )
755 V_SetPalette(0);
756 }
757
758 menuactivestate = menuactive;
759 oldgamestate = wipegamestate = gamestate;
760
761 // draw pause pic
762 if (paused && (!menuactive || netgame))
763 {
764 patch_t *patch;
765 if (automapactive)
766 y = 4;
767 else
768 y = viewwindowy + 4;
769 patch = W_CachePatchName("M_PAUSE", PU_CACHE); // endian fix
770 // 0
771 V_SetupDraw( 0 | V_SCALEPATCH | V_SCALESTART );
772 V_DrawScaledPatch(viewwindowx + (BASEVIDWIDTH - patch->width) / 2, y, patch);
773 }
774
775 //added:24-01-98:vid size change is now finished if it was on...
776 vid.recalc = 0;
777 rendermode_recalc = false;
778
779 // Exl: draw a faded background
780 if( fs_fadealpha != 0 )
781 {
782 #ifdef HWRENDER
783 if( rendermode != render_soft)
784 {
785 HWR_FadeScreenMenuBack(fs_fadecolor, fs_fadealpha, vid.height);
786 }
787 else
788 #endif
789 {
790 // Fade for software draw.
791 V_FadeRect(0, vid.width, vid.height, (0xFF - fs_fadealpha),
792 (fs_fadealpha * 32 / 0x100), fs_fadecolor );
793 }
794 }
795
796 //FIXME: draw either console or menu, not the two
797 CON_Drawer();
798
799 M_Drawer(); // menu is drawn even on top of everything
800 NetUpdate(); // send out any new accumulation
801
802 //
803 // normal update
804 //
805 if (!wipe)
806 {
807 if (cv_netstat.value)
808 {
809 char s[50];
810 Net_GetNetStat();
811 sprintf(s, "recv %d b/s", netstat_recv_bps);
812 V_DrawString(BASEVIDWIDTH - V_StringWidth(s), BASEVIDHEIGHT - ST_HEIGHT - 40, V_WHITEMAP, s);
813 sprintf(s, "send %d b/s", netstat_send_bps);
814 V_DrawString(BASEVIDWIDTH - V_StringWidth(s), BASEVIDHEIGHT - ST_HEIGHT - 30, V_WHITEMAP, s);
815 sprintf(s, "GameMiss %.2f%%", netstat_gamelost_percent);
816 V_DrawString(BASEVIDWIDTH - V_StringWidth(s), BASEVIDHEIGHT - ST_HEIGHT - 20, V_WHITEMAP, s);
817 sprintf(s, "SysMiss %.2f%%", netstat_lost_percent);
818 V_DrawString(BASEVIDWIDTH - V_StringWidth(s), BASEVIDHEIGHT - ST_HEIGHT - 10, V_WHITEMAP, s);
819 }
820
821 #ifdef TILTVIEW
822 //added:12-02-98: tilt view when marine dies... just for fun
823 if (gamestate == GS_LEVEL && cv_tiltview.value
824 && displayplayer_ptr->playerstate == PST_DEAD)
825 {
826 V_DrawTiltView(screens[0]);
827 }
828 else
829 #endif
830 #ifdef PERSPCORRECT
831 if (gamestate == GS_LEVEL && cv_perspcorr.value
832 && rendermode == render_soft )
833 {
834 V_DrawPerspView(screens[0], displayplayer_ptr->aiming);
835 }
836 else
837 #endif
838 {
839 //I_BeginProfile();
840 // display a graph of ticrate
841 if (cv_ticrate.value )
842 V_Draw_ticrate_graph();
843 I_FinishUpdate(); // page flip or blit buffer
844 //debug_Printf("last frame update took %d\n", I_EndProfile());
845 }
846 return;
847 }
848
849 //
850 // wipe update
851 //
852 if (!cv_screenslink.value)
853 return;
854
855 wipe_EndScreen();
856
857 wipestart = I_GetTime() - 1;
858 y = wipestart + 2 * TICRATE; // init a timeout
859 do
860 {
861 do
862 {
863 nowtime = I_GetTime();
864 tics = nowtime - wipestart;
865 } while (!tics);
866 wipestart = nowtime;
867 wipe_done = wipe_ScreenWipe(cv_screenslink.value - 1, tics);
868 I_OsPolling();
869 I_UpdateNoBlit();
870 M_Drawer(); // menu is drawn even on top of wipes
871 I_FinishUpdate(); // page flip or blit buffer
872 } while (!wipe_done && I_GetTime() < (unsigned) y);
873
874 ST_Invalidate();
875 }
876
877 // =========================================================================
878 // D_DoomLoop
879 // =========================================================================
880
881 tic_t rendergametic; // The last gametic that was rendered.
882 #ifdef CLIENTPREDICTION2
883 boolean spirit_update;
884 #endif
885
886 //#define SAVECPU_EXPERIMENTAL
887
888 // Called by port main program.
D_DoomLoop(void)889 void D_DoomLoop(void)
890 {
891 char acbuf[_MAX_PATH ];
892 tic_t oldentertics, entertic, realtics, rendertimeout = -1;
893
894 if (demorecording)
895 G_BeginRecording();
896
897 // [WDJ] DoomLegacy may be installed local or in system directory.
898 // Feature Request by Leonardo Montenegro.
899 // There may be a local autoexec, and/or a system autoexec.
900 // Standard: The local file is preferred, and can chain to the system file when preferable.
901 cat_filename( acbuf, legacyhome, "autoexec.cfg"); // local file in doomlegacy home
902 if( access( acbuf, R_OK) == 0 )
903 {
904 // user settings
905 GenPrintf( EMSG_ver, "Exec Local autoexec: %s\n", acbuf );
906 COM_BufAddText( va( "exec %s\n", acbuf) );
907 }
908 else if( access( "autoexec.cfg", R_OK) == 0 ) // file with executable
909 {
910 // file with executable, may be system settings
911 GenPrintf( EMSG_ver, "Exec System autoexec\n" );
912 COM_BufAddText("exec autoexec.cfg\n");
913 }
914
915 // end of loading screen: CONS_Printf() will no more call FinishUpdate()
916 con_self_refresh = false;
917
918 oldentertics = I_GetTime();
919
920 // make sure to do a d_display to init mode _before_ load a level
921 if( setmodeneeded.modetype || drawmode_recalc )
922 {
923 // This may also execute accumulated commands.
924 SCR_SetMode( 1 ); // change video mode
925 SCR_Recalc();
926 drawmode_recalc = false;
927 }
928 if( rendermode_recalc )
929 {
930 I_Rendermode_setup();
931 rendermode_recalc = 0;
932 }
933
934 D_Clear_Events(); // clear input events to prevent startup jerks,
935 // motion during screen wipe still gets through
936
937 // Execute accumulated commands.
938 COM_BufExecute( CFG_none );
939
940 while (1)
941 {
942 // get real tics
943 entertic = I_GetTime();
944 realtics = entertic - oldentertics;
945 oldentertics = entertic;
946
947 #ifdef SAVECPU_EXPERIMENTAL
948 if (realtics == 0)
949 {
950 I_Sleep(10);
951 continue;
952 }
953 #endif
954
955 // frame synchronous IO operations
956 // UNUSED for the moment (18/12/98)
957 I_StartFrame();
958
959 #ifdef HW3SOUND
960 if( ! dedicated )
961 {
962 HW3S_BeginFrameUpdate();
963 }
964 #endif
965
966 // process tics (but maybe not if realtic==0)
967 TryRunTics(realtics);
968 #ifdef CLIENTPREDICTION2
969 if (singletics || spirit_update)
970 #else
971 if (singletics || gametic > rendergametic)
972 #endif
973 {
974 rendergametic = gametic;
975 rendertimeout = entertic + TICRATE / 17;
976
977 if( ! dedicated )
978 {
979 //added:16-01-98:consoleplayer -> displayplayer (hear sounds from viewpoint)
980 S_UpdateSounds(); // move positional sounds
981 // Update display, next frame, with current state.
982 D_Display();
983 }
984 #ifdef CLIENTPREDICTION2
985 spirit_update = false;
986 #endif
987 }
988 else if (rendertimeout < entertic) // in case the server hang or netsplit
989 {
990 if( ! dedicated )
991 {
992 D_Display();
993 }
994 }
995
996 if( ! dedicated )
997 {
998 //Other implementations might need to update the sound here.
999 #ifndef SNDSERV
1000 // Sound mixing for the buffer is snychronous.
1001 I_UpdateSound();
1002 #endif
1003 // Synchronous sound output is explicitly called.
1004 #ifndef SNDINTR
1005 // Update sound output.
1006 I_SubmitSound();
1007 #endif
1008
1009 #ifdef CDMUS
1010 // check for media change, loop music..
1011 I_UpdateCD();
1012 #endif
1013
1014 #ifdef HW3SOUND
1015 HW3S_EndFrameUpdate();
1016 #endif
1017 }
1018 }
1019 }
1020
1021 // =========================================================================
1022 // Demo
1023 // =========================================================================
1024
1025 //
1026 // D_PageTicker
1027 // Handles timing for warped projection
1028 //
D_PageTicker(void)1029 void D_PageTicker(void)
1030 {
1031 if (--pagetic < 0)
1032 D_AdvanceDemo();
1033 }
1034
1035 //
1036 // D_PageDrawer : draw a patch supposed to fill the screen,
1037 // fill the borders with a background pattern (a flat)
1038 // if the patch doesn't fit all the screen.
1039 //
D_PageDrawer(const char * lumpname)1040 void D_PageDrawer(const char *lumpname)
1041 {
1042 int x, y;
1043 byte *src;
1044 byte *dest; // within screen buffer
1045
1046 // [WDJ] Draw patch for all bpp, bytepp, and padded lines.
1047 V_SetupDraw( 0 | V_SCALESTART | V_SCALEPATCH | V_CENTERHORZ );
1048
1049 // software mode which uses generally lower resolutions doesn't look
1050 // good when the pic is scaled, so it fills space around with a pattern,
1051 // and the pic is only scaled to integer multiples (x2, x3...)
1052 if (rendermode == render_soft)
1053 {
1054 if ((vid.width > BASEVIDWIDTH) || (vid.height > BASEVIDHEIGHT))
1055 {
1056 src = scr_borderflat;
1057 dest = screens[0];
1058
1059 for (y = 0; y < vid.height; y++)
1060 {
1061 // repeatly draw a 64 pixel wide flat
1062 dest = screens[0] + (y * vid.ybytes); // within screen buffer
1063 for (x = 0; x < vid.width / 64; x++)
1064 {
1065 V_DrawPixels( dest, 0, 64, &src[(y & 63) << 6]);
1066 dest += (64 * vid.bytepp);
1067 }
1068 if (vid.width & 63)
1069 {
1070 V_DrawPixels( dest, 0, (vid.width & 63), &src[(y & 63) << 6]);
1071 }
1072 }
1073 }
1074 }
1075 // big hack for legacy's credits
1076 if (EN_heretic_hexen && (demosequence != 2))
1077 {
1078 V_DrawRawScreen_Num(0, 0, W_GetNumForName(lumpname), 320, 200);
1079 if (demosequence == 0 && pagetic <= 140)
1080 V_DrawScaledPatch_Name(4, 160, "ADVISOR" );
1081 }
1082 else
1083 {
1084 V_DrawScaledPatch_Name(0, 0, lumpname );
1085 }
1086 }
1087
1088
1089 //
1090 // D_AdvanceDemo
1091 // Called after each demo or intro demosequence finishes
1092 //
1093 // Called by D_StartTitle, with init of demosequence
1094 // Called by D_PageTicker, when gamestate == GS_DEMOSCREEN
1095 // Called by G_CheckDemoStatus when timing or playing a demo
D_AdvanceDemo(void)1096 void D_AdvanceDemo(void)
1097 {
1098 // [WDJ] do not start a demo when a menu or console is open
1099 if( !(demo_ctrl & DEMO_seq_disabled) && ! menuactive
1100 && ! console_open )
1101 demo_ctrl = DEMO_seq_advance; // flag to trigger D_DoAdvanceDemo
1102 }
1103
1104 //
1105 // This cycles through the demo sequences.
1106 // FIXME - version dependent demo numbers?
1107 //
1108 // Called by TryRunTics when demo_ctrl == DEMO_seq_advance
D_DoAdvanceDemo(void)1109 void D_DoAdvanceDemo(void)
1110 {
1111 const char * demo_name;
1112
1113 demo_ctrl = 0; // cancel DEMO_seq_advance
1114 players[consoleplayer].playerstate = PST_LIVE; // not reborn
1115 gameaction = ga_nothing;
1116
1117 if (gamemode == ultdoom_retail)
1118 demosequence = (demosequence + 1) % 7;
1119 else
1120 demosequence = (demosequence + 1) % 6;
1121
1122 switch (demosequence)
1123 {
1124 case 0:
1125 pagename = "TITLEPIC";
1126 switch (gamemode)
1127 {
1128 case hexen:
1129 case heretic:
1130 pagetic = 210 + 140;
1131 pagename = "TITLE";
1132 S_StartMusic(mus_htitl);
1133 break;
1134 case doom2_commercial:
1135 pagetic = TICRATE * 11;
1136 S_StartMusic(mus_dm2ttl);
1137 break;
1138 default:
1139 pagetic = 170;
1140 S_StartMusic(mus_intro);
1141 break;
1142 }
1143 gamestate = GS_DEMOSCREEN;
1144 break;
1145 case 1:
1146 demo_name = "demo1";
1147 goto playdemo;
1148 case 2:
1149 pagetic = 200;
1150 gamestate = GS_DEMOSCREEN;
1151 pagename = "CREDIT";
1152 break;
1153 case 3:
1154 demo_name = "demo2";
1155 goto playdemo;
1156 case 4:
1157 gamestate = GS_DEMOSCREEN;
1158 if (gamemode == doom2_commercial)
1159 {
1160 pagetic = TICRATE * 11;
1161 pagename = "TITLEPIC";
1162 S_StartMusic(mus_dm2ttl);
1163 }
1164 else if (gamemode == heretic)
1165 {
1166 pagetic = 200;
1167 if( ! VALID_LUMP( W_CheckNumForName("e2m1") ) )
1168 pagename = "ORDER";
1169 else
1170 pagename = "CREDIT";
1171 }
1172 else
1173 {
1174 pagetic = 200;
1175
1176 if (gamemode == ultdoom_retail)
1177 pagename = text[CREDIT_NUM];
1178 else
1179 pagename = text[HELP2_NUM];
1180 }
1181 break;
1182 case 5:
1183 demo_name = "demo3";
1184 goto playdemo;
1185 // THE DEFINITIVE DOOM Special Edition demo
1186 case 6:
1187 demo_name = "demo4";
1188 goto playdemo;
1189 }
1190 return;
1191
1192 playdemo:
1193 G_DeferedPlayDemo( demo_name );
1194 demo_ctrl = DEMO_seq_playdemo; // demo started here (not console)
1195 pagetic = 9999999;
1196 return;
1197 }
1198
1199 // Disable demos
1200 // Called when load game or init new game
D_DisableDemo(void)1201 void D_DisableDemo(void)
1202 {
1203 if( demoplayback )
1204 G_StopDemo();
1205 // stop DEMO_seq_advance, but preserve DEMO_seq_playdemo so can abort it
1206 demo_ctrl = (demo_ctrl & DEMO_seq_playdemo) | DEMO_seq_disabled;
1207 }
1208
1209 // =========================================================================
1210
1211 //
1212 // D_StartTitle
1213 //
1214 // Called by D_DoomMain(), when not server and not starting game
1215 // Called by Command_ExitGame_f
1216 // Called by CL_ConnectToServer when cannot join server, or aborting
1217 // Called by Got_KickCmd, when player kicked from game
1218 // Called by Net_Packet_Handler, upon server shutdown, timeout, or refused (NACK)
1219 // Called by G_InitNew, when aborting game because cannot downgrade
1220 // Called by M_Responder and M_Setup_prevMenu, when exiting menu and not playing game
D_StartTitle(void)1221 void D_StartTitle(void)
1222 {
1223 D_End_commandline();
1224
1225 gameaction = ga_nothing;
1226 playerdeadview = false;
1227 displayplayer = consoleplayer = statusbarplayer = 0;
1228 displayplayer_ptr = consoleplayer_ptr = &players[0]; // [WDJ]
1229 paused = 0;
1230 demo_ctrl = 0; // enable screens and seq demos
1231 demosequence = -1;
1232 CON_ToggleOff();
1233 D_AdvanceDemo();
1234 }
1235
1236 // End commandline game setup.
D_End_commandline(void)1237 void D_End_commandline( void )
1238 {
1239 // Does not affect video settings (CS_EV_PROT)
1240 if( command_EV_param )
1241 CV_Restore_User_Settings(); // remove temp settings
1242 }
1243
1244
1245
1246 // =========================================================================
1247 // D_DoomMain
1248 // =========================================================================
1249
1250
1251 // Print out the search directories for verbose, and error.
1252 // emf: EMSG_ver, EMSG_error, EMSG_warn
1253 // enables: 0x01 legacy.wad order
1254 // 0x02 IWAD order
1255 // 0x0F verbose all
1256 static
Print_search_directories(byte emf,byte enables)1257 void Print_search_directories( byte emf, byte enables )
1258 {
1259 int wdi;
1260 GenPrintf(emf, "Search directories:\n");
1261 // Extra legacy.wad search, and verbose.
1262 if( (enables&0x01) && progdir )
1263 GenPrintf(emf, " progdir: %s\n", progdir );
1264 // Verbose only. For IWAD or legacy.wad they are in doomwaddir entries.
1265 if( (enables==0x0F) && progdir_wads )
1266 GenPrintf(emf, " : %s\n", progdir_wads );
1267 if( (enables==0x0F) && defdir && defdir_search )
1268 GenPrintf(emf, " defdir: %s\n", defdir );
1269 #ifdef LEGACYWADDIR
1270 GenPrintf(emf, " LEGACYWADDIR: %s\n", LEGACYWADDIR );
1271 #endif
1272 for( wdi=0; wdi<MAX_NUM_DOOMWADDIR; wdi++ )
1273 {
1274 if( doomwaddir[wdi] )
1275 GenPrintf(emf, " Doomwaddir[%i]: %s\n", wdi, doomwaddir[wdi] );
1276 }
1277 }
1278
1279
1280
1281 //
1282 // D_AddFile
1283 //
1284 static
D_AddFile(const char * filename)1285 void D_AddFile(const char *filename)
1286 {
1287 int numwadfiles;
1288 char *newfile;
1289
1290 if( filename == NULL )
1291 return;
1292
1293 // find end of wad files by counting
1294 for (numwadfiles = 0; startupwadfiles[numwadfiles]; numwadfiles++)
1295 ;
1296 if( numwadfiles >= MAX_WADFILES )
1297 I_Error ( "Too many wadfiles, max=%i.\n", MAX_WADFILES );
1298
1299 newfile = malloc(strlen(filename) + 1);
1300 strcpy(newfile, filename);
1301
1302 startupwadfiles[numwadfiles] = newfile;
1303 }
1304
1305
1306 #ifdef LAUNCHER
D_Clear_Files(void)1307 static void D_Clear_Files( void )
1308 {
1309 int i;
1310 for (i = 0; startupwadfiles[i]; i++)
1311 {
1312 free( startupwadfiles[i] );
1313 startupwadfiles[i] = NULL;
1314 }
1315 }
1316 #endif
1317
1318
1319 // ==========================================================================
1320 // Identify the Doom version, and IWAD file to use.
1321 // Sets 'gamemode' to determine whether doom_registered/doom2_commercial
1322 // features are available (notable loading PWAD files).
1323 // ==========================================================================
1324
1325 // [WDJ] Title and file names used in GDESC_other table entry, and other uses.
1326 #define DESCNAME_SIZE 64
1327 char other_iwad_filename[ DESCNAME_SIZE ];
1328 char other_gname[ DESCNAME_SIZE ];
1329 char public_title[] = "Public DOOM";
1330
1331 game_desc_e gamedesc_id; // unique game id
1332 game_desc_t gamedesc; // active desc
1333
1334 // [WDJ] List of standard lump names to be checked, that appear in many
1335 // game wads. The game_desc_table also has a list of names that
1336 // are unique to that game wad.
1337 // This list sets a byte value of which are found.
1338 // Each table entry will have required and reject bit masks.
1339
1340 #define COMMON_LUMP_LIST_SIZE 4
1341 enum lumpname_e {
1342 LN_MAP01 =0x01, LN_E1M1 =0x02, LN_E2M2 =0x04, LN_TITLE =0x08
1343 };
1344 const char * common_lump_names[ COMMON_LUMP_LIST_SIZE ] =
1345 {
1346 "MAP01", "E1M1", "E2M2", "TITLE"
1347 };
1348
1349 // [WDJ] The gname (first) is used to recognize save games, so don't change it.
1350 // Some of the lump check information was obtained from ZDoom docs.
1351 // The startup_title will be centered on the Title page.
1352 // Switch names (idstr) need to be kept to 8 chars, all lowercase, so they
1353 // can be used in file names on all systems.
1354 // This table is the game search order.
1355 // The first entry matching all characteristics will be used !
1356 #define NUM_GDESC (GDESC_other+1) // number of entries in game_desc_table
1357 game_desc_t game_desc_table[ NUM_GDESC ] =
1358 {
1359 // Free wads should get their own gamemode identity
1360 // GDESC_freedoom: FreeDoom project, DoomII replacement
1361 // freedoom : prboom-plus, edge
1362 // freedoom2 : edge, chocolate
1363 { "FreeDoom", NULL, "freedoom",
1364 {"freedoom2.wad", "freedoom.wad","fdoom2.wad"}, NULL,
1365 {"FREEDOOM", NULL}, LN_MAP01, 0,
1366 0, GDESC_freedoom, doom2_commercial },
1367 // doom2f: french version Doom2, eternity.
1368 // prboom-plus
1369
1370 // GDESC_freedm: FreeDM project, DoomII deathmatch
1371 // freedm : edge, chocolate
1372 { "FreeDM", NULL, "freedm",
1373 {"freedm.wad","fdoomdm.wad",NULL}, NULL,
1374 {"FREEDOOM", "FREEDM"}, LN_MAP01, 0,
1375 0, GDESC_freedm, doom2_commercial },
1376 // GDESC_doom2: doom2wad
1377 { "Doom2", "DOOM 2: Hell on Earth", "doom2",
1378 {"doom2.wad",NULL,NULL}, NULL,
1379 {NULL, NULL}, LN_MAP01, LN_TITLE,
1380 GD_idwad, GDESC_doom2, doom2_commercial },
1381 // GDESC_freedoom_ultimate: FreeDoom project, Ultimate Doom replacement
1382 // freedoom1 : edge, chocolate
1383 { "Ultimate FreeDoom", NULL, "freedu",
1384 {"freedoom1.wad", "freedu.wad","fdoomu.wad"}, NULL,
1385 {"FREEDOOM", "E4M1"}, LN_E1M1+LN_E2M2, 0,
1386 0, GDESC_freedoom_ultimate, ultdoom_retail },
1387 // GDESC_ultimate: Doom1 1995, doomuwad
1388 // Doom1 1995 on floppy (doom_se.wad)
1389 { "Ultimate Doom", "The Ultimate DOOM", "doomu",
1390 {"doomu.wad","doom_se.wad","doom.wad"}, NULL,
1391 {"E4M1", NULL}, LN_E1M1+LN_E2M2, LN_TITLE,
1392 GD_idwad, GDESC_ultimate, ultdoom_retail },
1393 // GDESC_doom: DoomI 1994, doomwad
1394 { "Doom", "DOOM Registered", "doom",
1395 {"doom.wad",NULL,NULL}, NULL,
1396 {"E3M9", NULL}, LN_E1M1+LN_E2M2, LN_TITLE,
1397 GD_idwad, GDESC_doom, doom_registered },
1398 // GDESC_doom_shareware: DoomI shareware, doom1wad
1399 // doom1 : edge, chocolate,
1400 { "Doom shareware", "DOOM Shareware", "doom1",
1401 {"doom1.wad","doom.wad",NULL}, NULL,
1402 {NULL, NULL}, LN_E1M1, LN_TITLE,
1403 GD_idwad, GDESC_doom_shareware, doom_shareware },
1404 // GDESC_plutonia: FinalDoom : Plutonia, DoomII engine
1405 { "Plutonia", "DOOM 2: Plutonia Experiment", "plutonia",
1406 {"plutonia.wad",NULL,NULL}, NULL,
1407 {"CAMO1", NULL}, LN_MAP01, LN_TITLE,
1408 GD_idwad, GDESC_plutonia, doom2_commercial },
1409 // GDESC_tnt: FinalDoom : Tnt Evilution, DoomII engine
1410 { "Tnt Evilution", "DOOM 2: TNT - Evilution", "tnt",
1411 {"tnt.wad",NULL,NULL}, NULL,
1412 {"REDTNT2", NULL}, LN_MAP01, LN_TITLE,
1413 GD_idwad, GDESC_tnt, doom2_commercial },
1414 // GDESC_blasphemer: FreeDoom project, DoomII replacement
1415 { "Blasphemer", NULL, "blasphem",
1416 {"BLASPHEM.WAD","blasphem.wad","heretic.wad"}, NULL,
1417 {"BLASPHEM", NULL}, LN_E1M1+LN_TITLE, 0,
1418 0, GDESC_blasphemer, heretic },
1419 // GDESC_heretic: Heretic
1420 { "Heretic", NULL, "heretic",
1421 {"heretic.wad",NULL,NULL}, NULL,
1422 {NULL, NULL}, LN_E1M1+LN_E2M2+LN_TITLE, 0,
1423 GD_idwad, GDESC_heretic, heretic },
1424 // GDESC_heretic_shareware: Heretic shareware
1425 // heretic1 : chocolate
1426 { "Heretic shareware", NULL, "heretic1",
1427 {"heretic1.wad","heretic.wad",NULL}, NULL,
1428 {NULL, NULL}, LN_E1M1+LN_TITLE, LN_E2M2,
1429 GD_idwad, GDESC_heretic_shareware, heretic },
1430 // GDESC_hexen: Hexen
1431 { "Hexen", NULL, "hexen",
1432 {"hexen.wad",NULL,NULL}, NULL,
1433 {"MAP40", NULL}, LN_MAP01+LN_TITLE, 0,
1434 GD_idwad|GD_unsupported, GDESC_hexen, hexen },
1435 // GDESC_hexen_demo: Hexen
1436 { "Hexen Demo", NULL, "hexen1",
1437 {"hexen1.wad","hexen.wad",NULL}, NULL,
1438 {NULL, NULL}, LN_MAP01+LN_TITLE, 0,
1439 GD_idwad|GD_unsupported, GDESC_hexen_demo, hexen },
1440 // GDESC_strife: Strife
1441 { "Strife", NULL, "strife",
1442 {"strife.wad",NULL,NULL}, NULL,
1443 {"ENDSTRF", "MAP20"}, LN_MAP01, 0,
1444 GD_idwad|GD_unsupported, GDESC_strife, strife },
1445 // GDESC_strife_shareware: Strife shareware
1446 { "Strife shareware", NULL, "strife0",
1447 {"strife0.wad","strife.wad",NULL}, NULL,
1448 {"ENDSTRF", NULL}, 0, LN_MAP01,
1449 GD_idwad|GD_unsupported, GDESC_strife_shareware, strife },
1450 // GDESC_chex1: Chex Quest
1451 { "Chex Quest", NULL, "chex1",
1452 {"chex1.wad","chex.wad",NULL}, NULL,
1453 {"W94_1", "POSSH0M0"}, LN_E1M1, LN_TITLE,
1454 GD_iwad_pref, GDESC_chex1, chexquest1 },
1455 // GDESC_ultimate_mode: Ultimate Doom replacement
1456 { "Ultimate mode", NULL, "ultimode",
1457 {"doomu.wad","doom.wad",NULL}, NULL,
1458 { NULL, NULL}, LN_E1M1, 0,
1459 0, GDESC_ultimate, ultdoom_retail },
1460 // GDESC_doom_mode: DoomI replacement
1461 { "Doom mode", NULL, "doommode",
1462 {"doom1.wad","doom.wad",NULL}, NULL,
1463 { NULL, NULL}, LN_E1M1, 0,
1464 0, GDESC_doom_mode, doom_registered },
1465 // GDESC_heretic_mode: Heretic replacement
1466 { "Heretic mode", NULL, "heremode",
1467 {"heretic.wad",NULL,NULL}, NULL,
1468 { NULL, NULL}, LN_E1M1, 0,
1469 0, GDESC_heretic_mode, heretic },
1470 // GDESC_hexen_mode: Hexen replacement
1471 { "Hexen mode", NULL, "hexemode",
1472 {"hexen.wad",NULL,NULL}, NULL,
1473 { NULL, NULL}, LN_MAP01, 0,
1474 GD_unsupported, GDESC_hexen_mode, hexen },
1475 // GDESC_other: Other iwads, all DoomII features enabled,
1476 // strings are ptrs to buffers
1477 { other_gname, public_title, "",
1478 {other_iwad_filename,NULL,NULL}, NULL,
1479 { NULL, NULL}, LN_MAP01, 0,
1480 GD_iwad_pref, GDESC_other, doom2_commercial }
1481 };
1482
1483 #ifdef LAUNCHER
1484 // Lookup game by table index
D_GameDesc(int i)1485 game_desc_t * D_GameDesc( int i )
1486 {
1487 if ( i<0 || i > NUM_GDESC-1 ) return NULL;
1488 return &game_desc_table[i];
1489 }
1490 #endif
1491
1492
1493 // Check all lump names in lumpnames list, count is limited to 8
1494 // Return byte has a bit set for each lumpname found.
1495 static
Check_lumps(const char * wadname,const char * lumpnames[],int count)1496 byte Check_lumps( const char * wadname, const char * lumpnames[], int count )
1497 {
1498 #ifdef ZIPWAD
1499 byte zhand;
1500 #else
1501 FILE * wadfile;
1502 #endif
1503 const char * reason;
1504 wadinfo_t header;
1505 filelump_t lumpx;
1506 int hli, lc, bc;
1507 byte result = 0;
1508
1509 // This routine checks the directory, using the system file cache
1510 // instead of making an internal lumps directory.
1511 // Speed is not required here, so no extra speedup checks.
1512
1513 // List may be fixed length, with NULL entries.
1514 while( count>0 && (lumpnames[count-1] == NULL))
1515 {
1516 count--; // Reduce count by the number of NULL entries on end.
1517 // It is easier to consider a NULL as always found.
1518 result |= 1<<count;
1519 }
1520 if( count == 0 ) goto ret_result; // escape NULL list
1521
1522 // Read the wad file header and get directory
1523 #ifdef ZIPWAD
1524 // This handles normal files, and zip archive files.
1525 zhand = WZ_open( wadname );
1526 if( zhand == 0 )
1527 goto open_err;
1528
1529 bc = WZ_read( zhand, sizeof(header), /*OUT*/ (byte*)&header );
1530 if( bc < sizeof(header) )
1531 goto read_err;
1532 #else
1533 wadfile = fopen( wadname, "rb" );
1534 if( wadfile == NULL )
1535 goto open_err;
1536
1537 fread( &header, sizeof(header), 1, wadfile);
1538 #endif
1539
1540 // check for IWAD or PWAD
1541 if( strncmp(header.identification+1,"WAD",3) != 0 )
1542 goto not_a_wad;
1543
1544 // find directory
1545 header.numlumps = LE_SWAP32(header.numlumps);
1546 header.infotableofs = LE_SWAP32(header.infotableofs);
1547
1548 #ifdef ZIPWAD
1549 bc = WZ_seek( zhand, header.infotableofs );
1550 #else
1551 bc = fseek( wadfile, header.infotableofs, SEEK_SET );
1552 #endif
1553 if( bc < 0 )
1554 goto read_err;
1555
1556 // Check the directory as it is read out of the system file cache.
1557 for( hli=0; hli<header.numlumps; hli++ )
1558 {
1559 #ifdef ZIPWAD
1560 bc = WZ_read( zhand, sizeof(lumpx), /*OUT*/ (byte*)&lumpx );
1561 if( bc < sizeof(lumpx) )
1562 goto read_err;
1563 #else
1564 bc = fread( &lumpx, sizeof(lumpx), 1, wadfile );
1565 if( bc < 1 )
1566 goto read_err;
1567 #endif
1568
1569 #ifdef DETECT_TITLES
1570 if( strncasecmp( lumpx.name, "TITLE", 5 ) == 0 )
1571 {
1572 printf( "Lump=%8s : ", lumpx.name );
1573 for( lc=0; lc<count; lc++ )
1574 {
1575 int cmp = strncasecmp( lumpx.name, lumpname[lc], 8 );
1576 printf( " %c %8s", ( (cmp<0)?'<': (cmp>0)? '>' :'='), lumpname);
1577 }
1578 printf( "\n" );
1579 }
1580 #endif
1581 for( lc=0; lc<count; lc++ )
1582 {
1583 if( strncasecmp( lumpx.name, lumpnames[lc], 8 ) == 0 )
1584 result |= 1<<lc; // found it, record it
1585 }
1586 }
1587 #ifdef ZIPWAD
1588 WZ_close( zhand );
1589 #else
1590 fclose( wadfile );
1591 #endif
1592
1593 ret_result:
1594 return result; // default is not found
1595
1596 // Should only be called with known WAD files
1597 not_a_wad:
1598 reason = "Not a WAD file";
1599 goto err_ret0;
1600
1601 read_err: // read and seek errors
1602 reason = "Wad file err";
1603 goto err_ret0;
1604
1605 open_err:
1606 reason = "Wad file open err";
1607
1608 err_ret0:
1609 GenPrintf( EMSG_error, "File %s: %s\n", wadname, reason );
1610 #ifdef ZIPWAD
1611 if( zhand ) WZ_close( zhand );
1612 #else
1613 if( wadfile ) fclose( wadfile );
1614 #endif
1615 return 0;
1616 }
1617
1618
1619 static
Check_keylumps(game_desc_t * gmtp,const char * wadname)1620 boolean Check_keylumps ( game_desc_t * gmtp, const char * wadname )
1621 {
1622 byte lumpbits;
1623 if( gmtp->require_lump | gmtp->reject_lump )
1624 {
1625 lumpbits = Check_lumps( wadname,
1626 common_lump_names, COMMON_LUMP_LIST_SIZE );
1627 if((gmtp->require_lump & lumpbits) != gmtp->require_lump ) goto fail;
1628 if( gmtp->reject_lump & lumpbits ) goto fail;
1629 }
1630 // Check 2 unique lump names, NULLS are treated as found.
1631 lumpbits = Check_lumps( wadname, &(gmtp->keylump[0]), 2 );
1632 if( lumpbits != 0x03 ) goto fail;
1633 return 1; // lump checks successful
1634 fail:
1635 return 0; // does not match
1636 }
1637
1638
1639 // Checks the possible wad filenames in GDESC_ entry.
1640 // Return true when found and keylumps verified
1641 // Leaves name in pathbuf_p, which must be of MAX_PATH length.
1642 static
Check_wad_filenames(int gmi,char * pathbuf_p)1643 boolean Check_wad_filenames( int gmi, /*OUT*/ char * pathbuf_p )
1644 {
1645 game_desc_t * gmtp = &game_desc_table[gmi];
1646 filestatus_e fse;
1647 int w;
1648 // check each possible filename listed
1649 for( w=0; w<3; w++ )
1650 {
1651 if( gmtp->iwad_filename[w] == NULL )
1652 break;
1653
1654 fse = Search_doomwaddir( gmtp->iwad_filename[w], GAME_SEARCH_DEPTH,
1655 /*OUT*/ pathbuf_p );
1656
1657 #ifdef ZIPWAD
1658 if( fse == FS_ZIP )
1659 {
1660 // Check file in archive
1661 WZ_open_archive( pathbuf_p );
1662 byte fnd = Check_keylumps( gmtp, gmtp->iwad_filename[w] );
1663 WZ_close_archive();
1664 if( fnd )
1665 return true;
1666 }
1667 else
1668 #endif
1669 if( fse == FS_FOUND )
1670 {
1671 // File exists.
1672 if( Check_keylumps( gmtp, pathbuf_p ) )
1673 return true;
1674 }
1675 }
1676 return false;
1677 }
1678
1679
1680 // May be called again after command restart
1681 static
IdentifyVersion()1682 void IdentifyVersion()
1683 {
1684 char pathiwad[_MAX_PATH + 16];
1685 // debug_Printf("MAX_PATH: %i\n", _MAX_PATH);
1686
1687 boolean other_names = 0; // indicates -iwad other names
1688 #ifdef DEVPARM_LOADING
1689 boolean devgame = false; // indicates -devgame <game>
1690 #endif
1691
1692 int gamedesc_index = NUM_GDESC; // nothing
1693 int gmi;
1694
1695 // find legacy.wad, IWADs
1696 // and... Doom LEGACY !!! :)
1697 char *legacywad = NULL;
1698
1699 if( verbose )
1700 {
1701 Print_search_directories( EMSG_ver, 0x0F );
1702 }
1703
1704
1705 #if defined(__APPLE__) && defined(__MACH__) && defined( EXT_MAC_DIR_SPEC )
1706 //[segabor]: on Mac OS X legacy.wad is within .app folder
1707 // for uniformity, use the strdup at found_legacy_wad
1708 cat_filename(pathiwad, "", mac_legacy_wad );
1709 if( access( mac_legacy_wad, R_OK) == 0 ) goto found_legacy_wad;
1710 // check other locations
1711 #endif
1712
1713 // [WDJ]: find legacy.wad .
1714 // pathiwad must be MAX_WADPATH to be used by cat_filename.
1715 // Look in program directory first, because executable may have
1716 // its own version of legacy.wad.
1717 if( progdir && ( access( progdir, R_OK) == 0 ) )
1718 {
1719 // [WDJ] look for legacy.wad with doomlegacy
1720 cat_filename(pathiwad, progdir, "legacy.wad");
1721 if( access( pathiwad, R_OK) == 0 ) goto found_legacy_wad;
1722 }
1723
1724 #ifdef LEGACYWADDIR
1725 // [WDJ] Try LEGACYWADDIR as the first wad dir.
1726 if( access( LEGACYWADDIR , R_OK) == 0 )
1727 {
1728 // [WDJ] legacy.wad is in shared directory
1729 cat_filename(pathiwad, LEGACYWADDIR, "legacy.wad");
1730 if( access( pathiwad, R_OK) == 0 ) goto found_legacy_wad;
1731 }
1732 #endif
1733
1734 // Search wad directories.
1735 doomwaddir[1] = progdir_wads;
1736 // Should not be zipped
1737 if( Search_doomwaddir( "legacy.wad", 0, /*OUT*/ pathiwad ) == FS_FOUND )
1738 goto found_legacy_wad;
1739
1740 I_SoftError( "legacy.wad not found\n" ); // fatal exit
1741 GenPrintf(EMSG_error, "Looked for legacy.wad in:\n" );
1742 Print_search_directories( EMSG_error, 0x01 );
1743 goto fatal_err;
1744
1745
1746 found_legacy_wad:
1747 legacywad = strdup( pathiwad ); // malloc
1748 doomwaddir[1] = NULL;
1749
1750 if( verbose )
1751 {
1752 GenPrintf(EMSG_ver, "Legacy.wad: %s\n", legacywad );
1753 }
1754
1755 owner_wad_search_order();
1756
1757 /*
1758 French stuff.
1759 doom2fwad = malloc(strlen(doomwaddir)+1+10+1);
1760 sprintf(doom2fwad, "%s/doom2f.wad", doomwaddir);
1761 */
1762
1763 // [WDJ] were too many chained ELSE. Figured it out once and used direct goto.
1764
1765 #ifdef DEVPARM_LOADING
1766 // [WDJ] Old switches -shdev, -regdev, -comdev are now -devgame <game>
1767 // Earlier did direct test of -devparm, do not overwrite it.
1768 devgame = M_CheckParm("-devgame");
1769 // [WDJ] search for one of the listed GDESC_ forcing switches
1770 if ( devgame || M_CheckParm("-game") )
1771 #else
1772 if( M_CheckParm("-game") )
1773 #endif
1774 {
1775 char *temp = M_GetNextParm();
1776 if( temp == NULL )
1777 {
1778 #ifdef DEVPARM_LOADING
1779 I_SoftError( "Switch -game <name> or -devgame <name>\n" );
1780 #else
1781 I_SoftError( "Switch -game <name>\n" );
1782 #endif
1783 goto fatal_err;
1784 }
1785
1786 for( gmi=0; gmi<GDESC_other; gmi++ )
1787 {
1788 // compare to recognized game mode names
1789 if (!strcmp(temp, game_desc_table[gmi].idstr))
1790 goto game_switch_found;
1791 }
1792 I_SoftError( "Switch -game %s not recognized\n", temp );
1793 goto fatal_err;
1794
1795 game_switch_found:
1796 // switch forces the GDESC_ selection
1797 gamedesc_index = gmi;
1798 gamedesc = game_desc_table[gamedesc_index]; // copy the game descriptor
1799 if (gamedesc.gameflags & GD_unsupported) goto unsupported_wad;
1800
1801 #ifdef DEVPARM_LOADING
1802 // handle the recognized special -devgame switch
1803 if( devgame )
1804 {
1805 devparm = 1 + verbose;
1806 #if 0
1807 M_Set_configfile_main( DEVDATA CONFIGFILENAME );
1808 // [WDJ] Old, irrelevant, and it was interfering with new
1809 // GDESC changes.
1810 // Better to just use -file so I am disabling it.
1811 switch( gamedesc_index )
1812 {
1813 case GDESC_doom_shareware:
1814 // instead use:
1815 // doomlegacy -devgame doom1 -file data_se/texture1.lmp data_se/pnames.lmp
1816 D_AddFile(DEVDATA "doom1.wad");
1817 D_AddFile(DEVMAPS "data_se/texture1.lmp");
1818 D_AddFile(DEVMAPS "data_se/pnames.lmp");
1819 goto got_iwad;
1820 case GDESC_doom:
1821 // instead use:
1822 // doomlegacy -devgame doom1 -file data_se/texture1.lmp data_se/texture2.lmp data_se/pnames.lmp
1823 D_AddFile(DEVDATA "doom.wad");
1824 D_AddFile(DEVMAPS "data_se/texture1.lmp");
1825 D_AddFile(DEVMAPS "data_se/texture2.lmp");
1826 D_AddFile(DEVMAPS "data_se/pnames.lmp");
1827 goto got_iwad;
1828 case GDESC_doom2:
1829 // instead use:
1830 // doomlegacy -devgame doom2 -file cdata/texture1.lmp cdata/pnames.lmp
1831 D_AddFile(DEVDATA "doom2.wad");
1832 D_AddFile(DEVMAPS "cdata/texture1.lmp");
1833 D_AddFile(DEVMAPS "cdata/pnames.lmp");
1834 goto got_iwad;
1835 }
1836 #endif
1837 }
1838 #endif
1839 }
1840
1841
1842 // Specify the name of the IWAD file to use, so we can have several IWAD's
1843 // in the same directory, and/or have legacy.exe only once in a different location
1844 if (M_CheckParm("-iwad"))
1845 {
1846 filestatus_e fse = FS_NOTFOUND;
1847
1848 // BP: big hack for fullpath wad, we should use wadpath instead in d_addfile
1849 char *s = M_GetNextParm();
1850 if ( s == NULL )
1851 {
1852 I_SoftError("Switch -iwad <filename>.\n");
1853 goto fatal_err;
1854 }
1855
1856 const char * ipath = file_searchpath( s );
1857 if( ipath )
1858 {
1859 // Absolute or relative path, no search.
1860 cat_filename( pathiwad, ipath, s );
1861 }
1862 else
1863 {
1864 // Simple filename.
1865 // Find the IWAD in the doomwaddir.
1866 fse = Search_doomwaddir( s, IWAD_SEARCH_DEPTH, /*OUT*/ pathiwad );
1867 #ifdef ZIPWAD
1868 if( fse == FS_ZIP )
1869 {
1870 // Found zip archive in doomwaddir.
1871 // cat_filename( pathiwad, "", s );
1872 }
1873 else
1874 #endif
1875 if( fse != FS_FOUND )
1876 {
1877 // Not found in doomwaddir.
1878 cat_filename( pathiwad, "", s );
1879 }
1880 }
1881
1882 #ifdef LAUNCHER
1883 CV_Set( & cv_iwad, pathiwad ); // for launcher
1884 cv_iwad.state &= ~CS_MODIFIED;
1885 #endif
1886
1887 if ( access(pathiwad, R_OK) < 0 )
1888 {
1889 I_SoftError("IWAD %s not found\n", s);
1890 Print_search_directories( EMSG_error, 0x02 );
1891 goto fatal_err;
1892 }
1893
1894 char *filename = FIL_Filename_of( pathiwad );
1895 #ifdef ZIPWAD
1896 char filename_wad[MAX_WADPATH];
1897 if( fse == FS_ZIP )
1898 {
1899 // Need archive name for lookup.
1900 WZ_save_archive_name( filename );
1901 // Need wad name for GDESC lookup.
1902 if( WZ_make_name_with_extension( filename, "wad", /*OUT*/ filename_wad ) )
1903 filename = filename_wad; // use wad name instead of archive name
1904 }
1905 #endif
1906
1907 if ( gamedesc_index == NUM_GDESC ) // check forcing switch
1908 {
1909 // No forcing switch
1910 // [WDJ] search game table for matching iwad name
1911 #ifdef ZIPWAD
1912 if( fse == FS_ZIP )
1913 {
1914 // Check file in archive
1915 WZ_open_archive( pathiwad );
1916 }
1917 #endif
1918 for( gmi=0; gmi<GDESC_other; gmi++ )
1919 {
1920 game_desc_t * gmtp = &game_desc_table[gmi];
1921 int w;
1922 // check each possible filename listed
1923 for( w=0; w<3; w++ )
1924 {
1925 if( gmtp->iwad_filename[w] == NULL )
1926 break; // end of list
1927
1928 if( strcasecmp(gmtp->iwad_filename[w], filename) == 0 )
1929 {
1930 #ifdef ZIPWAD
1931 if( fse == FS_ZIP )
1932 {
1933 // Check file in archive
1934 byte fnd = Check_keylumps( gmtp, filename );
1935 if( fnd )
1936 goto got_gmi_iwad;
1937 }
1938 else
1939 #endif
1940 if( Check_keylumps( gmtp, pathiwad ) )
1941 goto got_gmi_iwad;
1942 }
1943 }
1944 }
1945 // unknown IWAD is GDESC_other
1946 gamedesc_index = GDESC_other;
1947 #ifdef ZIPWAD
1948 if( archive_open )
1949 {
1950 WZ_close_archive();
1951 }
1952 #endif
1953 }
1954
1955 other_names = 1; // preserve other names when forcing switch
1956 // for save game header
1957 strncpy( other_iwad_filename, filename, DESCNAME_SIZE );
1958 other_iwad_filename[ DESCNAME_SIZE-1 ] = 0; // safe
1959 // create game name from the wad name, used in save game
1960 strncpy( other_gname, other_iwad_filename, DESCNAME_SIZE );
1961 other_gname[ DESCNAME_SIZE-1 ] = 0; // safe
1962 // use the wad name, without the ".wad" as the gname
1963 {
1964 char * dp = strchr( other_gname, '.' );
1965 if( dp ) *dp = 0;
1966 }
1967 goto got_iwad;
1968 }
1969 // No -iwad switch:
1970 // [WDJ] Select IWAD by game switch
1971 if(gamedesc_index < GDESC_other) // selected by switch, and no -iwad
1972 {
1973 // make iwad name by switch
1974 // use pathiwad to output wad path from Check_wad_filenames
1975 if( Check_wad_filenames( gamedesc_index, pathiwad ) )
1976 goto got_iwad;
1977
1978 I_SoftError("IWAD %s not found in:\n",
1979 game_desc_table[gamedesc_index].iwad_filename[0]);
1980 Print_search_directories( EMSG_error, 0x02 );
1981 goto fatal_err;
1982 }
1983 // No -iwad switch, and no mode select switch:
1984 // [WDJ] search the table for the first iwad filename found
1985 for( gmi=0; gmi<GDESC_other; gmi++ )
1986 {
1987 // use pathiwad to output wad path from Check_wad_filenames
1988 if( Check_wad_filenames( gmi, pathiwad ) )
1989 goto got_gmi_iwad;
1990 }
1991
1992 I_SoftError("Main WAD file not found\n"
1993 "You need doom.wad, doom2.wad, heretic.wad or some other IWAD file\n"
1994 "from any shareware, commercial or free version of Doom or Heretic!\n"
1995 #if !defined(__WIN32__) && !(defined __DJGPP__)
1996 "If you have one of those files, be sure its name is lowercase\n"
1997 "or use the -iwad command line switch.\n"
1998 #endif
1999 );
2000 goto fatal_err;
2001
2002 got_gmi_iwad:
2003 gamedesc_index = gmi; // a search loop found it
2004 got_iwad:
2005 gamedesc = game_desc_table[gamedesc_index]; // copy the game descriptor
2006
2007 if( other_names ) // keep names from -iwad
2008 {
2009 gamedesc.gname = other_gname;
2010 gamedesc.iwad_filename[0] = other_iwad_filename;
2011 }
2012 gamedesc_id = gamedesc.gamedesc_id;
2013 G_set_gamemode( gamedesc.gamemode );
2014 GenPrintf( EMSG_info, "IWAD recognized: %s\n", gamedesc.gname);
2015
2016 if (gamedesc.gameflags & GD_unsupported) goto unsupported_wad;
2017
2018 D_AddFile(pathiwad);
2019 D_AddFile(legacywad); // So can replace some graphics with Legacy ones.
2020 if( gamedesc.gameflags & GD_iwad_pref )
2021 {
2022 // Because legacy.wad replaced some things it shouldn't, give the iwad
2023 // preference from both search directions.
2024 // Chexquest1: legacy.wad was replacing the green splats, with bloody ones.
2025 D_AddFile(pathiwad);
2026 }
2027 if( gamedesc.support_wad )
2028 D_AddFile( gamedesc.support_wad );
2029
2030 cleanup_ret:
2031 #ifdef ZIPWAD
2032 if( archive_open )
2033 {
2034 WZ_close_archive();
2035 }
2036 #endif
2037 free(legacywad); // from strdup, free local copy of name
2038 return;
2039
2040 unsupported_wad:
2041 I_SoftError("Doom Legacy currently does not support this game.\n");
2042 goto fatal_err;
2043
2044 fatal_err:
2045 if( legacywad )
2046 {
2047 // [WDJ] Load legacywad if possible, because it contains parts of the
2048 // user interface, and there will misleading errors.
2049 D_AddFile(legacywad); // To prevent additional errors.
2050 }
2051 fatal_error = 1;
2052 goto cleanup_ret;
2053 }
2054
2055 /* ======================================================================== */
2056 // Just print the nice red titlebar like the original DOOM2 for DOS.
2057 /* ======================================================================== */
2058 #ifdef SMIF_PC_DOS
D_Titlebar(const char * title1,const char * title2)2059 void D_Titlebar(const char *title1, const char *title2)
2060 {
2061 // DOOM LEGACY banner
2062 clrscr();
2063 textattr((BLUE << 4) + WHITE);
2064 clreol();
2065 cputs(title1);
2066
2067 // standard doom/doom2 banner
2068 textattr((RED << 4) + WHITE);
2069 clreol();
2070 gotoxy((80 - strlen(title2)) / 2, 2);
2071 cputs(title2);
2072 normvideo();
2073 gotoxy(1, 3);
2074 }
2075 #endif
2076
2077 #define MAX_TITLE_LEN 80
2078 static char legacytitle[MAX_TITLE_LEN+1]; // length of line
2079
2080 //added:11-01-98:
2081 //
2082 // Center the title string, then add the date and time of compilation.
2083 //
D_Make_legacytitle(void)2084 static void D_Make_legacytitle(void)
2085 {
2086 const char *s = VERSION_BANNER;
2087 int i;
2088
2089 memset(legacytitle, ' ', sizeof(legacytitle));
2090
2091 for (i = (MAX_TITLE_LEN - strlen(s)) / 2; *s; ) // center
2092 legacytitle[i++] = *s++;
2093
2094 const char *u = __DATE__;
2095 for (i = 0; i < 11; i++)
2096 legacytitle[i + 1] = u[i];
2097
2098 u = __TIME__;
2099 for (i = 0; i < 8; i++)
2100 legacytitle[i + 71] = u[i];
2101
2102 legacytitle[MAX_TITLE_LEN] = '\0';
2103 }
2104
2105
2106 // Check Legacy.wad
D_CheckWadVersion()2107 void D_CheckWadVersion()
2108 {
2109 int wadversion = 0;
2110 char hs[128];
2111 int wv2, hlen;
2112 lumpnum_t ver_lumpnum;
2113 /* BP: disabled since this should work fine now...
2114 // check main iwad using demo1 version
2115 ver_lumpnum = W_CheckNumForNameFirst("demo1");
2116 // well no demo1, this is not a main wad file
2117 if( ! VALID_LUMP(ver_lumpnum) )
2118 I_Error("%s is not a Main wad file (IWAD)\n"
2119 "try with Doom.wad or Doom2.wad\n"
2120 "\n"
2121 "Use -nocheckwadversion to remove this check,\n"
2122 "but this can cause Legacy to hang\n",wadfiles[0]->filename);
2123 W_ReadLumpHeader (lump,&wadversion,1);
2124 if( wadversion<109 )
2125 I_Error("Your %s file is version %d.%d\n"
2126 "Doom Legacy need version 1.9\n"
2127 "Upgrade your version to 1.9 using IdSofware patch\n"
2128 "\n"
2129 "Use -nocheckwadversion to remove this check,\n"
2130 "but this can cause Legacy to hang\n",wadfiles[0]->filename,wadversion/100,wadversion%100);
2131 */
2132 // check version, of legacy.wad using version lump
2133 ver_lumpnum = W_CheckNumForName("version");
2134 if( ! VALID_LUMP(ver_lumpnum) )
2135 {
2136 I_SoftError("No legacy.wad file.\n");
2137 fatal_error = 1;
2138 return;
2139 }
2140 hlen = W_ReadLumpHeader(ver_lumpnum, &hs, 128);
2141 if (hlen < 128)
2142 {
2143 hs[hlen] = '\0';
2144 if (sscanf(hs, "Doom Legacy WAD V%d.%d", &wv2, &wadversion) == 2)
2145 wadversion += wv2 * 100;
2146 }
2147 if (wadversion != cur_wadversion)
2148 {
2149 I_SoftError("Your legacy.wad file is version %d.%d, you need version %d.%d\n"
2150 "Use the legacy.wad that came in the same archive as this executable.\n"
2151 "\n"
2152 "Use -nocheckwadversion to remove this check,\n"
2153 "but this can cause Legacy to crash.\n",
2154 (wadversion / 100), (wadversion % 100),
2155 (int)(cur_wadversion / 100), (int)(cur_wadversion % 100) );
2156 if( wadversion < min_wadversion )
2157 fatal_error = 1;
2158 }
2159 }
2160
2161 //
2162 // D_DoomMain
2163 //
2164 // Called from port main program to processes setup.
2165 // Returns before game starts.
D_DoomMain()2166 void D_DoomMain()
2167 {
2168 int p, wdi;
2169 #ifdef DEVPARM_LOADING
2170 char fbuf[FILENAME_SIZE];
2171 #endif
2172 char dirbuf[_MAX_PATH ];
2173 char cfgbuf[_MAX_PATH ];
2174
2175 int startepisode;
2176 int startmap;
2177 boolean autostart;
2178
2179 #ifdef FRENCH_INLINE
2180 french_early_text();
2181 #endif
2182
2183 // print version banner just once here, use it anywhere
2184 sprintf(VERSION_BANNER, "Doom Legacy %d.%d.%d %s", VERSION/100, VERSION%100, REVISION, VERSIONSTRING);
2185 demoversion = VERSION;
2186
2187 D_Make_legacytitle();
2188
2189 memset( startupwadfiles, 0, sizeof(startupwadfiles) );
2190
2191 CON_Init_Setup(); // vid, zone independent
2192 EOUT_flags |= EOUT_con; // all msgs to CON buffer
2193 use_font1 = 1; // until PLAYPAL and fonts loaded
2194 vid.draw_ready = 0; // disable print reaching console
2195
2196 //added:18-02-98:keep error messages until the final flush(stderr)
2197 if (setvbuf(stderr, NULL, _IOFBF, 1000))
2198 GenPrintf(EMSG_warn,"setvbuf didnt work\n");
2199 setbuf(stdout, NULL); // non-buffered output
2200
2201 // get parameters from a response file (eg: doom3 @parms.txt)
2202 M_FindResponseFile();
2203
2204 // some basic commandline options
2205 if (M_CheckParm("--version"))
2206 {
2207 printf("%s\n", legacytitle);
2208 exit(0);
2209 }
2210
2211 if (M_CheckParm("-v"))
2212 {
2213 verbose = 1;
2214 }
2215 if (M_CheckParm("-v2"))
2216 {
2217 verbose = 2;
2218 }
2219
2220 if (M_CheckParm("--help") || M_CheckParm("-h"))
2221 {
2222 printf("%s\n", legacytitle);
2223 Help();
2224 exit(0);
2225 }
2226
2227 GenPrintf( EMSG_info|EMSG_all, "%s\n", legacytitle);
2228
2229 // Find or make a default dir that is not root dir
2230 // get the current directory (possible problem on NT with "." as current dir)
2231 if (getcwd(dirbuf, _MAX_PATH) != NULL)
2232 {
2233 // Need a working default dir, to prevent "" leading to root files.
2234 if( (strlen(dirbuf) > 4)
2235 || (strcmp( dirbuf, "." ) == 0) ) // systems that pass "."
2236 {
2237 defdir = strdup( dirbuf );
2238 if( verbose )
2239 GenPrintf(EMSG_ver, "Current directory: %s\n", defdir);
2240
2241 if( access( defdir, X_OK ) == 0 )
2242 defdir_stat = 1;
2243 }
2244 }
2245
2246 // [WDJ] When I_Get_Prog_Dir fails, progdir will be NULL.
2247 // Protect all uses of progdir and progdir_wads accordingly.
2248 if( I_Get_Prog_Dir( defdir, /*OUT*/ dirbuf ) )
2249 {
2250 // At worst, dirbuf may be an empty string. OS dependent.
2251 progdir = strdup( dirbuf );
2252 if( verbose )
2253 GenPrintf(EMSG_ver, "Program directory: %s\n", progdir);
2254
2255 // Set the directories that are relative to the program directory.
2256 if( access( progdir, X_OK ) == 0 )
2257 {
2258 cat_filename(dirbuf, progdir, "wads");
2259 progdir_wads = strdup(dirbuf);
2260 }
2261 }
2262
2263 memset( doomwaddir, 0, sizeof(doomwaddir) );
2264 doomwaddir[0] = getenv("DOOMWADDIR"); // ptr to environment string
2265
2266 // CDROM overrides doomwaddir (when valid)
2267 if (M_CheckParm("-cdrom"))
2268 {
2269 GenPrintf(EMSG_hud, D_CDROM);
2270 // [WDJ] Execute DoomLegacy off CDROM ??
2271 // DoomLegacy already has separate doomwaddir and legacyhome.
2272 // Legacy is not compatible with other port config and savegames,
2273 // so do not put such in old doom "c:\\doomdata".
2274 // Substitute CDROM for doomwaddir, but not legacyhome.
2275 if( defdir )
2276 doomwaddir[0] = ""; // wads from cur dir
2277 defdir_stat = 0; // do not let legacyhome use current dir
2278 }
2279
2280 #if 0
2281 //[WDJ] disabled in 143beta_macosx
2282 // was test on MACOS_DI but could exclude or include __MACH__ ??
2283 //[segabor]
2284 #if defined( __APPLE__ ) && ! defined( __MACH__ )
2285 // cwd is always "/" when app is dbl-clicked
2286 if (!strcasecmp(doomwaddir, "/"))
2287 {
2288 // doomwaddir maybe malloc string, maybe not
2289 doomwaddir[0] = I_GetWadDir();
2290 }
2291 #endif
2292 #endif
2293
2294 EOUT_flags = EOUT_text | EOUT_log | EOUT_con;
2295
2296 CONS_Printf(text[Z_INIT_NUM]);
2297 // Cannot Init nor register cv_ vars until after Z_Init and some
2298 // other systems are init first.
2299 // -mb cannot be changed by Launcher, use Response File instead
2300 Z_Init();
2301
2302 // Init once
2303 COM_Init(); // command buffer
2304 // Can now call CV_RegisterVar, and COM_AddCommand
2305
2306 // may have some command line dependent init, like joystick
2307 I_SysInit();
2308
2309 dedicated = M_CheckParm("-dedicated") != 0;
2310
2311 //---------------------------------------------------- START DISPLAY
2312 //--- Display Error Messages
2313 CONS_Printf("StartupGraphics...\n");
2314 // setup loading screen with dedicated=0 and vid=800,600
2315 V_Init_VideoControl(); // before I_StartupGraphics
2316
2317 if( ! dedicated )
2318 {
2319 I_StartupGraphics(); // window
2320 SCR_Startup();
2321 }
2322
2323 #ifdef PARANOID
2324 SCR_Set_dummy_draw();
2325 #endif
2326
2327 if( verbose > 1 )
2328 CONS_Printf("Init DEH, cht, menu\n");
2329
2330 P_clear_state_ext(); // init state_ext
2331 // save Doom, Heretic, Chex strings for DEH
2332 DEH_Init(); // Init DEH before files and lumps loaded
2333 cht_Init(); // init iwad independent cheats info, needed by Responder
2334
2335 M_Init(); // init menu
2336 R_Init_rdata();
2337
2338 if( verbose > 1 )
2339 CONS_Printf( "Register\n" );
2340
2341 // Any cv_ with CV_SAVE need to be registered here, before reading the config.
2342 // Some of these are dependent upon the dedicated command line switch.
2343 CON_Register();
2344 D_Register_ClientCommands(); //Hurdler: be sure that this is called before D_Setup_NetGame
2345 D_Register_MiscCommands(); //[WDJ] more than just DeathMatch
2346
2347 M_Register_Menu_Controls();
2348 HU_Register_Commands();
2349 ST_Register_Commands();
2350
2351 T_Register_Commands(); // fragglescript
2352 B_Register_Commands(); //added by AC for acbot
2353 R_Register_EngineStuff();
2354 S_Register_SoundStuff();
2355
2356 P_Register_Info_Commands();
2357
2358 #ifdef LAUNCHER
2359 CV_RegisterVar(&cv_home);
2360 CV_RegisterVar(&cv_doomwaddir);
2361 CV_RegisterVar(&cv_iwad);
2362 CV_Set( &cv_doomwaddir, doomwaddir[0] ? doomwaddir[0] : "" );
2363 cv_doomwaddir.state &= ~CS_MODIFIED;
2364 #endif
2365
2366 //Fab:29-04-98: do some dirty chatmacros strings initialisation
2367 HU_Init_Chatmacros();
2368
2369 // load default control
2370 G_Controldefault();
2371
2372 #ifdef ZIPWAD
2373 WZ_available(); // check for zip lib
2374 #endif
2375
2376 // Before this line are initializations that are run only one time.
2377 //----------------------------------------------------
2378 // After this line is code that deals with configuration,
2379 // game and wad selection, and finding files and directories.
2380 // It may retry some actions and may execute functions multiple times.
2381
2382 #ifdef LAUNCHER
2383 //---------------------------------------------------- LAUNCHER restarts here
2384 restart_command:
2385
2386 fatal_error = 0;
2387 verbose = 0; // verbose may be changed by launcher
2388 if (M_CheckParm("-v"))
2389 {
2390 verbose = 1;
2391 }
2392 if (M_CheckParm("-v2"))
2393 {
2394 verbose = 2;
2395 }
2396
2397 dedicated = M_CheckParm("-dedicated") != 0;
2398
2399 if( legacyhome )
2400 free( legacyhome ); // from previous
2401 #endif
2402
2403 V_SetupFont( 1, NULL, 0 ); // Startup font size
2404 EOUT_flags = EOUT_text | EOUT_log | EOUT_con;
2405
2406 //---------------------------------------------------- FIND FILES
2407 // -devgame is handled later, by IdentifyVersion
2408 devparm = M_CheckParm("-devparm"); // -devparm
2409 if (devparm)
2410 {
2411 devparm += verbose; // levels of devparm
2412 CONS_Printf(D_DEVSTR);
2413 }
2414
2415 if( verbose > 1 )
2416 CONS_Printf("Find HOME\n");
2417 // userhome section
2418 {
2419 const char * userhome = NULL;
2420 #ifdef LAUNCHER
2421 byte userhome_parm = 0;
2422 #endif
2423 if (M_CheckParm("-home"))
2424 {
2425 userhome = M_GetNextParm();
2426 if( userhome == NULL )
2427 {
2428 I_SoftError( "Switch -home <directory>\n" );
2429 userhome = "";
2430 fatal_error = 1;
2431 }
2432 #ifdef LAUNCHER
2433 userhome_parm = 1;
2434 #endif
2435 }
2436 else
2437 {
2438 userhome = getenv("HOME");
2439 if( userhome && verbose > 1 )
2440 CONS_Printf("HOME = %s\n", userhome);
2441 #ifdef WIN32
2442 if( userhome && strstr( userhome, "MSYS" ) )
2443 {
2444 // Ignore MSYS HOME, it is not the one wanted.
2445 if( verbose > 1 )
2446 CONS_Printf("Ignore MYS HOME = %s\n", userhome);
2447 userhome = NULL;
2448 }
2449 // Windows XP,
2450 if( !userhome )
2451 {
2452 userhome = getenv("UserProfile");
2453 if( userhome && verbose > 1 )
2454 CONS_Printf("UserProfile = %s\n", userhome);
2455 }
2456 #endif
2457 }
2458
2459 if (!userhome)
2460 {
2461 if(verbose)
2462 GenPrintf(EMSG_ver, "Please set $HOME to your home directory, or use -home switch\n");
2463
2464 #if 0
2465 // [WDJ] Using current directory just lead to the user losing
2466 // the config and savegames.
2467
2468 // Try to use current directory and defaults
2469 // Make an absolute default directory, not root.
2470 if( defdir_stat )
2471 {
2472 // have working default dir
2473 // userhome cannot be "", because save games can end up in root directory
2474 cat_filename( dirbuf, defdir, defhome );
2475 userhome = strdup(dirbuf); // malloc
2476 if(verbose)
2477 GenPrintf(EMSG_ver, " Using userhome= %s\n", userhome );
2478 }
2479 else
2480 {
2481 GenPrintf(EMSG_warn, " No home dir, and no defdir.\n" );
2482 }
2483 #endif
2484 }
2485
2486 #ifdef LAUNCHER
2487 if( (! userhome_parm || init_sequence == 0)
2488 && userhome )
2489 {
2490 // Save the input userhome for the Launcher, unless it came from -home.
2491 CV_Set( &cv_home, userhome );
2492 cv_home.state &= ~CS_MODIFIED;
2493 }
2494 #endif
2495
2496 #if defined(__APPLE__) && defined(__MACH__) && defined( EXT_MAC_DIR_SPEC )
2497 //[segabor] ... ([WDJ] MAC port has vars handy)
2498 // sprintf(configfile, "%s/DooMLegacy.cfg", mac_user_home);
2499 cat_filename( cfgbuf, mac_user_home, "DooMLegacy.cfg" );
2500 M_Set_configfile_main( cfgbuf );
2501 sprintf(savegamename, "%s/Saved games/Game %%d.doomSaveGame", mac_user_home);
2502 if ( ! userhome)
2503 userhome = mac_user_home;
2504 // legacyhome = strdup( mac_user_home );
2505 // Needs slash
2506 legacyhome = (char*) malloc( strlen(userhome) + 3 );
2507 // example: "/home/user/"
2508 sprintf(legacyhome, "%s/", userhome);
2509 #else
2510 // Find the legacyhome directory
2511 if (userhome)
2512 {
2513 // [WDJ] find directory, .doomlegacy, or .legacy
2514 char dirpath[ MAX_WADPATH ];
2515
2516 // form directory filename, with slash (for savegamename)
2517 cat_filename( dirpath, userhome, DEFAULTDIR1 SLASH );
2518 // if it exists then use it
2519 if( access(dirpath, R_OK) < 0 ) // not found
2520 {
2521 // not there, try 2nd choice
2522 cat_filename( dirpath, userhome, DEFAULTDIR2 SLASH );
2523 if( access(dirpath, R_OK) < 0 ) // not found
2524 {
2525 // not there either, then make primary default dir
2526 cat_filename( dirpath, userhome, DEFAULTDIR1 SLASH );
2527 }
2528 }
2529 // make subdirectory in userhome
2530 // example: "/home/user/.doomlegacy/"
2531 legacyhome = strdup( dirpath ); // malloc
2532 }
2533 else
2534 {
2535 // Check for an existing DEFHOME in current directory.
2536 // Only if user has made it.
2537 if( access(DEFHOME, R_OK) == 0 ) // legacy home found
2538 {
2539 legacyhome = strdup( DEFHOME ); // malloc, will be free.
2540 }
2541 }
2542
2543 if( ! legacyhome )
2544 {
2545 // Make a default legacy home in the program directory.
2546 // default absolute path, do not set to ""
2547 cat_filename( dirbuf, progdir, DEFHOME );
2548 legacyhome = strdup( dirbuf ); // malloc, will be free.
2549 if( verbose )
2550 GenPrintf(EMSG_ver, "Default legacyhome= %s\n", legacyhome );
2551 }
2552
2553 // Make the legacyhome directory
2554 if( access(legacyhome, R_OK) < 0 ) // not found
2555 {
2556 if( verbose )
2557 GenPrintf(EMSG_ver, "MKDIR legacyhome= %s\n", legacyhome );
2558 I_mkdir( legacyhome, 0700);
2559 }
2560 legacyhome_len = strlen(legacyhome);
2561
2562 // [WDJ] configfile must be set whereever legacyhome is on DOS or WIN32
2563 {
2564 const char * cfgstr;
2565 // user specific config file
2566 #ifdef DEVPARM_LOADING
2567 if( devparm )
2568 {
2569 // example: /home/user/.legacy/devdataconfig.cfg
2570 cfgstr = DEVDATA CONFIGFILENAME;
2571 }
2572 else
2573 #endif
2574 {
2575 // example: /home/user/.legacy/config.cfg
2576 cfgstr = CONFIGFILENAME;
2577 }
2578 cat_filename( cfgbuf, legacyhome, cfgstr );
2579 M_Set_configfile_main( cfgbuf );
2580 }
2581
2582 #ifdef SAVEGAMEDIR
2583 // default savegame file name, example: "/home/user/.legacy/%s/doomsav%i.dsg"
2584 // sprintf(savegamename, "%s%%s" SLASH "%s", legacyhome, text[NORM_SAVEI_NUM]);
2585 snprintf(savegamename, MAX_WADPATH-1, "%s%%s" SLASH "%s%s", legacyhome, SAVEGAMENAME, "%d.dsg");
2586 // so can extract legacyhome from savegamename later
2587 #else
2588 // default savegame file name, example: "/home/user/.legacy/doomsav%i.dsg"
2589 // sprintf(savegamename, "%s%s", legacyhome, text[NORM_SAVEI_NUM]);
2590 snprintf(savegamename, MAX_WADPATH-1, "%s%s%s", legacyhome, SAVEGAMENAME, "%d.dsg");
2591 #endif
2592 savegamename[MAX_WADPATH-1] = '\0';
2593 #endif
2594
2595 // [WDJ] Would have a doomwaddir in the config file too, but LoadConfig
2596 // is done way too late for that.
2597 for( wdi=0; wdi<(sizeof(dirlist)/sizeof(char*)); wdi++ )
2598 {
2599 char ** dwp = & doomwaddir[wdi+DOOMWADDIR_DIRLIST]; // where it goes in doomwaddir
2600 if( *dwp && (*dwp != dirlist[wdi]) )
2601 free( *dwp ); // was malloc
2602 // Default searches
2603 if( dirlist[wdi] && dirlist[wdi][0] == '~' )
2604 {
2605 // Relative to user home.
2606 cat_filename( dirbuf, (userhome? userhome : "" ), &dirlist[wdi][2]);
2607 *dwp = strdup( dirbuf ); // (malloc)
2608 }
2609 else
2610 {
2611 *dwp = dirlist[wdi]; // (ref)
2612 }
2613 }
2614 }
2615
2616 #if 0
2617 Print_search_directories( EMSG_debug, 0x0F );
2618 #endif
2619
2620 if( verbose )
2621 {
2622 GenPrintf(EMSG_ver, "Config: %s\n", configfile_main );
2623 GenPrintf(EMSG_ver, "Savegames: %s\n", savegamename );
2624 }
2625
2626 // identify the main IWAD file to use
2627 IdentifyVersion(); // game, iwad
2628 modifiedgame = false;
2629
2630 // Title page
2631 const char *gametitle = gamedesc.startup_title; // set by IdentifyVersion
2632 if( gametitle == NULL ) gametitle = gamedesc.gname;
2633 if( gametitle )
2634 GenPrintf(EMSG_info, "%s\n", gametitle);
2635
2636 #ifdef DEVPARM_LOADING
2637 // convenience hack to allow -wart e m to add a wad file
2638 p = M_CheckParm("-wart");
2639 if (p)
2640 {
2641 // big hack, change to -warp so a later CheckParm does the warp.
2642 myargv[p][4] = 'p';
2643
2644 // Map name handling. Form wad name from map/episode numbers.
2645 #ifdef WADFILE_RELOAD
2646 // prepend a tilde to the filename so wadfile will be reloadable
2647 #endif
2648 switch (gamemode)
2649 {
2650 case doom_shareware:
2651 case ultdoom_retail:
2652 case doom_registered:
2653 #ifdef WADFILE_RELOAD
2654 sprintf(fbuf, "~" DEVMAPS "E%cM%c.wad", myargv[p + 1][0], myargv[p + 2][0]);
2655 #else
2656 sprintf(fbuf, DEVMAPS "E%cM%c.wad", myargv[p + 1][0], myargv[p + 2][0]);
2657 #endif
2658 GenPrintf(EMSG_info, "Warping to Episode %s, Map %s.\n", myargv[p + 1], myargv[p + 2]);
2659 break;
2660
2661 case doom2_commercial:
2662 default:
2663 p = atoi(myargv[p + 1]);
2664 if (p < 10)
2665 #ifdef WADFILE_RELOAD
2666 sprintf(fbuf, "~" DEVMAPS "cdata/map0%i.wad", p);
2667 #else
2668 sprintf(fbuf, DEVMAPS "cdata/map0%i.wad", p);
2669 #endif
2670 else
2671 #ifdef WADFILE_RELOAD
2672 sprintf(fbuf, "~" DEVMAPS "cdata/map%i.wad", p);
2673 #else
2674 sprintf(fbuf, DEVMAPS "cdata/map%i.wad", p);
2675 #endif
2676 break;
2677 }
2678 D_AddFile(fbuf);
2679 // continue and execute -warp
2680 }
2681 #endif
2682
2683 // Add any files specified on the command line with -file <wadfile>
2684 // to the wad list
2685 if (M_CheckParm("-file"))
2686 {
2687 // the parms after p are wadfile/lump names,
2688 // until end of parms or another - preceded parm
2689 modifiedgame = true; // homebrew levels
2690 while (M_IsNextParm())
2691 D_AddFile( M_GetNextParm() );
2692 }
2693
2694 // load dehacked file
2695 p = M_CheckParm("-dehacked");
2696 if (!p)
2697 p = M_CheckParm("-deh"); //Fab:02-08-98:like Boom & DosDoom
2698 if (p != 0)
2699 {
2700 while (M_IsNextParm())
2701 D_AddFile( M_GetNextParm() );
2702 }
2703
2704 #ifdef FRENCH_INLINE
2705 french_text();
2706 #endif
2707
2708 #ifdef BEX_LANGUAGE
2709 if ( M_CheckParm("-lang") )
2710 {
2711 // will check for NULL parameter
2712 BEX_load_language( M_GetNextParm(), 2 ); // language name
2713 }
2714 #ifdef BEX_LANG_AUTO_LOAD
2715 else
2716 {
2717 BEX_load_language( NULL, 2 ); // default language name
2718 }
2719 #endif
2720 #endif
2721
2722 // Load wad, including the main wad file.
2723 // This will read DEH and BEX files. Need devparm and verbose.
2724 if( W_Init_MultipleFiles(startupwadfiles) == 0 )
2725 {
2726 // Some wad failed to load.
2727 if( !M_CheckParm( "-noloadfail" ) )
2728 fatal_error = true;
2729 }
2730
2731 if ( !M_CheckParm("-nocheckwadversion") )
2732 D_CheckWadVersion();
2733
2734
2735 //Hurdler: someone wants to keep those lines?
2736 //BP: i agree with you why should be registered to play someone wads ?
2737 // unfortunately most additional wad have more texture and monsters
2738 // that shareware wad do, so there will miss resource :(
2739
2740 if ( gamedesc.gameflags & GD_idwad )
2741 {
2742 // [WDJ] These warnings only apply to id iwad files, and should not
2743 // appear when only using FreeDoom or third party iwads.
2744
2745 // Check for -file in shareware
2746 if (modifiedgame)
2747 {
2748 // These are the lumps that will be checked in IWAD,
2749 // if any one is not present, execution will be aborted.
2750 char name[23][8] = {
2751 "e2m1", "e2m2", "e2m3", "e2m4", "e2m5", "e2m6", "e2m7", "e2m8", "e2m9",
2752 "e3m1", "e3m3", "e3m3", "e3m4", "e3m5", "e3m6", "e3m7", "e3m8", "e3m9",
2753 "dphoof", "bfgga0", "heada1", "cybra1", "spida1d1"
2754 };
2755
2756 if (gamemode == doom_shareware)
2757 CONS_Printf("\nYou shouldn't use -file with the shareware version. Register!\n");
2758
2759 // Check for fake IWAD with right name,
2760 // but w/o all the lumps of the registered version.
2761 if (gamemode == doom_registered)
2762 {
2763 int i;
2764 for (i = 0; i < 23; i++)
2765 {
2766 if( ! VALID_LUMP( W_CheckNumForName(name[i]) ) )
2767 CONS_Printf("\nThis is not the registered version.");
2768 }
2769 }
2770 }
2771
2772 // If additonal PWAD files are used, print modified banner
2773 if (modifiedgame)
2774 CONS_Printf(text[MODIFIED_NUM]);
2775
2776 // Check and print which version is executed.
2777 switch (gamemode)
2778 {
2779 case doom_shareware:
2780 case indetermined:
2781 CONS_Printf(text[SHAREWARE_NUM]);
2782 break;
2783 case doom_registered:
2784 case ultdoom_retail:
2785 case doom2_commercial:
2786 CONS_Printf(text[COMERCIAL_NUM]);
2787 break;
2788 default:
2789 // Ouch.
2790 break;
2791 }
2792 }
2793
2794 EOUT_flags = EOUT_text | EOUT_log | EOUT_con;
2795
2796
2797 #ifdef LAUNCHER
2798 //---------------------------------------------------- LAUNCHER display
2799 if ( fatal_error || init_sequence == 1 || (init_sequence == 0 && myargc < 2 ))
2800 {
2801 // [WDJ] Invoke built-in launcher command line
2802 if ( fatal_error )
2803 {
2804 CONS_Printf("Fatal error display: (press ESC to continue).\n");
2805 con_destlines = BASEVIDHEIGHT;
2806 do
2807 {
2808 CON_Draw_Console();
2809 I_OsPolling();
2810 D_Process_Events (); // menu and console responder
2811 CON_Ticker ();
2812 I_UpdateNoBlit();
2813 I_FinishUpdate(); // page flip or blit buffer
2814 } while( con_destlines>0 );
2815 }
2816 init_sequence = 1;
2817 M_LaunchMenu(); // changes init_sequence > 1 to exit restart loop
2818
2819 // restart
2820 Clear_SoftError();
2821 D_Clear_Files();
2822 con_Printf( "Launcher restart:\n" );
2823 goto restart_command;
2824 }
2825 #endif
2826
2827 //--------------------------------------------------------- LAUNCHED
2828 // After this line, commit to the initial game and video port selected.
2829 // Use I_Error.
2830
2831 if( ! VALID_LUMP( W_CheckNumForName ( "PLAYPAL" ) ) )
2832 {
2833 //Hurdler: I'm tired of that question ;)
2834 I_Error (
2835 "The main IWAD file is not found, or does not have PLAYPAL lump.\n"
2836 "The IWAD can be either doom.wad, doom1.wad, doom2.wad, tnt.wad\n"
2837 "plutonia.wad, heretic.wad, or heretic1.wad from any shareware\n"
2838 "or commercial version of Doom or Heretic, or some other IWAD!\n"
2839 "Cannot use legacy.wad, nor a PWAD, for an IWAD.\n" );
2840 }
2841
2842 if( fatal_error )
2843 {
2844 I_Error ( "Shutdown due to fatal error.\n" );
2845 }
2846
2847 //---------------------------------------------------- LOAD CONFIG
2848
2849 // The drawmode and video settings are now part of the config.
2850 // It needs to be loaded before the full graphics.
2851
2852 // check for an alternative config file
2853 p = M_CheckParm ("-config");
2854 if (p && p<myargc-1)
2855 {
2856 // substitute config file
2857 strncpy (cfgbuf, myargv[p+1], MAX_WADPATH-1);
2858 cfgbuf[MAX_WADPATH-1] = '\0';
2859 M_Set_configfile_main( cfgbuf );
2860 CONS_Printf ("config file: %s\n", configfile_main);
2861 }
2862 // This config will load the config drawmode setting.
2863 M_ClearConfig( CFG_main ); // due to launcher loop
2864 M_LoadConfig( CFG_main, configfile_main ); // WARNING : this do a "COM_BufExecute()"
2865
2866
2867 //---------------------------------------------------- READY SCREEN
2868 #ifdef HWRENDER
2869 // Init the rendermode patch storage.
2870 HWR_patchstore = 0;
2871 EN_HWR_flashpalette = 0; // software and default
2872 #endif
2873
2874 // we need to check for dedicated before initialization of some subsystems
2875 dedicated = M_CheckParm("-dedicated") != 0;
2876 if( dedicated )
2877 {
2878 nodrawers = true;
2879 vid.draw_ready = 0;
2880 drawmode_recalc = false;
2881 I_ShutdownGraphics();
2882 EOUT_flags = EOUT_log;
2883 }
2884 else
2885 {
2886 //--------------------------------------------------------- GRAPHICS SETTINGS
2887 set_drawmode = cv_drawmode.EV;
2888 req_bitpp = 0; // because of launcher looping
2889 req_alt_bitpp = 0;
2890
2891 if( M_CheckParm("-highcolor") )
2892 {
2893 set_drawmode = DRM_explicit_bpp; // 15 or 16 bpp
2894 req_bitpp = 16;
2895 req_alt_bitpp = 15;
2896 }
2897 if( M_CheckParm("-truecolor") )
2898 {
2899 set_drawmode = DRM_explicit_bpp; // 24 or 32 bpp
2900 req_bitpp = 32;
2901 req_alt_bitpp = 24;
2902 }
2903 if( M_CheckParm("-native") )
2904 {
2905 set_drawmode = DRM_native; // bpp of the default screen
2906 }
2907 p = M_CheckParm("-bpp"); // specific bit per pixel color
2908 if( p )
2909 {
2910 // binding, should fail if cannot find a mode
2911 req_bitpp = atoi(myargv[p + 1]);
2912 if( ! V_CanDraw( req_bitpp ) )
2913 {
2914 #ifdef LAUNCHER
2915 I_SoftError( "-bpp invalid\n");
2916 goto restart_command;
2917 #else
2918 I_Error( "-bpp invalid\n");
2919 #endif
2920 }
2921 set_drawmode = DRM_explicit_bpp;
2922 }
2923
2924 // Allow a config file for opengl to overload the config settings.
2925 // It may be edited to set only what settings should be specific to opengl.
2926 // May be a problem if opengl cannot really be started.
2927
2928 if( M_CheckParm("-opengl") )
2929 {
2930 set_drawmode = DRM_opengl; // opengl temporary
2931 }
2932 #ifdef SMIF_WIN_NATIVE
2933 #ifdef HWRENDER
2934 else if( M_CheckParm ("-3dfx") || M_CheckParm ("-glide") )
2935 {
2936 set_drawmode = DRM_glide; // glide temporary
2937 }
2938 else if( M_CheckParm ("-minigl") ) // MiniGL is considered to be opengl
2939 {
2940 set_drawmode = DRM_minigl; // opengl temporary
2941 }
2942 else if( M_CheckParm ("-d3d") )
2943 {
2944 set_drawmode = DRM_d3d; // D3D temporary
2945 }
2946 #endif
2947 #endif
2948
2949 M_ClearConfig( CFG_drawmode ); // due to launcher loop
2950 // Load the config file for this drawmode.
2951 // example: /home/user/.legacy/config32.cfg
2952 M_Set_configfile_drawmode( set_drawmode );
2953 // Conditional on name defined and file existing.
2954 // This cannot change the drawmode, but can load screen sizes.
2955 M_LoadConfig( CFG_drawmode, configfile_drawmode ); // WARNING : this do a "COM_BufExecute()"
2956
2957
2958 // 0 means not set at the cmd-line
2959 req_width = 0;
2960 req_height = 0;
2961
2962 p = M_CheckParm("-width");
2963 if (p && p < myargc-1)
2964 req_width = atoi(myargv[p+1]);
2965
2966 p = M_CheckParm("-height");
2967 if (p && p < myargc-1)
2968 req_height = atoi(myargv[p+1]);
2969
2970 req_command_video_settings = ((req_width > 0) && (req_height > 0));
2971
2972 //--------------------------------------------------------- FULL GRAPHICS
2973 // setup loading screen
2974 // Still using font1 during this init, up into CON_Init_Video.
2975 CONS_Printf("RequestFullGraphics...\n");
2976 // Allow VID_QueryModelist to detect fullscreen capability.
2977 allow_fullscreen = ! M_CheckParm("-window");
2978 cv_fullscreen.EV = cv_fullscreen.value && allow_fullscreen;
2979
2980 // Initial setup of rendermode
2981 V_switch_drawmode( set_drawmode, 0 ); // command line, do not change config files
2982
2983 // set user default mode or mode set at cmdline
2984 SCR_apply_video_settings(); // command line settings, or config file settings.
2985
2986 // Full graphics.
2987 // param: req_drawmode, req_bitpp, req_alt_bitpp, req_width, req_height.
2988 // If fails for one fullscreen mode, does not mean fails for all fullscreen modes.
2989 // Calls I_Rendermode_setup, V_Setup_VideoDraw, HWR_Startup_Render.
2990 // Calls V_SetPalette, HWR_SetPalette.
2991 drawmode_recalc = true;
2992 rendermode_recalc = true;
2993 SCR_SetMode( 0 );
2994
2995 SCR_Recalc();
2996 V_Clear_Display();
2997
2998 drawmode_recalc = false;
2999 rendermode_recalc = false;
3000
3001 //--------------------------------------------------------- CONSOLE
3002 // Need console fonts, colormaps, before can stop using font1.
3003 CONS_Printf(text[HU_INIT_NUM]);
3004 #ifdef PARANOID
3005 // Console fonts were loaded by SCR_SetMode.
3006 if( hu_fonts_loaded < 2 )
3007 {
3008 // Do not reload without unloading fonts first.
3009 if( hu_fonts_loaded == 0 )
3010 {
3011 GenPrintf( EMSG_warn, "Console fonts not loaded\n" );
3012 // Load console fonts, setting hu_fonts_loaded.
3013 HU_Load_Graphics(); // dependent upon dedicated and game
3014 }
3015 else
3016 {
3017 GenPrintf( EMSG_warn, "Console fonts not complete\n" );
3018 }
3019 }
3020 #endif
3021 // Load console colormaps, and size console.
3022 CON_Init_Video(); // dependent upon vid, hu_font
3023
3024 if( (hu_fonts_loaded == 2) && whitemap )
3025 use_font1 = 0; // Now use console fonts, no longer using font1.
3026
3027 EOUT_flags = EOUT_log | EOUT_con;
3028 }
3029
3030 #if 0
3031 p = M_CheckParm ("-cfgmod");
3032 if (p && p<myargc-1)
3033 {
3034 // Add mod config file
3035 strncpy (cfgbuf, myargv[p+1], MAX_WADPATH-1);
3036 cfgbuf[MAX_WADPATH-1] = '\0';
3037 // not saveable, so do not need to save name
3038 CONS_Printf ("add config file: %s\n", cfgbuf);
3039 // This cannot change the drawmode.
3040 M_LoadConfig( CFG_other, cfgbuf ); // WARNING : this do a "COM_BufExecute()"
3041 }
3042 #endif
3043
3044 //--------------------------------------------------------- GAME SETTINGS
3045 // get skill / episode / map from parms
3046 gameskill = sk_medium;
3047 startepisode = 1;
3048 startmap = 1;
3049 autostart = false;
3050
3051 p = M_CheckParm("-skill");
3052 if (p && p < myargc - 1)
3053 {
3054 gameskill = myargv[p + 1][0] - '1';
3055 autostart = true;
3056 }
3057
3058 p = M_CheckParm("-episode");
3059 if (p && p < myargc - 1)
3060 {
3061 startepisode = myargv[p + 1][0] - '0';
3062 startmap = 1;
3063 autostart = true;
3064 }
3065
3066 p = M_CheckParm("-warp");
3067 if (p && p < myargc - 1)
3068 {
3069 if (gamemode == doom2_commercial)
3070 startmap = atoi(myargv[p + 1]);
3071 else
3072 {
3073 startepisode = myargv[p + 1][0] - '0';
3074 if (p < myargc - 2 && myargv[p + 2][0] >= '0' && myargv[p + 2][0] <= '9')
3075 startmap = myargv[p + 2][0] - '0';
3076 else
3077 startmap = 1;
3078 }
3079 autostart = true;
3080 }
3081
3082 // [WDJ] This triggers the first draw to the screen,
3083 // debug it here instead of waiting for CONS_Printf in BloodTime_OnChange
3084 CONS_Printf( "Init after ...\n" );
3085
3086 CONS_Printf(text[W_INIT_NUM]);
3087 // adapt tables to legacy needs
3088 P_PatchInfoTables();
3089
3090 if (gamemode == heretic)
3091 {
3092 Heretic_PatchEngine();
3093 #ifdef FRENCH_INLINE
3094 french_heretic();
3095 #endif
3096 }
3097
3098 if(gamemode == chexquest1)
3099 {
3100 Chex1_PatchEngine();
3101 #ifdef FRENCH_INLINE
3102 french_chexquest();
3103 #endif
3104 }
3105
3106 B_Init_Bots(); //added by AC for acbot
3107
3108 wipegamestate = gamestate;
3109
3110 //------------------------------------------------ COMMAND LINE PARAMS
3111
3112 #ifdef CDMUS
3113 // Initialize CD-Audio, no music on a dedicated server
3114 if (!M_CheckParm("-nocd") && ! dedicated )
3115 I_InitCD();
3116 #endif
3117
3118 if (M_CheckParm("-splitscreen"))
3119 CV_SetParam(&cv_splitscreen, 1);
3120
3121 // Affects only the game started at the command line.
3122 // CV_NETVAR are sent by string, CV_SAVE are saved by string.
3123 nomonsters = M_CheckParm("-nomonsters");
3124
3125 if (M_CheckParm("-respawn"))
3126 CV_SetParam( &cv_respawnmonsters, 1 ); // NETVAR
3127 // COM_BufAddText("respawnmonsters 1\n");
3128 if (M_CheckParm("-coopmonsters"))
3129 CV_SetParam( &cv_monbehavior, 1 ); // NETVAR, SAVE
3130 // COM_BufAddText("monsterbehavior 1\n");
3131 if (M_CheckParm("-infight"))
3132 CV_SetParam( &cv_monbehavior, 2 ); // NETVAR, SAVE
3133 // COM_BufAddText("monsterbehavior 2\n");
3134 if (M_CheckParm("-teamplay"))
3135 CV_SetParam( &cv_teamplay, 1 ); // NETVAR
3136 // COM_BufAddText("teamplay 1\n");
3137 if (M_CheckParm("-teamskin"))
3138 CV_SetParam( &cv_teamplay, 2 ); // NETVAR
3139 // COM_BufAddText("teamplay 2\n");
3140 // Setting deathmatch also sets cv_itemrespawn (d_netcmd).
3141 if (M_CheckParm("-altdeath"))
3142 CV_SetParam( &cv_deathmatch, 2 ); // NETVAR
3143 // COM_BufAddText("deathmatch 2\n");
3144 else if (M_CheckParm("-deathmatch"))
3145 CV_SetParam( &cv_deathmatch, 1 ); // NETVAR
3146 // COM_BufAddText("deathmatch 1\n");
3147 if (M_CheckParm("-fast"))
3148 CV_SetParam( &cv_fastmonsters, 1 ); // NETVAR
3149 // COM_BufAddText("fastmonsters 1\n");
3150 //added by AC
3151 if (M_CheckParm("-predicting"))
3152 CV_SetParam( &cv_predictingmonsters, 1 ); // NETVAR
3153 // COM_BufAddText("predictingmonsters 1\n");
3154
3155 if (M_CheckParm("-timer"))
3156 {
3157 char *s = M_GetNextParm();
3158 if( s == NULL )
3159 {
3160 I_SoftError( "Switch -timer <seconds>\n" );
3161 }
3162 else
3163 {
3164 // May be larger than EV, so cannot use CV_SetParam.
3165 CV_Set( &cv_timelimit, s ); // NETVAR
3166 // COM_BufAddText(va("timelimit %s\n", s));
3167 }
3168 }
3169
3170 if (M_CheckParm("-avg"))
3171 {
3172 // May be larger than EV, so cannot use CV_SetParam.
3173 CV_SetValue( &cv_timelimit, 20 ); // NETVAR
3174 // COM_BufAddText("timelimit 20\n");
3175 CONS_Printf(text[AUSTIN_NUM]);
3176 }
3177
3178 // turbo option, is not meant to be saved in config, still
3179 // supported at cmd-line for compatibility
3180 if (M_CheckParm("-turbo"))
3181 {
3182 if( M_IsNextParm() )
3183 {
3184 COM_BufAddText(va("turbo %s\n", M_GetNextParm()));
3185 }
3186 else
3187 {
3188 I_SoftError( "Switch -turbo <10-255>\n" );
3189 }
3190 }
3191
3192 // push all "+" parameter at the command buffer
3193 M_PushSpecialParameters();
3194
3195 CONS_Printf(text[M_INIT_NUM]);
3196 M_Configure();
3197
3198 CONS_Printf(text[R_INIT_NUM]);
3199 R_Init();
3200
3201 //
3202 // setting up sound
3203 //
3204 CONS_Printf(text[S_SETSOUND_NUM]);
3205 nosoundfx = M_CheckParm("-nosound");
3206 nomusic = M_CheckParm("-nomusic");
3207 if( dedicated )
3208 {
3209 nosoundfx = 1;
3210 nomusic = 1;
3211 // allow sound driver to disable self
3212 }
3213 // Music init is in I_StartupSound
3214 I_StartupSound();
3215 S_Init(cv_soundvolume.value, cv_musicvolume.value);
3216
3217 CONS_Printf(text[ST_INIT_NUM]);
3218 ST_Init();
3219
3220 // SoM: Init FraggleScript
3221 T_Init_FS();
3222
3223 // init all NETWORK
3224 CONS_Printf(text[D_CHECKNET_NUM]);
3225 if (D_Startup_NetGame())
3226 autostart = true;
3227
3228 // check for a driver that wants intermission stats
3229 p = M_CheckParm("-statcopy");
3230 if (p && p < myargc - 1)
3231 {
3232 I_SoftError("Sorry but statcopy isn't supported at this time\n");
3233 /*
3234 // for statistics driver
3235 extern void* statcopy;
3236
3237 statcopy = (void*)atoi(myargv[p+1]);
3238 CONS_Printf (text[STATREG_NUM]);
3239 */
3240 }
3241
3242 // start the apropriate game based on parms
3243 p = M_CheckParm("-record");
3244 if (p && p < myargc - 1)
3245 {
3246 G_RecordDemo(myargv[p + 1]);
3247 autostart = true;
3248 }
3249
3250 // demo doesn't need anymore to be added with D_AddFile()
3251 p = M_CheckParm("-playdemo");
3252 if( !p && M_CheckParm("-timedemo") )
3253 p = 2500; // indicate timedemo
3254 if (p)
3255 {
3256 if( ! M_IsNextParm() )
3257 {
3258 I_SoftError( "Switch -playdemo <name> or -timedemo <name> \n" );
3259 }
3260 else
3261 {
3262 char demo_name[MAX_WADPATH]; // filename
3263 // add .lmp to identify the EXTERNAL demo file
3264 // it is NOT possible to play an internal demo using -playdemo,
3265 // rather push a playdemo command.. to do.
3266
3267 strncpy(demo_name, M_GetNextParm(), MAX_WADPATH-1);
3268 demo_name[MAX_WADPATH-1] = '\0';
3269 // get spaced filename or directory
3270 while (M_IsNextParm())
3271 {
3272 // [WDJ] Protect against long demo name on command line
3273 int dn_free = MAX_WADPATH - 2 - strlen(demo_name);
3274 if( dn_free > 1 )
3275 {
3276 strcat(demo_name, " ");
3277 strncat(demo_name, M_GetNextParm(), dn_free );
3278 demo_name[MAX_WADPATH-1] = '\0';
3279 }
3280 }
3281 FIL_DefaultExtension(demo_name, ".lmp");
3282
3283 CONS_Printf("Playing demo %s.\n", demo_name);
3284
3285 if( p == 2500 )
3286 { // timedemo
3287 G_TimeDemo(demo_name);
3288 }
3289 else
3290 { // playdemo
3291 singledemo = true; // quit after one demo
3292 G_DeferedPlayDemo(demo_name);
3293 }
3294
3295 gamestate = wipegamestate = GS_NULL;
3296
3297 return;
3298 }
3299 }
3300
3301 p = M_CheckParm("-loadgame");
3302 if (p && p < myargc - 1)
3303 {
3304 G_Load_Game(atoi(myargv[p + 1]));
3305 }
3306 else
3307 {
3308 if (dedicated && server)
3309 {
3310 pagename = "TITLEPIC";
3311 gamestate = GS_WAITINGPLAYERS;
3312 }
3313 else if (autostart || netgame
3314 || M_CheckParm("+connect") || M_CheckParm("-connect"))
3315 {
3316 //added:27-02-98: reset the current version number
3317 G_setup_VERSION();
3318 gameaction = ga_nothing;
3319 if (server && !M_CheckParm("+map"))
3320 COM_BufAddText(va("map \"%s\"\n", G_BuildMapName(startepisode, startmap)));
3321 }
3322 else
3323 {
3324 // Cancel commandline, restore cv_ var.
3325 D_StartTitle(); // start up intro loop
3326 }
3327
3328 }
3329
3330 drawmode_recalc = false;
3331 Clear_SoftError();
3332 // This leaves commands for the first COM_BufExecute in D_DoomLoop to execute.
3333 }
3334
3335
3336 // Print error and continue game [WDJ] 1/19/2009
3337 #define SOFTERROR_LISTSIZE 8
3338 static const char * SE_msg[SOFTERROR_LISTSIZE];
3339 static uint32_t SE_val[SOFTERROR_LISTSIZE]; // we only want to compare
3340 static int SE_msgcnt = 0;
3341 static int SE_next_msg_slot = 0;
3342
3343 byte EOUT_flags = EOUT_text | EOUT_log; // EOUT_e
3344
Clear_SoftError(void)3345 static void Clear_SoftError(void)
3346 {
3347 SE_msgcnt = 0;
3348 }
3349
3350
3351 // Print out error and continue program. Maintains list of errors and
3352 // does not repeat error messages in recent history.
I_SoftError(const char * errmsg,...)3353 void I_SoftError (const char *errmsg, ...)
3354 {
3355 va_list argptr;
3356 int index;
3357 uint32_t errval;
3358
3359 // Message first.
3360 va_start (argptr,errmsg);
3361 errval = va_arg( argptr, uint32_t ) ; // sample it as an int, no matter what
3362 va_end (argptr);
3363 // debug_Printf("errval=%d\n", errval ); // debug
3364 for( index = 0; index < SE_msgcnt; index ++ ){
3365 if( errmsg == SE_msg[index] ){
3366 if( errval == SE_val[index] ) goto done; // it is a repeat msg
3367 }
3368 }
3369 // save comparison info
3370 SE_msg[SE_next_msg_slot] = errmsg;
3371 SE_val[SE_next_msg_slot] = errval;
3372 SE_next_msg_slot++;
3373 if( SE_next_msg_slot > SE_msgcnt )
3374 SE_msgcnt = SE_next_msg_slot; // max
3375 if( SE_next_msg_slot >= SOFTERROR_LISTSIZE )
3376 SE_next_msg_slot = 0; // wrap
3377 // Error, always prints EMSG_text
3378 fprintf (stderr, "Warn: ");
3379 va_start (argptr,errmsg);
3380 GenPrintf_va( EMSG_error, errmsg, argptr ); // handles EOUT_con
3381 va_end (argptr);
3382
3383 done:
3384 fflush( stderr );
3385 }
3386
3387
3388 // The system independent quit and save config.
D_Quit_Save(quit_severity_e severity)3389 void D_Quit_Save ( quit_severity_e severity )
3390 {
3391 // Prevent recursive I_Quit(), mainly due to situation problems.
3392 static byte quitseq = 0;
3393 uint16_t * endtext = NULL;
3394
3395 // If this gets called twice, it cannot just return.
3396 // Some shutdown routine called I_Quit again due to an error and we
3397 // cannot get back to the previous invocation to finish the shutdown.
3398 if( quitseq == 0 )
3399 {
3400 quitseq = 1;
3401 //added:16-02-98: when recording a demo, should exit using 'q' key,
3402 // but sometimes we forget and use 'F10'.. so save here too.
3403 if (demorecording)
3404 G_CheckDemoStatus();
3405 }
3406 if( quitseq < 2 )
3407 {
3408 quitseq = 2;
3409 D_Quit_NetGame ();
3410 }
3411 if( quitseq < 5 )
3412 {
3413 quitseq = 5;
3414 I_ShutdownSound();
3415 }
3416 #ifdef CDMUS
3417 if( quitseq < 6 )
3418 {
3419 quitseq = 6;
3420 I_ShutdownCD();
3421 }
3422 #endif
3423 if( quitseq < 8 )
3424 {
3425 quitseq = 8;
3426 if( severity == QUIT_normal )
3427 {
3428 M_SaveAllConfig();
3429 }
3430 }
3431 if( quitseq < 10 )
3432 {
3433 quitseq = 10;
3434 if( (severity == QUIT_normal)
3435 && ! M_CheckParm("-noendtext") // normal spelling, docs
3436 && ! M_CheckParm("-noendtxt") // previous versions
3437 && cv_textout.EV > 0 )
3438 {
3439 // [WDJ] Check on errors during I_Error shutdown.
3440 // Avoid repeat errors during bad environment shutdown.
3441 lumpnum_t endtxt_num = W_CheckNumForName("ENDOOM");
3442 if( VALID_LUMP(endtxt_num) )
3443 endtext = W_CacheLumpNum( endtxt_num, PU_STATIC );
3444 // If there are any more errors, then do not show the end text.
3445 }
3446 }
3447 if( quitseq < 11 )
3448 {
3449 quitseq = 11;
3450 // Close open wad files.
3451 // Neccesity for a Mac. Open files hang devices.
3452 W_Shutdown();
3453 }
3454 if( quitseq < 15 )
3455 {
3456 quitseq = 15;
3457 I_Shutdown_IO();
3458 }
3459 if( quitseq < 20 )
3460 {
3461 quitseq = 20;
3462 if( severity != QUIT_normal )
3463 I_Sleep( 3000 ); // to see some messages
3464 vid.draw_ready = 0;
3465 I_ShutdownGraphics();
3466 HU_Release_Graphics();
3467 #ifdef HWRENDER
3468 if( HWR_patchstore )
3469 {
3470 HWR_Shutdown_Render();
3471 }
3472 #endif
3473 }
3474 if( quitseq < 22 )
3475 {
3476 quitseq = 22;
3477 I_ShutdownSystem();
3478 }
3479 if( quitseq < 29 )
3480 {
3481 quitseq = 29;
3482 if( (severity == QUIT_normal)
3483 && endtext )
3484 {
3485 // Show the ENDOOM text
3486 printf("\r");
3487 I_Show_EndText( endtext );
3488 }
3489 }
3490 }
3491
3492 // I_Quit exits with (exit 0).
3493 // No return
I_Quit(void)3494 void I_Quit (void)
3495 {
3496 D_Quit_Save( QUIT_normal );
3497 I_Quit_System(); // No Return
3498 }
3499
3500
Help(void)3501 static void Help( void )
3502 {
3503 char * np = M_GetNextParm();
3504
3505 if( np == NULL )
3506 {
3507 printf
3508 ("Usage: doomlegacy [-opengl] [-iwad xxx.wad] [-file pwad.wad ...]\n"
3509 "--version Print Doom Legacy version\n"
3510 "-h Help\n"
3511 "-h g Help game and wads\n"
3512 "-h m Help multiplayer\n"
3513 "-h c Help config\n"
3514 "-h s Help server\n"
3515 "-h d Help demo\n"
3516 "-h D Help Devmode\n"
3517 );
3518 return;
3519 }
3520 switch( np[0] )
3521 {
3522 case 'g': // game
3523 printf
3524 (
3525 "-game name doomu, doom2, tnt, plutonia, freedoom, heretic, chex1, etc.\n"
3526 "-iwad file The game wad\n"
3527 "-file file Load DEH and PWAD files (one or more)\n"
3528 "-deh file Load DEH files (one or more)\n"
3529 "-loadgame num Load savegame num\n"
3530 "-episode 2 Goto episode 2, level 1\n"
3531 "-skill 3 Skill 1 to 5\n"
3532 "-warp 13 Goto map13\n"
3533 "-warp 1 3 Goto episode 1 level 3\n"
3534 "-nomonsters No monsters\n"
3535 "-respawn Monsters respawn after killed\n"
3536 "-coopmonsters Monsters cooperate\n"
3537 "-infight Monsters fight each other\n"
3538 "-fast Monsters are fast\n"
3539 "-predicting Monsters aim better\n"
3540 "-turbo num Player speed %%, 10 to 255\n"
3541 );
3542 break;
3543 case 'm': // multiplayer
3544 printf
3545 (
3546 "-teamplay Play with teams by color\n"
3547 "-teamskin Play with teams using skins\n"
3548 "-splitscreen Two players on this screen\n"
3549 "-deathmatch Deathmatch, weapons respawn\n"
3550 "-altdeath Deathmatch, items respawn\n"
3551 "-timer num Timelimit in minutes\n"
3552 "-avg Austin 20 min rounds\n"
3553 );
3554 break;
3555 case 'c': // config
3556 printf
3557 (
3558 "-v -v2 Verbose\n"
3559 "-home name Config and savegame directory\n"
3560 "-config file Config file\n"
3561 "-opengl OpenGL hardware renderer\n"
3562 "-nosound No sound effects\n"
3563 #ifdef CDMUS
3564 "-nocd No CD music\n"
3565 #endif
3566 "-nomusic No music\n"
3567 "-precachesound Preload sound effects\n"
3568 "-mb num Pre-allocate num MiB of memory\n"
3569 "-window No fullscreen\n"
3570 "-width num Video mode width\n"
3571 "-height num Video mode height\n"
3572 "-highcolor Request 15bpp or 16bpp\n"
3573 "-truecolor Request 24bpp or 32bpp\n"
3574 "-native Video mode in native bpp\n"
3575 "-bpp num Video mode in (8,15,16,24,32) bpp\n"
3576 "-nocheckwadversion Ignore legacy.wad version\n"
3577 #ifdef BEX_LANGUAGE
3578 "-lang name Load BEX language file name.bex\n"
3579 #endif
3580 );
3581 break;
3582 case 's': // server
3583 printf
3584 (
3585 "-server Start as game server\n"
3586 "-dedicated Dedicated server, no player\n"
3587 "-connect name Connect to server name\n"
3588 "-bandwidth bps Net bandwidth in bytes/sec\n"
3589 "-packetsize num Net packetsize\n"
3590 "-nodownload No download from server\n"
3591 "-nofiles Download all from server\n"
3592 "-clientport x Use port x for client\n"
3593 "-udpport x Use udp port x for server (and client)\n"
3594 #ifdef USE_IPX
3595 "-ipx Use IPX\n"
3596 #endif
3597 "-extratic x Send redundant player movement\n"
3598 "-debugfile file Log to debug file\n"
3599 "-left Left slaved view\n"
3600 "-right Right slaved view\n"
3601 "-screendeg x Slaved view at x degrees\n"
3602 );
3603 break;
3604 case 'd': // demo
3605 printf
3606 (
3607 "-record file Record demo to file\n"
3608 "-maxdemo num Limit record demo size, in KiB\n"
3609 "-playdemo file Play demo from file\n"
3610 );
3611 break;
3612 case 'D': // devmode
3613 printf
3614 (
3615 "-devparm Develop mode\n"
3616 #ifdef DEVPARM_LOADING
3617 "-devgame gamename Develop mode, and specify game\n"
3618 "-wart 3 1 Load file devmaps/E3M1.wad, then warp to it\n"
3619 "-wart 13 Load file devmaps/cdata/map13.wad, then warp to it\n"
3620 #endif
3621 "-timedemo file Timedemo from file\n"
3622 "-nodraw Timedemo without draw\n"
3623 "-noblit Timedemo without blit\n"
3624 );
3625 break;
3626 }
3627 }
3628