//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHL2WarsGameMovement::PlayerMove() { // Other movetype than strategic? use base class if( player->GetMoveType() != MOVETYPE_STRATEGIC ) { CGameMovement::PlayerMove(); return; } VPROF( "CHL2WarsGameMovement::PlayerMove" ); CheckParameters(); // clear output applied velocity mv->m_outWishVel.Init(); mv->m_outJumpVel.Init(); MoveHelper( )->ResetTouchList(); // Assume we don't touch anything ReduceTimers(); AngleVectors (mv->m_vecViewAngles, &m_vecForward, &m_vecRight, &m_vecUp ); // Determine movement angles SetGroundEntity( NULL ); // Store off the starting water level m_nOldWaterLevel = player->GetWaterLevel(); m_nOnLadder = 0; StrategicPlayerMove(); }
//----------------------------------------------------------------------------- // Purpose: // Input : step - // fvol - // force - force sound to play //----------------------------------------------------------------------------- void CDODPlayer::PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force ) { if ( gpGlobals->maxClients > 1 && !sv_footsteps.GetFloat() ) return; #if defined( CLIENT_DLL ) // during prediction play footstep sounds only once if ( prediction->InPrediction() && !prediction->IsFirstTimePredicted() ) return; #endif if ( !psurface ) return; unsigned short stepSoundName = m_Local.m_nStepside ? psurface->sounds.stepleft : psurface->sounds.stepright; m_Local.m_nStepside = !m_Local.m_nStepside; if ( !stepSoundName ) return; IPhysicsSurfaceProps *physprops = MoveHelper( )->GetSurfaceProps(); const char *pSoundName = physprops->GetString( stepSoundName ); CSoundParameters params; // we don't always know the model, so go by team char *pModelNameForGender = DOD_PLAYERMODEL_AXIS_RIFLEMAN; if( GetTeamNumber() == TEAM_ALLIES ) pModelNameForGender = DOD_PLAYERMODEL_US_RIFLEMAN; if ( !CBaseEntity::GetParametersForSound( pSoundName, params, pModelNameForGender ) ) return; CRecipientFilter filter; filter.AddRecipientsByPAS( vecOrigin ); #ifndef CLIENT_DLL // im MP, server removed all players in origins PVS, these players // generate the footsteps clientside if ( gpGlobals->maxClients > 1 ) filter.RemoveRecipientsByPVS( vecOrigin ); #endif EmitSound_t ep; ep.m_nChannel = params.channel; ep.m_pSoundName = params.soundname; ep.m_flVolume = fvol; ep.m_SoundLevel = params.soundlevel; ep.m_nFlags = 0; ep.m_nPitch = params.pitch; ep.m_pOrigin = &vecOrigin; EmitSound( filter, entindex(), ep ); }
//----------------------------------------------------------------------------- // Purpose: // Input : step - // fvol - // force - force sound to play //----------------------------------------------------------------------------- void CHL2MP_Player::PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force ) { if ( gpGlobals->maxClients > 1 && !sv_footsteps.GetFloat() ) return; #if defined( CLIENT_DLL ) // during prediction play footstep sounds only once if ( !prediction->IsFirstTimePredicted() ) return; #endif if ( GetFlags() & FL_DUCKING ) return; int nSide = m_Local.m_nStepside; m_Local.m_nStepside = !m_Local.m_nStepside; unsigned short stepSoundName = nSide ? psurface->sounds.stepleft : psurface->sounds.stepright; IPhysicsSurfaceProps *physprops = MoveHelper()->GetSurfaceProps(); const char *pSoundName = physprops->GetString( stepSoundName ); CSoundParameters params; if ( GetParametersForSound( pSoundName, params, NULL ) == false ) return; CRecipientFilter filter; filter.AddRecipientsByPAS( vecOrigin ); #ifndef CLIENT_DLL // im MP, server removed all players in origins PVS, these players // generate the footsteps clientside if ( gpGlobals->maxClients > 1 ) filter.RemoveRecipientsByPVS( vecOrigin ); #endif EmitSound_t ep; ep.m_nChannel = CHAN_BODY; ep.m_pSoundName = params.soundname; ep.m_flVolume = fvol; ep.m_SoundLevel = params.soundlevel; ep.m_nFlags = 0; ep.m_nPitch = params.pitch; ep.m_pOrigin = &vecOrigin; EmitSound( filter, entindex(), ep ); }
void CMomentumGameMovement::CategorizeGroundSurface(trace_t &pm) { IPhysicsSurfaceProps *physprops = MoveHelper()->GetSurfaceProps(); //CMomentumPlayer *player = GetMomentumPlayer(); player->m_surfaceProps = pm.surface.surfaceProps; player->m_pSurfaceData = physprops->GetSurfaceData(player->m_surfaceProps); physprops->GetPhysicsProperties(player->m_surfaceProps, NULL, NULL, &player->m_surfaceFriction, NULL); // HACKHACK: Scale this to fudge the relationship between vphysics friction values and player friction values. // A value of 0.8f feels pretty normal for vphysics, whereas 1.0f is normal for players. // This scaling trivially makes them equivalent. REVISIT if this affects low friction surfaces too much. player->m_surfaceFriction *= 1.25f; if (player->m_surfaceFriction > 1.0f || (player->m_pSurfaceData->game.material == 'D' && player->m_pSurfaceData->physics.friction == 0.35f)) player->m_surfaceFriction = 1.0f;//fix for snow friction player->m_chTextureType = player->m_pSurfaceData->game.material; }
// This was the virtual void, overriding it for snow friction void CMomentumGameMovement::SetGroundEntity(trace_t *pm) { //CMomentumPlayer *player = GetMomentumPlayer(); CBaseEntity *newGround = pm ? pm->m_pEnt : NULL; CBaseEntity *oldGround = player->GetGroundEntity(); Vector vecBaseVelocity = player->GetBaseVelocity(); if (!oldGround && newGround) { // Subtract ground velocity at instant we hit ground jumping vecBaseVelocity -= newGround->GetAbsVelocity(); vecBaseVelocity.z = newGround->GetAbsVelocity().z; } else if (oldGround && !newGround) { // Add in ground velocity at instant we started jumping vecBaseVelocity += oldGround->GetAbsVelocity(); vecBaseVelocity.z = oldGround->GetAbsVelocity().z; } player->SetBaseVelocity(vecBaseVelocity); player->SetGroundEntity(newGround); // If we are on something... if (newGround) { CategorizeGroundSurface(*pm);//Snow friction override // Then we are not in water jump sequence player->m_flWaterJumpTime = 0; // Standing on an entity other than the world, so signal that we are touching something. if (!pm->DidHitWorld()) { MoveHelper()->AddToTouched(*pm, mv->m_vecVelocity); } mv->m_vecVelocity.z = 0.0f; } }
//----------------------------------------------------------------------------- // Implement this if you want to know when the player collides during OnPlayerMove //----------------------------------------------------------------------------- void CTFGameMovementRecon::OnTryPlayerMoveCollision( trace_t &tr ) { if ( !m_bPerformingAirMove ) return; // Only keep track of world collisions if ( tr.DidHitWorld() ) { CTFMoveData *pTFMove = TFMove(); if ( pTFMove ) { if ( ( pTFMove->ReconData().m_flSuppressionJumpTime == TIME_WALL_INVALID ) && ( pTFMove->ReconData().m_flSuppressionImpactTime == TIME_WALL_INVALID ) ) { // No walljumps off of mostly horizontal surfaces... if ( fabs( tr.plane.normal.z ) > 0.9f ) return; // No walljumps off of the same plane as the last one... if ( (pTFMove->ReconData().m_flImpactDist == tr.plane.dist) && (VectorsAreEqual(pTFMove->ReconData().m_vecImpactNormal, tr.plane.normal, 1e-2) ) ) { return; } // If you hit a wall, no double jumps for you pTFMove->ReconData().m_nJumpCount = 2; // Play an impact sound MoveHelper()->StartSound( pTFMove->m_vecAbsOrigin, "Recon.WallJump" ); pTFMove->ReconData().m_vecImpactNormal = tr.plane.normal; pTFMove->ReconData().m_flImpactDist = tr.plane.dist; pTFMove->ReconData().m_flActiveJumpTime = TIME_WALL_ACTIVATE_JUMP; pTFMove->ReconData().m_flSuppressionImpactTime = TIME_WALL_SUPPRESSION_IMPACT; } } } }
//----------------------------------------------------------------------------- // Purpose: // Input : step - // fvol - // force - force sound to play //----------------------------------------------------------------------------- void CBasePlayer::PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force ) { if ( gpGlobals->maxClients > 1 && !sv_footsteps.GetFloat() ) return; #if defined( CLIENT_DLL ) // during prediction play footstep sounds only once if ( prediction->InPrediction() && !prediction->IsFirstTimePredicted() ) return; #endif if ( !psurface ) return; int nSide = m_Local.m_nStepside; unsigned short stepSoundName = nSide ? psurface->sounds.stepleft : psurface->sounds.stepright; if ( !stepSoundName ) return; m_Local.m_nStepside = !nSide; CSoundParameters params; Assert( nSide == 0 || nSide == 1 ); if ( m_StepSoundCache[ nSide ].m_usSoundNameIndex == stepSoundName ) { params = m_StepSoundCache[ nSide ].m_SoundParameters; } else { IPhysicsSurfaceProps *physprops = MoveHelper()->GetSurfaceProps(); const char *pSoundName = physprops->GetString( stepSoundName ); if ( !CBaseEntity::GetParametersForSound( pSoundName, params, NULL ) ) return; // Only cache if there's one option. Otherwise we'd never here any other sounds if ( params.count == 1 ) { m_StepSoundCache[ nSide ].m_usSoundNameIndex = stepSoundName; m_StepSoundCache[ nSide ].m_SoundParameters = params; } } CRecipientFilter filter; filter.AddRecipientsByPAS( vecOrigin ); #ifndef CLIENT_DLL // in MP, server removes all players in the vecOrigin's PVS, these players generate the footsteps client side if ( gpGlobals->maxClients > 1 ) { filter.RemoveRecipientsByPVS( vecOrigin ); } #endif EmitSound_t ep; ep.m_nChannel = CHAN_BODY; ep.m_pSoundName = params.soundname; ep.m_flVolume = fvol; ep.m_SoundLevel = params.soundlevel; ep.m_nFlags = 0; ep.m_nPitch = params.pitch; ep.m_pOrigin = &vecOrigin; EmitSound( filter, entindex(), ep ); }
//----------------------------------------------------------------------------- // 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; }
void CMomentumGameMovement::CategorizePosition(float flReflectNormal) { Vector point; trace_t pm; // 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; // if the player hull point one unit down is solid, the player // is on ground // see if standing on something solid // 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(); // observers don't have a ground entity if (player->IsObserver()) return; float flOffset = 2.0f; point[0] = mv->GetAbsOrigin()[0]; point[1] = mv->GetAbsOrigin()[1]; point[2] = mv->GetAbsOrigin()[2] - flOffset; Vector bumpOrigin; bumpOrigin = mv->GetAbsOrigin(); // Shooting up really fast. Definitely not on ground. // On ladder moving up, so not on ground either // NOTE: 145 is a jump. #define NON_JUMP_VELOCITY 140.0f float zvel = mv->m_vecVelocity[2]; bool bMovingUp = zvel > 0.0f; bool bMovingUpRapidly = zvel > NON_JUMP_VELOCITY; float flGroundEntityVelZ = 0.0f; if (bMovingUpRapidly) { // Tracker 73219, 75878: ywb 8/2/07 // After save/restore (and maybe at other times), we can get a case where we were saved on a lift and // after restore we'll have a high local velocity due to the lift making our abs velocity appear high. // We need to account for standing on a moving ground object in that case in order to determine if we really // are moving away from the object we are standing on at too rapid a speed. Note that CheckJump already sets // ground entity to NULL, so this wouldn't have any effect unless we are moving up rapidly not from the jump button. CBaseEntity *ground = player->GetGroundEntity(); if (ground) { flGroundEntityVelZ = ground->GetAbsVelocity().z; bMovingUpRapidly = (zvel - flGroundEntityVelZ) > NON_JUMP_VELOCITY; } } // Was on ground, but now suddenly am not if (bMovingUpRapidly || (bMovingUp && player->GetMoveType() == MOVETYPE_LADDER)) { SetGroundEntity(NULL); } else { // Try and move down. TryTouchGround(bumpOrigin, point, GetPlayerMins(), GetPlayerMaxs(), MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, pm); // Was on ground, but now suddenly am not. If we hit a steep plane, we are not on ground if (!pm.m_pEnt || pm.plane.normal[2] < 0.7) { // Test four sub-boxes, to see if any of them would have found shallower slope we could actually stand on TryTouchGroundInQuadrants(bumpOrigin, point, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, pm); if (!pm.m_pEnt || pm.plane.normal[2] < 0.7) { SetGroundEntity(NULL); // probably want to add a check for a +z velocity too! if ((mv->m_vecVelocity.z > 0.0f) && (player->GetMoveType() != MOVETYPE_NOCLIP)) { player->m_surfaceFriction = 0.25f; } } else { if ( flReflectNormal == NO_REFL_NORMAL_CHANGE) { DoLateReflect(); CategorizePosition(1.0f); return; } SetGroundEntity(&pm); } } else { if ( flReflectNormal == NO_REFL_NORMAL_CHANGE ) { DoLateReflect(); CategorizePosition(1.0f); return; } SetGroundEntity(&pm); // Otherwise, point to index of ent under us. } #ifndef CLIENT_DLL // If our gamematerial has changed, tell any player surface triggers that are watching IPhysicsSurfaceProps *physprops = MoveHelper()->GetSurfaceProps(); surfacedata_t *pSurfaceProp = physprops->GetSurfaceData(pm.surface.surfaceProps); char cCurrGameMaterial = pSurfaceProp->game.material; if (!player->GetGroundEntity()) { cCurrGameMaterial = 0; } // Changed? if (player->m_chPreviousTextureType != cCurrGameMaterial) { CEnvPlayerSurfaceTrigger::SetPlayerSurface(player, cCurrGameMaterial); } player->m_chPreviousTextureType = cCurrGameMaterial; #endif } }
//----------------------------------------------------------------------------- // Purpose: // Input : &input - //----------------------------------------------------------------------------- void CPortalGameMovement::CategorizePosition( void ) { Vector point; trace_t pm; // if the player hull point one unit down is solid, the player // is on ground // see if standing on something solid // 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(); // observers don't have a ground entity if ( player->IsObserver() ) return; point[0] = mv->GetAbsOrigin()[0]; point[1] = mv->GetAbsOrigin()[1]; point[2] = mv->GetAbsOrigin()[2] - 2; Vector bumpOrigin; bumpOrigin = mv->GetAbsOrigin(); // Shooting up really fast. Definitely not on ground. // On ladder moving up, so not on ground either // NOTE: 145 is a jump. if ( mv->m_vecVelocity[2] > 140 || ( mv->m_vecVelocity[2] > 0.0f && player->GetMoveType() == MOVETYPE_LADDER ) ) { SetGroundEntity( NULL ); } else { // Try and move down. TracePlayerBBox( bumpOrigin, point, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, pm ); // If we hit a steep plane, we are not on ground if ( pm.plane.normal[2] < 0.7) { // Test four sub-boxes, to see if any of them would have found shallower slope we could // actually stand on TracePlayerBBoxForGround2( bumpOrigin, point, GetPlayerMins(), GetPlayerMaxs(), mv->m_nPlayerHandle.Get(), MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, pm ); if ( pm.plane.normal[2] < 0.7) { SetGroundEntity( NULL ); // too steep // probably want to add a check for a +z velocity too! if ( ( mv->m_vecVelocity.z > 0.0f ) && ( player->GetMoveType() != MOVETYPE_NOCLIP ) ) { player->m_surfaceFriction = 0.25f; } } else { SetGroundEntity( &pm ); // Otherwise, point to index of ent under us. } } else { SetGroundEntity( &pm ); // Otherwise, point to index of ent under us. } // If we are on something... if (player->GetGroundEntity() != NULL) { // Then we are not in water jump sequence player->m_flWaterJumpTime = 0; // If we could make the move, drop us down that 1 pixel if ( player->GetWaterLevel() < WL_Waist && !pm.startsolid && !pm.allsolid ) { // check distance we would like to move -- this is supposed to just keep up // "on the ground" surface not stap us back to earth (i.e. on move origin to // end position when the ground is within .5 units away) (2 units) if( pm.fraction ) // if( pm.fraction < 0.5) { mv->SetAbsOrigin( pm.endpos ); } } } #ifndef CLIENT_DLL //Adrian: vehicle code handles for us. if ( player->IsInAVehicle() == false ) { // If our gamematerial has changed, tell any player surface triggers that are watching IPhysicsSurfaceProps *physprops = MoveHelper()->GetSurfaceProps(); surfacedata_t *pSurfaceProp = physprops->GetSurfaceData( pm.surface.surfaceProps ); char cCurrGameMaterial = pSurfaceProp->game.material; if ( !player->GetGroundEntity() ) { cCurrGameMaterial = 0; } // Changed? if ( player->m_chPreviousTextureType != cCurrGameMaterial ) { CEnvPlayerSurfaceTrigger::SetPlayerSurface( player, cCurrGameMaterial ); } player->m_chPreviousTextureType = cCurrGameMaterial; } #endif } }