mirror of
https://github.com/celisej567/source-engine.git
synced 2026-01-04 18:09:53 +03:00
1
This commit is contained in:
366
game/server/tf2/tf_obj_powerpack.cpp
Normal file
366
game/server/tf2/tf_obj_powerpack.cpp
Normal file
@@ -0,0 +1,366 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Human's power pack
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "tf_player.h"
|
||||
#include "tf_team.h"
|
||||
#include "tf_obj.h"
|
||||
#include "tf_obj_powerpack.h"
|
||||
#include "tf_func_resource.h"
|
||||
#include "resource_chunk.h"
|
||||
#include "techtree.h"
|
||||
#include "sendproxy.h"
|
||||
#include "vstdlib/random.h"
|
||||
#include "tf_stats.h"
|
||||
#include "rope.h"
|
||||
#include "tf_shareddefs.h"
|
||||
#include "VGuiScreen.h"
|
||||
#include "hierarchy.h"
|
||||
|
||||
#define POWERPACK_MODEL "models/objects/human_obj_powerpack.mdl"
|
||||
#define POWERPACK_ASSEMBLING_MODEL "models/objects/human_obj_powerpack_build.mdl"
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST( CObjectPowerPack, DT_ObjectPowerPack )
|
||||
SendPropInt( SENDINFO(m_iObjectsAttached), 3, SPROP_UNSIGNED ),
|
||||
END_SEND_TABLE();
|
||||
|
||||
LINK_ENTITY_TO_CLASS(obj_powerpack, CObjectPowerPack);
|
||||
PRECACHE_REGISTER(obj_powerpack);
|
||||
|
||||
ConVar obj_powerpack_health( "obj_powerpack_health","100", FCVAR_NONE, "Human powerpack health" );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CObjectPowerPack::CObjectPowerPack()
|
||||
{
|
||||
UseClientSideAnimation();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CObjectPowerPack::Spawn( void )
|
||||
{
|
||||
SetModel( POWERPACK_MODEL );
|
||||
SetSolid( SOLID_BBOX );
|
||||
UTIL_SetSize(this, POWERPACK_MINS, POWERPACK_MAXS);
|
||||
|
||||
m_iHealth = obj_powerpack_health.GetInt();
|
||||
m_fObjectFlags |= OF_DOESNT_NEED_POWER;
|
||||
SetType( OBJ_POWERPACK );
|
||||
m_hPoweredObjects.Purge();
|
||||
m_iFreeAttachments = 0;
|
||||
m_iObjectsAttached = 0;
|
||||
|
||||
BaseClass::Spawn();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Gets info about the control panels
|
||||
//-----------------------------------------------------------------------------
|
||||
void CObjectPowerPack::GetControlPanelInfo( int nPanelIndex, const char *&pPanelName )
|
||||
{
|
||||
pPanelName = "screen_obj_power_pack";
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CObjectPowerPack::FinishedBuilding( void )
|
||||
{
|
||||
BaseClass::FinishedBuilding();
|
||||
|
||||
// Now tell all our objects we connected to, during placement, that they're really getting power
|
||||
// Walk backwards, because we might remove objects from our list that have somehow gained power
|
||||
// inbetween the time we placed and the time we finished building.
|
||||
int iSize = m_hPoweredObjects.Count();
|
||||
for (int i = iSize-1; i >= 0; i--)
|
||||
{
|
||||
if ( m_hPoweredObjects[i] )
|
||||
{
|
||||
if ( m_hPoweredObjects[i]->IsPowered() )
|
||||
{
|
||||
UnPowerObject( m_hPoweredObjects[i] );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_hPoweredObjects[i]->SetPowerPack( this );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PowerNearbyObjects();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CObjectPowerPack::Precache()
|
||||
{
|
||||
BaseClass::Precache();
|
||||
PrecacheModel( POWERPACK_MODEL );
|
||||
PrecacheModel( POWERPACK_ASSEMBLING_MODEL );
|
||||
PrecacheVGuiScreen( "screen_obj_power_pack" );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CObjectPowerPack::DestroyObject( void )
|
||||
{
|
||||
// Remove power from all my objects (backwards because list will change)
|
||||
int iSize = m_hPoweredObjects.Count();
|
||||
for (int i = iSize-1; i >= 0; i--)
|
||||
{
|
||||
if ( m_hPoweredObjects[i] )
|
||||
{
|
||||
UnPowerObject( m_hPoweredObjects[i] );
|
||||
}
|
||||
}
|
||||
|
||||
// Now tell all other powerpacks on this team to power nearby objects, in case they can cover for this one.
|
||||
if ( GetTFTeam() )
|
||||
{
|
||||
GetTFTeam()->UpdatePowerpacks( this, NULL );
|
||||
}
|
||||
|
||||
BaseClass::DestroyObject();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Update power connections on the fly while placing
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CObjectPowerPack::CalculatePlacement( CBaseTFPlayer *pPlayer )
|
||||
{
|
||||
bool bReturn = BaseClass::CalculatePlacement( pPlayer );
|
||||
|
||||
// First, disconnect any connections that should break
|
||||
int iSize = m_hPoweredObjects.Count();
|
||||
for (int i = iSize-1; i >= 0; i--)
|
||||
{
|
||||
if ( m_hPoweredObjects[i] )
|
||||
{
|
||||
EnsureObjectPower( m_hPoweredObjects[i] );
|
||||
}
|
||||
}
|
||||
|
||||
// If we have any spare connections, look for nearby objects to power
|
||||
if ( m_hPoweredObjects.Count() < MAX_OBJECTS_PER_PACK )
|
||||
{
|
||||
PowerNearbyObjects( NULL, true );
|
||||
}
|
||||
|
||||
return bReturn;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Find nearby objects and provide them with power
|
||||
//-----------------------------------------------------------------------------
|
||||
void CObjectPowerPack::PowerNearbyObjects( CBaseObject *pObjectToTarget, bool bPlacing )
|
||||
{
|
||||
if ( !GetTFTeam() )
|
||||
return;
|
||||
// Am I ready to power anything?
|
||||
if ( IsBuilding() || (!bPlacing && IsPlacing()) )
|
||||
return;
|
||||
|
||||
// Am I already full?
|
||||
if ( m_hPoweredObjects.Count() >= MAX_OBJECTS_PER_PACK )
|
||||
return;
|
||||
|
||||
// Do we have a specific target?
|
||||
if ( pObjectToTarget )
|
||||
{
|
||||
if ( !pObjectToTarget->CanPowerupNow(POWERUP_POWER) )
|
||||
return;
|
||||
|
||||
if ( IsWithinPowerRange( pObjectToTarget ) )
|
||||
{
|
||||
PowerObject( pObjectToTarget );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find nearby objects
|
||||
for ( int i = 0; i < GetTFTeam()->GetNumObjects(); i++ )
|
||||
{
|
||||
CBaseObject *pObject = GetTFTeam()->GetObject(i);
|
||||
assert(pObject);
|
||||
if ( pObject == this || !pObject->CanPowerupNow(POWERUP_POWER) )
|
||||
continue;
|
||||
// We might be rechecking our power because one of our own objects is dying.
|
||||
// Make sure we don't re-attach the sucker.
|
||||
if ( pObject->IsDying() )
|
||||
continue;
|
||||
|
||||
// Make sure it's within range
|
||||
if ( IsWithinPowerRange( pObject ) )
|
||||
{
|
||||
PowerObject( pObject, bPlacing );
|
||||
}
|
||||
|
||||
// Am I now full?
|
||||
if ( m_hPoweredObjects.Count() >= MAX_OBJECTS_PER_PACK )
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Provide power to the specified object
|
||||
//-----------------------------------------------------------------------------
|
||||
void CObjectPowerPack::PowerObject( CBaseObject *pObject, bool bPlacing )
|
||||
{
|
||||
// Make sure we're not already powering it
|
||||
ObjectHandle hObject;
|
||||
hObject = pObject;
|
||||
if ( m_hPoweredObjects.Find( hObject ) != m_hPoweredObjects.InvalidIndex() )
|
||||
return;
|
||||
|
||||
// Add it to our list
|
||||
m_hPoweredObjects.AddToTail( hObject );
|
||||
m_iObjectsAttached = m_hPoweredObjects.Count();
|
||||
|
||||
// Find a free attachment point
|
||||
int iPoint = 1;
|
||||
for ( int i = 0; i < MAX_OBJECTS_PER_PACK; i++ )
|
||||
{
|
||||
if ( !(m_iFreeAttachments & (1<<i)) )
|
||||
{
|
||||
m_iFreeAttachments |= (1<<i);
|
||||
iPoint = i+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Lookup the attachment point...
|
||||
int nAttachmentIndex = pObject->LookupAttachment("powerpoint");
|
||||
if (nAttachmentIndex < 0)
|
||||
nAttachmentIndex = 1;
|
||||
|
||||
// FIXME: Cache these off
|
||||
char sAttachment[32];
|
||||
Q_snprintf( sAttachment,sizeof(sAttachment), "cablepoint%d", iPoint );
|
||||
int nLocalAttachment = LookupAttachment( sAttachment );
|
||||
if ( nLocalAttachment > 0 )
|
||||
{
|
||||
// Throw a cable to it
|
||||
CRopeKeyframe *pRope = ConnectCableTo( pObject, nLocalAttachment, nAttachmentIndex );
|
||||
if ( pRope )
|
||||
{
|
||||
pRope->SetMaterial( "cable/human_powercable.vmt" );
|
||||
}
|
||||
}
|
||||
|
||||
// If we're placing only, don't tell it we're supplying power yet
|
||||
if ( IsPlacing() )
|
||||
return;
|
||||
|
||||
pObject->SetPowerPack( this );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Remove power to the specified object
|
||||
//-----------------------------------------------------------------------------
|
||||
void CObjectPowerPack::UnPowerObject( CBaseObject *pObject )
|
||||
{
|
||||
// Make sure it's in our list
|
||||
ObjectHandle hObject;
|
||||
hObject = pObject;
|
||||
if ( m_hPoweredObjects.Find( hObject ) == m_hPoweredObjects.InvalidIndex() )
|
||||
return;
|
||||
|
||||
// Remove it from our list
|
||||
m_hPoweredObjects.FindAndRemove( hObject );
|
||||
m_iObjectsAttached = m_hPoweredObjects.Count();
|
||||
|
||||
// Remove our cable to it
|
||||
for ( int i = 0; i < m_aRopes.Count(); i++ )
|
||||
{
|
||||
if ( (m_aRopes[i] != NULL) && (m_aRopes[i]->GetEndPoint() == pObject) )
|
||||
{
|
||||
// Free up the attachment point
|
||||
m_iFreeAttachments &= ~(1 << (m_aRopes[i]->GetEndAttachment()-1));
|
||||
UTIL_Remove( m_aRopes[i] );
|
||||
m_aRopes.Remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Tell the object that it has lost power
|
||||
if ( pObject->GetPowerPack() == this )
|
||||
{
|
||||
pObject->SetPowerPack( NULL );
|
||||
}
|
||||
|
||||
// If I'm not dying, immediately look for other things to power
|
||||
if ( !IsDying() )
|
||||
{
|
||||
PowerNearbyObjects();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Make sure the specified object is still within powering range
|
||||
//-----------------------------------------------------------------------------
|
||||
void CObjectPowerPack::EnsureObjectPower( CBaseObject *pObject )
|
||||
{
|
||||
if ( IsWithinPowerRange( pObject ) )
|
||||
return;
|
||||
|
||||
// It's obscured, or out of range. Remove it.
|
||||
UnPowerObject( pObject );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return true if this object is powerable
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CObjectPowerPack::IsWithinPowerRange( CBaseObject *pObject )
|
||||
{
|
||||
// If this powerpack is built on an attachment, it'll only power objects in the same hierarchy
|
||||
if ( GetParentObject() )
|
||||
{
|
||||
if ( GetRootMoveParent() != pObject->GetRootMoveParent() )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( (pObject->GetAbsOrigin() - GetAbsOrigin()).LengthSqr() < POWERPACK_RANGE )
|
||||
{
|
||||
// Can I see it?
|
||||
// Ignore things we're attached to
|
||||
trace_t tr;
|
||||
CTraceFilterWorldAndPropsOnly powerFilter;
|
||||
UTIL_TraceLine( WorldSpaceCenter(), pObject->WorldSpaceCenter(), MASK_SOLID_BRUSHONLY, &powerFilter, &tr );
|
||||
CBaseEntity *pEntity = tr.m_pEnt;
|
||||
if ( (tr.fraction == 1.0) || ( pEntity == pObject ) )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : act -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CObjectPowerPack::OnActivityChanged( Activity act )
|
||||
{
|
||||
BaseClass::OnActivityChanged( act );
|
||||
|
||||
switch ( act )
|
||||
{
|
||||
case ACT_OBJ_ASSEMBLING:
|
||||
SetModel( POWERPACK_ASSEMBLING_MODEL );
|
||||
break;
|
||||
default:
|
||||
SetModel( POWERPACK_MODEL );
|
||||
break;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user