The StatusValue message is sent after a Traceline that happens for the client (I assume every "think").
In CBasePlayer::UpdateClientData, pdata m_flNextSBarUpdateTime is checked, if time is passed, CBasePlayer::UpdateStatusBar is called and m_flNextSBarUpdateTime is set to gametime + 0.2.
( m_flNextSBarUpdateTime is 449 on windows, +5 on linux ).
hlsdk UpdateStatusBar code for reference :
Spoiler
Code:
void CBasePlayer::UpdateStatusBar()
{
int newSBarState[ SBAR_END ];
char sbuf0[ SBAR_STRING_SIZE ];
char sbuf1[ SBAR_STRING_SIZE ];
memset( newSBarState, 0, sizeof(newSBarState) );
strcpy( sbuf0, m_SbarString0 );
strcpy( sbuf1, m_SbarString1 );
// Find an ID Target
TraceResult tr;
UTIL_MakeVectors( pev->v_angle + pev->punchangle );
Vector vecSrc = EyePosition();
Vector vecEnd = vecSrc + (gpGlobals->v_forward * MAX_ID_RANGE);
UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, edict(), &tr);
if (tr.flFraction != 1.0)
{
if ( !FNullEnt( tr.pHit ) )
{
CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit );
if (pEntity->Classify() == CLASS_PLAYER )
{
newSBarState[ SBAR_ID_TARGETNAME ] = ENTINDEX( pEntity->edict() );
strcpy( sbuf1, "1 %p1\n2 Health: %i2%%\n3 Armor: %i3%%" );
// allies and medics get to see the targets health
if ( g_pGameRules->PlayerRelationship( this, pEntity ) == GR_TEAMMATE )
{
newSBarState[ SBAR_ID_TARGETHEALTH ] = 100 * (pEntity->pev->health / pEntity->pev->max_health);
newSBarState[ SBAR_ID_TARGETARMOR ] = pEntity->pev->armorvalue; //No need to get it % based since 100 it's the max.
}
m_flStatusBarDisappearDelay = gpGlobals->time + 1.0;
}
}
else if ( m_flStatusBarDisappearDelay > gpGlobals->time )
{
// hold the values for a short amount of time after viewing the object
newSBarState[ SBAR_ID_TARGETNAME ] = m_izSBarState[ SBAR_ID_TARGETNAME ];
newSBarState[ SBAR_ID_TARGETHEALTH ] = m_izSBarState[ SBAR_ID_TARGETHEALTH ];
newSBarState[ SBAR_ID_TARGETARMOR ] = m_izSBarState[ SBAR_ID_TARGETARMOR ];
}
}
BOOL bForceResend = FALSE;
if ( strcmp( sbuf0, m_SbarString0 ) )
{
MESSAGE_BEGIN( MSG_ONE, gmsgStatusText, NULL, pev );
WRITE_BYTE( 0 );
WRITE_STRING( sbuf0 );
MESSAGE_END();
strcpy( m_SbarString0, sbuf0 );
// make sure everything's resent
bForceResend = TRUE;
}
if ( strcmp( sbuf1, m_SbarString1 ) )
{
MESSAGE_BEGIN( MSG_ONE, gmsgStatusText, NULL, pev );
WRITE_BYTE( 1 );
WRITE_STRING( sbuf1 );
MESSAGE_END();
strcpy( m_SbarString1, sbuf1 );
// make sure everything's resent
bForceResend = TRUE;
}
// Check values and send if they don't match
for (int i = 1; i < SBAR_END; i++)
{
if ( newSBarState[i] != m_izSBarState[i] || bForceResend )
{
MESSAGE_BEGIN( MSG_ONE, gmsgStatusValue, NULL, pev );
WRITE_BYTE( i );
WRITE_SHORT( newSBarState[i] );
MESSAGE_END();
m_izSBarState[i] = newSBarState[i];
}
}
}
cs UpdateStatusBar code from ida (gonna hurt eyes !!), quite similar with HL one.