/* ================== PM_Friction Handles both ground friction and water friction ================== */ void PM_Friction (void) { float *vel; float speed, newspeed, control; float friction; float drop; vec3_t start, stop; pmtrace_t trace; if (pmove.waterjumptime) return; vel = pmove.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; } friction = movevars.friction; // if the leading edge is over a dropoff, increase friction if (onground != -1) { start[0] = stop[0] = pmove.origin[0] + vel[0]/speed*16; start[1] = stop[1] = pmove.origin[1] + vel[1]/speed*16; start[2] = pmove.origin[2] + player_mins[2]; stop[2] = start[2] - 34; trace = PM_PlayerMove (start, stop); if (trace.fraction == 1) { friction *= 2; } } drop = 0; if (waterlevel >= 2) // apply water friction drop += speed*movevars.waterfriction*waterlevel*frametime; else if (onground != -1) // apply ground friction { control = speed < movevars.stopspeed ? movevars.stopspeed : speed; drop += control*friction*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_CategorizePosition */ void PM_CategorizePosition (void) { vec3_t point; int cont; trace_t tr; // if the player hull point one unit down is solid, the player // is on ground // see if standing on something solid point[0] = pmove.origin[0]; point[1] = pmove.origin[1]; point[2] = pmove.origin[2] - 1; if (pmove.velocity[2] > 180) { onground = -1; } else { tr = PM_PlayerMove (pmove.origin, point); if (tr.plane.normal[2] < 0.7) onground = -1; // too steep else onground = tr.entnum; if (onground != -1) { pmove.waterjumptime = 0; if (!tr.startsolid && !tr.allsolid) VectorCopy (tr.endpos, pmove.origin); } // standing on an entity other than the world if (tr.entnum > 0) { pmove.touchindex[pmove.numtouch] = tr.entnum; pmove.numtouch++; } } // // get waterlevel // waterlevel = 0; watertype = CONTENTS_EMPTY; point[2] = pmove.origin[2] + player_mins[2] + 1; cont = PM_PointContents (point); if (cont <= CONTENTS_WATER) { watertype = cont; waterlevel = 1; point[2] = pmove.origin[2] + (player_mins[2] + player_maxs[2]) * 0.5; cont = PM_PointContents (point); if (cont <= CONTENTS_WATER) { waterlevel = 2; point[2] = pmove.origin[2] + 22; cont = PM_PointContents (point); if (cont <= CONTENTS_WATER) waterlevel = 3; } } }
void CL_PredictUsercmd (player_state_t *from, player_state_t *to, usercmd_t *u) { // split up very long moves if (u->msec > 50) { player_state_t temp; usercmd_t split; split = *u; split.msec /= 2; CL_PredictUsercmd (from, &temp, &split); CL_PredictUsercmd (&temp, to, &split); return; } VectorCopy (from->origin, pmove.origin); VectorCopy (u->angles, pmove.angles); VectorCopy (from->velocity, pmove.velocity); pmove.jump_msec = (cl.z_ext & Z_EXT_PM_TYPE) ? 0 : from->jump_msec; pmove.jump_held = from->jump_held; pmove.waterjumptime = from->waterjumptime; pmove.pm_type = from->pm_type; pmove.onground = from->onground; pmove.cmd = *u; #ifdef JSS_CAM if (cam_lockdir.value) { VectorCopy (saved_angles, pmove.cmd.angles); VectorCopy (saved_angles, pmove.angles); } else VectorCopy (pmove.cmd.angles, saved_angles); #endif movevars.entgravity = cl.entgravity; movevars.maxspeed = cl.maxspeed; movevars.bunnyspeedcap = cl.bunnyspeedcap; PM_PlayerMove (); to->waterjumptime = pmove.waterjumptime; to->pm_type = pmove.pm_type; to->jump_held = pmove.jump_held; to->jump_msec = pmove.jump_msec; pmove.jump_msec = 0; VectorCopy (pmove.origin, to->origin); VectorCopy (pmove.angles, to->viewangles); VectorCopy (pmove.velocity, to->velocity); to->onground = pmove.onground; to->weaponframe = from->weaponframe; }
/* =================== PM_WaterMove =================== */ void PM_WaterMove (void) { int i; vec3_t wishvel; float wishspeed; vec3_t wishdir; vec3_t start, dest; pmtrace_t trace; // // user intentions // for (i=0 ; i<3 ; i++) wishvel[i] = forward[i]*pmove.cmd.forwardmove + right[i]*pmove.cmd.sidemove; if (!pmove.cmd.forwardmove && !pmove.cmd.sidemove && !pmove.cmd.upmove) wishvel[2] -= 60; // drift towards bottom else wishvel[2] += pmove.cmd.upmove; VectorCopy (wishvel, wishdir); wishspeed = VectorNormalize(wishdir); if (wishspeed > movevars.maxspeed) { VectorScale (wishvel, movevars.maxspeed/wishspeed, wishvel); wishspeed = movevars.maxspeed; } wishspeed *= 0.7; // // water acceleration // // if (pmove.waterjumptime) // Con_Printf ("wm->%f, %f, %f\n", pmove.velocity[0], pmove.velocity[1], pmove.velocity[2]); PM_Accelerate (wishdir, wishspeed, movevars.wateraccelerate); // assume it is a stair or a slope, so press down from stepheight above VectorMA (pmove.origin, frametime, pmove.velocity, dest); VectorCopy (dest, start); start[2] += STEPSIZE + 1; trace = PM_PlayerMove (start, dest); if (!trace.startsolid && !trace.allsolid) // FIXME: check steep slope? { // walked up the step VectorCopy (trace.endpos, pmove.origin); return; } PM_FlyMove (); // if (pmove.waterjumptime) // Con_Printf ("<-wm%f, %f, %f\n", pmove.velocity[0], pmove.velocity[1], pmove.velocity[2]); }
pmtrace_t Cam_DoTrace(vec3_t vec1, vec3_t vec2) { #if 0 memset(&pmove, 0, sizeof(pmove)); pmove.numphysent = 1; VectorCopy (vec3_origin, pmove.physents[0].origin); pmove.physents[0].model = cl.worldmodel; #endif VectorCopy (vec1, pmove.origin); return PM_PlayerMove(pmove.origin, vec2); }
/* ============== CL_PredictUsercmd ============== */ void CL_PredictUsercmd (player_state_t *from, player_state_t *to, usercmd_t *u) { // split up very long moves if (u->msec > 50) { player_state_t temp; usercmd_t split; split = *u; split.msec /= 2; CL_PredictUsercmd (from, &temp, &split); CL_PredictUsercmd (&temp, to, &split); return; } VectorCopy (from->origin, cl.pmove.origin); // VectorCopy (from->viewangles, pmove.angles); VectorCopy (u->angles, cl.pmove.angles); VectorCopy (from->velocity, cl.pmove.velocity); if (cl.z_ext & Z_EXT_PM_TYPE) cl.pmove.jump_msec = 0; else cl.pmove.jump_msec = from->jump_msec; cl.pmove.jump_held = from->jump_held; cl.pmove.waterjumptime = from->waterjumptime; cl.pmove.pm_type = from->pm_type; cl.pmove.onground = from->onground; cl.pmove.cmd = *u; PM_PlayerMove (&cl.pmove, &cl.movevars); to->waterjumptime = cl.pmove.waterjumptime; to->pm_type = cl.pmove.pm_type; to->jump_held = cl.pmove.jump_held; to->jump_msec = cl.pmove.jump_msec; cl.pmove.jump_msec = 0; VectorCopy (cl.pmove.origin, to->origin); VectorCopy (cl.pmove.angles, to->viewangles); VectorCopy (cl.pmove.velocity, to->velocity); to->onground = cl.pmove.onground; to->weaponframe = from->weaponframe; }
/* PM_FlymodeMove Pre-PM_FlyMove function for MOVETYPE_FLY players. Could have altered other physics to fit this in, but that's to easy to screw up. --KB */ void PM_FlymodeMove (void) { vec3_t start, dest, pmvel, pmtmp; trace_t trace; float pmspeed; pmvel[0] = forward[0] * pmove.cmd.forwardmove + right[0] * pmove.cmd.sidemove; pmvel[1] = forward[1] * pmove.cmd.forwardmove + right[1] * pmove.cmd.sidemove; pmvel[2] = forward[2] * pmove.cmd.forwardmove + right[2] * pmove.cmd.sidemove + pmove.cmd.upmove; VectorCopy (pmvel, pmtmp); pmspeed = VectorNormalize (pmtmp); // don't alter pmvel if (pmspeed > movevars.maxspeed) // there IS a spoon, Neo.. { VectorScale (pmvel, movevars.maxspeed / pmspeed, pmvel); pmspeed = movevars.maxspeed; } PM_Accelerate (pmtmp, pmspeed, movevars.wateraccelerate); VectorMA (pmove.origin, frametime, pmove.velocity, dest); VectorCopy (dest, start); start[2] += STEPSIZE + 1; trace = PM_PlayerMove (start, dest); if (!trace.startsolid && !trace.allsolid) { VectorCopy (trace.endpos, pmove.origin); return; // just step up } PM_FlyMove (); // NOW we fly. }
/* PM_GroundMove Player is on ground, with no upwards velocity */ void PM_GroundMove (void) { vec3_t start, dest; trace_t trace; vec3_t original, originalvel, down, up, downvel; float downdist, updist; pmove.velocity[2] = 0; if (VectorIsNull(pmove.velocity)) return; // first try just moving to the destination dest[0] = pmove.origin[0] + pmove.velocity[0] * frametime; dest[1] = pmove.origin[1] + pmove.velocity[1] * frametime; dest[2] = pmove.origin[2]; // first try moving directly to the next spot VectorCopy (dest, start); trace = PM_PlayerMove (pmove.origin, dest); if (trace.fraction == 1) { VectorCopy (trace.endpos, pmove.origin); return; } // try sliding forward both on ground and up 16 pixels // take the move that goes farthest VectorCopy (pmove.origin, original); VectorCopy (pmove.velocity, originalvel); // slide move PM_FlyMove (); VectorCopy (pmove.origin, down); VectorCopy (pmove.velocity, downvel); VectorCopy (original, pmove.origin); VectorCopy (originalvel, pmove.velocity); // move up a stair height VectorCopy (pmove.origin, dest); dest[2] += STEPSIZE; trace = PM_PlayerMove (pmove.origin, dest); if (!trace.startsolid && !trace.allsolid) { VectorCopy (trace.endpos, pmove.origin); } // slide move PM_FlyMove (); // press down the stepheight VectorCopy (pmove.origin, dest); dest[2] -= STEPSIZE; trace = PM_PlayerMove (pmove.origin, dest); if (trace.plane.normal[2] < 0.7) goto usedown; if (!trace.startsolid && !trace.allsolid) { VectorCopy (trace.endpos, pmove.origin); } VectorCopy (pmove.origin, up); // decide which one went farther downdist = (down[0] - original[0]) * (down[0] - original[0]) + (down[1] - original[1]) * (down[1] - original[1]); updist = (up[0] - original[0]) * (up[0] - original[0]) + (up[1] - original[1]) * (up[1] - original[1]); if (downdist > updist) { usedown: VectorCopy (down, pmove.origin); VectorCopy (downvel, pmove.velocity); } else // copy z value from slide move pmove.velocity[2] = downvel[2]; // if at a dead stop, retry the move with nudges to get around lips }
int PM_FlyMove (void) { int bumpcount, numbumps; vec3_t dir; float d; int numplanes; vec3_t planes[MAX_CLIP_PLANES]; vec3_t primal_velocity, original_velocity; int i, j; trace_t trace; vec3_t end; float time_left; int blocked; numbumps = 4; blocked = 0; VectorCopy (pmove.velocity, original_velocity); VectorCopy (pmove.velocity, primal_velocity); numplanes = 0; time_left = frametime; for (bumpcount = 0; bumpcount < numbumps; bumpcount++) { for (i = 0; i < 3; i++) end[i] = pmove.origin[i] + time_left * pmove.velocity[i]; trace = PM_PlayerMove (pmove.origin, end); if (trace.startsolid || trace.allsolid) { // entity is trapped in // another solid VectorCopy (vec3_origin, pmove.velocity); return 3; } if (trace.fraction > 0) { // actually covered some distance VectorCopy (trace.endpos, pmove.origin); numplanes = 0; } if (trace.fraction == 1) break; // moved the entire distance // save entity for contact pmove.touchindex[pmove.numtouch] = trace.entnum; pmove.numtouch++; if (trace.plane.normal[2] > 0.7) { blocked |= 1; // floor } if (!trace.plane.normal[2]) { blocked |= 2; // step } time_left -= time_left * trace.fraction; // cliped to another plane if (numplanes >= MAX_CLIP_PLANES) { // this shouldn't really happen VectorCopy (vec3_origin, pmove.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 (original_velocity, planes[i], pmove.velocity, 1); for (j = 0; j < numplanes; j++) if (j != i) { if (DotProduct (pmove.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, pmove.velocity); break; } CrossProduct (planes[0], planes[1], dir); d = DotProduct (dir, pmove.velocity); VectorScale (dir, d, pmove.velocity); } // // if original velocity is against the original velocity, stop dead // to avoid tiny occilations in sloping corners // if (DotProduct (pmove.velocity, primal_velocity) <= 0) { VectorCopy (vec3_origin, pmove.velocity); break; } } if (pmove.waterjumptime) { VectorCopy (primal_velocity, pmove.velocity); } return blocked; }