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
// sv_user.c -- server code for moving users
21
 
22
#include "quakedef.h"
23
 
24
edict_t	*sv_player;
25
 
26
extern	cvar_t	sv_friction;
27
cvar_t	sv_edgefriction = {"edgefriction", "2"};
28
extern	cvar_t	sv_stopspeed;
29
 
30
static	vec3_t		forward, right, up;
31
 
32
vec3_t	wishdir;
33
float	wishspeed;
34
 
35
// world
36
float	*angles;
37
float	*origin;
38
float	*velocity;
39
 
40
qboolean	onground;
41
 
42
usercmd_t	cmd;
43
 
44
cvar_t	sv_idealpitchscale = {"sv_idealpitchscale","0.8"};
45
 
46
 
47
/*
48
===============
49
SV_SetIdealPitch
50
===============
51
*/
52
#define	MAX_FORWARD	6
53
void SV_SetIdealPitch (void)
54
{
55
	float	angleval, sinval, cosval;
56
	trace_t	tr;
57
	vec3_t	top, bottom;
58
	float	z[MAX_FORWARD];
59
	int		i, j;
60
	int		step, dir, steps;
61
 
62
	if (!((int)sv_player->v.flags & FL_ONGROUND))
63
		return;
64
 
65
	angleval = sv_player->v.angles[YAW] * M_PI*2 / 360;
66
	sinval = sin(angleval);
67
	cosval = cos(angleval);
68
 
69
	for (i=0 ; i
70
	{
71
		top[0] = sv_player->v.origin[0] + cosval*(i+3)*12;
72
		top[1] = sv_player->v.origin[1] + sinval*(i+3)*12;
73
		top[2] = sv_player->v.origin[2] + sv_player->v.view_ofs[2];
74
 
75
		bottom[0] = top[0];
76
		bottom[1] = top[1];
77
		bottom[2] = top[2] - 160;
78
 
79
		tr = SV_Move (top, vec3_origin, vec3_origin, bottom, 1, sv_player);
80
		if (tr.allsolid)
81
			return;	// looking at a wall, leave ideal the way is was
82
 
83
		if (tr.fraction == 1)
84
			return;	// near a dropoff
85
 
86
		z[i] = top[2] + tr.fraction*(bottom[2]-top[2]);
87
	}
88
 
89
	dir = 0;
90
	steps = 0;
91
	for (j=1 ; j
92
	{
93
		step = z[j] - z[j-1];
94
		if (step > -ON_EPSILON && step < ON_EPSILON)
95
			continue;
96
 
97
		if (dir && ( step-dir > ON_EPSILON || step-dir < -ON_EPSILON ) )
98
			return;		// mixed changes
99
 
100
		steps++;
101
		dir = step;
102
	}
103
 
104
	if (!dir)
105
	{
106
		sv_player->v.idealpitch = 0;
107
		return;
108
	}
109
 
110
	if (steps < 2)
111
		return;
112
	sv_player->v.idealpitch = -dir * sv_idealpitchscale.value;
113
}
114
 
115
 
116
/*
117
==================
118
SV_UserFriction
119
 
120
==================
121
*/
122
void SV_UserFriction (void)
123
{
124
	float	*vel;
125
	float	speed, newspeed, control;
126
	vec3_t	start, stop;
127
	float	friction;
128
	trace_t	trace;
129
 
130
	vel = velocity;
131
 
132
	speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);
133
	if (!speed)
134
		return;
135
 
136
// if the leading edge is over a dropoff, increase friction
137
	start[0] = stop[0] = origin[0] + vel[0]/speed*16;
138
	start[1] = stop[1] = origin[1] + vel[1]/speed*16;
139
	start[2] = origin[2] + sv_player->v.mins[2];
140
	stop[2] = start[2] - 34;
141
 
142
	trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, sv_player);
143
 
144
	if (trace.fraction == 1.0)
145
		friction = sv_friction.value*sv_edgefriction.value;
146
	else
147
		friction = sv_friction.value;
148
 
149
// apply friction
150
	control = speed < sv_stopspeed.value ? sv_stopspeed.value : speed;
151
	newspeed = speed - host_frametime*control*friction;
152
 
153
	if (newspeed < 0)
154
		newspeed = 0;
155
	newspeed /= speed;
156
 
157
	vel[0] = vel[0] * newspeed;
158
	vel[1] = vel[1] * newspeed;
159
	vel[2] = vel[2] * newspeed;
160
}
161
 
