Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

416 lines
13 KiB

//========= 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;
}