diff options
Diffstat (limited to 'game/client/tf/c_tf_halloween.cpp')
| -rw-r--r-- | game/client/tf/c_tf_halloween.cpp | 416 |
1 files changed, 416 insertions, 0 deletions
diff --git a/game/client/tf/c_tf_halloween.cpp b/game/client/tf/c_tf_halloween.cpp new file mode 100644 index 0000000..42884d6 --- /dev/null +++ b/game/client/tf/c_tf_halloween.cpp @@ -0,0 +1,416 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= +#include "cbase.h" + +#include "c_tf_player.h" +#include "collisionutils.h" +#include "econ_item_inventory.h" +#include "iclientmode.h" +#include "tf_gcmessages.h" +#include "tf_gamerules.h" +#include "econ_notifications.h" +#include "rtime.h" +#include "achievementmgr.h" +#include "baseachievement.h" +#include "achievements_tf.h" +#include "gc_clientsystem.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +EHalloweenMap GetHalloweenMap() +{ + if ( FStrEq( engine->GetLevelName(), "maps/cp_manor_event.bsp" ) ) + return kHalloweenMap_MannManor; + + if ( FStrEq( engine->GetLevelName(), "maps/koth_viaduct_event.bsp" ) ) + return kHalloweenMap_Viaduct; + + if ( FStrEq( engine->GetLevelName(), "maps/koth_lakeside_event.bsp" ) ) + return kHalloweenMap_Lakeside; + + if ( FStrEq( engine->GetLevelName(), "maps/plr_hightower_event.bsp" ) ) + return kHalloweenMap_Hightower; + + return kHalloweenMapCount; +} + + +//----------------------------------------------------------------------------- +// Created when the GC decides to give out an item. +// A player must intersect the item to claim it. +//----------------------------------------------------------------------------- +#define HALLOWEEN_ITEM_TIME_TO_READY 10.0f +class C_HalloweenItemPickup : public CBaseAnimating +{ + DECLARE_CLASS( C_HalloweenItemPickup, CBaseAnimating ); +public: + C_HalloweenItemPickup() + : m_bReadyForPickup( false ) + , m_bClaimed( false ) + , m_flTimeToReady( 0.0f ) + { + AddEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID ); + } + + virtual ~C_HalloweenItemPickup() + { + } + + bool Initialize() + { + const char *pszModelName = "models/props_halloween/halloween_gift.mdl"; + SetModelName( AllocPooledString( pszModelName ) ); + + if ( InitializeAsClientEntity( STRING(GetModelName()), RENDER_GROUP_OPAQUE_ENTITY ) == false ) + return false; + + const model_t *mod = GetModel(); + if ( mod ) + { + Vector mins, maxs; + modelinfo->GetModelBounds( mod, mins, maxs ); + SetCollisionBounds( mins, maxs ); + } + + Spawn(); + + // initialize as translucent + float alpha = 0.0f; + SetRenderMode( kRenderTransTexture ); + SetRenderColorA( alpha * 256 ); + m_flTimeToReady = gpGlobals->realtime + HALLOWEEN_ITEM_TIME_TO_READY; + + UpdatePartitionListEntry(); + + SetBlocksLOS( false ); // this should be a small object + + // Set up shadows; do it here so that objects can change shadowcasting state + CreateShadow(); + + UpdateVisibility(); + + SetNextClientThink( CLIENT_THINK_ALWAYS ); + + return true; + } + + virtual void Spawn() + { + Precache(); + BaseClass::Spawn(); + SetSolid( SOLID_NONE ); + AddSolidFlags( FSOLID_NOT_SOLID ); + SetMoveType( MOVETYPE_NONE ); + } + + virtual void ClientThink() + { + if ( m_bReadyForPickup ) + { + ClientThink_Active(); + return; + } + + float flTimeDelta = m_flTimeToReady - gpGlobals->realtime; + if ( flTimeDelta < 0 ) + { + m_bReadyForPickup = true; + ParticleProp()->Create( "halloween_pickup_active", PATTACH_ABSORIGIN_FOLLOW ); + SetRenderMode( kRenderNormal ); + } + else + { + float alpha = 0.75f * ( ( HALLOWEEN_ITEM_TIME_TO_READY - flTimeDelta ) / HALLOWEEN_ITEM_TIME_TO_READY ); + SetRenderColorA( alpha * 256 ); + } + } + + void ClientThink_Active( void ) + { + Vector vWorldMins = WorldAlignMins(); + Vector vWorldMaxs = WorldAlignMaxs(); + Vector vBoxMin1 = GetAbsOrigin() + vWorldMins; + Vector vBoxMax1 = GetAbsOrigin() + vWorldMaxs; + + float flBestDistance2 = 0.0f; + CSteamID bestSteamID; + bool bBestHasNoclip = false; + +#define CLIENT_HALLOWEEN_LOGIC_ENABLE_LOCAL_PLAYER_ONLY 1 + +#if !CLIENT_HALLOWEEN_LOGIC_ENABLE_LOCAL_PLAYER_ONLY + for( int iPlayerIndex = 1 ; iPlayerIndex <= MAX_PLAYERS; iPlayerIndex++ ) + { + C_TFPlayer *pPlayer = ToTFPlayer( UTIL_PlayerByIndex( iPlayerIndex ) ); +#else + do + { + C_TFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer(); +#endif + CSteamID steamID; + if ( pPlayer == NULL || pPlayer->IsBot() == true || pPlayer->GetSteamID( &steamID ) == false || + ( pPlayer->GetTeamNumber() != TF_TEAM_RED && pPlayer->GetTeamNumber() != TF_TEAM_BLUE ) || + pPlayer->IsAlive() == false || + pPlayer->GetObserverMode() != OBS_MODE_NONE ) + { + continue; + } + + Vector vPlayerMins = pPlayer->GetAbsOrigin() + pPlayer->WorldAlignMins(); + Vector vPlayerMaxs = pPlayer->GetAbsOrigin() + pPlayer->WorldAlignMaxs(); + bool bIntersecting = IsBoxIntersectingBox( vBoxMin1, vBoxMax1, vPlayerMins, vPlayerMaxs ); + float flDistance2 = ( pPlayer->GetAbsOrigin(), GetAbsOrigin() ).LengthSqr(); + if ( bIntersecting && ( bestSteamID.GetAccountID() == 0 || flDistance2 < flBestDistance2 ) ) + { + bestSteamID = steamID; + bBestHasNoclip = pPlayer->GetMoveType() == MOVETYPE_NOCLIP; + flBestDistance2 = flDistance2; + } + } +#if CLIENT_HALLOWEEN_LOGIC_ENABLE_LOCAL_PLAYER_ONLY + while ( false ); +#endif + + if ( bestSteamID.GetAccountID() != 0 ) + { + GCSDK::CProtoBufMsg<CMsgGC_Halloween_GrantItem> msg( k_EMsgGC_Halloween_GrantItem ); + msg.Body().set_recipient_account_id( bestSteamID.GetAccountID() ); + msg.Body().set_level_id( GetHalloweenMap() ); + msg.Body().set_flagged( bBestHasNoclip ); + GCClientSystem()->BSendMessage( msg ); + OnClaimed( true ); + return; + } + + SetNextClientThink( gpGlobals->curtime + 0.33f ); + } + + void OnClaimed( bool bPlayAudio ) + { + if ( m_bClaimed ) + return; + + m_bClaimed = true; + // stop thinking and remove sparkle... + ParticleProp()->StopParticlesNamed( "halloween_pickup_active", true ); + SetNextClientThink( CLIENT_THINK_NEVER ); + // throw up bday confetti + DispatchParticleEffect( "halloween_gift_pickup", GetAbsOrigin(), vec3_angle ); + + if ( bPlayAudio ) + { + C_BaseEntity::EmitSound( "Game.HappyBirthday" ); + } + SetRenderMode( kRenderNone ); + UpdateVisibility(); + } + + bool m_bReadyForPickup; + bool m_bClaimed; + float m_flTimeToReady; +}; + +LINK_ENTITY_TO_CLASS( tf_halloween_item_pickup, C_HalloweenItemPickup ); +PRECACHE_REGISTER( tf_halloween_item_pickup ); + +static EHANDLE gHalloweenPickup; + +#ifdef _DEBUG +CON_COMMAND( cl_halloween_test_cheating, "Test cheating the halloween pickup" ) +{ + GCSDK::CProtoBufMsg< CMsgGC_Halloween_GrantItem > msg( k_EMsgGC_Halloween_GrantItem ); + msg.Body().set_recipient_account_id( steamapicontext->SteamUser()->GetSteamID().GetAccountID() ); + GCClientSystem()->BSendMessage( msg ); +} + +CON_COMMAND( cl_halloween_test_spawn_pickup, "Test spawning the pickup item" ) +{ + C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); + if ( pLocalPlayer == NULL ) + return; + + // Now create the pickup item + C_HalloweenItemPickup *pEntity = new C_HalloweenItemPickup(); + if ( !pEntity ) + return; + + Vector vecTargetPoint; + trace_t tr; + Vector forward; + pLocalPlayer->EyeVectors( &forward ); + UTIL_TraceLine( pLocalPlayer->EyePosition(), + pLocalPlayer->EyePosition() + forward * MAX_TRACE_LENGTH,MASK_NPCSOLID, + pLocalPlayer, COLLISION_GROUP_NONE, &tr ); + + if ( tr.fraction != 1.0 ) + { + vecTargetPoint = tr.endpos; + } + + pEntity->SetAbsOrigin( vecTargetPoint ); + if ( !pEntity->Initialize() ) + { + pEntity->Release(); + } + else + { + if ( gHalloweenPickup.Get() ) + gHalloweenPickup->Release(); + gHalloweenPickup = pEntity; + } +} +#endif + +//----------------------------------------------------------------------------- +// GC has decided to drop a Halloween item +//----------------------------------------------------------------------------- +//class CGCHalloween_ReservedItem : public GCSDK::CGCClientJob +//{ +//public: +// CGCHalloween_ReservedItem( GCSDK::CGCClient *pClient ) : GCSDK::CGCClientJob( pClient ) {} +// +// virtual bool BYieldingRunGCJob( GCSDK::IMsgNetPacket *pNetPacket ) +// { +// GCSDK::CProtoBufMsg<CMsgGC_Halloween_ReservedItem> msg( pNetPacket ); +// +// // Figure out which level we're on so we know how to handle notifications, etc. +// EHalloweenMap eMap = GetHalloweenMap(); +// if ( eMap == kHalloweenMapCount ) +// return true; +// +// // Sanity-check the message contents from the GC. +// if ( msg.Body().x_size() != msg.Body().y_size() || msg.Body().y_size() != msg.Body().z_size() ) +// return true; +// +// if ( msg.Body().x_size() <= eMap ) +// return true; +// +// // Don't spawn gifts during startup. +// if ( TFGameRules() == NULL +// || TFGameRules()->State_Get() != GR_STATE_RND_RUNNING +// || TFGameRules()->InSetup() +// || TFGameRules()->IsInWaitingForPlayers() +// || TFGameRules()->ArePlayersInHell() ) // Dont spawn gifts if players are in 2013 Hell +// return true; +// +// C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); +// if ( pLocalPlayer == NULL ) +// return true; +// +// // If we don't already know about this gift pickup, create one. +// if ( gHalloweenPickup.Get() == NULL ) +// { +// // Now create the pickup item +// C_HalloweenItemPickup *pEntity = new C_HalloweenItemPickup(); +// if ( !pEntity ) +// return true; +// +// Vector position( msg.Body().x( eMap ), msg.Body().y( eMap ), msg.Body().z( eMap ) ); +// pEntity->SetAbsOrigin( position ); +// if ( !pEntity->Initialize() ) +// { +// pEntity->Release(); +// } +// else +// { +// gHalloweenPickup = pEntity; +// } +// } +// +// // Regardless of whether we created a new gift or whether this was a new notification about an old gift, +// // display a UI notification for the user. +// CEconNotification *pNotification = new CEconNotification(); +// pNotification->SetText( "#TF_HalloweenItem_Reserved" ); +// pNotification->SetLifetime( 15.0f ); +// pNotification->SetSoundFilename( "ui/halloween_loot_spawn.wav" ); +// NotificationQueue_Add( pNotification ); +// +// return true; +// } +//}; +//GC_REG_JOB( GCSDK::CGCClient, CGCHalloween_ReservedItem, "CGCHalloween_ReservedItem", k_EMsgGC_Halloween_ReservedItem, GCSDK::k_EServerTypeGCClient ); + +//----------------------------------------------------------------------------- +// GC gave out the Halloween item to a player +//----------------------------------------------------------------------------- +//class CGCHalloween_GrantedItemResponse : public GCSDK::CGCClientJob +//{ +//public: +// CGCHalloween_GrantedItemResponse( GCSDK::CGCClient *pClient ) : GCSDK::CGCClientJob( pClient ) {} +// +// virtual bool BYieldingRunGCJob( GCSDK::IMsgNetPacket *pNetPacket ) +// { +// GCSDK::CProtoBufMsg<CMsgGC_Halloween_GrantItemResponse> msg( pNetPacket ); +// +// // which Steam universe are we in? +// EUniverse eUniverse = steamapicontext && steamapicontext->SteamUtils() +// ? steamapicontext->SteamUtils()->GetConnectedUniverse() +// : k_EUniverseInvalid; +// +// CSteamID steamIDRecipient( msg.Body().recipient_account_id(), eUniverse, k_EAccountTypeIndividual ); +// bool bIsValidRecipient = steamIDRecipient.IsValid(); +// +// if ( gHalloweenPickup.Get() != NULL ) +// { +// assert_cast<C_HalloweenItemPickup *>( gHalloweenPickup.Get() )->OnClaimed( bIsValidRecipient ); +// gHalloweenPickup->Release(); +// gHalloweenPickup = NULL; +// } +// +// // don't do any work if we're not on a Halloween map +// EHalloweenMap eMap = GetHalloweenMap(); +// if ( eMap == kHalloweenMapCount ) +// return true; +// +// // add alert +// const char* pPlayerName = InventoryManager()->PersonaName_Get( steamIDRecipient.GetAccountID() ); +// wchar_t wszPlayerName[MAX_PLAYER_NAME_LENGTH] = L""; +// if ( pPlayerName != NULL && FStrEq( pPlayerName, "" ) == false ) +// { +// g_pVGuiLocalize->ConvertANSIToUnicode( pPlayerName, wszPlayerName, sizeof(wszPlayerName) ); +// } +// CEconNotification *pNotification = new CEconNotification(); +// pNotification->SetLifetime( 15.0f ); +// +// if ( bIsValidRecipient ) +// { +// pNotification->SetText( "#TF_HalloweenItem_Granted" ); +// pNotification->AddStringToken( "recipient", wszPlayerName ); +// pNotification->SetSteamID( steamIDRecipient ); +// pNotification->SetSoundFilename( "ui/halloween_loot_found.wav" ); +// } +// else +// { +// pNotification->SetText( "#TF_HalloweenItem_GrantPickupFail" ); +// // pNotification->SetSoundFilename( "coach/coach_student_died.wav" ); +// } +// +// NotificationQueue_Add( pNotification ); +// +// // is this the local player? award the achievement... +// if ( steamapicontext && steamapicontext->SteamUser() ) +// { +// CSteamID localSteamID = steamapicontext->SteamUser()->GetSteamID(); +// if ( steamIDRecipient == localSteamID ) +// { +// g_AchievementMgrTF.OnAchievementEvent( ACHIEVEMENT_TF_HALLOWEEN_COLLECT_GOODY_BAG ); +// } +// } +// +// return true; +// } +//}; +//GC_REG_JOB( GCSDK::CGCClient, CGCHalloween_GrantedItemResponse, "CGCHalloween_GrantedItemResponse", k_EMsgGC_Halloween_GrantItemResponse, GCSDK::k_EServerTypeGCClient ); + + +//----------------------------------------------------------------------------- + +void CL_Halloween_LevelShutdown() +{ + gHalloweenPickup = NULL; +} |