Subversion Repositories Kolibri OS

Rev

Rev 8644 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
5131 clevermous 1
/*
2
Copyright (C) 1996-1997 Id Software, Inc.
3
 
4
This program is free software; you can redistribute it and/or
5
modify it under the terms of the GNU General Public License
6
as published by the Free Software Foundation; either version 2
7
of the License, or (at your option) any later version.
8
 
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
 
13
See the GNU General Public License for more details.
14
 
15
You should have received a copy of the GNU General Public License
16
along with this program; if not, write to the Free Software
17
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
 
19
*/
20
// host.c -- coordinates spawning and killing of local servers
21
 
22
#include "quakedef.h"
23
#include "r_local.h"
24
 
25
/*
26
 
27
A server can allways be started, even if the system started out as a client
28
to a remote system.
29
 
30
A client can NOT be started if the system started as a dedicated server.
31
 
32
Memory is cleared / released when a server or client begins, not when they end.
33
 
34
*/
35
 
36
quakeparms_t host_parms;
37
 
38
qboolean	host_initialized;		// true if into command execution
39
 
40
double		host_frametime;
41
double		host_time;
42
double		realtime;				// without any filtering or bounding
43
double		oldrealtime;			// last frame run
44
int			host_framecount;
45
 
46
int			host_hunklevel;
47
 
48
int			minimum_memory;
49
 
50
client_t	*host_client;			// current client
51
 
52
jmp_buf 	host_abortserver;
53
 
54
byte		*host_basepal;
55
byte		*host_colormap;
56
 
57
cvar_t	host_framerate = {"host_framerate","0"};	// set for slow motion
58
cvar_t	host_speeds = {"host_speeds","0"};			// set for running times
59
 
60
cvar_t	sys_ticrate = {"sys_ticrate","0.05"};
61
cvar_t	serverprofile = {"serverprofile","0"};
62
 
63
cvar_t	fraglimit = {"fraglimit","0",false,true};
64
cvar_t	timelimit = {"timelimit","0",false,true};
65
cvar_t	teamplay = {"teamplay","0",false,true};
66
 
67
cvar_t	samelevel = {"samelevel","0"};
68
cvar_t	noexit = {"noexit","0",false,true};
69
 
70
#ifdef QUAKE2
71
cvar_t	developer = {"developer","1"};	// should be 0 for release!
72
#else
73
cvar_t	developer = {"developer","0"};
74
#endif
75
 
76
cvar_t	skill = {"skill","1"};						// 0 - 3
77
cvar_t	deathmatch = {"deathmatch","0"};			// 0, 1, or 2
78
cvar_t	coop = {"coop","0"};			// 0 or 1
79
 
80
cvar_t	pausable = {"pausable","1"};
81
 
82
cvar_t	temp1 = {"temp1","0"};
83
 
84
 
85
/*
86
================
87
Host_EndGame
88
================
89
*/
90
void Host_EndGame (char *message, ...)
91
{
92
	va_list		argptr;
93
	char		string[1024];
94
 
95
	va_start (argptr,message);
96
	vsprintf (string,message,argptr);
97
	va_end (argptr);
98
	Con_DPrintf ("Host_EndGame: %s\n",string);
99
 
100
	if (sv.active)
101
		Host_ShutdownServer (false);
102
 
103
	if (cls.state == ca_dedicated)
104
		Sys_Error ("Host_EndGame: %s\n",string);	// dedicated servers exit
105
 
106
	if (cls.demonum != -1)
107
		CL_NextDemo ();
108
	else
109
		CL_Disconnect ();
110
 
111
	longjmp (host_abortserver, 1);
112
}
113
 
