//========================================================= // NoFriendlyFire - checks for possibility of friendly fire // // Builds a large box in front of the grunt and checks to see // if any squad members are in that box. //========================================================= bool CHL1BaseNPC::NoFriendlyFire( void ) { if ( !m_pSquad ) { return true; } CPlane backPlane; CPlane leftPlane; CPlane rightPlane; Vector vecLeftSide; Vector vecRightSide; Vector v_left; Vector vForward, vRight, vUp; QAngle vAngleToEnemy; if ( GetEnemy() != NULL ) { //!!!BUGBUG - to fix this, the planes must be aligned to where the monster will be firing its gun, not the direction it is facing!!! VectorAngles( ( GetEnemy()->WorldSpaceCenter() - GetAbsOrigin() ), vAngleToEnemy ); AngleVectors ( vAngleToEnemy, &vForward, &vRight, &vUp ); } else { // if there's no enemy, pretend there's a friendly in the way, so the grunt won't shoot. return false; } vecLeftSide = GetAbsOrigin() - ( vRight * ( WorldAlignSize().x * 1.5 ) ); vecRightSide = GetAbsOrigin() + ( vRight * ( WorldAlignSize().x * 1.5 ) ); v_left = vRight * -1; leftPlane.InitializePlane ( vRight, vecLeftSide ); rightPlane.InitializePlane ( v_left, vecRightSide ); backPlane.InitializePlane ( vForward, GetAbsOrigin() ); AISquadIter_t iter; for ( CAI_BaseNPC *pSquadMember = m_pSquad->GetFirstMember( &iter ); pSquadMember; pSquadMember = m_pSquad->GetNextMember( &iter ) ) { if ( pSquadMember == NULL ) continue; if ( pSquadMember == this ) continue; if ( backPlane.PointInFront ( pSquadMember->GetAbsOrigin() ) && leftPlane.PointInFront ( pSquadMember->GetAbsOrigin() ) && rightPlane.PointInFront ( pSquadMember->GetAbsOrigin()) ) { // this guy is in the check volume! Don't shoot! return false; } } return true; }
int CHL2MP_Player::OnTakeDamage( const CTakeDamageInfo &inputInfo ) { #ifndef GE_DLL //return here if the player is in the respawn grace period vs. slams. if ( gpGlobals->curtime < m_flSlamProtectTime && (inputInfo.GetDamageType() == DMG_BLAST ) ) return 0; m_vecTotalBulletForce += inputInfo.GetDamageForce(); gamestats->Event_PlayerDamage( this, inputInfo ); #else CBaseEntity *attacker = inputInfo.GetAttacker(); Vector force = inputInfo.GetDamageForce(); if ( force == vec3_origin && attacker ) { Vector vecDir = vec3_origin; if ( inputInfo.GetInflictor() && GetMoveType() == MOVETYPE_WALK && !attacker->IsSolidFlagSet(FSOLID_TRIGGER) ) { vecDir = inputInfo.GetInflictor()->WorldSpaceCenter() - Vector ( 0, 0, 10 ) - WorldSpaceCenter(); VectorNormalize( vecDir ); force = vecDir * -DamageForce( WorldAlignSize(), inputInfo.GetBaseDamage() ); } } m_vecTotalBulletForce += force; #endif return BaseClass::OnTakeDamage( inputInfo ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CNPC_Bug_Warrior::MeleeAttack( float distance, float damage, QAngle& viewPunch, Vector& shove ) { if ( GetEnemy() == NULL ) return; // Trace directly at my target Vector vStart = GetAbsOrigin(); vStart.z += WorldAlignSize().z * 0.5; Vector vecForward = (GetEnemy()->EyePosition() - vStart); VectorNormalize( vecForward ); Vector vEnd = vStart + (vecForward * distance ); // Use half the size of my target for the box Vector vecHalfTraceBox = (GetEnemy()->WorldAlignMaxs() - GetEnemy()->WorldAlignMins()) * 0.25; //NDebugOverlay::Box( vStart, -Vector(10,10,10), Vector(10,10,10), 0,255,0,20,1.0); //NDebugOverlay::Box( GetEnemy()->EyePosition(), -Vector(10,10,10), Vector(10,10,10), 255,255,255,20,1.0); CBaseEntity *pHurt = CheckTraceHullAttack( vStart, vEnd, -vecHalfTraceBox, vecHalfTraceBox, damage, DMG_SLASH ); if ( pHurt ) { CBasePlayer *pPlayer = ToBasePlayer( pHurt ); if ( pPlayer ) { //Kick the player angles pPlayer->ViewPunch( viewPunch ); Vector dir = pHurt->GetAbsOrigin() - GetAbsOrigin(); VectorNormalize(dir); QAngle angles; VectorAngles( dir, angles ); Vector forward, right; AngleVectors( angles, &forward, &right, NULL ); // Push the target back Vector vecImpulse; VectorMultiply( right, -shove[1], vecImpulse ); VectorMA( vecImpulse, -shove[0], forward, vecImpulse ); pHurt->ApplyAbsVelocityImpulse( vecImpulse ); } // Play a random attack hit sound EmitSound( "NPC_Bug_Warrior.AttackHit" ); } }
CBaseEntity *CASW_Simple_Alien::CheckTraceHullAttack( float flDist, const Vector &mins, const Vector &maxs, int iDamage, int iDmgType, float forceScale, bool bDamageAnyNPC ) { // If only a length is given assume we want to trace in our facing direction Vector forward; AngleVectors( GetAbsAngles(), &forward ); Vector vStart = GetAbsOrigin(); // The ideal place to start the trace is in the center of the attacker's bounding box. // however, we need to make sure there's enough clearance. Some of the smaller monsters aren't // as big as the hull we try to trace with. (SJB) float flVerticalOffset = WorldAlignSize().z * 0.5; if( flVerticalOffset < maxs.z ) { // There isn't enough room to trace this hull, it's going to drag the ground. // so make the vertical offset just enough to clear the ground. flVerticalOffset = maxs.z + 1.0; } vStart.z += flVerticalOffset; Vector vEnd = vStart + (forward * flDist ); return CheckTraceHullAttack( vStart, vEnd, mins, maxs, iDamage, iDmgType, forceScale, bDamageAnyNPC ); }
/// @TODO: lead target void CASW_Sentry_Top_Cannon::Fire() { if ( !m_hEnemy.IsValid() || !m_hEnemy.Get() || !HasAmmo() ) return; BaseClass::Fire(); Vector diff = m_hEnemy->WorldSpaceCenter() - GetFiringPosition(); diff.NormalizeInPlace(); //FireBulletsInfo_t( int nShots, const Vector &vecSrc, const Vector &vecDir, const Vector &vecSpread, float flDistance, int nAmmoType, bool bPrimaryAttack = true ) Vector launchVector = diff * 1000.0f; CASW_Marine * RESTRICT pMarineDeployer = GetSentryBase()->m_hDeployer.Get(); Assert( pMarineDeployer ); float fGrenadeDamage = CASW_Weapon_Grenades::GetBoomDamage(pMarineDeployer) * 0.5f; float fGrenadeRadius = CASW_Weapon_Grenades::GetBoomRadius(pMarineDeployer) * 0.5f; CASW_Rifle_Grenade::Rifle_Grenade_Create( fGrenadeDamage, fGrenadeRadius, GetFiringPosition() + (diff * ( WorldAlignSize().Length() * 0.5f ) ), GetAbsAngles(), launchVector, AngularImpulse(0,0,0), pMarineDeployer, this ); if( pMarineDeployer ) pMarineDeployer->OnWeaponFired( this, 1 ); EmitSound("ASW_Sentry.CannonFire"); m_fNextFireTime = gpGlobals->curtime + ASW_SENTRY_CANNON_FIRE_RATE; // use ammo if ( GetSentryBase() ) { GetSentryBase()->OnFiredShots(); } }
//----------------------------------------------------------------------------- // 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 ); }
Vector QUA_helicopter::CalcDamageForceVector( const CTakeDamageInfo &info ) { // Already have a damage force in the data, use that. if (info.GetDamageForce() != vec3_origin || (info.GetDamageType() & /*DMG_NO_PHYSICS_FORCE*/DMG_BLAST)) { //if( info.GetDamageType() & DMG_BLAST ) //{ // Fudge blast forces a little bit, so that each // victim gets a slightly different trajectory. // This simulates features that usually vary from // person-to-person variables such as bodyweight, // which are all indentical for characters using the same model. float scale = random->RandomFloat( 0.85, 1.15 ); Vector force = info.GetDamageForce(); force.x *= scale; force.y *= scale; // Try to always exaggerate the upward force because we've got pretty harsh gravity force.z *= (force.z > 0) ? 1.15 : scale; return force; //} return info.GetDamageForce(); } CBaseEntity *pForce = info.GetInflictor(); if ( !pForce ) { pForce = info.GetAttacker(); } if ( pForce ) { // Calculate an impulse large enough to push a 75kg man 4 in/sec per point of damage float forceScale = info.GetDamage() * 75 * 4; Vector forceVector; // If the damage is a blast, point the force vector higher than usual, this gives // the ragdolls a bodacious "really got blowed up" look. if( info.GetDamageType() & DMG_BLAST ) { // exaggerate the force from explosions a little (37.5%) forceVector = (GetLocalOrigin() + Vector(0, 0, WorldAlignSize().z) ) - pForce->GetLocalOrigin(); VectorNormalize(forceVector); forceVector *= 1.375f; } else { // taking damage from self? Take a little random force, but still try to collapse on the spot. if ( this == pForce ) { forceVector.x = random->RandomFloat( -1.0f, 1.0f ); forceVector.y = random->RandomFloat( -1.0f, 1.0f ); forceVector.z = 0.0; forceScale = random->RandomFloat( 1000.0f, 2000.0f ); } else { // UNDONE: Collision forces are baked in to CTakeDamageInfo now // UNDONE: Is this MOVETYPE_VPHYSICS code still necessary? if ( pForce->GetMoveType() == MOVETYPE_VPHYSICS ) { // killed by a physics object IPhysicsObject *pPhysics = VPhysicsGetObject(); if ( !pPhysics ) { pPhysics = pForce->VPhysicsGetObject(); } pPhysics->GetVelocity( &forceVector, NULL ); forceScale = pPhysics->GetMass(); } else { forceVector = GetLocalOrigin() - pForce->GetLocalOrigin(); VectorNormalize(forceVector); } } } return forceVector * forceScale; } return vec3_origin; }
Vector CASW_Simple_Alien::CalcDeathForceVector( const CTakeDamageInfo &info ) { // Already have a damage force in the data, use that. if ( info.GetDamageForce() != vec3_origin || (g_pGameRules->Damage_NoPhysicsForce(info.GetDamageType()))) { if( info.GetDamageType() & DMG_BLAST ) { float scale = random->RandomFloat( 0.85, 1.15 ); Vector force = info.GetDamageForce(); force.x *= scale; force.y *= scale; // Try to always exaggerate the upward force because we've got pretty harsh gravity force.z *= (force.z > 0) ? 1.15 : scale; return force; } return info.GetDamageForce(); } CBaseEntity *pForce = info.GetInflictor(); if ( !pForce ) { pForce = info.GetAttacker(); } if ( pForce ) { // Calculate an impulse large enough to push a 75kg man 4 in/sec per point of damage float forceScale = info.GetDamage() * 75 * 4; Vector forceVector; // If the damage is a blast, point the force vector higher than usual, this gives // the ragdolls a bodacious "really got blowed up" look. if( info.GetDamageType() & DMG_BLAST ) { // exaggerate the force from explosions a little (37.5%) forceVector = (GetLocalOrigin() + Vector(0, 0, WorldAlignSize().z) ) - pForce->GetLocalOrigin(); VectorNormalize(forceVector); forceVector *= 1.375f; } else { // taking damage from self? Take a little random force, but still try to collapse on the spot. if ( this == pForce ) { forceVector.x = random->RandomFloat( -1.0f, 1.0f ); forceVector.y = random->RandomFloat( -1.0f, 1.0f ); forceVector.z = 0.0; forceScale = random->RandomFloat( 1000.0f, 2000.0f ); } else { // UNDONE: Collision forces are baked in to CTakeDamageInfo now // UNDONE: Is this MOVETYPE_VPHYSICS code still necessary? if ( pForce->GetMoveType() == MOVETYPE_VPHYSICS ) { // killed by a physics object IPhysicsObject *pPhysics = VPhysicsGetObject(); if ( !pPhysics ) { pPhysics = pForce->VPhysicsGetObject(); } pPhysics->GetVelocity( &forceVector, NULL ); forceScale = pPhysics->GetMass(); } else { forceVector = GetLocalOrigin() - pForce->GetLocalOrigin(); VectorNormalize(forceVector); } } } return forceVector * forceScale; } return vec3_origin; }
//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CFastZombie::PrescheduleThink( void ) { BaseClass::PrescheduleThink(); if( m_pMoanSound && gpGlobals->curtime > m_flTimeUpdateSine ) { // Manage the snorting sound, pitch up for closer. float flDistNoBBox; if( GetEnemy() && m_NPCState == NPC_STATE_COMBAT ) { flDistNoBBox = ( GetEnemy()->WorldSpaceCenter() - WorldSpaceCenter() ).Length(); flDistNoBBox -= WorldAlignSize().x; } else { // Calm down! flDistNoBBox = FASTZOMBIE_EXCITE_DIST; m_flTimeUpdateSine += 1.0; } if( flDistNoBBox >= FASTZOMBIE_EXCITE_DIST && m_flDistFactor != 1.0 ) { // Go back to normal pitch. m_flDistFactor = 1.0; ENVELOPE_CONTROLLER.SoundChangePitch( m_pMoanSound, FASTZOMBIE_IDLE_PITCH, 0.7 ); } else if( flDistNoBBox < FASTZOMBIE_EXCITE_DIST ) { // Zombie is close! Recalculate pitch. int iPitch; m_flDistFactor = min( 1.0, 1 - flDistNoBBox / FASTZOMBIE_EXCITE_DIST ); iPitch = FASTZOMBIE_MIN_PITCH + ( ( FASTZOMBIE_MAX_PITCH - FASTZOMBIE_MIN_PITCH ) * m_flDistFactor); ENVELOPE_CONTROLLER.SoundChangePitch( m_pMoanSound, iPitch, 0.1 ); } if( flDistNoBBox >= FASTZOMBIE_EXCITE_DIST || m_NPCState != NPC_STATE_COMBAT ) { // If i'm not close by or pissed off, then don't be so vocal. /* float flFrequency; float flFreqFactor; flFreqFactor = 1.0 - m_flDistFactor; if( flFreqFactor <= 0.0 ) { flFreqFactor = 1.0; } flFrequency = max( 0.2, FASTZOMBIE_BASE_FREQ * flFreqFactor ); Msg("DIST FACTOR:%f 1- Factor:%f FREQUENCY:%f\n", m_flDistFactor, flFreqFactor, flFrequency ); */ if( m_fSineTrendUp ) { ENVELOPE_CONTROLLER.SoundChangeVolume( m_pMoanSound, 0.0, m_flSineFrequency ); m_flTimeUpdateSine = gpGlobals->curtime + m_flSineFrequency; m_fSineTrendUp = false; // Now that we're at zero volume again, change my frequency. This keeps // multiple zombies out of phase. m_flSineFrequency = random->RandomFloat( 1.0, 2.0 ); } else { ENVELOPE_CONTROLLER.SoundChangeVolume( m_pMoanSound, 1.0, m_flSineFrequency ); m_flTimeUpdateSine = gpGlobals->curtime + m_flSineFrequency; m_fSineTrendUp = true; } } } // Crudely detect the apex of our jump if( IsNavJumping() && !m_fHitApex && GetAbsVelocity().z <= 0.0 ) { OnNavJumpHitApex(); } }