#include "qcommon.h"
#define STEPSIZE 18
typedef struct {
vec3_t origin; vec3_t velocity;
vec3_t forward, right, up;
float frametime;
csurface_t *groundsurface;
cplane_t groundplane;
int groundcontents;
vec3_t previous_origin;
bool ladder;
} pml_t;
pmove_t *pm;
pml_t pml;
float pm_stopspeed = 100;
float pm_maxspeed = 300;
float pm_duckspeed = 100;
float pm_accelerate = 10;
float pm_airaccelerate = 0;
float pm_wateraccelerate = 10;
float pm_friction = 6;
float pm_waterfriction = 1;
float pm_waterspeed = 400;
#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;
}
}
#define MIN_STEP_NORMAL 0.7
#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(pm->cmodel_index, pml.origin, pm->mins, pm->maxs, end);
if(trace.allsolid) { pml.velocity[2] = 0; return;
}
if(trace.fraction > 0) { VectorCopy(trace.endpos, pml.origin);
numplanes = 0;
}
if(trace.fraction == 1)
break;
if(pm->numtouch < MAXTOUCH && trace.ent) {
pm->touchents[pm->numtouch] = trace.ent;
pm->numtouch++;
}
time_left -= time_left * trace.fraction;
if(numplanes >= MAX_CLIP_PLANES) { VectorCopy(vec3_origin, pml.velocity);
break;
}
VectorCopy(trace.plane.normal, planes[numplanes]);
numplanes++;
#if 0#else
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; }
if(j == numplanes)
break;
}
if(i != numplanes) { } else { if(numplanes != 2) {
VectorCopy(vec3_origin, pml.velocity);
break;
}
CrossProduct(planes[0], planes[1], dir);
d = DotProduct(dir, pml.velocity);
VectorScale(dir, d, pml.velocity);
}
#endif
if(DotProduct(pml.velocity, primal_velocity) <= 0) {
VectorCopy(vec3_origin, pml.velocity);
break;
}
}
if(pm->s.pm_time) {
VectorCopy(primal_velocity, pml.velocity);
}
}
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 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(pm->cmodel_index, up, pm->mins, pm->maxs, up);
if(trace.allsolid)
return;
VectorCopy(up, pml.origin);
VectorCopy(start_v, pml.velocity);
PM_StepSlideMove_();
VectorCopy(pml.origin, down);
down[2] -= STEPSIZE;
trace = pm->trace(pm->cmodel_index, pml.origin, pm->mins, pm->maxs, down);
if(!trace.allsolid) {
VectorCopy(trace.endpos, pml.origin);
}
#if 0#else
VectorCopy(pml.origin, up);
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]);
#endif
if(down_dist > up_dist || trace.plane.normal[2] < MIN_STEP_NORMAL) {
VectorCopy(down_o, pml.origin);
VectorCopy(down_v, pml.velocity);
return;
}
pml.velocity[2] = down_v[2];
}
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;
if((pm->groundentity && pml.groundsurface && !(pml.groundsurface->flags & SURF_SLICK)) || (pml.ladder)) {
friction = pm_friction;
control = speed < pm_stopspeed ? pm_stopspeed : speed;
drop += control * friction * pml.frametime;
}
if(pm->waterlevel && !pml.ladder)
drop += speed * pm_waterfriction * pm->waterlevel * pml.frametime;
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;
}
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];
}
void PM_AddCurrents(vec3_t wishvel) {
vec3_t v;
float s;
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;
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;
}
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);
}
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 , v, wishvel);
}
}
void PM_WaterMove(void) {
int i;
vec3_t wishvel;
float wishspeed;
vec3_t wishdir;
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; else
wishvel[2] += pm->cmd.upmove;
PM_AddCurrents(wishvel);
VectorCopy(wishvel, wishdir);
wishspeed = VectorNormalize(wishdir);
if(wishspeed > pm_maxspeed) {
VectorScale(wishvel, pm_maxspeed / wishspeed, wishvel);
wishspeed = pm_maxspeed;
}
wishspeed *= 0.5;
PM_Accelerate(wishdir, wishspeed, pm_wateraccelerate);
PM_StepSlideMove();
}
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;
#if 0#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);
maxspeed = (pm->s.pm_flags & PMF_DUCKED) ? pm_duckspeed : pm_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) { pml.velocity[2] = 0; PM_Accelerate(wishdir, wishspeed, pm_accelerate);
if(pm->s.gravity > 0)
pml.velocity[2] = 0;
else
pml.velocity[2] -= pm->s.gravity * pml.frametime;
if(!pml.velocity[0] && !pml.velocity[1])
return;
PM_StepSlideMove();
} else { if(pm_airaccelerate)
PM_AirAccelerate(wishdir, wishspeed, pm_accelerate);
else
PM_Accelerate(wishdir, wishspeed, 1);
pml.velocity[2] -= pm->s.gravity * pml.frametime;
PM_StepSlideMove();
}
}
void PM_CatagorizePosition(void) {
vec3_t point;
int cont;
trace_t trace;
int sample1;
int sample2;
point[0] = pml.origin[0];
point[1] = pml.origin[1];
point[2] = pml.origin[2] - 0.25;
if(pml.velocity[2] > 180) {
pm->s.pm_flags &= ~PMF_ON_GROUND;
pm->groundentity = NULL;
} else {
trace = pm->trace(pm->cmodel_index, 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;
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)) { pm->s.pm_flags |= PMF_ON_GROUND;
if(pml.velocity[2] < -200) {
pm->s.pm_flags |= PMF_TIME_LAND;
if(pml.velocity[2] < -400)
pm->s.pm_time = 25;
else
pm->s.pm_time = 18;
}
}
}
#if 0#endif
if(pm->numtouch < MAXTOUCH && trace.ent) {
pm->touchents[pm->numtouch] = trace.ent;
pm->numtouch++;
}
}
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(pm->cmodel_index, point);
if(cont & MASK_WATER) {
pm->watertype = cont;
pm->waterlevel = 1;
point[2] = pml.origin[2] + pm->mins[2] + sample1;
cont = pm->pointcontents(pm->cmodel_index, point);
if(cont & MASK_WATER) {
pm->waterlevel = 2;
point[2] = pml.origin[2] + pm->mins[2] + sample2;
cont = pm->pointcontents(pm->cmodel_index, point);
if(cont & MASK_WATER)
pm->waterlevel = 3;
}
}
}
void PM_CheckJump(void) {
if(pm->s.pm_flags & PMF_TIME_LAND) { return;
}
if(pm->cmd.upmove < 10) { pm->s.pm_flags &= ~PMF_JUMP_HELD;
return;
}
if(pm->s.pm_flags & PMF_JUMP_HELD)
return;
if(pm->s.pm_type == PM_DEAD)
return;
if(pm->waterlevel >= 2) { 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;
pm->s.pm_flags |= PMF_JUMP_HELD;
pm->groundentity = NULL;
pml.velocity[2] += 270;
if(pml.velocity[2] < 270)
pml.velocity[2] = 270;
}
void PM_CheckSpecialMovement(void) {
vec3_t spot;
int cont;
vec3_t flatforward;
trace_t trace;
if(pm->s.pm_time)
return;
pml.ladder = false;
flatforward[0] = pml.forward[0];
flatforward[1] = pml.forward[1];
flatforward[2] = 0;
VectorNormalize(flatforward);
VectorMA(pml.origin, 1, flatforward, spot);
trace = pm->trace(pm->cmodel_index, pml.origin, pm->mins, pm->maxs, spot);
if((trace.fraction < 1) && (trace.contents & CONTENTS_LADDER))
pml.ladder = true;
if(pm->waterlevel != 2)
return;
VectorMA(pml.origin, 30, flatforward, spot);
spot[2] += 4;
cont = pm->pointcontents(pm->cmodel_index, spot);
if(!(cont & CONTENTS_SOLID))
return;
spot[2] += 16;
cont = pm->pointcontents(pm->cmodel_index, spot);
if(cont)
return;
VectorScale(flatforward, 50, pml.velocity);
pml.velocity[2] = 350;
pm->s.pm_flags |= PMF_TIME_WATERJUMP;
pm->s.pm_time = 255;
}
void PM_FlyMove(bool 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;
speed = VectorLength(pml.velocity);
if(speed < 1) {
VectorCopy(vec3_origin, pml.velocity);
} else {
drop = 0;
friction = pm_friction * 1.5; control = speed < pm_stopspeed ? pm_stopspeed : speed;
drop += control * friction * pml.frametime;
newspeed = speed - drop;
if(newspeed < 0)
newspeed = 0;
newspeed /= speed;
VectorScale(pml.velocity, newspeed, pml.velocity);
}
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);
if(wishspeed > pm_maxspeed) {
VectorScale(wishvel, pm_maxspeed / wishspeed, wishvel);
wishspeed = pm_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(pm->cmodel_index, pml.origin, pm->mins, pm->maxs, end);
VectorCopy(trace.endpos, pml.origin);
} else {
VectorMA(pml.origin, pml.frametime, pml.velocity, pml.origin);
}
}
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)) { pm->s.pm_flags |= PMF_DUCKED;
} else { if(pm->s.pm_flags & PMF_DUCKED) {
pm->maxs[2] = 32;
trace = pm->trace(pm->cmodel_index, 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;
}
}
void PM_DeadMove(void) {
float forward;
if(!pm->groundentity)
return;
forward = VectorLength(pml.velocity);
forward -= 20;
if(forward <= 0) {
VectorClear(pml.velocity);
} else {
VectorNormalize(pml.velocity);
VectorScale(pml.velocity, forward, pml.velocity);
}
}
bool PM_GoodPosition(void) {
trace_t trace;
vec3_t origin, end;
int i;
if(pm->s.pm_type == PM_SPECTATOR)
return true;
for(i = 0; i < 3; i++)
origin[i] = end[i] = pm->s.origin[i] * 0.125;
trace = pm->trace(pm->cmodel_index, origin, pm->mins, pm->maxs, end);
return !trace.allsolid;
}
void PM_SnapPosition(void) {
int sign[3];
int i, j, bits;
short base[3];
static int jitterbits[8] = {0, 4, 1, 2, 3, 5, 6, 7};
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);
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;
}
VectorCopy(pml.previous_origin, pm->s.origin);
}
#if 0#else
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;
VectorCopy(pm->s.origin, pml.previous_origin);
return;
}
}
}
}
Com_DPrintf("Bad InitialSnapPosition\n");
}
#endif
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 {
for(i = 0; i < 3; i++) {
temp = pm->cmd.angles[i] + pm->s.delta_angles[i];
pm->viewangles[i] = SHORT2ANGLE(temp);
}
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);
}
void Pmove(pmove_t *pmove) {
pm = pmove;
pm->numtouch = 0;
VectorClear(pm->viewangles);
pm->viewheight = 0;
pm->groundentity = 0;
pm->watertype = 0;
pm->waterlevel = 0;
memset(&pml, 0, sizeof(pml));
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;
pml.velocity[0] = pm->s.velocity[0] * 0.125;
pml.velocity[1] = pm->s.velocity[1] * 0.125;
pml.velocity[2] = pm->s.velocity[2] * 0.125;
VectorCopy(pm->s.origin, pml.previous_origin);
pml.frametime = pm->cmd.msec * 0.001;
PM_ClampAngles();
if(pm->s.pm_type == PM_SPECTATOR) {
PM_FlyMove(false);
PM_SnapPosition();
return;
}
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;
PM_CheckDuck();
if(pm->snapinitial)
PM_InitialSnapPosition();
PM_CatagorizePosition();
if(pm->s.pm_type == PM_DEAD)
PM_DeadMove();
PM_CheckSpecialMovement();
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) { } else if(pm->s.pm_flags & PMF_TIME_WATERJUMP) { pml.velocity[2] -= pm->s.gravity * pml.frametime;
if(pml.velocity[2] < 0) { 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();
}
}
PM_CatagorizePosition();
PM_SnapPosition();
}