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 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include "qcommon.h"
26 
27 
28 
29 #define	STEPSIZE	18
30 
31 extern cvar_t *sv_joustmode;
32 extern cvar_t *sv_tactical;
33 extern cvar_t *sv_excessive;
34 
35 // all of the locals will be zeroed before each
36 // pmove, just to make damn sure we don't have
37 // any differences when running on client or server
38 
39 typedef struct
40 {
41 	vec3_t		origin;			// full float precision
42 	vec3_t		velocity;		// full float precision
43 
44 	vec3_t		forward, right, up;
45 	float		frametime;
46 
47 
48 	csurface_t	*groundsurface;
49 	cplane_t	groundplane;
50 	int			groundcontents;
51 
52 	vec3_t		previous_origin;
53 	qboolean	ladder;
54 } pml_t;
55 
56 pmove_t		*pm;
57 pml_t		pml;
58 
59 
60 // movement parameters
61 float	pm_stopspeed = 100;
62 float	pm_maxspeed = 300;
63 float	pm_duckspeed = 100;
64 float	pm_accelerate = 10;
65 float	pm_airaccelerate = 0;
66 float	pm_wateraccelerate = 10;
67 float	pm_friction = 6;
68 float	pm_waterfriction = 1;
69 float	pm_waterspeed = 400;
70 
71 /*
72 
73   walking up a step should kill some velocity
74 
75 */
76 
77 
78 /*
79 ==================
80 PM_ClipVelocity
81 
82 Slide off of the impacting object
83 returns the blocked flags (1 = floor, 2 = step / wall)
84 ==================
85 */
86 #define	STOP_EPSILON	0.1
87 
PM_ClipVelocity(vec3_t in,vec3_t normal,vec3_t out,float overbounce)88 void PM_ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
89 {
90 	float	backoff;
91 	float	change;
92 	int		i;
93 
94 	backoff = DotProduct (in, normal) * overbounce;
95 
96 	for (i=0 ; i<3 ; i++)
97 	{
98 		change = normal[i]*backoff;
99 		out[i] = in[i] - change;
100 		if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
101 			out[i] = 0;
102 	}
103 }
104 
105 
106 
107 
108 /*
109 ==================
110 PM_StepSlideMove
111 
112 Each intersection will try to step over the obstruction instead of
113 sliding along it.
114 
115 Returns a new origin, velocity, and contact entity
116 Does not modify any world state?
117 ==================
118 */
119 #define	MIN_STEP_NORMAL	0.7		// can't step up onto very steep slopes
120 #define	MAX_CLIP_PLANES	5
PM_StepSlideMove_(void)121 void PM_StepSlideMove_ (void)
122 {
123 	int			bumpcount, numbumps;
124 	vec3_t		dir;
125 	float		d;
126 	int			numplanes;
127 	vec3_t		planes[MAX_CLIP_PLANES];
128 	vec3_t		primal_velocity;
129 	int			i, j;
130 	trace_t	trace;
131 	vec3_t		end;
132 	float		time_left;
133 
134 	numbumps = 4;
135 
136 	VectorCopy (pml.velocity, primal_velocity);
137 	numplanes = 0;
138 
139 	time_left = pml.frametime;
140 
141 	for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
142 	{
143 		for (i=0 ; i<3 ; i++)
144 			end[i] = pml.origin[i] + time_left * pml.velocity[i];
145 
146 		trace = pm->trace (pml.origin, pm->mins, pm->maxs, end);
147 
148 		if (trace.allsolid)
149 		{	// entity is trapped in another solid
150 			pml.velocity[2] = 0;	// don't build up falling damage
151 			return;
152 		}
153 
154 		if (trace.fraction > 0)
155 		{	// actually covered some distance
156 			VectorCopy (trace.endpos, pml.origin);
157 			numplanes = 0;
158 		}
159 
160 		if (trace.fraction == 1)
161 			 break;		// moved the entire distance
162 
163 		// save entity for contact
164 		if (pm->numtouch < MAXTOUCH && trace.ent)
165 		{
166 			pm->touchents[pm->numtouch] = trace.ent;
167 			pm->numtouch++;
168 		}
169 
170 		time_left -= time_left * trace.fraction;
171 
172 		// slide along this plane
173 		if (numplanes >= MAX_CLIP_PLANES)
174 		{	// this shouldn't really happen
175 			VectorCopy (vec3_origin, pml.velocity);
176 			break;
177 		}
178 
179 		VectorCopy (trace.plane.normal, planes[numplanes]);
180 		numplanes++;
181 
182 #if 0
183 	float		rub;
184 
185 		//
186 		// modify velocity so it parallels all of the clip planes
187 		//
188 		if (numplanes == 1)
189 		{	// go along this plane
190 			VectorCopy (pml.velocity, dir);
191 			VectorNormalize (dir);
192 			rub = 1.0 + 0.5 * DotProduct (dir, planes[0]);
193 
194 			// slide along the plane
195 			PM_ClipVelocity (pml.velocity, planes[0], pml.velocity, 1.01);
196 			// rub some extra speed off on xy axis
197 			// not on Z, or you can scrub down walls
198 			pml.velocity[0] *= rub;
199 			pml.velocity[1] *= rub;
200 			pml.velocity[2] *= rub;
201 		}
202 		else if (numplanes == 2)
203 		{	// go along the crease
204 			VectorCopy (pml.velocity, dir);
205 			VectorNormalize (dir);
206 			rub = 1.0 + 0.5 * DotProduct (dir, planes[0]);
207 
208 			// slide along the plane
209 			CrossProduct (planes[0], planes[1], dir);
210 			d = DotProduct (dir, pml.velocity);
211 			VectorScale (dir, d, pml.velocity);
212 
213 			// rub some extra speed off
214 			VectorScale (pml.velocity, rub, pml.velocity);
215 		}
216 		else
217 		{
218 //			Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
219 			VectorCopy (vec3_origin, pml.velocity);
220 			break;
221 		}
222 
223 #else
224 //
225 // modify original_velocity so it parallels all of the clip planes
226 //
227 		for (i=0 ; i<numplanes ; i++)
228 		{
229 			PM_ClipVelocity (pml.velocity, planes[i], pml.velocity, 1.01);
230 			for (j=0 ; j<numplanes ; j++)
231 				if (j != i)
232 				{
233 					if (DotProduct (pml.velocity, planes[j]) < 0)
234 						break;	// not ok
235 				}
236 			if (j == numplanes)
237 				break;
238 		}
239 
240 		if (i != numplanes)
241 		{	// go along this plane
242 		}
243 		else
244 		{	// go along the crease
245 			if (numplanes != 2)
246 			{
247 //				Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
248 				VectorCopy (vec3_origin, pml.velocity);
249 				break;
250 			}
251 			CrossProduct (planes[0], planes[1], dir);
252 			d = DotProduct (dir, pml.velocity);
253 			VectorScale (dir, d, pml.velocity);
254 		}
255 #endif
256 		//
257 		// if velocity is against the original velocity, stop dead
258 		// to avoid tiny occilations in sloping corners
259 		//
260 		if (DotProduct (pml.velocity, primal_velocity) <= 0)
261 		{
262 			VectorCopy (vec3_origin, pml.velocity);
263 			break;
264 		}
265 	}
266 
267 	if (pm->s.pm_time)
268 	{
269 		VectorCopy (primal_velocity, pml.velocity);
270 	}
271 }
272 
273 /*
274 ==================
275 PM_StepSlideMove
276 
277 ==================
278 */
PM_StepSlideMove(void)279 void PM_StepSlideMove (void)
280 {
281 	vec3_t		start_o, start_v;
282 	vec3_t		down_o, down_v;
283 	trace_t		trace;
284 	float		down_dist, up_dist;
285 //	vec3_t		delta;
286 	vec3_t		up, down;
287 
288 	VectorCopy (pml.origin, start_o);
289 	VectorCopy (pml.velocity, start_v);
290 
291 	PM_StepSlideMove_ ();
292 
293 	VectorCopy (pml.origin, down_o);
294 	VectorCopy (pml.velocity, down_v);
295 
296 	VectorCopy (start_o, up);
297 	up[2] += STEPSIZE;
298 
299 	trace = pm->trace (up, pm->mins, pm->maxs, up);
300 	if (trace.allsolid)
301 		return;		// can't step up
302 
303 	// try sliding above
304 	VectorCopy (up, pml.origin);
305 	VectorCopy (start_v, pml.velocity);
306 
307 	PM_StepSlideMove_ ();
308 
309 	// push down the final amount
310 	VectorCopy (pml.origin, down);
311 	down[2] -= STEPSIZE;
312 	trace = pm->trace (pml.origin, pm->mins, pm->maxs, down);
313 	if (!trace.allsolid)
314 	{
315 		VectorCopy (trace.endpos, pml.origin);
316 	}
317 
318 #if 0
319 	VectorSubtract (pml.origin, up, delta);
320 	up_dist = DotProduct (delta, start_v);
321 
322 	VectorSubtract (down_o, start_o, delta);
323 	down_dist = DotProduct (delta, start_v);
324 #else
325 	VectorCopy(pml.origin, up);
326 
327 	// decide which one went farther
328     down_dist = (down_o[0] - start_o[0])*(down_o[0] - start_o[0])
329         + (down_o[1] - start_o[1])*(down_o[1] - start_o[1]);
330     up_dist = (up[0] - start_o[0])*(up[0] - start_o[0])
331         + (up[1] - start_o[1])*(up[1] - start_o[1]);
332 #endif
333 
334 	if (down_dist > up_dist || trace.plane.normal[2] < MIN_STEP_NORMAL)
335 	{
336 		VectorCopy (down_o, pml.origin);
337 		VectorCopy (down_v, pml.velocity);
338 		return;
339 	}
340 	//!! Special case
341 	// if we were walking along a plane, then we need to copy the Z over
342 	pml.velocity[2] = down_v[2];
343 }
344 
345 
346 /*
347 ==================
348 PM_Friction
349 
350 Handles both ground friction and water friction
351 ==================
352 */
PM_Friction(void)353 void PM_Friction (void)
354 {
355 	float	*vel;
356 	float	speed, newspeed, control;
357 	float	friction;
358 	float	drop;
359 
360 	vel = pml.velocity;
361 
362 	speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1] + vel[2]*vel[2]);
363 	if (speed < 1)
364 	{
365 		vel[0] = 0;
366 		vel[1] = 0;
367 		return;
368 	}
369 
370 	drop = 0;
371 
372 // apply ground friction
373 	if ((pm->groundentity && pml.groundsurface && !(pml.groundsurface->flags & SURF_SLICK) ) || (pml.ladder) )
374 	{
375 		friction = pm_friction;
376 		control = speed < pm_stopspeed ? pm_stopspeed : speed;
377 		drop += control*friction*pml.frametime;
378 	}
379 
380 // apply water friction
381 	if (pm->waterlevel && !pml.ladder)
382 		drop += speed*pm_waterfriction*pm->waterlevel*pml.frametime;
383 
384 // scale the velocity
385 	newspeed = speed - drop;
386 	if (newspeed < 0)
387 	{
388 		newspeed = 0;
389 	}
390 	newspeed /= speed;
391 
392 	vel[0] = vel[0] * newspeed;
393 	vel[1] = vel[1] * newspeed;
394 	vel[2] = vel[2] * newspeed;
395 }
396 
397 
398 /*
399 ==============
400 PM_Accelerate
401 
402 Handles user intended acceleration
403 ==============
404 */
PM_Accelerate(vec3_t wishdir,float wishspeed,float accel)405 void PM_Accelerate (vec3_t wishdir, float wishspeed, float accel)
406 {
407 	int			i;
408 	float		addspeed, accelspeed, currentspeed;
409 
410 	currentspeed = DotProduct (pml.velocity, wishdir);
411 	addspeed = wishspeed - currentspeed;
412 	if (addspeed <= 0)
413 		return;
414 	accelspeed = accel*pml.frametime*wishspeed;
415 	if (accelspeed > addspeed)
416 		accelspeed = addspeed;
417 
418 	for (i=0 ; i<3 ; i++)
419 		pml.velocity[i] += accelspeed*wishdir[i];
420 }
421 
PM_AirAccelerate(vec3_t wishdir,float wishspeed,float accel)422 void PM_AirAccelerate (vec3_t wishdir, float wishspeed, float accel)
423 {
424 	int			i;
425 	float		addspeed, accelspeed, currentspeed, wishspd = wishspeed;
426 
427 	if (wishspd > 30)
428 		wishspd = 30;
429 	currentspeed = DotProduct (pml.velocity, wishdir);
430 	addspeed = wishspd - currentspeed;
431 	if (addspeed <= 0)
432 		return;
433 	accelspeed = accel * wishspeed * pml.frametime;
434 	if (accelspeed > addspeed)
435 		accelspeed = addspeed;
436 
437 	for (i=0 ; i<3 ; i++)
438 		pml.velocity[i] += accelspeed*wishdir[i];
439 }
440 
441 /*
442 =============
443 PM_AddCurrents
444 =============
445 */
PM_AddCurrents(vec3_t wishvel)446 void PM_AddCurrents (vec3_t	wishvel)
447 {
448 	vec3_t	v;
449 	float	s;
450 
451 	//
452 	// account for ladders
453 	//
454 
455 	if (pml.ladder && fabs(pml.velocity[2]) <= 200)
456 	{
457 		if ((pm->viewangles[PITCH] <= -15) && (pm->cmd.forwardmove > 0))
458 			wishvel[2] = 200;
459 		else if ((pm->viewangles[PITCH] >= 15) && (pm->cmd.forwardmove > 0))
460 			wishvel[2] = -200;
461 		else if (pm->cmd.upmove > 0)
462 			wishvel[2] = 200;
463 		else if (pm->cmd.upmove < 0)
464 			wishvel[2] = -200;
465 		else
466 			wishvel[2] = 0;
467 
468 		// limit horizontal speed when on a ladder
469 		if (wishvel[0] < -25)
470 			wishvel[0] = -25;
471 		else if (wishvel[0] > 25)
472 			wishvel[0] = 25;
473 
474 		if (wishvel[1] < -25)
475 			wishvel[1] = -25;
476 		else if (wishvel[1] > 25)
477 			wishvel[1] = 25;
478 	}
479 
480 
481 	//
482 	// add water currents
483 	//
484 
485 	if (pm->watertype & MASK_CURRENT)
486 	{
487 		VectorClear (v);
488 
489 		if (pm->watertype & CONTENTS_CURRENT_0)
490 			v[0] += 1;
491 		if (pm->watertype & CONTENTS_CURRENT_90)
492 			v[1] += 1;
493 		if (pm->watertype & CONTENTS_CURRENT_180)
494 			v[0] -= 1;
495 		if (pm->watertype & CONTENTS_CURRENT_270)
496 			v[1] -= 1;
497 		if (pm->watertype & CONTENTS_CURRENT_UP)
498 			v[2] += 1;
499 		if (pm->watertype & CONTENTS_CURRENT_DOWN)
500 			v[2] -= 1;
501 
502 		s = pm_waterspeed;
503 		if ((pm->waterlevel == 1) && (pm->groundentity))
504 			s /= 2;
505 
506 		VectorMA (wishvel, s, v, wishvel);
507 	}
508 
509 	//
510 	// add conveyor belt velocities
511 	//
512 
513 	if (pm->groundentity)
514 	{
515 		VectorClear (v);
516 
517 		if (pml.groundcontents & CONTENTS_CURRENT_0)
518 			v[0] += 1;
519 		if (pml.groundcontents & CONTENTS_CURRENT_90)
520 			v[1] += 1;
521 		if (pml.groundcontents & CONTENTS_CURRENT_180)
522 			v[0] -= 1;
523 		if (pml.groundcontents & CONTENTS_CURRENT_270)
524 			v[1] -= 1;
525 		if (pml.groundcontents & CONTENTS_CURRENT_UP)
526 			v[2] += 1;
527 		if (pml.groundcontents & CONTENTS_CURRENT_DOWN)
528 			v[2] -= 1;
529 
530 		VectorMA (wishvel, 100 /* pm->groundentity->speed */, v, wishvel);
531 	}
532 }
533 
534 
535 /*
536 ===================
537 PM_WaterMove
538 
539 ===================
540 */
PM_WaterMove(void)541 void PM_WaterMove (void)
542 {
543 	int		i;
544 	vec3_t	wishvel;
545 	float	wishspeed;
546 	vec3_t	wishdir;
547 
548 	if(sv_tactical->value)
549 		pm_maxspeed = 200;
550 	else if(sv_excessive->value)
551 		pm_maxspeed = 450;
552 	else
553 		pm_maxspeed = remoteserver_runspeed;
554 
555 //
556 // user intentions
557 //
558 	for (i=0 ; i<3 ; i++)
559 		wishvel[i] = pml.forward[i]*pm->cmd.forwardmove + pml.right[i]*pm->cmd.sidemove;
560 
561 	if (!pm->cmd.forwardmove && !pm->cmd.sidemove && !pm->cmd.upmove)
562 		wishvel[2] -= 60;		// drift towards bottom
563 	else
564 		wishvel[2] += pm->cmd.upmove;
565 
566 	PM_AddCurrents (wishvel);
567 
568 	VectorCopy (wishvel, wishdir);
569 	wishspeed = VectorNormalize(wishdir);
570 
571 	if (wishspeed > pm_maxspeed)
572 	{
573 		VectorScale (wishvel, pm_maxspeed/wishspeed, wishvel);
574 		wishspeed = pm_maxspeed;
575 	}
576 	wishspeed *= 0.5;
577 
578 	PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate);
579 
580 	PM_StepSlideMove ();
581 }
582 
583 
584 /*
585 ===================
586 PM_AirMove
587 
588 ===================
589 */
PM_AirMove(void)590 void PM_AirMove (void)
591 {
592 	int			i;
593 	vec3_t		wishvel;
594 	float		fmove, smove;
595 	vec3_t		wishdir;
596 	float		wishspeed;
597 	float		maxspeed;
598 
599 	if(sv_tactical->value)
600 		pm_maxspeed = 200;
601 	else if(sv_excessive->value)
602 		pm_maxspeed = 450;
603 	else
604 		pm_maxspeed = remoteserver_runspeed;
605 
606 	fmove = pm->cmd.forwardmove;
607 	smove = pm->cmd.sidemove;
608 
609 //!!!!! pitch should be 1/3 so this isn't needed??!
610 #if 0
611 	pml.forward[2] = 0;
612 	pml.right[2] = 0;
613 	VectorNormalize (pml.forward);
614 	VectorNormalize (pml.right);
615 #endif
616 
617 	for (i=0 ; i<2 ; i++)
618 		wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
619 	wishvel[2] = 0;
620 
621 	PM_AddCurrents (wishvel);
622 
623 	VectorCopy (wishvel, wishdir);
624 	wishspeed = VectorNormalize(wishdir);
625 
626 //
627 // clamp to server defined max speed
628 //
629 	maxspeed = (pm->s.pm_flags & PMF_DUCKED) ? pm_duckspeed : pm_maxspeed;
630 
631 	if (wishspeed > maxspeed)
632 	{
633 		VectorScale (wishvel, maxspeed/wishspeed, wishvel);
634 		wishspeed = maxspeed;
635 	}
636 
637 	if ( pml.ladder )
638 	{
639 		PM_Accelerate (wishdir, wishspeed, pm_accelerate);
640 		if (!wishvel[2])
641 		{
642 			if (pml.velocity[2] > 0)
643 			{
644 				pml.velocity[2] -= pm->s.gravity * pml.frametime;
645 				if (pml.velocity[2] < 0)
646 					pml.velocity[2]  = 0;
647 			}
648 			else
649 			{
650 				pml.velocity[2] += pm->s.gravity * pml.frametime;
651 				if (pml.velocity[2] > 0)
652 					pml.velocity[2]  = 0;
653 			}
654 		}
655 		PM_StepSlideMove ();
656 	}
657 	else if ( pm->groundentity )
658 	{	// walking on ground
659 		pml.velocity[2] = 0; //!!! this is before the accel
660 		PM_Accelerate (wishdir, wishspeed, pm_accelerate);
661 
662 // PGM	-- fix for negative trigger_gravity fields
663 //		pml.velocity[2] = 0;
664 		if(pm->s.gravity > 0)
665 			pml.velocity[2] = 0;
666 		else
667 			pml.velocity[2] -= pm->s.gravity * pml.frametime;
668 // PGM
669 
670 		if (!pml.velocity[0] && !pml.velocity[1])
671 			return;
672 		PM_StepSlideMove ();
673 	}
674 	else
675 	{	// not on ground, so little effect on velocity
676 		if (pm_airaccelerate)
677 			PM_AirAccelerate (wishdir, wishspeed, pm_accelerate);
678 		else
679 			PM_Accelerate (wishdir, wishspeed, 1);
680 		// add gravity
681 		pml.velocity[2] -= pm->s.gravity * pml.frametime;
682 		PM_StepSlideMove ();
683 	}
684 }
685 
686 
687 
688 /*
689 =============
690 PM_CatagorizePosition
691 =============
692 */
PM_CatagorizePosition(void)693 void PM_CatagorizePosition (void)
694 {
695 	vec3_t		point;
696 	int			cont;
697 	trace_t		trace;
698 	int			sample1;
699 	int			sample2;
700 
701 // if the player hull point one unit down is solid, the player
702 // is on ground
703 
704 // see if standing on something solid
705 	point[0] = pml.origin[0];
706 	point[1] = pml.origin[1];
707 	point[2] = pml.origin[2] - 0.15; //Irritant - changed from 0.25 - this seems to fix the issue
708 									 //in which sometimes while strafejumping it seemed the jump
709 									 //was getting "lost"
710 	if (pml.velocity[2] > 180) //!!ZOID changed from 100 to 180 (ramp accel)
711 	{
712 		pm->s.pm_flags &= ~PMF_ON_GROUND;
713 		pm->groundentity = NULL;
714 	}
715 	else
716 	{
717 		trace = pm->trace (pml.origin, pm->mins, pm->maxs, point);
718 		pml.groundplane = trace.plane;
719 		pml.groundsurface = trace.surface;
720 		pml.groundcontents = trace.contents;
721 
722 		if (!trace.ent || (trace.plane.normal[2] < 0.7 && !trace.startsolid) )
723 		{
724 			pm->groundentity = NULL;
725 			pm->s.pm_flags &= ~PMF_ON_GROUND;
726 		}
727 		else
728 		{
729 			pm->groundentity = trace.ent;
730 
731 			// hitting solid ground will end a waterjump
732 			if (pm->s.pm_flags & PMF_TIME_WATERJUMP)
733 			{
734 				pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
735 				pm->s.pm_time = 0;
736 			}
737 
738 			if (! (pm->s.pm_flags & PMF_ON_GROUND) )
739 			{	// just hit the ground
740 				pm->s.pm_flags |= PMF_ON_GROUND;
741 				// don't do landing time if we were just going down a slope
742 				if (pml.velocity[2] < -200)
743 				{
744 					pm->s.pm_flags |= PMF_TIME_LAND;
745 					// don't allow another jump for a little while
746 					if (pml.velocity[2] < -400)
747 						pm->s.pm_time = 25;
748 					else
749 						pm->s.pm_time = 18;
750 				}
751 			}
752 		}
753 
754 #if 0
755 		if (trace.fraction < 1.0 && trace.ent && pml.velocity[2] < 0)
756 			pml.velocity[2] = 0;
757 #endif
758 
759 		if (pm->numtouch < MAXTOUCH && trace.ent)
760 		{
761 			pm->touchents[pm->numtouch] = trace.ent;
762 			pm->numtouch++;
763 		}
764 	}
765 
766 //
767 // get waterlevel, accounting for ducking
768 //
769 	pm->waterlevel = 0;
770 	pm->watertype = 0;
771 
772 	sample2 = pm->viewheight - pm->mins[2];
773 	sample1 = sample2 / 2;
774 
775 	point[2] = pml.origin[2] + pm->mins[2] + 1;
776 	cont = pm->pointcontents (point);
777 
778 	if (cont & MASK_WATER)
779 	{
780 		pm->watertype = cont;
781 		pm->waterlevel = 1;
782 		point[2] = pml.origin[2] + pm->mins[2] + sample1;
783 		cont = pm->pointcontents (point);
784 		if (cont & MASK_WATER)
785 		{
786 			pm->waterlevel = 2;
787 			point[2] = pml.origin[2] + pm->mins[2] + sample2;
788 			cont = pm->pointcontents (point);
789 			if (cont & MASK_WATER)
790 				pm->waterlevel = 3;
791 		}
792 	}
793 
794 }
795 
796 
797 /*
798 =============
799 PM_CheckJump
800 =============
801 */
PM_CheckJump(void)802 void PM_CheckJump (void)
803 {
804 	qboolean jousting = false;
805 
806 	if(sv_joustmode->value)
807 		jousting = true;
808 
809 	if (remoteserver_jousting)
810 	    jousting = true;
811 
812 //	if (pm->s.pm_flags & PMF_TIME_LAND)
813 //	{	// hasn't been long enough since landing to jump again
814 //		return;
815 //	}
816 
817 	if (pm->cmd.upmove < 10)
818 	{	// not holding jump
819 		pm->s.pm_flags &= ~PMF_JUMP_HELD;
820 		return;
821 	}
822 
823 	// must wait for jump to be released
824 	if (pm->s.pm_flags & PMF_JUMP_HELD)
825 		return;
826 
827 	if (pm->s.pm_type == PM_DEAD)
828 		return;
829 
830 	if (pm->waterlevel >= 2)
831 	{	// swimming, not jumping
832 		pm->groundentity = NULL;
833 
834 		if (pml.velocity[2] <= -300)
835 			return;
836 
837 		if (pm->watertype == CONTENTS_WATER)
838 			pml.velocity[2] = 100;
839 		else if (pm->watertype == CONTENTS_SLIME)
840 			pml.velocity[2] = 80;
841 		else
842 			pml.velocity[2] = 50;
843 		return;
844 	}
845 
846 	if (pm->groundentity == NULL && !jousting)
847 		return;		// in air, so no effect
848 
849 	//joust mode
850 	if(pm->joustattempts > 30 && jousting) {
851 		return;
852 	}
853 
854 	pm->s.pm_flags |= PMF_JUMP_HELD;
855 
856 	pm->groundentity = NULL;
857 	pml.velocity[2] += 270;
858 	if (pml.velocity[2] < 270)
859 		pml.velocity[2] = 270;
860 }
861 
862 
863 /*
864 =============
865 PM_CheckSpecialMovement
866 =============
867 */
PM_CheckSpecialMovement(void)868 void PM_CheckSpecialMovement (void)
869 {
870 	vec3_t	spot;
871 	int		cont;
872 	vec3_t	flatforward;
873 	trace_t	trace;
874 
875 	if (pm->s.pm_time)
876 		return;
877 
878 	pml.ladder = false;
879 
880 	// check for ladder
881 	flatforward[0] = pml.forward[0];
882 	flatforward[1] = pml.forward[1];
883 	flatforward[2] = 0;
884 	VectorNormalize (flatforward);
885 
886 	VectorMA (pml.origin, 1, flatforward, spot);
887 	trace = pm->trace (pml.origin, pm->mins, pm->maxs, spot);
888 	if ((trace.fraction < 1) && (trace.contents & CONTENTS_LADDER))
889 		pml.ladder = true;
890 
891 	// check for water jump
892 	if (pm->waterlevel != 2)
893 		return;
894 
895 	VectorMA (pml.origin, 30, flatforward, spot);
896 	spot[2] += 4;
897 	cont = pm->pointcontents (spot);
898 	if (!(cont & CONTENTS_SOLID))
899 		return;
900 
901 	spot[2] += 16;
902 	cont = pm->pointcontents (spot);
903 	if (cont)
904 		return;
905 	// jump out of water
906 	VectorScale (flatforward, 50, pml.velocity);
907 	pml.velocity[2] = 350;
908 
909 	pm->s.pm_flags |= PMF_TIME_WATERJUMP;
910 	pm->s.pm_time = 255;
911 }
912 
913 
914 /*
915 ===============
916 PM_FlyMove
917 ===============
918 */
PM_FlyMove(qboolean doclip)919 void PM_FlyMove (qboolean doclip)
920 {
921 	float	speed, drop, friction, control, newspeed;
922 	float	currentspeed, addspeed, accelspeed;
923 	int			i;
924 	vec3_t		wishvel;
925 	float		fmove, smove;
926 	vec3_t		wishdir;
927 	float		wishspeed;
928 	vec3_t		end;
929 	trace_t	trace;
930 
931 	if(sv_tactical->value)
932 		pm_maxspeed = 200;
933 	else if(sv_excessive->value)
934 		pm_maxspeed = 450;
935 	else
936 		pm_maxspeed = remoteserver_runspeed;
937 
938 	pm->viewheight = 22;
939 
940 	// friction
941 
942 	speed = VectorLength (pml.velocity);
943 	if (speed < 1)
944 	{
945 		VectorCopy (vec3_origin, pml.velocity);
946 	}
947 	else
948 	{
949 		drop = 0;
950 
951 		friction = pm_friction*1.5;	// extra friction
952 		control = speed < pm_stopspeed ? pm_stopspeed : speed;
953 		drop += control*friction*pml.frametime;
954 
955 		// scale the velocity
956 		newspeed = speed - drop;
957 		if (newspeed < 0)
958 			newspeed = 0;
959 		newspeed /= speed;
960 
961 		VectorScale (pml.velocity, newspeed, pml.velocity);
962 	}
963 
964 	// accelerate
965 	fmove = pm->cmd.forwardmove;
966 	smove = pm->cmd.sidemove;
967 
968 	VectorNormalize (pml.forward);
969 	VectorNormalize (pml.right);
970 
971 	for (i=0 ; i<3 ; i++)
972 		wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
973 	wishvel[2] += pm->cmd.upmove;
974 
975 	VectorCopy (wishvel, wishdir);
976 	wishspeed = VectorNormalize(wishdir);
977 
978 	//
979 	// clamp to server defined max speed
980 	//
981 	if (wishspeed > pm_maxspeed)
982 	{
983 		VectorScale (wishvel, pm_maxspeed/wishspeed, wishvel);
984 		wishspeed = pm_maxspeed;
985 	}
986 
987 
988 	currentspeed = DotProduct(pml.velocity, wishdir);
989 	addspeed = wishspeed - currentspeed;
990 	if (addspeed <= 0)
991 		return;
992 	accelspeed = pm_accelerate*pml.frametime*wishspeed;
993 	if (accelspeed > addspeed)
994 		accelspeed = addspeed;
995 
996 	for (i=0 ; i<3 ; i++)
997 		pml.velocity[i] += accelspeed*wishdir[i];
998 
999 	if (doclip) {
1000 		for (i=0 ; i<3 ; i++)
1001 			end[i] = pml.origin[i] + pml.frametime * pml.velocity[i];
1002 
1003 		trace = pm->trace (pml.origin, pm->mins, pm->maxs, end);
1004 
1005 		VectorCopy (trace.endpos, pml.origin);
1006 	} else {
1007 		// move
1008 		VectorMA (pml.origin, pml.frametime, pml.velocity, pml.origin);
1009 	}
1010 }
1011 
1012 
1013 /*
1014 ==============
1015 PM_CheckDuck
1016 
1017 Sets mins, maxs, and pm->viewheight
1018 ==============
1019 */
PM_CheckDuck(void)1020 void PM_CheckDuck (void)
1021 {
1022 	trace_t	trace;
1023 
1024 	pm->mins[0] = -16;
1025 	pm->mins[1] = -16;
1026 
1027 	pm->maxs[0] = 16;
1028 	pm->maxs[1] = 16;
1029 
1030 	if (pm->s.pm_type == PM_GIB)
1031 	{
1032 		pm->mins[2] = 0;
1033 		pm->maxs[2] = 16;
1034 		pm->viewheight = 8;
1035 		return;
1036 	}
1037 
1038 	pm->mins[2] = -24;
1039 
1040 	if (pm->s.pm_type == PM_DEAD)
1041 	{
1042 		pm->s.pm_flags |= PMF_DUCKED;
1043 	}
1044 	else if (pm->cmd.upmove < 0 && (pm->s.pm_flags & PMF_ON_GROUND) )
1045 	{	// duck
1046 		pm->s.pm_flags |= PMF_DUCKED;
1047 	}
1048 	else
1049 	{	// stand up if possible
1050 		if (pm->s.pm_flags & PMF_DUCKED)
1051 		{
1052 			// try to stand up
1053 			pm->maxs[2] = 32;
1054 			trace = pm->trace (pml.origin, pm->mins, pm->maxs, pml.origin);
1055 			if (!trace.allsolid)
1056 				pm->s.pm_flags &= ~PMF_DUCKED;
1057 		}
1058 	}
1059 
1060 	if (pm->s.pm_flags & PMF_DUCKED)
1061 	{
1062 		pm->maxs[2] = 20;
1063 		pm->viewheight = -2;
1064 	}
1065 	else
1066 	{
1067 		pm->maxs[2] = 32;
1068 		pm->viewheight = 22;
1069 	}
1070 }
1071 
1072 
1073 /*
1074 ==============
1075 PM_DeadMove
1076 ==============
1077 */
PM_DeadMove(void)1078 void PM_DeadMove (void)
1079 {
1080 	float	forward;
1081 
1082 	if (!pm->groundentity)
1083 		return;
1084 
1085 	// extra friction
1086 
1087 	forward = VectorLength (pml.velocity);
1088 	forward -= 20;
1089 	if (forward <= 0)
1090 	{
1091 		VectorClear (pml.velocity);
1092 	}
1093 	else
1094 	{
1095 		VectorNormalize (pml.velocity);
1096 		VectorScale (pml.velocity, forward, pml.velocity);
1097 	}
1098 }
1099 
1100 
PM_GoodPosition(void)1101 qboolean	PM_GoodPosition (void)
1102 {
1103 	trace_t	trace;
1104 	vec3_t	origin, end;
1105 	int		i;
1106 
1107 	if (pm->s.pm_type == PM_SPECTATOR)
1108 		return true;
1109 
1110 	for (i=0 ; i<3 ; i++)
1111 		origin[i] = end[i] = pm->s.origin[i]*0.125;
1112 	trace = pm->trace (origin, pm->mins, pm->maxs, end);
1113 
1114 	return !trace.allsolid;
1115 }
1116 
1117 /*
1118 ================
1119 PM_SnapPosition
1120 
1121 On exit, the origin will have a value that is pre-quantized to the 0.125
1122 precision of the network channel and in a valid position.
1123 ================
1124 */
PM_SnapPosition(void)1125 void PM_SnapPosition (void)
1126 {
1127 	int		sign[3];
1128 	int		i, j, bits;
1129 	int 	base[3];
1130 	// try all single bits first
1131 	static int jitterbits[8] = {0,4,1,2,3,5,6,7};
1132 
1133 	// snap velocity to eigths
1134 	for (i=0 ; i<3 ; i++)
1135 		pm->s.velocity[i] = (int)(pml.velocity[i]*8);
1136 
1137 	for (i=0 ; i<3 ; i++)
1138 	{
1139 		if (pml.origin[i] >= 0)
1140 			sign[i] = 1;
1141 		else
1142 			sign[i] = -1;
1143 		pm->s.origin[i] = (int)(pml.origin[i]*8);
1144 		if (pm->s.origin[i]*0.125 == pml.origin[i])
1145 			sign[i] = 0;
1146 	}
1147 	VectorCopy (pm->s.origin, base);
1148 
1149 	// try all combinations
1150 	for (j=0 ; j<8 ; j++)
1151 	{
1152 		bits = jitterbits[j];
1153 		VectorCopy (base, pm->s.origin);
1154 		for (i=0 ; i<3 ; i++)
1155 			if (bits & (1<<i) )
1156 				pm->s.origin[i] += sign[i];
1157 
1158 		if (PM_GoodPosition ())
1159 			return;
1160 	}
1161 
1162 	// go back to the last position
1163 	VectorCopy (pml.previous_origin, pm->s.origin);
1164 //	Com_DPrintf ("using previous_origin\n");
1165 }
1166 
1167 #if 0
1168 //NO LONGER USED
1169 /*
1170 ================
1171 PM_InitialSnapPosition
1172 
1173 ================
1174 */
1175 void PM_InitialSnapPosition (void)
1176 {
1177 	int		x, y, z;
1178 	short	base[3];
1179 
1180 	VectorCopy (pm->s.origin, base);
1181 
1182 	for (z=1 ; z>=-1 ; z--)
1183 	{
1184 		pm->s.origin[2] = base[2] + z;
1185 		for (y=1 ; y>=-1 ; y--)
1186 		{
1187 			pm->s.origin[1] = base[1] + y;
1188 			for (x=1 ; x>=-1 ; x--)
1189 			{
1190 				pm->s.origin[0] = base[0] + x;
1191 				if (PM_GoodPosition ())
1192 				{
1193 					pml.origin[0] = pm->s.origin[0]*0.125;
1194 					pml.origin[1] = pm->s.origin[1]*0.125;
1195 					pml.origin[2] = pm->s.origin[2]*0.125;
1196 					VectorCopy (pm->s.origin, pml.previous_origin);
1197 					return;
1198 				}
1199 			}
1200 		}
1201 	}
1202 
1203 	Com_DPrintf ("Bad InitialSnapPosition\n");
1204 }
1205 #else
1206 /*
1207 ================
1208 PM_InitialSnapPosition
1209 
1210 ================
1211 */
PM_InitialSnapPosition(void)1212 void PM_InitialSnapPosition(void)
1213 {
1214 	int        x, y, z;
1215 	int        base[3];
1216 	static int offset[3] = { 0, -1, 1 };
1217 
1218 	VectorCopy (pm->s.origin, base);
1219 
1220 	for ( z = 0; z < 3; z++ ) {
1221 		pm->s.origin[2] = base[2] + offset[ z ];
1222 		for ( y = 0; y < 3; y++ ) {
1223 			pm->s.origin[1] = base[1] + offset[ y ];
1224 			for ( x = 0; x < 3; x++ ) {
1225 				pm->s.origin[0] = base[0] + offset[ x ];
1226 				if (PM_GoodPosition ()) {
1227 					pml.origin[0] = pm->s.origin[0]*0.125;
1228 					pml.origin[1] = pm->s.origin[1]*0.125;
1229 					pml.origin[2] = pm->s.origin[2]*0.125;
1230 					VectorCopy (pm->s.origin, pml.previous_origin);
1231 					return;
1232 				}
1233 			}
1234 		}
1235 	}
1236 
1237 	Com_DPrintf ("Bad InitialSnapPosition\n");
1238 }
1239 
1240 #endif
1241 
1242 /*
1243 ================
1244 PM_ClampAngles
1245 
1246 ================
1247 */
PM_ClampAngles(void)1248 void PM_ClampAngles (void)
1249 {
1250 	short	temp;
1251 	int		i;
1252 
1253 	if (pm->s.pm_flags & PMF_TIME_TELEPORT)
1254 	{
1255 		pm->viewangles[YAW] = SHORT2ANGLE(pm->cmd.angles[YAW] + pm->s.delta_angles[YAW]);
1256 		pm->viewangles[PITCH] = 0;
1257 		pm->viewangles[ROLL] = 0;
1258 	}
1259 	else
1260 	{
1261 		// circularly clamp the angles with deltas
1262 		for (i=0 ; i<3 ; i++)
1263 		{
1264 			temp = pm->cmd.angles[i] + pm->s.delta_angles[i];
1265 			pm->viewangles[i] = SHORT2ANGLE(temp);
1266 		}
1267 
1268 		// don't let the player look up or down more than 90 degrees
1269 		if (pm->viewangles[PITCH] > 89 && pm->viewangles[PITCH] < 180)
1270 			pm->viewangles[PITCH] = 89;
1271 		else if (pm->viewangles[PITCH] < 271 && pm->viewangles[PITCH] >= 180)
1272 			pm->viewangles[PITCH] = 271;
1273 	}
1274 	AngleVectors (pm->viewangles, pml.forward, pml.right, pml.up);
1275 }
1276 
1277 /*
1278 ================
1279 Pmove
1280 
1281 Can be called by either the server or the client
1282 ================
1283 */
Pmove(pmove_t * pmove)1284 void Pmove (pmove_t *pmove)
1285 {
1286 	pm = pmove;
1287 
1288 	// clear results
1289 	pm->numtouch = 0;
1290 	VectorClear (pm->viewangles);
1291 	pm->viewheight = 0;
1292 	pm->groundentity = 0;
1293 	pm->watertype = 0;
1294 	pm->waterlevel = 0;
1295 
1296 	// clear all pmove local vars
1297 	memset (&pml, 0, sizeof(pml));
1298 
1299 	// convert origin and velocity to float values
1300 	pml.origin[0] = pm->s.origin[0]*0.125f;
1301 	pml.origin[1] = pm->s.origin[1]*0.125f;
1302 	pml.origin[2] = pm->s.origin[2]*0.125f;
1303 
1304 	pml.velocity[0] = pm->s.velocity[0]*0.125f;
1305 	pml.velocity[1] = pm->s.velocity[1]*0.125f;
1306 	pml.velocity[2] = pm->s.velocity[2]*0.125f;
1307 
1308 	// save old org in case we get stuck
1309 	VectorCopy (pm->s.origin, pml.previous_origin);
1310 
1311 	pml.frametime = pm->cmd.msec * 0.001f;
1312 
1313 	PM_ClampAngles ();
1314 
1315 	if (pm->s.pm_type == PM_SPECTATOR)
1316 	{
1317 		PM_FlyMove (false);
1318 		PM_SnapPosition ();
1319 		return;
1320 	}
1321 
1322 	if (pm->s.pm_type >= PM_DEAD)
1323 	{
1324 		pm->cmd.forwardmove = 0;
1325 		pm->cmd.sidemove = 0;
1326 		pm->cmd.upmove = 0;
1327 	}
1328 
1329 	if (pm->s.pm_type == PM_FREEZE)
1330 		return;		// no movement at all
1331 
1332 	// set mins, maxs, and viewheight
1333 	PM_CheckDuck ();
1334 
1335 	if (pm->snapinitial)
1336 		PM_InitialSnapPosition ();
1337 
1338 	// set groundentity, watertype, and waterlevel
1339 	PM_CatagorizePosition ();
1340 
1341 	if (pm->s.pm_type == PM_DEAD)
1342 		PM_DeadMove ();
1343 
1344 	PM_CheckSpecialMovement ();
1345 
1346 	// drop timing counter
1347 	if (pm->s.pm_time)
1348 	{
1349 		int		msec;
1350 
1351 		msec = pm->cmd.msec >> 3;
1352 		if (!msec)
1353 			msec = 1;
1354 		if ( msec >= pm->s.pm_time)
1355 		{
1356 			pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
1357 			pm->s.pm_time = 0;
1358 		}
1359 		else
1360 			pm->s.pm_time -= msec;
1361 	}
1362 
1363 	if (pm->s.pm_flags & PMF_TIME_TELEPORT)
1364 	{	// teleport pause stays exactly in place
1365 	}
1366 	else if (pm->s.pm_flags & PMF_TIME_WATERJUMP)
1367 	{	// waterjump has no control, but falls
1368 		pml.velocity[2] -= pm->s.gravity * pml.frametime;
1369 		if (pml.velocity[2] < 0)
1370 		{	// cancel as soon as we are falling down again
1371 			pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
1372 			pm->s.pm_time = 0;
1373 		}
1374 
1375 		PM_StepSlideMove ();
1376 	}
1377 	else
1378 	{
1379 		PM_CheckJump ();
1380 
1381 		PM_Friction ();
1382 
1383 		if (pm->waterlevel >= 2)
1384 			PM_WaterMove ();
1385 		else {
1386 			vec3_t	angles;
1387 
1388 			VectorCopy(pm->viewangles, angles);
1389 			if (angles[PITCH] > 180)
1390 				angles[PITCH] = angles[PITCH] - 360;
1391 			angles[PITCH] /= 3;
1392 
1393 			AngleVectors (angles, pml.forward, pml.right, pml.up);
1394 
1395 			PM_AirMove ();
1396 		}
1397 	}
1398 
1399 	// set groundentity, watertype, and waterlevel for final spot
1400 	PM_CatagorizePosition ();
1401 
1402 	PM_SnapPosition ();
1403 }
1404 
1405