//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void C_BaseEntity::PhysicsCustom() { PhysicsCheckWater(); // regular thinking if ( !PhysicsRunThink() ) return; // Moving upward, off the ground, or resting on something that isn't ground if ( m_vecVelocity[2] > 0 || !GetGroundEntity() || !GetGroundEntity()->IsStandable() ) { SetGroundEntity( NULL ); } // NOTE: The entity must set the position, angles, velocity in its custom movement Vector vecNewPosition = GetAbsOrigin(); if ( vecNewPosition == vec3_origin ) { // Shouldn't be at world origin Assert( 0 ); } Vector vecNewVelocity = m_vecVelocity; QAngle angNewAngles = GetAbsAngles(); QAngle angNewAngVelocity = m_vecAngVelocity; PerformCustomPhysics( &vecNewPosition, &vecNewVelocity, &angNewAngles, &angNewAngVelocity ); // Store off all of the new state information... m_vecVelocity = vecNewVelocity; SetAbsAngles( angNewAngles ); m_vecAngVelocity = angNewAngVelocity; Vector move; VectorSubtract( vecNewPosition, GetAbsOrigin(), move ); // move origin trace_t trace; PhysicsPushEntity( move, &trace ); PhysicsCheckVelocity(); if (trace.allsolid) { // entity is trapped in another solid // UNDONE: does this entity needs to be removed? VectorCopy (vec3_origin, m_vecVelocity); VectorCopy (vec3_angle, m_vecAngVelocity); return; } #if !defined( CLIENT_DLL ) if (pev->free) return; #endif // check for in water PhysicsCheckWaterTransition(); }
// set the mine up for exploding void CASW_Mine::Prime() { if (asw_debug_mine.GetBool()) Msg("Mine primed!\n"); EmitSound("ASW_Mine.Lay"); SetSolid( SOLID_BBOX ); float boxWidth = 150; UTIL_SetSize(this, Vector(-boxWidth,-boxWidth,-boxWidth),Vector(boxWidth,boxWidth,boxWidth * 2)); SetCollisionGroup( ASW_COLLISION_GROUP_PASSABLE ); CollisionProp()->UseTriggerBounds( true, 24 ); AddSolidFlags(FSOLID_TRIGGER); AddSolidFlags(FSOLID_NOT_SOLID); SetTouch( &CASW_Mine::MineTouch ); m_bPrimed = true; // attach to whatever we're standing on CBaseEntity *pGround = GetGroundEntity(); if ( pGround && !pGround->IsWorld() ) { if (asw_debug_mine.GetBool()) Msg( "Parenting mine to %s\n", GetGroundEntity()->GetClassname() ); SetParent( GetGroundEntity() ); SetMoveType( MOVETYPE_NONE ); } }
int CNPC_BabyCrab::RangeAttack1Conditions( float flDot, float flDist ) { if ( GetFlags() & FL_ONGROUND ) { if ( GetGroundEntity() && ( GetGroundEntity()->GetFlags() & ( FL_CLIENT | FL_NPC ) ) ) return COND_CAN_RANGE_ATTACK1; // A little less accurate, but jump from closer if ( flDist <= 180 && flDot >= 0.55 ) return COND_CAN_RANGE_ATTACK1; } return COND_NONE; }
void CSDKPlayer::PickupObject( CBaseEntity *pObject, bool bLimitMassAndSize ) { // can't pick up what you're standing on if ( GetGroundEntity() == pObject ) { DevMsg("Failed to pickup object: Player is standing on object!\n"); PlayUseDenySound(); return; } if ( bLimitMassAndSize == true ) { if ( CanPickupObject( pObject, PLAYER_MAX_LIFT_MASS, PLAYER_MAX_LIFT_SIZE ) == false ) { DevMsg("Failed to pickup object: Object too heavy!\n"); PlayUseDenySound(); return; } } // Can't be picked up if NPCs are on me if ( pObject->HasNPCsOnIt() ) return; // Bool is to tell the client that we have an object. This is incase you want to change the crosshair // or something for your project. m_bPlayerPickedUpObject = true; PlayerPickupObject( this, pObject ); }
//----------------------------------------------------------------------------- // Purpose: The grenade has a slight delay before it goes live. That way the // person firing it can bounce it off a nearby wall. However if it // hits another character it blows up immediately // Input : // Output : //----------------------------------------------------------------------------- void CGrenadeAR2::GrenadeAR2Think( void ) { SetNextThink( gpGlobals->curtime + 0.05f ); if (!m_bIsLive) { // Go live after a short delay if (m_fSpawnTime + MAX_AR2_NO_COLLIDE_TIME < gpGlobals->curtime) { m_bIsLive = true; } } // If I just went solid and my velocity is zero, it means I'm resting on // the floor already when I went solid so blow up if (m_bIsLive) { if (GetAbsVelocity().Length() == 0.0 || GetGroundEntity() != NULL ) { Detonate(); } } // The old way of making danger sounds would scare the crap out of EVERYONE between you and where the grenade // was going to hit. The radius of the danger sound now 'blossoms' over the grenade's lifetime, making it seem // dangerous to a larger area downrange than it does from where it was fired. if( m_fDangerRadius <= AR2_GRENADE_MAX_DANGER_RADIUS ) { m_fDangerRadius += ( AR2_GRENADE_MAX_DANGER_RADIUS * 0.05 ); } CSoundEnt::InsertSound( SOUND_DANGER, GetAbsOrigin() + GetAbsVelocity() * 0.5, m_fDangerRadius, 0.2, this, SOUNDENT_CHANNEL_REPEATED_DANGER ); }
//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() != 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"); }
bool CAI_BaseHumanoid::OnMoveBlocked( AIMoveResult_t *pResult ) { if ( *pResult != AIMR_BLOCKED_NPC && GetNavigator()->GetBlockingEntity() && !GetNavigator()->GetBlockingEntity()->IsNPC() ) { CBaseEntity *pBlocker = GetNavigator()->GetBlockingEntity(); float massBonus = ( IsNavigationUrgent() ) ? 40.0 : 0; if ( pBlocker->GetMoveType() == MOVETYPE_VPHYSICS && pBlocker != GetGroundEntity() && !pBlocker->IsNavIgnored() && !dynamic_cast<CBasePropDoor *>(pBlocker) && pBlocker->VPhysicsGetObject() && pBlocker->VPhysicsGetObject()->IsMoveable() && ( pBlocker->VPhysicsGetObject()->GetMass() <= 35.0 + massBonus + 0.1 || ( pBlocker->VPhysicsGetObject()->GetMass() <= 50.0 + massBonus + 0.1 && IsSmall( pBlocker ) ) ) ) { DbgNavMsg1( this, "Setting ignore on object %s", pBlocker->GetDebugName() ); pBlocker->SetNavIgnore( 2.5 ); } #if 0 else { CPhysicsProp *pProp = dynamic_cast<CPhysicsProp*>( pBlocker ); if ( pProp && pProp->GetHealth() && pProp->GetExplosiveDamage() == 0.0 && GetActiveWeapon() && !GetActiveWeapon()->ClassMatches( "weapon_rpg" ) ) { Msg( "!\n" ); // Destroy! } } #endif } return BaseClass::OnMoveBlocked( pResult ); }
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"); }
TVector CCharacter::GetGlobalGravity() const { if (GetGroundEntity()) return TVector(); return BaseClass::GetGlobalGravity(); }
float CSDKPlayer::GetPlayerMaxSpeed(bool bDucking) { float flMaxSpeed; // This check is now simplified, just use CanChangePosition because it checks the two things we need to check anyway. if ( m_Shared.IsProne() && m_Shared.CanChangePosition() && GetGroundEntity() != NULL ) { if (m_Shared.m_bProneSliding) flMaxSpeed = m_Shared.ModifySkillValue(m_Shared.m_flSlideSpeed, 0.5f, SKILL_ATHLETIC); else flMaxSpeed = m_Shared.ModifySkillValue(m_Shared.m_flProneSpeed, 0.5f, SKILL_ATHLETIC); } //not prone - standing or crouching and possibly moving else if ( (m_Shared.IsSliding() && !m_Shared.IsGettingUpFromSlide()) && GetGroundEntity() ) flMaxSpeed = GetMaxSlideSpeed(); else if ( m_Shared.IsRolling() && GetGroundEntity() ) flMaxSpeed = m_Shared.ModifySkillValue(m_Shared.m_flRollSpeed, 0.25f, SKILL_ATHLETIC); else if ( m_Shared.IsDiving() && !GetGroundEntity() ) { ConVarRef sdk_dive_speed_adrenaline("sdk_dive_speed_adrenaline"); ConVarRef sdk_dive_speed("sdk_dive_speed"); float flSpeedRatio = sdk_dive_speed_adrenaline.GetFloat()/sdk_dive_speed.GetFloat(); flSpeedRatio -= 1; // 0 means unchanged. flSpeedRatio /= 2; // It gets doubled when the skill is on. flMaxSpeed = m_Shared.ModifySkillValue(sdk_dive_speed.GetFloat(), flSpeedRatio, SKILL_ATHLETIC); } else { if ( bDucking ) flMaxSpeed = m_Shared.m_flRunSpeed; //gets cut in fraction later else { if ( m_Shared.IsAimedIn() ) flMaxSpeed = RemapValClamped(m_Shared.GetAimIn(), 0, 1, m_Shared.m_flRunSpeed, m_Shared.m_flAimInSpeed); else flMaxSpeed = m_Shared.m_flRunSpeed; } flMaxSpeed = m_Shared.ModifySkillValue(flMaxSpeed, 0.25f, SKILL_ATHLETIC); } return flMaxSpeed; }
//----------------------------------------------------------------------------- // Handle view smoothing when going up or down stairs //----------------------------------------------------------------------------- void CBasePlayer::SmoothViewOnStairs( Vector& eyeOrigin ) { CBaseEntity *pGroundEntity = GetGroundEntity(); float flCurrentPlayerZ = GetLocalOrigin().z; float flCurrentPlayerViewOffsetZ = GetViewOffset().z; // Smooth out stair step ups // NOTE: Don't want to do this when the ground entity is moving the player if ( ( pGroundEntity != NULL && pGroundEntity->GetMoveType() == MOVETYPE_NONE ) && ( flCurrentPlayerZ != m_flOldPlayerZ ) && smoothstairs.GetBool() && m_flOldPlayerViewOffsetZ == flCurrentPlayerViewOffsetZ ) { int dir = ( flCurrentPlayerZ > m_flOldPlayerZ ) ? 1 : -1; float steptime = gpGlobals->frametime; if (steptime < 0) { steptime = 0; } m_flOldPlayerZ += steptime * 150 * dir; const float stepSize = 18.0f; if ( dir > 0 ) { if (m_flOldPlayerZ > flCurrentPlayerZ) { m_flOldPlayerZ = flCurrentPlayerZ; } if (flCurrentPlayerZ - m_flOldPlayerZ > stepSize) { m_flOldPlayerZ = flCurrentPlayerZ - stepSize; } } else { if (m_flOldPlayerZ < flCurrentPlayerZ) { m_flOldPlayerZ = flCurrentPlayerZ; } if (flCurrentPlayerZ - m_flOldPlayerZ < -stepSize) { m_flOldPlayerZ = flCurrentPlayerZ + stepSize; } } eyeOrigin[2] += m_flOldPlayerZ - flCurrentPlayerZ; } else { m_flOldPlayerZ = flCurrentPlayerZ; m_flOldPlayerViewOffsetZ = flCurrentPlayerViewOffsetZ; } }
// make this alien jump off the head of the ent he's standing on bool CASW_Alien_Jumper::DoJumpOffHead() { //Too soon to try to jump if ( m_flJumpTime > gpGlobals->curtime ) return false; if (!(GetGroundEntity()) || GetNavType() == NAV_JUMP ) return false; // force this drone to have jumping capabilities m_bDisableJump = false; CapabilitiesAdd( bits_CAP_MOVE_JUMP ); //Vector vecDest = RandomVector(-1, 1); //vecDest.z = 0; //vecDest *= random->RandomFloat(30, 100); Vector vecDest; AngleVectors(GetAbsAngles(), &vecDest); vecDest *= 200.0f; vecDest += GetAbsOrigin(); // Try the jump AIMoveTrace_t moveTrace; GetMoveProbe()->MoveLimit( NAV_JUMP, GetAbsOrigin(), vecDest, MASK_NPCSOLID, NULL, &moveTrace ); //See if it succeeded if ( IsMoveBlocked( moveTrace.fStatus ) ) { if ( asw_debug_aliens.GetInt() == 2 ) { NDebugOverlay::Box( vecDest, GetHullMins(), GetHullMaxs(), 255, 0, 0, 0, 5 ); NDebugOverlay::Line( GetAbsOrigin(), vecDest, 255, 0, 0, 0, 5 ); } m_flJumpTime = gpGlobals->curtime + random->RandomFloat( 1.0f, 2.0f ); return false; } if ( asw_debug_aliens.GetInt() == 2 ) { NDebugOverlay::Box( vecDest, GetHullMins(), GetHullMaxs(), 0, 255, 0, 0, 5 ); NDebugOverlay::Line( GetAbsOrigin(), vecDest, 0, 255, 0, 0, 5 ); } //Save this jump in case the next time fails m_vecSavedJump = moveTrace.vJumpVelocity; m_vecLastJumpAttempt = vecDest; SetSchedule(SCHED_ASW_ALIEN_JUMP); m_bForcedStuckJump = true; return true; }
void CHL1_Player::Touch( CBaseEntity *pOther ) { if ( pOther == GetGroundEntity() ) return; if ( pOther->GetMoveType() != MOVETYPE_VPHYSICS || pOther->GetSolid() != SOLID_VPHYSICS ) return; IPhysicsObject *pPhys = pOther->VPhysicsGetObject(); if ( !pPhys || !pPhys->IsMoveable() ) return; SetTouchedPhysics( true ); }
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 CFlockingFlyer :: FallHack( void ) { if( pev->flags & FL_ONGROUND ) { if( GetGroundEntity() != g_pWorld ) { pev->flags &= ~FL_ONGROUND; pev->nextthink = gpGlobals->time + 0.1; } else { SetAbsVelocity( g_vecZero ); SetThink( NULL ); } } }
//----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void UnitBaseAirLocomotion::FullAirMove() { CategorizePosition(); UpdateCurrentHeight(); if( mv->upmove == 0.0f ) { // Get Ground distance and compare to desired height. Modify up/down velocity based on it. float fDiff = m_fDesiredHeight - m_fCurrentHeight; if( fDiff < 0.0f ) mv->velocity.z = Max(fDiff, -mv->maxspeed); else mv->velocity.z = Min(fDiff, mv->maxspeed); if( m_fFlyNoiseZ > DIST_EPSILON && mv->sidemove == 0.0f && mv->forwardmove == 0.0f ) { if( m_bFlyNoiseUp ) { m_fFlyCurNoise += m_fFlyNoiseRate * mv->interval; if( m_fFlyCurNoise > m_fFlyNoiseZ ) m_bFlyNoiseUp = !m_bFlyNoiseUp; } else { m_fFlyCurNoise -= m_fFlyNoiseRate * mv->interval; if( m_fFlyCurNoise < -m_fFlyNoiseZ ) m_bFlyNoiseUp = !m_bFlyNoiseUp; } mv->velocity.z += m_fFlyCurNoise; } } else { mv->velocity.z = Min(mv->upmove, mv->maxspeed); } // Always air move AirMove(); mv->stopdistance = GetStopDistance(); // If we are on ground, no downward velocity. if( GetGroundEntity() != NULL) mv->velocity.z = 0.0f; }
void CFlex::DoBodyLean( void ) { CAI_NPC *myNpc = MyNPCPointer( ); if (myNpc) { Vector vecDelta; Vector vecPos; Vector vecOrigin = GetAbsOrigin(); if (m_vecPrevOrigin == vec3_origin) { m_vecPrevOrigin = vecOrigin; } vecDelta = vecOrigin - m_vecPrevOrigin; vecDelta.x = clamp( vecDelta.x, -50, 50 ); vecDelta.y = clamp( vecDelta.y, -50, 50 ); vecDelta.z = clamp( vecDelta.z, -50, 50 ); float dt = gpGlobals->curtime - GetLastThink(); bool bSkip = ((GetFlags() & (FL_FLY | FL_SWIM)) != 0) || (GetMoveParent() != NULL) || (GetGroundEntity() == NULL) || (GetGroundEntity()->IsMoving()); bSkip |= myNpc->TaskRanAutomovement() || (myNpc->GetVehicleEntity() != NULL); if (!bSkip) { if (vecDelta.LengthSqr() > m_vecPrevVelocity.LengthSqr()) { float decay = ExponentialDecay( 0.6, 0.1, dt ); m_vecPrevVelocity = m_vecPrevVelocity * (decay) + vecDelta * (1.f - decay); } else { float decay = ExponentialDecay( 0.4, 0.1, dt ); m_vecPrevVelocity = m_vecPrevVelocity * (decay) + vecDelta * (1.f - decay); } vecPos = m_vecPrevOrigin + m_vecPrevVelocity; float decay = ExponentialDecay( 0.5, 0.1, dt ); m_vecShift = m_vecShift * (decay) + (vecOrigin - vecPos) * (1.f - decay); // FIXME: Scale this m_vecLean = (vecOrigin - vecPos) * 1.0; // FIXME: Scale this } else { m_vecPrevVelocity = vecDelta; float decay = ExponentialDecay( 0.5, 0.1, dt ); m_vecShift = m_vecLean * decay; m_vecLean = m_vecShift * decay; } m_vecPrevOrigin = vecOrigin; /* DevMsg( "%.2f %.2f %.2f (%.2f %.2f %.2f)\n", m_vecLean.Get().x, m_vecLean.Get().y, m_vecLean.Get().z, vecDelta.x, vecDelta.y, vecDelta.z ); */ } }
//----------------------------------------------------------------------------- // Purpose: Allow pre-frame adjustments on the player //----------------------------------------------------------------------------- void CHL1_Player::PreThink(void) { CheckExplosionEffects(); if ( player_showpredictedposition.GetBool() ) { Vector predPos; UTIL_PredictedPosition( this, player_showpredictedposition_timestep.GetFloat(), &predPos ); NDebugOverlay::Box( predPos, NAI_Hull::Mins( GetHullType() ), NAI_Hull::Maxs( GetHullType() ), 0, 255, 0, 0, 0.01f ); NDebugOverlay::Line( GetAbsOrigin(), predPos, 0, 255, 0, 0, 0.01f ); } int buttonsChanged; buttonsChanged = m_afButtonPressed | m_afButtonReleased; g_pGameRules->PlayerThink( this ); if ( g_fGameOver || IsPlayerLockedInPlace() ) return; // intermission or finale ItemPreFrame( ); WaterMove(); if ( g_pGameRules && g_pGameRules->FAllowFlashlight() ) m_Local.m_iHideHUD &= ~HIDEHUD_FLASHLIGHT; else m_Local.m_iHideHUD |= HIDEHUD_FLASHLIGHT; // checks if new client data (for HUD and view control) needs to be sent to the client UpdateClientData(); CheckTimeBasedDamage(); CheckSuitUpdate(); if (m_lifeState >= LIFE_DYING) { PlayerDeathThink(); return; } // So the correct flags get sent to client asap. // if ( m_afPhysicsFlags & PFLAG_DIROVERRIDE ) AddFlag( FL_ONTRAIN ); else RemoveFlag( FL_ONTRAIN ); // Train speed control if ( m_afPhysicsFlags & PFLAG_DIROVERRIDE ) { CBaseEntity *pTrain = GetGroundEntity(); float vel; if ( pTrain ) { if ( !(pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) ) pTrain = NULL; } if ( !pTrain ) { if ( GetActiveWeapon() && (GetActiveWeapon()->ObjectCaps() & FCAP_DIRECTIONAL_USE) ) { m_iTrain = TRAIN_ACTIVE | TRAIN_NEW; if ( m_nButtons & IN_FORWARD ) { m_iTrain |= TRAIN_FAST; } else if ( m_nButtons & IN_BACK ) { m_iTrain |= TRAIN_BACK; } else { m_iTrain |= TRAIN_NEUTRAL; } return; } else { trace_t trainTrace; // Maybe this is on the other side of a level transition UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + Vector(0,0,-38), MASK_PLAYERSOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &trainTrace ); if ( trainTrace.fraction != 1.0 && trainTrace.m_pEnt ) pTrain = trainTrace.m_pEnt; if ( !pTrain || !(pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) || !pTrain->OnControls(GetContainingEntity(pev)) ) { // Warning( "In train mode with no train!\n" ); m_afPhysicsFlags &= ~PFLAG_DIROVERRIDE; m_iTrain = TRAIN_NEW|TRAIN_OFF; return; } } } else if ( !( GetFlags() & FL_ONGROUND ) || pTrain->HasSpawnFlags( SF_TRACKTRAIN_NOCONTROL ) || (m_nButtons & (IN_MOVELEFT|IN_MOVERIGHT) ) ) { // Turn off the train if you jump, strafe, or the train controls go dead m_afPhysicsFlags &= ~PFLAG_DIROVERRIDE; m_iTrain = TRAIN_NEW|TRAIN_OFF; return; } SetAbsVelocity( vec3_origin ); vel = 0; if ( m_afButtonPressed & IN_FORWARD ) { vel = 1; pTrain->Use( this, this, USE_SET, (float)vel ); } else if ( m_afButtonPressed & IN_BACK ) { vel = -1; pTrain->Use( this, this, USE_SET, (float)vel ); } if (vel) { m_iTrain = TrainSpeed(pTrain->m_flSpeed, ((CFuncTrackTrain*)pTrain)->GetMaxSpeed()); m_iTrain |= TRAIN_ACTIVE|TRAIN_NEW; } } else if (m_iTrain & TRAIN_ACTIVE) { m_iTrain = TRAIN_NEW; // turn off train } // THIS CODE DOESN'T SEEM TO DO ANYTHING!!! // WHY IS IT STILL HERE? (sjb) if (m_nButtons & IN_JUMP) { // If on a ladder, jump off the ladder // else Jump Jump(); } // If trying to duck, already ducked, or in the process of ducking if ((m_nButtons & IN_DUCK) || (GetFlags() & FL_DUCKING) || (m_afPhysicsFlags & PFLAG_DUCKING) ) Duck(); // // If we're not on the ground, we're falling. Update our falling velocity. // if ( !( GetFlags() & FL_ONGROUND ) ) { m_Local.m_flFallVelocity = -GetAbsVelocity().z; } if ( m_afPhysicsFlags & PFLAG_ONBARNACLE ) { SetAbsVelocity( vec3_origin ); } // StudioFrameAdvance( );//!!!HACKHACK!!! Can't be hit by traceline when not animating? //Find targets for NPC to shoot if they decide to miss us FindMissTargets(); }
//----------------------------------------------------------------------------- // Purpose: Handles USE keypress //----------------------------------------------------------------------------- void CBasePlayer::PlayerUse ( void ) { #ifdef GAME_DLL // Was use pressed or released? if ( ! ((m_nButtons | m_afButtonPressed | m_afButtonReleased) & IN_USE) ) return; if ( IsObserver() ) { // do special use operation in oberserver mode if ( m_afButtonPressed & IN_USE ) ObserverUse( true ); else if ( m_afButtonReleased & IN_USE ) ObserverUse( false ); return; } #if !defined(_XBOX) // push objects in turbo physics mode if ( (m_nButtons & IN_USE) && sv_turbophysics.GetBool() ) { Vector forward, up; EyeVectors( &forward, NULL, &up ); trace_t tr; // Search for objects in a sphere (tests for entities that are not solid, yet still useable) Vector searchCenter = EyePosition(); CUsePushFilter filter; UTIL_TraceLine( searchCenter, searchCenter + forward * 96.0f, MASK_SOLID, &filter, &tr ); // try the hit entity if there is one, or the ground entity if there isn't. CBaseEntity *entity = tr.m_pEnt; if ( entity ) { IPhysicsObject *pObj = entity->VPhysicsGetObject(); if ( pObj ) { Vector vPushAway = (entity->WorldSpaceCenter() - WorldSpaceCenter()); vPushAway.z = 0; float flDist = VectorNormalize( vPushAway ); flDist = max( flDist, 1 ); float flForce = sv_pushaway_force.GetFloat() / flDist; flForce = min( flForce, sv_pushaway_max_force.GetFloat() ); pObj->ApplyForceOffset( vPushAway * flForce, WorldSpaceCenter() ); } } } #endif if ( m_afButtonPressed & IN_USE ) { // Controlling some latched entity? if ( ClearUseEntity() ) { return; } else { if ( m_afPhysicsFlags & PFLAG_DIROVERRIDE ) { m_afPhysicsFlags &= ~PFLAG_DIROVERRIDE; m_iTrain = TRAIN_NEW|TRAIN_OFF; return; } else { // Start controlling the train! CBaseEntity *pTrain = GetGroundEntity(); if ( pTrain && !(m_nButtons & IN_JUMP) && (GetFlags() & FL_ONGROUND) && (pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) && pTrain->OnControls(this) ) { m_afPhysicsFlags |= PFLAG_DIROVERRIDE; m_iTrain = TrainSpeed(pTrain->m_flSpeed, ((CFuncTrackTrain*)pTrain)->GetMaxSpeed()); m_iTrain |= TRAIN_NEW; EmitSound( "Player.UseTrain" ); return; } } } } CBaseEntity *pUseEntity = FindUseEntity(); // Found an object if ( pUseEntity ) { //!!!UNDONE: traceline here to prevent +USEing buttons through walls int caps = pUseEntity->ObjectCaps(); variant_t emptyVariant; if ( ( (m_nButtons & IN_USE) && (caps & FCAP_CONTINUOUS_USE) ) || ( (m_afButtonPressed & IN_USE) && (caps & (FCAP_IMPULSE_USE|FCAP_ONOFF_USE)) ) ) { if ( caps & FCAP_CONTINUOUS_USE ) { m_afPhysicsFlags |= PFLAG_USING; } if ( pUseEntity->ObjectCaps() & FCAP_ONOFF_USE ) { pUseEntity->AcceptInput( "Use", this, this, emptyVariant, USE_ON ); } else { pUseEntity->AcceptInput( "Use", this, this, emptyVariant, USE_TOGGLE ); } } // UNDONE: Send different USE codes for ON/OFF. Cache last ONOFF_USE object to send 'off' if you turn away else if ( (m_afButtonReleased & IN_USE) && (pUseEntity->ObjectCaps() & FCAP_ONOFF_USE) ) // BUGBUG This is an "off" use { pUseEntity->AcceptInput( "Use", this, this, emptyVariant, USE_OFF ); } } else if ( m_afButtonPressed & IN_USE ) { PlayUseDenySound(); } #endif }
CBaseEntity *CBasePlayer::FindUseEntity() { Vector forward, up; EyeVectors( &forward, NULL, &up ); trace_t tr; // Search for objects in a sphere (tests for entities that are not solid, yet still useable) Vector searchCenter = EyePosition(); // NOTE: Some debris objects are useable too, so hit those as well // A button, etc. can be made out of clip brushes, make sure it's +useable via a traceline, too. int useableContents = MASK_SOLID | CONTENTS_DEBRIS | CONTENTS_PLAYERCLIP; #ifdef CSTRIKE_DLL useableContents = MASK_NPCSOLID_BRUSHONLY | MASK_OPAQUE_AND_NPCS; #endif #ifdef HL1_DLL useableContents = MASK_SOLID; #endif #ifndef CLIENT_DLL CBaseEntity *pFoundByTrace = NULL; #endif // UNDONE: Might be faster to just fold this range into the sphere query CBaseEntity *pObject = NULL; float nearestDist = FLT_MAX; // try the hit entity if there is one, or the ground entity if there isn't. CBaseEntity *pNearest = NULL; const int NUM_TANGENTS = 8; // trace a box at successive angles down // forward, 45 deg, 30 deg, 20 deg, 15 deg, 10 deg, -10, -15 const float tangents[NUM_TANGENTS] = { 0, 1, 0.57735026919f, 0.3639702342f, 0.267949192431f, 0.1763269807f, -0.1763269807f, -0.267949192431f }; for ( int i = 0; i < NUM_TANGENTS; i++ ) { if ( i == 0 ) { UTIL_TraceLine( searchCenter, searchCenter + forward * 1024, useableContents, this, COLLISION_GROUP_NONE, &tr ); } else { Vector down = forward - tangents[i]*up; VectorNormalize(down); UTIL_TraceHull( searchCenter, searchCenter + down * 72, -Vector(16,16,16), Vector(16,16,16), useableContents, this, COLLISION_GROUP_NONE, &tr ); } pObject = tr.m_pEnt; #ifndef CLIENT_DLL pFoundByTrace = pObject; #endif bool bUsable = IsUseableEntity(pObject, 0); while ( pObject && !bUsable && pObject->GetMoveParent() ) { pObject = pObject->GetMoveParent(); bUsable = IsUseableEntity(pObject, 0); } if ( bUsable ) { Vector delta = tr.endpos - tr.startpos; float centerZ = CollisionProp()->WorldSpaceCenter().z; delta.z = IntervalDistance( tr.endpos.z, centerZ + CollisionProp()->OBBMins().z, centerZ + CollisionProp()->OBBMaxs().z ); float dist = delta.Length(); if ( dist < PLAYER_USE_RADIUS ) { #ifndef CLIENT_DLL if ( sv_debug_player_use.GetBool() ) { NDebugOverlay::Line( searchCenter, tr.endpos, 0, 255, 0, true, 30 ); NDebugOverlay::Cross3D( tr.endpos, 16, 0, 255, 0, true, 30 ); } if ( pObject->MyNPCPointer() && pObject->MyNPCPointer()->IsPlayerAlly( this ) ) { // If about to select an NPC, do a more thorough check to ensure // that we're selecting the right one from a group. pObject = DoubleCheckUseNPC( pObject, searchCenter, forward ); } #endif if ( sv_debug_player_use.GetBool() ) { Msg( "Trace using: %s\n", pObject ? pObject->GetDebugName() : "no usable entity found" ); } pNearest = pObject; // if this is directly under the cursor just return it now if ( i == 0 ) return pObject; } } } // check ground entity first // if you've got a useable ground entity, then shrink the cone of this search to 45 degrees // otherwise, search out in a 90 degree cone (hemisphere) if ( GetGroundEntity() && IsUseableEntity(GetGroundEntity(), FCAP_USE_ONGROUND) ) { pNearest = GetGroundEntity(); } if ( pNearest ) { // estimate nearest object by distance from the view vector Vector point; pNearest->CollisionProp()->CalcNearestPoint( searchCenter, &point ); nearestDist = CalcDistanceToLine( point, searchCenter, forward ); if ( sv_debug_player_use.GetBool() ) { Msg("Trace found %s, dist %.2f\n", pNearest->GetClassname(), nearestDist ); } } for ( CEntitySphereQuery sphere( searchCenter, PLAYER_USE_RADIUS ); ( pObject = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() ) { if ( !pObject ) continue; if ( !IsUseableEntity( pObject, FCAP_USE_IN_RADIUS ) ) continue; // see if it's more roughly in front of the player than previous guess Vector point; pObject->CollisionProp()->CalcNearestPoint( searchCenter, &point ); Vector dir = point - searchCenter; VectorNormalize(dir); float dot = DotProduct( dir, forward ); // Need to be looking at the object more or less if ( dot < 0.8 ) continue; float dist = CalcDistanceToLine( point, searchCenter, forward ); if ( sv_debug_player_use.GetBool() ) { Msg("Radius found %s, dist %.2f\n", pObject->GetClassname(), dist ); } if ( dist < nearestDist ) { // Since this has purely been a radius search to this point, we now // make sure the object isn't behind glass or a grate. trace_t trCheckOccluded; UTIL_TraceLine( searchCenter, point, useableContents, this, COLLISION_GROUP_NONE, &trCheckOccluded ); if ( trCheckOccluded.fraction == 1.0 || trCheckOccluded.m_pEnt == pObject ) { pNearest = pObject; nearestDist = dist; } } } #ifndef CLIENT_DLL if ( !pNearest ) { // Haven't found anything near the player to use, nor any NPC's at distance. // Check to see if the player is trying to select an NPC through a rail, fence, or other 'see-though' volume. trace_t trAllies; UTIL_TraceLine( searchCenter, searchCenter + forward * PLAYER_USE_RADIUS, MASK_OPAQUE_AND_NPCS, this, COLLISION_GROUP_NONE, &trAllies ); if ( trAllies.m_pEnt && IsUseableEntity( trAllies.m_pEnt, 0 ) && trAllies.m_pEnt->MyNPCPointer() && trAllies.m_pEnt->MyNPCPointer()->IsPlayerAlly( this ) ) { // This is an NPC, take it! pNearest = trAllies.m_pEnt; } } if ( pNearest && pNearest->MyNPCPointer() && pNearest->MyNPCPointer()->IsPlayerAlly( this ) ) { pNearest = DoubleCheckUseNPC( pNearest, searchCenter, forward ); } if ( sv_debug_player_use.GetBool() ) { if ( !pNearest ) { NDebugOverlay::Line( searchCenter, tr.endpos, 255, 0, 0, true, 30 ); NDebugOverlay::Cross3D( tr.endpos, 16, 255, 0, 0, true, 30 ); } else if ( pNearest == pFoundByTrace ) { NDebugOverlay::Line( searchCenter, tr.endpos, 0, 255, 0, true, 30 ); NDebugOverlay::Cross3D( tr.endpos, 16, 0, 255, 0, true, 30 ); } else { NDebugOverlay::Box( pNearest->WorldSpaceCenter(), Vector(-8, -8, -8), Vector(8, 8, 8), 0, 255, 0, true, 30 ); } } #endif if ( sv_debug_player_use.GetBool() ) { Msg( "Radial using: %s\n", pNearest ? pNearest->GetDebugName() : "no usable entity found" ); } return pNearest; }
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"); }
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"); }
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; } }
void C_HL2MP_Player::AvoidPlayers( CUserCmd *pCmd ) { // This is only used in team play. if ( !HL2MPRules()->IsTeamplay() ) return; // Don't test if the player doesn't exist or is dead. if ( IsAlive() == false ) return; C_Team *pTeam = ( C_Team * )GetTeam(); if ( !pTeam ) return; // Up vector. static Vector vecUp( 0.0f, 0.0f, 1.0f ); Vector vecHL2MPPlayerCenter = GetAbsOrigin(); Vector vecHL2MPPlayerMin = GetPlayerMins(); Vector vecHL2MPPlayerMax = GetPlayerMaxs(); float flZHeight = vecHL2MPPlayerMax.z - vecHL2MPPlayerMin.z; vecHL2MPPlayerCenter.z += 0.5f * flZHeight; VectorAdd( vecHL2MPPlayerMin, vecHL2MPPlayerCenter, vecHL2MPPlayerMin ); VectorAdd( vecHL2MPPlayerMax, vecHL2MPPlayerCenter, vecHL2MPPlayerMax ); // Find an intersecting player or object. int nAvoidPlayerCount = 0; C_HL2MP_Player *pAvoidPlayerList[MAX_PLAYERS]; C_HL2MP_Player *pIntersectPlayer = NULL; float flAvoidRadius = 0.0f; Vector vecAvoidCenter, vecAvoidMin, vecAvoidMax; for ( int i = 0; i < pTeam->GetNumPlayers(); ++i ) { C_HL2MP_Player *pAvoidPlayer = static_cast< C_HL2MP_Player * >( pTeam->GetPlayer( i ) ); if ( pAvoidPlayer == NULL ) continue; // Is the avoid player me? if ( pAvoidPlayer == this ) continue; // Save as list to check against for objects. pAvoidPlayerList[nAvoidPlayerCount] = pAvoidPlayer; ++nAvoidPlayerCount; // Check to see if the avoid player is dormant. if ( pAvoidPlayer->IsDormant() ) continue; // Is the avoid player solid? if ( pAvoidPlayer->IsSolidFlagSet( FSOLID_NOT_SOLID ) ) continue; Vector t1, t2; vecAvoidCenter = pAvoidPlayer->GetAbsOrigin(); vecAvoidMin = pAvoidPlayer->GetPlayerMins(); vecAvoidMax = pAvoidPlayer->GetPlayerMaxs(); flZHeight = vecAvoidMax.z - vecAvoidMin.z; vecAvoidCenter.z += 0.5f * flZHeight; VectorAdd( vecAvoidMin, vecAvoidCenter, vecAvoidMin ); VectorAdd( vecAvoidMax, vecAvoidCenter, vecAvoidMax ); if ( IsBoxIntersectingBox( vecHL2MPPlayerMin, vecHL2MPPlayerMax, vecAvoidMin, vecAvoidMax ) ) { // Need to avoid this player. if ( !pIntersectPlayer ) { pIntersectPlayer = pAvoidPlayer; break; } } } // Anything to avoid? if ( !pIntersectPlayer ) return; // Calculate the push strength and direction. Vector vecDelta; // Avoid a player - they have precedence. if ( pIntersectPlayer ) { VectorSubtract( pIntersectPlayer->WorldSpaceCenter(), vecHL2MPPlayerCenter, vecDelta ); Vector vRad = pIntersectPlayer->WorldAlignMaxs() - pIntersectPlayer->WorldAlignMins(); vRad.z = 0; flAvoidRadius = vRad.Length(); } float flPushStrength = RemapValClamped( vecDelta.Length(), flAvoidRadius, 0, 0, hl2mp_max_separation_force.GetInt() ); //flPushScale; //Msg( "PushScale = %f\n", flPushStrength ); // Check to see if we have enough push strength to make a difference. if ( flPushStrength < 0.01f ) return; Vector vecPush; if ( GetAbsVelocity().Length2DSqr() > 0.1f ) { Vector vecVelocity = GetAbsVelocity(); vecVelocity.z = 0.0f; CrossProduct( vecUp, vecVelocity, vecPush ); VectorNormalize( vecPush ); } else { // We are not moving, but we're still intersecting. QAngle angView = pCmd->viewangles; angView.x = 0.0f; AngleVectors( angView, NULL, &vecPush, NULL ); } // Move away from the other player/object. Vector vecSeparationVelocity; if ( vecDelta.Dot( vecPush ) < 0 ) { vecSeparationVelocity = vecPush * flPushStrength; } else { vecSeparationVelocity = vecPush * -flPushStrength; } // Don't allow the max push speed to be greater than the max player speed. float flMaxPlayerSpeed = MaxSpeed(); float flCropFraction = 1.33333333f; if ( ( GetFlags() & FL_DUCKING ) && ( GetGroundEntity() != NULL ) ) { flMaxPlayerSpeed *= flCropFraction; } float flMaxPlayerSpeedSqr = flMaxPlayerSpeed * flMaxPlayerSpeed; if ( vecSeparationVelocity.LengthSqr() > flMaxPlayerSpeedSqr ) { vecSeparationVelocity.NormalizeInPlace(); VectorScale( vecSeparationVelocity, flMaxPlayerSpeed, vecSeparationVelocity ); } QAngle vAngles = pCmd->viewangles; vAngles.x = 0; Vector currentdir; Vector rightdir; AngleVectors( vAngles, ¤tdir, &rightdir, NULL ); Vector vDirection = vecSeparationVelocity; VectorNormalize( vDirection ); float fwd = currentdir.Dot( vDirection ); float rt = rightdir.Dot( vDirection ); float forward = fwd * flPushStrength; float side = rt * flPushStrength; //Msg( "fwd: %f - rt: %f - forward: %f - side: %f\n", fwd, rt, forward, side ); pCmd->forwardmove += forward; pCmd->sidemove += side; // 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( "Pforwardmove=%f, sidemove=%f\n", pCmd->forwardmove, pCmd->sidemove ); }
void CBasePlayer::PreThink() { const int buttonsChanged = ( m_afButtonLast ^ GetButtons().Get() ); // These buttons have changed this frame // Debounced button codes for pressed/released // UNDONE: Do we need auto-repeat? m_afButtonPressed = buttonsChanged & GetButtons().Get(); // The changed ones still down are "pressed" m_afButtonReleased = buttonsChanged & ( ~GetButtons().Get() ); // The ones not down are "released" g_pGameRules->PlayerThink( this ); bool bCheckVehicles = true; #if USE_ANGELSCRIPT uint32_t uiFlags = PreThinkFlag::NONE; CallGlobalEvent( g_PlayerPreThinkEvent, CallFlag::NONE, this, &uiFlags ); bCheckVehicles = !( uiFlags & PreThinkFlag::SKIP_VEHICLES ); #endif if( g_fGameOver ) return; // intermission or finale UTIL_MakeVectors( GetViewAngle() ); // is this still used? ItemPreFrame(); WaterMove(); if( g_pGameRules && g_pGameRules->FAllowFlashlight() ) m_iHideHUD &= ~HIDEHUD_FLASHLIGHT; else m_iHideHUD |= HIDEHUD_FLASHLIGHT; // JOHN: checks if new client data (for HUD and view control) needs to be sent to the client UpdateClientData(); CheckTimeBasedDamage(); CheckSuitUpdate(); // Observer Button Handling if( IsObserver() ) { Observer_HandleButtons(); Observer_CheckTarget(); Observer_CheckProperties(); SetImpulse( 0 ); return; } if( GetDeadFlag() >= DEAD_DYING ) { PlayerDeathThink(); return; } // So the correct flags get sent to client asap. // if( m_afPhysicsFlags & PFLAG_ONTRAIN ) GetFlags() |= FL_ONTRAIN; else GetFlags().ClearFlags( FL_ONTRAIN ); if( bCheckVehicles ) { #if USE_OPFOR //We're on a rope. - Solokiller if( m_afPhysicsFlags & PFLAG_ONROPE && m_pRope ) { SetAbsVelocity( g_vecZero ); const Vector vecAttachPos = m_pRope->GetAttachedObjectsPosition(); SetAbsOrigin( vecAttachPos ); Vector vecForce; /* //TODO: This causes sideways acceleration that doesn't occur in Op4. - Solokiller //TODO: should be IN_MOVERIGHT and IN_MOVELEFT - Solokiller if( GetButtons().Any( IN_DUCK ) ) { vecForce.x = gpGlobals->v_right.x; vecForce.y = gpGlobals->v_right.y; vecForce.z = 0; m_pRope->ApplyForceFromPlayer( vecForce ); } if( GetButtons().Any( IN_JUMP ) ) { vecForce.x = -gpGlobals->v_right.x; vecForce.y = -gpGlobals->v_right.y; vecForce.z = 0; m_pRope->ApplyForceFromPlayer( vecForce ); } */ //Determine if any force should be applied to the rope, or if we should move around. - Solokiller if( GetButtons().Any( IN_BACK | IN_FORWARD ) ) { if( ( gpGlobals->v_forward.x * gpGlobals->v_forward.x + gpGlobals->v_forward.y * gpGlobals->v_forward.y - gpGlobals->v_forward.z * gpGlobals->v_forward.z ) <= 0.0 ) { if( m_bIsClimbing ) { const float flDelta = gpGlobals->time - m_flLastClimbTime; m_flLastClimbTime = gpGlobals->time; if( GetButtons().Any( IN_FORWARD ) ) { if( gpGlobals->v_forward.z < 0.0 ) { if( !m_pRope->MoveDown( flDelta ) ) { //Let go of the rope, detach. - Solokiller SetMoveType( MOVETYPE_WALK ); SetSolidType( SOLID_SLIDEBOX ); m_afPhysicsFlags &= ~PFLAG_ONROPE; m_pRope->DetachObject(); m_pRope = nullptr; m_bIsClimbing = false; } } else { m_pRope->MoveUp( flDelta ); } } if( GetButtons().Any( IN_BACK ) ) { if( gpGlobals->v_forward.z < 0.0 ) { m_pRope->MoveUp( flDelta ); } else if( !m_pRope->MoveDown( flDelta ) ) { //Let go of the rope, detach. - Solokiller SetMoveType( MOVETYPE_WALK ); SetSolidType( SOLID_SLIDEBOX ); m_afPhysicsFlags &= ~PFLAG_ONROPE; m_pRope->DetachObject(); m_pRope = nullptr; m_bIsClimbing = false; } } } else { m_bIsClimbing = true; m_flLastClimbTime = gpGlobals->time; } } else { vecForce.x = gpGlobals->v_forward.x; vecForce.y = gpGlobals->v_forward.y; vecForce.z = 0.0; if( GetButtons().Any( IN_BACK ) ) { vecForce.x = -gpGlobals->v_forward.x; vecForce.y = -gpGlobals->v_forward.y; vecForce.z = 0; } m_pRope->ApplyForceFromPlayer( vecForce ); m_bIsClimbing = false; } } else { m_bIsClimbing = false; } if( m_afButtonPressed & IN_JUMP ) { //We've jumped off the rope, give us some momentum - Solokiller SetMoveType( MOVETYPE_WALK ); SetSolidType( SOLID_SLIDEBOX ); this->m_afPhysicsFlags &= ~PFLAG_ONROPE; Vector vecDir = gpGlobals->v_up * 165.0 + gpGlobals->v_forward * 150.0; Vector vecVelocity = m_pRope->GetAttachedObjectsVelocity() * 2; vecVelocity.NormalizeInPlace(); vecVelocity = vecVelocity * 200; SetAbsVelocity( vecVelocity + vecDir ); m_pRope->DetachObject(); m_pRope = nullptr; m_bIsClimbing = false; } return; } #endif // Train speed control if( m_afPhysicsFlags & PFLAG_ONTRAIN ) { CBaseEntity *pTrain = GetGroundEntity(); //To match original behavior, Instance returns the world if entity is null - Solokiller if( !pTrain ) pTrain = CWorld::GetInstance(); float vel; if( !pTrain ) { TraceResult trainTrace; // Maybe this is on the other side of a level transition UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + Vector( 0, 0, -38 ), ignore_monsters, ENT( pev ), &trainTrace ); // HACKHACK - Just look for the func_tracktrain classname if( trainTrace.flFraction != 1.0 && trainTrace.pHit ) pTrain = CBaseEntity::Instance( trainTrace.pHit ); if( !pTrain || !( pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE ) || !pTrain->OnControls( this ) ) { //ALERT( at_error, "In train mode with no train!\n" ); m_afPhysicsFlags &= ~PFLAG_ONTRAIN; m_iTrain = TRAIN_NEW | TRAIN_OFF; return; } } else if( !GetFlags().Any( FL_ONGROUND ) || pTrain->GetSpawnFlags().Any( SF_TRACKTRAIN_NOCONTROL ) || ( GetButtons().Any( IN_MOVELEFT | IN_MOVERIGHT ) ) ) { // Turn off the train if you jump, strafe, or the train controls go dead m_afPhysicsFlags &= ~PFLAG_ONTRAIN; m_iTrain = TRAIN_NEW | TRAIN_OFF; return; } SetAbsVelocity( g_vecZero ); vel = 0; if( m_afButtonPressed & IN_FORWARD ) { vel = 1; pTrain->Use( this, this, USE_SET, ( float ) vel ); } else if( m_afButtonPressed & IN_BACK ) { vel = -1; pTrain->Use( this, this, USE_SET, ( float ) vel ); } if( vel ) { m_iTrain = TrainSpeed( pTrain->GetSpeed(), pTrain->GetImpulse() ); m_iTrain |= TRAIN_ACTIVE | TRAIN_NEW; } } else if( m_iTrain & TRAIN_ACTIVE ) m_iTrain = TRAIN_NEW; // turn off train } if( GetButtons().Any( IN_JUMP ) ) { // If on a ladder, jump off the ladder // else Jump Jump(); } // If trying to duck, already ducked, or in the process of ducking if( GetButtons().Any( IN_DUCK ) || GetFlags().Any( FL_DUCKING ) || ( m_afPhysicsFlags & PFLAG_DUCKING ) ) Duck(); if( !GetFlags().Any( FL_ONGROUND ) ) { m_flFallVelocity = -GetAbsVelocity().z; } // StudioFrameAdvance( );//!!!HACKHACK!!! Can't be hit by traceline when not animating? // Clear out ladder pointer m_hEnemy = NULL; if( m_afPhysicsFlags & PFLAG_ONBARNACLE ) { SetAbsVelocity( g_vecZero ); } }