source-engine/game/shared/hintmessage.cpp
2023-10-03 17:23:56 +03:00

301 lines
8.5 KiB
C++

//====== Copyright © 1996-2004, Valve Corporation, All rights reserved. =======
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "hintmessage.h"
#include "hintsystem.h"
#ifdef GAME_DLL
#include "util.h"
#endif
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
//--------------------------------------------------------------------------------------------------------
/**
* Simple utility function to allocate memory and duplicate a string
*/
inline char *CloneString( const char *str )
{
char *cloneStr = new char [ strlen(str)+1 ];
strcpy( cloneStr, str );
return cloneStr;
}
extern int gmsgHudText;
enum { HMQ_SIZE = 8 }; // Maximum number of messages queue can hold
// If the limit is reached, no more can be
// added.
//--------------------------------------------------------------------------------------------------------------
CHintMessage::CHintMessage( const char * hintString, CUtlVector< const char * > * args, float duration )
{
m_hintString = hintString;
m_duration = duration;
if ( args )
{
for ( int i=0; i<args->Count(); ++i )
{
m_args.AddToTail( CloneString( (*args)[i] ) );
}
}
}
//--------------------------------------------------------------------------------------------------------------
CHintMessage::~CHintMessage()
{
for ( int i=0; i<m_args.Count(); ++i )
{
delete[] m_args[i];
}
m_args.RemoveAll();
}
//--------------------------------------------------------------------------------------------------------------
bool CHintMessage::IsEquivalent( const char *hintString, CUtlVector< const char * > * args ) const
{
if ( FStrEq( hintString, m_hintString ) )
{
if ( !args && !m_args.Count() )
{
return true;
}
if ( !args )
return false;
if ( args->Count() != m_args.Count() )
return false;
for ( int i=0; i<args->Count(); ++i )
{
if ( !FStrEq( (*args)[i], m_args[i] ) )
{
return false;
}
}
}
return false;
}
//--------------------------------------------------------------------------------------------------------------
void CHintMessage::Send( CBasePlayer * client )
{
if ( !client )
return;
#ifdef GAME_DLL
// Custom hint text sending to allow for arguments. This is OK because the client has a custom
// message parser for hint text that can read the arguments.
CSingleUserRecipientFilter user( (CBasePlayer *)client );
user.MakeReliable();
// client can handle 1 string only
UserMessageBegin( user, "HintText" );
WRITE_STRING( m_hintString );
MessageEnd();
#endif
}
//--------------------------------------------------------------------------------------------------------------
CHintMessageQueue::CHintMessageQueue( CBasePlayer *pPlayer )
{
m_pPlayer = pPlayer;
}
//--------------------------------------------------------------------------------------------------------------
void CHintMessageQueue::Reset()
{
m_tmMessageEnd = 0;
for ( int i=0; i<m_messages.Count(); ++i )
{
delete m_messages[i];
}
m_messages.RemoveAll();
}
//--------------------------------------------------------------------------------------------------------------
void CHintMessageQueue::Update()
{
if ( !m_pPlayer )
return;
// test this - send the message as soon as it is ready,
// just stomp the old message
//if ( gpGlobals->curtime > m_tmMessageEnd )
{
if ( m_messages.Count() )
{
CHintMessage *msg = m_messages[0];
m_tmMessageEnd = gpGlobals->curtime + msg->GetDuration();
msg->Send( m_pPlayer );
delete msg;
m_messages.Remove( 0 );
}
}
}
//--------------------------------------------------------------------------------------------------------------
bool CHintMessageQueue::AddMessage( const char* message, float duration, CUtlVector< const char * > * args )
{
if ( !m_pPlayer )
return false;
for ( int i=0; i<m_messages.Count(); ++i )
{
// weed out duplicates
if ( m_messages[i]->IsEquivalent( message, args ) )
{
return true;
}
}
// 'message' is not copied, so the pointer must remain valid forever
CHintMessage *msg = new CHintMessage( message, args, duration );
m_messages.AddToTail( msg );
return true;
}
//--------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pPlayer -
//-----------------------------------------------------------------------------
CHintMessageTimers::CHintMessageTimers( CHintSystem *pSystem, CHintMessageQueue *pQueue )
{
m_pHintSystem = pSystem;
m_pQueue = pQueue;
}
//-----------------------------------------------------------------------------
// Purpose: Clear out all registered timers
//-----------------------------------------------------------------------------
void CHintMessageTimers::Reset()
{
for ( int i=0; i<m_Timers.Count(); ++i )
{
delete m_Timers[i];
}
m_Timers.RemoveAll();
}
//-----------------------------------------------------------------------------
// Purpose: Check & fire any timers that should fire based on their duration.
//-----------------------------------------------------------------------------
void CHintMessageTimers::Update()
{
if ( !m_pHintSystem )
return;
for ( int i = 0; i < m_Timers.Count(); i++ )
{
if ( m_Timers[i]->timer.Expired() )
{
if ( m_pHintSystem->TimerShouldFire( m_Timers[i]->iHintID ) )
{
//Warning("TIMER FIRED: %s\n", m_pszHintMessages[m_Timers[i]->iHintID] );
m_pHintSystem->HintMessage( m_Timers[i]->iHintID );
// Remove and return. No reason to bring up multiple hints.
RemoveTimer( m_Timers[i]->iHintID );
return;
}
else
{
// Push the timer out again
m_Timers[i]->timer.Start();
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Register a new timer that the system should should keep track of.
// Input : iHintID - The ID of the hint message
// timer_duration - the total time the timer should run for until it fires the hint message
// message_duration - the duration passed into the hint message system when the hint fires
// args - the arguments passed into the hint message system when the hint fires
//-----------------------------------------------------------------------------
void CHintMessageTimers::AddTimer( int iHintID, float timer_duration, float message_duration, CUtlVector< const char * > * args )
{
if ( GetTimerIndex(iHintID) != m_Timers.InvalidIndex() )
return;
// 'message' is not copied, so the pointer must remain valid forever
hintmessagetime_t *newTimer = new hintmessagetime_t( timer_duration );
newTimer->iHintID = iHintID;
newTimer->flMessageDuration = message_duration;
if ( args )
{
for ( int i=0; i<args->Count(); ++i )
{
newTimer->args.AddToTail( CloneString( (*args)[i] ) );
}
}
m_Timers.AddToTail( newTimer );
//Warning("TIMER ADDED: %s\n", m_pszHintMessages[iHintID] );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHintMessageTimers::RemoveTimer( int iHintID )
{
int iIndex = GetTimerIndex(iHintID);
if ( iIndex != m_Timers.InvalidIndex() )
{
//Warning("TIMER REMOVED: %s\n", m_pszHintMessages[iHintID] );
m_Timers.Remove( iIndex );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHintMessageTimers::StartTimer( int iHintID )
{
int iIndex = GetTimerIndex(iHintID);
if ( iIndex != m_Timers.InvalidIndex() )
{
//Warning("TIMER STARTED: %s\n", m_pszHintMessages[iHintID] );
m_Timers[iIndex]->timer.Start();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHintMessageTimers::StopTimer( int iHintID )
{
int iIndex = GetTimerIndex(iHintID);
if ( iIndex != m_Timers.InvalidIndex() )
{
//Warning("TIMER STOPPED: %s\n", m_pszHintMessages[iHintID] );
m_Timers[iIndex]->timer.Stop();
}
}
//-----------------------------------------------------------------------------
// Purpose: Return the index of the hint message in the timer list, if any
//-----------------------------------------------------------------------------
int CHintMessageTimers::GetTimerIndex( int iHintID )
{
for ( int i = 0; i < m_Timers.Count(); i++ )
{
if ( m_Timers[i]->iHintID == iHintID )
return i;
}
return m_Timers.InvalidIndex();
}