Subversion Repositories Kolibri OS

Rev

Details | 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
// cl_main.c  -- client main loop
21
 
22
#include "quakedef.h"
23
 
24
// we need to declare some mouse variables here, because the menu system
25
// references them even when on a unix system.
26
 
27
// these two are not intended to be set directly
28
cvar_t	cl_name = {"_cl_name", "player", true};
29
cvar_t	cl_color = {"_cl_color", "0", true};
30
 
31
cvar_t	cl_shownet = {"cl_shownet","0"};	// can be 0, 1, or 2
32
cvar_t	cl_nolerp = {"cl_nolerp","0"};
33
 
34
cvar_t	lookspring = {"lookspring","0", true};
35
cvar_t	lookstrafe = {"lookstrafe","0", true};
36
cvar_t	sensitivity = {"sensitivity","3", true};
37
 
38
cvar_t	m_pitch = {"m_pitch","0.022", true};
39
cvar_t	m_yaw = {"m_yaw","0.022", true};
40
cvar_t	m_forward = {"m_forward","1", true};
41
cvar_t	m_side = {"m_side","0.8", true};
42
 
43
 
44
client_static_t	cls;
45
client_state_t	cl;
46
// FIXME: put these on hunk?
47
efrag_t			cl_efrags[MAX_EFRAGS];
48
entity_t		cl_entities[MAX_EDICTS];
49
entity_t		cl_static_entities[MAX_STATIC_ENTITIES];
50
lightstyle_t	cl_lightstyle[MAX_LIGHTSTYLES];
51
dlight_t		cl_dlights[MAX_DLIGHTS];
52
 
53
int				cl_numvisedicts;
54
entity_t		*cl_visedicts[MAX_VISEDICTS];
55
 