162
/*
163
==============
164
SV_Accelerate
165
==============
166
*/
167
cvar_t	sv_maxspeed = {"sv_maxspeed", "320", false, true};
168
cvar_t	sv_accelerate = {"sv_accelerate", "10"};
169
#if 0
170
void SV_Accelerate (vec3_t wishvel)
171
{
172
	int			i;
173
	float		addspeed, accelspeed;
174
	vec3_t		pushvec;
175
 
176
	if (wishspeed == 0)
177
		return;
178
 
179
	VectorSubtract (wishvel, velocity, pushvec);
180
	addspeed = VectorNormalize (pushvec);
181
 
182
	accelspeed = sv_accelerate.value*host_frametime*addspeed;
183
	if (accelspeed > addspeed)
184
		accelspeed = addspeed;
185
 
186
	for (i=0 ; i<3 ; i++)
187
		velocity[i] += accelspeed*pushvec[i];
188
}
189
#endif
190
void SV_Accelerate (void)
191
{
192
	int			i;
193
	float		addspeed, accelspeed, currentspeed;
194
 
195
	currentspeed = DotProduct (velocity, wishdir);
196
	addspeed = wishspeed - currentspeed;
197
	if (addspeed <= 0)
198
		return;
199
	accelspeed = sv_accelerate.value*host_frametime*wishspeed;
200
	if (accelspeed > addspeed)
201
		accelspeed = addspeed;
202
 
203
	for (i=0 ; i<3 ; i++)
204
		velocity[i] += accelspeed*wishdir[i];
205
}
206
 
207
void SV_AirAccelerate (vec3_t wishveloc)
208
{
209
	int			i;
210
	float		addspeed, wishspd, accelspeed, currentspeed;
211
 
212
	wishspd = VectorNormalize (wishveloc);
213
	if (wishspd > 30)
214
		wishspd = 30;
215
	currentspeed = DotProduct (velocity, wishveloc);
216
	addspeed = wishspd - currentspeed;
217
	if (addspeed <= 0)
218
		return;
219
//	accelspeed = sv_accelerate.value * host_frametime;
220
	accelspeed = sv_accelerate.value*wishspeed * host_frametime;
221
	if (accelspeed > addspeed)
222
		accelspeed = addspeed;
223
 
224
	for (i=0 ; i<3 ; i++)
225
		velocity[i] += accelspeed*wishveloc[i];
226
}
227
 
228
 
229
void DropPunchAngle (void)
230
{
231
	float	len;
232
 
233
	len = VectorNormalize (sv_player->v.punchangle);
234
 
235
	len -= 10*host_frametime;
236
	if (len < 0)
237
		len = 0;
238
	VectorScale (sv_player->v.punchangle, len, sv_player->v.punchangle);
239
}
240
 