114
/*
115
================
116
Host_Error
117
 
118
This shuts down both the client and server
119
================
120
*/
121
void Host_Error (char *error, ...)
122
{
123
	va_list		argptr;
124
	char		string[1024];
125
	static	qboolean inerror = false;
126
 
127
	if (inerror)
128
		Sys_Error ("Host_Error: recursively entered");
129
	inerror = true;
130
 
131
	SCR_EndLoadingPlaque ();		// reenable screen updates
132
 
133
	va_start (argptr,error);
134
	vsprintf (string,error,argptr);
135
	va_end (argptr);
136
	Con_Printf ("Host_Error: %s\n",string);
137
 
138
	if (sv.active)
139
		Host_ShutdownServer (false);
140
 
141
	if (cls.state == ca_dedicated)
142
		Sys_Error ("Host_Error: %s\n",string);	// dedicated servers exit
143
 
144
	CL_Disconnect ();
145
	cls.demonum = -1;
146
 
147
	inerror = false;
148
 
149
	longjmp (host_abortserver, 1);
150
}
151
 
152
/*
153
================
154
Host_FindMaxClients
155
================
156
*/
157
void	Host_FindMaxClients (void)
158
{
159
	int		i;
160
 
161
	svs.maxclients = 1;
162
 
163
	i = COM_CheckParm ("-dedicated");
164
	if (i)
165
	{
166
		cls.state = ca_dedicated;
167
		if (i != (com_argc - 1))
168
		{
169
			svs.maxclients = Q_atoi (com_argv[i+1]);
170
		}
171
		else
172
			svs.maxclients = 8;
173
	}
174
	else
175
		cls.state = ca_disconnected;
176
 
177
	i = COM_CheckParm ("-listen");
178
	if (i)
179
	{
180
		if (cls.state == ca_dedicated)
181
			Sys_Error ("Only one of -dedicated or -listen can be specified");
182
		if (i != (com_argc - 1))
183
			svs.maxclients = Q_atoi (com_argv[i+1]);
184
		else
185
			svs.maxclients = 8;
186
	}
187
	if (svs.maxclients < 1)
188
		svs.maxclients = 8;
189
	else if (svs.maxclients > MAX_SCOREBOARD)
190
		svs.maxclients = MAX_SCOREBOARD;
191
 
192
	svs.maxclientslimit = svs.maxclients;
193
	if (svs.maxclientslimit < 4)
194
		svs.maxclientslimit = 4;
195
	svs.clients = Hunk_AllocName (svs.maxclientslimit*sizeof(client_t), "clients");
196
 
197
	if (svs.maxclients > 1)
198
		Cvar_SetValue ("deathmatch", 1.0);
199
	else
200
		Cvar_SetValue ("deathmatch", 0.0);
201
}
202
 
203
 
204
/*
205
=======================
206
Host_InitLocal
207
======================
208
*/
209
void Host_InitLocal (void)
210
{
211
	Host_InitCommands ();
212
 
213
	Cvar_RegisterVariable (&host_framerate);
214
	Cvar_RegisterVariable (&host_speeds);
215
 
216
	Cvar_RegisterVariable (&sys_ticrate);
217
	Cvar_RegisterVariable (&serverprofile);
218
 
219
	Cvar_RegisterVariable (&fraglimit);
220
	Cvar_RegisterVariable (&timelimit);
221
	Cvar_RegisterVariable (&teamplay);
222
	Cvar_RegisterVariable (&samelevel);
223
	Cvar_RegisterVariable (&noexit);
224
	Cvar_RegisterVariable (&skill);
225
	Cvar_RegisterVariable (&developer);
226
	Cvar_RegisterVariable (&deathmatch);
227
	Cvar_RegisterVariable (&coop);
228
 
229
	Cvar_RegisterVariable (&pausable);
230
 
231
	Cvar_RegisterVariable (&temp1);
232
 
233
	Host_FindMaxClients ();
234
 
235
	host_time = 1.0;		// so a think at time 0 won't get called
236
}
237
 
238
 
239
/*
240
===============
241
Host_WriteConfiguration
242
 
243
Writes key bindings and archived cvars to config.cfg
244
===============
245
*/
246
void Host_WriteConfiguration (void)
247
{
248
	FILE	*f;
249
 
250
// dedicated servers initialize the host but don't parse and set the
251
// config.cfg cvars
252
	if (host_initialized & !isDedicated)
253
	{
254
		f = fopen (va("%s/config.cfg",com_gamedir), "w");
255
		if (!f)
256
		{
257
			Con_Printf ("Couldn't write config.cfg.\n");
258
			return;
259
		}
260
 
261
		Key_WriteBindings (f);
262
		Cvar_WriteVariables (f);
263
 
264
		fclose (f);
265
	}
266
}
267
 
