summaryrefslogtreecommitdiff
path: root/game/client/tf2/hud_minimap.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/client/tf2/hud_minimap.cpp')
-rw-r--r--game/client/tf2/hud_minimap.cpp1367
1 files changed, 1367 insertions, 0 deletions
diff --git a/game/client/tf2/hud_minimap.cpp b/game/client/tf2/hud_minimap.cpp
new file mode 100644
index 0000000..dded27a
--- /dev/null
+++ b/game/client/tf2/hud_minimap.cpp
@@ -0,0 +1,1367 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud_minimap.h"
+#include <vgui_controls/Controls.h>
+#include <vgui/ISurface.h>
+#include <vgui/IVGui.h>
+#include <vgui/IInput.h>
+#include <vgui_controls/AnimationController.h>
+#include "vgui_bitmapimage.h"
+#include "clientmode_tfbase.h"
+#include "clientmode_tfnormal.h"
+#include "hud.h"
+#include "hud_commander_statuspanel.h"
+#include "view.h"
+#include "filesystem.h"
+#include "imessagechars.h"
+#include "hud_macros.h"
+#include "c_tfteam.h"
+#include "c_info_act.h"
+#include "engine/IEngineSound.h"
+#include "iinput.h"
+#include "in_buttons.h"
+#include "c_basetfplayer.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+static ConVar minimap_visible( "minimap_visible", "1", 0, "Draw minimap?" );
+ConVar minimap_zoomtime( "minimap_zoomtime", "0.4", 0, "How long it takes to resize the minimap." );
+
+
+static ConVar current_team( "current_team", "-1", 0 );
+
+// Start out new maps at this zoom level
+#define DEFAULT_ZOOM_LEVEL 0
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Instantiate a temporary trace (position based, or entity based)
+//-----------------------------------------------------------------------------
+void MinimapCreateTempTrace( const char* pMetaClassName, int sortOrder, const Vector &vecPosition )
+{
+ MinimapInitData_t initData;
+ initData.m_vecPosition = vecPosition;
+
+ PanelMetaClassMgr()->CreatePanelMetaClass(
+ pMetaClassName, sortOrder, &initData, CMinimapPanel::MinimapRootPanel() );
+}
+
+void MinimapCreateTempTrace( const char* pMetaClassName, int sortOrder, C_BaseEntity *pEntity, const Vector &vecOffset )
+{
+ MinimapInitData_t initData;
+ initData.m_pEntity = pEntity;
+ initData.m_vecPosition = vecOffset;
+
+ PanelMetaClassMgr()->CreatePanelMetaClass(
+ pMetaClassName, sortOrder, &initData, CMinimapPanel::MinimapRootPanel() );
+}
+
+//-----------------------------------------------------------------------------
+// dummy root panel for all minimap traces
+//-----------------------------------------------------------------------------
+class CMinimapRootPanel : public Panel
+{
+ typedef Panel BaseClass;
+
+public:
+ CMinimapRootPanel( Panel *pParent = NULL )
+ : BaseClass( pParent,"CMinimapRootPanel" )
+ {
+ SetPaintBackgroundEnabled( false );
+ SetPaintEnabled( false );
+ SetAutoDelete( false );
+ }
+};
+
+class CTextHelpPanel : public vgui::Panel
+{
+ DECLARE_CLASS_SIMPLE( CTextHelpPanel, vgui::Panel )
+
+public:
+
+ CTextHelpPanel();
+
+ virtual void Paint();
+ virtual void PaintBackground();
+
+ void SetImage( BitmapImage *image );
+
+ virtual void ApplySettings( KeyValues *inResourceData )
+ {
+ BaseClass::ApplySettings( inResourceData );
+ }
+
+private:
+
+ BitmapImage *m_pImage;
+
+ CPanelAnimationVar( Color, m_OverlayColor, "OverlayColor", "White" );
+ CPanelAnimationVar( Color, m_BorderColor, "BorderColor", "BrightFg" );
+ CPanelAnimationVar( Color, m_BackgroundColor, "BackgroundColor", "Black" );
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTextHelpPanel::CTextHelpPanel()
+: BaseClass( NULL, "HudMinimapTextHelpPanel" )
+{
+ Panel *pParent = g_pClientMode->GetViewport();
+ SetParent( pParent );
+
+ SetVisible( false );
+ SetZPos( 1 );
+
+ m_pImage = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTextHelpPanel::PaintBackground()
+{
+ // Get alpha from image
+ if ( m_pImage )
+ {
+ Color bg = m_BackgroundColor;
+ int r, g, b, a;
+ m_pImage->GetColor( r, g, b, a );
+ bg[3] = a;
+ SetBgColor( bg );
+
+ BaseClass::PaintBackground();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTextHelpPanel::Paint()
+{
+ BaseClass::Paint();
+
+ if ( !m_pImage )
+ return;
+
+ m_pImage->SetColor( m_OverlayColor );
+ m_pImage->DoPaint( GetVPanel() );
+
+ int w, h;
+ GetSize( w, h );
+
+ surface()->DrawSetColor( m_BorderColor );
+ surface()->DrawOutlinedRect( 0, 0, w, h );
+ surface()->DrawOutlinedRect( 1, 1, w-1, h-1 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *image -
+// x -
+// y -
+// w -
+// h -
+//-----------------------------------------------------------------------------
+void CTextHelpPanel::SetImage( BitmapImage *image )
+{
+ m_pImage = image;
+}
+
+//-----------------------------------------------------------------------------
+// globals
+//-----------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+// All traces are children of this panel
+//-----------------------------------------------------------------------------
+Panel *CMinimapPanel::MinimapRootPanel()
+{
+ static CMinimapRootPanel s_MinimapRootPanel;
+ return &s_MinimapRootPanel;
+}
+
+CMinimapPanel *CMinimapPanel::MinimapPanel()
+{
+ ClientModeTFBase *pBasemode = ( ClientModeTFBase * )g_pClientMode;
+ if ( !pBasemode )
+ return NULL;
+
+ return pBasemode->GetMinimap();
+}
+
+DECLARE_HUDELEMENT( CMinimapPanel );
+DECLARE_HUD_MESSAGE( CMinimapPanel, MinimapPulse );
+
+//-----------------------------------------------------------------------------
+// Purpose: Placeholder for small overview map with viewport rectangle/selector
+//-----------------------------------------------------------------------------
+CMinimapPanel::CMinimapPanel( const char *pElementName )
+: CHudElement( pElementName ), BaseClass( NULL, "HudMinimap" )
+{
+ Panel *pParent = g_pClientMode->GetViewport();
+ SetParent( pParent );
+
+ SetAutoDelete( false );
+ for ( int i = 0; i < MAX_ACT_TEAMS; i++ )
+ {
+ m_pBackground[ i ] = 0;
+ }
+ memset( m_rgOverlays, 0, sizeof( m_rgOverlays ) );
+
+ m_flExpansionFrac = 0.0f;
+
+ // Minimap zoom
+ m_bMinimapZoomed = false;
+ m_nZoomLevel = DEFAULT_ZOOM_LEVEL;
+
+ m_vecCurrentOrigin.Init();
+ m_vecMapCenter.Init();
+ m_flMapAspectRatio = 1.0f;
+ m_flViewportAspectRatio = 1.0f;
+ m_flAspectAdjustment = 1.0f;
+ m_flNormalizedXScale = 1.0f;
+ m_flNormalizedYScale = 1.0f;
+ m_flNormalizedXOffset = 0.0f;
+ m_flNormalizedYOffset = 0.0f;
+
+ m_nCurrentAct = ACT_NONE_SPECIFIED;
+
+ m_pTextPanel = new CTextHelpPanel();
+ m_pBackgroundPanel = new Panel( NULL, "BackgroundPanel" );
+
+ // We're gonna manage the lifetime of the text panel
+ // since we change it's hierarchical connections from time to time
+ m_pTextPanel->SetAutoDelete( false );
+ m_pBackgroundPanel->SetAutoDelete( false );
+ SetAutoDelete( false );
+
+ m_pClient = NULL;
+
+ m_flZoomAdjust = 1.0f;
+ m_flPrevZoomAmount = 0.01f;
+
+ SetZPos( 10 );
+
+ ivgui()->AddTickSignal( GetVPanel() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CMinimapPanel::~CMinimapPanel( void )
+{
+ delete m_pTextPanel;
+ delete m_pBackgroundPanel;
+
+ for ( int i = 0; i < MAX_ACT_TEAMS; i++ )
+ {
+ delete m_pBackground[ i ];
+ }
+
+ ShutdownOverlays();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *scheme -
+//-----------------------------------------------------------------------------
+void CMinimapPanel::ApplySchemeSettings( IScheme *scheme )
+{
+ BaseClass::ApplySchemeSettings( scheme );
+ SetPaintBackgroundEnabled( false );
+}
+
+
+//-----------------------------------------------------------------------------
+// initialization
+//-----------------------------------------------------------------------------
+void CMinimapPanel::Init( IMinimapClient* pClient )
+{
+ m_pClient = pClient;
+}
+
+//-----------------------------------------------------------------------------
+// Call this when the minimap panel is going to be drawn...
+//-----------------------------------------------------------------------------
+void CMinimapPanel::Activate()
+{
+ // The panel is a view into the minimap root panel
+ MinimapRootPanel()->SetParent( this );
+
+ Panel *pParent = g_pClientMode->GetViewport();
+
+ if ( pParent && m_pBackgroundPanel )
+ {
+ m_pBackgroundPanel->SetParent( pParent );
+ m_pBackgroundPanel->SetBounds( XRES( 0 ), YRES( 0 ), XRES( 640 ), YRES( 480 ) );
+ m_pBackgroundPanel->SetVisible( false );
+ m_pBackgroundPanel->SetZPos( 0 );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : w -
+// h -
+//-----------------------------------------------------------------------------
+void CMinimapPanel::OnSizeChanged( int w, int h )
+{
+ BaseClass::OnSizeChanged( w, h );
+
+ MinimapRootPanel()->SetSize( w, h );
+
+ // Make sure icons are snapped to current window size
+ InvokeOnTickOnChildren( this );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : float
+//-----------------------------------------------------------------------------
+float CMinimapPanel::GetAdjustedZoom( void )
+{
+ return m_flZoomAmount * m_flZoomAdjust;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : float
+//-----------------------------------------------------------------------------
+float CMinimapPanel::GetTrueZoom()
+{
+ return m_flZoomAmount;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : center -
+// scale -
+//-----------------------------------------------------------------------------
+void CMinimapPanel::GetMapOriginAndScale( Vector& origin, float& scale )
+{
+ origin = m_vecCurrentOrigin;
+ scale = GetAdjustedZoom();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : clip -
+// pos -
+// outx -
+// outy -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CMinimapPanel::WorldToMinimap( MinimapPosType_t posType, const Vector& pos, float& outx, float& outy )
+{
+ Vector origin;
+ float zoomscale;
+
+ GetMapOriginAndScale( origin, zoomscale );
+
+ return InternalWorldToMinimap( posType, pos, origin, zoomscale, outx, outy );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : x -
+// y -
+//-----------------------------------------------------------------------------
+void CMinimapPanel::AdjustNormalizedPositionForAspectRatio( float& x, float& y )
+{
+ x = m_flNormalizedXOffset + x * m_flNormalizedXScale;
+ y = m_flNormalizedYOffset + y * m_flNormalizedYScale;
+}
+
+//-----------------------------------------------------------------------------
+// Converts a world-space position to a coordinate in minimap panel space
+//-----------------------------------------------------------------------------
+bool CMinimapPanel::InternalWorldToMinimap( MinimapPosType_t posType, const Vector &pos, const Vector& origin, float zoomscale, float& outx, float& outy )
+{
+ int wide, tall;
+ MinimapRootPanel()->GetSize( wide, tall );
+
+ Vector worldmins, worldmaxs;
+ MapData().GetMapBounds( worldmins, worldmaxs );
+ Vector worldsize = worldmaxs - worldmins;
+
+ Vector test = ( pos - origin );
+
+ float xfraction = 0.0f;
+
+ if ( worldsize.x > 0 )
+ {
+ xfraction = (test.x - worldmins.x) / (worldmaxs.x - worldmins.x);
+ }
+
+ float yfraction = 0.0f;
+
+ if ( worldsize.y > 0 )
+ {
+ yfraction = (test.y - worldmins.y) / (worldmaxs.y - worldmins.y);
+ }
+
+ xfraction = ( xfraction - 0.5f ) * zoomscale + 0.5f;
+ yfraction = ( yfraction - 0.5f ) * zoomscale + 0.5f;
+
+ yfraction = 1.0f - yfraction;
+
+ // Adjust in case not all of map can be shown
+ AdjustNormalizedPositionForAspectRatio( xfraction, yfraction );
+
+ // Normalize?
+ bool inside = true;
+ switch ( posType )
+ {
+ case MINIMAP_CLIP:
+ {
+ // Clip the vector from minimap center to object
+ // to the minimap bounds and put the object on the edge
+ Vector2D delta( xfraction - 0.5f, yfraction - 0.5f );
+ Vector2D fdelta( fabs(delta.x), fabs(delta.y) );
+ if (fdelta.x > fdelta.y)
+ {
+ // It's more horizontal than vertical..
+ if (fdelta.x >= 0.5f)
+ {
+ float flRatio = delta.y / delta.x;
+ xfraction = clamp(xfraction, 0, 1);
+ yfraction = (xfraction - 0.5f) * flRatio + 0.5f;
+ }
+ }
+ else
+ {
+ if (fdelta.y >= 0.5f)
+ {
+ // It's more vertical than horizontal
+ float flRatio = delta.x / delta.y;
+ yfraction = clamp(yfraction, 0, 1);
+ xfraction = (yfraction - 0.5f) * flRatio + 0.5f;
+ }
+ }
+ }
+ break;
+
+ case MINIMAP_CLAMP:
+ {
+ // Clamp the position to lie within the minimap
+ xfraction = clamp(xfraction, 0, 1);
+ yfraction = clamp(yfraction, 0, 1);
+ }
+ break;
+
+ case MINIMAP_NOCLIP:
+ {
+ // See if it's off screen
+ if ( xfraction < 0.0 || xfraction > 1.0 ||
+ yfraction < 0.0 || yfraction > 1.0 )
+ {
+ inside = false;
+ }
+ }
+ break;
+ }
+
+ outx = xfraction * wide;
+ outy = yfraction * tall;
+
+ return inside;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *mapname -
+//-----------------------------------------------------------------------------
+void CMinimapPanel::LevelInit( const char *mapname )
+{
+ SetBackgroundMaterials( MapData().m_Minimap.m_szBackgroundMaterial );
+
+ m_nZoomLevel = DEFAULT_ZOOM_LEVEL;
+
+ HOOK_HUD_MESSAGE( CMinimapPanel, MinimapPulse );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Play a pulse on the minimap
+//-----------------------------------------------------------------------------
+void CMinimapPanel::MsgFunc_MinimapPulse( bf_read &msg )
+{
+ Vector vecPosition;
+ msg.ReadBitVec3Coord( vecPosition );
+ C_TFTeam *pTeam = (C_TFTeam *)GetLocalTeam();
+ if ( pTeam )
+ {
+ pTeam->NotifyBaseUnderAttack( vecPosition, false );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMinimapPanel::LevelShutdown( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Sets the background material
+//-----------------------------------------------------------------------------
+void CMinimapPanel::SetBackgroundMaterials( const char *pMaterialName )
+{
+ int i;
+ for ( i = 0; i < MAX_ACT_TEAMS; i++ )
+ {
+ delete m_pBackground[ i ];
+ m_pBackground[ i ] = NULL;
+ }
+
+ if ( pMaterialName[ 0 ] )
+ {
+ for ( i = 0; i < MAX_ACT_TEAMS; i++ )
+ {
+ char teammaterial[ 512 ];
+
+ Q_snprintf( teammaterial, sizeof( teammaterial ), "%s_team%i",
+ pMaterialName, i + 1 );
+
+ // If a _team# version exists, use that, otherwise, use the default
+ if ( g_pFullFileSystem->FileExists( VarArgs( "materials/%s.vmt", teammaterial ) ) )
+ {
+ m_pBackground[ i ] = new BitmapImage( GetVPanel(), teammaterial );
+ }
+ else
+ {
+ m_pBackground[ i ] = new BitmapImage( GetVPanel(), pMaterialName );
+ }
+ }
+ }
+
+ if ( m_pTextPanel )
+ {
+ m_pTextPanel->SetImage( NULL );
+ }
+
+ ShutdownOverlays();
+ InitOverlays( pMaterialName );
+}
+
+//-----------------------------------------------------------------------------
+// Called when the mouse is hit
+//-----------------------------------------------------------------------------
+void CMinimapPanel::OnMousePressed(MouseCode code)
+{
+ if ((code == MOUSE_LEFT) && m_pClient)
+ {
+ // Convert mouse position to world position
+ int x, y;
+ vgui::input()->GetCursorPos( x, y );
+
+ int w, h;
+ GetSize( w, h );
+
+ Vector worldPos;
+ worldPos.x = (float) x / (float) w;
+ worldPos.y = 1.0f - (float) y / (float) h;
+ worldPos.z = 0; // z isn't used
+
+ Vector worldMins, worldMaxs;
+ MapData().GetMapBounds( worldMins, worldMaxs );
+ worldPos *= (worldMaxs - worldMins);
+ worldPos += worldMins;
+
+ m_pClient->MinimapClicked( worldPos );
+ }
+}
+
+void CMinimapPanel::SetBackgroundViewport( float minx, float miny, float maxx, float maxy, bool includedetails )
+{
+ int i;
+ int x, y, w, h;
+
+ x = 0;
+ y = 0;
+ w = GetWide();
+ h = GetTall();
+
+ if ( minx < 0.0f || maxx > 1.0f ||
+ miny < 0.0f || maxy > 1.0f )
+ {
+ float x0 = 0.0f;
+ float y0 = 0.0f;
+ float x1 = 1.0f;
+ float y1 = 1.0f;
+
+ float xrange = maxx - minx;
+ float yrange = maxy - miny;
+
+ if ( minx < 0.0f )
+ {
+ x0 = -minx / xrange;
+ //xrange += minx;
+ maxx -= minx;
+ minx = 0.0f;
+ }
+ if ( maxx > 1.0f )
+ {
+ x1 = 1.0f - ( maxx - 1.0f ) / xrange;
+ maxx = 1.0f;
+ }
+ if ( miny < 0.0f )
+ {
+ y0 = -miny / yrange;
+ //yrange += miny;
+ maxy -= miny;
+ miny = 0.0f;
+ }
+ if ( maxy > 1.0f )
+ {
+ y1 = 1.0f - ( maxy - 1.0f ) / yrange;
+ maxy = 1.0f;
+ }
+
+ x = x0 * w;
+ y = y0 * h;
+ w = x1 * w;
+ h = y1 * h;
+ }
+
+ for ( i = 0; i < MAX_ACT_TEAMS; i++ )
+ {
+ if ( m_pBackground[ i ] )
+ {
+ m_pBackground[ i ]->SetPos( x, y );
+ m_pBackground[ i ]->SetRenderSize( w, h );
+ m_pBackground[ i ]->SetViewport( true, minx, miny, maxx, maxy );
+ }
+ }
+
+ if ( includedetails )
+ {
+ int t;
+ for ( t = 0; t < MAX_ACT_TEAMS; t++ )
+ {
+ for ( i = 0; i < MAX_ACTS; i++ )
+ {
+ Overlays *p = &m_rgOverlays[ t ][ i ];
+ if ( !p->m_bInUse )
+ continue;
+
+ if ( !p->m_pOverlay )
+ continue;
+
+ p->m_pOverlay->SetPos( x, y );
+ p->m_pOverlay->SetRenderSize( w, h );
+ p->m_pOverlay->SetViewport( true, minx, miny, maxx, maxy );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMinimapPanel::PaintActOverlays( int teamIndex, int alpha )
+{
+ Assert( teamIndex >= 0 && teamIndex < MAX_ACT_TEAMS );
+
+ bool textshowing = false;
+
+ int i = GetCurrentActNumber();
+ if ( i != ACT_NONE_SPECIFIED )
+ {
+ i = clamp( i, 0, MAX_ACTS - 1 );
+ Overlays *p = &m_rgOverlays[ teamIndex ][ i ];
+ if ( p->m_bInUse )
+ {
+ int r, g, b, a;
+
+ if ( p->m_pOverlay )
+ {
+ p->m_pOverlay->GetColor( r, g, b, a );
+ Color clr( r, g, b, alpha );
+ p->m_pOverlay->SetColor( clr );
+ p->m_pOverlay->DoPaint( NULL, 0, (float)alpha/255.0f );
+ }
+
+ if ( p->m_pText && m_pTextPanel )
+ {
+ p->m_pText->GetColor( r, g, b, a );
+ Color clr( r, g, b, alpha );
+ p->m_pText->SetColor( clr );
+
+ m_pTextPanel->SetImage( p->m_pText );
+
+ clr = m_BackgroundColor;
+ clr[3] = alpha;
+ m_pBackgroundPanel->SetBgColor( clr );
+
+ textshowing = true;
+ }
+ }
+ }
+
+ if ( !textshowing )
+ {
+ m_pTextPanel->SetVisible( false );
+ m_pTextPanel->SetImage( NULL );
+ m_pBackgroundPanel->SetVisible( false );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMinimapPanel::OnThink()
+{
+ BaseClass::OnThink();
+
+ C_BaseTFPlayer *local = C_BaseTFPlayer::GetLocalPlayer();
+ if ( local )
+ {
+ if ( local->m_TFLocal.m_bForceMapOverview && m_bMinimapZoomed != local->m_TFLocal.m_bForceMapOverview )
+ {
+ SetMinimapZoom( local->m_TFLocal.m_bForceMapOverview );
+ }
+ }
+
+ if ( !IsVisible() )
+ return;
+
+ if ( m_flZoomAmount != m_flPrevZoomAmount )
+ {
+ m_flPrevZoomAmount = m_flZoomAmount;
+ ComputeMapOrigin( m_vecCurrentOrigin );
+ InvokeOnTickOnChildren( this );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMinimapPanel::Paint()
+{
+ if ( gHUD.IsHidden( HIDEHUD_MISCSTATUS ) )
+ {
+ // Remove the minimap zoom if the hud's hidden
+ SetMinimapZoom( false );
+ return;
+ }
+
+ C_BasePlayer *local = C_BasePlayer::GetLocalPlayer();
+ int team = 0;
+ if ( local )
+ {
+ team = local->GetTeamNumber();
+ }
+
+ int w, h;
+ GetSize( w, h );
+
+ int alpha;
+ bool shouldDrawDetails = ShouldDrawZoomDetails( alpha );
+
+ if ( m_pTextPanel && m_pBackgroundPanel )
+ {
+ m_pTextPanel->SetVisible( shouldDrawDetails );
+ m_pBackgroundPanel->SetVisible( shouldDrawDetails );
+ }
+
+ // DEBUGGING: Allow cvar override
+ if ( current_team.GetInt() >= 0 )
+ {
+ team = current_team.GetInt();
+ }
+
+ // Can can be 0 through MAX_ACT_TEAMS
+ team = clamp( team, 0, MAX_ACT_TEAMS );
+
+ // Array index is 0 to MAX_ACT_TEAMS - 1 where a team of zero means no team and won't be indexed
+ // due to logic that checks team > 0
+ int teamIndex = clamp( team - 1, 0, MAX_ACT_TEAMS - 1 );
+
+ if ( m_pBackground[ teamIndex ] )
+ {
+ if ( shouldDrawDetails )
+ {
+ Color clr = m_BackgroundColor;
+ clr[3] *= alpha / 255.0f;
+ surface()->DrawSetColor( clr );
+ surface()->DrawFilledRect( 0, 0, w, h );
+ }
+
+ float offsetx, offsety;
+
+ // Need to translate m_vecCurrentOrigin into minimap space
+ InternalWorldToMinimap(
+ MINIMAP_NOCLIP,
+ m_vecCurrentOrigin,
+ -m_vecMapCenter,
+ 1,
+ offsetx, offsety );
+
+ // Scale to 0.0f to 1.0f
+ offsetx /= (float)w;
+ offsety /= (float)h;
+
+ float minx, maxx, miny, maxy;
+
+ float xscale = 1.0f;
+ float yscale = 1.0f;
+ float startx = 0.0f;
+ float starty = 0.0f;
+
+ Assert( m_flAspectAdjustment > 0.0f );
+
+ // Note, the scale sense is inverted here
+ float invaspect = 1.0f / m_flAspectAdjustment;
+
+ if ( m_flAspectAdjustment < 1.0f )
+ {
+ xscale = invaspect;
+ startx = ( 1.0f - xscale ) * 0.5f;
+ }
+ else
+ {
+ yscale = m_flAspectAdjustment;
+ starty = ( 1.0f - yscale ) * 0.5f;
+ }
+
+ float halfzoom = ( 1.0f / GetAdjustedZoom() ) * 0.5f;
+
+ // zoom scale is already normalized, so just take half in one direction, half the other
+ minx = startx + xscale * ( offsetx - halfzoom );
+ miny = starty + yscale * ( offsety - halfzoom );
+ maxx = startx + xscale * ( offsetx + halfzoom );
+ maxy = starty + yscale * ( offsety + halfzoom );
+
+ SetBackgroundViewport( minx, miny, maxx, maxy, shouldDrawDetails );
+
+ m_pBackground[ teamIndex ]->DoPaint( NULL );
+
+ if ( shouldDrawDetails && ( team > 0 ) )
+ {
+ PaintActOverlays( teamIndex, alpha );
+ }
+ }
+ else
+ {
+ Color clr = m_BackgroundColor;
+ clr[3] *= alpha * 0.9f / 255.0f;
+
+ surface()->DrawSetColor( clr );
+ surface()->DrawFilledRect( 0, 0, w, h );
+ }
+
+ // Dumb place to do this
+ if ( !shouldDrawDetails && CurrentActIsAWaitingAct() )
+ {
+ char *cmsg = "Wait for game start...";
+ int width, height;
+ messagechars->GetStringLength( g_hFontTrebuchet24, &width, &height, cmsg );
+ messagechars->DrawString( g_hFontTrebuchet24, XRES(16), ScreenHeight() - (height * 6), 255, 255, 245, 255, cmsg, IMessageChars::MESSAGESTRINGID_NONE );
+ }
+
+ Color border = m_BorderColor;
+ border[3] = border[3] * ( alpha * 0.9f ) / 255.0f;
+
+ //border = vgui::Color( 255, 0, 120, 255 );
+
+ surface()->DrawSetColor( border );
+ surface()->DrawOutlinedRect( 0, 0, w, h );
+ surface()->DrawOutlinedRect( 1, 1, w-1, h-1 );
+}
+
+void CMinimapPanel::InvokeOnTickOnChildren( vgui::Panel *parent )
+{
+ if ( !parent )
+ return;
+
+ int c = parent->GetChildCount();
+ int i;
+ for ( i = 0; i < c; i++ )
+ {
+ vgui::Panel *child = parent->GetChild( i );
+ child->OnTick();
+ InvokeOnTickOnChildren( child );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMinimapPanel::OnTick()
+{
+ // See if the act's changed. If it has, bring up the act overlays.
+ if ( m_nCurrentAct != GetCurrentActNumber() )
+ {
+ // g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "MinimapActChanged" );
+ // SetMinimapZoom( true );
+ m_nCurrentAct = GetCurrentActNumber();
+ }
+
+ // Cache these only once per frame if in a valid game
+ if ( C_BasePlayer::GetLocalPlayer() && minimap_visible.GetBool() )
+ {
+ SetVisible( true );
+ ComputeMapOrigin( m_vecCurrentOrigin );
+ }
+ else
+ {
+ SetVisible( false );
+ }
+
+ InvokeOnTickOnChildren( this );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : alpha -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CMinimapPanel::ShouldDrawZoomDetails( int& alpha )
+{
+ alpha = (int)m_flDetailsAlpha;
+ alpha = clamp( alpha, 0, 255 );
+
+ if ( !alpha )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : center -
+//-----------------------------------------------------------------------------
+void CMinimapPanel::ComputeMapOrigin( Vector& origin )
+{
+ Vector worldmins, worldmaxs, worldsize;
+ MapData().GetMapBounds( worldmins, worldmaxs );
+ VectorSubtract( worldmaxs, worldmins, worldsize );
+
+ // Cache true map center
+ m_vecMapCenter = ( worldmins + worldmaxs ) * 0.5f;
+
+ C_BasePlayer* pPlayer = C_BasePlayer::GetLocalPlayer();
+
+ Vector playerOrigin;
+
+ if( !pPlayer )
+ {
+ playerOrigin = m_vecMapCenter;
+ }
+ else
+ {
+ playerOrigin = pPlayer->GetAbsOrigin();
+ }
+
+ origin.Init();
+
+ playerOrigin.z = m_vecMapCenter.z = 0.0f;
+
+ Vector delta = playerOrigin - m_vecMapCenter;
+
+ // Map center pointer is biased toward player origin as we become zoomed in to 1.0x to 2.5x and toward true world center as we zoom all the way out
+ VectorScale( delta, m_flCenterOnPlayer, origin );
+
+ int vw, vh;
+ GetSize( vw, vh );
+
+ m_flMapAspectRatio = 1.0f;
+ m_flViewportAspectRatio = 1.0f;
+ m_flAspectAdjustment = 1.0f;
+
+ if ( vh > 0 )
+ {
+ m_flViewportAspectRatio = ( float )vw / ( float )vh;
+ }
+
+ if ( worldsize.y > 0 )
+ {
+ m_flMapAspectRatio = worldsize.x / worldsize.y;
+ }
+
+ if ( m_flViewportAspectRatio > 0 )
+ {
+ m_flAspectAdjustment = m_flMapAspectRatio / m_flViewportAspectRatio;
+ }
+
+ float fittedworldunitsperpixel;
+ float zoomedworldunitsperpixel;
+ float zooomedoutworldunitsperpixel;
+ float actualworldunitsperpixel;
+
+ if ( m_flAspectAdjustment > 1.0f )
+ {
+ // World height fits exactly in minimap height at zoom 1x
+ fittedworldunitsperpixel = worldsize.y / (float)( vh );
+
+ // At higher zoom we get less world units per pixel
+ zoomedworldunitsperpixel = fittedworldunitsperpixel / m_flZoomAmount;
+
+ // at fully zoomed back view, world width fits window width instead
+ zooomedoutworldunitsperpixel = worldsize.x / (float)( vw );
+
+ // As we center more on player, we move away from zoomed out units and toward zoomed units per pixel
+ actualworldunitsperpixel = zooomedoutworldunitsperpixel + m_flCenterOnPlayer * ( zoomedworldunitsperpixel - zooomedoutworldunitsperpixel );
+
+ m_flZoomAdjust = (1-m_flCenterOnPlayer) + m_flCenterOnPlayer * ( 1/m_flViewportAspectRatio );
+ }
+ else
+ {
+ // World width fits exactly in minimap width at zoom 1x
+ fittedworldunitsperpixel = worldsize.x / (float)( vw );
+
+ // At higher zoom we get less world units per pixel
+ zoomedworldunitsperpixel = fittedworldunitsperpixel / m_flZoomAmount;
+
+ // at fully zoomed back view, world height fits window height instead
+ zooomedoutworldunitsperpixel = worldsize.y / (float)( vh );
+
+ // As we center more on player, we move away from zoomed out units and toward zoomed units per pixel
+ actualworldunitsperpixel = zooomedoutworldunitsperpixel + m_flCenterOnPlayer * ( zoomedworldunitsperpixel - zooomedoutworldunitsperpixel );
+
+ m_flZoomAdjust = (1-m_flCenterOnPlayer) + m_flCenterOnPlayer * ( 1/m_flAspectAdjustment );
+ }
+
+ Vector preOrigin = origin;
+
+ float inset_pixels = m_flInsetPixels;
+
+ float viewport_width_world_units = ( float )( vw - 2 * inset_pixels ) * actualworldunitsperpixel;
+ float viewport_height_world_units = ( float )( vh - 2 * inset_pixels ) * actualworldunitsperpixel;
+
+ // Insets apply when centering on player
+ m_flWorldSpaceInsets[ 0 ] = MIN( m_vecMapCenter.x, worldmins.x + m_flCenterOnPlayer * ( viewport_width_world_units ) * 0.5f );
+ m_flWorldSpaceInsets[ 1 ] = MIN( m_vecMapCenter.y, worldmins.y + m_flCenterOnPlayer * ( viewport_height_world_units ) * 0.5f );
+ m_flWorldSpaceInsets[ 2 ] = MAX( m_vecMapCenter.x, worldmaxs.x - m_flCenterOnPlayer * ( viewport_width_world_units ) * 0.5f );
+ m_flWorldSpaceInsets[ 3 ] = MAX( m_vecMapCenter.y, worldmaxs.y - m_flCenterOnPlayer * ( viewport_height_world_units ) * 0.5f );
+
+ // Assuming origin is at center of view, compute world space left, top, right, bottom
+ m_flWorldSpaceBounds[ 0 ] = m_vecMapCenter.x + origin.x - viewport_width_world_units * 0.5f;
+ m_flWorldSpaceBounds[ 1 ] = m_vecMapCenter.y + origin.y - viewport_height_world_units * 0.5f;
+ m_flWorldSpaceBounds[ 2 ] = m_vecMapCenter.x + origin.x + viewport_width_world_units * 0.5f;
+ m_flWorldSpaceBounds[ 3 ] = m_vecMapCenter.y + origin.y + viewport_height_world_units * 0.5f;
+
+ // Clip these bounds
+ m_flClippedWorldSpaceBounds[ 0 ] = MAX( worldmins.x, m_flWorldSpaceBounds[ 0 ] );
+ m_flClippedWorldSpaceBounds[ 1 ] = MAX( worldmins.y, m_flWorldSpaceBounds[ 1 ] );
+ m_flClippedWorldSpaceBounds[ 2 ] = MIN( worldmaxs.x, m_flWorldSpaceBounds[ 2 ] );
+ m_flClippedWorldSpaceBounds[ 3 ] = MIN( worldmaxs.y, m_flWorldSpaceBounds[ 3 ] );
+
+ // Clip origin to inserts
+ origin.x = clamp( origin.x, m_flWorldSpaceInsets[ 0 ] - m_vecMapCenter.x, m_flWorldSpaceInsets[ 2 ] - m_vecMapCenter.x );
+ origin.y = clamp( origin.y, m_flWorldSpaceInsets[ 1 ] - m_vecMapCenter.y, m_flWorldSpaceInsets[ 3 ] - m_vecMapCenter.y );
+
+ /*
+ engine->Con_NPrintf( 1, "map bounds left %i top %i right %i bottom %i",
+ (int)worldmins.x,
+ (int)worldmins.y,
+ (int)worldmaxs.x,
+ (int)worldmaxs.y );
+
+ engine->Con_NPrintf( 2, "world space bounds left %i top %i right %i bottom %i",
+ (int)m_flWorldSpaceBounds[ 0 ],
+ (int)m_flWorldSpaceBounds[ 1 ],
+ (int)m_flWorldSpaceBounds[ 2 ],
+ (int)m_flWorldSpaceBounds[ 3 ] );
+
+ engine->Con_NPrintf( 3, "world space insets left %i top %i right %i bottom %i",
+ (int)m_flWorldSpaceInsets[ 0 ],
+ (int)m_flWorldSpaceInsets[ 1 ],
+ (int)m_flWorldSpaceInsets[ 2 ],
+ (int)m_flWorldSpaceInsets[ 3 ] );
+
+ engine->Con_NPrintf( 4, "world space clipping left %i top %i right %i bottom %i",
+ (int)m_flClippedWorldSpaceBounds[ 0 ],
+ (int)m_flClippedWorldSpaceBounds[ 1 ],
+ (int)m_flClippedWorldSpaceBounds[ 2 ],
+ (int)m_flClippedWorldSpaceBounds[ 3 ] );
+
+
+ engine->Con_NPrintf( 5, "world center %i %i",
+ (int)m_vecMapCenter.x, (int)m_vecMapCenter.y );
+
+ engine->Con_NPrintf( 6, "player origin %i %i",
+ (int)playerOrigin.x, (int)playerOrigin.y );
+
+ engine->Con_NPrintf( 7, "desired map center %i %i",
+ (int)( m_vecMapCenter.x + preOrigin.x ), (int)( preOrigin.y + m_vecMapCenter.x ) );
+
+ engine->Con_NPrintf( 8, "actual map center %i %i",
+ (int)( m_vecMapCenter.x + origin.x ), (int)( origin.y + m_vecMapCenter.y ) );
+
+ engine->Con_NPrintf( 9, "viewport (%ix%i) aspect %.2f world (%ix%i) aspect %f",
+ vw, vh, m_flViewportAspectRatio, (int)worldsize.x, (int)worldsize.y, m_flMapAspectRatio );
+
+ engine->Con_NPrintf( 10, "zoom %.3f zoom adjust %.3f",
+ m_flZoomAmount, m_flZoomAdjust );
+
+ engine->Con_NPrintf( 11, "viewport %i x %i",
+ (int)viewport_width_world_units, (int)viewport_height_world_units );
+ */
+
+ // Assume 100% scale and no x or y offset to make up for aspect ration diff
+ m_flNormalizedXScale = 1.0f;
+ m_flNormalizedYScale = 1.0f;
+ m_flNormalizedXOffset = 0.0f;
+ m_flNormalizedYOffset = 0.0f;
+
+ if ( m_flAspectAdjustment < 1.0f )
+ {
+ m_flNormalizedXScale = m_flAspectAdjustment;
+ // Offset 0->1 version of x value
+ m_flNormalizedXOffset = ( 1.0f - m_flNormalizedXScale ) * 0.5f;
+ }
+ else
+ {
+ m_flNormalizedYScale = 1.0f / m_flAspectAdjustment;
+ // Offset 0->1 version of y value
+ m_flNormalizedYOffset = ( 1.0f - m_flNormalizedYScale ) * 0.5f;
+ }
+}
+
+void CMinimapPanel::InitOverlays( const char *materialrootname )
+{
+ if ( !materialrootname || !materialrootname[0] )
+ return;
+
+ int t;
+ for ( t = 0; t < MAX_ACT_TEAMS; t++ )
+ {
+ char teamnum[ 2 ];
+ Q_snprintf( teamnum, sizeof( teamnum ), "%01i", t + 1 );
+
+ int i;
+ for ( i = 0; i < MAX_ACTS; i++ )
+ {
+ char actnum[ 3 ];
+
+ char filename[ 512 ];
+
+ Q_snprintf( actnum, sizeof( actnum ), "%02i", i );
+
+ Overlays *p = &m_rgOverlays[ t ][ i ];
+ Assert( p && !p->m_bInUse );
+
+ Q_snprintf( filename, sizeof( filename ), "%s_act%s_overlay_team%s",
+ materialrootname, actnum, teamnum );
+
+ // Check if file exists
+ if ( g_pFullFileSystem->FileExists( VarArgs( "materials/%s.vmt", filename ) ) )
+ {
+ p->m_pOverlay = new BitmapImage( GetVPanel(), filename );
+ p->m_bInUse = true;
+ }
+ else
+ {
+ // Try it without the team number
+ Q_snprintf( filename, sizeof( filename ), "%s_act%s_overlay",
+ materialrootname, actnum );
+
+ if ( g_pFullFileSystem->FileExists( VarArgs( "materials/%s.vmt", filename ) ) )
+ {
+ p->m_pOverlay = new BitmapImage( GetVPanel(), filename );
+ p->m_bInUse = true;
+ }
+ }
+
+ Q_snprintf( filename, sizeof( filename ), "%s_act%s_text_team%s",
+ materialrootname, actnum, teamnum );
+
+ // Check if file exists
+ if ( g_pFullFileSystem->FileExists( VarArgs( "materials/%s.vmt", filename ) ) )
+ {
+ p->m_pText = new BitmapImage( GetTextPaintPanel()->GetVPanel(), filename );
+ p->m_bInUse = true;
+ }
+ else
+ {
+ // Try it without the team number
+ Q_snprintf( filename, sizeof( filename ), "%s_act%s_text",
+ materialrootname, actnum );
+
+ // Check if file exists
+ if ( g_pFullFileSystem->FileExists( VarArgs( "materials/%s.vmt", filename ) ) )
+ {
+ p->m_pText = new BitmapImage( GetTextPaintPanel()->GetVPanel(), filename );
+ p->m_bInUse = true;
+ }
+ }
+ }
+ }
+}
+
+void CMinimapPanel::ShutdownOverlays( void )
+{
+ int t;
+ for ( t = 0; t < MAX_ACT_TEAMS; t++ )
+ {
+
+ int i;
+ for ( i = 0; i < MAX_ACTS; i++ )
+ {
+ Overlays *p = &m_rgOverlays[ t ][ i ];
+ Assert( p );
+ if ( !p->m_bInUse )
+ continue;
+
+ delete p->m_pOverlay;
+ delete p->m_pText;
+ p->m_bInUse = false;
+ p->m_pOverlay = NULL;
+ p->m_pText = NULL;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Panel
+//-----------------------------------------------------------------------------
+Panel *CMinimapPanel::GetTextPaintPanel( void )
+{
+ ClientModeTFBase *basemode = ( ClientModeTFBase * )g_pClientMode;
+ if ( !basemode )
+ {
+ Assert( 0 );
+ return NULL;
+ }
+
+ return basemode->GetMinimapParent();
+}
+
+void CMinimapPanel::ZoomIn( void )
+{
+ if ( m_flDetailsAlpha > 0 )
+ {
+ if ( m_nZoomLevel != 0 )
+ {
+ // g_pClientMode->GetViewportAnimationController()->StartAnimationSequence(
+ // "MinimapZoomLevel0" );
+ }
+
+ // Full window
+ m_nZoomLevel = 0;
+ }
+ else
+ {
+ m_nZoomLevel = ( m_nZoomLevel + 1 ) % ( NUM_WIDTHS );
+ m_nZoomLevel = clamp( m_nZoomLevel, 0, NUM_WIDTHS - 1 );
+
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence(
+ m_nZoomLevel == 0 ?
+ "MinimapZoomLevel0" :
+ "MinimapZoomLevel1" );
+ }
+}
+
+void CMinimapPanel::Zoom_Minimap_f( void )
+{
+ ClientModeTFBase *basemode = ( ClientModeTFBase * )g_pClientMode;
+ if ( !basemode )
+ return;
+
+ CMinimapPanel *minimap = basemode->GetMinimap();
+ if ( !minimap )
+ return;
+
+ minimap->ZoomIn();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMinimapPanel::ToggleMinimap( void )
+{
+ int iKeybits = ::input->GetButtonBits( 0 );
+ bool hitting_button = ( iKeybits & (IN_ATTACK | IN_ATTACK2 | IN_JUMP) ) ? true : false;
+ if ( hitting_button && !m_bMinimapZoomed )
+ {
+ CLocalPlayerFilter filter;
+ C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "ClientModeTFNormal.ToggleMinimap" );
+ }
+
+ SetMinimapZoom( !m_bMinimapZoomed );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void Toggle_Minimap_f( void )
+{
+ ClientModeTFBase *basemode = ( ClientModeTFBase * )g_pClientMode;
+ if ( !basemode )
+ return;
+
+ CMinimapPanel *minimap = basemode->GetMinimap();
+ if ( !minimap )
+ return;
+ minimap->ToggleMinimap();
+}
+
+static ConCommand minimap( "minimap", Toggle_Minimap_f, "Toggle size of the tf2 minimap." );
+
+//-----------------------------------------------------------------------------
+// Purpose: Set the state of the minimap's zoom
+//-----------------------------------------------------------------------------
+void CMinimapPanel::SetMinimapZoom( bool bZoom )
+{
+ C_BaseTFPlayer *local = C_BaseTFPlayer::GetLocalPlayer();
+ if ( local && local->m_TFLocal.m_bForceMapOverview )
+ {
+ bZoom = true;
+ }
+
+ bool changed = bZoom != m_bMinimapZoomed;
+ m_bMinimapZoomed = bZoom;
+ if ( bZoom )
+ {
+ m_nZoomLevel = 0;
+ }
+
+ if ( changed )
+ {
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence(
+ m_bMinimapZoomed ?
+ "MinimapZoomToFullScreen" :
+ "MinimapZoomToCorner");
+
+ CLocalPlayerFilter filter;
+ C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, m_bMinimapZoomed ? "Minimap.ZoomIn" : "Minimap.ZoomOut" );
+
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get at input data before it's used
+//-----------------------------------------------------------------------------
+void CMinimapPanel::ProcessInput()
+{
+ int iKeybits = ::input->GetButtonBits( 0 );
+
+ bool hitting_button = ( iKeybits & (IN_ATTACK | IN_ATTACK2 | IN_JUMP) ) ? true : false;
+
+ // While the minimap's zoomed,
+ if ( m_bMinimapZoomed && hitting_button )
+ {
+ SetMinimapZoom( false );
+ ::input->ClearInputButton( (IN_ATTACK | IN_ATTACK2 | IN_JUMP) );
+ }
+
+ CHudElement::ProcessInput();
+}
+
+static ConCommand zoom_minimap( "zoom_minimap", CMinimapPanel::Zoom_Minimap_f, "Zoom in on minimap." );
+
+
+
+