//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- int CPhysBox::OnTakeDamage( const CTakeDamageInfo &info ) { // note: if motion is disabled, OnTakeDamage can't apply physics force int ret = BaseClass::OnTakeDamage( info ); // Check our health against the threshold: if( m_damageToEnableMotion > 0 && GetHealth() < m_damageToEnableMotion ) { // only do this once m_damageToEnableMotion = 0; IPhysicsObject *pPhysicsObject = VPhysicsGetObject(); if ( pPhysicsObject != NULL ) { pPhysicsObject->Wake(); pPhysicsObject->EnableMotion( true ); VPhysicsTakeDamage( info ); } } if ( info.GetInflictor() ) { m_OnDamaged.FireOutput( info.GetAttacker(), this ); } return ret; }
void CStatueProp::Event_Killed( const CTakeDamageInfo &info ) { IPhysicsObject *pPhysics = VPhysicsGetObject(); if ( pPhysics && !pPhysics->IsMoveable() ) { pPhysics->EnableMotion( true ); VPhysicsTakeDamage( info ); } m_nShatterFlags = 0; // If you have some flags to network for the shatter effect, put them here! m_vShatterPosition = info.GetDamagePosition(); m_vShatterForce = info.GetDamageForce(); m_bShatter = true; // Skip over breaking code! //Break( info.GetInflictor(), info ); //BaseClass::Event_Killed( info ); // FIXME: Short delay before we actually remove so that the client statue gets a network update before we need it // This isn't a reliable way to do this and needs to be rethought. AddSolidFlags( FSOLID_NOT_SOLID ); SetNextThink( gpGlobals->curtime + 0.2f ); SetThink( &CBaseEntity::SUB_Remove ); }
// as CItem, but we don't install the touch function void CASW_Pickup::Spawn( void ) { SetMoveType( MOVETYPE_FLYGRAVITY ); SetSolid( SOLID_BBOX ); SetBlocksLOS( false ); AddEFlags( EFL_NO_ROTORWASH_PUSH ); // This will make them not collide with the player, but will collide // against other items + weapons SetCollisionGroup( COLLISION_GROUP_WEAPON ); CollisionProp()->UseTriggerBounds( true, ITEM_PICKUP_BOX_BLOAT ); //SetTouch(&CItem::ItemTouch); if ( CreateItemVPhysicsObject() == false ) return; m_takedamage = DAMAGE_EVENTS_ONLY; #ifdef HL2MP SetThink( &CItem::FallThink ); SetNextThink( gpGlobals->curtime + 0.1f ); #endif if ( m_bFreezePickup ) { IPhysicsObject *pPhysicsObject = VPhysicsGetObject(); if ( pPhysicsObject != NULL ) { pPhysicsObject->EnableMotion( false ); } } }
//----------------------------------------------------------------------------- // Purpose: Disable any physics motion or collision response //----------------------------------------------------------------------------- void CPhysBox::InputDisableMotion( inputdata_t &inputdata ) { IPhysicsObject *pPhysicsObject = VPhysicsGetObject(); if ( pPhysicsObject != NULL ) { pPhysicsObject->EnableMotion( false ); } }
//------------------------------------------------------------------------------ // Pow! //------------------------------------------------------------------------------ void CPropAPC2::ExplodeAndThrowChunk( const Vector &vecExplosionPos ) { ExplosionCreate( vecExplosionPos, vec3_angle, this, 1000, 500.0f, SF_ENVEXPLOSION_NODAMAGE | SF_ENVEXPLOSION_NOSPARKS | SF_ENVEXPLOSION_NODLIGHTS | SF_ENVEXPLOSION_NOSMOKE | SF_ENVEXPLOSION_NOFIREBALLSMOKE, 0 ); UTIL_ScreenShake( vecExplosionPos, 25.0, 150.0, 1.0, 750.0f, SHAKE_START ); // Drop a flaming, smoking chunk. CGib *pChunk = CREATE_ENTITY( CGib, "gib" ); pChunk->Spawn( "models/gibs/hgibs.mdl" ); pChunk->SetBloodColor( DONT_BLEED ); QAngle vecSpawnAngles; vecSpawnAngles.Random( -90, 90 ); pChunk->SetAbsOrigin( vecExplosionPos ); pChunk->SetAbsAngles( vecSpawnAngles ); int nGib = random->RandomInt( 0, APC_MAX_CHUNKS - 1 ); pChunk->Spawn( s_pChunkModelName[nGib] ); pChunk->SetOwnerEntity( this ); pChunk->m_lifeTime = random->RandomFloat( 6.0f, 8.0f ); pChunk->SetCollisionGroup( COLLISION_GROUP_DEBRIS ); IPhysicsObject *pPhysicsObject = pChunk->VPhysicsInitNormal( SOLID_VPHYSICS, pChunk->GetSolidFlags(), false ); // Set the velocity if ( pPhysicsObject ) { pPhysicsObject->EnableMotion( true ); Vector vecVelocity; QAngle angles; angles.x = random->RandomFloat( -40, 0 ); angles.y = random->RandomFloat( 0, 360 ); angles.z = 0.0f; AngleVectors( angles, &vecVelocity ); vecVelocity *= random->RandomFloat( 300, 900 ); vecVelocity += GetAbsVelocity(); AngularImpulse angImpulse; angImpulse = RandomAngularImpulse( -180, 180 ); pChunk->SetAbsVelocity( vecVelocity ); pPhysicsObject->SetVelocity(&vecVelocity, &angImpulse ); } CEntityFlame *pFlame = CEntityFlame::Create( pChunk, false ); if ( pFlame != NULL ) { pFlame->SetLifetime( pChunk->m_lifeTime ); } pChunk->Dissolve( NULL, gpGlobals->curtime, false, ENTITY_DISSOLVE_NORMAL ); }
void CASW_Barrel_Explosive::Event_Killed( const CTakeDamageInfo &info ) { IPhysicsObject *pPhysics = VPhysicsGetObject(); if ( pPhysics && !pPhysics->IsMoveable() ) { pPhysics->EnableMotion( true ); VPhysicsTakeDamage( info ); } QueueForExplode( info ); // Break( info.GetInflictor(), info ); // DoExplosion(); }
void CWeaponSF132Cannon::FreezeHeldBlock( void ) { #ifndef CLIENT_DLL CBaseEntity *pEntity = m_grabController.GetAttached(); if ( pEntity ) { IPhysicsObject *pPhysicsObject = pEntity->VPhysicsGetObject(); if ( pPhysicsObject != NULL ) { pPhysicsObject->EnableMotion( false ); } } #endif // CLIENT_DLL }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CObjectSiegePlatform::Spawn() { Precache(); SetModel( SIEGE_TOWER_PLATFORM_MODEL ); SetSolid( SOLID_VPHYSICS ); m_takedamage = DAMAGE_NO; BaseClass::Spawn(); IPhysicsObject *pPhysics = VPhysicsInitStatic(); if ( pPhysics ) { pPhysics->EnableMotion( false ); } SetCollisionGroup( TFCOLLISION_GROUP_OBJECT_SOLIDTOPLAYERMOVEMENT ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CObjectTowerLadder::Spawn() { Precache(); SetModel( TOWER_LADDER_MODEL ); SetSolid( SOLID_VPHYSICS ); m_takedamage = DAMAGE_NO; BaseClass::Spawn(); IPhysicsObject *pPhysics = VPhysicsInitStatic(); if ( pPhysics ) { pPhysics->EnableMotion( false ); } SetCollisionGroup( COLLISION_GROUP_VEHICLE ); }
void CTripmineGrenade::Spawn( void ) { Precache( ); // motor SetMoveType( MOVETYPE_FLY ); SetSolid( SOLID_BBOX ); SetModel( "models/Weapons/w_slam.mdl" ); IPhysicsObject *pObject = VPhysicsInitNormal( SOLID_BBOX, GetSolidFlags() | FSOLID_TRIGGER, true ); pObject->EnableMotion( false ); SetCollisionGroup( COLLISION_GROUP_WEAPON ); SetCycle( 0.0f ); m_nBody = 3; m_flDamage = sk_plr_dmg_tripmine.GetFloat(); m_DmgRadius = sk_tripmine_radius.GetFloat(); ResetSequenceInfo( ); m_flPlaybackRate = 0; UTIL_SetSize(this, Vector( -4, -4, -2), Vector(4, 4, 2)); m_flPowerUp = gpGlobals->curtime + 2.0; SetThink( &CTripmineGrenade::PowerupThink ); SetNextThink( gpGlobals->curtime + 0.2 ); m_takedamage = DAMAGE_YES; m_iHealth = 1; EmitSound( "TripmineGrenade.Place" ); SetDamage ( 200 ); // Tripmine sits at 90 on wall so rotate back to get m_vecDir QAngle angles = GetAbsAngles(); angles.x -= 90; AngleVectors( angles, &m_vecDir ); m_vecEnd = GetAbsOrigin() + m_vecDir * 2048; AddEffects( EF_NOSHADOW ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTriggerPortalCleanser::TransferPhysicsObject( CBaseEntity *pFrom, CBaseEntity *pTo, bool wakeUp ) { IPhysicsObject *pVPhysics = pFrom->VPhysicsGetObject(); if ( !pVPhysics || pVPhysics->IsStatic() ) return false; Vector vecVelocity, vecAngular; pVPhysics->GetVelocity( &vecVelocity, &vecAngular ); // clear out the pointer so it won't get deleted pFrom->VPhysicsSwapObject( NULL ); // remove any AI behavior bound to it pVPhysics->RemoveShadowController(); // transfer to the new owner pTo->VPhysicsSetObject( pVPhysics ); pVPhysics->SetGameData( (void *)pTo ); pTo->VPhysicsUpdate( pVPhysics ); // may have been temporarily disabled by the old object pVPhysics->EnableMotion( true ); pVPhysics->EnableGravity( false ); // Slow down and push up the object. vecVelocity /= 2; vecAngular /= 2; vecVelocity.z += 10; pVPhysics->SetVelocity( &vecVelocity, &vecAngular ); // Update for the new entity solid type pVPhysics->RecheckCollisionFilter(); if ( wakeUp ) { pVPhysics->Wake(); } return true; }
// UNDONE: Is this worth it?, just recreate the object instead? (that happens when this returns false anyway) // recreating works, but is more expensive and won't inherit properties (velocity, constraints, etc) bool TransferPhysicsObject( CBaseEntity *pFrom, CBaseEntity *pTo ) { IPhysicsObject *pVPhysics = pFrom->VPhysicsGetObject(); if ( !pVPhysics || pVPhysics->IsStatic() ) return false; // clear out the pointer so it won't get deleted pFrom->VPhysicsSwapObject( NULL ); // remove any AI behavior bound to it pVPhysics->RemoveShadowController(); // transfer to the new owner pTo->VPhysicsSetObject( pVPhysics ); pVPhysics->SetGameData( (void *)pTo ); pTo->VPhysicsUpdate( pVPhysics ); // may have been temporarily disabled by the old object pVPhysics->EnableMotion( true ); pVPhysics->EnableGravity( true ); // Update for the new entity solid type pVPhysics->RecheckCollisionFilter(); return true; }
void CGEPropDynamic::Event_Killed(const CTakeDamageInfo &info) { // More or less just the kill event copied straight from prop_physics_respawnable, though it does not teleport as it cannot move on its own. IPhysicsObject *pPhysics = VPhysicsGetObject(); if (pPhysics && !pPhysics->IsMoveable()) { pPhysics->EnableMotion(true); VPhysicsTakeDamage(info); } Break(info.GetInflictor(), info); PhysCleanupFrictionSounds(this); VPhysicsDestroyObject(); CBaseEntity::PhysicsRemoveTouchedList(this); CBaseEntity::PhysicsRemoveGroundList(this); DestroyAllDataObjects(); AddEffects(EF_NODRAW); if (IsOnFire() || IsDissolving()) { UTIL_Remove(GetEffectEntity()); } SetContextThink(NULL, 0, "PROP_CLEARFLAGS"); if (m_flRespawnTime > 0) { SetThink(&CGEPropDynamic::Materialize); SetNextThink(gpGlobals->curtime + m_flRespawnTime); } }
//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 PropBreakableCreateAll( int modelindex, IPhysicsObject *pPhysics, const breakablepropparams_t ¶ms, CBaseEntity *pEntity, int iPrecomputedBreakableCount, bool bIgnoreGibLimit, bool defaultLocation ) { // Check for prop breakable count reset. int nPropCount = props_break_max_pieces_perframe.GetInt(); if ( nPropCount != -1 ) { if ( nFrameNumber != gpGlobals->framecount ) { nPropBreakablesPerFrameCount = 0; nFrameNumber = gpGlobals->framecount; } // Check for max breakable count for the frame. if ( nPropBreakablesPerFrameCount >= nPropCount ) return; } int iMaxBreakCount = bIgnoreGibLimit ? -1 : props_break_max_pieces.GetInt(); if ( iMaxBreakCount != -1 ) { if ( iPrecomputedBreakableCount != -1 ) { iPrecomputedBreakableCount = MIN( iMaxBreakCount, iPrecomputedBreakableCount ); } else { iPrecomputedBreakableCount = iMaxBreakCount; } } #ifdef GAME_DLL // On server limit break model creation if ( !PropBreakableCapEdictsOnCreateAll(modelindex, pPhysics, params, pEntity, iPrecomputedBreakableCount ) ) { DevMsg( "Failed to create PropBreakable: would exceed MAX_EDICTS\n" ); return; } #endif vcollide_t *pCollide = modelinfo->GetVCollide( modelindex ); if ( !pCollide ) return; int nSkin = 0; CBaseEntity *pOwnerEntity = pEntity; CBaseAnimating *pOwnerAnim = NULL; if ( pPhysics ) { pOwnerEntity = static_cast<CBaseEntity *>(pPhysics->GetGameData()); } if ( pOwnerEntity ) { pOwnerAnim = pOwnerEntity->GetBaseAnimating(); if ( pOwnerAnim ) { nSkin = pOwnerAnim->m_nSkin; } } matrix3x4_t localToWorld; CStudioHdr studioHdr; const model_t *model = modelinfo->GetModel( modelindex ); if ( model ) { studioHdr.Init( modelinfo->GetStudiomodel( model ) ); } Vector parentOrigin = vec3_origin; int parentAttachment = Studio_FindAttachment( &studioHdr, "placementOrigin" ) + 1; if ( parentAttachment > 0 ) { GetAttachmentLocalSpace( &studioHdr, parentAttachment-1, localToWorld ); MatrixGetColumn( localToWorld, 3, parentOrigin ); } else { AngleMatrix( vec3_angle, localToWorld ); } CUtlVector<breakmodel_t> list; BreakModelList( list, modelindex, params.defBurstScale, params.defCollisionGroup ); if ( list.Count() ) { for ( int i = 0; i < list.Count(); i++ ) { int modelIndex = modelinfo->GetModelIndex( list[i].modelName ); if ( modelIndex <= 0 ) continue; // Skip multiplayer pieces that should be spawning on the other dll #ifdef GAME_DLL if ( gpGlobals->maxClients > 1 && breakable_multiplayer.GetBool() ) #else if ( gpGlobals->maxClients > 1 ) #endif { #ifdef GAME_DLL if ( list[i].mpBreakMode == MULTIPLAYER_BREAK_CLIENTSIDE ) continue; #else if ( list[i].mpBreakMode == MULTIPLAYER_BREAK_SERVERSIDE ) continue; #endif if ( !defaultLocation && list[i].mpBreakMode == MULTIPLAYER_BREAK_DEFAULT ) continue; } if ( ( nPropCount != -1 ) && ( nPropBreakablesPerFrameCount > nPropCount ) ) break; if ( ( iPrecomputedBreakableCount != -1 ) && ( i >= iPrecomputedBreakableCount ) ) break; matrix3x4_t matrix; AngleMatrix( params.angles, params.origin, matrix ); CStudioHdr studioHdr; const model_t *model = modelinfo->GetModel( modelIndex ); if ( model ) { studioHdr.Init( modelinfo->GetStudiomodel( model ) ); } // Increment the number of breakable props this frame. ++nPropBreakablesPerFrameCount; Vector position = vec3_origin; QAngle angles = params.angles; if ( pOwnerAnim && list[i].placementName[0] ) { if ( list[i].placementIsBone ) { int boneIndex = pOwnerAnim->LookupBone( list[i].placementName ); if ( boneIndex >= 0 ) { pOwnerAnim->GetBonePosition( boneIndex, position, angles ); AngleMatrix( angles, position, matrix ); } } else { int attachmentIndex = Studio_FindAttachment( &studioHdr, list[i].placementName ) + 1; if ( attachmentIndex > 0 ) { pOwnerAnim->GetAttachment( attachmentIndex, matrix ); MatrixAngles( matrix, angles ); } } } else { int placementIndex = Studio_FindAttachment( &studioHdr, "placementOrigin" ) + 1; Vector placementOrigin = parentOrigin; if ( placementIndex > 0 ) { GetAttachmentLocalSpace( &studioHdr, placementIndex-1, localToWorld ); MatrixGetColumn( localToWorld, 3, placementOrigin ); placementOrigin -= parentOrigin; } VectorTransform( list[i].offset - placementOrigin, matrix, position ); } Vector objectVelocity = params.velocity; if (pPhysics) { pPhysics->GetVelocityAtPoint( position, &objectVelocity ); } int nActualSkin = nSkin; if ( nActualSkin > studioHdr.numskinfamilies() ) nActualSkin = 0; CBaseEntity *pBreakable = NULL; #ifdef GAME_DLL if ( GetGibManager() == NULL || GetGibManager()->AllowedToSpawnGib() ) #endif { pBreakable = BreakModelCreateSingle( pOwnerEntity, &list[i], position, angles, objectVelocity, params.angularVelocity, nActualSkin, params ); } if ( pBreakable ) { #ifdef GAME_DLL if ( GetGibManager() ) { GetGibManager()->AddGibToLRU( pBreakable->GetBaseAnimating() ); } #endif if ( pOwnerEntity && pOwnerEntity->IsEffectActive( EF_NOSHADOW ) ) { pBreakable->AddEffects( EF_NOSHADOW ); } // If burst scale is set, this piece should 'burst' away from // the origin in addition to travelling in the wished velocity. if ( list[i].burstScale != 0.0 ) { Vector vecBurstDir = position - params.origin; // If $autocenter wasn't used, try the center of the piece if ( vecBurstDir == vec3_origin ) { vecBurstDir = pBreakable->WorldSpaceCenter() - params.origin; } VectorNormalize( vecBurstDir ); pBreakable->ApplyAbsVelocityImpulse( vecBurstDir * list[i].burstScale ); } // If this piece is supposed to be motion disabled, disable it if ( list[i].isMotionDisabled ) { IPhysicsObject *pPhysicsObject = pBreakable->VPhysicsGetObject(); if ( pPhysicsObject != NULL ) { pPhysicsObject->EnableMotion( false ); } } } } } // Then see if the propdata specifies any breakable pieces else if ( pEntity ) { IBreakableWithPropData *pBreakableInterface = dynamic_cast<IBreakableWithPropData*>(pEntity); if ( pBreakableInterface && pBreakableInterface->GetBreakableModel() != NULL_STRING && pBreakableInterface->GetBreakableCount() ) { breakmodel_t breakModel; for ( int i = 0; i < pBreakableInterface->GetBreakableCount(); i++ ) { if ( ( iPrecomputedBreakableCount != -1 ) && ( i >= iPrecomputedBreakableCount ) ) break; Q_strncpy( breakModel.modelName, g_PropDataSystem.GetRandomChunkModel(STRING(pBreakableInterface->GetBreakableModel()), pBreakableInterface->GetMaxBreakableSize()), sizeof(breakModel.modelName) ); breakModel.health = 1; breakModel.fadeTime = RandomFloat(5,10); breakModel.fadeMinDist = 0.0f; breakModel.fadeMaxDist = 0.0f; breakModel.burstScale = params.defBurstScale; breakModel.collisionGroup = COLLISION_GROUP_DEBRIS; breakModel.isRagdoll = false; breakModel.isMotionDisabled = false; breakModel.placementName[0] = 0; breakModel.placementIsBone = false; Vector vecObbSize = pEntity->CollisionProp()->OBBSize(); // Find a random point on the plane of the original's two largest axis int smallestAxis = SmallestAxis( vecObbSize ); Vector vecMins(0,0,0); Vector vecMaxs(1,1,1); vecMins[smallestAxis] = 0.5; vecMaxs[smallestAxis] = 0.5; pEntity->CollisionProp()->RandomPointInBounds( vecMins, vecMaxs, &breakModel.offset ); // Push all chunks away from the center Vector vecBurstDir = breakModel.offset - params.origin; VectorNormalize( vecBurstDir ); Vector vecVelocity = vecBurstDir * params.defBurstScale; QAngle vecAngles = pEntity->GetAbsAngles(); int iSkin = pBreakableInterface->GetBreakableSkin(); CBaseEntity *pBreakable = NULL; #ifdef GAME_DLL if ( GetGibManager() == NULL || GetGibManager()->AllowedToSpawnGib() ) #endif { pBreakable = BreakModelCreateSingle( pOwnerEntity, &breakModel, breakModel.offset, vecAngles, vecVelocity, vec3_origin/*params.angularVelocity*/, iSkin, params ); if ( !pBreakable ) { DevWarning( "PropBreakableCreateAll: Could not create model %s\n", breakModel.modelName ); } } if ( pBreakable ) { #ifdef GAME_DLL if ( GetGibManager() ) { GetGibManager()->AddGibToLRU( pBreakable->GetBaseAnimating() ); } #endif Vector vecBreakableObbSize = pBreakable->CollisionProp()->OBBSize(); // Try to align the gibs along the original axis matrix3x4_t matrix; AngleMatrix( vecAngles, matrix ); AlignBoxes( &matrix, vecObbSize, vecBreakableObbSize ); MatrixAngles( matrix, vecAngles ); if ( pBreakable->VPhysicsGetObject() ) { Vector pos; pBreakable->VPhysicsGetObject()->GetPosition( &pos, NULL ); pBreakable->VPhysicsGetObject()->SetPosition( pos, vecAngles, true ); } pBreakable->SetAbsAngles( vecAngles ); if ( pOwnerEntity->IsEffectActive( EF_NOSHADOW ) ) { pBreakable->AddEffects( EF_NOSHADOW ); } } } } } }
//----------------------------------------------------------------------------- // Purpose: // Input : *pOther - //----------------------------------------------------------------------------- void CGrappleHook::HookTouch(CBaseEntity *pOther) { if (!pOther->IsSolid() || pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS)) return; if ((pOther != m_hOwner) && (pOther->m_takedamage != DAMAGE_NO)) { m_hOwner->NotifyHookDied(); SetTouch(NULL); SetThink(NULL); UTIL_Remove(this); } else { trace_t tr; tr = BaseClass::GetTouchTrace(); // See if we struck the world if (pOther->GetMoveType() == MOVETYPE_NONE && !(tr.surface.flags & SURF_SKY)) { EmitSound("Weapon_AR2.Reload_Push"); // if what we hit is static architecture, can stay around for a while. Vector vecDir = GetAbsVelocity(); //FIXME: We actually want to stick (with hierarchy) to what we've hit SetMoveType(MOVETYPE_NONE); Vector vForward; AngleVectors(GetAbsAngles(), &vForward); VectorNormalize(vForward); CEffectData data; data.m_vOrigin = tr.endpos; data.m_vNormal = vForward; data.m_nEntIndex = 0; // DispatchEffect( "Impact", data ); // AddEffects( EF_NODRAW ); SetTouch(NULL); VPhysicsDestroyObject(); VPhysicsInitNormal(SOLID_VPHYSICS, FSOLID_NOT_STANDABLE, false); AddSolidFlags(FSOLID_NOT_SOLID); // SetMoveType( MOVETYPE_NONE ); if (!m_hPlayer) { Assert(0); return; } // Set Jay's gai flag m_hPlayer->SetPhysicsFlag(PFLAG_VPHYSICS_MOTIONCONTROLLER, true); //IPhysicsObject *pPhysObject = m_hPlayer->VPhysicsGetObject(); IPhysicsObject *pRootPhysObject = VPhysicsGetObject(); Assert(pRootPhysObject); //Assert(pPhysObject); pRootPhysObject->EnableMotion(false); // Root has huge mass, tip has little pRootPhysObject->SetMass(VPHYSICS_MAX_MASS); // pPhysObject->SetMass( 100 ); // float damping = 3; // pPhysObject->SetDamping( &damping, &damping ); Vector origin = m_hPlayer->GetAbsOrigin(); Vector rootOrigin = GetAbsOrigin(); m_fSpringLength = (origin - rootOrigin).Length(); m_bPlayerWasStanding = ((m_hPlayer->GetFlags() & FL_DUCKING) == 0); SetThink(&CGrappleHook::HookedThink); SetNextThink(gpGlobals->curtime + 0.1f); } else { // Put a mark unless we've hit the sky if ((tr.surface.flags & SURF_SKY) == false) { UTIL_ImpactTrace(&tr, DMG_BULLET); } SetTouch(NULL); SetThink(NULL); m_hOwner->NotifyHookDied(); UTIL_Remove(this); } } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CPropAPC::Event_Killed( const CTakeDamageInfo &info ) { m_OnDeath.FireOutput( info.GetAttacker(), this ); Vector vecAbsMins, vecAbsMaxs; CollisionProp()->WorldSpaceAABB( &vecAbsMins, &vecAbsMaxs ); Vector vecNormalizedMins, vecNormalizedMaxs; CollisionProp()->WorldToNormalizedSpace( vecAbsMins, &vecNormalizedMins ); CollisionProp()->WorldToNormalizedSpace( vecAbsMaxs, &vecNormalizedMaxs ); Vector vecAbsPoint; CPASFilter filter( GetAbsOrigin() ); for (int i = 0; i < 5; i++) { CollisionProp()->RandomPointInBounds( vecNormalizedMins, vecNormalizedMaxs, &vecAbsPoint ); te->Explosion( filter, random->RandomFloat( 0.0, 1.0 ), &vecAbsPoint, g_sModelIndexFireball, random->RandomInt( 4, 10 ), random->RandomInt( 8, 15 ), ( i < 2 ) ? TE_EXPLFLAG_NODLIGHTS : TE_EXPLFLAG_NOPARTICLES | TE_EXPLFLAG_NOFIREBALLSMOKE | TE_EXPLFLAG_NODLIGHTS, 100, 0 ); } // TODO: make the gibs spawn in sync with the delayed explosions int nGibs = random->RandomInt( 1, 4 ); for ( int i = 0; i < nGibs; i++) { // Throw a flaming, smoking chunk. CGib *pChunk = CREATE_ENTITY( CGib, "gib" ); pChunk->Spawn( "models/gibs/hgibs.mdl" ); pChunk->SetBloodColor( DONT_BLEED ); QAngle vecSpawnAngles; vecSpawnAngles.Random( -90, 90 ); pChunk->SetAbsOrigin( vecAbsPoint ); pChunk->SetAbsAngles( vecSpawnAngles ); int nGib = random->RandomInt( 0, APC_MAX_CHUNKS - 1 ); pChunk->Spawn( s_pChunkModelName[nGib] ); pChunk->SetOwnerEntity( this ); pChunk->m_lifeTime = random->RandomFloat( 6.0f, 8.0f ); pChunk->SetCollisionGroup( COLLISION_GROUP_DEBRIS ); IPhysicsObject *pPhysicsObject = pChunk->VPhysicsInitNormal( SOLID_VPHYSICS, pChunk->GetSolidFlags(), false ); // Set the velocity if ( pPhysicsObject ) { pPhysicsObject->EnableMotion( true ); Vector vecVelocity; QAngle angles; angles.x = random->RandomFloat( -20, 20 ); angles.y = random->RandomFloat( 0, 360 ); angles.z = 0.0f; AngleVectors( angles, &vecVelocity ); vecVelocity *= random->RandomFloat( 300, 900 ); vecVelocity += GetAbsVelocity(); AngularImpulse angImpulse; angImpulse = RandomAngularImpulse( -180, 180 ); pChunk->SetAbsVelocity( vecVelocity ); pPhysicsObject->SetVelocity(&vecVelocity, &angImpulse ); } CEntityFlame *pFlame = CEntityFlame::Create( pChunk, false ); if ( pFlame != NULL ) { pFlame->SetLifetime( pChunk->m_lifeTime ); } } UTIL_ScreenShake( vecAbsPoint, 25.0, 150.0, 1.0, 750.0f, SHAKE_START ); if( hl2_episodic.GetBool() ) { // EP1 perf hit Ignite( 6, false ); } else { Ignite( 60, false ); } m_lifeState = LIFE_DYING; // Spawn a lesser amount if the player is close m_iRocketSalvoLeft = DEATH_VOLLEY_ROCKET_COUNT; m_flRocketTime = gpGlobals->curtime; }