//====== Copyright 1996-2005, Valve Corporation, All rights reserved. ======= // // Purpose: Temp entity for testing physcannon ammo // //============================================================================= #include "cbase.h" #include "props.h" #include "vphysics/constraints.h" #include "physics_saverestore.h" class CPropStickyBomb : public CPhysicsProp { DECLARE_CLASS( CPropStickyBomb, CPhysicsProp ); DECLARE_DATADESC(); public: CPropStickyBomb( void ); virtual void Precache( void ); virtual void Spawn( void ); virtual void VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ); virtual void UpdateOnRemove( void ); private: bool StickToWorld( int index, gamevcollisionevent_t *pEvent ); bool StickToEntity( int index, gamevcollisionevent_t *pEvent ); bool CreateConstraintToObject( CBaseEntity *pObject ); bool CreateConstraintToNPC( CAI_BaseNPC *pNPC ); void OnConstraintBroken( void ); IPhysicsConstraint *m_pConstraint; EHANDLE m_hConstrainedEntity; }; LINK_ENTITY_TO_CLASS( prop_stickybomb, CPropStickyBomb ); BEGIN_DATADESC( CPropStickyBomb ) DEFINE_FIELD( m_hConstrainedEntity, FIELD_EHANDLE ), DEFINE_PHYSPTR( m_pConstraint ), END_DATADESC() CPropStickyBomb::CPropStickyBomb( void ) : m_pConstraint(NULL) { } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CPropStickyBomb::Precache( void ) { m_iszBreakableModel = AllocPooledString( "models/props_outland/pumpkin_explosive.mdl" ); PrecacheModel( STRING( m_iszBreakableModel ) ); PrecacheScriptSound( "NPC_AntlionGrub.Squash" ); BaseClass::Precache(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CPropStickyBomb::Spawn( void ) { BaseClass::Spawn(); } //----------------------------------------------------------------------------- // Purpose: Stick to the world // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CPropStickyBomb::StickToWorld( int index, gamevcollisionevent_t *pEvent ) { Vector vecDir = pEvent->preVelocity[ index ]; float speed = VectorNormalize( vecDir ); // Make sure the object is travelling fast enough to stick. if( speed > 1000.0f ) { Vector vecPos; QAngle angles; VPhysicsGetObject()->GetPosition( &vecPos, &angles ); Vector vecVelocity = pEvent->preVelocity[0]; VectorNormalize(vecVelocity); trace_t tr; UTIL_TraceLine( vecPos, vecPos + (vecVelocity * 64), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); // Finally, inhibit sticking in metal, grates, sky, or anything else that doesn't make a sound. surfacedata_t *psurf= physprops->GetSurfaceData( pEvent->surfaceProps[!index] ); if ( psurf->game.material != 'X' ) { EmitSound( "NPC_AntlionGrub.Squash" ); Vector savePosition = vecPos; Vector vecEmbed = pEvent->preVelocity[ index ]; VectorNormalize( vecEmbed ); vecEmbed *= 8; vecPos += vecEmbed; Teleport( &vecPos, NULL, NULL ); SetEnableMotionPosition( savePosition, angles ); // this uses hierarchy, so it must be set after teleport VPhysicsGetObject()->EnableMotion( false ); AddSpawnFlags( SF_PHYSPROP_ENABLE_ON_PHYSCANNON ); SetCollisionGroup( COLLISION_GROUP_DEBRIS ); UTIL_DecalTrace( &tr, "PaintSplatGreen" ); return true; } } return false; } //----------------------------------------------------------------------------- // Purpose: Create a constraint between this object and another // Input : *pObject - Object to constrain ourselves to // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CPropStickyBomb::CreateConstraintToObject( CBaseEntity *pObject ) { if ( m_pConstraint != NULL ) { // Should we destroy the constraint and make a new one at this point? Assert( 0 ); return false; } if ( pObject == NULL ) return false; IPhysicsObject *pPhysObject = pObject->VPhysicsGetObject(); if ( pPhysObject == NULL ) return false; IPhysicsObject *pMyPhysObject = VPhysicsGetObject(); if ( pPhysObject == NULL ) return false; // Create the fixed constraint constraint_fixedparams_t fixedConstraint; fixedConstraint.Defaults(); fixedConstraint.InitWithCurrentObjectState( pPhysObject, pMyPhysObject ); IPhysicsConstraint *pConstraint = physenv->CreateFixedConstraint( pPhysObject, pMyPhysObject, NULL, fixedConstraint ); if ( pConstraint == NULL ) return false; // Hold on to us m_pConstraint = pConstraint; pConstraint->SetGameData( (void *)this ); m_hConstrainedEntity = pObject; // Disable collisions between the two ents PhysDisableObjectCollisions( pPhysObject, pMyPhysObject ); EmitSound( "NPC_AntlionGrub.Squash" ); return true; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CPropStickyBomb::UpdateOnRemove( void ) { OnConstraintBroken(); BaseClass::UpdateOnRemove(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CPropStickyBomb::OnConstraintBroken( void ) { // Destroy the constraint if ( m_pConstraint != NULL ) { physenv->DestroyConstraint( m_pConstraint ); m_pConstraint = NULL; } if ( m_hConstrainedEntity != NULL ) { // Re-enable the collisions between the objects IPhysicsObject *pPhysObject = m_hConstrainedEntity->VPhysicsGetObject(); IPhysicsObject *pMyPhysObject = VPhysicsGetObject(); PhysEnableEntityCollisions( pPhysObject, pMyPhysObject ); m_hConstrainedEntity = NULL; } } //----------------------------------------------------------------------------- // Purpose: // Input : *pNPC - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CPropStickyBomb::CreateConstraintToNPC( CAI_BaseNPC *pNPC ) { // Find the nearest bone to our position return false; } //----------------------------------------------------------------------------- // Purpose: Stick to an entity (using hierarchy if we can) // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CPropStickyBomb::StickToEntity( int index, gamevcollisionevent_t *pEvent ) { // Make sure the object is travelling fast enough to stick float flSpeedSqr = ( pEvent->preVelocity[ index ] ).LengthSqr(); if ( flSpeedSqr < Square( 1000.0f ) ) return false; CBaseEntity *pOther = pEvent->pEntities[!index]; // Handle NPCs CAI_BaseNPC *pNPC = pOther->MyNPCPointer(); if ( pNPC != NULL ) { // Attach this object to the nearest bone // TODO: How does this affect the NPC's behavior? return CreateConstraintToNPC( pNPC ); } // Handle physics props CPhysicsProp *pProp = dynamic_cast<CPhysicsProp *>(pOther); if ( pProp != NULL ) { // Create a constraint to this object return CreateConstraintToObject( pProp ); } return false; } //----------------------------------------------------------------------------- // Purpose: Handle a collision using our special behavior //----------------------------------------------------------------------------- void CPropStickyBomb::VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ) { // Find out what we hit CBaseEntity *pVictim = pEvent->pEntities[!index]; if ( pVictim == NULL || m_pConstraint != NULL ) { BaseClass::VPhysicsCollision( index, pEvent ); return; } // Attempt to stick to the world if ( pVictim->IsWorld() ) { // Done if we succeeded if ( StickToWorld( index, pEvent ) ) return; // Just bounce BaseClass::VPhysicsCollision( index, pEvent ); return; } // Attempt to stick to an entity if ( StickToEntity( index, pEvent ) ) return; // Just bounce BaseClass::VPhysicsCollision( index, pEvent ); }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 5821 | Knut Wikstrom |
Added Valve Source code. This is NOT to be commited to other than new code from Valve. |