1 /*
2 Copyright (C) 1997-2001 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 //
21 // sv_pmove.c
22 // Necessary to keep 3.21 compatibility and allow cgame dlls
23 //
24 
25 #include "sv_local.h"
26 
27 // all of the locals will be zeroed before each pmove, just to make damn sure
28 // we don't have any differences when running on client or server
29 
30 typedef struct pMoveLocal_s {
31 	vec3_t			origin;			// full float precision
32 	vec3_t			velocity;		// full float precision
33 
34 	vec3_t			forward, right, up;
35 	float			frameTime;
36 
37 	cBspSurface_t	*groundSurface;
38 	int				groundContents;
39 
40 	svec3_t			previousOrigin;
41 	qBool			ladder;
42 } pMoveLocal_t;
43 
44 static pMoveNew_t	*pm;
45 static pMoveLocal_t	pml;
46 
47 static float	pmAirAcceleration = 0;
48 
49 #define STEPSIZE			18
50 #define MIN_STEP_NORMAL		0.7f		// can't step up onto very steep slopes
51 #define MAX_CLIP_PLANES		5
52 
53 // movement parameters
54 #define SV_PM_STOPSPEED			100.0f
55 #define SV_PM_MAXSPEED			300.0f
56 #define SV_PM_DUCKSPEED			100.0f
57 #define SV_PM_ACCELERATE		10.0f
58 #define SV_PM_WATERACCELERATE	10.0f
59 #define SV_PM_FRICTION			6.0f
60 #define SV_PM_WATERFRICTION		1.0f
61 #define SV_PM_WATERSPEED		400.0f
62 
63 /*
64 ==================
65 SV_PM_ClipVelocity
66 
67 Slide off of the impacting object
68 returns the blocked flags (1 = floor, 2 = step / wall)
69 ==================
70 */
SV_PM_ClipVelocity(vec3_t in,vec3_t normal,vec3_t out,float overbounce)71 static void SV_PM_ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce) {
72 	float	backoff;
73 	float	change;
74 	int		i;
75 
76 	backoff = DotProduct (in, normal) * overbounce;
77 
78 	for (i=0 ; i<3 ; i++) {
79 		change = normal[i]*backoff;
80 		out[i] = in[i] - change;
81 		if ((out[i] > -LARGE_EPSILON) && (out[i] < LARGE_EPSILON))
82 			out[i] = 0;
83 	}
84 }
85 
86 
87 /*
88 ==================
89 SV_PM_StepSlideMove
90 
91 Each intersection will try to step over the obstruction instead of
92 sliding along it.
93 
94 Returns a new origin, velocity, and contact entity
95 Does not modify any world state?
96 ==================
97 */
SV_PM_StepSlideMove_(void)98 static void SV_PM_StepSlideMove_ (void) {
99 	int			bumpcount, numbumps;
100 	vec3_t		dir;
101 	float		d;
102 	int			numPlanes;
103 	vec3_t		planes[MAX_CLIP_PLANES];
104 	vec3_t		primal_velocity;
105 	int			i, j;
106 	trace_t		trace;
107 	vec3_t		end;
108 	float		time_left;
109 
110 	numbumps = 4;
111 
112 	Vec3Copy (pml.velocity, primal_velocity);
113 	numPlanes = 0;
114 
115 	time_left = pml.frameTime;
116 
117 	for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++) {
118 		end[0] = pml.origin[0] + time_left * pml.velocity[0];
119 		end[1] = pml.origin[1] + time_left * pml.velocity[1];
120 		end[2] = pml.origin[2] + time_left * pml.velocity[2];
121 
122 		trace = pm->trace (pml.origin, pm->mins, pm->maxs, end);
123 
124 		if (trace.allSolid) {
125 			// entity is trapped in another solid
126 			pml.velocity[2] = 0;	// don't build up falling damage
127 			return;
128 		}
129 
130 		if (trace.fraction > 0) {
131 			// actually covered some distance
132 			Vec3Copy (trace.endPos, pml.origin);
133 			numPlanes = 0;
134 		}
135 
136 		if (trace.fraction == 1)
137 			 break;		// moved the entire distance
138 
139 		// save entity for contact
140 		if ((pm->numTouch < MAXTOUCH) && trace.ent) {
141 			pm->touchEnts[pm->numTouch] = trace.ent;
142 			pm->numTouch++;
143 		}
144 
145 		time_left -= time_left * trace.fraction;
146 
147 		// slide along this plane
148 		if (numPlanes >= MAX_CLIP_PLANES) {
149 			// this shouldn't really happen
150 			Vec3Clear (pml.velocity);
151 			break;
152 		}
153 
154 		Vec3Copy (trace.plane.normal, planes[numPlanes]);
155 		numPlanes++;
156 
157 		// modify original_velocity so it parallels all of the clip planes
158 		for (i=0 ; i<numPlanes ; i++) {
159 			SV_PM_ClipVelocity (pml.velocity, planes[i], pml.velocity, 1.01f);
160 			for (j=0 ; j<numPlanes ; j++) {
161 				if (j != i) {
162 					if (DotProduct (pml.velocity, planes[j]) < 0)
163 						break;	// not ok
164 				}
165 			}
166 			if (j == numPlanes)
167 				break;
168 		}
169 
170 		if (i != numPlanes) {
171 			// go along this plane
172 		}
173 		else {
174 			// go along the crease
175 			if (numPlanes != 2) {
176 				Vec3Clear (pml.velocity);
177 				break;
178 			}
179 			CrossProduct (planes[0], planes[1], dir);
180 			d = DotProduct (dir, pml.velocity);
181 			Vec3Scale (dir, d, pml.velocity);
182 		}
183 
184 		/*
185 		** if velocity is against the original velocity, stop dead
186 		** to avoid tiny occilations in sloping corners
187 		*/
188 		if (DotProduct (pml.velocity, primal_velocity) <= 0) {
189 			Vec3Clear (pml.velocity);
190 			break;
191 		}
192 	}
193 
194 	if (pm->state.pmTime)
195 		Vec3Copy (primal_velocity, pml.velocity);
196 }
197 
SV_PM_StepSlideMove(void)198 static void SV_PM_StepSlideMove (void) {
199 	vec3_t		start_o, start_v;
200 	vec3_t		down_o, down_v;
201 	trace_t		trace;
202 	float		down_dist, up_dist;
203 	vec3_t		up, down;
204 
205 	Vec3Copy (pml.origin, start_o);
206 	Vec3Copy (pml.velocity, start_v);
207 
208 	SV_PM_StepSlideMove_ ();
209 
210 	Vec3Copy (pml.origin, down_o);
211 	Vec3Copy (pml.velocity, down_v);
212 
213 	Vec3Copy (start_o, up);
214 	up[2] += STEPSIZE;
215 
216 	trace = pm->trace (up, pm->mins, pm->maxs, up);
217 	if (trace.allSolid)
218 		return;		// can't step up
219 
220 	// try sliding above
221 	Vec3Copy (up, pml.origin);
222 	Vec3Copy (start_v, pml.velocity);
223 
224 	SV_PM_StepSlideMove_ ();
225 
226 	// push down the final amount
227 	Vec3Copy (pml.origin, down);
228 	down[2] -= STEPSIZE;
229 	trace = pm->trace (pml.origin, pm->mins, pm->maxs, down);
230 	if (!trace.allSolid)
231 		Vec3Copy (trace.endPos, pml.origin);
232 
233 	Vec3Copy (pml.origin, up);
234 
235 	// decide which one went farther
236 	down_dist = (down_o[0] - start_o[0])*(down_o[0] - start_o[0])
237 		+ (down_o[1] - start_o[1])*(down_o[1] - start_o[1]);
238 	up_dist = (up[0] - start_o[0])*(up[0] - start_o[0])
239 		+ (up[1] - start_o[1])*(up[1] - start_o[1]);
240 
241 	if (down_dist > up_dist || trace.plane.normal[2] < MIN_STEP_NORMAL) {
242 		Vec3Copy (down_o, pml.origin);
243 		Vec3Copy (down_v, pml.velocity);
244 		return;
245 	}
246 	// !! Special case !!
247 	// if we were walking along a plane, then we need to copy the Z over
248 	pml.velocity[2] = down_v[2];
249 }
250 
251 
252 /*
253 ==================
254 SV_PM_Friction
255 
256 Handles both ground friction and water friction
257 ==================
258 */
SV_PM_Friction(void)259 static void SV_PM_Friction (void) {
260 	float	*vel;
261 	float	speed, newspeed, control;
262 	float	friction;
263 	float	drop;
264 
265 	vel = pml.velocity;
266 
267 	speed = Vec3Length (vel);
268 	if (speed < 1) {
269 		vel[0] = 0;
270 		vel[1] = 0;
271 		return;
272 	}
273 
274 	drop = 0;
275 
276 	// apply ground friction
277 	if ((pm->groundEntity && pml.groundSurface && !(pml.groundSurface->flags & SURF_TEXINFO_SLICK)) || pml.ladder) {
278 		friction = SV_PM_FRICTION;
279 		control = (speed < SV_PM_STOPSPEED) ? SV_PM_STOPSPEED : speed;
280 		drop += control*friction*pml.frameTime;
281 	}
282 
283 	// apply water friction
284 	if (pm->waterLevel && !pml.ladder)
285 		drop += speed*SV_PM_WATERFRICTION*pm->waterLevel*pml.frameTime;
286 
287 	// scale the velocity
288 	newspeed = speed - drop;
289 	if (newspeed < 0)
290 		newspeed = 0;
291 
292 	newspeed /= speed;
293 
294 	vel[0] = vel[0] * newspeed;
295 	vel[1] = vel[1] * newspeed;
296 	vel[2] = vel[2] * newspeed;
297 }
298 
299 
300 /*
301 ==============
302 SV_PM_Accelerate
303 
304 Handles user intended acceleration
305 ==============
306 */
SV_PM_Accelerate(vec3_t wishdir,float wishspeed,float accel)307 static void SV_PM_Accelerate (vec3_t wishdir, float wishspeed, float accel) {
308 	float		addspeed, accelspeed, currentspeed;
309 
310 	currentspeed = DotProduct (pml.velocity, wishdir);
311 	addspeed = wishspeed - currentspeed;
312 	if (addspeed <= 0)
313 		return;
314 
315 	accelspeed = accel*pml.frameTime*wishspeed;
316 	if (accelspeed > addspeed)
317 		accelspeed = addspeed;
318 
319 	pml.velocity[0] += accelspeed*wishdir[0];
320 	pml.velocity[1] += accelspeed*wishdir[1];
321 	pml.velocity[2] += accelspeed*wishdir[2];
322 }
323 
324 
325 /*
326 ==============
327 SV_PM_AirAccelerate
328 
329 Handles user intended air acceleration
330 ==============
331 */
SV_PM_AirAccelerate(vec3_t wishdir,float wishspeed,float accel)332 static void SV_PM_AirAccelerate (vec3_t wishdir, float wishspeed, float accel) {
333 	float		addspeed, accelspeed;
334 	float		currentspeed, wishspd = wishspeed;
335 
336 	if (wishspd > 30)
337 		wishspd = 30;
338 	currentspeed = DotProduct (pml.velocity, wishdir);
339 	addspeed = wishspd - currentspeed;
340 	if (addspeed <= 0)
341 		return;
342 
343 	accelspeed = accel * wishspeed * pml.frameTime;
344 	if (accelspeed > addspeed)
345 		accelspeed = addspeed;
346 
347 	pml.velocity[0] += accelspeed*wishdir[0];
348 	pml.velocity[1] += accelspeed*wishdir[1];
349 	pml.velocity[2] += accelspeed*wishdir[2];
350 }
351 
352 
353 /*
354 =============
355 SV_PM_AddCurrents
356 =============
357 */
SV_PM_AddCurrents(vec3_t wishvel)358 static void SV_PM_AddCurrents (vec3_t	wishvel) {
359 	vec3_t	v;
360 	float	s;
361 
362 	// account for ladders
363 	if (pml.ladder && fabs (pml.velocity[2]) <= 200) {
364 		if ((pm->viewAngles[PITCH] <= -15) && (pm->cmd.forwardMove > 0))
365 			wishvel[2] = 200;
366 		else if ((pm->viewAngles[PITCH] >= 15) && (pm->cmd.forwardMove > 0))
367 			wishvel[2] = -200;
368 		else if (pm->cmd.upMove > 0)
369 			wishvel[2] = 200;
370 		else if (pm->cmd.upMove < 0)
371 			wishvel[2] = -200;
372 		else
373 			wishvel[2] = 0;
374 
375 		// limit horizontal speed when on a ladder
376 		if (wishvel[0] < -25)		wishvel[0] = -25;
377 		else if (wishvel[0] > 25)	wishvel[0] = 25;
378 
379 		if (wishvel[1] < -25)		wishvel[1] = -25;
380 		else if (wishvel[1] > 25)	wishvel[1] = 25;
381 	}
382 
383 	// add water currents
384 	if (pm->waterType & MASK_CURRENT) {
385 		Vec3Clear (v);
386 
387 		if (pm->waterType & CONTENTS_CURRENT_0)		v[0] += 1;
388 		if (pm->waterType & CONTENTS_CURRENT_90)	v[1] += 1;
389 		if (pm->waterType & CONTENTS_CURRENT_180)	v[0] -= 1;
390 		if (pm->waterType & CONTENTS_CURRENT_270)	v[1] -= 1;
391 		if (pm->waterType & CONTENTS_CURRENT_UP)	v[2] += 1;
392 		if (pm->waterType & CONTENTS_CURRENT_DOWN)	v[2] -= 1;
393 
394 		s = SV_PM_WATERSPEED;
395 		if ((pm->waterLevel == 1) && (pm->groundEntity))
396 			s /= 2;
397 
398 		Vec3MA (wishvel, s, v, wishvel);
399 	}
400 
401 	// add conveyor belt velocities
402 	if (pm->groundEntity) {
403 		Vec3Clear (v);
404 
405 		if (pml.groundContents & CONTENTS_CURRENT_0)	v[0] += 1;
406 		if (pml.groundContents & CONTENTS_CURRENT_90)	v[1] += 1;
407 		if (pml.groundContents & CONTENTS_CURRENT_180)	v[0] -= 1;
408 		if (pml.groundContents & CONTENTS_CURRENT_270)	v[1] -= 1;
409 		if (pml.groundContents & CONTENTS_CURRENT_UP)	v[2] += 1;
410 		if (pml.groundContents & CONTENTS_CURRENT_DOWN)	v[2] -= 1;
411 
412 		Vec3MA (wishvel, 100 /* pm->groundEntity->speed */, v, wishvel);
413 	}
414 }
415 
416 
417 /*
418 ===================
419 SV_PM_WaterMove
420 ===================
421 */
SV_PM_WaterMove(void)422 static void SV_PM_WaterMove (void) {
423 	vec3_t	wishvel, wishdir;
424 	float	wishspeed;
425 
426 	// user intentions
427 	wishvel[0] = pml.forward[0]*pm->cmd.forwardMove + pml.right[0]*pm->cmd.sideMove;
428 	wishvel[1] = pml.forward[1]*pm->cmd.forwardMove + pml.right[1]*pm->cmd.sideMove;
429 	wishvel[2] = pml.forward[2]*pm->cmd.forwardMove + pml.right[2]*pm->cmd.sideMove;
430 
431 	if (!pm->cmd.forwardMove && !pm->cmd.sideMove && !pm->cmd.upMove)
432 		wishvel[2] -= 60;		// drift towards bottom
433 	else
434 		wishvel[2] += pm->cmd.upMove;
435 
436 	SV_PM_AddCurrents (wishvel);
437 
438 	Vec3Copy (wishvel, wishdir);
439 	wishspeed = VectorNormalizef (wishdir, wishdir);
440 
441 	if (wishspeed > SV_PM_MAXSPEED) {
442 		Vec3Scale (wishvel, SV_PM_MAXSPEED/wishspeed, wishvel);
443 		wishspeed = SV_PM_MAXSPEED;
444 	}
445 	wishspeed *= 0.5;
446 
447 	SV_PM_Accelerate (wishdir, wishspeed, SV_PM_WATERACCELERATE);
448 
449 	SV_PM_StepSlideMove ();
450 }
451 
452 
453 /*
454 ===================
455 SV_PM_AirMove
456 ===================
457 */
SV_PM_AirMove(void)458 static void SV_PM_AirMove (void) {
459 	vec3_t		wishvel, wishdir;
460 	float		fmove, smove;
461 	float		wishspeed;
462 	float		maxspeed;
463 
464 	fmove = pm->cmd.forwardMove;
465 	smove = pm->cmd.sideMove;
466 
467 	wishvel[0] = pml.forward[0]*fmove + pml.right[0]*smove;
468 	wishvel[1] = pml.forward[1]*fmove + pml.right[1]*smove;
469 	wishvel[2] = 0;
470 
471 	SV_PM_AddCurrents (wishvel);
472 
473 	Vec3Copy (wishvel, wishdir);
474 	wishspeed = VectorNormalizef (wishdir, wishdir);
475 
476 	// clamp to server defined max speed
477 	maxspeed = (pm->state.pmFlags & PMF_DUCKED) ? SV_PM_DUCKSPEED : SV_PM_MAXSPEED;
478 
479 	if (wishspeed > maxspeed) {
480 		Vec3Scale (wishvel, maxspeed/wishspeed, wishvel);
481 		wishspeed = maxspeed;
482 	}
483 
484 	if (pml.ladder) {
485 		SV_PM_Accelerate (wishdir, wishspeed, SV_PM_ACCELERATE);
486 		if (!wishvel[2]) {
487 			if (pml.velocity[2] > 0) {
488 				pml.velocity[2] -= pm->state.gravity * pml.frameTime;
489 				if (pml.velocity[2] < 0)
490 					pml.velocity[2]  = 0;
491 			}
492 			else {
493 				pml.velocity[2] += pm->state.gravity * pml.frameTime;
494 				if (pml.velocity[2] > 0)
495 					pml.velocity[2]  = 0;
496 			}
497 		}
498 
499 		SV_PM_StepSlideMove ();
500 	}
501 	else if (pm->groundEntity) {
502 		// walking on ground
503 		pml.velocity[2] = 0; //!!! this is before the accel
504 		SV_PM_Accelerate (wishdir, wishspeed, SV_PM_ACCELERATE);
505 
506 		// PGM	-- fix for negative trigger_gravity fields
507 		//		pml.velocity[2] = 0;
508 		if (pm->state.gravity > 0)
509 			pml.velocity[2] = 0;
510 		else
511 			pml.velocity[2] -= pm->state.gravity * pml.frameTime;
512 		// PGM
513 
514 		if (!pml.velocity[0] && !pml.velocity[1])
515 			return;
516 		SV_PM_StepSlideMove ();
517 	}
518 	else {
519 		// not on ground, so little effect on velocity
520 		if (pmAirAcceleration)
521 			SV_PM_AirAccelerate (wishdir, wishspeed, SV_PM_ACCELERATE);
522 		else
523 			SV_PM_Accelerate (wishdir, wishspeed, 1);
524 
525 		// add gravity
526 		pml.velocity[2] -= pm->state.gravity * pml.frameTime;
527 		SV_PM_StepSlideMove ();
528 	}
529 }
530 
531 
532 /*
533 =============
534 SV_PM_CatagorizePosition
535 =============
536 */
SV_PM_CatagorizePosition(void)537 static void SV_PM_CatagorizePosition (void) {
538 	vec3_t		point;
539 	int			cont;
540 	trace_t		trace;
541 	float		sample1;
542 	float		sample2;
543 
544 	// if the player hull point one unit down is solid, the player is on ground
545 	// see if standing on something solid
546 	point[0] = pml.origin[0];
547 	point[1] = pml.origin[1];
548 	point[2] = pml.origin[2] - 0.25;
549 
550 	if (pml.velocity[2] > 180) {
551 		pm->state.pmFlags &= ~PMF_ON_GROUND;
552 		pm->groundEntity = NULL;
553 	}
554 	else {
555 		trace = pm->trace (pml.origin, pm->mins, pm->maxs, point);
556 		pml.groundSurface = trace.surface;
557 		pml.groundContents = trace.contents;
558 
559 		if (!trace.ent || ((trace.plane.normal[2] < 0.7) && !trace.startSolid)) {
560 			pm->groundEntity = NULL;
561 			pm->state.pmFlags &= ~PMF_ON_GROUND;
562 		}
563 		else {
564 			pm->groundEntity = trace.ent;
565 
566 			// hitting solid ground will end a waterjump
567 			if (pm->state.pmFlags & PMF_TIME_WATERJUMP) {
568 				pm->state.pmFlags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
569 				pm->state.pmTime = 0;
570 			}
571 
572 			if (!(pm->state.pmFlags & PMF_ON_GROUND)) {
573 				// just hit the ground
574 				pm->state.pmFlags |= PMF_ON_GROUND;
575 				// don't do landing time if we were just going down a slope
576 				if (pml.velocity[2] < -200) {
577 					pm->state.pmFlags |= PMF_TIME_LAND;
578 					// don't allow another jump for a little while
579 					if (pml.velocity[2] < -400)
580 						pm->state.pmTime = 25;
581 					else
582 						pm->state.pmTime = 18;
583 				}
584 			}
585 		}
586 
587 		if ((pm->numTouch < MAXTOUCH) && trace.ent) {
588 			pm->touchEnts[pm->numTouch] = trace.ent;
589 			pm->numTouch++;
590 		}
591 	}
592 
593 	// get waterLevel, accounting for ducking
594 	pm->waterLevel = 0;
595 	pm->waterType = 0;
596 
597 	sample2 = pm->viewHeight - pm->mins[2];
598 	sample1 = sample2 / 2;
599 
600 	point[2] = pml.origin[2] + pm->mins[2] + 1;
601 	cont = pm->pointContents (point);
602 
603 	if (cont & MASK_WATER) {
604 		pm->waterType = cont;
605 		pm->waterLevel = 1;
606 		point[2] = pml.origin[2] + pm->mins[2] + sample1;
607 		cont = pm->pointContents (point);
608 		if (cont & MASK_WATER) {
609 			pm->waterLevel = 2;
610 			point[2] = pml.origin[2] + pm->mins[2] + sample2;
611 			cont = pm->pointContents (point);
612 			if (cont & MASK_WATER)
613 				pm->waterLevel = 3;
614 		}
615 	}
616 }
617 
618 
619 /*
620 =============
621 SV_PM_CheckJump
622 =============
623 */
SV_PM_CheckJump(void)624 static void SV_PM_CheckJump (void) {
625 	if (pm->state.pmFlags & PMF_TIME_LAND) {
626 		// hasn't been long enough since landing to jump again
627 		return;
628 	}
629 
630 	if (pm->cmd.upMove < 10) {
631 		// not holding jump
632 		pm->state.pmFlags &= ~PMF_JUMP_HELD;
633 		return;
634 	}
635 
636 	// must wait for jump to be released
637 	if (pm->state.pmFlags & PMF_JUMP_HELD)
638 		return;
639 
640 	if (pm->state.pmType == PMT_DEAD)
641 		return;
642 
643 	if (pm->waterLevel >= 2) {
644 		// swimming, not jumping
645 		pm->groundEntity = NULL;
646 
647 		if (pml.velocity[2] <= -300)
648 			return;
649 
650 		if (pm->waterType == CONTENTS_WATER)
651 			pml.velocity[2] = 100;
652 		else if (pm->waterType == CONTENTS_SLIME)
653 			pml.velocity[2] = 80;
654 		else
655 			pml.velocity[2] = 50;
656 		return;
657 	}
658 
659 	if (pm->groundEntity == NULL)
660 		return;		// in air, so no effect
661 
662 	pm->state.pmFlags |= PMF_JUMP_HELD;
663 
664 	pm->groundEntity = NULL;
665 	pml.velocity[2] += 270;
666 	if (pml.velocity[2] < 270)
667 		pml.velocity[2] = 270;
668 }
669 
670 
671 /*
672 =============
673 SV_PM_CheckSpecialMovement
674 =============
675 */
SV_PM_CheckSpecialMovement(void)676 static void SV_PM_CheckSpecialMovement (void) {
677 	vec3_t	spot;
678 	int		cont;
679 	vec3_t	flatforward;
680 	trace_t	trace;
681 
682 	if (pm->state.pmTime)
683 		return;
684 
685 	pml.ladder = qFalse;
686 
687 	// check for ladder
688 	flatforward[0] = pml.forward[0];
689 	flatforward[1] = pml.forward[1];
690 	flatforward[2] = 0;
691 	VectorNormalizef (flatforward, flatforward);
692 
693 	Vec3MA (pml.origin, 1, flatforward, spot);
694 	trace = pm->trace (pml.origin, pm->mins, pm->maxs, spot);
695 	if ((trace.fraction < 1) && (trace.contents & CONTENTS_LADDER))
696 		pml.ladder = qTrue;
697 
698 	// check for water jump
699 	if (pm->waterLevel != 2)
700 		return;
701 
702 	Vec3MA (pml.origin, 30, flatforward, spot);
703 	spot[2] += 4;
704 	cont = pm->pointContents (spot);
705 	if (!(cont & CONTENTS_SOLID))
706 		return;
707 
708 	spot[2] += 16;
709 	cont = pm->pointContents (spot);
710 	if (cont)
711 		return;
712 
713 	// jump out of water
714 	Vec3Scale (flatforward, 50, pml.velocity);
715 	pml.velocity[2] = 350;
716 
717 	pm->state.pmFlags |= PMF_TIME_WATERJUMP;
718 	pm->state.pmTime = 255;
719 }
720 
721 
722 /*
723 ===============
724 SV_PM_FlyMove
725 ===============
726 */
SV_PM_FlyMove(qBool doClip)727 static void SV_PM_FlyMove (qBool doClip) {
728 	float	speed, drop, friction, control, newspeed;
729 	float	currentspeed, addspeed, accelspeed;
730 	vec3_t	wishvel, wishdir, end;
731 	float	fmove, smove, wishspeed;
732 	trace_t	trace;
733 
734 	pm->viewHeight = 22;
735 
736 	// friction
737 	speed = Vec3Length (pml.velocity);
738 	if (speed < 1)
739 		Vec3Clear (pml.velocity);
740 	else {
741 		drop = 0;
742 
743 		friction = SV_PM_FRICTION*1.5;	// extra friction
744 		control = (speed < SV_PM_STOPSPEED) ? SV_PM_STOPSPEED : speed;
745 		drop += control*friction*pml.frameTime;
746 
747 		// scale the velocity
748 		newspeed = speed - drop;
749 		if (newspeed < 0)
750 			newspeed = 0;
751 		newspeed /= speed;
752 
753 		Vec3Scale (pml.velocity, newspeed, pml.velocity);
754 	}
755 
756 	// accelerate
757 	fmove = pm->cmd.forwardMove;
758 	smove = pm->cmd.sideMove;
759 
760 	VectorNormalizef (pml.forward, pml.forward);
761 	VectorNormalizef (pml.right, pml.right);
762 
763 	wishvel[0] = pml.forward[0]*fmove + pml.right[0]*smove;
764 	wishvel[1] = pml.forward[1]*fmove + pml.right[1]*smove;
765 	wishvel[2] = pml.forward[2]*fmove + pml.right[2]*smove + pm->cmd.upMove;
766 
767 	Vec3Copy (wishvel, wishdir);
768 	wishspeed = VectorNormalizef (wishdir, wishdir);
769 
770 	// clamp to server defined max speed
771 	if (wishspeed > SV_PM_MAXSPEED) {
772 		Vec3Scale (wishvel, SV_PM_MAXSPEED/wishspeed, wishvel);
773 		wishspeed = SV_PM_MAXSPEED;
774 	}
775 
776 	currentspeed = DotProduct (pml.velocity, wishdir);
777 	addspeed = wishspeed - currentspeed;
778 	if (addspeed <= 0)
779 		return;
780 
781 	accelspeed = SV_PM_ACCELERATE*pml.frameTime*wishspeed;
782 	if (accelspeed > addspeed)
783 		accelspeed = addspeed;
784 
785 	pml.velocity[0] += accelspeed*wishdir[0];
786 	pml.velocity[1] += accelspeed*wishdir[1];
787 	pml.velocity[2] += accelspeed*wishdir[2];
788 
789 	if (doClip) {
790 		end[0] = pml.origin[0] + pml.frameTime * pml.velocity[0];
791 		end[1] = pml.origin[1] + pml.frameTime * pml.velocity[1];
792 		end[2] = pml.origin[2] + pml.frameTime * pml.velocity[2];
793 
794 		trace = pm->trace (pml.origin, pm->mins, pm->maxs, end);
795 
796 		Vec3Copy (trace.endPos, pml.origin);
797 	}
798 	else {
799 		// move
800 		Vec3MA (pml.origin, pml.frameTime, pml.velocity, pml.origin);
801 	}
802 }
803 
804 
805 /*
806 ==============
807 SV_PM_CheckDuck
808 
809 Sets mins, maxs, and pm->viewHeight
810 ==============
811 */
SV_PM_CheckDuck(void)812 static void SV_PM_CheckDuck (void) {
813 	trace_t	trace;
814 
815 	pm->mins[0] = -16;
816 	pm->mins[1] = -16;
817 
818 	pm->maxs[0] = 16;
819 	pm->maxs[1] = 16;
820 
821 	if (pm->state.pmType == PMT_GIB) {
822 		pm->mins[2] = 0;
823 		pm->maxs[2] = 16;
824 		pm->viewHeight = 8;
825 		return;
826 	}
827 
828 	pm->mins[2] = -24;
829 
830 	if (pm->state.pmType == PMT_DEAD) {
831 		pm->state.pmFlags |= PMF_DUCKED;
832 	}
833 	else if (pm->cmd.upMove < 0 && (pm->state.pmFlags & PMF_ON_GROUND)) {
834 		// duck
835 		pm->state.pmFlags |= PMF_DUCKED;
836 	}
837 	else {
838 		// stand up if possible
839 		if (pm->state.pmFlags & PMF_DUCKED) {
840 			// try to stand up
841 			pm->maxs[2] = 32;
842 			trace = pm->trace (pml.origin, pm->mins, pm->maxs, pml.origin);
843 			if (!trace.allSolid)
844 				pm->state.pmFlags &= ~PMF_DUCKED;
845 		}
846 	}
847 
848 	if (pm->state.pmFlags & PMF_DUCKED) {
849 		pm->maxs[2] = 4;
850 		pm->viewHeight = -2;
851 	}
852 	else {
853 		pm->maxs[2] = 32;
854 		pm->viewHeight = 22;
855 	}
856 }
857 
858 
859 /*
860 ==============
861 SV_PM_DeadMove
862 ==============
863 */
SV_PM_DeadMove(void)864 static void SV_PM_DeadMove (void)
865 {
866 	float	forward;
867 
868 	if (!pm->groundEntity)
869 		return;
870 
871 	// extra friction
872 	forward = Vec3Length (pml.velocity);
873 	forward -= 20;
874 	if (forward <= 0)
875 		Vec3Clear (pml.velocity);
876 	else {
877 		VectorNormalizef (pml.velocity, pml.velocity);
878 		Vec3Scale (pml.velocity, forward, pml.velocity);
879 	}
880 }
881 
882 
883 /*
884 ================
885 SV_PM_GoodPosition
886 ================
887 */
SV_PM_GoodPosition(void)888 static qBool SV_PM_GoodPosition (void)
889 {
890 	trace_t	trace;
891 	vec3_t	origin, end;
892 
893 	if (pm->state.pmType == PMT_SPECTATOR)
894 		return qTrue;
895 
896 	origin[0] = end[0] = pm->state.origin[0]*(1.0f/8.0f);
897 	origin[1] = end[1] = pm->state.origin[1]*(1.0f/8.0f);
898 	origin[2] = end[2] = pm->state.origin[2]*(1.0f/8.0f);
899 	trace = pm->trace (origin, pm->mins, pm->maxs, end);
900 
901 	return !trace.allSolid;
902 }
903 
904 
905 /*
906 ================
907 SV_PM_SnapPosition
908 
909 On exit, the origin will have a value that is pre-quantized to the (1.0f/8.0f)
910 precision of the network channel and in a valid position.
911 ================
912 */
SV_PM_SnapPosition(void)913 static void SV_PM_SnapPosition (void)
914 {
915 	int		sign[3];
916 	int		i, bits;
917 	int16	base[3];
918 	// try all single bits first
919 	static const int jitterBits[8] = {0,4,1,2,3,5,6,7};
920 
921 	// snap velocity to eigths
922 	pm->state.velocity[0] = (int)(pml.velocity[0]*8);
923 	pm->state.velocity[1] = (int)(pml.velocity[1]*8);
924 	pm->state.velocity[2] = (int)(pml.velocity[2]*8);
925 
926 	for (i=0 ; i<3 ; i++) {
927 		if (pml.origin[i] >= 0)
928 			sign[i] = 1;
929 		else
930 			sign[i] = -1;
931 		pm->state.origin[i] = (int)(pml.origin[i]*8);
932 		if (pm->state.origin[i]*(1.0f/8.0f) == pml.origin[i])
933 			sign[i] = 0;
934 	}
935 	Vec3Copy (pm->state.origin, base);
936 
937 	// try all combinations
938 	for (i=0 ; i<8 ; i++) {
939 		bits = jitterBits[i];
940 		Vec3Copy (base, pm->state.origin);
941 
942 		if (bits & (1<<0))
943 			pm->state.origin[0] += sign[0];
944 		if (bits & (1<<1))
945 			pm->state.origin[1] += sign[1];
946 		if (bits & (1<<2))
947 			pm->state.origin[2] += sign[2];
948 
949 		if (SV_PM_GoodPosition ())
950 			return;
951 	}
952 
953 	// go back to the last position
954 	Vec3Copy (pml.previousOrigin, pm->state.origin);
955 }
956 
957 
958 /*
959 ================
960 SV_PM_InitialSnapPosition
961 ================
962 */
SV_PM_InitialSnapPosition(void)963 static void SV_PM_InitialSnapPosition (void) {
964 	int			x, y, z;
965 	int16		base[3];
966 	static int	offset[3] = { 0, -1, 1 };
967 
968 	Vec3Copy (pm->state.origin, base);
969 
970 	for (z=0 ; z<3 ; z++) {
971 		pm->state.origin[2] = base[2] + offset[z];
972 		for (y=0 ; y<3 ; y++) {
973 			pm->state.origin[1] = base[1] + offset[y];
974 			for (x=0 ; x<3 ; x++) {
975 				pm->state.origin[0] = base[0] + offset[x];
976 				if (SV_PM_GoodPosition ()) {
977 					pml.origin[0] = pm->state.origin[0]*(1.0f/8.0f);
978 					pml.origin[1] = pm->state.origin[1]*(1.0f/8.0f);
979 					pml.origin[2] = pm->state.origin[2]*(1.0f/8.0f);
980 					Vec3Copy (pm->state.origin, pml.previousOrigin);
981 					return;
982 				}
983 			}
984 		}
985 	}
986 
987 	Com_DevPrintf (PRNT_WARNING, "Bad InitialSnapPosition\n");
988 }
989 
990 
991 /*
992 ================
993 SV_PM_ClampAngles
994 ================
995 */
SV_PM_ClampAngles(void)996 static void SV_PM_ClampAngles (void) {
997 	int16	temp;
998 
999 	if (pm->state.pmFlags & PMF_TIME_TELEPORT) {
1000 		pm->viewAngles[YAW] = SHORT2ANGLE (pm->cmd.angles[YAW] + pm->state.deltaAngles[YAW]);
1001 		pm->viewAngles[PITCH] = 0;
1002 		pm->viewAngles[ROLL] = 0;
1003 	}
1004 	else {
1005 		// circularly clamp the angles with deltas
1006 		temp = pm->cmd.angles[0] + pm->state.deltaAngles[0];
1007 		pm->viewAngles[0] = SHORT2ANGLE(temp);
1008 
1009 		temp = pm->cmd.angles[1] + pm->state.deltaAngles[1];
1010 		pm->viewAngles[1] = SHORT2ANGLE(temp);
1011 
1012 		temp = pm->cmd.angles[2] + pm->state.deltaAngles[2];
1013 		pm->viewAngles[2] = SHORT2ANGLE(temp);
1014 
1015 		// don't let the player look up or down more than 90 degrees
1016 		if ((pm->viewAngles[PITCH] > 89) && (pm->viewAngles[PITCH] < 180))
1017 			pm->viewAngles[PITCH] = 89;
1018 		else if ((pm->viewAngles[PITCH] < 271) && (pm->viewAngles[PITCH] >= 180))
1019 			pm->viewAngles[PITCH] = 271;
1020 	}
1021 
1022 	Angles_Vectors (pm->viewAngles, pml.forward, pml.right, pml.up);
1023 }
1024 
1025 
1026 /*
1027 ================
1028 SV_Pmove
1029 
1030 Can be called by either the server or the client
1031 ================
1032 */
SV_Pmove(pMoveNew_t * pMove,float airAcceleration)1033 void SV_Pmove (pMoveNew_t *pMove, float airAcceleration) {
1034 	pm = pMove;
1035 	pmAirAcceleration = airAcceleration;
1036 
1037 	// clear results
1038 	pm->numTouch = 0;
1039 	Vec3Clear (pm->viewAngles);
1040 	pm->viewHeight = 0;
1041 	pm->groundEntity = 0;
1042 	pm->waterType = 0;
1043 	pm->waterLevel = 0;
1044 
1045 	// clear all pmove local vars
1046 	memset (&pml, 0, sizeof (pml));
1047 
1048 	// convert origin and velocity to float values
1049 	pml.origin[0] = pm->state.origin[0]*(1.0f/8.0f);
1050 	pml.origin[1] = pm->state.origin[1]*(1.0f/8.0f);
1051 	pml.origin[2] = pm->state.origin[2]*(1.0f/8.0f);
1052 
1053 	pml.velocity[0] = pm->state.velocity[0]*(1.0f/8.0f);
1054 	pml.velocity[1] = pm->state.velocity[1]*(1.0f/8.0f);
1055 	pml.velocity[2] = pm->state.velocity[2]*(1.0f/8.0f);
1056 
1057 	// save old org in case we get stuck
1058 	Vec3Copy (pm->state.origin, pml.previousOrigin);
1059 
1060 	pml.frameTime = pm->cmd.msec * 0.001;
1061 
1062 	SV_PM_ClampAngles ();
1063 
1064 	if (pm->state.pmType == PMT_SPECTATOR) {
1065 		SV_PM_FlyMove (qFalse);
1066 		SV_PM_SnapPosition ();
1067 		return;
1068 	}
1069 
1070 	if (pm->state.pmType >= PMT_DEAD) {
1071 		pm->cmd.forwardMove = 0;
1072 		pm->cmd.sideMove = 0;
1073 		pm->cmd.upMove = 0;
1074 	}
1075 
1076 	if (pm->state.pmType == PMT_FREEZE)
1077 		return;		// no movement at all
1078 
1079 	// set mins, maxs, and viewHeight
1080 	SV_PM_CheckDuck ();
1081 
1082 	if (pm->snapInitial)
1083 		SV_PM_InitialSnapPosition ();
1084 
1085 	// set groundEntity, waterType, and waterLevel
1086 	SV_PM_CatagorizePosition ();
1087 
1088 	if (pm->state.pmType == PMT_DEAD)
1089 		SV_PM_DeadMove ();
1090 
1091 	SV_PM_CheckSpecialMovement ();
1092 
1093 	// drop timing counter
1094 	if (pm->state.pmTime) {
1095 		int		msec;
1096 
1097 		msec = pm->cmd.msec >> 3;
1098 		if (!msec)
1099 			msec = 1;
1100 		if (msec >= pm->state.pmTime) {
1101 			pm->state.pmFlags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
1102 			pm->state.pmTime = 0;
1103 		}
1104 		else
1105 			pm->state.pmTime -= msec;
1106 	}
1107 
1108 	if (pm->state.pmFlags & PMF_TIME_TELEPORT) {
1109 		// teleport pause stays exactly in place
1110 	}
1111 	else if (pm->state.pmFlags & PMF_TIME_WATERJUMP) {
1112 		// waterjump has no control, but falls
1113 		pml.velocity[2] -= pm->state.gravity * pml.frameTime;
1114 		if (pml.velocity[2] < 0) {
1115 			// cancel as soon as we are falling down again
1116 			pm->state.pmFlags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
1117 			pm->state.pmTime = 0;
1118 		}
1119 
1120 		SV_PM_StepSlideMove ();
1121 	}
1122 	else {
1123 		SV_PM_CheckJump ();
1124 
1125 		SV_PM_Friction ();
1126 
1127 		if (pm->waterLevel >= 2)
1128 			SV_PM_WaterMove ();
1129 		else {
1130 			vec3_t	angles;
1131 
1132 			Vec3Copy(pm->viewAngles, angles);
1133 			if (angles[PITCH] > 180)
1134 				angles[PITCH] = angles[PITCH] - 360;
1135 			angles[PITCH] /= 3;
1136 
1137 			Angles_Vectors (angles, pml.forward, pml.right, pml.up);
1138 
1139 			SV_PM_AirMove ();
1140 		}
1141 	}
1142 
1143 	// set groundEntity, waterType, and waterLevel for final spot
1144 	SV_PM_CatagorizePosition ();
1145 
1146 	SV_PM_SnapPosition ();
1147 }
1148