summaryrefslogtreecommitdiff
path: root/game/server/hl1/hl1_env_speaker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/server/hl1/hl1_env_speaker.cpp')
-rw-r--r--game/server/hl1/hl1_env_speaker.cpp219
1 files changed, 219 insertions, 0 deletions
diff --git a/game/server/hl1/hl1_env_speaker.cpp b/game/server/hl1/hl1_env_speaker.cpp
new file mode 100644
index 0000000..97bf22c
--- /dev/null
+++ b/game/server/hl1/hl1_env_speaker.cpp
@@ -0,0 +1,219 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "player.h"
+#include "mathlib/mathlib.h"
+#include "ai_speech.h"
+#include "stringregistry.h"
+#include "gamerules.h"
+#include "game.h"
+#include <ctype.h>
+#include "entitylist.h"
+#include "vstdlib/random.h"
+#include "engine/IEngineSound.h"
+#include "ndebugoverlay.h"
+#include "soundscape.h"
+
+#define SPEAKER_START_SILENT 1 // wait for trigger 'on' to start announcements
+
+// ===================================================================================
+//
+// Speaker class. Used for announcements per level, for door lock/unlock spoken voice.
+//
+
+class CSpeaker : public CPointEntity
+{
+ DECLARE_CLASS( CSpeaker, CPointEntity );
+public:
+ bool KeyValue( const char *szKeyName, const char *szValue );
+ void Spawn( void );
+ void Precache( void );
+ void ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
+ void SpeakerThink( void );
+
+ virtual int ObjectCaps( void ) { return (CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION); }
+
+ int m_preset; // preset number
+ string_t m_iszMessage;
+
+ DECLARE_DATADESC();
+};
+
+LINK_ENTITY_TO_CLASS( speaker, CSpeaker );
+
+BEGIN_DATADESC( CSpeaker )
+ DEFINE_FIELD( m_preset, FIELD_INTEGER ),
+ DEFINE_KEYFIELD( m_iszMessage, FIELD_STRING, "message" ),
+ DEFINE_THINKFUNC( SpeakerThink ),
+ DEFINE_USEFUNC( ToggleUse ),
+END_DATADESC()
+
+//
+// ambient_generic - general-purpose user-defined static sound
+//
+void CSpeaker::Spawn( void )
+{
+ char* szSoundFile = (char*) STRING( m_iszMessage );
+
+ if ( !m_preset && ( m_iszMessage == NULL_STRING || strlen( szSoundFile ) < 1 ) )
+ {
+ Msg( "SPEAKER with no Level/Sentence! at: %f, %f, %f\n", GetAbsOrigin().x, GetAbsOrigin().y, GetAbsOrigin().z );
+ SetNextThink( gpGlobals->curtime + 0.1 );
+ SetThink( &CSpeaker::SUB_Remove );
+ return;
+ }
+ SetSolid( SOLID_NONE );
+ SetMoveType( MOVETYPE_NONE );
+
+
+ SetThink(&CSpeaker::SpeakerThink);
+ SetNextThink( TICK_NEVER_THINK );
+
+ // allow on/off switching via 'use' function.
+ SetUse ( &CSpeaker::ToggleUse );
+
+ Precache( );
+}
+
+#define ANNOUNCE_MINUTES_MIN 0.25
+#define ANNOUNCE_MINUTES_MAX 2.25
+
+void CSpeaker::Precache( void )
+{
+ if ( !FBitSet ( GetSpawnFlags(), SPEAKER_START_SILENT ) )
+ // set first announcement time for random n second
+ SetNextThink( gpGlobals->curtime + random->RandomFloat( 5.0, 15.0 ) );
+}
+void CSpeaker::SpeakerThink( void )
+{
+ char* szSoundFile = NULL;
+ float flvolume = m_iHealth * 0.1;
+ int flags = 0;
+ int pitch = 100;
+
+
+ // Wait for the talking characters to finish first.
+ if ( !g_AIFriendliesTalkSemaphore.IsAvailable( this ) || !g_AIFoesTalkSemaphore.IsAvailable( this ) )
+ {
+ float releaseTime = MAX( g_AIFriendliesTalkSemaphore.GetReleaseTime(), g_AIFoesTalkSemaphore.GetReleaseTime() );
+ SetNextThink( gpGlobals->curtime + releaseTime + random->RandomFloat( 5, 10 ) );
+ return;
+ }
+
+ if (m_preset)
+ {
+ // go lookup preset text, assign szSoundFile
+ switch (m_preset)
+ {
+ case 1: szSoundFile = "C1A0_"; break;
+ case 2: szSoundFile = "C1A1_"; break;
+ case 3: szSoundFile = "C1A2_"; break;
+ case 4: szSoundFile = "C1A3_"; break;
+ case 5: szSoundFile = "C1A4_"; break;
+ case 6: szSoundFile = "C2A1_"; break;
+ case 7: szSoundFile = "C2A2_"; break;
+ case 8: szSoundFile = "C2A3_"; break;
+ case 9: szSoundFile = "C2A4_"; break;
+ case 10: szSoundFile = "C2A5_"; break;
+ case 11: szSoundFile = "C3A1_"; break;
+ case 12: szSoundFile = "C3A2_"; break;
+ }
+ } else
+ szSoundFile = (char*) STRING( m_iszMessage );
+
+ if (szSoundFile[0] == '!')
+ {
+ // play single sentence, one shot
+ UTIL_EmitAmbientSound ( GetSoundSourceIndex(), GetAbsOrigin(), szSoundFile,
+ flvolume, SNDLVL_120dB, flags, pitch);
+
+ // shut off and reset
+ SetNextThink( TICK_NEVER_THINK );
+ }
+ else
+ {
+ // make random announcement from sentence group
+
+ if ( SENTENCEG_PlayRndSz( edict(), szSoundFile, flvolume, SNDLVL_120dB, flags, pitch) < 0 )
+ Msg( "Level Design Error!\nSPEAKER has bad sentence group name: %s\n",szSoundFile);
+
+ // set next announcement time for random 5 to 10 minute delay
+ SetNextThink ( gpGlobals->curtime +
+ random->RandomFloat( ANNOUNCE_MINUTES_MIN * 60.0, ANNOUNCE_MINUTES_MAX * 60.0 ) );
+
+ // time delay until it's ok to speak: used so that two NPCs don't talk at once
+ g_AIFriendliesTalkSemaphore.Acquire( 5, this );
+ g_AIFoesTalkSemaphore.Acquire( 5, this );
+ }
+
+ return;
+}
+
+
+//
+// ToggleUse - if an announcement is pending, cancel it. If no announcement is pending, start one.
+//
+void CSpeaker::ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
+{
+ int fActive = (GetNextThink() > 0.0);
+
+ // fActive is TRUE only if an announcement is pending
+
+ if ( useType != USE_TOGGLE )
+ {
+ // ignore if we're just turning something on that's already on, or
+ // turning something off that's already off.
+ if ( (fActive && useType == USE_ON) || (!fActive && useType == USE_OFF) )
+ return;
+ }
+
+ if ( useType == USE_ON )
+ {
+ // turn on announcements
+ SetNextThink( gpGlobals->curtime + 0.1 );
+ return;
+ }
+
+ if ( useType == USE_OFF )
+ {
+ // turn off announcements
+ SetNextThink( TICK_NEVER_THINK );
+ return;
+
+ }
+
+ // Toggle announcements
+
+
+ if ( fActive )
+ {
+ // turn off announcements
+ SetNextThink( TICK_NEVER_THINK );
+ }
+ else
+ {
+ // turn on announcements
+ SetNextThink( gpGlobals->curtime + 0.1 );
+ }
+}
+
+// KeyValue - load keyvalue pairs into member data
+// NOTE: called BEFORE spawn!
+
+bool CSpeaker::KeyValue( const char *szKeyName, const char *szValue )
+{
+ // preset
+ if (FStrEq(szKeyName, "preset"))
+ {
+ m_preset = atoi(szValue);
+ return true;
+ }
+ else
+ return BaseClass::KeyValue( szKeyName, szValue );
+}