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.
 
 
 
 
 
 

410 lines
10 KiB

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================
#include "cbase.h"
#include "hud.h"
#include "hudelement.h"
#include "c_tf_player.h"
#include "iclientmode.h"
#include "ienginevgui.h"
#include "tf_gamerules.h"
#include <vgui/ILocalize.h>
#include <vgui/ISurface.h>
#include <vgui/IVGui.h>
#include "c_baseobject.h"
#include "tf_hud_menu_engy_destroy.h"
#include "tf_hud_menu_engy_build.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui;
extern const EngyConstructBuilding_t g_kEngyBuildings[];
//======================================
DECLARE_BUILD_FACTORY( CEngyDestroyMenuItem );
//======================================
DECLARE_HUDELEMENT_DEPTH( CHudMenuEngyDestroy, 40 ); // in front of engy building status
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CHudMenuEngyDestroy::CHudMenuEngyDestroy( const char *pElementName )
: CHudBaseBuildMenu( pElementName, "HudMenuEngyDestroy" )
{
Panel *pParent = g_pClientMode->GetViewport();
SetParent( pParent );
m_iCurrentDestroyMenuLayout = DESTROYMENU_DEFAULT;
SetHiddenBits( HIDEHUD_MISCSTATUS );
for ( int i=0; i<NUM_ENGY_BUILDINGS; i++ )
{
char buf[32];
Q_snprintf( buf, sizeof(buf), "active_item_%d", i+1 );
m_pActiveItems[i] = new CEngyDestroyMenuItem( this, buf );
Q_snprintf( buf, sizeof(buf), "inactive_item_%d", i+1 );
m_pInactiveItems[i] = new CEngyDestroyMenuItem( this, buf );
Q_snprintf( buf, sizeof(buf), "unavailable_item_%d", i+1 );
m_pUnavailableItems[i] = new CEngyDestroyMenuItem( this, buf );
}
vgui::ivgui()->AddTickSignal( GetVPanel() );
RegisterForRenderGroup( "mid" );
}
//-----------------------------------------------------------------------------
// Purpose: called whenever a new level is starting
//-----------------------------------------------------------------------------
void CHudMenuEngyDestroy::LevelInit( void )
{
//RecalculateBuildingItemState( ALL_BUILDINGS );
CHudElement::LevelInit();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudMenuEngyDestroy::ApplySchemeSettings( IScheme *pScheme )
{
const char *pszCustomDir = NULL;
switch( m_iCurrentDestroyMenuLayout )
{
case DESTROYMENU_PIPBOY:
pszCustomDir = "resource/UI/destroy_menu/pipboy";
break;
default:
case DESTROYMENU_DEFAULT:
pszCustomDir = "resource/UI/destroy_menu";
break;
}
// load control settings...
LoadControlSettings( VarArgs("%s/HudMenuEngyDestroy.res",pszCustomDir) );
for ( int i=0; i<NUM_ENGY_BUILDINGS; ++i )
{
CExLabel *pNumberLabel = NULL;
if ( m_Buildings[i].m_pszDestroyActiveObjectRes )
{
m_pActiveItems[i]->LoadControlSettings( VarArgs( "%s/%s", pszCustomDir, m_Buildings[i].m_pszDestroyActiveObjectRes ) );
}
if ( m_Buildings[i].m_pszDestroyInactiveObjectRes )
{
m_pInactiveItems[i]->LoadControlSettings( VarArgs( "%s/%s", pszCustomDir, m_Buildings[i].m_pszDestroyInactiveObjectRes ) );
}
if ( m_Buildings[i].m_pszDestroyUnavailableObjectRes )
{
m_pUnavailableItems[i]->LoadControlSettings( VarArgs( "%s/%s", pszCustomDir, m_Buildings[i].m_pszDestroyUnavailableObjectRes ) );
}
// Set the Numerical Number
pNumberLabel = dynamic_cast<CExLabel *>( m_pActiveItems[i]->FindChildByName( "NumberLabel" ) );
if ( pNumberLabel )
{
pNumberLabel->SetText( VarArgs( "%d", i + 1 ) );
}
pNumberLabel = dynamic_cast<CExLabel *>( m_pInactiveItems[i]->FindChildByName( "NumberLabel" ) );
if ( pNumberLabel )
{
pNumberLabel->SetText( VarArgs( "%d", i + 1 ) );
}
pNumberLabel = dynamic_cast<CExLabel *>( m_pUnavailableItems[i]->FindChildByName( "NumberLabel" ) );
if ( pNumberLabel )
{
pNumberLabel->SetText( VarArgs( "%d", i + 1 ) );
}
}
for ( int i = 0; i < NUM_ENGY_BUILDINGS; ++i )
{
vgui::Panel* pNotBuiltLabel = m_pUnavailableItems[i]->FindChildByName( "NotBuiltLabel" );
vgui::Panel* pUnavailableLabel = m_pUnavailableItems[i]->FindChildByName( "UnavailableLabel" );
if ( pNotBuiltLabel )
{
pNotBuiltLabel->SetVisible( false );
}
if ( pUnavailableLabel )
{
pUnavailableLabel->SetVisible( true );
}
}
BaseClass::ApplySchemeSettings( pScheme );
}
//-----------------------------------------------------------------------------
// Purpose: Keyboard input hook. Return 0 if handled
//-----------------------------------------------------------------------------
int CHudMenuEngyDestroy::HudElementKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding )
{
if ( !ShouldDraw() )
{
return 1;
}
if ( !down )
{
return 1;
}
C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
if ( !pLocalPlayer )
return 1;
bool bCanDestroyBuildings = true;
if ( TFGameRules() && TFGameRules()->IsInTraining() )
{
ConVarRef training_can_destroy_buildings("training_can_destroy_buildings");
bCanDestroyBuildings = training_can_destroy_buildings.GetBool();
}
if ( bCanDestroyBuildings == false )
{
return 1;
}
bool bHandled = false;
int iSlot = -1;
// convert slot1, slot2 etc to 1,2,3,4
if( pszCurrentBinding && !Q_strncmp( pszCurrentBinding, "slot", NUM_ENGY_BUILDINGS ) && Q_strlen(pszCurrentBinding) > NUM_ENGY_BUILDINGS )
{
const char *pszNum = pszCurrentBinding+NUM_ENGY_BUILDINGS;
iSlot = atoi(pszNum);
// slot10 cancels
if ( iSlot == 10 )
{
engine->ExecuteClientCmd( "lastinv" );
return 0;
}
iSlot -= 1; // adjust to be 0 based
// allow slot1 - slot4
if ( iSlot < 0 || iSlot > 3 )
return 1;
}
else
{
switch( keynum )
{
case KEY_1:
case KEY_XBUTTON_UP:
iSlot = 0;
bHandled = true;
break;
case KEY_2:
case KEY_XBUTTON_RIGHT:
iSlot = 1;
bHandled = true;
break;
case KEY_3:
case KEY_XBUTTON_DOWN:
iSlot = 2;
bHandled = true;
break;
case KEY_4:
case KEY_XBUTTON_LEFT:
iSlot = 3;
bHandled = true;
break;
case KEY_5:
case KEY_6:
case KEY_7:
case KEY_8:
case KEY_9:
// Eat these keys
bHandled = true;
break;
case KEY_0:
case KEY_XBUTTON_B:
engine->ExecuteClientCmd( "lastinv" );
bHandled = true;
break;
default:
break;
}
}
if ( iSlot >= 0 )
{
int iBuildingID, iMode;
CHudMenuEngyBuild::GetBuildingIDAndModeFromSlot( iSlot+1, iBuildingID, iMode, m_Buildings );
C_BaseObject *pObj = pLocalPlayer->GetObjectOfType( iBuildingID, iMode );
if ( pObj && !pObj->HasSapper() && !pObj->IsPlasmaDisabled() )
{
char szCmd[128];
Q_snprintf( szCmd, sizeof(szCmd), "destroy %d %d; lastinv", iBuildingID, iMode );
engine->ExecuteClientCmd( szCmd );
}
else
{
ErrorSound();
}
}
// return 0 if we ate the key
return ( bHandled == false );
}
void CHudMenuEngyDestroy::ErrorSound( void )
{
C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
if ( pLocalPlayer )
{
pLocalPlayer->EmitSound( "Player.DenyWeaponSelection" );
}
}
void CHudMenuEngyDestroy::OnTick( void )
{
C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
bool bCanDestroyBuildings = true;
if ( TFGameRules() && TFGameRules()->IsInTraining() )
{
ConVarRef training_can_destroy_buildings("training_can_destroy_buildings");
bCanDestroyBuildings = training_can_destroy_buildings.GetBool();
}
int i;
for ( i=0;i<NUM_ENGY_BUILDINGS; i++ )
{
int iRemappedObjectID, iMode;
CHudMenuEngyBuild::GetBuildingIDAndModeFromSlot( i + 1, iRemappedObjectID, iMode, m_Buildings );
// update this slot
C_BaseObject *pObj = NULL;
if ( pLocalPlayer )
{
pObj = pLocalPlayer->GetObjectOfType( iRemappedObjectID, iMode );
}
// If the building is built, we can destroy it
// unless we are in training, then we check the convar
if( m_Buildings[i].m_bEnabled == false )
{
m_pActiveItems[i]->SetVisible( false );
m_pInactiveItems[i]->SetVisible( false );
m_pUnavailableItems[i]->SetVisible( false );
}
else if ( bCanDestroyBuildings == false )
{
m_pActiveItems[i]->SetVisible( false );
m_pInactiveItems[i]->SetVisible( false );
m_pUnavailableItems[i]->SetVisible( true );
}
else if ( pObj != NULL && !pObj->IsPlacing() )
{
m_pActiveItems[i]->SetVisible( true );
m_pInactiveItems[i]->SetVisible( false );
m_pUnavailableItems[i]->SetVisible( false );
}
else
{
m_pActiveItems[i]->SetVisible( false );
m_pInactiveItems[i]->SetVisible( true );
m_pUnavailableItems[i]->SetVisible( false );
}
}
}
void CHudMenuEngyDestroy::SetVisible( bool state )
{
if ( state == IsVisible() )
return;
InitBuildings();
if ( state == true )
{
// See if our layout needs to change, due to equipped items
int iDesired = CalcCustomDestroyMenuLayout();
if ( iDesired != m_iCurrentDestroyMenuLayout )
{
m_iCurrentDestroyMenuLayout = (destroymenulayouts_t)iDesired;
InvalidateLayout( true, true );
}
// set the %lastinv% dialog var to our binding
const char *key = engine->Key_LookupBinding( "lastinv" );
if ( !key )
{
key = "< not bound >";
}
SetDialogVariable( "lastinv", key );
//RecalculateBuildingState( ALL_BUILDINGS );
HideLowerPriorityHudElementsInGroup( "mid" );
}
else
{
UnhideLowerPriorityHudElementsInGroup( "mid" );
}
BaseClass::SetVisible( state );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CHudMenuEngyDestroy::CalcCustomDestroyMenuLayout( void )
{
C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
if ( !pLocalPlayer )
return DESTROYMENU_DEFAULT;
int iMenu = DESTROYMENU_DEFAULT;
CALL_ATTRIB_HOOK_INT_ON_OTHER( pLocalPlayer, iMenu, set_custom_buildmenu );
return iMenu;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudMenuEngyDestroy::InitBuildings()
{
for( int i=0; i<NUM_ENGY_BUILDINGS; ++i )
{
m_Buildings[i] = g_kEngyBuildings[i];
}
CHudMenuEngyBuild::ReplaceBuildings( m_Buildings );
InvalidateLayout( true, true );
}