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 > pm_maxspeed) { VectorScale (wishvel, pm_maxspeed/wishspeed, wishvel); wishspeed = pm_maxspeed; } wishspeed *= 0.5; PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate); PM_StepSlideMove (); }
/* =================== PM_FlyMove Only with the flight powerup =================== */ static void PM_FlyMove( void ) { int i; vec3_t wishvel; float wishspeed; vec3_t wishdir; float scale; // normal slowdown PM_Friction (); scale = PM_CmdScale( &pm->cmd ); // // user intentions // if ( !scale ) { wishvel[0] = 0; wishvel[1] = 0; wishvel[2] = 0; } else { for (i=0 ; i<3 ; i++) { wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove; } wishvel[2] += scale * pm->cmd.upmove; } VectorCopy (wishvel, wishdir); wishspeed = VectorNormalize(wishdir); PM_Accelerate (wishdir, wishspeed, pm_flyaccelerate); PM_StepSlideMove( qfalse ); }
/* =================== PM_WaterMove =================== */ static void PM_WaterMove (void) { vec3_t wishvel, wishdir; float wishspeed; // user intentions wishvel[0] = pml.forward[0] * pm->cmd.forwardmove + pml.right[0] * pm->cmd.sidemove; wishvel[1] = pml.forward[1] * pm->cmd.forwardmove + pml.right[1] * pm->cmd.sidemove; wishvel[2] = pml.forward[2] * pm->cmd.forwardmove + pml.right[2] * 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 > pm_maxspeed) { VectorScale (wishvel, pm_maxspeed/wishspeed, wishvel); wishspeed = pm_maxspeed; } wishspeed *= 0.5f; PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate); PM_StepSlideMove (); }
/* =================== PM_AirMove =================== */ static void PM_AirMove( void ) { int i; vec3_t wishvel; float fmove, smove; vec3_t wishdir; float wishspeed; float scale; usercmd_t cmd; PM_Friction(); fmove = pm->cmd.forwardmove; smove = pm->cmd.rightmove; cmd = pm->cmd; scale = PM_CmdScale( &cmd ); // set the movementDir so clients can rotate the legs for strafing PM_SetMovementDir(); // project moves down to flat plane pml.forward[2] = 0; pml.right[2] = 0; VectorNormalize (pml.forward); VectorNormalize (pml.right); for ( i = 0 ; i < 2 ; i++ ) { wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove; } wishvel[2] = 0; VectorCopy (wishvel, wishdir); wishspeed = VectorNormalize(wishdir); wishspeed *= scale; // not on ground, so little effect on velocity PM_Accelerate (wishdir, wishspeed, pm_airaccelerate); // we may have a ground plane that is very steep, even // though we don't have a groundentity // slide along the steep plane if ( pml.groundPlane ) { PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity, OVERCLIP ); } #if 0 //ZOID: If we are on the grapple, try stair-stepping //this allows a player to use the grapple to pull himself //over a ledge if (pm->ps->pm_flags & PMF_GRAPPLE_PULL) PM_StepSlideMove ( qtrue ); else PM_SlideMove ( qtrue ); #endif PM_StepSlideMove ( qtrue ); }
/* =============== PM_NoclipMove =============== */ static void PM_NoclipMove( void ) { float speed, drop, friction, control, newspeed; int i; vec3_t wishvel; float fmove, smove; vec3_t wishdir; float wishspeed; float scale; pm->ps->viewheight = DEFAULT_VIEWHEIGHT; // friction speed = VectorLength (pm->ps->velocity); if (speed < 1) { VectorCopy (vec3_origin, pm->ps->velocity); } else { drop = 0; friction = pm_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 (pm->ps->velocity, newspeed, pm->ps->velocity); } // accelerate scale = PM_CmdScale( &pm->cmd ); fmove = pm->cmd.forwardmove; smove = pm->cmd.rightmove; 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); wishspeed *= scale; PM_Accelerate( wishdir, wishspeed, pm_accelerate ); // move VectorMA (pm->ps->origin, pml.frametime, pm->ps->velocity, pm->ps->origin); }
/* =================== 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_LadderMove() by: Calrathan [Arthur Tomlin] Right now all I know is that this works for VERTICAL ladders. Ladders with angles on them (urban2 for AQ2) haven't been tested. =================== */ static void PM_LadderMove( void ) { int i; vec3_t wishvel; float wishspeed; vec3_t wishdir; float scale; float vel; PM_Friction (); scale = PM_CmdScale( &pm->cmd ); // user intentions [what the user is attempting to do] if ( !scale ) { wishvel[0] = 0; wishvel[1] = 0; wishvel[2] = 0; } else { // if they're trying to move... lets calculate it for (i=0 ; i<3 ; i++) wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove; wishvel[2] += scale * pm->cmd.upmove; } VectorCopy (wishvel, wishdir); wishspeed = VectorNormalize(wishdir); if ( wishspeed > pm->ps->speed * pm_ladderScale ) { wishspeed = pm->ps->speed * pm_ladderScale; } PM_Accelerate (wishdir, wishspeed, pm_ladderAccelerate); // This SHOULD help us with sloped ladders, but it remains untested. if ( pml.groundPlane && DotProduct( pm->ps->velocity, pml.groundTrace.plane.normal ) < 0 ) { vel = VectorLength(pm->ps->velocity); // slide along the ground plane [the ladder section under our feet] PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity, OVERCLIP ); VectorNormalize(pm->ps->velocity); VectorScale(pm->ps->velocity, vel, pm->ps->velocity); } PM_SlideMove( qfalse ); // move without gravity }
/* 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); } } } }
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; 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 : 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 ) { /* walking on ground */ 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 { /* not on ground, so little effect on velocity */ if (pm_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_WalkMove =================== */ static void PM_WalkMove( void ) { int i; vec3_t wishvel; float fmove, smove; vec3_t wishdir; float wishspeed; float scale; usercmd_t cmd; float accelerate; float vel; if ( pm->waterlevel > 2 && DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) { // begin swimming PM_WaterMove(); return; } if ( PM_CheckJump () ) { // jumped away if ( pm->waterlevel > 1 ) { PM_WaterMove(); } else { PM_AirMove(); } return; } PM_Friction (); fmove = pm->cmd.forwardmove; smove = pm->cmd.rightmove; cmd = pm->cmd; scale = PM_CmdScale( &cmd ); // set the movementDir so clients can rotate the legs for strafing PM_SetMovementDir(); // project moves down to flat plane pml.forward[2] = 0; pml.right[2] = 0; // project the forward and right directions onto the ground plane PM_ClipVelocity (pml.forward, pml.groundTrace.plane.normal, pml.forward, OVERCLIP ); PM_ClipVelocity (pml.right, pml.groundTrace.plane.normal, pml.right, OVERCLIP ); // VectorNormalize (pml.forward); VectorNormalize (pml.right); for ( i = 0 ; i < 3 ; i++ ) { wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove; } // when going up or down slopes the wish velocity should Not be zero // wishvel[2] = 0; VectorCopy (wishvel, wishdir); wishspeed = VectorNormalize(wishdir); wishspeed *= scale; // clamp the speed lower if ducking if ( pm->ps->pm_flags & PMF_DUCKED ) { if ( wishspeed > pm->ps->speed * pm_duckScale ) { wishspeed = pm->ps->speed * pm_duckScale; } } // clamp the speed lower if wading or walking on the bottom if ( pm->waterlevel ) { float waterScale; waterScale = pm->waterlevel / 3.0; waterScale = 1.0 - ( 1.0 - pm_swimScale ) * waterScale; if ( wishspeed > pm->ps->speed * waterScale ) { wishspeed = pm->ps->speed * waterScale; } } // when a player gets hit, they temporarily lose // full control, which allows them to be moved a bit if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) { accelerate = pm_airaccelerate; } else { accelerate = pm_accelerate; } PM_Accelerate (wishdir, wishspeed, accelerate); //Com_Printf("velocity = %1.1f %1.1f %1.1f\n", pm->ps->velocity[0], pm->ps->velocity[1], pm->ps->velocity[2]); //Com_Printf("velocity1 = %1.1f\n", VectorLength(pm->ps->velocity)); if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) { pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime; } else { // don't reset the z velocity for slopes // pm->ps->velocity[2] = 0; } vel = VectorLength(pm->ps->velocity); // slide along the ground plane PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity, OVERCLIP ); // don't decrease velocity when going up or down a slope VectorNormalize(pm->ps->velocity); VectorScale(pm->ps->velocity, vel, pm->ps->velocity); // don't do anything if standing still if (!pm->ps->velocity[0] && !pm->ps->velocity[1]) { return; } PM_StepSlideMove( qfalse ); //Com_Printf("velocity2 = %1.1f\n", VectorLength(pm->ps->velocity)); }
/* =================== PM_WaterMove =================== */ static void PM_WaterMove( void ) { int i; vec3_t wishvel; float wishspeed; vec3_t wishdir; float scale; float vel; if ( PM_CheckWaterJump() ) { PM_WaterJumpMove(); return; } #if 0 // jump = head for surface if ( pm->cmd.upmove >= 10 ) { if (pm->ps->velocity[2] > -300) { if ( pm->watertype == CONTENTS_WATER ) { pm->ps->velocity[2] = 100; } else if (pm->watertype == CONTENTS_SLIME) { pm->ps->velocity[2] = 80; } else { pm->ps->velocity[2] = 50; } } } #endif PM_Friction (); scale = PM_CmdScale( &pm->cmd ); // // user intentions // if ( !scale ) { wishvel[0] = 0; wishvel[1] = 0; wishvel[2] = -60; // sink towards bottom } else { for (i=0 ; i<3 ; i++) wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove; wishvel[2] += scale * pm->cmd.upmove; } VectorCopy (wishvel, wishdir); wishspeed = VectorNormalize(wishdir); if ( wishspeed > pm->ps->speed * pm_swimScale ) { wishspeed = pm->ps->speed * pm_swimScale; } PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate); // make sure we can go up slopes easily under water if ( pml.groundPlane && DotProduct( pm->ps->velocity, pml.groundTrace.plane.normal ) < 0 ) { vel = VectorLength(pm->ps->velocity); // slide along the ground plane PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity, OVERCLIP ); VectorNormalize(pm->ps->velocity); VectorScale(pm->ps->velocity, vel, pm->ps->velocity); } PM_SlideMove( qfalse ); }
/* =================== 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 : 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 ) { // 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 (pm_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_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]); }
static void ApplyPhysics (gedict_t* self) { float drop = 0; vec3_t expected_velocity; float vel_length = 0; float hor_speed_squared; float movement_skill = bound (0, self->fb.skill.movement, 1.0); qbool onGround = (int)self->s.v.flags & FL_ONGROUND; // Just perform the move if we're backing away if (FUTURE (arrow_time2)) { return; } if (deathmatch >= 4 && isDuel() && !self->fb.skill.wiggle_run_dmm4) { return; } // Step 1: Apply friction VectorCopy (self->s.v.velocity, expected_velocity); vel_length = VectorLength (expected_velocity); if (vel_length < 1) return; if (self->s.v.waterlevel >= 2) { // Swimming... float waterfriction = cvar ("sv_waterfriction"); drop = vel_length * waterfriction * self->s.v.waterlevel * g_globalvars.frametime; } else if (onGround) { // FIXME: friction is doubled if player is about to drop off a ledge float stopspeed = cvar ("sv_stopspeed"); float friction = cvar ("sv_friction"); float control = vel_length < stopspeed ? stopspeed : vel_length; drop = control * friction * g_globalvars.frametime; } if (drop) { float new_vel = max (vel_length - drop, 0); VectorScale (expected_velocity, new_vel / vel_length, expected_velocity); vel_length = new_vel; } else { vel_length = VectorLength (expected_velocity); } // Step 2: change direction to maximise acceleration in desired direction if (self->s.v.waterlevel >= 2) { // Water movement } else { float min_numerator = onGround ? 319 : 29; float max_numerator = onGround ? 281.6 : -8.4; float used_numerator; float max_incr; vec3_t current_direction; vec3_t original_direction; // Gravity kicks in /* if (!onGround) expected_velocity[2] -= self->gravity * cvar ("sv_gravity") * g_globalvars.frametime; else expected_velocity[2] = 0; */ // Ground & air acceleration is the same hor_speed_squared = (expected_velocity[0] * expected_velocity[0] + expected_velocity[1] * expected_velocity[1]); if (onGround && hor_speed_squared < sv_maxspeed * sv_maxspeed * 0.8 * 0.8) { return; } self->fb.dir_move_[2] = 0; normalize(self->fb.dir_move_, original_direction); normalize(expected_velocity, current_direction); used_numerator = min_numerator + movement_skill * (max_numerator - min_numerator); max_incr = used_numerator * used_numerator; if (hor_speed_squared >= max_incr) { vec3_t perpendicular; vec3_t up_vector = { 0, 0, 1 }; float rotation = acos(max_incr / hor_speed_squared) * 180 / M_PI; // Find out if rotation should be positive or negative CrossProduct (current_direction, original_direction, perpendicular); if ((self->fb.path_state & BOTPATH_CURLJUMP_HINT) && !onGround) { // Once in the air, we rotate in opposite direction // FIXME: THIS IS UGLY HACK if (framecount % 3) { rotation = 0; } else if (self->fb.angle_hint > 0) { rotation = -rotation; } } else if (deathmatch == 4) { if (self->fb.wiggle_run_dir == 0) { self->fb.wiggle_increasing = perpendicular[2] > 0; self->fb.wiggle_run_dir = self->fb.wiggle_increasing ? 1 : -1; } else if (self->fb.wiggle_run_dir > self->fb.skill.wiggle_run_limit && perpendicular[2] < 0) { self->fb.wiggle_increasing = false; } else if (self->fb.wiggle_run_dir < -self->fb.skill.wiggle_run_limit && perpendicular[2] > 0) { self->fb.wiggle_increasing = 1; } else if (self->fb.wiggle_increasing) { ++self->fb.wiggle_run_dir; } else { --self->fb.wiggle_run_dir; } if (self->fb.wiggle_increasing) { rotation = -rotation; } } else if (perpendicular[2] < 0) { rotation = -rotation; } if (rotation) { vec3_t proposed_dir; vec3_t vel_after_rot; vec3_t vel_std; float dp_std, dp_rot; RotatePointAroundVector (proposed_dir, up_vector, current_direction, rotation); // Calculate what mvdsv will do (roughly) PM_Accelerate (expected_velocity, (int)self->s.v.flags & FL_ONGROUND, proposed_dir, vel_after_rot, false); PM_Accelerate (expected_velocity, (int)self->s.v.flags & FL_ONGROUND, current_direction, vel_std, false); // Only rotate if 'better' than moving normally dp_rot = DotProduct (vel_after_rot, original_direction); dp_std = DotProduct (vel_std, original_direction); if (dp_rot > dp_std || dp_rot >= 0.9) { VectorCopy (proposed_dir, self->fb.dir_move_); if (self->fb.debug_path) { PM_Accelerate(expected_velocity, (int)self->s.v.flags & FL_ONGROUND, proposed_dir, vel_after_rot, true); } } else if (self->fb.debug_path) { PM_Accelerate (expected_velocity, (int)self->s.v.flags & FL_ONGROUND, current_direction, vel_std, true); } } else { #ifdef DEBUG_MOVEMENT if (self->fb.debug_path && ! onGround) { G_bprint (PRINT_HIGH, "> AirControl rotation: <ignoring>\n"); } #endif } } } }