56
/*
57
=====================
58
CL_ClearState
59
 
60
=====================
61
*/
62
void CL_ClearState (void)
63
{
64
	int			i;
65
 
66
	if (!sv.active)
67
		Host_ClearMemory ();
68
 
69
// wipe the entire cl structure
70
	memset (&cl, 0, sizeof(cl));
71
 
72
	SZ_Clear (&cls.message);
73
 
74
// clear other arrays
75
	memset (cl_efrags, 0, sizeof(cl_efrags));
76
	memset (cl_entities, 0, sizeof(cl_entities));
77
	memset (cl_dlights, 0, sizeof(cl_dlights));
78
	memset (cl_lightstyle, 0, sizeof(cl_lightstyle));
79
	memset (cl_temp_entities, 0, sizeof(cl_temp_entities));
80
	memset (cl_beams, 0, sizeof(cl_beams));
81
 
82
//
83
// allocate the efrags and chain together into a free list
84
//
85
	cl.free_efrags = cl_efrags;
86
	for (i=0 ; i
87
		cl.free_efrags[i].entnext = &cl.free_efrags[i+1];
88
	cl.free_efrags[i].entnext = NULL;
89
}
90
 
91
/*
92
=====================
93
CL_Disconnect
94
 
95
Sends a disconnect message to the server
96
This is also called on Host_Error, so it shouldn't cause any errors
97
=====================
98
*/
99
void CL_Disconnect (void)
100
{
101
// stop sounds (especially looping!)
102
	S_StopAllSounds (true);
103
 
104
// bring the console down and fade the colors back to normal
105
//	SCR_BringDownConsole ();
106
 
107
// if running a local server, shut it down
108
	if (cls.demoplayback)
109
		CL_StopPlayback ();
110
	else if (cls.state == ca_connected)
111
	{
112
		if (cls.demorecording)
113
			CL_Stop_f ();
114
 
115
		Con_DPrintf ("Sending clc_disconnect\n");
116
		SZ_Clear (&cls.message);
117
		MSG_WriteByte (&cls.message, clc_disconnect);
118
		NET_SendUnreliableMessage (cls.netcon, &cls.message);
119
		SZ_Clear (&cls.message);
120
		NET_Close (cls.netcon);
121
 
122
		cls.state = ca_disconnected;
123
		if (sv.active)
124
			Host_ShutdownServer(false);
125
	}
126
 
127
	cls.demoplayback = cls.timedemo = false;
128
	cls.signon = 0;
129
}
130
 
131
void CL_Disconnect_f (void)
132
{
133
	CL_Disconnect ();
134
	if (sv.active)
135
		Host_ShutdownServer (false);
136
}
137
 
138
 
139
 
140
 
141
/*
142
=====================
143
CL_EstablishConnection
144
 
145
Host should be either "local" or a net address to be passed on
146
=====================
147
*/
148
void CL_EstablishConnection (char *host)
149
{
150
	if (cls.state == ca_dedicated)
151
		return;
152
 
153
	if (cls.demoplayback)
154
		return;
155
 
156
	CL_Disconnect ();
157
 
158
	cls.netcon = NET_Connect (host);
159
	if (!cls.netcon)
160
		Host_Error ("CL_Connect: connect failed\n");
161
	Con_DPrintf ("CL_EstablishConnection: connected to %s\n", host);
162
 
163
	cls.demonum = -1;			// not in the demo loop now
164
	cls.state = ca_connected;
165
	cls.signon = 0;				// need all the signon messages before playing
166
}
167
 
168
/*
169
=====================
170
CL_SignonReply
171
 
172
An svc_signonnum has been received, perform a client side setup
173
=====================
174
*/
175
void CL_SignonReply (void)
176
{
177
	char 	str[8192];
178
 
179
Con_DPrintf ("CL_SignonReply: %i\n", cls.signon);
180
 
181
	switch (cls.signon)
182
	{
183
	case 1:
184
		MSG_WriteByte (&cls.message, clc_stringcmd);
185
		MSG_WriteString (&cls.message, "prespawn");
186
		break;
187
 
188
	case 2:
189
		MSG_WriteByte (&cls.message, clc_stringcmd);
190
		MSG_WriteString (&cls.message, va("name \"%s\"\n", cl_name.string));
191
 
192
		MSG_WriteByte (&cls.message, clc_stringcmd);
193
		MSG_WriteString (&cls.message, va("color %i %i\n", ((int)cl_color.value)>>4, ((int)cl_color.value)&15));
194
 
195
		MSG_WriteByte (&cls.message, clc_stringcmd);
196
		sprintf (str, "spawn %s", cls.spawnparms);
197
		MSG_WriteString (&cls.message, str);
198
		break;
199
 
200
	case 3:
201
		MSG_WriteByte (&cls.message, clc_stringcmd);
202
		MSG_WriteString (&cls.message, "begin");
203
		Cache_Report ();		// print remaining memory
204
		break;
205
 
206
	case 4:
207
		SCR_EndLoadingPlaque ();		// allow normal screen updates
208
		break;
209
	}
210
}
211
 
212
/*
213
=====================
214
CL_NextDemo
215
 
216
Called to play the next demo in the demo loop
217
=====================
218
*/
219
void CL_NextDemo (void)
220
{
221
	char	str[1024];
222
 
223
	if (cls.demonum == -1)
224
		return;		// don't play demos
225
 
226
	SCR_BeginLoadingPlaque ();
227
 
228
	if (!cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS)
229
	{
230
		cls.demonum = 0;
231
		if (!cls.demos[cls.demonum][0])
232
		{
233
			Con_Printf ("No demos listed with startdemos\n");
234
			cls.demonum = -1;
235
			return;
236
		}
237
	}
238
 
239
	sprintf (str,"playdemo %s\n", cls.demos[cls.demonum]);
240
	Cbuf_InsertText (str);
241
	cls.demonum++;
242
}
243
 
244
/*
245
==============
246
CL_PrintEntities_f
247
==============
248
*/
249
void CL_PrintEntities_f (void)
250
{
251
	entity_t	*ent;
252
	int			i;
253
 
254
	for (i=0,ent=cl_entities ; i
255
	{
256
		Con_Printf ("%3i:",i);
257
		if (!ent->model)
258
		{
259
			Con_Printf ("EMPTY\n");
260
			continue;
261
		}
262
		Con_Printf ("%s:%2i  (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n"
263
		,ent->model->name,ent->frame, ent->origin[0], ent->origin[1], ent->origin[2], ent->angles[0], ent->angles[1], ent->angles[2]);
264
	}
265
}
266
 
267
 
268
/*
269
===============
270
SetPal
271
 
272
Debugging tool, just flashes the screen
273
===============
274
*/
275
void SetPal (int i)
276
{
277
#if 0
278
	static int old;
279
	byte	pal[768];
280
	int		c;
281
 
282
	if (i == old)
283
		return;
284
	old = i;
285
 
286
	if (i==0)
287
		VID_SetPalette (host_basepal);
288
	else if (i==1)
289
	{
290
		for (c=0 ; c<768 ; c+=3)
291
		{
292
			pal[c] = 0;
293
			pal[c+1] = 255;
294
			pal[c+2] = 0;
295
		}
296
		VID_SetPalette (pal);
297
	}
298
	else
299
	{
300
		for (c=0 ; c<768 ; c+=3)
301
		{
302
			pal[c] = 0;
303
			pal[c+1] = 0;
304
			pal[c+2] = 255;
305
		}
306
		VID_SetPalette (pal);
307
	}
308
#endif
309
}
310
 
311
/*
312
===============
313
CL_AllocDlight
314
 
315
===============
316
*/
317
dlight_t *CL_AllocDlight (int key)
318
{
319
	int		i;
320
	dlight_t	*dl;
321
 
322
// first look for an exact key match
323
	if (key)
324
	{
325
		dl = cl_dlights;
326
		for (i=0 ; i
327
		{
328
			if (dl->key == key)
329
			{
330
				memset (dl, 0, sizeof(*dl));
331
				dl->key = key;
332
				return dl;
333
			}
334
		}
335
	}
336
 
337
// then look for anything else
338
	dl = cl_dlights;
339
	for (i=0 ; i
340
	{
341
		if (dl->die < cl.time)
342
		{
343
			memset (dl, 0, sizeof(*dl));
344
			dl->key = key;
345
			return dl;
346
		}
347
	}
348
 
349
	dl = &cl_dlights[0];
350
	memset (dl, 0, sizeof(*dl));
351
	dl->key = key;
352
	return dl;
353
}
354
 
355
 
356
/*
357
===============
358
CL_DecayLights
359
 
360
===============
361
*/
362
void CL_DecayLights (void)
363
{
364
	int			i;
365
	dlight_t	*dl;
366
	float		time;
367
 
368
	time = cl.time - cl.oldtime;
369
 
370
	dl = cl_dlights;
371
	for (i=0 ; i
372
	{
373
		if (dl->die < cl.time || !dl->radius)
374
			continue;
375
 
376
		dl->radius -= time*dl->decay;
377
		if (dl->radius < 0)
378
			dl->radius = 0;
379
	}
380
}
381
 
382
 
383
/*
384
===============
385
CL_LerpPoint
386
 
387
Determines the fraction between the last two messages that the objects
388
should be put at.
389
===============
390
*/
391
float	CL_LerpPoint (void)
392
{
393
	float	f, frac;
394
 
395
	f = cl.mtime[0] - cl.mtime[1];
396
 
397
	if (!f || cl_nolerp.value || cls.timedemo || sv.active)
398
	{
399
		cl.time = cl.mtime[0];
400
		return 1;
401
	}
402
 
403
	if (f > 0.1)
404
	{	// dropped packet, or start of demo
405
		cl.mtime[1] = cl.mtime[0] - 0.1;
406
		f = 0.1;
407
	}
408
	frac = (cl.time - cl.mtime[1]) / f;
409
//Con_Printf ("frac: %f\n",frac);
410
	if (frac < 0)
411
	{
412
		if (frac < -0.01)
413
		{
414
SetPal(1);
415
			cl.time = cl.mtime[1];
416
//				Con_Printf ("low frac\n");
417
		}
418
		frac = 0;
419
	}
420
	else if (frac > 1)
421
	{
422
		if (frac > 1.01)
423
		{
424
SetPal(2);
425
			cl.time = cl.mtime[0];
426
//				Con_Printf ("high frac\n");
427
		}
428
		frac = 1;
429
	}
430
	else
431
		SetPal(0);
432
 
433
	return frac;
434
}
435
 
436
 
437
/*
438
===============
439
CL_RelinkEntities
440
===============
441
*/
442
void CL_RelinkEntities (void)
443
{
444
	entity_t	*ent;
445
	int			i, j;
446
	float		frac, f, d;
447
	vec3_t		delta;
448
	float		bobjrotate;
449
	vec3_t		oldorg;
450
	dlight_t	*dl;
451
 
452
// determine partial update time
453
	frac = CL_LerpPoint ();
454
 
455
	cl_numvisedicts = 0;
456
 
457
//
458
// interpolate player info
459
//
460
	for (i=0 ; i<3 ; i++)
461
		cl.velocity[i] = cl.mvelocity[1][i] +
462
			frac * (cl.mvelocity[0][i] - cl.mvelocity[1][i]);
463
 
464
	if (cls.demoplayback)
465
	{
466
	// interpolate the angles
467
		for (j=0 ; j<3 ; j++)
468
		{
469
			d = cl.mviewangles[0][j] - cl.mviewangles[1][j];
470
			if (d > 180)
471
				d -= 360;
472
			else if (d < -180)
473
				d += 360;
474
			cl.viewangles[j] = cl.mviewangles[1][j] + frac*d;
475
		}
476
	}
477
 
478
	bobjrotate = anglemod(100*cl.time);
479
 
480
// start on the entity after the world
481
	for (i=1,ent=cl_entities+1 ; i
482
	{
483
		if (!ent->model)
484
		{	// empty slot
485
			if (ent->forcelink)
486
				R_RemoveEfrags (ent);	// just became empty
487
			continue;
488
		}
489
 
490
// if the object wasn't included in the last packet, remove it
491
		if (ent->msgtime != cl.mtime[0])
492
		{
493
			ent->model = NULL;
494
			continue;
495
		}
496
 
497
		VectorCopy (ent->origin, oldorg);
498
 
499
		if (ent->forcelink)
500
		{	// the entity was not updated in the last message
501
			// so move to the final spot
502
			VectorCopy (ent->msg_origins[0], ent->origin);
503
			VectorCopy (ent->msg_angles[0], ent->angles);
504
		}
505
		else
506
		{	// if the delta is large, assume a teleport and don't lerp
507
			f = frac;
508
			for (j=0 ; j<3 ; j++)
509
			{
510
				delta[j] = ent->msg_origins[0][j] - ent->msg_origins[1][j];
511
				if (delta[j] > 100 || delta[j] < -100)
512
					f = 1;		// assume a teleportation, not a motion
513
			}
514
 
515
		// interpolate the origin and angles
516
			for (j=0 ; j<3 ; j++)
517
			{
518
				ent->origin[j] = ent->msg_origins[1][j] + f*delta[j];
519
 
520
				d = ent->msg_angles[0][j] - ent->msg_angles[1][j];
521
				if (d > 180)
522
					d -= 360;
523
				else if (d < -180)
524
					d += 360;
525
				ent->angles[j] = ent->msg_angles[1][j] + f*d;
526
			}
527
 
528
		}
529
 
530
// rotate binary objects locally
531
		if (ent->model->flags & EF_ROTATE)
532
			ent->angles[1] = bobjrotate;
533
 
534
		if (ent->effects & EF_BRIGHTFIELD)
535
			R_EntityParticles (ent);
536
#ifdef QUAKE2
537
		if (ent->effects & EF_DARKFIELD)
538
			R_DarkFieldParticles (ent);
539
#endif
540
		if (ent->effects & EF_MUZZLEFLASH)
541
		{
542
			vec3_t		fv, rv, uv;
543
 
544
			dl = CL_AllocDlight (i);
545
			VectorCopy (ent->origin,  dl->origin);
546
			dl->origin[2] += 16;
547
			AngleVectors (ent->angles, fv, rv, uv);
548
 
549
			VectorMA (dl->origin, 18, fv, dl->origin);
550
			dl->radius = 200 + (rand()&31);
551
			dl->minlight = 32;
552
			dl->die = cl.time + 0.1;
553
		}
554
		if (ent->effects & EF_BRIGHTLIGHT)
555
		{
556
			dl = CL_AllocDlight (i);
557
			VectorCopy (ent->origin,  dl->origin);
558
			dl->origin[2] += 16;
559
			dl->radius = 400 + (rand()&31);
560
			dl->die = cl.time + 0.001;
561
		}
562
		if (ent->effects & EF_DIMLIGHT)
563
		{
564
			dl = CL_AllocDlight (i);
565
			VectorCopy (ent->origin,  dl->origin);
566
			dl->radius = 200 + (rand()&31);
567
			dl->die = cl.time + 0.001;
568
		}
569
#ifdef QUAKE2
570
		if (ent->effects & EF_DARKLIGHT)
571
		{
572
			dl = CL_AllocDlight (i);
573
			VectorCopy (ent->origin,  dl->origin);
574
			dl->radius = 200.0 + (rand()&31);
575
			dl->die = cl.time + 0.001;
576
			dl->dark = true;
577
		}
578
		if (ent->effects & EF_LIGHT)
579
		{
580
			dl = CL_AllocDlight (i);
581
			VectorCopy (ent->origin,  dl->origin);
582
			dl->radius = 200;
583
			dl->die = cl.time + 0.001;
584
		}
585
#endif
586
 
587
		if (ent->model->flags & EF_GIB)
588
			R_RocketTrail (oldorg, ent->origin, 2);
589
		else if (ent->model->flags & EF_ZOMGIB)
590
			R_RocketTrail (oldorg, ent->origin, 4);
591
		else if (ent->model->flags & EF_TRACER)
592
			R_RocketTrail (oldorg, ent->origin, 3);
593
		else if (ent->model->flags & EF_TRACER2)
594
			R_RocketTrail (oldorg, ent->origin, 5);
595
		else if (ent->model->flags & EF_ROCKET)
596
		{
597
			R_RocketTrail (oldorg, ent->origin, 0);
598
			dl = CL_AllocDlight (i);
599
			VectorCopy (ent->origin, dl->origin);
600
			dl->radius = 200;
601
			dl->die = cl.time + 0.01;
602
		}
603
		else if (ent->model->flags & EF_GRENADE)
604
			R_RocketTrail (oldorg, ent->origin, 1);
605
		else if (ent->model->flags & EF_TRACER3)
606
			R_RocketTrail (oldorg, ent->origin, 6);
607
 
608
		ent->forcelink = false;
609
 
610
		if (i == cl.viewentity && !chase_active.value)
611
			continue;
612
 
613
#ifdef QUAKE2
614
		if ( ent->effects & EF_NODRAW )
615
			continue;
616
#endif
617
		if (cl_numvisedicts < MAX_VISEDICTS)
618
		{
619
			cl_visedicts[cl_numvisedicts] = ent;
620
			cl_numvisedicts++;
621
		}
622
	}
623
 
624
}
625
 
626
 
627
/*
628
===============
629
CL_ReadFromServer
630
 
631
Read all incoming data from the server
632
===============
633
*/
634
int CL_ReadFromServer (void)
635
{
636
	int		ret;
637
 
638
	cl.oldtime = cl.time;
639
	cl.time += host_frametime;
640
 
641
	do
642
	{
643
		ret = CL_GetMessage ();
644
		if (ret == -1)
645
			Host_Error ("CL_ReadFromServer: lost server connection");
646
		if (!ret)
647
			break;
648
 
649
		cl.last_received_message = realtime;
650
		CL_ParseServerMessage ();
651
	} while (ret && cls.state == ca_connected);
652
 
653
	if (cl_shownet.value)
654
		Con_Printf ("\n");
655
 
656
	CL_RelinkEntities ();
657
	CL_UpdateTEnts ();
658
 
659
//
660
// bring the links up to date
661
//
662
	return 0;
663
}
664
 
665
/*
666
=================
667
CL_SendCmd
668
=================
669
*/
670
void CL_SendCmd (void)
671
{
672
	usercmd_t		cmd;
673
 
674
	if (cls.state != ca_connected)
675
		return;
676
 
677
	if (cls.signon == SIGNONS)
678
	{
679
	// get basic movement from keyboard
680
		CL_BaseMove (&cmd);
681
 
682
	// allow mice or other external controllers to add to the move
683
		IN_Move (&cmd);
684
 
685
	// send the unreliable message
686
		CL_SendMove (&cmd);
687
 
688
	}
689
 
690
	if (cls.demoplayback)
691
	{
692
		SZ_Clear (&cls.message);
693
		return;
694
	}
695
 
696
// send the reliable message
697
	if (!cls.message.cursize)
698
		return;		// no message at all
699
 
700
	if (!NET_CanSendMessage (cls.netcon))
701
	{
702
		Con_DPrintf ("CL_WriteToServer: can't send\n");
703
		return;
704
	}
705
 
706
	if (NET_SendMessage (cls.netcon, &cls.message) == -1)
707
		Host_Error ("CL_WriteToServer: lost server connection");
708
 
709
	SZ_Clear (&cls.message);
710
}
711
 
712
/*
713
=================
714
CL_Init
715
=================
716
*/
717
void CL_Init (void)
718
{
719
	SZ_Alloc (&cls.message, 1024);
720
 
721
	CL_InitInput ();
722
	CL_InitTEnts ();
723
 
724
//
725
// register our commands
726
//
727
	Cvar_RegisterVariable (&cl_name);
728
	Cvar_RegisterVariable (&cl_color);
729
	Cvar_RegisterVariable (&cl_upspeed);
730
	Cvar_RegisterVariable (&cl_forwardspeed);
731
	Cvar_RegisterVariable (&cl_backspeed);
732
	Cvar_RegisterVariable (&cl_sidespeed);
733
	Cvar_RegisterVariable (&cl_movespeedkey);
734
	Cvar_RegisterVariable (&cl_yawspeed);
735
	Cvar_RegisterVariable (&cl_pitchspeed);
736
	Cvar_RegisterVariable (&cl_anglespeedkey);
737
	Cvar_RegisterVariable (&cl_shownet);
738
	Cvar_RegisterVariable (&cl_nolerp);
739
	Cvar_RegisterVariable (&lookspring);
740
	Cvar_RegisterVariable (&lookstrafe);
741
	Cvar_RegisterVariable (&sensitivity);
742
 
743
	Cvar_RegisterVariable (&m_pitch);
744
	Cvar_RegisterVariable (&m_yaw);
745
	Cvar_RegisterVariable (&m_forward);
746
	Cvar_RegisterVariable (&m_side);
747
 
748
//	Cvar_RegisterVariable (&cl_autofire);
749
 
750
	Cmd_AddCommand ("entities", CL_PrintEntities_f);
751
	Cmd_AddCommand ("disconnect", CL_Disconnect_f);
752
	Cmd_AddCommand ("record", CL_Record_f);
753
	Cmd_AddCommand ("stop", CL_Stop_f);
754
	Cmd_AddCommand ("playdemo", CL_PlayDemo_f);
755
	Cmd_AddCommand ("timedemo", CL_TimeDemo_f);
756
}
757