diff options
author | Andrey Nazarov <skuller@skuller.net> | 2007-08-14 20:18:08 +0000 |
---|---|---|
committer | Andrey Nazarov <skuller@skuller.net> | 2007-08-14 20:18:08 +0000 |
commit | f294db4ccf45f6274e65260dd6f9a2c5faa94313 (patch) | |
tree | e8cf1ba2bfe9c8417eec17faf912442f52fc4ef2 /source/pmove.c |
Initial import of the new Q2PRO tree.
Diffstat (limited to 'source/pmove.c')
-rw-r--r-- | source/pmove.c | 1319 |
1 files changed, 1319 insertions, 0 deletions
diff --git a/source/pmove.c b/source/pmove.c new file mode 100644 index 0000000..23c81e6 --- /dev/null +++ b/source/pmove.c @@ -0,0 +1,1319 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "com_local.h" + + + +#define STEPSIZE 18 + +// all of the locals will be zeroed before each +// pmove, just to make damn sure we don't have +// any differences when running on client or server + +typedef struct +{ + vec3_t origin; // full float precision + vec3_t velocity; // full float precision + + vec3_t forward, right, up; + float frametime; + + + csurface_t *groundsurface; + cplane_t groundplane; + int groundcontents; + + vec3_t previous_origin; + qboolean ladder; +} pml_t; + +static pmove_t *pm; +static pml_t pml; + +static pmoveParams_t *pmp; + +// movement parameters +static float pm_stopspeed = 100; +static float pm_duckspeed = 100; +static float pm_accelerate = 10; +static float pm_wateraccelerate = 10; +static float pm_waterspeed = 400; + +/* + + walking up a step should kill some velocity + +*/ + + +/* +================== +PM_ClipVelocity + +Slide off of the impacting object +returns the blocked flags (1 = floor, 2 = step / wall) +================== +*/ +#define STOP_EPSILON 0.1 + +void PM_ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce) +{ + float backoff; + float change; + int i; + + backoff = DotProduct (in, normal) * overbounce; + + for (i=0 ; i<3 ; i++) + { + change = normal[i]*backoff; + out[i] = in[i] - change; + if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON) + out[i] = 0; + } +} + + + + +/* +================== +PM_StepSlideMove + +Each intersection will try to step over the obstruction instead of +sliding along it. + +Returns a new origin, velocity, and contact entity +Does not modify any world state? +================== +*/ +#define MIN_STEP_NORMAL 0.7 // can't step up onto very steep slopes +#define MAX_CLIP_PLANES 5 +void PM_StepSlideMove_ (void) +{ + int bumpcount, numbumps; + vec3_t dir; + float d; + int numplanes; + vec3_t planes[MAX_CLIP_PLANES]; + vec3_t primal_velocity; + int i, j; + trace_t trace; + vec3_t end; + float time_left; + + numbumps = 4; + + VectorCopy (pml.velocity, primal_velocity); + numplanes = 0; + + time_left = pml.frametime; + + for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++) + { + for (i=0 ; i<3 ; i++) + end[i] = pml.origin[i] + time_left * pml.velocity[i]; + + trace = pm->trace (pml.origin, pm->mins, pm->maxs, end); + + if (trace.allsolid) + { // entity is trapped in another solid + pml.velocity[2] = 0; // don't build up falling damage + return; + } + + if (trace.fraction > 0) + { // actually covered some distance + VectorCopy (trace.endpos, pml.origin); + numplanes = 0; + } + + if (trace.fraction == 1) + break; // moved the entire distance + + // save entity for contact + if (pm->numtouch < MAXTOUCH && trace.ent) + { + pm->touchents[pm->numtouch] = trace.ent; + pm->numtouch++; + } + + time_left -= time_left * trace.fraction; + + // slide along this plane + if (numplanes >= MAX_CLIP_PLANES) + { // this shouldn't really happen + VectorCopy (vec3_origin, pml.velocity); + break; + } + + VectorCopy (trace.plane.normal, planes[numplanes]); + numplanes++; + +// +// modify original_velocity so it parallels all of the clip planes +// + for (i=0 ; i<numplanes ; i++) + { + PM_ClipVelocity (pml.velocity, planes[i], pml.velocity, 1.01); + for (j=0 ; j<numplanes ; j++) + if (j != i) + { + if (DotProduct (pml.velocity, planes[j]) < 0) + break; // not ok + } + if (j == numplanes) + break; + } + + if (i != numplanes) + { // go along this plane + } + else + { // go along the crease + if (numplanes != 2) + { +// Con_Printf ("clip velocity, numplanes == %i\n",numplanes); + VectorCopy (vec3_origin, pml.velocity); + break; + } + CrossProduct (planes[0], planes[1], dir); + d = DotProduct (dir, pml.velocity); + VectorScale (dir, d, pml.velocity); + } + + // + // if velocity is against the original velocity, stop dead + // to avoid tiny occilations in sloping corners + // + if (DotProduct (pml.velocity, primal_velocity) <= 0) + { + VectorCopy (vec3_origin, pml.velocity); + break; + } + } + + if (pm->s.pm_time) + { + VectorCopy (primal_velocity, pml.velocity); + } +} + +/* +================== +PM_StepSlideMove + +================== +*/ +void PM_StepSlideMove (void) +{ + vec3_t start_o, start_v; + vec3_t down_o, down_v; + trace_t trace; + float down_dist, up_dist; +// vec3_t delta; + vec3_t up, down; + + VectorCopy (pml.origin, start_o); + VectorCopy (pml.velocity, start_v); + + PM_StepSlideMove_ (); + + VectorCopy (pml.origin, down_o); + VectorCopy (pml.velocity, down_v); + + VectorCopy (start_o, up); + up[2] += STEPSIZE; + + trace = pm->trace (up, pm->mins, pm->maxs, up); + if (trace.allsolid) + return; // can't step up + + // try sliding above + VectorCopy (up, pml.origin); + VectorCopy (start_v, pml.velocity); + + PM_StepSlideMove_ (); + + // push down the final amount + VectorCopy (pml.origin, down); + down[2] -= STEPSIZE; + trace = pm->trace (pml.origin, pm->mins, pm->maxs, down); + if (!trace.allsolid) + { + VectorCopy (trace.endpos, pml.origin); + } + + VectorCopy(pml.origin, up); + + // decide which one went farther + down_dist = (down_o[0] - start_o[0])*(down_o[0] - start_o[0]) + + (down_o[1] - start_o[1])*(down_o[1] - start_o[1]); + up_dist = (up[0] - start_o[0])*(up[0] - start_o[0]) + + (up[1] - start_o[1])*(up[1] - start_o[1]); + + if (down_dist > up_dist || trace.plane.normal[2] < MIN_STEP_NORMAL) + { + VectorCopy (down_o, pml.origin); + VectorCopy (down_v, pml.velocity); + return; + } + //!! Special case + // if we were walking along a plane, then we need to copy the Z over + pml.velocity[2] = down_v[2]; +} + + +/* +================== +PM_Friction + +Handles both ground friction and water friction +================== +*/ +void PM_Friction (void) +{ + float *vel; + float speed, newspeed, control; + float friction; + float drop; + + vel = pml.velocity; + + speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1] + vel[2]*vel[2]); + if (speed < 1) + { + vel[0] = 0; + vel[1] = 0; + return; + } + + drop = 0; + +// apply ground friction + if ((pm->groundentity && pml.groundsurface && !(pml.groundsurface->flags & SURF_SLICK) ) || (pml.ladder) ) + { + friction = pmp->friction; + control = speed < pm_stopspeed ? pm_stopspeed : speed; + drop += control*friction*pml.frametime; + } + +// apply water friction + if (pm->waterlevel && !pml.ladder) + drop += speed*pmp->waterfriction*pm->waterlevel*pml.frametime; + +// scale the velocity + newspeed = speed - drop; + if (newspeed < 0) + { + newspeed = 0; + } + newspeed /= speed; + + vel[0] = vel[0] * newspeed; + vel[1] = vel[1] * newspeed; + vel[2] = vel[2] * newspeed; +} + + +/* +============== +PM_Accelerate + +Handles user intended acceleration +============== +*/ +void PM_Accelerate (vec3_t wishdir, float wishspeed, float accel) +{ + int i; + float addspeed, accelspeed, currentspeed; + + currentspeed = DotProduct (pml.velocity, wishdir); + addspeed = wishspeed - currentspeed; + if (addspeed <= 0) + return; + accelspeed = accel*pml.frametime*wishspeed; + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i=0 ; i<3 ; i++) + pml.velocity[i] += accelspeed*wishdir[i]; +} + +void PM_AirAccelerate (vec3_t wishdir, float wishspeed, float accel) +{ + int i; + float addspeed, accelspeed, currentspeed, wishspd = wishspeed; + + if (wishspd > 30) + wishspd = 30; + currentspeed = DotProduct (pml.velocity, wishdir); + addspeed = wishspd - currentspeed; + if (addspeed <= 0) + return; + accelspeed = accel * wishspeed * pml.frametime; + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i=0 ; i<3 ; i++) + pml.velocity[i] += accelspeed*wishdir[i]; +} + +/* +============= +PM_AddCurrents +============= +*/ +void PM_AddCurrents (vec3_t wishvel) +{ + vec3_t v; + float s; + + // + // account for ladders + // + + if (pml.ladder && fabs(pml.velocity[2]) <= 200) + { + if ((pm->viewangles[PITCH] <= -15) && (pm->cmd.forwardmove > 0)) + wishvel[2] = 200; + else if ((pm->viewangles[PITCH] >= 15) && (pm->cmd.forwardmove > 0)) + wishvel[2] = -200; + else if (pm->cmd.upmove > 0) + wishvel[2] = 200; + else if (pm->cmd.upmove < 0) + wishvel[2] = -200; + else + wishvel[2] = 0; + + // limit horizontal speed when on a ladder + if (wishvel[0] < -25) + wishvel[0] = -25; + else if (wishvel[0] > 25) + wishvel[0] = 25; + + if (wishvel[1] < -25) + wishvel[1] = -25; + else if (wishvel[1] > 25) + wishvel[1] = 25; + } + + + // + // add water currents + // + + if (pm->watertype & MASK_CURRENT) + { + VectorClear (v); + + if (pm->watertype & CONTENTS_CURRENT_0) + v[0] += 1; + if (pm->watertype & CONTENTS_CURRENT_90) + v[1] += 1; + if (pm->watertype & CONTENTS_CURRENT_180) + v[0] -= 1; + if (pm->watertype & CONTENTS_CURRENT_270) + v[1] -= 1; + if (pm->watertype & CONTENTS_CURRENT_UP) + v[2] += 1; + if (pm->watertype & CONTENTS_CURRENT_DOWN) + v[2] -= 1; + + s = pm_waterspeed; + if ((pm->waterlevel == 1) && (pm->groundentity)) + s /= 2; + + VectorMA (wishvel, s, v, wishvel); + } + + // + // add conveyor belt velocities + // + + if (pm->groundentity) + { + VectorClear (v); + + if (pml.groundcontents & CONTENTS_CURRENT_0) + v[0] += 1; + if (pml.groundcontents & CONTENTS_CURRENT_90) + v[1] += 1; + if (pml.groundcontents & CONTENTS_CURRENT_180) + v[0] -= 1; + if (pml.groundcontents & CONTENTS_CURRENT_270) + v[1] -= 1; + if (pml.groundcontents & CONTENTS_CURRENT_UP) + v[2] += 1; + if (pml.groundcontents & CONTENTS_CURRENT_DOWN) + v[2] -= 1; + + VectorMA (wishvel, 100 /* pm->groundentity->speed */, v, wishvel); + } +} + + +/* +=================== +PM_WaterMove + +=================== +*/ +void PM_WaterMove (void) +{ + int i; + vec3_t wishvel; + float wishspeed; + vec3_t wishdir; + +// +// user intentions +// + for (i=0 ; i<3 ; i++) + wishvel[i] = pml.forward[i]*pm->cmd.forwardmove + pml.right[i]*pm->cmd.sidemove; + + if (!pm->cmd.forwardmove && !pm->cmd.sidemove && !pm->cmd.upmove) + wishvel[2] -= 60; // drift towards bottom + else + wishvel[2] += pm->cmd.upmove; + + PM_AddCurrents (wishvel); + + VectorCopy (wishvel, wishdir); + wishspeed = VectorNormalize(wishdir); + + if (wishspeed > pmp->maxspeed) + { + VectorScale (wishvel, pmp->maxspeed / wishspeed, wishvel); + wishspeed = pmp->maxspeed; + } + wishspeed *= ( (pmp->qwmod) ? 0.7 : 0.5 ); //atu QWMod + + + PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate); + + PM_StepSlideMove (); +} + + +/* +=================== +PM_AirMove + +=================== +*/ +void PM_AirMove (void) +{ + int i; + vec3_t wishvel; + float fmove, smove; + vec3_t wishdir; + float wishspeed; + float maxspeed; + + fmove = pm->cmd.forwardmove; + smove = pm->cmd.sidemove; + +//!!!!! pitch should be 1/3 so this isn't needed??! +#if 0 + pml.forward[2] = 0; + pml.right[2] = 0; + VectorNormalize (pml.forward); + VectorNormalize (pml.right); +#endif + + for (i=0 ; i<2 ; i++) + wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove; + wishvel[2] = 0; + + PM_AddCurrents (wishvel); + + VectorCopy (wishvel, wishdir); + wishspeed = VectorNormalize(wishdir); + +// +// clamp to server defined max speed +// + maxspeed = (pm->s.pm_flags & PMF_DUCKED) ? pm_duckspeed : pmp->maxspeed; + + if (wishspeed > maxspeed) + { + VectorScale (wishvel, maxspeed/wishspeed, wishvel); + wishspeed = maxspeed; + } + + if ( pml.ladder ) + { + PM_Accelerate (wishdir, wishspeed, pm_accelerate); + if (!wishvel[2]) + { + if (pml.velocity[2] > 0) + { + pml.velocity[2] -= pm->s.gravity * pml.frametime; + if (pml.velocity[2] < 0) + pml.velocity[2] = 0; + } + else + { + pml.velocity[2] += pm->s.gravity * pml.frametime; + if (pml.velocity[2] > 0) + pml.velocity[2] = 0; + } + } + PM_StepSlideMove (); + } + else if ( pm->groundentity ) + { // walking on ground + pml.velocity[2] = 0; //!!! this is before the accel + PM_Accelerate (wishdir, wishspeed, pm_accelerate); + +// PGM -- fix for negative trigger_gravity fields +// pml.velocity[2] = 0; + if(pm->s.gravity > 0) + pml.velocity[2] = 0; + else + pml.velocity[2] -= pm->s.gravity * pml.frametime; +// PGM + + if (!pml.velocity[0] && !pml.velocity[1]) + return; + PM_StepSlideMove (); + } + else + { // not on ground, so little effect on velocity + if (pmp->airaccelerate) + PM_AirAccelerate (wishdir, wishspeed, pm_accelerate); + else + PM_Accelerate (wishdir, wishspeed, 1); + // add gravity + pml.velocity[2] -= pm->s.gravity * pml.frametime; + PM_StepSlideMove (); + } +} + + + +/* +============= +PM_CategorizePosition +============= +*/ +void PM_CategorizePosition (void) +{ + vec3_t point; + int cont; + trace_t trace; + int sample1; + int sample2; + +// if the player hull point one unit down is solid, the player +// is on ground + +// see if standing on something solid + point[0] = pml.origin[0]; + point[1] = pml.origin[1]; + point[2] = pml.origin[2] - ( (pmp->qwmod == 2) ? 1 : 0.25 ); //atu QWMod + if (pml.velocity[2] > 180) //!!ZOID changed from 100 to 180 (ramp accel) + { + pm->s.pm_flags &= ~PMF_ON_GROUND; + pm->groundentity = NULL; + } + else + { + trace = pm->trace (pml.origin, pm->mins, pm->maxs, point); + pml.groundplane = trace.plane; + pml.groundsurface = trace.surface; + pml.groundcontents = trace.contents; + + if (!trace.ent || (trace.plane.normal[2] < 0.7 && !trace.startsolid) ) + { + pm->groundentity = NULL; + pm->s.pm_flags &= ~PMF_ON_GROUND; + } + else + { + pm->groundentity = trace.ent; + + // hitting solid ground will end a waterjump + if (pm->s.pm_flags & PMF_TIME_WATERJUMP) + { + pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT); + pm->s.pm_time = 0; + } + + if (! (pm->s.pm_flags & PMF_ON_GROUND) ) + { // just hit the ground + pm->s.pm_flags |= PMF_ON_GROUND; + // don't do landing time if we were just going down a slope + if (pml.velocity[2] < -200 && !pmp->strafeHack ) + { + pm->s.pm_flags |= PMF_TIME_LAND; + // don't allow another jump for a little while + if (pml.velocity[2] < -400) + pm->s.pm_time = 25; + else + pm->s.pm_time = 18; + } + } + } + + if (pm->numtouch < MAXTOUCH && trace.ent) + { + pm->touchents[pm->numtouch] = trace.ent; + pm->numtouch++; + } + } + +// +// get waterlevel, accounting for ducking +// + pm->waterlevel = 0; + pm->watertype = 0; + + sample2 = pm->viewheight - pm->mins[2]; + sample1 = sample2 / 2; + + point[2] = pml.origin[2] + pm->mins[2] + 1; + cont = pm->pointcontents (point); + + if (cont & MASK_WATER) + { + pm->watertype = cont; + pm->waterlevel = 1; + point[2] = pml.origin[2] + pm->mins[2] + sample1; + cont = pm->pointcontents (point); + if (cont & MASK_WATER) + { + pm->waterlevel = 2; + point[2] = pml.origin[2] + pm->mins[2] + sample2; + cont = pm->pointcontents (point); + if (cont & MASK_WATER) + pm->waterlevel = 3; + } + } + +} + + +/* +============= +PM_CheckJump +============= +*/ +void PM_CheckJump (void) +{ + if (pm->s.pm_flags & PMF_TIME_LAND) + { // hasn't been long enough since landing to jump again + return; + } + + if (pm->cmd.upmove < 10) + { // not holding jump + pm->s.pm_flags &= ~PMF_JUMP_HELD; + return; + } + + // must wait for jump to be released + if (pm->s.pm_flags & PMF_JUMP_HELD) + return; + + if (pm->s.pm_type == PM_DEAD) + return; + + if (pm->waterlevel >= 2) + { // swimming, not jumping + pm->groundentity = NULL; + + if (pml.velocity[2] <= -300) + return; + + if (pm->watertype == CONTENTS_WATER) + pml.velocity[2] = 100; + else if (pm->watertype == CONTENTS_SLIME) + pml.velocity[2] = 80; + else + pml.velocity[2] = 50; + return; + } + + if (pm->groundentity == NULL) + return; // in air, so no effect + + pm->s.pm_flags |= PMF_JUMP_HELD; + + pm->groundentity = NULL; + pm->s.pm_flags &= ~PMF_ON_GROUND; + pml.velocity[2] += 270; + if (pml.velocity[2] < 270) + pml.velocity[2] = 270; +} + + +/* +============= +PM_CheckSpecialMovement +============= +*/ +void PM_CheckSpecialMovement (void) +{ + vec3_t spot; + int cont; + vec3_t flatforward; + trace_t trace; + + if (pm->s.pm_time) + return; + + pml.ladder = qfalse; + + // check for ladder + flatforward[0] = pml.forward[0]; + flatforward[1] = pml.forward[1]; + flatforward[2] = 0; + VectorNormalize (flatforward); + + VectorMA (pml.origin, 1, flatforward, spot); + trace = pm->trace (pml.origin, pm->mins, pm->maxs, spot); + if ((trace.fraction < 1) && (trace.contents & CONTENTS_LADDER)) + pml.ladder = qtrue; + + // check for water jump + if (pm->waterlevel != 2) + return; + + VectorMA (pml.origin, 30, flatforward, spot); + spot[2] += 4; + cont = pm->pointcontents (spot); + if (!(cont & CONTENTS_SOLID)) + return; + + spot[2] += 16; + cont = pm->pointcontents (spot); + if (cont) + return; + // jump out of water + VectorScale (flatforward, 50, pml.velocity); + pml.velocity[2] = 350; + + pm->s.pm_flags |= PMF_TIME_WATERJUMP; + pm->s.pm_time = 255; +} + + +/* +=============== +PM_FlyMove +=============== +*/ +void PM_FlyMove (qboolean doclip) +{ + float speed, drop, friction, control, newspeed; + float currentspeed, addspeed, accelspeed; + int i; + vec3_t wishvel; + float fmove, smove; + vec3_t wishdir; + float wishspeed; + vec3_t end; + trace_t trace; + + pm->viewheight = 22; + + // friction + + speed = VectorLength (pml.velocity); + if (speed < 1) + { + VectorCopy (vec3_origin, pml.velocity); + } + else + { + drop = 0; + + friction = pmp->friction * 1.5; // extra friction + control = speed < pm_stopspeed ? pm_stopspeed : speed; + drop += control*friction*pml.frametime; + + // scale the velocity + newspeed = speed - drop; + if (newspeed < 0) + newspeed = 0; + newspeed /= speed; + + VectorScale (pml.velocity, newspeed, pml.velocity); + } + + // accelerate + fmove = pm->cmd.forwardmove; + smove = pm->cmd.sidemove; + + VectorNormalize (pml.forward); + VectorNormalize (pml.right); + + for (i=0 ; i<3 ; i++) + wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove; + wishvel[2] += pm->cmd.upmove; + + VectorCopy (wishvel, wishdir); + wishspeed = VectorNormalize(wishdir); + + // + // clamp to server defined max speed + // + if (wishspeed > pmp->maxspeed) + { + VectorScale (wishvel, pmp->maxspeed / wishspeed, wishvel); + wishspeed = pmp->maxspeed; + } + + + currentspeed = DotProduct(pml.velocity, wishdir); + addspeed = wishspeed - currentspeed; + if (addspeed <= 0) + return; + accelspeed = pm_accelerate*pml.frametime*wishspeed; + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i=0 ; i<3 ; i++) + pml.velocity[i] += accelspeed*wishdir[i]; + + if (doclip) { + for (i=0 ; i<3 ; i++) + end[i] = pml.origin[i] + pml.frametime * pml.velocity[i]; + + trace = pm->trace (pml.origin, pm->mins, pm->maxs, end); + + VectorCopy (trace.endpos, pml.origin); + } else { + // move + VectorMA (pml.origin, pml.frametime, pml.velocity, pml.origin); + } +} + + +/* +============== +PM_CheckDuck + +Sets mins, maxs, and pm->viewheight +============== +*/ +void PM_CheckDuck (void) +{ + trace_t trace; + + pm->mins[0] = -16; + pm->mins[1] = -16; + + pm->maxs[0] = 16; + pm->maxs[1] = 16; + + if (pm->s.pm_type == PM_GIB) + { + pm->mins[2] = 0; + pm->maxs[2] = 16; + pm->viewheight = 8; + return; + } + + pm->mins[2] = -24; + + if (pm->s.pm_type == PM_DEAD) + { + pm->s.pm_flags |= PMF_DUCKED; + } + else if (pm->cmd.upmove < 0 && (pm->s.pm_flags & PMF_ON_GROUND) ) + { // duck + pm->s.pm_flags |= PMF_DUCKED; + } + else + { // stand up if possible + if (pm->s.pm_flags & PMF_DUCKED) + { + // try to stand up + pm->maxs[2] = 32; + trace = pm->trace (pml.origin, pm->mins, pm->maxs, pml.origin); + if (!trace.allsolid) + pm->s.pm_flags &= ~PMF_DUCKED; + } + } + + if (pm->s.pm_flags & PMF_DUCKED) + { + pm->maxs[2] = 4; + pm->viewheight = -2; + } + else + { + pm->maxs[2] = 32; + pm->viewheight = 22; + } +} + + +/* +============== +PM_DeadMove +============== +*/ +void PM_DeadMove (void) +{ + float forward; + + if (!pm->groundentity) + return; + + // extra friction + + forward = VectorLength (pml.velocity); + forward -= 20; + if (forward <= 0) + { + VectorClear (pml.velocity); + } + else + { + VectorNormalize (pml.velocity); + VectorScale (pml.velocity, forward, pml.velocity); + } +} + + +qboolean PM_GoodPosition (void) +{ + trace_t trace; + vec3_t origin, end; + int i; + + if (pm->s.pm_type == PM_SPECTATOR) + return qtrue; + + for (i=0 ; i<3 ; i++) + origin[i] = end[i] = pm->s.origin[i]*0.125; + trace = pm->trace (origin, pm->mins, pm->maxs, end); + + return !trace.allsolid; +} + +/* +================ +PM_SnapPosition + +On exit, the origin will have a value that is pre-quantized to the 0.125 +precision of the network channel and in a valid position. +================ +*/ +void PM_SnapPosition (void) +{ + int sign[3]; + int i, j, bits; + short base[3]; + // try all single bits first + static int jitterbits[8] = {0,4,1,2,3,5,6,7}; + +#ifdef PMOVE_HACK + if( pmp->highprec ) { + VectorCopy( pml.origin, pmp->origin ); + VectorCopy( pml.velocity, pmp->velocity ); + } +#endif + + // snap velocity to eigths + for (i=0 ; i<3 ; i++) + pm->s.velocity[i] = (int)(pml.velocity[i]*8); + + for (i=0 ; i<3 ; i++) + { + if (pml.origin[i] >= 0) + sign[i] = 1; + else + sign[i] = -1; + pm->s.origin[i] = (int)(pml.origin[i]*8); + if (pm->s.origin[i]*0.125 == pml.origin[i]) + sign[i] = 0; + } + VectorCopy (pm->s.origin, base); + + // try all combinations + for (j=0 ; j<8 ; j++) + { + bits = jitterbits[j]; + VectorCopy (base, pm->s.origin); + for (i=0 ; i<3 ; i++) + if (bits & (1<<i) ) + pm->s.origin[i] += sign[i]; + + if (PM_GoodPosition ()) + return; + } + + // go back to the last position +#ifdef PMOVE_HACK + if( pmp->highprec ) { + VectorCopy( pml.previous_origin, pmp->origin ); + for (i=0 ; i<3 ; i++) + pm->s.origin[i] = (int)(pml.previous_origin[i]*8); + } else +#endif + { + VectorCopy( pml.previous_origin, pm->s.origin ); + } +// Com_DPrintf ("using previous_origin\n"); +} + + + +/* +================ +PM_InitialSnapPosition + +================ +*/ +void PM_InitialSnapPosition(void) +{ + int x, y, z; + short base[3]; + static int offset[3] = { 0, -1, 1 }; + + VectorCopy (pm->s.origin, base); + + for ( z = 0; z < 3; z++ ) { + pm->s.origin[2] = base[2] + offset[ z ]; + for ( y = 0; y < 3; y++ ) { + pm->s.origin[1] = base[1] + offset[ y ]; + for ( x = 0; x < 3; x++ ) { + pm->s.origin[0] = base[0] + offset[ x ]; + if (PM_GoodPosition ()) { + pml.origin[0] = pm->s.origin[0]*0.125; + pml.origin[1] = pm->s.origin[1]*0.125; + pml.origin[2] = pm->s.origin[2]*0.125; +#ifdef PMOVE_HACK + if( pmp->highprec ) { + VectorCopy( pml.origin, pmp->origin ); + VectorCopy( pml.origin, pml.previous_origin ); + } else +#endif + { + VectorCopy( pm->s.origin, pml.previous_origin ); + } + return; + } + } + } + } + + Com_DPrintf ("Bad InitialSnapPosition\n"); +} + +/* +================ +PM_ClampAngles + +================ +*/ +void PM_ClampAngles (void) +{ + short temp; + int i; + + if (pm->s.pm_flags & PMF_TIME_TELEPORT) + { + pm->viewangles[YAW] = SHORT2ANGLE(pm->cmd.angles[YAW] + pm->s.delta_angles[YAW]); + pm->viewangles[PITCH] = 0; + pm->viewangles[ROLL] = 0; + } + else + { + // circularly clamp the angles with deltas + for (i=0 ; i<3 ; i++) + { + temp = pm->cmd.angles[i] + pm->s.delta_angles[i]; + pm->viewangles[i] = SHORT2ANGLE(temp); + } + + // don't let the player look up or down more than 90 degrees + if (pm->viewangles[PITCH] > 89 && pm->viewangles[PITCH] < 180) + pm->viewangles[PITCH] = 89; + else if (pm->viewangles[PITCH] < 271 && pm->viewangles[PITCH] >= 180) + pm->viewangles[PITCH] = 271; + } + AngleVectors (pm->viewangles, pml.forward, pml.right, pml.up); +} + +/* +================ +Pmove + +Can be called by either the server or the client +================ +*/ +void Pmove( pmove_t *pmove, pmoveParams_t *params ) +{ + pm = pmove; + pmp = params; + + // clear results + pm->numtouch = 0; + VectorClear (pm->viewangles); + pm->viewheight = 0; + pm->groundentity = 0; + pm->watertype = 0; + pm->waterlevel = 0; + + // clear all pmove local vars + memset (&pml, 0, sizeof(pml)); + + // convert origin and velocity to float values +#ifdef PMOVE_HACK + if( params->highprec ) { + vec3_t o, v; + vec_t d; + + VectorScale( pm->s.origin, 0.125f, o ); + VectorScale( pm->s.velocity, 0.125f, v ); + + VectorSubtract( params->origin, o, o ); + VectorSubtract( params->velocity, v, v ); + + d = VectorLengthSquared( o ); + if( d > 10 ) { + VectorScale( pm->s.origin, 0.125f, pml.origin ); + Com_Printf( "reset origin: %f\n", d ); + } else { + VectorCopy( params->origin, pml.origin ); + } + + d = VectorLengthSquared( v ); + if( d > 10 ) { + VectorScale( pm->s.velocity, 0.125f, pml.velocity ); + Com_Printf( "reset velocity: %f\n", d ); + } else { + VectorCopy( params->velocity, pml.velocity ); + } + + // save old org in case we get stuck + VectorCopy (params->origin, pml.previous_origin); + } else +#endif + { + VectorScale( pm->s.origin, 0.125f, pml.origin ); + VectorScale( pm->s.velocity, 0.125f, pml.velocity ); + + // save old org in case we get stuck + VectorCopy (pm->s.origin, pml.previous_origin); + } + + PM_ClampAngles (); + + if (pm->s.pm_type == PM_SPECTATOR) + { + pml.frametime = pmp->speedMultiplier * pm->cmd.msec * 0.001f; + PM_FlyMove (qfalse); + PM_SnapPosition (); + return; + } + + pml.frametime = pm->cmd.msec * 0.001f; + + if (pm->s.pm_type >= PM_DEAD) + { + pm->cmd.forwardmove = 0; + pm->cmd.sidemove = 0; + pm->cmd.upmove = 0; + } + + if (pm->s.pm_type == PM_FREEZE) + return; // no movement at all + + // set mins, maxs, and viewheight + PM_CheckDuck (); + + if (pm->snapinitial) + PM_InitialSnapPosition (); + + // set groundentity, watertype, and waterlevel + PM_CategorizePosition (); + + if (pm->s.pm_type == PM_DEAD) + PM_DeadMove (); + + PM_CheckSpecialMovement (); + + // drop timing counter + if (pm->s.pm_time) + { + int msec; + + msec = pm->cmd.msec >> 3; + if (!msec) + msec = 1; + if ( msec >= pm->s.pm_time) + { + pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT); + pm->s.pm_time = 0; + } + else + pm->s.pm_time -= msec; + } + + if (pm->s.pm_flags & PMF_TIME_TELEPORT) + { // teleport pause stays exactly in place + } + else if (pm->s.pm_flags & PMF_TIME_WATERJUMP) + { // waterjump has no control, but falls + pml.velocity[2] -= pm->s.gravity * pml.frametime; + if (pml.velocity[2] < 0) + { // cancel as soon as we are falling down again + pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT); + pm->s.pm_time = 0; + } + + PM_StepSlideMove (); + } + else + { + PM_CheckJump (); + + PM_Friction (); + + if (pm->waterlevel >= 2) + PM_WaterMove (); + else { + vec3_t angles; + + VectorCopy(pm->viewangles, angles); + if (angles[PITCH] > 180) + angles[PITCH] = angles[PITCH] - 360; + angles[PITCH] /= 3; + + AngleVectors (angles, pml.forward, pml.right, pml.up); + + PM_AirMove (); + } + } + + // set groundentity, watertype, and waterlevel for final spot + PM_CategorizePosition (); + + PM_SnapPosition (); +} + |