diff options
Diffstat (limited to 'game/shared/tf/tf_wheel_of_doom.cpp')
| -rw-r--r-- | game/shared/tf/tf_wheel_of_doom.cpp | 1117 |
1 files changed, 1117 insertions, 0 deletions
diff --git a/game/shared/tf/tf_wheel_of_doom.cpp b/game/shared/tf/tf_wheel_of_doom.cpp new file mode 100644 index 0000000..d9a471a --- /dev/null +++ b/game/shared/tf/tf_wheel_of_doom.cpp @@ -0,0 +1,1117 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Auto Repair +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "tf/halloween/merasmus/merasmus.h" +#include "tf/halloween/merasmus/merasmus_dancer.h" +#include "tf_gamerules.h" +#include "tf_weapon_jar.h" +#include "tf_wheel_of_doom.h" + + +LINK_ENTITY_TO_CLASS( wheel_of_doom, CWheelOfDoom ); + +// Data Description +BEGIN_DATADESC( CWheelOfDoom ) + + // Keyfields + DEFINE_KEYFIELD( m_flDuration, FIELD_FLOAT, "effect_duration" ), + DEFINE_KEYFIELD( m_bHasSpiral, FIELD_BOOLEAN, "has_spiral" ), + + DEFINE_INPUTFUNC( FIELD_STRING, "Spin", Spin ), + DEFINE_INPUTFUNC( FIELD_STRING, "ClearAllEffects", ClearAllEffects ), + + // Outputs + DEFINE_OUTPUT( m_EffectApplied, "OnEffectApplied" ), + DEFINE_OUTPUT( m_EffectExpired, "OnEffectExpired" ), + +END_DATADESC() + +extern ConVar sv_gravity; + +#define WHEEL_SPIN_TIME 5.75f +#define WHEEL_SPIN_TIME_BIAS 0.3f +#define WHEEL_FASTEST_SPIN_RATE 0.1f +#define WHEEL_SLOWEST_SPIN_RATE 0.55f + +#define WHEEL_SPIRAL_GROW_RATE 0.55f +#define WHEEL_SPIRAL_SHRINK_RATE 0.55f + + +#define EFFECT_WHAMMY 1<<0 +#define EFFECT_DOES_NOT_REAPPLY_ON_SPAWN 1<<1 + + +class CWheelOfDoomSpiral : public CBaseAnimating +{ + DECLARE_CLASS( CWheelOfDoom, CBaseAnimating ); + DECLARE_DATADESC(); + +public: + CWheelOfDoomSpiral() + { + m_flScale = 0.f; + SetModelScale( 0.f ); + } + + virtual void Spawn() + { + SetThink( NULL ); + } + + virtual void Precache() + { + PrecacheModel( "models/props_lakeside_event/wof_plane2.mdl" ); + } + + void GrowAndBecomeVisible() + { + RemoveEffects( EF_NODRAW ); + + SetThink( &CWheelOfDoomSpiral::GrowThink ); + SetNextThink( gpGlobals->curtime ); + } + + void ShrinkAndHide() + { + SetThink( &CWheelOfDoomSpiral::ShrinkThink ); + SetNextThink( gpGlobals->curtime ); + } + +private: + + void GrowThink() + { + // Grow ourselves over time + m_flScale += WHEEL_SPIRAL_GROW_RATE * gpGlobals->frametime; + + if( m_flScale >= 1.f ) + { + m_flScale = 1.f; + SetThink( NULL ); + } + + SetModelScale( m_flScale ); + + SetNextThink( gpGlobals->curtime ); + } + + void ShrinkThink() + { + // Shrink ourselves over time + m_flScale -= WHEEL_SPIRAL_SHRINK_RATE * gpGlobals->frametime; + + if( m_flScale <= 0.f ) + { + m_flScale = 0.f; + AddEffects( EF_NODRAW ); + SetThink( NULL ); + } + + SetModelScale( m_flScale ); + + SetNextThink( gpGlobals->curtime ); + } + + float m_flScale; +}; + +LINK_ENTITY_TO_CLASS( wheel_of_doom_spiral, CWheelOfDoomSpiral ); + +// Data Description +BEGIN_DATADESC( CWheelOfDoomSpiral ) +END_DATADESC() + +#ifdef STAGING_ONLY +static void ProcWheelEffect( const CCommand &args ) +{ + CBaseEntity *pOther = gEntList.FindEntityByClassname( NULL, "wheel_of_doom" ); + + CWheelOfDoom* pWheel = dynamic_cast<CWheelOfDoom*>( pOther ); + if( pWheel ) + { + pWheel->DBG_ApplyEffectByName( args.ArgS() ); + } +} +ConCommand cc_proc_wheel_effect( "cc_proc_wheel_effect", ProcWheelEffect, "Force a Wheel of Doom entity to apply the specified effect" ); +#endif + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CWheelOfDoom::CWheelOfDoom( void ) : + m_EffectManager( this ), + m_pChosenEffect( NULL ), + m_pSpiral( NULL ), + m_flFinishBroadcastingEffectTime( 0.f ) +{ + AddEffects( EF_NODRAW ); + + RegisterEffect( new WOD_UberEffect() ); + RegisterEffect( new WOD_CritsEffect() ); + RegisterEffect( new WOD_SuperSpeedEffect() ); + RegisterEffect( new WOD_SuperJumpEffect() ); + RegisterEffect( new WOD_BigHeadEffect() ); + RegisterEffect( new WOD_SmallHeadEffect() ); + RegisterEffect( new WOD_LowGravityEffect() ); + RegisterEffect( new WOD_Dance(), EFFECT_DOES_NOT_REAPPLY_ON_SPAWN ); + RegisterEffect( new WOD_Pee(), EFFECT_WHAMMY | EFFECT_DOES_NOT_REAPPLY_ON_SPAWN ); + RegisterEffect( new WOD_Burn(), EFFECT_WHAMMY | EFFECT_DOES_NOT_REAPPLY_ON_SPAWN ); + RegisterEffect( new WOD_Ghosts(), EFFECT_WHAMMY | EFFECT_DOES_NOT_REAPPLY_ON_SPAWN ); +} + + +CWheelOfDoom::~CWheelOfDoom( void ) +{ + m_EffectManager.ClearEffects(); + m_vecEffects.PurgeAndDeleteElements(); +} + + +void CWheelOfDoom::RegisterEffect( WOD_BaseEffect* pEffect, int nFlags ) +{ + pEffect->SetListFlags( nFlags ); + m_vecEffects.AddToTail( pEffect ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWheelOfDoom::Precache( void ) +{ + PrecacheModel( GetScreenModelName() ); + PrecacheModel( "models/props_lakeside_event/wof_plane2.mdl" ); + + PrecacheScriptSound( "Halloween.WheelofFate" ); + PrecacheScriptSound( "Halloween.dance_howl" ); + PrecacheScriptSound( "Halloween.dance_loop" ); + + PrecacheScriptSound( "Halloween.HeadlessBossAxeHitWorld" ); + PrecacheScriptSound( "Halloween.LightsOn" ); + PrecacheScriptSound( "Weapon_StickyBombLauncher.BoltForward" ); + PrecacheScriptSound( "TFPlayer.InvulnerableOff" ); + + m_EffectManager.Precache(); +} + +const char* CWheelOfDoom::GetScreenModelName() +{ + return "models/props_lakeside_event/buff_plane.mdl"; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWheelOfDoom::Spawn( void ) +{ + Precache(); + + SetModel( GetScreenModelName() ); + + SetSolid( SOLID_BBOX ); + AddSolidFlags( FSOLID_NOT_SOLID ); + SetMoveType( MOVETYPE_NONE ); + + ListenForGameEvent( "player_spawn" ); + + SetThink( &CWheelOfDoom::IdleThink ); + SetNextThink( gpGlobals->curtime + 0.1f ); + + if ( TFGameRules() != NULL ) + { + TFGameRules()->ClearHalloweenEffectStatus(); + } + + if( m_bHasSpiral ) + { + m_pSpiral = assert_cast<CWheelOfDoomSpiral*>( CreateEntityByName( "wheel_of_doom_spiral" ) ); + Assert( m_pSpiral ); + m_pSpiral->SetModel( "models/props_lakeside_event/wof_plane2.mdl" ); + m_pSpiral->AddEffects( EF_NODRAW ); + m_pSpiral->SetAbsOrigin( GetAbsOrigin() ); + m_pSpiral->SetAbsAngles( GetAbsAngles() ); + m_pSpiral->SetParent( this ); + } +} + +void CWheelOfDoom::FireGameEvent( IGameEvent *gameEvent ) +{ + if( FStrEq( gameEvent->GetName(), "player_spawn" ) ) + { + const int nUserID = gameEvent->GetInt( "userid" ); + CTFPlayer *pPlayer = ToTFPlayer( UTIL_PlayerByUserId( nUserID ) ); + if( pPlayer ) + { + m_EffectManager.ApplyAllEffectsToPlayer( pPlayer ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWheelOfDoom::IdleThink( void ) +{ + if( m_EffectManager.UpdateAndClearExpiredEffects() ) + { + AddEffects( EF_NODRAW ); + + m_EffectExpired.FireOutput( this, this ); + + // Clear the skin to blank + SetSkin( 0 ); + + // Clear the HUD + TFGameRules()->ClearHalloweenEffectStatus(); + + if( m_bHasSpiral ) + { + // Make our spirals shrink down and hide themselves + m_pSpiral->ShrinkAndHide(); + FOR_EACH_VEC( m_vecOtherWODs, i ) + { + if( m_vecOtherWODs[i]->m_bHasSpiral ) + { + m_vecOtherWODs[i]->m_pSpiral->ShrinkAndHide(); + } + } + } + } + + //Next update + SetNextThink( gpGlobals->curtime + 0.1f ); +} + +void CWheelOfDoom::SetSkin( int nSkin ) +{ + m_nSkin = nSkin; + + FOR_EACH_VEC( m_vecOtherWODs, i ) + { + m_vecOtherWODs[i]->m_nSkin = nSkin; + } +} + +void CWheelOfDoom::SetScale( float flScale ) +{ + SetModelScale( flScale ); + + FOR_EACH_VEC( m_vecOtherWODs, i ) + { + m_vecOtherWODs[i]->SetModelScale( flScale ); + } +} + + +void CWheelOfDoom::PlaySound( const char* pszSound ) +{ + EmitSound( pszSound ); + + FOR_EACH_VEC( m_vecOtherWODs, i ) + { + m_vecOtherWODs[i]->EmitSound( pszSound ); + } +} + + +void CWheelOfDoom::SpinThink( void ) +{ + if( m_EffectManager.UpdateAndClearExpiredEffects() ) + { + m_EffectExpired.FireOutput( this, this ); + + // Clear the HUD + TFGameRules()->ClearHalloweenEffectStatus(); + } + + // Are we done spinning? + if( gpGlobals->curtime > m_flStopSpinTime ) + { + if( gpGlobals->curtime > m_flStopSpinTime + 1.f ) + { + //PlaySound( "Halloween.LightsOn" ); + SetScale( 1.f ); + + m_EffectApplied.FireOutput( this, this ); + + // Apply the effect! + SetSkin( m_EffectManager.AddEffect( m_pChosenEffect, m_flDuration ) ); + + SetThink( &CWheelOfDoom::IdleThink ); + + m_flStopSpinTime = 0.f; + m_flNextTickTime = 0.f; + m_pChosenEffect = NULL; + } + } + // Is it time for another tick of the wheel? + else if( gpGlobals->curtime > m_flNextTickTime ) + { + int nRandSkin = RandomInt( 1, EFFECT_COUNT-1 ); + if( nRandSkin == m_nSkin ) + ++nRandSkin; + + // Roll over to 1. 0 is blank so skip that one. + if( nRandSkin == EFFECT_COUNT ) + nRandSkin = 1; + + SetSkin( nRandSkin ); + SetScale( RemapVal( CalcSpinCompletion(), 0.f, 1.f, 0.3f, 0.9f) ); + + m_flNextTickTime = CalcNextTickTime(); + } + + //Is it time for Merasmus to announce the spin? + if (gpGlobals->curtime > m_flNextAnnounceTime && !m_bAnnounced) + { + m_bAnnounced = true; + CMerasmus* pMerasmus = assert_cast< CMerasmus* >( TFGameRules()->GetActiveBoss() ); + if (pMerasmus) + { + pMerasmus->PlayHighPrioritySound("Halloween.MerasmusWheelSpin"); + } + else + { + TFGameRules()->BroadcastSound(255,"Halloween.MerasmusWheelSpin"); + } + } + + // Next update + SetNextThink( gpGlobals->curtime ); +} + +float CWheelOfDoom::CalcNextTickTime() const +{ + float flProgress = CalcSpinCompletion(); + float flBias = Bias( flProgress, WHEEL_SPIN_TIME_BIAS ); + return gpGlobals->curtime + (( 1 - flBias ) * WHEEL_FASTEST_SPIN_RATE) + (flBias) * WHEEL_SLOWEST_SPIN_RATE; +} + + +float CWheelOfDoom::CalcSpinCompletion() const +{ + const float& flDuration = WHEEL_SPIN_TIME; + return ( flDuration - (m_flStopSpinTime - gpGlobals->curtime) ) / flDuration; +} + +void CWheelOfDoom::StartSpin( void ) +{ + RemoveEffects( EF_NODRAW ); + m_vecOtherWODs.Purge(); + CBaseEntity *pOther = gEntList.FindEntityByClassname( NULL, "wheel_of_doom" ); + + // Play the sound of the wheel starting to spin + if( TFGameRules() ) + { + TFGameRules()->BroadcastSound( 255, "Halloween.WheelofFate" ); + } + + // Gather all of the other WheelofDoom entities so we can control their screens as we spin + while ( pOther ) + { + if( pOther != this ) + { + m_vecOtherWODs.AddToTail( dynamic_cast<CWheelOfDoom*>( pOther ) ); + } + + // Change the target over + pOther = gEntList.FindEntityByClassname( pOther, "wheel_of_doom" ); + } + + if( m_bHasSpiral ) + { + // Make our spirals show up and grow + m_pSpiral->GrowAndBecomeVisible(); + FOR_EACH_VEC( m_vecOtherWODs, i ) + { + if( m_vecOtherWODs[i]->m_bHasSpiral ) + { + m_vecOtherWODs[i]->m_pSpiral->GrowAndBecomeVisible(); + } + } + } + + // Setup spin logic + m_flStopSpinTime = gpGlobals->curtime + WHEEL_SPIN_TIME; + m_flNextTickTime = CalcNextTickTime(); + m_flNextAnnounceTime = gpGlobals->curtime + 1.6; + m_bAnnounced = false; + + m_flFinishBroadcastingEffectTime = m_flStopSpinTime + 10.f; + + SetThink( &CWheelOfDoom::SpinThink ); + SetNextThink( gpGlobals->curtime ); +} + + +void CWheelOfDoom::Spin( inputdata_t& inputdata ) +{ + // Remember which effect was chosen so we can apply it once the spinning is done + m_pChosenEffect = GetRandomEffectWithFlags(); + StartSpin(); +} + + +CWheelOfDoom::WOD_BaseEffect* CWheelOfDoom::GetRandomEffectWithFlags() +{ + int nNumWhammys = 0; + int nNumGoodEffects = 0; + CUtlVector<WOD_BaseEffect*> vecMatchingEffects; + + // Collect all of the effects that match our criteria. + // Buffs in the front of the vector and whammys on the end + FOR_EACH_VEC( m_vecEffects, i ) + { + WOD_BaseEffect* pEffect = m_vecEffects[i]; + + if( pEffect->GetListFlags() & EFFECT_WHAMMY ) + { + // Tally up all the whammys + ++nNumWhammys; + vecMatchingEffects.AddToTail( pEffect ); + } + else + { + ++nNumGoodEffects; + vecMatchingEffects.AddToHead( pEffect ); + } + } + + // No matching effects. Return null + if( vecMatchingEffects.Count() == 0 ) + { + return NULL; + } + + // No Whammies? Just return a random one + if( nNumWhammys == 0 ) + { + return vecMatchingEffects[RandomInt( 0, nNumGoodEffects-1 )]; + } + + // Given n good buffs, give a 1/n+1 chance of hitting a whammy + int nRand = RandomInt( 0, nNumGoodEffects ); + + // Rolled a whammy! + if( nRand == nNumGoodEffects ) + { + //Roll again to find out which whammy we get + nRand = nNumGoodEffects + RandomInt( 0, nNumWhammys-1 ); + } + + return vecMatchingEffects[nRand]; +} + + +void CWheelOfDoom::ClearAllEffects( inputdata_t& inputdata ) +{ + m_EffectManager.ClearEffects(); +} + + +bool CWheelOfDoom::IsDoneBoardcastingEffectSound() const +{ + return gpGlobals->curtime > m_flFinishBroadcastingEffectTime; +} + + +void CWheelOfDoom::DBG_ApplyEffectByName( const char* pszEffectName ) +{ + FOR_EACH_VEC( m_vecEffects, i ) + { + WOD_BaseEffect* pEffect = m_vecEffects[i]; + if( FStrEq( pEffect->GetName(), pszEffectName ) ) + { + m_EffectManager.AddEffect( pEffect, m_flDuration ); + } + } +} + +CWheelOfDoom::WOD_BaseEffect::WOD_BaseEffect() +{ + m_flExpireTime = 0; + m_pszEffectAnnouncementSound = NULL; + m_pszName = NULL; + m_iListFlags = 0; +} + +void CWheelOfDoom::WOD_BaseEffect::InitEffect( float flDefaultDuration ) +{ + m_flExpireTime = gpGlobals->curtime + flDefaultDuration; +} + +void CWheelOfDoom::WOD_BaseEffect::SetListFlags( int iFlags ) +{ + m_iListFlags = iFlags; +} + +CWheelOfDoom::EffectManager::~EffectManager() +{ +} + +int CWheelOfDoom::EffectManager::AddEffect( WOD_BaseEffect* pEffect, float flDefaultDuration ) +{ + Assert( pEffect ); + + EffectData_t data; + data.m_pWheel = m_pWheel; + CollectPlayers( &data.m_vecPlayers ); + pEffect->InitEffect( flDefaultDuration ); + pEffect->ActivateEffect( data ); + + float flExpireDiff = pEffect->m_flExpireTime - gpGlobals->curtime; + DevMsg( "[WHEEL OF DOOM]\t Activating: \"%s\" set to expire in %3.2fs\n", pEffect->m_pszName, flExpireDiff ); + + if( TFGameRules() ) + { + CMerasmus* pMerasmus = assert_cast< CMerasmus* >( TFGameRules()->GetActiveBoss() ); + if (pMerasmus) + { + pMerasmus->PlayHighPrioritySound(pEffect->m_pszEffectAnnouncementSound); + } + else + { + TFGameRules()->BroadcastSound(255,pEffect->m_pszEffectAnnouncementSound); + } + // Update the HUD + TFGameRules()->SetHalloweenEffectStatus( int(pEffect->m_nSkin), flExpireDiff ); + SpeakMagicConceptToAllPlayers(pEffect->m_pszEffectAnnouncementSound); + } + + // Remember this effect + m_vecActiveEffects.AddToTail( pEffect ); + + return pEffect->m_nSkin; +} + +void CWheelOfDoom::EffectManager::ApplyAllEffectsToPlayer( CTFPlayer* pPlayer ) +{ + EffectData_t data; + data.m_pWheel = m_pWheel; + data.m_vecPlayers.AddToTail( pPlayer ); + + FOR_EACH_VEC( m_vecActiveEffects, i ) + { + if( m_vecActiveEffects[i]->GetListFlags() & EFFECT_DOES_NOT_REAPPLY_ON_SPAWN ) + continue; + + m_vecActiveEffects[i]->ActivateEffect( data ); + } +} + +void CWheelOfDoom::EffectManager::ClearEffects() +{ + FOR_EACH_VEC( m_vecActiveEffects, i ) + { + DevMsg( "[WHEEL OF DOOM]\t Deactivating: %s\n", m_vecActiveEffects[i]->m_pszName ); + + EffectData_t data; + data.m_pWheel = m_pWheel; + CollectPlayers( &data.m_vecPlayers ); + + m_vecActiveEffects[i]->DeactivateEffect( data ); + } + + m_vecActiveEffects.Purge(); +} + +bool CWheelOfDoom::EffectManager::UpdateAndClearExpiredEffects() +{ + bool bEffectExpired = false; + + EffectData_t data; + data.m_pWheel = m_pWheel; + CollectPlayers( &data.m_vecPlayers ); + + FOR_EACH_VEC_BACK( m_vecActiveEffects, i ) + { + // Check if the effect is expired. If so, run its DeactivateEffect and remove it + WOD_BaseEffect* pEffect = m_vecActiveEffects[i]; + if( gpGlobals->curtime > pEffect->m_flExpireTime ) + { + DevMsg( "[WHEEL OF DOOM]\t Effect expired: %s\n", pEffect->m_pszName ); + bEffectExpired = true; + + pEffect->DeactivateEffect( data ); + + m_vecActiveEffects.Remove( i ); + } + else // If it's not expired, then update + { + pEffect->UpdateEffect( data ); + } + } + + return bEffectExpired; +} + + +void CWheelOfDoom::EffectManager::Precache() +{ + FOR_EACH_VEC( m_vecActiveEffects, i ) + { + PrecacheScriptSound( m_vecActiveEffects[i]->m_pszEffectAnnouncementSound ); + } +} + +void CWheelOfDoom::SpeakMagicConceptToAllPlayers( const char* pszEffect ) +{ + int iConcept = -1; + + if ( !V_stricmp( pszEffect, "Halloween.MerasmusWheelBigHead") ) + { + iConcept = MP_CONCEPT_MAGIC_BIGHEAD; + } + else if ( !V_stricmp( pszEffect, "Halloween.MerasmusWheelShrunkHead") ) + { + iConcept = MP_CONCEPT_MAGIC_SMALLHEAD; + } + else if ( !V_stricmp( pszEffect, "Halloween.MerasmusWheelGravity") ) + { + iConcept = MP_CONCEPT_MAGIC_GRAVITY; + } + else if ( (!V_stricmp( pszEffect, "Halloween.MerasmusWheelCrits")) || (!V_stricmp( pszEffect, "Halloween.MerasmusWheelUber")) || (!V_stricmp( pszEffect, "Halloween.MerasmusWheelSuperSpeed"))) + { + iConcept = MP_CONCEPT_MAGIC_GOOD; + } + else if ( !V_stricmp( pszEffect, "Halloween.MerasmusWheelDance") ) + { + iConcept = MP_CONCEPT_MAGIC_DANCE; + } + + if (iConcept >= 0) + { + CUtlVector< CTFPlayer * > playerVector; + CollectPlayers( &playerVector ); + FOR_EACH_VEC( playerVector, i ) + { + playerVector[i]->SpeakConceptIfAllowed(iConcept); + } + } +} + + + +void CWheelOfDoom::ApplyAttributeToAllPlayers( const char* pszAttribName, float flValue ) +{ + CUtlVector< CTFPlayer * > playerVector; + CollectPlayers( &playerVector ); + FOR_EACH_VEC( playerVector, i ) + { + ApplyAttributeToPlayer( playerVector[i], pszAttribName, flValue ); + } +} + +void CWheelOfDoom::ApplyAttributeToPlayer( CTFPlayer* pPlayer, const char* pszAttribName, float flValue ) +{ + Assert( pPlayer ); + + const CEconItemAttributeDefinition *pDef = GetItemSchema()->GetAttributeDefinitionByName( pszAttribName ); + + pPlayer->GetAttributeList()->SetRuntimeAttributeValue( pDef, flValue ); + pPlayer->TeamFortress_SetSpeed(); +} + +void CWheelOfDoom::RemoveAttributeFromAllPlayers( const char* pszAttributeName ) +{ + const CEconItemAttributeDefinition *pDef = GetItemSchema()->GetAttributeDefinitionByName( pszAttributeName ); + + CUtlVector< CTFPlayer * > playerVector; + CollectPlayers( &playerVector ); + FOR_EACH_VEC( playerVector, i ) + { + CTFPlayer* pPlayer = playerVector[i]; + pPlayer->GetAttributeList()->RemoveAttribute( pDef ); + } +} + +void CWheelOfDoom::RemoveAttributeFromPlayer( CTFPlayer* pPlayer, const char* pszAttribName ) +{ + const CEconItemAttributeDefinition *pDef = GetItemSchema()->GetAttributeDefinitionByName( pszAttribName ); + pPlayer->GetAttributeList()->RemoveAttribute( pDef ); +} + +void CWheelOfDoom::WOD_UberEffect::InitEffect( float flDefaultExpireTime ) +{ + m_flExpireTime = gpGlobals->curtime + Min( flDefaultExpireTime, 10.f ); +} + +void CWheelOfDoom::WOD_UberEffect::ActivateEffect( EffectData_t& data ) +{ + float flDuration = m_flExpireTime - gpGlobals->curtime; + + FOR_EACH_VEC( data.m_vecPlayers, i ) + { + CTFPlayer* pPlayer = data.m_vecPlayers[i]; + pPlayer->m_Shared.AddCond( TF_COND_INVULNERABLE, flDuration ); + } +} + + +void CWheelOfDoom::WOD_CritsEffect::ActivateEffect( EffectData_t& data ) +{ + float flDuration = m_flExpireTime - gpGlobals->curtime; + + FOR_EACH_VEC( data.m_vecPlayers, i ) + { + CTFPlayer* pPlayer = data.m_vecPlayers[i]; + pPlayer->m_Shared.AddCond( TF_COND_CRITBOOSTED_PUMPKIN, flDuration ); + } +} + + +void CWheelOfDoom::WOD_SuperSpeedEffect::ActivateEffect( EffectData_t& data ) +{ + FOR_EACH_VEC( data.m_vecPlayers, i ) + { + CTFPlayer* pPlayer = data.m_vecPlayers[i]; + CWheelOfDoom::ApplyAttributeToPlayer( pPlayer, "major move speed bonus", 2.f ); + } +} + + +void CWheelOfDoom::WOD_SuperSpeedEffect::DeactivateEffect( EffectData_t& data ) +{ + FOR_EACH_VEC( data.m_vecPlayers, i ) + { + CTFPlayer* pPlayer = data.m_vecPlayers[i]; + CWheelOfDoom::RemoveAttributeFromPlayer( pPlayer, "major move speed bonus" ); + // Recalc our max speed + pPlayer->TeamFortress_SetSpeed(); + } +} + + +void CWheelOfDoom::WOD_SuperJumpEffect::ActivateEffect( EffectData_t& data ) +{ + FOR_EACH_VEC( data.m_vecPlayers, i ) + { + CTFPlayer* pPlayer = data.m_vecPlayers[i]; + CWheelOfDoom::ApplyAttributeToPlayer( pPlayer, "major increased jump height", 3.f ); + CWheelOfDoom::ApplyAttributeToPlayer( pPlayer, "cancel falling damage", 1.f ); + } +} + +void CWheelOfDoom::WOD_SuperJumpEffect::DeactivateEffect( EffectData_t& data ) +{ + FOR_EACH_VEC( data.m_vecPlayers, i ) + { + CTFPlayer* pPlayer = data.m_vecPlayers[i]; + CWheelOfDoom::RemoveAttributeFromPlayer( pPlayer, "major increased jump height" ); + CWheelOfDoom::RemoveAttributeFromPlayer( pPlayer, "cancel falling damage" ); + } +} + + +void CWheelOfDoom::WOD_BigHeadEffect::ActivateEffect( EffectData_t& data ) +{ + FOR_EACH_VEC( data.m_vecPlayers, i ) + { + CTFPlayer* pPlayer = data.m_vecPlayers[i]; + ApplyAttributeToPlayer( pPlayer, "voice pitch scale", 0.85f ); + ApplyAttributeToPlayer( pPlayer, "head scale", 3.f ); + } +} + +void CWheelOfDoom::WOD_BigHeadEffect::DeactivateEffect( EffectData_t& data ) +{ + FOR_EACH_VEC( data.m_vecPlayers, i ) + { + CTFPlayer* pPlayer = data.m_vecPlayers[i]; + RemoveAttributeFromPlayer( pPlayer, "voice pitch scale" ); + RemoveAttributeFromPlayer( pPlayer, "head scale" ); + } +} + + +void CWheelOfDoom::WOD_SmallHeadEffect::ActivateEffect( EffectData_t& data ) +{ + FOR_EACH_VEC( data.m_vecPlayers, i ) + { + CTFPlayer* pPlayer = data.m_vecPlayers[i]; + ApplyAttributeToPlayer( pPlayer, "voice pitch scale", 1.3f ); + ApplyAttributeToPlayer( pPlayer, "head scale", 0.5f ); + } +} + +void CWheelOfDoom::WOD_SmallHeadEffect::DeactivateEffect( EffectData_t& data ) +{ + FOR_EACH_VEC( data.m_vecPlayers, i ) + { + CTFPlayer* pPlayer = data.m_vecPlayers[i]; + RemoveAttributeFromPlayer( pPlayer, "voice pitch scale" ); + RemoveAttributeFromPlayer( pPlayer, "head scale" ); + } +} + + + +void CWheelOfDoom::WOD_LowGravityEffect::ActivateEffect( EffectData_t& /*data*/ ) +{ + if ( TFGameRules() ) + { + TFGameRules()->SetGravityMultiplier( 0.25f ); + } +} + +void CWheelOfDoom::WOD_LowGravityEffect::DeactivateEffect( EffectData_t& /*data*/ ) +{ + if ( TFGameRules() ) + { + TFGameRules()->SetGravityMultiplier( 1.0f ); + } +} + + +void CWheelOfDoom::WOD_Pee::ActivateEffect( EffectData_t& data ) +{ + m_vecClouds.Purge(); + + // Collect all of the "spawn_cloud" entities + CBaseEntity *pOther = gEntList.FindEntityByName( NULL, "spawn_cloud" ); + while( pOther ) + { + m_vecClouds.AddToTail( pOther ); + pOther = gEntList.FindEntityByName( pOther, "spawn_cloud" ); + } + + m_flNextPeeTime = gpGlobals->curtime + 0.25f; +} + +void CWheelOfDoom::WOD_Pee::UpdateEffect( EffectData_t& data ) +{ + if( gpGlobals->curtime < m_flNextPeeTime || m_vecClouds.Count() == 0 ) + return; + + m_flNextPeeTime = gpGlobals->curtime + RandomFloat(0.2f, 0.5f); + + // Choose one at random + int nRandIndex = RandomInt( 0, m_vecClouds.Count() - 1 ); + CBaseEntity* pCloud = m_vecClouds[nRandIndex]; + + // Get a random point within the brush + Vector vWorldMins = pCloud->WorldAlignMins(); + Vector vWorldMaxs = pCloud->WorldAlignMaxs(); + Vector vBoxMin = pCloud->GetAbsOrigin() + vWorldMins; + Vector vBoxMax = pCloud->GetAbsOrigin() + vWorldMaxs; + Vector vRandomPos( RandomFloat( vBoxMin.x, vBoxMax.x ), + RandomFloat( vBoxMin.y, vBoxMax.y ), + RandomFloat( vBoxMin.z, vBoxMax.z ) ); + + // Drop some pee + CTFProjectile_Jar *pGrenade = static_cast<CTFProjectile_Jar*>( CBaseEntity::CreateNoSpawn( "tf_projectile_jar", vRandomPos, QAngle(0,0,0), NULL ) ); + DispatchSpawn( pGrenade ); + + // Random angular impulse + Vector angImpulse( RandomFloat( -300.f, 300.f ), + RandomFloat( -300.f, 300.f ), + RandomFloat( -300.f, 300.f ) ); + + // Add some spin + IPhysicsObject *pPhysicsObject = pGrenade->VPhysicsGetObject(); + if ( pPhysicsObject ) + { + pPhysicsObject->AddVelocity( &vec3_origin, &angImpulse ); + } +} + + +void CWheelOfDoom::WOD_Burn::InitEffect( float flDefaultDuration ) +{ + m_flExpireTime = gpGlobals->curtime + 10.f; +} + + +void CWheelOfDoom::WOD_Burn::ActivateEffect( EffectData_t& data ) +{ + FOR_EACH_VEC( data.m_vecPlayers, i ) + { + CTFPlayer* pPlayer = data.m_vecPlayers[i]; + pPlayer->m_Shared.SelfBurn( Min( data.m_pWheel->GetDuration(), 10.f ) ); + } +} + + +void CWheelOfDoom::WOD_Ghosts::ActivateEffect( EffectData_t& data ) +{ + if( TFGameRules() ) + { + TFGameRules()->BeginHaunting( 4, data.m_pWheel->GetDuration() / 2.f, data.m_pWheel->GetDuration() ); + } +} + +void CWheelOfDoom::WOD_Ghosts::DeactivateEffect( EffectData_t& data ) +{ + FOR_EACH_VEC( data.m_vecPlayers, i ) + { + CTFPlayer* pPlayer = data.m_vecPlayers[i]; + pPlayer->m_Shared.RemoveCond( TF_COND_BURNING ); + } +} + +void CWheelOfDoom::WOD_Dance::InitEffect( float /*flDefaultExpireTime*/ ) +{ + // Don't do the same order every time + m_iCurrentMerasmusCreateInfo = RandomInt( 0, 1 ); + + // Ignore the passed in expire time. We want to have the buff for 5 seconds with 2 taunt cycles + m_flExpireTime = gpGlobals->curtime + 8.f; + m_flNextDanceTime = gpGlobals->curtime + 1.5f; + + m_vecDancers.PurgeAndDeleteElements(); + + CUtlVector< CTFPlayer * > playerVector; + CollectPlayers( &playerVector, TEAM_ANY, true ); + + // We'll calculate the average position and place merasmus there + float aMerasmusY[2] = { FLT_MAX, -FLT_MAX }; + float flMerasmusX = 0.0f, flMerasmusZ = 0.0f; + int nNumPositions = 0; // Keep a separate count for the average, since there's a case pOther can be NULL below + + FOR_EACH_VEC( playerVector, i ) + { + CTFPlayer* pPlayer = playerVector[i]; + + // Get our params + const char* pzsTeam = pPlayer->GetTeamNumber() == TF_TEAM_RED ? "red" : "blue"; + int nInfoNumber = GetNumOFTeamDancing( pPlayer->GetTeamNumber() ); + + // Cook up the name of the entity we want + const char* pszTargetName = CFmtStr( "dance_teleport_%s%d", pzsTeam, nInfoNumber ); + // If we got it, then do the magic + CBaseEntity *pOther = gEntList.FindEntityByName( NULL, pszTargetName ); + if( pOther ) + { + Dancer_t* dancer = new Dancer_t(); + + dancer->m_vecPos = pOther->GetAbsOrigin(); + dancer->m_vecAngles = pOther->GetAbsAngles(); + dancer->m_hPlayer.Set( pPlayer ); + + // Average in the player's position + aMerasmusY[0] = MIN( aMerasmusY[0], dancer->m_vecPos.y ); + aMerasmusY[1] = MAX( aMerasmusY[1], dancer->m_vecPos.y ); + flMerasmusX += dancer->m_vecPos.x; + flMerasmusZ = dancer->m_vecPos.z; + ++nNumPositions; + + // Slam them, for the jam + SlamPosAndAngles( pPlayer, dancer->m_vecPos, dancer->m_vecAngles ); + + // Force the halloween taunt. This will force the player to stand still. + pPlayer->m_Shared.AddCond( TF_COND_HALLOWEEN_THRILLER ); + + // Remember we're effecting this player + m_vecDancers.AddToTail( dancer ); + } + } + + // Average out the Merasmus position + flMerasmusX /= nNumPositions; + + m_vecMerasmusDancerCreateInfos.AddToTail( MerasmusCreateInfo_t( Vector( flMerasmusX, aMerasmusY[0], flMerasmusZ ), QAngle( 0.0f, 90.0f, 0.0f ) ) ); + m_vecMerasmusDancerCreateInfos.AddToTail( MerasmusCreateInfo_t( Vector( flMerasmusX, aMerasmusY[1], flMerasmusZ ), QAngle( 0.0f,-90.0f, 0.0f ) ) ); +} + + +void CWheelOfDoom::WOD_Dance::UpdateEffect( EffectData_t& /*data*/ ) +{ + bool bShouldSlam = ( m_flNextDanceTime - gpGlobals->curtime ) < 0.2f; + + bool bShouldTaunt = false; + if( gpGlobals->curtime > m_flNextDanceTime ) + { + bShouldTaunt = true; + m_flNextDanceTime = gpGlobals->curtime + 3.5f; + } + + FOR_EACH_VEC_BACK( m_vecDancers, i ) + { + Dancer_t* dancer = m_vecDancers[i]; + CTFPlayer* pPlayer = dancer->m_hPlayer.Get(); + + // This players is no more (disconnected). Forget about them. + if( pPlayer == NULL ) + { + delete dancer; + m_vecDancers.Remove(i); + continue; + } + + if( bShouldTaunt ) + { + pPlayer->Taunt(); + + } + + if( bShouldSlam ) + { + // Slam them, for the jam + SlamPosAndAngles( pPlayer, dancer->m_vecPos, dancer->m_vecAngles ); + } + } + + // Party time. + if ( bShouldTaunt ) + { + if ( m_hMerasmusDancer ) + { + m_hMerasmusDancer->Vanish(); // Poof! + } + + // Create a new Merasmus + const MerasmusCreateInfo_t &info = m_vecMerasmusDancerCreateInfos[ m_iCurrentMerasmusCreateInfo % m_vecMerasmusDancerCreateInfos.Count() ]; + m_hMerasmusDancer = (CMerasmusDancer *)CBaseEntity::Create( "merasmus_dancer", info.m_vecPos, info.m_vecAngles ); + + if ( m_hMerasmusDancer ) + { + m_hMerasmusDancer->Dance(); + } + + // Move to the next location + m_iCurrentMerasmusCreateInfo = ( m_iCurrentMerasmusCreateInfo + 1 ) % m_vecMerasmusDancerCreateInfos.Count(); + } +} + +void CWheelOfDoom::WOD_Dance::DeactivateEffect( EffectData_t& data ) +{ + FOR_EACH_VEC( data.m_vecPlayers, i ) + { + CTFPlayer* pPlayer = data.m_vecPlayers[i]; + pPlayer->m_Shared.RemoveCond( TF_COND_HALLOWEEN_THRILLER ); + } + + m_vecDancers.Purge(); + + if ( m_hMerasmusDancer ) + { + m_hMerasmusDancer->BlastOff(); + m_vecMerasmusDancerCreateInfos.Purge(); + } +} + + +int CWheelOfDoom::WOD_Dance::GetNumOFTeamDancing( int nTeam ) const +{ + int nCount = 0; + FOR_EACH_VEC( m_vecDancers, i ) + { + if( m_vecDancers[i]->m_hPlayer.Get()->GetTeamNumber() == nTeam ) + nCount++; + } + + return nCount; +} + +void CWheelOfDoom::WOD_Dance::SlamPosAndAngles( CTFPlayer* pPlayer, const Vector& vPos, const QAngle& vAng ) +{ + // This calls: SetAbsOrigin(), SetAbsVelocity( vec3_origin ), SetLocalAngles(), SnapEyeAngles() + pPlayer->Teleport( &vPos, &vAng, &vec3_origin ); + pPlayer->pl.v_angle = vAng; +}
\ No newline at end of file |