268
 
269
/*
270
=================
271
SV_ClientPrintf
272
 
273
Sends text across to be displayed
274
FIXME: make this just a stuffed echo?
275
=================
276
*/
277
void SV_ClientPrintf (char *fmt, ...)
278
{
279
	va_list		argptr;
280
	char		string[1024];
281
 
282
	va_start (argptr,fmt);
283
	vsprintf (string, fmt,argptr);
284
	va_end (argptr);
285
 
286
	MSG_WriteByte (&host_client->message, svc_print);
287
	MSG_WriteString (&host_client->message, string);
288
}
289
 
290
/*
291
=================
292
SV_BroadcastPrintf
293
 
294
Sends text to all active clients
295
=================
296
*/
297
void SV_BroadcastPrintf (char *fmt, ...)
298
{
299
	va_list		argptr;
300
	char		string[1024];
301
	int			i;
302
 
303
	va_start (argptr,fmt);
304
	vsprintf (string, fmt,argptr);
305
	va_end (argptr);
306
 
307
	for (i=0 ; i
308
		if (svs.clients[i].active && svs.clients[i].spawned)
309
		{
310
			MSG_WriteByte (&svs.clients[i].message, svc_print);
311
			MSG_WriteString (&svs.clients[i].message, string);
312
		}
313
}
314
 
315
/*
316
=================
317
Host_ClientCommands
318
 
319
Send text over to the client to be executed
320
=================
321
*/
322
void Host_ClientCommands (char *fmt, ...)
323
{
324
	va_list		argptr;
325
	char		string[1024];
326
 
327
	va_start (argptr,fmt);
328
	vsprintf (string, fmt,argptr);
329
	va_end (argptr);
330
 
331
	MSG_WriteByte (&host_client->message, svc_stufftext);
332
	MSG_WriteString (&host_client->message, string);
333
}
334
 
335
/*
336
=====================
337
SV_DropClient
338
 
339
Called when the player is getting totally kicked off the host
340
if (crash = true), don't bother sending signofs
341
=====================
342
*/
343
void SV_DropClient (qboolean crash)
344
{
345
	int		saveSelf;
346
	int		i;
347
	client_t *client;
348
 
349
	if (!crash)
350
	{
351
		// send any final messages (don't check for errors)
352
		if (NET_CanSendMessage (host_client->netconnection))
353
		{
354
			MSG_WriteByte (&host_client->message, svc_disconnect);
355
			NET_SendMessage (host_client->netconnection, &host_client->message);
356
		}
357
 
358
		if (host_client->edict && host_client->spawned)
359
		{
360
		// call the prog function for removing a client
361
		// this will set the body to a dead frame, among other things
362
			saveSelf = pr_global_struct->self;
363
			pr_global_struct->self = EDICT_TO_PROG(host_client->edict);
364
			PR_ExecuteProgram (pr_global_struct->ClientDisconnect);
365
			pr_global_struct->self = saveSelf;
366
		}
367
 
368
		Sys_Printf ("Client %s removed\n",host_client->name);
369
	}
370
 
371
// break the net connection
372
	NET_Close (host_client->netconnection);
373
	host_client->netconnection = NULL;
374
 
375
// free the client (the body stays around)
376
	host_client->active = false;
377
	host_client->name[0] = 0;
378
	host_client->old_frags = -999999;
379
	net_activeconnections--;
380
 
381
// send notification to all clients
382
	for (i=0, client = svs.clients ; i
383
	{
384
		if (!client->active)
385
			continue;
386
		MSG_WriteByte (&client->message, svc_updatename);
387
		MSG_WriteByte (&client->message, host_client - svs.clients);
388
		MSG_WriteString (&client->message, "");
389
		MSG_WriteByte (&client->message, svc_updatefrags);
390
		MSG_WriteByte (&client->message, host_client - svs.clients);
391
		MSG_WriteShort (&client->message, 0);
392
		MSG_WriteByte (&client->message, svc_updatecolors);
393
		MSG_WriteByte (&client->message, host_client - svs.clients);
394
		MSG_WriteByte (&client->message, 0);
395
	}
396
}
397
 
398
/*
399
==================
400
Host_ShutdownServer
401
 
402
This only happens at the end of a game, not between levels
403
==================
404
*/
405
void Host_ShutdownServer(qboolean crash)
406
{
407
	int		i;
408
	int		count;
409
	sizebuf_t	buf;
410
	char		message[4];
411
	double	start;
412
 
413
	if (!sv.active)
414
		return;
415
 
416
	sv.active = false;
417
 
418
// stop all client sounds immediately
419
	if (cls.state == ca_connected)
420
		CL_Disconnect ();
421
 
422
// flush any pending messages - like the score!!!
423
	start = Sys_FloatTime();
424
	do
425
	{
426
		count = 0;
427
		for (i=0, host_client = svs.clients ; i
428
		{
429
			if (host_client->active && host_client->message.cursize)
430
			{
431
				if (NET_CanSendMessage (host_client->netconnection))
432
				{
433
					NET_SendMessage(host_client->netconnection, &host_client->message);
434
					SZ_Clear (&host_client->message);
435
				}
436
				else
437
				{
438
					NET_GetMessage(host_client->netconnection);
439
					count++;
440
				}
441
			}
442
		}
443
		if ((Sys_FloatTime() - start) > 3.0)
444
			break;
445
	}
446
	while (count);
447
 
448
// make sure all the clients know we're disconnecting
449
	buf.data = message;
450
	buf.maxsize = 4;
451
	buf.cursize = 0;
452
	MSG_WriteByte(&buf, svc_disconnect);
453
	count = NET_SendToAll(&buf, 5);
454
	if (count)
455
		Con_Printf("Host_ShutdownServer: NET_SendToAll failed for %u clients\n", count);
456
 
457
	for (i=0, host_client = svs.clients ; i
458
		if (host_client->active)
459
			SV_DropClient(crash);
460
 
461
//
462
// clear structures
463
//
464
	memset (&sv, 0, sizeof(sv));
465
	memset (svs.clients, 0, svs.maxclientslimit*sizeof(client_t));
466
}
467
 
468
 
469
/*
470
================
471
Host_ClearMemory
472
 
473
This clears all the memory used by both the client and server, but does
474
not reinitialize anything.
475
================
476
*/
477
void Host_ClearMemory (void)
478
{
479
	Con_DPrintf ("Clearing memory\n");
480
	D_FlushCaches ();
481
	Mod_ClearAll ();
482
	if (host_hunklevel)
483
		Hunk_FreeToLowMark (host_hunklevel);
484
 
485
	cls.signon = 0;
486
	memset (&sv, 0, sizeof(sv));
487
	memset (&cl, 0, sizeof(cl));
488
}
489
 
490
 
491
//============================================================================
492
 
493
 
494
/*
495
===================
496
Host_FilterTime
497
 
498
Returns false if the time is too short to run a frame
499
===================
500
*/
501
qboolean Host_FilterTime (float time)
502
{
503
	realtime += time;
504
 
505
	if (!cls.timedemo && realtime - oldrealtime < 1.0/72.0)
506
		return false;		// framerate is too high
507
 
508
	host_frametime = realtime - oldrealtime;
509
	oldrealtime = realtime;
510
 
511
	if (host_framerate.value > 0)
512
		host_frametime = host_framerate.value;
513
	else
514
	{	// don't allow really long or short frames
515
		if (host_frametime > 0.1)
516
			host_frametime = 0.1;
517
		if (host_frametime < 0.001)
518
			host_frametime = 0.001;
519
	}
520
 
521
	return true;
522
}
523
 
524
 
525
/*
526
===================
527
Host_GetConsoleCommands
528
 
529
Add them exactly as if they had been typed at the console
530
===================
531
*/
532
void Host_GetConsoleCommands (void)
533
{
534
	char	*cmd;
535
 
536
	while (1)
537
	{
538
		cmd = Sys_ConsoleInput ();
539
		if (!cmd)
540
			break;
541
		Cbuf_AddText (cmd);
542
	}
543
}
544
 
545
 
546
/*
547
==================
548
Host_ServerFrame
549
 
550
==================
551
*/
552
#ifdef FPS_20
553
 
554
void _Host_ServerFrame (void)
555
{
556
// run the world state
557
	pr_global_struct->frametime = host_frametime;
558
 
559
// read client messages
560
	SV_RunClients ();
561
 
562
// move things around and think
563
// always pause in single player if in console or menus
564
	if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) )
565
		SV_Physics ();
566
}
567
 
568
void Host_ServerFrame (void)
569
{
570
	float	save_host_frametime;
571
	float	temp_host_frametime;
572
 
573
// run the world state
574
	pr_global_struct->frametime = host_frametime;
575
 
576
// set the time and clear the general datagram
577
	SV_ClearDatagram ();
578
 
579
// check for new clients
580
	SV_CheckForNewClients ();
581
 
582
	temp_host_frametime = save_host_frametime = host_frametime;
583
	while(temp_host_frametime > (1.0/72.0))
584
	{
585
		if (temp_host_frametime > 0.05)
586
			host_frametime = 0.05;
587
		else
588
			host_frametime = temp_host_frametime;
589
		temp_host_frametime -= host_frametime;
590
		_Host_ServerFrame ();
591
	}
592
	host_frametime = save_host_frametime;
593
 
594
// send all messages to the clients
595
	SV_SendClientMessages ();
596
}
597
 
598
#else
599
 
600
void Host_ServerFrame (void)
601
{
602
// run the world state
603
	pr_global_struct->frametime = host_frametime;
604
 
605
// set the time and clear the general datagram
606
	SV_ClearDatagram ();
607
 
608
// check for new clients
609
	SV_CheckForNewClients ();
610
 
611
// read client messages
612
	SV_RunClients ();
613
 
614
// move things around and think
615
// always pause in single player if in console or menus
616
	if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) )
617
		SV_Physics ();
618
 
619
// send all messages to the clients
620
	SV_SendClientMessages ();
621
}
622
 
