void CClientLeafSystem::RemoveRenderable( ClientRenderHandle_t handle ) { // This can happen upon level shutdown if (!m_Renderables.IsValidIndex(handle)) return; // Reset the render handle in the entity. IClientRenderable *pRenderable = m_Renderables[handle].m_pRenderable; Assert( handle == pRenderable->RenderHandle() ); pRenderable->RenderHandle() = INVALID_CLIENT_RENDER_HANDLE; // Reemove the renderable from the dirty list if ( m_Renderables[handle].m_Flags & RENDER_FLAGS_HASCHANGED ) { // NOTE: This isn't particularly fast (linear search), // but I'm assuming it's an unusual case where we remove // renderables that are changing or that m_DirtyRenderables usually // only has a couple entries int i = m_DirtyRenderables.Find( handle ); Assert( i != m_DirtyRenderables.InvalidIndex() ); m_DirtyRenderables.FastRemove( i ); } if ( IsViewModelRenderGroup( (RenderGroup_t)m_Renderables[handle].m_RenderGroup ) ) { RemoveFromViewModelList( handle ); } RemoveFromTree( handle ); m_Renderables.Remove( handle ); }
static void GoToMarketplaceForOffer() { #ifdef _X360 // Stop installing to the hard drive, otherwise STFC fragmentation hazard, as multiple non sequential HDD writes will occur. // This needs to be done before the DLC might be downloaded to the HDD, otherwise it could be fragmented. // We restart the installer on DLC download completion. We do not handle the cancel/abort case. The installer // will restart through the pre-dlc path, i.e. after attract or exiting a map back to the main menu. if ( g_pXboxInstaller ) g_pXboxInstaller->Stop(); // See if we need to free some of the queries for ( int k = 0; k < g_arrMarketPlaceQueries.Count(); ++ k ) { X360MarketPlaceQuery *pQuery = g_arrMarketPlaceQueries[k]; if ( XHasOverlappedIoCompleted( &pQuery->xOverlapped ) ) { delete pQuery; g_arrMarketPlaceQueries.FastRemove( k -- ); } } // Allocate a new query X360MarketPlaceQuery *pQuery = new X360MarketPlaceQuery; memset( pQuery, 0, sizeof( *pQuery ) ); pQuery->uiOfferID = g_MarketplaceEntryPoint.uiOfferID; g_arrMarketPlaceQueries.AddToTail( pQuery ); // Open the marketplace entry point int iSlot = CBaseModPanel::GetSingleton().GetLastActiveUserId(); int iCtrlr = XBX_GetUserIsGuest( iSlot ) ? XBX_GetPrimaryUserId() : XBX_GetUserId( iSlot ); xonline->XShowMarketplaceDownloadItemsUI( iCtrlr, g_MarketplaceEntryPoint.dwEntryPoint, &pQuery->uiOfferID, 1, &pQuery->hResult, &pQuery->xOverlapped ); #endif }
//----------------------------------------------------------------------------- // 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; } }
void CSecobModportal1List::RemoveFromList( CNPC_SecobModportal1 *pSecobModportal1 ) { int index = m_list.Find( pSecobModportal1 ); if ( index != m_list.InvalidIndex() ) { m_list.FastRemove( index ); } }
void CBullseyeList::RemoveFromList( CNPC_Bullseye *pBullseye ) { int index = m_list.Find( pBullseye ); if ( index != m_list.InvalidIndex() ) { m_list.FastRemove( index ); } }
CModelLookupContext::~CModelLookupContext() { if ( m_lookupIndex >= 0 ) { Assert(m_lookupIndex == (g_ModelLookup.Count()-1)); g_ModelLookup.FastRemove(m_lookupIndex); g_ModelLookupIndex = g_ModelLookup.Count()-1; } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CCollisionEvent::UpdateFluidEvents( void ) { for ( int i = m_fluidEvents.Count()-1; i >= 0; --i ) { if ( (gpGlobals->curtime - m_fluidEvents[i].impactTime) > FLUID_TIME_MAX ) { m_fluidEvents.FastRemove(i); } } }
// Remove noitfication for an entity void CNotifyList::RemoveEntity( CBaseEntity *pNotify, CBaseEntity *pWatched ) { for ( int i = m_notifyList.Count(); --i >= 0; ) { if ( m_notifyList[i].pNotify == pNotify && m_notifyList[i].pWatched == pWatched) { m_notifyList.FastRemove(i); } } }
// UNDONE: Slow linear search? void CNotifyList::ClearEntity( CBaseEntity *pNotify ) { for ( int i = m_notifyList.Count(); --i >= 0; ) { if ( m_notifyList[i].pNotify == pNotify || m_notifyList[i].pWatched == pNotify) { m_notifyList.FastRemove(i); } } }
void CAI_FollowManager::RemoveGroup( AI_FollowGroup_t *pGroup ) { for ( int i = 0; i < m_groups.Count(); i++ ) { if ( m_groups[i] == pGroup ) { delete m_groups[i]; m_groups.FastRemove(i); return; } } }
// NOTE: This assumes entity pointers are sorted to simplify search! void CCollisionEvent::UpdatePenetrateEvents() { const float MAX_PENETRATION_TIME = 3.0f; for ( int i = m_penetrateEvents.Count()-1; i >= 0; --i ) { float timeSincePenetration = gpGlobals->curtime - m_penetrateEvents[i].timeStamp; if ( timeSincePenetration > 0.1f ) { m_penetrateEvents.FastRemove(i); continue; } float timeInPenetration = m_penetrateEvents[i].timeStamp - m_penetrateEvents[i].startTime; // it's been too long, just give up and disable collisions if ( timeInPenetration > MAX_PENETRATION_TIME ) { PhysDisableEntityCollisions( m_penetrateEvents[i].pEntity0, m_penetrateEvents[i].pEntity1 ); m_penetrateEvents.FastRemove(i); continue; } } }
// this samples the lighting at each sample and removes any unnecessary samples void CompressAmbientSampleList( CUtlVector<ambientsample_t> &list ) { Vector testCube[6]; for ( int i = 0; i < list.Count(); i++ ) { if ( list.Count() > 1 ) { Mod_LeafAmbientColorAtPos( testCube, list[i].pos, list, i ); if ( CubeDeltaGammaSpace(testCube, list[i].cube) < 3 ) { list.FastRemove(i); i--; } } } }
void Update() { if ( tickCount > gpGlobals->tickcount ) { list.RemoveAll(); return; } for ( int i = list.Count()-1; i >= 0; --i ) { if ( list[i].tickCount != gpGlobals->tickcount ) { list.FastRemove(i); } } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CDarknessLightSourcesSystem::AreThereLightSourcesWithinRadius( CBaseEntity *pLooker, float flRadius ) { float flRadiusSqr = (flRadius * flRadius); for ( int i = m_LightSources.Count() - 1; i >= 0; i-- ) { // Removed? if ( m_LightSources[i].hEntity == NULL || m_LightSources[i].hEntity->IsMarkedForDeletion() ) { m_LightSources.FastRemove( i ); continue; } CBaseEntity *pLightSource = m_LightSources[i].hEntity; // Close enough to a light source? float flDistanceSqr = (pLooker->WorldSpaceCenter() - pLightSource->GetAbsOrigin()).LengthSqr(); if ( flDistanceSqr < flRadiusSqr ) { trace_t tr; AI_TraceLine( pLooker->EyePosition(), pLightSource->GetAbsOrigin(), MASK_SOLID_BRUSHONLY, pLooker, COLLISION_GROUP_NONE, &tr ); if ( g_debug_darkness.GetBool() ) { if (tr.fraction != 1.0) { NDebugOverlay::Line( pLooker->WorldSpaceCenter(), tr.endpos, 255,0,0,true, 0.1); } else { NDebugOverlay::Line( pLooker->WorldSpaceCenter(), tr.endpos, 0,255,0,true, 0.1); NDebugOverlay::Line( pLightSource->GetAbsOrigin(), tr.endpos, 255,0,0,true, 0.1); } } if ( tr.fraction == 1.0 ) return true; } } return false; }
void CTilegenAction_FilterCandidatesByDirection::Execute( CLayoutSystem *pLayoutSystem ) { CUtlVector< CRoomCandidate > *pRoomCandidateList = pLayoutSystem->GetRoomCandidateList(); if ( pRoomCandidateList->Count() == 0 ) { return; } const char *pDirection = m_pDirectionExpression->Evaluate( pLayoutSystem->GetFreeVariables() ); int nThreshold = m_pThresholdExpression->Evaluate( pLayoutSystem->GetFreeVariables() ); nThreshold = MAX( 0, nThreshold ); ExitDirection_t direction = GetDirectionFromString( pDirection ); if ( direction < EXITDIR_BEGIN || direction >= EXITDIR_END ) { Log_Warning( LOG_TilegenLayoutSystem, "Invalid direction specified: %s.\n", pDirection ); return; } // First go through and figure out the highest score int nHighScore = INT_MIN; for ( int i = 0; i < pRoomCandidateList->Count(); ++ i ) { const CRoomCandidate *pCandidate = &pRoomCandidateList->Element( i ); int nScore = ComputeScore( direction, pCandidate->m_iXPos, pCandidate->m_iYPos ); if ( nScore > nHighScore ) { nHighScore = nScore; } } // Now go through and set the chance of each candidate to 1.0f for any with that score or 0.0f for those with a lower score // @TODO: allow for specifying a numerical range in which candidates are chosen for ( int i = pRoomCandidateList->Count() - 1; i >= 0; -- i ) { const CRoomCandidate *pCandidate = &pRoomCandidateList->Element( i ); if ( ComputeScore( direction, pCandidate->m_iXPos, pCandidate->m_iYPos ) < ( nHighScore - nThreshold ) ) { pRoomCandidateList->FastRemove( i ); } } }
//----------------------------------------------------------------------------- // Purpose: Update the active sounds, dequeue any events and move the ramps //----------------------------------------------------------------------------- void CSoundControllerImp::SystemUpdate( void ) { float time = g_pEffects->Time(); float deltaTime = time - m_flLastTime; // handle clock resets if ( deltaTime < 0 ) deltaTime = 0; m_flLastTime = time; while ( m_commandList.Count() ) { SoundCommand_t *pCmd = m_commandList.ElementAtHead(); // Commands are sorted by time. // process any that should occur by the current time if ( time >= pCmd->m_time ) { m_commandList.RemoveAtHead(); ProcessCommand( pCmd ); delete pCmd; } else { break; } } // NOTE: Because this loop goes from the end to the beginning // we can fast remove inside it without breaking the indexing for ( int i = m_soundList.Count()-1; i >=0; i-- ) { CSoundPatch *pNode = m_soundList[i]; if ( !pNode->Update( time, deltaTime ) ) { pNode->Reset(); m_soundList.FastRemove( i ); } } }
//----------------------------------------------------------------------------- // Purpose: Called by the sound system whenever a sound is played so that // active microphones can have a chance to pick up the sound. // Output : Returns whether or not the sound was swallowed by the microphone. // Swallowed sounds should not be played by the sound system. //----------------------------------------------------------------------------- bool CEnvMicrophone::OnSoundPlayed( int entindex, const char *soundname, soundlevel_t soundlevel, float flVolume, int iFlags, int iPitch, const Vector *pOrigin, float soundtime, CUtlVector< Vector >& soundorigins ) { bool bSwallowed = false; // Loop through all registered microphones and tell them the sound was just played int iCount = s_Microphones.Count(); if ( iCount > 0 ) { // Iterate backwards because we might be deleting microphones. for ( int i = iCount - 1; i >= 0; i-- ) { if ( s_Microphones[i] ) { MicrophoneResult_t eResult = s_Microphones[i]->SoundPlayed( entindex, soundname, soundlevel, flVolume, iFlags, iPitch, pOrigin, soundtime, soundorigins ); if ( eResult == MicrophoneResult_Swallow ) { // Microphone told us to swallow it bSwallowed = true; } else if ( eResult == MicrophoneResult_Remove ) { s_Microphones.FastRemove( i ); } } } } return bSwallowed; }
void CGlobalEntityList::OnRemoveEntity( IHandleEntity *pEnt, CBaseHandle handle ) { #ifdef DEBUG if ( !g_fInCleanupDelete ) { int i; for ( i = 0; i < g_DeleteList.Count(); i++ ) { if ( g_DeleteList[i]->GetEntityHandle() == pEnt ) { g_DeleteList.FastRemove( i ); Msg( "ERROR: Entity being destroyed but previously threaded on g_DeleteList\n" ); break; } } } #endif CBaseEntity *pBaseEnt = static_cast<IServerUnknown*>(pEnt)->GetBaseEntity(); if ( pBaseEnt->edict() ) m_iNumEdicts--; m_iNumEnts--; }
void CTilegenAction_FilterCandidatesForLinearGrowth::Execute( CLayoutSystem *pLayoutSystem ) { CUtlVector< CRoomCandidate > *pRoomCandidateList = pLayoutSystem->GetRoomCandidateList(); if ( pRoomCandidateList->Count() == 0 ) { return; } int nThreshold = m_pThresholdExpression->Evaluate( pLayoutSystem->GetFreeVariables() ); if ( nThreshold < 0 ) nThreshold = INT_MAX; // First go through and find the most recently placed source room. int nHighestPlacementIndex = -1; for ( int i = 0; i < pRoomCandidateList->Count(); ++ i ) { const CRoomCandidate *pCandidate = &pRoomCandidateList->Element( i ); const CRoom *pSourceRoom = pCandidate->m_pExit->pSourceRoom; if ( pSourceRoom->m_nPlacementIndex > nHighestPlacementIndex ) { nHighestPlacementIndex = pSourceRoom->m_nPlacementIndex; } } CMapLayout *pMapLayout = pLayoutSystem->GetMapLayout(); int nMinimumPlacementIndex = pMapLayout->m_PlacedRooms.Count() - 1 - nThreshold; // Now go through and remove any candidates not within the threshold of the most recently placed source room. for ( int i = pRoomCandidateList->Count() - 1; i >= 0; -- i ) { const CRoomCandidate *pCandidate = &pRoomCandidateList->Element( i ); if ( pCandidate->m_pExit->pSourceRoom->m_nPlacementIndex < nHighestPlacementIndex || pCandidate->m_pExit->pSourceRoom->m_nPlacementIndex < nMinimumPlacementIndex ) { pRoomCandidateList->FastRemove( i ); } } }
void CTilegenAction_AddConnectorRoomCandidates::Execute( CLayoutSystem *pLayoutSystem ) { CUtlVector< const CRoomTemplate * > roomTemplateList; if ( m_pTargetRoomTemplate != NULL ) { Assert( m_pTargetRoomTemplateFilter == NULL && m_pTargetThemeNameExpression == NULL ); roomTemplateList.AddToTail( m_pTargetRoomTemplate ); } else { Assert( m_pTargetRoomTemplateFilter != NULL && m_pTargetThemeNameExpression != NULL ); if ( m_pLevelTheme == NULL ) { const char *pThemeName = m_pTargetThemeNameExpression->Evaluate( pLayoutSystem->GetFreeVariables() ); m_pLevelTheme = CLevelTheme::FindTheme( pThemeName ); if ( m_pLevelTheme == NULL ) { Log_Warning( LOG_TilegenLayoutSystem, "Theme %s not found.\n", pThemeName ); pLayoutSystem->OnError(); return; } } BuildRoomTemplateList( pLayoutSystem, m_pLevelTheme, m_pTargetRoomTemplateFilter, true, &roomTemplateList ); } // Build a list of exit types we're looking for CUtlVector< CExit > desiredMatchingExits; for ( int i = 0; i < roomTemplateList.Count(); ++ i ) { const CRoomTemplate *pTemplate = roomTemplateList[i]; for ( int j = 0; j < pTemplate->m_Exits.Count(); ++ j ) { desiredMatchingExits.AddToTail( CExit( 0, 0, CRoomTemplateExit::GetOppositeDirection( pTemplate->m_Exits[j]->m_ExitDirection ), pTemplate->m_Exits[j]->m_szExitTag, NULL, false ) ); } } // Build up a room of connector candidates pLayoutSystem->ExecuteAction( m_pAddConnectorCandidates, NULL ); // Filter the set down by eliminating candidates which don't connect to the desired direction. CUtlVector< CRoomCandidate > *pRoomCandidateList = pLayoutSystem->GetRoomCandidateList(); CUtlVector< CExit > newOpenExits; for ( int i = pRoomCandidateList->Count() - 1; i >= 0; -- i ) { bool bMatch = false; newOpenExits.RemoveAll(); // Figure out which new exits would be open as a result of placing this room candidate. BuildOpenExitList( pRoomCandidateList->Element( i ), pLayoutSystem->GetMapLayout(), &newOpenExits ); // For every new open exit potentially created by this candidate, // see if one of them could connect to one of our desired exits. for ( int j = 0; j < newOpenExits.Count(); ++ j ) { const CExit *pNewOpenExit = &newOpenExits[j]; for ( int k = 0; k < desiredMatchingExits.Count(); ++ k ) { const CExit *pDesiredMatchingExit = &desiredMatchingExits[k]; if ( pNewOpenExit->ExitDirection == pDesiredMatchingExit->ExitDirection && Q_stricmp( pNewOpenExit->m_szExitTag, pDesiredMatchingExit->m_szExitTag ) == 0 ) { // Found a match! bMatch = true; break; } } if ( bMatch ) break; } if ( !bMatch ) { pRoomCandidateList->FastRemove( i ); } } }
// add the sample to the list. If we exceed the maximum number of samples, the worst sample will // be discarded. This has the effect of converging on the best samples when enough are added. void AddSampleToList( CUtlVector<ambientsample_t> &list, const Vector &samplePosition, Vector *pCube ) { const int MAX_SAMPLES = 16; int index = list.AddToTail(); list[index].pos = samplePosition; for ( int i = 0; i < 6; i++ ) { list[index].cube[i] = pCube[i]; } if ( list.Count() <= MAX_SAMPLES ) return; int nearestNeighborIndex = 0; float nearestNeighborDist = FLT_MAX; float nearestNeighborTotal = 0; for ( int i = 0; i < list.Count(); i++ ) { int closestIndex = 0; float closestDist = FLT_MAX; float totalDC = 0; for ( int j = 0; j < list.Count(); j++ ) { if ( j == i ) continue; float dist = (list[i].pos - list[j].pos).Length(); float maxDC = 0; for ( int k = 0; k < 6; k++ ) { // color delta is computed per-component, per cube side for (int s = 0; s < 3; s++ ) { float dc = fabs(list[i].cube[k][s] - list[j].cube[k][s]); maxDC = max(maxDC,dc); } totalDC += maxDC; } // need a measurable difference in color or we'll just rely on position if ( maxDC < 1e-4f ) { maxDC = 0; } else if ( maxDC > 1.0f ) { maxDC = 1.0f; } // selection criteria is 10% distance, 90% color difference // choose samples that fill the space (large distance from each other) // and have largest color variation float distanceFactor = 0.1f + (maxDC * 0.9f); dist *= distanceFactor; // find the "closest" sample to this one if ( dist < closestDist ) { closestDist = dist; closestIndex = j; } } // the sample with the "closest" neighbor is rejected if ( closestDist < nearestNeighborDist || (closestDist == nearestNeighborDist && totalDC < nearestNeighborTotal) ) { nearestNeighborDist = closestDist; nearestNeighborIndex = i; } } list.FastRemove( nearestNeighborIndex ); }
void CClientLeafSystem::RemoveFromViewModelList( ClientRenderHandle_t handle ) { int i = m_ViewModels.Find( handle ); Assert( i != m_ViewModels.InvalidIndex() ); m_ViewModels.FastRemove( i ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CDarknessLightSourcesSystem::IsEntityVisibleToTarget( CBaseEntity *pLooker, CBaseEntity *pTarget ) { if ( pTarget->IsEffectActive( EF_BRIGHTLIGHT ) || pTarget->IsEffectActive( EF_DIMLIGHT ) ) return true; bool bDebug = g_debug_darkness.GetBool(); if ( bDebug && pLooker ) { bDebug = (pLooker->m_debugOverlays & OVERLAY_NPC_SELECTED_BIT) != 0; } trace_t tr; // Loop through all the light sources. Do it backwards, so we can remove dead ones. for ( int i = m_LightSources.Count() - 1; i >= 0; i-- ) { // Removed? if ( m_LightSources[i].hEntity == NULL || m_LightSources[i].hEntity->IsMarkedForDeletion() ) { m_LightSources.FastRemove( i ); continue; } CInfoDarknessLightSource *pLightSource = m_LightSources[i].hEntity; // Close enough to a light source? float flDistanceSqr = (pTarget->WorldSpaceCenter() - pLightSource->GetAbsOrigin()).LengthSqr(); if ( flDistanceSqr < m_LightSources[i].flLightRadiusSqr ) { if ( pLightSource->ShouldIgnoreLOS() ) { if ( bDebug ) { NDebugOverlay::Line( pTarget->WorldSpaceCenter(), pLightSource->GetAbsOrigin(), 0,255,0,true, 0.1); } return true; } // Check LOS from the light to the target CTraceFilterSkipTwoEntities filter( pTarget, pLooker, COLLISION_GROUP_NONE ); AI_TraceLine( pTarget->WorldSpaceCenter(), pLightSource->GetAbsOrigin(), MASK_OPAQUE, &filter, &tr ); if ( tr.fraction == 1.0 ) { if ( bDebug ) { NDebugOverlay::Line( tr.startpos, tr.endpos, 0,255,0,true, 0.1); } return true; } if ( bDebug ) { NDebugOverlay::Line( tr.startpos, tr.endpos, 255,0,0,true, 0.1); NDebugOverlay::Line( tr.endpos, pLightSource->GetAbsOrigin(), 128,0,0,true, 0.1); } // If the target is within the radius of the light, don't do sillhouette checks continue; } if ( !pLooker ) continue; // Between a light source and the looker? Vector vecLookerToLight = (pLightSource->GetAbsOrigin() - pLooker->WorldSpaceCenter()); Vector vecLookerToTarget = (pTarget->WorldSpaceCenter() - pLooker->WorldSpaceCenter()); float flDistToSource = VectorNormalize( vecLookerToLight ); float flDistToTarget = VectorNormalize( vecLookerToTarget ); float flDot = DotProduct( vecLookerToLight, vecLookerToTarget ); if ( flDot > 0 ) { // Make sure the target is in front of the lightsource if ( flDistToTarget < flDistToSource ) { if ( bDebug ) { NDebugOverlay::Line( pLooker->WorldSpaceCenter(), pLooker->WorldSpaceCenter() + (vecLookerToLight * 128), 255,255,255,true, 0.1); NDebugOverlay::Line( pLooker->WorldSpaceCenter(), pLooker->WorldSpaceCenter() + (vecLookerToTarget * 128), 255,0,0,true, 0.1); } // Now, we need to find out if the light source is obscured by anything. // To do this, we want to calculate the point of intersection between the light source // sphere and the line from the looker through the target. float flASqr = (flDistToSource * flDistToSource); float flB = -2 * flDistToSource * flDot; float flCSqr = m_LightSources[i].flLightRadiusSqr; float flDesc = (flB * flB) - (4 * (flASqr - flCSqr)); if ( flDesc >= 0 ) { float flLength = (-flB - sqrt(flDesc)) / 2; Vector vecSpherePoint = pLooker->WorldSpaceCenter() + (vecLookerToTarget * flLength); // We've got the point of intersection. See if we can see it. CTraceFilterSkipTwoEntities filter( pTarget, pLooker, COLLISION_GROUP_NONE ); AI_TraceLine( pLooker->EyePosition(), vecSpherePoint, MASK_SOLID_BRUSHONLY, &filter, &tr ); if ( bDebug ) { if (tr.fraction != 1.0) { NDebugOverlay::Line( pLooker->WorldSpaceCenter(), vecSpherePoint, 255,0,0,true, 0.1); } else { NDebugOverlay::Line( pLooker->WorldSpaceCenter(), vecSpherePoint, 0,255,0,true, 0.1); NDebugOverlay::Line( pLightSource->GetAbsOrigin(), vecSpherePoint, 255,0,0,true, 0.1); } } if ( tr.fraction == 1.0 ) return true; } } } } return false; }
//----------------------------------------------------------------------------- // Purpose: Apply noise to the eye position. // UNDONE: Feedback a bit of this into the view model position. It shakes too much //----------------------------------------------------------------------------- void CViewEffects::CalcShake( void ) { float fraction, freq; // We'll accumulate the aggregate shake for this frame into these data members. m_vecShakeAppliedOffset.Init(0, 0, 0); m_flShakeAppliedAngle = 0; float flRumbleAngle = 0; bool bShow = shake_show.GetBool(); int nShakeCount = m_ShakeList.Count(); for ( int nShake = nShakeCount - 1; nShake >= 0; nShake-- ) { screenshake_t *pShake = m_ShakeList.Element( nShake ); if ( pShake->endtime == 0 ) { // Shouldn't be any such shakes in the list. Assert( false ); continue; } if ( ( gpGlobals->curtime > pShake->endtime ) || pShake->duration <= 0 || pShake->amplitude <= 0 || pShake->frequency <= 0 ) { // Retire this shake. delete m_ShakeList.Element( nShake ); m_ShakeList.FastRemove( nShake ); continue; } if ( bShow ) { con_nprint_t np; np.time_to_live = 2.0f; np.fixed_width_font = true; np.color[0] = 1.0; np.color[1] = 0.8; np.color[2] = 0.1; np.index = nShake + 2; engine->Con_NXPrintf( &np, "%02d: dur(%8.2f) amp(%8.2f) freq(%8.2f)", nShake + 1, (double)pShake->duration, (double)pShake->amplitude, (double)pShake->frequency ); } if ( gpGlobals->curtime > pShake->nextShake ) { // Higher frequency means we recalc the extents more often and perturb the display again pShake->nextShake = gpGlobals->curtime + (1.0f / pShake->frequency); // Compute random shake extents (the shake will settle down from this) for (int i = 0; i < 3; i++ ) { pShake->offset[i] = random->RandomFloat( -pShake->amplitude, pShake->amplitude ); } pShake->angle = random->RandomFloat( -pShake->amplitude*0.25, pShake->amplitude*0.25 ); } // Ramp down amplitude over duration (fraction goes from 1 to 0 linearly with slope 1/duration) fraction = ( pShake->endtime - gpGlobals->curtime ) / pShake->duration; // Ramp up frequency over duration if ( fraction ) { freq = (pShake->frequency / fraction); } else { freq = 0; } // square fraction to approach zero more quickly fraction *= fraction; // Sine wave that slowly settles to zero float angle = gpGlobals->curtime * freq; if ( angle > 1e8 ) { angle = 1e8; } fraction = fraction * sin( angle ); if( pShake->command != SHAKE_START_NORUMBLE ) { // As long as this isn't a NO RUMBLE effect, then accumulate rumble flRumbleAngle += pShake->angle * fraction; } if( pShake->command != SHAKE_START_RUMBLEONLY ) { // As long as this isn't a RUMBLE ONLY effect, then accumulate screen shake // Add to view origin m_vecShakeAppliedOffset += pShake->offset * fraction; // Add to roll m_flShakeAppliedAngle += pShake->angle * fraction; } // Drop amplitude a bit, less for higher frequency shakes pShake->amplitude -= pShake->amplitude * ( gpGlobals->frametime / (pShake->duration * pShake->frequency) ); } // Feed this to the rumble system! UpdateScreenShakeRumble( flRumbleAngle ); }
void CGEObjectives::OnThink( void ) { if ( m_flNextThink > gpGlobals->curtime ) return; // If we aren't drawing, don't think CBasePlayer *pLocalPlayer = CBasePlayer::GetLocalPlayer(); if ( !ShouldDraw() || !pLocalPlayer ) { ThinkAdvance( 0.5f ); return; } // Clear our validity flags for ( int i=0; i < m_vObjectives.Count(); i++ ) m_vObjectives[i]->valid = false; int plr_serial = pLocalPlayer->GetRefEHandle().ToInt(); vgui::HFont text_font = scheme()->GetIScheme( GetScheme() )->GetFont("GETargetID", true); // Go through our Radar Resource to get any new entities / updates to existing ones for( int i=0; i < MAX_NET_RADAR_ENTS; ++i ) { if ( !g_RR->IsObjective(i) || g_RR->GetState(i) != RADAR_STATE_DRAW ) continue; int team = g_RR->GetObjectiveTeam(i); int serial = g_RR->GetEntSerial(i); const char *tkn = g_RR->GetObjectiveToken(i); bool tkn_held = true; if ( tkn[0] == '!' ) { tkn++; tkn_held = false; } if ( serial != plr_serial && (team == TEAM_UNASSIGNED || team == pLocalPlayer->GetTeamNumber()) && (!tkn[0] || (pLocalPlayer->Weapon_OwnsThisType(tkn) != NULL) == tkn_held) && (!pLocalPlayer->GetObserverTarget() || pLocalPlayer->GetObserverTarget()->GetRefEHandle().ToInt() != serial)) { GEObjective *obj = FindObjective( serial ); if ( !obj ) { // New objective! Initialize us obj = new GEObjective; obj->hEnt = EHANDLE::FromIndex( serial ); obj->curr_pos = g_RR->GetOrigin(i); obj->pulse_mod = 0; obj->refText[0] = '\0'; obj->text[0] = L'\0'; m_vObjectives.AddToTail( obj ); } // Ensure text is the same if ( Q_strcmp( obj->refText, g_RR->GetObjectiveText(i) ) ) { Q_strncpy( obj->refText, g_RR->GetObjectiveText(i), 32 ); GEUTIL_ParseLocalization( obj->text, 16, g_RR->GetObjectiveText(i) ); GEUTIL_GetTextSize( obj->text, text_font, obj->txtW, obj->txtH ); } obj->last_pos = obj->curr_pos; obj->curr_pos = g_RR->GetOrigin(i); obj->min_dist = max( g_RR->GetObjectiveMinDist(i), OBJ_ABS_MIN_DIST ); obj->update_time = gpGlobals->curtime; obj->pulse = g_RR->GetObjectivePulse(i); obj->color = g_RR->GetObjectiveColor(i); obj->valid = true; } } // Delete defunct objectives for ( int i=0; i < m_vObjectives.Count(); i++ ) { if ( !m_vObjectives[i]->valid ) { GEObjective *obj = m_vObjectives[i]; m_vObjectives.FastRemove(i); delete obj; } } ThinkAdvance( RADAR_THINK_INT * 0.75f ); }
//--------------------------------------------------------- // Count of all the weapons in the world of my type and // see if we have a surplus. If there is a surplus, try // to find suitable candidates for removal. // // Right now we just remove the first weapons we find that // are behind the player, or are out of the player's PVS. // Later, we may want to score the results so that we // removed the farthest gun that's not in the player's // viewcone, etc. // // Some notes and thoughts: // // This code is designed NOT to remove weapons that are // hand-placed by level designers. It should only clean // up weapons dropped by dead NPCs, which is useful in // situations where enemies are spawned in for a sustained // period of time. // // Right now we PREFER to remove weapons that are not in the // player's PVS, but this could be opposite of what we // really want. We may only want to conduct the cleanup on // weapons that are IN the player's PVS. //--------------------------------------------------------- void CGameWeaponManager::Think() { int i; // Don't have to think all that often. SetNextThink( gpGlobals->curtime + 2.0 ); const char *pszWeaponName = STRING( m_iszWeaponName ); CUtlVector<CBaseEntity *> candidates( 0, 64 ); if ( m_bExpectingWeapon ) { CBaseCombatWeapon *pWeapon = NULL; // Firstly, count the total number of weapons of this type in the world. // Also count how many of those can potentially be removed. pWeapon = assert_cast<CBaseCombatWeapon *>(gEntList.FindEntityByClassname( pWeapon, pszWeaponName )); while( pWeapon ) { if( !pWeapon->IsEffectActive( EF_NODRAW ) && pWeapon->IsRemoveable() ) { candidates.AddToTail( pWeapon ); } pWeapon = assert_cast<CBaseCombatWeapon *>(gEntList.FindEntityByClassname( pWeapon, pszWeaponName )); } } else { for ( i = 0; i < m_ManagedNonWeapons.Count(); i++) { CBaseEntity *pEntity = m_ManagedNonWeapons[i]; if ( pEntity ) { Assert( pEntity->m_iClassname == m_iszWeaponName ); if ( !pEntity->IsEffectActive( EF_NODRAW ) ) { candidates.AddToTail( pEntity ); } } else { m_ManagedNonWeapons.FastRemove( i-- ); } } } // Calculate the surplus. int surplus = candidates.Count() - m_iMaxPieces; // Based on what the player can see, try to clean up the world by removing weapons that // the player cannot see right at the moment. CBaseEntity *pCandidate; for ( i = 0; i < candidates.Count() && surplus > 0; i++ ) { bool fRemovedOne = false; pCandidate = candidates[i]; Assert( !pCandidate->IsEffectActive( EF_NODRAW ) ); // if ( gpGlobals->maxClients == 1 ) { CBasePlayer *pPlayer = UTIL_GetNearestVisiblePlayer(pCandidate); // Nodraw serves as a flag that this weapon is already being removed since // all we're really doing inside this loop is marking them for removal by // the entity system. We don't want to count the same weapon as removed // more than once. if( !UTIL_FindClientInPVS( pCandidate->edict() ) ) { fRemovedOne = true; } else if( !pPlayer->FInViewCone( pCandidate ) ) { fRemovedOne = true; } else if ( UTIL_DistApprox( pPlayer->GetAbsOrigin(), pCandidate->GetAbsOrigin() ) > (30*12) ) { fRemovedOne = true; } } // else // { // fRemovedOne = true; // } if( fRemovedOne ) { pCandidate->AddEffects( EF_NODRAW ); UTIL_Remove( pCandidate ); DevMsg( 2, "Surplus %s removed\n", pszWeaponName); surplus--; } } }
//--------------------------------------------------------- // Purpose: See if it is time to poll and do so. // // SOON: We need to load-balance this. //--------------------------------------------------------- void CVisibilityMonitor::FrameUpdatePostEntityThink() { if( gpGlobals->curtime < m_flTimeNextPoll ) return; m_flTimeNextPoll = gpGlobals->curtime + vismon_poll_frequency.GetFloat(); int iDebugging = debug_visibility_monitor.GetInt(); if( m_Entities.Count() > m_iMaxEntitiesPerThink ) m_iMaxEntitiesPerThink = m_Entities.Count(); if( iDebugging > 1 ) { Msg("\nVisMon: Polling now. (Frequency: %f)\n", m_flPollFrequency ); Msg("VisMon: Time: %f - Tracking %d Entities. (Max:%d)\n", gpGlobals->curtime, m_Entities.Count(), m_iMaxEntitiesPerThink ); } // Cleanup, dump entities that have been removed since we last polled. for ( int i = 0 ; i < m_Entities.Count() ; i++ ) { if ( m_Entities[i].entity == NULL ) { m_Entities.FastRemove(i); if ( i >= m_Entities.Count() ) { break; } } } int numTraces = 0; bool bHitTraceLimit = false; if( m_iStartElement >= m_Entities.Count() ) { if( iDebugging > 1 ) { Msg("VisMon: RESET\n"); } m_iStartElement = 0; } if( iDebugging > 1 ) { Msg("VisMon: Starting at element: %d\n", m_iStartElement ); } for( int i = m_iStartElement ; i < m_Entities.Count() ; i++ ) { for( int j = 1 ; j <= gpGlobals->maxClients ; j++ ) { CBasePlayer *pPlayer =UTIL_PlayerByIndex( j ); if( pPlayer != NULL && pPlayer->IsAlive() && !pPlayer->IsBot() ) { int memoryBit = 1 << j; // The bit that is used to remember whether a given entity has been seen by a given player. CBaseEntity *pSeeEntity = m_Entities[ i ].entity.Get(); if( pSeeEntity == NULL ) { continue; } if( !(m_Entities[i].memory & memoryBit) ) { // If this player hasn't seen this entity yet, check it. if( EntityIsVisibleToPlayer( m_Entities[i], pPlayer, &numTraces ) ) { bool bIgnore = false; if( m_Entities[i].pfnEvaluator != NULL && !m_Entities[i].pfnEvaluator( m_Entities[i].entity, pPlayer ) ) { bIgnore = true; } // See it! Generate our event. if( iDebugging > 0 ) { if( bIgnore ) { Msg("VisMon: Player %s IGNORING VISIBILE Entity: %s\n", pPlayer->GetDebugName(), pSeeEntity->GetDebugName() ); NDebugOverlay::Cross3D( pSeeEntity->WorldSpaceCenter(), 16, 255, 0, 0, false, 10.0f ); } else { Msg("VisMon: Player %s sees Entity: %s\n", pPlayer->GetDebugName(), pSeeEntity->GetDebugName() ); NDebugOverlay::Cross3D( pSeeEntity->WorldSpaceCenter(), 16, 0, 255, 0, false, 10.0f ); } } if( !bIgnore ) { bool bGenerateEvent = true; if( m_Entities[i].pfnCallback != NULL ) { // Make the callback, and let it determine whether to generate the simple event. bGenerateEvent = m_Entities[i].pfnCallback( m_Entities[i].entity, pPlayer ); } if( bGenerateEvent ) { // No callback, generate the generic game event. IGameEvent * event = gameeventmanager->CreateEvent( "entity_visible" ); if ( event ) { event->SetInt( "userid", pPlayer->GetUserID() ); event->SetInt( "subject", pSeeEntity->entindex() ); event->SetString( "classname", pSeeEntity->GetClassname() ); event->SetString( "entityname", STRING( pSeeEntity->GetEntityName() ) ); gameeventmanager->FireEvent( event ); } } // Remember that this entity was visible to the player m_Entities[i].memory |= memoryBit; } } } } } if( numTraces >= vismon_trace_limit.GetInt() ) { if( iDebugging > 1 ) { Msg("VisMon: MAX Traces. Stopping after element %d\n", i ); } m_iStartElement = i + 1; // Pick up here next think. bHitTraceLimit = true; break; } } if( !bHitTraceLimit ) { m_iStartElement = 0; } if( numTraces > m_iMaxTracesPerThink ) m_iMaxTracesPerThink = numTraces; if( iDebugging > 1 ) { Msg("VisMon: %d traces performed during this polling cycle (Max: %d)\n\n", numTraces, m_iMaxTracesPerThink ); } }