diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/shared/tf2/weapon_builder.cpp | |
| download | archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip | |
Diffstat (limited to 'game/shared/tf2/weapon_builder.cpp')
| -rw-r--r-- | game/shared/tf2/weapon_builder.cpp | 530 |
1 files changed, 530 insertions, 0 deletions
diff --git a/game/shared/tf2/weapon_builder.cpp b/game/shared/tf2/weapon_builder.cpp new file mode 100644 index 0000000..7d90410 --- /dev/null +++ b/game/shared/tf2/weapon_builder.cpp @@ -0,0 +1,530 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: The "weapon" used to build objects +// +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "tf_player.h" +#include "tf_basecombatweapon.h" +#include "EntityList.h" +#include "in_buttons.h" +#include "weapon_builder.h" +#include "tf_obj.h" +#include "sendproxy.h" +#include "weapon_objectselection.h" +#include "info_act.h" +#include "vguiscreen.h" + +extern ConVar tf2_object_hard_limits; +extern ConVar tf_fastbuild; + +EXTERN_SEND_TABLE(DT_BaseCombatWeapon) + +IMPLEMENT_SERVERCLASS_ST(CWeaponBuilder, DT_WeaponBuilder) + SendPropInt( SENDINFO( m_iBuildState ), 4, SPROP_UNSIGNED ), + SendPropInt( SENDINFO( m_iCurrentObject ), BUILDER_OBJECT_BITS, SPROP_UNSIGNED ), + SendPropInt( SENDINFO( m_iCurrentObjectState ), 4, SPROP_UNSIGNED ), + SendPropEHandle( SENDINFO( m_hObjectBeingBuilt ) ), + SendPropTime( SENDINFO( m_flStartTime ) ), + SendPropTime( SENDINFO( m_flTotalTime ) ), + SendPropArray + ( + SendPropInt( SENDINFO_ARRAY(m_bObjectValidity), 1, SPROP_UNSIGNED), m_bObjectValidity + ), + SendPropArray + ( + SendPropInt( SENDINFO_ARRAY(m_bObjectBuildability), 1, SPROP_UNSIGNED), m_bObjectBuildability + ), +END_SEND_TABLE() + +LINK_ENTITY_TO_CLASS( weapon_builder, CWeaponBuilder ); +PRECACHE_WEAPON_REGISTER(weapon_builder); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CWeaponBuilder::CWeaponBuilder() +{ + for ( int i=0; i < m_bObjectValidity.Count(); i++ ) + m_bObjectValidity.Set( i, 0 ); + + m_iCurrentObject = BUILDER_INVALID_OBJECT; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponBuilder::Precache( void ) +{ + BaseClass::Precache(); + + PrecacheModel( "models/weapons/v_slam.mdl" ); + PrecacheVGuiScreen( "screen_human_pda" ); +} + +//----------------------------------------------------------------------------- +// Purpose: Gets info about the control panels +//----------------------------------------------------------------------------- +void CWeaponBuilder::GetControlPanelInfo( int nPanelIndex, const char *&pPanelName ) +{ + pPanelName = "screen_human_pda"; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CWeaponBuilder::ShouldShowControlPanels( void ) +{ + if ( GetActivity() == ACT_VM_IDLE ) + return true; + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponBuilder::UpdateOnRemove( void ) +{ + // Tell the player he's lost his build weapon + CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() ); + if ( pOwner && pOwner->GetWeaponBuilder() == this ) + { + pOwner->SetWeaponBuilder( NULL ); + } + + // Chain at end to mimic destructor unwind order + BaseClass::UpdateOnRemove(); +} + +//----------------------------------------------------------------------------- +// Purpose: Builder weapon has just been given to a player +//----------------------------------------------------------------------------- +void CWeaponBuilder::Equip( CBaseCombatCharacter *pOwner ) +{ + BaseClass::Equip( pOwner ); + ((CBaseTFPlayer*)pOwner)->SetWeaponBuilder( this ); +} + +//----------------------------------------------------------------------------- +// Purpose: Add a new object type to this build weapon. This will allow +// the player carrying this builder to build the object. +//----------------------------------------------------------------------------- +void CWeaponBuilder::AddBuildableObject( int iObjectType ) +{ + m_bObjectValidity.Set( iObjectType, true ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CWeaponBuilder::CanDeploy( void ) +{ + if ( m_iCurrentObject != BUILDER_INVALID_OBJECT ) + { + SetCurrentState( BS_PLACING ); + StartPlacement(); + m_flNextPrimaryAttack = gpGlobals->curtime + 0.35f; + } + else + { + m_hObjectBeingBuilt = NULL; + SetCurrentState( BS_IDLE ); + SetCurrentObject( m_iCurrentObject ); + } + return BaseClass::CanDeploy(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CWeaponBuilder::Deploy( ) +{ +#if !defined( CLIENT_DLL ) + if ( m_hObjectBeingBuilt.Get() && m_hObjectBeingBuilt->IsAnUpgrade() ) + return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), ACT_SLAM_STICKWALL_ND_DRAW, (char*)GetAnimPrefix() ); + + return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), ACT_VM_DRAW, (char*)GetAnimPrefix() ); +#else + return true; +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: Prevent switching when working on something +//----------------------------------------------------------------------------- +bool CWeaponBuilder::CanHolster( void ) +{ + if ( IsBuilding() ) + return false; + + return BaseClass::CanHolster(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CBaseCombatWeapon *CWeaponBuilder::GetLastWeapon( void ) +{ + return BaseClass::GetLastWeapon(); +} + +//----------------------------------------------------------------------------- +// Purpose: Stop placement when holstering +//----------------------------------------------------------------------------- +bool CWeaponBuilder::Holster( CBaseCombatWeapon *pSwitchingTo ) +{ + if ( m_iBuildState == BS_PLACING || m_iBuildState == BS_PLACING_INVALID ) + { + SetCurrentState( BS_IDLE ); + } + StopPlacement(); + + return BaseClass::Holster(pSwitchingTo); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponBuilder::ItemPostFrame( void ) +{ + CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() ); + if ( !pOwner ) + return; + + // Ignore input while the player's building anything + if ( pOwner->IsBuilding() ) + return; + + // Switch away if I'm not in placement mode + if ( m_iBuildState != BS_PLACING && m_iBuildState != BS_PLACING_INVALID ) + { + pOwner->SwitchToNextBestWeapon( NULL ); + return; + } + + if (( pOwner->m_nButtons & IN_ATTACK ) && (m_flNextPrimaryAttack <= gpGlobals->curtime) ) + { + PrimaryAttack(); + } + + // Allow shield post frame + AllowShieldPostFrame( true ); + + WeaponIdle(); +} + +//----------------------------------------------------------------------------- +// Purpose: Start placing or building the currently selected object +//----------------------------------------------------------------------------- +void CWeaponBuilder::PrimaryAttack( void ) +{ + CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() ); + if ( !pOwner ) + return; + + // What state should we move to? + switch( m_iBuildState ) + { + case BS_IDLE: + { + // Idle state starts selection + SetCurrentState( BS_SELECTING ); + } + break; + + case BS_SELECTING: + { + // Do nothing, client handles selection + return; + } + break; + + case BS_PLACING: + { + if ( m_hObjectBeingBuilt ) + { + // Give the object a chance to veto the "start building" command. Objects like barbed wire + // may want to change their properties instead of actually building yet. + if ( m_hObjectBeingBuilt->PreStartBuilding() ) + { + int iFlags = m_hObjectBeingBuilt->GetObjectFlags(); + + // Can't build if the game hasn't started + if ( !tf_fastbuild.GetInt() && CurrentActIsAWaitingAct() ) + { + ClientPrint( pOwner, HUD_PRINTCENTER, "Can't build until the game's started.\n" ); + return; + } + + StartBuilding(); + + // Should we switch away? + if ( iFlags & OF_ALLOW_REPEAT_PLACEMENT ) + { + // Start placing another + SetCurrentState( BS_PLACING ); + StartPlacement(); + } + else + { + pOwner->SwitchToNextBestWeapon( NULL ); + } + } + } + } + break; + + case BS_PLACING_INVALID: + { + WeaponSound( SINGLE_NPC ); + + // If there is any associated error text when placing the object, display it + if( m_hObjectBeingBuilt != NULL ) + { + if (m_hObjectBeingBuilt->MustBeBuiltInResourceZone()) + { + ClientPrint( pOwner, HUD_PRINTCENTER, "Only placeable in an empty resource zone.\n" ); + } + else if (m_hObjectBeingBuilt->MustBeBuiltInConstructionYard()) + { + ClientPrint( pOwner, HUD_PRINTCENTER, "Only placeable in a construction yard.\n" ); + } + } + } + break; + } + + m_flNextPrimaryAttack = gpGlobals->curtime + 0.2f; +} + +//----------------------------------------------------------------------------- +// Purpose: Set the builder to the specified state +//----------------------------------------------------------------------------- +void CWeaponBuilder::SetCurrentState( int iState ) +{ + // Check the current build state... we may need to shut some stuff down... + switch(m_iBuildState) + { + case BS_PLACING: + case BS_PLACING_INVALID: + { + if ((iState != BS_PLACING) && (iState != BS_PLACING_INVALID) && (iState != BS_BUILDING)) + { + StopPlacement(); + WeaponSound( SPECIAL1 ); + } + } + break; + } + + m_iBuildState = iState; +} + +//----------------------------------------------------------------------------- +// Purpose: Set the builder to the specified object +//----------------------------------------------------------------------------- +void CWeaponBuilder::SetCurrentObject( int iObject ) +{ + // Fixup for invalid objects + if (iObject < 0) + iObject = BUILDER_INVALID_OBJECT; + + CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() ); + if ( !pOwner ) + return; + + int i; + + // If -1 was passed in, set to our first available object + if ( iObject == BUILDER_INVALID_OBJECT ) + { + for ( i = 0; i < OBJ_LAST; i++ ) + { + if ( m_bObjectValidity[i] ) + { + iObject = i; + break; + } + } + } + + // Recalculate the buildability of each object (for propagation to the client) + for ( i=0; i < m_bObjectBuildability.Count(); i++ ) + m_bObjectBuildability.Set( i, 0 ); + + for ( i = 0; i < OBJ_LAST; i++ ) + { + if ( m_bObjectValidity[i] && pOwner->CanBuild(i) == CB_CAN_BUILD ) + { + m_bObjectBuildability.Set( i, true ); + } + } + + m_iCurrentObject = iObject; + m_iCurrentObjectState = pOwner->CanBuild( m_iCurrentObject ); + m_flStartTime = 0; + m_flTotalTime = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Idle updates the position of the build placement model +//----------------------------------------------------------------------------- +void CWeaponBuilder::WeaponIdle( void ) +{ + CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() ); + if ( !pOwner ) + return; + + // If we're in placement mode, update the placement model + switch( m_iBuildState ) + { + case BS_PLACING: + case BS_PLACING_INVALID: + { + if ( UpdatePlacement() ) + { + SetCurrentState( BS_PLACING ); + } + else + { + SetCurrentState( BS_PLACING_INVALID ); + } + } + break; + + default: + break; + } + + if ( HasWeaponIdleTimeElapsed() ) + { + SendWeaponAnim( ACT_VM_IDLE ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: The player holding this weapon has just gained new technology. +// Check to see if it affects the medikit +//----------------------------------------------------------------------------- +void CWeaponBuilder::GainedNewTechnology( CBaseTechnology *pTechnology ) +{ + CBaseTFPlayer *pPlayer = ToBaseTFPlayer( GetOwner() ); + if ( pPlayer ) + { + // Force a recalculation of the state for this object + SetCurrentObject( m_iCurrentObject ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Start placing the object +//----------------------------------------------------------------------------- +void CWeaponBuilder::StartPlacement( void ) +{ + StopPlacement(); + + // Create the slab + m_hObjectBeingBuilt = (CBaseObject*)CreateEntityByName( GetObjectInfo( m_iCurrentObject )->m_pClassName ); + if ( m_hObjectBeingBuilt ) + { + m_hObjectBeingBuilt->Spawn(); + m_hObjectBeingBuilt->StartPlacement( ToBaseTFPlayer( GetOwner() ) ); + UpdatePlacement(); + + // Stomp this here in the same frame we make the object, so prevent clientside warnings that it's under attack + m_hObjectBeingBuilt->m_iHealth = OBJECT_CONSTRUCTION_STARTINGHEALTH; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Set the viewmodel according to the type of object we're placing +//----------------------------------------------------------------------------- +const char *CWeaponBuilder::GetViewModel( int viewmodelindex /*=0*/ ) const +{ + if ( m_hObjectBeingBuilt.Get() && m_hObjectBeingBuilt->IsAnUpgrade() ) + return "models/weapons/v_slam.mdl"; + + return BaseClass::GetViewModel( viewmodelindex ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponBuilder::StopPlacement( void ) +{ + if ( m_hObjectBeingBuilt ) + { + m_hObjectBeingBuilt->StopPlacement(); + m_hObjectBeingBuilt = NULL; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Move the placement model to the current position. Return false if it's an invalid position +//----------------------------------------------------------------------------- +bool CWeaponBuilder::UpdatePlacement( void ) +{ + if ( !m_hObjectBeingBuilt ) + return false; + + return m_hObjectBeingBuilt->UpdatePlacement( ToBaseTFPlayer(GetOwner()) ); +} + +//----------------------------------------------------------------------------- +// Purpose: Player holding this weapon has started building something +//----------------------------------------------------------------------------- +void CWeaponBuilder::StartBuilding( void ) +{ + if ( m_hObjectBeingBuilt.Get() && UpdatePlacement() ) + { + SetCurrentState( BS_BUILDING ); + m_hObjectBeingBuilt->StartBuilding( GetOwner() ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Player holding this weapon has aborted the build of an object +//----------------------------------------------------------------------------- +void CWeaponBuilder::StoppedBuilding( int iObjectType ) +{ + CBaseTFPlayer *pPlayer = ToBaseTFPlayer( GetOwner() ); + if ( pPlayer ) + { + // Force a recalculation of the state for this object + SetCurrentObject( m_iCurrentObject ); + SetCurrentState( BS_IDLE ); + + WeaponSound( SPECIAL2 ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CWeaponBuilder::IsBuilding( void ) +{ + return ( m_iBuildState == BS_BUILDING ); +} + +//----------------------------------------------------------------------------- +// Purpose: The player holding this weapon has just finished building an object +//----------------------------------------------------------------------------- +void CWeaponBuilder::FinishedObject( void ) +{ + CBaseTFPlayer *pPlayer = ToBaseTFPlayer( GetOwner() ); + if ( pPlayer ) + { + // We're no longer building anything... + m_hObjectBeingBuilt = NULL; + + // Force a recalculation of the state for this object + SetCurrentObject( m_iCurrentObject ); + SetCurrentState( BS_IDLE ); + } +} |