623
#endif
624
 
625
 
626
/*
627
==================
628
Host_Frame
629
 
630
Runs all active servers
631
==================
632
*/
633
void _Host_Frame (float time)
634
{
635
	static double		time1 = 0;
636
	static double		time2 = 0;
637
	static double		time3 = 0;
638
	int			pass1, pass2, pass3;
639
 
640
	if (setjmp (host_abortserver) )
641
		return;			// something bad happened, or the server disconnected
642
 
643
// keep the random time dependent
644
	rand ();
645
 
646
// decide the simulation time
647
	if (!Host_FilterTime (time))
648
		return;			// don't run too fast, or packets will flood out
649
 
650
// get new key events
651
	Sys_SendKeyEvents ();
652
 
653
// allow mice or other external controllers to add commands
654
	IN_Commands ();
655
 
656
// process console commands
657
	Cbuf_Execute ();
658
 
659
	NET_Poll();
660
 
661
// if running the server locally, make intentions now
662
	if (sv.active)
663
		CL_SendCmd ();
664
 
665
//-------------------
666
//
667
// server operations
668
//
669
//-------------------
670
 
671
// check for commands typed to the host
672
	Host_GetConsoleCommands ();
673
 
674
	if (sv.active)
675
		Host_ServerFrame ();
676
 
677
//-------------------
678
//
679
// client operations
680
//
681
//-------------------
682
 
683
// if running the server remotely, send intentions now after
684
// the incoming messages have been read
685
	if (!sv.active)
686
		CL_SendCmd ();
687
 
688
	host_time += host_frametime;
689
 
690
// fetch results from server
691
	if (cls.state == ca_connected)
692
	{
693
		CL_ReadFromServer ();
694
	}
695
 
696
// update video
697
	if (host_speeds.value)
698
		time1 = Sys_FloatTime ();
699
 
700
	SCR_UpdateScreen ();
701
 
702
	if (host_speeds.value)
703
		time2 = Sys_FloatTime ();
704
 
705
// update audio
706
	if (cls.signon == SIGNONS)
707
	{
708
		S_Update (r_origin, vpn, vright, vup);
709
		CL_DecayLights ();
710
	}
711
	else
712
		S_Update (vec3_origin, vec3_origin, vec3_origin, vec3_origin);
713
 
714
	CDAudio_Update();
715
 
716
	if (host_speeds.value)
717
	{
718
		pass1 = (time1 - time3)*1000;
719
		time3 = Sys_FloatTime ();
720
		pass2 = (time2 - time1)*1000;
721
		pass3 = (time3 - time2)*1000;
722
		Con_Printf ("%3i tot %3i server %3i gfx %3i snd\n",
723
					pass1+pass2+pass3, pass1, pass2, pass3);
724
	}
725
 
726
	host_framecount++;
727
}
728
 
