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.

219 lines
5.7 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "cbase.h"
  9. #include "player.h"
  10. #include "mathlib/mathlib.h"
  11. #include "ai_speech.h"
  12. #include "stringregistry.h"
  13. #include "gamerules.h"
  14. #include "game.h"
  15. #include <ctype.h>
  16. #include "entitylist.h"
  17. #include "vstdlib/random.h"
  18. #include "engine/IEngineSound.h"
  19. #include "ndebugoverlay.h"
  20. #include "soundscape.h"
  21. #define SPEAKER_START_SILENT 1 // wait for trigger 'on' to start announcements
  22. // ===================================================================================
  23. //
  24. // Speaker class. Used for announcements per level, for door lock/unlock spoken voice.
  25. //
  26. class CSpeaker : public CPointEntity
  27. {
  28. DECLARE_CLASS( CSpeaker, CPointEntity );
  29. public:
  30. bool KeyValue( const char *szKeyName, const char *szValue );
  31. void Spawn( void );
  32. void Precache( void );
  33. void ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
  34. void SpeakerThink( void );
  35. virtual int ObjectCaps( void ) { return (CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION); }
  36. int m_preset; // preset number
  37. string_t m_iszMessage;
  38. DECLARE_DATADESC();
  39. };
  40. LINK_ENTITY_TO_CLASS( speaker, CSpeaker );
  41. BEGIN_DATADESC( CSpeaker )
  42. DEFINE_FIELD( m_preset, FIELD_INTEGER ),
  43. DEFINE_KEYFIELD( m_iszMessage, FIELD_STRING, "message" ),
  44. DEFINE_THINKFUNC( SpeakerThink ),
  45. DEFINE_USEFUNC( ToggleUse ),
  46. END_DATADESC()
  47. //
  48. // ambient_generic - general-purpose user-defined static sound
  49. //
  50. void CSpeaker::Spawn( void )
  51. {
  52. char* szSoundFile = (char*) STRING( m_iszMessage );
  53. if ( !m_preset && ( m_iszMessage == NULL_STRING || strlen( szSoundFile ) < 1 ) )
  54. {
  55. Msg( "SPEAKER with no Level/Sentence! at: %f, %f, %f\n", GetAbsOrigin().x, GetAbsOrigin().y, GetAbsOrigin().z );
  56. SetNextThink( gpGlobals->curtime + 0.1 );
  57. SetThink( &CSpeaker::SUB_Remove );
  58. return;
  59. }
  60. SetSolid( SOLID_NONE );
  61. SetMoveType( MOVETYPE_NONE );
  62. SetThink(&CSpeaker::SpeakerThink);
  63. SetNextThink( TICK_NEVER_THINK );
  64. // allow on/off switching via 'use' function.
  65. SetUse ( &CSpeaker::ToggleUse );
  66. Precache( );
  67. }
  68. #define ANNOUNCE_MINUTES_MIN 0.25
  69. #define ANNOUNCE_MINUTES_MAX 2.25
  70. void CSpeaker::Precache( void )
  71. {
  72. if ( !FBitSet ( GetSpawnFlags(), SPEAKER_START_SILENT ) )
  73. // set first announcement time for random n second
  74. SetNextThink( gpGlobals->curtime + random->RandomFloat( 5.0, 15.0 ) );
  75. }
  76. void CSpeaker::SpeakerThink( void )
  77. {
  78. char* szSoundFile = NULL;
  79. float flvolume = m_iHealth * 0.1;
  80. int flags = 0;
  81. int pitch = 100;
  82. // Wait for the talking characters to finish first.
  83. if ( !g_AIFriendliesTalkSemaphore.IsAvailable( this ) || !g_AIFoesTalkSemaphore.IsAvailable( this ) )
  84. {
  85. float releaseTime = MAX( g_AIFriendliesTalkSemaphore.GetReleaseTime(), g_AIFoesTalkSemaphore.GetReleaseTime() );
  86. SetNextThink( gpGlobals->curtime + releaseTime + random->RandomFloat( 5, 10 ) );
  87. return;
  88. }
  89. if (m_preset)
  90. {
  91. // go lookup preset text, assign szSoundFile
  92. switch (m_preset)
  93. {
  94. case 1: szSoundFile = "C1A0_"; break;
  95. case 2: szSoundFile = "C1A1_"; break;
  96. case 3: szSoundFile = "C1A2_"; break;
  97. case 4: szSoundFile = "C1A3_"; break;
  98. case 5: szSoundFile = "C1A4_"; break;
  99. case 6: szSoundFile = "C2A1_"; break;
  100. case 7: szSoundFile = "C2A2_"; break;
  101. case 8: szSoundFile = "C2A3_"; break;
  102. case 9: szSoundFile = "C2A4_"; break;
  103. case 10: szSoundFile = "C2A5_"; break;
  104. case 11: szSoundFile = "C3A1_"; break;
  105. case 12: szSoundFile = "C3A2_"; break;
  106. }
  107. } else
  108. szSoundFile = (char*) STRING( m_iszMessage );
  109. if (szSoundFile[0] == '!')
  110. {
  111. // play single sentence, one shot
  112. UTIL_EmitAmbientSound ( GetSoundSourceIndex(), GetAbsOrigin(), szSoundFile,
  113. flvolume, SNDLVL_120dB, flags, pitch);
  114. // shut off and reset
  115. SetNextThink( TICK_NEVER_THINK );
  116. }
  117. else
  118. {
  119. // make random announcement from sentence group
  120. if ( SENTENCEG_PlayRndSz( edict(), szSoundFile, flvolume, SNDLVL_120dB, flags, pitch) < 0 )
  121. Msg( "Level Design Error!\nSPEAKER has bad sentence group name: %s\n",szSoundFile);
  122. // set next announcement time for random 5 to 10 minute delay
  123. SetNextThink ( gpGlobals->curtime +
  124. random->RandomFloat( ANNOUNCE_MINUTES_MIN * 60.0, ANNOUNCE_MINUTES_MAX * 60.0 ) );
  125. // time delay until it's ok to speak: used so that two NPCs don't talk at once
  126. g_AIFriendliesTalkSemaphore.Acquire( 5, this );
  127. g_AIFoesTalkSemaphore.Acquire( 5, this );
  128. }
  129. return;
  130. }
  131. //
  132. // ToggleUse - if an announcement is pending, cancel it. If no announcement is pending, start one.
  133. //
  134. void CSpeaker::ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  135. {
  136. int fActive = (GetNextThink() > 0.0);
  137. // fActive is TRUE only if an announcement is pending
  138. if ( useType != USE_TOGGLE )
  139. {
  140. // ignore if we're just turning something on that's already on, or
  141. // turning something off that's already off.
  142. if ( (fActive && useType == USE_ON) || (!fActive && useType == USE_OFF) )
  143. return;
  144. }
  145. if ( useType == USE_ON )
  146. {
  147. // turn on announcements
  148. SetNextThink( gpGlobals->curtime + 0.1 );
  149. return;
  150. }
  151. if ( useType == USE_OFF )
  152. {
  153. // turn off announcements
  154. SetNextThink( TICK_NEVER_THINK );
  155. return;
  156. }
  157. // Toggle announcements
  158. if ( fActive )
  159. {
  160. // turn off announcements
  161. SetNextThink( TICK_NEVER_THINK );
  162. }
  163. else
  164. {
  165. // turn on announcements
  166. SetNextThink( gpGlobals->curtime + 0.1 );
  167. }
  168. }
  169. // KeyValue - load keyvalue pairs into member data
  170. // NOTE: called BEFORE spawn!
  171. bool CSpeaker::KeyValue( const char *szKeyName, const char *szValue )
  172. {
  173. // preset
  174. if (FStrEq(szKeyName, "preset"))
  175. {
  176. m_preset = atoi(szValue);
  177. return true;
  178. }
  179. else
  180. return BaseClass::KeyValue( szKeyName, szValue );
  181. }