//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= // // Purpose: // //============================================================================= #include "cbase.h" #include "hintsystem.h" #include "hintmessage.h" #ifdef GAME_DLL #else #include #endif // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" #ifdef CLIENT_DLL ConVar cl_showhelp( "cl_showhelp", "1", FCVAR_ARCHIVE, "Set to 0 to not show on-screen help" ); #endif //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CHintSystem::CHintSystem( void ) { Init( NULL, 0, NULL ); m_pHintMessageQueue = NULL; m_pHintMessageTimers = NULL; m_flLastHintPlayedAt = 0; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CHintSystem::~CHintSystem( void ) { if ( m_pHintMessageTimers ) { delete m_pHintMessageTimers; m_pHintMessageTimers = NULL; } if ( m_pHintMessageQueue ) { delete m_pHintMessageQueue; m_pHintMessageQueue = NULL; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHintSystem::Init( CBasePlayer *pPlayer, int iMaxHintTypes, const char **pszHintStrings ) { m_pPlayer = pPlayer; m_bShowHints = true; m_HintHistory.Resize( iMaxHintTypes ); m_HintHistory.ClearAll(); m_pszHintMessages = pszHintStrings; if ( m_pPlayer ) { m_pHintMessageQueue = new CHintMessageQueue( m_pPlayer ); m_pHintMessageTimers = new CHintMessageTimers( this, m_pHintMessageQueue ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHintSystem::Update( void ) { if ( m_pHintMessageQueue ) { m_pHintMessageQueue->Update(); } if ( m_pHintMessageTimers ) { m_pHintMessageTimers->Update(); } } //----------------------------------------------------------------------------- // Purpose: Displays a hint message to the player // Input : hint - enum'd hint to show // bForce - always play this hint even if they have seen it before //----------------------------------------------------------------------------- bool CHintSystem::HintMessage( int hint, bool bForce /* = false */, bool bOnlyIfClear /* = false */ ) { Assert( m_pPlayer ); Assert( hint < m_HintHistory.GetNumBits() ); // Not really an optimal solution, but saves us querying the hud element, // which wouldn't be easy with derived versions in different mods. if ( bOnlyIfClear && (gpGlobals->curtime - m_flLastHintPlayedAt < 11 ) ) return false; if ( bForce || !HasPlayedHint(hint) ) { PlayedAHint(); HintMessage( m_pszHintMessages[hint] ); m_HintHistory.Set(hint); return true; } return false; } //----------------------------------------------------------------------------- // Purpose: Displays a hint message to the player // Input : *pMessage - //----------------------------------------------------------------------------- void CHintSystem::HintMessage( const char *pMessage ) { Assert( m_pPlayer ); #ifdef GAME_DLL // On the server, we send it down to the queue who sends it to the client if ( !m_pPlayer->IsNetClient() || !m_pHintMessageQueue ) return; if ( !m_bShowHints ) return; m_pHintMessageQueue->AddMessage( pMessage ); #else // On the client, we just send it straight to the hint hud element if ( cl_showhelp.GetBool() ) { IGameEvent *event = gameeventmanager->CreateEvent( "player_hintmessage" ); if ( event ) { event->SetString( "hintmessage", pMessage ); gameeventmanager->FireEventClientSide( event ); } } #endif } //----------------------------------------------------------------------------- // Purpose: Clear out the existing timers, and register new ones for any // hints that haven't been displayed yet. //----------------------------------------------------------------------------- void CHintSystem::ResetHints( void ) { if ( !m_pHintMessageTimers ) return; m_pHintMessageTimers->Reset(); // Readd registered hints for (int i = 0; i < m_RegisteredResetHints.Count(); i++ ) { ReAddHintTimerIfNotDisplayed( m_RegisteredResetHints[i].iHintID, m_RegisteredResetHints[i].flTimer ); } // Reset our queue if ( m_pHintMessageQueue ) { m_pHintMessageQueue->Reset(); } } //----------------------------------------------------------------------------- // Purpose: Call this to add a hint message that should be re-added // everytime we're reset, if it hasn't been displayed yet. //----------------------------------------------------------------------------- void CHintSystem::RegisterHintTimer( int iHintID, float flTimerDuration, bool bOnlyIfClear /* = false */, HintTimerCallback pfnCallback ) { Assert( m_pPlayer ); Assert( iHintID < m_HintHistory.GetNumBits() ); onresethints_t newHint; newHint.iHintID = iHintID; newHint.flTimer = flTimerDuration; newHint.bOnlyIfClear = bOnlyIfClear; newHint.pfnCallback = pfnCallback; m_RegisteredResetHints.AddToTail( newHint ); } //----------------------------------------------------------------------------- // Purpose: If the hint hasn't been displayed, start a timer for it //----------------------------------------------------------------------------- void CHintSystem::ReAddHintTimerIfNotDisplayed( int iHintID, float flTimerDuration ) { Assert( iHintID < m_HintHistory.GetNumBits() ); if ( m_HintHistory[iHintID] == 0 ) { m_pHintMessageTimers->AddTimer( iHintID, flTimerDuration ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHintSystem::StartHintTimer( int iHintID ) { Assert( m_pPlayer ); Assert( iHintID < m_HintHistory.GetNumBits() ); Assert(m_pHintMessageTimers); m_pHintMessageTimers->StartTimer( iHintID ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHintSystem::StopHintTimer( int iHintID ) { Assert( m_pPlayer ); Assert( iHintID < m_HintHistory.GetNumBits() ); Assert(m_pHintMessageTimers); m_pHintMessageTimers->StopTimer( iHintID ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHintSystem::ResetHintTimers( void ) { Assert( m_pPlayer ); Assert(m_pHintMessageTimers); m_pHintMessageTimers->Reset(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHintSystem::RemoveHintTimer( int iHintID ) { Assert( m_pPlayer ); Assert( iHintID < m_HintHistory.GetNumBits() ); Assert(m_pHintMessageTimers); m_pHintMessageTimers->RemoveTimer( iHintID ); // Mark us as having heard this hint m_HintHistory.Set(iHintID); } //----------------------------------------------------------------------------- // Purpose: See if there's a callback registered for the specified hint. // If so, see if it wants to allow the hint to fire. //----------------------------------------------------------------------------- bool CHintSystem::TimerShouldFire( int iHintID ) { for (int i = 0; i < m_RegisteredResetHints.Count(); i++ ) { if ( m_RegisteredResetHints[i].iHintID != iHintID ) continue; if ( m_RegisteredResetHints[i].bOnlyIfClear && HintIsCurrentlyVisible() ) return false; if ( m_RegisteredResetHints[i].pfnCallback ) return m_RegisteredResetHints[i].pfnCallback( m_pPlayer ); } return true; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CHintSystem::ShouldShowHints( void ) { #ifdef GAME_DLL return m_bShowHints; #else return cl_showhelp.GetBool(); #endif } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHintSystem::PlayedAHint( void ) { m_flLastHintPlayedAt = gpGlobals->curtime; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CHintSystem::HasPlayedHint( int iHintID ) { Assert( m_pPlayer ); Assert( iHintID < m_HintHistory.GetNumBits() ); return ( m_HintHistory[iHintID] > 0 ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHintSystem::SetHintPlayed( int iHintID ) { Assert( m_pPlayer ); Assert( iHintID < m_HintHistory.GetNumBits() ); m_HintHistory.Set(iHintID); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void HintClear( void ) { #ifdef CLIENT_DLL C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); #else CBasePlayer* pPlayer = UTIL_GetCommandClient(); #endif if ( pPlayer && pPlayer->Hints() ) { pPlayer->Hints()->ClearHintHistory(); } } #ifdef CLIENT_DLL ConCommand cl_clearhinthistory( "cl_clearhinthistory", HintClear, "Clear memory of client side hints displayed to the player." ); #else ConCommand sv_clearhinthistory( "sv_clearhinthistory", HintClear, "Clear memory of server side hints displayed to the player." ); #endif