diff options
Diffstat (limited to 'game/server/hl1/hl1_env_speaker.cpp')
| -rw-r--r-- | game/server/hl1/hl1_env_speaker.cpp | 219 |
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 ); +} |