void CStructure::PostSetLocalTransform(const TMatrix& m) { BaseClass::PostSetLocalTransform(m); CPlanet* pPlanet = GameData().GetPlanet(); if (!pPlanet) return; if (!pPlanet->GetChunkManager()->HasGroupCenter()) return; TMatrix mLocalTransform = m; CBaseEntity* pMoveParent = GetMoveParent(); if (pMoveParent) { while (pMoveParent != pPlanet) { mLocalTransform = pMoveParent->GetLocalTransform() * mLocalTransform; pMoveParent = pMoveParent->GetMoveParent(); } } else mLocalTransform = pPlanet->GetGlobalToLocalTransform() * m; GameData().SetGroupTransform(pPlanet->GetChunkManager()->GetPlanetToGroupCenterTransform() * mLocalTransform.GetMeters()); }
//------------------------------------------------------------------------------ // Purpose: //------------------------------------------------------------------------------ void CPointTeleport::Activate( void ) { CBaseEntity *pTarget = GetNextTarget(); if (pTarget) { if ( pTarget->GetMoveParent() != NULL ) { Warning("ERROR: (%s) can't teleport object (%s) as it has a parent!\n",GetDebugName(),pTarget->GetDebugName()); return; } if (m_spawnflags & SF_TELEPORT_TO_SPAWN_POS) { m_vSaveOrigin = pTarget->GetAbsOrigin(); m_vSaveAngles = pTarget->GetAbsAngles(); } else { m_vSaveOrigin = GetAbsOrigin(); m_vSaveAngles = GetAbsAngles(); } } else { Warning("ERROR: (%s) given no target. Deleting.\n",GetDebugName()); UTIL_Remove(this); return; } BaseClass::Activate(); }
void CStructure::SetPhysicsTransform(const Matrix4x4& m) { CPlanet* pPlanet = GameData().GetPlanet(); if (!pPlanet) { SetLocalTransform(TMatrix(m)); return; } if (!pPlanet->GetChunkManager()->HasGroupCenter()) { SetLocalTransform(TMatrix(m)); return; } GameData().SetGroupTransform(m); TMatrix mLocalTransform(pPlanet->GetChunkManager()->GetGroupCenterToPlanetTransform() * m); CBaseEntity* pMoveParent = GetMoveParent(); TAssert(pMoveParent); if (pMoveParent) { while (pMoveParent != pPlanet) { mLocalTransform = pMoveParent->GetLocalTransform().InvertedRT() * mLocalTransform; pMoveParent = pMoveParent->GetMoveParent(); } } SetLocalTransform(mLocalTransform); }
//------------------------------------------------------------------------------ // Purpose: //------------------------------------------------------------------------------ void CPointTeleport::InputTeleport( inputdata_t &inputdata ) { CBaseEntity *pTarget = GetNextTarget(); if (pTarget) { // If teleport object is in a movement hierarchy, remove it first if ( pTarget->GetMoveParent() != NULL ) { Warning("ERROR: (%s) can't teleport object (%s) as it has a parent (%s)!\n",GetDebugName(),pTarget->GetDebugName(),pTarget->GetMoveParent()->GetDebugName()); return; } pTarget->Teleport( &m_vSaveOrigin, &m_vSaveAngles, NULL ); } }
CBaseEntity *CBasePlayer::FindUseEntity() { Vector forward, up; EyeVectors( &forward, NULL, &up ); trace_t tr; // Search for objects in a sphere (tests for entities that are not solid, yet still useable) Vector searchCenter = EyePosition(); // NOTE: Some debris objects are useable too, so hit those as well // A button, etc. can be made out of clip brushes, make sure it's +useable via a traceline, too. int useableContents = MASK_SOLID | CONTENTS_DEBRIS | CONTENTS_PLAYERCLIP; #ifdef CSTRIKE_DLL useableContents = MASK_NPCSOLID_BRUSHONLY | MASK_OPAQUE_AND_NPCS; #endif #ifdef HL1_DLL useableContents = MASK_SOLID; #endif #ifndef CLIENT_DLL CBaseEntity *pFoundByTrace = NULL; #endif // UNDONE: Might be faster to just fold this range into the sphere query CBaseEntity *pObject = NULL; float nearestDist = FLT_MAX; // try the hit entity if there is one, or the ground entity if there isn't. CBaseEntity *pNearest = NULL; const int NUM_TANGENTS = 8; // trace a box at successive angles down // forward, 45 deg, 30 deg, 20 deg, 15 deg, 10 deg, -10, -15 const float tangents[NUM_TANGENTS] = { 0, 1, 0.57735026919f, 0.3639702342f, 0.267949192431f, 0.1763269807f, -0.1763269807f, -0.267949192431f }; for ( int i = 0; i < NUM_TANGENTS; i++ ) { if ( i == 0 ) { UTIL_TraceLine( searchCenter, searchCenter + forward * 1024, useableContents, this, COLLISION_GROUP_NONE, &tr ); } else { Vector down = forward - tangents[i]*up; VectorNormalize(down); UTIL_TraceHull( searchCenter, searchCenter + down * 72, -Vector(16,16,16), Vector(16,16,16), useableContents, this, COLLISION_GROUP_NONE, &tr ); } pObject = tr.m_pEnt; #ifndef CLIENT_DLL pFoundByTrace = pObject; #endif bool bUsable = IsUseableEntity(pObject, 0); while ( pObject && !bUsable && pObject->GetMoveParent() ) { pObject = pObject->GetMoveParent(); bUsable = IsUseableEntity(pObject, 0); } if ( bUsable ) { Vector delta = tr.endpos - tr.startpos; float centerZ = CollisionProp()->WorldSpaceCenter().z; delta.z = IntervalDistance( tr.endpos.z, centerZ + CollisionProp()->OBBMins().z, centerZ + CollisionProp()->OBBMaxs().z ); float dist = delta.Length(); if ( dist < PLAYER_USE_RADIUS ) { #ifndef CLIENT_DLL if ( sv_debug_player_use.GetBool() ) { NDebugOverlay::Line( searchCenter, tr.endpos, 0, 255, 0, true, 30 ); NDebugOverlay::Cross3D( tr.endpos, 16, 0, 255, 0, true, 30 ); } if ( pObject->MyNPCPointer() && pObject->MyNPCPointer()->IsPlayerAlly( this ) ) { // If about to select an NPC, do a more thorough check to ensure // that we're selecting the right one from a group. pObject = DoubleCheckUseNPC( pObject, searchCenter, forward ); } #endif if ( sv_debug_player_use.GetBool() ) { Msg( "Trace using: %s\n", pObject ? pObject->GetDebugName() : "no usable entity found" ); } pNearest = pObject; // if this is directly under the cursor just return it now if ( i == 0 ) return pObject; } } } // check ground entity first // if you've got a useable ground entity, then shrink the cone of this search to 45 degrees // otherwise, search out in a 90 degree cone (hemisphere) if ( GetGroundEntity() && IsUseableEntity(GetGroundEntity(), FCAP_USE_ONGROUND) ) { pNearest = GetGroundEntity(); } if ( pNearest ) { // estimate nearest object by distance from the view vector Vector point; pNearest->CollisionProp()->CalcNearestPoint( searchCenter, &point ); nearestDist = CalcDistanceToLine( point, searchCenter, forward ); if ( sv_debug_player_use.GetBool() ) { Msg("Trace found %s, dist %.2f\n", pNearest->GetClassname(), nearestDist ); } } for ( CEntitySphereQuery sphere( searchCenter, PLAYER_USE_RADIUS ); ( pObject = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() ) { if ( !pObject ) continue; if ( !IsUseableEntity( pObject, FCAP_USE_IN_RADIUS ) ) continue; // see if it's more roughly in front of the player than previous guess Vector point; pObject->CollisionProp()->CalcNearestPoint( searchCenter, &point ); Vector dir = point - searchCenter; VectorNormalize(dir); float dot = DotProduct( dir, forward ); // Need to be looking at the object more or less if ( dot < 0.8 ) continue; float dist = CalcDistanceToLine( point, searchCenter, forward ); if ( sv_debug_player_use.GetBool() ) { Msg("Radius found %s, dist %.2f\n", pObject->GetClassname(), dist ); } if ( dist < nearestDist ) { // Since this has purely been a radius search to this point, we now // make sure the object isn't behind glass or a grate. trace_t trCheckOccluded; UTIL_TraceLine( searchCenter, point, useableContents, this, COLLISION_GROUP_NONE, &trCheckOccluded ); if ( trCheckOccluded.fraction == 1.0 || trCheckOccluded.m_pEnt == pObject ) { pNearest = pObject; nearestDist = dist; } } } #ifndef CLIENT_DLL if ( !pNearest ) { // Haven't found anything near the player to use, nor any NPC's at distance. // Check to see if the player is trying to select an NPC through a rail, fence, or other 'see-though' volume. trace_t trAllies; UTIL_TraceLine( searchCenter, searchCenter + forward * PLAYER_USE_RADIUS, MASK_OPAQUE_AND_NPCS, this, COLLISION_GROUP_NONE, &trAllies ); if ( trAllies.m_pEnt && IsUseableEntity( trAllies.m_pEnt, 0 ) && trAllies.m_pEnt->MyNPCPointer() && trAllies.m_pEnt->MyNPCPointer()->IsPlayerAlly( this ) ) { // This is an NPC, take it! pNearest = trAllies.m_pEnt; } } if ( pNearest && pNearest->MyNPCPointer() && pNearest->MyNPCPointer()->IsPlayerAlly( this ) ) { pNearest = DoubleCheckUseNPC( pNearest, searchCenter, forward ); } if ( sv_debug_player_use.GetBool() ) { if ( !pNearest ) { NDebugOverlay::Line( searchCenter, tr.endpos, 255, 0, 0, true, 30 ); NDebugOverlay::Cross3D( tr.endpos, 16, 255, 0, 0, true, 30 ); } else if ( pNearest == pFoundByTrace ) { NDebugOverlay::Line( searchCenter, tr.endpos, 0, 255, 0, true, 30 ); NDebugOverlay::Cross3D( tr.endpos, 16, 0, 255, 0, true, 30 ); } else { NDebugOverlay::Box( pNearest->WorldSpaceCenter(), Vector(-8, -8, -8), Vector(8, 8, 8), 0, 255, 0, true, 30 ); } } #endif if ( sv_debug_player_use.GetBool() ) { Msg( "Radial using: %s\n", pNearest ? pNearest->GetDebugName() : "no usable entity found" ); } return pNearest; }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void CPointTeleport::Activate( void ) { // Start with our origin point m_vSaveOrigin = GetAbsOrigin(); m_vSaveAngles = GetAbsAngles(); // Save off the spawn position of the target if instructed to do so if ( m_spawnflags & SF_TELEPORT_TO_SPAWN_POS ) { CBaseEntity *pTarget = gEntList.FindEntityByName( NULL, m_target ); if ( pTarget ) { // If teleport object is in a movement hierarchy, remove it first if ( EntityMayTeleport( pTarget ) ) { // Save the points m_vSaveOrigin = pTarget->GetAbsOrigin(); m_vSaveAngles = pTarget->GetAbsAngles(); } else { Warning("ERROR: (%s) can't teleport object (%s) as it has a parent (%s)!\n",GetDebugName(),pTarget->GetDebugName(),pTarget->GetMoveParent()->GetDebugName()); BaseClass::Activate(); return; } } else { Warning("ERROR: (%s) target '%s' not found. Deleting.\n", GetDebugName(), STRING(m_target)); UTIL_Remove( this ); return; } } BaseClass::Activate(); }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void CPointTeleport::DoTeleport( inputdata_t &inputdata, const Vector &vecOrigin, const QAngle &angRotation, bool bOverrideTarget ) { // Attempt to find the entity in question CBaseEntity *pTarget; if( bOverrideTarget ) { // Use the inputdata to find the entity that the designer supplied in the parameter override pTarget = gEntList.FindEntityByName( NULL, inputdata.value.String(), this, inputdata.pActivator, inputdata.pCaller ); } else { // Default behavior: Just find the entity that I am hardwired in Hammer to teleport. pTarget = gEntList.FindEntityByName( NULL, m_target, this, inputdata.pActivator, inputdata.pCaller ); } if ( pTarget == NULL ) return; // If teleport object is in a movement hierarchy, remove it first if ( EntityMayTeleport( pTarget ) == false ) { Warning("ERROR: (%s) can't teleport object (%s) as it has a parent (%s)!\n",GetDebugName(),pTarget->GetDebugName(),pTarget->GetMoveParent()->GetDebugName()); return; } // in episodic, we have a special spawn flag that forces Gordon into a duck #ifdef HL2_EPISODIC if ( (m_spawnflags & SF_TELEPORT_INTO_DUCK) && pTarget->IsPlayer() ) { CBasePlayer *pPlayer = ToBasePlayer( pTarget ); if ( pPlayer != NULL ) { pPlayer->m_nButtons |= IN_DUCK; pPlayer->AddFlag( FL_DUCKING ); pPlayer->m_Local.m_bDucked = true; pPlayer->m_Local.m_bDucking = true; pPlayer->m_Local.m_nDuckTimeMsecs = 0; pPlayer->SetViewOffset( VEC_DUCK_VIEW ); pPlayer->SetCollisionBounds( VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX ); } } #endif pTarget->Teleport( &vecOrigin, &angRotation, NULL ); }
//------------------------------------------------------------------------------ // Purpose: //------------------------------------------------------------------------------ void CPointTeleport::InputTeleport( inputdata_t &inputdata ) { // Attempt to find the entity in question CBaseEntity *pTarget = gEntList.FindEntityByName( NULL, m_target, this, inputdata.pActivator, inputdata.pCaller ); if ( pTarget == NULL ) return; // If teleport object is in a movement hierarchy, remove it first if ( EntityMayTeleport( pTarget ) == false ) { Warning("ERROR: (%s) can't teleport object (%s) as it has a parent (%s)!\n",GetDebugName(),pTarget->GetDebugName(),pTarget->GetMoveParent()->GetDebugName()); return; } pTarget->Teleport( &m_vSaveOrigin, &m_vSaveAngles, NULL ); }