Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

pmove.c (27381B)


      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 
     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
    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 */
    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 */
    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 */
    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 
    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 */
    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 */
    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 */
    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 */
    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 */
    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 */
    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 */
    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 */
    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 */
   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 
   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 */
   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 */
   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 */
   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 */
   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