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