void RestoreBlock( IRestore *pRestore, const PhysObjectHeader_t &header ) { CBaseEntity * pOwner = header.hEntity.Get(); unsigned short iQueued = m_QueuedRestores.Find( pOwner ); if ( iQueued != m_QueuedRestores.InvalidIndex() ) { MDLCACHE_CRITICAL_SECTION(); if ( pOwner->ShouldSavePhysics() && header.nObjects > 0 ) { QueuedItem_t *pItem = m_QueuedRestores[iQueued]->FindItem( header.fieldName ); if ( pItem ) { int nObjects = MIN( header.nObjects, pItem->header.nObjects ); if ( pItem->header.type == PIID_IPHYSICSOBJECT && nObjects == 1 ) { RestorePhysicsObjectAndModel( pRestore, header, pItem, nObjects ); } else { void **ppPhysObj = pItem->ppPhysObj; for ( int i = 0; i < nObjects; i++ ) { pRestore->StartBlock(); RestorePhysicsObject( pRestore, header, ppPhysObj + i ); pRestore->EndBlock(); if ( header.type == PIID_IPHYSICSMOTIONCONTROLLER ) { void *pObj = ppPhysObj[i]; IPhysicsMotionController *pController = (IPhysicsMotionController *)pObj; if ( pController ) { // If the entity is the motion callback handler, then automatically set it // NOTE: This is usually the case IMotionEvent *pEvent = dynamic_cast<IMotionEvent *>(pOwner); if ( pEvent ) { pController->SetEventHandler( pEvent ); } } } } } } } else pOwner->CreateVPhysics(); } }
void CGrabController::OnRestore() { if ( m_controller ) { m_controller->SetEventHandler( this ); } }
void CGravControllerPoint::AttachEntity( CBasePlayer *pPlayer, CBaseEntity *pEntity, IPhysicsObject *pPhys, short physicsbone, const Vector &vGrabPosition ) { m_attachedEntity = pEntity; m_attachedPhysicsBone = physicsbone; pPhys->WorldToLocal( &m_localPosition, vGrabPosition ); m_worldPosition = vGrabPosition; pPhys->GetDamping( NULL, &m_saveDamping ); m_saveMass = pPhys->GetMass(); float damping = 2; pPhys->SetDamping( NULL, &damping ); pPhys->SetMass( 50000 ); m_controller = physenv->CreateMotionController( this ); m_controller->AttachObject( pPhys, true ); Vector position; QAngle angles; pPhys->GetPosition( &position, &angles ); SetTargetPosition( vGrabPosition, angles ); m_targetRotation = TransformAnglesToPlayerSpace( angles, pPlayer ); #ifdef ARGG // adnan // we need to grab the preferred/non preferred carry angles here for the rotatedcarryangles m_vecRotatedCarryAngles = m_targetRotation; // end adnan #endif }
void CPhysForce::ScaleForce( float scale ) { if ( !m_pController ) ForceOn(); m_integrator.ScaleConstantForce( scale ); m_pController->WakeObjects(); }
void CGravControllerPoint::AttachEntity( CBaseEntity *pEntity, IPhysicsObject *pPhys, const Vector &position ) { m_attachedEntity = pEntity; pPhys->WorldToLocal( &m_localPosition, position ); m_worldPosition = position; pPhys->GetDamping( NULL, &m_saveDamping ); float damping = 2; pPhys->SetDamping( NULL, &damping ); m_controller = physenv->CreateMotionController( this ); m_controller->AttachObject( pPhys, true ); m_controller->SetPriority( IPhysicsMotionController::HIGH_PRIORITY ); SetTargetPosition( position ); m_maxAcceleration = phys_gunforce.GetFloat() * pPhys->GetInvMass(); m_targetRotation = pEntity->GetAbsAngles(); float torque = phys_guntorque.GetFloat(); m_maxAngularAcceleration = torque * pPhys->GetInvInertia(); }
void CPhysForce::OnRestore( ) { BaseClass::OnRestore(); if ( m_pController ) { m_pController->SetEventHandler( &m_integrator ); } }
//----------------------------------------------------------------------------- // Purpose: Restore the motion controller //----------------------------------------------------------------------------- void CASWEnvShake::OnRestore( void ) { BaseClass::OnRestore(); if ( m_pShakeController ) { m_pShakeController->SetEventHandler( &m_shakeCallback ); } }
void CPhysicsNPCSolver::BecomePenetrationSolver() { CBaseEntity *pEntity = m_hEntity.Get(); if ( pEntity ) { m_allowIntersection = true; IPhysicsObject *pList[VPHYSICS_MAX_OBJECT_LIST_COUNT]; int listCount = pEntity->VPhysicsGetObjectList( pList, ARRAYSIZE(pList) ); PhysDisableEntityCollisions( m_hNPC, pEntity ); m_pController = physenv->CreateMotionController( this ); for ( int i = 0; i < listCount; i++ ) { m_pController->AttachObject( pList[i], false ); pList[i]->Wake(); } m_pController->SetPriority( IPhysicsMotionController::HIGH_PRIORITY ); } }
//----------------------------------------------------------------------------- // Purpose: Calculates the physics shake values //----------------------------------------------------------------------------- void CASWEnvShake::Think( void ) { int i; if ( gpGlobals->curtime > m_nextShake ) { // Higher frequency means we recalc the extents more often and perturb the display again m_nextShake = gpGlobals->curtime + (1.0f / Frequency()); // Compute random shake extents (the shake will settle down from this) for (i = 0; i < 2; i++ ) { m_maxForce[i] = random->RandomFloat( -1, 1 ); } // make the force it point mostly up m_maxForce.z = 4; VectorNormalize( m_maxForce ); m_maxForce *= m_currentAmp * 400; // amplitude is the acceleration of a 100kg object } float fraction = ( m_stopTime - gpGlobals->curtime ) / Duration(); if ( fraction < 0 ) { m_pShakeController->ClearObjects(); return; } float freq = 0; // Ramp up frequency over duration if ( fraction ) { freq = (Frequency() / fraction); } // square fraction to approach zero more quickly fraction *= fraction; // Sine wave that slowly settles to zero fraction = fraction * sin( gpGlobals->curtime * freq ); // Add to view origin for ( i = 0; i < 3; i++ ) { // store the force in the controller callback m_shakeCallback.m_force[i] = m_maxForce[i] * fraction; } // Drop amplitude a bit, less for higher frequency shakes m_currentAmp -= m_currentAmp * ( gpGlobals->frametime / (Duration() * Frequency()) ); SetNextThink( gpGlobals->curtime ); }
void CGravControllerPoint::AttachEntity( CBasePlayer *pPlayer, CBaseEntity *pEntity, IPhysicsObject *pPhys, const Vector &vGrabPosition ) { m_attachedEntity = pEntity; pPhys->WorldToLocal( &m_localPosition, vGrabPosition ); m_worldPosition = vGrabPosition; pPhys->GetDamping( NULL, &m_saveDamping ); m_saveMass = pPhys->GetMass(); float damping = 2; pPhys->SetDamping( NULL, &damping ); pPhys->SetMass( 50000 ); m_controller = physenv->CreateMotionController( this ); m_controller->AttachObject( pPhys, true ); Vector position; QAngle angles; pPhys->GetPosition( &position, &angles ); SetTargetPosition( vGrabPosition, angles ); m_targetRotation = angles; }
void CPhysForce::ActivateForce( void ) { BaseClass::Activate(); IPhysicsObject *pPhys = NULL; if ( m_attachedObject ) { pPhys = m_attachedObject->VPhysicsGetObject(); } if ( !pPhys ) return; Vector linear; AngularImpulse angular; SetupForces( pPhys, linear, angular ); m_integrator.SetConstantForce( linear, angular ); m_pController = physenv->CreateMotionController( &m_integrator ); m_pController->AttachObject( pPhys ); // Make sure the object is simulated pPhys->Wake(); }
void CPhysMotor::Activate( void ) { BaseClass::Activate(); // This gets called after all objects spawn and after all objects restore if ( m_attachedObject == NULL ) { CBaseEntity *pAttach = gEntList.FindEntityByName( NULL, m_nameAttach, NULL ); if ( pAttach && pAttach->GetMoveType() == MOVETYPE_VPHYSICS ) { m_attachedObject = pAttach; IPhysicsObject *pPhys = m_attachedObject->VPhysicsGetObject(); CalculateAcceleration(); matrix3x4_t matrix; pPhys->GetPositionMatrix( matrix ); Vector motorAxis_ls; VectorIRotate( m_motor.m_axis, matrix, motorAxis_ls ); float inertia = DotProductAbs( pPhys->GetInertia(), motorAxis_ls ); m_motor.m_maxTorque = inertia * m_motor.m_inertiaFactor * (m_angularAcceleration + m_additionalAcceleration); m_motor.m_restistanceDamping = 1.0f; } } if ( m_attachedObject ) { IPhysicsObject *pPhys = m_attachedObject->VPhysicsGetObject(); // create a hinge constraint for this object? if ( m_spawnflags & SF_MOTOR_HINGE ) { // UNDONE: Don't do this on restore? if ( !m_pHinge ) { constraint_hingeparams_t hingeParams; hingeParams.Defaults(); hingeParams.worldAxisDirection = m_motor.m_axis; hingeParams.worldPosition = GetLocalOrigin(); m_pHinge = physenv->CreateHingeConstraint( g_PhysWorldObject, pPhys, NULL, hingeParams ); m_pHinge->SetGameData( (void *)this ); } if ( m_spawnflags & SF_MOTOR_NOCOLLIDE ) { physenv->DisableCollisions( pPhys, g_PhysWorldObject ); } } else { m_pHinge = NULL; } // NOTE: On restore, this path isn't run because m_pController will not be NULL if ( !m_pController ) { m_pController = physenv->CreateMotionController( &m_motor ); m_pController->AttachObject( m_attachedObject->VPhysicsGetObject() ); if ( m_spawnflags & SF_MOTOR_START_ON ) { TurnOn(); } } } // Need to do this on restore since there's no good way to save this if ( m_pController ) { m_pController->SetEventHandler( &m_motor ); } }
void CPhysMotor::TargetSpeedChanged( void ) { SetNextThink( gpGlobals->curtime ); m_lastTime = gpGlobals->curtime; m_pController->WakeObjects(); }
void CGrabController::AttachEntity( CBasePlayer *pPlayer, CBaseEntity *pEntity, IPhysicsObject *pPhys, bool bIsMegaPhysCannon, const Vector &vGrabPosition, bool bUseGrabPosition ) { // play the impact sound of the object hitting the player // used as feedback to let the player know he picked up the object int hitMaterial = pPhys->GetMaterialIndex(); int playerMaterial = pPlayer->VPhysicsGetObject() ? pPlayer->VPhysicsGetObject()->GetMaterialIndex() : hitMaterial; PhysicsImpactSound( pPlayer, pPhys, CHAN_STATIC, hitMaterial, playerMaterial, 1.0, 64 ); Vector position; QAngle angles; pPhys->GetPosition( &position, &angles ); // If it has a preferred orientation, use that instead. Pickup_GetPreferredCarryAngles( pEntity, pPlayer, pPlayer->EntityToWorldTransform(), angles ); // ComputeMaxSpeed( pEntity, pPhys ); // If we haven't been killed by a grab, we allow the gun to grab the nearest part of a ragdoll if ( bUseGrabPosition ) { IPhysicsObject *pChild = GetRagdollChildAtPosition( pEntity, vGrabPosition ); if ( pChild ) { pPhys = pChild; } } // Carried entities can never block LOS m_bCarriedEntityBlocksLOS = pEntity->BlocksLOS(); pEntity->SetBlocksLOS( false ); m_controller = physenv->CreateMotionController( this ); m_controller->AttachObject( pPhys, true ); // Don't do this, it's causing trouble with constraint solvers. //m_controller->SetPriority( IPhysicsMotionController::HIGH_PRIORITY ); pPhys->Wake(); PhysSetGameFlags( pPhys, FVPHYSICS_PLAYER_HELD ); SetTargetPosition( position, angles ); m_attachedEntity = pEntity; IPhysicsObject *pList[VPHYSICS_MAX_OBJECT_LIST_COUNT]; int count = pEntity->VPhysicsGetObjectList( pList, ARRAYSIZE(pList) ); m_flLoadWeight = 0; float damping = 10; float flFactor = count / 7.5f; if ( flFactor < 1.0f ) { flFactor = 1.0f; } for ( int i = 0; i < count; i++ ) { float mass = pList[i]->GetMass(); pList[i]->GetDamping( NULL, &m_savedRotDamping[i] ); m_flLoadWeight += mass; m_savedMass[i] = mass; // reduce the mass to prevent the player from adding crazy amounts of energy to the system pList[i]->SetMass( REDUCED_CARRY_MASS / flFactor ); pList[i]->SetDamping( NULL, &damping ); } // Give extra mass to the phys object we're actually picking up pPhys->SetMass( REDUCED_CARRY_MASS ); pPhys->EnableDrag( false ); m_errorTime = bIsMegaPhysCannon ? -1.5f : -1.0f; // 1 seconds until error starts accumulating m_error = 0; m_contactAmount = 0; m_attachedAnglesPlayerSpace = TransformAnglesToPlayerSpace( angles, pPlayer ); if ( m_angleAlignment != 0 ) { m_attachedAnglesPlayerSpace = AlignAngles( m_attachedAnglesPlayerSpace, m_angleAlignment ); } // Ragdolls don't offset this way if ( dynamic_cast<CRagdollProp*>(pEntity) ) { m_attachedPositionObjectSpace.Init(); } else { VectorITransform( pEntity->WorldSpaceCenter(), pEntity->EntityToWorldTransform(), m_attachedPositionObjectSpace ); } // If it's a prop, see if it has desired carry angles CPhysicsProp *pProp = dynamic_cast<CPhysicsProp *>(pEntity); if ( pProp ) { m_bHasPreferredCarryAngles = pProp->GetPropDataAngles( "preferred_carryangles", m_vecPreferredCarryAngles ); m_flDistanceOffset = pProp->GetCarryDistanceOffset(); } else { m_bHasPreferredCarryAngles = false; m_flDistanceOffset = 0; } m_bAllowObjectOverhead = IsObjectAllowedOverhead( pEntity ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CASWEnvShake::ApplyShake( ShakeCommand_t command ) { if ( !HasSpawnFlags( SF_ASW_SHAKE_NO_VIEW ) ) { bool air = (GetSpawnFlags() & SF_ASW_SHAKE_INAIR) ? true : false; UTIL_ASW_ScreenShake( GetAbsOrigin(), Amplitude(), Frequency(), Duration(), Radius(), command, air ); } if ( GetSpawnFlags() & SF_ASW_SHAKE_ROPES ) { CRopeKeyframe::ShakeRopes( GetAbsOrigin(), Radius(), Frequency() ); } if ( GetSpawnFlags() & SF_ASW_SHAKE_PHYSICS ) { if ( !m_pShakeController ) { m_pShakeController = physenv->CreateMotionController( &m_shakeCallback ); } // do physics shake switch( command ) { case SHAKE_START: { m_stopTime = gpGlobals->curtime + Duration(); m_nextShake = 0; m_pShakeController->ClearObjects(); SetNextThink( gpGlobals->curtime ); m_currentAmp = Amplitude(); CBaseEntity *list[1024]; float radius = Radius(); // probably checked "Shake Everywhere" do a big radius if ( !radius ) { radius = MAX_COORD_INTEGER; } Vector extents = Vector(radius, radius, radius); Vector mins = GetAbsOrigin() - extents; Vector maxs = GetAbsOrigin() + extents; int count = UTIL_EntitiesInBox( list, 1024, mins, maxs, 0 ); for ( int i = 0; i < count; i++ ) { // // Only shake physics entities that players can see. This is one frame out of date // so it's possible that we could miss objects if a player changed PVS this frame. // if ( ( list[i]->GetMoveType() == MOVETYPE_VPHYSICS ) ) { IPhysicsObject *pPhys = list[i]->VPhysicsGetObject(); if ( pPhys && pPhys->IsMoveable() ) { m_pShakeController->AttachObject( pPhys, false ); pPhys->Wake(); } } } } break; case SHAKE_STOP: m_pShakeController->ClearObjects(); break; case SHAKE_AMPLITUDE: m_currentAmp = Amplitude(); case SHAKE_FREQUENCY: m_pShakeController->WakeObjects(); break; } } }