//----------------------------------------------------------------------------- // Purpose: Playback sound file that contains phonemes // Input : *actor - // *parameters - //----------------------------------------------------------------------------- void C_SceneEntity::DispatchStartSpeak( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event, soundlevel_t iSoundlevel ) { // Emit sound if ( IsClientOnly() && actor ) { CSingleUserRecipientFilter filter( C_BasePlayer::GetLocalPlayer() ); float time_in_past = m_flCurrentTime - event->GetStartTime() ; float soundtime = gpGlobals->curtime - time_in_past; EmitSound_t es; es.m_nChannel = CHAN_VOICE; es.m_flVolume = 1; es.m_SoundLevel = iSoundlevel; es.m_flSoundTime = soundtime; // No CC since we do it manually // FIXME: This will change es.m_bEmitCloseCaption = false; es.m_pSoundName = event->GetParameters(); EmitSound( filter, actor->entindex(), es ); actor->AddSceneEvent( scene, event, NULL, IsClientOnly() ); // Close captioning only on master token no matter what... if ( event->GetCloseCaptionType() == CChoreoEvent::CC_MASTER ) { char tok[ CChoreoEvent::MAX_CCTOKEN_STRING ]; bool validtoken = event->GetPlaybackCloseCaptionToken( tok, sizeof( tok ) ); if ( validtoken ) { CRC32_t tokenCRC; CRC32_Init( &tokenCRC ); char lowercase[ 256 ]; Q_strncpy( lowercase, tok, sizeof( lowercase ) ); Q_strlower( lowercase ); CRC32_ProcessBuffer( &tokenCRC, lowercase, Q_strlen( lowercase ) ); CRC32_Final( &tokenCRC ); float endtime = event->GetLastSlaveEndTime(); float durationShort = event->GetDuration(); float durationLong = endtime - event->GetStartTime(); float duration = MAX( durationShort, durationLong ); CHudCloseCaption *hudCloseCaption = GET_HUDELEMENT( CHudCloseCaption ); if ( hudCloseCaption ) { hudCloseCaption->ProcessCaption( lowercase, duration ); } } } } }
void EmitCloseCaption( IRecipientFilter& filter, int entindex, bool fromplayer, char const *token, CUtlVector< Vector >& originlist, float duration, bool warnifmissing /*= false*/ ) { // No close captions in multiplayer... if ( gpGlobals->maxClients > 1 || (gpGlobals->maxClients==1 && !g_pClosecaption->GetBool())) { return; } // A negative duration means fill it in from the wav file if possible if ( duration < 0.0f ) { char const *wav = soundemitterbase->GetWavFileForSound( token, GENDER_NONE ); if ( wav ) { duration = enginesound->GetSoundDuration( wav ); } else { duration = 2.0f; } } char lowercase[ 256 ]; Q_strncpy( lowercase, token, sizeof( lowercase ) ); Q_strlower( lowercase ); if ( Q_strstr( lowercase, "\\" ) ) { Hack_FixEscapeChars( lowercase ); } // NOTE: We must make a copy or else if the filter is owned by a SoundPatch, we'll end up destructively removing // all players from it!!!! CRecipientFilter filterCopy; filterCopy.CopyFrom( (CRecipientFilter &)filter ); // Remove any players who don't want close captions CBaseEntity::RemoveRecipientsIfNotCloseCaptioning( (CRecipientFilter &)filterCopy ); #if !defined( CLIENT_DLL ) { // Defined in sceneentity.cpp bool AttenuateCaption( const char *token, const Vector& listener, CUtlVector< Vector >& soundorigins ); if ( filterCopy.GetRecipientCount() > 0 ) { int c = filterCopy.GetRecipientCount(); for ( int i = c - 1 ; i >= 0; --i ) { CBasePlayer *player = UTIL_PlayerByIndex( filterCopy.GetRecipientIndex( i ) ); if ( !player ) continue; Vector playerOrigin = player->GetAbsOrigin(); if ( AttenuateCaption( lowercase, playerOrigin, originlist ) ) { filterCopy.RemoveRecipient( player ); } } } } #endif // Anyone left? if ( filterCopy.GetRecipientCount() > 0 ) { #if !defined( CLIENT_DLL ) byte byteflags = 0; if ( warnifmissing ) { byteflags |= CLOSE_CAPTION_WARNIFMISSING; } if ( fromplayer ) { byteflags |= CLOSE_CAPTION_FROMPLAYER; } CBaseEntity *pActor = CBaseEntity::Instance( entindex ); if ( pActor ) { char const *pszActorModel = STRING( pActor->GetModelName() ); gender_t gender = soundemitterbase->GetActorGender( pszActorModel ); if ( gender == GENDER_MALE ) { byteflags |= CLOSE_CAPTION_GENDER_MALE; } else if ( gender == GENDER_FEMALE ) { byteflags |= CLOSE_CAPTION_GENDER_FEMALE; } } // Send caption and duration hint down to client UserMessageBegin( filterCopy, "CloseCaption" ); WRITE_STRING( lowercase ); WRITE_SHORT( MIN( 255, (int)( duration * 10.0f ) ) ), WRITE_BYTE( byteflags ), MessageEnd(); #else // Direct dispatch CHudCloseCaption *cchud = GET_HUDELEMENT( CHudCloseCaption ); if ( cchud ) { cchud->ProcessCaption( lowercase, duration, fromplayer ); } #endif } }