void CWeaponGravityGun::AttachObject( CBaseEntity *pObject, const Vector& start, const Vector &end, float distance ) { CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); if( !pOwner ) return; m_hObject = pObject; m_useDown = false; IPhysicsObject *pPhysics = pObject ? (pObject->VPhysicsGetObject()) : NULL; if ( pPhysics && pObject->GetMoveType() == MOVETYPE_VPHYSICS ) { m_distance = distance; Vector worldPosition; pObject->WorldToEntitySpace( end, &worldPosition ); m_worldPosition = worldPosition; m_gravCallback.AttachEntity( pOwner, pObject, pPhysics, pObject->GetAbsOrigin() ); m_originalObjectPosition = pObject->GetAbsOrigin(); pPhysics->Wake(); PhysSetGameFlags( pPhysics, FVPHYSICS_PLAYER_HELD ); #ifndef CLIENT_DLL Pickup_OnPhysGunPickup( pObject, pOwner ); #endif } else { m_hObject = NULL; } }
void CWeaponGravityGun::AttachObject( CBaseEntity *pObject, const Vector& start, const Vector &end, float distance ) { m_hObject = pObject; m_useDown = false; IPhysicsObject *pPhysics = pObject ? (pObject->VPhysicsGetObject()) : NULL; if ( pPhysics && pObject->GetMoveType() == MOVETYPE_VPHYSICS ) { m_distance = distance; m_gravCallback.AttachEntity( pObject, pPhysics, end ); float mass = pPhysics->GetMass(); Msg( "Object mass: %.2f lbs (%.2f kg)\n", kg2lbs(mass), mass ); float vel = phys_gunvel.GetFloat(); if ( mass > phys_gunmass.GetFloat() ) { vel = (vel*phys_gunmass.GetFloat())/mass; } m_gravCallback.SetMaxVelocity( vel ); // Msg( "Object mass: %.2f lbs (%.2f kg) %f %f %f\n", kg2lbs(mass), mass, pObject->GetAbsOrigin().x, pObject->GetAbsOrigin().y, pObject->GetAbsOrigin().z ); // Msg( "ANG: %f %f %f\n", pObject->GetAbsAngles().x, pObject->GetAbsAngles().y, pObject->GetAbsAngles().z ); m_originalObjectPosition = pObject->GetAbsOrigin(); m_pelletAttract = -1; m_pelletHeld = -1; pPhysics->Wake(); SortPelletsForObject( pObject ); CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); if( pOwner ) { Pickup_OnPhysGunPickup( pObject, pOwner ); } } else { m_hObject = NULL; } }
void CWeaponGravityGun::UpdateObject( void ) { CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); Assert( pPlayer ); CBaseEntity *pObject = m_hObject; if ( !pObject ) return; if ( !m_gravCallback.UpdateObject( pPlayer, pObject ) ) { DetachObject(); return; } }
void CWeaponGravityGun::DetachObject( void ) { m_pelletHeld = -1; m_pelletAttract = -1; m_glueTouching = false; SetObjectPelletsColor( 255, 0, 0 ); m_objectPelletCount = 0; if ( m_hObject ) { CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); Pickup_OnPhysGunDrop( m_hObject, pOwner, DROPPED_BY_CANNON ); m_gravCallback.DetachEntity(); m_hObject = NULL; } }
void CWeaponGravityGun::DetachObject( void ) { if ( m_hObject ) { #ifndef CLIENT_DLL CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); Pickup_OnPhysGunDrop( m_hObject, pOwner, DROPPED_BY_CANNON ); #endif IPhysicsObject *pPhysics = m_hObject->VPhysicsGetObject(); if ( pPhysics ) { PhysClearGameFlags( pPhysics, FVPHYSICS_PLAYER_HELD ); } m_gravCallback.DetachEntity(); m_hObject = NULL; } }
void CWeaponGravityGun::DetachObject( void ) { if ( m_hObject ) { #ifndef CLIENT_DLL CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); Pickup_OnPhysGunDrop( m_hObject, pOwner, DROPPED_BY_CANNON ); #endif IPhysicsObject *pList[VPHYSICS_MAX_OBJECT_LIST_COUNT]; int count = m_hObject->VPhysicsGetObjectList( pList, ARRAYSIZE(pList) ); for ( int i = 0; i < count; i++ ) { PhysClearGameFlags( pList[i], FVPHYSICS_PLAYER_HELD ); } m_gravCallback.DetachEntity(); m_hObject = NULL; m_physicsBone = 0; } }
void CWeaponGravityGun::AttachObject( CBaseEntity *pObject, IPhysicsObject *pPhysics, short physicsbone, const Vector& start, const Vector &end, float distance ) { CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); if( !pOwner ) return; m_hObject = pObject; m_physicsBone = physicsbone; m_useDown = false; if ( pPhysics && pObject->GetMoveType() == MOVETYPE_VPHYSICS ) { m_distance = distance; Vector worldPosition; pPhysics->WorldToLocal( &worldPosition, end ); m_worldPosition = worldPosition; Vector vecOrigin; pPhysics->GetPosition( &vecOrigin, NULL ); m_gravCallback.AttachEntity( pOwner, pObject, pPhysics, physicsbone, vecOrigin ); m_originalObjectPosition = vecOrigin; pPhysics->Wake(); IPhysicsObject *pList[VPHYSICS_MAX_OBJECT_LIST_COUNT]; int count = pObject->VPhysicsGetObjectList( pList, ARRAYSIZE(pList) ); for ( int i = 0; i < count; i++ ) { PhysSetGameFlags( pList[i], FVPHYSICS_PLAYER_HELD ); } #ifndef CLIENT_DLL Pickup_OnPhysGunPickup( pObject, pOwner ); #endif } else { m_hObject = NULL; m_physicsBone = 0; } }
void CWeaponGravityGun::EffectUpdate( void ) { Vector start, angles, forward, right; trace_t tr; CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); if ( !pOwner ) return; m_viewModelIndex = pOwner->entindex(); // Make sure I've got a view model CBaseViewModel *vm = pOwner->GetViewModel(); if ( vm ) { m_viewModelIndex = vm->entindex(); } pOwner->EyeVectors( &forward, &right, NULL ); start = pOwner->Weapon_ShootPosition(); Vector end = start + forward * 4096; UTIL_TraceLine( start, end, MASK_SHOT, pOwner, COLLISION_GROUP_NONE, &tr ); end = tr.endpos; float distance = tr.fraction * 4096; if ( tr.fraction != 1 ) { // too close to the player, drop the object if ( distance < 36 ) { DetachObject(); return; } } if ( m_hObject == NULL && tr.DidHitNonWorldEntity() ) { CBaseEntity *pEntity = tr.m_pEnt; // inform the object what was hit ClearMultiDamage(); pEntity->DispatchTraceAttack( CTakeDamageInfo( pOwner, pOwner, 0, DMG_PHYSGUN ), forward, &tr ); ApplyMultiDamage(); AttachObject( pEntity, start, tr.endpos, distance ); m_lastYaw = pOwner->EyeAngles().y; } // Add the incremental player yaw to the target transform matrix3x4_t curMatrix, incMatrix, nextMatrix; QAngle ang(0.0f, pOwner->EyeAngles().y - m_lastYaw, 0.0f); AngleMatrix( m_gravCallback.m_targetRotation, curMatrix ); AngleMatrix( ang, incMatrix ); ConcatTransforms( incMatrix, curMatrix, nextMatrix ); MatrixAngles( nextMatrix, m_gravCallback.m_targetRotation ); m_lastYaw = pOwner->EyeAngles().y; CBaseEntity *pObject = m_hObject; if ( pObject ) { if ( m_useDown ) { if ( pOwner->m_afButtonPressed & IN_USE ) { m_useDown = false; } } else { if ( pOwner->m_afButtonPressed & IN_USE ) { m_useDown = true; } } if ( m_useDown ) { pOwner->SetPhysicsFlag( PFLAG_DIROVERRIDE, true ); if ( pOwner->m_nButtons & IN_FORWARD ) { m_distance = UTIL_Approach( 1024, m_distance, gpGlobals->frametime * 100 ); } if ( pOwner->m_nButtons & IN_BACK ) { m_distance = UTIL_Approach( 40, m_distance, gpGlobals->frametime * 100 ); } } if ( pOwner->m_nButtons & IN_WEAPON1 ) { m_distance = UTIL_Approach( 1024, m_distance, m_distance * 0.1 ); } if ( pOwner->m_nButtons & IN_WEAPON2 ) { m_distance = UTIL_Approach( 40, m_distance, m_distance * 0.1 ); } // Send the object a physics damage message (0 damage). Some objects interpret this // as something else being in control of their physics temporarily. pObject->TakeDamage( CTakeDamageInfo( this, pOwner, 0, DMG_PHYSGUN ) ); Vector newPosition = start + forward * m_distance; // 24 is a little larger than 16 * sqrt(2) (extent of player bbox) // HACKHACK: We do this so we can "ignore" the player and the object we're manipulating // If we had a filter for tracelines, we could simply filter both ents and start from "start" Vector awayfromPlayer = start + forward * 24; UTIL_TraceLine( start, awayfromPlayer, MASK_SOLID, pOwner, COLLISION_GROUP_NONE, &tr ); if ( tr.fraction == 1 ) { UTIL_TraceLine( awayfromPlayer, newPosition, MASK_SOLID, pObject, COLLISION_GROUP_NONE, &tr ); Vector dir = tr.endpos - newPosition; float distance = VectorNormalize(dir); float maxDist = m_gravCallback.m_maxVel * gpGlobals->frametime; if ( distance > maxDist ) { newPosition += dir * maxDist; } else { newPosition = tr.endpos; } } else { newPosition = tr.endpos; } CreatePelletAttraction( phys_gunglueradius.GetFloat(), pObject ); // If I'm looking more than 20 degrees away from the glue point, then give up // This lets the player "gesture" for the glue to let go. Vector pelletDir = m_gravCallback.m_worldPosition - start; VectorNormalize(pelletDir); if ( DotProduct( pelletDir, forward ) < 0.939 ) // 0.939 ~= cos(20deg) { // lose attach for 2 seconds if you're too far away m_glueTime = gpGlobals->curtime + 1; } if ( m_pelletHeld >= 0 && gpGlobals->curtime > m_glueTime ) { CGravityPellet *pPelletAttract = m_activePellets[m_pelletAttract].pellet; g_pEffects->Sparks( pPelletAttract->GetAbsOrigin() ); } m_gravCallback.SetTargetPosition( newPosition ); Vector dir = (newPosition - pObject->GetLocalOrigin()); m_movementLength = dir.Length(); } else { m_gravCallback.SetTargetPosition( end ); } if ( m_pelletHeld >= 0 && gpGlobals->curtime > m_glueTime ) { Vector worldNormal, worldPos; GetPelletWorldCoords( m_pelletAttract, &worldPos, &worldNormal ); m_gravCallback.SetAutoAlign( m_activePellets[m_pelletHeld].localNormal, m_activePellets[m_pelletHeld].pellet->GetLocalOrigin(), worldNormal, worldPos ); } else { m_gravCallback.ClearAutoAlign(); } }
void CWeaponGravityGun::EffectUpdate( void ) { Vector start, forward, right; trace_t tr; CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); if ( !pOwner ) return; pOwner->EyeVectors( &forward, &right, NULL ); start = pOwner->Weapon_ShootPosition(); TraceLine( &tr ); Vector end = tr.endpos; float distance = tr.fraction * 4096; if ( m_hObject == NULL && tr.DidHitNonWorldEntity() ) { CBaseEntity *pEntity = tr.m_pEnt; AttachObject( pEntity, GetPhysObjFromPhysicsBone( pEntity, tr.physicsbone ), tr.physicsbone, start, tr.endpos, distance ); } // Add the incremental player yaw to the target transform QAngle angles = m_gravCallback.TransformAnglesFromPlayerSpace( m_gravCallback.m_targetRotation, pOwner ); CBaseEntity *pObject = m_hObject; if ( pObject ) { if ( m_useDown ) { if ( pOwner->m_afButtonPressed & IN_USE ) { m_useDown = false; } } else { if ( pOwner->m_afButtonPressed & IN_USE ) { m_useDown = true; } } if ( m_useDown ) { #ifndef CLIENT_DLL pOwner->SetPhysicsFlag( PFLAG_DIROVERRIDE, true ); #endif if ( pOwner->m_nButtons & IN_FORWARD ) { m_distance = Approach( 1024, m_distance, gpGlobals->frametime * 100 ); } if ( pOwner->m_nButtons & IN_BACK ) { m_distance = Approach( 40, m_distance, gpGlobals->frametime * 100 ); } } if ( pOwner->m_nButtons & IN_WEAPON1 ) { m_distance = Approach( 1024, m_distance, m_distance * 0.1 ); } if ( pOwner->m_nButtons & IN_WEAPON2 ) { m_distance = Approach( 40, m_distance, m_distance * 0.1 ); } IPhysicsObject *pPhys = GetPhysObjFromPhysicsBone( pObject, m_physicsBone ); if ( pPhys ) { if ( pPhys->IsAsleep() ) { // on the odd chance that it's gone to sleep while under anti-gravity pPhys->Wake(); } Vector newPosition = start + forward * m_distance; Vector offset; pPhys->LocalToWorld( &offset, m_worldPosition ); Vector vecOrigin; pPhys->GetPosition( &vecOrigin, NULL ); m_gravCallback.SetTargetPosition( newPosition + (vecOrigin - offset), angles ); Vector dir = (newPosition - pObject->GetLocalOrigin()); m_movementLength = dir.Length(); } } else { m_targetPosition = end; //m_gravCallback.SetTargetPosition( end, m_gravCallback.m_targetRotation ); } }
void CWeaponGravityGun::EffectUpdate( void ) { Vector start, forward, right; trace_t tr; CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); if ( !pOwner ) return; pOwner->EyeVectors( &forward, &right, NULL ); start = pOwner->Weapon_ShootPosition(); TraceLine( &tr ); Vector end = tr.endpos; float distance = tr.fraction * 4096; if ( tr.fraction != 1 ) { // too close to the player, drop the object if ( distance < 36 ) { DetachObject(); return; } } if ( m_hObject == NULL && tr.DidHitNonWorldEntity() ) { CBaseEntity *pEntity = tr.m_pEnt; AttachObject( pEntity, start, tr.endpos, distance ); m_lastYaw = pOwner->EyeAngles().y; } // Add the incremental player yaw to the target transform matrix3x4_t curMatrix, incMatrix, nextMatrix; AngleMatrix( m_gravCallback.m_targetRotation, curMatrix ); AngleMatrix( QAngle(0,pOwner->EyeAngles().y - m_lastYaw,0), incMatrix ); ConcatTransforms( incMatrix, curMatrix, nextMatrix ); MatrixAngles( nextMatrix, m_gravCallback.m_targetRotation ); m_lastYaw = pOwner->EyeAngles().y; CBaseEntity *pObject = m_hObject; if ( pObject ) { if ( m_useDown ) { if ( pOwner->m_afButtonPressed & IN_USE ) { m_useDown = false; } } else { if ( pOwner->m_afButtonPressed & IN_USE ) { m_useDown = true; } } if ( m_useDown ) { #ifndef CLIENT_DLL pOwner->SetPhysicsFlag( PFLAG_DIROVERRIDE, true ); #endif if ( pOwner->m_nButtons & IN_FORWARD ) { m_distance = Approach( 1024, m_distance, gpGlobals->frametime * 100 ); } if ( pOwner->m_nButtons & IN_BACK ) { m_distance = Approach( 40, m_distance, gpGlobals->frametime * 100 ); } } if ( pOwner->m_nButtons & IN_WEAPON1 ) { m_distance = Approach( 1024, m_distance, m_distance * 0.1 ); #ifdef CLIENT_DLL if ( gpGlobals->maxClients > 1 ) { gHUD.m_bSkipClear = false; } #endif } if ( pOwner->m_nButtons & IN_WEAPON2 ) { m_distance = Approach( 40, m_distance, m_distance * 0.1 ); #ifdef CLIENT_DLL if ( gpGlobals->maxClients > 1 ) { gHUD.m_bSkipClear = false; } #endif } IPhysicsObject *pPhys = pObject->VPhysicsGetObject(); if ( pPhys && pPhys->IsAsleep() ) { // on the odd chance that it's gone to sleep while under anti-gravity pPhys->Wake(); } Vector newPosition = start + forward * m_distance; Vector offset; pObject->EntityToWorldSpace( m_worldPosition, &offset ); m_gravCallback.SetTargetPosition( newPosition + (pObject->GetAbsOrigin() - offset), m_gravCallback.m_targetRotation ); Vector dir = (newPosition - pObject->GetLocalOrigin()); m_movementLength = dir.Length(); } else { m_targetPosition = end; //m_gravCallback.SetTargetPosition( end, m_gravCallback.m_targetRotation ); } }