void C_HL2MPRagdoll::ImpactTrace( trace_t *pTrace, int iDamageType, char *pCustomImpactName ) { IPhysicsObject *pPhysicsObject = VPhysicsGetObject(); if( !pPhysicsObject ) return; Vector dir = pTrace->endpos - pTrace->startpos; if ( iDamageType == DMG_BLAST ) { dir *= 4000; // adjust impact strenght // apply force at object mass center pPhysicsObject->ApplyForceCenter( dir ); } else { Vector hitpos; VectorMA( pTrace->startpos, pTrace->fraction, dir, hitpos ); VectorNormalize( dir ); dir *= 4000; // adjust impact strenght // apply force where we hit it pPhysicsObject->ApplyForceOffset( dir, hitpos ); // Blood spray! // FX_CS_BloodSpray( hitpos, dir, 10 ); } m_pRagdoll->ResetRagdollSleepAfterTime(); }
//----------------------------------------------------------------------------------------------------- void PerformObstaclePushaway( CBaseCombatCharacter *pPushingEntity ) { if ( pPushingEntity->m_lifeState != LIFE_ALIVE ) return; // Give a push to any barrels that we're touching. // The client handles adjusting our usercmd to push us away. CBaseEntity *props[256]; #ifdef CLIENT_DLL // if sv_pushaway_clientside is disabled, clientside phys objects don't bounce away if ( sv_pushaway_clientside.GetInt() == 0 ) return; // if sv_pushaway_clientside is 1, only local player can push them CBasePlayer *pPlayer = pPushingEntity->IsPlayer() ? (dynamic_cast< CBasePlayer * >(pPushingEntity)) : NULL; if ( (sv_pushaway_clientside.GetInt() == 1) && (!pPlayer || !pPlayer->IsLocalPlayer()) ) return; int nEnts = GetPushawayEnts( pPushingEntity, props, ARRAYSIZE( props ), 3.0f, PARTITION_CLIENT_RESPONSIVE_EDICTS, NULL ); #else int nEnts = GetPushawayEnts( pPushingEntity, props, ARRAYSIZE( props ), 3.0f, PARTITION_ENGINE_SOLID_EDICTS, NULL ); #endif for ( int i=0; i < nEnts; i++ ) { // If this entity uas PHYSICS_MULTIPLAYER_FULL set (ie: it's not just debris), and we're moving too slow, don't push it away. // Instead, let the client bounce off it. This allows players to get close to and duck behind things without knocking them over. IMultiplayerPhysics *pInterface = dynamic_cast<IMultiplayerPhysics*>( props[i] ); if ( pInterface && pInterface->GetMultiplayerPhysicsMode() == PHYSICS_MULTIPLAYER_SOLID ) { if ( pPushingEntity->GetAbsVelocity().Length2D() < sv_pushaway_min_player_speed.GetFloat() ) continue; } IPhysicsObject *pObj = props[i]->VPhysicsGetObject(); if ( pObj ) { Vector vPushAway = (props[i]->WorldSpaceCenter() - pPushingEntity->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, pPushingEntity->WorldSpaceCenter() ); } } }
void CBlobElement::ModifyVelocityForSurface( float flInterval, float flSpeed ) { trace_t tr; Vector vecStart = GetAbsOrigin(); Vector up = Vector( 0, 0, BLOB_TRACE_HEIGHT ); Vector vecWishedGoal = vecStart + (GetAbsVelocity() * flInterval); UTIL_TraceLine( vecStart + up, vecWishedGoal + up, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); //NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 0, 0, false, 0.1f ); m_bOnWall = false; if( tr.fraction == 1.0f ) { UTIL_TraceLine( vecWishedGoal + up, vecWishedGoal - (up * 2.0f), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); //NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 255, 0, false, 0.1f ); tr.endpos.z += MOVE_HEIGHT_EPSILON; } else { //NDebugOverlay::Cross3D( GetAbsOrigin(), 16, 255, 255, 0, false, 0.025f ); m_bOnWall = true; if( tr.m_pEnt != NULL && !tr.m_pEnt->IsWorld() ) { IPhysicsObject *pPhysics = tr.m_pEnt->VPhysicsGetObject(); if( pPhysics != NULL ) { Vector vecMassCenter; Vector vecMassCenterWorld; vecMassCenter = pPhysics->GetMassCenterLocalSpace(); pPhysics->LocalToWorld( &vecMassCenterWorld, vecMassCenter ); if( tr.endpos.z > vecMassCenterWorld.z ) { pPhysics->ApplyForceOffset( (-150.0f * m_flRandomEightyPercent) * tr.plane.normal, tr.endpos ); } } } } Vector vecDir = tr.endpos - vecStart; VectorNormalize( vecDir ); SetElementVelocity( vecDir * flSpeed, false ); }
void CNPC_Hydra::Nudge( CBaseEntity *pOther, const Vector &vecContact, const Vector &vecSpeed ) { if ( pOther->GetMoveType() != MOVETYPE_VPHYSICS ) { return; } IPhysicsObject *pOtherPhysics = pOther->VPhysicsGetObject(); // Put the force on the line between the "contact point" and hit object origin //Vector posOther; //pOtherPhysics->GetPosition( &posOther, NULL ); // force is a 30kg object going 100 in/s pOtherPhysics->ApplyForceOffset( vecSpeed * 30, vecContact ); }
IterationRetval_t CRagdollEnumerator::EnumElement( IHandleEntity *pHandleEntity ) { C_BaseEntity *pEnt = ClientEntityList().GetBaseEntityFromHandle( pHandleEntity->GetRefEHandle() ); if ( pEnt == NULL ) return ITERATION_CONTINUE; C_BaseAnimating *pModel = static_cast< C_BaseAnimating * >( pEnt ); if ( pModel == NULL ) return ITERATION_CONTINUE; trace_t tr; enginetrace->ClipRayToEntity( m_rayShot, MASK_SHOT, pModel, &tr ); IPhysicsObject *pPhysicsObject = pModel->VPhysicsGetObject(); if ( pPhysicsObject == NULL ) return ITERATION_CONTINUE; if ( tr.fraction < 1.0 ) { //Send the ragdoll the explosion force Vector dir = m_rayShot.m_Delta; VectorNormalize( dir ); pPhysicsObject->ApplyForceOffset( dir * m_flForce, tr.endpos ); /* //FIXME: JDW - Can't do this until the decal references are client-side as well int decalNumber = decalsystem->GetDecalIndexForName( GetImpactDecal( pModel, &tr, m_iDamageType ) ); if ( pModel != NULL ) { pModel->AddDecal( m_rayShot.m_Start, tr.endpos, tr.endpos, tr.hitbox, decalNumber, true, tr ); } */ m_bHit = true; //FIXME: Yes? No? return ITERATION_STOP; } return ITERATION_CONTINUE; }
void C_GENPCRagdoll::ImpactTrace( trace_t *pTrace, int iDamageType, char *pCustomImpactName ) { static bool bInTrace = false; if ( bInTrace ) return; IPhysicsObject *pPhysicsObject = VPhysicsGetObject(); if( !pPhysicsObject ) return; Vector dir = pTrace->endpos - pTrace->startpos; if ( iDamageType == DMG_BLAST ) { dir *= 4000; // adjust impact strength // apply force at object mass center pPhysicsObject->ApplyForceCenter( dir ); } else { Vector hitpos; VectorMA( pTrace->startpos, pTrace->fraction, dir, hitpos ); VectorNormalize( dir ); dir *= 4000; // adjust impact strength // apply force where we hit it pPhysicsObject->ApplyForceOffset( dir, hitpos ); UTIL_BloodDrips( pTrace->endpos, dir, BLOOD_COLOR_RED, 20 ); bInTrace = true; //<-- Prevent infinite recursion! C_BaseEntity::ImpactTrace( pTrace, iDamageType, pCustomImpactName ); bInTrace = false; } m_pRagdoll->ResetRagdollSleepAfterTime(); }
void C_SDKRagdoll::ImpactTrace( trace_t *pTrace, int iDamageType, char *pCustomImpactName ) { // DevMsg("C_SDKRagDoll::ImpactTrace: %i\n", iDamageType); IPhysicsObject *pPhysicsObject = VPhysicsGetObject(); if( !pPhysicsObject ) return; Vector dir = pTrace->endpos - pTrace->startpos; if ( iDamageType == DMG_BLAST ) { dir *= 4000; // adjust impact strength // apply force at object mass center pPhysicsObject->ApplyForceCenter( dir ); } else { Vector hitpos; VectorMA( pTrace->startpos, pTrace->fraction, dir, hitpos ); VectorNormalize( dir ); // Blood spray! FX_BloodSpray( hitpos, dir, 3, 72, 0, 0, FX_BLOODSPRAY_ALL ); dir *= 4000; // adjust impact strenght // apply force where we hit it pPhysicsObject->ApplyForceOffset( dir, hitpos ); //Tony; throw in some bleeds! - just use a generic value for damage. TraceBleed( 40, dir, pTrace, iDamageType ); } m_pRagdoll->ResetRagdollSleepAfterTime(); }
//----------------------------------------------------------------------------- // Purpose: // Input : *pActivator - // *pCaller - // useType - // value - //----------------------------------------------------------------------------- void CPhysImpact::InputImpact( inputdata_t &inputdata ) { Vector dir; trace_t trace; AngleVectors( GetAbsAngles(), &dir ); //Setup our trace information float dist = HasSpawnFlags( bitsPHYSIMPACT_INFINITE_LENGTH ) ? MAX_TRACE_LENGTH : m_distance; Vector start = GetAbsOrigin(); Vector end = start + ( dir * dist ); //Trace out UTIL_TraceLine( start, end, MASK_SHOT, this, 0, &trace ); if ( trace.fraction != 1.0 ) { CBaseEntity *pEnt = trace.m_pEnt; IPhysicsObject *pPhysics = pEnt->VPhysicsGetObject(); //If the entity is valid, hit it if ( ( pEnt != NULL ) && ( pPhysics != NULL ) ) { //Damage falls off unless specified or the ray's length is infinite float damage = HasSpawnFlags( bitsPHYSIMPACT_NOFALLOFF | bitsPHYSIMPACT_INFINITE_LENGTH ) ? m_damage : (m_damage * (1.0f-trace.fraction)); if ( HasSpawnFlags( bitsPHYSIMPACT_IGNORE_MASS ) ) { damage *= pPhysics->GetMass(); } pPhysics->ApplyForceOffset( -damage * trace.plane.normal * phys_pushscale.GetFloat(), trace.endpos ); } } }
//----------------------------------------------------------------------------- // 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 }
void C_PhysPropClientside::ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName ) { VPROF( "C_PhysPropClientside::ImpactTrace" ); IPhysicsObject *pPhysicsObject = VPhysicsGetObject(); if( !pPhysicsObject ) return; Vector dir = pTrace->endpos - pTrace->startpos; int iDamage = 0; if ( iDamageType == DMG_BLAST ) { iDamage = VectorLength( dir ); dir *= 500; // adjust impact strenght // apply force at object mass center pPhysicsObject->ApplyForceCenter( dir ); } else { Vector hitpos; VectorMA( pTrace->startpos, pTrace->fraction, dir, hitpos ); VectorNormalize( dir ); // guess avg damage if ( iDamageType == DMG_BULLET ) { iDamage = 30; } else { iDamage = 50; } dir *= 4000; // adjust impact strenght // apply force where we hit it pPhysicsObject->ApplyForceOffset( dir, hitpos ); // Build the impact data CEffectData data; data.m_vOrigin = pTrace->endpos; data.m_vStart = pTrace->startpos; data.m_nSurfaceProp = pTrace->surface.surfaceProps; data.m_nDamageType = iDamageType; data.m_nHitBox = pTrace->hitbox; data.m_hEntity = GetRefEHandle(); // Send it on its way if ( !pCustomImpactName ) { DispatchEffect( "Impact", data ); } else { DispatchEffect( pCustomImpactName, data ); } } // Clone( dir ); // debug code OnTakeDamage( iDamage ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CASW_PropJeep::FireChargedCannon( void ) { bool penetrated = false; m_bCannonCharging = false; m_flCannonTime = gpGlobals->curtime + 0.5f; StopChargeSound(); CPASAttenuationFilter sndFilter( this, "PropJeep.FireChargedCannon" ); EmitSound( sndFilter, entindex(), "PropJeep.FireChargedCannon" ); //Find the direction the gun is pointing in Vector aimDir; GetCannonAim( &aimDir ); Vector endPos = m_vecGunOrigin + ( aimDir * MAX_TRACE_LENGTH ); //Shoot a shot straight out trace_t tr; UTIL_TraceLine( m_vecGunOrigin, endPos, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); ClearMultiDamage(); //Find how much damage to do float flChargeAmount = ( gpGlobals->curtime - m_flCannonChargeStartTime ) / MAX_GAUSS_CHARGE_TIME; //Clamp this if ( flChargeAmount > 1.0f ) { flChargeAmount = 1.0f; } //Determine the damage amount //FIXME: Use ConVars! float flDamage = 15 + ( ( 250 - 15 ) * flChargeAmount ); CBaseEntity *pHit = tr.m_pEnt; //Look for wall penetration if ( tr.DidHitWorld() && !(tr.surface.flags & SURF_SKY) ) { //Try wall penetration UTIL_ImpactTrace( &tr, m_nBulletType, "ImpactJeep" ); UTIL_DecalTrace( &tr, "RedGlowFade" ); CPVSFilter filter( tr.endpos ); te->GaussExplosion( filter, 0.0f, tr.endpos, tr.plane.normal, 0 ); Vector testPos = tr.endpos + ( aimDir * 48.0f ); UTIL_TraceLine( testPos, tr.endpos, MASK_SHOT, GetDriver(), COLLISION_GROUP_NONE, &tr ); if ( tr.allsolid == false ) { UTIL_DecalTrace( &tr, "RedGlowFade" ); penetrated = true; } } else if ( pHit != NULL ) { CTakeDamageInfo dmgInfo( this, GetDriver(), flDamage, DMG_SHOCK ); CalculateBulletDamageForce( &dmgInfo, GetAmmoDef()->Index("GaussEnergy"), aimDir, tr.endpos, 1.0f + flChargeAmount * 4.0f ); //Do direct damage to anything in our path pHit->DispatchTraceAttack( dmgInfo, aimDir, &tr ); } ApplyMultiDamage(); //Kick up an effect if ( !(tr.surface.flags & SURF_SKY) ) { UTIL_ImpactTrace( &tr, m_nBulletType, "ImpactJeep" ); //Do a gauss explosion CPVSFilter filter( tr.endpos ); te->GaussExplosion( filter, 0.0f, tr.endpos, tr.plane.normal, 0 ); } //Show the effect DrawBeam( m_vecGunOrigin, tr.endpos, 9.6 ); // Register a muzzleflash for the AI if ( m_hPlayer ) { m_hPlayer->SetMuzzleFlashTime( gpGlobals->curtime + 0.5f ); } //Rock the car IPhysicsObject *pObj = VPhysicsGetObject(); if ( pObj != NULL ) { Vector shoveDir = aimDir * -( flDamage * 500.0f ); pObj->ApplyForceOffset( shoveDir, m_vecGunOrigin ); } //Do radius damage if we didn't penetrate the wall if ( penetrated == true ) { RadiusDamage( CTakeDamageInfo( this, this, flDamage, DMG_SHOCK ), tr.endpos, 200.0f, CLASS_NONE, NULL ); } }