/* =================== 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]); }
/* 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_AirMove */ void PM_AirMove (void) { int i; vec3_t wishvel; float fmove, smove; vec3_t wishdir; float wishspeed; vec3_t original; fmove = pmove.cmd.forwardmove; smove = pmove.cmd.sidemove; forward[2] = 0; right[2] = 0; VectorNormalize (forward); VectorNormalize (right); for (i = 0; i < 2; i++) wishvel[i] = forward[i] * fmove + right[i] * smove; wishvel[2] = 0; VectorCopy (wishvel, wishdir); wishspeed = VectorNormalize (wishdir); // // clamp to server defined max speed // if (wishspeed > movevars.maxspeed) { VectorScale (wishvel, movevars.maxspeed / wishspeed, wishvel); wishspeed = movevars.maxspeed; } if (onground != -1) { pmove.velocity[2] = 0; PM_Accelerate (wishdir, wishspeed, movevars.accelerate); pmove.velocity[2] -= movevars.entgravity * movevars.gravity * frametime; PM_GroundMove (); } else if (pmove.flying) { PM_AirAccelerate (wishdir, wishspeed, movevars.accelerate); PM_FlyMove (); } else { // not on ground, so little effect on velocity PM_AirAccelerate (wishdir, wishspeed, movevars.accelerate); // add gravity pmove.velocity[2] -= movevars.entgravity * movevars.gravity * frametime; if (!PM_FlyMove ()) { // the move didn't get blocked PM_CategorizePosition (); if (onground != -1) // but we're on ground now { // This is a hack to fix the jumping bug VectorCopy (pmove.origin, original); // Calculate correct velocity if (!PM_FlyMove ()) { // This shouldn't probably happen (?) if (pmove.velocity[2] < 0) pmove.velocity[2] = 0; } VectorCopy (original, pmove.origin); } } } }
/* 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 }
/* * Can be called by either the server or the client */ void Pmove (pmove_t *pmove) { #if !defined(DEDICATED_ONLY) && defined(USE_OPENAL) static int underwater; #endif pm = pmove; /* 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 */ pml.origin[0] = pm->s.origin[0]*0.125f; pml.origin[1] = pm->s.origin[1]*0.125f; pml.origin[2] = pm->s.origin[2]*0.125f; pml.velocity[0] = pm->s.velocity[0]*0.125f; pml.velocity[1] = pm->s.velocity[1]*0.125f; pml.velocity[2] = pm->s.velocity[2]*0.125f; /* save old org in case we get stuck */ VectorCopy (pm->s.origin, pml.previous_origin); pml.frametime = pm->cmd.msec * 0.001f; 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; /* no movement at all */ /* set mins, maxs, and viewheight */ PM_CheckDuck (); if (pm->snapinitial) PM_InitialSnapPosition (); /* set groundentity, watertype, and waterlevel */ PM_CatagorizePosition (); 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; }
void PmoveSingle (pmove_t *pmove) { pm = pmove; // this counter lets us debug movement problems with a journal // by setting a conditional breakpoint fot the previous frame c_pmove++; // clear results pm->numtouch = 0; pm->watertype = 0; pm->waterlevel = 0; if ( pm->ps->stats[STAT_HEALTH] <= 0 ) { pm->tracemask &= ~CONTENTS_BODY; // corpses can fly through bodies } // make sure walking button is clear if they are running, to avoid // proxy no-footsteps cheats if ( abs( pm->cmd.forwardmove ) > 64 || abs( pm->cmd.rightmove ) > 64 ) { pm->cmd.buttons &= ~BUTTON_WALKING; } // set the talk balloon flag if ( pm->cmd.buttons & BUTTON_TALK ) { pm->ps->eFlags |= EF_TALK; } else { pm->ps->eFlags &= ~EF_TALK; } // set the firing flag for continuous beam weapons if ( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION && pm->ps->pm_type != PM_NOCLIP && ( pm->cmd.buttons & BUTTON_ATTACK ) && pm->ps->ammo[ pm->ps->weapon ] ) { pm->ps->eFlags |= EF_FIRING; } else { pm->ps->eFlags &= ~EF_FIRING; } // clear the respawned flag if attack and use are cleared if ( pm->ps->stats[STAT_HEALTH] > 0 && !( pm->cmd.buttons & (BUTTON_ATTACK | BUTTON_USE_HOLDABLE) ) ) { pm->ps->pm_flags &= ~PMF_RESPAWNED; } // if talk button is down, dissallow all other input // this is to prevent any possible intercept proxy from // adding fake talk balloons if ( pmove->cmd.buttons & BUTTON_TALK ) { // keep the talk button set tho for when the cmd.serverTime > 66 msec // and the same cmd is used multiple times in Pmove pmove->cmd.buttons = BUTTON_TALK; pmove->cmd.forwardmove = 0; pmove->cmd.rightmove = 0; pmove->cmd.upmove = 0; } // clear all pmove local vars memset (&pml, 0, sizeof(pml)); // determine the time pml.msec = pmove->cmd.serverTime - pm->ps->commandTime; if ( pml.msec < 1 ) { pml.msec = 1; } else if ( pml.msec > 200 ) { pml.msec = 200; } pm->ps->commandTime = pmove->cmd.serverTime; // save old org in case we get stuck VectorCopy (pm->ps->origin, pml.previous_origin); // save old velocity for crashlanding VectorCopy (pm->ps->velocity, pml.previous_velocity); pml.frametime = pml.msec * 0.001; // update the viewangles PM_UpdateViewAngles( pm->ps, &pm->cmd ); AngleVectors (pm->ps->viewangles, pml.forward, pml.right, pml.up); if ( pm->cmd.upmove < 10 ) { // not holding jump pm->ps->pm_flags &= ~PMF_JUMP_HELD; } // decide if backpedaling animations should be used if ( pm->cmd.forwardmove < 0 ) { pm->ps->pm_flags |= PMF_BACKWARDS_RUN; } else if ( pm->cmd.forwardmove > 0 || ( pm->cmd.forwardmove == 0 && pm->cmd.rightmove ) ) { pm->ps->pm_flags &= ~PMF_BACKWARDS_RUN; } if ( pm->ps->pm_type >= PM_DEAD ) { pm->cmd.forwardmove = 0; pm->cmd.rightmove = 0; pm->cmd.upmove = 0; } if ( pm->ps->pm_type == PM_SPECTATOR ) { PM_CheckDuck (); PM_FlyMove (); PM_DropTimers (); return; } if ( pm->ps->pm_type == PM_NOCLIP ) { PM_NoclipMove (); PM_DropTimers (); return; } if (pm->ps->pm_type == PM_FREEZE) { return; // no movement at all } if ( pm->ps->pm_type == PM_INTERMISSION || pm->ps->pm_type == PM_SPINTERMISSION) { return; // no movement at all } // set watertype, and waterlevel PM_SetWaterLevel(); pml.previous_waterlevel = pmove->waterlevel; // set mins, maxs, and viewheight PM_CheckDuck (); // set groundentity PM_GroundTrace(); if ( pm->ps->pm_type == PM_DEAD ) { PM_DeadMove (); } PM_DropTimers(); #ifdef MISSIONPACK if ( pm->ps->powerups[PW_INVULNERABILITY] ) { PM_InvulnerabilityMove(); } else #endif if ( pm->ps->powerups[PW_FLIGHT] ) { // flight powerup doesn't allow jump and has different friction PM_FlyMove(); } else if (pm->ps->pm_flags & PMF_GRAPPLE_PULL) { PM_GrappleMove(); // We can wiggle a bit PM_AirMove(); } else if (pm->ps->pm_flags & PMF_TIME_WATERJUMP) { PM_WaterJumpMove(); } else if ( pm->waterlevel > 1 ) { // swimming PM_WaterMove(); } else if ( pml.walking ) { // walking on ground PM_WalkMove(); } else { // airborne PM_AirMove(); } PM_Animate(); // set groundentity, watertype, and waterlevel PM_GroundTrace(); PM_SetWaterLevel(); // weapons PM_Weapon(); // torso animation PM_TorsoAnimation(); // footstep events / legs animations PM_Footsteps(); // entering / leaving water splashes PM_WaterEvents(); // snap some parts of playerstate to save network bandwidth trap_SnapVector( pm->ps->velocity ); }
/* =================== PM_AirMove =================== */ void PM_AirMove (void) { int i; vec3_t wishvel; float fmove, smove; vec3_t wishdir; float wishspeed; fmove = pmove.cmd.forwardmove; smove = pmove.cmd.sidemove; forward[2] = 0; right[2] = 0; VectorNormalize (forward); VectorNormalize (right); for (i=0 ; i<2 ; i++) wishvel[i] = forward[i]*fmove + right[i]*smove; wishvel[2] = 0; VectorCopy (wishvel, wishdir); wishspeed = VectorNormalize(wishdir); // // clamp to server defined max speed // if (wishspeed > movevars.maxspeed) { VectorScale (wishvel, movevars.maxspeed/wishspeed, wishvel); wishspeed = movevars.maxspeed; } // if (pmove.waterjumptime) // Con_Printf ("am->%f, %f, %f\n", pmove.velocity[0], pmove.velocity[1], pmove.velocity[2]); if ( onground != -1) { pmove.velocity[2] = 0; PM_Accelerate (wishdir, wishspeed, movevars.accelerate); pmove.velocity[2] -= movevars.entgravity * movevars.gravity * frametime; PM_GroundMove (); } else { // not on ground, so little effect on velocity PM_AirAccelerate (wishdir, wishspeed, movevars.accelerate); // add gravity pmove.velocity[2] -= movevars.entgravity * movevars.gravity * frametime; PM_FlyMove (); } //Con_Printf("airmove:vec: %4.2f %4.2f %4.2f\n", // pmove.velocity[0], // pmove.velocity[1], // pmove.velocity[2]); // // if (pmove.waterjumptime) // Con_Printf ("<-am%f, %f, %f\n", pmove.velocity[0], pmove.velocity[1], pmove.velocity[2]); }
/* ================ Pmove Can be called by either the server or the client ================ */ void Pmove (pmove_t *pmove) { pm = pmove; // 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 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; // save old org in case we get stuck 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; // no movement at all // set mins, maxs, and viewheight PM_CheckDuck (); if (pm->snapinitial) PM_InitialSnapPosition (); // set groundentity, watertype, and waterlevel PM_CatagorizePosition (); 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; byte_write(&pm->s.pm_time, 0); byte_write(&pm->s.pm_flags, pm->s.pm_flags & ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT)); } else pm->s.pm_time -= msec; }