729
void Host_Frame (float time)
730
{
731
	double	time1, time2;
732
	static double	timetotal;
733
	static int		timecount;
734
	int		i, c, m;
735
 
736
	if (!serverprofile.value)
737
	{
738
		_Host_Frame (time);
739
		return;
740
	}
741
 
742
	time1 = Sys_FloatTime ();
743
	_Host_Frame (time);
744
	time2 = Sys_FloatTime ();
745
 
746
	timetotal += time2 - time1;
747
	timecount++;
748
 
749
	if (timecount < 1000)
750
		return;
751
 
752
	m = timetotal*1000/timecount;
753
	timecount = 0;
754
	timetotal = 0;
755
	c = 0;
756
	for (i=0 ; i
757
	{
758
		if (svs.clients[i].active)
759
			c++;
760
	}
761
 
762
	Con_Printf ("serverprofile: %2i clients %2i msec\n",  c,  m);
763
}
764
 
765
//============================================================================
766
 
767
 
768
extern int vcrFile;
769
#define	VCR_SIGNATURE	0x56435231
770
// "VCR1"
771
 
772
void Host_InitVCR (quakeparms_t *parms)
773
{
774
	int		i, len, n;
775
	char	*p;
776
 
777
	if (COM_CheckParm("-playback"))
778
	{
779
		if (com_argc != 2)
780
			Sys_Error("No other parameters allowed with -playback\n");
781
 
782
		Sys_FileOpenRead("quake.vcr", &vcrFile);
783
		if (vcrFile == -1)
784
			Sys_Error("playback file not found\n");
785
 
786
		Sys_FileRead (vcrFile, &i, sizeof(int));
787
		if (i != VCR_SIGNATURE)
788
			Sys_Error("Invalid signature in vcr file\n");
789
 
790
		Sys_FileRead (vcrFile, &com_argc, sizeof(int));
791
		com_argv = malloc(com_argc * sizeof(char *));
792
		com_argv[0] = parms->argv[0];
793
		for (i = 0; i < com_argc; i++)
794
		{
795
			Sys_FileRead (vcrFile, &len, sizeof(int));
796
			p = malloc(len);
797
			Sys_FileRead (vcrFile, p, len);
798
			com_argv[i+1] = p;
799
		}
800
		com_argc++; /* add one for arg[0] */
801
		parms->argc = com_argc;
802
		parms->argv = com_argv;
803
	}
804
 
805
	if ( (n = COM_CheckParm("-record")) != 0)
806
	{
807
		vcrFile = Sys_FileOpenWrite("quake.vcr");
808
 
809
		i = VCR_SIGNATURE;
810
		Sys_FileWrite(vcrFile, &i, sizeof(int));
811
		i = com_argc - 1;
812
		Sys_FileWrite(vcrFile, &i, sizeof(int));
813
		for (i = 1; i < com_argc; i++)
814
		{
815
			if (i == n)
816
			{
817
				len = 10;
818
				Sys_FileWrite(vcrFile, &len, sizeof(int));
819
				Sys_FileWrite(vcrFile, "-playback", len);
820
				continue;
821
			}
822
			len = Q_strlen(com_argv[i]) + 1;
823
			Sys_FileWrite(vcrFile, &len, sizeof(int));
824
			Sys_FileWrite(vcrFile, com_argv[i], len);
825
		}
826
	}
827
 
828
}
829
 
830
/*
831
====================
832
Host_Init
833
====================
834
*/
835
void Host_Init (quakeparms_t *parms)
836
{
837
	if (standard_quake)
838
		minimum_memory = MINIMUM_MEMORY;
839
	else
840
		minimum_memory = MINIMUM_MEMORY_LEVELPAK;
841
 
842
	if (COM_CheckParm ("-minmemory"))
843
		parms->memsize = minimum_memory;
844
 
845
	host_parms = *parms;
846
 
847
	if (parms->memsize < minimum_memory)
848
		Sys_Error ("Only %4.1f megs of memory available, can't execute game", parms->memsize / (float)0x100000);
849
 
850
	com_argc = parms->argc;
851
	com_argv = parms->argv;
852
 
853
	Memory_Init (parms->membase, parms->memsize);
854
	Cbuf_Init ();
855
	Cmd_Init ();
856
	V_Init ();
857
	Chase_Init ();
858
	Host_InitVCR (parms);
859
	COM_Init (parms->basedir);
860
	Host_InitLocal ();
861
	W_LoadWadFile ("gfx.wad");
862
	Key_Init ();
863
	Con_Init ();
864
	M_Init ();
865
	PR_Init ();
866
	Mod_Init ();
867
	NET_Init ();
868
	SV_Init ();
869
 
870
	Con_Printf ("Exe: "__TIME__" "__DATE__"\n");
871
	Con_Printf ("%4.1f megabyte heap\n",parms->memsize/ (1024*1024.0));
872
 
873
	R_InitTextures ();		// needed even for dedicated servers
874
 
875
	if (cls.state != ca_dedicated)
876
	{
877
		host_basepal = (byte *)COM_LoadHunkFile ("gfx/palette.lmp");
878
		if (!host_basepal)
879
			Sys_Error ("Couldn't load gfx/palette.lmp");
880
		host_colormap = (byte *)COM_LoadHunkFile ("gfx/colormap.lmp");
881
		if (!host_colormap)
882
			Sys_Error ("Couldn't load gfx/colormap.lmp");
883
 
884
#ifndef _WIN32 // on non win32, mouse comes before video for security reasons
885
		IN_Init ();
886
#endif
887
		VID_Init (host_basepal);
888
 
889
		Draw_Init ();
890
		SCR_Init ();
891
		R_Init ();
892
#ifndef	_WIN32
893
	// on Win32, sound initialization has to come before video initialization, so we
894
	// can put up a popup if the sound hardware is in use
895
		S_Init ();
896
#else
897
 
898
#ifdef	GLQUAKE
899
	// FIXME: doesn't use the new one-window approach yet
900
		S_Init ();
901
#endif
902
 
903
#endif	// _WIN32
904
		CDAudio_Init ();
905
		Sbar_Init ();
906
		CL_Init ();
907
#ifdef _WIN32 // on non win32, mouse comes before video for security reasons
908
		IN_Init ();
909
#endif
910
	}
911
 
912
	Cbuf_InsertText ("exec quake.rc\n");
913
 
914
	Hunk_AllocName (0, "-HOST_HUNKLEVEL-");
915
	host_hunklevel = Hunk_LowMark ();
916
 
917
	host_initialized = true;
918
 
919
	Sys_Printf ("========Quake Initialized=========\n");
920
}
921
 
922
 
923
/*
924
===============
925
Host_Shutdown
926
 
927
FIXME: this is a callback from Sys_Quit and Sys_Error.  It would be better
928
to run quit through here before the final handoff to the sys code.
929
===============
930
*/
931
void Host_Shutdown(void)
932
{
933
	static qboolean isdown = false;
934
 
935
	if (isdown)
936
	{
937
		printf ("recursive shutdown\n");
938
		return;
939
	}
940
	isdown = true;
941
 
942
// keep Con_Printf from trying to update the screen
943
	scr_disabled_for_loading = true;
944
 
945
	Host_WriteConfiguration ();
946
 
947
	CDAudio_Shutdown ();
948
	NET_Shutdown ();
949
	S_Shutdown();
950
	IN_Shutdown ();
951
 
952
	if (cls.state != ca_dedicated)
953
	{
954
		VID_Shutdown();
955
	}
956
}
957