void CClientStreamer::AddToSortedList ( list < CClientStreamElement* > * pList, CClientStreamElement * pElement ) { // Make sure it's exp distance is updated float fDistance = pElement->GetDistanceToBoundingBoxSquared ( m_vecPosition ); pElement->SetExpDistance ( fDistance ); // Don't add if already in the list if ( ListContains ( *pList, pElement ) ) return; // Search through our list. Add it behind the first item further away than this CClientStreamElement * pTemp = NULL; list < CClientStreamElement* > :: iterator iter = pList->begin (); for ( ; iter != pList->end (); iter++ ) { pTemp = *iter; // Is it further than the one we add? if ( pTemp->GetDistanceToBoundingBoxSquared ( m_vecPosition ) > fDistance ) { // Add it before here pList->insert ( iter, pElement ); return; } } // We have no elements in the list, add it at the beginning pList->push_back ( pElement ); }
void CClientStreamer::OnEnterSector ( CClientStreamSector * pSector ) { CClientStreamElement * pElement = NULL; if ( m_pSector ) { // Grab the unwanted sectors list < CClientStreamSector * > common, uncommon; pSector->CompareSurroundings ( m_pSector, &common, &uncommon, true ); // Deactivate the unwanted sectors CClientStreamSector * pTempSector = NULL; list < CClientStreamSector * > ::iterator iter = uncommon.begin (); for ( ; iter != uncommon.end () ; iter++ ) { pTempSector = *iter; // Make sure we dont unload our new sector if ( pTempSector != pSector ) { if ( pTempSector->IsActivated () ) { list < CClientStreamElement * > ::iterator iter = pTempSector->Begin (); for ( ; iter != pTempSector->End () ; iter++ ) { pElement = *iter; if ( pElement->IsStreamedIn () ) { // Add it to our streaming out list m_ToStreamOut.push_back ( pElement ); } } pTempSector->RemoveElements ( &m_ActiveElements ); pTempSector->SetActivated ( false ); } } } // Grab the wanted sectors m_pSector->CompareSurroundings ( pSector, &common, &uncommon, true ); // Activate the unwanted sectors iter = uncommon.begin (); for ( ; iter != uncommon.end () ; iter++ ) { pTempSector = *iter; if ( !pTempSector->IsActivated () ) { pTempSector->AddElements ( &m_ActiveElements ); pTempSector->SetActivated ( true ); } } } m_pSector = pSector; SetExpDistances ( &m_ActiveElements ); m_ActiveElements.sort ( CompareExpDistance ); }
void CClientStreamer::SetExpDistances ( list < CClientStreamElement * > * pList ) { // Run through our list setting distances to world center CClientStreamElement * pElement = NULL; list < CClientStreamElement* >:: iterator iter = pList->begin (); for ( ; iter != pList->end (); iter++ ) { pElement = *iter; // Set its distance ^ 2 pElement->SetExpDistance ( pElement->GetDistanceToBoundingBoxSquared ( m_vecPosition ) ); } }
void CClientStreamElement::UpdateStreamPosition ( const CVector & vecPosition ) { m_vecStreamPosition = vecPosition; m_pStreamer->OnUpdateStreamPosition ( this ); m_pManager->OnUpdateStreamPosition ( this ); // Update attached elements stream position list < CClientEntity* >::iterator i = m_AttachedEntities.begin(); for (; i != m_AttachedEntities.end(); i++) { CClientStreamElement* attachedElement = dynamic_cast< CClientStreamElement* > (*i); if ( attachedElement ) { attachedElement->UpdateStreamPosition( vecPosition + attachedElement->m_vecAttachedPosition ); } } }
void CClientStreamElement::InternalStreamOut ( void ) { if ( m_bStreamedIn ) { StreamOut (); m_bStreamedIn = false; // Stream out attached elements list < CClientEntity* >::iterator i = m_AttachedEntities.begin(); for (; i != m_AttachedEntities.end(); i++) { CClientStreamElement* attachedElement = dynamic_cast< CClientStreamElement* > (*i); if ( attachedElement ) { attachedElement->InternalStreamOut(); } } CLuaArguments Arguments; CallEvent ( "onClientElementStreamOut", Arguments, true ); } }
void CClientStreamer::SetDimension ( unsigned short usDimension ) { // Different dimension than before? if ( usDimension != m_usDimension ) { // Set the new dimension m_usDimension = usDimension; // That means all of the currently streamed in elements will have to // go. Unstream all elements that are streamed in. CClientStreamElement * pElement = NULL; list < CClientStreamElement * > ::iterator iter = m_ActiveElements.begin (); for ( ; iter != m_ActiveElements.end () ; iter++ ) { pElement = *iter; if ( pElement->IsStreamedIn () ) { // Unstream it m_ToStreamOut.push_back ( pElement ); } } } }
void CClientStreamer::Restream ( bool bMovedFar ) { // Limit distance stream in/out rate // Vehicles might have to ignore this to reduce blocking loads elsewhere. int iMaxOut = 6; int iMaxIn = 6; if ( bMovedFar ) { iMaxOut = 1000; iMaxIn = 1000; } // Do we have any elements waiting to be streamed out? while ( !m_ToStreamOut.empty () ) { CClientStreamElement* pElement = m_ToStreamOut.front (); // Make sure we have no stream-references if ( pElement->GetTotalStreamReferences () == 0 ) { // Stream out 1 of them per frame pElement->InternalStreamOut (); iMaxOut--; } m_ToStreamOut.remove ( pElement ); if ( iMaxOut <= 0 ) break; } static std::vector < CClientStreamElement* > ClosestStreamedOutList; static std::vector < CClientStreamElement* > FurthestStreamedInList; ClosestStreamedOutList.clear(); FurthestStreamedInList.clear(); bool bReachedLimit = ReachedLimit (); // Loop through our active elements list (they should be ordered closest to furthest) list < CClientStreamElement* > ::iterator iter = m_ActiveElements.begin (); for ( ; iter != m_ActiveElements.end (); iter++ ) { CClientStreamElement* pElement = *iter; float fElementDistanceExp = pElement->GetExpDistance (); // Is this element streamed in? if ( pElement->IsStreamedIn () ) { if ( IS_VEHICLE ( pElement ) ) { CClientVehicle* pVehicle = DynamicCast < CClientVehicle > ( pElement ); if ( pVehicle ) { if ( pVehicle->GetOccupant ( ) && IS_PLAYER ( pVehicle->GetOccupant ( ) ) ) { CClientPlayer* pPlayer = DynamicCast < CClientPlayer > ( pVehicle->GetOccupant ( ) ); if ( pPlayer->GetLastPuresyncType ( ) == PURESYNC_TYPE_LIGHTSYNC ) { // if the last packet was ls he shouldn't be streamed in m_ToStreamOut.push_back ( pElement ); } } // Is this a trailer? if ( pVehicle->GetTowedByVehicle ( ) != NULL ) { // Don't stream it out (this is handled by the towing vehicle) continue; } } } if ( IS_PLAYER ( pElement ) ) { CClientPlayer* pPlayer = DynamicCast < CClientPlayer > ( pElement ); if ( pPlayer->GetLastPuresyncType ( ) == PURESYNC_TYPE_LIGHTSYNC ) { // if the last packet was ls he isn't/shouldn't be streamed in m_ToStreamOut.push_back ( pElement ); } } // Too far away? Use the threshold so we won't flicker load it if it's on the border moving. if ( fElementDistanceExp > m_fMaxDistanceThreshold ) { // Unstream it now? if ( iMaxOut > 0 ) { // Make sure we have no stream-references if ( pElement->GetTotalStreamReferences () == 0 ) { // Stream out now pElement->InternalStreamOut (); iMaxOut--; } m_ToStreamOut.remove ( pElement ); } else { // or later m_ToStreamOut.push_back ( pElement ); } } else { FurthestStreamedInList.push_back( pElement ); } } else { // Same dimension as us? if ( pElement->GetDimension () == m_usDimension ) { // Too far away? Stop here. if ( fElementDistanceExp > m_fMaxDistanceExp ) continue; if ( IS_VEHICLE ( pElement ) ) { CClientVehicle* pVehicle = DynamicCast < CClientVehicle > ( pElement ); if ( pVehicle && pVehicle->GetOccupant ( ) && IS_PLAYER ( pVehicle->GetOccupant ( ) )) { CClientPlayer* pPlayer = DynamicCast < CClientPlayer > ( pVehicle->GetOccupant ( ) ); if ( pPlayer->GetLastPuresyncType ( ) == PURESYNC_TYPE_LIGHTSYNC ) { // if the last packet was ls he isn't streaming in soon. continue; } } if ( pVehicle && pVehicle->GetTowedByVehicle ( ) ) { // Streaming in of towed vehicles is done in CClientVehicle::StreamIn by the towing vehicle continue; } } if ( IS_PLAYER ( pElement ) ) { CClientPlayer* pPlayer = DynamicCast < CClientPlayer > ( pElement ); if ( pPlayer->GetLastPuresyncType ( ) == PURESYNC_TYPE_LIGHTSYNC ) { // if the last packet was ls he isn't streaming in soon. continue; } } // If attached and attached-to is streamed out, don't consider for streaming in CClientStreamElement* pAttachedTo = DynamicCast< CClientStreamElement >( pElement->GetAttachedTo() ); if ( pAttachedTo && !pAttachedTo->IsStreamedIn() ) { // ...unless attached to low LOD version CClientObject* pAttachedToObject = DynamicCast < CClientObject > ( pAttachedTo ); CClientObject* pObject = DynamicCast < CClientObject > ( pElement ); if ( !pObject || !pAttachedToObject || pObject->IsLowLod () == pAttachedToObject->IsLowLod () ) continue; } // Not room to stream in more elements? if ( bReachedLimit ) { // Add to the list that might be streamed in during the final phase if ( (int)ClosestStreamedOutList.size() < iMaxIn ) // (only add if there is a chance it will be used) ClosestStreamedOutList.push_back( pElement ); } else { // Stream in the new element. Don't do it instantly unless moved from far away. pElement->InternalStreamIn ( bMovedFar ); bReachedLimit = ReachedLimit (); if ( !bReachedLimit ) { iMaxIn--; if ( iMaxIn <= 0 ) break; } } } } } // Complex code of doom: // ClosestStreamedOutList is {nearest to furthest} list of streamed out elements within streaming distance // FurthestStreamedInList is {nearest to furthest} list of streamed in elements if ( bReachedLimit ) { // Check 'furthest streamed in' against 'closest streamed out' to see if the state can be swapped int iFurthestStreamedInIndex = FurthestStreamedInList.size() - 1; uint uiClosestStreamedOutIndex = 0; for( uint i = 0 ; i < 10 ; i++ ) { // Check limits for this frame if ( iMaxIn <= 0 || iMaxOut <= 0 ) break; // Check indicies are valid if ( iFurthestStreamedInIndex < 0 ) break; if ( uiClosestStreamedOutIndex >= ClosestStreamedOutList.size() ) break; // See if ClosestStreamedOut is nearer than FurthestStreamedIn CClientStreamElement* pFurthestStreamedIn = FurthestStreamedInList[ iFurthestStreamedInIndex ]; CClientStreamElement* pClosestStreamedOut = ClosestStreamedOutList[ uiClosestStreamedOutIndex ]; if ( pClosestStreamedOut->GetExpDistance () >= pFurthestStreamedIn->GetExpDistance () ) break; // Stream out FurthestStreamedIn candidate if possible if ( pFurthestStreamedIn->GetTotalStreamReferences () == 0 ) { // Stream out now pFurthestStreamedIn->InternalStreamOut (); iMaxOut--; } m_ToStreamOut.remove ( pFurthestStreamedIn ); iFurthestStreamedInIndex--; // Always advance to the next candidate // Stream in ClosestStreamedOut candidate if possible if ( !ReachedLimit () ) { // Stream in the new element. No need to do it instantly unless moved from far away. pClosestStreamedOut->InternalStreamIn ( bMovedFar ); iMaxIn--; uiClosestStreamedOutIndex++; } } } }
void CNametags::DrawDefault() { // Grab the resolution width and height static float fResWidth = static_cast<float>(g_pCore->GetGraphics()->GetViewportWidth()); static float fResHeight = static_cast<float>(g_pCore->GetGraphics()->GetViewportHeight()); // Got any players that are not local? if (m_pPlayerManager->Count() <= 1) return; list<CClientPlayer*> playerTags; // Grab the local player CClientPlayer* pLocalPlayer = m_pPlayerManager->GetLocalPlayer(); if (!pLocalPlayer) return; CClientVehicle* pSniperTargetedVehicle = NULL; CClientPlayer* pSniperTargetedPlayer = NULL; // Grab our current weapon slot. Use screen center if melee or none eWeaponSlot eSlot = pLocalPlayer->GetCurrentWeaponSlot(); if (eSlot >= WEAPONSLOT_TYPE_HANDGUN && eSlot <= WEAPONSLOT_TYPE_RIFLE) { CVector vecOrigin, vecTarget; pLocalPlayer->GetShotData(&vecOrigin, &vecTarget); // Ignore the local player for this pLocalPlayer->WorldIgnore(true); // Do the raycast CColPoint* pColPoint = NULL; CEntity* pEntity = NULL; SLineOfSightFlags flags; flags.bCheckBuildings = true; flags.bCheckVehicles = true; flags.bCheckPeds = true; flags.bCheckObjects = true; flags.bCheckDummies = true; flags.bSeeThroughStuff = true; flags.bIgnoreSomeObjectsForCamera = false; flags.bShootThroughStuff = true; g_pGame->GetWorld()->ProcessLineOfSight(&vecOrigin, &vecTarget, &pColPoint, &pEntity, flags); if (pColPoint) pColPoint->Destroy(); // Un-ignore the local player pLocalPlayer->WorldIgnore(false); // Did we find an entity? if (pEntity) { // Grab the CClientEntity belonging to this game_sa entity CClientEntity* pClientEntity = reinterpret_cast<CClientEntity*>(pEntity->GetStoredPointer()); if (pClientEntity) { // Is it a vehicle? Is it a ped? eClientEntityType EntityType = pClientEntity->GetType(); switch (EntityType) { case CCLIENTVEHICLE: { pSniperTargetedVehicle = static_cast<CClientVehicle*>(pClientEntity); break; } case CCLIENTPLAYER: { pSniperTargetedPlayer = static_cast<CClientPlayer*>(pClientEntity); break; } default: break; } } } } // Grab the local player vehicle CClientVehicle* pLocalVehicle = pLocalPlayer->GetOccupiedVehicle(); CVehicle* pLocalGameVehicle = NULL; if (pLocalVehicle) pLocalGameVehicle = pLocalVehicle->GetGameVehicle(); CMatrix CameraMatrix; g_pGame->GetCamera()->GetMatrix(&CameraMatrix); // Remove collision from our local vehicle (if we have one) if (pLocalVehicle) pLocalVehicle->WorldIgnore(true); // Draw the nametags we need to CVector vecPlayerPosition; CClientVehicle* pPlayerVehicle = NULL; float fDistanceExp; bool bCollision; CColPoint* pColPoint = NULL; CEntity* pGameEntity = NULL; CClientEntity* pEntity = NULL; CClientPlayer* pPlayer; CClientStreamElement* pElement; list<CClientStreamElement*>::const_iterator iter = m_pPlayerStreamer->ActiveElementsBegin(); for (; iter != m_pPlayerStreamer->ActiveElementsEnd(); ++iter) { pElement = *iter; if (!pElement->IsStreamedIn()) continue; if (pElement->GetType() != CCLIENTPLAYER) continue; pPlayer = static_cast<CClientPlayer*>(pElement); if (pPlayer->IsLocalPlayer()) continue; // Get the distance from the camera pPlayer->GetPosition(vecPlayerPosition); fDistanceExp = pPlayer->GetExpDistance(); pPlayerVehicle = pPlayer->GetOccupiedVehicle(); // Is he in the same vehicle as the local player? if ((pSniperTargetedPlayer == pPlayer) || (pSniperTargetedVehicle && pSniperTargetedVehicle == pPlayerVehicle) || (pLocalVehicle && pLocalVehicle == pPlayerVehicle) || (fDistanceExp < DEFAULT_VIEW_RANGE_EXP && pPlayer->IsOnScreen())) { SLineOfSightFlags flags; flags.bCheckBuildings = true; flags.bCheckVehicles = true; flags.bCheckPeds = false; flags.bCheckObjects = true; bCollision = g_pCore->GetGame()->GetWorld()->ProcessLineOfSight(&CameraMatrix.vPos, &vecPlayerPosition, &pColPoint, &pGameEntity, flags); if (!bCollision || (pGameEntity && pPlayerVehicle && pGameEntity == pPlayerVehicle->GetGameEntity())) { pPlayer->SetNametagDistance(sqrt(fDistanceExp)); playerTags.push_front(pPlayer); } // Destroy the colpoint if (pColPoint) pColPoint->Destroy(); } } // Readd collision from our local vehicle (if we have one) if (pLocalVehicle) pLocalVehicle->WorldIgnore(false); // Draw each player's nametag float fAlphaModifier; unsigned char ucAlpha; float fDistance; list<CClientPlayer*>::iterator iterTags = playerTags.begin(); for (; iterTags != playerTags.end(); ++iterTags) { pPlayer = *iterTags; fDistance = pPlayer->GetNametagDistance(); static float fFullAlphaDistance = 7.0f; if ((fDistance < fFullAlphaDistance) || (pSniperTargetedPlayer && pSniperTargetedPlayer == pPlayer) || (pSniperTargetedVehicle && pSniperTargetedVehicle == pPlayer->GetOccupiedVehicle())) { fAlphaModifier = 1.0f; } else { fAlphaModifier = 1.0f - ((fDistance - fFullAlphaDistance) / (DEFAULT_VIEW_RANGE - fFullAlphaDistance)); } // Calculate the alpha for the nametag ucAlpha = static_cast<unsigned char>(180.0f * fAlphaModifier); // Draw the tag DrawTagForPlayer(pPlayer, ucAlpha); } }
void CNametags::DrawFromAim() { unsigned long ulCurrentTime = CClientTime::GetTime(); // Got any players that are not local? if (m_pPlayerManager->Count() > 1) { // Grab the local player CClientPlayer* pLocalPlayer = m_pPlayerManager->GetLocalPlayer(); if (pLocalPlayer) { // Grab the current time and the camera unsigned long ulCurrentTime = CClientTime::GetTime(); CCamera* pCamera = g_pGame->GetCamera(); // Grab our controller state CControllerState State; g_pGame->GetPad()->GetCurrentControllerState(&State); // Grab our current weapon slot. Use screen center if melee or none CVector vecStart; CVector vecTarget; eWeaponSlot eSlot = pLocalPlayer->GetCurrentWeaponSlot(); if (eSlot == WEAPONSLOT_TYPE_UNARMED || eSlot == WEAPONSLOT_TYPE_MELEE || eSlot == WEAPONSLOT_TYPE_RIFLE || eSlot == WEAPONSLOT_TYPE_THROWN || eSlot == WEAPONSLOT_TYPE_SPECIAL || eSlot == WEAPONSLOT_TYPE_GIFT || eSlot == WEAPONSLOT_TYPE_PARACHUTE || eSlot == WEAPONSLOT_TYPE_DETONATOR) { // Grab the active cam CCamera* pCamera = g_pGame->GetCamera(); CCam* pActive = pCamera->GetCam(pCamera->GetActiveCam()); // Grab the camera matrix CMatrix matCamera; pCamera->GetMatrix(&matCamera); vecStart = matCamera.vPos; // Range float fRange; eWeaponType eWeapon = pLocalPlayer->GetCurrentWeaponType(); float fSkill = pLocalPlayer->GetStat(g_pGame->GetStats()->GetSkillStatIndex(eWeapon)); CWeaponStat* pWeaponStat = g_pGame->GetWeaponStatManager()->GetWeaponStatsFromSkillLevel(eWeapon, fSkill); if (pWeaponStat) { fRange = pWeaponStat->GetTargetRange(); } else { fRange = MELEE_VISIBLE_RANGE; } // Find the target position CVector vecFront = *pActive->GetFront(); vecFront.Normalize(); vecTarget = *pActive->GetSource() + vecFront * fRange; } else { // Grab the weapon and keysync state. If it exists and he holds Target down CWeapon* pPlayerWeapon = pLocalPlayer->GetWeapon(); if (pPlayerWeapon && State.RightShoulder1) { // Grab the gun muzzle position eWeaponType eWeapon = pLocalPlayer->GetCurrentWeaponType(); float fSkill = pLocalPlayer->GetStat(g_pGame->GetStats()->GetSkillStatIndex(eWeapon)); CWeaponStat* pWeaponStat = g_pGame->GetWeaponStatManager()->GetWeaponStatsFromSkillLevel(eWeapon, fSkill); CVector vecGunMuzzle = *pWeaponStat->GetFireOffset(); pLocalPlayer->GetTransformedBonePosition(BONE_RIGHTWRIST, vecGunMuzzle); // Grab the target point pCamera->Find3rdPersonCamTargetVector(AIM_VISIBLE_RANGE, &vecGunMuzzle, &vecStart, &vecTarget); } else { // Grab the active cam CCam* pActive = pCamera->GetCam(pCamera->GetActiveCam()); // Grab the camera matrix CMatrix matCamera; pCamera->GetMatrix(&matCamera); vecStart = matCamera.vPos; // Find the target position CVector vecFront = *pActive->GetFront(); vecFront.Normalize(); vecTarget = *pActive->GetSource() + vecFront * MELEE_VISIBLE_RANGE; } } // Ignore the local player for this pLocalPlayer->WorldIgnore(true); // Do the raycast CColPoint* pColPoint = NULL; CEntity* pEntity = NULL; SLineOfSightFlags flags; flags.bCheckBuildings = true; flags.bCheckVehicles = true; flags.bCheckPeds = true; flags.bCheckObjects = true; flags.bCheckDummies = true; flags.bSeeThroughStuff = true; flags.bIgnoreSomeObjectsForCamera = false; flags.bShootThroughStuff = true; g_pGame->GetWorld()->ProcessLineOfSight(&vecStart, &vecTarget, &pColPoint, &pEntity, flags); if (pColPoint) pColPoint->Destroy(); // Un-ignore the local player pLocalPlayer->WorldIgnore(false); // Did we find an entity? if (pEntity) { // Grab the CClientEntity belonging to this game_sa entity CClientEntity* pClientEntity = reinterpret_cast<CClientEntity*>(pEntity->GetStoredPointer()); if (pClientEntity) { // Is it a vehicle? Is it a ped? eClientEntityType EntityType = pClientEntity->GetType(); if (EntityType == CCLIENTVEHICLE) { CClientVehicle* pClientVehicle = static_cast<CClientVehicle*>(pClientEntity); // Set the current time as the last draw time for all players inside CClientPed* pPed; int i; for (i = 0; i < 8; i++) { // Grab this seat's occupant and set its last nametag show time to now pPed = pClientVehicle->GetOccupant(i); if (pPed && pPed->GetType() == CCLIENTPLAYER) { static_cast<CClientPlayer*>(pPed)->SetLastNametagShow(ulCurrentTime); } } } else if (EntityType == CCLIENTPLAYER) { // Grab the player this entity is CClientPlayer* pClientPlayer = static_cast<CClientPlayer*>(pClientEntity); if (pClientPlayer) { // Set now as the last time we had the cursor above him pClientPlayer->SetLastNametagShow(ulCurrentTime); } } } } // Grab the local player vehicle CClientVehicle* pLocalVehicle = pLocalPlayer->GetOccupiedVehicle(); // Draw the nametags we need to CClientPlayer* pPlayer; CClientStreamElement* pElement; list<CClientStreamElement*>::const_iterator iter = m_pPlayerStreamer->ActiveElementsBegin(); for (; iter != m_pPlayerStreamer->ActiveElementsEnd(); ++iter) { pElement = *iter; if (!pElement->IsStreamedIn()) continue; if (pElement->GetType() != CCLIENTPLAYER) continue; pPlayer = static_cast<CClientPlayer*>(pElement); if (pPlayer->IsLocalPlayer()) continue; // Is he in the same vehicle as the local player? if (pLocalVehicle && pPlayer->GetOccupiedVehicle() == pLocalVehicle) { pPlayer->SetLastNametagShow(ulCurrentTime); } // Can we show this player's nametag unsigned long ulLastNametagShow = pPlayer->GetLastNametagShow(); if (ulLastNametagShow != 0 && ulCurrentTime <= ulLastNametagShow + NAMETAG_END_FADE_TIME) { unsigned long ulLastNametagShow = pPlayer->GetLastNametagShow(); // Calculate the alpha modifier float fAlphaTimeModifier; if (ulCurrentTime < ulLastNametagShow + NAMETAG_BEGIN_FADE_TIME) { fAlphaTimeModifier = 1.0f; } else { fAlphaTimeModifier = 1.0f - (ulCurrentTime - ulLastNametagShow - NAMETAG_BEGIN_FADE_TIME) / 1000.0f; } // Calculate the alpha for the nametag unsigned char ucAlpha = static_cast<unsigned char>(180.0f * fAlphaTimeModifier); // Draw it DrawTagForPlayer(pPlayer, ucAlpha); } } } } }