void CPlayerPickupController::Init( CBasePlayer *pPlayer, CBaseEntity *pObject ) { m_pPlayer = pPlayer; IPhysicsObject *pPhysics = pObject->VPhysicsGetObject(); Vector position; QAngle angles; pPhysics->GetPosition( &position, &angles ); m_grabController.SetMaxImpulse( Vector(20*100,20*100,20*100), AngularImpulse(20*180,20*180,20*180) ); m_grabController.AttachEntity( pObject, pPhysics, position, angles ); // Holster player's weapon if ( m_pPlayer->GetActiveWeapon() ) { if ( !m_pPlayer->GetActiveWeapon()->Holster() ) { Shutdown(); return; } } m_pPlayer->m_Local.m_iHideHUD |= HIDEHUD_WEAPONS; m_pPlayer->SetUseEntity( this ); matrix3x4_t tmp; ComputePlayerMatrix( tmp ); VectorITransform( position, tmp, m_positionPlayerSpace ); // UNDONE: This algorithm needs a bit more thought. REVISIT. // put the bottom of the object arms' length below eye level // get bottommost point of object Vector bottom = physcollision->CollideGetExtent( pPhysics->GetCollide(), vec3_origin, angles, Vector(0,0,-1) ); // get the real eye origin Vector playerEye = pPlayer->EyePosition(); // move target up so that bottom of object is at PLAYER_HOLD_LEVEL z in local space // float delta = PLAYER_HOLD_LEVEL_EYES - bottom.z - m_positionPlayerSpace.z; float delta = 0; // player can reach down 2ft below his feet float maxPickup = (playerEye.z + PLAYER_HOLD_LEVEL_EYES) - (pPlayer->GetAbsMins().z - PLAYER_REACH_DOWN_DISTANCE); delta = clamp( delta, pPlayer->WorldAlignMins().z, maxPickup ); m_positionPlayerSpace.z += delta; m_anglesPlayerSpace = TransformAnglesToLocalSpace( angles, tmp ); m_anglesPlayerSpace = AlignAngles( m_anglesPlayerSpace, DOT_30DEGREE ); // re-transform and check angles = TransformAnglesToWorldSpace( m_anglesPlayerSpace, tmp ); VectorTransform( m_positionPlayerSpace, tmp, position ); // hackhack: Move up to eye position for the check float saveZ = position.z; position.z = playerEye.z; CheckObjectPosition( position, angles, position ); // move back to original position position.z = saveZ; VectorITransform( position, tmp, m_positionPlayerSpace ); }
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 ); }