241
/*
242
===================
243
SV_WaterMove
244
 
245
===================
246
*/
247
void SV_WaterMove (void)
248
{
249
	int		i;
250
	vec3_t	wishvel;
251
	float	speed, newspeed, wishspeed, addspeed, accelspeed;
252
 
253
//
254
// user intentions
255
//
256
	AngleVectors (sv_player->v.v_angle, forward, right, up);
257
 
258
	for (i=0 ; i<3 ; i++)
259
		wishvel[i] = forward[i]*cmd.forwardmove + right[i]*cmd.sidemove;
260
 
261
	if (!cmd.forwardmove && !cmd.sidemove && !cmd.upmove)
262
		wishvel[2] -= 60;		// drift towards bottom
263
	else
264
		wishvel[2] += cmd.upmove;
265
 
266
	wishspeed = Length(wishvel);
267
	if (wishspeed > sv_maxspeed.value)
268
	{
269
		VectorScale (wishvel, sv_maxspeed.value/wishspeed, wishvel);
270
		wishspeed = sv_maxspeed.value;
271
	}
272
	wishspeed *= 0.7;
273
 
274
//
275
// water friction
276
//
277
	speed = Length (velocity);
278
	if (speed)
279
	{
280
		newspeed = speed - host_frametime * speed * sv_friction.value;
281
		if (newspeed < 0)
282
			newspeed = 0;
283
		VectorScale (velocity, newspeed/speed, velocity);
284
	}
285
	else
286
		newspeed = 0;
287
 
288
//
289
// water acceleration
290
//
291
	if (!wishspeed)
292
		return;
293
 
294
	addspeed = wishspeed - newspeed;
295
	if (addspeed <= 0)
296
		return;
297
 
298
	VectorNormalize (wishvel);
299
	accelspeed = sv_accelerate.value * wishspeed * host_frametime;
300
	if (accelspeed > addspeed)
301
		accelspeed = addspeed;
302
 
303
	for (i=0 ; i<3 ; i++)
304
		velocity[i] += accelspeed * wishvel[i];
305
}
306
 
307
void SV_WaterJump (void)
308
{
309
	if (sv.time > sv_player->v.teleport_time
310
	|| !sv_player->v.waterlevel)
311
	{
312
		sv_player->v.flags = (int)sv_player->v.flags & ~FL_WATERJUMP;
313
		sv_player->v.teleport_time = 0;
314
	}
315
	sv_player->v.velocity[0] = sv_player->v.movedir[0];
316
	sv_player->v.velocity[1] = sv_player->v.movedir[1];
317
}
318
 
319
 
320
/*
321
===================
322
SV_AirMove
323
 
324
===================
325
*/
326
void SV_AirMove (void)
327
{
328
	int			i;
329
	vec3_t		wishvel;
330
	float		fmove, smove;
331
 
332
	AngleVectors (sv_player->v.angles, forward, right, up);
333
 
334
	fmove = cmd.forwardmove;
335
	smove = cmd.sidemove;
336
 
337
// hack to not let you back into teleporter
338
	if (sv.time < sv_player->v.teleport_time && fmove < 0)
339
		fmove = 0;
340
 
341
	for (i=0 ; i<3 ; i++)
342
		wishvel[i] = forward[i]*fmove + right[i]*smove;
343
 
344
	if ( (int)sv_player->v.movetype != MOVETYPE_WALK)
345
		wishvel[2] = cmd.upmove;
346
	else
347
		wishvel[2] = 0;
348
 
349
	VectorCopy (wishvel, wishdir);
350
	wishspeed = VectorNormalize(wishdir);
351
	if (wishspeed > sv_maxspeed.value)
352
	{
353
		VectorScale (wishvel, sv_maxspeed.value/wishspeed, wishvel);
354
		wishspeed = sv_maxspeed.value;
355
	}
356
 
357
	if ( sv_player->v.movetype == MOVETYPE_NOCLIP)
358
	{	// noclip
359
		VectorCopy (wishvel, velocity);
360
	}
361
	else if ( onground )
362
	{
363
		SV_UserFriction ();
364
		SV_Accelerate ();
365
	}
366
	else
367
	{	// not on ground, so little effect on velocity
368
		SV_AirAccelerate (wishvel);
369
	}
370
}
371
 
