Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

296 lines
8.4 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "hintmessage.h"
  8. #include "hintsystem.h"
  9. #ifdef GAME_DLL
  10. #include "util.h"
  11. #endif
  12. //--------------------------------------------------------------------------------------------------------
  13. /**
  14. * Simple utility function to allocate memory and duplicate a string
  15. */
  16. inline char *CloneString( const char *str )
  17. {
  18. char *cloneStr = new char [ strlen(str)+1 ];
  19. strcpy( cloneStr, str );
  20. return cloneStr;
  21. }
  22. extern int gmsgHudText;
  23. enum { HMQ_SIZE = 8 }; // Maximum number of messages queue can hold
  24. // If the limit is reached, no more can be
  25. // added.
  26. //--------------------------------------------------------------------------------------------------------------
  27. CHintMessage::CHintMessage( const char * hintString, CUtlVector< const char * > * args, float duration )
  28. {
  29. m_hintString = hintString;
  30. m_duration = duration;
  31. if ( args )
  32. {
  33. for ( int i=0; i<args->Count(); ++i )
  34. {
  35. m_args.AddToTail( CloneString( (*args)[i] ) );
  36. }
  37. }
  38. }
  39. //--------------------------------------------------------------------------------------------------------------
  40. CHintMessage::~CHintMessage()
  41. {
  42. for ( int i=0; i<m_args.Count(); ++i )
  43. {
  44. delete[] m_args[i];
  45. }
  46. m_args.RemoveAll();
  47. }
  48. //--------------------------------------------------------------------------------------------------------------
  49. bool CHintMessage::IsEquivalent( const char *hintString, CUtlVector< const char * > * args ) const
  50. {
  51. if ( FStrEq( hintString, m_hintString ) )
  52. {
  53. if ( !args && !m_args.Count() )
  54. {
  55. return true;
  56. }
  57. if ( !args )
  58. return false;
  59. if ( args->Count() != m_args.Count() )
  60. return false;
  61. for ( int i=0; i<args->Count(); ++i )
  62. {
  63. if ( !FStrEq( (*args)[i], m_args[i] ) )
  64. {
  65. return false;
  66. }
  67. }
  68. }
  69. return false;
  70. }
  71. //--------------------------------------------------------------------------------------------------------------
  72. void CHintMessage::Send( CBasePlayer * client )
  73. {
  74. if ( !client )
  75. return;
  76. #ifdef GAME_DLL
  77. // Custom hint text sending to allow for arguments. This is OK because the client has a custom
  78. // message parser for hint text that can read the arguments.
  79. CSingleUserRecipientFilter user( (CBasePlayer *)client );
  80. user.MakeReliable();
  81. // client can handle 1 string only
  82. UserMessageBegin( user, "HintText" );
  83. WRITE_STRING( m_hintString );
  84. MessageEnd();
  85. #endif
  86. }
  87. //--------------------------------------------------------------------------------------------------------------
  88. CHintMessageQueue::CHintMessageQueue( CBasePlayer *pPlayer )
  89. {
  90. m_pPlayer = pPlayer;
  91. }
  92. //--------------------------------------------------------------------------------------------------------------
  93. void CHintMessageQueue::Reset()
  94. {
  95. m_tmMessageEnd = 0;
  96. for ( int i=0; i<m_messages.Count(); ++i )
  97. {
  98. delete m_messages[i];
  99. }
  100. m_messages.RemoveAll();
  101. }
  102. //--------------------------------------------------------------------------------------------------------------
  103. void CHintMessageQueue::Update()
  104. {
  105. if ( !m_pPlayer )
  106. return;
  107. // test this - send the message as soon as it is ready,
  108. // just stomp the old message
  109. //if ( gpGlobals->curtime > m_tmMessageEnd )
  110. {
  111. if ( m_messages.Count() )
  112. {
  113. CHintMessage *msg = m_messages[0];
  114. m_tmMessageEnd = gpGlobals->curtime + msg->GetDuration();
  115. msg->Send( m_pPlayer );
  116. delete msg;
  117. m_messages.Remove( 0 );
  118. }
  119. }
  120. }
  121. //--------------------------------------------------------------------------------------------------------------
  122. bool CHintMessageQueue::AddMessage( const char* message, float duration, CUtlVector< const char * > * args )
  123. {
  124. if ( !m_pPlayer )
  125. return false;
  126. for ( int i=0; i<m_messages.Count(); ++i )
  127. {
  128. // weed out duplicates
  129. if ( m_messages[i]->IsEquivalent( message, args ) )
  130. {
  131. return true;
  132. }
  133. }
  134. // 'message' is not copied, so the pointer must remain valid forever
  135. CHintMessage *msg = new CHintMessage( message, args, duration );
  136. m_messages.AddToTail( msg );
  137. return true;
  138. }
  139. //--------------------------------------------------------------------------------------------------------------
  140. //-----------------------------------------------------------------------------
  141. // Purpose:
  142. // Input : *pPlayer -
  143. //-----------------------------------------------------------------------------
  144. CHintMessageTimers::CHintMessageTimers( CHintSystem *pSystem, CHintMessageQueue *pQueue )
  145. {
  146. m_pHintSystem = pSystem;
  147. m_pQueue = pQueue;
  148. }
  149. //-----------------------------------------------------------------------------
  150. // Purpose: Clear out all registered timers
  151. //-----------------------------------------------------------------------------
  152. void CHintMessageTimers::Reset()
  153. {
  154. for ( int i=0; i<m_Timers.Count(); ++i )
  155. {
  156. delete m_Timers[i];
  157. }
  158. m_Timers.RemoveAll();
  159. }
  160. //-----------------------------------------------------------------------------
  161. // Purpose: Check & fire any timers that should fire based on their duration.
  162. //-----------------------------------------------------------------------------
  163. void CHintMessageTimers::Update()
  164. {
  165. if ( !m_pHintSystem )
  166. return;
  167. for ( int i = 0; i < m_Timers.Count(); i++ )
  168. {
  169. if ( m_Timers[i]->timer.Expired() )
  170. {
  171. if ( m_pHintSystem->TimerShouldFire( m_Timers[i]->iHintID ) )
  172. {
  173. //Warning("TIMER FIRED: %s\n", m_pszHintMessages[m_Timers[i]->iHintID] );
  174. m_pHintSystem->HintMessage( m_Timers[i]->iHintID );
  175. // Remove and return. No reason to bring up multiple hints.
  176. RemoveTimer( m_Timers[i]->iHintID );
  177. return;
  178. }
  179. else
  180. {
  181. // Push the timer out again
  182. m_Timers[i]->timer.Start();
  183. }
  184. }
  185. }
  186. }
  187. //-----------------------------------------------------------------------------
  188. // Purpose: Register a new timer that the system should should keep track of.
  189. // Input : iHintID - The ID of the hint message
  190. // timer_duration - the total time the timer should run for until it fires the hint message
  191. // message_duration - the duration passed into the hint message system when the hint fires
  192. // args - the arguments passed into the hint message system when the hint fires
  193. //-----------------------------------------------------------------------------
  194. void CHintMessageTimers::AddTimer( int iHintID, float timer_duration, float message_duration, CUtlVector< const char * > * args )
  195. {
  196. if ( GetTimerIndex(iHintID) != m_Timers.InvalidIndex() )
  197. return;
  198. // 'message' is not copied, so the pointer must remain valid forever
  199. hintmessagetime_t *newTimer = new hintmessagetime_t( timer_duration );
  200. newTimer->iHintID = iHintID;
  201. newTimer->flMessageDuration = message_duration;
  202. if ( args )
  203. {
  204. for ( int i=0; i<args->Count(); ++i )
  205. {
  206. newTimer->args.AddToTail( CloneString( (*args)[i] ) );
  207. }
  208. }
  209. m_Timers.AddToTail( newTimer );
  210. //Warning("TIMER ADDED: %s\n", m_pszHintMessages[iHintID] );
  211. }
  212. //-----------------------------------------------------------------------------
  213. // Purpose:
  214. //-----------------------------------------------------------------------------
  215. void CHintMessageTimers::RemoveTimer( int iHintID )
  216. {
  217. int iIndex = GetTimerIndex(iHintID);
  218. if ( iIndex != m_Timers.InvalidIndex() )
  219. {
  220. //Warning("TIMER REMOVED: %s\n", m_pszHintMessages[iHintID] );
  221. m_Timers.Remove( iIndex );
  222. }
  223. }
  224. //-----------------------------------------------------------------------------
  225. // Purpose:
  226. //-----------------------------------------------------------------------------
  227. void CHintMessageTimers::StartTimer( int iHintID )
  228. {
  229. int iIndex = GetTimerIndex(iHintID);
  230. if ( iIndex != m_Timers.InvalidIndex() )
  231. {
  232. //Warning("TIMER STARTED: %s\n", m_pszHintMessages[iHintID] );
  233. m_Timers[iIndex]->timer.Start();
  234. }
  235. }
  236. //-----------------------------------------------------------------------------
  237. // Purpose:
  238. //-----------------------------------------------------------------------------
  239. void CHintMessageTimers::StopTimer( int iHintID )
  240. {
  241. int iIndex = GetTimerIndex(iHintID);
  242. if ( iIndex != m_Timers.InvalidIndex() )
  243. {
  244. //Warning("TIMER STOPPED: %s\n", m_pszHintMessages[iHintID] );
  245. m_Timers[iIndex]->timer.Stop();
  246. }
  247. }
  248. //-----------------------------------------------------------------------------
  249. // Purpose: Return the index of the hint message in the timer list, if any
  250. //-----------------------------------------------------------------------------
  251. int CHintMessageTimers::GetTimerIndex( int iHintID )
  252. {
  253. for ( int i = 0; i < m_Timers.Count(); i++ )
  254. {
  255. if ( m_Timers[i]->iHintID == iHintID )
  256. return i;
  257. }
  258. return m_Timers.InvalidIndex();
  259. }