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