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.
887 lines
24 KiB
887 lines
24 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#include "cbase.h" |
|
#include "inputsystem/iinputsystem.h" |
|
#include "input.h" |
|
#include <cdll_client_int.h> |
|
#include <globalvars_base.h> |
|
#include <cdll_util.h> |
|
#include <KeyValues.h> |
|
|
|
#include "spectatorgui.h" |
|
|
|
#include <vgui/IScheme.h> |
|
#include <vgui/ILocalize.h> |
|
#include <vgui/ISurface.h> |
|
#include <vgui/IPanel.h> |
|
#include <vgui_controls/ImageList.h> |
|
#include <vgui_controls/MenuItem.h> |
|
#include <vgui_controls/TextImage.h> |
|
|
|
#include <stdio.h> // _snprintf define |
|
|
|
#include <game/client/iviewport.h> |
|
#include "commandmenu.h" |
|
#include "hltvcamera.h" |
|
#if defined( REPLAY_ENABLED ) |
|
#include "replay/replaycamera.h" |
|
#endif |
|
|
|
#include <vgui_controls/TextEntry.h> |
|
#include <vgui_controls/Panel.h> |
|
#include <vgui_controls/ImagePanel.h> |
|
#include <vgui_controls/Menu.h> |
|
#include "IGameUIFuncs.h" // for key bindings |
|
#include <imapoverview.h> |
|
#include <shareddefs.h> |
|
#include <igameresources.h> |
|
|
|
#ifdef TF_CLIENT_DLL |
|
#include "tf_gamerules.h" |
|
void AddSubKeyNamed( KeyValues *pKeys, const char *pszName ); |
|
#endif |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
#ifndef _XBOX |
|
extern IGameUIFuncs *gameuifuncs; // for key binding details |
|
#endif |
|
|
|
// void DuckMessage(const char *str); // from vgui_teamfortressviewport.cpp |
|
|
|
ConVar spec_scoreboard( "spec_scoreboard", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE ); |
|
|
|
CSpectatorGUI *g_pSpectatorGUI = NULL; |
|
|
|
|
|
// NB disconnect between localization text and observer mode enums |
|
static const char *s_SpectatorModes[] = |
|
{ |
|
"#Spec_Mode0", // OBS_MODE_NONE = 0, |
|
"#Spec_Mode1", // OBS_MODE_DEATHCAM, |
|
"", // OBS_MODE_FREEZECAM, |
|
"#Spec_Mode2", // OBS_MODE_FIXED, |
|
"#Spec_Mode3", // OBS_MODE_IN_EYE, |
|
"#Spec_Mode4", // OBS_MODE_CHASE, |
|
"#Spec_Mode_POI", // OBS_MODE_POI, PASSTIME |
|
"#Spec_Mode5", // OBS_MODE_ROAMING, |
|
}; |
|
|
|
using namespace vgui; |
|
|
|
ConVar cl_spec_mode( |
|
"cl_spec_mode", |
|
"1", |
|
FCVAR_ARCHIVE | FCVAR_USERINFO | FCVAR_SERVER_CAN_EXECUTE, |
|
"spectator mode" ); |
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: left and right buttons pointing buttons |
|
//----------------------------------------------------------------------------- |
|
class CSpecButton : public Button |
|
{ |
|
public: |
|
CSpecButton(Panel *parent, const char *panelName): Button(parent, panelName, "") {} |
|
|
|
private: |
|
void ApplySchemeSettings(vgui::IScheme *pScheme) |
|
{ |
|
Button::ApplySchemeSettings(pScheme); |
|
SetFont(pScheme->GetFont("Marlett", IsProportional()) ); |
|
} |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Constructor |
|
//----------------------------------------------------------------------------- |
|
CSpectatorMenu::CSpectatorMenu( IViewPort *pViewPort ) : Frame( NULL, PANEL_SPECMENU ) |
|
{ |
|
m_iDuckKey = BUTTON_CODE_INVALID; |
|
|
|
m_pViewPort = pViewPort; |
|
|
|
SetMouseInputEnabled( true ); |
|
SetKeyBoardInputEnabled( true ); |
|
SetTitleBarVisible( false ); // don't draw a title bar |
|
SetMoveable( false ); |
|
SetSizeable( false ); |
|
SetProportional(true); |
|
|
|
SetScheme("ClientScheme"); |
|
|
|
m_pPlayerList = new ComboBox(this, "playercombo", 10 , false); |
|
HFont hFallbackFont = scheme()->GetIScheme( GetScheme() )->GetFont( "DefaultVerySmallFallBack", false ); |
|
if ( INVALID_FONT != hFallbackFont ) |
|
{ |
|
m_pPlayerList->SetUseFallbackFont( true, hFallbackFont ); |
|
} |
|
|
|
m_pViewOptions = new ComboBox(this, "viewcombo", 10 , false ); |
|
m_pConfigSettings = new ComboBox(this, "settingscombo", 10 , false ); |
|
|
|
m_pLeftButton = new CSpecButton( this, "specprev"); |
|
m_pLeftButton->SetText("3"); |
|
m_pRightButton = new CSpecButton( this, "specnext"); |
|
m_pRightButton->SetText("4"); |
|
|
|
m_pPlayerList->SetText(""); |
|
m_pViewOptions->SetText("#Spec_Modes"); |
|
m_pConfigSettings->SetText("#Spec_Options"); |
|
|
|
m_pPlayerList->SetOpenDirection( Menu::UP ); |
|
m_pViewOptions->SetOpenDirection( Menu::UP ); |
|
m_pConfigSettings->SetOpenDirection( Menu::UP ); |
|
|
|
// create view config menu |
|
CommandMenu * menu = new CommandMenu(m_pConfigSettings, "spectatormenu", gViewPortInterface); |
|
menu->LoadFromFile( "Resource/spectatormenu.res" ); |
|
m_pConfigSettings->SetMenu( menu ); // attach menu to combo box |
|
|
|
// create view mode menu |
|
menu = new CommandMenu(m_pViewOptions, "spectatormodes", gViewPortInterface); |
|
menu->LoadFromFile("Resource/spectatormodes.res"); |
|
m_pViewOptions->SetMenu( menu ); // attach menu to combo box |
|
|
|
LoadControlSettings( "Resource/UI/BottomSpectator.res" ); |
|
|
|
ListenForGameEvent( "spec_target_updated" ); |
|
} |
|
|
|
void CSpectatorMenu::ApplySchemeSettings(IScheme *pScheme) |
|
{ |
|
BaseClass::ApplySchemeSettings(pScheme); |
|
// need to MakeReadyForUse() on the menus so we can set their bg color before they are displayed |
|
m_pConfigSettings->GetMenu()->MakeReadyForUse(); |
|
m_pViewOptions->GetMenu()->MakeReadyForUse(); |
|
m_pPlayerList->GetMenu()->MakeReadyForUse(); |
|
|
|
if ( g_pSpectatorGUI ) |
|
{ |
|
m_pConfigSettings->GetMenu()->SetBgColor( g_pSpectatorGUI->GetBlackBarColor() ); |
|
m_pViewOptions->GetMenu()->SetBgColor( g_pSpectatorGUI->GetBlackBarColor() ); |
|
m_pPlayerList->GetMenu()->SetBgColor( g_pSpectatorGUI->GetBlackBarColor() ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: makes the GUI fill the screen |
|
//----------------------------------------------------------------------------- |
|
void CSpectatorMenu::PerformLayout() |
|
{ |
|
int w,h; |
|
GetHudSize(w, h); |
|
|
|
// fill the screen |
|
SetSize(w,GetTall()); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Handles changes to combo boxes |
|
//----------------------------------------------------------------------------- |
|
void CSpectatorMenu::OnTextChanged(KeyValues *data) |
|
{ |
|
Panel *panel = reinterpret_cast<vgui::Panel *>( data->GetPtr("panel") ); |
|
|
|
vgui::ComboBox *box = dynamic_cast<vgui::ComboBox *>( panel ); |
|
|
|
if( box == m_pConfigSettings) // don't change the text in the config setting combo |
|
{ |
|
m_pConfigSettings->SetText("#Spec_Options"); |
|
} |
|
else if ( box == m_pPlayerList ) |
|
{ |
|
KeyValues *kv = box->GetActiveItemUserData(); |
|
if ( kv && GameResources() ) |
|
{ |
|
const char *player = kv->GetString("player"); |
|
|
|
int currentPlayerNum = GetSpectatorTarget(); |
|
const char *currentPlayerName = GameResources()->GetPlayerName( currentPlayerNum ); |
|
|
|
if ( !FStrEq( currentPlayerName, player ) ) |
|
{ |
|
char command[128]; |
|
Q_snprintf( command, sizeof(command), "spec_player \"%s\"", player ); |
|
engine->ClientCmd( command ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
void CSpectatorMenu::OnCommand( const char *command ) |
|
{ |
|
if (!stricmp(command, "specnext") ) |
|
{ |
|
engine->ClientCmd("spec_next"); |
|
} |
|
else if (!stricmp(command, "specprev") ) |
|
{ |
|
engine->ClientCmd("spec_prev"); |
|
} |
|
} |
|
|
|
void CSpectatorMenu::FireGameEvent( IGameEvent * event ) |
|
{ |
|
const char *pEventName = event->GetName(); |
|
|
|
if ( Q_strcmp( "spec_target_updated", pEventName ) == 0 ) |
|
{ |
|
IGameResources *gr = GameResources(); |
|
if ( !gr ) |
|
return; |
|
|
|
// make sure the player combo box is up to date |
|
int playernum = GetSpectatorTarget(); |
|
if ( playernum < 1 || playernum > MAX_PLAYERS ) |
|
return; |
|
|
|
const char *selectedPlayerName = gr->GetPlayerName( playernum ); |
|
const char *currentPlayerName = ""; |
|
KeyValues *kv = m_pPlayerList->GetActiveItemUserData(); |
|
if ( kv ) |
|
{ |
|
currentPlayerName = kv->GetString( "player" ); |
|
} |
|
if ( !FStrEq( currentPlayerName, selectedPlayerName ) ) |
|
{ |
|
for ( int i=0; i<m_pPlayerList->GetItemCount(); ++i ) |
|
{ |
|
KeyValues *pKv = m_pPlayerList->GetItemUserData( i ); |
|
if ( pKv && FStrEq( pKv->GetString( "player" ), selectedPlayerName ) ) |
|
{ |
|
m_pPlayerList->ActivateItemByRow( i ); |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: when duck is pressed it hides the active part of the GUI |
|
//----------------------------------------------------------------------------- |
|
void CSpectatorMenu::OnKeyCodePressed(KeyCode code) |
|
{ |
|
if ( code == m_iDuckKey ) |
|
{ |
|
// hide if DUCK is pressed again |
|
m_pViewPort->ShowPanel( this, false ); |
|
} |
|
} |
|
|
|
void CSpectatorMenu::ShowPanel(bool bShow) |
|
{ |
|
if ( BaseClass::IsVisible() == bShow ) |
|
return; |
|
|
|
if ( bShow ) |
|
{ |
|
// Force relayout in case Steam Controller stuff has changed. |
|
InvalidateLayout( true, true ); |
|
Activate(); |
|
SetMouseInputEnabled( true ); |
|
SetKeyBoardInputEnabled( true ); |
|
} |
|
else |
|
{ |
|
SetVisible( false ); |
|
SetMouseInputEnabled( false ); |
|
SetKeyBoardInputEnabled( false ); |
|
} |
|
|
|
bool bIsEnabled = true; |
|
|
|
if ( engine->IsHLTV() && HLTVCamera()->IsPVSLocked() ) |
|
{ |
|
// when watching HLTV or Replay with a locked PVS, some elements are disabled |
|
bIsEnabled = false; |
|
} |
|
|
|
m_pLeftButton->SetVisible( bIsEnabled ); |
|
m_pRightButton->SetVisible( bIsEnabled ); |
|
m_pPlayerList->SetVisible( bIsEnabled ); |
|
m_pViewOptions->SetVisible( bIsEnabled ); |
|
} |
|
|
|
void CSpectatorMenu::Update( void ) |
|
{ |
|
IGameResources *gr = GameResources(); |
|
|
|
Reset(); |
|
|
|
if ( m_iDuckKey == BUTTON_CODE_INVALID ) |
|
{ |
|
m_iDuckKey = gameuifuncs->GetButtonCodeForBind( "duck" ); |
|
} |
|
|
|
if ( !gr ) |
|
return; |
|
|
|
int iPlayerIndex; |
|
for ( iPlayerIndex = 1 ; iPlayerIndex <= gpGlobals->maxClients; iPlayerIndex++ ) |
|
{ |
|
|
|
// does this slot in the array have a name? |
|
if ( !gr->IsConnected( iPlayerIndex ) ) |
|
continue; |
|
|
|
if ( gr->IsLocalPlayer( iPlayerIndex ) ) |
|
continue; |
|
|
|
if ( !gr->IsAlive( iPlayerIndex ) ) |
|
continue; |
|
|
|
wchar_t playerText[ 80 ], playerName[ 64 ], *team, teamText[ 64 ]; |
|
char localizeTeamName[64]; |
|
char szPlayerIndex[16]; |
|
g_pVGuiLocalize->ConvertANSIToUnicode( UTIL_SafeName( gr->GetPlayerName(iPlayerIndex) ), playerName, sizeof( playerName ) ); |
|
const char * teamname = gr->GetTeamName( gr->GetTeam(iPlayerIndex) ); |
|
if ( teamname ) |
|
{ |
|
Q_snprintf( localizeTeamName, sizeof( localizeTeamName ), "#%s", teamname ); |
|
team=g_pVGuiLocalize->Find( localizeTeamName ); |
|
|
|
if ( !team ) |
|
{ |
|
g_pVGuiLocalize->ConvertANSIToUnicode( teamname , teamText, sizeof( teamText ) ); |
|
team = teamText; |
|
} |
|
|
|
g_pVGuiLocalize->ConstructString_safe( playerText, g_pVGuiLocalize->Find( "#Spec_PlayerItem_Team" ), 2, playerName, team ); |
|
} |
|
else |
|
{ |
|
g_pVGuiLocalize->ConstructString_safe( playerText, g_pVGuiLocalize->Find( "#Spec_PlayerItem" ), 1, playerName ); |
|
} |
|
|
|
Q_snprintf( szPlayerIndex, sizeof( szPlayerIndex ), "%d", iPlayerIndex ); |
|
|
|
KeyValues *kv = new KeyValues( "UserData", "player", gr->GetPlayerName( iPlayerIndex ), "index", szPlayerIndex ); |
|
m_pPlayerList->AddItem( playerText, kv ); |
|
kv->deleteThis(); |
|
} |
|
|
|
// make sure the player combo box is up to date |
|
int playernum = GetSpectatorTarget(); |
|
const char *selectedPlayerName = gr->GetPlayerName( playernum ); |
|
for ( iPlayerIndex=0; iPlayerIndex<m_pPlayerList->GetItemCount(); ++iPlayerIndex ) |
|
{ |
|
KeyValues *kv = m_pPlayerList->GetItemUserData( iPlayerIndex ); |
|
if ( kv && FStrEq( kv->GetString( "player" ), selectedPlayerName ) ) |
|
{ |
|
m_pPlayerList->ActivateItemByRow( iPlayerIndex ); |
|
break; |
|
} |
|
} |
|
|
|
//============================================================================= |
|
// HPE_BEGIN: |
|
// [pfreese] make sure the view mode combo box is up to date - the spectator |
|
// mode can be changed multiple ways |
|
//============================================================================= |
|
|
|
int specmode = GetSpectatorMode(); |
|
m_pViewOptions->SetText(s_SpectatorModes[specmode]); |
|
|
|
//============================================================================= |
|
// HPE_END |
|
//============================================================================= |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// main spectator panel |
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Constructor |
|
//----------------------------------------------------------------------------- |
|
CSpectatorGUI::CSpectatorGUI(IViewPort *pViewPort) : EditablePanel( NULL, PANEL_SPECGUI ) |
|
{ |
|
// m_bHelpShown = false; |
|
// m_bInsetVisible = false; |
|
// m_iDuckKey = KEY_NONE; |
|
SetSize( 10, 10 ); // Quiet "parent not sized yet" spew |
|
m_bSpecScoreboard = false; |
|
|
|
m_pViewPort = pViewPort; |
|
g_pSpectatorGUI = this; |
|
|
|
// initialize dialog |
|
SetVisible(false); |
|
SetProportional(true); |
|
|
|
// load the new scheme early!! |
|
SetScheme("ClientScheme"); |
|
SetMouseInputEnabled( false ); |
|
SetKeyBoardInputEnabled( false ); |
|
|
|
m_pTopBar = new Panel( this, "topbar" ); |
|
m_pBottomBarBlank = new Panel( this, "bottombarblank" ); |
|
|
|
// m_pBannerImage = new ImagePanel( m_pTopBar, NULL ); |
|
m_pPlayerLabel = new Label( this, "playerlabel", "" ); |
|
m_pPlayerLabel->SetVisible( false ); |
|
TextImage *image = m_pPlayerLabel->GetTextImage(); |
|
if ( image ) |
|
{ |
|
HFont hFallbackFont = scheme()->GetIScheme( GetScheme() )->GetFont( "DefaultVerySmallFallBack", false ); |
|
if ( INVALID_FONT != hFallbackFont ) |
|
{ |
|
image->SetUseFallbackFont( true, hFallbackFont ); |
|
} |
|
} |
|
|
|
SetPaintBorderEnabled(false); |
|
SetPaintBackgroundEnabled(false); |
|
|
|
// m_pBannerImage->SetVisible(false); |
|
InvalidateLayout(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Destructor |
|
//----------------------------------------------------------------------------- |
|
CSpectatorGUI::~CSpectatorGUI() |
|
{ |
|
g_pSpectatorGUI = NULL; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Sets the colour of the top and bottom bars |
|
//----------------------------------------------------------------------------- |
|
void CSpectatorGUI::ApplySchemeSettings(IScheme *pScheme) |
|
{ |
|
KeyValues *pConditions = NULL; |
|
|
|
#ifdef TF_CLIENT_DLL |
|
if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() ) |
|
{ |
|
pConditions = new KeyValues( "conditions" ); |
|
AddSubKeyNamed( pConditions, "if_mvm" ); |
|
} |
|
#endif |
|
|
|
LoadControlSettings( GetResFile(), NULL, NULL, pConditions ); |
|
|
|
if ( pConditions ) |
|
{ |
|
pConditions->deleteThis(); |
|
} |
|
|
|
m_pBottomBarBlank->SetVisible( true ); |
|
m_pTopBar->SetVisible( true ); |
|
|
|
BaseClass::ApplySchemeSettings( pScheme ); |
|
SetBgColor(Color( 0,0,0,0 ) ); // make the background transparent |
|
m_pTopBar->SetBgColor(GetBlackBarColor()); |
|
m_pBottomBarBlank->SetBgColor(GetBlackBarColor()); |
|
// m_pBottomBar->SetBgColor(Color( 0,0,0,0 )); |
|
SetPaintBorderEnabled(false); |
|
|
|
SetBorder( NULL ); |
|
|
|
#ifdef CSTRIKE_DLL |
|
SetZPos(80); // guarantee it shows above the scope |
|
#endif |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: makes the GUI fill the screen |
|
//----------------------------------------------------------------------------- |
|
void CSpectatorGUI::PerformLayout() |
|
{ |
|
int w,h,x,y; |
|
GetHudSize(w, h); |
|
|
|
// fill the screen |
|
SetBounds(0,0,w,h); |
|
|
|
// stretch the bottom bar across the screen |
|
m_pBottomBarBlank->GetPos(x,y); |
|
m_pBottomBarBlank->SetSize( w, h - y ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: checks spec_scoreboard cvar to see if the scoreboard should be displayed |
|
//----------------------------------------------------------------------------- |
|
void CSpectatorGUI::OnThink() |
|
{ |
|
BaseClass::OnThink(); |
|
|
|
if ( IsVisible() ) |
|
{ |
|
if ( m_bSpecScoreboard != spec_scoreboard.GetBool() ) |
|
{ |
|
if ( !spec_scoreboard.GetBool() || !gViewPortInterface->GetActivePanel() ) |
|
{ |
|
m_bSpecScoreboard = spec_scoreboard.GetBool(); |
|
gViewPortInterface->ShowPanel( PANEL_SCOREBOARD, m_bSpecScoreboard ); |
|
} |
|
} |
|
|
|
#ifdef TF_CLIENT_DLL |
|
if ( TFGameRules() && TFGameRules()->ShowMatchSummary() ) |
|
{ |
|
SetVisible( false ); |
|
} |
|
#endif |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: sets the image to display for the banner in the top right corner |
|
//----------------------------------------------------------------------------- |
|
void CSpectatorGUI::SetLogoImage(const char *image) |
|
{ |
|
if ( m_pBannerImage ) |
|
{ |
|
m_pBannerImage->SetImage( scheme()->GetImage(image, false) ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Sets the text of a control by name |
|
//----------------------------------------------------------------------------- |
|
void CSpectatorGUI::SetLabelText(const char *textEntryName, const char *text) |
|
{ |
|
Label *entry = dynamic_cast<Label *>(FindChildByName(textEntryName)); |
|
if (entry) |
|
{ |
|
entry->SetText(text); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Sets the text of a control by name |
|
//----------------------------------------------------------------------------- |
|
void CSpectatorGUI::SetLabelText(const char *textEntryName, wchar_t *text) |
|
{ |
|
Label *entry = dynamic_cast<Label *>(FindChildByName(textEntryName)); |
|
if (entry) |
|
{ |
|
entry->SetText(text); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Sets the text of a control by name |
|
//----------------------------------------------------------------------------- |
|
void CSpectatorGUI::MoveLabelToFront(const char *textEntryName) |
|
{ |
|
Label *entry = dynamic_cast<Label *>(FindChildByName(textEntryName)); |
|
if (entry) |
|
{ |
|
entry->MoveToFront(); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: shows/hides the buy menu |
|
//----------------------------------------------------------------------------- |
|
void CSpectatorGUI::ShowPanel(bool bShow) |
|
{ |
|
if ( bShow && !IsVisible() ) |
|
{ |
|
InvalidateLayout( true, true ); |
|
m_bSpecScoreboard = false; |
|
} |
|
|
|
SetVisible( bShow ); |
|
|
|
if ( !bShow && m_bSpecScoreboard ) |
|
{ |
|
gViewPortInterface->ShowPanel( PANEL_SCOREBOARD, false ); |
|
} |
|
} |
|
|
|
bool CSpectatorGUI::ShouldShowPlayerLabel( int specmode ) |
|
{ |
|
return ( (specmode == OBS_MODE_IN_EYE) || (specmode == OBS_MODE_CHASE) ); |
|
} |
|
//----------------------------------------------------------------------------- |
|
// Purpose: Updates the gui, rearranges elements |
|
//----------------------------------------------------------------------------- |
|
void CSpectatorGUI::Update() |
|
{ |
|
int wide, tall; |
|
int bx, by, bwide, btall; |
|
|
|
GetHudSize(wide, tall); |
|
m_pTopBar->GetBounds( bx, by, bwide, btall ); |
|
|
|
IGameResources *gr = GameResources(); |
|
int specmode = GetSpectatorMode(); |
|
int playernum = GetSpectatorTarget(); |
|
|
|
IViewPortPanel *overview = gViewPortInterface->FindPanelByName( PANEL_OVERVIEW ); |
|
|
|
if ( overview && overview->IsVisible() ) |
|
{ |
|
int mx, my, mwide, mtall; |
|
|
|
VPANEL p = overview->GetVPanel(); |
|
vgui::ipanel()->GetPos( p, mx, my ); |
|
vgui::ipanel()->GetSize( p, mwide, mtall ); |
|
|
|
if ( my < btall ) |
|
{ |
|
// reduce to bar |
|
m_pTopBar->SetSize( wide - (mx + mwide), btall ); |
|
m_pTopBar->SetPos( (mx + mwide), 0 ); |
|
} |
|
else |
|
{ |
|
// full top bar |
|
m_pTopBar->SetSize( wide , btall ); |
|
m_pTopBar->SetPos( 0, 0 ); |
|
} |
|
} |
|
else |
|
{ |
|
// full top bar |
|
m_pTopBar->SetSize( wide , btall ); // change width, keep height |
|
m_pTopBar->SetPos( 0, 0 ); |
|
} |
|
|
|
m_pPlayerLabel->SetVisible( ShouldShowPlayerLabel(specmode) ); |
|
|
|
// update player name filed, text & color |
|
|
|
if ( playernum > 0 && playernum <= gpGlobals->maxClients && gr ) |
|
{ |
|
Color c = gr->GetTeamColor( gr->GetTeam(playernum) ); // Player's team color |
|
|
|
m_pPlayerLabel->SetFgColor( c ); |
|
|
|
wchar_t playerText[ 80 ], playerName[ 64 ], health[ 10 ]; |
|
V_wcsncpy( playerText, L"Unable to find #Spec_PlayerItem*", sizeof( playerText ) ); |
|
memset( playerName, 0x0, sizeof( playerName ) ); |
|
|
|
g_pVGuiLocalize->ConvertANSIToUnicode( UTIL_SafeName(gr->GetPlayerName( playernum )), playerName, sizeof( playerName ) ); |
|
int iHealth = gr->GetHealth( playernum ); |
|
if ( iHealth > 0 && gr->IsAlive(playernum) ) |
|
{ |
|
_snwprintf( health, ARRAYSIZE( health ), L"%i", iHealth ); |
|
g_pVGuiLocalize->ConstructString_safe( playerText, g_pVGuiLocalize->Find( "#Spec_PlayerItem_Team" ), 2, playerName, health ); |
|
} |
|
else |
|
{ |
|
g_pVGuiLocalize->ConstructString_safe( playerText, g_pVGuiLocalize->Find( "#Spec_PlayerItem" ), 1, playerName ); |
|
} |
|
|
|
m_pPlayerLabel->SetText( playerText ); |
|
} |
|
else |
|
{ |
|
m_pPlayerLabel->SetText( L"" ); |
|
} |
|
|
|
// update extra info field |
|
wchar_t szEtxraInfo[1024]; |
|
wchar_t szTitleLabel[1024]; |
|
char tempstr[128]; |
|
|
|
if ( engine->IsHLTV() ) |
|
{ |
|
// set spectator number and HLTV title |
|
Q_snprintf(tempstr,sizeof(tempstr),"Spectators : %d", HLTVCamera()->GetNumSpectators() ); |
|
g_pVGuiLocalize->ConvertANSIToUnicode(tempstr,szEtxraInfo,sizeof(szEtxraInfo)); |
|
|
|
Q_strncpy( tempstr, HLTVCamera()->GetTitleText(), sizeof(tempstr) ); |
|
g_pVGuiLocalize->ConvertANSIToUnicode(tempstr,szTitleLabel,sizeof(szTitleLabel)); |
|
} |
|
else |
|
{ |
|
// otherwise show map name |
|
Q_FileBase( engine->GetLevelName(), tempstr, sizeof(tempstr) ); |
|
|
|
wchar_t wMapName[64]; |
|
g_pVGuiLocalize->ConvertANSIToUnicode(tempstr,wMapName,sizeof(wMapName)); |
|
g_pVGuiLocalize->ConstructString_safe( szEtxraInfo, g_pVGuiLocalize->Find("#Spec_Map" ),1, wMapName ); |
|
|
|
g_pVGuiLocalize->ConvertANSIToUnicode( "" ,szTitleLabel,sizeof(szTitleLabel)); |
|
} |
|
|
|
SetLabelText("extrainfo", szEtxraInfo ); |
|
SetLabelText("titlelabel", szTitleLabel ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Gets the res file we should use (depends on if we're in Steam Controller mode) |
|
//----------------------------------------------------------------------------- |
|
const char * CSpectatorGUI::GetResFile( void ) |
|
{ |
|
if ( ::input->IsSteamControllerActive() ) |
|
{ |
|
return "Resource/UI/Spectator_SC.res"; |
|
} |
|
else |
|
{ |
|
return "Resource/UI/Spectator.res"; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Updates the timer label if one exists |
|
//----------------------------------------------------------------------------- |
|
void CSpectatorGUI::UpdateTimer() |
|
{ |
|
wchar_t szText[ 63 ]; |
|
|
|
int timer = 0; |
|
|
|
V_swprintf_safe ( szText, L"%d:%02d\n", (timer / 60), (timer % 60) ); |
|
|
|
SetLabelText("timerlabel", szText ); |
|
} |
|
|
|
static void ForwardSpecCmdToServer( const CCommand &args ) |
|
{ |
|
if ( engine->IsPlayingDemo() ) |
|
return; |
|
|
|
if ( args.ArgC() == 1 ) |
|
{ |
|
// just forward the command without parameters |
|
engine->ServerCmd( args[ 0 ] ); |
|
} |
|
else if ( args.ArgC() == 2 ) |
|
{ |
|
// forward the command with parameter |
|
// XXX(JohnS): Whyyyyy |
|
char command[128]; |
|
Q_snprintf( command, sizeof(command), "%s \"%s\"", args[ 0 ], args[ 1 ] ); |
|
engine->ServerCmd( command ); |
|
} |
|
} |
|
|
|
CON_COMMAND_F( spec_next, "Spectate next player", FCVAR_CLIENTCMD_CAN_EXECUTE ) |
|
{ |
|
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); |
|
|
|
if ( !pPlayer || !pPlayer->IsObserver() ) |
|
return; |
|
|
|
if ( engine->IsHLTV() ) |
|
{ |
|
// handle the command clientside |
|
if ( !HLTVCamera()->IsPVSLocked() ) |
|
{ |
|
HLTVCamera()->SpecNextPlayer( false ); |
|
} |
|
} |
|
else |
|
{ |
|
ForwardSpecCmdToServer( args ); |
|
} |
|
} |
|
|
|
CON_COMMAND_F( spec_prev, "Spectate previous player", FCVAR_CLIENTCMD_CAN_EXECUTE ) |
|
{ |
|
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); |
|
|
|
if ( !pPlayer || !pPlayer->IsObserver() ) |
|
return; |
|
|
|
if ( engine->IsHLTV() ) |
|
{ |
|
// handle the command clientside |
|
if ( !HLTVCamera()->IsPVSLocked() ) |
|
{ |
|
HLTVCamera()->SpecNextPlayer( true ); |
|
} |
|
} |
|
else |
|
{ |
|
ForwardSpecCmdToServer( args ); |
|
} |
|
} |
|
|
|
CON_COMMAND_F( spec_mode, "Set spectator mode", FCVAR_CLIENTCMD_CAN_EXECUTE ) |
|
{ |
|
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); |
|
|
|
if ( !pPlayer || !pPlayer->IsObserver() ) |
|
return; |
|
|
|
if ( engine->IsHLTV() ) |
|
{ |
|
if ( HLTVCamera()->IsPVSLocked() ) |
|
{ |
|
// in locked mode we can only switch between first and 3rd person |
|
HLTVCamera()->ToggleChaseAsFirstPerson(); |
|
} |
|
else |
|
{ |
|
// we can choose any mode, not loked to PVS |
|
int mode; |
|
|
|
if ( args.ArgC() == 2 ) |
|
{ |
|
// set specifc mode |
|
mode = Q_atoi( args[1] ); |
|
} |
|
else |
|
{ |
|
// set next mode |
|
mode = HLTVCamera()->GetMode()+1; |
|
|
|
if ( mode > LAST_PLAYER_OBSERVERMODE ) |
|
mode = OBS_MODE_IN_EYE; |
|
else if ( mode == OBS_MODE_POI ) // PASSTIME skip POI mode since hltv doesn't have the entity data required to make it work |
|
mode = OBS_MODE_ROAMING; |
|
} |
|
|
|
// handle the command clientside |
|
HLTVCamera()->SetMode( mode ); |
|
} |
|
|
|
// turn off auto director once user tried to change view settings |
|
HLTVCamera()->SetAutoDirector( false ); |
|
} |
|
else |
|
{ |
|
// we spectate on a game server, forward command |
|
ForwardSpecCmdToServer( args ); |
|
} |
|
} |
|
|
|
CON_COMMAND_F( spec_player, "Spectate player by partial name, steamid, or userid", FCVAR_CLIENTCMD_CAN_EXECUTE ) |
|
{ |
|
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); |
|
|
|
if ( !pPlayer || !pPlayer->IsObserver() ) |
|
return; |
|
|
|
if ( args.ArgC() != 2 ) |
|
{ |
|
ConMsg( "Usage: spec_player { steamid | #userid | partial name match }\n" ); |
|
return; |
|
} |
|
|
|
if ( engine->IsHLTV() ) |
|
{ |
|
// we can only switch primary spectator targets is PVS isnt locked by auto-director |
|
if ( !HLTVCamera()->IsPVSLocked() ) |
|
{ |
|
HLTVCamera()->SpecPlayerByPredicate( args[1] ); |
|
} |
|
} |
|
else |
|
{ |
|
ForwardSpecCmdToServer( args ); |
|
} |
|
} |
|
|
|
|
|
|
|
|