372
/*
373
===================
374
SV_ClientThink
375
 
376
the move fields specify an intended velocity in pix/sec
377
the angle fields specify an exact angular motion in degrees
378
===================
379
*/
380
void SV_ClientThink (void)
381
{
382
	vec3_t		v_angle;
383
 
384
	if (sv_player->v.movetype == MOVETYPE_NONE)
385
		return;
386
 
387
	onground = (int)sv_player->v.flags & FL_ONGROUND;
388
 
389
	origin = sv_player->v.origin;
390
	velocity = sv_player->v.velocity;
391
 
392
	DropPunchAngle ();
393
 
394
//
395
// if dead, behave differently
396
//
397
	if (sv_player->v.health <= 0)
398
		return;
399
 
400
//
401
// angles
402
// show 1/3 the pitch angle and all the roll angle
403
	cmd = host_client->cmd;
404
	angles = sv_player->v.angles;
405
 
406
	VectorAdd (sv_player->v.v_angle, sv_player->v.punchangle, v_angle);
407
	angles[ROLL] = V_CalcRoll (sv_player->v.angles, sv_player->v.velocity)*4;
408
	if (!sv_player->v.fixangle)
409
	{
410
		angles[PITCH] = -v_angle[PITCH]/3;
411
		angles[YAW] = v_angle[YAW];
412
	}
413
 
414
	if ( (int)sv_player->v.flags & FL_WATERJUMP )
415
	{
416
		SV_WaterJump ();
417
		return;
418
	}
419
//
420
// walk
421
//
422
	if ( (sv_player->v.waterlevel >= 2)
423
	&& (sv_player->v.movetype != MOVETYPE_NOCLIP) )
424
	{
425
		SV_WaterMove ();
426
		return;
427
	}
428
 
429
	SV_AirMove ();
430
}
431
 
432
 
433
/*
434
===================
435
SV_ReadClientMove
436
===================
437
*/
438
void SV_ReadClientMove (usercmd_t *move)
439
{
440
	int		i;
441
	vec3_t	angle;
442
	int		bits;
443
 
444
// read ping time
445
	host_client->ping_times[host_client->num_pings%NUM_PING_TIMES]
446
		= sv.time - MSG_ReadFloat ();
447
	host_client->num_pings++;
448
 
449
// read current angles
450
	for (i=0 ; i<3 ; i++)
451
		angle[i] = MSG_ReadAngle ();
452
 
453
	VectorCopy (angle, host_client->edict->v.v_angle);
454
 
455
// read movement
456
	move->forwardmove = MSG_ReadShort ();
457
	move->sidemove = MSG_ReadShort ();
458
	move->upmove = MSG_ReadShort ();
459
 
460
// read buttons
461
	bits = MSG_ReadByte ();
462
	host_client->edict->v.button0 = bits & 1;
463
	host_client->edict->v.button2 = (bits & 2)>>1;
464
 
465
	i = MSG_ReadByte ();
466
	if (i)
467
		host_client->edict->v.impulse = i;
468
 
469
#ifdef QUAKE2
470
// read light level
471
	host_client->edict->v.light_level = MSG_ReadByte ();
472
#endif
473
}
474
 
