//----------------------------------------------------------------------------- // Purpose: Used to iterate all the entities within a sphere. // Input : pStartEntity - // vecCenter - // flRadius - //----------------------------------------------------------------------------- CBaseEntity *CGlobalEntityList::FindEntityInSphere( CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius ) { const CEntInfo *pInfo = pStartEntity ? GetEntInfoPtr( pStartEntity->GetRefEHandle() )->m_pNext : FirstEntInfo(); for ( ;pInfo; pInfo = pInfo->m_pNext ) { CBaseEntity *ent = (CBaseEntity *)pInfo->m_pEntity; if ( !ent ) { DevWarning( "NULL entity in global entity list!\n" ); continue; } if ( !ent->edict() ) continue; Vector vecRelativeCenter; ent->CollisionProp()->WorldToCollisionSpace( vecCenter, &vecRelativeCenter ); if ( !IsBoxIntersectingSphere( ent->CollisionProp()->OBBMins(), ent->CollisionProp()->OBBMaxs(), vecRelativeCenter, flRadius ) ) continue; return ent; } // nothing found return NULL; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CBaseEntity *CNPCSimpleTalker::EnumFriends( CBaseEntity *pPrevious, int listNumber, bool bTrace ) { CBaseEntity *pFriend = pPrevious; char *pszFriend; trace_t tr; Vector vecCheck; pszFriend = m_szFriends[ FriendNumber(listNumber) ]; while ( pszFriend != NULL && ((pFriend = gEntList.FindEntityByClassname( pFriend, pszFriend )) != NULL) ) { if (pFriend == this || !pFriend->IsAlive()) // don't talk to self or dead people continue; if ( bTrace ) { Vector vecCheck; pFriend->CollisionProp()->NormalizedToWorldSpace( Vector( 0.5f, 0.5f, 1.0f ), &vecCheck ); UTIL_TraceLine( GetAbsOrigin(), vecCheck, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr); } else { tr.fraction = 1.0; } if (tr.fraction == 1.0) { return pFriend; } } return NULL; }
//----------------------------------------------------------------------------- // Makes sure all entries in the KD tree are in the correct position //----------------------------------------------------------------------------- void CDirtySpatialPartitionEntityList::OnPreQuery( SpatialPartitionListMask_t listMask ) { #ifdef CLIENT_DLL if ( !( listMask & PARTITION_CLIENT_GAME_EDICTS ) ) return; // FIXME: This should really be an assertion... feh! if ( !C_BaseEntity::IsAbsRecomputationsEnabled() ) { m_mutex.Lock(); return; } #else if ( !( listMask & PARTITION_SERVER_GAME_EDICTS ) ) return; #endif m_mutex.Lock(); CUtlVector< CBaseHandle > vecStillDirty; int nDirtyEntityCount = m_DirtyEntities.Count(); while ( nDirtyEntityCount > 0 ) { CBaseHandle handle; handle = m_DirtyEntities[nDirtyEntityCount-1]; #ifndef CLIENT_DLL CBaseEntity *pEntity = gEntList.GetBaseEntity( handle ); #else CBaseEntity *pEntity = cl_entitylist->GetBaseEntityFromHandle( handle ); #endif m_DirtyEntities.FastRemove( nDirtyEntityCount-1 ); if ( pEntity ) { // If an entity is in the middle of bone setup, don't call UpdatePartition // which can cause it to redo bone setup on the same frame causing a recursive // call to bone setup. if ( !pEntity->IsEFlagSet( EFL_SETTING_UP_BONES ) ) { pEntity->CollisionProp()->UpdatePartition(); } else { vecStillDirty.AddToTail( handle ); } } nDirtyEntityCount = m_DirtyEntities.Count(); } if ( vecStillDirty.Count() > 0 ) { m_DirtyEntities = vecStillDirty; } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CWeaponMedigun::MaintainTargetInSlot() { CTFPlayer *pOwner = ToTFPlayer( GetOwnerEntity() ); if ( !pOwner ) return; CBaseEntity *pTarget = m_hHealingTarget; Assert( pTarget ); // Make sure the guy didn't go out of range. bool bLostTarget = true; Vector vecSrc = pOwner->Weapon_ShootPosition( ); Vector vecTargetPoint = pTarget->WorldSpaceCenter(); Vector vecPoint; // If it's brush built, use absmins/absmaxs pTarget->CollisionProp()->CalcNearestPoint( vecSrc, &vecPoint ); float flDistance = (vecPoint - vecSrc).Length(); if ( flDistance < GetStickRange() ) { if ( m_flNextTargetCheckTime > gpGlobals->curtime ) return; m_flNextTargetCheckTime = gpGlobals->curtime + 1.0f; trace_t tr; CMedigunFilter drainFilter( pOwner ); Vector vecAiming; pOwner->EyeVectors( &vecAiming ); Vector vecEnd = vecSrc + vecAiming * GetTargetRange(); UTIL_TraceLine( vecSrc, vecEnd, (MASK_SHOT & ~CONTENTS_HITBOX), pOwner, DMG_GENERIC, &tr ); // Still visible? if ( tr.m_pEnt == pTarget ) return; UTIL_TraceLine( vecSrc, vecTargetPoint, MASK_SHOT, &drainFilter, &tr ); // Still visible? if (( tr.fraction == 1.0f) || (tr.m_pEnt == pTarget)) return; // If we failed, try the target's eye point as well UTIL_TraceLine( vecSrc, pTarget->EyePosition(), MASK_SHOT, &drainFilter, &tr ); if (( tr.fraction == 1.0f) || (tr.m_pEnt == pTarget)) return; } // We've lost this guy if ( bLostTarget ) { RemoveHealingTarget(); } }
//----------------------------------------------------------------------------- // Purpose: Finds the nearest entity by class name withing given search radius. // Input : szName - Entity name to search for. Treated as a target name first, // then as an entity class name, ie "info_target". // vecSrc - Center of search radius. // flRadius - Search radius for classname search, 0 to search everywhere. // Output : Returns a pointer to the found entity, NULL if none. //----------------------------------------------------------------------------- CBaseEntity *CGlobalEntityList::FindEntityByClassnameNearest( const char *szName, const Vector &vecSrc, float flRadius, int brushPrecision ) { CBaseEntity *pEntity = NULL; // // Check for matching class names within the search radius. // float flMaxDist2 = flRadius * flRadius; if (flMaxDist2 == 0) { flMaxDist2 = MAX_TRACE_LENGTH * MAX_TRACE_LENGTH; } CBaseEntity *pSearch = NULL; while ((pSearch = gEntList.FindEntityByClassname( pSearch, szName )) != NULL) { if ( !pSearch->edict() ) continue; Vector origin; if ( pSearch->IsBSPModel() && pSearch->CollisionProp()) { if ( brushPrecision == BRUSHPRECISION_NEAREST ) pSearch->CollisionProp()->CalcNearestPoint(vecSrc,&origin); else origin = pSearch->CollisionProp()->GetCollisionOrigin(); } else origin = pSearch->GetAbsOrigin(); float flDist2 = (origin - vecSrc).LengthSqr(); if (flMaxDist2 > flDist2) { pEntity = pSearch; flMaxDist2 = flDist2; } } return pEntity; }
void CAI_PlaneSolver::GenerateObstacleNpcs( const AILocalMoveGoal_t &goal, float probeDist ) { if ( !ProbeForNpcs() ) { CAI_BaseNPC **ppAIs = g_AI_Manager.AccessAIs(); Vector minsSelf, maxsSelf; m_pNpc->CollisionProp()->WorldSpaceSurroundingBounds( &minsSelf, &maxsSelf ); float radiusSelf = (minsSelf.AsVector2D() - maxsSelf.AsVector2D()).Length() * 0.5; for ( int i = 0; i < g_AI_Manager.NumAIs(); i++ ) { CAI_BaseNPC *pAI = ppAIs[i]; if ( pAI != m_pNpc && pAI->IsAlive() && ( !goal.pPath || pAI != goal.pPath->GetTarget() ) ) { Vector mins, maxs; pAI->CollisionProp()->WorldSpaceSurroundingBounds( &mins, &maxs ); if ( mins.z < maxsSelf.z + 12.0 && maxs.z > minsSelf.z - 12.0 ) { float radius = (mins.AsVector2D() - maxs.AsVector2D()).Length() * 0.5; float distance = ( pAI->GetAbsOrigin().AsVector2D() - m_pNpc->GetAbsOrigin().AsVector2D() ).Length(); if ( distance - radius < radiusSelf + probeDist ) { AddObstacle( pAI->WorldSpaceCenter(), radius, pAI, AIMST_AVOID_NPC ); } } } } #ifdef SecobMod__Enable_Fixed_Multiplayer_AI CBaseEntity *pPlayer = UTIL_GetNearestPlayer(m_pNpc->GetAbsOrigin()); #else CBaseEntity *pPlayer = UTIL_PlayerByIndex( 1 ); #endif //SecobMod__Enable_Fixed_Multiplayer_AI if ( pPlayer ) { Vector mins, maxs; pPlayer->CollisionProp()->WorldSpaceSurroundingBounds( &mins, &maxs ); if ( mins.z < maxsSelf.z + 12.0 && maxs.z > minsSelf.z - 12.0 ) { float radius = (mins.AsVector2D() - maxs.AsVector2D()).Length(); float distance = ( pPlayer->GetAbsOrigin().AsVector2D() - m_pNpc->GetAbsOrigin().AsVector2D() ).Length(); if ( distance - radius < radiusSelf + probeDist ) { AddObstacle( pPlayer->WorldSpaceCenter(), radius, pPlayer, AIMST_AVOID_NPC ); } } } } }
const matrix3x4_t *CCollisionProperty::GetRootParentToWorldTransform() const { if ( IsSolidFlagSet( FSOLID_ROOT_PARENT_ALIGNED ) ) { CBaseEntity *pEntity = m_pOuter->GetRootMoveParent(); Assert(pEntity); if ( pEntity ) { return &pEntity->CollisionProp()->CollisionToWorldTransform(); } } return NULL; }
void OnDensityConVarChanged( IConVar *var, const char *pOldValue, float flOldValue ) { CBaseEntity *pEnt = gEntList.FirstEnt(); while( pEnt ) { const Vector& vMins = pEnt->CollisionProp()->OBBMins(); const Vector& vMaxs = pEnt->CollisionProp()->OBBMaxs(); pEnt->DensityMap()->RecalculateWeights(vMins, vMaxs); //pEnt->DensityMap()->OnCollisionSizeChanged(); pEnt = gEntList.NextEnt( pEnt ); } }
//----------------------------------------------------------------------------- // Purpose: Finds the first entity by name within a radius // Input : pStartEntity - The entity to start from when doing the search. // szName - Entity name to search for. // vecSrc - Center of search radius. // flRadius - Search radius for classname search, 0 to search everywhere. // pSearchingEntity - The entity that is doing the search. // pActivator - The activator entity if this was called from an input // or Use handler, NULL otherwise. // Output : Returns a pointer to the found entity, NULL if none. //----------------------------------------------------------------------------- CBaseEntity *CGlobalEntityList::FindEntityByNameWithin( CBaseEntity *pStartEntity, const char *szName, const Vector &vecSrc, float flRadius, CBaseEntity *pSearchingEntity, CBaseEntity *pActivator, CBaseEntity *pCaller, int brushPrecision ) { // // Check for matching class names within the search radius. // CBaseEntity *pEntity = pStartEntity; float flMaxDist2 = flRadius * flRadius; if (flMaxDist2 == 0) { return gEntList.FindEntityByName( pEntity, szName, pSearchingEntity, pActivator, pCaller ); } while ((pEntity = gEntList.FindEntityByName( pEntity, szName, pSearchingEntity, pActivator, pCaller )) != NULL) { if ( !pEntity->edict() ) continue; Vector origin; if ( pEntity->IsBSPModel() && pEntity->CollisionProp()) { if ( brushPrecision == BRUSHPRECISION_NEAREST ) pEntity->CollisionProp()->CalcNearestPoint(vecSrc,&origin); else origin = pEntity->CollisionProp()->GetCollisionOrigin(); } else origin = pEntity->GetAbsOrigin(); float flDist2 = (origin - vecSrc).LengthSqr(); if (flMaxDist2 > flDist2) { return pEntity; } } return NULL; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CItem_DynamicResupply::SpawnItemFromRatio( int nCount, DynamicResupplyItems_t *pItems, int iDebug, SpawnInfo_t *pSpawnInfo, Vector *pVecSpawnOrigin ) { // Now find the one we're farthest from float flFarthest = 0; int iSelectedIndex = -1; for ( int i = 0; i < nCount; ++i ) { if ( pSpawnInfo[i].m_flDelta > flFarthest ) { flFarthest = pSpawnInfo[i].m_flDelta; iSelectedIndex = i; } } if ( iSelectedIndex < 0 ) return false; if ( iDebug ) { Msg("Chosen item: %s (had farthest delta, %.2f)\n", pItems[iSelectedIndex].sEntityName, pSpawnInfo[iSelectedIndex].m_flDelta ); } CBaseEntity *pEnt = CBaseEntity::Create( pItems[iSelectedIndex].sEntityName, *pVecSpawnOrigin, GetAbsAngles(), this ); pEnt->SetAbsVelocity( GetAbsVelocity() ); pEnt->SetLocalAngularVelocity( GetLocalAngularVelocity() ); // Move the entity up so that it doesn't go below the spawn origin Vector vecWorldMins, vecWorldMaxs; pEnt->CollisionProp()->WorldSpaceAABB( &vecWorldMins, &vecWorldMaxs ); if ( vecWorldMins.z < pVecSpawnOrigin->z ) { float dz = pVecSpawnOrigin->z - vecWorldMins.z; pVecSpawnOrigin->z += dz; vecWorldMaxs.z += dz; pEnt->SetAbsOrigin( *pVecSpawnOrigin ); } // Update the spawn position to spawn them on top of each other pVecSpawnOrigin->z = vecWorldMaxs.z + 6.0f; pVecSpawnOrigin->x += random->RandomFloat( -6, 6 ); pVecSpawnOrigin->y += random->RandomFloat( -6, 6 ); return true; }
void CParticleSystemQuery::GetControllingObjectOBBox( CParticleCollection *pParticles, int nControlPointNumber, Vector vecMin, Vector vecMax ) { vecMin = vecMax = vec3_origin; #ifndef GAME_DLL EHANDLE *phMoveParent = reinterpret_cast<EHANDLE *> ( pParticles->ControlPoint( nControlPointNumber ).m_pObject ); CBaseEntity *pMoveParent = NULL; if ( phMoveParent ) { pMoveParent = *( phMoveParent ); } if ( pMoveParent ) { vecMin = pMoveParent->CollisionProp()->OBBMins(); vecMax = pMoveParent->CollisionProp()->OBBMaxs(); } #endif }
//----------------------------------------------------------------------------- // Purpose: Finds the first entity within an extent by class name. // Input : pStartEntity - The entity to start from when doing the search. // szName - Entity class name, ie "info_target". // vecMins - Search mins. // vecMaxs - Search maxs. // Output : Returns a pointer to the found entity, NULL if none. //----------------------------------------------------------------------------- CBaseEntity *CGlobalEntityList::FindEntityByClassnameWithin( CBaseEntity *pStartEntity, const char *szName, const Vector &vecMins, const Vector &vecMaxs ) { // // Check for matching class names within the search radius. // CBaseEntity *pEntity = pStartEntity; while ((pEntity = gEntList.FindEntityByClassname( pEntity, szName )) != NULL) { if ( !pEntity->edict() && !pEntity->IsEFlagSet( EFL_SERVER_ONLY ) ) continue; // check if the aabb intersects the search aabb. Vector entMins, entMaxs; pEntity->CollisionProp()->WorldSpaceAABB( &entMins, &entMaxs ); if ( IsBoxIntersectingBox( vecMins, vecMaxs, entMins, entMaxs ) ) { return pEntity; } } return NULL; }
//----------------------------------------------------------------------------- bool CAI_PlaneSolver::GenerateCircleObstacleSuggestions( const AILocalMoveGoal_t &moveGoal, float probeDist ) { bool result = false; Vector npcLoc = m_pNpc->WorldSpaceCenter(); Vector mins, maxs; m_pNpc->CollisionProp()->WorldSpaceSurroundingBounds( &mins, &maxs ); float radiusNpc = (mins.AsVector2D() - maxs.AsVector2D()).Length() * 0.5; for ( int i = 0; i < m_Obstacles.Count(); i++ ) { CBaseEntity *pObstacleEntity = NULL; float zDistTooFar; if ( m_Obstacles[i].hEntity && m_Obstacles[i].hEntity->CollisionProp() ) { pObstacleEntity = m_Obstacles[i].hEntity.Get(); if( pObstacleEntity == moveGoal.pMoveTarget && (pObstacleEntity->IsNPC() || pObstacleEntity->IsPlayer()) ) { // HEY! I'm trying to avoid the very thing I'm trying to get to. This will make we wobble like a drunk as I approach. Don't do it. continue; } pObstacleEntity->CollisionProp()->WorldSpaceSurroundingBounds( &mins, &maxs ); zDistTooFar = ( maxs.z - mins.z ) * 0.5 + GetNpc()->GetHullHeight() * 0.5; } else zDistTooFar = GetNpc()->GetHullHeight(); if ( fabs( m_Obstacles[i].center.z - npcLoc.z ) > zDistTooFar ) continue; Vector vecToNpc = npcLoc - m_Obstacles[i].center; vecToNpc.z = 0; float distToObstacleSq = sq(vecToNpc.x) + sq(vecToNpc.y); float radius = m_Obstacles[i].radius + radiusNpc; if ( distToObstacleSq > 0.001 && distToObstacleSq < sq( radius + probeDist ) ) { Vector vecToObstacle = vecToNpc * -1; float distToObstacle = VectorNormalize( vecToObstacle ); float weight; float arc; float radiusSq = sq(radius); float flDot = DotProduct( vecToObstacle, moveGoal.dir ); // Don't steer around to avoid obstacles we've already passed, unless we're right up against them. // That is, do this computation without the probeDist added in. if( flDot < 0.0f && distToObstacleSq > radiusSq ) { continue; } if ( radiusSq < distToObstacleSq ) { Vector vecTangent; float distToTangent = FastSqrt( distToObstacleSq - radiusSq ); float oneOverDistToObstacleSq = 1 / distToObstacleSq; vecTangent.x = ( -distToTangent * vecToNpc.x + radius * vecToNpc.y ) * oneOverDistToObstacleSq; vecTangent.y = ( -distToTangent * vecToNpc.y - radius * vecToNpc.x ) * oneOverDistToObstacleSq; vecTangent.z = 0; float cosHalfArc = vecToObstacle.Dot( vecTangent ); arc = RAD2DEG(acosf( cosHalfArc )) * 2.0; weight = 1.0 - (distToObstacle - radius) / probeDist; if ( weight > 0.75 ) arc += (arc * 0.5) * (weight - 0.75) / 0.25; Assert( weight >= 0.0 && weight <= 1.0 ); #if DEBUG_OBSTACLES // ------------------------- Msg( "Adding arc %f, w %f\n", arc, weight ); Vector pointTangent = npcLoc + ( vecTangent * distToTangent ); NDebugOverlay::Line( npcLoc - Vector( 0, 0, 64 ), npcLoc + Vector(0,0,64), 0,255,0, false, 0.1 ); NDebugOverlay::Line( center - Vector( 0, 0, 64 ), center + Vector(0,0,64), 0,255,0, false, 0.1 ); NDebugOverlay::Line( pointTangent - Vector( 0, 0, 64 ), pointTangent + Vector(0,0,64), 0,255,0, false, 0.1 ); NDebugOverlay::Line( npcLoc + Vector(0,0,64), center + Vector(0,0,64), 0,0,255, false, 0.1 ); NDebugOverlay::Line( center + Vector(0,0,64), pointTangent + Vector(0,0,64), 0,0,255, false, 0.1 ); NDebugOverlay::Line( pointTangent + Vector(0,0,64), npcLoc + Vector(0,0,64), 0,0,255, false, 0.1 ); #endif } else { arc = 210; weight = 1.0; } if ( m_Obstacles[i].hEntity != NULL ) { weight = AdjustRegulationWeight( m_Obstacles[i].hEntity, weight ); } AI_MoveSuggestion_t suggestion( m_Obstacles[i].type, weight, UTIL_VecToYaw(vecToObstacle), arc ); m_Solver.AddRegulation( suggestion ); result = true; } } m_Obstacles.RemoveAll(); return result; }
//----------------------------------------------------------------------------- // Makes sure all entries in the KD tree are in the correct position //----------------------------------------------------------------------------- void CDirtySpatialPartitionEntityList::OnPreQuery( SpatialPartitionListMask_t listMask ) { #ifdef CLIENT_DLL const int validMask = PARTITION_CLIENT_GAME_EDICTS; #else const int validMask = PARTITION_SERVER_GAME_EDICTS; #endif if ( !( listMask & validMask ) ) return; if ( m_partitionWriteId != 0 && m_partitionWriteId == ThreadGetCurrentId() ) return; #ifdef CLIENT_DLL // FIXME: This should really be an assertion... feh! if ( !C_BaseEntity::IsAbsRecomputationsEnabled() ) { LockPartitionForRead(); return; } #endif // if you're holding a read lock, then these are entities that were still dirty after your trace started // or became dirty due to some other thread or callback. Updating them may cause corruption further up the // stack (e.g. partition iterator). Ignoring the state change should be safe since it happened after the // trace was requested or was unable to be resolved in a previous attempt (still dirty). if ( m_DirtyEntities.Count() && !m_readLockCount ) { CUtlVector< CBaseHandle > vecStillDirty; m_partitionMutex.LockForWrite(); m_partitionWriteId = ThreadGetCurrentId(); CTSListWithFreeList<CBaseHandle>::Node_t *pCurrent, *pNext; while ( ( pCurrent = m_DirtyEntities.Detach() ) != NULL ) { while ( pCurrent ) { CBaseHandle handle = pCurrent->elem; pNext = (CTSListWithFreeList<CBaseHandle>::Node_t *)pCurrent->Next; m_DirtyEntities.FreeNode( pCurrent ); pCurrent = pNext; #ifndef CLIENT_DLL CBaseEntity *pEntity = gEntList.GetBaseEntity( handle ); #else CBaseEntity *pEntity = cl_entitylist->GetBaseEntityFromHandle( handle ); #endif if ( pEntity ) { // If an entity is in the middle of bone setup, don't call UpdatePartition // which can cause it to redo bone setup on the same frame causing a recursive // call to bone setup. if ( !pEntity->IsEFlagSet( EFL_SETTING_UP_BONES ) ) { pEntity->CollisionProp()->UpdatePartition(); } else { vecStillDirty.AddToTail( handle ); } } } } if ( vecStillDirty.Count() > 0 ) { for ( int i = 0; i < vecStillDirty.Count(); i++ ) { m_DirtyEntities.PushItem( vecStillDirty[i] ); } } m_partitionWriteId = 0; m_partitionMutex.UnlockWrite(); } LockPartitionForRead(); }
//----------------------------------------------------------------------------- // Purpose: Override to check throw // Input : // Output : //----------------------------------------------------------------------------- int CWeaponMolotov::WeaponRangeAttack1Condition( float flDot, float flDist ) { // If things haven't changed too much since last time // just return that previously calculated value if (gpGlobals->curtime < m_fNextThrowCheck ) { return m_iThrowBits; } if ( flDist < m_fMinRange1) { m_iThrowBits = COND_TOO_CLOSE_TO_ATTACK; } else if (flDist > m_fMaxRange1) { m_iThrowBits = COND_TOO_FAR_TO_ATTACK; } else if (flDot < 0.5) { m_iThrowBits = COND_NOT_FACING_ATTACK; } // If moving, can't throw. else if ( m_flGroundSpeed != 0 ) { m_iThrowBits = COND_NONE; } else { // Ok we should check again as some time has passed // This function is only used by NPC's so we can cast to a Base Monster CAI_BaseNPC *pNPC = GetOwner()->MyNPCPointer(); CBaseEntity *pEnemy = pNPC->GetEnemy(); if (!pEnemy) { m_iThrowBits = COND_NONE; } // Get Enemy Position Vector vecTarget; pEnemy->CollisionProp()->NormalizedToWorldSpace( Vector( 0.5f, 0.5f, 0.0f ), &vecTarget ); // Get Toss Vector Vector throwStart = pNPC->Weapon_ShootPosition(); Vector vecToss; CBaseEntity* pBlocker = NULL; float throwDist = (throwStart - vecTarget).Length(); float fGravity = sv_gravity.GetFloat(); float throwLimit = pNPC->ThrowLimit(throwStart, vecTarget, fGravity, 35, WorldAlignMins(), WorldAlignMaxs(), pEnemy, &vecToss, &pBlocker); // If I can make the throw (or most of the throw) if (!throwLimit || (throwLimit != throwDist && throwLimit > 0.8*throwDist)) { m_vecTossVelocity = vecToss; m_iThrowBits = COND_CAN_RANGE_ATTACK1; } else { m_iThrowBits = COND_NONE; } } // don't check again for a while. m_fNextThrowCheck = gpGlobals->curtime + 0.33; // 1/3 second. return m_iThrowBits; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFreezePanel::UpdateCallout( void ) { CTFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer(); if ( !pPlayer ) return; // Abort early if we have no gibs or ragdoll CUtlVector<EHANDLE> *pGibList = pPlayer->GetSpawnedGibs(); IRagdoll *pRagdoll = pPlayer->GetRepresentativeRagdoll(); if ( (!pGibList || pGibList->Count() == 0) && !pRagdoll ) return; if ( m_pFreezePanelBG == NULL ) return; // Precalc the vectors of the freezepanel & statpanel int iX, iY; m_pFreezePanelBG->GetPos( iX, iY ); Vector vecFreezeTL( iX, iY, 0 ); Vector vecFreezeBR( iX + m_pFreezePanelBG->GetWide(), iY + m_pFreezePanelBG->GetTall(), 1 ); CUtlVector<Vector> vecCalloutsTL; CUtlVector<Vector> vecCalloutsBR; Vector vecStatTL(0,0,0); Vector vecStatBR(0,0,1); CTFStatPanel *pStatPanel = GET_HUDELEMENT( CTFStatPanel ); if ( pStatPanel && pStatPanel->IsVisible() ) { pStatPanel->GetPos( iX, iY ); vecStatTL.x = iX; vecStatTL.y = iY; vecStatBR.x = vecStatTL.x + pStatPanel->GetWide(); vecStatBR.y = vecStatTL.y + pStatPanel->GetTall(); } Vector vMins, vMaxs; // Check gibs if ( pGibList && pGibList->Count() ) { int iCount = 0; for ( int i = 0; i < pGibList->Count(); i++ ) { CBaseEntity *pGib = pGibList->Element(i); if ( pGib ) { Vector origin = pGib->GetRenderOrigin(); IPhysicsObject *pPhysicsObject = pGib->VPhysicsGetObject(); if( pPhysicsObject ) { Vector vecMassCenter = pPhysicsObject->GetMassCenterLocalSpace(); pGib->CollisionProp()->CollisionToWorldSpace( vecMassCenter, &origin ); } pGib->GetRenderBounds( vMins, vMaxs ); // Try and add the callout CTFFreezePanelCallout *pCallout = TestAndAddCallout( origin, vMins, vMaxs, &vecCalloutsTL, &vecCalloutsBR, vecFreezeTL, vecFreezeBR, vecStatTL, vecStatBR, &iX, &iY ); if ( pCallout ) { pCallout->UpdateForGib( i, iCount ); iCount++; } } } } else if ( pRagdoll ) { Vector origin = pRagdoll->GetRagdollOrigin(); pRagdoll->GetRagdollBounds( vMins, vMaxs ); // Try and add the callout CTFFreezePanelCallout *pCallout = TestAndAddCallout( origin, vMins, vMaxs, &vecCalloutsTL, &vecCalloutsBR, vecFreezeTL, vecFreezeBR, vecStatTL, vecStatBR, &iX, &iY ); if ( pCallout ) { pCallout->UpdateForRagdoll(); } // even if the callout failed, check that our ragdoll is onscreen and our killer is taunting us (for an achievement) if ( GetVectorInScreenSpace( origin, iX, iY ) ) { C_TFPlayer *pKiller = ToTFPlayer( UTIL_PlayerByIndex( GetSpectatorTarget() ) ); if ( pKiller && pKiller->m_Shared.InCond( TF_COND_TAUNTING ) ) { // tell the server our ragdoll just got taunted during our freezecam char cmd[256]; int iPlayerID = pPlayer->GetUserID(); unsigned short mask = UTIL_GetAchievementEventMask(); Q_snprintf( cmd, sizeof( cmd ), "freezecam_taunt %d %d", GetSpectatorTarget() ^ mask, ( iPlayerID ^ GetSpectatorTarget() ) ^ mask ); engine->ClientCmd_Unrestricted( cmd ); } } } }
bool CNPC_Dog::FindPhysicsObject( const char *pPickupName, CBaseEntity *pIgnore ) { CBaseEntity *pEnt = NULL; CBaseEntity *pNearest = NULL; float flDist; IPhysicsObject *pPhysObj = NULL; float flNearestDist = 99999; if ( pPickupName != NULL && strlen( pPickupName ) > 0 ) { pEnt = gEntList.FindEntityByName( NULL, pPickupName ); if ( m_hUnreachableObjects.Find( pEnt ) == -1 ) { m_bHasObject = false; m_hPhysicsEnt = pEnt; return true; } } while ( ( pEnt = gEntList.FindEntityByClassname( pEnt, "prop_physics" ) ) != NULL ) { //We don't want this one. if ( pEnt == pIgnore ) continue; if ( m_hUnreachableObjects.Find( pEnt ) != -1 ) continue; pPhysObj = pEnt->VPhysicsGetObject(); if( pPhysObj == NULL ) continue; if ( pPhysObj->GetMass() > DOG_MAX_THROW_MASS ) continue; Vector center = pEnt->WorldSpaceCenter(); flDist = UTIL_DistApprox2D( GetAbsOrigin(), center ); vcollide_t *pCollide = modelinfo->GetVCollide( pEnt->GetModelIndex() ); if ( pCollide == NULL ) continue; if ( pPhysObj->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) continue; if ( pPhysObj->IsMoveable() == false ) continue; if ( pEnt->GetCollisionGroup() == COLLISION_GROUP_DEBRIS || pEnt->GetCollisionGroup() == COLLISION_GROUP_INTERACTIVE_DEBRIS ) continue; if ( center.z > EyePosition().z ) continue; if ( flDist >= flNearestDist ) continue; if ( FVisible( pEnt ) == false ) continue; pNearest = pEnt; flNearestDist = flDist; } m_bHasObject = false; m_hPhysicsEnt = pNearest; if ( dog_debug.GetBool() == true ) { if ( pNearest ) NDebugOverlay::Box( pNearest->WorldSpaceCenter(), pNearest->CollisionProp()->OBBMins(), pNearest->CollisionProp()->OBBMaxs(), 255, 0, 255, true, 3 ); } if( m_hPhysicsEnt == NULL ) { return false; } else { return true; } }
bool CSDKPlayer::PlayerUse() { #ifdef GAME_DLL // Was use pressed or released? if ( ((m_nButtons | m_afButtonPressed | m_afButtonReleased) & IN_USE) && !IsObserver() ) { Vector forward, up; EyeVectors( &forward, NULL, &up ); Vector vecSearchCenter = EyePosition(); CBaseEntity *pObject = nullptr; CBaseEntity *pNearest = nullptr; float flNearest = FLT_MAX; // Look for grenades so we can prioritize picking them up first. for ( CEntitySphereQuery sphere( vecSearchCenter, PLAYER_USE_RADIUS ); ( pObject = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() ) { if ( !pObject ) continue; if ( !IsUseableEntity( pObject, FCAP_USE_IN_RADIUS ) ) continue; CWeaponSDKBase* pWeapon = dynamic_cast<CWeaponSDKBase*>(pObject); if (!pWeapon) continue; if (pWeapon->GetWeaponID() != SDK_WEAPON_GRENADE) continue; // If we're full up on grenades, pass over to whatever other weapons are lying around. if (!g_pGameRules->CanHavePlayerItem(this, pWeapon)) continue; // see if it's more roughly in front of the player than previous guess Vector point; pObject->CollisionProp()->CalcNearestPoint( vecSearchCenter, &point ); Vector dir = point - vecSearchCenter; 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, vecSearchCenter, forward ); ConVarRef sv_debug_player_use("sv_debug_player_use"); if ( sv_debug_player_use.GetBool() ) { Msg("Radius found %s, dist %.2f\n", pObject->GetClassname(), dist ); } // Not worried about shit being behind a wall at this point. // Just greedily gobble up all nearby grenades since there's // no penalty to the player for doing so. if ( dist < flNearest ) { pNearest = pObject; flNearest = dist; } } if (pNearest) { // This is a grenade. Use it to pick it up. variant_t emptyVariant; pNearest->AcceptInput( "Use", this, this, emptyVariant, USE_TOGGLE ); return true; } } #endif bool bUsed = BaseClass::PlayerUse(); if (bUsed) return bUsed; if (!(m_afButtonPressed & IN_USE)) return false; if (!IsAlive()) return false; return false; }
//----------------------------------------------------------------------------- // Purpose: Update the fire and its children //----------------------------------------------------------------------------- void CFire::Update( float simTime ) { VPROF_FIRE( "CFire::Update" ); if ( m_flFuel != 0 ) { m_flFuel -= simTime; if ( m_flFuel <= 0 ) { GoOutInSeconds( 1 ); return; } } float strength = m_flHeatLevel / FIRE_MAX_HEAT_LEVEL; if ( m_flHeatLevel != m_flLastHeatLevel ) { m_flLastHeatLevel = m_flHeatLevel; // Make the effect the appropriate size given the heat level m_hEffect->Scale( strength, 0.5f ); } // add heat to myself (grow) float addedHeat = (m_flAttackTime > 0) ? m_flMaxHeat / m_flAttackTime : m_flMaxHeat; addedHeat *= simTime * fire_growthrate.GetFloat(); AddHeat( addedHeat, true ); // add heat to nearby fires float outputHeat = strength * m_flHeatLevel; Vector fireMins; Vector fireMaxs; Vector fireEntityDamageMins; Vector fireEntityDamageMaxs; GetFireDimensions( &fireMins, &fireMaxs ); if ( FIRE_SPREAD_DAMAGE_MULTIPLIER != 1.0 ) // if set to 1.0, optimizer will remove this code { fireEntityDamageMins = fireMins / FIRE_SPREAD_DAMAGE_MULTIPLIER; fireEntityDamageMaxs = fireMaxs / FIRE_SPREAD_DAMAGE_MULTIPLIER; } //NDebugOverlay::Box( GetAbsOrigin(), fireMins, fireMaxs, 255, 255, 255, 0, fire_dmginterval.GetFloat() ); fireMins += GetAbsOrigin(); fireMaxs += GetAbsOrigin(); if ( FIRE_SPREAD_DAMAGE_MULTIPLIER != 1.0 ) { fireEntityDamageMins += GetAbsOrigin(); fireEntityDamageMaxs += GetAbsOrigin(); } CBaseEntity *pNearby[256]; CFire *pFires[16]; int nearbyCount = UTIL_EntitiesInBox( pNearby, ARRAYSIZE(pNearby), fireMins, fireMaxs, 0 ); int fireCount = 0; int i; // is it time to do damage? bool damage = false; int outputDamage = 0; if ( m_flDamageTime <= gpGlobals->curtime ) { m_flDamageTime = gpGlobals->curtime + fire_dmginterval.GetFloat(); outputDamage = (fire_dmgbase.GetFloat() + outputHeat * fire_dmgscale.GetFloat() * m_flDamageScale) * fire_dmginterval.GetFloat(); if ( outputDamage ) { damage = true; } } int damageFlags = (m_nFireType == FIRE_NATURAL) ? DMG_BURN : DMG_PLASMA; for ( i = 0; i < nearbyCount; i++ ) { CBaseEntity *pOther = pNearby[i]; if ( pOther == this ) { continue; } else if ( FClassnameIs( pOther, "env_fire" ) ) { if ( fireCount < ARRAYSIZE(pFires) ) { pFires[fireCount] = (CFire *)pOther; fireCount++; } continue; } else if ( pOther->m_takedamage == DAMAGE_NO ) { pNearby[i] = NULL; } else if ( damage ) { bool bDoDamage; if ( FIRE_SPREAD_DAMAGE_MULTIPLIER != 1.0 && !pOther->IsPlayer() ) // if set to 1.0, optimizer will remove this code { Vector otherMins, otherMaxs; pOther->CollisionProp()->WorldSpaceAABB( &otherMins, &otherMaxs ); bDoDamage = IsBoxIntersectingBox( otherMins, otherMaxs, fireEntityDamageMins, fireEntityDamageMaxs ); } else bDoDamage = true; if ( bDoDamage ) { // Make sure can actually see entity (don't damage through walls) trace_t tr; UTIL_TraceLine( this->WorldSpaceCenter(), pOther->WorldSpaceCenter(), MASK_FIRE_SOLID, pOther, COLLISION_GROUP_NONE, &tr ); if (tr.fraction == 1.0 && !tr.startsolid) { pOther->TakeDamage( CTakeDamageInfo( this, this, outputDamage, damageFlags ) ); } } } } outputHeat *= fire_heatscale.GetFloat() * simTime; if ( fireCount > 0 ) { outputHeat /= fireCount; for ( i = 0; i < fireCount; i++ ) { pFires[i]->AddHeat( outputHeat, false ); } } }
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 PropBreakableCreateAll( int modelindex, IPhysicsObject *pPhysics, const breakablepropparams_t ¶ms, CBaseEntity *pEntity, int iPrecomputedBreakableCount, bool bIgnoreGibLimit, bool defaultLocation ) { // Check for prop breakable count reset. int nPropCount = props_break_max_pieces_perframe.GetInt(); if ( nPropCount != -1 ) { if ( nFrameNumber != gpGlobals->framecount ) { nPropBreakablesPerFrameCount = 0; nFrameNumber = gpGlobals->framecount; } // Check for max breakable count for the frame. if ( nPropBreakablesPerFrameCount >= nPropCount ) return; } int iMaxBreakCount = bIgnoreGibLimit ? -1 : props_break_max_pieces.GetInt(); if ( iMaxBreakCount != -1 ) { if ( iPrecomputedBreakableCount != -1 ) { iPrecomputedBreakableCount = MIN( iMaxBreakCount, iPrecomputedBreakableCount ); } else { iPrecomputedBreakableCount = iMaxBreakCount; } } #ifdef GAME_DLL // On server limit break model creation if ( !PropBreakableCapEdictsOnCreateAll(modelindex, pPhysics, params, pEntity, iPrecomputedBreakableCount ) ) { DevMsg( "Failed to create PropBreakable: would exceed MAX_EDICTS\n" ); return; } #endif vcollide_t *pCollide = modelinfo->GetVCollide( modelindex ); if ( !pCollide ) return; int nSkin = 0; CBaseEntity *pOwnerEntity = pEntity; CBaseAnimating *pOwnerAnim = NULL; if ( pPhysics ) { pOwnerEntity = static_cast<CBaseEntity *>(pPhysics->GetGameData()); } if ( pOwnerEntity ) { pOwnerAnim = pOwnerEntity->GetBaseAnimating(); if ( pOwnerAnim ) { nSkin = pOwnerAnim->m_nSkin; } } matrix3x4_t localToWorld; CStudioHdr studioHdr; const model_t *model = modelinfo->GetModel( modelindex ); if ( model ) { studioHdr.Init( modelinfo->GetStudiomodel( model ) ); } Vector parentOrigin = vec3_origin; int parentAttachment = Studio_FindAttachment( &studioHdr, "placementOrigin" ) + 1; if ( parentAttachment > 0 ) { GetAttachmentLocalSpace( &studioHdr, parentAttachment-1, localToWorld ); MatrixGetColumn( localToWorld, 3, parentOrigin ); } else { AngleMatrix( vec3_angle, localToWorld ); } CUtlVector<breakmodel_t> list; BreakModelList( list, modelindex, params.defBurstScale, params.defCollisionGroup ); if ( list.Count() ) { for ( int i = 0; i < list.Count(); i++ ) { int modelIndex = modelinfo->GetModelIndex( list[i].modelName ); if ( modelIndex <= 0 ) continue; // Skip multiplayer pieces that should be spawning on the other dll #ifdef GAME_DLL if ( gpGlobals->maxClients > 1 && breakable_multiplayer.GetBool() ) #else if ( gpGlobals->maxClients > 1 ) #endif { #ifdef GAME_DLL if ( list[i].mpBreakMode == MULTIPLAYER_BREAK_CLIENTSIDE ) continue; #else if ( list[i].mpBreakMode == MULTIPLAYER_BREAK_SERVERSIDE ) continue; #endif if ( !defaultLocation && list[i].mpBreakMode == MULTIPLAYER_BREAK_DEFAULT ) continue; } if ( ( nPropCount != -1 ) && ( nPropBreakablesPerFrameCount > nPropCount ) ) break; if ( ( iPrecomputedBreakableCount != -1 ) && ( i >= iPrecomputedBreakableCount ) ) break; matrix3x4_t matrix; AngleMatrix( params.angles, params.origin, matrix ); CStudioHdr studioHdr; const model_t *model = modelinfo->GetModel( modelIndex ); if ( model ) { studioHdr.Init( modelinfo->GetStudiomodel( model ) ); } // Increment the number of breakable props this frame. ++nPropBreakablesPerFrameCount; Vector position = vec3_origin; QAngle angles = params.angles; if ( pOwnerAnim && list[i].placementName[0] ) { if ( list[i].placementIsBone ) { int boneIndex = pOwnerAnim->LookupBone( list[i].placementName ); if ( boneIndex >= 0 ) { pOwnerAnim->GetBonePosition( boneIndex, position, angles ); AngleMatrix( angles, position, matrix ); } } else { int attachmentIndex = Studio_FindAttachment( &studioHdr, list[i].placementName ) + 1; if ( attachmentIndex > 0 ) { pOwnerAnim->GetAttachment( attachmentIndex, matrix ); MatrixAngles( matrix, angles ); } } } else { int placementIndex = Studio_FindAttachment( &studioHdr, "placementOrigin" ) + 1; Vector placementOrigin = parentOrigin; if ( placementIndex > 0 ) { GetAttachmentLocalSpace( &studioHdr, placementIndex-1, localToWorld ); MatrixGetColumn( localToWorld, 3, placementOrigin ); placementOrigin -= parentOrigin; } VectorTransform( list[i].offset - placementOrigin, matrix, position ); } Vector objectVelocity = params.velocity; if (pPhysics) { pPhysics->GetVelocityAtPoint( position, &objectVelocity ); } int nActualSkin = nSkin; if ( nActualSkin > studioHdr.numskinfamilies() ) nActualSkin = 0; CBaseEntity *pBreakable = NULL; #ifdef GAME_DLL if ( GetGibManager() == NULL || GetGibManager()->AllowedToSpawnGib() ) #endif { pBreakable = BreakModelCreateSingle( pOwnerEntity, &list[i], position, angles, objectVelocity, params.angularVelocity, nActualSkin, params ); } if ( pBreakable ) { #ifdef GAME_DLL if ( GetGibManager() ) { GetGibManager()->AddGibToLRU( pBreakable->GetBaseAnimating() ); } #endif if ( pOwnerEntity && pOwnerEntity->IsEffectActive( EF_NOSHADOW ) ) { pBreakable->AddEffects( EF_NOSHADOW ); } // If burst scale is set, this piece should 'burst' away from // the origin in addition to travelling in the wished velocity. if ( list[i].burstScale != 0.0 ) { Vector vecBurstDir = position - params.origin; // If $autocenter wasn't used, try the center of the piece if ( vecBurstDir == vec3_origin ) { vecBurstDir = pBreakable->WorldSpaceCenter() - params.origin; } VectorNormalize( vecBurstDir ); pBreakable->ApplyAbsVelocityImpulse( vecBurstDir * list[i].burstScale ); } // If this piece is supposed to be motion disabled, disable it if ( list[i].isMotionDisabled ) { IPhysicsObject *pPhysicsObject = pBreakable->VPhysicsGetObject(); if ( pPhysicsObject != NULL ) { pPhysicsObject->EnableMotion( false ); } } } } } // Then see if the propdata specifies any breakable pieces else if ( pEntity ) { IBreakableWithPropData *pBreakableInterface = dynamic_cast<IBreakableWithPropData*>(pEntity); if ( pBreakableInterface && pBreakableInterface->GetBreakableModel() != NULL_STRING && pBreakableInterface->GetBreakableCount() ) { breakmodel_t breakModel; for ( int i = 0; i < pBreakableInterface->GetBreakableCount(); i++ ) { if ( ( iPrecomputedBreakableCount != -1 ) && ( i >= iPrecomputedBreakableCount ) ) break; Q_strncpy( breakModel.modelName, g_PropDataSystem.GetRandomChunkModel(STRING(pBreakableInterface->GetBreakableModel()), pBreakableInterface->GetMaxBreakableSize()), sizeof(breakModel.modelName) ); breakModel.health = 1; breakModel.fadeTime = RandomFloat(5,10); breakModel.fadeMinDist = 0.0f; breakModel.fadeMaxDist = 0.0f; breakModel.burstScale = params.defBurstScale; breakModel.collisionGroup = COLLISION_GROUP_DEBRIS; breakModel.isRagdoll = false; breakModel.isMotionDisabled = false; breakModel.placementName[0] = 0; breakModel.placementIsBone = false; Vector vecObbSize = pEntity->CollisionProp()->OBBSize(); // Find a random point on the plane of the original's two largest axis int smallestAxis = SmallestAxis( vecObbSize ); Vector vecMins(0,0,0); Vector vecMaxs(1,1,1); vecMins[smallestAxis] = 0.5; vecMaxs[smallestAxis] = 0.5; pEntity->CollisionProp()->RandomPointInBounds( vecMins, vecMaxs, &breakModel.offset ); // Push all chunks away from the center Vector vecBurstDir = breakModel.offset - params.origin; VectorNormalize( vecBurstDir ); Vector vecVelocity = vecBurstDir * params.defBurstScale; QAngle vecAngles = pEntity->GetAbsAngles(); int iSkin = pBreakableInterface->GetBreakableSkin(); CBaseEntity *pBreakable = NULL; #ifdef GAME_DLL if ( GetGibManager() == NULL || GetGibManager()->AllowedToSpawnGib() ) #endif { pBreakable = BreakModelCreateSingle( pOwnerEntity, &breakModel, breakModel.offset, vecAngles, vecVelocity, vec3_origin/*params.angularVelocity*/, iSkin, params ); if ( !pBreakable ) { DevWarning( "PropBreakableCreateAll: Could not create model %s\n", breakModel.modelName ); } } if ( pBreakable ) { #ifdef GAME_DLL if ( GetGibManager() ) { GetGibManager()->AddGibToLRU( pBreakable->GetBaseAnimating() ); } #endif Vector vecBreakableObbSize = pBreakable->CollisionProp()->OBBSize(); // Try to align the gibs along the original axis matrix3x4_t matrix; AngleMatrix( vecAngles, matrix ); AlignBoxes( &matrix, vecObbSize, vecBreakableObbSize ); MatrixAngles( matrix, vecAngles ); if ( pBreakable->VPhysicsGetObject() ) { Vector pos; pBreakable->VPhysicsGetObject()->GetPosition( &pos, NULL ); pBreakable->VPhysicsGetObject()->SetPosition( pos, vecAngles, true ); } pBreakable->SetAbsAngles( vecAngles ); if ( pOwnerEntity->IsEffectActive( EF_NOSHADOW ) ) { pBreakable->AddEffects( EF_NOSHADOW ); } } } } } }
void CGEObjectives::Paint( void ) { C_GEPlayer *pPlayer = ToGEPlayer( C_BasePlayer::GetLocalPlayer() ); if ( !pPlayer || !m_pCardTexture ) return; Vector myEyePos = pPlayer->EyePosition(); Vector myAbsPos = pPlayer->GetAbsOrigin(); int half_w = ScreenWidth() / 2, half_h = ScreenHeight() / 2, card_w = XRES(20), card_h = XRES(20), buffer = XRES(5), off_upleft_x = m_iInnerBound, off_lowleft_x = m_iInnerBound, off_upright_x = ScreenWidth() - m_iInnerBound - card_w, off_lowright_x = ScreenWidth() - m_iInnerBound - card_w; vgui::HFont text_font = scheme()->GetIScheme( GetScheme() )->GetFont("GETargetID", true); for ( int i=0; i < m_vObjectives.Count(); i++ ) { GEObjective *obj = m_vObjectives[i]; Vector screen; Vector objAbsPos; // Calculate the current position based off of interpolation VectorLerp(obj->last_pos, obj->curr_pos, (gpGlobals->curtime - obj->update_time) / RADAR_THINK_INT, objAbsPos ); // This lets us mess with the objective position without losing our "real" position Vector objPos = objAbsPos; int x = 0, y = 0; float theta = 0; CBaseEntity *pEnt = obj->hEnt.Get(); if ( pEnt ) { // If we aren't dormant use our known position if ( !pEnt->IsDormant() ) { // Try to get our NPC's position if we are really a bot C_GEBotPlayer *pBot = ToGEBotPlayer( pEnt ); if ( pBot && pBot->GetNPC() ) objPos = pBot->GetNPC()->GetAbsOrigin(); else objPos = pEnt->GetAbsOrigin(); } // Add our collision box which (usually) surrounds the entire entity float height = pEnt->CollisionProp()->OBBMaxs().z; // Add additional z for player specific reasons if ( pEnt->IsPlayer() ) objPos.z += height + ToGEPlayer(pEnt)->GetHeadOffset(); else objPos.z += max( height, 40.0f ); } // Calculate parameters Vector toEye = objPos - myEyePos; float dist = toEye.Length(); // Check out min distance parameter float alpha_mod = 1.0f; if ( obj->min_dist > 0 ) alpha_mod = RemapValClamped( dist, obj->min_dist, obj->min_dist + 80, 0, 1.0f ); if ( alpha_mod == 0 ) continue; // Find where on the screen to draw the indicator // Note: we don't draw it behind us if we are really close bool behind = ScreenTransform( objPos, screen ) && dist > OBJ_ABS_MIN_DIST; if ( !behind && screen.x > -1.0 && screen.x < 1.0 ) { x = half_w + screen.x*half_w - card_w/2; y = half_h - screen.y*half_h - card_h; // We are off-screen vertically, flip the card if ( screen.y > 1.0 ) theta = M_PI; } else { bool onLeft = screen.x < 0; // Calculate a new position for our object to make it "on-screen" at the same height Vector forward; pPlayer->EyeVectors( &forward ); Vector newPos; VectorMA( myEyePos, dist, forward, newPos ); newPos.z = objPos.z; if ( abs(toEye.z) > 100.0f ) newPos.z += toEye.z; //debugoverlay->AddBoxOverlay( newPos, Vector(-5), Vector(5), vec3_angle, 255, 0, 0, 200, gpGlobals->frametime ); // Find our new screen coordinates ScreenTransform( newPos, screen ); if ( screen.y > 0.97f ) { // The obj is above us and off-screen y = m_iInnerBound; if ( onLeft ) { x = off_upleft_x; theta = 0.75 * M_PI; off_upleft_x += card_w + buffer; } else { x = off_upright_x; theta = 1.25 * M_PI; off_upright_x -= card_w + buffer; } } else if ( screen.y < -0.97f ) { // The obj is below us and off-screen y = ScreenHeight() - m_iInnerBound; if ( onLeft ) { x = off_lowleft_x; theta = 0.25 * M_PI; off_lowleft_x += card_w + buffer; } else { x = off_lowright_x; theta = -0.25 * M_PI; off_lowright_x -= card_w + buffer; } } else { // The obj is "on-screen" and level with us if ( onLeft ) { x = m_iInnerBound; y = half_h - screen.y*half_h; theta = M_HALFPI; } else { x = ScreenWidth() - m_iInnerBound - card_w; y = half_h - screen.y*half_h; theta = -M_HALFPI; } } } // Default color is white Color c = obj->color; if ( c.a() == 0 ) c = Color( 255, 255, 255, 120 ); // Apply alpha mod if ( (!behind && screen.x > -1.0 && screen.x < 1.0) ) c[3] *= alpha_mod; // Bound our results x = clamp( x, m_iInnerBound, ScreenWidth() - m_iInnerBound - card_w ); y = clamp( y, m_iInnerBound, ScreenHeight() - m_iInnerBound - card_h ); // Draw text (if defined) before applying pulse so we don't affect it's color if ( obj->text[0] ) { // This is where we clamp the size to 16 int txtX, txtY; txtX = clamp( (x + card_w/2) - obj->txtW/2, XRES(3), ScreenWidth() - obj->txtW - XRES(3) ); txtY = y - obj->txtH - YRES(3); if ( txtY < 0 ) txtY = y + card_h + YRES(3); surface()->DrawSetTextColor( c ); surface()->DrawSetTextFont( text_font ); surface()->DrawSetTextPos( txtX, txtY ); surface()->DrawUnicodeString( obj->text ); } // Apply Pulse if ( obj->pulse ) { float blink = SmoothCurve( obj->pulse_mod ); c[0] = c[0] + (blink * (255-c[0]) * 0.15f); c[1] = c[1] + (blink * (255-c[1]) * 0.15f); c[2] = c[2] + (blink * (255-c[2]) * 0.15f); // Modulate the blink obj->pulse_mod += 1.2f * gpGlobals->frametime; if ( obj->pulse_mod > 1.0f ) obj->pulse_mod -= 1.0f; } m_pCardTexture->DrawSelfRotated( x, y, card_w, card_h, theta, c ); } }
bool CParticleSystemQuery::IsPointInControllingObjectHitBox( CParticleCollection *pParticles, int nControlPointNumber, Vector vecPos, bool bBBoxOnly ) { bool bSuccess = false; #ifndef GAME_DLL EHANDLE *phMoveParent = reinterpret_cast<EHANDLE *> ( pParticles->m_ControlPoints[nControlPointNumber].m_pObject ); CBaseEntity *pMoveParent = NULL; if ( phMoveParent ) { pMoveParent = *( phMoveParent ); } if ( pMoveParent ) { s_BoneMutex.Lock(); C_BaseAnimating *pAnimating = pMoveParent->GetBaseAnimating(); bool bInBBox = false; Vector vecBBoxMin; Vector vecBBoxMax; Vector vecOrigin; vecBBoxMin = pMoveParent->CollisionProp()->OBBMins(); vecBBoxMax = pMoveParent->CollisionProp()->OBBMaxs(); matrix3x4_t matOrientation; matOrientation = pMoveParent->EntityToWorldTransform(); Vector vecLocalPos; VectorITransform( vecPos, matOrientation, vecLocalPos ); if ( IsPointInBox( vecLocalPos, vecBBoxMin, vecBBoxMax ) ) bInBBox = true; if ( bInBBox && bBBoxOnly ) bSuccess = true; else if ( pAnimating && bInBBox ) { matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; if ( pAnimating->HitboxToWorldTransforms( hitboxbones ) ) { studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() ); if ( pStudioHdr ) { mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() ); if ( set ) { // do a point in solid test Ray_t ray; trace_t tr; ray.Init( vecPos, vecPos ); enginetrace->ClipRayToEntity( ray, MASK_ALL, pMoveParent, &tr ); if ( tr.startsolid ) bSuccess = true; } } } } else if ( pMoveParent->IsBrushModel() && bInBBox ) { // do a point in solid test Ray_t ray; trace_t tr; ray.Init( vecPos, vecPos ); enginetrace->ClipRayToEntity( ray, MASK_ALL, pMoveParent, &tr ); if ( tr.startsolid ) bSuccess = true; } s_BoneMutex.Unlock(); } #endif return bSuccess; }
IterationRetval_t CPortalCollideableEnumerator::EnumElement( IHandleEntity *pHandleEntity ) { EHANDLE hEnt = pHandleEntity->GetRefEHandle(); CBaseEntity *pEnt = hEnt.Get(); if( pEnt == NULL ) //I really never thought this would be necessary return ITERATION_CONTINUE; if( hEnt == m_hTestPortal ) return ITERATION_CONTINUE; //ignore this portal /*if( staticpropmgr->IsStaticProp( pHandleEntity ) ) { //we're dealing with a static prop, which unfortunately doesn't have everything I want to use for checking ICollideable *pCollideable = pEnt->GetCollideable(); Vector vMins, vMaxs; pCollideable->WorldSpaceSurroundingBounds( &vMins, &vMaxs ); Vector ptTest( (m_vPlaneNormal.x > 0.0f)?(vMaxs.x):(vMins.x), (m_vPlaneNormal.y > 0.0f)?(vMaxs.y):(vMins.y), (m_vPlaneNormal.z > 0.0f)?(vMaxs.z):(vMins.z) ); float fPtPlaneDist = m_vPlaneNormal.Dot( ptTest ) - m_fPlaneDist; if( fPtPlaneDist <= 0.0f ) return ITERATION_CONTINUE; } else*/ { //not a static prop, w00t CCollisionProperty *pEntityCollision = pEnt->CollisionProp(); if( !pEntityCollision->IsSolid() ) return ITERATION_CONTINUE; //not solid Vector ptEntCenter = pEntityCollision->WorldSpaceCenter(); float fBoundRadius = pEntityCollision->BoundingRadius(); float fPtPlaneDist = m_vPlaneNormal.Dot( ptEntCenter ) - m_fPlaneDist; if( fPtPlaneDist < -fBoundRadius ) return ITERATION_CONTINUE; //object wholly behind the portal if( !(fPtPlaneDist > fBoundRadius) && (fPtPlaneDist > -fBoundRadius) ) //object is not wholly in front of the portal, but could be partially in front, do more checks { Vector ptNearest; pEntityCollision->CalcNearestPoint( m_ptForward1000, &ptNearest ); fPtPlaneDist = m_vPlaneNormal.Dot( ptNearest ) - m_fPlaneDist; if( fPtPlaneDist < 0.0f ) return ITERATION_CONTINUE; //closest point was behind the portal plane, we don't want it } } //if we're down here, this entity needs to be added to our enumeration Assert( m_iHandleCount < 1024 ); if( m_iHandleCount < 1024 ) m_pHandles[m_iHandleCount] = pHandleEntity; ++m_iHandleCount; return ITERATION_CONTINUE; }