diff --git a/mp/src/game/client/client_ff.vpc b/mp/src/game/client/client_ff.vpc index 127ff508..038c5017 100644 --- a/mp/src/game/client/client_ff.vpc +++ b/mp/src/game/client/client_ff.vpc @@ -18,8 +18,8 @@ $Configuration { $Compiler { - $AdditionalIncludeDirectories "$BASE;ff\ui,.\ff,$SRCDIR\game\shared\ff,.\ff,.\ff\elements,$SRCDIR\game\shared\ff;$THIRDPARTYDIR\lua;$THIRDPARTYDIR" - $PreprocessorDefinitions "$BASE;FF;FF_CLIENT_DLL" + $AdditionalIncludeDirectories "$BASE;.\ff;$SRCDIR\game\shared\ff;$THIRDPARTYDIR\lua;$THIRDPARTYDIR" + $PreprocessorDefinitions "$BASE;FF;FF_CLIENT_DLL" } } diff --git a/mp/src/game/server/ff/entities/ff_sv_item_ff_goal.cpp b/mp/src/game/server/ff/entities/ff_sv_item_ff_goal.cpp new file mode 100644 index 00000000..91e9e1f5 --- /dev/null +++ b/mp/src/game/server/ff/entities/ff_sv_item_ff_goal.cpp @@ -0,0 +1,225 @@ +#include "cbase.h" +#include "ff_sv_util.h" +#include "ff_sv_teamcheck_target.h" + + +class CFF_SV_ItemFFGoal : public CFF_SV_TeamcheckTarget +{ +public: + DECLARE_CLASS( CFF_SV_ItemFFGoal, CFF_SV_TeamcheckTarget ); + DECLARE_DATADESC(); + + CFF_SV_ItemFFGoal() + { + SetThink( NULL ); + + m_bEnabled = true; + m_bActive = false; + + m_fActiveTime = 1.5f; + m_fActiveDelay = 0.0f; + } + + void Precache( void ); + void Spawn( void ); + + void OnTouch( CBaseEntity *pOther ); + + void SetActive( CBasePlayer *pPlayer ); + void SetInactive( void ); + +private: + COutputEvent m_OnStartTouch; + COutputEvent m_OnEndTouch; + + void InputEnable( inputdata_t &inputdata ); + void InputDisable( inputdata_t &inputdata ); + void InputSetActive( inputdata_t &inputdata ); + void InputSetInactive( inputdata_t &inputdata ); + + void ThinkDoActive( void ); + void ThinkSetInactive( void ); + + bool m_bEnabled; // If disabled then the goal will ignore all Inputs (except for Enable). + bool m_bActive; // Is the goal active? + + float m_fActiveTime; // How long to stay in the active state. + float m_fActiveDelay; // How long to wait before going in the active state. + + EHANDLE m_hGoalActivator; // The player that activated this goal (this is not always the owner). + EHANDLE m_hGoalOwner; // The player that owns this goal (this is not always the activator). + + string_t m_iszActivatedMsgToAll; // The message sent to everyone when the goal is activated. + string_t m_iszActivatedMsgToOwner; // The message sent to the owner when the goal is activated. + + string_t m_iszSoundName; +}; + + +LINK_ENTITY_TO_CLASS( item_ff_goal, CFF_SV_ItemFFGoal ); + +BEGIN_DATADESC( CFF_SV_ItemFFGoal ) + // Goal keyfields. + DEFINE_KEYFIELD_NOT_SAVED( m_bEnabled, FIELD_BOOLEAN, "enabled" ), + DEFINE_KEYFIELD_NOT_SAVED( m_bActive, FIELD_BOOLEAN, "active" ), + DEFINE_KEYFIELD_NOT_SAVED( m_fActiveTime, FIELD_FLOAT, "active_time" ), + DEFINE_KEYFIELD_NOT_SAVED( m_fActiveDelay, FIELD_FLOAT, "active_delay" ), + + DEFINE_KEYFIELD_NOT_SAVED( m_iszActivatedMsgToAll, FIELD_STRING, "msg_activated_to_all" ), + DEFINE_KEYFIELD_NOT_SAVED( m_iszActivatedMsgToOwner, FIELD_STRING, "msg_activated_to_owner" ), + + DEFINE_KEYFIELD_NOT_SAVED( m_iszSoundName, FIELD_SOUNDNAME, "sound" ), + + // Goal touch functions. + DEFINE_FUNCTION( OnTouch ), + + // Goal think functions. + DEFINE_THINKFUNC( ThinkDoActive ), + DEFINE_THINKFUNC( ThinkSetInactive ), + + // Goal inputs. + DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ), + DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ), + DEFINE_INPUTFUNC( FIELD_VOID, "SetActive", InputSetActive ), + DEFINE_INPUTFUNC( FIELD_VOID, "SetInactive", InputSetInactive ), +END_DATADESC() + + +void CFF_SV_ItemFFGoal::Precache( void ) +{ + if( GetModelName().ToCStr()[0] ) + PrecacheModel( GetModelName().ToCStr() ); + + const char *szSound = m_iszSoundName.ToCStr(); + if( m_iszSoundName != NULL_STRING ) + { + if (*szSound != '!') + PrecacheScriptSound(szSound); + } + + BaseClass::Precache(); +} + +void CFF_SV_ItemFFGoal::Spawn( void ) +{ + Precache(); + + if( GetModelName().ToCStr()[0] ) + SetModel( GetModelName().ToCStr() ); + + SetMoveType( MOVETYPE_NONE ); + //SetSolid( SOLID_VPHYSICS ); // WARNING: If the entity doesn't have a model then we MUST use SOLID_BBOX or the game will crash. + SetSolid( SOLID_BBOX ); + AddSolidFlags( FSOLID_NOT_SOLID | FSOLID_TRIGGER ); + + SetTouch( &CFF_SV_ItemFFGoal::OnTouch ); +} + +void CFF_SV_ItemFFGoal::OnTouch( CBaseEntity *pOther ) +{ + // TODO: Should we just hook this function in StartTouch() instead? + + if(!m_bEnabled || m_bActive) + return; + + // Make sure pOther is a player. + CBasePlayer *pPlayer = dynamic_cast(pOther); + if(!pPlayer) + return; + + SetActive(pPlayer); +} + +void CFF_SV_ItemFFGoal::InputEnable( inputdata_t &inputdata ) +{ + m_bEnabled = true; +} + +void CFF_SV_ItemFFGoal::InputDisable( inputdata_t &inputdata ) +{ + m_bEnabled = false; +} + +void CFF_SV_ItemFFGoal::InputSetActive( inputdata_t &inputdata ) +{ + if(!m_bEnabled || m_bActive) + return; + + SetActive( dynamic_cast(inputdata.pActivator) ); +} + +void CFF_SV_ItemFFGoal::InputSetInactive( inputdata_t &inputdata ) +{ + if(!m_bEnabled || !m_bActive) + return; + + SetInactive(); +} + +void CFF_SV_ItemFFGoal::SetActive( CBasePlayer *pPlayer ) +{ + if( !IsTeamAllowed( pPlayer->GetTeamNumber() ) ) + return; + + m_hGoalActivator = pPlayer; + m_bActive = true; + + if(m_fActiveDelay) + { + SetThink( &CFF_SV_ItemFFGoal::ThinkDoActive ); + SetNextThink( gpGlobals->curtime + m_fActiveDelay ); + } + else + { + ThinkDoActive(); + } +} + +void CFF_SV_ItemFFGoal::SetInactive() +{ + RemoveEffects( EF_NODRAW ); + + m_bActive = false; + + SetThink( NULL ); +} + +void CFF_SV_ItemFFGoal::ThinkDoActive() +{ + AddEffects( EF_NODRAW ); + + CBasePlayer *pActivator = dynamic_cast(m_hGoalActivator.Get()); + if( pActivator ) + { + color32 color = {200, 200, 200, 255}; + FF_UTIL_HudMessageFormat( pActivator, -1.0f, 0.7f, HUD_EFFECT_FADE_IN_OUT, color, color, 0.2f, 0.3f, 1.3f, 0.0f, 1, STRING(m_iszActivatedMsgToOwner) ); + } + + if( m_iszSoundName.ToCStr()[0] ) + { + CRecipientFilter filter; + filter.AddRecipientsByPVS( GetAbsOrigin() ); + filter.MakeReliable(); + + EmitSound_t params; + params.m_pSoundName = m_iszSoundName.ToCStr(); + + EmitSound( filter, ENTINDEX(this), params ); + } + + // Start setting inactive. + if(m_fActiveTime) + { + SetThink( &CFF_SV_ItemFFGoal::ThinkSetInactive ); + SetNextThink( gpGlobals->curtime + m_fActiveTime ); + } + else + { + ThinkSetInactive(); + } +} + +void CFF_SV_ItemFFGoal::ThinkSetInactive() +{ + SetInactive(); +} diff --git a/mp/src/game/server/ff/entities/ff_sv_point_ff_teamcheck.cpp b/mp/src/game/server/ff/entities/ff_sv_point_ff_teamcheck.cpp new file mode 100644 index 00000000..7bcd729a --- /dev/null +++ b/mp/src/game/server/ff/entities/ff_sv_point_ff_teamcheck.cpp @@ -0,0 +1,37 @@ +#include "cbase.h" +#include "ff_sh_util.h" +#include "ff_sv_point_ff_teamcheck.h" + + +LINK_ENTITY_TO_CLASS( point_ff_teamcheck, CFF_SV_PointFFTeamCheck ); + +BEGIN_DATADESC( CFF_SV_PointFFTeamCheck ) + // Keyfields. + DEFINE_KEYFIELD_NOT_SAVED( m_iTeamsAllowed, FIELD_INTEGER, "teams_allowed" ), + + // Inputs. + DEFINE_INPUTFUNC( FIELD_INTEGER, "SetTeamsAllowed", InputSetTeamsAllowed ), + DEFINE_INPUTFUNC( FIELD_VOID, "SwapTeams", InputSwapTeams ), +END_DATADESC() + + +void CFF_SV_PointFFTeamCheck::InputSetTeamsAllowed( inputdata_t &inputdata ) +{ + m_iTeamsAllowed = inputdata.value.Int(); +} + +void CFF_SV_PointFFTeamCheck::InputSwapTeams( inputdata_t &inputdata ) +{ + m_iTeamsAllowed = ~m_iTeamsAllowed; +} + +bool CFF_SV_PointFFTeamCheck::IsTeamAllowed(int iTeamNum) +{ + if(!m_iTeamsAllowed) + return true; + + if(m_iTeamsAllowed & FF_UTIL_GetTeamBit(iTeamNum)) + return true; + + return false; +} diff --git a/mp/src/game/server/ff/entities/ff_sv_point_ff_teamcheck.h b/mp/src/game/server/ff/entities/ff_sv_point_ff_teamcheck.h new file mode 100644 index 00000000..046b4788 --- /dev/null +++ b/mp/src/game/server/ff/entities/ff_sv_point_ff_teamcheck.h @@ -0,0 +1,27 @@ +#pragma once + +#ifndef FF_SV_POINT_FF_TEAMCHECK_H +#define FF_SV_POINT_FF_TEAMCHECK_H + + +class CFF_SV_PointFFTeamCheck : public CBaseEntity +{ +public: + DECLARE_CLASS( CFF_SV_PointFFTeamCheck, CBaseEntity ); + DECLARE_DATADESC(); + + CFF_SV_PointFFTeamCheck() + { + } + + bool IsTeamAllowed(int iTeamNum); + +private: + void InputSetTeamsAllowed( inputdata_t &inputdata ); + void InputSwapTeams( inputdata_t &inputdata ); + + int m_iTeamsAllowed; +}; + + +#endif // FF_SV_POINT_FF_TEAMCHECK_H diff --git a/mp/src/game/server/ff/entities/ff_sv_teamcheck_target.cpp b/mp/src/game/server/ff/entities/ff_sv_teamcheck_target.cpp new file mode 100644 index 00000000..71bb22e0 --- /dev/null +++ b/mp/src/game/server/ff/entities/ff_sv_teamcheck_target.cpp @@ -0,0 +1,28 @@ +#include "cbase.h" +#include "ff_sv_point_ff_teamcheck.h" +#include "ff_sv_teamcheck_target.h" + + +// Don't link this class to an entity. This class is only to be for inheritance. +//LINK_ENTITY_TO_CLASS( teamcheck_target, CFF_SV_TeamcheckTarget ); + +BEGIN_DATADESC( CFF_SV_TeamcheckTarget ) + // Keyfields. + DEFINE_KEYFIELD_NOT_SAVED( m_iszTeamTarget, FIELD_STRING, "teamcheck_target" ), +END_DATADESC() + + +bool CFF_SV_TeamcheckTarget::IsTeamAllowed( int iTeamNum ) +{ + if( !m_iszTeamTarget ) + return true; + + CFF_SV_PointFFTeamCheck *pEnt = dynamic_cast( gEntList.FindEntityByName( NULL, m_iszTeamTarget ) ); + if( !pEnt ) + return true; + + if( pEnt->IsTeamAllowed( iTeamNum ) ) + return true; + + return false; +} diff --git a/mp/src/game/server/ff/entities/ff_sv_teamcheck_target.h b/mp/src/game/server/ff/entities/ff_sv_teamcheck_target.h new file mode 100644 index 00000000..e243a36c --- /dev/null +++ b/mp/src/game/server/ff/entities/ff_sv_teamcheck_target.h @@ -0,0 +1,25 @@ +#pragma once + +#ifndef FF_SV_TEAMCHECK_TARGET_H +#define FF_SV_TEAMCHECK_TARGET_H + + +// NOTE: We might just have to delete this entity and place all the code in CBaseEntity. Unless we find a way to derive from multiple classes. +class CFF_SV_TeamcheckTarget : public CBaseAnimating +{ +public: + DECLARE_CLASS( CFF_SV_TeamcheckTarget, CBaseAnimating ); + DECLARE_DATADESC(); + + CFF_SV_TeamcheckTarget() + { + } + + bool IsTeamAllowed(int iTeamNum); + +private: + string_t m_iszTeamTarget; +}; + + +#endif // FF_SV_TEAMCHECK_TARGET_H diff --git a/mp/src/game/server/ff/ff_sv_util.cpp b/mp/src/game/server/ff/other/ff_sv_util.cpp similarity index 100% rename from mp/src/game/server/ff/ff_sv_util.cpp rename to mp/src/game/server/ff/other/ff_sv_util.cpp diff --git a/mp/src/game/server/ff/ff_sv_util.h b/mp/src/game/server/ff/other/ff_sv_util.h similarity index 93% rename from mp/src/game/server/ff/ff_sv_util.h rename to mp/src/game/server/ff/other/ff_sv_util.h index e35383b8..b9444fed 100644 --- a/mp/src/game/server/ff/ff_sv_util.h +++ b/mp/src/game/server/ff/other/ff_sv_util.h @@ -4,12 +4,12 @@ #define FF_SV_UTIL_H // HUD Messages -typedef enum +enum HUD_MSG_EFFECT { HUD_EFFECT_FADE_IN_OUT = 0, HUD_EFFECT_FLICKER, HUD_EFFECT_WRITE_OUT -} HUD_MSG_EFFECT; +}; void FF_UTIL_HudMessage( CBasePlayer *pToPlayer, float x, float y, HUD_MSG_EFFECT effect, color32 color1, color32 color2, float fadeInTime, float fadeOutTime, float holdTime, float fxTime, int channel, const char *pszMessage ); void FF_UTIL_HudMessageFormat( CBasePlayer *pToPlayer, float x, float y, HUD_MSG_EFFECT effect, color32 color1, color32 color2, float fadeInTime, float fadeOutTime, float holdTime, float fxTime, int channel, const char *pszFormat, ... ); @@ -17,4 +17,4 @@ void FF_UTIL_HudMessageAll( float x, float y, HUD_MSG_EFFECT effect, color32 col void FF_UTIL_HudMessageAllFormat( float x, float y, HUD_MSG_EFFECT effect, color32 color1, color32 color2, float fadeInTime, float fadeOutTime, float holdTime, float fxTime, int channel, const char *pszFormat, ... ); -#endif //FF_SV_UTIL_H +#endif // FF_SV_UTIL_H diff --git a/mp/src/game/server/server_ff.vpc b/mp/src/game/server/server_ff.vpc index d6e95944..c9b3fd19 100644 --- a/mp/src/game/server/server_ff.vpc +++ b/mp/src/game/server/server_ff.vpc @@ -17,8 +17,8 @@ $Configuration { $Compiler { - $AdditionalIncludeDirectories "$BASE;$SRCDIR\game\shared\ff,.\ff,.\ff,$SRCDIR\game\shared\ff;$THIRDPARTYDIR\lua;$THIRDPARTYDIR" - $PreprocessorDefinitions "$BASE;FF;FF_DLL" + $AdditionalIncludeDirectories "$BASE;.\ff;.\ff\other;.\ff\entities;$SRCDIR\game\shared\ff;$SRCDIR\game\shared\ff\other;$THIRDPARTYDIR\lua;$THIRDPARTYDIR" + $PreprocessorDefinitions "$BASE;FF;FF_DLL" } } @@ -40,9 +40,19 @@ $Project "Server (FF)" $File "ff\ff_sv_player.cpp" $File "ff\ff_sv_player.h" } - - $File "ff\ff_sv_util.cpp" - $File "ff\ff_sv_util.h" + $Folder "Entities" + { + $File "ff\entities\ff_sv_item_ff_goal.cpp" + $File "ff\entities\ff_sv_point_ff_teamcheck.cpp" + $File "ff\entities\ff_sv_point_ff_teamcheck.h" + $File "ff\entities\ff_sv_teamcheck_target.h" + $File "ff\entities\ff_sv_teamcheck_target.cpp" + } + $Folder "Other" + { + $File "ff\other\ff_sv_util.cpp" + $File "ff\other\ff_sv_util.h" + } } diff --git a/mp/src/game/shared/ff/ff_sh_shareddefs.h b/mp/src/game/shared/ff/ff_sh_shareddefs.h index 11151908..6eff7804 100644 --- a/mp/src/game/shared/ff/ff_sh_shareddefs.h +++ b/mp/src/game/shared/ff/ff_sh_shareddefs.h @@ -6,7 +6,7 @@ // FF Team stuff // note, when ported i switched to an enum so we have our custom team stuff a little more obvious -typedef enum +typedef enum { TEAM_BLUE = 2, TEAM_RED, @@ -24,7 +24,7 @@ typedef enum } FF_TEAM; -typedef enum +typedef enum { FF_CLASS_UNASSIGNED = 0, FF_CLASS_SCOUT, @@ -40,4 +40,53 @@ typedef enum FF_CLASS_COUNT } FF_CLASS; + +enum +{ + FF_TEAM_NUM_UNASSIGNED = 0, + FF_TEAM_NUM_SPECTATE, + FF_TEAM_NUM_ONE, + FF_TEAM_NUM_TWO, + FF_TEAM_NUM_THREE, + FF_TEAM_NUM_FOUR, + FF_TEAM_NUM_FIVE, + FF_TEAM_NUM_SIX, + FF_TEAM_NUM_SEVEN, + FF_TEAM_NUM_EIGHT, + FF_TEAM_NUM_NINE, + FF_TEAM_NUM_TEN, + FF_TEAM_NUM_ELEVEN, + FF_TEAM_NUM_TWELVE, + FF_TEAM_NUM_THIRTEEN, + FF_TEAM_NUM_FOURTEEN, + FF_TEAM_NUM_FIFTEEN, + FF_TEAM_NUM_SIXTEEN, + FF_TEAM_NUM_SEVENTEEN, + FF_TEAM_NUM_EIGHTEEN, + FF_TEAM_NUM_NINETEEN, + FF_TEAM_NUM_TWENTY, + FF_TEAM_NUM_TWENTYONE, + FF_TEAM_NUM_TWENTYTWO, + FF_TEAM_NUM_TWENTYTHREE, + FF_TEAM_NUM_TWENTYFOUR, + FF_TEAM_NUM_TWENTYFIVE, + FF_TEAM_NUM_TWENTYSIX, + FF_TEAM_NUM_TWENTYSEVEN, + FF_TEAM_NUM_TWENTYEIGHT, + FF_TEAM_NUM_TWENTYNINE, + FF_TEAM_NUM_THIRTY, + FF_TEAM_NUM_THIRTYONE +}; + +const int FF_TEAM_BITS[] = +{ + 0, 0, (1<<0), (1<<1), (1<<2), + (1<<3), (1<<4), (1<<5), (1<<6), (1<<7), + (1<<8), (1<<9), (1<<10), (1<<11), (1<<12), + (1<<13), (1<<14), (1<<15), (1<<16), (1<<17), + (1<<18), (1<<19), (1<<20), (1<<21), (1<<22), + (1<<23), (1<<24), (1<<25), (1<<26), (1<<27), + (1<<28), (1<<29), (1<<30) +}; + #endif // FF_SH_SHAREDDEFS_H \ No newline at end of file diff --git a/mp/src/game/shared/ff/ff_shared.vpc b/mp/src/game/shared/ff/ff_shared.vpc index 6e414aaa..ce0b179c 100644 --- a/mp/src/game/shared/ff/ff_shared.vpc +++ b/mp/src/game/shared/ff/ff_shared.vpc @@ -1,4 +1,4 @@ -// VPC included in client/server FF VPCs containing all shared +// VPC included in client/server FF VPCs containing all shared // expects $SRCDIR macro to exist $Project @@ -37,6 +37,11 @@ $Project $File "$SRCDIR\game\shared\ff\ff_sh_team_manager.h" $File "$SRCDIR\game\shared\ff\ff_sh_team_manager.cpp" } + $Folder "Other" + { + $File "$SRCDIR\game\shared\ff\other\ff_sh_util.cpp" + $File "$SRCDIR\game\shared\ff\other\ff_sh_util.h" + } } // folder structure has to match for remove to work correctly.. diff --git a/mp/src/game/shared/ff/other/ff_sh_util.cpp b/mp/src/game/shared/ff/other/ff_sh_util.cpp new file mode 100644 index 00000000..c29c68ee --- /dev/null +++ b/mp/src/game/shared/ff/other/ff_sh_util.cpp @@ -0,0 +1,12 @@ +#include "cbase.h" +#include "ff_sh_util.h" +#include "ff_sh_shareddefs.h" + + +int FF_UTIL_GetTeamBit( int teamNum ) +{ + if( teamNum >= sizeof(FF_TEAM_BITS) || teamNum < 0 ) + return 0; + + return FF_TEAM_BITS[teamNum]; +} diff --git a/mp/src/game/shared/ff/other/ff_sh_util.h b/mp/src/game/shared/ff/other/ff_sh_util.h new file mode 100644 index 00000000..1d2f146e --- /dev/null +++ b/mp/src/game/shared/ff/other/ff_sh_util.h @@ -0,0 +1,10 @@ +#pragma once + +#ifndef FF_SH_UTIL_H +#define FF_SH_UTIL_H + + +int FF_UTIL_GetTeamBit( int teamNum ); + + +#endif // FF_SH_UTIL_H