//========= 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 #include #include #include "c_baseobject.h" #include "inputsystem/iinputsystem.h" #include "tf_hud_menu_eureka_teleport.h" // NVNT haptics for buildings #include "haptics/haptic_utils.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" using namespace vgui; // Set to 1 to simulate xbox-style menu interaction extern ConVar tf_build_menu_controller_mode; DECLARE_HUDELEMENT_DEPTH( CHudEurekaEffectTeleportMenu, 41 ); // in front of engy building status //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CHudEurekaEffectTeleportMenu::CHudEurekaEffectTeleportMenu( const char *pElementName ) : CHudElement( pElementName ) , BaseClass( NULL, "HudEurekaEffectTeleportMenu" ) , m_bWantsToTeleport( false ) , m_eSelectedTeleportTarget( EUREKA_TELEPORT_HOME ) , m_eCurrentBuildMenuLayout( BUILDMENU_DEFAULT ) { Panel *pParent = g_pClientMode->GetViewport(); SetParent( pParent ); SetHiddenBits( HIDEHUD_MISCSTATUS ); vgui::ivgui()->AddTickSignal( GetVPanel() ); for( int i=0; i < EUREKA_NUM_TARGETS; ++i ) { m_pAvilableTargets[ i ] = new EditablePanel( this, VarArgs( "available_target_%d", i+1 ) ); m_pUnavailableTargets[ i ] = new EditablePanel( this, VarArgs( "unavailable_target_%d", i+1 ) ); } RegisterForRenderGroup( "mid" ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHudEurekaEffectTeleportMenu::ApplySchemeSettings( IScheme *pScheme ) { const char *pszCustomDir = NULL; switch( m_eCurrentBuildMenuLayout ) { case BUILDMENU_PIPBOY: pszCustomDir = "resource/UI/build_menu/pipboy"; break; default: case BUILDMENU_DEFAULT: if ( ::input->IsSteamControllerActive() ) { pszCustomDir = "resource/UI/build_menu_sc"; } else { pszCustomDir = "resource/UI/build_menu"; } break; } LoadControlSettings( VarArgs( "%s/HudMenuEurekaEffect.res", pszCustomDir) ); m_pAvilableTargets[ EUREKA_TELEPORT_HOME ]->LoadControlSettings( VarArgs( "%s/eureka_target_home_avail.res", pszCustomDir ) ); m_pAvilableTargets[ EUREKA_TELEPORT_TELEPORTER_EXIT ]->LoadControlSettings( VarArgs( "%s/eureka_target_tele_exit_avail.res", pszCustomDir ) ); m_pUnavailableTargets[ EUREKA_TELEPORT_HOME ]->LoadControlSettings( VarArgs( "%s/eureka_target_home_unavail.res", pszCustomDir ) ); m_pUnavailableTargets[ EUREKA_TELEPORT_TELEPORTER_EXIT ]->LoadControlSettings( VarArgs( "%s/eureka_target_tele_exit_unavail.res", pszCustomDir ) ); BaseClass::ApplySchemeSettings( pScheme ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CHudEurekaEffectTeleportMenu::ShouldDraw( void ) { if ( !CanTeleport() ) { m_bWantsToTeleport = false; return false; } return true; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHudEurekaEffectTeleportMenu::SetVisible( bool bState ) { if ( bState == true ) { // close the weapon selection menu engine->ClientCmd( "cancelselect" ); // See if our layout needs to change, due to equipped items buildmenulayouts_t eDesired = CHudMenuEngyBuild::CalcCustomBuildMenuLayout(); if ( eDesired != m_eCurrentBuildMenuLayout ) { m_eCurrentBuildMenuLayout = eDesired; InvalidateLayout( true, true ); } const char* key = engine->Key_LookupBinding( "lastinv" ); if ( !key ) { key = "< not bound >"; } SetDialogVariable( "lastinv", key ); // Set selection to the first available building that we can build C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); if ( !pLocalPlayer ) return; m_eSelectedTeleportTarget = EUREKA_TELEPORT_HOME; SetSelectedItem( m_eSelectedTeleportTarget ); HideLowerPriorityHudElementsInGroup( "mid" ); } else { UnhideLowerPriorityHudElementsInGroup( "mid" ); } BaseClass::SetVisible( bState ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CHudEurekaEffectTeleportMenu::CanTeleport() const { if ( !m_bWantsToTeleport ) return false; CTFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer(); if ( !pPlayer ) return false; CTFWeaponBase *pWpn = pPlayer->GetActiveTFWeapon(); if ( !pWpn ) return false; // Don't show the menu for first person spectator if ( pPlayer != pWpn->GetOwner() ) return false; if ( !const_cast(this)->CHudElement::ShouldDraw() ) return false; return ( pWpn->GetWeaponID() == TF_WEAPON_WRENCH ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHudEurekaEffectTeleportMenu::SendTeleportMessage( eEurekaTeleportTargets eTeleportTarget ) { // They've made their selection. Setting this to false will close this panel. m_bWantsToTeleport = false; C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); if ( !pLocalPlayer ) return; // We do code elsewhere that set the available targets panel visible if they're available. // If it's not visible, it's not available. // Can not use while karting if ( !m_pAvilableTargets[ eTeleportTarget ]->IsVisible() || pLocalPlayer->m_Shared.InCond( TF_COND_HALLOWEEN_KART ) ) { pLocalPlayer->EmitSound( "Player.DenyWeaponSelection" ); return; } char szCmd[128]; Q_snprintf( szCmd, sizeof(szCmd), "eureka_teleport %d", (int)eTeleportTarget ); engine->ClientCmd( szCmd ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- int CHudEurekaEffectTeleportMenu::HudElementKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ) { if ( !ShouldDraw() ) { return 1; } if ( !down ) { return 1; } bool bConsoleController = ( IsConsole() || ( keynum >= JOYSTICK_FIRST && !IsSteamControllerCode(keynum)) ); if ( bConsoleController ) { int nNewSelection = m_eSelectedTeleportTarget; switch( keynum ) { case KEY_XBUTTON_UP: // jump to last nNewSelection = EUREKA_LAST_TARGET; break; case KEY_XBUTTON_DOWN: // jump to first nNewSelection = EUREKA_FIRST_TARGET; break; case KEY_XBUTTON_RIGHT: // move selection to the right nNewSelection++; if ( nNewSelection > EUREKA_LAST_TARGET ) nNewSelection = EUREKA_FIRST_TARGET; break; case KEY_XBUTTON_LEFT: // move selection to the left nNewSelection--; if ( nNewSelection <= 0 ) nNewSelection = EUREKA_LAST_TARGET; break; case KEY_XBUTTON_A: case KEY_XBUTTON_RTRIGGER: case KEY_XBUTTON_Y: case KEY_XBUTTON_LTRIGGER: // build selected item SendTeleportMessage( (eEurekaTeleportTargets)nNewSelection ); return 0; case KEY_XBUTTON_B: // cancel, close the menu engine->ExecuteClientCmd( "lastinv" ); return 0; default: return 1; // key not handled } SetSelectedItem( (eEurekaTeleportTargets)nNewSelection ); return 0; } else { int iSlot = 0; // 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; } // allow slot1 - slot4 if ( iSlot < 1 || iSlot > EUREKA_NUM_TARGETS ) return 1; } else { switch( keynum ) { case KEY_1: iSlot = 1; break; case KEY_2: iSlot = 2; break; case KEY_3: case KEY_4: case KEY_5: case KEY_6: case KEY_7: case KEY_8: case KEY_9: // Eat these keys return 0; case KEY_0: case KEY_XBUTTON_B: case STEAMCONTROLLER_B: // cancel, close the menu engine->ExecuteClientCmd( "lastinv" ); return 0; case STEAMCONTROLLER_DPAD_LEFT: SendTeleportMessage( EUREKA_TELEPORT_HOME ); return 0; case STEAMCONTROLLER_DPAD_RIGHT: SendTeleportMessage( EUREKA_TELEPORT_TELEPORTER_EXIT ); return 0; default: return 1; // key not handled } } if ( iSlot > 0 ) { SendTeleportMessage( (eEurekaTeleportTargets)(iSlot-1) ); return 0; } } return 1; // key not handled } void CHudEurekaEffectTeleportMenu::WantsToTeleport() { m_bWantsToTeleport = true; InvalidateLayout( true, true ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHudEurekaEffectTeleportMenu::SetSelectedItem( eEurekaTeleportTargets eSelectedTeleportTarget ) { if ( m_eSelectedTeleportTarget != eSelectedTeleportTarget ) { m_eSelectedTeleportTarget = eSelectedTeleportTarget; // move the selection item to the new position if ( m_pActiveSelection ) { // move the selection background int x, y; m_pAvilableTargets[m_eSelectedTeleportTarget]->GetPos( x, y ); x -= XRES(4); y -= XRES(4); m_pActiveSelection->SetPos( x, y ); UpdateHintLabels(); } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHudEurekaEffectTeleportMenu::OnTick( void ) { if ( !IsVisible() ) return; C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); if ( !pLocalPlayer ) return; m_pAvilableTargets[ EUREKA_TELEPORT_HOME ]->SetVisible( true ); m_pUnavailableTargets[ EUREKA_TELEPORT_HOME ]->SetVisible( false ); const C_BaseObject *pObj = pLocalPlayer->GetObjectOfType( OBJ_TELEPORTER, MODE_TELEPORTER_EXIT ); bool bTeleAvailable = pObj && !pObj->IsBuilding() && !pObj->IsPlacing() && !pObj->IsUpgrading() && !pObj->IsCarried(); m_pAvilableTargets[ EUREKA_TELEPORT_TELEPORTER_EXIT ]->SetVisible( bTeleAvailable ); m_pUnavailableTargets[ EUREKA_TELEPORT_TELEPORTER_EXIT ]->SetVisible( !bTeleAvailable ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHudEurekaEffectTeleportMenu::UpdateHintLabels( void ) { }