#include "cbase.h" #include "forcefeedback.h" #include "hud_macros.h" #include "input.h" // NOTE: This has to be the last file included! #include "tier0/memdbgon.h" #define FF_CLIENT_FLAG 0x8000 class FFParams { public: FORCEFEEDBACK_t m_nEffectType; FFBaseParams_t m_BaseParams; }; struct FFEffectInfo_t { FORCEFEEDBACK_t effectType; char const *name; }; #define DECLARE_FFEFFECT( name ) { name, #name } static FFEffectInfo_t g_EffectTypes[] = { DECLARE_FFEFFECT( FORCE_FEEDBACK_SHOT_SINGLE ), DECLARE_FFEFFECT( FORCE_FEEDBACK_SHOT_DOUBLE ), DECLARE_FFEFFECT( FORCE_FEEDBACK_TAKEDAMAGE ), DECLARE_FFEFFECT( FORCE_FEEDBACK_SCREENSHAKE ), DECLARE_FFEFFECT( FORCE_FEEDBACK_SKIDDING ), DECLARE_FFEFFECT( FORCE_FEEDBACK_BREAKING ) }; //----------------------------------------------------------------------------- // Purpose: // Input : effect - // Output : char const //----------------------------------------------------------------------------- char const *NameForForceFeedbackEffect( FORCEFEEDBACK_t effect ) { int c = ARRAYSIZE( g_EffectTypes ); if ( (int)effect < 0 || (int)effect >= c ) return "???"; const FFEffectInfo_t& info = g_EffectTypes[ (int)effect ]; Assert( info.effectType == effect ); return info.name; } //----------------------------------------------------------------------------- // Purpose: // Input : *name - // Output : FORCEFEEDBACK_t //----------------------------------------------------------------------------- FORCEFEEDBACK_t ForceFeedbackEffectForName( const char *name ) { int c = ARRAYSIZE( g_EffectTypes ); for ( int i = 0 ; i < c; ++i ) { const FFEffectInfo_t& info = g_EffectTypes[ i ]; if ( !Q_stricmp( info.name, name ) ) return info.effectType; } return ( FORCEFEEDBACK_t )-1; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- class CForceFeedback : public IForceFeedback, public CAutoGameSystem { public: virtual bool Init(); virtual void Shutdown(); // API virtual void StopAllEffects( CBasePlayer *player ); virtual void StopEffect( CBasePlayer *player, FORCEFEEDBACK_t effect ); virtual void StartEffect( CBasePlayer *player, FORCEFEEDBACK_t effect, const FFBaseParams_t& params ); virtual void PauseAll( CBasePlayer *player ); virtual void ResumeAll( CBasePlayer *player ); void MsgFunc_ForceFeedback( bf_read &msg ); private: void Internal_StopAllEffects(); void Internal_StopEffect( FORCEFEEDBACK_t effect ); void Internal_StartEffect( FORCEFEEDBACK_t, const FFBaseParams_t& params ); void Internal_PauseAll(); void Internal_ResumeAll(); }; static CForceFeedback g_ForceFeedbackSingleton; IForceFeedback *forcefeedback = &g_ForceFeedbackSingleton; //----------------------------------------------------------------------------- // Purpose: // Input : &msg - //----------------------------------------------------------------------------- void __MsgFunc_ForceFeedback( bf_read &msg ) { g_ForceFeedbackSingleton.MsgFunc_ForceFeedback( msg ); } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CForceFeedback::Init() { HOOK_MESSAGE( ForceFeedback ); return true; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CForceFeedback::Shutdown() { } //----------------------------------------------------------------------------- // Purpose: // Input : *player - //----------------------------------------------------------------------------- void CForceFeedback::StopAllEffects( CBasePlayer *player ) { if ( !player ) return; Internal_StopAllEffects(); } //----------------------------------------------------------------------------- // Purpose: // Input : *player - // effect - //----------------------------------------------------------------------------- void CForceFeedback::StopEffect( CBasePlayer *player, FORCEFEEDBACK_t effect ) { if ( !player ) return; Internal_StopEffect( effect ); } //----------------------------------------------------------------------------- // Purpose: // Input : *player - // effect - // params - //----------------------------------------------------------------------------- void CForceFeedback::StartEffect( CBasePlayer *player, FORCEFEEDBACK_t effect, const FFBaseParams_t& params ) { if ( !player ) { return; } Internal_StartEffect( effect, params ); } //----------------------------------------------------------------------------- // Purpose: // Input : *player - //----------------------------------------------------------------------------- void CForceFeedback::PauseAll( CBasePlayer *player ) { if ( !player ) return; Internal_PauseAll(); } //----------------------------------------------------------------------------- // Purpose: // Input : *player - //----------------------------------------------------------------------------- void CForceFeedback::ResumeAll( CBasePlayer *player ) { if ( !player ) return; Internal_ResumeAll(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CForceFeedback::Internal_StopAllEffects() { input->ForceFeedback_StopAll(); } //----------------------------------------------------------------------------- // Purpose: // Input : heffect - //----------------------------------------------------------------------------- void CForceFeedback::Internal_StopEffect( FORCEFEEDBACK_t effect ) { input->ForceFeedback_Stop( effect ); } //----------------------------------------------------------------------------- // Purpose: // Input : effect - //----------------------------------------------------------------------------- void CForceFeedback::Internal_StartEffect( FORCEFEEDBACK_t effect, const FFBaseParams_t& params) { char const *name = NameForForceFeedbackEffect( effect ); Msg( "Starting FF effect '%s'\n", name ); FFParams p; p.m_nEffectType = effect; p.m_BaseParams = params; input->ForceFeedback_Start( effect, params ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CForceFeedback::Internal_PauseAll() { input->ForceFeedback_Pause(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CForceFeedback::Internal_ResumeAll() { input->ForceFeedback_Resume(); } //----------------------------------------------------------------------------- // Purpose: // Input : *pszName - // iSize - // *pbuf - //----------------------------------------------------------------------------- void CForceFeedback::MsgFunc_ForceFeedback( bf_read &msg ) { byte msgType = msg.ReadByte(); switch ( msgType ) { default: { Warning( "Bad parse in MsgFunc_ForceFeedback!\n" ); } break; case FFMSG_STOPALL: { Internal_StopAllEffects(); } break; case FFMSG_START: { FORCEFEEDBACK_t effectType = (FORCEFEEDBACK_t)msg.ReadByte(); FFBaseParams_t params; params.m_flDirection = 360.0f * ( (byte)msg.ReadByte() / 255.0f ); params.m_flDuration = (float)msg.ReadLong() / 1000.0f; params.m_flGain = ( (byte)msg.ReadByte() / 255.0f ); params.m_nPriority = msg.ReadByte(); params.m_bSolo = msg.ReadByte() == 0 ? false : true; if ( effectType >= 0 && effectType < NUM_FORCE_FEEDBACK_PRESETS ) { Internal_StartEffect( effectType, params ); } else { Warning( "Bad parse in MsgFunc_ForceFeedback, FFMSG_START (%i)!\n", effectType ); } } break; case FFMSG_STOP: { FORCEFEEDBACK_t effectType = (FORCEFEEDBACK_t)msg.ReadByte(); Internal_StopEffect( effectType ); } break; case FFMSG_PAUSE: { Internal_PauseAll(); } break; case FFMSG_RESUME: { Internal_ResumeAll(); } break; } }