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.
460 lines
14 KiB
460 lines
14 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: Client's CWeaponBuilder class |
|
// |
|
// $Workfile: $ |
|
// $Date: $ |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
#include "cbase.h" |
|
#include "hud.h" |
|
#include "in_buttons.h" |
|
#include "clientmode_tf.h" |
|
#include "engine/IEngineSound.h" |
|
#include "c_tf_weapon_builder.h" |
|
#include "c_weapon__stubs.h" |
|
#include "iinput.h" |
|
#include <vgui/IVGui.h> |
|
#include "c_tf_player.h" |
|
#include "c_vguiscreen.h" |
|
#include "ienginevgui.h" |
|
|
|
STUB_WEAPON_CLASS_IMPLEMENT( tf_weapon_builder, C_TFWeaponBuilder ); |
|
PRECACHE_WEAPON_REGISTER( tf_weapon_builder ); |
|
|
|
// SUPER HACK TO FIX DEMOS. For a couple days, we accidently renamed |
|
// CTFWeaponBuilder to C_TFWeaponBuilder on the server. This was fine for |
|
// playing the game but broke all previously recorded demos. Fixing this and |
|
// re-renaming the class back to the original name fixed all demos recorded |
|
// with the brokenly-renamed class. To handle these demos that think the class |
|
// is called C_TFWeaponBuilder on the server, we're creating a new class that derives from |
|
// the real C_TFWeaponBuilder and does nothing special except that it calls |
|
// IMPLEMENT_CLIENTCLASS and maps itself to serverclass "C_TFWeaponBuilder" |
|
// (which, if you've followed along, doesn't exist anymore). |
|
// |
|
// As a history lesson, this broke from the change in tf_player_shared.h in cl 1722245 |
|
class C_TFWeaponBuilderReplayHack : public C_TFWeaponBuilder |
|
{ |
|
DECLARE_CLASS( C_TFWeaponBuilderReplayHack, C_TFWeaponBuilder ); |
|
public: |
|
DECLARE_CLIENTCLASS(); |
|
DECLARE_PREDICTABLE(); |
|
}; |
|
IMPLEMENT_CLIENTCLASS( C_TFWeaponBuilderReplayHack, DT_TFWeaponBuilder, C_TFWeaponBuilder ) |
|
BEGIN_PREDICTION_DATA( C_TFWeaponBuilderReplayHack ) |
|
END_PREDICTION_DATA() |
|
|
|
|
|
IMPLEMENT_NETWORKCLASS_ALIASED( TFWeaponBuilder, DT_TFWeaponBuilder ) |
|
|
|
// Recalc object sprite when we receive a new object type to build |
|
void RecvProxy_ObjectType( const CRecvProxyData *pData, void *pStruct, void *pOut ) |
|
{ |
|
// Pass to normal Int recvproxy |
|
RecvProxy_Int32ToInt32( pData, pStruct, pOut ); |
|
|
|
// Reset the object sprite |
|
C_TFWeaponBuilder *pBuilder = ( C_TFWeaponBuilder * )pStruct; |
|
pBuilder->SetupObjectSelectionSprite(); |
|
} |
|
|
|
BEGIN_NETWORK_TABLE_NOBASE( C_TFWeaponBuilder, DT_BuilderLocalData ) |
|
RecvPropInt( RECVINFO(m_iObjectType), 0, RecvProxy_ObjectType ), |
|
RecvPropEHandle( RECVINFO(m_hObjectBeingBuilt) ), |
|
RecvPropArray3( RECVINFO_ARRAY( m_aBuildableObjectTypes ), RecvPropBool( RECVINFO( m_aBuildableObjectTypes[0] ) ) ), |
|
END_NETWORK_TABLE() |
|
|
|
BEGIN_NETWORK_TABLE( C_TFWeaponBuilder, DT_TFWeaponBuilder ) |
|
RecvPropInt( RECVINFO(m_iBuildState) ), |
|
RecvPropDataTable( "BuilderLocalData", 0, 0, &REFERENCE_RECV_TABLE( DT_BuilderLocalData ) ), |
|
RecvPropInt( RECVINFO(m_iObjectMode) ), |
|
RecvPropFloat( RECVINFO( m_flWheatleyTalkingUntil) ), |
|
END_RECV_TABLE() |
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
IMPLEMENT_NETWORKCLASS_ALIASED( TFWeaponSapper, DT_TFWeaponSapper ) |
|
BEGIN_NETWORK_TABLE( C_TFWeaponSapper, DT_TFWeaponSapper ) |
|
RecvPropFloat( RECVINFO( m_flChargeBeginTime ) ), |
|
END_NETWORK_TABLE() |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
C_TFWeaponBuilder::C_TFWeaponBuilder() |
|
{ |
|
m_iBuildState = 0; |
|
m_iObjectType = BUILDER_INVALID_OBJECT; |
|
m_pSelectionTextureActive = NULL; |
|
m_pSelectionTextureInactive = NULL; |
|
m_iValidBuildPoseParam = -1; |
|
m_flWheatleyTalkingUntil = 0; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
C_TFWeaponBuilder::~C_TFWeaponBuilder() |
|
{ |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Output : char const |
|
//----------------------------------------------------------------------------- |
|
const char *C_TFWeaponBuilder::GetCurrentSelectionObjectName( void ) |
|
{ |
|
if ( m_iObjectType == -1 || (m_iBuildState == BS_SELECTING) ) |
|
return ""; |
|
|
|
return GetObjectInfo( m_iObjectType )->m_pBuilderWeaponName; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool C_TFWeaponBuilder::Deploy( void ) |
|
{ |
|
bool bDeploy = BaseClass::Deploy(); |
|
|
|
if ( bDeploy ) |
|
{ |
|
m_flNextPrimaryAttack = gpGlobals->curtime + 0.35f; |
|
m_flNextSecondaryAttack = gpGlobals->curtime; // asap |
|
|
|
CTFPlayer *pPlayer = ToTFPlayer( GetOwner() ); |
|
if (!pPlayer) |
|
return false; |
|
|
|
pPlayer->SetNextAttack( gpGlobals->curtime ); |
|
|
|
m_iWorldModelIndex = modelinfo->GetModelIndex( GetWorldModel() ); |
|
} |
|
|
|
return bDeploy; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void C_TFWeaponBuilder::SecondaryAttack( void ) |
|
{ |
|
if ( m_bInAttack2 ) |
|
return; |
|
|
|
// require a re-press |
|
m_bInAttack2 = true; |
|
|
|
CTFPlayer *pOwner = ToTFPlayer( GetOwner() ); |
|
if ( !pOwner ) |
|
return; |
|
|
|
pOwner->DoClassSpecialSkill(); |
|
|
|
m_flNextSecondaryAttack = gpGlobals->curtime + 0.2f; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: cache the build pos pose param |
|
//----------------------------------------------------------------------------- |
|
CStudioHdr *C_TFWeaponBuilder::OnNewModel( void ) |
|
{ |
|
CStudioHdr *hdr = BaseClass::OnNewModel(); |
|
|
|
m_iValidBuildPoseParam = LookupPoseParameter( "valid_build_pos" ); |
|
|
|
return hdr; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// ---------------------------------------------------------------------------- |
|
void C_TFWeaponBuilder::PostDataUpdate( DataUpdateType_t type ) |
|
{ |
|
if ( type == DATA_UPDATE_CREATED ) |
|
{ |
|
// m_iViewModelIndex is set by the base Precache(), which didn't know what |
|
// type of object we built, so it didn't get the right viewmodel index. |
|
// Now that our data is filled in, go and get the right index. |
|
const char *pszViewModel = GetViewModel(0); |
|
if ( pszViewModel && pszViewModel[0] ) |
|
{ |
|
m_iViewModelIndex = CBaseEntity::PrecacheModel( pszViewModel ); |
|
} |
|
} |
|
|
|
BaseClass::PostDataUpdate( type ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: only called for local player |
|
//----------------------------------------------------------------------------- |
|
void C_TFWeaponBuilder::Redraw() |
|
{ |
|
if ( m_iValidBuildPoseParam >= 0 ) |
|
{ |
|
CTFPlayer *pOwner = ToTFPlayer( GetOwner() ); |
|
if ( !pOwner ) |
|
return; |
|
|
|
// Assuming here that our model is the same as our viewmodel's model! |
|
CBaseViewModel *pViewModel = pOwner->GetViewModel(0); |
|
|
|
if ( pViewModel ) |
|
{ |
|
float flPoseParamValue = pViewModel->GetPoseParameter( m_iValidBuildPoseParam ); |
|
|
|
C_BaseObject *pObj = m_hObjectBeingBuilt.Get(); |
|
|
|
if ( pObj && pObj->WasLastPlacementPosValid() ) |
|
{ |
|
// pose param approach 1.0 |
|
flPoseParamValue = Approach( 1.0, flPoseParamValue, 3.0 * gpGlobals->frametime ); |
|
} |
|
else |
|
{ |
|
// pose param approach 0.0 |
|
flPoseParamValue = Approach( 0.0, flPoseParamValue, 1.5 * gpGlobals->frametime ); |
|
} |
|
|
|
pViewModel->SetPoseParameter( m_iValidBuildPoseParam, flPoseParamValue ); |
|
} |
|
} |
|
|
|
BaseClass::Redraw(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Output : Returns true on success, false on failure. |
|
//----------------------------------------------------------------------------- |
|
bool C_TFWeaponBuilder::IsPlacingObject( void ) |
|
{ |
|
if ( m_iBuildState == BS_PLACING || m_iBuildState == BS_PLACING_INVALID ) |
|
return true; |
|
|
|
return false; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int C_TFWeaponBuilder::GetSlot( void ) const |
|
{ |
|
return GetObjectInfo( m_iObjectType )->m_SelectionSlot; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int C_TFWeaponBuilder::GetPosition( void ) const |
|
{ |
|
return GetObjectInfo( m_iObjectType )->m_SelectionPosition; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void C_TFWeaponBuilder::SetupObjectSelectionSprite( void ) |
|
{ |
|
#ifdef CLIENT_DLL |
|
// Use the sprite details from the text file, with a custom sprite |
|
char *iconTexture = GetObjectInfo( m_iObjectType )->m_pIconActive; |
|
if ( iconTexture && iconTexture[ 0 ] ) |
|
{ |
|
m_pSelectionTextureActive = gHUD.GetIcon( iconTexture ); |
|
} |
|
else |
|
{ |
|
m_pSelectionTextureActive = NULL; |
|
} |
|
|
|
iconTexture = GetObjectInfo( m_iObjectType )->m_pIconInactive; |
|
if ( iconTexture && iconTexture[ 0 ] ) |
|
{ |
|
m_pSelectionTextureInactive = gHUD.GetIcon( iconTexture ); |
|
} |
|
else |
|
{ |
|
m_pSelectionTextureInactive = NULL; |
|
} |
|
#endif |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CHudTexture const *C_TFWeaponBuilder::GetSpriteActive( void ) const |
|
{ |
|
return m_pSelectionTextureActive; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CHudTexture const *C_TFWeaponBuilder::GetSpriteInactive( void ) const |
|
{ |
|
return m_pSelectionTextureInactive; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Output : char const |
|
//----------------------------------------------------------------------------- |
|
const char *C_TFWeaponBuilder::GetPrintName( void ) const |
|
{ |
|
return GetObjectInfo( m_iObjectType )->m_AltModes[m_iObjectMode].pszStatusName; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int C_TFWeaponBuilder::GetSubType( void ) |
|
{ |
|
return m_iObjectType; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Return true if this weapon can be selected via the weapon selection |
|
//----------------------------------------------------------------------------- |
|
bool C_TFWeaponBuilder::CanBeSelected( void ) |
|
{ |
|
CTFPlayer *pOwner = ToTFPlayer( GetOwner() ); |
|
if ( !pOwner ) |
|
return false; |
|
|
|
if ( pOwner->CanBuild( m_iObjectType, m_iObjectMode ) != CB_CAN_BUILD ) |
|
return false; |
|
|
|
return HasAmmo(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Return true if this weapon should be visible in the weapon selection |
|
//----------------------------------------------------------------------------- |
|
bool C_TFWeaponBuilder::VisibleInWeaponSelection( void ) |
|
{ |
|
if ( BaseClass::VisibleInWeaponSelection() == false ) |
|
return false; |
|
if ( m_iObjectType != BUILDER_INVALID_OBJECT ) |
|
return GetObjectInfo( m_iObjectType )->m_bVisibleInWeaponSelection; |
|
return false; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Return true if this weapon has some ammo |
|
//----------------------------------------------------------------------------- |
|
bool C_TFWeaponBuilder::HasAmmo( void ) |
|
{ |
|
CTFPlayer *pOwner = ToTFPlayer( GetOwner() ); |
|
if ( !pOwner ) |
|
return false; |
|
|
|
int iCost = pOwner->m_Shared.CalculateObjectCost( pOwner, m_iObjectType ); |
|
return ( pOwner->GetBuildResources() >= iCost ); |
|
} |
|
|
|
// ----------------------------------------------------------------------------- |
|
// Purpose: |
|
// ----------------------------------------------------------------------------- |
|
bool C_TFWeaponBuilder::CanBuildObjectType( int iObjectType ) |
|
{ |
|
if ( iObjectType < 0 || iObjectType >= OBJ_LAST ) |
|
return false; |
|
|
|
return m_aBuildableObjectTypes[iObjectType]; |
|
} |
|
|
|
// ----------------------------------------------------------------------------- |
|
// Purpose: |
|
// ----------------------------------------------------------------------------- |
|
void C_TFWeaponBuilder::UpdateAttachmentModels( void ) |
|
{ |
|
if ( m_iObjectType != BUILDER_INVALID_OBJECT && GetObjectInfo( m_iObjectType )->m_bUseItemInfo ) |
|
{ |
|
BaseClass::UpdateAttachmentModels(); |
|
} |
|
} |
|
|
|
// ----------------------------------------------------------------------------- |
|
// Purpose: |
|
// ----------------------------------------------------------------------------- |
|
const char *C_TFWeaponBuilder::GetViewModel( int iViewModel ) const |
|
{ |
|
if ( GetPlayerOwner() == NULL ) |
|
{ |
|
return BaseClass::GetViewModel(); |
|
} |
|
|
|
if ( m_iObjectType != BUILDER_INVALID_OBJECT ) |
|
{ |
|
if ( GetObjectInfo( m_iObjectType )->m_bUseItemInfo ) |
|
return BaseClass::GetViewModel(); |
|
|
|
return GetObjectInfo( m_iObjectType )->m_pViewModel; |
|
} |
|
|
|
return BaseClass::GetViewModel(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
const char *C_TFWeaponBuilder::GetWorldModel( void ) const |
|
{ |
|
if ( GetPlayerOwner() == NULL ) |
|
{ |
|
return BaseClass::GetWorldModel(); |
|
} |
|
|
|
if ( m_iObjectType != BUILDER_INVALID_OBJECT ) |
|
{ |
|
return GetObjectInfo( m_iObjectType )->m_pPlayerModel; |
|
} |
|
|
|
return BaseClass::GetWorldModel(); |
|
} |
|
|
|
Activity C_TFWeaponBuilder::GetDrawActivity( void ) |
|
{ |
|
// sapper used to call different draw animations , one when invis and one when not. |
|
// now you can go invis *while* deploying, so let's always use the one-handed deploy. |
|
if ( GetType() == OBJ_ATTACHMENT_SAPPER ) |
|
{ |
|
return ACT_VM_DRAW_DEPLOYED; |
|
} |
|
|
|
return BaseClass::GetDrawActivity(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool C_TFWeaponBuilder::EffectMeterShouldFlash( void ) |
|
{ |
|
if ( !GetOwner() ) |
|
return false; |
|
|
|
int iRoboSapper = 0; |
|
CALL_ATTRIB_HOOK_INT_ON_OTHER( GetOwner(), iRoboSapper, robo_sapper ); |
|
|
|
return ( iRoboSapper && GetEffectBarProgress() >= 1.f ); |
|
} |
|
|
|
const char *C_TFWeaponSapper::GetViewModel( int iViewModel ) const |
|
{ |
|
// Skip over Builder's version |
|
return C_TFWeaponBase::GetViewModel(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
const char *C_TFWeaponSapper::GetWorldModel( void ) const |
|
{ |
|
// Skip over Builder's version |
|
return C_TFWeaponBase::GetWorldModel(); |
|
}
|
|
|