// here bot updates important info that is used multiple times along the thinking process void CSDKBot::InfoGathering() { if (!GetEnemy()) { m_flBotToEnemyDist = 9999; m_flHeightDifToEnemy = 0; m_bEnemyOnSights = false; m_flDistTraveled += fabs(GetLocalVelocity().Length()); // this is used for stuck checking, return; } m_flBotToEnemyDist = (GetLocalOrigin() - GetEnemy()->GetLocalOrigin()).Length(); trace_t tr; UTIL_TraceHull( EyePosition(), GetEnemy()->EyePosition() - Vector(0,0,20), -BotTestHull, BotTestHull, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); if( tr.m_pEnt == GetEnemy() ) // vision line between both m_bEnemyOnSights = true; else m_bEnemyOnSights = false; m_bInRangeToAttack = (m_flBotToEnemyDist < m_flMinRangeAttack) && FInViewCone( GetEnemy() ); m_flDistTraveled += fabs(GetLocalVelocity().Length()); // this is used for stuck checking, m_flHeightDifToEnemy = GetLocalOrigin().z - GetEnemy()->GetLocalOrigin().z; }
void CMomentumPlayer::CalculateAverageStats() { ConVarRef hvel("mom_speedometer_hvel"); if (g_Timer.IsRunning()) { int currentStage = g_Timer.GetCurrentStageNumber(); m_flStageTotalSync[currentStage] += m_flStrafeSync; m_flStageTotalSync2[currentStage] += m_flStrafeSync2; m_flStageTotalVelocity[currentStage] += hvel.GetBool() ? GetLocalVelocity().Length2D() : GetLocalVelocity().Length(); m_nStageAvgCount[currentStage]++; m_flStageStrafeSyncAvg[currentStage] = m_flStageTotalSync[currentStage] / float(m_nStageAvgCount[currentStage]); m_flStageStrafeSync2Avg[currentStage] = m_flStageTotalSync2[currentStage] / float(m_nStageAvgCount[currentStage]); m_flStageVelocityAvg[currentStage] = m_flStageTotalVelocity[currentStage] / float(m_nStageAvgCount[currentStage]); //stage 0 is "overall" - also update these as well, no matter which stage we are on m_flStageTotalSync[0] += m_flStrafeSync; m_flStageTotalSync2[0] += m_flStrafeSync2; m_flStageTotalVelocity[0] += hvel.GetBool() ? GetLocalVelocity().Length2D() : GetLocalVelocity().Length(); m_nStageAvgCount[0]++; m_flStageStrafeSyncAvg[0] = m_flStageTotalSync[currentStage] / float(m_nStageAvgCount[currentStage]); m_flStageStrafeSync2Avg[0] = m_flStageTotalSync2[currentStage] / float(m_nStageAvgCount[currentStage]); m_flStageVelocityAvg[0] = m_flStageTotalVelocity[currentStage] / float(m_nStageAvgCount[currentStage]); } // think once per 0.1 second interval so we avoid making the totals extremely large SetNextThink(gpGlobals->curtime + AVERAGE_STATS_INTERVAL, "THINK_AVERAGE_STATS"); }
//This limits the player's speed in the start zone, depending on which gamemode the player is currently playing. //On surf/other, it only limits practice mode speed. On bhop/scroll, it limits the movement speed above a certain threshhold, and //clamps the player's velocity if they go above it. This is to prevent prespeeding and is different per gamemode due to the different //respective playstyles of surf and bhop. void CMomentumPlayer::LimitSpeedInStartZone() { ConVarRef gm("mom_gamemode"); CTriggerTimerStart *startTrigger = g_Timer.GetStartTrigger(); bool bhopGameMode = (gm.GetInt() == MOMGM_BHOP || gm.GetInt() == MOMGM_SCROLL); if (m_bInsideStartZone) { if (GetGroundEntity() == NULL && !g_Timer.IsPracticeMode(this)) //don't count ticks in air if we're in practice mode m_nTicksInAir++; else m_nTicksInAir = 0; //set bhop flag to true so we can't prespeed with practice mode if (g_Timer.IsPracticeMode(this)) m_bDidPlayerBhop = true; //depending on gamemode, limit speed outright when player exceeds punish vel if (bhopGameMode && ((!g_Timer.IsRunning() && m_nTicksInAir > MAX_AIRTIME_TICKS))) { Vector velocity = GetLocalVelocity(); float PunishVelSquared = startTrigger->GetPunishSpeed()*startTrigger->GetPunishSpeed(); if (velocity.Length2DSqr() > PunishVelSquared) //more efficent to check agaisnt the square of velocity { velocity = (velocity / velocity.Length()) * startTrigger->GetPunishSpeed(); SetAbsVelocity(Vector(velocity.x, velocity.y, velocity.z)); } } } SetNextThink(gpGlobals->curtime, "CURTIME_FOR_START"); }
void CMomentumPlayer::CheckForBhop() { if (GetGroundEntity() != nullptr) { m_flTicksOnGround += gpGlobals->interval_per_tick; // true is player is on ground for less than 10 ticks, false if they are on ground for more s m_bDidPlayerBhop = (m_flTicksOnGround < NUM_TICKS_TO_BHOP * gpGlobals->interval_per_tick) != 0; if (!m_bDidPlayerBhop) m_iSuccessiveBhops = 0; if (m_nButtons & IN_JUMP) { m_RunData.m_flLastJumpVel = GetLocalVelocity().Length2D(); m_iSuccessiveBhops++; if (g_Timer->IsRunning()) { int currentZone = m_RunData.m_iCurrentZone; m_RunStats.SetZoneJumps(0, m_RunStats.GetZoneJumps(0) + 1); m_RunStats.SetZoneJumps(currentZone, m_RunStats.GetZoneJumps(currentZone) + 1); } } } else m_flTicksOnGround = 0; SetNextThink(gpGlobals->curtime, "CURTIME"); }
void CMomentumPlayer::CheckForBhop() { if (GetGroundEntity() != NULL) { m_flTicksOnGround += gpGlobals->interval_per_tick; // true is player is on ground for less than 10 ticks, false if they are on ground for more s m_bDidPlayerBhop = (m_flTicksOnGround < NUM_TICKS_TO_BHOP * gpGlobals->interval_per_tick) != 0; if (!m_bDidPlayerBhop) m_iSuccessiveBhops = 0; if (m_nButtons & IN_JUMP) { m_flLastJumpVel = GetLocalVelocity().Length2D(); m_iSuccessiveBhops++; if (g_Timer.IsRunning()) { int currentStage = g_Timer.GetCurrentStageNumber(); m_nStageJumps[0]++; m_nStageJumps[currentStage]++; } } } else m_flTicksOnGround = 0; SetNextThink(gpGlobals->curtime, "CURTIME"); }
// Obtains the player's previous origin using a vector as the base, subtracting one tick's worth of velocity. Vector CMomentumPlayer::GetPrevOrigin(const Vector &base) { Vector velocity = GetLocalVelocity(); Vector prevOrigin(base.x - (velocity.x * gpGlobals->interval_per_tick), base.y - (velocity.y * gpGlobals->interval_per_tick), base.z - (velocity.z * gpGlobals->interval_per_tick)); return prevOrigin; }
void CMomentumPlayer::CalculateAverageStats() { if (g_Timer->IsRunning()) { int currentZone = m_RunData.m_iCurrentZone;//g_Timer->GetCurrentZoneNumber(); m_flZoneTotalSync[currentZone] += m_RunData.m_flStrafeSync; m_flZoneTotalSync2[currentZone] += m_RunData.m_flStrafeSync2; m_flZoneTotalVelocity[currentZone][0] += GetLocalVelocity().Length(); m_flZoneTotalVelocity[currentZone][1] += GetLocalVelocity().Length2D(); m_nZoneAvgCount[currentZone]++; m_RunStats.SetZoneStrafeSyncAvg(currentZone, m_flZoneTotalSync[currentZone] / float(m_nZoneAvgCount[currentZone])); m_RunStats.SetZoneStrafeSync2Avg(currentZone, m_flZoneTotalSync2[currentZone] / float(m_nZoneAvgCount[currentZone])); m_RunStats.SetZoneVelocityAvg(currentZone, m_flZoneTotalVelocity[currentZone][0] / float(m_nZoneAvgCount[currentZone]), m_flZoneTotalVelocity[currentZone][1] / float(m_nZoneAvgCount[currentZone])); // stage 0 is "overall" - also update these as well, no matter which stage we are on m_flZoneTotalSync[0] += m_RunData.m_flStrafeSync; m_flZoneTotalSync2[0] += m_RunData.m_flStrafeSync2; m_flZoneTotalVelocity[0][0] += GetLocalVelocity().Length(); m_flZoneTotalVelocity[0][1] += GetLocalVelocity().Length2D(); m_nZoneAvgCount[0]++; m_RunStats.SetZoneStrafeSyncAvg(0, m_flZoneTotalSync[currentZone] / float(m_nZoneAvgCount[currentZone])); m_RunStats.SetZoneStrafeSync2Avg(0, m_flZoneTotalSync2[currentZone] / float(m_nZoneAvgCount[currentZone])); m_RunStats.SetZoneVelocityAvg(0, m_flZoneTotalVelocity[currentZone][0] / float(m_nZoneAvgCount[currentZone]), m_flZoneTotalVelocity[currentZone][1] / float(m_nZoneAvgCount[currentZone])); } // think once per 0.1 second interval so we avoid making the totals extremely large SetNextThink(gpGlobals->curtime + AVERAGE_STATS_INTERVAL, "THINK_AVERAGE_STATS"); }
void CSDKPlayer::UpdateViewBobRamp() { #ifdef CLIENT_DLL // It's not filled in for remote clients, so force the local one since it's the same. float flMaxBobSpeed = C_SDKPlayer::GetLocalSDKPlayer()->m_Shared.m_flRunSpeed*0.7f; #else float flMaxBobSpeed = m_Shared.m_flRunSpeed*0.7f; #endif float flBobRampGoal = RemapValClamped(GetLocalVelocity().LengthSqr(), 0, flMaxBobSpeed*flMaxBobSpeed, 0, 1); if (!(GetFlags() & FL_ONGROUND) || m_Shared.IsRolling() || m_Shared.IsSliding()) flBobRampGoal = 0; m_Shared.m_flViewBobRamp = Approach(flBobRampGoal, m_Shared.m_flViewBobRamp, gpGlobals->frametime*m_flSlowMoMultiplier*4); }
void CCharacter::Jump() { if (!GetGroundEntity()) return; SetGroundEntity(NULL); Vector vecLocalUp = GetUpVector(); if (HasMoveParent()) { TMatrix mGlobalToLocal = GetMoveParent()->GetGlobalToLocalTransform(); vecLocalUp = mGlobalToLocal.TransformNoTranslate(vecLocalUp); } SetLocalVelocity(GetLocalVelocity() + vecLocalUp * JumpStrength()); }
void C_SkeletonPlayer::UpdateClientSideAnimation() { int curSeq = GetSequence(); Vector vel = GetLocalVelocity(); //EstimateAbsVelocity( vel ); int goalSeq = curSeq; if ( vel.LengthSqr() > 4 ) { QAngle velAng; VectorAngles( vel, velAng ); goalSeq = SelectWeightedSequence( ACT_RUN ); float speed = vel.Length2D(); float yaw = AngleNormalize( -(GetRenderAngles().y - velAng.y) ); float seqspeed = 150.0f; float rate = speed / seqspeed; SetPoseParameter( LookupPoseParameter( "move_x" ), cos( DEG2RAD( yaw ) ) * rate ); SetPoseParameter( LookupPoseParameter( "move_y" ), -sin( DEG2RAD( yaw ) ) * rate ); SetPlaybackRate( clamp( rate * 0.6f, 1, 1.5f ) ); } else goalSeq = SelectWeightedSequence( ACT_IDLE ); if ( curSeq != goalSeq ) { ResetSequence( goalSeq ); } //m_flAnimTime = gpGlobals->curtime; //StudioFrameAdvance(); if ( GetCycle() >= 1.0f ) SetCycle( GetCycle() - 1.0f ); }
//----------------------------------------------------------------------------- // Little hack to avoid game crash when changing bodygroup (DmitRex) //----------------------------------------------------------------------------- void CZombie::SetHeadlessModel( void ) { SetModel(""); CreateRagGib( "models/zombie/classic.mdl", GetLocalOrigin(), GetLocalAngles(), GetLocalVelocity(), 0, ShouldIgniteZombieGib() ); }
//----------------------------------------------------------------------------- // Client-side obstacle avoidance //----------------------------------------------------------------------------- void C_BaseHLPlayer::PerformClientSideObstacleAvoidance( float flFrameTime, CUserCmd *pCmd ) { // Don't avoid if noclipping or in movetype none switch ( GetMoveType() ) { case MOVETYPE_NOCLIP: case MOVETYPE_NONE: case MOVETYPE_OBSERVER: return; default: break; } // Try to steer away from any objects/players we might interpenetrate Vector size = WorldAlignSize(); float radius = 0.7f * sqrt( size.x * size.x + size.y * size.y ); float curspeed = GetLocalVelocity().Length2D(); //int slot = 1; //engine->Con_NPrintf( slot++, "speed %f\n", curspeed ); //engine->Con_NPrintf( slot++, "radius %f\n", radius ); // If running, use a larger radius float factor = 1.0f; if ( curspeed > 150.0f ) { curspeed = MIN( 2048.0f, curspeed ); factor = ( 1.0f + ( curspeed - 150.0f ) / 150.0f ); //engine->Con_NPrintf( slot++, "scaleup (%f) to radius %f\n", factor, radius * factor ); radius = radius * factor; } Vector currentdir; Vector rightdir; QAngle vAngles = pCmd->viewangles; vAngles.x = 0; AngleVectors( vAngles, ¤tdir, &rightdir, NULL ); bool istryingtomove = false; bool ismovingforward = false; if ( fabs( pCmd->forwardmove ) > 0.0f || fabs( pCmd->sidemove ) > 0.0f ) { istryingtomove = true; if ( pCmd->forwardmove > 1.0f ) { ismovingforward = true; } } if ( istryingtomove == true ) radius *= 1.3f; CPlayerAndObjectEnumerator avoid( radius ); partition->EnumerateElementsInSphere( PARTITION_CLIENT_SOLID_EDICTS, GetAbsOrigin(), radius, false, &avoid ); // Okay, decide how to avoid if there's anything close by int c = avoid.GetObjectCount(); if ( c <= 0 ) return; //engine->Con_NPrintf( slot++, "moving %s forward %s\n", istryingtomove ? "true" : "false", ismovingforward ? "true" : "false" ); float adjustforwardmove = 0.0f; float adjustsidemove = 0.0f; for ( int i = 0; i < c; i++ ) { C_AI_BaseNPC *obj = dynamic_cast< C_AI_BaseNPC *>(avoid.GetObject( i )); if( !obj ) continue; Vector vecToObject = obj->GetAbsOrigin() - GetAbsOrigin(); float flDist = vecToObject.Length2D(); // Figure out a 2D radius for the object Vector vecWorldMins, vecWorldMaxs; obj->CollisionProp()->WorldSpaceAABB( &vecWorldMins, &vecWorldMaxs ); Vector objSize = vecWorldMaxs - vecWorldMins; float objectradius = 0.5f * sqrt( objSize.x * objSize.x + objSize.y * objSize.y ); //Don't run this code if the NPC is not moving UNLESS we are in stuck inside of them. if ( !obj->IsMoving() && flDist > objectradius ) continue; if ( flDist > objectradius && obj->IsEffectActive( EF_NODRAW ) ) { obj->RemoveEffects( EF_NODRAW ); } Vector vecNPCVelocity; obj->EstimateAbsVelocity( vecNPCVelocity ); float flNPCSpeed = VectorNormalize( vecNPCVelocity ); Vector vPlayerVel = GetAbsVelocity(); VectorNormalize( vPlayerVel ); float flHit1, flHit2; Vector vRayDir = vecToObject; VectorNormalize( vRayDir ); float flVelProduct = DotProduct( vecNPCVelocity, vPlayerVel ); float flDirProduct = DotProduct( vRayDir, vPlayerVel ); if ( !IntersectInfiniteRayWithSphere( GetAbsOrigin(), vRayDir, obj->GetAbsOrigin(), radius, &flHit1, &flHit2 ) ) continue; Vector dirToObject = -vecToObject; VectorNormalize( dirToObject ); float fwd = 0; float rt = 0; float sidescale = 2.0f; float forwardscale = 1.0f; bool foundResult = false; Vector vMoveDir = vecNPCVelocity; if ( flNPCSpeed > 0.001f ) { // This NPC is moving. First try deflecting the player left or right relative to the NPC's velocity. // Start with whatever side they're on relative to the NPC's velocity. Vector vecNPCTrajectoryRight = CrossProduct( vecNPCVelocity, Vector( 0, 0, 1) ); int iDirection = ( vecNPCTrajectoryRight.Dot( dirToObject ) > 0 ) ? 1 : -1; for ( int nTries = 0; nTries < 2; nTries++ ) { Vector vecTryMove = vecNPCTrajectoryRight * iDirection; VectorNormalize( vecTryMove ); Vector vTestPosition = GetAbsOrigin() + vecTryMove * radius * 2; if ( TestMove( vTestPosition, size.z * 2, radius * 2, obj->GetAbsOrigin(), vMoveDir ) ) { fwd = currentdir.Dot( vecTryMove ); rt = rightdir.Dot( vecTryMove ); //Msg( "PUSH DEFLECT fwd=%f, rt=%f\n", fwd, rt ); foundResult = true; break; } else { // Try the other direction. iDirection *= -1; } } } else { // the object isn't moving, so try moving opposite the way it's facing Vector vecNPCForward; obj->GetVectors( &vecNPCForward, NULL, NULL ); Vector vTestPosition = GetAbsOrigin() - vecNPCForward * radius * 2; if ( TestMove( vTestPosition, size.z * 2, radius * 2, obj->GetAbsOrigin(), vMoveDir ) ) { fwd = currentdir.Dot( -vecNPCForward ); rt = rightdir.Dot( -vecNPCForward ); if ( flDist < objectradius ) { obj->AddEffects( EF_NODRAW ); } //Msg( "PUSH AWAY FACE fwd=%f, rt=%f\n", fwd, rt ); foundResult = true; } } if ( !foundResult ) { // test if we can move in the direction the object is moving Vector vTestPosition = GetAbsOrigin() + vMoveDir * radius * 2; if ( TestMove( vTestPosition, size.z * 2, radius * 2, obj->GetAbsOrigin(), vMoveDir ) ) { fwd = currentdir.Dot( vMoveDir ); rt = rightdir.Dot( vMoveDir ); if ( flDist < objectradius ) { obj->AddEffects( EF_NODRAW ); } //Msg( "PUSH ALONG fwd=%f, rt=%f\n", fwd, rt ); foundResult = true; } else { // try moving directly away from the object Vector vTestPosition = GetAbsOrigin() - dirToObject * radius * 2; if ( TestMove( vTestPosition, size.z * 2, radius * 2, obj->GetAbsOrigin(), vMoveDir ) ) { fwd = currentdir.Dot( -dirToObject ); rt = rightdir.Dot( -dirToObject ); foundResult = true; //Msg( "PUSH AWAY fwd=%f, rt=%f\n", fwd, rt ); } } } if ( !foundResult ) { // test if we can move through the object Vector vTestPosition = GetAbsOrigin() - vMoveDir * radius * 2; fwd = currentdir.Dot( -vMoveDir ); rt = rightdir.Dot( -vMoveDir ); if ( flDist < objectradius ) { obj->AddEffects( EF_NODRAW ); } //Msg( "PUSH THROUGH fwd=%f, rt=%f\n", fwd, rt ); foundResult = true; } // If running, then do a lot more sideways veer since we're not going to do anything to // forward velocity if ( istryingtomove ) { sidescale = 6.0f; } if ( flVelProduct > 0.0f && flDirProduct > 0.0f ) { sidescale = 0.1f; } float force = 1.0f; float forward = forwardscale * fwd * force * AVOID_SPEED; float side = sidescale * rt * force * AVOID_SPEED; adjustforwardmove += forward; adjustsidemove += side; } pCmd->forwardmove += adjustforwardmove; pCmd->sidemove += adjustsidemove; // Clamp the move to within legal limits, preserving direction. This is a little // complicated because we have different limits for forward, back, and side //Msg( "PRECLAMP: forwardmove=%f, sidemove=%f\n", pCmd->forwardmove, pCmd->sidemove ); float flForwardScale = 1.0f; if ( pCmd->forwardmove > fabs( cl_forwardspeed.GetFloat() ) ) { flForwardScale = fabs( cl_forwardspeed.GetFloat() ) / pCmd->forwardmove; } else if ( pCmd->forwardmove < -fabs( cl_backspeed.GetFloat() ) ) { flForwardScale = fabs( cl_backspeed.GetFloat() ) / fabs( pCmd->forwardmove ); } float flSideScale = 1.0f; if ( fabs( pCmd->sidemove ) > fabs( cl_sidespeed.GetFloat() ) ) { flSideScale = fabs( cl_sidespeed.GetFloat() ) / fabs( pCmd->sidemove ); } float flScale = MIN( flForwardScale, flSideScale ); pCmd->forwardmove *= flScale; pCmd->sidemove *= flScale; //Msg( "POSTCLAMP: forwardmove=%f, sidemove=%f\n", pCmd->forwardmove, pCmd->sidemove ); }
void CMomentumPlayer::UpdateRunStats() { float velocity = GetLocalVelocity().Length(); float velocity2D = GetLocalVelocity().Length2D(); if (g_Timer->IsRunning()) { int currentZone = m_RunData.m_iCurrentZone;//g_Timer->GetCurrentZoneNumber(); if (!m_bPrevTimerRunning) // timer started on this tick { // Compare against successive bhops to avoid incrimenting when the player was in the air without jumping // (for surf) if (GetGroundEntity() == nullptr && m_iSuccessiveBhops) { m_RunStats.SetZoneJumps(0, m_RunStats.GetZoneJumps(0) + 1); m_RunStats.SetZoneJumps(currentZone, m_RunStats.GetZoneJumps(currentZone) + 1); } if (m_nButtons & IN_MOVERIGHT || m_nButtons & IN_MOVELEFT) { m_RunStats.SetZoneStrafes(0, m_RunStats.GetZoneStrafes(0) + 1); m_RunStats.SetZoneStrafes(currentZone, m_RunStats.GetZoneStrafes(currentZone) + 1); } } if (m_nButtons & IN_MOVELEFT && !(m_nPrevButtons & IN_MOVELEFT)) { m_RunStats.SetZoneStrafes(0, m_RunStats.GetZoneStrafes(0) + 1); m_RunStats.SetZoneStrafes(currentZone, m_RunStats.GetZoneStrafes(currentZone) + 1); } else if (m_nButtons & IN_MOVERIGHT && !(m_nPrevButtons & IN_MOVERIGHT)) { m_RunStats.SetZoneStrafes(0, m_RunStats.GetZoneStrafes(0) + 1); m_RunStats.SetZoneStrafes(currentZone, m_RunStats.GetZoneStrafes(currentZone) + 1); } // ---- MAX VELOCITY ---- float maxOverallVel = velocity; float maxOverallVel2D = velocity2D; float maxCurrentVel = velocity; float maxCurrentVel2D = velocity2D; if (maxOverallVel <= m_RunStats.GetZoneVelocityMax(0, false)) maxOverallVel = m_RunStats.GetZoneVelocityMax(0, false); if (maxOverallVel2D <= m_RunStats.GetZoneVelocityMax(0, true)) maxOverallVel2D = m_RunStats.GetZoneVelocityMax(0, true); if (maxCurrentVel <= m_RunStats.GetZoneVelocityMax(currentZone, false)) maxCurrentVel = m_RunStats.GetZoneVelocityMax(currentZone, false); if (maxCurrentVel2D <= m_RunStats.GetZoneVelocityMax(currentZone, true)) maxCurrentVel2D = m_RunStats.GetZoneVelocityMax(currentZone, true); m_RunStats.SetZoneVelocityMax(0, maxOverallVel, maxOverallVel2D); m_RunStats.SetZoneVelocityMax(currentZone, maxCurrentVel, maxCurrentVel2D); // ---------- // ---- STRAFE SYNC ----- float SyncVelocity = GetLocalVelocity().Length2DSqr(); // we always want HVEL for checking velocity sync if (!(GetFlags() & (FL_ONGROUND | FL_INWATER)) && GetMoveType() != MOVETYPE_LADDER) { if (EyeAngles().y > m_qangLastAngle.y) // player turned left { m_nStrafeTicks++; if ((m_nButtons & IN_MOVELEFT) && !(m_nButtons & IN_MOVERIGHT)) m_nPerfectSyncTicks++; if (SyncVelocity > m_flLastSyncVelocity) m_nAccelTicks++; } else if (EyeAngles().y < m_qangLastAngle.y) // player turned right { m_nStrafeTicks++; if ((m_nButtons & IN_MOVERIGHT) && !(m_nButtons & IN_MOVELEFT)) m_nPerfectSyncTicks++; if (SyncVelocity > m_flLastSyncVelocity) m_nAccelTicks++; } } if (m_nStrafeTicks && m_nAccelTicks && m_nPerfectSyncTicks) { m_RunData.m_flStrafeSync = (float(m_nPerfectSyncTicks) / float(m_nStrafeTicks)) * 100.0f; // ticks strafing perfectly / ticks strafing m_RunData.m_flStrafeSync2 = (float(m_nAccelTicks) / float(m_nStrafeTicks)) * 100.0f; // ticks gaining speed / ticks strafing } // ---------- m_qangLastAngle = EyeAngles(); m_flLastSyncVelocity = SyncVelocity; // this might be used in a later update // m_flLastVelocity = velocity; m_bPrevTimerRunning = g_Timer->IsRunning(); m_nPrevButtons = m_nButtons; } // think once per tick SetNextThink(gpGlobals->curtime + gpGlobals->interval_per_tick, "THINK_EVERY_TICK"); }
//----------------------------------------------------------------------------- // Purpose: Returns the velocity imparted to players standing on us. //----------------------------------------------------------------------------- void CBaseToggle::GetGroundVelocityToApply( Vector &vecGroundVel ) { vecGroundVel = GetLocalVelocity(); }
void CCharacter::MoveThink() { if (!GetGroundEntity()) return; if (m_vecGoalVelocity.LengthSqr()) m_vecGoalVelocity.Normalize(); m_vecMoveVelocity.x = Approach(m_vecGoalVelocity.x, m_vecMoveVelocity.x, GameServer()->GetFrameTime()*4); m_vecMoveVelocity.y = 0; m_vecMoveVelocity.z = Approach(m_vecGoalVelocity.z, m_vecMoveVelocity.z, GameServer()->GetFrameTime()*4); if (m_vecMoveVelocity.LengthSqr() > 0) { TMatrix m = GetLocalTransform(); Vector vecUp = GetUpVector(); if (HasMoveParent()) { TMatrix mGlobalToLocal = GetMoveParent()->GetGlobalToLocalTransform(); vecUp = mGlobalToLocal.TransformNoTranslate(vecUp); } Vector vecRight = m.GetForwardVector().Cross(vecUp).Normalized(); Vector vecForward = vecUp.Cross(vecRight).Normalized(); m.SetColumn(0, vecForward); m.SetColumn(1, vecUp); m.SetColumn(2, vecRight); TVector vecMove = m_vecMoveVelocity * CharacterSpeed(); TVector vecLocalVelocity = m.TransformNoTranslate(vecMove); SetLocalVelocity(vecLocalVelocity); } else SetLocalVelocity(TVector()); eastl::vector<CEntityHandle<CBaseEntity> > apCollisionList; size_t iMaxEntities = GameServer()->GetMaxEntities(); for (size_t j = 0; j < iMaxEntities; j++) { CBaseEntity* pEntity2 = CBaseEntity::GetEntity(j); if (!pEntity2) continue; if (pEntity2->IsDeleted()) continue; if (pEntity2 == this) continue; if (!pEntity2->ShouldCollide()) continue; apCollisionList.push_back(pEntity2); } TMatrix mGlobalToLocalRotation; if (HasMoveParent()) { mGlobalToLocalRotation = GetMoveParent()->GetGlobalToLocalTransform(); mGlobalToLocalRotation.SetTranslation(TVector()); } float flSimulationFrameTime = 0.01f; // Break simulations up into consistent small steps to preserve accuracy. for (; m_flMoveSimulationTime < GameServer()->GetGameTime(); m_flMoveSimulationTime += flSimulationFrameTime) { TVector vecVelocity = GetLocalVelocity(); TVector vecLocalOrigin = GetLocalOrigin(); TVector vecGlobalOrigin = GetGlobalOrigin(); vecVelocity = vecVelocity * flSimulationFrameTime; TVector vecLocalDestination = vecLocalOrigin + vecVelocity; TVector vecGlobalDestination = vecLocalDestination; if (GetMoveParent()) vecGlobalDestination = GetMoveParent()->GetGlobalTransform() * vecLocalDestination; TVector vecNewLocalOrigin = vecLocalDestination; size_t iTries = 0; while (true) { iTries++; TVector vecPoint, vecNormal; TVector vecLocalCollisionPoint, vecGlobalCollisionPoint; bool bContact = false; for (size_t i = 0; i < apCollisionList.size(); i++) { CBaseEntity* pEntity2 = apCollisionList[i]; if (GetMoveParent() == pEntity2) { if (pEntity2->CollideLocal(vecLocalOrigin, vecLocalDestination, vecPoint, vecNormal)) { bContact = true; Touching(pEntity2); vecLocalCollisionPoint = vecPoint; vecGlobalCollisionPoint = GetMoveParent()->GetGlobalTransform() * vecPoint; } } else { if (pEntity2->Collide(vecGlobalOrigin, vecGlobalDestination, vecPoint, vecNormal)) { bContact = true; Touching(pEntity2); vecGlobalCollisionPoint = vecPoint; if (GetMoveParent()) { vecLocalCollisionPoint = GetMoveParent()->GetGlobalToLocalTransform() * vecPoint; vecNormal = GetMoveParent()->GetGlobalToLocalTransform().TransformNoTranslate(vecNormal); } else vecLocalCollisionPoint = vecGlobalCollisionPoint; } } } if (bContact) { vecNewLocalOrigin = vecLocalCollisionPoint; vecVelocity -= vecLocalCollisionPoint - vecLocalOrigin; } if (!bContact) break; if (iTries > 4) break; vecLocalOrigin = vecLocalCollisionPoint; vecGlobalOrigin = vecGlobalCollisionPoint; // Clip the velocity to the surface normal of whatever we hit. TFloat flDistance = vecVelocity.Dot(vecNormal); vecVelocity = vecVelocity - vecNormal * flDistance; // Do it one more time just to make sure we're not headed towards the plane. TFloat flAdjust = vecVelocity.Dot(vecNormal); if (flAdjust < 0.0f) vecVelocity -= (vecNormal * flAdjust); vecLocalDestination = vecLocalOrigin + vecVelocity; if (GetMoveParent()) vecGlobalDestination = GetMoveParent()->GetGlobalTransform() * vecLocalDestination; else vecGlobalDestination = vecLocalDestination; SetLocalVelocity(vecVelocity.Normalized() * GetLocalVelocity().Length()); } SetLocalOrigin(vecNewLocalOrigin); // Try to keep the player on the ground. // Untested. /*TVector vecStart = GetGlobalOrigin() + GetGlobalTransform().GetUpVector()*m_flMaxStepSize; TVector vecEnd = GetGlobalOrigin() - GetGlobalTransform().GetUpVector()*m_flMaxStepSize; // First go up a bit TVector vecHit, vecNormal; Game()->TraceLine(GetGlobalOrigin(), vecStart, vecHit, vecNormal, NULL); vecStart = vecHit; // Now see if there's ground underneath us. bool bHit = Game()->TraceLine(vecStart, vecEnd, vecHit, vecNormal, NULL); if (bHit && vecNormal.y >= TFloat(0.7f)) SetGlobalOrigin(vecHit);*/ m_flMoveSimulationTime += flSimulationFrameTime; } }
//Called from PhysicsSimulate() or ReceiveMessage() bool CDHLProjectile::OnTouch( trace_t &touchtr, bool bDecalOnly /*= false*/, ITraceFilter* pTraceFilter /*= NULL*/ ) { //Direction Vector vecDir = touchtr.endpos - touchtr.startpos; if ( vecDir == vec3_origin ) //Sometimes endpos==startpos so we need to get dir from velocity instead { #ifdef CLIENT_DLL vecDir = GetLocalVelocity(); #else vecDir = m_vecCurVelocity; #endif VectorNormalize( vecDir ); } CBaseEntity* ent = touchtr.m_pEnt; if ( !ent ) return false; if ( touchtr.DidHit() ) { //Never collide with self, shooter, or other projectiles if ( ent == this || dynamic_cast<CDHLProjectile*>(ent) || ent == (CBaseEntity*)m_pShooter ) //|| ( (m_iType == DHL_PROJECTILE_TYPE_COMBATKNIFE) && (ent == m_pFiringWeapon) ) ) //Combat knife - don't collide with weapon ent return false; //Hack: Sometimes hits are registered prematurely (usually to the torso area) with no hitbox. Pretend nothing happened unless one is found. if ( ent->IsPlayer() && touchtr.hitgroup == 0 ) return false; //Check friendly fire if ( CheckFriendlyFire( ent ) ) { if ( !bDecalOnly ) { ClearMultiDamage(); //Do damage CTakeDamageInfo dmgInfo( this, GetOwnerEntity(), m_iDamage, DMG_BULLET ); if ( m_iType == DHL_PROJECTILE_TYPE_COMBATKNIFE ) { //CalculateMeleeDamageForce( &dmgInfo, vecDir, touchtr.endpos, 0.01f ); Vector vecForce = vecDir; VectorNormalize( vecForce ); //vecForce *= 10.0f; //Ripped from C_ClientRagdoll::ImpactTrace dmgInfo.SetDamageForce( vecForce ); #ifndef CLIENT_DLL if ( IsOnFire() ) { CBaseAnimating* pBAnim = dynamic_cast<CBaseAnimating*>(ent); if ( pBAnim ) pBAnim->Ignite( 10.0f, false ); } #endif } else CalculateBulletDamageForce( &dmgInfo, m_iAmmoType, vecDir, touchtr.endpos, 1.0f ); dmgInfo.SetDamagePosition( touchtr.endpos ); ent->DispatchTraceAttack( dmgInfo, vecDir, &touchtr ); ApplyMultiDamage(); } #ifdef CLIENT_DLL if ( ent->GetCollisionGroup() == COLLISION_GROUP_BREAKABLE_GLASS ) return false; //Decals and such if ( !( touchtr.surface.flags & SURF_SKY ) && !touchtr.allsolid ) { IPredictionSystem::SuppressEvents( false ); if ( (m_iType == DHL_PROJECTILE_TYPE_BULLET || m_iType == DHL_PROJECTILE_TYPE_PELLET) ) { UTIL_ImpactTrace( &touchtr, DMG_BULLET ); } if ( m_iType == DHL_PROJECTILE_TYPE_COMBATKNIFE ) PlayImpactSound( touchtr.m_pEnt, touchtr, touchtr.endpos, touchtr.surface.surfaceProps ); IPredictionSystem::SuppressEvents( !prediction->IsFirstTimePredicted() ); } #endif } if ( pTraceFilter && m_iType != DHL_PROJECTILE_TYPE_COMBATKNIFE ) { PenetrationData_t nPenetrationData = DHLShared::TestPenetration( touchtr, m_pShooter, pTraceFilter, m_iTimesPenetrated, m_flDistanceTravelled, m_iAmmoType ); if ( nPenetrationData.m_bShouldPenetrate ) { m_flDistanceTravelled += GetLocalOrigin().DistTo( nPenetrationData.m_vecNewBulletPos ); MoveProjectileToPosition( nPenetrationData.m_vecNewBulletPos ); m_iTimesPenetrated++; return true; //Keep going - but don't do anything else in this frame of PhysicsSimulate() } } //We're done unless what we hit was breakable glass if ( ent->GetCollisionGroup() != COLLISION_GROUP_BREAKABLE_GLASS ) { #ifdef CLIENT_DLL m_bCollided = true; AddEffects( EF_NODRAW ); if ( m_pTrail ) //NULL pointer here sometimes somehow... m_pTrail->AddEffects( EF_NODRAW ); #else EntityMessageBegin( this ); WRITE_BYTE( MSG_NOTIFY_REMOVAL ); MessageEnd(); if ( touchtr.DidHitWorld() && m_iType == DHL_PROJECTILE_TYPE_COMBATKNIFE && !( touchtr.surface.flags & SURF_SKY ) ) { CBaseCombatWeapon* pKnifeEnt = assert_cast<CBaseCombatWeapon*>(CreateEntityByName( "weapon_combatknife" )); if ( pKnifeEnt ) { pKnifeEnt->AddSpawnFlags( SF_NORESPAWN ); //Needed for weapon spawn & VPhysics setup to work correctly pKnifeEnt->SetAbsOrigin( touchtr.endpos ); QAngle angles = vec3_angle; Vector vecKnifeDir = touchtr.startpos - touchtr.endpos; VectorAngles( vecKnifeDir, angles ); angles[PITCH] -= 15.0f; //Correct for the .mdl being offset a bit pKnifeEnt->SetLocalAngles( angles ); DispatchSpawn( pKnifeEnt ); //Spawns vphys object and sets it up, essentially a copy of CWeaponHL2MPBase::FallInit() pKnifeEnt->VPhysicsDestroyObject(); //Using SOLID_VPHYSICS instead of SOLID_BBOX (as ordinary weapons do) helps resolve some of the client side collision oddities Assert( pKnifeEnt->VPhysicsInitNormal( SOLID_VPHYSICS, FSOLID_NOT_STANDABLE | FSOLID_TRIGGER, true ) ); pKnifeEnt->SetPickupTouch(); //Sets up automagic removal after time IPhysicsObject* pKnifePhys = pKnifeEnt->VPhysicsGetObject(); if ( pKnifePhys ) { //Knives are solid to bullets...the only way to make them non-solid to bullets is to do SetSolid( SOLID_NONE ) or AddSolidFlags( FSOLID_NOT_SOLID ) //which breaks the +use pickup even with FSOLID_TRIGGER set. Let's just call it a feature :) pKnifePhys->EnableMotion( false ); pKnifePhys->EnableCollisions( false ); } if ( IsOnFire() ) pKnifeEnt->Ignite( 10.0f, false ); } } //SetThink( &CDHLProjectile::SUB_Remove ); //SetNextThink( gpGlobals->curtime + 0.1 ); //SUB_Remove(); //SetMoveType( MOVETYPE_NONE ); m_flRemoveAt = gpGlobals->curtime + 0.1f; //Give the notification message a head start so that the client will have time to react #endif } } return true; }
void CDHLProjectile::PhysicsSimulate( void ) { //------------------------------------------------------------------------------- //Our own movement/physics simulation! //------------------------------------------------------------------------------- #ifdef CLIENT_DLL if ( m_bCollided ) return; if ( !m_pShooter && m_hShooter ) m_pShooter = m_hShooter.Get(); #else if ( m_flRemoveAt > 0.0f ) { if ( m_flRemoveAt < gpGlobals->curtime ) { m_flRemoveAt = 0.0f; SUB_Remove(); } return; } if ( IsMarkedForDeletion() ) return; #endif float flFrametime = gpGlobals->frametime; //Scale for slow motion if ( DHLRules() ) { if ( (m_iType == DHL_PROJECTILE_TYPE_BULLET || m_iType == DHL_PROJECTILE_TYPE_PELLET) ) flFrametime *= (dhl_bulletspeed.GetFloat() * DHLRules()->GetTimescale()); else if ( m_iType == DHL_PROJECTILE_TYPE_COMBATKNIFE ) flFrametime *= (dhl_knifespeed.GetFloat() * DHLRules()->GetTimescale()); else flFrametime *= DHLRules()->GetTimescale(); } Vector vecDir = vec3_origin; #ifndef CLIENT_DLL Vector vecStartPos = m_vecCurPosition; //This is where we are Vector vecEndPos = m_vecCurPosition; //This is where we're going Vector vecVelocity = m_vecCurVelocity; //Velocity #else Vector vecStartPos = GetLocalOrigin(); //This is where we are Vector vecEndPos = GetLocalOrigin(); //This is where we're going Vector vecVelocity = GetLocalVelocity(); //Velocity #endif //Find out where we should move to if ( vecVelocity != vec3_origin ) { static ConVarRef gravVar( "sv_gravity" ); //Gravity float newZVelocity = vecVelocity.z - ( flFrametime * gravVar.GetFloat() * GetGravity() ); vecVelocity.z = ( (vecVelocity.z + newZVelocity) / 2 ); vecDir = vecVelocity; VectorNormalize( vecDir ); //Gravity needs to be cumulative #ifndef CLIENT_DLL m_vecCurVelocity = vecVelocity; #else SetLocalVelocity( vecVelocity ); #endif vecVelocity *= flFrametime; vecEndPos = vecStartPos + vecVelocity; if ( vecEndPos.IsValid() ) { CTraceFilterSkipTwoEntities movetrfilter( this, m_pShooter, COLLISION_GROUP_NONE ); trace_t movetr; UTIL_TraceLine( vecStartPos, vecEndPos, MASK_SHOT, &movetrfilter, &movetr ); #ifndef CLIENT_DLL //Trace to triggers so we can hit surf glass and such CTakeDamageInfo triggerInfo( this, GetOwnerEntity(), m_iDamage, DMG_BULLET ); if ( m_iType == DHL_PROJECTILE_TYPE_COMBATKNIFE ) { //CalculateMeleeDamageForce( &triggerInfo, vecDir, movetr.endpos, 0.7f ); Vector vecForce = vecDir; VectorNormalize( vecForce ); //vecForce *= 10.0f; triggerInfo.SetDamageForce( vecForce ); } else CalculateBulletDamageForce( &triggerInfo, m_iAmmoType, vecDir, movetr.endpos, 1.0f ); triggerInfo.SetDamagePosition( movetr.endpos ); TraceAttackToTriggers( triggerInfo, movetr.startpos, movetr.endpos, vecDir ); #else //Hit ragdolls on the client CBaseEntity* pEnt = DHL_FX_AffectRagdolls( movetr.endpos, movetr.startpos, DMG_BULLET, &m_RagdollHitList ); //Keep track of ones we've hit if ( pEnt ) m_RagdollHitList.AddToTail( pEnt ); #endif if ( movetr.DidHit() ) if ( OnTouch( movetr, false, &movetrfilter ) ) return; MoveProjectileToPosition( vecEndPos ); m_flDistanceTravelled += vecEndPos.DistTo( vecStartPos ); #ifndef CLIENT_DLL //On rare occasions the projectile likes to fly right through the world and keep going forever, causing a memory leak if ( m_flDistanceTravelled > MAX_TRACE_LENGTH ) { SUB_Remove(); //SetThink( &CDHLProjectile::SUB_Remove ); //SetNextThink( gpGlobals->curtime + 0.1 ); } #endif } //Simulate Angles //QAngle angles; #ifdef CLIENT_DLL QAngle angles = GetLocalAngles(); //VectorAngles( vecDir, angles ); //angles.z = GetLocalAngles().z; //Vector conversion loses z QAngle angVel = GetLocalAngularVelocity(); angles += angVel * flFrametime; SetLocalAngles( angles ); SetNetworkAngles( angles ); #endif } }
void UPhysicsMovementComponent::ServerUpdateMovementVars() { location = GetLocalLocation(); velocity = GetLocalVelocity(); }
void CMomentumPlayer::UpdateRunStats() { //should velocity be XY or XYZ? ConVarRef hvel("mom_speedometer_hvel"); IGameEvent *playerMoveEvent = gameeventmanager->CreateEvent("keypress"); float velocity = hvel.GetBool() ? GetLocalVelocity().Length2D() : GetLocalVelocity().Length(); if (g_Timer.IsRunning()) { int currentStage = g_Timer.GetCurrentStageNumber(); if (!m_bPrevTimerRunning) //timer started on this tick { //Reset old run stats ResetRunStats(); m_flStartSpeed = GetLocalVelocity().Length2D(); //prestrafe should always be XY only //Comapre against successive bhops to avoid incrimenting when the player was in the air without jumping (for surf) if (GetGroundEntity() == NULL && m_iSuccessiveBhops) { m_nStageJumps[0]++; } } if (m_nButtons & IN_MOVELEFT && !(m_nPrevButtons & IN_MOVELEFT)) { m_nStageStrafes[0]++; m_nStageStrafes[currentStage]++; } else if (m_nButtons & IN_MOVERIGHT && !(m_nPrevButtons & IN_MOVERIGHT)) { m_nStageStrafes[0]++; m_nStageStrafes[currentStage]++; } // ---- MAX VELOCITY ---- if (velocity > m_flStageVelocityMax[0]) m_flStageVelocityMax[0] = velocity; //also do max velocity per stage if (velocity > m_flStageVelocityMax[currentStage]) m_flStageVelocityMax[currentStage] = velocity; // ---------- // --- STAGE ENTER VELOCITY --- } // ---- STRAFE SYNC ----- float SyncVelocity = GetLocalVelocity().Length2DSqr(); //we always want HVEL for checking velocity sync if (!(GetFlags() & (FL_ONGROUND | FL_INWATER)) && GetMoveType() != MOVETYPE_LADDER) { if (EyeAngles().y > m_qangLastAngle.y) //player turned left { m_nStrafeTicks++; if ((m_nButtons & IN_MOVELEFT) && !(m_nButtons & IN_MOVERIGHT)) m_nPerfectSyncTicks++; if (SyncVelocity > m_flLastSyncVelocity) m_nAccelTicks++; } else if (EyeAngles().y < m_qangLastAngle.y) //player turned right { m_nStrafeTicks++; if ((m_nButtons & IN_MOVERIGHT) && !(m_nButtons & IN_MOVELEFT)) m_nPerfectSyncTicks++; if (SyncVelocity > m_flLastSyncVelocity) m_nAccelTicks++; } } if (m_nStrafeTicks && m_nAccelTicks && m_nPerfectSyncTicks) { m_flStrafeSync = ((float)m_nPerfectSyncTicks / (float)m_nStrafeTicks) * 100; // ticks strafing perfectly / ticks strafing m_flStrafeSync2 = ((float)m_nAccelTicks / (float)m_nStrafeTicks) * 100; // ticks gaining speed / ticks strafing } // ---------- m_qangLastAngle = EyeAngles(); m_flLastSyncVelocity = SyncVelocity; //this might be used in a later update //m_flLastVelocity = velocity; m_bPrevTimerRunning = g_Timer.IsRunning(); m_nPrevButtons = m_nButtons; if (playerMoveEvent) { playerMoveEvent->SetInt("num_strafes", m_nStageStrafes[0]); playerMoveEvent->SetInt("num_jumps", m_nStageJumps[0]); if ((m_nButtons & IN_JUMP && GetGroundEntity() != NULL) || m_nButtons & IN_MOVELEFT | IN_MOVERIGHT) gameeventmanager->FireEvent(playerMoveEvent); } //think once per tick SetNextThink(gpGlobals->curtime + gpGlobals->interval_per_tick, "THINK_EVERY_TICK"); }