void CMomentumGameMovement::CheckForLadders(bool wasOnGround) { if (!wasOnGround) { // If we're higher than the last place we were on the ground, bail - obviously we're not dropping // past a ladder we might want to grab. if (mv->GetAbsOrigin().z > player->m_lastStandingPos.z) return; Vector dir = -player->m_lastStandingPos + mv->GetAbsOrigin(); if (!dir.x && !dir.y) { // If we're dropping straight down, we don't know which way to look for a ladder. Oh well. return; } dir.z = 0.0f; float dist = dir.NormalizeInPlace(); if (dist > 64.0f) { // Don't grab ladders too far behind us. return; } trace_t trace; TracePlayerBBox( mv->GetAbsOrigin(), player->m_lastStandingPos - dir*(5 + dist), (PlayerSolidMask() & (~CONTENTS_PLAYERCLIP)), COLLISION_GROUP_PLAYER_MOVEMENT, trace); if (trace.fraction != 1.0f && OnLadder(trace) && trace.plane.normal.z != 1.0f) { if (player->CanGrabLadder(trace.endpos, trace.plane.normal)) { player->SetMoveType(MOVETYPE_LADDER); player->SetMoveCollide(MOVECOLLIDE_DEFAULT); player->SetLadderNormal(trace.plane.normal); mv->m_vecVelocity.Init(); // The ladder check ignored playerclips, to fix a bug exposed by de_train, where a clipbrush is // flush with a ladder. This causes the above tracehull to fail unless we ignore playerclips. // However, we have to check for playerclips before we snap to that pos, so we don't warp a // player into a clipbrush. TracePlayerBBox( mv->GetAbsOrigin(), player->m_lastStandingPos - dir*(5 + dist), PlayerSolidMask(), COLLISION_GROUP_PLAYER_MOVEMENT, trace); mv->SetAbsOrigin(trace.endpos); } } } else { player->m_lastStandingPos = mv->GetAbsOrigin(); } }
bool CHL2GameMovement::CanUnduck() { trace_t trace; Vector newOrigin; VectorCopy(mv->GetAbsOrigin(), newOrigin); if (player->GetGroundEntity() != NULL) { newOrigin += VEC_DUCK_HULL_MIN - VEC_HULL_MIN; } else { // If in air an letting go of croush, make sure we can offset origin to make // up for uncrouching Vector hullSizeNormal = VEC_HULL_MAX - VEC_HULL_MIN; Vector hullSizeCrouch = VEC_DUCK_HULL_MAX - VEC_DUCK_HULL_MIN; newOrigin += -0.5f * (hullSizeNormal - hullSizeCrouch); } UTIL_TraceHull(mv->GetAbsOrigin(), newOrigin, VEC_HULL_MIN, VEC_HULL_MAX, PlayerSolidMask(), player, COLLISION_GROUP_PLAYER_MOVEMENT, &trace); if (trace.startsolid || (trace.fraction != 1.0f)) return false; return true; }
void CMomentumGameMovement::PlayerMove() { BaseClass::PlayerMove(); if (player->IsAlive()) { // Check if our eye height is too close to the ceiling and lower it. // This is needed because we have taller models with the old collision bounds. const float eyeClearance = 12.0f; // eye pos must be this far below the ceiling Vector offset = player->GetViewOffset(); Vector vHullMin = GetPlayerMins(player->m_Local.m_bDucked); vHullMin.z = 0.0f; Vector vHullMax = GetPlayerMaxs(player->m_Local.m_bDucked); Vector start = player->GetAbsOrigin(); start.z += vHullMax.z; Vector end = start; end.z += eyeClearance - vHullMax.z; end.z += player->m_Local.m_bDucked ? VEC_DUCK_VIEW.z : VEC_VIEW.z; vHullMax.z = 0.0f; Vector fudge(1, 1, 0); vHullMin += fudge; vHullMax -= fudge; trace_t trace; Ray_t ray; ray.Init(start, end, vHullMin, vHullMax); UTIL_TraceRay(ray, PlayerSolidMask(), mv->m_nPlayerHandle.Get(), COLLISION_GROUP_PLAYER_MOVEMENT, &trace); if (trace.fraction < 1.0f) { float est = start.z + trace.fraction * (end.z - start.z) - player->GetAbsOrigin().z - eyeClearance; if ((player->GetFlags() & FL_DUCKING) == 0 && !player->m_Local.m_bDucking && !player->m_Local.m_bDucked) { offset.z = est; } else { offset.z = min(est, offset.z); } player->SetViewOffset(offset); } else { if ((player->GetFlags() & FL_DUCKING) == 0 && !player->m_Local.m_bDucking && !player->m_Local.m_bDucked) { player->SetViewOffset(VEC_VIEW); } else if (player->m_Local.m_bDucked && !player->m_Local.m_bDucking) { player->SetViewOffset(VEC_DUCK_VIEW); } } } }
CBaseHandle CTFGameMovement::TestPlayerPosition( const Vector& pos, int collisionGroup, trace_t& pm ) { if( tf_solidobjects.GetBool() == false ) return BaseClass::TestPlayerPosition( pos, collisionGroup, pm ); Ray_t ray; ray.Init( pos, pos, GetPlayerMins(), GetPlayerMaxs() ); CTraceFilterObject traceFilter( mv->m_nPlayerHandle.Get(), collisionGroup ); enginetrace->TraceRay( ray, PlayerSolidMask(), &traceFilter, &pm ); if ( (pm.contents & PlayerSolidMask()) && pm.m_pEnt ) { return pm.m_pEnt->GetRefEHandle(); } else { return INVALID_EHANDLE_INDEX; } }
CBaseHandle CHL2WarsGameMovement::TestPlayerPosition( const Vector& pos, int collisionGroup, trace_t& pm ) { if( player->GetMoveType() != MOVETYPE_STRATEGIC ) { return CGameMovement::TestPlayerPosition( pos, collisionGroup, pm ); } Ray_t ray; ray.Init( pos, pos, GetPlayerMins(), GetPlayerMaxs() ); CTraceFilterWars traceFilter( mv->m_nPlayerHandle.Get(), collisionGroup ); enginetrace->TraceRay( ray, PlayerSolidMask(), &traceFilter, &pm ); if ( (pm.contents & PlayerSolidMask()) && pm.m_pEnt ) { return pm.m_pEnt->GetRefEHandle(); } else { return INVALID_EHANDLE_INDEX; } }
void CSDKGameMovement::CategorizePosition( void ) { // Observer. if ( player->IsObserver() ) return; // Reset this each time we-recategorize, otherwise we have bogus friction when we jump into water and plunge downward really quickly player->m_surfaceFriction = 1.0f; // Doing this before we move may introduce a potential latency in water detection, but // doing it after can get us stuck on the bottom in water if the amount we move up // is less than the 1 pixel 'threshold' we're about to snap to. Also, we'll call // this several times per frame, so we really need to avoid sticking to the bottom of // water on each call, and the converse case will correct itself if called twice. CheckWater(); // If standing on a ladder we are not on ground. if ( player->GetMoveType() == MOVETYPE_LADDER ) { SetGroundEntity( NULL ); return; } // Check for a jump. if ( mv->m_vecVelocity.z > 250.0f ) { SetGroundEntity( NULL ); return; } // Calculate the start and end position. Vector vecStartPos = mv->GetAbsOrigin(); Vector vecEndPos( mv->GetAbsOrigin().x, mv->GetAbsOrigin().y, ( mv->GetAbsOrigin().z - 2.0f ) ); // NOTE YWB 7/5/07: Since we're already doing a traceline here, we'll subsume the StayOnGround (stair debouncing) check into the main traceline we do here to see what we're standing on bool bUnderwater = ( player->GetWaterLevel() >= WL_Eyes ); bool bMoveToEndPos = false; if ( player->GetMoveType() == MOVETYPE_WALK && player->GetGroundEntity() != NULL && !bUnderwater ) { // if walking and still think we're on ground, we'll extend trace down by stepsize so we don't bounce down slopes vecEndPos.z -= player->GetStepSize(); bMoveToEndPos = true; } trace_t trace; TracePlayerBBox( vecStartPos, vecEndPos, PlayerSolidMask(), COLLISION_GROUP_PLAYER_MOVEMENT, trace ); // Steep plane, not on ground. if ( trace.plane.normal.z < 0.7f ) { // Test four sub-boxes, to see if any of them would have found shallower slope we could actually stand on. TracePlayerBBoxForGround( vecStartPos, vecEndPos, GetPlayerMins(), GetPlayerMaxs(), mv->m_nPlayerHandle.Get(), PlayerSolidMask(), COLLISION_GROUP_PLAYER_MOVEMENT, trace ); if ( trace.plane.normal[2] < 0.7f ) { // Too steep. SetGroundEntity( NULL ); if ( ( mv->m_vecVelocity.z > 0.0f ) && ( player->GetMoveType() != MOVETYPE_NOCLIP ) ) { player->m_surfaceFriction = 0.25f; } } else { SetGroundEntity( &trace ); } } else { // YWB: This logic block essentially lifted from StayOnGround implementation if ( bMoveToEndPos && !trace.startsolid && // not sure we need this check as fraction would == 0.0f? trace.fraction > 0.0f && // must go somewhere trace.fraction < 1.0f ) // must hit something { float flDelta = fabs( mv->GetAbsOrigin().z - trace.endpos.z ); // HACK HACK: The real problem is that trace returning that strange value // we can't network over based on bit precision of networking origins if ( flDelta > 0.5f * COORD_RESOLUTION ) { Vector org = mv->GetAbsOrigin(); org.z = trace.endpos.z; mv->SetAbsOrigin( org ); } } SetGroundEntity( &trace ); } }
void CSDKGameMovement::WalkMove( void ) { #if defined ( SDK_USE_SPRINTING ) float flSpeedCheck = m_pSDKPlayer->GetAbsVelocity().Length2D(); bool bSprintButtonPressed = ( mv->m_nButtons & IN_SPEED ) > 0; if( bSprintButtonPressed && ( mv->m_nButtons & IN_FORWARD ) && #if defined ( SDK_USE_PRONE ) !m_pSDKPlayer->m_Shared.IsProne() && #endif !m_pSDKPlayer->m_Shared.IsDucking() && flSpeedCheck > 80 ) { m_pSDKPlayer->SetSprinting( true ); } else { m_pSDKPlayer->SetSprinting( false ); } #endif // SDK_USE_SPRINTING // Get the movement angles. Vector vecForward, vecRight, vecUp; AngleVectors( mv->m_vecViewAngles, &vecForward, &vecRight, &vecUp ); vecForward.z = 0.0f; vecRight.z = 0.0f; VectorNormalize( vecForward ); VectorNormalize( vecRight ); // Copy movement amounts float flForwardMove = mv->m_flForwardMove; float flSideMove = mv->m_flSideMove; // Find the direction,velocity in the x,y plane. Vector vecWishDirection( ( ( vecForward.x * flForwardMove ) + ( vecRight.x * flSideMove ) ), ( ( vecForward.y * flForwardMove ) + ( vecRight.y * flSideMove ) ), 0.0f ); // Calculate the speed and direction of movement, then clamp the speed. float flWishSpeed = VectorNormalize( vecWishDirection ); flWishSpeed = clamp( flWishSpeed, 0.0f, mv->m_flMaxSpeed ); // Accelerate in the x,y plane. mv->m_vecVelocity.z = 0; Accelerate( vecWishDirection, flWishSpeed, sv_accelerate.GetFloat() ); Assert( mv->m_vecVelocity.z == 0.0f ); // Clamp the players speed in x,y. float flNewSpeed = VectorLength( mv->m_vecVelocity ); if ( flNewSpeed > mv->m_flMaxSpeed ) { float flScale = ( mv->m_flMaxSpeed / flNewSpeed ); mv->m_vecVelocity.x *= flScale; mv->m_vecVelocity.y *= flScale; } // Now reduce their backwards speed to some percent of max, if they are travelling backwards unless they are under some minimum if ( sdk_clamp_back_speed.GetFloat() < 1.0 && VectorLength( mv->m_vecVelocity ) > sdk_clamp_back_speed_min.GetFloat() ) { float flDot = DotProduct( vecForward, mv->m_vecVelocity ); // are we moving backwards at all? if ( flDot < 0 ) { Vector vecBackMove = vecForward * flDot; Vector vecRightMove = vecRight * DotProduct( vecRight, mv->m_vecVelocity ); // clamp the back move vector if it is faster than max float flBackSpeed = VectorLength( vecBackMove ); float flMaxBackSpeed = ( mv->m_flMaxSpeed * sdk_clamp_back_speed.GetFloat() ); if ( flBackSpeed > flMaxBackSpeed ) { vecBackMove *= flMaxBackSpeed / flBackSpeed; } // reassemble velocity mv->m_vecVelocity = vecBackMove + vecRightMove; } } // Add base velocity to the player's current velocity - base velocity = velocity from conveyors, etc. VectorAdd( mv->m_vecVelocity, player->GetBaseVelocity(), mv->m_vecVelocity ); // Calculate the current speed and return if we are not really moving. float flSpeed = VectorLength( mv->m_vecVelocity ); if ( flSpeed < 1.0f ) { // I didn't remove the base velocity here since it wasn't moving us in the first place. mv->m_vecVelocity.Init(); return; } // Calculate the destination. Vector vecDestination; vecDestination.x = mv->GetAbsOrigin().x + ( mv->m_vecVelocity.x * gpGlobals->frametime ); vecDestination.y = mv->GetAbsOrigin().y + ( mv->m_vecVelocity.y * gpGlobals->frametime ); vecDestination.z = mv->GetAbsOrigin().z; // Try moving to the destination. trace_t trace; TracePlayerBBox( mv->GetAbsOrigin(), vecDestination, PlayerSolidMask(), COLLISION_GROUP_PLAYER_MOVEMENT, trace ); if ( trace.fraction == 1.0f ) { // Made it to the destination (remove the base velocity). mv->SetAbsOrigin( trace.endpos ); VectorSubtract( mv->m_vecVelocity, player->GetBaseVelocity(), mv->m_vecVelocity ); // Save the wish velocity. mv->m_outWishVel += ( vecWishDirection * flWishSpeed ); // Try and keep the player on the ground. // NOTE YWB 7/5/07: Don't do this here, our version of CategorizePosition encompasses this test // StayOnGround(); return; } // Now try and do a step move. StepMove( vecDestination, trace ); // Remove base velocity. Vector baseVelocity = player->GetBaseVelocity(); VectorSubtract( mv->m_vecVelocity, baseVelocity, mv->m_vecVelocity ); // Save the wish velocity. mv->m_outWishVel += ( vecWishDirection * flWishSpeed ); // Try and keep the player on the ground. // NOTE YWB 7/5/07: Don't do this here, our version of CategorizePosition encompasses this test // StayOnGround(); }
//----------------------------------------------------------------------------- // Purpose: // Output : int //----------------------------------------------------------------------------- int CHL2WarsGameMovement::TryStrategicMove( Vector *pFirstDest, trace_t *pFirstTrace ) { int bumpcount, numbumps; Vector dir; float d; int numplanes; Vector planes[MAX_CLIP_PLANES]; Vector primal_velocity, original_velocity; Vector new_velocity; int i, j; trace_t pm; Vector end; float time_left, allFraction; int blocked; numbumps = 4; // Bump up to four times blocked = 0; // Assume not blocked numplanes = 0; // and not sliding along any planes VectorCopy (mv->m_vecVelocity, original_velocity); // Store original velocity VectorCopy (mv->m_vecVelocity, primal_velocity); allFraction = 0; time_left = gpGlobals->frametime; // Total time for this movement operation. new_velocity.Init(); for (bumpcount=0 ; bumpcount < numbumps; bumpcount++) { if ( mv->m_vecVelocity.Length() == 0.0 ) break; // Assume we can move all the way from the current origin to the // end point. VectorMA( mv->GetAbsOrigin(), time_left, mv->m_vecVelocity, end ); // See if we can make it from origin to end point. TracePlayerBBox( mv->GetAbsOrigin(), end, PlayerSolidMask(), COLLISION_GROUP_PLAYER_MOVEMENT, pm ); allFraction += pm.fraction; // If we started in a solid object, or we were in solid space // the whole way, zero out our velocity and return that we // are blocked by floor and wall. if (pm.allsolid) { #if defined( PLAYER_GETTING_STUCK_TESTING ) Msg( "Trapped!!! :(\n" ); #endif // entity is trapped in another solid VectorCopy (vec3_origin, mv->m_vecVelocity); return 4; } // If we moved some portion of the total distance, then // copy the end position into the pmove.origin and // zero the plane counter. if( pm.fraction > 0 ) { if ( numbumps > 0 && pm.fraction == 1 ) { // There's a precision issue with terrain tracing that can cause a swept box to successfully trace // when the end position is stuck in the triangle. Re-run the test with an uswept box to catch that // case until the bug is fixed. // If we detect getting stuck, don't allow the movement trace_t stuck; TracePlayerBBox( pm.endpos, pm.endpos, PlayerSolidMask(), COLLISION_GROUP_PLAYER_MOVEMENT, stuck ); if ( stuck.startsolid || stuck.fraction != 1.0f ) { //Msg( "Player will become stuck!!!\n" ); VectorCopy (vec3_origin, mv->m_vecVelocity); break; } } #if defined( PLAYER_GETTING_STUCK_TESTING ) trace_t foo; TracePlayerBBox( pm.endpos, pm.endpos, PlayerSolidMask(), COLLISION_GROUP_PLAYER_MOVEMENT, foo ); if ( foo.startsolid || foo.fraction != 1.0f ) { Msg( "Player will become stuck!!!\n" ); } #endif // actually covered some distance mv->SetAbsOrigin( pm.endpos); VectorCopy (mv->m_vecVelocity, original_velocity); numplanes = 0; } // If we covered the entire distance, we are done // and can return. if (pm.fraction == 1) { break; // moved the entire distance } // Save entity that blocked us (since fraction was < 1.0) // for contact // Add it if it's not already in the list!!! MoveHelper( )->AddToTouched( pm, mv->m_vecVelocity ); // If the plane we hit has a high z component in the normal, then // it's probably a floor if (pm.plane.normal[2] > 0.7) { blocked |= 1; // floor } // If the plane has a zero z component in the normal, then it's a // step or wall if (!pm.plane.normal[2]) { blocked |= 2; // step / wall } // Reduce amount of m_flFrameTime left by total time left * fraction // that we covered. time_left -= time_left * pm.fraction; // Did we run out of planes to clip against? if (numplanes >= MAX_CLIP_PLANES) { // this shouldn't really happen // Stop our movement if so. VectorCopy (vec3_origin, mv->m_vecVelocity); //Con_DPrintf("Too many planes 4\n"); break; } // Set up next clipping plane VectorCopy (pm.plane.normal, planes[numplanes]); numplanes++; // modify original_velocity so it parallels all of the clip planes // // reflect player velocity // Only give this a try for first impact plane because you can get yourself stuck in an acute corner by jumping in place // and pressing forward and nobody was really using this bounce/reflection feature anyway... if ( numplanes == 1 && player->GetMoveType() == MOVETYPE_WALK && player->GetGroundEntity() == NULL ) { for ( i = 0; i < numplanes; i++ ) { if ( planes[i][2] > 0.7 ) { // floor or slope ClipVelocity( original_velocity, planes[i], new_velocity, 1 ); VectorCopy( new_velocity, original_velocity ); } else { ClipVelocity( original_velocity, planes[i], new_velocity, 1.0 + sv_bounce.GetFloat() * (1 - player->m_surfaceFriction) ); } } VectorCopy( new_velocity, mv->m_vecVelocity ); VectorCopy( new_velocity, original_velocity ); } else { for (i=0 ; i < numplanes ; i++) { ClipVelocity ( original_velocity, planes[i], mv->m_vecVelocity, 1); for (j=0 ; j<numplanes ; j++) if (j != i) { // Are we now moving against this plane? if (mv->m_vecVelocity.Dot(planes[j]) < 0) break; // not ok } if (j == numplanes) // Didn't have to clip, so we're ok break; } // Did we go all the way through plane set if (i != numplanes) { // go along this plane // pmove.velocity is set in clipping call, no need to set again. ; } else { // go along the crease if (numplanes != 2) { VectorCopy (vec3_origin, mv->m_vecVelocity); break; } CrossProduct (planes[0], planes[1], dir); dir.NormalizeInPlace(); d = dir.Dot(mv->m_vecVelocity); VectorScale (dir, d, mv->m_vecVelocity ); } // // if original velocity is against the original velocity, stop dead // to avoid tiny occilations in sloping corners // d = mv->m_vecVelocity.Dot(primal_velocity); if (d <= 0) { //Con_DPrintf("Back\n"); VectorCopy (vec3_origin, mv->m_vecVelocity); break; } } } if ( allFraction == 0 ) { VectorCopy (vec3_origin, mv->m_vecVelocity); } #if 0 // Check if they slammed into a wall float fSlamVol = 0.0f; float fLateralStoppingAmount = primal_velocity.Length2D() - mv->m_vecVelocity.Length2D(); if ( fLateralStoppingAmount > PLAYER_MAX_SAFE_FALL_SPEED * 2.0f ) { fSlamVol = 1.0f; } else if ( fLateralStoppingAmount > PLAYER_MAX_SAFE_FALL_SPEED ) { fSlamVol = 0.85f; } PlayerRoughLandingEffects( fSlamVol ); #endif // 0 return blocked; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHL2WarsGameMovement::StrategicPlayerMove() { trace_t pm; Vector move; Vector forward, right, up; Vector wishvel; Vector wishdir; float wishspeed, heightchange; float maxspeed = strategic_cam_maxspeed.GetFloat(); // Server defined max speed CHL2WarsPlayer *warsplayer = dynamic_cast<CHL2WarsPlayer *>( player ); if( !warsplayer ) return; float speed = warsplayer->GetCamSpeed(); float maxacceleration = warsplayer->GetCamAcceleration(); float friction = warsplayer->GetCamFriction(); float stopspeed = warsplayer->GetCamStopSpeed(); // Determine our current height warsplayer->CalculateHeight( mv->GetAbsOrigin() ); // Determine movement angles AngleVectors (mv->m_vecViewAngles, &forward, &right, &up); up.z = 0.0f; right.z = 0.0f; VectorNormalize (up); VectorNormalize (right); VectorNormalize (forward); // Zoom direction // Copy movement amounts // Assume max move is 450.0, so we can scale it to the correct speed value // NOTE: Swapped fmove and umove in terms of usage. float smove = (mv->m_flSideMove/450.0f) * speed; float fmove = (mv->m_flForwardMove/450.0f) * speed; float umove = (mv->m_flUpMove/450.0f) * speed; // Zoom when there is no map boundary for (int i=0 ; i<2 ; i++) // Determine x and y parts of velocity wishvel[i] = up[i]*fmove + right[i]*smove; wishvel[2] = 0.0f; if( warsplayer->GetCamHeight() != -1 && warsplayer->GetCamHeight() > 2.0f ) ;//wishvel[2] = -warsplayer->GetCamHeight() * 4.0f; // Force player origin down else wishvel = wishvel + forward*umove*4.0; // Zooming is forward VectorCopy (wishvel, wishdir); // Determine maginitude of speed of move wishspeed = VectorNormalize(wishdir); // // Clamp to user defined wish speed // if (wishspeed > speed ) { VectorScale (wishvel, speed/wishspeed, wishvel); wishspeed = speed; } // // Clamp to server defined max speed // if (wishspeed > maxspeed ) { VectorScale (wishvel, maxspeed/wishspeed, wishvel); wishspeed = maxspeed; } if ( maxacceleration > 0.0 ) { // Set pmove velocity Accelerate ( wishdir, wishspeed, maxacceleration ); float spd = VectorLength( mv->m_vecVelocity ); if (spd < 1.0f) { mv->m_vecVelocity.Init(); return; } // Bleed off some speed, but if we have less than the bleed // threshhold, bleed the theshold amount. float control = (spd < stopspeed) ? stopspeed : spd; // Add the amount to the drop amount. float drop = control * friction * gpGlobals->frametime; // scale the velocity float newspeed = spd - drop; if (newspeed < 0) newspeed = 0; // Determine proportion of old speed we are using. newspeed /= spd; VectorScale( mv->m_vecVelocity, newspeed, mv->m_vecVelocity ); } else { VectorCopy( wishvel, mv->m_vecVelocity ); } #ifdef CLIENT_DLL if( cl_showmovementspeed.GetInt() == player->entindex() ) { engine->Con_NPrintf( 1, "CLIENT Movement speed: %6.1f | maxspeed: %6.1f | userspeed: %6.1f | pos: %6.1f %6.1f %6.1f | mins: %6.1f %6.1f %6.1f | maxs: %6.1f %6.1f %6.1f", mv->m_vecVelocity.Length(), maxspeed, speed, mv->GetAbsOrigin().x, mv->GetAbsOrigin().y, mv->GetAbsOrigin().z, GetPlayerMins().x, GetPlayerMins().y, GetPlayerMins().z, GetPlayerMaxs().x, GetPlayerMaxs().y, GetPlayerMaxs().z ); } #else if( sv_showmovementspeed.GetInt() == player->entindex() ) { engine->Con_NPrintf( 3, "SERVER Movement speed: %6.1f | maxspeed: %6.1f | userspeed: %6.1f | pos: %6.1f %6.1f %6.1f | mins: %6.1f %6.1f %6.1f | maxs: %6.1f %6.1f %6.1f", mv->m_vecVelocity.Length(), maxspeed, speed, mv->GetAbsOrigin().x, mv->GetAbsOrigin().y, mv->GetAbsOrigin().z, GetPlayerMins().x, GetPlayerMins().y, GetPlayerMins().z, GetPlayerMaxs().x, GetPlayerMaxs().y, GetPlayerMaxs().z ); } #endif // CLIENT_DLL //CheckVelocity(); // Store current height heightchange = mv->GetAbsOrigin().z; if( warsplayer->GetCamHeight() != -1 ) { //Vector vCamOffsetZ = Vector(0.0f, 0.0f, warsplayer->GetCameraOffset().z); //TracePlayerBBox( mv->GetAbsOrigin(), warsplayer->GetCamGroundPos()+vCamOffsetZ, PlayerSolidMask(), COLLISION_GROUP_PLAYER_MOVEMENT, pm ); TracePlayerBBox( mv->GetAbsOrigin(), warsplayer->GetCamGroundPos()+Vector(0, 0, warsplayer->GetCamMaxHeight()-48.0f), PlayerSolidMask(), COLLISION_GROUP_PLAYER_MOVEMENT, pm ); mv->SetAbsOrigin( pm.endpos ); //NDebugOverlay::Box( warsplayer->GetCamGroundPos()+vCamOffsetZ, -Vector(16, 16, 16), Vector(16, 16, 16), 255, 0, 0, 255, gpGlobals->frametime ); } // Try moving, only obstructed by the map boundaries. Vector destination; VectorMA( mv->GetAbsOrigin(), gpGlobals->frametime, mv->m_vecVelocity, destination ); TracePlayerBBox( mv->GetAbsOrigin(), destination, PlayerSolidMask(), COLLISION_GROUP_PLAYER_MOVEMENT, pm ); if (pm.fraction == 1) { mv->SetAbsOrigin( pm.endpos ); } else { // Try moving straight along out normal path. TryStrategicMove(); } // Determine new height and return player to the ground warsplayer->CalculateHeight( mv->GetAbsOrigin() ); if( warsplayer->GetCamHeight() != -1 ) { TracePlayerBBox( mv->GetAbsOrigin(), warsplayer->GetCamGroundPos(), PlayerSolidMask(), COLLISION_GROUP_PLAYER_MOVEMENT, pm ); mv->SetAbsOrigin( pm.endpos ); //NDebugOverlay::Box( pm.endpos, -Vector(16, 16, 16), Vector(16, 16, 16), 0, 255, 0, 255, gpGlobals->frametime ); // Determine new height again :) warsplayer->CalculateHeight( mv->GetAbsOrigin() ); } // Determine height change and notify input heightchange = mv->GetAbsOrigin().z - heightchange; #ifdef CLIENT_DLL if( heightchange > 0.1f ) { } #endif // CLIENT_DLL //CheckVelocity(); // Zero out velocity if in noaccel mode if ( maxacceleration < 0.0f ) { mv->m_vecVelocity.Init(); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFGameMovement::WalkMove( void ) { // Get the movement angles. Vector vecForward, vecRight, vecUp; AngleVectors( mv->m_vecViewAngles, &vecForward, &vecRight, &vecUp ); vecForward.z = 0.0f; vecRight.z = 0.0f; VectorNormalize( vecForward ); VectorNormalize( vecRight ); // Copy movement amounts float flForwardMove = mv->m_flForwardMove; float flSideMove = mv->m_flSideMove; // Find the direction,velocity in the x,y plane. Vector vecWishDirection( ( ( vecForward.x * flForwardMove ) + ( vecRight.x * flSideMove ) ), ( ( vecForward.y * flForwardMove ) + ( vecRight.y * flSideMove ) ), 0.0f ); // Calculate the speed and direction of movement, then clamp the speed. float flWishSpeed = VectorNormalize( vecWishDirection ); flWishSpeed = clamp( flWishSpeed, 0.0f, mv->m_flMaxSpeed ); // Accelerate in the x,y plane. mv->m_vecVelocity.z = 0; Accelerate( vecWishDirection, flWishSpeed, sv_accelerate.GetFloat() ); Assert( mv->m_vecVelocity.z == 0.0f ); // Clamp the players speed in x,y. if ( tf2c_groundspeed_cap.GetBool() ) { float flNewSpeed = VectorLength(mv->m_vecVelocity); if (flNewSpeed > mv->m_flMaxSpeed) { float flScale = (mv->m_flMaxSpeed / flNewSpeed); mv->m_vecVelocity.x *= flScale; mv->m_vecVelocity.y *= flScale; } } // Now reduce their backwards speed to some percent of max, if they are travelling backwards // unless they are under some minimum, to not penalize deployed snipers or heavies if ( tf_clamp_back_speed.GetFloat() < 1.0 && VectorLength( mv->m_vecVelocity ) > tf_clamp_back_speed_min.GetFloat() ) { float flDot = DotProduct( vecForward, mv->m_vecVelocity ); // are we moving backwards at all? if ( flDot < 0 ) { Vector vecBackMove = vecForward * flDot; Vector vecRightMove = vecRight * DotProduct( vecRight, mv->m_vecVelocity ); // clamp the back move vector if it is faster than max float flBackSpeed = VectorLength( vecBackMove ); float flMaxBackSpeed = ( mv->m_flMaxSpeed * tf_clamp_back_speed.GetFloat() ); if ( flBackSpeed > flMaxBackSpeed ) { vecBackMove *= flMaxBackSpeed / flBackSpeed; } // reassemble velocity mv->m_vecVelocity = vecBackMove + vecRightMove; } } // Add base velocity to the player's current velocity - base velocity = velocity from conveyors, etc. VectorAdd( mv->m_vecVelocity, player->GetBaseVelocity(), mv->m_vecVelocity ); // Calculate the current speed and return if we are not really moving. float flSpeed = VectorLength( mv->m_vecVelocity ); if ( flSpeed < 1.0f ) { // I didn't remove the base velocity here since it wasn't moving us in the first place. mv->m_vecVelocity.Init(); return; } // Calculate the destination. Vector vecDestination; vecDestination.x = mv->GetAbsOrigin().x + ( mv->m_vecVelocity.x * gpGlobals->frametime ); vecDestination.y = mv->GetAbsOrigin().y + ( mv->m_vecVelocity.y * gpGlobals->frametime ); vecDestination.z = mv->GetAbsOrigin().z; // Try moving to the destination. trace_t trace; TracePlayerBBox( mv->GetAbsOrigin(), vecDestination, PlayerSolidMask(), COLLISION_GROUP_PLAYER_MOVEMENT, trace ); if ( trace.fraction == 1.0f ) { // Made it to the destination (remove the base velocity). mv->SetAbsOrigin( trace.endpos ); VectorSubtract( mv->m_vecVelocity, player->GetBaseVelocity(), mv->m_vecVelocity ); // Save the wish velocity. mv->m_outWishVel += ( vecWishDirection * flWishSpeed ); // Try and keep the player on the ground. // NOTE YWB 7/5/07: Don't do this here, our version of CategorizePosition encompasses this test // StayOnGround(); return; } // Now try and do a step move. StepMove( vecDestination, trace ); // Remove base velocity. Vector baseVelocity = player->GetBaseVelocity(); VectorSubtract( mv->m_vecVelocity, baseVelocity, mv->m_vecVelocity ); // Save the wish velocity. mv->m_outWishVel += ( vecWishDirection * flWishSpeed ); // Try and keep the player on the ground. // NOTE YWB 7/5/07: Don't do this here, our version of CategorizePosition encompasses this test // StayOnGround(); #if 0 // Debugging!!! Vector vecTestVelocity = mv->m_vecVelocity; vecTestVelocity.z = 0.0f; float flTestSpeed = VectorLength( vecTestVelocity ); if ( baseVelocity.IsZero() && ( flTestSpeed > ( mv->m_flMaxSpeed + 1.0f ) ) ) { Msg( "Step Max Speed < %f\n", flTestSpeed ); } if ( tf_showspeed.GetBool() ) { Msg( "Speed=%f\n", flTestSpeed ); } #endif }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFGameMovement::WaterMove( void ) { int i; float wishspeed; Vector wishdir; Vector start, dest; Vector temp; trace_t pm; float speed, newspeed, addspeed, accelspeed; // Determine movement angles. Vector vecForward, vecRight, vecUp; AngleVectors( mv->m_vecViewAngles, &vecForward, &vecRight, &vecUp ); // Calculate the desired direction and speed. Vector vecWishVelocity; int iAxis; for ( iAxis = 0 ; iAxis < 3; ++iAxis ) { vecWishVelocity[iAxis] = ( vecForward[iAxis] * mv->m_flForwardMove ) + ( vecRight[iAxis] * mv->m_flSideMove ); } // Check for upward velocity (JUMP). if ( mv->m_nButtons & IN_JUMP ) { if ( player->GetWaterLevel() == WL_Eyes ) { vecWishVelocity[2] += mv->m_flClientMaxSpeed; } } // Sinking if not moving. else if ( !mv->m_flForwardMove && !mv->m_flSideMove && !mv->m_flUpMove ) { vecWishVelocity[2] -= 60; } // Move up based on view angle. else { vecWishVelocity[2] += mv->m_flUpMove; } // Copy it over and determine speed VectorCopy( vecWishVelocity, wishdir ); wishspeed = VectorNormalize( wishdir ); // Cap speed. if (wishspeed > mv->m_flMaxSpeed) { VectorScale( vecWishVelocity, mv->m_flMaxSpeed/wishspeed, vecWishVelocity ); wishspeed = mv->m_flMaxSpeed; } // Slow us down a bit. wishspeed *= 0.8; // Water friction VectorCopy( mv->m_vecVelocity, temp ); speed = VectorNormalize( temp ); if ( speed ) { newspeed = speed - gpGlobals->frametime * speed * sv_friction.GetFloat() * player->m_surfaceFriction; if ( newspeed < 0.1f ) { newspeed = 0; } VectorScale (mv->m_vecVelocity, newspeed/speed, mv->m_vecVelocity); } else { newspeed = 0; } // water acceleration if (wishspeed >= 0.1f) // old ! { addspeed = wishspeed - newspeed; if (addspeed > 0) { VectorNormalize(vecWishVelocity); accelspeed = sv_accelerate.GetFloat() * wishspeed * gpGlobals->frametime * player->m_surfaceFriction; if (accelspeed > addspeed) { accelspeed = addspeed; } for (i = 0; i < 3; i++) { float deltaSpeed = accelspeed * vecWishVelocity[i]; mv->m_vecVelocity[i] += deltaSpeed; mv->m_outWishVel[i] += deltaSpeed; } } } VectorAdd (mv->m_vecVelocity, player->GetBaseVelocity(), mv->m_vecVelocity); // Now move // assume it is a stair or a slope, so press down from stepheight above VectorMA (mv->GetAbsOrigin(), gpGlobals->frametime, mv->m_vecVelocity, dest); TracePlayerBBox( mv->GetAbsOrigin(), dest, PlayerSolidMask(), COLLISION_GROUP_PLAYER_MOVEMENT, pm ); if ( pm.fraction == 1.0f ) { VectorCopy( dest, start ); if ( player->m_Local.m_bAllowAutoMovement ) { start[2] += player->m_Local.m_flStepSize + 1; } TracePlayerBBox( start, dest, PlayerSolidMask(), COLLISION_GROUP_PLAYER_MOVEMENT, pm ); if (!pm.startsolid && !pm.allsolid) { #if 0 float stepDist = pm.endpos.z - mv->GetAbsOrigin().z; mv->m_outStepHeight += stepDist; // walked up the step, so just keep result and exit Vector vecNewWaterPoint; VectorCopy( m_vecWaterPoint, vecNewWaterPoint ); vecNewWaterPoint.z += ( dest.z - mv->GetAbsOrigin().z ); bool bOutOfWater = !( enginetrace->GetPointContents( vecNewWaterPoint ) & MASK_WATER ); if ( bOutOfWater && ( mv->m_vecVelocity.z > 0.0f ) && ( pm.fraction == 1.0f ) ) { // Check the waist level water positions. trace_t traceWater; UTIL_TraceLine( vecNewWaterPoint, m_vecWaterPoint, CONTENTS_WATER, player, COLLISION_GROUP_NONE, &traceWater ); if( traceWater.fraction < 1.0f ) { float flFraction = 1.0f - traceWater.fraction; // Vector vecSegment; // VectorSubtract( mv->GetAbsOrigin(), dest, vecSegment ); // VectorMA( mv->GetAbsOrigin(), flFraction, vecSegment, mv->GetAbsOrigin() ); float flZDiff = dest.z - mv->GetAbsOrigin().z; float flSetZ = mv->GetAbsOrigin().z + ( flFraction * flZDiff ); flSetZ -= 0.0325f; VectorCopy (pm.endpos, mv->GetAbsOrigin()); mv->GetAbsOrigin().z = flSetZ; VectorSubtract( mv->m_vecVelocity, player->GetBaseVelocity(), mv->m_vecVelocity ); mv->m_vecVelocity.z = 0.0f; } } else { VectorCopy (pm.endpos, mv->GetAbsOrigin()); VectorSubtract( mv->m_vecVelocity, player->GetBaseVelocity(), mv->m_vecVelocity ); } return; #endif float stepDist = pm.endpos.z - mv->GetAbsOrigin().z; mv->m_outStepHeight += stepDist; // walked up the step, so just keep result and exit mv->SetAbsOrigin( pm.endpos ); VectorSubtract( mv->m_vecVelocity, player->GetBaseVelocity(), mv->m_vecVelocity ); return; } // Try moving straight along out normal path. TryPlayerMove(); } else { if ( !player->GetGroundEntity() ) { TryPlayerMove(); VectorSubtract( mv->m_vecVelocity, player->GetBaseVelocity(), mv->m_vecVelocity ); return; } StepMove( dest, pm ); } VectorSubtract( mv->m_vecVelocity, player->GetBaseVelocity(), mv->m_vecVelocity ); }
//----------------------------------------------------------------------------- // Purpose: Does the basic move attempting to climb up step heights. It uses // the mv->GetAbsOrigin() and mv->m_vecVelocity. It returns a new // new mv->GetAbsOrigin(), mv->m_vecVelocity, and mv->m_outStepHeight. //----------------------------------------------------------------------------- void CTFGameMovement::StepMove( Vector &vecDestination, trace_t &trace ) { trace_t saveTrace; saveTrace = trace; Vector vecEndPos; VectorCopy( vecDestination, vecEndPos ); Vector vecPos, vecVel; VectorCopy( mv->GetAbsOrigin(), vecPos ); VectorCopy( mv->m_vecVelocity, vecVel ); bool bLowRoad = false; bool bUpRoad = true; // First try the "high road" where we move up and over obstacles if ( player->m_Local.m_bAllowAutoMovement ) { // Trace up by step height VectorCopy( mv->GetAbsOrigin(), vecEndPos ); vecEndPos.z += player->m_Local.m_flStepSize + DIST_EPSILON; TracePlayerBBox( mv->GetAbsOrigin(), vecEndPos, PlayerSolidMask(), COLLISION_GROUP_PLAYER_MOVEMENT, trace ); if ( !trace.startsolid && !trace.allsolid ) { mv->SetAbsOrigin( trace.endpos ); } // Trace over from there TryPlayerMove(); // Then trace back down by step height to get final position VectorCopy( mv->GetAbsOrigin(), vecEndPos ); vecEndPos.z -= player->m_Local.m_flStepSize + DIST_EPSILON; TracePlayerBBox( mv->GetAbsOrigin(), vecEndPos, PlayerSolidMask(), COLLISION_GROUP_PLAYER_MOVEMENT, trace ); // If the trace ended up in empty space, copy the end over to the origin. if ( !trace.startsolid && !trace.allsolid ) { mv->SetAbsOrigin( trace.endpos ); } // If we are not on the standable ground any more or going the "high road" didn't move us at all, then we'll also want to check the "low road" if ( ( trace.fraction != 1.0f && trace.plane.normal[2] < 0.7 ) || VectorCompare( mv->GetAbsOrigin(), vecPos ) ) { bLowRoad = true; bUpRoad = false; } } else { bLowRoad = true; bUpRoad = false; } if ( bLowRoad ) { // Save off upward results Vector vecUpPos, vecUpVel; if ( bUpRoad ) { VectorCopy( mv->GetAbsOrigin(), vecUpPos ); VectorCopy( mv->m_vecVelocity, vecUpVel ); } // Take the "low" road mv->SetAbsOrigin( vecPos ); VectorCopy( vecVel, mv->m_vecVelocity ); VectorCopy( vecDestination, vecEndPos ); TryPlayerMove( &vecEndPos, &saveTrace ); // Down results. Vector vecDownPos, vecDownVel; VectorCopy( mv->GetAbsOrigin(), vecDownPos ); VectorCopy( mv->m_vecVelocity, vecDownVel ); if ( bUpRoad ) { float flUpDist = ( vecUpPos.x - vecPos.x ) * ( vecUpPos.x - vecPos.x ) + ( vecUpPos.y - vecPos.y ) * ( vecUpPos.y - vecPos.y ); float flDownDist = ( vecDownPos.x - vecPos.x ) * ( vecDownPos.x - vecPos.x ) + ( vecDownPos.y - vecPos.y ) * ( vecDownPos.y - vecPos.y ); // decide which one went farther if ( flUpDist >= flDownDist ) { mv->SetAbsOrigin( vecUpPos ); VectorCopy( vecUpVel, mv->m_vecVelocity ); // copy z value from the Low Road move mv->m_vecVelocity.z = vecDownVel.z; } } } float flStepDist = mv->GetAbsOrigin().z - vecPos.z; if ( flStepDist > 0 ) { mv->m_outStepHeight += flStepDist; } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFGameMovement::CheckWaterJump( void ) { Vector flatforward; Vector flatvelocity; float curspeed; // Jump button down? bool bJump = ( ( mv->m_nButtons & IN_JUMP ) != 0 ); Vector forward, right; AngleVectors( mv->m_vecViewAngles, &forward, &right, NULL ); // Determine movement angles // Already water jumping. if (player->m_flWaterJumpTime) return; // Don't hop out if we just jumped in if (mv->m_vecVelocity[2] < -180) return; // only hop out if we are moving up // See if we are backing up flatvelocity[0] = mv->m_vecVelocity[0]; flatvelocity[1] = mv->m_vecVelocity[1]; flatvelocity[2] = 0; // Must be moving curspeed = VectorNormalize( flatvelocity ); #if 1 // Copy movement amounts float fmove = mv->m_flForwardMove; float smove = mv->m_flSideMove; for ( int iAxis = 0; iAxis < 2; ++iAxis ) { flatforward[iAxis] = forward[iAxis] * fmove + right[iAxis] * smove; } #else // see if near an edge flatforward[0] = forward[0]; flatforward[1] = forward[1]; #endif flatforward[2] = 0; VectorNormalize( flatforward ); // Are we backing into water from steps or something? If so, don't pop forward if ( curspeed != 0.0 && ( DotProduct( flatvelocity, flatforward ) < 0.0 ) && !bJump ) return; Vector vecStart; // Start line trace at waist height (using the center of the player for this here) vecStart= mv->GetAbsOrigin() + (GetPlayerMins() + GetPlayerMaxs() ) * 0.5; Vector vecEnd; VectorMA( vecStart, TF_WATERJUMP_FORWARD/*tf_waterjump_forward.GetFloat()*/, flatforward, vecEnd ); trace_t tr; TracePlayerBBox( vecStart, vecEnd, PlayerSolidMask(), COLLISION_GROUP_PLAYER_MOVEMENT, tr ); if ( tr.fraction < 1.0 ) // solid at waist { IPhysicsObject *pPhysObj = tr.m_pEnt->VPhysicsGetObject(); if ( pPhysObj ) { if ( pPhysObj->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) return; } vecStart.z = mv->GetAbsOrigin().z + player->GetViewOffset().z + WATERJUMP_HEIGHT; VectorMA( vecStart, TF_WATERJUMP_FORWARD/*tf_waterjump_forward.GetFloat()*/, flatforward, vecEnd ); VectorMA( vec3_origin, -50.0f, tr.plane.normal, player->m_vecWaterJumpVel ); TracePlayerBBox( vecStart, vecEnd, PlayerSolidMask(), COLLISION_GROUP_PLAYER_MOVEMENT, tr ); if ( tr.fraction == 1.0 ) // open at eye level { // Now trace down to see if we would actually land on a standable surface. VectorCopy( vecEnd, vecStart ); vecEnd.z -= 1024.0f; TracePlayerBBox( vecStart, vecEnd, PlayerSolidMask(), COLLISION_GROUP_PLAYER_MOVEMENT, tr ); if ( ( tr.fraction < 1.0f ) && ( tr.plane.normal.z >= 0.7 ) ) { mv->m_vecVelocity[2] = TF_WATERJUMP_UP/*tf_waterjump_up.GetFloat()*/; // Push up mv->m_nOldButtons |= IN_JUMP; // Don't jump again until released player->AddFlag( FL_WATERJUMP ); player->m_flWaterJumpTime = 2000.0f; // Do this for 2 seconds } } } }
void CMomentumGameMovement::Duck(void) { int buttonsChanged = (mv->m_nOldButtons ^ mv->m_nButtons); // These buttons have changed this frame int buttonsPressed = buttonsChanged & mv->m_nButtons; // The changed ones still down are "pressed" int buttonsReleased = buttonsChanged & mv->m_nOldButtons; // The changed ones which were previously down are "released" // Check to see if we are in the air. bool bInAir = player->GetGroundEntity() == NULL && player->GetMoveType() != MOVETYPE_LADDER; if (mv->m_nButtons & IN_DUCK) { mv->m_nOldButtons |= IN_DUCK; } else { mv->m_nOldButtons &= ~IN_DUCK; } if (IsDead()) { // Unduck if (player->GetFlags() & FL_DUCKING) { FinishUnDuck(); } return; } HandleDuckingSpeedCrop(); if (player->m_duckUntilOnGround) { if (!bInAir) { player->m_duckUntilOnGround = false; if (CanUnduck()) { FinishUnDuck(); } return; } else { if (mv->m_vecVelocity.z > 0.0f) return; // Check if we can un-duck. We want to unduck if we have space for the standing hull, and // if it is less than 2 inches off the ground. trace_t trace; Vector newOrigin; Vector groundCheck; VectorCopy(mv->GetAbsOrigin(), newOrigin); Vector hullSizeNormal = VEC_HULL_MAX - VEC_HULL_MIN; Vector hullSizeCrouch = VEC_DUCK_HULL_MAX - VEC_DUCK_HULL_MIN; newOrigin -= (hullSizeNormal - hullSizeCrouch); groundCheck = newOrigin; groundCheck.z -= player->GetStepSize(); UTIL_TraceHull(newOrigin, groundCheck, VEC_HULL_MIN, VEC_HULL_MAX, PlayerSolidMask(), player, COLLISION_GROUP_PLAYER_MOVEMENT, &trace); if (trace.startsolid || trace.fraction == 1.0f) return; // Can't even stand up, or there's no ground underneath us player->m_duckUntilOnGround = false; if (CanUnduck()) { FinishUnDuck(); } return; } } // Holding duck, in process of ducking or fully ducked? if ((mv->m_nButtons & IN_DUCK) || (player->m_Local.m_bDucking) || (player->GetFlags() & FL_DUCKING)) { if (mv->m_nButtons & IN_DUCK) { bool alreadyDucked = (player->GetFlags() & FL_DUCKING) ? true : false; if ((buttonsPressed & IN_DUCK) && !(player->GetFlags() & FL_DUCKING)) { // Use 1 second so super long jump will work player->m_Local.m_flDucktime = 1000; player->m_Local.m_bDucking = true; } float duckmilliseconds = max(0.0f, 1000.0f - (float)player->m_Local.m_flDucktime); float duckseconds = duckmilliseconds / 1000.0f; //time = max( 0.0, ( 1.0 - (float)player->m_Local.m_flDucktime / 1000.0 ) ); if (player->m_Local.m_bDucking) { // Finish ducking immediately if duck time is over or not on ground if ((duckseconds > TIME_TO_DUCK) || (player->GetGroundEntity() == NULL) || alreadyDucked) { FinishDuck(); } else { // Calc parametric time float duckFraction = SimpleSpline(duckseconds / TIME_TO_DUCK); SetDuckedEyeOffset(duckFraction); } } } else { // Try to unduck unless automovement is not allowed // NOTE: When not onground, you can always unduck if (player->m_Local.m_bAllowAutoMovement || player->GetGroundEntity() == NULL) { if ((buttonsReleased & IN_DUCK) && (player->GetFlags() & FL_DUCKING)) { // Use 1 second so super long jump will work player->m_Local.m_flDucktime = 1000; player->m_Local.m_bDucking = true; // or unducking } float duckmilliseconds = max(0.0f, 1000.0f - (float)player->m_Local.m_flDucktime); float duckseconds = duckmilliseconds / 1000.0f; if (CanUnduck()) { if (player->m_Local.m_bDucking || player->m_Local.m_bDucked) // or unducking { // Finish ducking immediately if duck time is over or not on ground if ((duckseconds > TIME_TO_UNDUCK) || (player->GetGroundEntity() == NULL)) { FinishUnDuck(); } else { // Calc parametric time float duckFraction = SimpleSpline(1.0f - (duckseconds / TIME_TO_UNDUCK)); SetDuckedEyeOffset(duckFraction); } } } else { // Still under something where we can't unduck, so make sure we reset this timer so // that we'll unduck once we exit the tunnel, etc. player->m_Local.m_flDucktime = 1000; } } } } }