475
/*
476
===================
477
SV_ReadClientMessage
478
 
479
Returns false if the client should be killed
480
===================
481
*/
482
qboolean SV_ReadClientMessage (void)
483
{
484
	int		ret;
485
	int		cmd;
486
	char		*s;
487
 
488
	do
489
	{
490
nextmsg:
491
		ret = NET_GetMessage (host_client->netconnection);
492
		if (ret == -1)
493
		{
494
			Sys_Printf ("SV_ReadClientMessage: NET_GetMessage failed\n");
495
			return false;
496
		}
497
		if (!ret)
498
			return true;
499
 
500
		MSG_BeginReading ();
501
 
502
		while (1)
503
		{
504
			if (!host_client->active)
505
				return false;	// a command caused an error
506
 
507
			if (msg_badread)
508
			{
509
				Sys_Printf ("SV_ReadClientMessage: badread\n");
510
				return false;
511
			}
512
 
513
			cmd = MSG_ReadChar ();
514
 
515
			switch (cmd)
516
			{
517
			case -1:
518
				goto nextmsg;		// end of message
519
 
520
			default:
521
				Sys_Printf ("SV_ReadClientMessage: unknown command char\n");
522
				return false;
523
 
524
			case clc_nop:
525
//				Sys_Printf ("clc_nop\n");
526
				break;
527
 
528
			case clc_stringcmd:
529
				s = MSG_ReadString ();
530
				if (host_client->privileged)
531
					ret = 2;
532
				else
533
					ret = 0;
534
				if (Q_strncasecmp(s, "status", 6) == 0)
535
					ret = 1;
536
				else if (Q_strncasecmp(s, "god", 3) == 0)
537
					ret = 1;
538
				else if (Q_strncasecmp(s, "notarget", 8) == 0)
539
					ret = 1;
540
				else if (Q_strncasecmp(s, "fly", 3) == 0)
541
					ret = 1;
542
				else if (Q_strncasecmp(s, "name", 4) == 0)
543
					ret = 1;
544
				else if (Q_strncasecmp(s, "noclip", 6) == 0)
545
					ret = 1;
546
				else if (Q_strncasecmp(s, "say", 3) == 0)
547
					ret = 1;
548
				else if (Q_strncasecmp(s, "say_team", 8) == 0)
549
					ret = 1;
550
				else if (Q_strncasecmp(s, "tell", 4) == 0)
551
					ret = 1;
552
				else if (Q_strncasecmp(s, "color", 5) == 0)
553
					ret = 1;
554
				else if (Q_strncasecmp(s, "kill", 4) == 0)
555
					ret = 1;
556
				else if (Q_strncasecmp(s, "pause", 5) == 0)
557
					ret = 1;
558
				else if (Q_strncasecmp(s, "spawn", 5) == 0)
559
					ret = 1;
560
				else if (Q_strncasecmp(s, "begin", 5) == 0)
561
					ret = 1;
562
				else if (Q_strncasecmp(s, "prespawn", 8) == 0)
563
					ret = 1;
564
				else if (Q_strncasecmp(s, "kick", 4) == 0)
565
					ret = 1;
566
				else if (Q_strncasecmp(s, "ping", 4) == 0)
567
					ret = 1;
568
				else if (Q_strncasecmp(s, "give", 4) == 0)
569
					ret = 1;
570
				else if (Q_strncasecmp(s, "ban", 3) == 0)
571
					ret = 1;
572
				if (ret == 2)
573
					Cbuf_InsertText (s);
574
				else if (ret == 1)
575
					Cmd_ExecuteString (s, src_client);
576
				else
577
					Con_DPrintf("%s tried to %s\n", host_client->name, s);
578
				break;
579
 
580
			case clc_disconnect:
581
//				Sys_Printf ("SV_ReadClientMessage: client disconnected\n");
582
				return false;
583
 
584
			case clc_move:
585
				SV_ReadClientMove (&host_client->cmd);
586
				break;
587
			}
588
		}
589
	} while (ret == 1);
590
 
591
	return true;
592
}
593
 
594
 
595
/*
596
==================
597
SV_RunClients
598
==================
599
*/
600
void SV_RunClients (void)
601
{
602
	int				i;
603
 
604
	for (i=0, host_client = svs.clients ; i
605
	{
606
		if (!host_client->active)
607
			continue;
608
 
609
		sv_player = host_client->edict;
610
 
611
		if (!SV_ReadClientMessage ())
612
		{
613
			SV_DropClient (false);	// client misbehaved...
614
			continue;
615
		}
616
 
617
		if (!host_client->spawned)
618
		{
619
		// clear client movement until a new packet is received
620
			memset (&host_client->cmd, 0, sizeof(host_client->cmd));
621
			continue;
622
		}
623
 
624
// always pause in single player if in console or menus
625
		if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) )
626
			SV_ClientThink ();
627
	}
628
}
629