1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: d_main.cpp 4542 2014-02-09 17:39:42Z dr_sean $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Copyright (C) 2006-2014 by The Odamex 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 // DESCRIPTION:
20 // DOOM main program (D_DoomMain) and game loop (D_DoomLoop),
21 // plus functions to determine game mode (shareware, registered),
22 // parse command line parameters, configure game parameters (turbo),
23 // and call the startup functions.
24 //
25 //-----------------------------------------------------------------------------
26
27 #include "version.h"
28
29 #include <sstream>
30 #include <string>
31 #include <vector>
32 #include <algorithm>
33
34 #include "win32inc.h"
35 #ifndef _WIN32
36 #include <sys/stat.h>
37 #endif
38
39 #ifdef UNIX
40 #include <unistd.h>
41 #include <dirent.h>
42 #endif
43
44 #include <time.h>
45 #include <math.h>
46
47 #include "errors.h"
48
49 #include "m_alloc.h"
50 #include "m_random.h"
51 #include "minilzo.h"
52 #include "doomdef.h"
53 #include "doomstat.h"
54 #include "gstrings.h"
55 #include "z_zone.h"
56 #include "w_wad.h"
57 #include "s_sound.h"
58 #include "v_video.h"
59 #include "f_finale.h"
60 #include "f_wipe.h"
61 #include "m_argv.h"
62 #include "m_fileio.h"
63 #include "m_misc.h"
64 #include "m_menu.h"
65 #include "c_console.h"
66 #include "c_dispatch.h"
67 #include "i_system.h"
68 #include "i_sound.h"
69 #include "i_video.h"
70 #include "i_input.h"
71 #include "g_game.h"
72 #include "hu_stuff.h"
73 #include "wi_stuff.h"
74 #include "st_stuff.h"
75 #include "am_map.h"
76 #include "c_effect.h"
77 #include "p_setup.h"
78 #include "r_local.h"
79 #include "r_sky.h"
80 #include "d_main.h"
81 #include "d_dehacked.h"
82 #include "cmdlib.h"
83 #include "s_sound.h"
84 #include "m_swap.h"
85 #include "v_text.h"
86 #include "gi.h"
87 #include "stats.h"
88 #include "p_ctf.h"
89 #include "cl_main.h"
90
91 #ifdef GEKKO
92 #include "i_wii.h"
93 #endif
94
95 #ifdef _XBOX
96 #include "i_xbox.h"
97 #endif
98
99 extern size_t got_heapsize;
100
101 //extern void M_RestoreMode (void); // [Toke - Menu]
102 extern void R_ExecuteSetViewSize (void);
103 void V_InitPalette (void);
104
105 void D_CheckNetGame (void);
106 void D_ProcessEvents (void);
107 void D_DoAdvanceDemo (void);
108
109 void D_DoomLoop (void);
110
111 extern QWORD testingmode;
112 extern BOOL setsizeneeded;
113 extern BOOL setmodeneeded;
114 extern int NewWidth, NewHeight, NewBits, DisplayBits;
115 EXTERN_CVAR (st_scale)
116 extern BOOL gameisdead;
117 extern BOOL demorecording;
118 extern bool M_DemoNoPlay; // [RH] if true, then skip any demos in the loop
119 extern DThinker ThinkerCap;
120 extern int NoWipe; // [RH] Don't wipe when travelling in hubs
121
122 BOOL devparm; // started game with -devparm
123 const char *D_DrawIcon; // [RH] Patch name of icon to draw on next refresh
124 int NoWipe; // [RH] Allow wipe? (Needs to be set each time)
125 static bool wiping_screen = false;
126
127 char startmap[8];
128 BOOL autostart;
129 BOOL autorecord;
130 std::string demorecordfile;
131 BOOL advancedemo;
132 event_t events[MAXEVENTS];
133 int eventhead;
134 int eventtail;
135 gamestate_t wipegamestate = GS_DEMOSCREEN; // can be -1 to force a wipe
136 DCanvas *page;
137 bool demotest;
138
139 static int demosequence;
140 static int pagetic;
141
142 EXTERN_CVAR (sv_allowexit)
143 EXTERN_CVAR (sv_nomonsters)
144 EXTERN_CVAR (sv_monstersrespawn)
145 EXTERN_CVAR (sv_fastmonsters)
146 EXTERN_CVAR (sv_freelook)
147 EXTERN_CVAR (sv_allowjump)
148 EXTERN_CVAR (sv_allowredscreen)
149 EXTERN_CVAR (snd_sfxvolume) // maximum volume for sound
150 EXTERN_CVAR (snd_musicvolume) // maximum volume for music
151
152 const char *LOG_FILE;
153
154 void M_RestoreMode (void);
155 void M_ModeFlashTestText (void);
156
157 //
158 // D_ProcessEvents
159 // Send all the events of the given timestamp down the responder chain
160 //
D_ProcessEvents(void)161 void D_ProcessEvents (void)
162 {
163 event_t *ev;
164
165 // [RH] If testing mode, do not accept input until test is over
166 if (testingmode)
167 {
168 if (testingmode <= I_MSTime() * TICRATE / 1000)
169 M_RestoreMode ();
170 else
171 M_ModeFlashTestText();
172
173 return;
174 }
175
176 for (; eventtail != eventhead ; eventtail = ++eventtail<MAXEVENTS ? eventtail : 0)
177 {
178 ev = &events[eventtail];
179 if (C_Responder (ev))
180 continue; // console ate the event
181 if (M_Responder (ev))
182 continue; // menu ate the event
183 G_Responder (ev);
184 }
185 }
186
187 //
188 // D_PostEvent
189 // Called by the I/O functions when input is detected
190 //
D_PostEvent(const event_t * ev)191 void D_PostEvent (const event_t* ev)
192 {
193 events[eventhead] = *ev;
194
195 if(++eventhead >= MAXEVENTS)
196 eventhead = 0;
197 }
198
199 //
200 // D_DisplayTicker
201 //
202 // Called once every gametic to provide timing for display functions such
203 // as screenwipes.
204 //
D_DisplayTicker()205 void D_DisplayTicker()
206 {
207 if (wiping_screen)
208 wiping_screen = (Wipe_Ticker() == false);
209 }
210
211
212 //
213 // D_Display
214 // draw current display, possibly wiping it from the previous
215 //
D_Display(void)216 void D_Display (void)
217 {
218 if (nodrawers)
219 return; // for comparative timing / profiling
220
221 BEGIN_STAT(D_Display);
222
223 // [RH] change the screen mode if needed
224 if (setmodeneeded)
225 {
226 // Change screen mode.
227 if (!V_SetResolution (NewWidth, NewHeight, NewBits))
228 I_FatalError ("Could not change screen mode");
229
230 // Recalculate various view parameters.
231 setsizeneeded = true;
232 // Trick status bar into rethinking its position
233 st_scale.Callback ();
234 // Refresh the console.
235 C_NewModeAdjust ();
236 }
237
238 // [AM] Moved to below setmodeneeded so we have accurate screen size info.
239 if (gamestate == GS_LEVEL && viewactive && consoleplayer().camera)
240 {
241 if (consoleplayer().camera->player)
242 R_SetFOV(consoleplayer().camera->player->fov, setmodeneeded || setsizeneeded);
243 else
244 R_SetFOV(90.0f, setmodeneeded || setsizeneeded);
245 }
246
247 // change the view size if needed
248 if (setsizeneeded)
249 {
250 R_ExecuteSetViewSize ();
251 setmodeneeded = false;
252 }
253
254 I_BeginUpdate ();
255
256 // [RH] Allow temporarily disabling wipes
257 if (NoWipe)
258 {
259 NoWipe--;
260 wipegamestate = gamestate;
261 }
262 else if (gamestate != wipegamestate && gamestate != GS_FULLCONSOLE)
263 {
264 wipegamestate = gamestate;
265 Wipe_Start();
266 wiping_screen = true;
267 }
268
269 switch (gamestate)
270 {
271 case GS_FULLCONSOLE:
272 case GS_DOWNLOAD:
273 case GS_CONNECTING:
274 case GS_CONNECTED:
275 C_DrawConsole ();
276 M_Drawer ();
277 I_FinishUpdate ();
278 return;
279
280 case GS_LEVEL:
281 if (!gametic)
282 break;
283
284 // denis - freshen the borders (ffs..)
285 R_DrawViewBorder (); // erase old menu stuff
286
287 if (viewactive)
288 R_RenderPlayerView (&displayplayer());
289 if (automapactive)
290 AM_Drawer ();
291 C_DrawMid ();
292 C_DrawGMid();
293 CTF_DrawHud ();
294 ST_Drawer ();
295 HU_Drawer ();
296 V_DoPaletteEffects();
297 break;
298
299 case GS_INTERMISSION:
300 if (viewactive)
301 R_RenderPlayerView (&displayplayer());
302 C_DrawMid ();
303 CTF_DrawHud ();
304 WI_Drawer ();
305 HU_Drawer ();
306 break;
307
308 case GS_FINALE:
309 F_Drawer ();
310 break;
311
312 case GS_DEMOSCREEN:
313 D_PageDrawer ();
314 break;
315
316 default:
317 break;
318 }
319
320 // draw pause pic
321 if (paused && !menuactive)
322 {
323 patch_t *pause = W_CachePatch ("M_PAUSE");
324 int y;
325
326 y = (automapactive && !viewactive) ? 4 : viewwindowy + 4;
327 screen->DrawPatchCleanNoMove (pause, (screen->width-(pause->width())*CleanXfac)/2, y);
328 }
329
330 // [RH] Draw icon, if any
331 if (D_DrawIcon)
332 {
333 int lump = W_CheckNumForName (D_DrawIcon);
334
335 D_DrawIcon = NULL;
336 if (lump >= 0)
337 {
338 patch_t *p = W_CachePatch (lump);
339
340 screen->DrawPatchIndirect (p, 160-p->width()/2, 100-p->height()/2);
341 }
342 NoWipe = 10;
343 }
344
345 if (wiping_screen)
346 Wipe_Drawer();
347
348 C_DrawConsole(); // draw console
349 M_Drawer(); // menu is drawn even on top of everything
350 I_FinishUpdate(); // page flip or blit buffer
351
352 END_STAT(D_Display);
353 }
354
355 //
356 // D_DoomLoop
357 //
D_DoomLoop(void)358 void D_DoomLoop (void)
359 {
360 while (1)
361 {
362 try
363 {
364 D_RunTics(CL_RunTics, CL_DisplayTics);
365 }
366 catch (CRecoverableError &error)
367 {
368 Printf_Bold ("\n%s\n", error.GetMsg().c_str());
369
370 CL_QuitNetGame ();
371
372 G_ClearSnapshots ();
373
374 DThinker::DestroyAllThinkers();
375
376 players.clear();
377
378 gameaction = ga_fullconsole;
379 }
380 }
381 }
382
383 //
384 // D_PageTicker
385 // Handles timing for warped projection
386 //
D_PageTicker(void)387 void D_PageTicker (void)
388 {
389 if (--pagetic < 0)
390 D_AdvanceDemo ();
391 }
392
393 //
394 // D_PageDrawer
395 //
D_PageDrawer(void)396 void D_PageDrawer (void)
397 {
398 if (page)
399 {
400 page->Blit (0, 0, page->width, page->height,
401 screen, 0, 0, screen->width, screen->height);
402 }
403 else
404 {
405 screen->Clear (0, 0, screen->width, screen->height, 0);
406 //screen->PrintStr (0, 0, "Page graphic goes here", 22);
407 }
408 }
409
410 //
411 // D_AdvanceDemo
412 // Called after each demo or intro demosequence finishes
413 //
D_AdvanceDemo(void)414 void D_AdvanceDemo (void)
415 {
416 advancedemo = true;
417 }
418
419 //
420 // This cycles through the demo sequences.
421 //
D_DoAdvanceDemo(void)422 void D_DoAdvanceDemo (void)
423 {
424 const char *pagename = NULL;
425
426 consoleplayer().playerstate = PST_LIVE; // not reborn
427 advancedemo = false;
428 usergame = false; // no save / end game here
429 paused = false;
430 gameaction = ga_nothing;
431
432 // [Russell] - Old demo sequence used in original games, zdoom's
433 // dynamic one was too dynamic for its own good
434 // [Nes] - Newer demo sequence with better flow.
435 if (W_CheckNumForName("DEMO4") >= 0 && gamemode != retail_chex)
436 demosequence = (demosequence+1)%8;
437 else
438 demosequence = (demosequence+1)%6;
439
440 switch (demosequence)
441 {
442 case 0:
443 if (gameinfo.flags & GI_MAPxx)
444 pagetic = TICRATE * 11;
445 else
446 pagetic = 170;
447
448 gamestate = GS_DEMOSCREEN;
449 pagename = gameinfo.titlePage;
450
451 S_StartMusic(gameinfo.titleMusic);
452
453 break;
454 case 1:
455 G_DeferedPlayDemo("DEMO1");
456
457 break;
458 case 2:
459 pagetic = 200;
460 gamestate = GS_DEMOSCREEN;
461 pagename = gameinfo.creditPage1;
462
463 break;
464 case 3:
465 G_DeferedPlayDemo("DEMO2");
466
467 break;
468 case 4:
469 gamestate = GS_DEMOSCREEN;
470
471 if ((gameinfo.flags & GI_MAPxx) || (gameinfo.flags & GI_MENUHACK_RETAIL))
472 {
473 if (gameinfo.flags & GI_MAPxx)
474 pagetic = TICRATE * 11;
475 else
476 pagetic = 170;
477 pagename = gameinfo.titlePage;
478 S_StartMusic(gameinfo.titleMusic);
479 }
480 else
481 {
482 pagetic = 200;
483 if (gamemode == retail_chex) // [ML] Chex mode just cycles this screen
484 pagename = gameinfo.creditPage1;
485 else
486 pagename = gameinfo.creditPage2;
487 }
488
489 break;
490 case 5:
491 G_DeferedPlayDemo("DEMO3");
492
493 break;
494 case 6:
495 pagetic = 200;
496 gamestate = GS_DEMOSCREEN;
497 pagename = gameinfo.creditPage2;
498
499 break;
500 case 7:
501 G_DeferedPlayDemo("DEMO4");
502
503 break;
504 }
505
506 // [Russell] - Still need this toilet humor for now unfortunately
507 if (pagename)
508 {
509 const int width = 320, height = 200;
510 patch_t *data;
511
512 if (page && (page->width != screen->width || page->height != screen->height))
513 {
514 I_FreeScreen(page);
515 page = NULL;
516 }
517
518 data = W_CachePatch (pagename);
519
520 if (page == NULL)
521 {
522 if (screen->isProtectedRes())
523 page = I_AllocateScreen(data->width(), data->height(), 8);
524 else
525 page = I_AllocateScreen(screen->width, screen->height, 8);
526 }
527
528 page->Lock ();
529
530 if (gameinfo.flags & GI_PAGESARERAW)
531 page->DrawBlock (0, 0, width, height, (byte *)data);
532 else
533 page->DrawPatchFullScreen(data);
534
535 page->Unlock ();
536 }
537 }
538
539 //
540 // D_Close
541 //
D_Close(void)542 void STACK_ARGS D_Close (void)
543 {
544 if(page)
545 {
546 I_FreeScreen(page);
547 page = NULL;
548 }
549
550 D_ClearTaskSchedulers();
551 }
552
553 //
554 // D_StartTitle
555 //
D_StartTitle(void)556 void D_StartTitle (void)
557 {
558 // CL_QuitNetGame();
559 bool firstTime = true;
560 if(firstTime)
561 atterm (D_Close);
562
563 gameaction = ga_nothing;
564 demosequence = -1;
565 D_AdvanceDemo ();
566 }
567
HashOk(std::string & required,std::string & available)568 bool HashOk(std::string &required, std::string &available)
569 {
570 if(!required.length())
571 return false;
572
573 return required == available;
574 }
575
576 //
577 // D_NewWadInit
578 //
579 // Client code that should be reset every time a new set of WADs are loaded
580 //
D_NewWadInit()581 void D_NewWadInit()
582 {
583 AM_Stop();
584
585 HU_Init ();
586
587 if (!(InitPalettes("PLAYPAL")))
588 I_Error("Could not reinitialize palette");
589 V_InitPalette();
590
591 G_SetLevelStrings ();
592 G_ParseMapInfo ();
593 G_ParseMusInfo ();
594 S_ParseSndInfo();
595
596 M_Init();
597 R_Init();
598 P_InitEffects(); // [ML] Do this here so we don't have to put particle crap in server
599 P_Init();
600
601 S_Init (snd_sfxvolume, snd_musicvolume);
602 ST_Init();
603 }
604
605 void CL_NetDemoRecord(const std::string &filename);
606 void CL_NetDemoPlay(const std::string &filename);
607
608 //
609 // D_DoomMain
610 //
D_DoomMain(void)611 void D_DoomMain (void)
612 {
613 unsigned p;
614 extern std::string defdemoname;
615
616 M_ClearRandom();
617
618 gamestate = GS_STARTUP;
619 SetLanguageIDs ();
620 M_FindResponseFile(); // [ML] 23/1/07 - Add Response file support back in
621
622 if (lzo_init () != LZO_E_OK) // [RH] Initialize the minilzo package.
623 I_FatalError ("Could not initialize LZO routines");
624
625 C_ExecCmdLineParams (false, true); // [Nes] test for +logfile command
626
627 Printf (PRINT_HIGH, "Heapsize: %u megabytes\n", got_heapsize);
628
629 M_LoadDefaults (); // load before initing other systems
630 C_ExecCmdLineParams (true, false); // [RH] do all +set commands on the command line
631
632 const char* iwad = Args.CheckValue("-iwad");
633 if (!iwad)
634 iwad = "";
635
636 std::vector<std::string> newwadfiles, newpatchfiles;
637 newwadfiles.push_back(iwad);
638 D_AddWadCommandLineFiles(newwadfiles);
639 D_AddDehCommandLineFiles(newpatchfiles);
640
641 D_LoadResourceFiles(newwadfiles, newpatchfiles);
642
643 // [RH] Initialize configurable strings.
644 //D_InitStrings ();
645
646 // [RH] Moved these up here so that we can do most of our
647 // startup output in a fullscreen console.
648
649 HU_Init ();
650 I_Init ();
651 V_Init ();
652
653 // SDL needs video mode set up first before input code can be used
654 I_InitInput();
655
656 // Base systems have been inited; enable cvar callbacks
657 cvar_t::EnableCallbacks ();
658
659 // [RH] User-configurable startup strings. Because BOOM does.
660 if (GStrings(STARTUP1)[0]) Printf (PRINT_HIGH, "%s\n", GStrings(STARTUP1));
661 if (GStrings(STARTUP2)[0]) Printf (PRINT_HIGH, "%s\n", GStrings(STARTUP2));
662 if (GStrings(STARTUP3)[0]) Printf (PRINT_HIGH, "%s\n", GStrings(STARTUP3));
663 if (GStrings(STARTUP4)[0]) Printf (PRINT_HIGH, "%s\n", GStrings(STARTUP4));
664 if (GStrings(STARTUP5)[0]) Printf (PRINT_HIGH, "%s\n", GStrings(STARTUP5));
665
666 // Nomonsters
667 sv_nomonsters = Args.CheckParm("-nomonsters");
668
669 // Respawn
670 sv_monstersrespawn = Args.CheckParm("-respawn");
671
672 // Fast
673 sv_fastmonsters = Args.CheckParm("-fast");
674
675 // developer mode
676 devparm = Args.CheckParm ("-devparm");
677
678 // Record a vanilla demo
679 p = Args.CheckParm ("-record");
680 if (p)
681 {
682 autorecord = true;
683 autostart = true;
684 demorecordfile = Args.GetArg (p+1);
685 }
686
687 // get skill / episode / map from parms
688 strcpy (startmap, (gameinfo.flags & GI_MAPxx) ? "MAP01" : "E1M1");
689
690 // Check for -playdemo, play a single demo then quit.
691 p = Args.CheckParm ("-playdemo");
692 // Hack to check for +playdemo command, since if you just add it normally
693 // it won't run because it's attempting to run a demo and still set up the
694 // first map as normal.
695 if (!p)
696 p = Args.CheckParm ("+playdemo");
697 if (p && p < Args.NumArgs()-1)
698 {
699 Printf (PRINT_HIGH, "Playdemo parameter found on command line.\n");
700 singledemo = true;
701 defdemoname = Args.GetArg (p+1);
702 }
703
704 // [SL] check for -timedemo (was removed at some point)
705 p = Args.CheckParm("-timedemo");
706 if (p && p < Args.NumArgs() - 1)
707 {
708 singledemo = true;
709 G_TimeDemo(Args.GetArg(p + 1));
710 }
711
712 const char *val = Args.CheckValue ("-skill");
713 if (val)
714 {
715 sv_skill.Set (val[0]-'0');
716 }
717
718 p = Args.CheckParm ("-warp");
719 if (p && p < Args.NumArgs() - (1+(gameinfo.flags & GI_MAPxx ? 0 : 1)))
720 {
721 int ep, map;
722
723 if (gameinfo.flags & GI_MAPxx)
724 {
725 ep = 1;
726 map = atoi (Args.GetArg(p+1));
727 }
728 else
729 {
730 ep = Args.GetArg(p+1)[0]-'0';
731 map = Args.GetArg(p+2)[0]-'0';
732 }
733
734 strncpy (startmap, CalcMapName (ep, map), 8);
735 autostart = true;
736 }
737
738 // [RH] Hack to handle +map
739 p = Args.CheckParm ("+map");
740 if (p && p < Args.NumArgs()-1)
741 {
742 strncpy (startmap, Args.GetArg (p+1), 8);
743 ((char *)Args.GetArg (p))[0] = '-';
744 autostart = true;
745 }
746 if (devparm)
747 Printf (PRINT_HIGH, "%s", GStrings(D_DEVSTR)); // D_DEVSTR
748
749 // [RH] Now that all text strings are set up,
750 // insert them into the level and cluster data.
751 G_SetLevelStrings ();
752
753 // [RH] Parse through all loaded mapinfo lumps
754 G_ParseMapInfo ();
755
756 // [ML] Parse musinfo lump
757 G_ParseMusInfo ();
758
759 // [RH] Parse any SNDINFO lumps
760 S_ParseSndInfo();
761
762 // Check for -file in shareware
763 if (modifiedgame && (gameinfo.flags & GI_SHAREWARE))
764 I_Error ("You cannot -file with the shareware version. Register!");
765
766 #ifdef _WIN32
767 const char *sdlv = getenv("SDL_VIDEODRIVER");
768 Printf (PRINT_HIGH, "Using %s video driver.\n",sdlv);
769 #endif
770
771 Printf (PRINT_HIGH, "M_Init: Init miscellaneous info.\n");
772 M_Init ();
773
774 Printf (PRINT_HIGH, "R_Init: Init DOOM refresh daemon.\n");
775 R_Init ();
776
777 Printf (PRINT_HIGH, "P_Init: Init Playloop state.\n");
778 P_InitEffects(); // [ML] Do this here so we don't have to put particle crap in server
779 P_Init ();
780
781 // NOTE(jsd): Set up local player color
782 EXTERN_CVAR(cl_color);
783 R_BuildPlayerTranslation (0, V_GetColorFromString (NULL, cl_color.cstring()));
784
785 Printf (PRINT_HIGH, "S_Init: Setting up sound.\n");
786 Printf (PRINT_HIGH, "S_Init: default sfx volume is %g\n", (float)snd_sfxvolume);
787 Printf (PRINT_HIGH, "S_Init: default music volume is %g\n", (float)snd_musicvolume);
788 S_Init (snd_sfxvolume, snd_musicvolume);
789
790 I_FinishClockCalibration ();
791
792 Printf (PRINT_HIGH, "D_CheckNetGame: Checking network game status.\n");
793 D_CheckNetGame ();
794
795 Printf (PRINT_HIGH, "ST_Init: Init status bar.\n");
796 ST_Init ();
797
798 // [RH] Initialize items. Still only used for the give command. :-(
799 InitItems ();
800
801 // [RH] Lock any cvars that should be locked now that we're
802 // about to begin the game.
803 cvar_t::EnableNoSet ();
804
805 // [RH] Now that all game subsystems have been initialized,
806 // do all commands on the command line other than +set
807 C_ExecCmdLineParams (false, false);
808
809 Printf_Bold("\n\35\36\36\36\36 Odamex Client Initialized \36\36\36\36\37\n");
810 if(gamestate != GS_CONNECTING)
811 Printf(PRINT_HIGH, "Type connect <address> or use the Odamex Launcher to connect to a game.\n");
812 Printf(PRINT_HIGH, "\n");
813
814 setmodeneeded = false; // [Fly] we don't need to set a video mode here!
815 //gamestate = GS_FULLCONSOLE;
816
817 // [SL] allow the user to pass the name of a netdemo as the first argument.
818 // This allows easy launching of netdemos from Windows Explorer or other GUIs.
819
820 // [Xyltol]
821 if (Args.GetArg(1))
822 {
823 std::string demoarg = Args.GetArg(1);
824 if (demoarg.find(".odd") != std::string::npos)
825 CL_NetDemoPlay(demoarg);
826 }
827
828 p = Args.CheckParm("-netplay");
829 if (p)
830 {
831 if (Args.GetArg(p + 1))
832 {
833 std::string filename = Args.GetArg(p + 1);
834 CL_NetDemoPlay(filename);
835 }
836 else
837 {
838 Printf(PRINT_HIGH, "No netdemo filename specified.\n");
839 }
840 }
841
842 // denis - bring back the demos
843 if ( gameaction != ga_loadgame )
844 {
845 if (autostart || netgame || singledemo)
846 {
847 if (singledemo)
848 G_DoPlayDemo();
849 else
850 {
851 if(autostart)
852 {
853 // single player warp (like in g_level)
854 serverside = true;
855 sv_allowexit = "1";
856 sv_freelook = "1";
857 sv_allowjump = "1";
858 sv_allowredscreen = "1";
859 sv_gametype = GM_COOP;
860
861 players.clear();
862 players.push_back(player_t());
863 players.back().playerstate = PST_REBORN;
864 consoleplayer_id = displayplayer_id = players.back().id = 1;
865 }
866
867 G_InitNew (startmap);
868 if (autorecord)
869 G_RecordDemo(startmap, demorecordfile);
870 }
871 }
872 else
873 {
874 if (gamestate != GS_CONNECTING)
875 gamestate = GS_HIDECONSOLE;
876
877 C_HideConsole();
878
879 if (gamemode == commercial_bfg) // DOOM 2 BFG Edtion
880 AddCommandString("menu_main");
881
882 D_StartTitle (); // start up intro loop
883 }
884 }
885
886 // denis - this will run a demo and quit
887 p = Args.CheckParm ("+demotest");
888 if (p && p < Args.NumArgs()-1)
889 {
890 demotest = 1;
891 defdemoname = Args.GetArg (p+1);
892 G_DoPlayDemo();
893
894 while(demoplayback)
895 {
896 DObject::BeginFrame ();
897 G_Ticker();
898 DObject::EndFrame ();
899 gametic++;
900 }
901 }
902 else
903 {
904 demotest = 0;
905 D_DoomLoop (); // never returns
906 }
907 }
908
909 VERSION_CONTROL (d_main_cpp, "$Id: d_main.cpp 4542 2014-02-09 17:39:42Z dr_sean $")
910
911
912
913
914
915