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/client/tf2 | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/client/tf2')
252 files changed, 45841 insertions, 0 deletions
diff --git a/game/client/tf2/ObjectBuildAlphaProxy.cpp b/game/client/tf2/ObjectBuildAlphaProxy.cpp new file mode 100644 index 0000000..a25add8 --- /dev/null +++ b/game/client/tf2/ObjectBuildAlphaProxy.cpp @@ -0,0 +1,117 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "proxyentity.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/imaterialvar.h" +#include "c_baseobject.h" +#include <KeyValues.h> + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CObjectBuildAlphaProxy : public CEntityMaterialProxy +{ +public: + CObjectBuildAlphaProxy(); + virtual ~CObjectBuildAlphaProxy(); + virtual bool Init( IMaterial *pMaterial, KeyValues* pKeyValues ); + virtual void OnBind( C_BaseEntity *pC_BaseEntity ); + +private: + IMaterialVar* m_pAlphaVar; + + float buildstart; + float buildend; +}; + + +//----------------------------------------------------------------------------- +// Constructor, destructor +//----------------------------------------------------------------------------- + +CObjectBuildAlphaProxy::CObjectBuildAlphaProxy() +{ + m_pAlphaVar = 0; +} + +CObjectBuildAlphaProxy::~CObjectBuildAlphaProxy() +{ +} + +//----------------------------------------------------------------------------- +// Init baby... +//----------------------------------------------------------------------------- +bool CObjectBuildAlphaProxy::Init( IMaterial *pMaterial, KeyValues* pKeyValues ) +{ + + bool foundVar; + m_pAlphaVar = pMaterial->FindVar( "$alpha", &foundVar, false ); + if( !foundVar ) + { + m_pAlphaVar = 0; + } + + buildstart = pKeyValues->GetFloat( "buildstart", 1.0f ); + buildend = pKeyValues->GetFloat( "buildfinish", 1.0f ); + + return true; +} + + +//----------------------------------------------------------------------------- +// Set the appropriate texture... +//----------------------------------------------------------------------------- +void CObjectBuildAlphaProxy::OnBind( C_BaseEntity *pEntity ) +{ + if( !m_pAlphaVar ) + return; + + // It needs to be a TF2 C_BaseObject to have this proxy applied + C_BaseObject *pObject = dynamic_cast< C_BaseObject * >( pEntity ); + if ( !pObject ) + return; + + float build_amount = pObject->GetCycle(); //pObject->GetPercentageConstructed(); + float frac; + + if ( build_amount <= buildstart ) + { + frac = 0.0f; + } + else if ( build_amount >= buildend ) + { + frac = 1.0f; + } + else + { + // Avoid div by zero + if ( buildend == buildstart ) + { + frac = 1.0f; + } + else + { + frac = ( build_amount - buildstart ) / ( buildend - buildstart ); + frac = clamp( frac, 0.0f, 1.0f ); + } + } + + if ( !pObject->IsBuilding() ) + { + frac = 1.0f; + } + + m_pAlphaVar->SetFloatValue( frac ); +} + +EXPOSE_INTERFACE( CObjectBuildAlphaProxy, IMaterialProxy, "TFObjectBuildAlpha" IMATERIAL_PROXY_INTERFACE_VERSION ); + + diff --git a/game/client/tf2/ObjectControlPanel.cpp b/game/client/tf2/ObjectControlPanel.cpp new file mode 100644 index 0000000..eef89b0 --- /dev/null +++ b/game/client/tf2/ObjectControlPanel.cpp @@ -0,0 +1,355 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "ObjectControlPanel.h" +#include <vgui_controls/Controls.h> +#include <vgui_controls/Label.h> +#include "vgui_bitmapbutton.h" +#include <vgui/ISurface.h> +#include <vgui/IVGui.h> +#include "C_BaseTFPlayer.h" +#include "clientmode_tfbase.h" +#include <vgui/IScheme.h> +#include <vgui_controls/Slider.h> +#include "vgui_rotation_slider.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +#define DISMANTLE_WAIT_TIME 5.0 + + +//----------------------------------------------------------------------------- +// Standard VGUI panel for objects +//----------------------------------------------------------------------------- +DECLARE_VGUI_SCREEN_FACTORY( CObjectControlPanel, "object_control_panel" ); + + +//----------------------------------------------------------------------------- +// Constructor: +//----------------------------------------------------------------------------- +CObjectControlPanel::CObjectControlPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, panelName, g_hVGuiObjectScheme ) +{ + // Make some high-level panels to group stuff we want to activate/deactivate + m_pActivePanel = new CCommandChainingPanel( this, "ActivePanel" ); + m_pDeterioratingPanel = new CCommandChainingPanel( this, "DeterioratingPanel" ); + m_pDismantlingPanel = new CCommandChainingPanel( this, "DismantlingPanel" ); + + SetCursor( vgui::dc_none ); // don't draw a VGUI cursor for this panel, and for its children + + // Make sure these are behind everything + m_pActivePanel->SetZPos( -1 ); + m_pDeterioratingPanel->SetZPos( -1 ); + m_pDismantlingPanel->SetZPos( -1 ); +} + + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- +bool CObjectControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ) +{ + // Grab ahold of certain well-known controls + m_pHealthLabel = new vgui::Label( this, "HealthReadout", "" ); + m_pOwnerLabel = new vgui::Label( this, "OwnerReadout", "" ); + m_pDismantleButton = new CBitmapButton( this, "DismantleButton", "Dismantle" ); + m_pAssumeControlButton = new CBitmapButton( GetDeterioratingPanel(), "AssumeControl", "" ); + m_pDismantleTimeLabel = new vgui::Label( GetDismantlingPanel(), "DismantleTime", "" ); + + m_flDismantleTime = -1; + + // Make sure we get ticked... + vgui::ivgui()->AddTickSignal( GetVPanel() ); + + if (!BaseClass::Init(pKeyValues, pInitData)) + return false; + + SetCursor( vgui::dc_none ); // don't draw a VGUI cursor for this panel, and for its children + + // Make the bounds of the sub-panels match + int x, y, w, h; + GetBounds( x, y, w, h ); + m_pActivePanel->SetBounds( x, y, w, h ); + m_pDeterioratingPanel->SetBounds( x, y, w, h ); + m_pDismantlingPanel->SetBounds( x, y, w, h ); + + // Make em all invisible + m_pActivePanel->SetVisible( false ); + m_pDeterioratingPanel->SetVisible( false ); + m_pDismantlingPanel->SetVisible( false ); + m_pCurrentPanel = m_pActivePanel; + + return true; +} + + +//----------------------------------------------------------------------------- +// Returns the object it's attached to +//----------------------------------------------------------------------------- +C_BaseObject *CObjectControlPanel::GetOwningObject() const +{ + C_BaseEntity *pScreenEnt = GetEntity(); + if (!pScreenEnt) + return NULL; + + C_BaseEntity *pObj = pScreenEnt->GetOwnerEntity(); + if (!pObj) + return NULL; + + Assert( dynamic_cast<C_BaseObject*>(pObj) ); + return static_cast<C_BaseObject*>(pObj); +} + + +//----------------------------------------------------------------------------- +// Ticks the panel when its in its various states +//----------------------------------------------------------------------------- + +void CObjectControlPanel::OnTickDeteriorating( C_BaseObject *pObj, C_BaseTFPlayer *pLocalPlayer ) +{ + char buf[256]; + if ( pLocalPlayer && ClassCanBuild( pLocalPlayer->PlayerClass(), pObj->GetType() ) ) + { + int nCost = CalculateObjectCost( pObj->GetType(), pLocalPlayer->GetNumObjects( pObj->GetType() ), pLocalPlayer->GetTeamNumber() ); + Q_snprintf( buf, sizeof( buf ), "Buy for %d", nCost ); + m_pAssumeControlButton->SetText( buf ); + m_pAssumeControlButton->SetVisible( true ); + + bool bHasEnoughResources = pLocalPlayer->GetBankResources() >= nCost; + m_pAssumeControlButton->SetEnabled( bHasEnoughResources ); + } + else + { + m_pAssumeControlButton->SetVisible( false ); + } + + ShowDismantleButton( false ); +} + +void CObjectControlPanel::OnTickActive( C_BaseObject *pObj, C_BaseTFPlayer *pLocalPlayer ) +{ + ShowDismantleButton( !(pObj->GetFlags() & OF_CANNOT_BE_DISMANTLED) && pObj->GetOwner() == pLocalPlayer ); +} + +void CObjectControlPanel::OnTickDismantling( C_BaseObject *pObj, C_BaseTFPlayer *pLocalPlayer ) +{ + ShowDismantleButton( false ); + if ( !m_bDismantled && (gpGlobals->curtime >= m_flDismantleTime)) + { + Dismantle(); + m_bDismantled = true; + } + + int nSec = (int)(m_flDismantleTime - gpGlobals->curtime + 0.5f); + if (nSec < 0) + nSec = 0; + + char buf[256]; + int nLen = Q_snprintf( buf, sizeof( buf ), "%d second", nSec ); + if (nSec != 1) + { + buf[nLen] = 's'; + ++nLen; + buf[nLen] = 0; + } + + m_pDismantleTimeLabel->SetText( buf ); +} + + +vgui::Panel* CObjectControlPanel::TickCurrentPanel() +{ + C_BaseTFPlayer *pLocalPlayer = C_BaseTFPlayer::GetLocalPlayer(); + C_BaseObject *pObj = GetOwningObject(); + + if (IsDismantling()) + { + m_pCurrentPanel = GetDismantlingPanel(); + + OnTickDismantling(pObj, pLocalPlayer); + } + else if (pObj->IsDeteriorating()) + { + m_pCurrentPanel = GetDeterioratingPanel(); + + OnTickDeteriorating(pObj, pLocalPlayer); + } + else + { + m_pCurrentPanel = GetActivePanel(); + + OnTickActive(pObj, pLocalPlayer); + } + + return m_pCurrentPanel; +} + + +void CObjectControlPanel::ShowDismantleButton( bool bShow ) +{ + m_pDismantleButton->SetVisible( bShow ); +} + + +void CObjectControlPanel::ShowOwnerLabel( bool bShow ) +{ + m_pOwnerLabel->SetVisible( bShow ); +} + + +void CObjectControlPanel::ShowHealthLabel( bool bShow ) +{ + m_pHealthLabel->SetVisible( bShow ); +} + + +void CObjectControlPanel::SendToServerObject( const char *pMsg ) +{ + C_BaseObject *pObj = GetOwningObject(); + if (pObj) + { + pObj->SendClientCommand( pMsg ); + } +} + + +//----------------------------------------------------------------------------- +// Frame-based update +//----------------------------------------------------------------------------- +void CObjectControlPanel::OnTick() +{ + BaseClass::OnTick(); + + C_BaseObject *pObj = GetOwningObject(); + if (!pObj) + return; + + char buf[256]; + Q_snprintf( buf, sizeof( buf ), "Health: %d%%", (int)(pObj->HealthFraction() * 100.0f) ); + m_pHealthLabel->SetText( buf ); + + C_BaseTFPlayer *pPlayer = pObj->GetOwner(); + if (pPlayer) + { + Q_snprintf( buf, sizeof( buf ), "Owner: %s", pPlayer->GetPlayerName() ); + } + else + { + Q_snprintf( buf, sizeof( buf ), "No Owner" ); + } + + m_pOwnerLabel->SetText( buf ); + + // Update the current subpanel + m_pCurrentPanel->SetVisible( false ); + + m_pCurrentPanel = TickCurrentPanel(); + + m_pCurrentPanel->SetVisible( true ); +} + + +//----------------------------------------------------------------------------- +// Dismantles the object +//----------------------------------------------------------------------------- +void CObjectControlPanel::Dismantle() +{ + SendToServerObject( "dismantle" ); +} + + +//----------------------------------------------------------------------------- +// Starts/stops dismantling +//----------------------------------------------------------------------------- +void CObjectControlPanel::StartDismantling() +{ + m_flDismantleTime = gpGlobals->curtime + DISMANTLE_WAIT_TIME; + m_bDismantled = false; +} + +void CObjectControlPanel::StopDismantling() +{ + m_flDismantleTime = -1.0f; +} + +bool CObjectControlPanel::IsDismantling() const +{ + return m_flDismantleTime >= 0.0f; +} + + +//----------------------------------------------------------------------------- +// Assumes control of the object +//----------------------------------------------------------------------------- +void CObjectControlPanel::AssumeControl() +{ + SendToServerObject( "takecontrol" ); +} + + +//----------------------------------------------------------------------------- +// Button click handlers +//----------------------------------------------------------------------------- +void CObjectControlPanel::OnCommand( const char *command ) +{ + if (!Q_strnicmp(command, "Dismantle", 10)) + { + StartDismantling(); + return; + } + + if (!Q_strnicmp(command, "CancelDismantle", 20)) + { + StopDismantling(); + return; + } + + if (!Q_strnicmp(command, "AssumeControl", 15)) + { + AssumeControl(); + return; + } + + BaseClass::OnCommand(command); +} + + +DECLARE_VGUI_SCREEN_FACTORY( CRotatingObjectControlPanel, "rotating_object_control_panel" ); + + +//----------------------------------------------------------------------------- +// This is a panel for an object that has rotational controls +//----------------------------------------------------------------------------- +CRotatingObjectControlPanel::CRotatingObjectControlPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, panelName ) +{ +} + +bool CRotatingObjectControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ) +{ + // Grab ahold of certain well-known controls + m_pRotationSlider = new CRotationSlider( GetActivePanel(), "RotationSlider" ); + m_pRotationLabel = new vgui::Label( GetActivePanel(), "RotationLabel", "Rotation Control" ); + + if (!BaseClass::Init(pKeyValues, pInitData)) + return false; + + m_pRotationSlider->SetControlledObject( GetOwningObject() ); + + return true; +} + +void CRotatingObjectControlPanel::OnTickActive( C_BaseObject *pObj, C_BaseTFPlayer *pLocalPlayer ) +{ + BaseClass::OnTickActive( pObj, pLocalPlayer ); + bool bEnable = (pObj->GetOwner() == pLocalPlayer); + m_pRotationSlider->SetVisible( bEnable ); + m_pRotationLabel->SetVisible( bEnable ); +} + diff --git a/game/client/tf2/ObjectControlPanel.h b/game/client/tf2/ObjectControlPanel.h new file mode 100644 index 0000000..c1de4ec --- /dev/null +++ b/game/client/tf2/ObjectControlPanel.h @@ -0,0 +1,135 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Clients CBaseObject +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef OBJECTCONTROLPANEL_H +#define OBJECTCONTROLPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "c_vguiscreen.h" + +namespace vgui +{ + class Panel; + class Label; + class Button; +} + +class C_BaseObject; +class CRotationSlider; +class C_BaseTFPlayer; + +//----------------------------------------------------------------------------- +// Base class for all vgui screens on objects: +//----------------------------------------------------------------------------- +class CObjectControlPanel : public CVGuiScreenPanel +{ + DECLARE_CLASS( CObjectControlPanel, CVGuiScreenPanel ); + +public: + CObjectControlPanel( vgui::Panel *parent, const char *panelName ); + + virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); + virtual void OnCommand( const char *command ); + virtual void OnTick(); + +protected: + // Method to add controls to particular panels + vgui::Panel *GetActivePanel() { return m_pActivePanel; } + vgui::Panel *GetDeterioratingPanel() { return m_pDeterioratingPanel; } + vgui::Panel *GetDismantlingPanel() { return m_pDismantlingPanel; } + + // Override these to deal with various controls in various modes + virtual void OnTickDeteriorating( C_BaseObject *pObj, C_BaseTFPlayer *pLocalPlayer ); + virtual void OnTickActive( C_BaseObject *pObj, C_BaseTFPlayer *pLocalPlayer ); + virtual void OnTickDismantling( C_BaseObject *pObj, C_BaseTFPlayer *pLocalPlayer ); + + C_BaseObject *GetOwningObject() const; + + // This should update the current panel and return that panel. + virtual vgui::Panel* TickCurrentPanel(); + + // The dismantle button has its own logic about whether or not to hide itself. + // Use this to make it go away. + void ShowDismantleButton( bool bShow ); + void ShowOwnerLabel( bool bShow ); + void ShowHealthLabel( bool bShow ); + + // Send a message to the owner. + void SendToServerObject( const char *pMsg ); + +private: + // Operations performed through the controls + void AssumeControl(); + void Dismantle(); + void StartDismantling(); + void StopDismantling(); + bool IsDismantling() const; + + vgui::EditablePanel *m_pActivePanel; + vgui::EditablePanel *m_pDeterioratingPanel; + vgui::EditablePanel *m_pDismantlingPanel; + + vgui::Label *m_pHealthLabel; + vgui::Label *m_pOwnerLabel; + vgui::Button *m_pDismantleButton; + vgui::Button *m_pAssumeControlButton; + vgui::Label *m_pDismantleTimeLabel; + + vgui::Panel *m_pCurrentPanel; + + bool m_bDismantled; + float m_flDismantleTime; +}; + + +// This is used for child panels. It forwards the messages to the parent panel. +class CCommandChainingPanel : public vgui::EditablePanel +{ + typedef vgui::EditablePanel BaseClass; + +public: + CCommandChainingPanel( vgui::Panel *parent, const char *panelName ) : + BaseClass( parent, panelName ) + { + SetPaintBackgroundEnabled( false ); + } + + void OnCommand( const char *command ) + { + BaseClass::OnCommand( command ); + if (GetParent()) + { + GetParent()->OnCommand(command); + } + } +}; + + +//----------------------------------------------------------------------------- +// This is a panel for an object that has rotational controls +//----------------------------------------------------------------------------- +class CRotatingObjectControlPanel : public CObjectControlPanel +{ + DECLARE_CLASS( CRotatingObjectControlPanel, CObjectControlPanel ); + +public: + CRotatingObjectControlPanel( vgui::Panel *parent, const char *panelName ); + + virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); + +protected: + virtual void OnTickActive( C_BaseObject *pObj, C_BaseTFPlayer *pLocalPlayer ); + +private: + CRotationSlider *m_pRotationSlider; + vgui::Label *m_pRotationLabel; +}; + +#endif // OBJECTCONTROLPANEL_H diff --git a/game/client/tf2/ProxyTFPlayer.cpp b/game/client/tf2/ProxyTFPlayer.cpp new file mode 100644 index 0000000..9d14a34 --- /dev/null +++ b/game/client/tf2/ProxyTFPlayer.cpp @@ -0,0 +1,198 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/imaterialsystem.h" +#include <KeyValues.h> +#include "materialsystem/imaterialvar.h" +#include "C_BaseTFPlayer.h" +#include "functionproxy.h" +#include "C_PlayerResource.h" + + +//----------------------------------------------------------------------------- +// Returns the player health (from 0 to 1) +//----------------------------------------------------------------------------- +class CPlayerHealthProxy : public CResultProxy +{ +public: + bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); + void OnBind( void *pEnt ); + +private: + CFloatInput m_Factor; +}; + +bool CPlayerHealthProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) +{ + if (!CResultProxy::Init( pMaterial, pKeyValues )) + return false; + + if (!m_Factor.Init( pMaterial, pKeyValues, "scale", 1 )) + return false; + + return true; +} + +void CPlayerHealthProxy::OnBind( void *pArg ) +{ + // NOTE: Player health max is not available on the server... + C_BaseEntity *pEntity = BindArgToEntity( pArg ); + C_BaseTFPlayer* pPlayer = dynamic_cast<C_BaseTFPlayer*>(pEntity); + if (!pPlayer) + return; + + Assert( m_pResult ); + SetFloatResult( pPlayer->HealthFraction() * m_Factor.GetFloat() ); + + /* + // Should we draw their health? + // If he's not on our team we can't see it unless we're a command with "targetinginfo". + if ( GetLocalTeam() != GetTeam() && !(local->HasNamedTechnology("targetinginfo") && IsLocalPlayerClass(TFCLASS_COMMANDO) )) + return drawn; + // Don't draw health bars above myself + if ( local == this ) + return drawn; + // Don't draw health bars over dead/dying player + if ( GetHealth() <= 0 ) + return drawn; + + return drawn; + */ +} + +EXPOSE_INTERFACE( CPlayerHealthProxy, IMaterialProxy, "PlayerHealth" IMATERIAL_PROXY_INTERFACE_VERSION ); + + +//----------------------------------------------------------------------------- +// A function that returns the time since last being damaged +//----------------------------------------------------------------------------- +class CPlayerDamageTimeProxy : public CResultProxy +{ +public: + bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); + void OnBind( void *pEnt ); + +private: + CFloatInput m_Factor; +}; + +bool CPlayerDamageTimeProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) +{ + if (!CResultProxy::Init( pMaterial, pKeyValues )) + return false; + + if (!m_Factor.Init( pMaterial, pKeyValues, "scale", 1.0f )) + return false; + + return true; +} + +void CPlayerDamageTimeProxy::OnBind( void *pArg ) +{ + C_BaseEntity *pEntity = BindArgToEntity( pArg ); + + // NOTE: Player health max is not available on the server... + C_BaseTFPlayer* pPlayer = dynamic_cast<C_BaseTFPlayer*>(pEntity); + if (!pPlayer) + { + SetFloatResult( 10000 * m_Factor.GetFloat() ); + return; + } + + Assert( m_pResult ); + float dt = gpGlobals->curtime - pPlayer->GetLastDamageTime(); + SetFloatResult( dt * m_Factor.GetFloat() ); +} + +EXPOSE_INTERFACE( CPlayerDamageTimeProxy, IMaterialProxy, "PlayerDamageTime" IMATERIAL_PROXY_INTERFACE_VERSION ); + + +//----------------------------------------------------------------------------- +// A function that returns the time since last being healed +//----------------------------------------------------------------------------- +class CPlayerHealTimeProxy : public CResultProxy +{ +public: + bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); + void OnBind( void *pEnt ); + +private: + CFloatInput m_Factor; +}; + +bool CPlayerHealTimeProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) +{ + if (!CResultProxy::Init( pMaterial, pKeyValues )) + return false; + + if (!m_Factor.Init( pMaterial, pKeyValues, "scale", 1.0f )) + return false; + + return true; +} + +void CPlayerHealTimeProxy::OnBind( void *pArg ) +{ + // NOTE: Player health max is not available on the server... + C_BaseEntity *pEntity = BindArgToEntity( pArg ); + C_BaseTFPlayer* pPlayer = dynamic_cast<C_BaseTFPlayer*>(pEntity); + if (!pPlayer) + return; + + Assert( m_pResult ); + float dt = gpGlobals->curtime - pPlayer->GetLastGainHealthTime(); + SetFloatResult( dt * m_Factor.GetFloat() ); +} + +EXPOSE_INTERFACE( CPlayerHealTimeProxy, IMaterialProxy, "PlayerHealTime" IMATERIAL_PROXY_INTERFACE_VERSION ); + + +//----------------------------------------------------------------------------- +// Returns the player score +//----------------------------------------------------------------------------- +class CPlayerScoreProxy : public CResultProxy +{ +public: + bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); + void OnBind( void *pEntity ); + +private: + CFloatInput m_Factor; +}; + +bool CPlayerScoreProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) +{ + if (!CResultProxy::Init( pMaterial, pKeyValues )) + return false; + + if (!m_Factor.Init( pMaterial, pKeyValues, "scale", 1 )) + return false; + + return true; +} + +void CPlayerScoreProxy::OnBind( void *pArg ) +{ + // Find the view angle between the player and this entity.... + C_BaseEntity *pEntity = BindArgToEntity( pArg ); + C_BaseTFPlayer* pPlayer = dynamic_cast<C_BaseTFPlayer*>(pEntity); + if (!pPlayer) + return; + + if ( !g_PR ) + return; + + int score = g_PR->GetPlayerScore(pPlayer->index); + + Assert( m_pResult ); + SetFloatResult( score * m_Factor.GetFloat() ); +} + +EXPOSE_INTERFACE( CPlayerScoreProxy, IMaterialProxy, "PlayerScore" IMATERIAL_PROXY_INTERFACE_VERSION ); + + diff --git a/game/client/tf2/RespawnWaveVGuiScreen.cpp b/game/client/tf2/RespawnWaveVGuiScreen.cpp new file mode 100644 index 0000000..e9ba442 --- /dev/null +++ b/game/client/tf2/RespawnWaveVGuiScreen.cpp @@ -0,0 +1,101 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_vguiscreen.h" +#include "clientmode_tfbase.h" +#include <vgui/IVGui.h> +#include <vgui_controls/Controls.h> +#include <vgui_controls/Label.h> +#include "c_info_act.h" + + +//----------------------------------------------------------------------------- +// Base class for all vgui screens on objects: +//----------------------------------------------------------------------------- +class CRespawnWaveVGuiScreen : public CVGuiScreenPanel +{ + DECLARE_CLASS( CRespawnWaveVGuiScreen, CVGuiScreenPanel ); + +public: + CRespawnWaveVGuiScreen( vgui::Panel *parent, const char *panelName ); + + virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); + virtual void OnTick(); + +private: + vgui::Label *m_pTime1RemainingLabel; + vgui::Label *m_pTime2RemainingLabel; +}; + + +//----------------------------------------------------------------------------- +// Standard VGUI panel for objects +//----------------------------------------------------------------------------- +DECLARE_VGUI_SCREEN_FACTORY( CRespawnWaveVGuiScreen, "respawn_wave_screen" ); + + +//----------------------------------------------------------------------------- +// Constructor: +//----------------------------------------------------------------------------- +CRespawnWaveVGuiScreen::CRespawnWaveVGuiScreen( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, panelName, g_hVGuiObjectScheme ) +{ +} + + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- +bool CRespawnWaveVGuiScreen::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ) +{ + // Load all of the controls in + if (!BaseClass::Init(pKeyValues, pInitData)) + return false; + + // Make sure we get ticked... + vgui::ivgui()->AddTickSignal( GetVPanel() ); + + // Grab ahold of certain well-known controls + // NOTE: it is valid for these controls to not exist! + m_pTime1RemainingLabel = dynamic_cast<vgui::Label*>(FindChildByName( "RespawnTime1Remaining" )); + m_pTime2RemainingLabel = dynamic_cast<vgui::Label*>(FindChildByName( "RespawnTime2Remaining" )); + + return true; +} + + +//----------------------------------------------------------------------------- +// Frame-based update +//----------------------------------------------------------------------------- +void CRespawnWaveVGuiScreen::OnTick() +{ + BaseClass::OnTick(); + + if (!GetEntity()) + return; + + int nTime1Remaining = 0; + int nTime2Remaining = 0; + if (g_hCurrentAct.Get()) + { + nTime1Remaining = g_hCurrentAct->RespawnTimeRemaining( GetEntity()->GetTeamNumber(), 1 ); + nTime2Remaining = g_hCurrentAct->RespawnTimeRemaining( GetEntity()->GetTeamNumber(), 2 ); + } + + char buf[32]; + if (m_pTime1RemainingLabel) + { + Q_snprintf( buf, sizeof( buf ), "%d", nTime1Remaining ); + m_pTime1RemainingLabel->SetText( buf ); + } + if (m_pTime2RemainingLabel) + { + Q_snprintf( buf, sizeof( buf ), "%d", nTime2Remaining ); + m_pTime2RemainingLabel->SetText( buf ); + } +} + diff --git a/game/client/tf2/VGuiScreenVehicleBay.cpp b/game/client/tf2/VGuiScreenVehicleBay.cpp new file mode 100644 index 0000000..cf8cce9 --- /dev/null +++ b/game/client/tf2/VGuiScreenVehicleBay.cpp @@ -0,0 +1,148 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_vguiscreen.h" +#include "clientmode_tfbase.h" +#include <vgui/IVGui.h> +#include <vgui_controls/Controls.h> +#include <vgui_controls/Label.h> +#include "vgui_bitmapbutton.h" +#include "c_info_act.h" +#include "tf_shareddefs.h" +#include "c_basetfplayer.h" + +int g_ValidVehicles[] = +{ + OBJ_WAGON, + OBJ_BATTERING_RAM, + OBJ_VEHICLE_TANK, + OBJ_VEHICLE_TELEPORT_STATION, + OBJ_WALKER_STRIDER, + OBJ_WALKER_MINI_STRIDER + + // If you add a new vehicle here, you have to add a button for it to the screen_vehicle_bay.res file. + // The button's name must be VehicleButton%d, where %d is it's index into this array. + // Then add the build%d command to OnCommand at the bottom of this file. +}; + +#define NUM_VEHICLES ARRAYSIZE(g_ValidVehicles) + +//----------------------------------------------------------------------------- +// Vgui screen handling vehicle selection in vehicle bays +//----------------------------------------------------------------------------- +class CVehicleBayVGuiScreen : public CVGuiScreenPanel +{ + DECLARE_CLASS( CVehicleBayVGuiScreen, CVGuiScreenPanel ); + +public: + CVehicleBayVGuiScreen( vgui::Panel *parent, const char *panelName ); + + virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); + virtual void OnTick(); + virtual void OnCommand( const char *command ); + +private: + vgui::Button *m_pVehicleButtons[ NUM_VEHICLES ]; +}; + + +//----------------------------------------------------------------------------- +// Standard VGUI panel for objects +//----------------------------------------------------------------------------- +DECLARE_VGUI_SCREEN_FACTORY( CVehicleBayVGuiScreen, "vehicle_bay_screen" ); + + +//----------------------------------------------------------------------------- +// Constructor: +//----------------------------------------------------------------------------- +CVehicleBayVGuiScreen::CVehicleBayVGuiScreen( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, panelName, g_hVGuiObjectScheme ) +{ +} + + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- +bool CVehicleBayVGuiScreen::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ) +{ + // Create our vehicle buttons + for ( int i = 0; i < NUM_VEHICLES; i++ ) + { + char ch[128]; + Q_snprintf( ch, sizeof(ch), "VehicleButton%d", i ); + m_pVehicleButtons[i] = new CBitmapButton( this, ch, "Name" ); + } + + // Load all of the controls in + if (!BaseClass::Init(pKeyValues, pInitData)) + return false; + + // Make sure we get ticked... + vgui::ivgui()->AddTickSignal( GetVPanel() ); + + return true; +} + +//----------------------------------------------------------------------------- +// Frame-based update +//----------------------------------------------------------------------------- +void CVehicleBayVGuiScreen::OnTick() +{ + BaseClass::OnTick(); + + if (!GetEntity()) + return; + + C_BaseTFPlayer *pLocalPlayer = C_BaseTFPlayer::GetLocalPlayer(); + if ( !pLocalPlayer ) + return; + + int nBankResources = pLocalPlayer ? pLocalPlayer->GetBankResources() : 0; + + // Set the vehicles costs + for ( int i = 0; i < NUM_VEHICLES; i++ ) + { + if ( !m_pVehicleButtons[i] ) + continue; + + char buf[128]; + int iCost = CalculateObjectCost( g_ValidVehicles[i], pLocalPlayer->GetNumObjects( g_ValidVehicles[i] ), pLocalPlayer->GetTeamNumber() ); + Q_snprintf( buf, sizeof( buf ), "%s : %d", GetObjectInfo( g_ValidVehicles[i] )->m_pStatusName, iCost ); + m_pVehicleButtons[i]->SetText( buf ); + // Can't build if the game hasn't started + if ( CurrentActIsAWaitingAct() ) + { + m_pVehicleButtons[i]->SetEnabled( false ); + } + else + { + m_pVehicleButtons[i]->SetEnabled( nBankResources >= iCost ); + } + } +} + +//----------------------------------------------------------------------------- +// Button click handlers +//----------------------------------------------------------------------------- +void CVehicleBayVGuiScreen::OnCommand( const char *command ) +{ + if (!Q_strnicmp(command, "build", 5)) + { + int iButton; + int nCount = sscanf( command, "build%d", &iButton ); + if (nCount == 1) + { + char szbuf[64]; + Q_snprintf( szbuf, sizeof( szbuf ), "buildvehicle %d %d", GetEntity()->entindex(), g_ValidVehicles[iButton] ); + engine->ClientCmd(szbuf); + return; + } + } + + BaseClass::OnCommand(command); +} diff --git a/game/client/tf2/c_basecombatcharacter_tf2.cpp b/game/client/tf2/c_basecombatcharacter_tf2.cpp new file mode 100644 index 0000000..87df975 --- /dev/null +++ b/game/client/tf2/c_basecombatcharacter_tf2.cpp @@ -0,0 +1,284 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: TF2 Specific C_BaseCombatCharacter code. +// +//=============================================================================// +#include "cbase.h" +#include "c_basecombatcharacter.h" +#include "tf_shareddefs.h" +#include "particles_simple.h" +#include "functionproxy.h" +#include "IEffects.h" +#include "weapon_combatshield.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseCombatCharacter::Release( void ) +{ + RemoveAllPowerups(); + + BaseClass::Release(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseCombatCharacter::SetDormant( bool bDormant ) +{ + // If we're going dormant, stop all our powerup sounds + if ( bDormant ) + { + RemoveAllPowerups(); + } + else + { + // Restart any powerups on him + for ( int i = 0; i < MAX_POWERUPS; i++ ) + { + if ( m_iPowerups & (1 << i) ) + { + PowerupStart( i, false ); + } + } + } + + BaseClass::SetDormant( bDormant ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : updateType - +//----------------------------------------------------------------------------- +void C_BaseCombatCharacter::OnPreDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnPreDataChanged( updateType ); + + m_iPrevPowerups = m_iPowerups; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseCombatCharacter::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + if ( updateType == DATA_UPDATE_CREATED ) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } + + // Power state changed? + if ( m_iPowerups != m_iPrevPowerups ) + { + for ( int i = 0; i < MAX_POWERUPS; i++ ) + { + bool bPoweredNow = ( m_iPowerups & (1 << i) ); + bool bPoweredThen = ( m_iPrevPowerups & (1 << i) ); + + if ( !bPoweredThen && bPoweredNow ) + { + PowerupStart( i, true ); + } + else if ( bPoweredThen && !bPoweredNow ) + { + PowerupEnd( i ); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Powerup has just started +// If bInitial is set, the server's just told us this powerup has come on. +// If it's false, the entity had it on when it left PVS, and now it's re-entered +//----------------------------------------------------------------------------- +void C_BaseCombatCharacter::PowerupStart( int iPowerup, bool bInitial ) +{ + Assert( iPowerup >= 0 && iPowerup < MAX_POWERUPS ); + + switch( iPowerup ) + { + case POWERUP_BOOST: + break; + + case POWERUP_EMP: + { + // Play the EMP sound + if ( !bInitial ) + { + EmitSound( "BaseCombatCharacter.EMPPulse" ); + } + } + break; + + default: + break; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Powerup has just finished +//----------------------------------------------------------------------------- +void C_BaseCombatCharacter::PowerupEnd( int iPowerup ) +{ +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseCombatCharacter::RemoveAllPowerups( void ) +{ + // Stop any powerups we have + if ( m_iPowerups ) + { + for ( int i = 0; i < MAX_POWERUPS; i++ ) + { + if ( m_iPowerups & (1 << i) ) + { + PowerupEnd( i ); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseCombatCharacter::ClientThink( void ) +{ + BaseClass::ClientThink(); + + if ( !IsDormant() ) + { + if ( HasPowerup(POWERUP_EMP) ) + { + AddEMPEffect( WorldAlignSize().Length() * 0.15 ); + } + + if ( HasPowerup(POWERUP_BOOST) ) + { + AddBuffEffect( WorldAlignSize().Length() * 0.15 ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Draw an effect to show this entity has been EMPed +//----------------------------------------------------------------------------- +void C_BaseCombatCharacter::AddEMPEffect( float flSize ) +{ + // Don't draw on the local player + if ( this == C_BasePlayer::GetLocalPlayer() ) + return; + + CSmartPtr<CSimpleEmitter> pEmitter; + PMaterialHandle hParticleMaterial; + TimedEvent pParticleEvent; + + pParticleEvent.Init( 300 ); + pEmitter = CSimpleEmitter::Create( "ObjectEMPEffect" ); + hParticleMaterial = pEmitter->GetPMaterial( "sprites/chargeball" ); + + // Add particles + float flCur = gpGlobals->frametime; + Vector vCenter = WorldSpaceCenter( ); + + while ( pParticleEvent.NextEvent( flCur ) ) + { + Vector vPos; + Vector vOffset = RandomVector( -1, 1 ); + VectorNormalize( vOffset ); + vPos = vCenter + (vOffset * RandomFloat( 0, flSize )); + + pEmitter->SetSortOrigin( vPos ); + SimpleParticle *pParticle = pEmitter->AddSimpleParticle( hParticleMaterial, vPos ); + if ( pParticle ) + { + // Move the points along the path. + pParticle->m_vecVelocity.Init(); + pParticle->m_flRoll = 0; + pParticle->m_flRollDelta = 0; + pParticle->m_flDieTime = 0.4f; + pParticle->m_flLifetime = 0; + pParticle->m_uchColor[0] = 255; + pParticle->m_uchColor[1] = 255; + pParticle->m_uchColor[2] = 255; + pParticle->m_uchStartAlpha = 32; + pParticle->m_uchEndAlpha = 0; + pParticle->m_uchStartSize = 4; + pParticle->m_uchEndSize = 2; + pParticle->m_iFlags = 0; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Draw an effect to show this entity is being buffed +//----------------------------------------------------------------------------- +void C_BaseCombatCharacter::AddBuffEffect( float flSize ) +{ + // Don't draw on the local player + if ( this == C_BasePlayer::GetLocalPlayer() ) + return; + + CSmartPtr<CSimpleEmitter> pEmitter; + PMaterialHandle hParticleMaterial; + TimedEvent pParticleEvent; + + pParticleEvent.Init( 300 ); + pEmitter = CSimpleEmitter::Create( "ObjectBuffEffect" ); + hParticleMaterial = pEmitter->GetPMaterial( "sprites/chargeball" ); + + // Add particles + float flCur = gpGlobals->frametime; + Vector vCenter = WorldSpaceCenter( ); + + while ( pParticleEvent.NextEvent( flCur ) ) + { + Vector vPos; + Vector vOffset = RandomVector( -1, 1 ); + VectorNormalize( vOffset ); + vPos = vCenter + (vOffset * RandomFloat( 0, flSize )); + + SimpleParticle *pParticle = pEmitter->AddSimpleParticle( hParticleMaterial, vPos ); + if ( pParticle ) + { + // Move the points along the path. + pParticle->m_vecVelocity.Init(); + pParticle->m_flRoll = 0; + pParticle->m_flRollDelta = 0; + pParticle->m_flDieTime = 0.4f; + pParticle->m_flLifetime = 0; + pParticle->m_uchColor[1] = 255; pParticle->m_uchColor[0] = pParticle->m_uchColor[2] = 0; + pParticle->m_uchStartAlpha = 128; + pParticle->m_uchEndAlpha = 0; + pParticle->m_uchStartSize = 3; + pParticle->m_uchEndSize = 1; + pParticle->m_iFlags = 0; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Returns shield if owned. +//----------------------------------------------------------------------------- +C_WeaponCombatShield *C_BaseCombatCharacter::GetShield( void ) +{ + C_BaseCombatWeapon *pWeapon; + if ( GetTeamNumber() == TEAM_ALIENS ) + { + pWeapon = Weapon_OwnsThisType( "weapon_combat_shield_alien" ); + } + else + { + pWeapon = Weapon_OwnsThisType( "weapon_combat_shield" ); + } + + if ( !pWeapon ) + return NULL; + + return ( CWeaponCombatShield* )pWeapon; +} diff --git a/game/client/tf2/c_basefourwheelvehicle.cpp b/game/client/tf2/c_basefourwheelvehicle.cpp new file mode 100644 index 0000000..88b98e3 --- /dev/null +++ b/game/client/tf2/c_basefourwheelvehicle.cpp @@ -0,0 +1,89 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "C_BaseFourWheelVehicle.h" + +IMPLEMENT_CLIENTCLASS_DT(C_BaseTFFourWheelVehicle, DT_BaseTFFourWheelVehicle, CBaseTFFourWheelVehicle) + RecvPropFloat( RECVINFO( m_flDeployFinishTime ) ), + RecvPropInt( RECVINFO( m_eDeployMode ) ), + RecvPropInt( RECVINFO( m_bBoostUpgrade ) ), + RecvPropInt( RECVINFO( m_nBoostTimeLeft ) ), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_BaseTFFourWheelVehicle::C_BaseTFFourWheelVehicle() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +float C_BaseTFFourWheelVehicle::GetDeployFinishTime() const +{ + return m_flDeployFinishTime; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +VehicleModeDeploy_e C_BaseTFFourWheelVehicle::GetVehicleModeDeploy() const +{ + return m_eDeployMode; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseTFFourWheelVehicle::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + if ( updateType == DATA_UPDATE_CREATED ) + { + // Start thinking (Baseclass stops it) + ClientThinkList()->SetNextClientThink( GetClientHandle(), CLIENT_THINK_ALWAYS ); + } +} + +//----------------------------------------------------------------------------- +// Restricts the view within a range of the center... +//----------------------------------------------------------------------------- +void C_BaseTFFourWheelVehicle::RestrictView( int nRole, float flMinYaw, float flMaxYaw, QAngle &vecViewAngles ) +{ + Assert( nRole >= 0 ); + Vector vehicleEyeOrigin; + QAngle vehicleEyeAngles; + GetRoleViewPosition( nRole, &vehicleEyeOrigin, &vehicleEyeAngles ); + + // Confine the view to the appropriate yaw range... + float flCenterYaw = vehicleEyeAngles[YAW]; + + // View angles are dealt with in absolute terms here... + float flAngleDiff = AngleDiff( vecViewAngles[YAW], flCenterYaw ); + + // Here, we must clamp to the cone... + if (flAngleDiff < flMinYaw) + vecViewAngles[YAW] = anglemod(flCenterYaw + flMinYaw); + else if (flAngleDiff > flMaxYaw) + vecViewAngles[YAW] = anglemod(flCenterYaw + flMaxYaw); +} + + +//----------------------------------------------------------------------------- +// Clamps the view angles while driving the vehicle +//----------------------------------------------------------------------------- +void C_BaseTFFourWheelVehicle::UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd ) +{ + int nRole = GetPassengerRole( pLocalPlayer ); + if ( nRole != VEHICLE_ROLE_DRIVER ) + { + RestrictView( nRole, -90, 90, pCmd->viewangles ); + } +} + diff --git a/game/client/tf2/c_basefourwheelvehicle.h b/game/client/tf2/c_basefourwheelvehicle.h new file mode 100644 index 0000000..5ccbcaf --- /dev/null +++ b/game/client/tf2/c_basefourwheelvehicle.h @@ -0,0 +1,51 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_BASE_FOUR_WHEEL_VEHICLE_H +#define C_BASE_FOUR_WHEEL_VEHICLE_H + +#include "basetfvehicle.h" + +class C_BasePlayer; + +class C_BaseTFFourWheelVehicle : public C_BaseTFVehicle +{ + DECLARE_CLASS( C_BaseTFFourWheelVehicle, C_BaseTFVehicle ); + DECLARE_CLIENTCLASS(); + +public: + + C_BaseTFFourWheelVehicle(); + + float GetDeployFinishTime() const; + VehicleModeDeploy_e GetVehicleModeDeploy() const; + + // TF2 vehicles are animated by the server + virtual bool IsSelfAnimating() { return false; }; + + virtual void OnDataChanged( DataUpdateType_t updateType ); + +// IClientVehicle overrides. +public: + virtual void UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd ); + +protected: + // Restricts the view within a range of the center... + void RestrictView( int nRole, float flMinYaw, float flMaxYaw, QAngle &vecViewAngles ); + +private: + + C_BaseTFFourWheelVehicle( const C_BaseTFFourWheelVehicle & ); // not defined, not accessible + +private: + + // Used to draw deploy timer on vgui screens. + float m_flDeployFinishTime; + VehicleModeDeploy_e m_eDeployMode; +}; + +#endif // C_BASE_FOUR_WHEEL_VEHICLE_H
\ No newline at end of file diff --git a/game/client/tf2/c_baseobject.cpp b/game/client/tf2/c_baseobject.cpp new file mode 100644 index 0000000..491dba9 --- /dev/null +++ b/game/client/tf2/c_baseobject.cpp @@ -0,0 +1,921 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Clients CBaseObject +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_baseobject.h" +#include "c_basetfplayer.h" +#include "hud.h" +#include "c_tfteam.h" +#include "engine/IEngineSound.h" +#include "particles_simple.h" +#include "functionproxy.h" +#include "IEffects.h" +#include "c_hint_events.h" +#include "model_types.h" +#include "particlemgr.h" +#include "particle_collision.h" +#include "env_objecteffects.h" +#include "basetfvehicle.h" +#include "c_weapon_builder.h" +#include "ivrenderview.h" +#include "ObjectControlPanel.h" +#include "engine/ivmodelinfo.h" +#include "c_te_effect_dispatch.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define MAX_VISIBLE_BUILDPOINT_DISTANCE (400 * 400) + +// Remove aliasing of name due to shared code +#undef CBaseObject + +IMPLEMENT_CLIENTCLASS_DT(C_BaseObject, DT_BaseObject, CBaseObject) + RecvPropInt(RECVINFO(m_iHealth)), + RecvPropInt(RECVINFO(m_iMaxHealth)), + RecvPropInt(RECVINFO(m_bHasSapper)), + RecvPropInt(RECVINFO(m_iObjectType)), + RecvPropInt(RECVINFO(m_bBuilding)), + RecvPropInt(RECVINFO(m_bPlacing)), + RecvPropFloat(RECVINFO(m_flPercentageConstructed)), + RecvPropInt(RECVINFO(m_fObjectFlags)), + RecvPropInt(RECVINFO(m_bDeteriorating)), + RecvPropEHandle(RECVINFO(m_hBuiltOnEntity)), + RecvPropInt(RECVINFO( m_takedamage ) ), + RecvPropInt( RECVINFO( m_bDisabled ) ), + RecvPropEHandle( RECVINFO( m_hBuilder ) ), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_BaseObject::C_BaseObject( ) +{ + m_flDamageFlash = 0; + m_YawPreviewState = YAW_PREVIEW_OFF; + m_bBuilding = false; + m_bPlacing = false; + m_flPercentageConstructed = 0; + m_flNextEffect = 0; + m_bOldSapper = m_bHasSapper = false; + m_fObjectFlags = 0; + m_bDeteriorating = false; + m_ThermalMaterial.Init("player/thermal/thermal",TEXTURE_GROUP_CLIENT_EFFECTS); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_BaseObject::~C_BaseObject( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseObject::PreDataUpdate( DataUpdateType_t updateType ) +{ + BaseClass::PreDataUpdate( updateType ); + + m_iOldHealth = m_iHealth; + m_bOldSapper = m_bHasSapper; + m_hOldOwner = GetOwner(); + m_bWasActive = ShouldBeActive(); + m_bWasBuilding = m_bBuilding; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseObject::OnDataChanged( DataUpdateType_t updateType ) +{ + if (updateType == DATA_UPDATE_CREATED) + { + if ( !IS_MINIMAP_PANEL_DEFINED( ) && !(m_fObjectFlags & OF_SUPPRESS_APPEAR_ON_MINIMAP) ) + { + CONSTRUCT_MINIMAP_PANEL( "minimap_object", MINIMAP_OBJECTS ); + } + + CreateBuildPoints(); + } + + BaseClass::OnDataChanged( updateType ); + + // Did we just finish building? + if ( m_bWasBuilding && !m_bBuilding ) + { + FinishedBuilding(); + } + + // Did we just go active? + bool bShouldBeActive = ShouldBeActive(); + if ( !m_bWasActive && bShouldBeActive ) + { + OnGoActive(); + } + else if ( m_bWasActive && !bShouldBeActive ) + { + OnGoInactive(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseObject::SetDormant( bool bDormant ) +{ + BaseClass::SetDormant( bDormant ); + //ENTITY_PANEL_ACTIVATE( "analyzed_object", !bDormant ); +} + +#define TF_OBJ_BODYGROUPTURNON 1 +#define TF_OBJ_BODYGROUPTURNOFF 0 + +//----------------------------------------------------------------------------- +// Purpose: +// Input : origin - +// angles - +// event - +// *options - +//----------------------------------------------------------------------------- +void C_BaseObject::FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options ) +{ + switch ( event ) + { + default: + { + BaseClass::FireEvent( origin, angles, event, options ); + } + break; + case TF_OBJ_PLAYBUILDSOUND: + { + EmitSound( options ); + } + break; + case TF_OBJ_ENABLEBODYGROUP: + { + int index = FindBodygroupByName( options ); + if ( index >= 0 ) + { + SetBodygroup( index, TF_OBJ_BODYGROUPTURNON ); + } + } + break; + case TF_OBJ_DISABLEBODYGROUP: + { + int index = FindBodygroupByName( options ); + if ( index >= 0 ) + { + SetBodygroup( index, TF_OBJ_BODYGROUPTURNOFF ); + } + } + break; + case TF_OBJ_ENABLEALLBODYGROUPS: + case TF_OBJ_DISABLEALLBODYGROUPS: + { + // Start at 1, because body 0 is the main .mdl body... + // Is this the way we want to do this? + int count = GetNumBodyGroups(); + for ( int i = 1; i < count; i++ ) + { + int subpartcount = GetBodygroupCount( i ); + if ( subpartcount == 2 ) + { + SetBodygroup( i, + ( event == TF_OBJ_ENABLEALLBODYGROUPS ) ? + TF_OBJ_BODYGROUPTURNON : TF_OBJ_BODYGROUPTURNOFF ); + } + else + { + DevMsg( "TF_OBJ_ENABLE/DISABLEBODY GROUP: %s has a group with %i subparts, should be exactly 2\n", + GetClassname(), subpartcount ); + } + } + } + break; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_BaseObject::OffsetObjectOrigin( Vector& origin ) +{ + if ( !m_bBuilding ) + return false; + + if ( inv_demo.GetBool() ) + return false; + + Vector vecWorldMins, vecWorldMaxs; + CollisionProp()->WorldSpaceAABB( &vecWorldMins, &vecWorldMaxs ); + float flSize = vecWorldMaxs.z - vecWorldMins.z; + origin.z -= (flSize * (1 - m_flPercentageConstructed)); + + // If we're building, fake sliding the object out of the ground + return true; +} + + +const char* C_BaseObject::GetStatusName() const +{ + return GetObjectInfo( GetType() )->m_pStatusName; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int C_BaseObject::DrawModel( int flags ) +{ + Vector vRealOrigin = GetLocalOrigin(); + Vector vOrigin = vRealOrigin; + bool needOriginReset = OffsetObjectOrigin( vOrigin ); + if ( needOriginReset ) + { + SetLocalOrigin( vOrigin ); + InvalidateBoneCache(); + } + + int drawn; + C_BaseTFPlayer *pLocal = C_BaseTFPlayer::GetLocalPlayer(); + if ( pLocal && pLocal->IsUsingThermalVision() ) + { + modelrender->ForcedMaterialOverride( m_ThermalMaterial ); + drawn = BaseClass::DrawModel(flags); + modelrender->ForcedMaterialOverride( NULL ); + } + else + { + // If we're a brush-built, map-defined object chain up to baseentity draw + if ( modelinfo->GetModelType( GetModel() ) == mod_brush ) + { + drawn = CBaseEntity::DrawModel(flags); + } + else + { + drawn = BaseClass::DrawModel(flags); + } + } + + // Restore faked origin + if ( needOriginReset ) + { + SetLocalOrigin( vRealOrigin ); + } + + // If we were drawn, draw building effects if we're building, or damage effects if we're damaged + if ( drawn && (m_flNextEffect < gpGlobals->curtime) ) + { + // Haxory LOD + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( (GetAbsOrigin() - pPlayer->GetAbsOrigin()).LengthSqr() < lod_effect_distance.GetFloat() ) + { + if ( IsBuilding() ) + { + DrawBuildEffects(); + } + if ( !m_bPlacing && !m_bBuilding ) + { + if ( !HasPowerup( POWERUP_EMP ) ) + { + DrawRunningEffects(); + } + + if ( GetHealth() < GetMaxHealth() ) + { + DrawDamageEffects(); + } + } + } + } + + HighlightBuildPoints( flags ); + + return drawn; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseObject::HighlightBuildPoints( int flags ) +{ + C_BaseTFPlayer *pLocal = C_BaseTFPlayer::GetLocalPlayer(); + if ( !pLocal ) + return; + + if ( !GetNumBuildPoints() || !InLocalTeam() ) + return; + + C_WeaponBuilder *pBuilderWpn = dynamic_cast< C_WeaponBuilder * >( pLocal->GetActiveWeaponForSelection() ); + if ( !pBuilderWpn ) + return; + if ( !pBuilderWpn->IsPlacingObject() ) + return; + C_BaseObject *pPlacementObj = pBuilderWpn->GetPlacementModel(); + if ( !pPlacementObj || pPlacementObj == this ) + return; + + // Near enough? + if ( (GetAbsOrigin() - pLocal->GetAbsOrigin()).LengthSqr() < MAX_VISIBLE_BUILDPOINT_DISTANCE ) + { + bool bRestoreModel = false; + Vector vecPrevAbsOrigin = pPlacementObj->GetAbsOrigin(); + QAngle vecPrevAbsAngles = pPlacementObj->GetAbsAngles(); + + Vector orgColor; + render->GetColorModulation( orgColor.Base() ); + float orgBlend = render->GetBlend(); + + // Any empty buildpoints? + for ( int i = 0; i < GetNumBuildPoints(); i++ ) + { + // Can this object build on this point? + if ( CanBuildObjectOnBuildPoint( i, pPlacementObj->GetType() ) ) + { + Vector vecBPOrigin; + QAngle vecBPAngles; + if ( GetBuildPoint(i, vecBPOrigin, vecBPAngles) ) + { + pPlacementObj->InvalidateBoneCaches(); + + Vector color( 0, 255, 0 ); + render->SetColorModulation( color.Base() ); + float frac = fmod( gpGlobals->curtime, 3 ); + frac *= 2 * M_PI; + frac = cos( frac ); + render->SetBlend( (175 + (int)( frac * 75.0f )) / 255.0 ); + + // HACK: Fixup angles on the HL2 model we're using + if ( !strcmp( modelinfo->GetModelName( pPlacementObj->GetModel() ), "models/items/HealthKit.mdl" ) ) + { + vecBPAngles.x += 90; + } + + // FIXME: This truly sucks! The bone cache should use + // render location for this computation instead of directly accessing AbsAngles + // Necessary for bone cache computations to work + pPlacementObj->SetAbsOrigin( vecBPOrigin ); + pPlacementObj->SetAbsAngles( vecBPAngles ); + + + modelrender->DrawModel( + flags, + pPlacementObj, + pPlacementObj->GetModelInstance(), + pPlacementObj->index, + pPlacementObj->GetModel(), + vecBPOrigin, + vecBPAngles, + pPlacementObj->m_nSkin, + pPlacementObj->m_nBody, + pPlacementObj->m_nHitboxSet + ); + + bRestoreModel = true; + } + } + } + + if ( bRestoreModel ) + { + pPlacementObj->SetAbsOrigin(vecPrevAbsOrigin); + pPlacementObj->SetAbsAngles(vecPrevAbsAngles); + pPlacementObj->InvalidateBoneCaches(); + + render->SetColorModulation( orgColor.Base() ); + render->SetBlend( orgBlend ); + } + } +} + + +//----------------------------------------------------------------------------- +// Exit points for mounted vehicles.... +//----------------------------------------------------------------------------- +void C_BaseObject::GetExitPoint( CBaseEntity *pPlayer, int nBuildPoint, Vector *pAbsPosition, QAngle *pAbsAngles ) +{ + Assert(0); +} + + +//----------------------------------------------------------------------------- +// Purpose: Overridden to allow for brush-built map defined objects +//----------------------------------------------------------------------------- +bool C_BaseObject::IsIdentityBrush( void ) +{ + return false; +} + +//----------------------------------------------------------------------------- +// Builder preview... +//----------------------------------------------------------------------------- +void C_BaseObject::ActivateYawPreview( bool enable ) +{ + m_YawPreviewState = enable ? YAW_PREVIEW_ON : YAW_PREVIEW_WAITING_FOR_UPDATE; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseObject::PreviewYaw( float yaw ) +{ + m_fYawPreview = yaw; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_BaseObject::IsPreviewingYaw() const +{ + return m_YawPreviewState != YAW_PREVIEW_OFF; +} + +//----------------------------------------------------------------------------- +// Purpose: This is called to get the initial builder yaw... +//----------------------------------------------------------------------------- +float C_BaseObject::GetInitialBuilderYaw() +{ + return GetAbsAngles().y; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseObject::PostDataUpdate( DataUpdateType_t updateType ) +{ + BaseClass::PostDataUpdate( updateType ); + + bool bNewEntity = (updateType == DATA_UPDATE_CREATED); + if ( bNewEntity ) + { + m_flAttackTime = -1000; + } + + // Determine if we're under attack + if ( !bNewEntity ) + { + if ( m_iHealth < m_iOldHealth ) + { + // Deteriorating objects don't play sounds + if ( !IsDeteriorating() ) + { + m_flAttackTime = gpGlobals->curtime; + } + } + else if ( m_iHealth > m_iOldHealth && m_iHealth == m_iMaxHealth ) + { + // If we were just fully healed, remove all decals + RemoveAllDecals(); + } + } + + if ( m_bHasSapper ) + { + // Play a specific sound for a sapper... + if ( m_bOldSapper != m_bHasSapper ) + { + // Don't create these for dragonsteeth + if ( InLocalTeam() && GetType() != OBJ_DRAGONSTEETH ) + { + // Play a sound. + CLocalPlayerFilter filter; + EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "BaseObject.SapperDestroyingTeamBuilding" ); + + MinimapCreateTempTrace( "minimap_under_attack", MINIMAP_PERSONAL_ORDERS, GetAbsOrigin() ); + } + } + } + + // Notify the hint system of the object being built. + if ( bNewEntity && GetOwner() && ( GetOwner() == C_BasePlayer::GetLocalPlayer() ) ) + { + C_HintEvent_ObjectBuiltByLocalPlayer event( this ); + GlobalHintEvent( &event ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseObject::Release( void ) +{ + // Remove any reticles on this entity + C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + if ( pPlayer ) + { + pPlayer->Remove_Target( this ); + } + + BaseClass::Release(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_BaseObject::IsUnderAttack( ) +{ + // It's under attack for the 3 seconds after the last attack time + return (gpGlobals->curtime - m_flAttackTime) < 5.0f; +} + +//----------------------------------------------------------------------------- +// Ownership: +//----------------------------------------------------------------------------- +C_BaseTFPlayer *C_BaseObject::GetOwner() +{ + return m_hBuilder; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_BaseObject::IsOwnedByLocalPlayer() const +{ + if ( !m_hBuilder ) + return false; + + return ( m_hBuilder == C_BaseTFPlayer::GetLocalPlayer() ); +} + +//----------------------------------------------------------------------------- +// Purpose: Add entity to visibile entities list +//----------------------------------------------------------------------------- +void C_BaseObject::AddEntity( void ) +{ + // If set to invisible, skip. Do this before resetting the entity pointer so it has + // valid data to decide whether it's visible. + if ( !ShouldDraw() ) + { + return; + } + + // Update the entity position + UpdatePosition(); + + // Yaw preview + if (m_YawPreviewState != YAW_PREVIEW_OFF) + { + // This piece of code makes it so we keep using the preview + // until we get a network update which matches the update value + if (m_YawPreviewState == YAW_PREVIEW_WAITING_FOR_UPDATE) + { + if (fmod( fabs(GetLocalAngles().y - m_fYawPreview), 360.0f) < 1.0f) + { + m_YawPreviewState = YAW_PREVIEW_OFF; + } + } + + if (GetLocalOrigin().y != m_fYawPreview) + { + SetLocalAnglesDim( Y_INDEX, m_fYawPreview ); + InvalidateBoneCache(); + } + } + + // Create flashlight effects, etc. + CreateLightEffects(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseObject::Select( void ) +{ + C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + pPlayer->SetSelectedObject( this ); +} + +//----------------------------------------------------------------------------- +// Sends client commands back to the server: +//----------------------------------------------------------------------------- +void C_BaseObject::SendClientCommand( const char *pCmd ) +{ + char szbuf[128]; + Q_snprintf( szbuf, sizeof( szbuf ), "objcmd %d %s", entindex(), pCmd ); + engine->ClientCmd(szbuf); +} + + +//----------------------------------------------------------------------------- +// Purpose: Get a text description for the object target +//----------------------------------------------------------------------------- +const char *C_BaseObject::GetTargetDescription( void ) const +{ + return GetStatusName(); +} + +//----------------------------------------------------------------------------- +// Purpose: Get a text description for the object target (more verbose) +//----------------------------------------------------------------------------- +char *C_BaseObject::GetIDString( void ) +{ + m_szIDString[0] = 0; + RecalculateIDString(); + return m_szIDString; +} + + +//----------------------------------------------------------------------------- +// It's a valid ID target when it's building +//----------------------------------------------------------------------------- +bool C_BaseObject::IsValidIDTarget( void ) +{ + return InSameTeam( C_BaseTFPlayer::GetLocalPlayer() ) && m_bBuilding; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseObject::RecalculateIDString( void ) +{ + // Subclasses may have filled this out with a string + if ( !m_szIDString[0] ) + { + Q_strncpy( m_szIDString, GetTargetDescription(), sizeof(m_szIDString) ); + } + + // Have I taken damage? + if ( m_iHealth < m_iMaxHealth ) + { + char szHealth[ MAX_ID_STRING ]; + if ( IsDeteriorating() ) + { + Q_snprintf( szHealth, sizeof(szHealth), "\nBUILDER LOST, DETERIORATING... %.0f percent", ceil(((float)m_iHealth / (float)m_iMaxHealth) * 100) ); + } + else if ( m_bBuilding ) + { + Q_snprintf( szHealth, sizeof(szHealth), "\nConstruction at %.0f percent\nHealth at %.0f percent", (m_flPercentageConstructed * 100), ceil(((float)m_iHealth / (float)m_iMaxHealth) * 100) ); + } + else + { + Q_snprintf( szHealth, sizeof(szHealth), "\nHealth at %.0f percent", ceil(((float)m_iHealth / (float)m_iMaxHealth) * 100) ); + } + Q_strncat( m_szIDString, szHealth, sizeof(m_szIDString), COPY_ALL_CHARACTERS ); + } + + if ( m_bHasSapper ) + { + Q_strncat( m_szIDString, "\nUse it to remove the attached enemy object", sizeof(m_szIDString), COPY_ALL_CHARACTERS ); + } + + // If it's deteriorating, and I can buy it, tell me + C_BaseTFPlayer *pLocalPlayer = C_BaseTFPlayer::GetLocalPlayer(); + if ( IsDeteriorating() && pLocalPlayer && ClassCanBuild( pLocalPlayer->PlayerClass(), GetType() ) ) + { + char szBuy[ MAX_ID_STRING ]; + int iCost = CalculateObjectCost( GetType(), pLocalPlayer->GetNumObjects( GetType() ), pLocalPlayer->GetTeamNumber() ); + Q_snprintf( szBuy, sizeof(szBuy), "\nBUY THIS OBJECT FOR %d RESOURCES", iCost ); + Q_strncat( m_szIDString, szBuy, sizeof(m_szIDString), COPY_ALL_CHARACTERS ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Effects created when the object's running +//----------------------------------------------------------------------------- +void C_BaseObject::DrawRunningEffects( void ) +{ + if ( !GetMaxHealth() ) + return; + + // Get the overall damage percentage + float flDamaged = 1.0 - ((float)GetHealth() / (float)GetMaxHealth()); + + // Damage attachment points + int iSmokeAttachment, iSparkAttachment; + Vector vecSmoke, vecSpark, vecSmokeDir, dir; + QAngle angSmoke, angSpark; + + // Look for damage points + iSmokeAttachment = LookupRandomAttachment( "r_smoke" ); + + // Get the points + if ( GetAttachment( iSmokeAttachment, vecSmoke, angSmoke ) ) + { + AngleVectors( angSmoke, &vecSmokeDir); + + float r, g, b; + r = g = b = random->RandomFloat( 16, 92 ); + + // Smoke + CSmartPtr<CObjectSmokeParticles> pSmokeEmitter = CObjectSmokeParticles::Create( "DrawRunningEffects 1" ); + pSmokeEmitter->SetSortOrigin( vecSmoke ); + ObjectSmokeParticle *pParticle = (ObjectSmokeParticle *) pSmokeEmitter->AddParticle( sizeof(ObjectSmokeParticle), g_Mat_DustPuff[1], vecSmoke ); + if ( pParticle ) + { + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = random->RandomFloat( 2.0f, 3.0f ); + pParticle->m_uchStartSize = random->RandomFloat( 2, 3 ); + pParticle->m_uchEndSize = random->RandomFloat( 5, 10 ); + dir[0] = vecSmokeDir[0] + random->RandomFloat( -0.1f, 0.1f ); + dir[1] = vecSmokeDir[1] + random->RandomFloat( -0.1f, 0.1f ); + dir[2] = vecSmokeDir[2] + random->RandomFloat( -0.1f, 0.1f ); + pParticle->m_vecVelocity = dir * random->RandomFloat( 30.0f, 40.0f ); + pParticle->m_uchStartAlpha = random->RandomFloat( 128,255 ); + pParticle->m_uchEndAlpha = 0; + pParticle->m_flRoll = random->RandomFloat( 180, 360 ); + pParticle->m_flRollDelta = random->RandomFloat( -1, 1 ); + pParticle->m_uchColor[0] = r; + pParticle->m_uchColor[1] = g; + pParticle->m_uchColor[2] = b; + pParticle->m_vecAcceleration = Vector(0,0,10); + } + } + + // Sparks + for ( float flSparks = flDamaged - 0.3; flSparks > 0; flSparks -= 0.3 ) + { + // Get random spark attachment point + iSparkAttachment = LookupRandomAttachment( "r_spark" ); + if ( GetAttachment( iSparkAttachment, vecSpark, angSpark ) ) + { + g_pEffects->Sparks( vecSpark ); + } + } + + m_flNextEffect = gpGlobals->curtime + random->RandomFloat( 0.05, 0.1 ); +} + +//----------------------------------------------------------------------------- +// Purpose: Effects created while the object's building itself +//----------------------------------------------------------------------------- +void C_BaseObject::DrawBuildEffects( void ) +{ + m_flNextEffect = gpGlobals->curtime + 10; +} + +//----------------------------------------------------------------------------- +// Purpose: Effects created when the object's damaged +//----------------------------------------------------------------------------- +void C_BaseObject::DrawDamageEffects( void ) +{ + if ( !GetMaxHealth() ) + return; + + // Get the overall damage percentage + float flDamaged = 1.0 - ((float)GetHealth() / (float)GetMaxHealth()); + + // Damage attachment points + int iSmokeAttachment, iFireAttachment, iSparkAttachment; + Vector vecSmoke, vecFire, vecSpark, vecSmokeDir, dir; + QAngle angSmoke, angFire, angSpark; + + // HACK: Calculate a random origin + // This can go away when we require all objects to have damage attachment points + Vector vecOrigin; + CollisionProp()->RandomPointInBounds( vec3_origin, Vector( 1, 1, 1 ), &vecOrigin ); + + // Look for damage points + iSmokeAttachment = LookupRandomAttachment( "d_smoke" ); + iFireAttachment = LookupRandomAttachment( "d_fire" ); + + // Get the points, and if we can't find 'em, use the random origin + if ( GetAttachment( iSmokeAttachment, vecSmoke, angSmoke ) ) + { + AngleVectors( angSmoke, &vecSmokeDir ); + } + else + { + vecSmoke = vecOrigin; + vecSmokeDir = Vector(0,0,1); + } + if ( !GetAttachment( iFireAttachment, vecFire, angFire ) ) + { + vecFire = vecOrigin; + angFire = QAngle(0,0,0); + } + + float r, g, b; + r = g = b = random->RandomFloat( 16, 92 ); + + // Smoke + CSmartPtr<CSimpleEmitter> pSmokeEmitter = CSimpleEmitter::Create( "DrawDamageEffects 1" ); + pSmokeEmitter->SetSortOrigin( vecSmoke ); + SimpleParticle *pParticle = (SimpleParticle *) pSmokeEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[1], vecSmoke ); + if ( pParticle ) + { + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = random->RandomFloat( 2.0f, 3.0f ); + pParticle->m_uchStartSize = MAX( 1, 20 * flDamaged ); + pParticle->m_uchEndSize = MAX( 10, 80 * flDamaged ); + dir[0] = vecSmokeDir[0] + random->RandomFloat( -0.2f, 0.2f ); + dir[1] = vecSmokeDir[1] + random->RandomFloat( -0.2f, 0.2f ); + dir[2] = vecSmokeDir[2] + random->RandomFloat( -0.2f, 0.2f ); + pParticle->m_vecVelocity = dir * random->RandomFloat( 60.0f, 80.0f ); + pParticle->m_uchStartAlpha = 255; + pParticle->m_uchEndAlpha = 0; + pParticle->m_flRoll = random->RandomFloat( 180, 360 ); + pParticle->m_flRollDelta = random->RandomFloat( -1, 1 ); + pParticle->m_uchColor[0] = r; + pParticle->m_uchColor[1] = g; + pParticle->m_uchColor[2] = b; + } + + // If we're really hurt, start burning + if ( flDamaged > 0.25 ) + { + CSmartPtr<CObjectFireParticles> pFireEmitter = CObjectFireParticles::Create( "DrawDamageEffects 1" ); + pFireEmitter->SetSortOrigin( vecFire ); + PMaterialHandle hSphereMaterial = pFireEmitter->GetPMaterial( "sprites/floorflame" ); + ObjectFireParticle *pParticle = (ObjectFireParticle *) pFireEmitter->AddParticle( sizeof(ObjectFireParticle), hSphereMaterial, vecFire ); + if ( pParticle ) + { + pParticle->m_hParent = this; + pParticle->m_iAttachmentPoint = iFireAttachment; + + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = 1.0; + pParticle->m_uchStartSize = MAX( 5, 30 * (flDamaged - 0.25) ); + pParticle->m_uchEndSize = pParticle->m_uchStartSize; + pParticle->m_vecVelocity = Vector(0,0,1); + pParticle->m_uchStartAlpha = 255; + pParticle->m_uchEndAlpha = 255; + pParticle->m_flRoll = 0; + pParticle->m_flRollDelta = 0; + } + } + + // Sparks + for ( float flSparks = flDamaged - 0.3; flSparks > 0; flSparks -= 0.3 ) + { + // Get random spark attachment point + iSparkAttachment = LookupRandomAttachment( "d_spark" ); + if ( !GetAttachment( iSparkAttachment, vecSpark, angSpark ) ) + { + vecSpark = vecOrigin; + angSpark = QAngle(0,0,0); + } + + g_pEffects->Sparks( vecSpark ); + } + + m_flNextEffect = gpGlobals->curtime + random->RandomFloat( 0.2, 0.5 ); +} + +//============================================================================================================ +// POWER PROXY +//============================================================================================================ +class CObjectPowerProxy : public CResultProxy +{ +public: + bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); + void OnBind( void *pC_BaseEntity ); + +private: + CFloatInput m_Factor; +}; + +bool CObjectPowerProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) +{ + if (!CResultProxy::Init( pMaterial, pKeyValues )) + return false; + + if (!m_Factor.Init( pMaterial, pKeyValues, "scale", 1 )) + return false; + + return true; +} + +void CObjectPowerProxy::OnBind( void *pRenderable ) +{ + // Find the view angle between the player and this entity.... + IClientRenderable *pRend = (IClientRenderable *)pRenderable; + C_BaseEntity *pEntity = pRend->GetIClientUnknown()->GetBaseEntity(); + C_BaseObject *pObject = dynamic_cast<C_BaseObject*>(pEntity); + if (!pObject) + return; + + int iPowered = pObject->IsPowered(); + + SetFloatResult( iPowered * m_Factor.GetFloat() ); +} + +EXPOSE_INTERFACE( CObjectPowerProxy, IMaterialProxy, "ObjectPower" IMATERIAL_PROXY_INTERFACE_VERSION ); + +//----------------------------------------------------------------------------- +// Control screen +//----------------------------------------------------------------------------- +class CBasicControlPanel : public CObjectControlPanel +{ + DECLARE_CLASS( CBasicControlPanel, CObjectControlPanel ); + +public: + CBasicControlPanel( vgui::Panel *parent, const char *panelName ); +}; + + +DECLARE_VGUI_SCREEN_FACTORY( CBasicControlPanel, "basic_control_panel" ); + + +//----------------------------------------------------------------------------- +// Constructor: +//----------------------------------------------------------------------------- +CBasicControlPanel::CBasicControlPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, "CBasicControlPanel" ) +{ +} diff --git a/game/client/tf2/c_baseobject.h b/game/client/tf2/c_baseobject.h new file mode 100644 index 0000000..a26ade8 --- /dev/null +++ b/game/client/tf2/c_baseobject.h @@ -0,0 +1,223 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Clients CBaseObject +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_BASEOBJECT_H +#define C_BASEOBJECT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "baseobject_shared.h" +#include <vgui_controls/Panel.h> +#include <vgui_controls/Label.h> +#include "vgui_healthbar.h" +#include "commanderoverlay.h" +#include "hud_minimap.h" +#include "particlemgr.h" +#include "particle_prototype.h" +#include "particle_util.h" +#include "c_basecombatcharacter.h" +#include "ihasbuildpoints.h" + +class C_BaseTFPlayer; + +// Max Length of ID Strings +#define MAX_ID_STRING 256 + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_BaseObject : public C_BaseCombatCharacter, public IHasBuildPoints +{ + DECLARE_CLASS( C_BaseObject, C_BaseCombatCharacter ); +public: + DECLARE_CLIENTCLASS(); + DECLARE_ENTITY_PANEL(); + DECLARE_MINIMAP_PANEL(); + + C_BaseObject(); + ~C_BaseObject( void ); + + virtual bool IsBaseObject( void ) const { return true; } + virtual bool IsAnUpgrade(void ) const { return false; } + virtual bool IsAVehicle( void ) const { return false; } + + virtual void SetType( int iObjectType ); + + virtual void AddEntity(); + virtual void Select( void ); + + void SetActivity( Activity act ); + Activity GetActivity( ) const; + void SetObjectSequence( int sequence ); + virtual void OnActivityChanged( Activity act ); + + virtual void PreDataUpdate( DataUpdateType_t updateType ); + virtual void PostDataUpdate( DataUpdateType_t updateType ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void Release( void ); + + virtual int GetHealth() const { return m_iHealth; } + void SetHealth( int health ) { m_iHealth = health; } + virtual int GetMaxHealth() const { return m_iMaxHealth; } + int GetObjectFlags( void ) { return m_fObjectFlags; } + void SetObjectFlags( int flags ) { m_fObjectFlags = flags; } + + // Derive to customize an object's attached version + virtual void SetupAttachedVersion( void ) { return; } + virtual void SetupUnattachedVersion( void ) { return; } + virtual void OnLostPower( void ) { return; }; + + virtual const char *GetTargetDescription( void ) const; + virtual char *GetIDString( void ); + virtual bool IsValidIDTarget( void ); + + void AttemptToGoActive( void ); + virtual bool ShouldBeActive( void ); + virtual void OnGoActive( void ); + virtual void OnGoInactive( void ); + + virtual void SetDormant( bool bDormant ); + + void SendClientCommand( const char *pCmd ); + + virtual void FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options ); + + // Builder preview... + void ActivateYawPreview( bool enable ); + void PreviewYaw( float yaw ); + bool IsPreviewingYaw() const; + + // This is called to get the initial builder yaw... + virtual float GetInitialBuilderYaw(); + + virtual void RecalculateIDString( void ); + + int GetType() const { return m_iObjectType; } + bool IsOwnedByLocalPlayer() const; + C_BaseTFPlayer *GetOwner(); + + // Are we under attack? + bool IsUnderAttack( ); + + virtual int DrawModel( int flags ); + virtual bool IsIdentityBrush( void ); + + // Effects + void DrawRunningEffects( void ); + void DrawBuildEffects( void ); + void DrawDamageEffects( void ); + + // Deterioration + bool IsDeteriorating( void ) { return m_bDeteriorating; }; + + float GetPercentageConstructed( void ) { return m_flPercentageConstructed; } + + bool IsPlacing( void ) const { return m_bPlacing; } + bool IsBuilding( void ) const { return m_bBuilding; } + + virtual void FinishedBuilding( void ) { return; } + + virtual bool OffsetObjectOrigin( Vector& origin ); + + virtual const char* GetStatusName() const; + + // Object Previews + void HighlightBuildPoints( int flags ); + +public: + // Client/Server shared build point code + void CreateBuildPoints( void ); + void AddAndParseBuildPoint( int iAttachmentNumber, KeyValues *pkvBuildPoint ); + virtual int AddBuildPoint( int iAttachmentNum ); + virtual void AddValidObjectToBuildPoint( int iPoint, int iObjectType ); + virtual CBaseObject *GetBuildPointObject( int iPoint ); + bool IsBuiltOnAttachment( void ) { return (m_hBuiltOnEntity != NULL); } + void AttachObjectToObject( CBaseEntity *pEntity, int iPoint, Vector &vecOrigin ); + CBaseObject *GetParentObject( void ); + void SetBuildPointPassenger( int iPoint, int iPassenger ); + int GetBuildPointPassenger( int iPoint ) const; + + // Build points + CUtlVector<BuildPoint_t> m_BuildPoints; + + // Power + bool IsPowered( void ); + virtual bool CanPowerupEver( int iPowerup ); + virtual bool CanPowerupNow( int iPowerup ); + + bool IsDisabled( void ) { return m_bDisabled; } + + virtual float GetSapperAttachTime( void ); + +// IHasBuildPoints +public: + virtual int GetNumBuildPoints( void ) const; + virtual bool GetBuildPoint( int iPoint, Vector &vecOrigin, QAngle &vecAngles ); + virtual int GetBuildPointAttachmentIndex( int iPoint ) const; + virtual bool CanBuildObjectOnBuildPoint( int iPoint, int iObjectType ); + virtual void SetObjectOnBuildPoint( int iPoint, CBaseObject *pObject ); + virtual float GetMaxSnapDistance( int iBuildPoint ); + virtual bool ShouldCheckForMovement( void ) { return true; } + virtual int GetNumObjectsOnMe( void ); + virtual CBaseEntity *GetFirstObjectOnMe( void ); + virtual CBaseObject *GetObjectOfTypeOnMe( int iObjectType ); + virtual void RemoveAllObjects( void ); + virtual int FindObjectOnBuildPoint( CBaseObject *pObject ); + virtual void GetExitPoint( CBaseEntity *pPlayer, int iPoint, Vector *pAbsOrigin, QAngle *pAbsAngles ); + + virtual bool TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ); + +protected: + char m_szIDString[ MAX_ID_STRING ]; + +private: + enum + { + YAW_PREVIEW_OFF = 0, + YAW_PREVIEW_ON, + YAW_PREVIEW_WAITING_FOR_UPDATE + }; + + Activity m_Activity; + + int m_fObjectFlags; + float m_fYawPreview; + char m_YawPreviewState; + CHandle< C_BaseTFPlayer > m_hOldOwner; + CHandle< C_BaseTFPlayer > m_hBuilder; + bool m_bWasActive; + int m_iOldHealth; + bool m_bHasSapper; + bool m_bOldSapper; + int m_iObjectType; + int m_iHealth; + int m_iMaxHealth; + bool m_bWasBuilding; + bool m_bBuilding; + bool m_bPlacing; + bool m_bDeteriorating; + bool m_bDisabled; + float m_flPercentageConstructed; + EHANDLE m_hBuiltOnEntity; + + CHealthBarPanel *m_pHealthBar; + vgui::Label *m_pNameLabel; + float m_flDamageFlash; // Used to flash the panel when the object takes damage + int m_iFlashes; + + float m_flAttackTime; + CMaterialReference m_ThermalMaterial; + + // Effects + float m_flNextEffect; + +private: + C_BaseObject( const C_BaseObject & ); // not defined, not accessible +}; + +#endif // C_BASEOBJECT_H diff --git a/game/client/tf2/c_basetfplayer.cpp b/game/client/tf2/c_basetfplayer.cpp new file mode 100644 index 0000000..a85c2ed --- /dev/null +++ b/game/client/tf2/c_basetfplayer.cpp @@ -0,0 +1,2705 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_basetfplayer.h" +#include "beamdraw.h" +#include <stdarg.h> +#include "ivmodemanager.h" +#include "shake.h" +#include "ivieweffects.h" +#include "c_tfteam.h" +#include "view.h" +#include "UserCmd.h" +#include "ivrenderview.h" +#include "model_types.h" +#include "view_shared.h" +#include "hud_orders.h" +#include "weapon_twohandedcontainer.h" +#include "particles_simple.h" +#include "playerandobjectenumerator.h" +#include "iclientvehicle.h" +#include "input.h" +#include "basetfvehicle.h" +#include "c_vehicle_teleport_station.h" +#include "weapon_combatshield.h" +#include "hud_vehicle_role.h" +#include "hud_technologytreedoc.h" +#include "iclientmode.h" +#include "weapon_selection.h" +#include "clienteffectprecachesystem.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +// Don't alias here +#if defined( CBaseTFPlayer ) +#undef CBaseTFPlayer +#endif + +void CAM_ToThirdPerson(void); +void CAM_ToFirstPerson(void); +void FX_ReconParticle( const Vector &vecOrigin, bool bBlue ); + +static ConVar tf2_showstate( "tf2_showstate", "0", 0, "Print state name\n" ); +extern ConVar mannedgun_usethirdperson; +ConVar damageboost_modeloffset( "damageboost_modeloffset", "1" ); +ConVar damageboost_modelphasespeed_min( "damageboost_modelphasespeed_min", "99" ); +ConVar damageboost_modelphasespeed_max( "damageboost_modelphasespeed_max", "170" ); + + +CLIENTEFFECT_REGISTER_BEGIN( PrecacheBaseTFPlayer ) +CLIENTEFFECT_MATERIAL( "sprites/physbeam" ) +CLIENTEFFECT_MATERIAL( "player/infiltratorcamo/infiltratorcamo" ) +CLIENTEFFECT_REGISTER_END() + + +class CPersonalShieldEffect +{ +public: + + static CPersonalShieldEffect* Create( C_BaseTFPlayer *pEnt, const Vector &vOffsetFromEnt, const Vector &vIncomingDirection, int iDamage ); + + ~CPersonalShieldEffect(); + + // Returns false if the effect is done and should be deleted. + bool Update( float dt ); + + void Render(); // Draw the effect. + +private: + + CPersonalShieldEffect(); + +private: + + CHandle<C_BaseTFPlayer> m_hEnt; + Vector m_vOffsetFromEnt; + Vector m_vIncomingDirection; + float m_flDamage; + + enum + { + NUM_TRACERS = 10 + }; + + Vector m_vTracerEndPoints[NUM_TRACERS]; // These are relative to the model's origin. + float m_flLifetimeRemaining; + float m_flTotalLifetime; +}; + + +CPersonalShieldEffect* CPersonalShieldEffect::Create( + C_BaseTFPlayer *pEnt, + const Vector &vOffsetFromEnt, + const Vector &vIncomingDirection, + int iDamage ) +{ + CPersonalShieldEffect *pRet = new CPersonalShieldEffect; + if ( pRet ) + { + pRet->m_hEnt = pEnt; + pRet->m_vOffsetFromEnt = vOffsetFromEnt; + pRet->m_flDamage = iDamage; + + Vector vNormal = vIncomingDirection; + VectorNormalize( vNormal ); + + for ( int i=0; i < CPersonalShieldEffect::NUM_TRACERS; i++ ) + { + pRet->m_vTracerEndPoints[i] = pRet->m_vOffsetFromEnt; + + Vector vOffset = RandomVector( -1, 1 ); + + // Make it tangent to a sphere enclosing the player. + float flDot = vNormal.Dot( vOffset ); + vOffset -= vNormal * flDot; + + VectorNormalize( vOffset ); + vOffset *= 10; + + pRet->m_vTracerEndPoints[i] += vOffset; + } + + pRet->m_flLifetimeRemaining = pRet->m_flTotalLifetime = 0.15; + pRet->m_vIncomingDirection = vIncomingDirection; + } + return pRet; +} + +CPersonalShieldEffect::CPersonalShieldEffect() +{ +} + + +CPersonalShieldEffect::~CPersonalShieldEffect() +{ +} + + +bool CPersonalShieldEffect::Update( float dt ) +{ + if ( !m_hEnt.Get() ) + return false; + + m_flLifetimeRemaining -= dt; + if ( m_flLifetimeRemaining >= 0 ) + { + return true; + } + else + { + return false; + } +} + + +void CPersonalShieldEffect::Render() +{ + if ( !m_hEnt.Get() ) + return; + + Vector vCenter = m_hEnt->WorldSpaceCenter( ); + + const Vector vBasePos = vCenter + m_vOffsetFromEnt; + IMaterial *pMat = materials->FindMaterial( "sprites/physbeam", TEXTURE_GROUP_CLIENT_EFFECTS ); + + CBeamSeg seg; + + // Get redder as their health goes down. + float flColor = (float)m_hEnt->GetHealth() / m_hEnt->GetMaxHealth(); + flColor = clamp(flColor, 0, 1); + seg.m_vColor.Init( 0.5 + 0.5*flColor, flColor, flColor ); + + seg.m_flAlpha = 1; + seg.m_flTexCoord = 0; + seg.m_flWidth = 2; + + for ( int i=0; i < CPersonalShieldEffect::NUM_TRACERS; i++ ) + { + const Vector vEndPos = vCenter + m_vTracerEndPoints[i]; + + static int nSegs = 5; + + CBeamSegDraw beamDraw; + beamDraw.Start( nSegs, pMat ); + + for ( int iSeg=0; iSeg < nSegs; iSeg++ ) + { + float t = (float)iSeg / (nSegs-1); + VectorLerp( vBasePos, vEndPos, t, seg.m_vPos ); + + // Add a random offset. + seg.m_vPos += RandomVector( -3, 3 ); + seg.m_flTexCoord += 0.1f; + + beamDraw.NextSeg( &seg ); + } + + beamDraw.End(); + } + +/* + Vector vEggBounds[2]; + m_hEnt->GetBounds( vEggBounds[0], vEggBounds[1] ); + vEggBounds[0] += m_hEnt->GetAbsOrigin(); + vEggBounds[1] += m_hEnt->GetAbsOrigin(); + Vector vEggCenter = (vEggBounds[0] + vEggBounds[1]) * 0.5f; + Vector vEggDims = (vEggBounds[1] - vEggBounds[0]) * 0.5f; + + Vector vUp( 0, 0, 1 ); + Vector vForward = m_vIncomingDirection; + vForward.z = 0; + VectorNormalize( vForward ); + Vector vRight = vUp.Cross( vForward ); + + // Now draw an eggshell around the player showing their health. + seg.m_vColor.Init( 1, flColor, flColor ); + seg.m_flAlpha = 0.3f; + seg.m_flWidth = 1; + + static int nSamples = 30; + CBeamSegDraw beamDraw; + beamDraw.Start( nSamples, pMat ); + + for ( int iSeg=0; iSeg < nSamples; iSeg++ ) + { + float t = (float)iSeg / (nSamples-1); + float angle = M_PI * 2.0f * t; + seg.m_vPos = vEggCenter + vUp*vEggDims.z*sin( angle ) + vRight*vEggDims.x*cos( angle ); + beamDraw.NextSeg( &seg ); + } + + beamDraw.End(); +*/ +} + + +//----------------------------------------------------------------------------- +// Purpose: Helper for animation state machine +// Input : clear - +// destination - +// *pFormat - +// ... - +//----------------------------------------------------------------------------- +void StatusPrintf( bool clear, int destination, char *pFormat, ... ) +{ + if ( destination != 4 && destination != 5 ) + return; + char data[ 2048 ]; + va_list argptr; + + va_start( argptr, pFormat ); + Q_vsnprintf( data, sizeof( data ), pFormat, argptr ); + va_end( argptr ); + + char *out = data; + if ( destination == 5 ) + out += 2; + + if ( destination == 5 ) + { + char slot[3]; + Q_strncpy( slot, data, 3 ); + + slot[2] = 0; + + int s = atoi( slot ); + s &= 31; + + engine->Con_NPrintf( s, "%s", out ); + } + else + { + Msg( "%s", out ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: RecvProxy that converts the Player's object UtlVector to entindexes +//----------------------------------------------------------------------------- +void RecvProxy_PlayerObjectList( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + CTFPlayerLocalData *pLocalData = (CTFPlayerLocalData*)pStruct; + CBaseHandle *pHandle = (CBaseHandle*)(&(pLocalData->m_aObjects[pData->m_iElement])); + RecvProxy_IntToEHandle( pData, pStruct, pHandle ); +} + + +void RecvProxyArrayLength_PlayerObjects( void *pStruct, int objectID, int currentArrayLength ) +{ + CTFPlayerLocalData *pLocalData = (CTFPlayerLocalData*)pStruct; + + if ( pLocalData->m_aObjects.Count() != currentArrayLength ) + { + pLocalData->m_aObjects.SetSize( currentArrayLength ); + } +} + +BEGIN_RECV_TABLE_NOBASE( CTFPlayerLocalData, DT_TFLocal ) + RecvPropInt( RECVINFO(m_nInTacticalView) ), + RecvPropInt( RECVINFO( m_bKnockedDown )), + RecvPropVector( RECVINFO( m_vecKnockDownDir )), + RecvPropInt( RECVINFO( m_bThermalVision )), + RecvPropInt( RECVINFO( m_iIDEntIndex )), + RecvPropArray( RecvPropInt( RECVINFO(m_iResourceAmmo[0])), m_iResourceAmmo), + RecvPropInt( RECVINFO(m_iBankResources) ), + RecvPropArray2( + RecvProxyArrayLength_PlayerObjects, + RecvPropInt( "player_object_array_element", 0, SIZEOF_IGNORE, 0, RecvProxy_PlayerObjectList ), + MAX_OBJECTS_PER_PLAYER, + 0, + "player_object_array" ), + RecvPropInt( RECVINFO( m_bAttachingSapper ) ), + RecvPropFloat( RECVINFO( m_flSapperAttachmentFrac ) ), + RecvPropInt( RECVINFO( m_bForceMapOverview ) ), +END_RECV_TABLE() + +IMPLEMENT_CLIENTCLASS_DT(C_BaseTFPlayer, DT_BaseTFPlayer, CBaseTFPlayer) + RecvPropDataTable(RECVINFO_DT(m_TFLocal),0, &REFERENCE_RECV_TABLE(DT_TFLocal), DataTableRecvProxy_StaticDataTable), + + // Class Data Tables + RecvPropInt( RECVINFO(m_iPlayerClass)), + RecvPropDataTable( RECVINFO_DT( m_PlayerClasses ), 0, &REFERENCE_RECV_TABLE( DT_AllPlayerClasses ), DataTableRecvProxy_StaticDataTable ), + + RecvPropEHandle( RECVINFO( m_hSelectedMCV ) ), + RecvPropInt( RECVINFO(m_iCurrentZoneState ) ), + RecvPropInt( RECVINFO(m_iMaxHealth ) ), + RecvPropInt( RECVINFO(m_TFPlayerFlags) ), + RecvPropInt( RECVINFO( m_bUnderAttack )), + RecvPropInt( RECVINFO( m_bIsBlocking )), + + // Sniper - will get moved to a class data table + RecvPropVector( RECVINFO(m_vecDeployedAngles) ), + RecvPropInt( RECVINFO( m_bDeployed )), + RecvPropInt( RECVINFO( m_bDeploying )), + RecvPropInt( RECVINFO( m_bUnDeploying )), + + // Infiltrator - will get moved to a class data table + RecvPropFloat( RECVINFO( m_flCamouflageAmount )), + RecvPropEHandle(RECVINFO(m_hSpawnPoint)), +END_RECV_TABLE() + +BEGIN_PREDICTION_DATA_NO_BASE( CTFPlayerLocalData ) + + DEFINE_PRED_FIELD( m_nInTacticalView, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_bKnockedDown, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_vecKnockDownDir, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_bThermalVision, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), +// DEFINE_PRED_FIELD( m_iIDEntIndex, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_iBankResources, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_ARRAY( m_iResourceAmmo, FIELD_INTEGER, RESOURCE_TYPES, FTYPEDESC_INSENDTABLE ), + //DEFINE_PRED_ARRAY( m_aObjects, FIELD_EHANDLE, MAX_OBJECTS_PER_PLAYER, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_bAttachingSapper, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_flSapperAttachmentFrac, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_bForceMapOverview, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), + +END_PREDICTION_DATA() + + +// TODO: consolidate all these includes and the DEFINE_PRED... for each class type +// into tf_shareddefs.h. +#include "c_tf_class_commando.h" +#include "c_tf_class_defender.h" +#include "c_tf_class_escort.h" +#include "c_tf_class_infiltrator.h" +#include "c_tf_class_medic.h" +#include "c_tf_class_recon.h" +#include "c_tf_class_sniper.h" +#include "c_tf_class_support.h" +#include "c_tf_class_sapper.h" +#include "c_tf_class_pyro.h" + + +BEGIN_PREDICTION_DATA( C_BaseTFPlayer ) + + DEFINE_PRED_TYPEDESCRIPTION( m_TFLocal, CTFPlayerLocalData ), + + DEFINE_PRED_FIELD( m_flCycle, FIELD_FLOAT, FTYPEDESC_INSENDTABLE | FTYPEDESC_PRIVATE | FTYPEDESC_OVERRIDE ), + DEFINE_PRED_FIELD( m_flPlaybackRate, FIELD_FLOAT, FTYPEDESC_INSENDTABLE | FTYPEDESC_PRIVATE | FTYPEDESC_OVERRIDE ), + + DEFINE_PRED_TYPEDESCRIPTION_PTR( m_PlayerClasses.m_pClasses[TFCLASS_COMMANDO], C_PlayerClassCommando ), + DEFINE_PRED_TYPEDESCRIPTION_PTR( m_PlayerClasses.m_pClasses[TFCLASS_DEFENDER], C_PlayerClassDefender ), + DEFINE_PRED_TYPEDESCRIPTION_PTR( m_PlayerClasses.m_pClasses[TFCLASS_ESCORT], C_PlayerClassEscort ), + DEFINE_PRED_TYPEDESCRIPTION_PTR( m_PlayerClasses.m_pClasses[TFCLASS_INFILTRATOR], C_PlayerClassInfiltrator ), + DEFINE_PRED_TYPEDESCRIPTION_PTR( m_PlayerClasses.m_pClasses[TFCLASS_MEDIC], C_PlayerClassMedic ), + DEFINE_PRED_TYPEDESCRIPTION_PTR( m_PlayerClasses.m_pClasses[TFCLASS_RECON], C_PlayerClassRecon ), + DEFINE_PRED_TYPEDESCRIPTION_PTR( m_PlayerClasses.m_pClasses[TFCLASS_SNIPER], C_PlayerClassSniper ), + DEFINE_PRED_TYPEDESCRIPTION_PTR( m_PlayerClasses.m_pClasses[TFCLASS_SUPPORT], C_PlayerClassSupport ), + DEFINE_PRED_TYPEDESCRIPTION_PTR( m_PlayerClasses.m_pClasses[TFCLASS_SAPPER], C_PlayerClassSapper ), + + DEFINE_PRED_FIELD( m_iPlayerClass, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_flCamouflageAmount, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_hSpawnPoint, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_iMaxHealth, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_bDeployed, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_bDeploying, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_bUnDeploying, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_vecDeployedAngles, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_iCurrentZoneState, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_TFPlayerFlags, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_bUnderAttack, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), + + DEFINE_PRED_FIELD( m_vecConstraintCenter, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_flConstraintRadius, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_flConstraintWidth, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_flConstraintSpeedFactor, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), + + DEFINE_FIELD( m_vecPosDelta, FIELD_VECTOR ), + DEFINE_ARRAY( m_aMomentum, FIELD_FLOAT, C_BaseTFPlayer::MOMENTUM_MAXSIZE ), + DEFINE_FIELD( m_iMomentumHead, FIELD_INTEGER ), + //DEFINE_FIELD( m_iSelectedTarget, FIELD_INTEGER ), + //DEFINE_FIELD( m_iPersonalTarget, FIELD_INTEGER ), + //DEFINE_FIELD( m_iLastHealth, FIELD_INTEGER ), + //DEFINE_FIELD( m_nOldTacticalView, FIELD_INTEGER ), + //DEFINE_FIELD( m_nOldPlayerClass, FIELD_INTEGER ), + //DEFINE_FIELD( m_bOldThermalVision, FIELD_BOOLEAN ), + //DEFINE_FIELD( m_bOldKnockDownState, FIELD_BOOLEAN ), + //DEFINE_FIELD( m_flStartKnockdown, FIELD_FLOAT ), + //DEFINE_FIELD( m_flEndKnockdown, FIELD_FLOAT ), + //DEFINE_FIELD( m_vecOriginalViewAngles, FIELD_VECTOR ), + //DEFINE_FIELD( m_vecCurrentKnockdownAngles, FIELD_VECTOR ), + //DEFINE_FIELD( m_vecKnockDownGoalAngles, FIELD_VECTOR ), + //DEFINE_FIELD( m_bKnockdownOverrideAngles, FIELD_BOOLEAN ), + //DEFINE_FIELD( m_flKnockdownViewheightAdjust, FIELD_FLOAT ), + //DEFINE_FIELD( m_flLastMoveTime, FIELD_FLOAT ), + //DEFINE_FIELD( m_vecLastOrigin, FIELD_VECTOR ), + //DEFINE_FIELD( m_flLastDamageTime, FIELD_FLOAT ), + //DEFINE_FIELD( m_flLastGainHealthTime, FIELD_FLOAT ), + //DEFINE_FIELD( m_flDampeningAmount, FIELD_FLOAT ), + //DEFINE_FIELD( m_flGoalDampeningAmount, FIELD_FLOAT ), + //DEFINE_FIELD( m_flDampeningStayoutTime, FIELD_FLOAT ), + //DEFINE_FIELD( m_flMovementCamoSuppression, FIELD_FLOAT ), + //DEFINE_FIELD( m_flGoalMovementCamoSuppressionAmount, FIELD_FLOAT ), + //DEFINE_FIELD( m_flMovementCamoSuppressionStayoutTime, FIELD_FLOAT ), + //DEFINE_FIELD( m_flNextAdrenalinEffect, FIELD_FLOAT ), + //DEFINE_FIELD( m_bFadingIn, FIELD_BOOLEAN ), + //DEFINE_FIELD( m_iIDEntIndex, FIELD_INTEGER ), + //DEFINE_ARRAY( m_BoostModelAngles, FIELD_FLOAT, 3 ), + + // DEFINE_PRED_TYPEDESCRIPTION( m_RideVehicle, CRideVehicle ), + // DEFINE_FIELD( m_aTargetReticles, CUtlVector < CTargetReticle * > ), + // DEFINE_FIELD( m_aSpyCameras, CUtlVector < C_SpyCamera * > ), + // DEFINE_FIELD( m_ParticleEffect, CParticleEffectBinding ), + // DEFINE_FIELD( m_ParticleTimer, TimedEvent ), + // DEFINE_FIELD( m_MaterialHandle, PMaterialHandle ), + // DEFINE_FIELD( m_pParticleMgr, CParticleMgr ), + // DEFINE_FIELD( m_pThermalMaterial, IMaterial ), + // DEFINE_FIELD( m_pCamoEffectMaterial, IMaterial ), + // DEFINE_FIELD( m_BoostMaterial, CMaterialReference ), + // DEFINE_FIELD( m_EMPMaterial, CMaterialReference ), + // DEFINE_FIELD( m_PersonalShieldEffects, CUtlLinkedList < CPersonalShieldEffect* , int > ), + // DEFINE_FIELD( m_hSelectedOrder, CHandle < C_Order > ), + // DEFINE_FIELD( m_hPersonalOrder, FIELD_EHANDLE ), + // DEFINE_FIELD( m_hSelectedObject, CHandle < C_BaseObject > ), + +END_PREDICTION_DATA() + +LINK_ENTITY_TO_CLASS( player, C_BaseTFPlayer ); + +ConVar cl_TargetInfoFadeDist("cl_TargetInfoFadeDist", "800", 0, "Distance at which TF player targetting info fades out."); + +//----------------------------------------------------------------------------- +// Purpose: Return true if the local player is the specified class +//----------------------------------------------------------------------------- +bool IsLocalPlayerClass( int iClass ) +{ + C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + if ( pPlayer ) + { + return ( pPlayer->PlayerClass() == iClass ); + } + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Return the local player's class +//----------------------------------------------------------------------------- +int GetLocalPlayerClass( void ) +{ + C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + if ( pPlayer ) + { + return pPlayer->PlayerClass(); + } + return TFCLASS_UNDECIDED; +} + +//----------------------------------------------------------------------------- +// returns true if the local player is in tactical view +//----------------------------------------------------------------------------- +bool IsLocalPlayerInTactical( void ) +{ + C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + if (!pPlayer) + return false; + + return !!pPlayer->m_TFLocal.m_nInTacticalView; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_BaseTFPlayer::C_BaseTFPlayer() : + m_PlayerClasses( this ), m_PlayerAnimState( this ) +{ + Clear(); +} + +void C_BaseTFPlayer::Clear() +{ + m_iPlayerClass = TFCLASS_UNDECIDED; + m_iCurrentZoneState = 0; + m_TFPlayerFlags = 0; + m_hSelectedOrder = NULL; + m_hPersonalOrder = NULL; + m_hSelectedObject = NULL; + m_iSelectedTarget = 0; + m_iPersonalTarget = 0; + m_iIDEntIndex = 0; + m_bStoreRagdollInfo = true; + m_flNextUseCheck = 0; + m_pSapperAttachmentStatus = NULL; + + int i; + for ( i=0; i < ARRAYSIZE( m_BoostModelAngles ); i++ ) + { + m_BoostModelAngles[i] = RandomFloat( 0, 360 ); + } + + + for ( i = 0; i < MOMENTUM_MAXSIZE; i++ ) + { + m_aMomentum[ i ] = 1.0f; + } +} + + +bool C_BaseTFPlayer::IsHidden() const +{ + return (m_TFPlayerFlags & TF_PLAYER_HIDDEN) != 0; +} + + +bool C_BaseTFPlayer::IsDamageBoosted() const +{ + return (m_TFPlayerFlags & TF_PLAYER_DAMAGE_BOOST) != 0; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_BaseTFPlayer::~C_BaseTFPlayer() +{ + int iSize = m_aTargetReticles.Size(); + for (int i = iSize-1; i >= 0; i-- ) + { + delete m_aTargetReticles[i]; + } + m_aTargetReticles.Purge(); + + if ( m_pThermalMaterial ) + { + m_pThermalMaterial->DecrementReferenceCount(); + } + if ( m_pCamoEffectMaterial ) + { + m_pCamoEffectMaterial->DecrementReferenceCount(); + } + + m_PersonalShieldEffects.PurgeAndDeleteElements(); + + if ( m_pSapperAttachmentStatus ) + { + delete m_pSapperAttachmentStatus; + } +} + +//----------------------------------------------------------------------------- +// Add, remove object from the panel +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::SetDormant( bool bDormant ) +{ + BaseClass::SetDormant( bDormant ); + ENTITY_PANEL_ACTIVATE( "player", !bDormant ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_BaseTFPlayer::HasNamedTechnology( const char *name ) +{ + CTechnologyTree *pTree = GetTechnologyTreeDoc().GetTechnologyTree(); + if ( !pTree ) + return false; + + CBaseTechnology *pItem = pTree->GetTechnology(name); + // If the tech doesn't exist, everyone has it by default + if ( !pItem ) + return true; + + return pItem->GetActive(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_BaseTFPlayer::ShouldDraw() +{ + if ( IsHidden() ) + return false; + + C_BaseTFPlayer *local = C_BaseTFPlayer::GetLocalPlayer(); + if ( local && local->IsUsingThermalVision() ) + return true; + + // Draw the local player if he's the driver of a vehicle. + // We can safely return true here because vehicles will hide drivers that shouldn't be visible. + if ( mannedgun_usethirdperson.GetInt() && IsVehicleMounted() && IsLocalPlayer() ) + { + IClientVehicle *pVehicle = GetVehicle(); + int nRole = pVehicle->GetPassengerRole( this ); + if ( nRole == VEHICLE_ROLE_DRIVER ) + return !IsEffectActive(EF_NODRAW); + } + + return BaseClass::ShouldDraw(); +} + + +//----------------------------------------------------------------------------- +// Should this object cast shadows? +//----------------------------------------------------------------------------- +ShadowType_t C_BaseTFPlayer::ShadowCastType() +{ + // FIXME: This check can be removed once we've dealt with the interpolation problem + C_BaseTFPlayer *local = C_BaseTFPlayer::GetLocalPlayer(); + if (local == this) + return SHADOWS_NONE; + + if (IsCamouflaged()) + return SHADOWS_NONE; + + return SHADOWS_RENDER_TO_TEXTURE_DYNAMIC; +} + + +//----------------------------------------------------------------------------- +// Purpose: Called once per frame for the local player only. +// Called after rendering ( called in PostRender() ) the 3d objects ( i.e., other players ) +// but before vgui paints 2d overlays so that we can update the positions of all world +// targets before rendering +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::UpdateTargetReticles( void ) +{ + // Update all the target reticles + for ( int i = 0; i < m_aTargetReticles.Size(); i++ ) + { + m_aTargetReticles[i]->Update(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Called to update hud elements contained in the player +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::ClientThink( void ) +{ + BaseClass::ClientThink(); + + SetNextClientThink( CLIENT_THINK_ALWAYS ); + + CheckKnockdownState(); + CheckMovementCamoSuppression(); + CheckCamoDampening(); + CheckLastMovement(); + CheckAdrenalin(); + UpdateIDTarget(); + + // update personal shield effects. + int iNext; + for ( int i=m_PersonalShieldEffects.Head(); i != m_PersonalShieldEffects.InvalidIndex(); i = iNext ) + { + iNext = m_PersonalShieldEffects.Next( i ); + CPersonalShieldEffect *pEffect = m_PersonalShieldEffects[i]; + + if ( !pEffect->Update( gpGlobals->frametime ) ) + { + delete pEffect; + m_PersonalShieldEffects.Remove( i ); + } + } + + // Let the classes think as well. + if ( GetPlayerClass() ) + { + GetPlayerClass()->ClassThink(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Store off old movetype ( commander or not ) +// Input : bnewentity - +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::OnPreDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnPreDataChanged( updateType ); + + m_nOldTacticalView = m_TFLocal.m_nInTacticalView; + + m_iLastHealth = GetHealth(); + m_bOldKnockDownState = m_TFLocal.m_bKnockedDown; + + m_bOldThermalVision = m_TFLocal.m_bThermalVision; + + m_nOldPlayerClass = m_iPlayerClass; + + // Chain. + if ( GetPlayerClass() ) + { + GetPlayerClass()->ClassPreDataUpdate(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Switch to/from commander mode if necessary +// Input : bnewentity - +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::OnDataChanged( DataUpdateType_t updateType ) +{ + bool bnewentity = (updateType == DATA_UPDATE_CREATED); + if ( bnewentity ) + { + // Do the minimap panel thing here because we don't + // want predicted players to have traces + CONSTRUCT_MINIMAP_PANEL( "minimap_player", MINIMAP_PLAYERS ); + + SetNextClientThink( CLIENT_THINK_ALWAYS ); + m_BoostMaterial.Init( "player/damageboost/thermal", TEXTURE_GROUP_CLIENT_EFFECTS ); + m_EMPMaterial.Init( "player/empeffect", TEXTURE_GROUP_CLIENT_EFFECTS ); + } + + BaseClass::OnDataChanged( updateType ); + + // Only care about this stuff for the local player + if ( IsLocalPlayer() ) + { + // Check to see if we switched into/out of the commander mode. + if ( m_TFLocal.m_nInTacticalView != m_nOldTacticalView ) + { + // Is this the local player + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + if ( player == this ) + { + // Tell mode switcher that server changed our mode + modemanager->SwitchMode( m_TFLocal.m_nInTacticalView ? true : false, false ); + } + } + + // Knockdown + if ( m_bOldKnockDownState != m_TFLocal.m_bKnockedDown ) + { + if ( IsKnockedDown() ) + { + m_flStartKnockdown = gpGlobals->curtime; + m_vecOriginalViewAngles = GetAbsAngles(); + + m_vecKnockDownGoalAngles = m_TFLocal.m_vecKnockDownDir; + } + else + { + m_flEndKnockdown = gpGlobals->curtime; + } + } + + // Thermal Vision + if ( m_bOldThermalVision != m_TFLocal.m_bThermalVision ) + { + if ( m_TFLocal.m_bThermalVision ) + { + ScreenFade_t sf; + memset( &sf, 0, sizeof( sf ) ); + sf.a = 128; + sf.r = 0; + sf.g = 0; + sf.b = 255; + sf.duration = 0; // not used + sf.holdTime = (float)(1<<SCREENFADE_FRACBITS) * 30.0f; + sf.fadeFlags = FFADE_STAYOUT; + vieweffects->Fade( sf ); + } + else + { + vieweffects->ClearPermanentFades(); + } + } + + if ( m_nOldPlayerClass != m_iPlayerClass ) + { + engine->ClientCmd( "cancelselect\n" ); + } + } + + if ( bnewentity ) + { + m_iLastHealth = GetHealth(); + m_flLastDamageTime = -10000; + m_flLastGainHealthTime = -10000; + } + + if (m_iLastHealth != GetHealth()) + { + if (m_iLastHealth > GetHealth()) + { + if (GetHealth() < GetMaxHealth()) + { + m_flLastDamageTime = gpGlobals->curtime; + + C_TFTeam *pTeam = static_cast<C_TFTeam*>(GetTeam()); + if (pTeam && !IsLocalPlayer() && m_bUnderAttack ) + pTeam->NotifyBaseUnderAttack( GetAbsOrigin(), false ); + } + } + else + { + m_flLastGainHealthTime = gpGlobals->curtime; + + // If we were just fully healed, remove all decals + if ( GetHealth() >= GetMaxHealth() ) + { + RemoveAllDecals(); + } + } + } + + // Snap to 100 % since we round down + if ( m_flCamouflageAmount > 99.0f ) + { + m_flCamouflageAmount = 100.0f; + } + + // Chain. + if ( GetPlayerClass() ) + { + GetPlayerClass()->ClassOnDataChanged(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::PreDataUpdate( DataUpdateType_t updateType ) +{ + BaseClass::PreDataUpdate( updateType ); + + m_bOldAttachingSapper = m_TFLocal.m_bAttachingSapper; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::PostDataUpdate( DataUpdateType_t updateType ) +{ + BaseClass::PostDataUpdate( updateType ); + + // Only care about this stuff for the local player + if ( IsLocalPlayer() ) + { + // Sapper attachment + if ( m_bOldAttachingSapper != m_TFLocal.m_bAttachingSapper || m_TFLocal.m_bAttachingSapper ) + { + if ( !m_pSapperAttachmentStatus ) + { + // Create the attachment status + m_pSapperAttachmentStatus = new CHealthBarPanel(); + vgui::Panel *pParent = g_pClientMode->GetViewport(); + m_pSapperAttachmentStatus->SetParent( pParent ); + m_pSapperAttachmentStatus->SetAutoDelete( false ); + m_pSapperAttachmentStatus->SetPos( XRES(320) - XRES(40), YRES(250) ); + m_pSapperAttachmentStatus->SetSize( XRES(80), YRES(8) ); + m_pSapperAttachmentStatus->SetGoodColor( 240, 180, 63, 192 ); + m_pSapperAttachmentStatus->SetBadColor( 0, 0, 0, 192 ); + } + + m_pSapperAttachmentStatus->SetVisible( m_TFLocal.m_bAttachingSapper ); + if ( m_TFLocal.m_bAttachingSapper ) + { + m_pSapperAttachmentStatus->SetHealth( m_TFLocal.m_flSapperAttachmentFrac ); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::ReceiveMessage( int classID, bf_read &msg ) +{ + if ( classID != GetClientClass()->m_ClassID ) + { + // message is for subclass + BaseClass::ReceiveMessage( classID, msg ); + return; + } + + int messageType = msg.ReadByte(); + switch( messageType ) + { + case BASEENTITY_MSG_REMOVE_DECALS: + { + RemoveAllDecals(); + } + break; + case PLAYER_MSG_PERSONAL_SHIELD: + { + Vector vOffsetFromEnt; + msg.ReadBitVec3Coord( vOffsetFromEnt ); + + // Show a personal shield effect. + Vector vIncomingDirection; + msg.ReadBitVec3Normal( vIncomingDirection ); + + short iDamage = msg.ReadShort(); + + // Show the effect. + CPersonalShieldEffect *pEffect = CPersonalShieldEffect::Create( this, vOffsetFromEnt, vIncomingDirection, iDamage ); + if ( pEffect ) + m_PersonalShieldEffects.AddToTail( pEffect ); + } + break; + default: + break; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Free this entity +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::Release( void ) +{ + // Remove any reticles on this entity + C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + if ( pPlayer ) + { + pPlayer->Remove_Target( this ); + } + + BaseClass::Release(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::ItemPostFrame( void ) +{ + if ( m_flNextUseCheck < gpGlobals->curtime ) + { + m_flNextUseCheck = gpGlobals->curtime + 0.3; + + CVehicleRoleHudElement *pElement = GET_HUDELEMENT( CVehicleRoleHudElement ); + Assert( pElement ); + pElement->ShowVehicleRole( -1 ); + + // See if there's an entity we can +use + if ( IsAlive() && !GetVehicle() && ( gpGlobals->curtime > m_flNextAttack ) ) + { + CBaseEntity *pUseEntity = FindUseEntity(); + if ( pUseEntity ) + { + // Vehicles need to show we're going to get in them + C_BaseTFVehicle *pVehicle = dynamic_cast<C_BaseTFVehicle*>( pUseEntity ); + if ( pVehicle && InSameTeam(pVehicle) && !pVehicle->IsPlacing() && !pVehicle->IsBuilding() && pVehicle->GetMaxPassengerCount() >= 2 ) + { + pElement->ShowVehicleRole( pVehicle->LocateEntryPoint( this ) ); + } + } + } + } + + // Don't process items while in a vehicle. + if ( IsInAVehicle() ) + { + IClientVehicle *pVehicle = GetVehicle(); + Assert( pVehicle ); + + // NOTE: We *have* to do this before ItemPostFrame because ItemPostFrame + // may dump us out of the vehicle + int nRole = pVehicle->GetPassengerRole( this ); + bool bUsingStandardWeapons = pVehicle->IsPassengerUsingStandardWeapons( nRole ); + + pVehicle->ItemPostFrame( this ); + + // Fall through and check weapons, etc. if we're using them + if (!bUsingStandardWeapons || !IsInAVehicle()) + return; + } + + // If we're attaching a sapper, handle player use only + if ( m_TFLocal.m_bAttachingSapper ) + { + PlayerUse(); + return; + } + + BaseClass::ItemPostFrame(); + +#if 0 + if ( GetPlayerClass() ) + { + GetPlayerClass()->ItemPostFrame(); // Let the player class handle it. + } +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: Return true if I'm in a vehicle that's mounted on another vehicle +//----------------------------------------------------------------------------- +bool C_BaseTFPlayer::IsVehicleMounted() const +{ + CBaseTFVehicle *pVehicle = dynamic_cast< CBaseTFVehicle* >( GetMoveParent() ); + if ( pVehicle ) + return dynamic_cast< CBaseTFVehicle* >( pVehicle->GetMoveParent() ) != NULL; + + return false; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int C_BaseTFPlayer::DrawModel( int flags ) +{ + int drawn = 0; + + if ( !m_bReadyToDraw ) + return 0; + + QAngle saveAngles(0,0,0); + Vector saveLocalOrigin(0,0,0); + bool angleschanged = false; + bool originchanged = false; + + // If we're in a vehicle, use the vehicle's angles for the local player + if ( IsInAVehicle() && !IsInAVehicle() ) + { + IClientVehicle *pVehicle = GetVehicle(); + int nRole = pVehicle->GetPassengerRole( this ); + if ( nRole == VEHICLE_ROLE_DRIVER ) + { + C_BaseTFVehicle *pVehicleEntity = (CBaseTFVehicle*)pVehicle->GetVehicleEnt(); + angleschanged = true; + SetLocalAngles( pVehicleEntity->GetPassengerAngles( saveAngles, VEHICLE_ROLE_DRIVER ) ); + + // HACK: Stomp the origin + originchanged = true; + SetLocalOrigin( vec3_origin ); + } + } + else + { + angleschanged = true; + SetLocalAngles( m_PlayerAnimState.GetRenderAngles() ); + } + + drawn = BaseClass::DrawModel(flags); + + if ( angleschanged ) + { + SetLocalAngles( saveAngles ); + } + if ( originchanged ) + { + SetLocalOrigin( saveLocalOrigin ); + } + + // Draw all personal shield effects. + FOR_EACH_LL( m_PersonalShieldEffects, i ) + { + m_PersonalShieldEffects[i]->Render(); + } + + return drawn; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int C_BaseTFPlayer::GetClass( void ) +{ + if ( !GetPlayerClass() ) + return TFCLASS_UNDECIDED; + + return m_iPlayerClass; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::OverrideView( CViewSetup *pSetup ) +{ + if ( CheckKnockdownAngleOverride() ) + { + float adj = GetKnockdownViewheightAdjust(); + + pSetup->origin.z -= adj; + + return; + } + + BaseClass::OverrideView( pSetup ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_BaseTFPlayer::ShouldDrawViewModel() +{ + if ( CheckKnockdownAngleOverride() ) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Hack to search up the hierarchy looking for bones whose ultimate parent is 1 ( i.e., the pelvis ) since +// these are the lower body bones +//----------------------------------------------------------------------------- +bool ParentIsPelvis( mstudiobone_t *bones, int start, int pelvis, int spine ) +{ + int current = start; + + while ( bones[ current ].parent ) + { + // Root? + if ( bones[ current ].parent <= 0 ) + { + return false; + } + + if ( bones[ current ].parent == pelvis ) + return true; + + if ( bones[ current ].parent == spine ) + return false; + + current = bones[ current ].parent; + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Hack to find the bone indices of the pelvis and the spine so we can +// more quickly determine if a bones parent is the pelvis so we can merge bones correctly +//----------------------------------------------------------------------------- +static void FindPelvisAndSpine( int numbones, mstudiobone_t *bones, int *pelvis, int *spine ) +{ + *pelvis = *spine = -1; + + mstudiobone_t *bone = bones; + for ( int i = 0; i < numbones; i++, bone++ ) + { + if ( !stricmp( bone->pszName(), "Bip01 Pelvis" ) ) + { + *pelvis = i; + } + else if ( !stricmp( bone->pszName(), "Bip01 Spine" ) ) + { + *spine = i; + } + + if ( *spine >= 0 && *pelvis >= 0 ) + break; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Another hack, the TFC 1.5 v. 2 models expect controllers at the midpoint +// Input : controllers[MAXSTUDIOBONECTRLS] - +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::GetBoneControllers(float controllers[MAXSTUDIOBONECTRLS]) +{ + // Set controllers to a their zero value. + for(int i=0; i < MAXSTUDIOBONECTRLS; i++) + { + controllers[i] = 0.5; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Get a text description for the object target +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::GetTargetDescription( char *pDest, int bufferSize ) +{ + const char *pStr = GetPlayerName(); + if ( pStr ) + { + Q_strncpy( pDest, pStr, bufferSize ); + } + else + { + pDest[0] = 0; + } +} + +//===================================================================================================== +// ORDERS +//===================================================================================================== + + +//----------------------------------------------------------------------------- +// Purpose: Player has received a new personal order +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::SetPersonalOrder( C_Order *pOrder ) +{ + // Do we have an order already? + RemoveOrderTarget(); + + m_hPersonalOrder = pOrder; + m_iPersonalTarget = pOrder->GetTarget(); + + // Add a new target to our list + if ( pOrder->ShouldDrawReticle() ) + { + int iTargetIndex = pOrder->GetTarget(); + if ( iTargetIndex ) + { + C_BaseEntity *pTarget = cl_entitylist->GetBaseEntity( iTargetIndex ); + if ( pTarget ) + { + char desc[512]; + pOrder->GetTargetDescription( desc, sizeof( desc ) ); + Add_Target( pTarget, desc ); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Remove the target reticle for the specified order +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::RemoveOrderTarget() +{ + if ( m_iPersonalTarget ) + { + C_BaseEntity *pTarget = cl_entitylist->GetBaseEntity( m_iPersonalTarget ); + if ( pTarget ) + { + Remove_Target( pTarget ); + } + + m_iPersonalTarget = 0; + } +} + +//==================================================================================================== +// RESOURCES +//==================================================================================================== +// Purpose: +//----------------------------------------------------------------------------- +int C_BaseTFPlayer::GetBankResources( void ) +{ + return m_TFLocal.m_iBankResources; +} + + +//==================================================================================================== +// OBJECTS +//==================================================================================================== +// Purpose: Player has selected an Object +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::SetSelectedObject( C_BaseObject *pObject ) +{ + // Do we have an order already? + if ( m_hSelectedObject ) + { + Remove_Target( m_hSelectedObject ); + + // If we selected our existing one, we just wanted to deselect + if ( pObject == m_hSelectedObject ) + { + m_hSelectedObject = NULL; + return; + } + } + + m_hSelectedObject = pObject; + + // Add a new target to our list + if ( pObject ) + { + Add_Target( pObject, pObject->GetTargetDescription() ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Get the currently selected object +//----------------------------------------------------------------------------- +C_BaseObject *C_BaseTFPlayer::GetSelectedObject( void ) +{ + return m_hSelectedObject; +} + +//==================================================================================================== +// TARGET RETICLES +//==================================================================================================== +// Purpose: Add a new entity to the list of targets +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::Add_Target( C_BaseEntity *pTarget, const char *sName ) +{ + CTargetReticle *pTargetReticle = new CTargetReticle(); + pTargetReticle->Init( pTarget, sName ); + + m_aTargetReticles.AddToTail( pTargetReticle ); +} + +//----------------------------------------------------------------------------- +// Purpose: Remove an entity from the list of targets +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::Remove_Target( C_BaseEntity *pTarget ) +{ + for (int i = 0; i < m_aTargetReticles.Size(); i++ ) + { + CTargetReticle *pTargetReticle = m_aTargetReticles[i]; + if ( pTargetReticle->GetTarget() == pTarget ) + { + Remove_Target( pTargetReticle ); + return; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Remove a specific reticle from our list +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::Remove_Target( CTargetReticle *pTargetReticle ) +{ + m_aTargetReticles.FindAndRemove( pTargetReticle ); + delete pTargetReticle; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool C_BaseTFPlayer::IsUsingThermalVision( void ) const +{ + return m_TFLocal.m_bThermalVision; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int C_BaseTFPlayer::GetIDTarget( void ) const +{ + return m_iIDEntIndex; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool C_BaseTFPlayer::IsKnockedDown( void ) const +{ + return m_TFLocal.m_bKnockedDown; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : ang - +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::SetKnockdownAngles( const QAngle& ang ) +{ + m_bKnockdownOverrideAngles = true; + QAngle fixedAngles = ang; + NormalizeAngles( fixedAngles ); + m_vecCurrentKnockdownAngles = fixedAngles; + engine->SetViewAngles( fixedAngles ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : outAngles - +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::GetKnockdownAngles( QAngle& outAngles ) +{ + outAngles = m_vecCurrentKnockdownAngles; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::CheckKnockdownState( void ) +{ + m_bKnockdownOverrideAngles = false; + + if ( m_flStartKnockdown == 0.0f && + m_flEndKnockdown == 0.0f && + !IsKnockedDown() ) + { + m_flKnockdownViewheightAdjust = 0.0f; + return; + } + + float frac = 0.0f; + float dt; + if ( IsKnockedDown() ) + { + if ( m_flStartKnockdown != 0.0f ) + { + + dt = gpGlobals->curtime - m_flStartKnockdown; + if ( dt >= 0.0f && dt < KNOCKDOWN_BLEND_IN ) + { + frac = ( dt / KNOCKDOWN_BLEND_IN ); + frac = MAX( 0.0f, frac ); + frac = MIN( 1.0f, frac ); + } + else if ( dt >= KNOCKDOWN_BLEND_IN) + { + m_flStartKnockdown = 0.0f; + frac = 1.0f; + } + } + else + { + frac = 1.0f; + } + } + else + { + if ( m_flEndKnockdown != 0.0f ) + { + frac = 0.0f; + dt = gpGlobals->curtime - m_flEndKnockdown; + if ( dt >= 0 && dt < KNOCKDOWN_BLEND_OUT ) + { + frac = ( dt / KNOCKDOWN_BLEND_OUT ); + frac = 1.0f - frac; + } + else if ( dt >= KNOCKDOWN_BLEND_OUT ) + { + m_flEndKnockdown = 0.0f; + } + else + { + frac = 1.0f; + } + } + } + + if ( frac == 0.0f ) + { + SetKnockdownAngles( m_vecOriginalViewAngles ); + } + else if ( frac == 1.0f ) + { + SetKnockdownAngles( m_vecKnockDownGoalAngles ); + } + else + { + QAngle current; + InterpolateAngles( m_vecOriginalViewAngles, m_vecKnockDownGoalAngles, current, frac ); + SetKnockdownAngles( current ); + } + + Vector eyeZOffset; + VectorSubtract( EyePosition(), GetAbsOrigin(), eyeZOffset ); + float zsize = eyeZOffset.z; + + m_flKnockdownViewheightAdjust = frac * ( zsize - 12 ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool C_BaseTFPlayer::CheckKnockdownAngleOverride( void ) const +{ + return m_bKnockdownOverrideAngles; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : float +//----------------------------------------------------------------------------- +float C_BaseTFPlayer::GetKnockdownViewheightAdjust( void ) const +{ + return m_flKnockdownViewheightAdjust; +} + + +//----------------------------------------------------------------------------- +// Purpose: Player has changed to a new team +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::TeamChange( int iNewTeam ) +{ + BaseClass::TeamChange( iNewTeam ); + + // Did we change team? or did we just join our first team? + if ( iNewTeam != GetTeamNumber() ) + { + // Tell the tech tree to reload itself + GetTechnologyTreeDoc().ReloadTechTree(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: // Override so infiltrator's disguised as other team will work +// Output : int +//----------------------------------------------------------------------------- +int C_BaseTFPlayer::GetRenderTeamNumber( void ) +{ + return GetTeamNumber(); +} + + +// 50 % per second +#define CAMO_DAMPENING_CHANGERATE 300.0f +#define CAMO_MOVESUPPRESSION_CHANGERATE 100.0f +#define CAMO_DAMPENINGVELOCITY_CUTOFF 50.0f +#define CAMO_DAMPENINGVELOCITY_MAX 400.0f +#define CAMO_DAMPENINGAVEL_CUTOFF 1.0f +#define CAMO_DAMPENINGAVEL_MAX 5.0f +#define CAMO_STAYOUT_TIME 1.0f +#define CAMO_MOVEMENT_PENALTYTIME 1.0f + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool C_BaseTFPlayer::IsCamouflaged( void ) +{ + return ( m_flCamouflageAmount > 0.0f ) ? true : false; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : float +//----------------------------------------------------------------------------- +float C_BaseTFPlayer::GetCamouflageAmount( void ) +{ + return m_flCamouflageAmount; +} + +//----------------------------------------------------------------------------- +// Purpose: 0 to 1, where 1 means hardly visible and 0 means pretty noticeable +// Output : float +//----------------------------------------------------------------------------- + +#define DISTANCE_CAMO_EFFECT_AMOUNT 0.1f +#define LOCAL_MOTION_CAMO_EFFECT_AMOUNT 0.3f +#define MOVEMENT_CAMO_EFFECT_AMOUNT 0.2f + +float C_BaseTFPlayer::ComputeCamoEffectAmount( void ) +{ + if ( !IsCamouflaged() ) + return 1.0f; + + // Start with the amount from the server.... + float effect_amount = m_flCamouflageAmount / 100.0f; + + // If this player has moved recently, camo will not be as effective for him + effect_amount -= MOVEMENT_CAMO_EFFECT_AMOUNT * GetMovementCamoSuppression() / 100.0f; + if (effect_amount < 0) + effect_amount = 0; + + // Determine distance to render origin + Vector delta = GetAbsOrigin() - CurrentViewOrigin(); + float distance = delta.Length(); + + // At the max distance, make it n% less likely to see the camoed dude... + // At min distance, we're no less likely to see the dude + if ( distance >= CAMO_INNER_RADIUS ) + effect_amount *= 1 + DISTANCE_CAMO_EFFECT_AMOUNT; + else + { + float frac = distance / CAMO_INNER_RADIUS; + effect_amount *= 1 - frac + (1 + DISTANCE_CAMO_EFFECT_AMOUNT) * frac; + } + + // Local viewer movements make it n% less likely to see the camoed dude... + // No movement means we're no less likely to see the dude + // Dampening is based on the local viewer's movements + float dampening = 0.0f; + C_BaseTFPlayer *local = GetLocalPlayer(); + if ( local ) + { + dampening = local->GetDampeningAmount() / 100.0f; + } + + // Now apply suppression (i.e., less visible) based on camera and viewer movement + effect_amount *= 1 + LOCAL_MOTION_CAMO_EFFECT_AMOUNT * dampening; + + // Clamp to valid range + effect_amount = MAX( 0.0f, effect_amount ); + effect_amount = MIN( 0.99f, effect_amount ); + + return effect_amount; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int +//----------------------------------------------------------------------------- +int C_BaseTFPlayer::ComputeCamoAlpha( void ) +{ + Assert( IsCamouflaged() ); + + // Determine distance to render origin + Vector delta = GetAbsOrigin() - CurrentViewOrigin(); + float distance = delta.Length(); + + int baseline = 0; + + // Too far, just blend out completely + if ( distance >= CAMO_OUTER_RADIUS ) + { + baseline = 0; + } + else if ( distance >= CAMO_INNER_RADIUS ) + { + float frac = ( distance - CAMO_INNER_RADIUS ) / ( CAMO_OUTER_RADIUS - CAMO_INNER_RADIUS ); + frac = 1 - frac; + baseline = (int)( (float)( 255 - CAMO_INNER_ALPHA ) * frac ); + } + else if ( distance >= CAMO_INVIS_RADIUS ) + { + // We'll also render with the special effect + float frac = ( distance - CAMO_INVIS_RADIUS ) / ( CAMO_INNER_RADIUS - CAMO_INVIS_RADIUS ); + baseline = (int)( (float)( CAMO_INNER_ALPHA ) * frac ); + } + else + { + // NOTE: return 1 or else the renderer will skip drawing and we won't be + // able to draw the up close effect + baseline = 1; + } + + // Suppress everything based on server ramp + return baseline + (int)( (float)( 255 - baseline ) * ( m_flCamouflageAmount / 100.0f ) ); + +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::ComputeFxBlend( void ) +{ + if ( !IsCamouflaged() ) + { + BaseClass::ComputeFxBlend(); + return; + } + + m_nRenderFXBlend = ComputeCamoAlpha(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool C_BaseTFPlayer::IsTransparent( void ) +{ + if ( IsCamouflaged() ) + { + return true; + } + + return BaseClass::IsTransparent(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool C_BaseTFPlayer::ViewModel_IsTransparent( void ) +{ + if ( IsCamouflaged() ) + { + return true; + } + + return BaseClass::ViewModel_IsTransparent(); +} + +//----------------------------------------------------------------------------- +// Purpose: Return true if the player's viewmodel should match the player's model data +//----------------------------------------------------------------------------- +bool C_BaseTFPlayer::IsOverridingViewmodel( void ) +{ + // Don't override medic weapons since we have effects for them + if ( PlayerClass() == TFCLASS_MEDIC ) + return BaseClass::IsOverridingViewmodel(); + + if ( IsDamageBoosted() || IsCamouflaged() || HasPowerup(POWERUP_EMP) ) + return true; + + return BaseClass::IsOverridingViewmodel(); +} + +//----------------------------------------------------------------------------- +// Purpose: Draw my viewmodel in some special way +//----------------------------------------------------------------------------- +int C_BaseTFPlayer::DrawOverriddenViewmodel( C_BaseViewModel *pViewmodel, int flags ) +{ + int ret = 0; + + if ( IsCamouflaged() && ( ComputeCamoEffectAmount() != 1.0f ) ) + { + if ( GetCamoMaterial() ) + { + modelrender->ForcedMaterialOverride( GetCamoMaterial() ); + ret = pViewmodel->DrawOverriddenViewmodel( flags ); + modelrender->ForcedMaterialOverride( NULL ); + } + } + + if ( IsDamageBoosted() || HasPowerup(POWERUP_EMP) ) + { + + // First draw the model once normally. + pViewmodel->DrawOverriddenViewmodel( flags ); + + // NOTE: for the demo we do a different "BOOST" effect. What do we want to do here? + if ( !inv_demo.GetInt() ) + { + if ( IsDamageBoosted() && + pViewmodel->ViewModelIndex() != 0 ) + { + return ret; + } + + // Now overlay some shimmering ones. + render->SetBlend( 0.3 ); + + if ( IsDamageBoosted() ) + { + // Radeon 9700 having a problem with this guy: + modelrender->ForcedMaterialOverride( m_BoostMaterial ); + } + else + { + modelrender->ForcedMaterialOverride( m_EMPMaterial ); + } + + Vector vStart = pViewmodel->GetAbsOrigin(); + + float flOffset = damageboost_modeloffset.GetFloat(); + for ( int i=0; i < 3; i++ ) + { + // Place the model at a slight offset. + vStart[i] += flOffset * sin( m_BoostModelAngles[i] ); + pViewmodel->SetLocalOrigin( vStart ); + m_BoostModelAngles[i] += RandomFloat( damageboost_modelphasespeed_min.GetFloat(), damageboost_modelphasespeed_max.GetFloat() ) * gpGlobals->frametime; + + // Invalidate the bones because they've been setup with our original position and cached, + // and we want to render it in a new spot with different bone transforms. + pViewmodel->InvalidateBoneCache(); + ret = pViewmodel->DrawOverriddenViewmodel( flags ); + } + + // Reset the position and bone info. + pViewmodel->SetLocalOrigin( vStart ); + pViewmodel->InvalidateBoneCache(); + + modelrender->ForcedMaterialOverride( NULL ); + render->SetBlend( 1 ); + } + } + + return ret; +} + +//----------------------------------------------------------------------------- +// Purpose: Players under adrenalin animate faster +//----------------------------------------------------------------------------- +float C_BaseTFPlayer::GetDefaultAnimSpeed( void ) +{ + if ( HasPowerup( POWERUP_RUSH ) ) + return ADRENALIN_ANIM_SPEED; + + // Weapons may modify animation times + if ( GetActiveWeapon() ) + return GetActiveWeapon()->GetDefaultAnimSpeed(); + + return 1.0; +} + +//----------------------------------------------------------------------------- +// Purpose: This is used to penalize the local viewer for moving around or rotating +// the camera, it causes camo'd guys who are close to fade out their "white" effect +// for a bit of time +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::CheckCameraMovement( void ) +{ + float dt = gpGlobals->frametime; + + float vel = GetAbsVelocity().Length(); + float avel = fabs( GetLocalAngles().y - GetPrevLocalAngles().y ); + if ( dt > 0.0f ) + { + avel *= 1.0f / dt; + } + + float frac1 = 0.0f; + if ( vel > CAMO_DAMPENINGVELOCITY_CUTOFF ) + { + frac1 = ( vel - CAMO_DAMPENINGVELOCITY_CUTOFF ) / ( CAMO_DAMPENINGVELOCITY_MAX - CAMO_DAMPENINGVELOCITY_CUTOFF ); + frac1 = MIN( 0.0f, frac1 ); + frac1 = MAX( 1.0f, frac1 ); + + frac1 *= 50.0f; + + m_flDampeningStayoutTime = gpGlobals->curtime + CAMO_STAYOUT_TIME; + + } + + float frac2 = 0.0f; + if ( avel > CAMO_DAMPENINGAVEL_CUTOFF ) + { + frac2 = ( avel - CAMO_DAMPENINGAVEL_CUTOFF ) / ( CAMO_DAMPENINGAVEL_MAX - CAMO_DAMPENINGAVEL_CUTOFF ); + frac2 = MIN( 0.0f, frac2 ); + frac2 = MAX( 1.0f, frac2 ); + + frac2 *= 50.0f; + + m_flDampeningStayoutTime = gpGlobals->curtime + CAMO_STAYOUT_TIME; + + } + + // Pick the greater + float amount = MAX( frac1, frac2 ); + + SetCamoDampening( amount ); +} + +//----------------------------------------------------------------------------- +// Purpose: Decay suppression camo amount +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::CheckCamoDampening( void ) +{ + CheckCameraMovement(); + + if ( m_flGoalDampeningAmount == m_flDampeningAmount ) + return; + + // Camouflage + float dt = gpGlobals->frametime; + float changeamount = ( dt * CAMO_DAMPENING_CHANGERATE ); + + // Move but don't overshoot + if ( m_flGoalDampeningAmount > m_flDampeningAmount ) + { + m_flDampeningAmount += changeamount; + m_flDampeningAmount = MIN( m_flDampeningAmount, m_flGoalDampeningAmount ); + } + else + { + if ( gpGlobals->curtime < m_flDampeningStayoutTime ) + return; + + m_flDampeningAmount -= changeamount; + m_flDampeningAmount = MAX( m_flDampeningAmount, m_flGoalDampeningAmount ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Force amount, decay happens in CheckCamoDampening +// Input : amount - +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::SetCamoDampening( float amount ) +{ + m_flGoalDampeningAmount = amount; +} + +//----------------------------------------------------------------------------- +// Purpose: For camera movement by local player +// Output : float +//----------------------------------------------------------------------------- +float C_BaseTFPlayer::GetDampeningAmount( void ) +{ + return m_flDampeningAmount; +} + +//----------------------------------------------------------------------------- +// Purpose: This is used so that if you are watching a camo'd guy who is moving +// he becomes more visible for a bit of time, before fading back out. +// Input : amount - +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::SetMovementCamoSuppression( float amount ) +{ + m_flGoalMovementCamoSuppressionAmount = amount; +} + +//----------------------------------------------------------------------------- +// Purpose: This is used so that if you are watching a camo'd guy who is moving +// he becomes more visible for a bit of time, before fading back out. +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::CheckMovementCamoSuppression( void ) +{ + // FIXME: Don't bother with suppression during deployment... + if ( m_bDeployed ) + { + m_flMovementCamoSuppression = 0; + return; + } + + float flSuppression = 0; + + // Rotation blends them in a bit too + float avel = fabs( GetLocalAngles().y - GetPrevLocalAngles().y ) + fabs( GetLocalAngles().x - GetPrevLocalAngles().x ); + if ( avel > CAMO_DAMPENINGAVEL_CUTOFF ) + { + float frac2 = ( avel - CAMO_DAMPENINGAVEL_CUTOFF ) / ( CAMO_DAMPENINGAVEL_MAX - CAMO_DAMPENINGAVEL_CUTOFF ); + frac2 = MIN( 0.0f, frac2 ); + frac2 = MAX( 1.0f, frac2 ); + flSuppression = 50.0f * frac2; + } + + // Add in velocity blend + float vel = GetAbsVelocity().Length(); + if ( vel > CAMO_DAMPENINGVELOCITY_CUTOFF ) + { + float frac = ( vel- CAMO_DAMPENINGVELOCITY_CUTOFF ) / ( CAMO_DAMPENINGVELOCITY_MAX - CAMO_DAMPENINGVELOCITY_CUTOFF ); + frac = MIN( 1.0f, frac ); + flSuppression = MIN( 100.f, flSuppression + (100.0f * frac) ); + } + + // Set the camo aount + SetMovementCamoSuppression( flSuppression ); + if ( flSuppression ) + { + m_flMovementCamoSuppressionStayoutTime = gpGlobals->curtime + CAMO_MOVEMENT_PENALTYTIME; + } + + if ( m_flGoalMovementCamoSuppressionAmount == m_flMovementCamoSuppression ) + return; + + // Camouflage + float dt = gpGlobals->frametime; + float changeamount = ( dt * CAMO_MOVESUPPRESSION_CHANGERATE ); + + // Move but don't overshoot + if ( m_flGoalMovementCamoSuppressionAmount > m_flMovementCamoSuppression ) + { + m_flMovementCamoSuppression += changeamount; + m_flMovementCamoSuppression = MIN( m_flMovementCamoSuppression, m_flGoalMovementCamoSuppressionAmount ); + } + else + { + if ( gpGlobals->curtime < m_flMovementCamoSuppressionStayoutTime ) + return; + + m_flMovementCamoSuppression -= changeamount; + m_flMovementCamoSuppression = MAX( m_flMovementCamoSuppression, m_flGoalMovementCamoSuppressionAmount ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Get the material used for this player's camo +//----------------------------------------------------------------------------- +IMaterial *C_BaseTFPlayer::GetCamoMaterial( void ) +{ + if ( !m_pCamoEffectMaterial ) + { + m_pCamoEffectMaterial = materials->FindMaterial("player/infiltratorcamo/infiltratorcamo", TEXTURE_GROUP_CLIENT_EFFECTS); + if ( m_pCamoEffectMaterial ) + { + m_pCamoEffectMaterial->IncrementReferenceCount(); + } + } + + return m_pCamoEffectMaterial; +} + +//----------------------------------------------------------------------------- +// Purpose: Percentage suppression of camo effect up close based on velocity +// Output : float +//----------------------------------------------------------------------------- +float C_BaseTFPlayer::GetMovementCamoSuppression( void ) +{ + return m_flMovementCamoSuppression; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::CheckLastMovement( void ) +{ + if ( GetAbsOrigin() != m_vecLastOrigin ) + { + m_vecLastOrigin = GetAbsOrigin(); + m_flLastMoveTime = gpGlobals->curtime; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : float +//----------------------------------------------------------------------------- +float C_BaseTFPlayer::GetLastMoveTime( void ) +{ + return m_flLastMoveTime; +} + +float C_BaseTFPlayer::GetLastDamageTime( void ) const +{ + return m_flLastDamageTime; +} + +float C_BaseTFPlayer::GetLastGainHealthTime( void ) const +{ + return m_flLastGainHealthTime; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Output : float +//----------------------------------------------------------------------------- +float C_BaseTFPlayer::GetOverlayAlpha( void ) +{ + float alpha = 1.0f; + + C_BaseTFPlayer *local = GetLocalPlayer(); + if ( local && local != this ) + { + if ( local && GetTeamNumber() != local->GetTeamNumber() ) + { + if ( IsCamouflaged() ) + { + float frac = ( GetCamouflageAmount() / 100.0f ); + alpha *= ( 1.0f - frac ); + } + + // Only applies to sniper right now + if ( m_iPlayerClass == TFCLASS_SNIPER ) + { + float dt = gpGlobals->curtime - GetLastMoveTime(); + if ( dt > SNIPER_STATIONARY_FADESTART ) + { + if ( dt > SNIPER_STATIONARY_FADEFINISH ) + { + alpha = 0.0; + } + else + { + float frac = ( dt - SNIPER_STATIONARY_FADESTART ) / ( SNIPER_STATIONARY_FADEFINISH - SNIPER_STATIONARY_FADESTART ); + alpha *= ( 1.0f - frac ); + } + } + } + } + } + + alpha = MIN( 1.0f, alpha ); + alpha = MAX( 0.0f, alpha ); + + return alpha; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_BaseTFPlayer::IsDeployed( void ) +{ + return m_bDeployed; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_BaseTFPlayer::IsDeploying( void ) +{ + return m_bDeploying; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_BaseTFPlayer::IsUnDeploying( void ) +{ + return m_bUnDeploying; +} + +//----------------------------------------------------------------------------- +// Purpose: Return true if the player's allowed to switch weapons in his current state +//----------------------------------------------------------------------------- +bool C_BaseTFPlayer::IsAllowedToSwitchWeapons( void ) +{ + // Can't switch while deployed + if ( IsDeployed() || IsDeploying() || IsUnDeploying() ) + return false; + + if ( IsInAVehicle() && GetVehicle() ) + { + IClientVehicle *pVehicle = GetVehicle(); + int nRole = pVehicle->GetPassengerRole( this ); + if (!pVehicle->IsPassengerUsingStandardWeapons(nRole)) + { + return false; + } + } + + // See if the weapon will allow us to switch + if ( GetActiveWeapon() && GetActiveWeapon()->IsAllowedToSwitch() == false ) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Get the number of objects of the specified type that this player has +//----------------------------------------------------------------------------- +int C_BaseTFPlayer::GetNumObjects( int iObjectType ) +{ + int iCount = 0; + for (int i = 0; i < GetObjectCount(); i++) + { + if ( !GetObject(i) ) + continue; + + if ( GetObject(i)->GetType() == iObjectType ) + { + iCount++; + } + } + + return iCount; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int C_BaseTFPlayer::GetObjectCount( void ) +{ + return m_TFLocal.m_aObjects.Count(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_BaseObject *C_BaseTFPlayer::GetObject( int index ) +{ + return m_TFLocal.m_aObjects[index].Get(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::AddEntity( void ) +{ + BaseClass::AddEntity(); + + // Zero out model pitch, blending takes care of all of it. + SetLocalAnglesDim( X_INDEX, 0 ); + + m_PlayerAnimState.Update(); +} + +//----------------------------------------------------------------------------- +// Purpose: See if it's time to start another adrenalin effect +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::CheckAdrenalin( void ) +{ + if ( m_flNextAdrenalinEffect && gpGlobals->curtime > m_flNextAdrenalinEffect ) + { + ScreenFade_t sf; + memset( &sf, 0, sizeof( sf ) ); + sf.a = 128; + sf.r = 0; + sf.g = 128; + sf.b = 0; + // One second + sf.duration = (unsigned short)((float)(1<<SCREENFADE_FRACBITS) * 1.0f ); + if ( m_bFadingIn ) + { + sf.fadeFlags = FFADE_IN; + } + else + { + sf.fadeFlags = FFADE_OUT; + } + vieweffects->Fade( sf ); + + m_bFadingIn = !m_bFadingIn; + m_flNextAdrenalinEffect = gpGlobals->curtime + 1.0; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Update this client's target entity +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::UpdateIDTarget( void ) +{ + if ( !IsLocalPlayer() ) + return; + + // If the server's forcing us to a specific ID target, use it instead + if ( m_TFLocal.m_iIDEntIndex ) + { + m_iIDEntIndex = m_TFLocal.m_iIDEntIndex; + return; + } + + // Clear old target and find a new one + m_iIDEntIndex = 0; + + trace_t tr; + Vector vecStart, vecEnd; + VectorMA( MainViewOrigin(), 1500, MainViewForward(), vecEnd ); + VectorMA( MainViewOrigin(), 48, MainViewForward(), vecStart ); + UTIL_TraceLine( vecStart, vecEnd, MASK_SOLID, NULL, COLLISION_GROUP_NONE, &tr ); + if ( tr.DidHitNonWorldEntity() ) + { + C_BaseEntity *pEntity = tr.m_pEnt; + IClientVehicle *vehicle = GetVehicle(); + C_BaseEntity *pVehicleEntity = vehicle ? vehicle->GetVehicleEnt() : NULL; + + if ( pEntity && (pEntity != this) && (pEntity != pVehicleEntity) ) + { + // Make sure it's not an object + if ( !dynamic_cast<C_BaseObject*>( pEntity ) ) + { + m_iIDEntIndex = pEntity->entindex(); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Return the weapon to have open the weapon selection on, based upon our currently active weapon +// If the currently active weapon is a two handed weapon, returns it's primary weapon. +//----------------------------------------------------------------------------- +C_BaseCombatWeapon *C_BaseTFPlayer::GetActiveWeaponForSelection( void ) +{ + C_WeaponTwoHandedContainer *pTwoHandedWeapon = dynamic_cast<C_WeaponTwoHandedContainer*>( GetActiveWeapon() ); + if ( pTwoHandedWeapon ) + return pTwoHandedWeapon->m_hLeftWeapon; + + return BaseClass::GetActiveWeaponForSelection(); +} + +//----------------------------------------------------------------------------- +// HACK: Until we get a recon model, trail recon particles +//----------------------------------------------------------------------------- +void FX_ReconParticle( const Vector &vecOrigin, bool bBlue ) +{ + CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "reconparticle" ); + pSimple->SetSortOrigin( vecOrigin ); + pSimple->SetNearClip( 32, 64 ); + + SimpleParticle *pParticle; + + Vector offset; + + for ( int i = 0; i < 1; i++ ) + { + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[0], vecOrigin ); + + if ( pParticle != NULL ) + { + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = random->RandomFloat( 1.0f, 1.5f ); + + pParticle->m_vecVelocity = vec3_origin; + + int color = random->RandomInt( 128, 192 ); + + if ( bBlue ) + { + pParticle->m_uchColor[0] = color; + pParticle->m_uchColor[1] = color; + pParticle->m_uchColor[2] = 255; + } + else + { + pParticle->m_uchColor[0] = 255; + pParticle->m_uchColor[1] = color; + pParticle->m_uchColor[2] = color; + } + pParticle->m_uchStartAlpha = random->RandomInt( 192, 255 ); + pParticle->m_uchEndAlpha = 0; + pParticle->m_uchStartSize = random->RandomInt( 12, 16 ); + pParticle->m_uchEndSize = 0; + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = random->RandomFloat( -1.0f, 1.0f ); + } + } +} + +// Prediction stuff +void C_BaseTFPlayer::PreThink( void ) +{ + BaseClass::PreThink(); + + // Chain pre-think to player class. + if ( GetPlayerClass() ) + { + GetPlayerClass()->PreClassThink(); + } +} + +void C_BaseTFPlayer::PostThink( void ) +{ + BaseClass::PostThink(); + + // Chain post-think to player class. + if ( GetPlayerClass() ) + { + GetPlayerClass()->PostClassThink(); + } +} + +C_PlayerClass *C_BaseTFPlayer::GetPlayerClass( void ) +{ + return m_PlayerClasses.GetPlayerClass( PlayerClass() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::SetVehicleRole( int nRole ) +{ + if ( IsInAVehicle() ) + { + C_BaseTFVehicle *pVehicle = ( C_BaseTFVehicle* )GetVehicle(); + if ( pVehicle ) + { + if ( nRole >= pVehicle->GetMaxPassengerCount() ) + return; + } + } + + char szCmd[64]; + Q_snprintf( szCmd, sizeof( szCmd ), "vehicleRole %i\n", nRole ); + engine->ServerCmd( szCmd ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_BaseTFPlayer::CanGetInVehicle( void ) +{ + if ( GetPlayerClass() ) + { + return GetPlayerClass()->CanGetInVehicle(); + } + + return true; +} + + +// How fast to avoid collisions with center of other object, in units per second +#define AVOID_SPEED 1000.0f +extern ConVar cl_forwardspeed; +extern ConVar cl_backspeed; +extern ConVar cl_sidespeed; + +static ConVar tf2_solidplayers( "tf2_solidplayers", "1", 0, "Treat players and objects as solid." ); + +//----------------------------------------------------------------------------- +// Client-side obstacle avoidance +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::PerformClientSideObstacleAvoidance( float flFrameTime, CUserCmd *pCmd ) +{ + if ( !tf2_solidplayers.GetBool() ) + { + return; + } + + // Don't avoid if noclipping or in movetype none + switch ( GetMoveType() ) + { + case MOVETYPE_NOCLIP: + case MOVETYPE_NONE: + return; + default: + break; + } + + // Try to steer away from any objects/players we might interpenetrate + Vector size = WorldAlignSize(); + + float radius = 0.5f * sqrt( size.x * size.x + size.y * size.y ); + float curspeed = GetAbsVelocity().Length2D(); + + // int slot = 1; + + //engine->Con_NPrintf( slot++, "speed %f\n", curspeed ); + //engine->Con_NPrintf( slot++, "radius %f\n", radius ); + + // If running, use a larger radius + if ( curspeed > 100.0f ) + { + float factor = ( 1.0f + ( curspeed - 100.0f ) / 100.0f ); + + // engine->Con_NPrintf( slot++, "scaleup (%f) to radius %f\n", factor, radius * factor ); + + radius = radius * factor; + } + + CPlayerAndObjectEnumerator avoid( radius ); + partition->EnumerateElementsInSphere( PARTITION_CLIENT_SOLID_EDICTS, GetAbsOrigin(), radius, false, &avoid ); + + // Okay, decide how to avoid if there's anything close by + int c = avoid.GetObjectCount(); + if ( c <= 0 ) + return; + + Vector currentdir; + Vector rightdir; + AngleVectors( pCmd->viewangles, ¤tdir, &rightdir, NULL ); + + bool istryingtomove = false; + bool ismovingforward = false; + if ( fabs( pCmd->forwardmove ) > 0.0f || + fabs( pCmd->sidemove ) > 0.0f ) + { + istryingtomove = true; + if ( pCmd->forwardmove > 1.0f ) + { + ismovingforward = true; + } + } + + //engine->Con_NPrintf( slot++, "moving %s forward %s\n", istryingtomove ? "true" : "false", ismovingforward ? "true" : "false" ); + + float adjustforwardmove = 0.0f; + float adjustsidemove = 0.0f; + + int i; + for ( i = 0; i < c; i++ ) + { + C_BaseEntity *obj = avoid.GetObject( i ); + if( !obj ) + continue; + + float flHit1, flHit2; + + // Figure out a 2D radius for the object + Vector vecWorldMins, vecWorldMaxs; + obj->CollisionProp()->WorldSpaceAABB( &vecWorldMins, &vecWorldMaxs ); + Vector objSize = vecWorldMaxs - vecWorldMins; + + float objectradius = /*0.5f **/ 1.0 * sqrt( objSize.x * objSize.x + objSize.y * objSize.y ); + + if ( !IntersectInfiniteRayWithSphere( + GetAbsOrigin(), + currentdir, + obj->GetAbsOrigin(), + objectradius, + &flHit1, + &flHit2 ) ) + continue; + + float force = 0.0f; + + float forward = 0.0f, side = 0.0f; + + Vector vecToObject = obj->GetAbsOrigin() - GetAbsOrigin(); + Vector cross = vecToObject.Cross( currentdir ); + + //engine->Con_NPrintf( slot++, "object side %s\n", sign > 0.0f ? "right" : "left" ); + + if ( 0 && istryingtomove ) + { +/* + // Okay, line hits sphere in two points + // Determine how close line is to center of sphere and move sideways to avoid if we are + // actually trying to move forward + Vector deltaHit = vHit2 - vHit1; + float leg1 = ( deltaHit.Length() ) / 2.0f; + + float distfromcenter = sqrt( leg1 * leg1 + objectradius * objectradius ); + + force = distfromcenter / radius; + force = clamp( force, 0.0f, 1.0f ); + force = 1.0f - force; + + if ( force <= 0.5f ) + continue; + + side = force * AVOID_SPEED; + + // Move to right or left of object + side *= sign; +*/ + } + else + { + Vector deltaObject = vecToObject; + float dist = deltaObject.Length2D(); + + force = dist / radius; + force = clamp( force, 0.0f, 1.0f ); + force = 1.0f - force; + + //engine->Con_NPrintf( slot++, "dist %f/radius %f == %f\n", dist, radius, force ); + + if ( force <= 0.3f ) + continue; + + force = sqrt( force ); + + //engine->Con_NPrintf( slot++, "sqrt(force) == %f\n", force ); + + Vector moveDir = -vecToObject; + VectorNormalize( moveDir ); + + float fwd = currentdir.Dot( moveDir ); + float rt = rightdir.Dot( moveDir ); + + //engine->Con_NPrintf( slot++, "fwd %f right %f\n", fwd, rt ); + + float sidescale = 2.0f; + float forwardscale = 1.0f; + + if ( istryingtomove ) + { + // If running, then do a lot more sideways veer since we're not going to do anything to + // forward velocity + sidescale = 4.0f; + forwardscale = 2.0f; + } + + forward = forwardscale * fwd * force * AVOID_SPEED; + side = sidescale * rt * force * AVOID_SPEED; + + //engine->Con_NPrintf( slot++, "forward %f side %f\n", forward, side ); + } + + adjustforwardmove += forward; + adjustsidemove += side; + } + + pCmd->forwardmove += adjustforwardmove; + pCmd->sidemove += adjustsidemove; + + if ( pCmd->forwardmove > 0.0f ) + { + pCmd->forwardmove = clamp( pCmd->forwardmove, -cl_forwardspeed.GetFloat(), cl_forwardspeed.GetFloat() ); + } + else + { + pCmd->forwardmove = clamp( pCmd->forwardmove, -cl_backspeed.GetFloat(), cl_backspeed.GetFloat() ); + } + pCmd->sidemove = clamp( pCmd->sidemove, -cl_sidespeed.GetFloat(), cl_sidespeed.GetFloat() ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Input handling +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::CreateMove( float flInputSampleTime, CUserCmd *pCmd ) +{ + BaseClass::CreateMove( flInputSampleTime, pCmd ); + + // If the frozen flag is set, prevent view movement (server prevents the rest of the movement) + if ( GetFlags() & FL_FROZEN ) + { + return; + } + + if (!IsInVGuiInputMode() && !IsInAVehicle()) + { + PerformClientSideObstacleAvoidance( TICK_INTERVAL, pCmd ); + } +} + + +C_BaseAnimating* C_BaseTFPlayer::GetRenderedWeaponModel() +{ + // Attach to either their weapon model or their view model. + if ( C_BasePlayer::ShouldDrawLocalPlayer() || !IsLocalPlayer() ) + { + // Hook it to their external weapon model. + C_BaseCombatWeapon *pWeapon = GetActiveWeapon(); + if ( !pWeapon ) + return NULL; + + // If this a two-handed container (shield + weapon), return the left weapon. + C_WeaponTwoHandedContainer *pContainer = dynamic_cast< C_WeaponTwoHandedContainer* >( pWeapon ); + if ( pContainer ) + { + return pContainer->GetLeftWeapon(); + } + else + { + return pWeapon; + } + } + else + { + return GetViewModel(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::SetIDEnt( C_BaseEntity *pEntity ) +{ + if ( pEntity ) + m_TFLocal.m_iIDEntIndex = pEntity->entindex(); + else + m_TFLocal.m_iIDEntIndex = 0; +} + + +C_VehicleTeleportStation* C_BaseTFPlayer::GetSelectedMCV() const +{ + return dynamic_cast< C_VehicleTeleportStation* >( m_hSelectedMCV.Get() ); +} + +//----------------------------------------------------------------------------- +// Purpose: Return true if this object can be +used by the player +//----------------------------------------------------------------------------- +bool C_BaseTFPlayer::IsUseableEntity( CBaseEntity *pEntity ) +{ + // I can use vehicles + return dynamic_cast<C_BaseTFVehicle*>( pEntity ); +} + +//----------------------------------------------------------------------------- +// Purpose: Powerup has just started +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::PowerupStart( int iPowerup, bool bInitial ) +{ + Assert( iPowerup >= 0 && iPowerup < MAX_POWERUPS ); + + switch( iPowerup ) + { + case POWERUP_RUSH: + { + // Play the rage start + if ( bInitial ) + { + EmitSound( "BaseTFPlayer.Rage" ); + } + + // Start the looping breathing + CPASAttenuationFilter filter( this, "BaseTFPlayer.HeavyBreathing" ); + EmitSound( filter, entindex(), "BaseTFPlayer.HeavyBreathing" ); + + if ( IsLocalPlayer() ) + { + // Start the visual effects + if ( !m_flNextAdrenalinEffect ) + { + m_flNextAdrenalinEffect = gpGlobals->curtime; + m_bFadingIn = false; + } + } + } + break; + + default: + break; + } + + BaseClass::PowerupStart( iPowerup, bInitial ); +} + +//----------------------------------------------------------------------------- +// Purpose: Powerup has just finished +//----------------------------------------------------------------------------- +void C_BaseTFPlayer::PowerupEnd( int iPowerup ) +{ + Assert( iPowerup >= 0 && iPowerup < MAX_POWERUPS ); + + switch( iPowerup ) + { + case POWERUP_RUSH: + { + // Stop the looping breathing + StopSound( "BaseTFPlayer.HeavyBreathing" ); + + if ( IsLocalPlayer() ) + { + // Stop the visual effects + if ( m_flNextAdrenalinEffect ) + { + vieweffects->ClearAllFades(); + } + + m_flNextAdrenalinEffect = 0; + } + } + break; + + default: + break; + } + + BaseClass::PowerupEnd( iPowerup ); +} diff --git a/game/client/tf2/c_basetfplayer.h b/game/client/tf2/c_basetfplayer.h new file mode 100644 index 0000000..b2fc64c --- /dev/null +++ b/game/client/tf2/c_basetfplayer.h @@ -0,0 +1,386 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#if !defined( C_BASETFPLAYER_H ) +#define C_BASETFPLAYER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tf_vehicleshared.h" +#include "c_baseplayer.h" +#include "CommanderOverlay.h" +#include "hud_minimap.h" +#include "hud_targetreticle.h" +#include "c_tfplayerlocaldata.h" +#include "particlemgr.h" +#include "particle_prototype.h" +#include "particle_util.h" +#include "tf_playeranimstate.h" + +class C_VehicleTeleportStation; +class CViewSetup; +class IMaterial; +class C_Order; +class C_BaseObject; +class C_PlayerClass; +class CPersonalShieldEffect; +class CBasePredictedWeapon; +class C_BaseViewModel; +class CUserCmd; +class C_WeaponCombatShield; + +//----------------------------------------------------------------------------- +// Purpose: Client Side TF Player entity +//----------------------------------------------------------------------------- +class C_BaseTFPlayer : public C_BasePlayer +{ +public: + DECLARE_CLASS( C_BaseTFPlayer, C_BasePlayer ); + DECLARE_CLIENTCLASS(); + DECLARE_ENTITY_PANEL(); + DECLARE_MINIMAP_PANEL(); + DECLARE_PREDICTABLE(); + + C_BaseTFPlayer(); + virtual ~C_BaseTFPlayer(); + +private: + void Clear(); // Clear all elements. + +public: + bool IsHidden() const; + bool IsDamageBoosted() const; + + bool HasNamedTechnology( const char *name ); + + float LastAttackTime() const { return m_flLastAttackTime; } + void SetLastAttackTime( float flTime ) { m_flLastAttackTime = flTime; } + + // Return this client's C_BaseTFPlayer pointer + static C_BaseTFPlayer* GetLocalPlayer( void ) + { + return ( static_cast< C_BaseTFPlayer * >( C_BasePlayer::GetLocalPlayer() ) ); + } + + virtual void ClientThink( void ); + virtual void OnPreDataChanged( DataUpdateType_t updateType ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void PreDataUpdate( DataUpdateType_t updateType ); + virtual void PostDataUpdate( DataUpdateType_t updateType ); + virtual void ReceiveMessage( int classID, bf_read &msg ); + virtual void Release( void ); + + virtual void ItemPostFrame( void ); + + virtual bool ShouldDraw(); + virtual int DrawModel( int flags ); + + virtual void SetDormant( bool bDormant ); + + virtual void GetBoneControllers(float controllers[MAXSTUDIOBONES]); + + virtual int GetRenderTeamNumber( void ); + virtual void ComputeFxBlend( void ); + virtual bool IsTransparent( void ); + + // Called by the view model if its rendering is being overridden. + virtual bool ViewModel_IsTransparent( void ); + + virtual bool IsOverridingViewmodel( void ); + virtual int DrawOverriddenViewmodel( C_BaseViewModel *pViewmodel, int flags ); + virtual void CreateMove( float flInputSampleTime, CUserCmd *pCmd ); + virtual float GetDefaultAnimSpeed( void ); + + int GetClass( void ); + + // Called when not in tactical mode. Allows view to be overriden for things like driving a tank. + void OverrideView( CViewSetup *pSetup ); + + // Called when not in tactical mode. Allows view model drawing to be disabled for things like driving a tank. + bool ShouldDrawViewModel(); + + void GetTargetDescription( char *pDest, int bufferSize ); + + // Orders + void SetPersonalOrder( C_Order *pOrder ); + void RemoveOrderTarget(); + + // Resources + int GetBankResources( void ); + + // Objects + void SetSelectedObject( C_BaseObject *pObject ); + C_BaseObject *GetSelectedObject( void ); + int GetNumObjects( int iObjectType ); + int GetObjectCount( void ); + C_BaseObject *GetObject( int index ); + + // Targets + void Add_Target( C_BaseEntity *pTarget, const char *sName ); + void Remove_Target( C_BaseEntity *pTarget ); + void Remove_Target( CTargetReticle *pTargetReticle ); + + void UpdateTargetReticles( void ); + + bool IsUsingThermalVision( void ) const; + + // Weapon handling + virtual bool IsAllowedToSwitchWeapons( void ); + virtual bool Weapon_ShouldSetLast( CBaseCombatWeapon *pOldWeapon, CBaseCombatWeapon *pNewWeapon ); + virtual bool Weapon_ShouldSelectItem( CBaseCombatWeapon *pWeapon ); + virtual C_BaseCombatWeapon *GetActiveWeaponForSelection( void ); + virtual C_BaseCombatWeapon *GetLastWeaponBeforeObject( void ) { return m_hLastWeaponBeforeObject; } + + virtual C_BaseAnimating* GetRenderedWeaponModel(); + + // ID Target + void SetIDEnt( C_BaseEntity *pEntity ); + int GetIDTarget( void ) const; + void UpdateIDTarget( void ); + + bool IsKnockedDown( void ) const; + void CheckKnockdownState( void ); + bool CheckKnockdownAngleOverride( void ) const; + void SetKnockdownAngles( const QAngle& ang ); + void GetKnockdownAngles( QAngle& outAngles ); + float GetKnockdownViewheightAdjust( void ) const; + + // Team handling + virtual void TeamChange( int iNewTeam ); + + // Camouflage effect + virtual bool IsCamouflaged( void ); + virtual float GetCamouflageAmount( void ); + virtual float ComputeCamoEffectAmount( void ); // 0 - visible, 1 = invisible + virtual int ComputeCamoAlpha( void ); + virtual void CheckCamoDampening( void ); + virtual void SetCamoDampening( float amount ); + virtual float GetDampeningAmount( void ); + virtual void CheckCameraMovement( void ); + + IMaterial *GetCamoMaterial( void ); + virtual float GetMovementCamoSuppression( void ); + virtual void CheckMovementCamoSuppression( void ); + virtual void SetMovementCamoSuppression( float amount ); + + // Adrenalin + void CheckAdrenalin( void ); + + void CheckLastMovement( void ); + float GetLastMoveTime( void ); + float GetOverlayAlpha( void ); + + float GetLastDamageTime( void ) const; + float GetLastGainHealthTime( void ) const; + + // Powerups + virtual void PowerupStart( int iPowerup, bool bInitial ); + virtual void PowerupEnd( int iPowerup ); + + // Sniper + bool IsDeployed( void ); + bool IsDeploying( void ); + bool IsUnDeploying( void ); + + virtual void AddEntity( void ); + + // Vertification + inline bool HasClass( void ) { return GetPlayerClass() != NULL; } + + bool IsClass( TFClass iClass ); + + + virtual int GetMaxHealth() const { return m_iMaxHealth; } + + bool ClassProxyUpdate( int nClassID ); + + // Should this object cast shadows? + virtual ShadowType_t ShadowCastType(); + + // Prediction stuff + virtual void PreThink( void ); + virtual void PostThink( void ); + + // Combat prototyping + bool IsBlocking( void ) const { return m_bIsBlocking; } + bool IsParrying( void ) const { return m_bIsParrying; } + void SetBlocking( bool bBlocking ) { m_bIsBlocking = bBlocking; } + void SetParrying( bool bParrying ) { m_bIsParrying = bParrying; } + + // Vehicles + void SetVehicleRole( int nRole ); + bool CanGetInVehicle( void ); + + // Returns true if we're in a vehicle and it's mounted on another vehicle + // (ie: are we in a manned gun that's mounted on a tank). + bool IsVehicleMounted() const; + + virtual bool IsUseableEntity( CBaseEntity *pEntity ); + +// Shared Client / Server code +public: + bool IsHittingShield( const Vector &vecVelocity, float *flDamage ); + C_WeaponCombatShield *GetCombatShield( void ); + virtual void PainSound( void ); + +public: + // Data for only the local player + CTFPlayerLocalData m_TFLocal; + + // Accessors... + const QAngle& DeployedAngles() const { return m_vecDeployedAngles; } + int ZoneState() const { return m_iCurrentZoneState; } + float CamouflageAmount() const { return m_flCamouflageAmount; } + int PlayerClass() const { return m_iPlayerClass; } + C_PlayerClass *GetPlayerClass(); + C_Order *PersonalOrder() { return m_hPersonalOrder; } + C_BaseEntity *SpawnPoint() { return m_hSpawnPoint.Get(); } + + C_VehicleTeleportStation* GetSelectedMCV() const; + + // Object sapper placement handling + //float m_flSapperAttachmentFinishTime; + //float m_flSapperAttachmentStartTime; + //CHandle< CGrenadeObjectSapper > m_hSapper; + //CHandle< CBaseObject > m_hSappedObject; + CHealthBarPanel *m_pSapperAttachmentStatus; + +private: + C_BaseTFPlayer( const C_BaseTFPlayer & ); + + // Client-side obstacle avoidance + void PerformClientSideObstacleAvoidance( float flFrameTime, CUserCmd *pCmd ); + + float m_flLastAttackTime; + + EHANDLE m_hSelectedMCV; + + // Weapon used before switching to an object placement + CHandle<C_BaseCombatWeapon> m_hLastWeaponBeforeObject; + + float m_flCamouflageAmount; + + // Movement. + Vector m_vecPosDelta; + + enum { MOMENTUM_MAXSIZE = 10 }; + float m_aMomentum[MOMENTUM_MAXSIZE]; + int m_iMomentumHead; + + // Player Class + int m_iPlayerClass; + C_AllPlayerClasses m_PlayerClasses; + + // Spawn location... + EHANDLE m_hSpawnPoint; + + // Orders + CHandle< C_Order > m_hSelectedOrder; + CHandle< C_Order > m_hPersonalOrder; + int m_iSelectedTarget; + int m_iPersonalTarget; + CUtlVector< CTargetReticle * > m_aTargetReticles; // A list of entities to show target reticles for + + // Objects + CHandle< C_BaseObject > m_hSelectedObject; + + int m_iLastHealth; + + bool m_bIsBlocking; + bool m_bIsParrying; + + bool m_bUnderAttack; + int m_iMaxHealth; + bool m_bDeployed; + bool m_bDeploying; + bool m_bUnDeploying; + QAngle m_vecDeployedAngles; + int m_iCurrentZoneState; + int m_TFPlayerFlags; + + int m_nOldTacticalView; + int m_nOldPlayerClass; + + float m_flNextUseCheck; + + bool m_bOldThermalVision; + bool m_bOldAttachingSapper; + + bool m_bOldKnockDownState; + float m_flStartKnockdown; + float m_flEndKnockdown; + QAngle m_vecOriginalViewAngles; + QAngle m_vecCurrentKnockdownAngles; + QAngle m_vecKnockDownGoalAngles; + bool m_bKnockdownOverrideAngles; + float m_flKnockdownViewheightAdjust; + + CPlayerAnimState m_PlayerAnimState; + + // For sniper hiding + float m_flLastMoveTime; + Vector m_vecLastOrigin; + + // For material proxies + float m_flLastDamageTime; + float m_flLastGainHealthTime; + + IMaterial *m_pThermalMaterial; + IMaterial *m_pCamoEffectMaterial; + + // Camouflage + float m_flDampeningAmount; + float m_flGoalDampeningAmount; + float m_flDampeningStayoutTime; + + // Suppression of camo based on movement + float m_flMovementCamoSuppression; + float m_flGoalMovementCamoSuppressionAmount; + float m_flMovementCamoSuppressionStayoutTime; + + // Adrenalin + float m_flNextAdrenalinEffect; + bool m_bFadingIn; + + // ID Target + int m_iIDEntIndex; + + CMaterialReference m_BoostMaterial; + CMaterialReference m_EMPMaterial; + float m_BoostModelAngles[3]; + + // Personal shield effects. + CUtlLinkedList<CPersonalShieldEffect*, int> m_PersonalShieldEffects; + + CHandle< C_WeaponCombatShield > m_hWeaponCombatShield; + + // No one should call this + C_BaseTFPlayer& operator=( const C_BaseTFPlayer& src ); + + friend void RecvProxy_PlayerClass( const CRecvProxyData *pData, void *pStruct, void *pOut ); + + + friend class CTFPrediction; +}; + +int GetLocalPlayerClass( void ); +bool IsLocalPlayerClass( int iClass ); +bool IsLocalPlayerInTactical( ); +inline C_BaseTFPlayer *ToBaseTFPlayer( C_BaseEntity *pEntity ) +{ + if ( !pEntity || !pEntity->IsPlayer() ) + return NULL; + +#if _DEBUG + return dynamic_cast<C_BaseTFPlayer *>( pEntity ); +#else + return static_cast<C_BaseTFPlayer *>( pEntity ); +#endif +} + +#endif // C_BASETFPLAYER_H diff --git a/game/client/tf2/c_controlzone.cpp b/game/client/tf2/c_controlzone.cpp new file mode 100644 index 0000000..be220b4 --- /dev/null +++ b/game/client/tf2/c_controlzone.cpp @@ -0,0 +1,67 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_controlzone.h" +#include "mapdata.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ControlZone::C_ControlZone() +{ + m_nZoneNumber = 0; + + m_pShowTriggers = cvar->FindVar("showtriggers"); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ControlZone::~C_ControlZone() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Are we using showtriggers? +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool C_ControlZone::ShouldDraw() +{ + if ( !m_pShowTriggers ) + return false; + + return m_pShowTriggers->GetInt() != 0 ? true : false; +} + +//----------------------------------------------------------------------------- +// Purpose: Update global map state based on data received +// Input : bnewentity - +//----------------------------------------------------------------------------- +void C_ControlZone::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + CMapZones *zone; + if ( m_nZoneNumber < 1 || + m_nZoneNumber > MAX_ZONES ) + return; + + zone = &MapData().m_Zones[ m_nZoneNumber -1 ]; + zone->m_nControllingTeam = GetTeamNumber(); +} + +IMPLEMENT_CLIENTCLASS_DT(C_ControlZone, DT_ControlZone, CControlZone) + RecvPropInt( RECVINFO(m_nZoneNumber )), +END_RECV_TABLE() + + diff --git a/game/client/tf2/c_controlzone.h b/game/client/tf2/c_controlzone.h new file mode 100644 index 0000000..8d0af26 --- /dev/null +++ b/game/client/tf2/c_controlzone.h @@ -0,0 +1,39 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#if !defined( C_CONTROLZONE_H ) +#define C_CONTROLZONE_H +#ifdef _WIN32 +#pragma once +#endif + +class ConVar; +//----------------------------------------------------------------------------- +// Purpose: Client side rep of control zone entity ( trigger, so not usually visible ) +//----------------------------------------------------------------------------- +class C_ControlZone : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_ControlZone, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + C_ControlZone(); + virtual ~C_ControlZone(); + + virtual bool ShouldDraw(); + virtual void OnDataChanged( DataUpdateType_t updateType ); + +public: + int m_nZoneNumber; + +private: + const ConVar *m_pShowTriggers; +}; + +#endif // C_CONTROLZONE_H
\ No newline at end of file diff --git a/game/client/tf2/c_demo_entities.cpp b/game/client/tf2/c_demo_entities.cpp new file mode 100644 index 0000000..e186ebb --- /dev/null +++ b/game/client/tf2/c_demo_entities.cpp @@ -0,0 +1,35 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_demo_entities.h" + + +IMPLEMENT_CLIENTCLASS_DT(C_Cycler_TF2Commando, DT_Cycler_TF2Commando, CCycler_TF2Commando) + RecvPropInt( RECVINFO(m_bShieldActive) ), + RecvPropFloat( RECVINFO(m_flShieldRaiseTime) ), + RecvPropFloat( RECVINFO(m_flShieldLowerTime) ), +END_RECV_TABLE() + +C_Cycler_TF2Commando::C_Cycler_TF2Commando() +{ +} + +float C_Cycler_TF2Commando::GetShieldRaiseTime() const +{ + return m_bShieldActive ? gpGlobals->curtime - m_flShieldRaiseTime : 0.0f; +} + +float C_Cycler_TF2Commando::GetShieldLowerTime() const +{ + return !m_bShieldActive ? gpGlobals->curtime - m_flShieldLowerTime : 0.0f; +} + +bool C_Cycler_TF2Commando::IsShieldActive() const +{ + return m_bShieldActive; +} + diff --git a/game/client/tf2/c_demo_entities.h b/game/client/tf2/c_demo_entities.h new file mode 100644 index 0000000..3966aad --- /dev/null +++ b/game/client/tf2/c_demo_entities.h @@ -0,0 +1,36 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_DEMO_ENTITIES_H +#define C_DEMO_ENTITIES_H + +#include "c_ai_basenpc.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_Cycler_TF2Commando : public C_AI_BaseNPC +{ + DECLARE_CLASS( C_Cycler_TF2Commando, C_AI_BaseNPC ); +public: + DECLARE_CLIENTCLASS(); + + C_Cycler_TF2Commando(); + + float GetShieldRaiseTime() const; + float GetShieldLowerTime() const; + bool IsShieldActive() const; + +private: + C_Cycler_TF2Commando( const C_Cycler_TF2Commando& ); + + bool m_bShieldActive; + float m_flShieldRaiseTime; + float m_flShieldLowerTime; +}; + +#endif // C_DEMO_ENTITIES_H diff --git a/game/client/tf2/c_effect_shootingstar.cpp b/game/client/tf2/c_effect_shootingstar.cpp new file mode 100644 index 0000000..98a4ecc --- /dev/null +++ b/game/client/tf2/c_effect_shootingstar.cpp @@ -0,0 +1,179 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client's Meteor +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_effect_shootingstar.h" +#include "clienteffectprecachesystem.h" + +//============================================================================= +// +// Shooting Star Spawner Functionality +// + +IMPLEMENT_CLIENTCLASS_DT( C_ShootingStarSpawner, DT_ShootingStarSpawner, CShootingStarSpawner ) + RecvPropFloat( RECVINFO( m_flSpawnInterval ) ), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ShootingStarSpawner::C_ShootingStarSpawner( void ) +{ + SetNextClientThink( gpGlobals->curtime + m_flSpawnInterval ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ShootingStarSpawner::ClientThink( void ) +{ + // Spawn a number of shooting stars. + SpawnShootingStars(); + + // Randomly generate a next think time. + SetNextClientThink( gpGlobals->curtime + random->RandomFloat( 0.25, m_flSpawnInterval ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ShootingStarSpawner::SpawnShootingStars( void ) +{ + C_ShootingStar *pShootingStar = new C_ShootingStar; + if ( pShootingStar ) + { + // In Space. + pShootingStar->SetFriction( 1.0f ); + pShootingStar->SetGravity( 0.0f ); + + // Randomize the velocity. -- This isn't right, but works for the test! + Vector vecVelocity; + vecVelocity.x = ( GetAbsAngles().x ) * random->RandomFloat( 1.0f, 10.0f ); + vecVelocity.y = ( GetAbsAngles().y ) * random->RandomFloat( 1.0f, 10.0f ); + vecVelocity.z = ( GetAbsAngles().z ) * random->RandomFloat( 1.0f, 10.0f ); + + pShootingStar->Init( GetAbsOrigin(), vecVelocity, random->RandomFloat( 10.0f, 100.0f ), random->RandomFloat( 10.0f, 30.0f ) ); + } +} + +//============================================================================= +// +// Shooting Star Functionality +// + +//Precahce the effects +CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectShootingStars ) +CLIENTEFFECT_MATERIAL( "effects/redflare" ) +CLIENTEFFECT_REGISTER_END() + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +C_ShootingStar::C_ShootingStar( void ) : CSimpleEmitter( "ShootingStar" ) +{ + m_flScale = 1.0f; + SetDynamicallyAllocated( false ); +} + + +//----------------------------------------------------------------------------- +// Destructor +//----------------------------------------------------------------------------- +C_ShootingStar::~C_ShootingStar( void ) +{ +} + +//----------------------------------------------------------------------------- +// Destructor +//----------------------------------------------------------------------------- +void C_ShootingStar::Init( const Vector vecOrigin, const Vector vecVelocity, int nSize, + float flLifeTime ) +{ + // Set the sort origin. + SetSortOrigin( vecOrigin ); + + // Create the initial particle and set the data. + SimpleParticle *pParticle = ( SimpleParticle* )AddParticle( sizeof( SimpleParticle ), GetPMaterial( "effects/redflare" ), vecOrigin ); + if ( pParticle ) + { + pParticle->m_vecVelocity = vecVelocity; + + pParticle->m_uchColor[0] = pParticle->m_uchColor[1] = pParticle->m_uchColor[2] = 255; + + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = random->RandomFloat( 1.0f, 4.0f ); + + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = flLifeTime; + + pParticle->m_uchStartAlpha = 255; + pParticle->m_uchEndAlpha = 0; + pParticle->m_uchStartSize = nSize; + pParticle->m_uchEndSize = ( nSize / 3 ); + } + + int iParticle = m_aParticles.AddToTail(); + m_aParticles[iParticle] = pParticle; +} + +//----------------------------------------------------------------------------- +// Destructor +//----------------------------------------------------------------------------- +void C_ShootingStar::Destroy( void ) +{ + // Destroy shooting star particles. + int nParticleCount = m_aParticles.Count(); + for ( int iParticle = ( nParticleCount - 1 ); iParticle >= 0; iParticle-- ) + { + SimpleParticle *pParticle = m_aParticles[iParticle]; + m_aParticles.Remove( iParticle ); + CSimpleEmitter::NotifyDestroyParticle( pParticle ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ShootingStar::SetSortOrigin( const Vector &vSortOrigin ) +{ + CSimpleEmitter::SetSortOrigin( vSortOrigin ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : timeDelta - +//----------------------------------------------------------------------------- +void C_ShootingStar::Update( float timeDelta ) +{ + // Parent update. + CSimpleEmitter::Update( timeDelta ); + + // Don't update if the console is down. + if ( timeDelta <= 0.0f ) + return; + + // Are we still alive? Get the tail of the shooting star (last valid index) + // and test. + int nParticleCount = m_aParticles.Count(); + if ( nParticleCount <= 0 ) + return; + + SimpleParticle *pParticle = m_aParticles[nParticleCount-1]; + if ( pParticle->m_flLifetime >= pParticle->m_flDieTime ) + { + Destroy(); + return; + } + + // Update the particles lifetime. + pParticle->m_flLifetime += timeDelta; + + // Update the particle position. + pParticle->m_Pos += ( pParticle->m_vecVelocity * timeDelta ); + + SetLocalOrigin( pParticle->m_Pos ); + SetSortOrigin( GetAbsOrigin() ); +} diff --git a/game/client/tf2/c_effect_shootingstar.h b/game/client/tf2/c_effect_shootingstar.h new file mode 100644 index 0000000..a0f5671 --- /dev/null +++ b/game/client/tf2/c_effect_shootingstar.h @@ -0,0 +1,72 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client's Meteor +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_EFFECT_SHOOTINGSTAR_H +#define C_EFFECT_SHOOTINGSTAR_H +#pragma once + +#include "c_baseanimating.h" +#include "particles_simple.h" + +class C_ShootingStar; + +//============================================================================= +// +// Client-side shooting star spawner. +// +class C_ShootingStarSpawner : public C_BaseEntity +{ + DECLARE_CLASS( C_ShootingStarSpawner, C_BaseEntity ); + +public: + + DECLARE_CLIENTCLASS(); + + C_ShootingStarSpawner(); + + void ClientThink( void ); + void SpawnShootingStars( void ); + +public: + + float m_flSpawnInterval; // How often do I spawn meteors? +}; + + +//============================================================================= +// +// Shooting Star Effect +// +class C_ShootingStar : public C_BaseAnimating, CSimpleEmitter +{ + DECLARE_CLASS( C_ShootingStar, C_BaseAnimating ); + +public: + + C_ShootingStar( ); + ~C_ShootingStar( void ); + + void Init( const Vector vecOrigin, const Vector vecVelocity, int nSize, float flLifeTime ); + void Destroy( void ); + + void Update( float timeDelta ); + +public: + + float m_flScale; + +private: + + void SetSortOrigin( const Vector &vSortOrigin ); + +private: + C_ShootingStar( const C_ShootingStar & ); + + CUtlVector<SimpleParticle*> m_aParticles; +}; + +#endif // C_EFFECT_SHOOTINGSTAR_H
\ No newline at end of file diff --git a/game/client/tf2/c_entity_burn_effect.cpp b/game/client/tf2/c_entity_burn_effect.cpp new file mode 100644 index 0000000..08c4f89 --- /dev/null +++ b/game/client/tf2/c_entity_burn_effect.cpp @@ -0,0 +1,85 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_entity_burn_effect.h" + + +#define NUM_BURN_PARTICLES_PER_SEC 50 + + + +IMPLEMENT_CLIENTCLASS_DT( C_EntityBurnEffect, DT_EntityBurnEffect, CEntityBurnEffect ) + RecvPropInt( RECVINFO( m_hBurningEntity ) ) +END_RECV_TABLE() + + + +C_EntityBurnEffect::C_EntityBurnEffect() +{ + m_pEmitter = CSimpleEmitter::Create( "Entity burn effect" ); + if ( m_pEmitter.IsValid() ) + { + m_hFireMaterial = m_pEmitter->GetPMaterial( "particle/fire" ); + } + else + { + m_hFireMaterial = INVALID_MATERIAL_HANDLE; + } + m_Timer.Init( NUM_BURN_PARTICLES_PER_SEC ); +} + + +void C_EntityBurnEffect::OnDataChanged( DataUpdateType_t updateType ) +{ + if ( updateType == DATA_UPDATE_CREATED ) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } +} + + +void C_EntityBurnEffect::ClientThink() +{ + if ( !m_pEmitter.IsValid() || IsDormant() ) + return; + + // Add some burning particles to our target entity. + C_BaseEntity *pEnt = ClientEntityList().GetBaseEntity( m_hBurningEntity ); + if ( !pEnt ) + return; + + float dt = gpGlobals->frametime; + while ( m_Timer.NextEvent( dt ) ) + { + Vector vDims = (pEnt->WorldAlignMaxs() - pEnt->WorldAlignMins()) * 0.5f; + Vector vCenter = pEnt->GetAbsOrigin() + pEnt->WorldAlignMins() + vDims; + Vector vPos = vCenter + vDims * RandomVector( -0.7, 0.7 ); + + float flLifetime = 1; + float flRadius = 3; + unsigned char uchColor[4] = { 255, 100, 0, 100 }; + + SimpleParticle *pParticle = m_pEmitter->AddSimpleParticle( m_hFireMaterial, vPos, flLifetime, flRadius ); + if ( pParticle ) + { + pParticle->m_uchColor[0] = uchColor[0]; + pParticle->m_uchColor[1] = uchColor[1]; + pParticle->m_uchColor[2] = uchColor[2]; + + pParticle->m_uchEndAlpha = 0; + pParticle->m_uchStartAlpha = uchColor[3]; + + pParticle->m_vecVelocity.x = RandomFloat( -2, 2 ); + pParticle->m_vecVelocity.y = RandomFloat( -2, 2 ); + pParticle->m_vecVelocity.z = RandomFloat( 3, 29 ); + + // Pick up some velocity from the burning guy running around. + pParticle->m_vecVelocity += pEnt->GetAbsVelocity() * 0.6; + } + } +} + diff --git a/game/client/tf2/c_entity_burn_effect.h b/game/client/tf2/c_entity_burn_effect.h new file mode 100644 index 0000000..9a5d7d3 --- /dev/null +++ b/game/client/tf2/c_entity_burn_effect.h @@ -0,0 +1,44 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_ENTITY_BURN_EFFECT_H +#define C_ENTITY_BURN_EFFECT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_baseentity.h" +#include "particle_util.h" +#include "particles_simple.h" + +class C_EntityBurnEffect : public C_BaseEntity +{ +public: + + DECLARE_CLASS( C_EntityBurnEffect, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + C_EntityBurnEffect(); + + +// Overrides. +public: + + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void ClientThink(); + + +private: + int m_hBurningEntity; // todo: this should be an ehandle but base networkables aren't setup for ehandles yet. + + TimedEvent m_Timer; + CSmartPtr<CSimpleEmitter> m_pEmitter; + PMaterialHandle m_hFireMaterial; +}; + + +#endif // C_ENTITY_BURN_EFFECT_H diff --git a/game/client/tf2/c_env_meteor.cpp b/game/client/tf2/c_env_meteor.cpp new file mode 100644 index 0000000..e2ccf53 --- /dev/null +++ b/game/client/tf2/c_env_meteor.cpp @@ -0,0 +1,651 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "C_Env_Meteor.h" +#include "fx_explosion.h" +#include "tempentity.h" +#include "c_tracer.h" + +//============================================================================= +// +// Meteor Factory Functions +// + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void C_MeteorFactory::CreateMeteor( int nID, int iType, + const Vector &vecPosition, const Vector &vecDirection, + float flSpeed, float flStartTime, float flDamageRadius, + const Vector &vecTriggerMins, const Vector &vecTriggerMaxs ) +{ + C_EnvMeteor::Create( nID, iType, vecPosition, vecDirection, flSpeed, flStartTime, flDamageRadius, + vecTriggerMins, vecTriggerMaxs ); +} + + +//============================================================================= +// +// Meteor Spawner Functions +// + +void RecvProxy_MeteorTargetPositions( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + CEnvMeteorSpawnerShared *pSpawner = ( CEnvMeteorSpawnerShared* )pStruct; + pSpawner->m_aTargets[pData->m_iElement].m_vecPosition.x = pData->m_Value.m_Vector[0]; + pSpawner->m_aTargets[pData->m_iElement].m_vecPosition.y = pData->m_Value.m_Vector[1]; + pSpawner->m_aTargets[pData->m_iElement].m_vecPosition.z = pData->m_Value.m_Vector[2]; +} + +void RecvProxy_MeteorTargetRadii( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + CEnvMeteorSpawnerShared *pSpawner = ( CEnvMeteorSpawnerShared* )pStruct; + pSpawner->m_aTargets[pData->m_iElement].m_flRadius = pData->m_Value.m_Float; +} + +void RecvProxyArrayLength_MeteorTargets( void *pStruct, int objectID, int currentArrayLength ) +{ + CEnvMeteorSpawnerShared *pSpawner = ( CEnvMeteorSpawnerShared* )pStruct; + if ( pSpawner->m_aTargets.Count() < currentArrayLength ) + { + pSpawner->m_aTargets.SetSize( currentArrayLength ); + } +} + + +BEGIN_RECV_TABLE_NOBASE( CEnvMeteorSpawnerShared, DT_EnvMeteorSpawnerShared ) + // Setup (read from) Worldcraft. + RecvPropInt ( RECVINFO( m_iMeteorType ) ), + RecvPropInt ( RECVINFO( m_bSkybox ) ), + RecvPropFloat ( RECVINFO( m_flMinSpawnTime ) ), + RecvPropFloat ( RECVINFO( m_flMaxSpawnTime ) ), + RecvPropInt ( RECVINFO( m_nMinSpawnCount ) ), + RecvPropInt ( RECVINFO( m_nMaxSpawnCount ) ), + RecvPropFloat ( RECVINFO( m_flMinSpeed ) ), + RecvPropFloat ( RECVINFO( m_flMaxSpeed ) ), + + // Setup through Init. + RecvPropFloat ( RECVINFO( m_flStartTime ) ), + RecvPropInt ( RECVINFO( m_nRandomSeed ) ), + RecvPropVector ( RECVINFO( m_vecMinBounds ) ), + RecvPropVector ( RECVINFO( m_vecMaxBounds ) ), + RecvPropVector ( RECVINFO( m_vecTriggerMins ) ), + RecvPropVector ( RECVINFO( m_vecTriggerMaxs ) ), + + // Target List + RecvPropArray2( RecvProxyArrayLength_MeteorTargets, + RecvPropVector( "meteortargetposition_array_element", 0, 0, 0, RecvProxy_MeteorTargetPositions ), + 16, 0, "meteortargetposition_array" ), + + RecvPropArray2( RecvProxyArrayLength_MeteorTargets, + RecvPropFloat( "meteortargetradius_array_element", 0, 0, 0, RecvProxy_MeteorTargetRadii ), + 16, 0, "meteortargetradius_array" ) +END_RECV_TABLE() + +// This table encodes the CBaseEntity data. +IMPLEMENT_CLIENTCLASS_DT( C_EnvMeteorSpawner, DT_EnvMeteorSpawner, CEnvMeteorSpawner ) + RecvPropDataTable ( RECVINFO_DT( m_SpawnerShared ), 0, &REFERENCE_RECV_TABLE( DT_EnvMeteorSpawnerShared ) ), + RecvPropInt ( RECVINFO( m_fDisabled ) ), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +C_EnvMeteorSpawner::C_EnvMeteorSpawner() +{ +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void C_EnvMeteorSpawner::OnDataChanged( DataUpdateType_t updateType ) +{ + // Initialize the client side spawner. + m_SpawnerShared.Init( &m_Factory, m_SpawnerShared.m_nRandomSeed, m_SpawnerShared.m_flStartTime, + m_SpawnerShared.m_vecMinBounds, m_SpawnerShared.m_vecMaxBounds, + m_SpawnerShared.m_vecTriggerMins, m_SpawnerShared.m_vecTriggerMaxs ); + + // Set the next think to be the next spawn interval. + if ( !m_fDisabled ) + { + SetNextClientThink( m_SpawnerShared.m_flNextSpawnTime ); + } +} + +#if 0 +// Will probably be used later!! +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void C_EnvMeteorSpawner::ReceiveMessage( int classID, bf_read &msg ) +{ + if ( classID != GetClientClass()->m_ClassID ) + { + // message is for subclass + BaseClass::ReceiveMessage( classID, msg ); + return; + } + + m_SpawnerShared.m_flStartTime = msg.ReadLong(); + m_SpawnerShared.m_flNextSpawnTime = msg.ReadLong(); + SetNextClientThink( m_SpawnerShared.m_flNextSpawnTime ); +} +#endif + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void C_EnvMeteorSpawner::ClientThink( void ) +{ + SetNextClientThink( m_SpawnerShared.MeteorThink( gpGlobals->curtime ) ); +} + +//============================================================================= +// +// Meteor Tail Functions +// + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +C_EnvMeteorHead::C_EnvMeteorHead() +{ + m_vecPos.Init(); + m_vecPrevPos.Init(); + + m_flParticleScale = 1.0f; + + m_pSmokeEmitter = NULL; + m_flSmokeSpawnInterval = 0.0f; + m_hSmokeMaterial = INVALID_MATERIAL_HANDLE; + m_flSmokeLifetime = 2.5f; + m_bEmitSmoke = true; + + m_hFlareMaterial = INVALID_MATERIAL_HANDLE; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +C_EnvMeteorHead::~C_EnvMeteorHead() +{ + Destroy(); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void C_EnvMeteorHead::Start( const Vector &vecOrigin, const Vector &vecDirection ) +{ + // Emitters. + m_pSmokeEmitter = CSimpleEmitter::Create( "MeteorTrail" ); +// m_pFireEmitter = CSimpleEmitter::Create( "MeteorFire" ); + if ( !m_pSmokeEmitter /*|| !m_pFireEmitter*/ ) + return; + + // Smoke + m_pSmokeEmitter->SetSortOrigin( vecOrigin ); + m_hSmokeMaterial = m_pSmokeEmitter->GetPMaterial( "particle/SmokeStack" ); + Assert( m_hSmokeMaterial != INVALID_MATERIAL_HANDLE ); + + // Fire +// m_pFireEmitter->SetSortOrigin( vecOrigin ); +// m_hFireMaterial = m_pFireEmitter->GetPMaterial( "particle/particle_fire" ); +// Assert( m_hFireMaterial != INVALID_MATERIAL_HANDLE ); + + // Flare +// m_hFlareMaterial = m_ParticleEffect.FindOrAddMaterial( "effects/redflare" ); + + VectorCopy( vecDirection, m_vecDirection ); + VectorCopy( vecOrigin, m_vecPos ); + + m_bInitThink = true; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void C_EnvMeteorHead::Destroy( void ) +{ + m_pSmokeEmitter = NULL; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void C_EnvMeteorHead::MeteorHeadThink( const Vector &vecOrigin, float flTime ) +{ + if ( m_bInitThink ) + { + VectorCopy( vecOrigin, m_vecPrevPos ); + m_bInitThink = false; + } + + // Update the position of the emitters. + VectorCopy( vecOrigin, m_vecPos ); + + // Update Smoke + if ( m_pSmokeEmitter.IsValid() && m_bEmitSmoke ) + { + m_pSmokeEmitter->SetSortOrigin( m_vecPos ); + + // Get distance covered + Vector vecDelta; + VectorSubtract( m_vecPos, m_vecPrevPos, vecDelta ); + float flLength = vecDelta.Length(); + + int nParticleCount = flLength / 35.0f; + if ( nParticleCount < 1 ) + { + nParticleCount = 1; + } + + flLength /= nParticleCount; + + Vector vecPos; + for( int iParticle = 0; iParticle < nParticleCount; ++iParticle ) + { + vecPos = m_vecPrevPos + ( m_vecDirection * ( flLength * iParticle ) ); + + // Add some noise to the position. + Vector vecPosOffset; + vecPosOffset.Random( -m_flSmokeSpawnRadius, m_flSmokeSpawnRadius ); + VectorAdd( vecPosOffset, vecPos, vecPosOffset ); + + + SimpleParticle *pParticle = ( SimpleParticle* )m_pSmokeEmitter->AddParticle( sizeof( SimpleParticle ), + m_hSmokeMaterial, + vecPosOffset ); + if ( pParticle ) + { + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = m_flSmokeLifetime; + + // Add just a little movement. + pParticle->m_vecVelocity.Random( -5.0f, 5.0f ); + + pParticle->m_uchColor[0] = 255.0f; + pParticle->m_uchColor[1] = 255.0f; + pParticle->m_uchColor[2] = 255.0f; + + + pParticle->m_uchStartSize = 70 * m_flParticleScale; + pParticle->m_uchEndSize = 25 * m_flParticleScale; + + float flAlpha = random->RandomFloat( 0.5f, 1.0f ); + pParticle->m_uchStartAlpha = flAlpha * 255; + pParticle->m_uchEndAlpha = 0; + + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = random->RandomFloat( -1.0f, 1.0f ); + } + } + } + + // Update Fire +// if ( m_pFireEmitter && m_bEmitFire ) +// { +// } + + // Flare + + // Save off position. + VectorCopy( m_vecPos, m_vecPrevPos ); +} + +//============================================================================= +// +// Meteor Tail Functions +// + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +C_EnvMeteorTail::C_EnvMeteorTail() +{ + m_TailMaterialHandle = INVALID_MATERIAL_HANDLE; + + m_pParticleMgr = NULL; + m_pParticle = NULL; + + m_flFadeTime = 0.5f; + m_flWidth = 3.0f; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +C_EnvMeteorTail::~C_EnvMeteorTail() +{ + Destroy(); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void C_EnvMeteorTail::Start( const Vector &vecOrigin, const Vector &vecDirection, + float flSpeed ) +{ + // Set the particle manager. + m_pParticleMgr = ParticleMgr(); + m_pParticleMgr->AddEffect( &m_ParticleEffect, this ); + m_TailMaterialHandle = m_ParticleEffect.FindOrAddMaterial( "particle/guidedplasmaprojectile" ); + m_pParticle = m_ParticleEffect.AddParticle( sizeof( StandardParticle_t ), m_TailMaterialHandle ); + if ( m_pParticle ) + { + m_pParticle->m_Pos = vecOrigin; + } + + VectorCopy( vecDirection, m_vecDirection ); + m_flSpeed = flSpeed; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void C_EnvMeteorTail::Destroy( void ) +{ + if ( m_pParticleMgr ) + { + m_pParticleMgr->RemoveEffect( &m_ParticleEffect ); + m_pParticleMgr = NULL; + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void C_EnvMeteorTail::DrawFragment( ParticleDraw* pDraw, + const Vector &vecStart, const Vector &vecDelta, + const Vector4D &vecStartColor, const Vector4D &vecEndColor, + float flStartV, float flEndV ) +{ + if( !pDraw->GetMeshBuilder() ) + return; + + // Clip the fragment. + Vector vecVerts[4]; + if ( !Tracer_ComputeVerts( vecStart, vecDelta, m_flWidth, vecVerts ) ) + return; + + // NOTE: Gotta get the winding right so it's not backface culled + // (we need to turn of backface culling for these bad boys) + CMeshBuilder* pMeshBuilder = pDraw->GetMeshBuilder(); + + pMeshBuilder->Position3f( vecVerts[0].x, vecVerts[0].y, vecVerts[0].z ); + pMeshBuilder->TexCoord2f( 0, 0.0f, flStartV ); + pMeshBuilder->Color4fv( vecStartColor.Base() ); + pMeshBuilder->AdvanceVertex(); + + pMeshBuilder->Position3f( vecVerts[1].x, vecVerts[1].y, vecVerts[1].z ); + pMeshBuilder->TexCoord2f( 0, 1.0f, flStartV ); + pMeshBuilder->Color4fv( vecStartColor.Base() ); + pMeshBuilder->AdvanceVertex(); + + pMeshBuilder->Position3f( vecVerts[3].x, vecVerts[3].y, vecVerts[3].z ); + pMeshBuilder->TexCoord2f( 0, 1.0f, flEndV ); + pMeshBuilder->Color4fv( vecEndColor.Base() ); + pMeshBuilder->AdvanceVertex(); + + pMeshBuilder->Position3f( vecVerts[2].x, vecVerts[2].y, vecVerts[2].z ); + pMeshBuilder->TexCoord2f( 0, 0.0f, flEndV ); + pMeshBuilder->Color4fv( vecEndColor.Base() ); + pMeshBuilder->AdvanceVertex(); +} + +void C_EnvMeteorTail::SimulateParticles( CParticleSimulateIterator *pIterator ) +{ + Particle *pParticle = (Particle*)pIterator->GetFirst(); + while ( pParticle ) + { + // Update the particle position. + pParticle->m_Pos = GetLocalOrigin(); + + pParticle = (Particle*)pIterator->GetNext(); + } +} + + +void C_EnvMeteorTail::RenderParticles( CParticleRenderIterator *pIterator ) +{ + const Particle *pParticle = (const Particle *)pIterator->GetFirst(); + while ( pParticle ) + { + // Now draw the tail fragments... + Vector4D vecStartColor( 1.0f, 1.0f, 1.0f, 1.0f ); + Vector4D vecEndColor( 1.0f, 1.0f, 1.0f, 0.0f ); + Vector vecDelta, vecStartPos, vecEndPos; + + // Calculate the tail. + Vector vecTailEnd; + vecTailEnd = GetLocalOrigin() + ( m_vecDirection * -m_flSpeed ); + + // Transform particles into camera space. + TransformParticle( m_pParticleMgr->GetModelView(), GetLocalOrigin(), vecStartPos ); + TransformParticle( m_pParticleMgr->GetModelView(), vecTailEnd, vecEndPos ); + float sortKey = vecStartPos.z; + + // Draw the tail fragment. + VectorSubtract( vecStartPos, vecEndPos, vecDelta ); + DrawFragment( pIterator->GetParticleDraw(), vecEndPos, vecDelta, vecEndColor, vecStartColor, + 1.0f - vecEndColor[3], 1.0f - vecStartColor[3] ); + + pParticle = (const Particle *)pIterator->GetNext( sortKey ); + } +} + + +//============================================================================= +// +// Meteor Functions +// + +static g_MeteorCounter = 0; + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +C_EnvMeteor::C_EnvMeteor() +{ +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +C_EnvMeteor::~C_EnvMeteor() +{ +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void C_EnvMeteor::ClientThink( void ) +{ + // Get the current time. + float flTime = gpGlobals->curtime; + + // Update the meteor. + if ( m_Meteor.IsInSkybox( flTime ) ) + { + if ( m_Meteor.m_nLocation == METEOR_LOCATION_WORLD ) + { + WorldToSkyboxThink( flTime ); + } + else + { + SkyboxThink( flTime ); + } + } + else + { + if ( m_Meteor.m_nLocation == METEOR_LOCATION_SKYBOX ) + { + SkyboxToWorldThink( flTime ); + } + else + { + WorldThink( flTime ); + } + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void C_EnvMeteor::SkyboxThink( float flTime ) +{ + float flDeltaTime = flTime - m_Meteor.m_flStartTime; + if ( flDeltaTime > METEOR_MAX_LIFETIME ) + { + Destroy( this ); + return; + } + + // Check to see if the object is passive or not - act accordingly! + if ( !m_Meteor.IsPassive( flTime ) ) + { + // Update meteor position. + Vector origin; + m_Meteor.GetPositionAtTime( flTime, origin ); + SetLocalOrigin( origin ); + + // Update the position of the tail effect. + m_TailEffect.SetLocalOrigin( GetLocalOrigin() ); + m_HeadEffect.MeteorHeadThink( GetLocalOrigin(), flTime ); + } + + // Add the entity to the active list - update! + AddEntity(); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void C_EnvMeteor::WorldToSkyboxThink( float flTime ) +{ + // Move the meteor from the world into the skybox. + m_Meteor.ConvertFromWorldToSkybox(); + + // Destroy the head effect. Recreate it. + m_HeadEffect.Destroy(); + m_HeadEffect.Start( m_Meteor.m_vecStartPosition, m_vecTravelDir ); + m_HeadEffect.SetSmokeEmission( true ); + m_HeadEffect.SetParticleScale( 1.0f / 16.0f ); + m_HeadEffect.m_bInitThink = true; + + // Update to world model. + SetModel( "models/props/common/meteorites/meteor05.mdl" ); + + // Update the meteor position (move into the skybox!) + SetLocalOrigin( m_Meteor.m_vecStartPosition ); + + // Update (think). + SkyboxThink( flTime ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void C_EnvMeteor::SkyboxToWorldThink( float flTime ) +{ + // Move the meteor from the skybox into the world. + m_Meteor.ConvertFromSkyboxToWorld(); + + // Destroy the head effect. Recreate it. + m_HeadEffect.Destroy(); + m_HeadEffect.Start( m_Meteor.m_vecStartPosition, m_vecTravelDir ); + m_HeadEffect.SetSmokeEmission( true ); + m_HeadEffect.SetParticleScale( 1.0f ); + m_HeadEffect.m_bInitThink = true; + + // Update to world model. + SetModel( "models/props/common/meteorites/meteor04.mdl" ); + + SetLocalOrigin( m_Meteor.m_vecStartPosition ); + + // Update (think). + WorldThink( flTime ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void C_EnvMeteor::WorldThink( float flTime ) +{ + // Update meteor position. + Vector vecEndPosition; + m_Meteor.GetPositionAtTime( flTime, vecEndPosition ); + + // m_Meteor must return the end position in world space for the trace to work. + Assert( GetMoveParent() == NULL ); + +// Msg( "Client: Time = %lf, Position: %4.2f %4.2f %4.2f\n", flTime, vecEndPosition.x, vecEndPosition.y, vecEndPosition.z ); + + // Check to see if we struck the world. If so, cause an explosion. + trace_t trace; + + Vector vecMin, vecMax; + GetRenderBounds( vecMin, vecMax ); + + // NOTE: This code works only if we aren't in hierarchy!!! + Assert( !GetMoveParent() ); + + CTraceFilterWorldOnly traceFilter; + UTIL_TraceHull( GetAbsOrigin(), vecEndPosition, vecMin, vecMax, + MASK_SOLID_BRUSHONLY, &traceFilter, &trace ); + + // Collision. + if ( ( trace.fraction < 1.0f ) && !( trace.surface.flags & SURF_SKY ) ) + { + // Move up to the end. + Vector vecEnd = GetAbsOrigin() + ( ( vecEndPosition - GetAbsOrigin() ) * trace.fraction ); + + // Create an explosion effect! + BaseExplosionEffect().Create( vecEnd, 10, 32, TE_EXPLFLAG_NONE ); + + // Debugging Info!!!! +// debugoverlay->AddBoxOverlay( vecEnd, Vector( -10, -10, -10 ), Vector( 10, 10, 10 ), QAngle( 0.0f, 0.0f, 0.0f ), 255, 0, 0, 0, 100 ); + + Destroy( this ); + return; + } + else + { + // Move to the end. + SetLocalOrigin( vecEndPosition ); + } + + m_TailEffect.SetLocalOrigin( GetLocalOrigin() ); + m_HeadEffect.MeteorHeadThink( GetLocalOrigin(), flTime ); + + // Add the entity to the active list - update! + AddEntity(); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +C_EnvMeteor *C_EnvMeteor::Create( int nID, int iMeteorType, const Vector &vecOrigin, + const Vector &vecDirection, float flSpeed, float flStartTime, + float flDamageRadius, + const Vector &vecTriggerMins, const Vector &vecTriggerMaxs ) +{ + C_EnvMeteor *pMeteor = new C_EnvMeteor; + if ( pMeteor ) + { + pMeteor->m_Meteor.Init( nID, flStartTime, METEOR_PASSIVE_TIME, vecOrigin, vecDirection, flSpeed, flDamageRadius, + vecTriggerMins, vecTriggerMaxs ); + + // Initialize the meteor. + pMeteor->InitializeAsClientEntity( "models/props/common/meteorites/meteor05.mdl", RENDER_GROUP_OPAQUE_ENTITY ); + + // Handle forward simulation. + if ( ( pMeteor->m_Meteor.m_flStartTime + METEOR_MAX_LIFETIME ) < gpGlobals->curtime ) + { + Destroy( pMeteor ); + } + + // Meteor Head and Tail + pMeteor->SetTravelDirection( vecDirection ); + + pMeteor->m_HeadEffect.SetSmokeEmission( true ); + pMeteor->m_HeadEffect.Start( vecOrigin, vecDirection ); + pMeteor->m_HeadEffect.SetParticleScale( 1.0f / 16.0f ); + + pMeteor->m_TailEffect.Start( vecOrigin, vecDirection, flSpeed ); + + pMeteor->SetNextClientThink( CLIENT_THINK_ALWAYS ); + } + + return pMeteor; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void C_EnvMeteor::Destroy( C_EnvMeteor *pMeteor ) +{ + Assert( pMeteor->GetClientHandle() != INVALID_CLIENTENTITY_HANDLE ); + ClientThinkList()->AddToDeleteList( pMeteor->GetClientHandle() ); +} diff --git a/game/client/tf2/c_env_meteor.h b/game/client/tf2/c_env_meteor.h new file mode 100644 index 0000000..77e4d52 --- /dev/null +++ b/game/client/tf2/c_env_meteor.h @@ -0,0 +1,189 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_ENV_METEOR_H +#define C_ENV_METEOR_H +#pragma once + +#include "utlvector.h" +#include "env_meteor_shared.h" +#include "baseparticleentity.h" +#include "c_effect_shootingstar.h" + +//============================================================================= +// +// Client-side Meteor Factory Class +// +class C_MeteorFactory : public IMeteorFactory +{ +public: + + void CreateMeteor( int nID, int iType, const Vector &vecPosition, + const Vector &vecDirection, float flSpeed, float flStartTime, + float flDamageRadius, + const Vector &vecTriggerMins, const Vector &vecTriggerMaxs ); +}; + +//============================================================================= +// +// Meteor Spawner Class +// +class C_EnvMeteorSpawner : public C_BaseEntity +{ +public: + + DECLARE_CLASS( C_EnvMeteorSpawner, C_BaseEntity ); + + DECLARE_CLIENTCLASS(); + + C_EnvMeteorSpawner(); + + // Will more than likely be used for meteor input(s) later! +// void ReceiveMessage( const char *msgname, int length, void *data ); + + //------------------------------------------------------------------------- + // Networking + //------------------------------------------------------------------------- + void OnDataChanged( DataUpdateType_t updateType ); + + //------------------------------------------------------------------------- + // Think + //------------------------------------------------------------------------- + void ClientThink( void ); + +private: + + C_MeteorFactory m_Factory; + CEnvMeteorSpawnerShared m_SpawnerShared; + bool m_fDisabled; +}; + + +//============================================================================= +// +// Meteor Tail Class - Effect +// +class C_EnvMeteorHead +{ +public: + + C_EnvMeteorHead(); + ~C_EnvMeteorHead(); + + void Start( const Vector &vecOrigin, const Vector &vecDirection ); + void Destroy( void ); + + void MeteorHeadThink( const Vector &vecOrigin, float flTime ); + + void SetSmokeEmission( bool bEmit ) { m_bEmitSmoke = bEmit; } + bool EmitSmoke( void ) { return m_bEmitSmoke; } + + void SetParticleScale( float flScale ) { m_flParticleScale = flScale; } + + bool m_bInitThink; + +private: + + Vector m_vecPos; + Vector m_vecPrevPos; + Vector m_vecDirection; + + float m_flParticleScale; + + CSmartPtr<CSimpleEmitter> m_pSmokeEmitter; + float m_flSmokeSpawnInterval; + float m_flSmokeSpawnRadius; + PMaterialHandle m_hSmokeMaterial; + float m_flSmokeLifetime; // How long do the particles live? + bool m_bEmitSmoke; + + PMaterialHandle m_hFlareMaterial; +}; + +//============================================================================= +// +// Meteor Tail Class - Effect +// +class C_EnvMeteorTail : public C_BaseParticleEntity +{ +public: + + DECLARE_CLASS( C_EnvMeteorTail, C_BaseParticleEntity ); + + C_EnvMeteorTail(); + ~C_EnvMeteorTail(); + + void Start( const Vector &vecOrigin, const Vector &vecDirection, float flSpeed ); + void Destroy( void ); + virtual void RenderParticles( CParticleRenderIterator *pIterator ); + virtual void SimulateParticles( CParticleSimulateIterator *pIterator ); + +//protected: + + void DrawFragment( ParticleDraw* pDraw, const Vector &vecStart, const Vector &vecDelta, + const Vector4D &vecStartColor, const Vector4D &vecEndColor, + float flStartV, float flEndV ); + + CParticleMgr *m_pParticleMgr; + Particle *m_pParticle; + + PMaterialHandle m_TailMaterialHandle; + + // Properties. + float m_flFadeTime; + float m_flWidth; + float m_flSpeed; + Vector m_vecDirection; + +private: + C_EnvMeteorTail( const C_EnvMeteorTail & ); +}; + +//============================================================================= +// +// Meteor Class (Client-side only!) +// +class C_EnvMeteor : public C_BaseAnimating +{ +public: + + DECLARE_CLASS( C_EnvMeteor, C_BaseAnimating ); + + //------------------------------------------------------------------------- + // Initialization/Destruction + //------------------------------------------------------------------------- + C_EnvMeteor(); + ~C_EnvMeteor(); + static C_EnvMeteor *Create( int nID, int iMeteorType, const Vector &vecOrigin, + const Vector &vecDirection, float flSpeed, float flStartTime, + float flDamageRadius, + const Vector &vecTriggerMins, const Vector &vecTriggerMaxs ); + static void Destroy( C_EnvMeteor *pMeteor ); + + //------------------------------------------------------------------------- + // Think + //------------------------------------------------------------------------- + void ClientThink( void ); + void SkyboxThink( float flTime ); + void WorldThink( float flTime ); + void WorldToSkyboxThink( float flTime ); + void SkyboxToWorldThink( float flTime ); + + void SetTravelDirection( const Vector &vecDir ) { m_vecTravelDir = vecDir; } + +private: + C_EnvMeteor( const C_EnvMeteor & ); + + CEnvMeteorShared m_Meteor; + + // Effects + Vector m_vecTravelDir; + C_EnvMeteorHead m_HeadEffect; + C_EnvMeteorTail m_TailEffect; +}; + +#endif // C_ENV_METEOR_H diff --git a/game/client/tf2/c_func_construction_yard.cpp b/game/client/tf2/c_func_construction_yard.cpp new file mode 100644 index 0000000..200f8fd --- /dev/null +++ b/game/client/tf2/c_func_construction_yard.cpp @@ -0,0 +1,42 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A place where vehicles can be built +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" + +//----------------------------------------------------------------------------- +// Purpose: A place where vehicles can be built +//----------------------------------------------------------------------------- +class C_FuncConstructionYard : public C_BaseEntity +{ + DECLARE_CLASS( C_FuncConstructionYard, C_BaseEntity ); +public: + DECLARE_CLIENTCLASS(); +// DECLARE_MINIMAP_PANEL(); + + C_FuncConstructionYard(); + const char *GetTargetDescription( void ) const; +}; + + +IMPLEMENT_CLIENTCLASS_DT(C_FuncConstructionYard, DT_FuncConstructionYard, CFuncConstructionYard) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_FuncConstructionYard::C_FuncConstructionYard() +{ +// CONSTRUCT_MINIMAP_PANEL( "minimap_construction_yard", MINIMAP_RESOURCE_ZONES ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +const char *C_FuncConstructionYard::GetTargetDescription( void ) const +{ + return "Construction Yard"; +} + diff --git a/game/client/tf2/c_func_resource.cpp b/game/client/tf2/c_func_resource.cpp new file mode 100644 index 0000000..ac9dc5b --- /dev/null +++ b/game/client/tf2/c_func_resource.cpp @@ -0,0 +1,263 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client's CResourceZone. +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "engine/IEngineSound.h" +#include "c_func_resource.h" +#include "techtree.h" +#include "fx.h" +#include "fx_sparks.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// Chunk movement +#define CHUNK_FLECK_MIN_SPEED 25.0f +#define CHUNK_FLECK_MAX_SPEED 100.0f +#define CHUNK_FLECK_GRAVITY 800.0f +#define CHUNK_FLECK_DAMPEN 0.3f +#define CHUNK_FLECK_ANGULAR_SPRAY 0.8f + +IMPLEMENT_CLIENTCLASS_DT(C_ResourceZone, DT_ResourceZone, CResourceZone) + RecvPropFloat(RECVINFO(m_flClientResources)), + RecvPropInt(RECVINFO(m_nResourcesLeft)), +END_RECV_TABLE() + +LINK_ENTITY_TO_CLASS( trigger_resourcezone, C_ResourceZone ); +BEGIN_PREDICTION_DATA( C_ResourceZone ) +END_PREDICTION_DATA(); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ResourceZone::C_ResourceZone() +{ + CONSTRUCT_MINIMAP_PANEL( "minimap_resource_zone", MINIMAP_RESOURCE_ZONES ); +} + +//----------------------------------------------------------------------------- +// Add, remove object from the panel +//----------------------------------------------------------------------------- +void C_ResourceZone::SetDormant( bool bDormant ) +{ + BaseClass::SetDormant( bDormant ); + ENTITY_PANEL_ACTIVATE( "resourcezone", (!bDormant && m_flClientResources > 0) ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ResourceZone::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + if ( updateType == DATA_UPDATE_CREATED ) + { + SetNextClientThink( gpGlobals->curtime + 1.0 ); + } + + // If I've just dried up, remove me from the minimap + if ( m_flClientResources <= 0 ) + { + ENTITY_PANEL_ACTIVATE( "resourcezone", false ); + DESTRUCT_MINIMAP_PANEL(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +const char *C_ResourceZone::GetTargetDescription( void ) const +{ + return "Resource Zone"; +} + + +//========================================================================================================== +// Resource Spawner +//========================================================================================================== +IMPLEMENT_CLIENTCLASS_DT(C_ResourceSpawner, DT_ResourceSpawner, CResourceSpawner) + RecvPropInt(RECVINFO(m_bActive)), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ResourceSpawner::C_ResourceSpawner( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ResourceSpawner::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + if ( updateType == DATA_UPDATE_CREATED ) + { + SetNextClientThink( gpGlobals->curtime + random->RandomFloat( 2.0, 4.0 ) ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Receive a spawn message from the server +//----------------------------------------------------------------------------- +void C_ResourceSpawner::ReceiveMessage( int classID, bf_read &msg ) +{ + if ( classID != GetClientClass()->m_ClassID ) + { + // message is for subclass + BaseClass::ReceiveMessage( classID, msg ); + return; + } + + // Make some particles + SpawnEffect( true ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ResourceSpawner::ClientThink( void ) +{ + SetNextClientThink( gpGlobals->curtime + random->RandomFloat( 2.0, 10.0 ) ); + + // Don't do random puffs if I'm not active + if ( !m_bActive ) + return; + + // Occasionally spurt as if I was making a chunk + if ( random->RandomInt(0, 20) == 5 ) + { + SpawnEffect( true ); + } + else + { + SpawnEffect( false ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Particle effects created when we spawn a chunk +//----------------------------------------------------------------------------- +void C_ResourceSpawner::SpawnEffect( bool bSpawningChunk ) +{ + Vector normal = Vector(0,0,1); + Vector offset = GetAbsOrigin() + (normal * 16); + Vector dir; + + float r = sResourceColor.r; + float g = sResourceColor.g; + float b = sResourceColor.b; + + // Play a random puff sound + if ( bSpawningChunk ) + { + EmitSound( "ResourceSpawner.BigPuff" ); + } + else + { + EmitSound( "ResourceSpawner.Puff" ); + } + + // Chunks o'dirt + CSmartPtr<CFleckParticles> fleckEmitter = CFleckParticles::Create( "SpawnEffect 1", offset, Vector(5,5,5) ); + if ( !fleckEmitter ) + return; + + // Setup our collision information + fleckEmitter->m_ParticleCollision.Setup( offset, &normal, CHUNK_FLECK_ANGULAR_SPRAY, CHUNK_FLECK_MIN_SPEED, CHUNK_FLECK_MAX_SPEED, CHUNK_FLECK_GRAVITY, CHUNK_FLECK_DAMPEN ); + + int numFlecks; + if ( bSpawningChunk ) + numFlecks = random->RandomInt( 48, 64 ); + else + numFlecks = random->RandomInt( 1, 3 ); + + // Dump out flecks + int i; + for ( i = 0; i < numFlecks; i++ ) + { + FleckParticle *pParticle = (FleckParticle *) fleckEmitter->AddParticle( sizeof(FleckParticle), g_Mat_Fleck_Cement[random->RandomInt(0,1)], offset ); + + if ( pParticle == NULL ) + break; + + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = random->RandomFloat(3.0f,5.0f); + + if ( bSpawningChunk ) + { + pParticle->m_uchSize = random->RandomInt( 4, 8 ); + dir[0] = normal[0] + random->RandomFloat( -CHUNK_FLECK_ANGULAR_SPRAY, CHUNK_FLECK_ANGULAR_SPRAY ); + dir[1] = normal[1] + random->RandomFloat( -CHUNK_FLECK_ANGULAR_SPRAY, CHUNK_FLECK_ANGULAR_SPRAY ); + dir[2] = normal[2] + random->RandomFloat( -CHUNK_FLECK_ANGULAR_SPRAY, CHUNK_FLECK_ANGULAR_SPRAY ); + pParticle->m_vecVelocity = dir * ( random->RandomFloat( CHUNK_FLECK_MIN_SPEED, CHUNK_FLECK_MAX_SPEED ) * ( 9 - pParticle->m_uchSize ) ); + } + else + { + pParticle->m_uchSize = random->RandomInt( 2, 4 ); + dir[0] = normal[0] + (random->RandomFloat( -CHUNK_FLECK_ANGULAR_SPRAY, CHUNK_FLECK_ANGULAR_SPRAY ) * 0.5); + dir[1] = normal[1] + (random->RandomFloat( -CHUNK_FLECK_ANGULAR_SPRAY, CHUNK_FLECK_ANGULAR_SPRAY ) * 0.5); + dir[2] = normal[2] + (random->RandomFloat( -CHUNK_FLECK_ANGULAR_SPRAY, CHUNK_FLECK_ANGULAR_SPRAY ) * 0.5); + pParticle->m_vecVelocity = dir * ( random->RandomFloat( CHUNK_FLECK_MIN_SPEED, CHUNK_FLECK_MAX_SPEED ) * 3); + } + + pParticle->m_flRoll = random->RandomFloat( 0, 360 ); + pParticle->m_flRollDelta = random->RandomFloat( 0, 360 ); + + pParticle->m_uchColor[0] = r; + pParticle->m_uchColor[1] = g; + pParticle->m_uchColor[2] = b; + } + + + // Create a couple of big, floating smoke clouds + if ( bSpawningChunk || random->RandomInt(0,10) == 0 ) + { + CSmartPtr<CSimpleEmitter> pSmokeEmitter = CSimpleEmitter::Create( "SpawnEffect 2" ); + pSmokeEmitter->SetSortOrigin( offset ); + int iSmokeClouds = 2; + if ( !bSpawningChunk ) + iSmokeClouds = 1; + for ( i = 0; i < iSmokeClouds; i++ ) + { + SimpleParticle *pParticle = (SimpleParticle *) pSmokeEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[1], offset ); + if ( pParticle == NULL ) + break; + + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = random->RandomFloat( 2.0f, 3.0f ); + + if ( bSpawningChunk ) + { + pParticle->m_uchStartSize = 32; + pParticle->m_uchEndSize = 128; + } + else + { + pParticle->m_uchStartSize = 16; + pParticle->m_uchEndSize = 64; + } + + dir[0] = normal[0] + random->RandomFloat( -0.4f, 0.4f ); + dir[1] = normal[1] + random->RandomFloat( -0.4f, 0.4f ); + dir[2] = normal[2] + random->RandomFloat( 0, 0.6f ); + pParticle->m_vecVelocity = dir * random->RandomFloat( 2.0f, 24.0f )*(i+1); + pParticle->m_uchStartAlpha = 160; + pParticle->m_uchEndAlpha = 0; + pParticle->m_flRoll = random->RandomFloat( 180, 360 ); + pParticle->m_flRollDelta = random->RandomFloat( -1, 1 ); + + pParticle->m_uchColor[0] = r; + pParticle->m_uchColor[1] = g; + pParticle->m_uchColor[2] = b; + } + } +} diff --git a/game/client/tf2/c_func_resource.h b/game/client/tf2/c_func_resource.h new file mode 100644 index 0000000..fd22b28 --- /dev/null +++ b/game/client/tf2/c_func_resource.h @@ -0,0 +1,57 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client's CObjectSentrygun +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_FUNC_RESOURCE_H +#define C_FUNC_RESOURCE_H + +#include "commanderoverlay.h" +#include "hud_minimap.h" + + +//----------------------------------------------------------------------------- +// Purpose: A resource zone +//----------------------------------------------------------------------------- +class C_ResourceZone : public C_BaseEntity +{ + DECLARE_CLASS( C_ResourceZone, C_BaseEntity ); +public: + DECLARE_PREDICTABLE(); + DECLARE_CLIENTCLASS(); + DECLARE_ENTITY_PANEL(); + DECLARE_MINIMAP_PANEL(); + + C_ResourceZone(); + virtual void SetDormant( bool bDormant ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + const char *GetTargetDescription( void ) const; + +public: + float m_flClientResources; // Amount of resources left + int m_nResourcesLeft; +}; + +//----------------------------------------------------------------------------- +// Purpose: A resource chunk spawning point in a resource zone +//----------------------------------------------------------------------------- +class C_ResourceSpawner : public C_BaseAnimating +{ + DECLARE_CLASS( C_ResourceSpawner, C_BaseAnimating ); +public: + DECLARE_CLIENTCLASS(); + + C_ResourceSpawner(); + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void ReceiveMessage( int classID, bf_read &msg ); + virtual void SpawnEffect( bool bSpawningChunk ); + virtual void ClientThink( void ); + +public: + bool m_bActive; +}; + +#endif // C_FUNC_RESOURCE_H + diff --git a/game/client/tf2/c_gasoline_blob.cpp b/game/client/tf2/c_gasoline_blob.cpp new file mode 100644 index 0000000..800ee89 --- /dev/null +++ b/game/client/tf2/c_gasoline_blob.cpp @@ -0,0 +1,350 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_gasoline_blob.h" +#include "gasoline_shared.h" +#include "engine/IEngineSound.h" +#include "clienteffectprecachesystem.h" + +static CUtlLinkedList<C_GasolineBlob*, int> g_GasolineBlobs; + +// If multiple blobs are within this distance to each other, then only one will +// play a sound. +#define BLOB_SOUND_RELATED_DISTANCE 600 + + +#define PUDDLE_START_SIZE 35 +#define PUDDLE_END_SIZE 65 +#define PUDDLE_GROW_TIME 0.5 + +#define PUDDLE_FADE_TIME 1.0 + + +CLIENTEFFECT_REGISTER_BEGIN( PrecacheGasolineBlob ) +CLIENTEFFECT_MATERIAL( "decals/puddle" ) +CLIENTEFFECT_REGISTER_END() + +// ------------------------------------------------------------------------------------------------ // +// CGasolineEmitter. +// ------------------------------------------------------------------------------------------------ // + +CSmartPtr<CGasolineEmitter> CGasolineEmitter::Create( C_GasolineBlob *pBlob ) +{ + CGasolineEmitter *pEmitter = new CGasolineEmitter; + + pEmitter->m_pBlob = pBlob; + + pEmitter->m_hFireMaterial = pEmitter->GetPMaterial( "particle/fire" ); + pEmitter->m_hUnlitMaterial = pEmitter->GetPMaterial( "sprites/env_particles" ); + + pEmitter->m_Timer.Init( 40 ); + + return pEmitter; +} + + +void CGasolineEmitter::UpdateFire( float frametime ) +{ + float flLifetime = gpGlobals->curtime - m_pBlob->m_flCreateTime; + + float litPercent = 1; + if ( m_pBlob->IsLit() ) + { + litPercent = 1 - (flLifetime / m_pBlob->m_flMaxLifetime); + if ( litPercent <= 0 ) + return; + } + else + { + return; + } + + // Don't show a burn effect for a blob that hasn't hit anything yet. + // If you do, it tends to make the flamethrower effect look weird. + if ( !m_pBlob->IsStopped() ) + return; + + // Make a coordinate system in which to spawn the particles. It + Vector vUp, vRight; + vUp.Init(); + vRight.Init(); + if ( m_pBlob->IsStopped() ) + { + QAngle angles; + VectorAngles( m_pBlob->GetSurfaceNormal(), angles ); + AngleVectors( angles, NULL, &vRight, &vUp ); + } + + PMaterialHandle hMaterial = m_hFireMaterial; + float flParticleLifetime = 1; + float flRadius = 7; + unsigned char uchColor[4] = { 255, 128, 0, 128 }; + float flMaxZVel = 29; + + + float curDelta = frametime; + while ( m_Timer.NextEvent( curDelta ) ) + { + // Based on how close we are to expiring, show less particles. + if ( RandomFloat( 0, 1 ) > litPercent ) + continue; + + Vector vPos = m_pBlob->GetAbsOrigin(); + if ( m_pBlob->IsStopped() ) + { + float flAngle = RandomFloat( 0, M_PI * 2 ); + float flDist = RandomFloat( 0, GASOLINE_BLOB_RADIUS ); + vPos += vRight * (cos( flAngle ) * flDist); + vPos += vUp * ( sin( flAngle ) * flDist ); + } + else + { + vPos += RandomVector( -GASOLINE_BLOB_RADIUS, GASOLINE_BLOB_RADIUS ); + } + + SimpleParticle *pParticle = AddSimpleParticle( hMaterial, vPos, flParticleLifetime, flRadius ); + if ( pParticle ) + { + pParticle->m_uchColor[0] = uchColor[0]; + pParticle->m_uchColor[1] = uchColor[1]; + pParticle->m_uchColor[2] = uchColor[2]; + + pParticle->m_uchEndAlpha = 0; + pParticle->m_uchStartAlpha = uchColor[3]; + + pParticle->m_vecVelocity.x = RandomFloat( -2, 2 ); + pParticle->m_vecVelocity.y = RandomFloat( -2, 2 ); + pParticle->m_vecVelocity.z = RandomFloat( 3, flMaxZVel ); + } + } +} + + +// ------------------------------------------------------------------------------------------------ // +// C_GasolineBlob. +// ------------------------------------------------------------------------------------------------ // + +IMPLEMENT_CLIENTCLASS_DT_NOBASE( C_GasolineBlob, DT_GasolineBlob, CGasolineBlob ) + RecvPropInt( RECVINFO( m_BlobFlags ) ), + RecvPropVector( RECVINFO_NAME( m_vecNetworkOrigin, m_vecOrigin ) ), + RecvPropInt( RECVINFO_NAME(m_hNetworkMoveParent, moveparent), 0, RecvProxy_IntToMoveParent ), + RecvPropFloat( RECVINFO( m_flLitStartTime ) ), + RecvPropFloat( RECVINFO( m_flCreateTime ) ), + RecvPropFloat( RECVINFO( m_flMaxLifetime ) ), + RecvPropInt( RECVINFO( m_iTeamNum ) ), + RecvPropVector( RECVINFO( m_vSurfaceNormal ) ) +END_RECV_TABLE() + + +C_GasolineBlob::C_GasolineBlob() +{ + m_pEmitter = CGasolineEmitter::Create( this ); + m_vSurfaceNormal.Init(); + m_flLitStartTime = 0; + m_bSoundOn = false; + g_GasolineBlobs.AddToTail( this ); + m_flPuddleSize = PUDDLE_START_SIZE; + m_flPuddleFade = 1; +} + + +C_GasolineBlob::~C_GasolineBlob() +{ + g_GasolineBlobs.FindAndRemove( this ); + StopSound(); + + // If a bunch of nearby blobs weren't playing a sound because we were, have them start their sound now. + FOR_EACH_LL( g_GasolineBlobs, i ) + { + C_GasolineBlob *pBlob = g_GasolineBlobs[i]; + + if ( pBlob->IsSoundRelatedTo( this ) ) + pBlob->CheckStartSound(); + } +} + + +bool C_GasolineBlob::IsLit() const +{ + return (m_BlobFlags & BLOBFLAG_LIT) != 0; +} + + +bool C_GasolineBlob::IsStopped() const +{ + return (m_BlobFlags & BLOBFLAG_STOPPED) != 0; +} + + +const Vector& C_GasolineBlob::GetSurfaceNormal() const +{ + return m_vSurfaceNormal; +} + + +float C_GasolineBlob::GetLitStartTime() const +{ + return m_flLitStartTime; +} + + +void C_GasolineBlob::OnDataChanged( DataUpdateType_t type ) +{ + BaseClass::OnDataChanged( type ); + + if ( type == DATA_UPDATE_CREATED ) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } + + CheckStartSound(); +} + + +void C_GasolineBlob::ClientThink() +{ + if ( m_pEmitter.IsValid() ) + m_pEmitter->UpdateFire( gpGlobals->frametime ); + + // Grow the puddle a little. + if ( IsStopped() ) + { + if ( IsLit() ) + { + // Fade out after we get lit. + m_flPuddleFade -= gpGlobals->frametime / PUDDLE_FADE_TIME; + m_flPuddleFade = MAX( m_flPuddleFade, 0 ); + } + else + { + // Grow the puddle until it's at its max size. + m_flPuddleSize += gpGlobals->frametime * ( PUDDLE_END_SIZE - PUDDLE_START_SIZE ) / PUDDLE_GROW_TIME; + m_flPuddleSize = MIN( m_flPuddleSize, PUDDLE_END_SIZE ); + } + } +} + + +bool C_GasolineBlob::ShouldDraw() +{ + return IsStopped() && (m_flPuddleFade > 0); +} + + +int C_GasolineBlob::DrawModel( int flags ) +{ + // Generate a basis. + QAngle angles; + VectorAngles( m_vSurfaceNormal, angles ); + + Vector vRight, vUp; + AngleVectors( angles, NULL, &vRight, &vUp ); + + + float flAlpha = m_flPuddleFade * RemapVal( m_flPuddleSize, PUDDLE_START_SIZE, PUDDLE_END_SIZE, 0, 1 ); + if ( flAlpha <= 0 ) + return 0; + + + // Draw the puddle. + IMaterial *pMat = materials->FindMaterial( "decals/puddle", TEXTURE_GROUP_DECAL ); + IMesh *pMesh = materials->GetDynamicMesh( true, NULL, NULL, pMat ); + CMeshBuilder mb; + mb.Begin( pMesh, MATERIAL_QUADS, 1 ); + + Vector v; + + v = GetAbsOrigin() + m_vSurfaceNormal + vRight*m_flPuddleSize - vUp*m_flPuddleSize; + mb.Position3f( v.x, v.y, v.z ); + mb.Color4f( 1, 1, 1, flAlpha ); + mb.Normal3f( VectorExpand( m_vSurfaceNormal ) ); + mb.TexCoord2f( 0, 1, 0 ); + mb.AdvanceVertex(); + + v = GetAbsOrigin() + m_vSurfaceNormal + vRight*m_flPuddleSize + vUp*m_flPuddleSize; + mb.Position3f( v.x, v.y, v.z ); + mb.Color4f( 1, 1, 1, flAlpha ); + mb.Normal3f( VectorExpand( m_vSurfaceNormal ) ); + mb.TexCoord2f( 0, 1, 1 ); + mb.AdvanceVertex(); + + v = GetAbsOrigin() + m_vSurfaceNormal - vRight*m_flPuddleSize + vUp*m_flPuddleSize; + mb.Position3f( v.x, v.y, v.z ); + mb.Color4f( 1, 1, 1, flAlpha ); + mb.Normal3f( VectorExpand( m_vSurfaceNormal ) ); + mb.TexCoord2f( 0, 0, 1 ); + mb.AdvanceVertex(); + + v = GetAbsOrigin() + m_vSurfaceNormal - vRight*m_flPuddleSize - vUp*m_flPuddleSize; + mb.Position3f( v.x, v.y, v.z ); + mb.Color4f( 1, 1, 1, flAlpha ); + mb.Normal3f( VectorExpand( m_vSurfaceNormal ) ); + mb.TexCoord2f( 0, 0, 0 ); + mb.AdvanceVertex(); + + mb.End( false, true ); + + return 0; +} + + +bool C_GasolineBlob::IsSoundRelatedTo( const C_GasolineBlob *pBlob ) const +{ + return pBlob->GetAbsOrigin().DistTo( GetAbsOrigin() ) < BLOB_SOUND_RELATED_DISTANCE; +} + + +bool C_GasolineBlob::IsPlayingBurningSound() const +{ + return m_bSoundOn; +} + + +void C_GasolineBlob::CheckStartSound() +{ + if ( IsPlayingBurningSound() || (m_BlobFlags & BLOBFLAG_STOPPED) == 0 || !IsLit() ) + return; + + + // First, make sure no nearby blob is playing the sound. + FOR_EACH_LL( g_GasolineBlobs, i ) + { + C_GasolineBlob *pBlob = g_GasolineBlobs[i]; + + if ( pBlob != this && pBlob->IsSoundRelatedTo( this ) ) + { + // If it's already playing a sound, then don't start our sound. + if ( pBlob->IsPlayingBurningSound() ) + return; + } + } + + + StartSound(); +} + + +void C_GasolineBlob::StartSound() +{ + if ( !m_bSoundOn ) + { + EmitSound( "GasolineBlob.FlameSound" ); + + m_bSoundOn = true; + } +} + + +void C_GasolineBlob::StopSound() +{ + if ( m_bSoundOn ) + { + BaseClass::StopSound( "GasolineBlob.FlameSound" ); + m_bSoundOn = false; + } +} + diff --git a/game/client/tf2/c_gasoline_blob.h b/game/client/tf2/c_gasoline_blob.h new file mode 100644 index 0000000..101dfca --- /dev/null +++ b/game/client/tf2/c_gasoline_blob.h @@ -0,0 +1,107 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_GASOLINE_BLOB_H +#define C_GASOLINE_BLOB_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "c_baseentity.h" +#include "particles_simple.h" +#include "particle_util.h" + + +class C_GasolineBlob; + +class CGasolineEmitter : public CSimpleEmitter +{ +public: + + static CSmartPtr<CGasolineEmitter> Create( C_GasolineBlob *pBlob ); + + void UpdateFire( float frametime ); + + +private: + + CGasolineEmitter() : CSimpleEmitter( "Gasoline" ){} + CGasolineEmitter( const CGasolineEmitter & ); + + + C_GasolineBlob *m_pBlob; + + PMaterialHandle m_hFireMaterial; + PMaterialHandle m_hUnlitMaterial; + TimedEvent m_Timer; +}; + + +class C_GasolineBlob : public C_BaseEntity +{ +friend class CGasolineEmitter; + +public: + DECLARE_CLASS( C_GasolineBlob, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + + C_GasolineBlob(); + virtual ~C_GasolineBlob(); + + bool IsLit() const; + bool IsStopped() const; + const Vector& GetSurfaceNormal() const; + float GetLitStartTime() const; + + +// Overrides. +public: + + virtual void OnDataChanged( DataUpdateType_t type ); + virtual void ClientThink(); + virtual int DrawModel( int flags ); + virtual bool ShouldDraw(); + + +private: + + // Returns true if the two blobs relate their sound, meaning one blob won't play + // its sound if the other one is playing it. + bool IsSoundRelatedTo( const C_GasolineBlob *pBlob ) const; + + bool IsPlayingBurningSound() const; + + // Starts the burning sound if no other flames are playing the sound nearby. + void CheckStartSound(); + + // Make the burning sound. + void StartSound(); + void StopSound(); + + +private: + + bool m_bSoundOn; + float m_flPuddleSize; + float m_flPuddleFade; + + CSmartPtr<CGasolineEmitter> m_pEmitter; + + float m_flLitStartTime; + + float m_flCreateTime; + float m_flMaxLifetime; + + Vector m_vSurfaceNormal; + + int m_BlobFlags; // Combination of BLOBFLAG_ defines. +}; + + +#endif // C_GASOLINE_BLOB_H diff --git a/game/client/tf2/c_grenade_antipersonnel.cpp b/game/client/tf2/c_grenade_antipersonnel.cpp new file mode 100644 index 0000000..ee4d60e --- /dev/null +++ b/game/client/tf2/c_grenade_antipersonnel.cpp @@ -0,0 +1,84 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "grenade_base_empable.h" +#include "particles_simple.h" + +//----------------------------------------------------------------------------- +// Purpose: Client side entity for the antipersonnel grenades +//----------------------------------------------------------------------------- +class C_GrenadeAntiPersonnel : public C_BaseEMPableGrenade +{ + DECLARE_CLASS( C_GrenadeAntiPersonnel, C_BaseEMPableGrenade ); +public: + DECLARE_CLIENTCLASS(); + + C_GrenadeAntiPersonnel(); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void ClientThink( void ); + +public: + C_GrenadeAntiPersonnel( const C_GrenadeAntiPersonnel & ); +}; + +IMPLEMENT_CLIENTCLASS_DT(C_GrenadeAntiPersonnel, DT_GrenadeAntiPersonnel, CGrenadeAntiPersonnel) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_GrenadeAntiPersonnel::C_GrenadeAntiPersonnel( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_GrenadeAntiPersonnel::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + // Only think when sapping + SetNextClientThink( CLIENT_THINK_ALWAYS ); +} + +//----------------------------------------------------------------------------- +// Purpose: Spawn effects if I'm sapping +//----------------------------------------------------------------------------- +void C_GrenadeAntiPersonnel::ClientThink( void ) +{ + // Fire smoke puffs out the side + CSmartPtr<CSimpleEmitter> pSmokeEmitter = CSimpleEmitter::Create( "AntipersonnelGrenade::Effect" ); + pSmokeEmitter->SetSortOrigin( GetAbsOrigin() ); + int iSmokeClouds = random->RandomInt(1,2); + for ( int i = 0; i < iSmokeClouds; i++ ) + { + SimpleParticle *pParticle = (SimpleParticle *) pSmokeEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[1], GetAbsOrigin() ); + if ( pParticle == NULL ) + return; + + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = random->RandomFloat( 0.1f, 0.3f ); + + pParticle->m_uchStartSize = random->RandomFloat(2,5); + pParticle->m_uchEndSize = pParticle->m_uchStartSize + 2; + + pParticle->m_vecVelocity = vec3_origin; + pParticle->m_uchStartAlpha = 255; + pParticle->m_uchEndAlpha = 64; + pParticle->m_flRoll = random->RandomFloat( 180, 360 ); + pParticle->m_flRollDelta = random->RandomFloat( -1, 1 ); + + pParticle->m_uchColor[0] = 50; + pParticle->m_uchColor[1] = 250; + pParticle->m_uchColor[2] = 50; + } +} + + diff --git a/game/client/tf2/c_grenade_limpetmine.cpp b/game/client/tf2/c_grenade_limpetmine.cpp new file mode 100644 index 0000000..2f9754e --- /dev/null +++ b/game/client/tf2/c_grenade_limpetmine.cpp @@ -0,0 +1,109 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "basegrenade_shared.h" +#include "minimap_trace.h" +#include "particles_simple.h" + +//----------------------------------------------------------------------------- +// Purpose: Client side entity for the ferry target items +//----------------------------------------------------------------------------- +class C_LimpetMine : public C_BaseGrenade +{ + DECLARE_CLASS( C_LimpetMine, C_BaseGrenade ); +public: + DECLARE_CLIENTCLASS(); + DECLARE_MINIMAP_PANEL(); + + C_LimpetMine(); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void ClientThink( void ); + +public: + C_LimpetMine( const C_LimpetMine & ); + +private: + bool m_bLive; +}; + +IMPLEMENT_CLIENTCLASS_DT(C_LimpetMine, DT_LimpetMine, CLimpetMine) + RecvPropInt(RECVINFO(m_bLive)), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_LimpetMine::C_LimpetMine( void ) +{ + CONSTRUCT_MINIMAP_PANEL( "minimap_limpet", MINIMAP_OBJECTS ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_LimpetMine::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + // Only think when live + if ( m_bLive ) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } + else + { + SetNextClientThink( CLIENT_THINK_NEVER ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Spawn effects if I'm live +//----------------------------------------------------------------------------- +void C_LimpetMine::ClientThink( void ) +{ + if ( !InLocalTeam() ) + return; + + Vector up; + GetVectors( NULL, NULL, &up ); + up *= 8.0f; + Vector vecOrg = GetAbsOrigin() + up; + + // Make a single sprite + CSmartPtr<CSimpleEmitter> pSmokeEmitter = CSimpleEmitter::Create( "C_LimpetMine::Effect" ); + pSmokeEmitter->SetSortOrigin( vecOrg ); + PMaterialHandle hSphereMaterial = g_Mat_DustPuff[0]; + SimpleParticle *pParticle = (SimpleParticle *) pSmokeEmitter->AddParticle( sizeof(SimpleParticle), hSphereMaterial, vecOrg ); + if ( pParticle == NULL ) + return; + + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = 0.1f; + pParticle->m_uchStartSize = RandomInt(4,6); + pParticle->m_uchEndSize = pParticle->m_uchStartSize; + pParticle->m_vecVelocity = vec3_origin; + pParticle->m_uchStartAlpha = 255; + pParticle->m_uchEndAlpha = 255; + pParticle->m_flRoll = random->RandomFloat( 180, 360 ); + pParticle->m_flRollDelta = random->RandomFloat( -1, 1 ); + + if ( InLocalTeam() ) + { + pParticle->m_uchColor[0] = 0; + pParticle->m_uchColor[1] = 255; + pParticle->m_uchColor[2] = 0; + } + else + { + pParticle->m_uchColor[0] = 255; + pParticle->m_uchColor[1] = 50; + pParticle->m_uchColor[2] = 50; + } +} + + diff --git a/game/client/tf2/c_grenade_objectsapper.cpp b/game/client/tf2/c_grenade_objectsapper.cpp new file mode 100644 index 0000000..5b40dae --- /dev/null +++ b/game/client/tf2/c_grenade_objectsapper.cpp @@ -0,0 +1,82 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "basegrenade_shared.h" +#include "IEffects.h" +#include "c_baseplayer.h" + +extern ConVar lod_effect_distance; + +//----------------------------------------------------------------------------- +// Purpose: Client side entity for the ferry target items +//----------------------------------------------------------------------------- +class C_GrenadeObjectSapper : public C_BaseGrenade +{ + DECLARE_CLASS( C_GrenadeObjectSapper, C_BaseGrenade ); +public: + DECLARE_CLIENTCLASS(); + + C_GrenadeObjectSapper(); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void ClientThink( void ); + +public: + C_GrenadeObjectSapper( const C_GrenadeObjectSapper & ); + + bool m_bSapping; + float m_flNextEffectTime; +}; + +IMPLEMENT_CLIENTCLASS_DT(C_GrenadeObjectSapper, DT_GrenadeObjectSapper, CGrenadeObjectSapper) + RecvPropInt(RECVINFO(m_bSapping)), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_GrenadeObjectSapper::C_GrenadeObjectSapper( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_GrenadeObjectSapper::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + // Only think when sapping + if ( m_bSapping ) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); + m_flNextEffectTime = gpGlobals->curtime; + } + else + { + SetNextClientThink( CLIENT_THINK_NEVER ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Spawn effects if I'm sapping +//----------------------------------------------------------------------------- +void C_GrenadeObjectSapper::ClientThink( void ) +{ + if ( m_flNextEffectTime < gpGlobals->curtime ) + { + // Haxory LOD + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( (GetAbsOrigin() - pPlayer->GetAbsOrigin()).LengthSqr() < lod_effect_distance.GetFloat() ) + { + g_pEffects->Sparks( GetAbsOrigin() ); + } + + m_flNextEffectTime = gpGlobals->curtime + 0.3; + } +} diff --git a/game/client/tf2/c_grenade_rocket.cpp b/game/client/tf2/c_grenade_rocket.cpp new file mode 100644 index 0000000..3db4497 --- /dev/null +++ b/game/client/tf2/c_grenade_rocket.cpp @@ -0,0 +1,83 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "particles_simple.h" + +//----------------------------------------------------------------------------- +// Purpose: Client side entity for the antipersonnel grenades +//----------------------------------------------------------------------------- +class C_GrenadeRocket : public C_BaseAnimating +{ + DECLARE_CLASS( C_GrenadeRocket, C_BaseAnimating ); +public: + DECLARE_CLIENTCLASS(); + + C_GrenadeRocket(); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void ClientThink( void ); + +public: + C_GrenadeRocket( const C_GrenadeRocket & ); +}; + +IMPLEMENT_CLIENTCLASS_DT(C_GrenadeRocket, DT_GrenadeRocket, CGrenadeRocket) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_GrenadeRocket::C_GrenadeRocket( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_GrenadeRocket::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + // Only think when sapping + SetNextClientThink( CLIENT_THINK_ALWAYS ); +} + +//----------------------------------------------------------------------------- +// Purpose: Spawn effects if I'm sapping +//----------------------------------------------------------------------------- +void C_GrenadeRocket::ClientThink( void ) +{ + // Fire smoke puffs out the side + CSmartPtr<CSimpleEmitter> pSmokeEmitter = CSimpleEmitter::Create( "C_GrenadeRocket::Effect" ); + pSmokeEmitter->SetSortOrigin( GetAbsOrigin() ); + int iSmokeClouds = random->RandomInt(1,2); + for ( int i = 0; i < iSmokeClouds; i++ ) + { + SimpleParticle *pParticle = (SimpleParticle *) pSmokeEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[1], GetAbsOrigin() ); + if ( pParticle == NULL ) + return; + + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = random->RandomFloat( 0.1f, 0.3f ); + + pParticle->m_uchStartSize = 10; + pParticle->m_uchEndSize = pParticle->m_uchStartSize + 2; + + pParticle->m_vecVelocity = GetAbsVelocity(); + pParticle->m_uchStartAlpha = 255; + pParticle->m_uchEndAlpha = 64; + pParticle->m_flRoll = random->RandomFloat( 180, 360 ); + pParticle->m_flRollDelta = random->RandomFloat( -1, 1 ); + + pParticle->m_uchColor[0] = 50; + pParticle->m_uchColor[1] = 250; + pParticle->m_uchColor[2] = 50; + } +} + + diff --git a/game/client/tf2/c_harpoon.cpp b/game/client/tf2/c_harpoon.cpp new file mode 100644 index 0000000..1ea93e6 --- /dev/null +++ b/game/client/tf2/c_harpoon.cpp @@ -0,0 +1,95 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "particles_simple.h" + +//----------------------------------------------------------------------------- +// Purpose: Client side entity for the harpoon +//----------------------------------------------------------------------------- +class C_Harpoon : public C_BaseAnimating +{ + DECLARE_CLASS( C_Harpoon, C_BaseAnimating ); +public: + DECLARE_CLIENTCLASS(); + + C_Harpoon(); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pOrigin, QAngle *pAngles ); + +public: + C_Harpoon( const C_Harpoon & ); + +private: + // Impaling + Vector m_vecOffset; + QAngle m_angOffset; +}; + +IMPLEMENT_CLIENTCLASS_DT(C_Harpoon, DT_Harpoon, CHarpoon) + RecvPropVector( RECVINFO(m_vecOffset) ), + RecvPropVector( RECVINFO(m_angOffset) ), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_Harpoon::C_Harpoon( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_Harpoon::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); +} + + +//----------------------------------------------------------------------------- +// Returns the attachment render origin + origin +//----------------------------------------------------------------------------- +void C_Harpoon::GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pOrigin, QAngle *pAngles ) +{ + C_BaseAnimating *pEnt = dynamic_cast< C_BaseAnimating * >( pAttachedTo->GetBaseEntity() ); + if (!pEnt) + return; + + float controllers[MAXSTUDIOBONES]; + pEnt->GetBoneControllers(controllers); + + float headcontroller = controllers[ 0 ]; + + // Compute angles as well, since parent uses bone controller for rotation + + // Convert 0 - 1 to angles + float renderYaw = -180.0f + 360.0f * headcontroller; + + matrix3x4_t matrix; + + // Convert roll/pitch only to matrix + AngleMatrix( pEnt->GetAbsAngles(), matrix ); + + // Convert desired yaw to vector + QAngle anglesRotated( 0, renderYaw, 0 ); + Vector forward; + AngleVectors( anglesRotated, &forward ); + + Vector rotatedForward; + + // Rotate desired yaw vector by roll/pitch matrix + VectorRotate( forward, matrix, rotatedForward ); + + // Convert rotated vector back to orientation + VectorAngles( rotatedForward, *pAngles ); + //*pAngles -= m_angOffset; + + // HACK: Until we have a proper bone solution, hack the origin for all moving objects + *pOrigin = pEnt->WorldSpaceCenter( ); +}
\ No newline at end of file diff --git a/game/client/tf2/c_hint_events.cpp b/game/client/tf2/c_hint_events.cpp new file mode 100644 index 0000000..71b29e4 --- /dev/null +++ b/game/client/tf2/c_hint_events.cpp @@ -0,0 +1,49 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_hint_events.h" +#include "c_tf_hints.h" +#include "c_tf_hintmanager.h" +#include <KeyValues.h> +#include "c_baseobject.h" + + +void GlobalHintEvent( C_HintEvent_Base *pEvent ) +{ + // Call the static registered functions for each hint type. + for ( int i=0; i < GetNumHintDatas(); i++ ) + { + CHintData *pData = GetHintData( i ); + if ( pData && pData->m_pEventFn ) + pData->m_pEventFn( pData, pEvent ); + } +} + + +void HintEventFn_BuildObject( CHintData *pData, C_HintEvent_Base *pEvent ) +{ + if ( pEvent->GetType() == HINTEVENT_OBJECT_BUILT_BY_LOCAL_PLAYER ) + { + C_BaseObject *pObj = ((C_HintEvent_ObjectBuiltByLocalPlayer*)pEvent)->m_pObject; + + if ( pObj->GetType() == pData->m_ObjectType ) + { + // Ok, they just built the object that any hints of this type are referring to, so disable + // all further hints of this type. + KeyValues *pkvStats = GetHintDisplayStats(); + if ( pkvStats ) + { + KeyValues *pkvStatSection = pkvStats->FindKey( pData->name, true ); + if ( pkvStatSection ) + { + pkvStatSection->SetString( "times_shown", VarArgs( "%i", 100 ) ); + } + } + } + } +} + diff --git a/game/client/tf2/c_hint_events.h b/game/client/tf2/c_hint_events.h new file mode 100644 index 0000000..89dc0db --- /dev/null +++ b/game/client/tf2/c_hint_events.h @@ -0,0 +1,62 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_HINT_EVENTS_H +#define C_HINT_EVENTS_H +#ifdef _WIN32 +#pragma once +#endif + + +class CHintData; + + +typedef enum +{ + HINTEVENT_OBJECT_BUILT_BY_LOCAL_PLAYER=0 // C_HintEvent_ObjectBuiltByLocalPlayer +} HintEventType; + + +// All hint events derive from this. +class C_HintEvent_Base +{ +public: + // Find out what kind of event this is. + virtual HintEventType GetType() = 0; +}; + + +// Fire a global hint event. It goes to all hint types so they can determine if +// they want to react. +void GlobalHintEvent( C_HintEvent_Base *pEvent ); + + +// Hint callbacks for each type of hint. +void HintEventFn_BuildObject( CHintData *pData, C_HintEvent_Base *pEvent ); + + + +// This notifies the hint system that an object has been built by the local player so +// it can disable all further hints referring to objects of this type. +class C_BaseObject; + +class C_HintEvent_ObjectBuiltByLocalPlayer : public C_HintEvent_Base +{ +public: + C_HintEvent_ObjectBuiltByLocalPlayer( C_BaseObject *pObj ) + { + m_pObject = pObj; + } + + virtual HintEventType GetType() { return HINTEVENT_OBJECT_BUILT_BY_LOCAL_PLAYER; } + +public: + C_BaseObject *m_pObject; // The object just built. +}; + + +#endif // C_HINT_EVENTS_H diff --git a/game/client/tf2/c_info_act.cpp b/game/client/tf2/c_info_act.cpp new file mode 100644 index 0000000..71941dc --- /dev/null +++ b/game/client/tf2/c_info_act.cpp @@ -0,0 +1,196 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// +#include "cbase.h" +#include "tf_shareddefs.h" +#include "c_info_act.h" +#include "hud_timer.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// We may get act begin messages for acts we haven't yet received entities for (usually during connection) +// We store the current act in this, and if an act arrives matching it, we start that act. +static int g_iCurrentActNumber = -1; +static float g_flActStartTime; + +CHandle<C_InfoAct> g_hCurrentAct; + +IMPLEMENT_CLIENTCLASS_DT(C_InfoAct, DT_InfoAct, CInfoAct) + RecvPropInt( RECVINFO(m_iActNumber) ), + RecvPropInt( RECVINFO(m_spawnflags) ), + RecvPropFloat( RECVINFO(m_flActTimeLimit) ), + RecvPropInt(RECVINFO(m_nRespawn1Team1Time) ), + RecvPropInt(RECVINFO(m_nRespawn1Team2Time) ), + RecvPropInt(RECVINFO(m_nRespawn2Team1Time) ), + RecvPropInt(RECVINFO(m_nRespawn2Team2Time) ), + RecvPropInt(RECVINFO(m_nRespawnTeam1Delay) ), + RecvPropInt(RECVINFO(m_nRespawnTeam2Delay) ), +END_RECV_TABLE() + +typedef CHandle<C_InfoAct> ActHandle_t; +CUtlVector< ActHandle_t > g_hActs; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_InfoAct::C_InfoAct() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_InfoAct::~C_InfoAct() +{ + ActHandle_t hAct; + hAct = this; + g_hActs.FindAndRemove( hAct ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_InfoAct::OnPreDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnPreDataChanged( updateType ); + m_flPreviousTimeLimit = m_flActTimeLimit; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_InfoAct::OnDataChanged( DataUpdateType_t updateType ) +{ + ActHandle_t hAct; + hAct = this; + if ( g_hActs.Find( hAct ) == g_hActs.InvalidIndex() ) + { + g_hActs.AddToTail( hAct ); + + // Is this act the one that's supposed to be going? + if ( GetActNumber() == g_iCurrentActNumber ) + { + StartAct( g_flActStartTime ); + return; + } + } + + // Timer changed? + if ( g_hCurrentAct == this ) + { + if ( m_flPreviousTimeLimit != m_flActTimeLimit ) + { + CHudTimer *timer = GET_HUDELEMENT( CHudTimer ); + if ( timer ) + { + timer->SetFixedTimer( m_flStartTime, m_flActTimeLimit ); + } + } + } + + BaseClass::OnDataChanged( updateType ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_InfoAct::StartAct( float flStartTime ) +{ + g_hCurrentAct = this; + m_flStartTime = flStartTime; + + CHudTimer *timer = GET_HUDELEMENT( CHudTimer ); + if ( timer ) + { + timer->SetFixedTimer( m_flStartTime, m_flActTimeLimit ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_InfoAct::IsAWaitingAct( void ) +{ + return (m_spawnflags & SF_ACT_WAITINGFORGAMESTART) != 0; +} + + +//----------------------------------------------------------------------------- +// PReturns the respawn time remaining +//----------------------------------------------------------------------------- +float C_InfoAct::RespawnTimeRemaining( int nTeam, int nTimer ) const +{ + if ((g_hCurrentAct != this) || (nTeam == 0)) + return 0; + + int nTimerTime; + float flTimeDelta = gpGlobals->curtime - m_flStartTime; + if (flTimeDelta <= 0) + return 0; + + if (nTeam == 1) + { + nTimerTime = (nTimer == 1) ? m_nRespawn1Team1Time : m_nRespawn2Team1Time; + flTimeDelta -= m_nRespawnTeam1Delay; + } + else + { + nTimerTime = (nTimer == 1) ? m_nRespawn1Team2Time : m_nRespawn2Team2Time; + flTimeDelta -= m_nRespawnTeam2Delay; + } + + if (nTimerTime <= 0) + return 0.0f; + + // This case takes care of the initial spawn delay time... + if (flTimeDelta < 0) + { + return nTimerTime - flTimeDelta; + } + + int nFactor = flTimeDelta / nTimerTime; + return nTimerTime - (flTimeDelta - nFactor * nTimerTime); +} + + +//----------------------------------------------------------------------------- +// Purpose: Server's told us to start an act +//----------------------------------------------------------------------------- +void StartAct( int iActNumber, float flStartTime ) +{ + g_iCurrentActNumber = iActNumber; + g_flActStartTime = flStartTime; + + // Find the act + for ( int i = 0; i < g_hActs.Size(); i++ ) + { + if ( g_hActs[i] && g_hActs[i]->GetActNumber() == iActNumber ) + { + g_hActs[i]->StartAct( flStartTime ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int GetCurrentActNumber( void ) +{ + if ( g_hCurrentAct ) + return g_hCurrentAct->GetActNumber(); + return ACT_NONE_SPECIFIED; +} + +//----------------------------------------------------------------------------- +// Purpose: Return true if the current act (if any) is a waiting act. +//----------------------------------------------------------------------------- +bool CurrentActIsAWaitingAct( void ) +{ + if ( g_hCurrentAct ) + return g_hCurrentAct->IsAWaitingAct(); + + return false; +}
\ No newline at end of file diff --git a/game/client/tf2/c_info_act.h b/game/client/tf2/c_info_act.h new file mode 100644 index 0000000..ad97248 --- /dev/null +++ b/game/client/tf2/c_info_act.h @@ -0,0 +1,56 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef C_INFO_ACT_H +#define C_INFO_ACT_H +#ifdef _WIN32 +#pragma once +#endif + +#define ACT_NONE_SPECIFIED -1 + +//----------------------------------------------------------------------------- +// Purpose: Map entity that defines an act +//----------------------------------------------------------------------------- +class C_InfoAct : public C_BaseEntity +{ + DECLARE_CLASS( C_InfoAct, C_BaseEntity ); +public: + C_InfoAct(); + ~C_InfoAct(); + + DECLARE_CLIENTCLASS(); + + virtual void OnPreDataChanged( DataUpdateType_t updateType ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + + void StartAct( float flStartTime ); + + int GetActNumber( void ) { return m_iActNumber; } + bool IsAWaitingAct( void ); + + float RespawnTimeRemaining( int nTeam, int nTimer ) const; + +private: + int m_iActNumber; + int m_spawnflags; + float m_flActTimeLimit; + int m_nRespawn1Team1Time; + int m_nRespawn1Team2Time; + int m_nRespawn2Team1Time; + int m_nRespawn2Team2Time; + int m_nRespawnTeam1Delay; + int m_nRespawnTeam2Delay; + float m_flStartTime; + float m_flPreviousTimeLimit; +}; + +extern CHandle<C_InfoAct> g_hCurrentAct; +void StartAct( int iActNumber, float flStartTime ); +int GetCurrentActNumber( void ); +bool CurrentActIsAWaitingAct( void ); + +#endif // C_INFO_ACT_H diff --git a/game/client/tf2/c_info_customtech.cpp b/game/client/tf2/c_info_customtech.cpp new file mode 100644 index 0000000..d5ae027 --- /dev/null +++ b/game/client/tf2/c_info_customtech.cpp @@ -0,0 +1,51 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud_technologytreedoc.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_InfoCustomTechnology : public C_BaseEntity +{ + DECLARE_CLASS( C_InfoCustomTechnology, C_BaseEntity ); +public: + DECLARE_CLIENTCLASS(); + + C_InfoCustomTechnology( void ); + virtual void SetDormant( bool bDormant ); + +public: + // Sent via datatable + char m_szTechTreeFile[128]; +}; + +IMPLEMENT_CLIENTCLASS_DT(C_InfoCustomTechnology, DT_InfoCustomTechnology, CInfoCustomTechnology) + RecvPropString(RECVINFO(m_szTechTreeFile)), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_InfoCustomTechnology::C_InfoCustomTechnology( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Whenever we enter the PVS, add ourselves to the tech tree. This will +// only happen when the player joins a new team. +//----------------------------------------------------------------------------- +void C_InfoCustomTechnology::SetDormant( bool bDormant ) +{ + if ( IsDormant() && !bDormant ) + { + // Tell the techtree to add the file to it's list of technologies + GetTechnologyTreeDoc().AddTechnologyFile( m_szTechTreeFile ); + } + + BaseClass::SetDormant( bDormant ); +}
\ No newline at end of file diff --git a/game/client/tf2/c_maker_bughole.cpp b/game/client/tf2/c_maker_bughole.cpp new file mode 100644 index 0000000..a789e05 --- /dev/null +++ b/game/client/tf2/c_maker_bughole.cpp @@ -0,0 +1,109 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "c_ai_basenpc.h" +#include "IEffects.h" +#include "particles_simple.h" + +//----------------------------------------------------------------------------- +// Purpose: Client side entity for the NPC Bug hole +//----------------------------------------------------------------------------- +class C_Maker_Bughole : public C_BaseEntity +{ + DECLARE_CLASS( C_Maker_Bughole, C_BaseEntity ); +public: + DECLARE_CLIENTCLASS(); + + C_Maker_Bughole(); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void ClientThink( void ); + void SpawnEffect( void ); + +public: + C_Maker_Bughole( const C_Maker_Bughole & ); + + float m_flNextEffectTime; +}; + +IMPLEMENT_CLIENTCLASS_DT(C_Maker_Bughole, DT_Maker_Bughole, CMaker_Bughole) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_Maker_Bughole::C_Maker_Bughole( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_Maker_Bughole::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + if ( updateType == DATA_UPDATE_CREATED ) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); + m_flNextEffectTime = gpGlobals->curtime; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Spawn effects if I'm sapping +//----------------------------------------------------------------------------- +void C_Maker_Bughole::ClientThink( void ) +{ + if ( m_flNextEffectTime < gpGlobals->curtime ) + { + SpawnEffect(); + m_flNextEffectTime = gpGlobals->curtime + random->RandomFloat( 0.5, 1.0 ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Particle effects created when we spawn a chunk +//----------------------------------------------------------------------------- +void C_Maker_Bughole::SpawnEffect( void ) +{ + Vector normal = Vector(0,0,-1); + Vector offset = GetAbsOrigin() + (normal * 16); + Vector dir; + + // Create a couple of big, floating smoke clouds + CSmartPtr<CSimpleEmitter> pSmokeEmitter = CSimpleEmitter::Create( "C_Maker_Bughole::SpawnEffect" ); + pSmokeEmitter->SetSortOrigin( offset ); + int iSmokeClouds = random->RandomInt(2,5); + for ( int i = 0; i < iSmokeClouds; i++ ) + { + SimpleParticle *pParticle = (SimpleParticle *) pSmokeEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[1], offset ); + if ( pParticle == NULL ) + return; + + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = random->RandomFloat( 2.0f, 3.0f ); + + pParticle->m_uchStartSize = 8; + pParticle->m_uchEndSize = 48; + + dir[0] = normal[0] + random->RandomFloat( -0.4f, 0.4f ); + dir[1] = normal[1] + random->RandomFloat( -0.4f, 0.4f ); + dir[2] = normal[2] + random->RandomFloat( 0, 0.6f ); + pParticle->m_vecVelocity = dir * random->RandomFloat( 8.0f, 20.0f )*(i+1); + pParticle->m_uchStartAlpha = 255; + pParticle->m_uchEndAlpha = 0; + pParticle->m_flRoll = random->RandomFloat( 180, 360 ); + pParticle->m_flRollDelta = random->RandomFloat( -1, 1 ); + + float flColor = random->RandomFloat( 0,64 ); + pParticle->m_uchColor[0] = 100 + flColor; + pParticle->m_uchColor[1] = 50 + flColor; + pParticle->m_uchColor[2] = flColor; + } +} diff --git a/game/client/tf2/c_obj_barbed_wire.cpp b/game/client/tf2/c_obj_barbed_wire.cpp new file mode 100644 index 0000000..fdf74bd --- /dev/null +++ b/game/client/tf2/c_obj_barbed_wire.cpp @@ -0,0 +1,110 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "c_obj_barbed_wire.h" + + +IMPLEMENT_CLIENTCLASS_DT( C_ObjectBarbedWire, DT_ObjectBarbedWire, CObjectBarbedWire ) + RecvPropEHandle( RECVINFO( m_hConnectedTo ) ) +END_RECV_TABLE() + + +ConVar obj_barbed_wire_hang_dist( "obj_barbed_wire_hang_dist", "20" ); + + +C_ObjectBarbedWire::C_ObjectBarbedWire() +{ + m_vLastConnectedOrigin.Init( -999999999, -999999999, -999999999 ); + m_vLastOrigin = m_vLastConnectedOrigin; +} + + +C_ObjectBarbedWire::~C_ObjectBarbedWire() +{ + // Get rid of our rope if necessary. + if ( m_hRope ) + { + m_hRope->Release(); + } +} + + +void C_ObjectBarbedWire::OnDataChanged( DataUpdateType_t type ) +{ + if ( m_hConnectedTo != m_hLastConnectedTo ) + { + m_hLastConnectedTo = m_hConnectedTo; + + // Get rid of any old rope we had. + int iAttachment = LookupAttachment( "wire_attachment" ); + + // Create or delete our rope? + if ( m_hConnectedTo ) + { + if ( !m_hRope ) + { + + m_hRope = C_RopeKeyframe::Create( + this, + m_hConnectedTo, + iAttachment, + iAttachment, + 3, + "sprites/physbeam" + ); + } + } + else + { + if ( m_hRope ) + { + m_hRope->Release(); + m_hRope = NULL; + } + } + + // Update rope parameters. + if ( m_hRope ) + { + int r, g, b, a; + CMapTeamColors *team = &MapData().m_TeamColors[ GetTeamNumber() ]; + team->m_clrTeam.GetColor( r, g, b, a ); + m_hRope->SetColorMod( Vector( r / 255.0f, g / 255.0f, b / 255.0f ) ); + + m_hRope->SetEndEntity( m_hConnectedTo ); + m_hRope->SetRopeFlags( ROPE_SIMULATE | ROPE_BARBED ); + } + } + + BaseClass::OnDataChanged( type ); +} + + +void C_ObjectBarbedWire::Spawn() +{ +} + + +void C_ObjectBarbedWire::ClientThink() +{ + if ( m_hConnectedTo && m_hRope ) + { + if ( m_vLastOrigin != GetAbsOrigin() || m_vLastConnectedOrigin != m_hConnectedTo->GetAbsOrigin() ) + { + m_hRope->SetupHangDistance( obj_barbed_wire_hang_dist.GetFloat() ); + + m_vLastOrigin = GetAbsOrigin(); + m_vLastConnectedOrigin = m_hConnectedTo->GetAbsOrigin(); + } + } + + SetNextClientThink( gpGlobals->curtime + 0.1f ); +} + + + + diff --git a/game/client/tf2/c_obj_barbed_wire.h b/game/client/tf2/c_obj_barbed_wire.h new file mode 100644 index 0000000..b242640 --- /dev/null +++ b/game/client/tf2/c_obj_barbed_wire.h @@ -0,0 +1,46 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef C_OBJ_BARBED_WIRE_H +#define C_OBJ_BARBED_WIRE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "c_baseobject.h" +#include "c_rope.h" + + +class C_ObjectBarbedWire : public C_BaseObject +{ +public: + DECLARE_CLASS( C_ObjectBarbedWire, C_BaseObject ); + DECLARE_CLIENTCLASS(); + + C_ObjectBarbedWire(); + ~C_ObjectBarbedWire(); + + virtual void OnDataChanged( DataUpdateType_t type ); + + virtual void Spawn(); + virtual void ClientThink(); + + +private: + C_ObjectBarbedWire( C_ObjectBarbedWire& ) {} + + CHandle<C_ObjectBarbedWire> m_hConnectedTo; + CHandle<C_ObjectBarbedWire> m_hLastConnectedTo; + CHandle<C_RopeKeyframe> m_hRope; + + // Used to determine when to recalculate the hang distance. + Vector m_vLastOrigin; + Vector m_vLastConnectedOrigin; +}; + + +#endif // C_OBJ_BARBED_WIRE_H diff --git a/game/client/tf2/c_obj_base_manned_gun.cpp b/game/client/tf2/c_obj_base_manned_gun.cpp new file mode 100644 index 0000000..b7d7582 --- /dev/null +++ b/game/client/tf2/c_obj_base_manned_gun.cpp @@ -0,0 +1,122 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_obj_base_manned_gun.h" +#include "hudelement.h" +#include "tf_movedata.h" +#include "bone_setup.h" +#include "hud_ammo.h" +#include "vgui_bitmapbutton.h" + +extern ConVar mannedgun_usethirdperson; + +//================================================================================================= +// Control Screen +//================================================================================================= + +DECLARE_VGUI_SCREEN_FACTORY( CMannedPlasmagunControlPanel, "manned_plasmagun_control_panel" ); + +//----------------------------------------------------------------------------- +// Constructor: +//----------------------------------------------------------------------------- +CMannedPlasmagunControlPanel::CMannedPlasmagunControlPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, "CMannedPlasmagunControlPanel" ) +{ +} + + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- +bool CMannedPlasmagunControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ) +{ + m_pMannedLabel = new vgui::Label( this, "MannedReadout", "" ); + m_pOccupyButton = new CBitmapButton( this, "OccupyButton", "Occupy" ); + + if (!BaseClass::Init(pKeyValues, pInitData)) + return false; + + return true; +} + + +//----------------------------------------------------------------------------- +// Frame-based update +//----------------------------------------------------------------------------- +void CMannedPlasmagunControlPanel::OnTick() +{ + BaseClass::OnTick(); + + C_BaseObject *pObj = GetOwningObject(); + if (!pObj) + return; + + Assert( dynamic_cast<C_ObjectBaseMannedGun*>(pObj) ); + C_ObjectBaseMannedGun *pGun = static_cast<C_ObjectBaseMannedGun*>(pObj); + + char buf[256]; + // Update the currently manned player label + if ( pGun->GetDriverPlayer() ) + { + Q_snprintf( buf, sizeof( buf ), "Manned by %s", pGun->GetDriverPlayer()->GetPlayerName() ); + m_pMannedLabel->SetText( buf ); + m_pMannedLabel->SetVisible( true ); + } + else + { + m_pMannedLabel->SetVisible( false ); + } + + // Update the get in button + if ( pGun->GetDriverPlayer() ) + { + // Owners can boot other players to get in + if ( pGun->GetOwner() == C_BaseTFPlayer::GetLocalPlayer() && C_BaseTFPlayer::GetLocalPlayer() != pGun->GetDriverPlayer() ) + { + Q_snprintf( buf, sizeof( buf ), "Get In (Ejecting %s)", pGun->GetDriverPlayer()->GetPlayerName() ); + m_pMannedLabel->SetText( buf ); + m_pOccupyButton->SetEnabled( true ); + } + else + { + // Disable the button + m_pOccupyButton->SetEnabled( false ); + } + } + else + { + m_pOccupyButton->SetText( "Get In" ); + m_pOccupyButton->SetEnabled( true ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Handle clicking on the Occupy button +//----------------------------------------------------------------------------- +void CMannedPlasmagunControlPanel::GetInGun( void ) +{ + C_BaseObject *pObj = GetOwningObject(); + if (pObj) + { + pObj->SendClientCommand( "toggle_use" ); + } +} + +//----------------------------------------------------------------------------- +// Button click handlers +//----------------------------------------------------------------------------- +void CMannedPlasmagunControlPanel::OnCommand( const char *command ) +{ + if (!Q_strnicmp(command, "Occupy", 7)) + { + GetInGun(); + return; + } + + BaseClass::OnCommand(command); +} + diff --git a/game/client/tf2/c_obj_base_manned_gun.h b/game/client/tf2/c_obj_base_manned_gun.h new file mode 100644 index 0000000..94b2c74 --- /dev/null +++ b/game/client/tf2/c_obj_base_manned_gun.h @@ -0,0 +1,39 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef C_OBJ_BASE_MANNED_GUN_H +#define C_OBJ_BASE_MANNED_GUN_H +#ifdef _WIN32 +#pragma once +#endif + +#include "basetfvehicle.h" +#include "tf_obj_manned_plasmagun_shared.h" +#include "ObjectControlPanel.h" +#include "tf_obj_base_manned_gun.h" + + +//----------------------------------------------------------------------------- +// Control screen +//----------------------------------------------------------------------------- +class CMannedPlasmagunControlPanel : public CRotatingObjectControlPanel +{ + DECLARE_CLASS( CMannedPlasmagunControlPanel, CRotatingObjectControlPanel ); + +public: + CMannedPlasmagunControlPanel( vgui::Panel *parent, const char *panelName ); + virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); + virtual void OnTick(); + virtual void OnCommand( const char *command ); + + void GetInGun( void ); + +private: + vgui::Label *m_pMannedLabel; + vgui::Button *m_pOccupyButton; +}; + +#endif // C_OBJ_BASE_MANNED_GUN_H diff --git a/game/client/tf2/c_obj_buff_station.cpp b/game/client/tf2/c_obj_buff_station.cpp new file mode 100644 index 0000000..350862a --- /dev/null +++ b/game/client/tf2/c_obj_buff_station.cpp @@ -0,0 +1,272 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: The client-side version of the portable power generator +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_baseobject.h" +#include "tf_shareddefs.h" +#include "C_BaseTFPlayer.h" +#include "ObjectControlPanel.h" +#include "vgui_bitmapbutton.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//============================================================================= +// +// Portable Power Generator Class +// +class C_ObjectBuffStation : public C_BaseObject +{ + DECLARE_CLASS( C_ObjectBuffStation, C_BaseObject ); + +public: + + DECLARE_CLIENTCLASS(); + + C_ObjectBuffStation( void ); + + virtual void Release( void ); + virtual void OnPreDataChanged( DataUpdateType_t updateType ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + + // Since we have material proxies to show building amount, don't offset origin + virtual bool OffsetObjectOrigin( Vector& origin ) + { + return false; + } + + int PlayerSocketsLeft() const { return ( BUFF_STATION_MAX_PLAYERS - m_nPlayerCount ); } + int ObjectSocketsLeft() const { return ( BUFF_STATION_MAX_OBJECTS - m_nObjectCount ); } + + // Check if the local player is attached + bool IsLocalPlayerAttached( void ); + +private: + typedef CHandle<C_BaseTFPlayer> CPlayerHandle; + int m_nPlayerCount; + CPlayerHandle m_hPlayers[BUFF_STATION_MAX_PLAYERS]; + CPlayerHandle m_hOldPlayers[BUFF_STATION_MAX_PLAYERS]; + + typedef CHandle<C_BaseObject> CObjectHandle; + int m_nObjectCount; + CObjectHandle m_hObjects[BUFF_STATION_MAX_OBJECTS]; + +private: + C_ObjectBuffStation( const C_ObjectBuffStation & ); // not defined, not accessible +}; + + +IMPLEMENT_CLIENTCLASS_DT( C_ObjectBuffStation, DT_ObjectBuffStation, CObjectBuffStation ) + RecvPropInt( RECVINFO( m_nPlayerCount ) ), + RecvPropArray( RecvPropEHandle( RECVINFO( m_hPlayers[0]) ), m_hPlayers ), + RecvPropInt( RECVINFO( m_nObjectCount ) ), + RecvPropArray( RecvPropEHandle( RECVINFO( m_hObjects[0]) ), m_hObjects ), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ObjectBuffStation::C_ObjectBuffStation( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Check if the local player is attached +//----------------------------------------------------------------------------- +bool C_ObjectBuffStation::IsLocalPlayerAttached( void ) +{ + C_BaseTFPlayer *pLocalPlayer = C_BaseTFPlayer::GetLocalPlayer(); + for ( int iPlayer = 0; iPlayer < m_nPlayerCount; ++iPlayer ) + { + if ( m_hPlayers[iPlayer].Get() == pLocalPlayer ) + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ObjectBuffStation::Release( void ) +{ + // Remove any sounds for players attached + for ( int i = 0; i < BUFF_STATION_MAX_PLAYERS; i++ ) + { + if ( m_hPlayers[i] ) + { + // Stop the startup, in case it's still going + StopSound( m_hPlayers[i]->entindex(), "ObjectPortablePowerGenerator.Startup" ); + + // Start the shutdown sound + CPASAttenuationFilter filter( m_hPlayers[i], "ObjectPortablePowerGenerator.Shutdown" ); + EmitSound( filter, m_hPlayers[i]->entindex(), "ObjectPortablePowerGenerator.Shutdown" ); + } + } + + BaseClass::Release(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ObjectBuffStation::OnPreDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnPreDataChanged( updateType ); + + for ( int i = 0; i < BUFF_STATION_MAX_PLAYERS; i++ ) + { + m_hOldPlayers[i] = m_hPlayers[i]; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ObjectBuffStation::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + // Did a player connect / disconnect? + for ( int i = 0; i < BUFF_STATION_MAX_PLAYERS; i++ ) + { + // Something's changed + if ( m_hOldPlayers[i] != m_hPlayers[i] ) + { + // Disconnected? + if ( m_hOldPlayers[i] ) + { + // Stop the startup, in case it's still going + StopSound( m_hOldPlayers[i]->entindex(), "ObjectPortablePowerGenerator.Startup" ); + + // Start the shutdown sound + CPASAttenuationFilter filter( m_hOldPlayers[i], "ObjectPortablePowerGenerator.Shutdown" ); + EmitSound( filter, m_hOldPlayers[i]->entindex(), "ObjectPortablePowerGenerator.Shutdown" ); + } + + if ( m_hPlayers[i] ) + { + // Start "buff" sound. + CPASAttenuationFilter filter( m_hPlayers[i], "ObjectPortablePowerGenerator.Startup" ); + EmitSound( filter, m_hPlayers[i]->entindex(), "ObjectPortablePowerGenerator.Startup" ); + } + } + } +} + +//----------------------------------------------------------------------------- +// Control screen +//----------------------------------------------------------------------------- +class CBuffStationControlPanel : public CObjectControlPanel +{ + DECLARE_CLASS( CBuffStationControlPanel, CObjectControlPanel ); + +public: + + CBuffStationControlPanel( vgui::Panel *parent, const char *panelName ); + virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); + virtual void OnTick(); + virtual void OnCommand( const char *command ); + + void ConnectToStation( void ); + +private: + vgui::Label *m_pSocketsLabel; + vgui::Button *m_pConnectButton; +}; + + +DECLARE_VGUI_SCREEN_FACTORY( CBuffStationControlPanel, "buffstation_control_panel" ); + + +//----------------------------------------------------------------------------- +// Constructor: +//----------------------------------------------------------------------------- +CBuffStationControlPanel::CBuffStationControlPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, "CBuffStationControlPanel" ) +{ +} + + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- +bool CBuffStationControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ) +{ + m_pSocketsLabel = new vgui::Label( this, "SocketReadout", "" ); + m_pConnectButton = new CBitmapButton( this, "ConnectButton", "Connect" ); + + if (!BaseClass::Init(pKeyValues, pInitData)) + return false; + + return true; +} + + +//----------------------------------------------------------------------------- +// Frame-based update +//----------------------------------------------------------------------------- +void CBuffStationControlPanel::OnTick() +{ + BaseClass::OnTick(); + + C_BaseObject *pObj = GetOwningObject(); + if (!pObj) + return; + + Assert( dynamic_cast<C_ObjectBuffStation*>(pObj) ); + C_ObjectBuffStation *pStation = static_cast<C_ObjectBuffStation*>(pObj); + + char buf[256]; + int nSocketsLeft = pStation->PlayerSocketsLeft(); + if (nSocketsLeft > 0) + { + Q_snprintf( buf, sizeof( buf ), "%d sockets left", pStation->PlayerSocketsLeft() ); + } + else + { + Q_strncpy( buf, "No sockets left", sizeof( buf ) ); + } + + m_pSocketsLabel->SetText( buf ); + + // Make sure the connect/disconnect button is correct + if ( pStation->IsLocalPlayerAttached() ) + { + m_pConnectButton->SetText( "Disconnect from Station" ); + } + else + { + m_pConnectButton->SetText( "Connect To Station" ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Handle clicking on the Connect/Disconnect button +//----------------------------------------------------------------------------- +void CBuffStationControlPanel::ConnectToStation( void ) +{ + C_BaseObject *pObj = GetOwningObject(); + if (pObj) + { + pObj->SendClientCommand( "toggle_connect" ); + } +} + +//----------------------------------------------------------------------------- +// Button click handlers +//----------------------------------------------------------------------------- +void CBuffStationControlPanel::OnCommand( const char *command ) +{ + if (!Q_strnicmp(command, "Connect", 7)) + { + ConnectToStation(); + return; + } + + BaseClass::OnCommand(command); +} + diff --git a/game/client/tf2/c_obj_bunker.cpp b/game/client/tf2/c_obj_bunker.cpp new file mode 100644 index 0000000..bc590a1 --- /dev/null +++ b/game/client/tf2/c_obj_bunker.cpp @@ -0,0 +1,70 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "hud.h" +#include "commanderoverlay.h" +#include "c_baseobject.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_ObjectBunker : public C_BaseObject +{ + DECLARE_CLASS( C_ObjectBunker, C_BaseObject ); +public: + DECLARE_CLIENTCLASS(); + + C_ObjectBunker(); + +private: + C_ObjectBunker( const C_ObjectBunker & ); // not defined, not accessible +}; + +IMPLEMENT_CLIENTCLASS_DT(C_ObjectBunker, DT_ObjectBunker, CObjectBunker) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ObjectBunker::C_ObjectBunker() +{ +} + + +//============================================================================= +// Bunker Ladder +//============================================================================= + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_ObjectBunkerLadder : public C_BaseAnimating +{ + DECLARE_CLASS( C_ObjectBunkerLadder, C_BaseAnimating ); +public: + + DECLARE_CLIENTCLASS(); + + C_ObjectBunkerLadder(); + +private: + C_ObjectBunkerLadder( const C_ObjectBunkerLadder& ); // not defined, not accessible +}; + +IMPLEMENT_CLIENTCLASS_DT( C_ObjectBunkerLadder, DT_ObjectBunkerLadder, CObjectBunkerLadder ) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ObjectBunkerLadder::C_ObjectBunkerLadder() +{ +} + diff --git a/game/client/tf2/c_obj_dragonsteeth.cpp b/game/client/tf2/c_obj_dragonsteeth.cpp new file mode 100644 index 0000000..3f690bf --- /dev/null +++ b/game/client/tf2/c_obj_dragonsteeth.cpp @@ -0,0 +1,44 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "hud.h" +#include "commanderoverlay.h" +#include "c_baseobject.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_ObjectDragonsTeeth : public C_BaseObject +{ + DECLARE_CLASS( C_ObjectDragonsTeeth, C_BaseObject ); +public: + DECLARE_CLIENTCLASS(); + + C_ObjectDragonsTeeth(); + + // Since we have material proxies to show building amount, don't offset origin + virtual bool OffsetObjectOrigin( Vector& origin ) + { + return false; + } + +private: + C_ObjectDragonsTeeth( const C_ObjectDragonsTeeth & ); // not defined, not accessible +}; + +IMPLEMENT_CLIENTCLASS_DT(C_ObjectDragonsTeeth, DT_ObjectDragonsTeeth, CObjectDragonsTeeth) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ObjectDragonsTeeth::C_ObjectDragonsTeeth() +{ +} diff --git a/game/client/tf2/c_obj_empgenerator.cpp b/game/client/tf2/c_obj_empgenerator.cpp new file mode 100644 index 0000000..2782bc4 --- /dev/null +++ b/game/client/tf2/c_obj_empgenerator.cpp @@ -0,0 +1,99 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "c_baseobject.h" +#include "particles_simple.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_ObjectEMPGenerator : public C_BaseObject +{ + DECLARE_CLASS( C_ObjectEMPGenerator, C_BaseObject ); +public: + DECLARE_CLIENTCLASS(); + + C_ObjectEMPGenerator(); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void ClientThink( void ); + +private: + CSmartPtr<CSimpleEmitter> m_pEmitter; + PMaterialHandle m_hParticleMaterial; + TimedEvent m_ParticleEvent; + +private: + C_ObjectEMPGenerator( const C_ObjectEMPGenerator & ); // not defined, not accessible +}; + +IMPLEMENT_CLIENTCLASS_DT(C_ObjectEMPGenerator, DT_ObjectEMPGenerator, CObjectEMPGenerator) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ObjectEMPGenerator::C_ObjectEMPGenerator() +{ + m_ParticleEvent.Init( 300 ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ObjectEMPGenerator::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + if ( updateType == DATA_UPDATE_CREATED ) + { + m_pEmitter = CSimpleEmitter::Create( "C_ObjectEMPGenerator" ); + m_hParticleMaterial = m_pEmitter->GetPMaterial( "sprites/chargeball" ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ObjectEMPGenerator::ClientThink( void ) +{ + // Add particles at the target. + float flCur = gpGlobals->frametime; + while ( m_ParticleEvent.NextEvent( flCur ) ) + { + Vector vPos = WorldSpaceCenter( ); + Vector vOffset = RandomVector( -1, 1 ); + VectorNormalize( vOffset ); + vPos += vOffset * RandomFloat( 0, 50 ); + + SimpleParticle *pParticle = m_pEmitter->AddSimpleParticle( m_hParticleMaterial, vPos ); + if ( pParticle ) + { + // Move the points along the path. + pParticle->m_vecVelocity.Init(); + pParticle->m_flRoll = 0; + pParticle->m_flRollDelta = 0; + pParticle->m_flDieTime = 0.4f; + pParticle->m_flLifetime = 0; + pParticle->m_uchColor[0] = 255; + pParticle->m_uchColor[1] = 255; + pParticle->m_uchColor[2] = 255; + pParticle->m_uchStartAlpha = 32; + pParticle->m_uchEndAlpha = 0; + pParticle->m_uchStartSize = 6; + pParticle->m_uchEndSize = 4; + pParticle->m_iFlags = 0; + } + } +} + + + + + diff --git a/game/client/tf2/c_obj_explosives.cpp b/game/client/tf2/c_obj_explosives.cpp new file mode 100644 index 0000000..ed32caf --- /dev/null +++ b/game/client/tf2/c_obj_explosives.cpp @@ -0,0 +1,36 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "hud.h" +#include "commanderoverlay.h" +#include "tf_obj_baseupgrade_shared.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_ObjectExplosives : public C_BaseObjectUpgrade +{ + DECLARE_CLASS( C_ObjectExplosives, C_BaseObjectUpgrade ); +public: + DECLARE_CLIENTCLASS(); + + C_ObjectExplosives(); + +private: + C_ObjectExplosives( const C_ObjectExplosives & ); // not defined, not accessible +}; + +IMPLEMENT_CLIENTCLASS_DT(C_ObjectExplosives, DT_ObjectExplosives, CObjectExplosives) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ObjectExplosives::C_ObjectExplosives() +{ +} + diff --git a/game/client/tf2/c_obj_manned_missilelauncher.cpp b/game/client/tf2/c_obj_manned_missilelauncher.cpp new file mode 100644 index 0000000..d1f67ad --- /dev/null +++ b/game/client/tf2/c_obj_manned_missilelauncher.cpp @@ -0,0 +1,28 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "c_obj_base_manned_gun.h" + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_ObjectMannedMissileLauncher : public C_ObjectBaseMannedGun +{ + DECLARE_CLASS( C_ObjectMannedMissileLauncher, C_ObjectBaseMannedGun ); +public: + DECLARE_CLIENTCLASS(); + + C_ObjectMannedMissileLauncher() {} + +private: + C_ObjectMannedMissileLauncher( const C_ObjectMannedMissileLauncher & ); // not defined, not accessible +}; + +IMPLEMENT_CLIENTCLASS_DT(C_ObjectMannedMissileLauncher, DT_ObjectMannedMissileLauncher, CObjectMannedMissileLauncher) +END_RECV_TABLE() + diff --git a/game/client/tf2/c_obj_manned_plasmagun.cpp b/game/client/tf2/c_obj_manned_plasmagun.cpp new file mode 100644 index 0000000..0603671 --- /dev/null +++ b/game/client/tf2/c_obj_manned_plasmagun.cpp @@ -0,0 +1,27 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_obj_base_manned_gun.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_ObjectMannedPlasmagun : public C_ObjectBaseMannedGun +{ + DECLARE_CLASS( C_ObjectMannedPlasmagun, C_ObjectBaseMannedGun ); +public: + DECLARE_CLIENTCLASS(); + + C_ObjectMannedPlasmagun() {} + +private: + C_ObjectMannedPlasmagun( const C_ObjectMannedPlasmagun & ); // not defined, not accessible +}; + +IMPLEMENT_CLIENTCLASS_DT(C_ObjectMannedPlasmagun, DT_ObjectMannedPlasmagun, CObjectMannedPlasmagun) +END_RECV_TABLE() + diff --git a/game/client/tf2/c_obj_manned_shield.cpp b/game/client/tf2/c_obj_manned_shield.cpp new file mode 100644 index 0000000..61dd995 --- /dev/null +++ b/game/client/tf2/c_obj_manned_shield.cpp @@ -0,0 +1,27 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "c_obj_base_manned_gun.h" + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_ObjectMannedShield : public C_ObjectBaseMannedGun +{ + DECLARE_CLASS( C_ObjectMannedShield, C_ObjectBaseMannedGun ); +public: + DECLARE_CLIENTCLASS(); + + C_ObjectMannedShield() {} + +private: + C_ObjectMannedShield( const C_ObjectMannedShield & ); // not defined, not accessible +}; + +IMPLEMENT_CLIENTCLASS_DT( C_ObjectMannedShield, DT_ObjectMannedShield, CObjectMannedShield ) +END_RECV_TABLE() diff --git a/game/client/tf2/c_obj_mapdefined.cpp b/game/client/tf2/c_obj_mapdefined.cpp new file mode 100644 index 0000000..8cd5ce9 --- /dev/null +++ b/game/client/tf2/c_obj_mapdefined.cpp @@ -0,0 +1,37 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "tf_shareddefs.h" +#include "c_obj_mapdefined.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +IMPLEMENT_CLIENTCLASS_DT(C_ObjectMapDefined, DT_ObjectMapDefined, CObjectMapDefined) + RecvPropString( RECVINFO(m_szCustomName) ), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ObjectMapDefined::C_ObjectMapDefined() +{ + memset( m_szCustomName, 0, sizeof(m_szCustomName) ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Get a text description for the object target +//----------------------------------------------------------------------------- +const char *C_ObjectMapDefined::GetTargetDescription( void ) const +{ + if ( m_szCustomName && m_szCustomName[0] ) + return m_szCustomName; + + return BaseClass::GetTargetDescription(); +}
\ No newline at end of file diff --git a/game/client/tf2/c_obj_mapdefined.h b/game/client/tf2/c_obj_mapdefined.h new file mode 100644 index 0000000..610f1d9 --- /dev/null +++ b/game/client/tf2/c_obj_mapdefined.h @@ -0,0 +1,35 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_OBJ_MAPDEFINED_H +#define C_OBJ_MAPDEFINED_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_baseobject.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_ObjectMapDefined : public C_BaseObject +{ + DECLARE_CLASS( C_ObjectMapDefined, C_BaseObject ); +public: + DECLARE_CLIENTCLASS(); + + C_ObjectMapDefined(); + + virtual const char *GetTargetDescription( void ) const; + +private: + C_ObjectMapDefined( const C_ObjectMapDefined & ); // not defined, not accessible + + char m_szCustomName[ MAX_OBJ_CUSTOMNAME_SIZE ]; +}; + +#endif // C_OBJ_MAPDEFINED_H diff --git a/game/client/tf2/c_obj_mcv_selection_panel.cpp b/game/client/tf2/c_obj_mcv_selection_panel.cpp new file mode 100644 index 0000000..1e57f0b --- /dev/null +++ b/game/client/tf2/c_obj_mcv_selection_panel.cpp @@ -0,0 +1,279 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "c_baseobject.h" +#include "ObjectControlPanel.h" +#include "hud_minimap.h" +#include "vgui_bitmapimage.h" +#include "c_vehicle_teleport_station.h" +#include <vgui/MouseCode.h> + + +class C_ObjMCVSelectionPanel; +CUtlLinkedList<C_ObjMCVSelectionPanel*,int> g_SelectionPanels; + + +// ------------------------------------------------------------------------------------------------ // +// C_ObjMCVSelectionPanel +// ------------------------------------------------------------------------------------------------ // + +class C_ObjMCVSelectionPanel : public C_BaseObject +{ +public: + + DECLARE_CLASS( C_ObjMCVSelectionPanel, C_BaseObject ); + DECLARE_CLIENTCLASS(); + + C_ObjMCVSelectionPanel(); + ~C_ObjMCVSelectionPanel(); + + typedef CHandle<C_VehicleTeleportStation> VehicleTeleportStationHandle; + CUtlVector<VehicleTeleportStationHandle> m_DeployedTeleportStations; + + +private: + static C_ObjMCVSelectionPanel *s_pSelectionPanel; + + friend void RecvProxy_TeleportStationCount( void *pStruct, int objectID, int currentArrayLength ); + friend void RecvProxy_TeleportStationElement( const CRecvProxyData *pData, void *pStruct, void *pOut ); + + C_ObjMCVSelectionPanel( const C_ObjMCVSelectionPanel & ); +}; + + +void RecvProxy_TeleportStationCount( void *pStruct, int objectID, int currentArrayLength ) +{ + C_ObjMCVSelectionPanel *pPanel = (C_ObjMCVSelectionPanel*)pStruct; + if ( pPanel->m_DeployedTeleportStations.Count() != currentArrayLength ) + { + pPanel->m_DeployedTeleportStations.SetSize( currentArrayLength ); + } +} + + +void RecvProxy_TeleportStationElement( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + C_ObjMCVSelectionPanel *pPanel = (C_ObjMCVSelectionPanel*)pStruct; + + Assert( pData->m_iElement < pPanel->m_DeployedTeleportStations.Count() ); + + RecvProxy_IntToEHandle( pData, pStruct, &pPanel->m_DeployedTeleportStations[pData->m_iElement] ); +} + + +IMPLEMENT_CLIENTCLASS_DT( C_ObjMCVSelectionPanel, DT_MCVSelectionPanel, CObjMCVSelectionPanel ) + RecvPropVirtualArray( + RecvProxy_TeleportStationCount, + 32, + RecvPropEHandle( "teleport_station_element", 0, 0, RecvProxy_TeleportStationElement ), + "teleport_stations" ) +END_RECV_TABLE() + + +C_ObjMCVSelectionPanel::C_ObjMCVSelectionPanel() +{ + g_SelectionPanels.AddToTail( this ); +} + +C_ObjMCVSelectionPanel::~C_ObjMCVSelectionPanel() +{ + g_SelectionPanels.FindAndRemove( this ); +} + + + +//----------------------------------------------------------------------------- +// CMCVMinimapPanel +//----------------------------------------------------------------------------- + +class CMCVMinimapPanel : public CMinimapPanel +{ +public: + + DECLARE_CLASS( CMCVMinimapPanel, CMinimapPanel ); + + CMCVMinimapPanel( vgui::Panel *pParent, const char *pElementName ); + virtual ~CMCVMinimapPanel(); + + virtual void Paint(); + virtual void OnMousePressed( vgui::MouseCode code ); + virtual void OnCursorMoved( int x, int y ); + + +private: + BitmapImage m_MCVImage; + BitmapImage m_SelectedMCVImage; + int m_LastX, m_LastY; +}; + + +CMCVMinimapPanel::CMCVMinimapPanel( vgui::Panel *pParent, const char *pElementName ) + : CMinimapPanel( pElementName ) +{ + SetParent( pParent ); + m_MCVImage.Init( GetVPanel(), "hud/minimap/icon_mcv_unselected" ); + m_SelectedMCVImage.Init( GetVPanel(), "hud/minimap/icon_mcv_selected" ); + m_LastX = m_LastY = 0; +} + + +CMCVMinimapPanel::~CMCVMinimapPanel() +{ +} + + +void CMCVMinimapPanel::Paint() +{ + // Draw the minimap. + BaseClass::Paint(); + + // Now draw the MCVs. + if ( g_SelectionPanels.Count() > 0 ) + { + C_ObjMCVSelectionPanel *pPanel = g_SelectionPanels[ g_SelectionPanels.Head() ]; + C_BaseEntity *pSelectedMCV = C_BaseTFPlayer::GetLocalPlayer()->GetSelectedMCV(); + + for ( int i=0; i < pPanel->m_DeployedTeleportStations.Count(); i++ ) + { + C_VehicleTeleportStation *pStation = pPanel->m_DeployedTeleportStations[i]; + if ( pStation ) + { + float x, y; + if ( WorldToMinimap( MINIMAP_CLAMP, pStation->GetAbsOrigin(), x, y ) ) + { + int size = 20; + + if ( pStation == pSelectedMCV ) + m_SelectedMCVImage.DoPaint( x-size/2, y-size/2, size, size ); + else + m_MCVImage.DoPaint( x-size/2, y-size/2, size, size ); + } + } + } + } +} + + + +void CMCVMinimapPanel::OnMousePressed( vgui::MouseCode code ) +{ + BaseClass::OnMousePressed( code ); + + if ( code != vgui::MOUSE_LEFT ) + return; + + // Now draw the MCVs. + if ( g_SelectionPanels.Count() > 0 ) + { + C_ObjMCVSelectionPanel *pPanel = g_SelectionPanels[ g_SelectionPanels.Head() ]; + + // Find the closest MCV to their mouse press. + int iClosest = -1; + float flClosest = 1e24; + Vector2D curMousePos( m_LastX, m_LastY ); + + for ( int i=0; i < pPanel->m_DeployedTeleportStations.Count(); i++ ) + { + C_VehicleTeleportStation *pStation = pPanel->m_DeployedTeleportStations[i]; + if ( pStation ) + { + Vector2D mcvPos; + if ( WorldToMinimap( MINIMAP_CLAMP, pStation->GetAbsOrigin(), mcvPos.x, mcvPos.y ) ) + { + float flTestDist = mcvPos.DistTo( curMousePos ); + if ( flTestDist < flClosest ) + { + flClosest = flTestDist; + iClosest = i; + } + } + } + } + + if ( iClosest != -1 && flClosest < 10 ) + { + C_VehicleTeleportStation *pClosest = pPanel->m_DeployedTeleportStations[iClosest]; + + char str[512]; + Q_snprintf( str, sizeof( str ), "SelectMCV %d", pClosest->entindex() ); + pPanel->SendClientCommand( str ); + } + } +} + + +void CMCVMinimapPanel::OnCursorMoved( int x, int y ) +{ + BaseClass::OnCursorMoved( x, y ); + + m_LastX = x; + m_LastY = y; +} + + + +// ------------------------------------------------------------------------------------------------ // +// CMCVSelectionPanel +// ------------------------------------------------------------------------------------------------ // + +class CMCVSelectionPanel : public CObjectControlPanel +{ + DECLARE_CLASS( CMCVSelectionPanel, CObjectControlPanel ); + + +public: + + CMCVSelectionPanel( vgui::Panel *parent, const char *panelName ); + virtual ~CMCVSelectionPanel(); + + virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); + virtual void OnCommand( const char *command ); + + +private: + + CMCVMinimapPanel *m_pMinimapPanel; +}; + + +DECLARE_VGUI_SCREEN_FACTORY( CMCVSelectionPanel, "mcv_selection_panel" ); + + +CMCVSelectionPanel::CMCVSelectionPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, "CMCVSelectionPanel" ) +{ + m_pMinimapPanel = new CMCVMinimapPanel( this, "MinimapPanel" ); + m_pMinimapPanel->SetZPos( 10 ); + m_pMinimapPanel->Init( NULL ); +} + + +CMCVSelectionPanel::~CMCVSelectionPanel() +{ + delete m_pMinimapPanel; +} + + +bool CMCVSelectionPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ) +{ + if ( !BaseClass::Init( pKeyValues, pInitData ) ) + return false; + + m_pMinimapPanel->LevelInit( engine->GetLevelName() ); + m_pMinimapPanel->SetVisible( true ); + + return true; +} + + +void CMCVSelectionPanel::OnCommand( const char *command ) +{ + BaseClass::OnCommand( command ); +} + + + diff --git a/game/client/tf2/c_obj_mortar.cpp b/game/client/tf2/c_obj_mortar.cpp new file mode 100644 index 0000000..ea4e79b --- /dev/null +++ b/game/client/tf2/c_obj_mortar.cpp @@ -0,0 +1,389 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client version of CObjectMortar +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "CommanderOverlay.h" +#include "c_baseobject.h" +#include "tf_shareddefs.h" +#include "c_basetfplayer.h" +#include "ObjectControlPanel.h" +#include <vgui_controls/Label.h> +#include <vgui_controls/Button.h> +#include "vgui_rotation_slider.h" +#include <vgui/ISurface.h> +#include "vgui_basepanel.h" +#include "vgui_bitmapimage.h" +#include "iusesmortarpanel.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_ObjectMortar : public C_BaseObject, public IUsesMortarPanel +{ + DECLARE_CLASS( C_ObjectMortar, C_BaseObject ); +public: + DECLARE_CLIENTCLASS(); + DECLARE_ENTITY_PANEL(); + + C_ObjectMortar(); + + virtual void SetDormant( bool bDormant ); + virtual void Select( void ); + virtual void RecalculateIDString( void ); + + void FireMortar( void ); + +// IUsesMortarPanel +public: + // Get the data from this mortar needed by the panel + virtual void GetMortarData( float *flClientMortarYaw, bool *bAllowedToFire, float *flPower, float *flFiringPower, float *flFiringAccuracy, int *iFiringState ); + virtual void SendYawCommand( void ); + virtual void ForceClientYawCountdown( float flTime ); + virtual void ClickFire( void ); + +public: + int m_iRoundType; + int m_iMortarRounds[ MA_LASTAMMOTYPE ]; + + // Mortar firing info. + int m_iFiringState; // One of the MORTAR_ defines. + bool m_bMortarReloading; + float m_flPower; + bool m_bAllowedToFire; + + // Parameters for the next shot. + float m_flFiringPower; + float m_flFiringAccuracy; + + float m_flMortarYaw; // What direction the mortar is aimed in. + float m_flMortarPitch; + + // This is what is used on the client to draw the ground line and orient the mortar. + // It is usually copied right over from m_flClientMortarYaw (which comes from the server), + // but this is also used when rotating the mortar so you can see the line move smoothly. + float m_flClientMortarYaw; + + // This is set to about 1/4 seconds when you rotate the mortar line so you use the client's + // (smooth, non-lagged) yaw changes instead of the server's. + float m_flForceClientYawCountdown; + +private: + C_ObjectMortar( const C_ObjectMortar & ); // not defined, not accessible +}; + +IMPLEMENT_CLIENTCLASS_DT(C_ObjectMortar, DT_ObjectMortar, CObjectMortar) + RecvPropInt( RECVINFO(m_iRoundType) ), + RecvPropArray( RecvPropInt( RECVINFO(m_iMortarRounds[0]) ), m_iMortarRounds ) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ObjectMortar::C_ObjectMortar( void ) +{ + memset( m_iMortarRounds, 0, sizeof( m_iMortarRounds ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ObjectMortar::SetDormant( bool bDormant ) +{ + BaseClass::SetDormant( bDormant ); + ENTITY_PANEL_ACTIVATE( "mortar", !bDormant ); +} + +//----------------------------------------------------------------------------- +// Purpose: Cycle ammo types on the mortar +//----------------------------------------------------------------------------- +void C_ObjectMortar::Select( void ) +{ + C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + if ( pPlayer == NULL ) + return; + + int iOldType = m_iRoundType++; + + // Cycle to the next ammo type + while ( m_iRoundType != iOldType ) + { + // Hit the end of the round types? + if ( m_iRoundType == MA_LASTAMMOTYPE ) + { + m_iRoundType = MA_SHELL; + break; + } + + // Does this round type need a technology? + if ( MortarAmmoTechs[ m_iRoundType ] && MortarAmmoTechs[ m_iRoundType ][0] ) + { + // Does the player have the technology? + if ( pPlayer->HasNamedTechnology( MortarAmmoTechs[ m_iRoundType ] ) ) + { + // Do we have ammo? + if ( m_iMortarRounds[ m_iRoundType ] > 0 ) + break; + } + } + + // Go to the next round type + m_iRoundType++; + } + + engine->ClientCmd( VarArgs("mortarround %d", m_iRoundType) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ObjectMortar::RecalculateIDString( void ) +{ + // Only owners get full data + if ( IsOwnedByLocalPlayer() ) + { + if ( m_iRoundType >= 0 ) + { + // -1 means we have infinite rounds of this type + if ( m_iMortarRounds[ m_iRoundType ] == -1 ) + { + Q_snprintf( m_szIDString, sizeof(m_szIDString), "%s - %s", GetTargetDescription(), MortarAmmoNames[ m_iRoundType ] ); + } + else + { + Q_snprintf( m_szIDString, sizeof(m_szIDString), "%s - %d %s", GetTargetDescription(), m_iMortarRounds[ m_iRoundType ], MortarAmmoNames[ m_iRoundType ] ); + } + Q_strncat( m_szIDString, "\nUse it to change ammo types.", sizeof(m_szIDString), COPY_ALL_CHARACTERS ); + } + } + + BaseClass::RecalculateIDString(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ObjectMortar::ClickFire( void ) +{ + switch( m_iFiringState ) + { + case MORTAR_IDLE: + m_iFiringState = MORTAR_CHARGING_POWER; + break; + + case MORTAR_CHARGING_POWER: + m_flFiringPower = m_flPower; + m_iFiringState = MORTAR_CHARGING_ACCURACY; + break; + + case MORTAR_CHARGING_ACCURACY: + m_flFiringAccuracy = m_flPower; + m_iFiringState = MORTAR_IDLE; + + FireMortar(); + break; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ObjectMortar::GetMortarData( float *flClientMortarYaw, bool *bAllowedToFire, float *flPower, float *flFiringPower, float *flFiringAccuracy, int *iFiringState ) +{ + *flClientMortarYaw = m_flClientMortarYaw; + *bAllowedToFire = m_bAllowedToFire; + *flPower = m_flPower; + *flFiringPower = m_flFiringPower; + *flFiringAccuracy = m_flFiringAccuracy; + *iFiringState = m_iFiringState; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ObjectMortar::SendYawCommand( void ) +{ + char szbuf[48]; + Q_snprintf( szbuf, sizeof( szbuf ), "MortarYaw %0.2f\n", m_flClientMortarYaw ); + SendClientCommand( szbuf ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ObjectMortar::ForceClientYawCountdown( float flTime ) +{ + m_flForceClientYawCountdown = flTime; +} + + +//----------------------------------------------------------------------------- +// Control screen +//----------------------------------------------------------------------------- +class CMortarControlPanel : public CObjectControlPanel +{ + DECLARE_CLASS( CMortarControlPanel, CObjectControlPanel ); +public: + CMortarControlPanel( vgui::Panel *parent, const char *panelName ); + virtual ~CMortarControlPanel(); + + virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); + virtual void OnCommand( const char *command ); + C_ObjectMortar* GetMortar() const; + +protected: + virtual vgui::Panel* TickCurrentPanel(); + +private: + CMortarMinimapPanel *m_pMinimapPanel; +}; + + +DECLARE_VGUI_SCREEN_FACTORY( CMortarControlPanel, "mortar_control_panel" ); + + +//----------------------------------------------------------------------------- +// Constructor: +//----------------------------------------------------------------------------- +CMortarControlPanel::CMortarControlPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, "CMortarControlPanel" ) +{ + m_pMinimapPanel = new CMortarMinimapPanel( this, "MinimapPanel" ); + m_pMinimapPanel->Init( NULL ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CMortarControlPanel::~CMortarControlPanel() +{ + delete m_pMinimapPanel; +} + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- +bool CMortarControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ) +{ + // Make sure all named panels are created up above because BaseClass::Init initializes them + // all from their keyvalues. + if ( !BaseClass::Init( pKeyValues, pInitData ) ) + return false; + + // Init subpanels. + int x, y, w, h; + GetBounds( x, y, w, h ); + + m_pMinimapPanel->LevelInit( engine->GetLevelName() ); + m_pMinimapPanel->SetVisible( true ); + m_pMinimapPanel->InitMortarMinimap( GetMortar() ); + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ObjectMortar* CMortarControlPanel::GetMortar() const +{ + return dynamic_cast< C_ObjectMortar* >( GetOwningObject() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ObjectMortar::FireMortar( void ) +{ + char cmd[512]; + Q_snprintf( cmd, sizeof( cmd ), "FireMortar %.2f %.2f", m_flFiringPower, m_flFiringAccuracy ); + SendClientCommand( cmd ); +} + +//----------------------------------------------------------------------------- +// Frame-based update +//----------------------------------------------------------------------------- +vgui::Panel* CMortarControlPanel::TickCurrentPanel() +{ + C_BaseObject *pObj = GetOwningObject(); + if (!pObj) + return BaseClass::TickCurrentPanel();; + + ShowOwnerLabel( true ); + ShowHealthLabel( true ); + + C_ObjectMortar *pMortar = GetMortar(); + if ( !pMortar ) + return BaseClass::TickCurrentPanel();; + + ShowOwnerLabel( false ); + ShowHealthLabel( false ); + + m_pMinimapPanel->Repaint(); + + float flAccuracySpeed = (1.0 / MORTAR_CHARGE_ACCURACY_RATE); + + // Handle power charging + switch( pMortar->m_iFiringState ) + { + case MORTAR_IDLE: + pMortar->m_flPower = 0; + break; + + case MORTAR_CHARGING_POWER: + pMortar->m_flPower = MIN( pMortar->m_flPower + ( (1.0 / MORTAR_CHARGE_POWER_RATE) * gpGlobals->frametime), 1 ); + pMortar->m_flFiringPower = 0; + pMortar->m_flFiringAccuracy = 0; + if ( pMortar->m_flPower >= 1.0 ) + { + // Hit Max, start going down + pMortar->m_flFiringPower = pMortar->m_flPower; + pMortar->m_iFiringState = MORTAR_CHARGING_ACCURACY; + } + break; + + case MORTAR_CHARGING_ACCURACY: + // Calculate accuracy speed + if ( pMortar->m_flFiringPower > 0.5 ) + { + // Shots over halfway suffer an increased speed to the accuracy power, making accurate shots harder + float flAdjustedPower = (pMortar->m_flFiringPower - 0.5) * 3.0; + flAccuracySpeed += (pMortar->m_flFiringPower * flAdjustedPower); + } + + pMortar->m_flPower = MAX( pMortar->m_flPower - ( flAccuracySpeed * gpGlobals->frametime), -0.25f); + if ( pMortar->m_flPower <= -0.25 ) + { + // Hit Min, fire mortar + pMortar->m_flFiringAccuracy = pMortar->m_flPower; + pMortar->m_iFiringState = MORTAR_IDLE; + + pMortar->FireMortar(); + } + break; + + default: + break; + } + + return BaseClass::TickCurrentPanel(); +} + +//----------------------------------------------------------------------------- +// Button click handlers +//----------------------------------------------------------------------------- +void CMortarControlPanel::OnCommand( const char *command ) +{ + C_ObjectMortar *pMortar = GetMortar(); + if ( !pMortar ) + return; + + if ( !Q_stricmp( command, "FireMortar" ) ) + { + pMortar->ClickFire(); + } + + BaseClass::OnCommand(command); +} + diff --git a/game/client/tf2/c_obj_powerpack.cpp b/game/client/tf2/c_obj_powerpack.cpp new file mode 100644 index 0000000..edbfcfd --- /dev/null +++ b/game/client/tf2/c_obj_powerpack.cpp @@ -0,0 +1,340 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_baseobject.h" +#include "ObjectControlPanel.h" +#include "tf_shareddefs.h" +#include "tempent.h" +#include "c_te_legacytempents.h" +#include "iviewrender_beams.h" +#include "beamdraw.h" +#include "view.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define NUM_POWERPACK_GLOWS 6 + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_ObjectPowerPack : public C_BaseObject +{ + DECLARE_CLASS( C_ObjectPowerPack, C_BaseObject ); +public: + DECLARE_CLIENTCLASS(); + + C_ObjectPowerPack(); + ~C_ObjectPowerPack(); + int SocketsLeft() const { return (MAX_OBJECTS_PER_PACK - m_iObjectsAttached); } + + // Since we have material proxies to show building amount, don't offset origin + virtual bool OffsetObjectOrigin( Vector& origin ) + { + return false; + } + + virtual void OnGoActive( void ); + virtual void OnGoInactive( void ); + void RemoveGlows( void ); + virtual void ClientThink( void ); + virtual int DrawModel( int flags ); + +private: + int m_iObjectsAttached; + int m_iGlowModelIndex; + C_LocalTempEntity *m_pGlowSprites[ NUM_POWERPACK_GLOWS ]; + + // Jacob's laddder + Beam_t *m_pJacobsLadderBeam; + float m_flJacobsLeftPoint; + float m_flJacobsRightPoint; + Vector m_vecJacobsStart; + Vector m_vecJacobsEnd; + CMaterialReference m_hJacobsPointMaterial; + +private: + C_ObjectPowerPack( const C_ObjectPowerPack & ); // not defined, not accessible +}; + +IMPLEMENT_CLIENTCLASS_DT(C_ObjectPowerPack, DT_ObjectPowerPack, CObjectPowerPack) + RecvPropInt( RECVINFO(m_iObjectsAttached) ), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ObjectPowerPack::C_ObjectPowerPack() +{ + for ( int i = 0; i < NUM_POWERPACK_GLOWS; i++ ) + { + m_pGlowSprites[i] = NULL; + } + + m_iGlowModelIndex = PrecacheModel( "effects/human_object_glow.vmt" ); + m_pJacobsLadderBeam = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ObjectPowerPack::~C_ObjectPowerPack( void ) +{ + RemoveGlows(); +} + +//----------------------------------------------------------------------------- +// Purpose: We've just gone active +//----------------------------------------------------------------------------- +void C_ObjectPowerPack::OnGoActive( void ) +{ + // Turn on our glows + for ( int i = 0; i < NUM_POWERPACK_GLOWS; i++ ) + { + // Find the attachment point + int iAttachment = LookupAttachment( VarArgs("glow_%d",(i+1)) ); + Vector vecOrigin; + QAngle vecAngles; + if ( GetAttachment( iAttachment, vecOrigin, vecAngles ) ) + { + Vector vecForward; + AngleVectors( vecAngles, &vecForward ); + m_pGlowSprites[i] = tempents->TempSprite( vecOrigin, vec3_origin, 0.35, m_iGlowModelIndex, kRenderTransAdd, 0, 0.5, 1, FTENT_PERSIST | FTENT_NEVERDIE | FTENT_BEOCCLUDED, vecForward ); + } + } + + m_flJacobsLeftPoint = 0; + m_flJacobsRightPoint = 0; + m_hJacobsPointMaterial.Init( "sprites/blueflare2", TEXTURE_GROUP_CLIENT_EFFECTS ); +} + +//----------------------------------------------------------------------------- +// Purpose: We've just gone inactive +//----------------------------------------------------------------------------- +void C_ObjectPowerPack::OnGoInactive( void ) +{ + // Turn off our glows + RemoveGlows(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ObjectPowerPack::RemoveGlows( void ) +{ + for ( int i = 0; i < NUM_POWERPACK_GLOWS; i++ ) + { + if ( m_pGlowSprites[i] ) + { + m_pGlowSprites[i]->die = 0; + m_pGlowSprites[i] = NULL; + } + } + + // Stop the jacob's ladder + if ( m_pJacobsLadderBeam ) + { + m_pJacobsLadderBeam->flags &= ~FBEAM_FOREVER; + m_pJacobsLadderBeam->die = gpGlobals->curtime; + m_pJacobsLadderBeam = NULL; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ObjectPowerPack::ClientThink( void ) +{ + // Create the jacob's ladder + if ( !m_pJacobsLadderBeam ) + { + BeamInfo_t beamInfo; + beamInfo.m_vecStart.Init(); + beamInfo.m_vecEnd.Init(); + beamInfo.m_pszModelName = "sprites/physbeam.vmt"; + beamInfo.m_flHaloScale = 0.0f; + beamInfo.m_flLife = 0.0f; + beamInfo.m_flWidth = 8.0f; + beamInfo.m_flEndWidth = 4.0f; + beamInfo.m_flFadeLength = 0.0f; + beamInfo.m_flAmplitude = 20.0f; + beamInfo.m_flBrightness = 255.0f; + beamInfo.m_flSpeed = 0.0f; + beamInfo.m_nStartFrame = 0; + beamInfo.m_flFrameRate = 0.0f; + beamInfo.m_flRed = 206.0f; + beamInfo.m_flGreen = 181.0f; + beamInfo.m_flBlue = 127.0f; + beamInfo.m_nSegments = 5; + beamInfo.m_bRenderable = true; + m_pJacobsLadderBeam = beams->CreateBeamPoints( beamInfo ); + } + + // Update the position of the jacob's ladder + BeamInfo_t beamInfo; + QAngle vecAngle; + int iAttachment; + + // Setup a color reflecting the amount of power being used + color32 color; + color.r = 206; + color.g = 182; + color.b = 127; + color.a = 255; + + // Tesla Effect + Vector vecRightTop, vecRightBottom; + Vector vecLeftTop, vecLeftBottom; + iAttachment = LookupAttachment( "Tesla_ll" ); + GetAttachment( iAttachment, vecLeftBottom, vecAngle ); + iAttachment = LookupAttachment( "Tesla_ul" ); + GetAttachment( iAttachment, vecLeftTop, vecAngle ); + iAttachment = LookupAttachment( "Tesla_lr" ); + GetAttachment( iAttachment, vecRightBottom, vecAngle ); + iAttachment = LookupAttachment( "Tesla_ur" ); + GetAttachment( iAttachment, vecRightTop, vecAngle ); + + float flSpeed = 0.02; + + m_flJacobsLeftPoint += random->RandomFloat( flSpeed * 0.25, flSpeed * 2); + m_flJacobsRightPoint += random->RandomFloat( flSpeed * 0.25, flSpeed * 2); + + // If they've both hit the end, break the ladder + if ( m_flJacobsLeftPoint >= 1.0f && m_flJacobsRightPoint >= 1.0f ) + { + // Snap! + m_flJacobsLeftPoint = 0.0f; + m_flJacobsRightPoint = 0.0f; + } + else if ( m_flJacobsLeftPoint > 1.0f ) + { + // Only the left point's made it + m_flJacobsLeftPoint = 1.0f; + } + else if ( m_flJacobsRightPoint > 1.0f ) + { + // Only the right point's made it + m_flJacobsRightPoint = 1.0f; + } + + Vector vecLeft = vecLeftTop - vecLeftBottom; + Vector vecRight = vecRightTop - vecRightBottom; + m_vecJacobsStart = vecLeftBottom + ( m_flJacobsLeftPoint * vecLeft ); + m_vecJacobsEnd = vecRightBottom + ( m_flJacobsRightPoint * vecRight ); + + beamInfo.m_vecStart = m_vecJacobsStart; + beamInfo.m_vecEnd = m_vecJacobsEnd; + beamInfo.m_flRed = color.r; + beamInfo.m_flGreen = color.g; + beamInfo.m_flBlue = color.b; + beams->UpdateBeamInfo( m_pJacobsLadderBeam, beamInfo ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int C_ObjectPowerPack::DrawModel( int flags ) +{ + if ( BaseClass::DrawModel( flags ) ) + { + if ( ShouldBeActive() ) + { + // Get the distance to the view + float flDistance = (GetAbsOrigin() - MainViewOrigin()).LengthSqr(); + if ( flDistance < (1024 * 1024) ) + { + // Draw a sprite at the tips. + color32 color; + color.r = 255; + color.g = 255; + color.b = 255; + color.a = 255; + float flSize = 25.0f; + materials->Bind( m_hJacobsPointMaterial, this ); + DrawSprite( m_vecJacobsStart, flSize, flSize, color ); + DrawSprite( m_vecJacobsEnd, flSize, flSize, color ); + } + } + + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +// Control screen +//----------------------------------------------------------------------------- +class CPowerPackControlPanel : public CObjectControlPanel +{ + DECLARE_CLASS( CPowerPackControlPanel, CObjectControlPanel ); + +public: + CPowerPackControlPanel( vgui::Panel *parent, const char *panelName ); + virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); + virtual void OnTick(); + +private: + vgui::Label *m_pSocketsLabel; +}; + + +DECLARE_VGUI_SCREEN_FACTORY( CPowerPackControlPanel, "powerpack_control_panel" ); + + +//----------------------------------------------------------------------------- +// Constructor: +//----------------------------------------------------------------------------- +CPowerPackControlPanel::CPowerPackControlPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, "CPowerPackControlPanel" ) +{ +} + + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- +bool CPowerPackControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ) +{ + m_pSocketsLabel = new vgui::Label( GetActivePanel(), "SocketReadout", "" ); + + if (!BaseClass::Init(pKeyValues, pInitData)) + return false; + + return true; +} + + +//----------------------------------------------------------------------------- +// Frame-based update +//----------------------------------------------------------------------------- +void CPowerPackControlPanel::OnTick() +{ + BaseClass::OnTick(); + + C_BaseObject *pObj = GetOwningObject(); + if (!pObj) + return; + + Assert( dynamic_cast<C_ObjectPowerPack*>(pObj) ); + C_ObjectPowerPack *pPowerPack = static_cast<C_ObjectPowerPack*>(pObj); + + char buf[256]; + int nSocketsLeft = pPowerPack->SocketsLeft(); + if (nSocketsLeft > 0) + { + Q_snprintf( buf, sizeof( buf ), "%d sockets left", pPowerPack->SocketsLeft() ); + } + else + { + Q_strncpy( buf, "No sockets left", sizeof( buf ) ); + } + + m_pSocketsLabel->SetText( buf ); +} + + diff --git a/game/client/tf2/c_obj_rallyflag.cpp b/game/client/tf2/c_obj_rallyflag.cpp new file mode 100644 index 0000000..76a1ee5 --- /dev/null +++ b/game/client/tf2/c_obj_rallyflag.cpp @@ -0,0 +1,35 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "c_baseobject.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_ObjectRallyFlag : public C_BaseObject +{ + DECLARE_CLASS( C_ObjectRallyFlag, C_BaseObject ); +public: + DECLARE_CLIENTCLASS(); + + C_ObjectRallyFlag(); + +private: + C_ObjectRallyFlag( const C_ObjectRallyFlag & ); // not defined, not accessible +}; + +IMPLEMENT_CLIENTCLASS_DT(C_ObjectRallyFlag, DT_ObjectRallyFlag, CObjectRallyFlag) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ObjectRallyFlag::C_ObjectRallyFlag() +{ +} + diff --git a/game/client/tf2/c_obj_resourcepump.cpp b/game/client/tf2/c_obj_resourcepump.cpp new file mode 100644 index 0000000..13858ce --- /dev/null +++ b/game/client/tf2/c_obj_resourcepump.cpp @@ -0,0 +1,164 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "c_obj_resourcepump.h" +#include "commanderoverlay.h" +#include "vgui_healthbar.h" +#include "ObjectControlPanel.h" +#include "tf_shareddefs.h" +#include "vgui_bitmapbutton.h" +#include "C_Func_Resource.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +BEGIN_RECV_TABLE_NOBASE( C_ObjectResourcePump, DT_ResourcePumpTeamOnlyVars ) + RecvPropInt( RECVINFO(m_iPumpLevel) ), + RecvPropEHandle( RECVINFO(m_hResourceZone) ), +END_RECV_TABLE() + + +IMPLEMENT_CLIENTCLASS_DT(C_ObjectResourcePump, DT_ResourcePump, CObjectResourcePump) + RecvPropDataTable( "teamonly", 0, 0, &REFERENCE_RECV_TABLE( DT_ResourcePumpTeamOnlyVars ) ) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ObjectResourcePump::C_ObjectResourcePump() +{ + m_iPumpLevel = 1; + m_pResourceBar = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ObjectResourcePump::SetDormant( bool bDormant ) +{ + BaseClass::SetDormant( bDormant ); + ENTITY_PANEL_ACTIVATE( "resource_pump", !bDormant ); +} + + +//----------------------------------------------------------------------------- +// Control screen +//----------------------------------------------------------------------------- +class CResourcePumpControlPanel : public CObjectControlPanel +{ + DECLARE_CLASS( CResourcePumpControlPanel, CObjectControlPanel ); + +public: + CResourcePumpControlPanel( vgui::Panel *parent, const char *panelName ); + virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); + virtual void OnTick(); + virtual void OnCommand( const char *command ); + + void Upgrade( void ); + +private: + vgui::Button *m_pUpgradeButton; + vgui::Label *m_pResourcesLabel; +}; + + +DECLARE_VGUI_SCREEN_FACTORY( CResourcePumpControlPanel, "resourcepump_control_panel" ); + + +//----------------------------------------------------------------------------- +// Constructor: +//----------------------------------------------------------------------------- +CResourcePumpControlPanel::CResourcePumpControlPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, "CResourcePumpControlPanel" ) +{ +} + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- +bool CResourcePumpControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ) +{ + m_pUpgradeButton = new CBitmapButton( this, "UpgradeButton", "Upgrade" ); + m_pResourcesLabel = new vgui::Label( this, "ResourcesLabel", "Resources: 0" ); + + if (!BaseClass::Init(pKeyValues, pInitData)) + return false; + + // ROBIN: Removed upgrading for now + m_pUpgradeButton->SetVisible( false ); + + return true; +} + + +//----------------------------------------------------------------------------- +// Frame-based update +//----------------------------------------------------------------------------- +void CResourcePumpControlPanel::OnTick() +{ + BaseClass::OnTick(); + + C_BaseObject *pObj = GetOwningObject(); + if (!pObj) + return; + + Assert( dynamic_cast<C_ObjectResourcePump*>(pObj) ); + C_ObjectResourcePump *pPump = static_cast<C_ObjectResourcePump*>(pObj); + + char buf[256]; + int iPumpLevel = pPump->GetLevel(); + int iCost = CalculateObjectUpgrade( OBJ_RESOURCEPUMP, iPumpLevel ); + if ( iCost ) + { + Q_snprintf( buf, sizeof( buf ), "Upgrade to Level %d\nCost: %d", iPumpLevel+1, iCost ); + } + else + { + Q_snprintf( buf, sizeof( buf ), "Level %d", iPumpLevel ); + } + + m_pUpgradeButton->SetText( buf ); + + C_ResourceZone *pResourceZone = pPump->GetResourceZone(); + if (pResourceZone) + { + Q_snprintf( buf, sizeof( buf ), "Resources: %d", pResourceZone->m_nResourcesLeft ); + m_pResourcesLabel->SetText( buf ); + } + else + { + m_pResourcesLabel->SetText( "Resources: 0" ); + } +} + +//----------------------------------------------------------------------------- +// Dismantles the object +//----------------------------------------------------------------------------- +void CResourcePumpControlPanel::Upgrade( void ) +{ + C_BaseObject *pObj = GetOwningObject(); + if (pObj) + { + pObj->SendClientCommand( "upgrade" ); + } +} + +//----------------------------------------------------------------------------- +// Button click handlers +//----------------------------------------------------------------------------- +void CResourcePumpControlPanel::OnCommand( const char *command ) +{ + if (!Q_strnicmp(command, "Upgrade", 7)) + { + Upgrade(); + return; + } + + BaseClass::OnCommand(command); +} + diff --git a/game/client/tf2/c_obj_resourcepump.h b/game/client/tf2/c_obj_resourcepump.h new file mode 100644 index 0000000..3cab0e9 --- /dev/null +++ b/game/client/tf2/c_obj_resourcepump.h @@ -0,0 +1,44 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_OBJ_RESOURCEPUMP_H +#define C_OBJ_RESOURCEPUMP_H +#ifdef _WIN32 +#pragma once +#endif + +#include "CommanderOverlay.h" +#include "c_baseobject.h" + +class C_ResourceZone; + +class C_ObjectResourcePump : public C_BaseObject +{ + DECLARE_CLASS( C_ObjectResourcePump, C_BaseObject ); +public: + DECLARE_CLIENTCLASS(); + DECLARE_ENTITY_PANEL(); + + C_ObjectResourcePump(); + + virtual void SetDormant( bool bDormant ); + int GetLevel( void ) { return m_iPumpLevel; } + + C_ResourceZone* GetResourceZone() { return m_hResourceZone.Get(); } + +private: + CHealthBarPanel *m_pResourceBar; + int m_iPumpLevel; + CHandle<C_ResourceZone> m_hResourceZone; + +private: + C_ObjectResourcePump( const C_ObjectResourcePump & ); // not defined, not accessible +}; + + + +#endif // C_OBJ_RESOURCEPUMP_H diff --git a/game/client/tf2/c_obj_respawn_station.cpp b/game/client/tf2/c_obj_respawn_station.cpp new file mode 100644 index 0000000..65af05f --- /dev/null +++ b/game/client/tf2/c_obj_respawn_station.cpp @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client's CObjectSentrygun +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "CommanderOverlay.h" +#include "c_baseobject.h" +#include "vgui_healthbar.h" +#include "c_obj_respawn_station.h" +#include "C_BaseTFPlayer.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +IMPLEMENT_CLIENTCLASS_DT(C_ObjectRespawnStation, DT_ObjectRespawnStation, CObjectRespawnStation) +END_RECV_TABLE() + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ObjectRespawnStation::C_ObjectRespawnStation( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ObjectRespawnStation::SetDormant( bool bDormant ) +{ + BaseClass::SetDormant( bDormant ); + ENTITY_PANEL_ACTIVATE( "respawn_station", !bDormant ); +} + diff --git a/game/client/tf2/c_obj_respawn_station.h b/game/client/tf2/c_obj_respawn_station.h new file mode 100644 index 0000000..8b766f1 --- /dev/null +++ b/game/client/tf2/c_obj_respawn_station.h @@ -0,0 +1,39 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_OBJ_RESPAWN_STATION_H +#define C_OBJ_RESPAWN_STATION_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Purpose: Respawn Station object +//----------------------------------------------------------------------------- +class C_ObjectRespawnStation : public C_BaseObject +{ + DECLARE_CLASS( C_ObjectRespawnStation, C_BaseObject ); + +public: + DECLARE_CLIENTCLASS(); + DECLARE_ENTITY_PANEL(); + + C_ObjectRespawnStation(); + + // Status + virtual void SetDormant( bool bDormant ); + +protected: + // A special panel to indicate which one's the respawn station + CPanelRegistration m_SelectedRespawnPanel; + +private: + C_ObjectRespawnStation( const C_ObjectRespawnStation & ); // not defined, not accessible +}; + + +#endif // C_OBJ_RESPAWN_STATION_H diff --git a/game/client/tf2/c_obj_resupply.cpp b/game/client/tf2/c_obj_resupply.cpp new file mode 100644 index 0000000..c0134dd --- /dev/null +++ b/game/client/tf2/c_obj_resupply.cpp @@ -0,0 +1,151 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client's CObjectSentrygun +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_baseobject.h" +#include "c_basetfplayer.h" +#include "ObjectControlPanel.h" +#include "vgui_bitmapbutton.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +//----------------------------------------------------------------------------- +// Purpose: Resupply Station object +//----------------------------------------------------------------------------- +class C_ObjectResupply : public C_BaseObject +{ + DECLARE_CLASS( C_ObjectResupply, C_BaseObject ); +public: + DECLARE_CLIENTCLASS(); + + C_ObjectResupply(); + +private: + C_ObjectResupply( const C_ObjectResupply & ); // not defined, not accessible +}; + + +IMPLEMENT_CLIENTCLASS_DT(C_ObjectResupply, DT_ObjectResupply, CObjectResupply) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ObjectResupply::C_ObjectResupply() +{ +} + + +//----------------------------------------------------------------------------- +// Control screen +//----------------------------------------------------------------------------- +class CResupplyControlPanel : public CObjectControlPanel +{ + DECLARE_CLASS( CResupplyControlPanel, CObjectControlPanel ); + +public: + CResupplyControlPanel( vgui::Panel *parent, const char *panelName ); + virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); + virtual void OnCommand( const char *command ); + +protected: + virtual void OnTickActive( C_BaseObject *pObj, C_BaseTFPlayer *pLocalPlayer ); + +private: + void Buy( ResupplyBuyType_t type ); + + vgui::Button *m_pBuyAmmoButton; + vgui::Button *m_pBuyGrenadesButton; + vgui::Button *m_pBuyHealthButton; + vgui::Button *m_pBuyAllButton; +}; + + +DECLARE_VGUI_SCREEN_FACTORY( CResupplyControlPanel, "resupply_control_panel" ); + + +//----------------------------------------------------------------------------- +// Constructor: +//----------------------------------------------------------------------------- +CResupplyControlPanel::CResupplyControlPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, "CResupplyControlPanel" ) +{ +} + + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- +bool CResupplyControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ) +{ + // Grab ahold of certain well-known controls + m_pBuyAmmoButton = new CBitmapButton( GetActivePanel(), "BuyAmmoButton", "" ); + m_pBuyGrenadesButton = new CBitmapButton( GetActivePanel(), "BuyGrenadesButton", "" ); + m_pBuyHealthButton = new CBitmapButton( GetActivePanel(), "BuyHealthButton", "" ); + m_pBuyAllButton = new CBitmapButton( GetActivePanel(), "BuyAllButton", "" ); + + return BaseClass::Init( pKeyValues, pInitData ); +} + + +//----------------------------------------------------------------------------- +// Deactivates buttons we can't afford +//----------------------------------------------------------------------------- +void CResupplyControlPanel::OnTickActive( C_BaseObject *pObj, C_BaseTFPlayer *pLocalPlayer ) +{ + BaseClass::OnTickActive( pObj, pLocalPlayer ); + + int nBankResources = pLocalPlayer ? pLocalPlayer->GetBankResources() : 0; + m_pBuyAmmoButton->SetEnabled( nBankResources >= RESUPPLY_AMMO_COST ); + m_pBuyGrenadesButton->SetEnabled( nBankResources >= RESUPPLY_GRENADES_COST ); + m_pBuyHealthButton->SetEnabled( nBankResources >= RESUPPLY_HEALTH_COST ); + m_pBuyAllButton->SetEnabled( nBankResources >= RESUPPLY_ALL_COST ); +} + + +//----------------------------------------------------------------------------- +// Buys stuff +//----------------------------------------------------------------------------- +void CResupplyControlPanel::Buy( ResupplyBuyType_t type ) +{ + C_BaseObject *pObj = GetOwningObject(); + if (pObj) + { + char szbuf[48]; + Q_snprintf( szbuf, sizeof( szbuf ), "buy %d", type ); + pObj->SendClientCommand( szbuf ); + } +} + + +//----------------------------------------------------------------------------- +// Button click handlers +//----------------------------------------------------------------------------- +void CResupplyControlPanel::OnCommand( const char *command ) +{ + if (!Q_strnicmp(command, "BuyAmmo", 8)) + { + Buy(RESUPPLY_BUY_AMMO); + } + else if (!Q_strnicmp(command, "BuyHealth", 10)) + { + Buy(RESUPPLY_BUY_HEALTH); + } + else if (!Q_strnicmp(command, "BuyGrenades", 12)) + { + Buy(RESUPPLY_BUY_GRENADES); + } + else if (!Q_strnicmp(command, "BuyAll", 7)) + { + Buy(RESUPPLY_BUY_ALL); + } + else + { + BaseClass::OnCommand(command); + } +} diff --git a/game/client/tf2/c_obj_sandbag_bunker.cpp b/game/client/tf2/c_obj_sandbag_bunker.cpp new file mode 100644 index 0000000..4ae7a92 --- /dev/null +++ b/game/client/tf2/c_obj_sandbag_bunker.cpp @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "hud.h" +#include "commanderoverlay.h" +#include "c_baseobject.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_ObjectSandbagBunker : public C_BaseObject +{ + DECLARE_CLASS( C_ObjectSandbagBunker, C_BaseObject ); +public: + DECLARE_CLIENTCLASS(); + + C_ObjectSandbagBunker(); + +private: + C_ObjectSandbagBunker( const C_ObjectSandbagBunker & ); // not defined, not accessible +}; + +IMPLEMENT_CLIENTCLASS_DT(C_ObjectSandbagBunker, DT_ObjectSandbagBunker, CObjectSandbagBunker) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ObjectSandbagBunker::C_ObjectSandbagBunker() +{ +} diff --git a/game/client/tf2/c_obj_selfheal.cpp b/game/client/tf2/c_obj_selfheal.cpp new file mode 100644 index 0000000..5fec4e9 --- /dev/null +++ b/game/client/tf2/c_obj_selfheal.cpp @@ -0,0 +1,36 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "hud.h" +#include "commanderoverlay.h" +#include "tf_obj_baseupgrade_shared.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_ObjectSelfHeal : public C_BaseObjectUpgrade +{ + DECLARE_CLASS( C_ObjectSelfHeal, C_BaseObjectUpgrade ); +public: + DECLARE_CLIENTCLASS(); + + C_ObjectSelfHeal(); + +private: + C_ObjectSelfHeal( const C_ObjectSelfHeal & ); // not defined, not accessible +}; + +IMPLEMENT_CLIENTCLASS_DT(C_ObjectSelfHeal, DT_ObjectSelfHeal, CObjectSelfHeal) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ObjectSelfHeal::C_ObjectSelfHeal() +{ +} + diff --git a/game/client/tf2/c_obj_sentrygun.h b/game/client/tf2/c_obj_sentrygun.h new file mode 100644 index 0000000..c66fd81 --- /dev/null +++ b/game/client/tf2/c_obj_sentrygun.h @@ -0,0 +1,106 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_OBJ_SENTRYGUN_H +#define C_OBJ_SENTRYGUN_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Purpose: Base Sentrygun +//----------------------------------------------------------------------------- +class C_ObjectSentrygun : public C_BaseObject +{ + DECLARE_CLASS( C_ObjectSentrygun, C_BaseObject ); +public: + DECLARE_CLIENTCLASS(); + DECLARE_ENTITY_PANEL(); + + C_ObjectSentrygun(); + virtual void GetBoneControllers(float controllers[MAXSTUDIOBONES]); + virtual int DrawModel( int flags ); + virtual void SetDormant( bool bDormant ); + virtual void PreDataUpdate( DataUpdateType_t updateType ); + virtual void PostDataUpdate( DataUpdateType_t updateType ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual float GetInitialBuilderYaw(); + int GetAmmoLeft( void ) { return m_iAmmo; } + virtual void FinishedBuilding( void ); + + virtual void ClientThink( void ); + +private: + bool IsTurtled( void ) { return m_bTurtled; } + + // Turret Functions + bool MoveTurret( void ); + + // Recompute sentrygun orientation... + void RecomputeOrientation(); + +public: + + int m_iRightBound; + int m_iLeftBound; + bool m_bTurningRight; + + // Movement + int m_iBaseTurnRate; + float m_fTurnRate; + QAngle m_vecCurAngles; + QAngle m_vecGoalAngles; + Vector m_vecCurDishAngles; + + float m_fBoneXRotator; + float m_fBoneYRotator; + int m_iAmmo; + + // Turtling + bool m_bTurtled; + bool m_bLastTurtled; + float m_flStartedTurtlingAt; + float m_flStartedUnTurtlingAt; + + int m_nAnimationParity; + int m_nLastAnimationParity; + + // Networked from server + EHANDLE m_hEnemy; + + + QAngle m_angPrevLocalAngles; + int m_nOrientationParity; + int m_nPrevOrientationParity; + +private: + C_ObjectSentrygun( const C_ObjectSentrygun & ); // not defined, not accessible +}; + +class C_ObjectSentrygunPlasma : public C_ObjectSentrygun +{ + DECLARE_CLASS( C_ObjectSentrygunPlasma, C_ObjectSentrygun ); +public: + C_ObjectSentrygunPlasma(); + DECLARE_CLIENTCLASS(); + +private: + C_ObjectSentrygunPlasma( const C_ObjectSentrygunPlasma & ); // not defined, not accessible +}; + +class C_ObjectSentrygunRocketlauncher : public C_ObjectSentrygun +{ + DECLARE_CLASS( C_ObjectSentrygunRocketlauncher, C_ObjectSentrygun ); +public: + C_ObjectSentrygunRocketlauncher(); + DECLARE_CLIENTCLASS(); + +private: + C_ObjectSentrygunRocketlauncher( const C_ObjectSentrygunRocketlauncher & ); // not defined, not accessible +}; + +#endif // C_OBJ_SENTRYGUN_H diff --git a/game/client/tf2/c_obj_shieldwall.cpp b/game/client/tf2/c_obj_shieldwall.cpp new file mode 100644 index 0000000..b094502 --- /dev/null +++ b/game/client/tf2/c_obj_shieldwall.cpp @@ -0,0 +1,111 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client's CObjectSentrygun +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "CommanderOverlay.h" +#include "c_baseobject.h" +#include "vgui_healthbar.h" +#include "ObjectControlPanel.h" +#include "c_shield.h" + +//----------------------------------------------------------------------------- +// Purpose: Resupply Station object +//----------------------------------------------------------------------------- +class C_ObjectShieldWallBase : public C_BaseObject +{ + DECLARE_CLASS( C_ObjectShieldWallBase, C_BaseObject ); + +public: + C_ObjectShieldWallBase() {} + +public: + CHandle<C_Shield> m_hDeployedShield; + +private: + C_ObjectShieldWallBase( const C_ObjectShieldWallBase & ); // not defined, not accessible +}; + + +//----------------------------------------------------------------------------- +// +// Projected shield wall +// +//----------------------------------------------------------------------------- +class C_ObjectShieldWall : public C_ObjectShieldWallBase +{ + DECLARE_CLASS( C_ObjectShieldWall, C_ObjectShieldWallBase ); +public: + DECLARE_CLIENTCLASS(); + DECLARE_ENTITY_PANEL(); + + C_ObjectShieldWall( void ); + + virtual void SetDormant( bool bDormant ); + virtual void RecalculateIDString( void ); + +private: + C_ObjectShieldWall( const C_ObjectShieldWall & ); // not defined, not accessible +}; + +IMPLEMENT_CLIENTCLASS_DT(C_ObjectShieldWall, DT_ObjectShieldWall, CObjectShieldWall) + RecvPropEHandle(RECVINFO(m_hDeployedShield)), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ObjectShieldWall::C_ObjectShieldWall( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ObjectShieldWall::SetDormant( bool bDormant ) +{ + BaseClass::SetDormant( bDormant ); + ENTITY_PANEL_ACTIVATE( "shield_wall", !bDormant ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ObjectShieldWall::RecalculateIDString( void ) +{ + if ( m_hDeployedShield ) + { + // Report shield strength + Q_snprintf( m_szIDString, sizeof(m_szIDString), "Shield Strength: %.0f percent", m_hDeployedShield->GetPowerLevel() * 100 ); + } + + BaseClass::RecalculateIDString(); +} + +//----------------------------------------------------------------------------- +// Control screen +//----------------------------------------------------------------------------- +class CShieldWallControlPanel : public CRotatingObjectControlPanel +{ + DECLARE_CLASS( CShieldWallControlPanel, CRotatingObjectControlPanel ); + +public: + CShieldWallControlPanel( vgui::Panel *parent, const char *panelName ); +}; + + +DECLARE_VGUI_SCREEN_FACTORY( CShieldWallControlPanel, "shieldwall_control_panel" ); + + +//----------------------------------------------------------------------------- +// Constructor: +//----------------------------------------------------------------------------- +CShieldWallControlPanel::CShieldWallControlPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, "CShieldWallControlPanel" ) +{ +} + + diff --git a/game/client/tf2/c_obj_tower.cpp b/game/client/tf2/c_obj_tower.cpp new file mode 100644 index 0000000..14a0473 --- /dev/null +++ b/game/client/tf2/c_obj_tower.cpp @@ -0,0 +1,69 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "hud.h" +#include "commanderoverlay.h" +#include "c_baseobject.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_ObjectTower : public C_BaseObject +{ + DECLARE_CLASS( C_ObjectTower, C_BaseObject ); +public: + DECLARE_CLIENTCLASS(); + + C_ObjectTower(); + +private: + C_ObjectTower( const C_ObjectTower & ); // not defined, not accessible +}; + +IMPLEMENT_CLIENTCLASS_DT(C_ObjectTower, DT_ObjectTower, CObjectTower) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ObjectTower::C_ObjectTower() +{ +} + +//============================================================================= +// Tower Ladder +//============================================================================= + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_ObjectTowerLadder : public C_BaseAnimating +{ + DECLARE_CLASS( C_ObjectTowerLadder, C_BaseAnimating ); +public: + + DECLARE_CLIENTCLASS(); + + C_ObjectTowerLadder(); + +private: + C_ObjectTowerLadder( const C_ObjectTowerLadder& ); // not defined, not accessible +}; + +IMPLEMENT_CLIENTCLASS_DT( C_ObjectTowerLadder, DT_ObjectTowerLadder, CObjectTowerLadder ) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ObjectTowerLadder::C_ObjectTowerLadder() +{ +} + diff --git a/game/client/tf2/c_obj_tunnel.cpp b/game/client/tf2/c_obj_tunnel.cpp new file mode 100644 index 0000000..7794571 --- /dev/null +++ b/game/client/tf2/c_obj_tunnel.cpp @@ -0,0 +1,143 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "hud.h" +#include "c_obj_mapdefined.h" +#include "minimap_trace.h" +#include <KeyValues.h> +#include "VGuiMatSurface/IMatSystemSurface.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_ObjectTunnel : public C_ObjectMapDefined +{ + DECLARE_CLASS( C_ObjectTunnel, C_ObjectMapDefined ); +public: + DECLARE_PREDICTABLE(); + DECLARE_CLIENTCLASS(); + + C_ObjectTunnel(); + +private: + C_ObjectTunnel( const C_ObjectTunnel& src ); +}; + +LINK_ENTITY_TO_CLASS( obj_tunnel, C_ObjectTunnel ); +BEGIN_PREDICTION_DATA( C_ObjectTunnel ) +END_PREDICTION_DATA(); + + +IMPLEMENT_CLIENTCLASS_DT(C_ObjectTunnel, DT_ObjectTunnel, CObjectTunnel) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ObjectTunnel::C_ObjectTunnel() +{ + CONSTRUCT_MINIMAP_PANEL( "obj_tunnel", MINIMAP_OBJECTS ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CMinimapObjectTunnelPanel : public CMinimapTraceTeamBitmapPanel +{ + DECLARE_CLASS( CMinimapObjectTunnelPanel, CMinimapTraceTeamBitmapPanel ); + +public: + CMinimapObjectTunnelPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, "CMinimapObjectTunnelPanel" ) + { + } + + virtual bool Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData ); + virtual void Paint(); + +private: + enum + { + STATE_ENABLED = 0, + STATE_DISABLED, + + NUM_STATES + }; + + CTeamBitmapImage m_TeamImage[ NUM_STATES ]; +}; + +//----------------------------------------------------------------------------- +// +// A standard minimap renderable that displays a bitmap that changes when team changes +// +//----------------------------------------------------------------------------- +DECLARE_MINIMAP_FACTORY( CMinimapObjectTunnelPanel, "minimap_obj_tunnel_panel" ); + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pKeyValues - +// pInitData - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CMinimapObjectTunnelPanel::Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData ) +{ + if (!BaseClass::Init(pKeyValues, pInitData)) + return false; + + // Load viewcone material + KeyValues *enabled = pKeyValues->FindKey( "EnabledImage" ); + if ( enabled ) + { + if ( !m_TeamImage[ STATE_ENABLED ].Init( this, enabled, pInitData->m_pEntity ) ) + return false; + } + + KeyValues *disabled = pKeyValues->FindKey( "DisabledImage" ); + if ( disabled ) + { + if ( !m_TeamImage[ STATE_DISABLED ].Init( this, disabled, pInitData->m_pEntity ) ) + return false; + } + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMinimapObjectTunnelPanel::Paint() +{ + // Draw the view cone + C_BaseEntity *pEntity = GetEntity(); + Assert( pEntity ); + + if ( gHUD.IsHidden( HIDEHUD_MISCSTATUS ) ) + return; + + if ( !pEntity->IsBaseObject() ) + return; + + C_BaseObject *obj = static_cast< C_BaseObject * >( pEntity ); + Assert( obj ); + + bool enabled = !obj->IsDisabled(); + int image = enabled ? STATE_ENABLED : STATE_DISABLED; + + if (!m_bClipToMap) + { + g_pMatSystemSurface->DisableClipping( true ); + } + m_TeamImage[ image ].SetAlpha( ComputePanelAlpha() ); + m_TeamImage[ image ].Paint(); + g_pMatSystemSurface->DisableClipping( false ); +}
\ No newline at end of file diff --git a/game/client/tf2/c_obj_vehicleboost.cpp b/game/client/tf2/c_obj_vehicleboost.cpp new file mode 100644 index 0000000..652015b --- /dev/null +++ b/game/client/tf2/c_obj_vehicleboost.cpp @@ -0,0 +1,40 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "hud.h" +#include "commanderoverlay.h" +#include "tf_obj_baseupgrade_shared.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_ObjectVehicleBoost : public C_BaseObjectUpgrade +{ + + DECLARE_CLASS( C_ObjectVehicleBoost, C_BaseObjectUpgrade ); + +public: + + DECLARE_CLIENTCLASS(); + + C_ObjectVehicleBoost(); + +private: + + C_ObjectVehicleBoost( const C_ObjectVehicleBoost& ); // not defined, not accessible +}; + +IMPLEMENT_CLIENTCLASS_DT( C_ObjectVehicleBoost, DT_ObjectVehicleBoost, CObjectVehicleBoost ) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ObjectVehicleBoost::C_ObjectVehicleBoost() +{ +} + diff --git a/game/client/tf2/c_objectsentrygun.cpp b/game/client/tf2/c_objectsentrygun.cpp new file mode 100644 index 0000000..9d47a76 --- /dev/null +++ b/game/client/tf2/c_objectsentrygun.cpp @@ -0,0 +1,558 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client's CObjectSentrygun +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "bone_setup.h" +#include "CommanderOverlay.h" +#include "c_baseobject.h" +#include "C_Obj_SentryGun.h" +#include "tf_shareddefs.h" +#include "c_basetfplayer.h" +#include "ObjectControlPanel.h" +#include <vgui_controls/Button.h> + +inline float UTIL_AngleMod(float a) +{ + return anglemod(a); +} + +//----------------------------------------------------------------------------- +// Purpose: Base Sentrygun +//----------------------------------------------------------------------------- +BEGIN_RECV_TABLE_NOBASE(C_ObjectSentrygun, DT_SentrygunTeamOnlyVars) + RecvPropInt(RECVINFO( m_iAmmo )), +END_RECV_TABLE() + +IMPLEMENT_CLIENTCLASS_DT(C_ObjectSentrygun, DT_ObjectSentrygun, CObjectSentrygun) + RecvPropInt( RECVINFO( m_iBaseTurnRate ) ), + RecvPropEHandle(RECVINFO(m_hEnemy)), + RecvPropDataTable( "teamonly", 0, 0, &REFERENCE_RECV_TABLE( DT_SentrygunTeamOnlyVars )), + RecvPropInt(RECVINFO(m_bTurtled)), + RecvPropInt( RECVINFO( m_nAnimationParity ) ), + RecvPropInt( RECVINFO( m_nOrientationParity ) ), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ObjectSentrygun::C_ObjectSentrygun() +{ + m_fBoneXRotator = 0; + m_fBoneYRotator = 0; + m_iAmmo = 0; + m_bTurtled = false; + m_flStartedTurtlingAt = 0; + m_flStartedUnTurtlingAt = 0; + + SetViewOffset( Vector(0,0,22) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ObjectSentrygun::SetDormant( bool bDormant ) +{ + BaseClass::SetDormant( bDormant ); + ENTITY_PANEL_ACTIVATE( "sentrygun", !bDormant ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int C_ObjectSentrygun::DrawModel( int flags ) +{ + float flRealOriginZ = GetLocalOrigin().z; + + // If we're turtling, slide the model into the ground + if ( m_bTurtled ) + { + // How far down are we? + float flTime = MIN( gpGlobals->curtime - m_flStartedTurtlingAt, SENTRY_TURTLE_TIME ); + float flPercent = 1 - (SENTRY_TURTLE_TIME - flTime) / SENTRY_TURTLE_TIME; + + // FIXME: This is totally wrong!!! + Vector vNewOrigin = GetLocalOrigin(); + vNewOrigin.z -= (CollisionProp()->OBBSize().z * flPercent); + SetLocalOrigin( vNewOrigin ); + InvalidateBoneCache(); + } + else if ( !m_bTurtled ) + { + if ( m_flStartedUnTurtlingAt ) + { + float flTime = MIN( gpGlobals->curtime - m_flStartedUnTurtlingAt, SENTRY_TURTLE_TIME ); + float flPercent = (SENTRY_TURTLE_TIME - flTime) / SENTRY_TURTLE_TIME; + + // FIXME: This is totally wrong!!! + Vector vNewOrigin = GetLocalOrigin(); + vNewOrigin.z -= (CollisionProp()->OBBSize().z * flPercent); + SetLocalOrigin( vNewOrigin ); + InvalidateBoneCache(); + + // Fully unturtled? + if ( flTime >= SENTRY_TURTLE_TIME ) + { + m_flStartedUnTurtlingAt = 0; + } + } + } + + int drawn = BaseClass::DrawModel( flags ); + SetLocalOriginDim( Z_INDEX, flRealOriginZ ); + + return drawn; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ObjectSentrygun::PreDataUpdate( DataUpdateType_t updateType ) +{ + BaseClass::PreDataUpdate( updateType ); + + m_bLastTurtled = m_bTurtled; + m_nLastAnimationParity = m_nAnimationParity; + m_angPrevLocalAngles = GetLocalAngles(); + m_nPrevOrientationParity = m_nOrientationParity; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ObjectSentrygun::PostDataUpdate( DataUpdateType_t updateType ) +{ + BaseClass::PostDataUpdate( updateType ); + + if ( m_bLastTurtled != m_bTurtled ) + { + if ( m_bTurtled ) + { + m_flStartedTurtlingAt = gpGlobals->curtime; + m_flStartedUnTurtlingAt = 0; + } + else + { + m_flStartedUnTurtlingAt = gpGlobals->curtime; + m_flStartedTurtlingAt = 0; + } + } + + if ( m_nLastAnimationParity != m_nAnimationParity ) + { + SetCycle( 0.0f ); + } + + bool changed = false; + QAngle angleDiff; + angleDiff = ( GetAbsAngles() - m_angPrevLocalAngles ); + for (int i = 0;i < 3; i++ ) + { + angleDiff[i] = UTIL_AngleMod( angleDiff[ i ] ); + } + + if ( angleDiff.Length() > 0.1f ) + { + changed = true; + } + if ( updateType == DATA_UPDATE_CREATED || changed ) + { + // Orient it + m_vecCurAngles.y = UTIL_AngleMod( GetLocalAngles().y ); + RecomputeOrientation(); + } + else if ( m_nPrevOrientationParity != m_nOrientationParity ) + { + if ( changed ) + { + RecomputeOrientation(); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ObjectSentrygun::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + if ( updateType == DATA_UPDATE_CREATED ) + { + // Start thinking (Baseclass stops it) + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ObjectSentrygun::FinishedBuilding( void ) +{ + BaseClass::FinishedBuilding(); + + EmitSound( "ObjectSentrygun.Activate" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ObjectSentrygun::GetBoneControllers(float controllers[MAXSTUDIOBONECTRLS]) +{ + studiohdr_t *pModel = modelinfo->GetStudiomodel( GetModel() ); + + // When yaw preview is on, + if (!IsPreviewingYaw()) + { + Studio_SetController(pModel, 0, m_fBoneXRotator, controllers[0]); + } + else + { + // Bone rotation == 0 here to make it exactly match the preview + Studio_SetController(pModel, 0, 0, controllers[0]); + } + + Studio_SetController(pModel, 1, m_fBoneYRotator, controllers[1]); + Studio_SetController(pModel, 2, m_fBoneYRotator, controllers[2]); + Studio_SetController(pModel, 3, m_fBoneYRotator, controllers[3]); +} + +//----------------------------------------------------------------------------- +// Purpose: This is called to get the initial builder yaw... +//----------------------------------------------------------------------------- +float C_ObjectSentrygun::GetInitialBuilderYaw() +{ + // Take the current rotation into account + return GetAbsAngles().y + m_fBoneXRotator; +} + +//----------------------------------------------------------------------------- +// Called when a rotation happens +//----------------------------------------------------------------------------- +void C_ObjectSentrygun::RecomputeOrientation( ) +{ + m_iRightBound = UTIL_AngleMod( m_vecCurAngles.y - 50); + m_iLeftBound = UTIL_AngleMod( m_vecCurAngles.y + 50); + if ( m_iRightBound > m_iLeftBound ) + { + m_iRightBound = m_iLeftBound; + m_iLeftBound = UTIL_AngleMod( m_vecCurAngles.y - 50); + } + + // Start it rotating + m_vecGoalAngles.y = m_iRightBound;; + m_vecGoalAngles.x = m_vecCurAngles.x = 0; + + m_fBoneXRotator = 0.0f; + m_fBoneYRotator = 0.0f; + + m_bTurningRight = true; +} + + +//----------------------------------------------------------------------------- +// Purpose: Handle movement of the turret +//----------------------------------------------------------------------------- +bool C_ObjectSentrygun::MoveTurret(void) +{ + bool bMoved = 0; + + float turnrate = (float)(m_iBaseTurnRate) * 10.0f; + turnrate *= gpGlobals->frametime; + + // any x movement? + if ( m_vecCurAngles.x != m_vecGoalAngles.x ) + { + float flDir = m_vecGoalAngles.x > m_vecCurAngles.x ? 1 : -1 ; + + m_vecCurAngles.x += 0.1 * (turnrate * 5) * flDir; + + // if we started below the goal, and now we're past, peg to goal + if (flDir == 1) + { + if (m_vecCurAngles.x > m_vecGoalAngles.x) + m_vecCurAngles.x = m_vecGoalAngles.x; + } + else + { + if (m_vecCurAngles.x < m_vecGoalAngles.x) + m_vecCurAngles.x = m_vecGoalAngles.x; + } + + m_fBoneYRotator = m_vecCurAngles.x; + + bMoved = 1; + } + + if ( m_vecCurAngles.y != m_vecGoalAngles.y ) + { + float flDir = m_vecGoalAngles.y > m_vecCurAngles.y ? 1 : -1 ; + float flDist = fabs(m_vecGoalAngles.y - m_vecCurAngles.y); + bool bReversed = false; + + if (flDist > 180) + { + flDist = 360 - flDist; + flDir = -flDir; + bReversed = true; + } + + if (m_hEnemy == NULL ) + { + if (flDist > 30) + { + if (m_fTurnRate < turnrate * 20) + { + m_fTurnRate += turnrate; + } + } + else + { + // Slow down + if ( m_fTurnRate > (turnrate * 5) ) + m_fTurnRate -= turnrate; + } + } + else + { + // When tracking enemies, move faster and don't slow + if (flDist > 30) + { + if (m_fTurnRate < turnrate * 30) + { + m_fTurnRate += turnrate * 3; + } + } + } + + m_vecCurAngles.y += 0.1 * m_fTurnRate * flDir; + + // if we passed over the goal, peg right to it now + if (flDir == -1) + { + if ( (bReversed == false && m_vecGoalAngles.y > m_vecCurAngles.y) || (bReversed == true && m_vecGoalAngles.y < m_vecCurAngles.y) ) + m_vecCurAngles.y = m_vecGoalAngles.y; + } + else + { + if ( (bReversed == false && m_vecGoalAngles.y < m_vecCurAngles.y) || (bReversed == true && m_vecGoalAngles.y > m_vecCurAngles.y) ) + m_vecCurAngles.y = m_vecGoalAngles.y; + } + + if (m_vecCurAngles.y < 0) + m_vecCurAngles.y += 360; + else if (m_vecCurAngles.y >= 360) + m_vecCurAngles.y -= 360; + + if (flDist < (0.05 * turnrate)) + m_vecCurAngles.y = m_vecGoalAngles.y; + + m_fBoneXRotator = m_vecCurAngles.y - UTIL_AngleMod( GetAbsAngles().y ); + + bMoved = 1; + } + + if ( !bMoved || !m_fTurnRate ) + m_fTurnRate = turnrate; + + if ( bMoved ) + { + NetworkStateChanged(); + } + + return bMoved; +} + +void C_ObjectSentrygun::ClientThink( void ) +{ + // Turtling sentryguns don't think + if ( IsTurtled() ) + return; + + if ( IsPlacing() || IsBuilding() ) + return; + + + if ( m_hEnemy != NULL ) + { + // Figure out where we're firing at + Vector vecMid = EyePosition(); + Vector vecFireTarget = m_hEnemy->WorldSpaceCenter(); // + vecMid; // BodyTarget( vecMid ); + Vector vecDirToEnemy = vecFireTarget - vecMid; + QAngle angToTarget; + VectorAngles(vecDirToEnemy, angToTarget); + + angToTarget.y = UTIL_AngleMod( angToTarget.y ); + if (angToTarget.x < -180) + angToTarget.x += 360; + if (angToTarget.x > 180) + angToTarget.x -= 360; + + // now all numbers should be in [1...360] + // pin to turret limitations to [-50...50] + if (angToTarget.x > 50) + angToTarget.x = 50; + else if (angToTarget.x < -50) + angToTarget.x = -50; + + m_vecGoalAngles.y = angToTarget.y; + m_vecGoalAngles.x = angToTarget.x; + + MoveTurret(); + return; + } + + // Rotate + if ( !MoveTurret() ) + { + // Play a sound occasionally + if ( random->RandomFloat(0, 1) < 0.02 ) + { + EmitSound( "ObjectSentrygun.Idle" ); + } + + // Switch rotation direction + if (m_bTurningRight) + { + m_bTurningRight = false; + m_vecGoalAngles.y = m_iLeftBound; + } + else + { + m_bTurningRight = true; + m_vecGoalAngles.y = m_iRightBound; + } + + // Randomly look up and down a bit + if ( random->RandomFloat(0, 1) < 0.3 ) + { + m_vecGoalAngles.x = (int)random->RandomFloat(-10,10); + } + } +} + + +//----------------------------------------------------------------------------- +// Control screen +//----------------------------------------------------------------------------- +class CSentrygunControlPanel : public CRotatingObjectControlPanel +{ + DECLARE_CLASS( CSentrygunControlPanel, CRotatingObjectControlPanel ); + +public: + CSentrygunControlPanel( vgui::Panel *parent, const char *panelName ); + virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); + virtual void OnTick(); + virtual void OnCommand( const char *command ); + + void AddAmmo( void ); + +private: + vgui::Label *m_pAmmoLabel; +}; + + +DECLARE_VGUI_SCREEN_FACTORY( CSentrygunControlPanel, "sentrygun_control_panel" ); + + +//----------------------------------------------------------------------------- +// Constructor: +//----------------------------------------------------------------------------- +CSentrygunControlPanel::CSentrygunControlPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, "CSentrygunControlPanel" ) +{ +} + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- +bool CSentrygunControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ) +{ + m_pAmmoLabel = new vgui::Label( this, "AmmoReadout", "" ); + + if (!BaseClass::Init(pKeyValues, pInitData)) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// Frame-based update +//----------------------------------------------------------------------------- +void CSentrygunControlPanel::OnTick() +{ + BaseClass::OnTick(); + + C_BaseObject *pObj = GetOwningObject(); + if (!pObj) + return; + + Assert( dynamic_cast<C_ObjectSentrygun*>(pObj) ); + C_ObjectSentrygun *pSentrygun = static_cast<C_ObjectSentrygun*>(pObj); + + char buf[256]; + int iAmmo = pSentrygun->GetAmmoLeft(); + if (iAmmo > 0) + { + Q_snprintf( buf, sizeof( buf ), "%d rounds left", iAmmo ); + } + else + { + Q_snprintf( buf, sizeof( buf ), "OUT OF AMMO" ); + } + m_pAmmoLabel->SetText( buf ); +} + +//----------------------------------------------------------------------------- +// Purpose: Handle ammo input to the sentrygun +//----------------------------------------------------------------------------- +void CSentrygunControlPanel::AddAmmo( void ) +{ + C_BaseObject *pObj = GetOwningObject(); + if (pObj) + { + pObj->SendClientCommand( "addammo" ); + } +} + +//----------------------------------------------------------------------------- +// Button click handlers +//----------------------------------------------------------------------------- +void CSentrygunControlPanel::OnCommand( const char *command ) +{ + if (!Q_strnicmp(command, "AddAmmo", 7)) + { + AddAmmo(); + return; + } + + BaseClass::OnCommand(command); +} + + + +//====================================================================================================== +// SENTRYGUN TYPES +//====================================================================================================== +// Purpose: Plasma sentrygun +//----------------------------------------------------------------------------- +IMPLEMENT_CLIENTCLASS_DT(C_ObjectSentrygunPlasma, DT_ObjectSentrygunPlasma, CObjectSentrygunPlasma) +END_RECV_TABLE() + +C_ObjectSentrygunPlasma::C_ObjectSentrygunPlasma() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Rocket launcher sentrygun +//----------------------------------------------------------------------------- +IMPLEMENT_CLIENTCLASS_DT(C_ObjectSentrygunRocketlauncher, DT_ObjectSentrygunRocketlauncher, CObjectSentrygunRocketlauncher) +END_RECV_TABLE() + +C_ObjectSentrygunRocketlauncher::C_ObjectSentrygunRocketlauncher() +{ +} + + diff --git a/game/client/tf2/c_order.cpp b/game/client/tf2/c_order.cpp new file mode 100644 index 0000000..4309e63 --- /dev/null +++ b/game/client/tf2/c_order.cpp @@ -0,0 +1,462 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client Side COrder class +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud_orders.h" +#include "c_order.h" +#include <vgui_controls/Controls.h> +#include <vgui/ISurface.h> +#include "minimap_trace.h" +#include "VGuiMatSurface/IMatSystemSurface.h" +#include "c_func_resource.h" +#include "tf_shareddefs.h" +#include "c_baseobject.h" +#include "tf_hints.h" +#include "hud.h" +#include "c_basetfplayer.h" +#include "c_tf_hintmanager.h" +#include "clientmode_tfnormal.h" + +#define NEW_ORDER_ANIM_DURATION 1.0f +#define NEW_ORDERS_RIGHT XRES(640-8) +#define NEW_ORDERS_LEFT XRES(8) +#define NEW_ORDERS_WIDTH (ORDERS_RIGHT - NEW_ORDERS_LEFT) //(NEW_ORDERS_RIGHT - ORDERS_LEFT) + + +class COrderLabel : public vgui::Label +{ +public: + COrderLabel( vgui::Panel *pParent, const char *pPanelName, const char *pText ) + : vgui::Label( pParent, pPanelName, pText ) + { + } + + virtual void OnThink() + { + BaseClass::OnThink(); + + // Resize? + int x, y, w, h; + if( m_flAnimCounter < NEW_ORDER_ANIM_DURATION ) + { + int wantedWidth, dummy; + GetContentSize( wantedWidth, dummy ); + wantedWidth += 10; + + float flPercent = m_flAnimCounter / NEW_ORDER_ANIM_DURATION; + int newWidth = (int)(NEW_ORDERS_WIDTH + (wantedWidth - NEW_ORDERS_WIDTH) * flPercent); + + GetBounds( x, y, w, h ); + + m_flAnimCounter += gpGlobals->frametime; + if( m_flAnimCounter >= NEW_ORDER_ANIM_DURATION ) + { + SetBounds( ORDERS_RIGHT - wantedWidth, y, wantedWidth, h ); + } + else + { + SetBounds( ORDERS_RIGHT - newWidth, y, newWidth, h ); + } + } + } + + virtual void PaintBackground() + { + // BaseClass::PaintBackground(); + + // Draw our background. + int x, y, w, h; + GetBounds( x, y, w, h ); + + vgui::surface()->DrawSetColor( Color( 0, 0, 0, 160 ) ); + vgui::surface()->DrawFilledRect( 0, 0, w, h ); + + vgui::surface()->DrawSetColor( Color( 63, 63, 63, 255 ) ); + vgui::surface()->DrawOutlinedRect( 0, 0, w, h ); + } + +public: + float m_flAnimCounter; +}; + + +class CMinimapOrderPanel : public CMinimapTraceBitmapPanel +{ + DECLARE_CLASS( CMinimapOrderPanel, CMinimapTraceBitmapPanel ); + +public: + CMinimapOrderPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, "CMinimapOrderPanel" ) + { + } + virtual bool Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData ); + virtual void OnTick(); + virtual void Paint( ); + +private: + C_Order *m_pOrder; +}; + + +DECLARE_MINIMAP_FACTORY( CMinimapOrderPanel, "minimap_order_panel" ); + +bool CMinimapOrderPanel::Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData ) +{ + m_pOrder = dynamic_cast<C_Order*>(pInitData->m_pEntity); + if (!m_pOrder) + return false; + + if (!BaseClass::Init( pKeyValues, pInitData )) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// called when we're ticked... +//----------------------------------------------------------------------------- +void CMinimapOrderPanel::OnTick() +{ + // NOTE: Do *not* chain down the the base OnTick; it's going to do + // a totally different computation that will conflict with ours + Assert( m_pOrder ); + if( m_pOrder->GetTarget() <= 0 ) + { + SetVisible(false); + return; + } + + C_BaseEntity *pTarget = ClientEntityList().GetEnt( m_pOrder->GetTarget() ); + if( !pTarget ) + { + SetVisible(false); + return; + } + + SetEntity( pTarget ); + + // Now that we're attached to the correct target, compute position! + BaseClass::OnTick(); +} + + +void CMinimapOrderPanel::Paint( ) +{ + Assert( m_pOrder ); + + if( m_pOrder->GetTarget() <= 0 ) + return; + + C_BaseEntity *pTarget = ClientEntityList().GetEnt( m_pOrder->GetTarget() ); + if( !pTarget ) + return; + + g_pMatSystemSurface->DisableClipping( true ); + + static float flStrobeDuration = 0.5; + float flShade = sin( gpGlobals->curtime * M_PI / flStrobeDuration ) * 0.5f + 0.5f; + + Color color(255*flShade, 0, 0, 255); + m_Image.SetColor( color ); + m_Image.Paint(); + + g_pMatSystemSurface->DisableClipping( false ); +} + + + +enum GetTargetDescriptionType_t +{ + GETDESC_RESOURCEZONE=0, + GETDESC_OBJECT +}; + +char* GetTargetDescription( int entindex, GetTargetDescriptionType_t type ) +{ + static char szDesc[128]; + szDesc[0]=0; + + // Order target + if ( entindex ) + { + C_BaseEntity *pEnt = cl_entitylist->GetEnt( entindex ); + if ( pEnt ) + { + if( type == GETDESC_RESOURCEZONE ) + { + C_ResourceZone *pZone = dynamic_cast<C_ResourceZone*>(pEnt); + if ( pZone ) + Q_strncpy( szDesc, pZone->GetTargetDescription(), sizeof( szDesc ) ); + } + else if( type == GETDESC_OBJECT ) + { + C_BaseObject *pObj = dynamic_cast<C_BaseObject*>( pEnt ); + if( pObj ) + Q_strncpy( szDesc, pObj->GetTargetDescription(), sizeof( szDesc ) ); + } + } + } + + return szDesc; +} + + +IMPLEMENT_CLIENTCLASS_DT(C_Order, DT_Order, COrder) + RecvPropInt( RECVINFO(m_iPriority) ), + RecvPropInt( RECVINFO(m_iOrderType) ), + RecvPropInt( RECVINFO(m_iTargetEntIndex) ), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_Order::C_Order( void ) +{ + m_nHintID = TF_HINT_UNDEFINED; + + m_pNameLabel = NULL; + + CONSTRUCT_MINIMAP_PANEL( "minimap_order", MINIMAP_PERSONAL_ORDERS ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_Order::~C_Order( void ) +{ + RemoveOrder(); + + if( C_BaseTFPlayer::GetLocalPlayer() ) + C_BaseTFPlayer::GetLocalPlayer()->RemoveOrderTarget(); + + + if ( m_nHintID != TF_HINT_UNDEFINED ) + { + DestroyGlobalHint( m_nHintID ); + } +} + +void C_Order::ClientThink( void ) +{ + BaseClass::ClientThink(); + + if ( m_nHintID != TF_HINT_UNDEFINED ) + { + switch ( m_iOrderType ) + { + case ORDER_REPAIR: + m_nHintID = TF_HINT_REPAIROBJECT; + break; + default: + break; + } + } + + if ( m_nHintID != TF_HINT_UNDEFINED ) + { + CreateGlobalHint_Panel( m_pNameLabel, m_nHintID, NULL, index ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_Order::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + pPlayer->SetPersonalOrder( this ); + + // Update us if we've changed + if( updateType == DATA_UPDATE_CREATED ) + { + CreateStatus( GetClientModeNormal()->GetViewport() ); + } + else + { + GetHudOrderList()->RecalculateOrderList(); + UpdateStatus(); + } + + if( m_iTargetEntIndex > 0 ) + { + C_BaseEntity *pTarget = ClientEntityList().GetEnt( m_iTargetEntIndex ); + m_OverlayPanel.Activate( pTarget, "personal_order", true ); + } + + if ( (updateType == DATA_UPDATE_CREATED) && ( m_nHintID != TF_HINT_UNDEFINED ) ) + { + // Wait for animation to fly all the way in + SetNextClientThink( gpGlobals->curtime + NEW_ORDER_ANIM_DURATION + 0.25f ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Clean up a removed order +//----------------------------------------------------------------------------- +void C_Order::RemoveOrder( void ) +{ + m_OverlayPanel.RemoveOverlay(); + + DestroyStatus(); + + if ( m_pNameLabel ) + { + delete m_pNameLabel; + m_pNameLabel = NULL; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Get a text description of this order +//----------------------------------------------------------------------------- +void C_Order::GetDescription( char *pDest, int bufferSize ) +{ + char targetDesc[512]; + GetTargetDescription( targetDesc, sizeof( targetDesc ) ); + + switch ( m_iOrderType ) + { + case ORDER_ATTACK: + Q_snprintf( pDest, bufferSize, "Attack %s", targetDesc ); + break; + + case ORDER_DEFEND: + Q_snprintf( pDest, bufferSize, "Defend %s", targetDesc ); + break; + + case ORDER_CAPTURE: + Q_snprintf( pDest, bufferSize, "Capture %s", targetDesc ); + break; + + default: + Q_snprintf( pDest, bufferSize, "INVALID" ); + break; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Get a text description for the target of this order +//----------------------------------------------------------------------------- +void C_Order::GetTargetDescription( char *pDest, int bufferSize ) +{ + pDest[0] = 0; + + if ( !m_iTargetEntIndex ) + return; + + C_BaseEntity *pEnt = cl_entitylist->GetEnt( m_iTargetEntIndex ); + if ( !pEnt ) + return; + + C_ResourceZone *pZone = dynamic_cast<C_ResourceZone*>(pEnt); + if ( pZone ) + { + Q_strncpy( pDest, pZone->GetTargetDescription(), bufferSize ); + } + else + { + C_BaseObject *pObj = dynamic_cast<C_BaseObject*>( pEnt ); + if( pObj ) + Q_strncpy( pDest, pObj->GetTargetDescription(), bufferSize ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Create all elements needed in a status panel for this order +//----------------------------------------------------------------------------- +void C_Order::CreateStatus( vgui::Panel *pParent ) +{ + // If we already have our elements, we're just moving. + if ( m_pNameLabel ) + { + m_pNameLabel->SetParent( pParent ); + } + else + { + m_pNameLabel = new COrderLabel( pParent, "NameLabel", "Temp" ); + m_pNameLabel->SetBounds( ORDERS_LEFT, ORDERS_TOP, NEW_ORDERS_WIDTH, ORDERS_ELEMENT_HEIGHT ); + m_pNameLabel->SetAutoDelete( false ); + m_pNameLabel->SetPaintBackgroundEnabled( true ); + m_pNameLabel->SetFgColor( Color( 0, 0, 0, 255 ) ); + m_pNameLabel->SetContentAlignment( vgui::Label::a_east ); + m_pNameLabel->SetTextInset( -2, 0 ); + } + + UpdateStatus(); +} + +//----------------------------------------------------------------------------- +// Purpose: Destroy all elements in the status panel for this order +//----------------------------------------------------------------------------- +void C_Order::DestroyStatus( void ) +{ + if ( m_pNameLabel ) + { + delete m_pNameLabel; + m_pNameLabel = NULL; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Update all elements in the status panel for this order +//----------------------------------------------------------------------------- +void C_Order::UpdateStatus( void ) +{ + if ( m_pNameLabel ) + { + char desc[512]; + GetDescription( desc, sizeof( desc ) ); + + m_pNameLabel->SetText( desc ); + m_pNameLabel->m_flAnimCounter = 0; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Return true if this order wants a target reticle created around it's target +//----------------------------------------------------------------------------- +bool C_Order::ShouldDrawReticle( void ) +{ + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int C_Order::GetPriority( void ) +{ + return m_iPriority; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int C_Order::GetType( void ) +{ + return m_iOrderType; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int C_Order::GetTarget( void ) +{ + return m_iTargetEntIndex; +} + +//----------------------------------------------------------------------------- +// Purpose: Return true if this order is a personal one for this player +//----------------------------------------------------------------------------- +bool C_Order::IsPersonalOrder( void ) +{ + return (GetPriority() == 0); +} + diff --git a/game/client/tf2/c_order.h b/game/client/tf2/c_order.h new file mode 100644 index 0000000..b1623c8 --- /dev/null +++ b/game/client/tf2/c_order.h @@ -0,0 +1,73 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client Side COrder class +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_ORDER_H +#define C_ORDER_H +#ifdef _WIN32 +#pragma once +#endif + +#include <vgui_controls/Label.h> +#include <vgui_controls/Panel.h> +#include "CommanderOverlay.h" +#include "hud_minimap.h" + +class COrderLabel; + + +//----------------------------------------------------------------------------- +// Purpose: Datatable container class for orders +//----------------------------------------------------------------------------- +class C_Order : public C_BaseEntity +{ + DECLARE_CLASS( C_Order, C_BaseEntity ); +public: + DECLARE_CLIENTCLASS(); + + C_Order( void ); + ~C_Order( void ); + + virtual void ClientThink( void ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void RemoveOrder( void ); + virtual void GetDescription( char *pDest, int bufferSize ); + virtual void GetTargetDescription( char *pDest, int bufferSize ); + + // Status drawing + virtual void CreateStatus( vgui::Panel *pParent ); + virtual void DestroyStatus( void ); + virtual void UpdateStatus( void ); + virtual bool ShouldDrawReticle( void ); + + // Data access + int GetPriority( void ); + int GetTarget( void ); + int GetType( void ); + bool IsPersonalOrder( void ); + +protected: + // Received via datatable + int m_iPriority; + int m_iOrderType; + int m_iTargetEntIndex; + + // Used in status drawing + COrderLabel *m_pNameLabel; + + // Animating panel to show the new order. + float m_flNewOrderHighlightTimer; + + // Hook up the overlay on the tactical map. + DECLARE_ENTITY_PANEL(); + DECLARE_MINIMAP_PANEL(); + +protected: + int m_nHintID; +}; + + +#endif // C_ORDER_H diff --git a/game/client/tf2/c_order_assist.cpp b/game/client/tf2/c_order_assist.cpp new file mode 100644 index 0000000..ab18247 --- /dev/null +++ b/game/client/tf2/c_order_assist.cpp @@ -0,0 +1,22 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_order_assist.h" + + +IMPLEMENT_CLIENTCLASS_DT( C_OrderAssist, DT_OrderAssist, COrderAssist ) +END_RECV_TABLE() + + +void C_OrderAssist::GetDescription( char *pDest, int bufferSize ) +{ + char targetDesc[512]; + GetTargetDescription( targetDesc, sizeof( targetDesc ) ); + + Q_snprintf( pDest, bufferSize, "Assist %s", targetDesc ); +} + diff --git a/game/client/tf2/c_order_assist.h b/game/client/tf2/c_order_assist.h new file mode 100644 index 0000000..4457c3e --- /dev/null +++ b/game/client/tf2/c_order_assist.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_ORDER_ASSIST_H +#define C_ORDER_ASSIST_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "c_order_player.h" + + +class C_OrderAssist : public C_OrderPlayer +{ +public: + DECLARE_CLASS( C_OrderAssist, C_OrderPlayer ); + DECLARE_CLIENTCLASS(); + + +// C_Order overrides. +public: + + virtual void GetDescription( char *pDest, int bufferSize ); +}; + + +#endif // C_ORDER_ASSIST_H diff --git a/game/client/tf2/c_order_buildsentrygun.cpp b/game/client/tf2/c_order_buildsentrygun.cpp new file mode 100644 index 0000000..0a536d8 --- /dev/null +++ b/game/client/tf2/c_order_buildsentrygun.cpp @@ -0,0 +1,26 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_order_buildsentrygun.h" +#include "tf_hints.h" + + +IMPLEMENT_CLIENTCLASS_DT( C_OrderBuildSentryGun, DT_OrderBuildSentryGun, COrderBuildSentryGun ) +END_RECV_TABLE() + + +C_OrderBuildSentryGun::C_OrderBuildSentryGun() +{ + m_nHintID = TF_HINT_BUILDSENTRYGUN_PLASMA; +} + + +void C_OrderBuildSentryGun::GetDescription( char *pDest, int bufferSize ) +{ + Q_strncpy( pDest, "Build Sentry Gun To Protect Object", bufferSize ); +} + diff --git a/game/client/tf2/c_order_buildsentrygun.h b/game/client/tf2/c_order_buildsentrygun.h new file mode 100644 index 0000000..04c7ffa --- /dev/null +++ b/game/client/tf2/c_order_buildsentrygun.h @@ -0,0 +1,34 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_ORDER_BUILDSENTRYGUN_H +#define C_ORDER_BUILDSENTRYGUN_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "c_order.h" + + +class C_OrderBuildSentryGun : public C_Order +{ +public: + DECLARE_CLASS( C_OrderBuildSentryGun, C_Order ); + DECLARE_CLIENTCLASS(); + + C_OrderBuildSentryGun(); + + +// C_Order overrides. +public: + + virtual void GetDescription( char *pDest, int bufferSize ); +}; + + +#endif // C_ORDER_BUILDSENTRYGUN_H diff --git a/game/client/tf2/c_order_buildshieldwall.cpp b/game/client/tf2/c_order_buildshieldwall.cpp new file mode 100644 index 0000000..1139917 --- /dev/null +++ b/game/client/tf2/c_order_buildshieldwall.cpp @@ -0,0 +1,19 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_order_buildshieldwall.h" + + +IMPLEMENT_CLIENTCLASS_DT( C_OrderBuildShieldWall, DT_OrderBuildShieldWall, COrderBuildShieldWall ) +END_RECV_TABLE() + + +void C_OrderBuildShieldWall::GetDescription( char *pDest, int bufferSize ) +{ + Q_strncpy( pDest, "Build Shield Wall To Protect Object", bufferSize ); +} + diff --git a/game/client/tf2/c_order_buildshieldwall.h b/game/client/tf2/c_order_buildshieldwall.h new file mode 100644 index 0000000..b22f3b9 --- /dev/null +++ b/game/client/tf2/c_order_buildshieldwall.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_ORDER_BUILDSHIELDWALL_H +#define C_ORDER_BUILDSHIELDWALL_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "c_order.h" + + +class C_OrderBuildShieldWall : public C_Order +{ +public: + DECLARE_CLASS( C_OrderBuildShieldWall, C_Order ); + DECLARE_CLIENTCLASS(); + + +// C_Order overrides. +public: + + virtual void GetDescription( char *pDest, int bufferSize ); +}; + + +#endif // C_ORDER_BUILDSHIELDWALL_H diff --git a/game/client/tf2/c_order_heal.cpp b/game/client/tf2/c_order_heal.cpp new file mode 100644 index 0000000..555fb47 --- /dev/null +++ b/game/client/tf2/c_order_heal.cpp @@ -0,0 +1,22 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_order_heal.h" + + +IMPLEMENT_CLIENTCLASS_DT( C_OrderHeal, DT_OrderHeal, COrderHeal ) +END_RECV_TABLE() + + +void C_OrderHeal::GetDescription( char *pDest, int bufferSize ) +{ + char targetDesc[512]; + GetTargetDescription( targetDesc, sizeof( targetDesc ) ); + + Q_snprintf( pDest, bufferSize, "Heal %s", targetDesc ); +} + diff --git a/game/client/tf2/c_order_heal.h b/game/client/tf2/c_order_heal.h new file mode 100644 index 0000000..a1addc6 --- /dev/null +++ b/game/client/tf2/c_order_heal.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_ORDER_HEAL_H +#define C_ORDER_HEAL_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "c_order_player.h" + + +class C_OrderHeal : public C_OrderPlayer +{ +public: + DECLARE_CLASS( C_OrderHeal, C_OrderPlayer ); + DECLARE_CLIENTCLASS(); + + +// C_Order overrides. +public: + + virtual void GetDescription( char *pDest, int bufferSize ); +}; + + +#endif // C_ORDER_HEAL_H diff --git a/game/client/tf2/c_order_killmortarguy.cpp b/game/client/tf2/c_order_killmortarguy.cpp new file mode 100644 index 0000000..682a2f2 --- /dev/null +++ b/game/client/tf2/c_order_killmortarguy.cpp @@ -0,0 +1,22 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_order_killmortarguy.h" + + +IMPLEMENT_CLIENTCLASS_DT( C_OrderKillMortarGuy, DT_OrderKillMortarGuy, COrderKillMortarGuy ) +END_RECV_TABLE() + + +void C_OrderKillMortarGuy::GetDescription( char *pDest, int bufferSize ) +{ + char targetDesc[512]; + GetTargetDescription( targetDesc, sizeof( targetDesc ) ); + + Q_snprintf( pDest, bufferSize, "Kill Mortar Guy: %s", targetDesc ); +} + diff --git a/game/client/tf2/c_order_killmortarguy.h b/game/client/tf2/c_order_killmortarguy.h new file mode 100644 index 0000000..c3932ce --- /dev/null +++ b/game/client/tf2/c_order_killmortarguy.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_ORDER_KILLMORTARGUY_H +#define C_ORDER_KILLMORTARGUY_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "c_order_player.h" + + +class C_OrderKillMortarGuy : public C_OrderPlayer +{ +public: + DECLARE_CLASS( C_OrderKillMortarGuy, C_OrderPlayer ); + DECLARE_CLIENTCLASS(); + + +// C_Order overrides. +public: + + virtual void GetDescription( char *pDest, int bufferSize ); +}; + + +#endif // C_ORDER_KILLMORTARGUY_H diff --git a/game/client/tf2/c_order_mortar_attack.cpp b/game/client/tf2/c_order_mortar_attack.cpp new file mode 100644 index 0000000..67795a7 --- /dev/null +++ b/game/client/tf2/c_order_mortar_attack.cpp @@ -0,0 +1,22 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_order_mortar_attack.h" + + +IMPLEMENT_CLIENTCLASS_DT( C_OrderMortarAttack, DT_OrderMortarAttack, COrderMortarAttack ) +END_RECV_TABLE() + + +void C_OrderMortarAttack::GetDescription( char *pDest, int bufferSize ) +{ + char targetDesc[512]; + GetTargetDescription( targetDesc, sizeof( targetDesc ) ); + + Q_snprintf( pDest, bufferSize, "Attack %s with mortar", targetDesc ); +} + diff --git a/game/client/tf2/c_order_mortar_attack.h b/game/client/tf2/c_order_mortar_attack.h new file mode 100644 index 0000000..9502d6a --- /dev/null +++ b/game/client/tf2/c_order_mortar_attack.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_ORDER_MORTAR_ATTACK_H +#define C_ORDER_MORTAR_ATTACK_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "c_order.h" + + +class C_OrderMortarAttack : public C_Order +{ +public: + DECLARE_CLASS( C_OrderMortarAttack, C_Order ); + DECLARE_CLIENTCLASS(); + + +// C_Order overrides. +public: + + virtual void GetDescription( char *pDest, int bufferSize ); +}; + + +#endif // C_ORDER_MORTAR_ATTACK_H diff --git a/game/client/tf2/c_order_player.cpp b/game/client/tf2/c_order_player.cpp new file mode 100644 index 0000000..180c390 --- /dev/null +++ b/game/client/tf2/c_order_player.cpp @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_order_player.h" +#include "cliententitylist.h" +#include "c_basetfplayer.h" + + +IMPLEMENT_CLIENTCLASS_DT( C_OrderPlayer, DT_OrderPlayer, COrderPlayer ) +END_RECV_TABLE() + + +void C_OrderPlayer::GetTargetDescription( char *pDest, int bufferSize ) +{ + pDest[0] = 0; + + // Order target + if ( !m_iTargetEntIndex ) + return; + + C_BaseEntity *pEnt = cl_entitylist->GetEnt(m_iTargetEntIndex); + if ( !pEnt ) + return; + + C_BaseTFPlayer *pPlayer = dynamic_cast<C_BaseTFPlayer*>(pEnt); + if ( pPlayer ) + { + pPlayer->GetTargetDescription( pDest, bufferSize ); + } +} + + + + diff --git a/game/client/tf2/c_order_player.h b/game/client/tf2/c_order_player.h new file mode 100644 index 0000000..54b8961 --- /dev/null +++ b/game/client/tf2/c_order_player.h @@ -0,0 +1,33 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_ORDER_PLAYER_H +#define C_ORDER_PLAYER_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "c_order.h" + + +// Orders that point at players. +class C_OrderPlayer : public C_Order +{ +public: + DECLARE_CLASS( C_OrderPlayer, C_Order ); + DECLARE_CLIENTCLASS(); + + +// C_Order overrides. +public: + + virtual void GetTargetDescription( char *pDest, int bufferSize ); +}; + + +#endif // C_ORDER_PLAYER_H diff --git a/game/client/tf2/c_order_repair.cpp b/game/client/tf2/c_order_repair.cpp new file mode 100644 index 0000000..3ad2af7 --- /dev/null +++ b/game/client/tf2/c_order_repair.cpp @@ -0,0 +1,19 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_order_repair.h" + + +IMPLEMENT_CLIENTCLASS_DT( C_OrderRepair, DT_OrderRepair, COrderRepair ) +END_RECV_TABLE() + + +void C_OrderRepair::GetDescription( char *pDest, int bufferSize ) +{ + Q_strncpy( pDest, "Repair Structure", bufferSize ); +} + diff --git a/game/client/tf2/c_order_repair.h b/game/client/tf2/c_order_repair.h new file mode 100644 index 0000000..ffb9d8c --- /dev/null +++ b/game/client/tf2/c_order_repair.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_ORDER_REPAIR_H +#define C_ORDER_REPAIR_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "c_order.h" + + +class C_OrderRepair : public C_Order +{ +public: + DECLARE_CLASS( C_OrderRepair, C_Order ); + DECLARE_CLIENTCLASS(); + + +// C_Order overrides. +public: + + virtual void GetDescription( char *pDest, int bufferSize ); +}; + + +#endif // C_ORDER_REPAIR_H diff --git a/game/client/tf2/c_order_resourcepump.cpp b/game/client/tf2/c_order_resourcepump.cpp new file mode 100644 index 0000000..5e2e90d --- /dev/null +++ b/game/client/tf2/c_order_resourcepump.cpp @@ -0,0 +1,27 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "c_order_resourcepump.h" +#include "tf_hints.h" + + +IMPLEMENT_CLIENTCLASS_DT( C_OrderResourcePump, DT_OrderResourcePump, COrderResourcePump ) +END_RECV_TABLE() + + +C_OrderResourcePump::C_OrderResourcePump() +{ + m_nHintID = TF_HINT_BUILDRESOURCEPUMP; +} + + +void C_OrderResourcePump::GetDescription( char *pDest, int bufferSize ) +{ + Q_strncpy( pDest, "Build Resource Pump", bufferSize ); +} + diff --git a/game/client/tf2/c_order_resourcepump.h b/game/client/tf2/c_order_resourcepump.h new file mode 100644 index 0000000..11a24d8 --- /dev/null +++ b/game/client/tf2/c_order_resourcepump.h @@ -0,0 +1,34 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_ORDER_RESOURCEPUMP_H +#define C_ORDER_RESOURCEPUMP_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "c_order.h" + + +class C_OrderResourcePump : public C_Order +{ +public: + DECLARE_CLASS( C_OrderResourcePump, C_Order ); + DECLARE_CLIENTCLASS(); + + C_OrderResourcePump(); + + +// C_Order overrides. +public: + + virtual void GetDescription( char *pDest, int bufferSize ); +}; + + +#endif // C_ORDER_RESOURCEPUMP_H diff --git a/game/client/tf2/c_order_respawnstation.cpp b/game/client/tf2/c_order_respawnstation.cpp new file mode 100644 index 0000000..757f218 --- /dev/null +++ b/game/client/tf2/c_order_respawnstation.cpp @@ -0,0 +1,19 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_order_respawnstation.h" + + +IMPLEMENT_CLIENTCLASS_DT( C_OrderRespawnStation, DT_OrderRespawnStation, COrderRespawnStation ) +END_RECV_TABLE() + + +void C_OrderRespawnStation::GetDescription( char *pDest, int bufferSize ) +{ + Q_strncpy( pDest, "Build Respawn Station Near Object", bufferSize ); +} + diff --git a/game/client/tf2/c_order_respawnstation.h b/game/client/tf2/c_order_respawnstation.h new file mode 100644 index 0000000..f28e72c --- /dev/null +++ b/game/client/tf2/c_order_respawnstation.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_ORDER_RESPAWNSTATION_H +#define C_ORDER_RESPAWNSTATION_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "c_order_player.h" + + +class C_OrderRespawnStation : public C_Order +{ +public: + DECLARE_CLASS( C_OrderRespawnStation, C_Order ); + DECLARE_CLIENTCLASS(); + + +// C_Order overrides. +public: + + virtual void GetDescription( char *pDest, int bufferSize ); +}; + + +#endif // C_ORDER_RESPAWNSTATION_H diff --git a/game/client/tf2/c_order_resupply.cpp b/game/client/tf2/c_order_resupply.cpp new file mode 100644 index 0000000..ca71b93 --- /dev/null +++ b/game/client/tf2/c_order_resupply.cpp @@ -0,0 +1,19 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_order_resupply.h" + + +IMPLEMENT_CLIENTCLASS_DT( C_OrderResupply, DT_OrderResupply, COrderResupply ) +END_RECV_TABLE() + + +void C_OrderResupply::GetDescription( char *pDest, int bufferSize ) +{ + Q_strncpy( pDest, "Build Resupply Station Near Object", bufferSize ); +} + diff --git a/game/client/tf2/c_order_resupply.h b/game/client/tf2/c_order_resupply.h new file mode 100644 index 0000000..0db297a --- /dev/null +++ b/game/client/tf2/c_order_resupply.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_ORDER_RESUPPLY_H +#define C_ORDER_RESUPPLY_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "c_order.h" + + +class C_OrderResupply : public C_Order +{ +public: + DECLARE_CLASS( C_OrderResupply, C_Order ); + DECLARE_CLIENTCLASS(); + + +// C_Order overrides. +public: + + virtual void GetDescription( char *pDest, int bufferSize ); +}; + + +#endif // C_ORDER_RESUPPLY_H diff --git a/game/client/tf2/c_ragdoll_shadow.cpp b/game/client/tf2/c_ragdoll_shadow.cpp new file mode 100644 index 0000000..efb705b --- /dev/null +++ b/game/client/tf2/c_ragdoll_shadow.cpp @@ -0,0 +1,246 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "model_types.h" +#include "vcollide.h" +#include "vcollide_parse.h" +#include "solidsetdefaults.h" +#include "c_basetfplayer.h" +#include "bone_setup.h" +#include "engine/ivmodelinfo.h" + +CPhysCollide *PhysCreateBbox( const Vector &mins, const Vector &maxs ); +extern CSolidSetDefaults g_SolidSetup; +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_RagdollShadow : public C_BaseAnimating +{ + DECLARE_CLASS( C_RagdollShadow, C_BaseAnimating ); +public: + DECLARE_CLIENTCLASS(); + + C_RagdollShadow( void ); + ~C_RagdollShadow( void ); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + + virtual void ClientThink( void ); + virtual int DrawModel( int flags ); + +public: + IPhysicsObject *VPhysicsInitShadow( bool allowPhysicsMovement, bool allowPhysicsRotation ); + void VPhysicsSetObject( IPhysicsObject *pPhysics ); + void VPhysicsDestroyObject( void ); + + int m_nPlayer; + EHANDLE m_hPlayer; + + IPhysicsObject *m_pPhysicsObject; + IPhysicsSpring *m_pSpring; +}; + +IMPLEMENT_CLIENTCLASS_DT( C_RagdollShadow, DT_RagdollShadow, CRagdollShadow ) + RecvPropInt( RECVINFO( m_nPlayer ) ), +END_RECV_TABLE() + +C_RagdollShadow::C_RagdollShadow( void ) +{ + m_nPlayer = -1; + m_hPlayer = NULL; + + m_pPhysicsObject = NULL; + m_pSpring = NULL; +} + +C_RagdollShadow::~C_RagdollShadow( void ) +{ + VPhysicsDestroyObject(); + + delete m_pSpring; +} + +void C_RagdollShadow::VPhysicsDestroyObject( void ) +{ + if ( m_pPhysicsObject ) + { + physenv->DestroyObject( m_pPhysicsObject ); + m_pPhysicsObject = NULL; + } +} + +// Create a physics thingy based on an existing collision model +IPhysicsObject *PhysModelCreateCustom( C_BaseEntity *pEntity, const CPhysCollide *pModel, const Vector &origin, const QAngle &angles, const char *props ) +{ + solid_t solid; + solid.params = g_PhysDefaultObjectParams; + solid.params.mass = 85.0f; + solid.params.inertia = 1e24f; + int surfaceProp = -1; + if ( props && props[0] ) + { + surfaceProp = physprops->GetSurfaceIndex( props ); + } + solid.params.pGameData = static_cast<void *>(pEntity); + IPhysicsObject *pObject = physenv->CreatePolyObject( pModel, surfaceProp, origin, angles, &solid.params ); + return pObject; +} + +IPhysicsObject *PhysModelCreateRagdoll( C_BaseEntity *pEntity, int modelIndex, const Vector &origin, const QAngle &angles ) +{ + vcollide_t *pCollide = modelinfo->GetVCollide( modelIndex ); + if ( !pCollide ) + return NULL; + + solid_t solid; + memset( &solid, 0, sizeof(solid) ); + solid.params = g_PhysDefaultObjectParams; + + IVPhysicsKeyParser *pParse = physcollision->VPhysicsKeyParserCreate( pCollide->pKeyValues ); + while ( !pParse->Finished() ) + { + const char *pBlock = pParse->GetCurrentBlockName(); + if ( !strcmpi( pBlock, "solid" ) ) + { + pParse->ParseSolid( &solid, &g_SolidSetup ); + break; + } + else + { + pParse->SkipBlock(); + } + } + physcollision->VPhysicsKeyParserDestroy( pParse ); + + // collisions are off by default + solid.params.enableCollisions = true; + + int surfaceProp = -1; + if ( solid.surfaceprop[0] ) + { + surfaceProp = physprops->GetSurfaceIndex( solid.surfaceprop ); + } + solid.params.pGameData = static_cast<void *>(pEntity); + solid.params.pName = "ragdoll_player"; + IPhysicsObject *pObject = physenv->CreatePolyObject( pCollide->solids[0], surfaceProp, origin, angles, &solid.params ); + //PhysCheckAdd( pObject, STRING(pEntity->m_iClassname) ); + return pObject; +} + +void C_RagdollShadow::VPhysicsSetObject( IPhysicsObject *pPhysics ) +{ + if ( m_pPhysicsObject && pPhysics ) + { + Warning( "C_RagdollShadow::Overwriting physics object!\n" ); + } + m_pPhysicsObject = pPhysics; +} + + +// This creates a vphysics object with a shadow controller that follows the AI +IPhysicsObject *C_RagdollShadow::VPhysicsInitShadow( bool allowPhysicsMovement, bool allowPhysicsRotation ) +{ + CStudioHdr *hdr = GetModelPtr(); + if ( !hdr ) + { + return NULL; + } + + // If this entity already has a physics object, then it should have been deleted prior to making this call. + Assert(!m_pPhysicsObject); + + // make sure m_vecOrigin / m_vecAngles are correct + const Vector &origin = GetAbsOrigin(); + QAngle angles = GetAbsAngles(); + IPhysicsObject *pPhysicsObject = NULL; + + if ( GetSolid() == SOLID_BBOX ) + { + const char *pSurfaceProps = "flesh"; + if ( GetModelIndex() && modelinfo->GetModelType( GetModel() ) == mod_studio ) + { + pSurfaceProps = Studio_GetDefaultSurfaceProps( hdr ); + } + angles = vec3_angle; + CPhysCollide *pCollide = PhysCreateBbox( WorldAlignMins(), WorldAlignMaxs() ); + if ( !pCollide ) + return NULL; + pPhysicsObject = PhysModelCreateCustom( this, pCollide, origin, angles, pSurfaceProps ); + } + else + { + pPhysicsObject = PhysModelCreateRagdoll( this, GetModelIndex(), origin, angles ); + } + VPhysicsSetObject( pPhysicsObject ); + pPhysicsObject->SetShadow( 1e4, 1e4, allowPhysicsMovement, allowPhysicsRotation ); + pPhysicsObject->UpdateShadow( GetAbsOrigin(), GetAbsAngles(), false, 0 ); +// PhysAddShadow( this ); + return pPhysicsObject; +} + +void C_RagdollShadow::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + // Has to happen *after* the client handle is set + SetNextClientThink( CLIENT_THINK_ALWAYS ); + + bool bnewentity = (updateType == DATA_UPDATE_CREATED); + if ( bnewentity && ( m_nPlayer != 0 ) ) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); + + Assert( !m_pPhysicsObject ); + + C_BaseEntity *pl = static_cast< C_BaseEntity * >( cl_entitylist->GetEnt( m_nPlayer ) ); + if ( pl ) + { + m_hPlayer = pl; + } + + m_pPhysicsObject = VPhysicsInitShadow( true, false ); + } + + if ( m_pPhysicsObject ) + { + // Create the spring if we don't have one yet + if ( !m_pSpring ) + { + C_BaseTFPlayer *pl = static_cast< C_BaseTFPlayer * >( (C_BaseEntity *)m_hPlayer ); + if ( pl && pl->VPhysicsGetObject() ) + { + springparams_t spring; + spring.constant = 15000; + spring.damping = 1.0; + spring.naturalLength = 0.0f; + spring.relativeDamping = 100.0f; + VectorCopy( vec3_origin, spring.startPosition ); + VectorCopy( vec3_origin, spring.endPosition ); + spring.useLocalPositions = true; + + m_pSpring = physenv->CreateSpring( m_pPhysicsObject, pl->VPhysicsGetObject(), &spring ); + + PhysDisableObjectCollisions( m_pPhysicsObject, pl->VPhysicsGetObject() ); + } + } + + m_pPhysicsObject->UpdateShadow( GetAbsOrigin(), GetAbsAngles(), false, 0 ); + } + +} + +void C_RagdollShadow::ClientThink( void ) +{ + BaseClass::ClientThink(); +} + +int C_RagdollShadow::DrawModel( int flags ) +{ +// int drawn = BaseClass::DrawModel( flags ); +// return drawn; + return 0; +} diff --git a/game/client/tf2/c_resource_chunk.cpp b/game/client/tf2/c_resource_chunk.cpp new file mode 100644 index 0000000..ab4acf8 --- /dev/null +++ b/game/client/tf2/c_resource_chunk.cpp @@ -0,0 +1,22 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "particles_simple.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_ResourceChunk : public C_BaseAnimating +{ + DECLARE_CLASS( C_ResourceChunk, C_BaseAnimating ); +public: + DECLARE_CLIENTCLASS(); +}; + +IMPLEMENT_CLIENTCLASS_DT( C_ResourceChunk, DT_ResourceChunk, CResourceChunk ) +END_RECV_TABLE() + diff --git a/game/client/tf2/c_shield.cpp b/game/client/tf2/c_shield.cpp new file mode 100644 index 0000000..b404a92 --- /dev/null +++ b/game/client/tf2/c_shield.cpp @@ -0,0 +1,837 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client's sheild entity +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "C_Shield.h" +#include "clienteffectprecachesystem.h" +#include "clientmode.h" +#include "materialsystem/imesh.h" +#include "mapdata.h" +#include "ivrenderview.h" +#include "tf_shareddefs.h" +#include "collisionutils.h" +#include "functionproxy.h" + +// Precache the effects +CLIENTEFFECT_REGISTER_BEGIN( Shield ) +CLIENTEFFECT_MATERIAL( "shadertest/wireframevertexcolor" ) +CLIENTEFFECT_MATERIAL( "effects/shield/shield" ) +CLIENTEFFECT_MATERIAL( "effects/shieldhit" ) +CLIENTEFFECT_MATERIAL( "effects/shieldpass" ) +CLIENTEFFECT_MATERIAL( "effects/shieldpass2" ) +CLIENTEFFECT_REGISTER_END() + +//----------------------------------------------------------------------------- +// Stores a list of all active shields +//----------------------------------------------------------------------------- +CUtlVector< C_Shield* > C_Shield::s_Shields; + + +//----------------------------------------------------------------------------- +// Various important constants: +//----------------------------------------------------------------------------- + +#define SHIELD_DAMAGE_CHANGE_FIRST_PASS_TIME 0.3f +#define SHIELD_DAMAGE_CHANGE_TRANSITION_TIME 0.5f +#define SHIELD_DAMAGE_CHANGE_TRANSITION_START_TIME (SHIELD_DAMAGE_CHANGE_TIME - SHIELD_DAMAGE_CHANGE_TRANSITION_TIME) +#define SHIELD_DAMAGE_CHANGE_TOTAL_TIME (SHIELD_DAMAGE_CHANGE_TRANSITION_START_TIME + SHIELD_DAMAGE_CHANGE_TRANSITION_TIME) +#define SHIELD_TRANSITION_MAX_BLEND_AMT 0.2f + + +//----------------------------------------------------------------------------- +// Data table +//----------------------------------------------------------------------------- +//EXTERN_RECV_TABLE(DT_BaseEntity); + +IMPLEMENT_CLIENTCLASS_DT(C_Shield, DT_Shield, CShield) + RecvPropInt( RECVINFO(m_nOwningPlayerIndex) ), + RecvPropFloat( RECVINFO(m_flPowerLevel) ), + RecvPropInt( RECVINFO(m_bIsEMPed) ), +END_RECV_TABLE() + + +//----------------------------------------------------------------------------- +// Shield color for the various protection types +//----------------------------------------------------------------------------- +static unsigned char s_ImpactDecalColor[3] = { 0, 0, 255 }; + + +// ---------------------------------------------------------------------------- +// Functions. +// ---------------------------------------------------------------------------- +C_Shield::C_Shield() +{ + m_pWireframe.Init( "shadertest/wireframevertexcolor", TEXTURE_GROUP_OTHER ); + m_pShield.Init( "effects/shield/shield", TEXTURE_GROUP_CLIENT_EFFECTS ); + m_pHitDecal.Init( "effects/shieldhit", TEXTURE_GROUP_CLIENT_EFFECTS ); + m_pPassDecal.Init( "effects/shieldpass", TEXTURE_GROUP_CLIENT_EFFECTS ); + m_pPassDecal2.Init( "effects/shieldpass2", TEXTURE_GROUP_CLIENT_EFFECTS ); + m_FadeValue = 1.0f; + m_CurveValue = 1.0f; + m_bCollisionsActive = true; + + s_Shields.AddToTail(this); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_Shield::~C_Shield() +{ + int i = s_Shields.Find(this); + if ( i >= 0 ) + { + s_Shields.FastRemove(i); + } +} + +//----------------------------------------------------------------------------- +// Inherited classes should call this in their constructor to indicate size... +//----------------------------------------------------------------------------- +void C_Shield::InitShield( int w, int h, int subdivisions ) +{ + m_SplinePatch.Init( w, h, 2 ); + + m_SubdivisionCount = subdivisions; + Assert( m_SubdivisionCount > 1 ); + m_InvSubdivisionCount = 1.0f / (m_SubdivisionCount - 1); +} + +//----------------------------------------------------------------------------- +// This is called after a network update +//----------------------------------------------------------------------------- +void C_Shield::OnDataChanged( DataUpdateType_t updateType ) +{ + if (updateType == DATA_UPDATE_CREATED) + { + m_StartTime = engine->GetLastTimeStamp(); + } + + BaseClass::OnDataChanged( updateType ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : collisionGroup - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool C_Shield::ShouldCollide( int collisionGroup, int contentsMask ) const +{ + return m_bCollisionsActive && ((collisionGroup == TFCOLLISION_GROUP_WEAPON) || (collisionGroup == TFCOLLISION_GROUP_GRENADE)); +} + +//----------------------------------------------------------------------------- +// Should I draw? +//----------------------------------------------------------------------------- +bool C_Shield::ShouldDraw() +{ + // Let the client mode (like commander mode) reject drawing entities. + if (g_pClientMode && !g_pClientMode->ShouldDrawEntity(this) ) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// Activates/deactivates a shield for collision purposes +//----------------------------------------------------------------------------- +void C_Shield::ActivateCollisions( bool activate ) +{ + m_bCollisionsActive = activate; +} + +//----------------------------------------------------------------------------- +// Activates all shields +//----------------------------------------------------------------------------- +void C_Shield::ActivateShields( bool activate, int team ) +{ + for (int i = s_Shields.Count(); --i >= 0; ) + { + // Activate all shields on the same team + if ( (team == -1) || (team == s_Shields[i]->GetTeamNumber()) ) + { + s_Shields[i]->ActivateCollisions( activate ); + } + } +} + +//----------------------------------------------------------------------------- +// Helper method for collision testing +//----------------------------------------------------------------------------- +#pragma warning ( disable : 4701 ) + +bool C_Shield::TestCollision( const Ray_t& ray, unsigned int mask, trace_t& trace ) +{ + // Can't block anything if we're EMPed, or we've got no power left to block + if ( m_bIsEMPed ) + return false; + if ( m_flPowerLevel <= 0 ) + return false; + + // Here, we're gonna test for collision. + // If we don't stop this kind of bullet, we'll generate an effect here + // but we won't change the trace to indicate a collision. + + // It's just polygon soup... + int hitgroup; + bool firstTri; + int v1[2], v2[2], v3[2]; + float ihit, jhit; + float mint = FLT_MAX; + float t; + + int h = Height(); + int w = Width(); + + for (int i = 0; i < h - 1; ++i) + { + for (int j = 0; j < w - 1; ++j) + { + // Don't test if this panel ain't active... + if (!IsPanelActive( j, i )) + continue; + + // NOTE: Structure order of points so that our barycentric + // axes for each triangle are along the (u,v) directions of the mesh + // The barycentric coords we'll need below + + // Two triangles per quad... + t = IntersectRayWithTriangle( ray, + GetPoint( j, i + 1 ), + GetPoint( j + 1, i + 1 ), + GetPoint( j, i ), true ); + if ((t >= 0.0f) && (t < mint)) + { + mint = t; + v1[0] = j; v1[1] = i + 1; + v2[0] = j + 1; v2[1] = i + 1; + v3[0] = j; v3[1] = i; + ihit = i; jhit = j; + firstTri = true; + } + + t = IntersectRayWithTriangle( ray, + GetPoint( j + 1, i ), + GetPoint( j, i ), + GetPoint( j + 1, i + 1 ), true ); + if ((t >= 0.0f) && (t < mint)) + { + mint = t; + v1[0] = j + 1; v1[1] = i; + v2[0] = j; v2[1] = i; + v3[0] = j + 1; v3[1] = i + 1; + ihit = i; jhit = j; + firstTri = false; + } + } + } + + if (mint == FLT_MAX) + return false; + + // Stuff the barycentric coordinates of the triangle hit into the hit group + // For the first triangle, the first edge goes along u, the second edge goes + // along -v. For the second triangle, the first edge goes along -u, + // the second edge goes along v. + const Vector& v1vec = GetPoint(v1[0], v1[1]); + const Vector& v2vec = GetPoint(v2[0], v2[1]); + const Vector& v3vec = GetPoint(v3[0], v3[1]); + float u, v; + bool ok = ComputeIntersectionBarycentricCoordinates( ray, + v1vec, v2vec, v3vec, u, v ); + Assert( ok ); + if ( !ok ) + { + return false; + } + + if (firstTri) + v = 1.0 - v; + else + u = 1.0 - u; + v += ihit; u += jhit; + v /= (h - 1); + u /= (w - 1); + + // Compress (u,v) into 1 dot 15, v in top bits + hitgroup = (((int)(v * (1 << 15))) << 16) + (int)(u * (1 << 15)); + + Vector normal; + float intercept; + ComputeTrianglePlane( v1vec, v2vec, v3vec, normal, intercept ); + + UTIL_SetTrace( trace, ray, this, mint, hitgroup, CONTENTS_SOLID, normal, intercept ); + return true; +} + +#pragma warning ( default : 4701 ) + +//----------------------------------------------------------------------------- +// Called when we hit something that we deflect... +//----------------------------------------------------------------------------- +void C_Shield::RegisterDeflection(const Vector& vecDir, int bitsDamageType, trace_t *ptr) +{ + Vector normalDir; + VectorCopy( vecDir, normalDir ); + VectorNormalize( normalDir ); + + CreateShieldDeflection( ptr->hitgroup, normalDir, false ); +} + +//----------------------------------------------------------------------------- +// This is required to get all the decals to animate correctly +//----------------------------------------------------------------------------- +void C_Shield::SetCurrentDecal( int idx ) +{ + m_CurrentDecal = idx; +} + +//----------------------------------------------------------------------------- +// returns the address of a variable that stores the material animation frame +//----------------------------------------------------------------------------- +float C_Shield::GetTextureAnimationStartTime() +{ + if( m_CurrentDecal == -1 ) + return m_StartTime; + return m_Decals[m_CurrentDecal].m_StartTime; +} + +//----------------------------------------------------------------------------- +// Indicates that a texture animation has wrapped +//----------------------------------------------------------------------------- +void C_Shield::TextureAnimationWrapped() +{ + if( m_CurrentDecal != -1 ) + { + m_Decals[m_CurrentDecal].m_StartTime = -1.0f; + } +} + + +//----------------------------------------------------------------------------- +// Indicates a collision occurred: +//----------------------------------------------------------------------------- +void C_Shield::ReceiveMessage( int classID, bf_read &msg ) +{ + if ( classID != GetClientClass()->m_ClassID ) + { + // message is for subclass + BaseClass::ReceiveMessage( classID, msg ); + return; + } + + int hitgroup; + Vector dir; + unsigned char partialBlock; + + hitgroup = msg.ReadLong( ); + msg.ReadBitVec3Normal( dir ); + partialBlock = msg.ReadByte( ); + + CreateShieldDeflection( hitgroup, dir, partialBlock ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_Shield::CreateShieldDeflection( int hitgroup, const Vector &dir, bool partialBlock ) +{ + float hitU = (float)(hitgroup & 0xFFFF) / (float)(1 << 15); + float hitV = (float)(hitgroup >> 16) / (float)(1 << 15); + + Ripple_t ripple; + ripple.m_RippleU = hitU; + ripple.m_RippleV = hitV; + ripple.m_Amplitude = partialBlock ? 4 : 30; + ripple.m_Radius = 0.08f; + ripple.m_StartTime = engine->GetLastTimeStamp(); + ripple.m_Direction = dir; + m_Ripples.AddToTail(ripple); + + Decal_t decal; + decal.m_RippleU = hitU; + decal.m_RippleV = hitV; + decal.m_Radius = partialBlock ? 0.03f : 0.08f; + decal.m_StartTime = engine->GetLastTimeStamp(); + m_Decals.AddToTail(decal); +} + + +//----------------------------------------------------------------------------- +// Draws the control points in wireframe +//----------------------------------------------------------------------------- +void C_Shield::DrawWireframeModel( Vector const** ppPositions ) +{ + IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL, m_pWireframe ); + + int numLines = (Height() - 1) * Width() + Height() * (Width() - 1); + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_LINES, numLines ); + + Vector const* tmp; + for (int i = 0; i < Height(); ++i) + { + for (int j = 0; j < Width(); ++j) + { + if ( i > 0 ) + { + tmp = ppPositions[j + Width() * i]; + meshBuilder.Position3fv( tmp->Base() ); + meshBuilder.Color4ub( 255, 255, 255, 128 ); + meshBuilder.AdvanceVertex(); + + tmp = ppPositions[j + Width() * (i-1)]; + meshBuilder.Position3fv( tmp->Base() ); + meshBuilder.Color4ub( 255, 255, 255, 128 ); + meshBuilder.AdvanceVertex(); + } + + if (j > 0) + { + tmp = ppPositions[j + Width() * i]; + meshBuilder.Position3fv( tmp->Base() ); + meshBuilder.Color4ub( 255, 255, 255, 128 ); + meshBuilder.AdvanceVertex(); + + tmp = ppPositions[j - 1 + Width() * i]; + meshBuilder.Position3fv( tmp->Base() ); + meshBuilder.Color4ub( 255, 255, 255, 128 ); + meshBuilder.AdvanceVertex(); + } + } + } + + meshBuilder.End(); + pMesh->Draw(); +} + +//----------------------------------------------------------------------------- +// Draws the base shield +//----------------------------------------------------------------------------- +#define TRANSITION_REGION_WIDTH 0.5f + +extern ConVar mat_wireframe; + +void C_Shield::DrawShieldPoints(Vector* pt, Vector* normal, float* opacity) +{ + SetCurrentDecal( -1 ); + + if (mat_wireframe.GetInt() == 0) + materials->Bind( m_pShield, (IClientRenderable*)this ); + else + materials->Bind( m_pWireframe, (IClientRenderable*)this ); + IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL ); + + int numTriangles = (m_SubdivisionCount - 1) * (m_SubdivisionCount - 1) * 2; + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, numTriangles ); + + float du = 1.0f * m_InvSubdivisionCount; + float dv = du; + + unsigned char color[3]; + color[0] = 255; + color[1] = 255; + color[2] = 255; + + for ( int i = 0; i < m_SubdivisionCount - 1; ++i) + { + float v = i * dv; + + for (int j = 0; j < m_SubdivisionCount - 1; ++j) + { + int idx = i * m_SubdivisionCount + j; + float u = j * du; + + meshBuilder.Position3fv( pt[idx].Base() ); + meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx] ); + meshBuilder.Normal3fv( normal[idx].Base() ); + meshBuilder.TexCoord2f( 0, u, v ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv( pt[idx + m_SubdivisionCount].Base() ); + meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+m_SubdivisionCount] ); + meshBuilder.Normal3fv( normal[idx + m_SubdivisionCount].Base() ); + meshBuilder.TexCoord2f( 0, u, v + dv ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv( pt[idx + 1].Base() ); + meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+1] ); + meshBuilder.Normal3fv( normal[idx+1].Base() ); + meshBuilder.TexCoord2f( 0, u + du, v ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv( pt[idx + 1].Base() ); + meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+1] ); + meshBuilder.Normal3fv( normal[idx+1].Base() ); + meshBuilder.TexCoord2f( 0, u + du, v ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv( pt[idx + m_SubdivisionCount].Base() ); + meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+m_SubdivisionCount] ); + meshBuilder.Normal3fv( normal[idx + m_SubdivisionCount].Base() ); + meshBuilder.TexCoord2f( 0, u, v + dv ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv( pt[idx + m_SubdivisionCount + 1].Base() ); + meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+m_SubdivisionCount+1] ); + meshBuilder.Normal3fv( normal[idx + m_SubdivisionCount + 1].Base() ); + meshBuilder.TexCoord2f( 0, u + du, v + dv ); + meshBuilder.AdvanceVertex(); + } + } + + meshBuilder.End(); + pMesh->Draw(); +} + + + +//----------------------------------------------------------------------------- +// Draws shield decals +//----------------------------------------------------------------------------- +void C_Shield::DrawShieldDecals( Vector* pt, bool hitDecals ) +{ + if (m_Decals.Size() == 0) + return; + + // Compute ripples: + for ( int r = m_Decals.Size(); --r >= 0; ) + { + // At the moment, nothing passes! + bool passDecal = false; + if ((!hitDecals) && (passDecal == hitDecals)) + continue; + + SetCurrentDecal( r ); + + // We have to force a flush here because we're changing the proxy state + if (!hitDecals) + materials->Bind( m_pPassDecal, (IClientRenderable*)this ); + else + materials->Bind( passDecal ? m_pPassDecal2 : m_pHitDecal, (IClientRenderable*)this ); + + float dtime = gpGlobals->curtime - m_Decals[r].m_StartTime; + float decay = exp( -( 2 * dtime) ); + + // Retire the animation if it wraps + // This gets set by TextureAnimatedWrapped above + if ((m_Decals[r].m_StartTime < 0.0f) || (decay < 1e-3)) + { + m_Decals.Remove(r); + continue; + } + + IMesh* pMesh = materials->GetDynamicMesh(); + + // Figure out the quads we must mod2x.... + float u0 = m_Decals[r].m_RippleU - m_Decals[r].m_Radius; + float u1 = m_Decals[r].m_RippleU + m_Decals[r].m_Radius; + float v0 = m_Decals[r].m_RippleV - m_Decals[r].m_Radius; + float v1 = m_Decals[r].m_RippleV + m_Decals[r].m_Radius; + float du = u1 - u0; + float dv = v1 - v0; + + int i0 = Floor2Int( v0 * (m_SubdivisionCount - 1) ); + int i1 = Ceil2Int( v1 * (m_SubdivisionCount - 1) ); + int j0 = Floor2Int( u0 * (m_SubdivisionCount - 1) ); + int j1 = Ceil2Int( u1 * (m_SubdivisionCount - 1) ); + if (i0 < 0) + i0 = 0; + if (i1 >= m_SubdivisionCount) + i1 = m_SubdivisionCount - 1; + if (j0 < 0) + j0 = 0; + if (j1 >= m_SubdivisionCount) + j1 = m_SubdivisionCount - 1; + + int numTriangles = (i1 - i0) * (j1 - j0) * 2; + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, numTriangles ); + + float decalDu = m_InvSubdivisionCount / du; + float decalDv = m_InvSubdivisionCount / dv; + + unsigned char color[3]; + color[0] = s_ImpactDecalColor[0] * decay; + color[1] = s_ImpactDecalColor[1] * decay; + color[2] = s_ImpactDecalColor[2] * decay; + + for ( int i = i0; i < i1; ++i) + { + float t = (float)i * m_InvSubdivisionCount; + for (int j = j0; j < j1; ++j) + { + float s = (float)j * m_InvSubdivisionCount; + int idx = i * m_SubdivisionCount + j; + + // Compute (u,v) into the decal + float decalU = (s - u0) / du; + float decalV = (t - v0) / dv; + + meshBuilder.Position3fv( pt[idx].Base() ); + meshBuilder.Color3ubv( color ); + meshBuilder.TexCoord2f( 0, decalU, decalV ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv( pt[idx + m_SubdivisionCount].Base() ); + meshBuilder.Color3ubv( color ); + meshBuilder.TexCoord2f( 0, decalU, decalV + decalDv ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv( pt[idx + 1].Base() ); + meshBuilder.Color3ubv( color ); + meshBuilder.TexCoord2f( 0, decalU + decalDu, decalV ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv( pt[idx + 1].Base() ); + meshBuilder.Color3ubv( color ); + meshBuilder.TexCoord2f( 0, decalU + decalDu, decalV ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv( pt[idx + m_SubdivisionCount].Base() ); + meshBuilder.Color3ubv( color ); + meshBuilder.TexCoord2f( 0, decalU, decalV + decalDv ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv( pt[idx + m_SubdivisionCount + 1].Base() ); + meshBuilder.Color3ubv( color ); + meshBuilder.TexCoord2f( 0, decalU + decalDu, decalV + decalDv ); + meshBuilder.AdvanceVertex(); + } + } + + meshBuilder.End(); + pMesh->Draw(); + } +} + + +//----------------------------------------------------------------------------- +// Computes a single point +//----------------------------------------------------------------------------- +void C_Shield::ComputePoint( float s, float t, Vector& pt, Vector& normal, float& opacity ) +{ + // Precache some computations for the point on the spline at (s, t). + m_SplinePatch.SetupPatchQuery( s, t ); + + // Get the position + normal + m_SplinePatch.GetPointAndNormal( pt, normal ); + + // From here on down is all futzing with opacity + + // Check neighbors for activity... + bool active = IsPanelActive(m_SplinePatch.m_is, m_SplinePatch.m_it); + if (m_SplinePatch.m_fs == 0.0f) + active = active || IsPanelActive(m_SplinePatch.m_is - 1, m_SplinePatch.m_it); + if (m_SplinePatch.m_ft == 0.0f) + active = active || IsPanelActive(m_SplinePatch.m_is, m_SplinePatch.m_it - 1); + + if (!active) + { + // If the panel's not active, it's transparent. + opacity = 0.0f; + } + else + { + if ((s == 0.0f) || (t == 0.0f) || + (s == (Width() - 1.0f)) || (t == (Height() - 1.0f)) ) + { + // If it's on the edge, it's max opacity + opacity = 192.0f; + } + else + { + // Channel zero is the opacity data + opacity = m_SplinePatch.GetChannel( 0 ); + + // Make the shield translucent if the owner is the local player... + // Also don't mess with the edges.. + if (m_ShieldOwnedByLocalPlayer) + { + // Channel 1 is the opacity blend + float blendFactor = m_SplinePatch.GetChannel( 1 ); + blendFactor = clamp( blendFactor, 0.0f, 1.0f ); + + float blendValue = 1.0f; + Vector delta; + VectorSubtract( pt, GetAbsOrigin(), delta ); + float dist = VectorLength( delta ); + if (dist != 0.0f) + { + delta *= 1.0f / dist; + float dot = DotProduct( m_ViewDir, delta ); + float angle = acos( dot ); + float fov = M_PI * render->GetFieldOfView() / 180.0f; + if (angle < fov * .2f) + blendValue = 0.1f; + else if (angle < fov * 0.4f) + { + // Want a cos falloff between .2 and .4 + // 0.1 at .2 and 1.0 at .4 + angle -= fov * 0.2f; + blendValue = 1.0f - 0.9f * 0.5f * (cos ( M_PI * angle / (fov * 0.2f) ) + 1.0f); + } + } + + // Interpolate between 1 and the blend value based on the blend factor... + opacity *= (1.0f - blendFactor) + blendFactor * blendValue; + } + + opacity = clamp( opacity, 0.0f, 192.0f ); + } + } + opacity *= m_FadeValue; +} + + +//----------------------------------------------------------------------------- +// Compute the shield points using catmull-rom +//----------------------------------------------------------------------------- +void C_Shield::ComputeShieldPoints( Vector* pt, Vector* normal, float* opacity ) +{ + int i; + for ( i = 0; i < m_SubdivisionCount; ++i) + { + float t = (Height() - 1) * (float)i * m_InvSubdivisionCount; + for (int j = 0; j < m_SubdivisionCount; ++j) + { + float s = (Width() - 1) * (float)j * m_InvSubdivisionCount; + int idx = i * m_SubdivisionCount + j; + + ComputePoint( s, t, pt[idx], normal[idx], opacity[idx] ); + } + } +} + +//----------------------------------------------------------------------------- +// Compute the shield ripples from being hit +//----------------------------------------------------------------------------- +void C_Shield::RippleShieldPoints( Vector* pt, float* opacity ) +{ + // Compute ripples: + for ( int r = m_Ripples.Size(); --r >= 0; ) + { + float dtime = gpGlobals->curtime - m_Ripples[r].m_StartTime; + float decay = exp( -( 2 * dtime) ); + float amplitude = m_Ripples[r].m_Amplitude * decay; + + for ( int i = 0; i < m_SubdivisionCount; ++i) + { + float t = i * m_InvSubdivisionCount; + for (int j = 0; j < m_SubdivisionCount; ++j) + { + float s = j * m_InvSubdivisionCount; + int idx = i * m_SubdivisionCount + j; + + float ds = s - m_Ripples[r].m_RippleU; + float dt = t - m_Ripples[r].m_RippleV; + float dr = sqrt( ds * ds + dt * dt ); + if (dr < m_Ripples[r].m_Radius) + { + // need to apply ripple + float diff = amplitude * cos( 0.5f * M_PI * dr / m_Ripples[r].m_Radius ); + VectorMA( pt[idx], diff, m_Ripples[r].m_Direction, pt[idx] ); + + // Compute opacity at this point... + float impactopacity = 192.0f * decay * dr / m_Ripples[r].m_Radius; + if (impactopacity > opacity[idx]) + opacity[idx] = impactopacity; + } + } + } + + if (amplitude < 0.1) + m_Ripples.Remove(r); + } +} + +//----------------------------------------------------------------------------- +// Main draw entry point +//----------------------------------------------------------------------------- +int C_Shield::DrawModel( int flags ) +{ + if ( !m_bReadyToDraw ) + return 0; + + if (m_FadeValue == 0.0f) + return 1; + + // If I have no power, don't draw + if ( m_flPowerLevel <= 0 ) + return 1; + + // Make it curvy or not!! + m_SplinePatch.SetLinearBlend( m_CurveValue ); + + // Set up the patch with all the data it's going to need + int count = Width() * Height(); + Vector const** pControlPoints = (Vector const**)stackalloc(count * sizeof(Vector*)); + float* pControlOpacity = (float*)stackalloc(count * sizeof(float)); + float* pControlBlend = (float*)stackalloc(count * sizeof(float)); + + GetShieldData( pControlPoints, pControlOpacity, pControlBlend ); + m_SplinePatch.SetControlPositions( pControlPoints ); + m_SplinePatch.SetChannelData( 0, pControlOpacity ); + m_SplinePatch.SetChannelData( 1, pControlBlend ); + +// DrawWireframeModel( pControlPoints ); + + // Allocate space for temporary data + int numSubdivisions = m_SubdivisionCount * m_SubdivisionCount; + Vector* pt = (Vector*)stackalloc(numSubdivisions * sizeof(Vector)); + Vector* normal = (Vector*)stackalloc(numSubdivisions * sizeof(Vector)); + float* opacity = (float*)stackalloc(numSubdivisions * sizeof(float)); + + // Do something a little special if this shield is owned by the local player + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + m_ShieldOwnedByLocalPlayer = (player->entindex() == m_nOwningPlayerIndex); + if (m_ShieldOwnedByLocalPlayer) + { + QAngle viewAngles; + engine->GetViewAngles(viewAngles); + AngleVectors( viewAngles, &m_ViewDir ); + } + + ComputeShieldPoints( pt, normal, opacity ); + RippleShieldPoints( pt, opacity ); + + // Commented out because it causes things to not be drawn behind it +// DrawShieldDecals( pt, false ); + + DrawShieldPoints( pt, normal, opacity ); + DrawShieldDecals( pt, true ); + + return 1; +} + + + +//============================================================================================================ +// SHIELD POWERLEVEL PROXY +//============================================================================================================ +class CShieldPowerLevelProxy : public CResultProxy +{ +public: + void OnBind( void *pC_BaseEntity ); +}; + +void CShieldPowerLevelProxy::OnBind( void *pRenderable ) +{ + IClientRenderable *pRend = (IClientRenderable *)pRenderable; + C_BaseEntity *pEntity = pRend->GetIClientUnknown()->GetBaseEntity(); + C_Shield *pShield = dynamic_cast<C_Shield*>(pEntity); + if (!pShield) + return; + + SetFloatResult( pShield->GetPowerLevel() ); +} + +EXPOSE_INTERFACE( CShieldPowerLevelProxy, IMaterialProxy, "ShieldPowerLevel" IMATERIAL_PROXY_INTERFACE_VERSION ); diff --git a/game/client/tf2/c_shield.h b/game/client/tf2/c_shield.h new file mode 100644 index 0000000..2b92cb1 --- /dev/null +++ b/game/client/tf2/c_shield.h @@ -0,0 +1,199 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client's sheild entity +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_SHIELD_H +#define C_SHIELD_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "SplinePatch.h" + +//----------------------------------------------------------------------------- +// Shield: +//----------------------------------------------------------------------------- +class C_Shield : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_Shield, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + // constructor, destructor + C_Shield(); + ~C_Shield(); + + // Inherited classes should call this in their constructor to indicate size... + void InitShield( int w, int h, int subdivisions ); + + void OnDataChanged( DataUpdateType_t updateType ); + int DrawModel( int flags ); + void ReceiveMessage( int classID, bf_read &msg ); + + void CreateShieldDeflection( int hitgroup, const Vector &dir, bool partialBlock ); + + virtual bool ShouldDraw(); + virtual bool IsTransparent() { return true; } + virtual void SetAlwaysOrient( bool bOrient ) {} + virtual bool IsAlwaysOrienting( ) { return false; } + virtual void SetCenterAngles( const QAngle & ) {} + virtual void SetAttachmentIndex( int nAttachmentIndex ) {} + + // returns the address of a variable that stores the material animation frame + float GetTextureAnimationStartTime(); + + // Indicates that a texture animation has wrapped + void TextureAnimationWrapped(); + + virtual bool ShouldCollide( int collisionGroup, int contentsMask ) const; + + // Collision detection + // Activates/deactivates a shield for collision purposes + void ActivateCollisions( bool activate ); + + // Deactivates all shields of players on a particular team + // If you don't specify a team, it'll affect all shields + static void ActivateShields( bool activate, int team = -1 ); + virtual const Vector& GetPoint( int x, int y ) { return vec3_origin; } + + // For collision testing + bool TestCollision( const Ray_t& ray, unsigned int mask, trace_t& trace ); + + // Called when we hit something that we deflect... + void RegisterDeflection(const Vector& vecDir, int bitsDamageType, trace_t *ptr); + + float GetPowerLevel( void ) { return m_flPowerLevel; } + + bool IsEMPed() const; + void SetEMPed( bool bIsEmped ); + +protected: + // + // Inheriting classes must implement these methods!!! + // + + // Return true if the panel is active + virtual bool IsPanelActive( int x, int y ) { assert(0); return false; } + + // Gets at the control point data; who knows how it was made? + virtual void GetShieldData( Vector const** ppVerts, float* pOpacity, float* pBlend ) { assert(0); } + +private: + void DrawWireframeModel( Vector const** pPositions ); + void ComputePoint( float s, float t, Vector& pt, Vector& normal, float& opacity ); + void ComputeShieldPoints( Vector* pt, Vector* normal, float* opacity ); + void RippleShieldPoints( Vector* pt, float* opacity ); + void DrawShieldPoints(Vector* pt, Vector* normal, float* opacity); + void DrawShieldDecals(Vector* pt, bool hitDecals ); + void SetCurrentDecal( int idx ); + + int Width() const; + int Height() const; + +protected: + // Used to fade out the shield + float m_FadeValue; + + // Used to make the shield more or less curvy + float m_CurveValue; + +private: + // no copy constructor + C_Shield( const C_Shield& ); + + // Data needs to ripple the shield control points + struct Ripple_t + { + float m_RippleU; + float m_RippleV; + float m_Amplitude; + float m_Radius; + float m_StartTime; + Vector m_Direction; + }; + + struct Decal_t + { + float m_RippleU; + float m_RippleV; + float m_Radius; + float m_StartTime; + }; + + // Owner entity + int m_nOwningPlayerIndex; + + // number of subdivisions + int m_SubdivisionCount; + float m_InvSubdivisionCount; + + // Shield powerlevel + float m_flPowerLevel; + + // Texture animation + float m_StartTime; + + bool m_bCollisionsActive; + bool m_bIsEMPed; + + // Used to do spline queries + CSplinePatch m_SplinePatch; + + // List of all ripples + decals + int m_CurrentDecal; + CUtlVector< Ripple_t > m_Ripples; + CUtlVector< Decal_t > m_Decals; + + // All the various materials we use + CMaterialReference m_pWireframe; + CMaterialReference m_pShield; + CMaterialReference m_pHitDecal; + CMaterialReference m_pPassDecal; + CMaterialReference m_pPassDecal2; + + // A little state used only during rendering, but I didn't want + // to pass these as arguments to a bunch of functions + bool m_ShieldOwnedByLocalPlayer; + Vector m_ViewDir; + + // List of all active shields + static CUtlVector< C_Shield* > s_Shields; +}; + + +//----------------------------------------------------------------------------- +// Inline methods +//----------------------------------------------------------------------------- +inline int C_Shield::Width() const +{ + return m_SplinePatch.Width(); +} + +inline int C_Shield::Height() const +{ + return m_SplinePatch.Height(); +} + +inline bool C_Shield::IsEMPed() const +{ + return m_bIsEMPed; +} + +inline void C_Shield::SetEMPed( bool bIsEmped ) +{ + m_bIsEMPed = bIsEmped; +} + + +//----------------------------------------------------------------------------- +// Class factory methods to create the various versions of the shield +//----------------------------------------------------------------------------- +C_Shield* CreateMobileShield( C_BaseEntity *owner, float flFrontDistance = 0 ); + +#endif // C_SHIELD_H
\ No newline at end of file diff --git a/game/client/tf2/c_shield_flat.cpp b/game/client/tf2/c_shield_flat.cpp new file mode 100644 index 0000000..0d8316c --- /dev/null +++ b/game/client/tf2/c_shield_flat.cpp @@ -0,0 +1,350 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client's sheild entity +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "C_Shield.h" +#include "tf_shieldshared.h" +#include "c_basetfplayer.h" + +enum +{ + NUM_SUBDIVISIONS = 21, +}; + +#define EMP_WAVE_AMPLITUDE 6.0f +#define EMP_GROW_WIDTH_DELAY 0.2f +#define EMP_GROW_TIME 0.6f +#define EMP_GROW_ATTEN 0.5f +#define EMP_MIN_WIDTH 5.0f + +//----------------------------------------------------------------------------- +// Flat version of the shield +//----------------------------------------------------------------------------- + +class C_ShieldFlat : public C_Shield +{ +public: + DECLARE_CLASS( C_ShieldFlat, C_Shield ); + DECLARE_CLIENTCLASS(); + + C_ShieldFlat(); + ~C_ShieldFlat(); + + virtual void GetBounds( Vector& mins, Vector& maxs ); + + virtual void AddEntity( ); + + virtual void SetDormant( bool bDormant ); + + // Return true if the panel is active + virtual bool IsPanelActive( int x, int y ); + + // Gets at the control point data; who knows how it was made? + virtual void GetShieldData( Vector const** ppVerts, float* pOpacity, float* pBlend ); + virtual const Vector& GetPoint( int x, int y ); + + // Draws the model + virtual int DrawModel( int flags ); + +public: + // networked data + unsigned char m_ShieldState; + float m_Width; + float m_Height; + + float m_DeathFade; + float m_EMPFade; + +private: + void ShieldMoved( void ); + +private: + C_ShieldFlat( const C_ShieldFlat& ); + void ComputeEMPFade(); + void ComputeDeathFade(); + void ComputeSize( float& w, float& h ); + void PreRender( ); + + Vector m_pPositions[4]; + Vector m_Forward; + float m_EnterPVSTime; + + QAngle m_LastAngles; + Vector m_LastPosition; + Vector m_Pos[4]; +}; + + +//----------------------------------------------------------------------------- +// Data table +//----------------------------------------------------------------------------- + +IMPLEMENT_CLIENTCLASS_DT(C_ShieldFlat, DT_Shield_Flat, CShieldFlat) + + RecvPropInt( RECVINFO(m_ShieldState) ), + RecvPropFloat( RECVINFO(m_Width) ), + RecvPropFloat( RECVINFO(m_Height) ), + +END_RECV_TABLE() + + +//----------------------------------------------------------------------------- +// Constructor, destructor +//----------------------------------------------------------------------------- + +C_ShieldFlat::C_ShieldFlat() +{ + m_DeathFade = 1.0f; + m_EMPFade = 1.0f; + + InitShield( 2, 2, 6 ); +} + +C_ShieldFlat::~C_ShieldFlat() +{ +} + +//----------------------------------------------------------------------------- +// Leaving/entering the PVS on the server. +//----------------------------------------------------------------------------- + +void C_ShieldFlat::SetDormant( bool bDormant ) +{ + if (!bDormant) + { + if (m_ShieldState & SHIELD_FLAT_EMP) + { + m_EMPFade = 0.0f; + } + else + { + m_EMPFade = 1.0f; + } + + m_EnterPVSTime = 0.0f; + if (m_ShieldState & SHIELD_FLAT_INACTIVE) + { + m_DeathFade = 0.0f; + } + else + { + m_EnterPVSTime = gpGlobals->curtime; + m_DeathFade = 1.0f; + } + } + + BaseClass::SetDormant(bDormant); +} + +//----------------------------------------------------------------------------- +// Figures the EMP fade factor +//----------------------------------------------------------------------------- + +void C_ShieldFlat::ComputeEMPFade() +{ + if (m_ShieldState & SHIELD_FLAT_EMP) + { + // Decay fade if we've been EMPed or if we're inactive + if (m_EMPFade > 0.0f) + { + m_EMPFade -= gpGlobals->frametime / SHIELD_EMP_FADE_TIME; + if (m_EMPFade < 0.0f) + { + m_EMPFade = 0.0f; + } + else + { + Vector dir; + + // Futz with the control points if we've been EMPed + for (int i = 0; i < 4; ++i) + { + float dist = -EMP_WAVE_AMPLITUDE * sin( i * M_PI * 0.5f + gpGlobals->curtime * M_PI / SHIELD_EMP_WOBBLE_TIME ); + VectorMA( m_pPositions[i], dist, m_Forward, m_pPositions[i] ); + } + } + } + } + else + { + // Fade back in, no longer EMPed + if (m_EMPFade < 1.0f) + { + m_EMPFade += gpGlobals->frametime / SHIELD_EMP_FADE_TIME; + if (m_EMPFade >= 1.0f) + { + m_EMPFade = 1.0f; + } + } + } +} + + +//----------------------------------------------------------------------------- +// Figures the networked fade factor +//----------------------------------------------------------------------------- + +void C_ShieldFlat::ComputeDeathFade() +{ + if (m_ShieldState & SHIELD_FLAT_INACTIVE) + { + // Fade out when we become inactive + if (m_DeathFade > 0.0f) + { + m_DeathFade -= gpGlobals->frametime / SHIELD_FLAT_SHUTDOWN_TIME; + if (m_DeathFade < 0.0f) + { + m_DeathFade = 0.0f; + } + } + } + else + { + // Active? We should be visible + m_DeathFade = 1.0f; + } +} + +//----------------------------------------------------------------------------- +// A little pre-render processing +//----------------------------------------------------------------------------- + +void C_ShieldFlat::ComputeSize( float& w, float& h ) +{ + w = m_Width; + h = m_Height; + + float dt = gpGlobals->curtime - m_EnterPVSTime; + if (dt > EMP_GROW_TIME) + { + return; + } + + if (dt < 0) + dt = 0.0f; + + // Attenuate it up + w *= 1.0f - pow ( EMP_GROW_ATTEN, 10 * (dt / EMP_GROW_TIME )); + + if (w < EMP_MIN_WIDTH) + w = EMP_MIN_WIDTH; +} + +//----------------------------------------------------------------------------- +// A little pre-render processing +//----------------------------------------------------------------------------- + +void C_ShieldFlat::PreRender( ) +{ + // Compute the shield positions... + Vector right, up; + AngleVectors( GetRenderAngles(), &m_Forward, &right, &up ); + + float w, h; + ComputeSize( w, h ); + + VectorMA( GetRenderOrigin(), -w * 0.5, right, m_pPositions[0] ); + VectorMA( m_pPositions[0], -h * 0.5, up, m_pPositions[0] ); + VectorMA( m_pPositions[0], w, right, m_pPositions[1] ); + VectorMA( m_pPositions[0], h, up, m_pPositions[2] ); + VectorMA( m_pPositions[2], w, right, m_pPositions[3] ); + + ComputeEMPFade(); + ComputeDeathFade(); + + m_FadeValue = m_DeathFade * m_EMPFade; +} + +void C_ShieldFlat::AddEntity( ) +{ + BaseClass::AddEntity( ); + PreRender(); +} + +//----------------------------------------------------------------------------- +// Bounds computation +//----------------------------------------------------------------------------- + +void C_ShieldFlat::GetBounds( Vector& mins, Vector& maxs ) +{ + mins.Init( -1.0/16.0f, -m_Width * 0.5f, -m_Height * 0.5f ); + maxs.Init( 1.0/16.0f, m_Width * 0.5f, m_Height * 0.5f ); +} + +//----------------------------------------------------------------------------- +// Return true if the panel is active +//----------------------------------------------------------------------------- + +bool C_ShieldFlat::IsPanelActive( int x, int y ) +{ + return true; +} + +//----------------------------------------------------------------------------- +// Gets at the control point data; who knows how it was made? +//----------------------------------------------------------------------------- + +void C_ShieldFlat::GetShieldData( Vector const** ppVerts, float* pOpacity, float* pBlend ) +{ + for ( int i = 0; i < 4; ++i ) + { + ppVerts[i] = &m_pPositions[i]; + pOpacity[i] = 32.0f; + pBlend[i] = 0.0f; + } +} + +//----------------------------------------------------------------------------- +// Shield points +//----------------------------------------------------------------------------- +const Vector& C_ShieldFlat::GetPoint( int x, int y ) +{ + if ((m_LastAngles != GetAbsAngles()) || (m_LastPosition != GetAbsOrigin() )) + { + ShieldMoved(); + } + + int i = (x >= 1); + i += (y >= 1) * 2; + return m_Pos[i]; +} + +//----------------------------------------------------------------------------- +// Purpose: Computes the shield bounding box +//----------------------------------------------------------------------------- +void C_ShieldFlat::ShieldMoved( void ) +{ + Vector forward, right, up; + AngleVectors( GetAbsAngles(), &forward, &right, &up ); + + VectorMA( GetAbsOrigin(), -m_Width * 0.5, right, m_Pos[0] ); + VectorMA( m_Pos[0], -m_Height * 0.5, up, m_Pos[0] ); + VectorMA( m_Pos[0], m_Width, right, m_Pos[1] ); + VectorMA( m_Pos[0], m_Height, up, m_Pos[2] ); + VectorMA( m_Pos[2], m_Width, right, m_Pos[3] ); + + m_LastAngles = GetAbsAngles(); + m_LastPosition = GetAbsOrigin(); +} + +//----------------------------------------------------------------------------- +// Suppress rendering if the player owns it +//----------------------------------------------------------------------------- + +int C_ShieldFlat::DrawModel( int flags ) +{ + if ( !m_bReadyToDraw ) + return 0; + + // Don't draw it if the owner is the local player +// if ( m_OwnerEntity == C_BasePlayer::GetLocalPlayer()->index ) +// return 0; + + return BaseClass::DrawModel( flags ); +} + diff --git a/game/client/tf2/c_shield_mobile.cpp b/game/client/tf2/c_shield_mobile.cpp new file mode 100644 index 0000000..1de8592 --- /dev/null +++ b/game/client/tf2/c_shield_mobile.cpp @@ -0,0 +1,274 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client's sheild entity +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "C_Shield.h" +#include "tf_shieldshared.h" + +enum +{ + NUM_SUBDIVISIONS = 21, +}; + +#define EMP_WAVE_AMPLITUDE 8.0f + +//----------------------------------------------------------------------------- +// Mobile version of the shield +//----------------------------------------------------------------------------- + +class C_ShieldMobile; +class C_ShieldMobileActiveVertList : public IActiveVertList +{ +public: + void Init( C_ShieldMobile *pShield, unsigned char *pVertList ); + +// IActiveVertList overrides. +public: + + virtual int GetActiveVertState( int iVert ); + virtual void SetActiveVertState( int iVert, int bOn ); + +private: + C_ShieldMobile *m_pShield; + unsigned char *m_pVertsActive; +}; + + +class C_ShieldMobile : public C_Shield +{ + DECLARE_CLASS( C_ShieldMobile, C_Shield ); +public: + DECLARE_CLIENTCLASS(); + + C_ShieldMobile(); + ~C_ShieldMobile(); + + void OnDataChanged( DataUpdateType_t updateType ); + virtual void GetBounds( Vector& mins, Vector& maxs ); + + virtual void AddEntity( ); + + // Return true if the panel is active + virtual bool IsPanelActive( int x, int y ); + + // Gets at the control point data; who knows how it was made? + virtual void GetShieldData( Vector const** ppVerts, float* pOpacity, float* pBlend ); + virtual const Vector& GetPoint( int x, int y ) { return m_ShieldEffect.GetPoint( x, y ); } + + virtual void SetThetaPhi( float flTheta, float flPhi ) { m_ShieldEffect.SetThetaPhi(flTheta,flPhi); } + +public: + // networked data + unsigned char m_pVertsActive[SHIELD_VERTEX_BYTES]; + unsigned char m_ShieldState; + +private: + C_ShieldMobile( const C_ShieldMobile& ); + + // Is a particular panel an edge? + bool IsVertexValid( float s, float t ) const; + void PreRender( ); + +private: + CShieldEffect m_ShieldEffect; + C_ShieldMobileActiveVertList m_VertList; + float m_flTheta; + float m_flPhi; +}; + + +//----------------------------------------------------------------------------- +// C_ShieldMobileActiveVertList functions +//----------------------------------------------------------------------------- + +void C_ShieldMobileActiveVertList::Init( C_ShieldMobile *pShield, unsigned char *pVertList ) +{ + m_pShield = pShield; + m_pVertsActive = pVertList; +} + + +int C_ShieldMobileActiveVertList::GetActiveVertState( int iVert ) +{ + return m_pVertsActive[iVert>>3] & (1 << (iVert & 7)); +} + + +void C_ShieldMobileActiveVertList::SetActiveVertState( int iVert, int bOn ) +{ + if ( bOn ) + m_pVertsActive[iVert>>3] |= (1 << (iVert & 7)); + else + m_pVertsActive[iVert>>3] &= ~(1 << (iVert & 7)); +} + + +//----------------------------------------------------------------------------- +// Data table +//----------------------------------------------------------------------------- + +IMPLEMENT_CLIENTCLASS_DT(C_ShieldMobile, DT_Shield_Mobile, CShieldMobile) + + RecvPropInt( RECVINFO(m_ShieldState) ), + RecvPropArray( + RecvPropInt( RECVINFO(m_pVertsActive[0])), + m_pVertsActive + ), + RecvPropFloat( RECVINFO(m_flTheta) ), + RecvPropFloat( RECVINFO(m_flPhi) ), + +END_RECV_TABLE() + + +//----------------------------------------------------------------------------- +// Various raycasting routines +//----------------------------------------------------------------------------- + + +void ShieldTraceLine(const Vector &vecStart, const Vector &vecEnd, + unsigned int mask, int collisionGroup, trace_t *ptr) +{ + UTIL_TraceLine(vecStart, vecEnd, mask, NULL, collisionGroup, ptr ); +} + +void ShieldTraceHull(const Vector &vecStart, const Vector &vecEnd, + const Vector &hullMin, const Vector &hullMax, + unsigned int mask, int collisionGroup, trace_t *ptr) +{ + CTraceFilterWorldOnly traceFilter; + enginetrace->TraceHull( vecStart, vecEnd, hullMin, hullMax, mask, &traceFilter, ptr ); +} + + +//----------------------------------------------------------------------------- +// Constructor, destructor +//----------------------------------------------------------------------------- + +C_ShieldMobile::C_ShieldMobile() : m_ShieldEffect(ShieldTraceLine, ShieldTraceHull) +{ + m_VertList.Init( this, m_pVertsActive ); + m_ShieldEffect.SetActiveVertexList( &m_VertList ); + m_ShieldEffect.Spawn(vec3_origin, vec3_angle); + InitShield( SHIELD_NUM_HORIZONTAL_POINTS, SHIELD_NUM_VERTICAL_POINTS, NUM_SUBDIVISIONS ); +} + +C_ShieldMobile::~C_ShieldMobile() +{ +} + +//----------------------------------------------------------------------------- +// Get this after the data changes +//----------------------------------------------------------------------------- + +void C_ShieldMobile::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + m_ShieldEffect.SetCurrentPosition( GetAbsOrigin() ); + m_ShieldEffect.SetCurrentAngles( GetAbsAngles() ); + m_ShieldEffect.SetThetaPhi( m_flTheta, m_flPhi ); + + // No need to simulate, just compute active panels from network data + m_ShieldEffect.ComputeControlPoints(); + m_ShieldEffect.ComputePanelActivity(); +} + +//----------------------------------------------------------------------------- +// A little pre-render processing +//----------------------------------------------------------------------------- + +void C_ShieldMobile::PreRender( ) +{ + if (m_ShieldState & SHIELD_MOBILE_EMP) + { + // Decay fade if we've been EMPed or if we're inactive + if (m_FadeValue > 0.0f) + { + m_FadeValue -= gpGlobals->frametime / SHIELD_EMP_FADE_TIME; + if (m_FadeValue < 0.0f) + { + m_FadeValue = 0.0f; + + // Reset the shield to un-wobbled state + m_ShieldEffect.ComputeControlPoints(); + } + else + { + Vector dir; + AngleVectors( m_ShieldEffect.GetCurrentAngles(), & dir ); + + // Futz with the control points if we've been EMPed + for (int i = 0; i < SHIELD_NUM_CONTROL_POINTS; ++i) + { + // Get the direction for the point + float factor = -EMP_WAVE_AMPLITUDE * sin( i * M_PI * 0.5f + gpGlobals->curtime * M_PI / SHIELD_EMP_WOBBLE_TIME ); + m_ShieldEffect.GetPoint(i) += dir * factor; + } + } + } + } + else + { + // Fade back in, no longer EMPed + if (m_FadeValue < 1.0f) + { + m_FadeValue += gpGlobals->frametime / SHIELD_EMP_FADE_TIME; + if (m_FadeValue >= 1.0f) + { + m_FadeValue = 1.0f; + } + } + } +} + +void C_ShieldMobile::AddEntity( ) +{ + BaseClass::AddEntity( ); + PreRender(); +} + +//----------------------------------------------------------------------------- +// Bounds computation +//----------------------------------------------------------------------------- + +void C_ShieldMobile::GetBounds( Vector& mins, Vector& maxs ) +{ + m_ShieldEffect.ComputeBounds( mins, maxs ); +} + +//----------------------------------------------------------------------------- +// Return true if the panel is active +//----------------------------------------------------------------------------- + +bool C_ShieldMobile::IsPanelActive( int x, int y ) +{ + return m_ShieldEffect.IsPanelActive(x, y); +} + +//----------------------------------------------------------------------------- +// Gets at the control point data; who knows how it was made? +//----------------------------------------------------------------------------- + +void C_ShieldMobile::GetShieldData( Vector const** ppVerts, float* pOpacity, float* pBlend ) +{ + for ( int i = 0; i < SHIELD_NUM_CONTROL_POINTS; ++i ) + { + ppVerts[i] = &m_ShieldEffect.GetControlPoint(i); + + if ( m_pVertsActive[i >> 3] & (1 << (i & 0x7)) ) + { + pOpacity[i] = m_ShieldEffect.ComputeOpacity( *ppVerts[i], GetAbsOrigin() ); + pBlend[i] = 1.0f; + } + else + { + pOpacity[i] = 192.0f; + pBlend[i] = 0.0f; + } + } +} + diff --git a/game/client/tf2/c_tf2rootpanel.cpp b/game/client/tf2/c_tf2rootpanel.cpp new file mode 100644 index 0000000..7e01f6f --- /dev/null +++ b/game/client/tf2/c_tf2rootpanel.cpp @@ -0,0 +1,194 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "c_tf2rootpanel.h" +#include <vgui_controls/Controls.h> +#include <vgui/IVGui.h> +#include "paneleffect.h" +#include "itfhintitem.h" +#include "clientmode_commander.h" +#include "commanderoverlaypanel.h" + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *parent - +//----------------------------------------------------------------------------- +C_TF2RootPanel::C_TF2RootPanel( vgui::VPANEL parent ) + : BaseClass( NULL, "TF2 Root Panel" ) +{ + SetParent( parent ); + SetPaintEnabled( false ); + SetPaintBorderEnabled( false ); + SetPaintBackgroundEnabled( false ); + + // This panel does post child painting + SetPostChildPaintEnabled( true ); + + // Make it screen sized + SetBounds( 0, 0, ScreenWidth(), ScreenHeight() ); + + // Ask for OnTick messages + vgui::ivgui()->AddTickSignal( GetVPanel() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_TF2RootPanel::~C_TF2RootPanel( void ) +{ + ClearAllEffects(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_TF2RootPanel::PostChildPaint() +{ + BaseClass::PostChildPaint(); + + // Draw all panel effects + RenderPanelEffects(); +} + +//----------------------------------------------------------------------------- +// Purpose: For each panel effect, check if it wants to draw and draw it on +// this panel/surface if so +//----------------------------------------------------------------------------- +void C_TF2RootPanel::RenderPanelEffects( void ) +{ + for ( int i = 0; i < m_Effects.Size(); i++ ) + { + CPanelEffect *e = m_Effects[ i ]; + Assert( e ); + ITFHintItem *owner = e->GetOwner(); + if ( owner && !owner->ShouldRenderPanelEffects() ) + continue; + if ( e->GetVisible() ) + { + e->doPaint( this ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Add effect to list +// Input : *effect - +//----------------------------------------------------------------------------- +EFFECT_HANDLE C_TF2RootPanel::AddEffect( CPanelEffect *effect ) +{ + Assert( effect ); + + m_Effects.AddToTail( effect ); + + return effect->GetHandle(); +} + +//----------------------------------------------------------------------------- +// Purpose: Remove effect from list +// Input : *effect - +//----------------------------------------------------------------------------- +void C_TF2RootPanel::RemoveEffect( EFFECT_HANDLE handle ) +{ + for ( int i = m_Effects.Size() - 1; i >= 0; i-- ) + { + CPanelEffect *e = m_Effects[ i ]; + if ( e->GetHandle() == handle ) + { + m_Effects.Remove( i ); + delete e; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Find effect by handle +// Input : handle - +// Output : CPanelEffect +//----------------------------------------------------------------------------- +CPanelEffect *C_TF2RootPanel::FindEffect( EFFECT_HANDLE handle ) +{ + for ( int i = 0; i < m_Effects.Size(); i++ ) + { + CPanelEffect *e = m_Effects[ i ]; + if ( e->GetHandle() == handle ) + { + return e; + } + } + return NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: Delete all effects +//----------------------------------------------------------------------------- +void C_TF2RootPanel::ClearAllEffects( void ) +{ + while ( m_Effects.Size() > 0 ) + { + CPanelEffect *e = m_Effects[ 0 ]; + m_Effects.Remove( 0 ); + delete e; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_TF2RootPanel::OnTick( void ) +{ + // Go backards + for ( int i = m_Effects.Size() - 1; i >= 0; i-- ) + { + CPanelEffect *e = m_Effects[ i ]; + Assert( e ); + + // Allow panel to think + e->Think(); + + // See if panel should disappear + if ( e->ShouldRemove() ) + { + m_Effects.Remove( i ); + delete e; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Reset effects on level load/shutdown +//----------------------------------------------------------------------------- +void C_TF2RootPanel::LevelInit( void ) +{ + ClearAllEffects(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_TF2RootPanel::LevelShutdown( void ) +{ + ClearAllEffects(); +} + +//----------------------------------------------------------------------------- +// Purpose: Delete any panel effects owned by owner +// Input : *owner - +//----------------------------------------------------------------------------- +void C_TF2RootPanel::DestroyPanelEffects( ITFHintItem *owner ) +{ + for ( int i = m_Effects.Size() - 1; i >= 0; i-- ) + { + CPanelEffect *e = m_Effects[ i ]; + if ( e->GetOwner() == owner ) + { + m_Effects.Remove( i ); + delete e; + } + } +} + diff --git a/game/client/tf2/c_tf2rootpanel.h b/game/client/tf2/c_tf2rootpanel.h new file mode 100644 index 0000000..264475e --- /dev/null +++ b/game/client/tf2/c_tf2rootpanel.h @@ -0,0 +1,63 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_TF2ROOTPANEL_H +#define C_TF2ROOTPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include <vgui_controls/Panel.h> +#include <vgui_controls/EditablePanel.h> +#include "utlvector.h" + +class CPanelEffect; +class ITFHintItem; + +// Serial under of effect, for safe lookup +typedef unsigned int EFFECT_HANDLE; + +//----------------------------------------------------------------------------- +// Purpose: Sits between engine and client .dll panels +// Responsible for drawing screen overlays +//----------------------------------------------------------------------------- +class C_TF2RootPanel : public vgui::Panel +{ + typedef vgui::Panel BaseClass; +public: + C_TF2RootPanel( vgui::VPANEL parent ); + virtual ~C_TF2RootPanel( void ); + + // Draw Panel effects here + virtual void PostChildPaint(); + + // Clear list of Panel Effects + virtual void LevelInit( void ); + virtual void LevelShutdown( void ); + + // Panel Effect handlers + EFFECT_HANDLE AddEffect( CPanelEffect *effect ); + void RemoveEffect( EFFECT_HANDLE handle ); + CPanelEffect *FindEffect( EFFECT_HANDLE handle ); + void DestroyPanelEffects( ITFHintItem *owner ); + void ClearAllEffects( void ); + + // Run effects and let them decide whether to remove themselves + void OnTick( void ); + +private: + + // Render all panel effects + void RenderPanelEffects( void ); + + // List of current panel effects + CUtlVector< CPanelEffect *> m_Effects; +}; + +extern C_TF2RootPanel *g_pTF2RootPanel; + +#endif // C_TF2ROOTPANEL_H diff --git a/game/client/tf2/c_tf_basecombatweapon.cpp b/game/client/tf2/c_tf_basecombatweapon.cpp new file mode 100644 index 0000000..6408570 --- /dev/null +++ b/game/client/tf2/c_tf_basecombatweapon.cpp @@ -0,0 +1,310 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client's CBaseTFCombatWeapon +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_tf_basecombatweapon.h" +#include "hud.h" +#include "iclientmode.h" +#include "tf_hints.h" +#include "itfhintitem.h" +#include "c_tf_basehint.h" +#include "hud_technologytreedoc.h" +#include "c_tf_hintmanager.h" +#include "hud_ammo.h" +#include "c_weapon__stubs.h" +#include "c_tf_class_sapper.h" +#include <vgui/ISurface.h> + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +STUB_WEAPON_CLASS_IMPLEMENT( foo_tf_machine_gun, C_TFMachineGun ); + +IMPLEMENT_CLIENTCLASS_DT( C_TFMachineGun, DT_TFMachineGun, CTFMachineGun ) +END_RECV_TABLE() + +// Share crosshair stuff among all weapons +bool C_BaseTFCombatWeapon::m_bCrosshairInitialized = false; +vgui::Label *C_BaseTFCombatWeapon::m_pCrosshairAmmo = NULL; + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int C_BaseTFCombatWeapon::DrawModel( int flags ) +{ + int iDrawn = 0; + + // If my carrier is camouflaged, apply the camo to me too + if ( IsBeingCarried() ) + { + C_BaseTFPlayer *pPlayer = (C_BaseTFPlayer *)GetOwner(); + if ( pPlayer ) + { + if ( pPlayer->IsCamouflaged()) + { + if ( pPlayer->GetCamoMaterial() && ( pPlayer->ComputeCamoEffectAmount() != 1.0f ) ) + { + modelrender->ForcedMaterialOverride( pPlayer->GetCamoMaterial() ); + iDrawn = BaseClass::DrawModel(flags); + modelrender->ForcedMaterialOverride( NULL ); + } + return iDrawn; + } + } + } + + return BaseClass::DrawModel(flags); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int +//----------------------------------------------------------------------------- +int C_BaseTFCombatWeapon::GetFxBlend( void ) +{ + if ( !IsCamouflaged() ) + return BaseClass::GetFxBlend(); + + return ((C_BaseTFPlayer *)GetOwner())->GetFxBlend(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool C_BaseTFCombatWeapon::IsTransparent( void ) +{ + if ( IsCamouflaged() ) + return true; + + return BaseClass::IsTransparent(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : static void +//----------------------------------------------------------------------------- +void C_BaseTFCombatWeapon::CreateCrosshairPanels( void ) +{ + m_pCrosshairAmmo = new vgui::Label( (vgui::Panel *)NULL, "crosshairammo", "100" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseTFCombatWeapon::DestroyCrosshairPanels( void ) +{ + delete m_pCrosshairAmmo; + m_pCrosshairAmmo = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseTFCombatWeapon::InitializeCrosshairPanels( void ) +{ + // Init the crosshair labels if they haven't been + if ( m_bCrosshairInitialized ) + return; + + m_bCrosshairInitialized = true; + + vgui::Panel *pParent = g_pClientMode->GetViewport(); + m_pCrosshairAmmo->SetContentAlignment( vgui::Label::a_northeast ); + m_pCrosshairAmmo->SetFgColor( Color( 255, 170, 0, 255 ) ); + m_pCrosshairAmmo->SetPaintBackgroundEnabled( false ); + m_pCrosshairAmmo->SetPos( CROSSHAIR_AMMO_LEFT, CROSSHAIR_AMMO_TOP ); + m_pCrosshairAmmo->SetSize( CROSSHAIR_HEALTH_OFFSET / 2, m_pCrosshairAmmo->GetTall() ); + m_pCrosshairAmmo->SetParent( pParent ); + m_pCrosshairAmmo->SetAutoDelete( false ); +} + +//----------------------------------------------------------------------------- +// Purpose: Draw the ammo counts +//----------------------------------------------------------------------------- +void C_BaseTFCombatWeapon::DrawAmmo() +{ + // Get the local player + C_BaseTFPlayer *player = C_BaseTFPlayer::GetLocalPlayer(); + if ( player == NULL ) + return; + + GetHudAmmo()->SetPrimaryAmmo( + m_iPrimaryAmmoType, + GetPrimaryAmmo(), + Clip1(), + GetMaxClip1() ); + GetHudAmmo()->SetSecondaryAmmo( + m_iSecondaryAmmoType, + GetSecondaryAmmo(), + Clip2(), + GetMaxClip2() ); + + // ROBIN: Disabled mini ammo count for now + /* + InitializeCrosshairPanels(); + DrawMiniAmmo(); + */ + + // HACK: Draw technician's drain level + if ( IsLocalPlayerClass( TFCLASS_SAPPER ) ) + { + C_PlayerClassSapper *pSapper = (C_PlayerClassSapper *)player->GetPlayerClass(); + + int r, g, b, a; + int x, y; + + // Get the drained energy + float flPowerLevel = pSapper->m_flDrainedEnergy; + float flInverseFactor = 1.0 - flPowerLevel; + + gHUD.m_clrNormal.GetColor( r, g, b, a ); + + int iWidth = XRES(12); + int iHeight = YRES(64); + + x = XRES(64); + y = ( ScreenHeight() - YRES(2) - iHeight ); + + // draw the exhausted portion of the bar. + vgui::surface()->DrawSetColor( Color( r, g * flPowerLevel, b * flPowerLevel, 100 ) ); + vgui::surface()->DrawFilledRect( x, y, x + iWidth, y + iHeight * flInverseFactor ); + + // draw the powerered portion of the bar + vgui::surface()->DrawSetColor( Color( r, g * flPowerLevel, b * flPowerLevel, 190 ) ); + vgui::surface()->DrawFilledRect( x, y + iHeight * flInverseFactor, x + iWidth, y + iHeight * flInverseFactor + iHeight * flPowerLevel ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Draw the mini ammo/health counts around the health +//----------------------------------------------------------------------------- +void C_BaseTFCombatWeapon::DrawMiniAmmo() +{ + // Get the local player + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pPlayer == NULL ) + return; + + // Draw the ammo to the right of the crosshair + if ( m_iClip1 >= 0 ) + m_pCrosshairAmmo->SetText( VarArgs("%.3d", m_iClip1 < 999 ? m_iClip1 : 999) ); + else + m_pCrosshairAmmo->SetText( VarArgs("%.3d", GetPrimaryAmmo() < 999 ? GetPrimaryAmmo() : 999) ); + + // BUG: This shouldn't need to be reset, since it's set in the section above, on initialization + m_pCrosshairAmmo->SetSize( CROSSHAIR_HEALTH_OFFSET / 2, m_pCrosshairAmmo->GetTall() ); +} + +//----------------------------------------------------------------------------- +// Purpose: Return true if a weapon-pickup icon should be displayed when this weapon is received +//----------------------------------------------------------------------------- +bool C_BaseTFCombatWeapon::ShouldDrawPickup( void ) +{ + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : char const +//----------------------------------------------------------------------------- +const char *C_BaseTFCombatWeapon::GetPrintName( void ) +{ + return GetWpnData().szPrintName; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool C_BaseTFCombatWeapon::ShouldShowUsageHint( void ) +{ + return GetWpnData().bShowUsageHint; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : bnewentity - +//----------------------------------------------------------------------------- +void C_BaseTFCombatWeapon::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + if ( updateType != DATA_UPDATE_CREATED ) + return; + + if ( !ShouldShowUsageHint() ) + return; + + // See if the weapon is given as an associated weapon of a technology that + // is of level 1 or greater + CTechnologyTree *tree = GetTechnologyTreeDoc().GetTechnologyTree(); + if ( !tree ) + return; + + bool done = false; + for ( int i = 0; !done && ( i < tree->GetNumberTechnologies() ); i++ ) + { + CBaseTechnology *t = tree->GetTechnology( i ); + Assert( t ); + if ( !t ) + continue; + + // Must be associated with a tech >= level 1 + if ( t->GetLevel() < 1 ) + continue; + + for ( int j = 0; j < t->GetNumWeaponAssociations(); j++ ) + { + const char *associated_weapon = t->GetAssociatedWeapon( j ); + if ( !associated_weapon ) + continue; + + if ( !GetName() ) + continue; + + // Is this tech associating the weapon + if ( stricmp( GetName(), associated_weapon ) ) + continue; + + if ( t->GetHintsGiven( TF_HINT_WEAPONRECEIVED ) ) + continue; + + t->SetHintsGiven( TF_HINT_WEAPONRECEIVED, true ); + + // Fill in hint data for this weapon + // Only show a max of 3 or 4 weapon received hints at a time + C_TFBaseHint *hint = CreateGlobalHint( TF_HINT_WEAPONRECEIVED, GetPrintName(), -1, 3 ); + if ( hint ) + { + ITFHintItem *item = hint->GetHintItem( 0 ); + if ( item ) + { + item->SetKeyValue( "weapon", GetPrintName() ); + item->SetKeyValue( "weapontype", GetName() ); + } + } + + done = true; + break; + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int C_BaseTFCombatWeapon ::GetSecondaryAmmo( void ) +{ + // Get the local player + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pPlayer == NULL ) + return 0; + + return pPlayer->GetAmmoCount( m_iSecondaryAmmoType ); +} diff --git a/game/client/tf2/c_tf_basecombatweapon.h b/game/client/tf2/c_tf_basecombatweapon.h new file mode 100644 index 0000000..9ed6f52 --- /dev/null +++ b/game/client/tf2/c_tf_basecombatweapon.h @@ -0,0 +1,47 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Clients TF Base combat weapon +// +// $NoKeywords: $ +//=============================================================================// +#ifndef C_TF_BASECOMBATWEAPON_H +#define C_TF_BASECOMBATWEAPON_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_baseanimating.h" + +class CViewSetup; +class C_BaseTFPlayer; + +// Crosshair info positions +#define CROSSHAIR_HEALTH_TOP YRES(266) +#define CROSSHAIR_HEALTH_OFFSET XRES(80) +#define CROSSHAIR_HEALTH_LEFT ((ScreenWidth() - CROSSHAIR_HEALTH_OFFSET) / 2) +#define CROSSHAIR_AMMO_TOP CROSSHAIR_HEALTH_TOP +#define CROSSHAIR_AMMO_LEFT (ScreenWidth() / 2) + +namespace vgui +{ + class Label; +}; + +#include "basetfcombatweapon_shared.h" + +class C_TFMachineGun : public C_BaseTFCombatWeapon +{ +private: + DECLARE_CLASS( C_TFMachineGun, C_BaseTFCombatWeapon ); + +public: + C_TFMachineGun() {} + + DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); + +private: + C_TFMachineGun( const C_TFMachineGun & ); +}; + +#endif // C_TF_BASECOMBATWEAPON_H diff --git a/game/client/tf2/c_tf_basehint.cpp b/game/client/tf2/c_tf_basehint.cpp new file mode 100644 index 0000000..61c16c1 --- /dev/null +++ b/game/client/tf2/c_tf_basehint.cpp @@ -0,0 +1,691 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_tf_basehint.h" +#include "tf_hints.h" +#include "itfhintitem.h" +#include <vgui_controls/Controls.h> +#include <vgui/IVGui.h> +#include <vgui/Cursor.h> +#include <vgui_controls/Label.h> +#include <vgui/ISurface.h> +#include <vgui/IScheme.h> +#include "vgui_int.h" +#include "hintitembase.h" +#include <KeyValues.h> + +HINTCOMPLETIONFUNCTION LookupCompletionFunction( const char *name ); +//----------------------------------------------------------------------------- +// Purpose: +// Input : id - +// priority - +// player - +// entity - +//----------------------------------------------------------------------------- +C_TFBaseHint::C_TFBaseHint( int id, int priority, int entity, HINTCOMPLETIONFUNCTION pfn /*=NULL*/ ) + : vgui::Panel( NULL, "TFBaseHint" ), m_CursorNone( vgui::dc_none ) +{ + m_pObject = NULL; + m_pClearLabel = NULL; + m_pCaption = NULL; + m_pfnCompletion = pfn; + + // Child of main panel + SetParent( VGui_GetClientDLLRootPanel() ); + + // Put at top of z-order (happens in Think, too) +// MoveToFront(); + + // No cursor + SetCursor( m_CursorNone ); + // Set to default size + SetSize( TFBASEHINT_DEFAULT_WIDTH, TFBASEHINT_DEFAULT_HEIGHT ); + // We'll expressly delete it + SetAutoDelete( false ); + + // Set up default values + SetID( id ); + SetPriority( priority ); + SetEntity( entity ); + SetCompleted( false ); + // Target panel + m_hTarget = NULL; + + m_bMoving = false; + m_flMoveRemaining = 0.0f; + m_flMoveTotal = 0.0f; + + for ( int pt = 0; pt < 2; pt++ ) + { + m_nMoveStart[ pt ] = 0; + m_nMoveEnd[ pt ] = 0; + } + + vgui::ivgui()->AddTickSignal( GetVPanel() ); + + // Create clear label + m_pClearLabel = new vgui::Label( this, "CLEAR", "[Enter] to remove, [Enter] twice quickly to remove all..." ); + m_pClearLabel->SetContentAlignment( vgui::Label::a_west ); + m_pClearLabel->SetTextInset( 3, 2 ); + + // Create window caption + m_pCaption = new vgui::Label( this, "CAPTION", "" ); + m_pCaption->SetContentAlignment( vgui::Label::a_west ); + m_pCaption->SetTextInset( 3, 0 ); + + // See if the hint started out complete! + CheckForCompletion(); + + // Always start out hidden + SetVisible( false ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_TFBaseHint::~C_TFBaseHint( void ) +{ + RemoveAllHintItems( true ); +} + + +//----------------------------------------------------------------------------- +// Applying scheme settings +//----------------------------------------------------------------------------- +void C_TFBaseHint::ApplySchemeSettings(vgui::IScheme *pScheme) +{ + BaseClass::ApplySchemeSettings(pScheme); + + vgui::HFont hSmallFont = pScheme->GetFont( "DefaultVerySmall" ); + vgui::HFont hCaptionFont = pScheme->GetFont( "DefaultSmall" ); + m_pClearLabel->SetFont( hSmallFont ); + m_pCaption->SetFont( hCaptionFont ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pkv - +//----------------------------------------------------------------------------- +void C_TFBaseHint::ParseFromData( KeyValues *pkv ) +{ + int priority = pkv->GetInt( "priority", 100 ); + SetPriority( priority ); + int width = pkv->GetInt( "width", TFBASEHINT_DEFAULT_WIDTH ); + if ( !width && !stricmp( pkv->GetString( "width" ), "default" ) ) + { + width = TFBASEHINT_DEFAULT_WIDTH; + } + SetSize( width, TFBASEHINT_DEFAULT_HEIGHT ); + const char *title = pkv->GetString( "title" ); + if ( title ) + { + SetTitle( title ); + } + + const char *completionfunction = pkv->GetString( "completionfunction" ); + if ( completionfunction && strlen( completionfunction ) > 0 ) + { + SetCompletionFunction( LookupCompletionFunction( completionfunction ) ); + } + + KeyValues *items = pkv->FindKey( "items" ); + if ( items ) + { + KeyValues *pkvItem = items->GetFirstSubKey(); + for( ; pkvItem ; pkvItem = pkvItem->GetNextKey() ) + { + CHintItemBase *item = CreateHintItem( this, pkvItem->GetName() ); + if ( item ) + { + item->ParseItem( pkvItem ); + item->ComputeTitle(); + + item->SetSize( GetWide(), 20 ); + + AddHintItem( item ); + } + else + { + Msg( "C_TFBaseHint::ParseFromData: Failed to create hint item %s\n", pkvItem->GetName() ); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : int&x - +// y - +// w - +// &h - +//----------------------------------------------------------------------------- +void C_TFBaseHint::GetClientArea( int&x, int& y, int& w, int &h ) +{ + GetSize( w, h ); + + x = BORDER; + y = BORDER + CAPTION; + + w -= 2 * BORDER; + h -= 2 * BORDER; + + h -= CAPTION; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *title - +//----------------------------------------------------------------------------- +void C_TFBaseHint::SetTitle( const char *title ) +{ + if ( m_pCaption ) + { + m_pCaption->SetText( title ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_TFBaseHint::PaintBackground() +{ + SetBgColor( Color( 240, 240, 220, 255 ) ); + if ( m_pCaption ) + { + m_pCaption->SetBgColor( Color( 163, 180, 200, 255 ) ); + + m_pCaption->SetFgColor( Color( 0, 0, 0, 255 ) ); + } + if ( m_pClearLabel ) + { + m_pClearLabel->SetBgColor( Color( 230, 230, 210, 255 ) ); + m_pClearLabel->SetFgColor( Color( 100, 127, 160, 255 ) ); + } + + BaseClass::PaintBackground(); + + int w, h; + GetSize( w, h ); + + vgui::surface()->DrawSetColor( 0, 0, 0, 255 ); + vgui::surface()->DrawOutlinedRect( 0, 0, w, h ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_TFBaseHint::PerformLayout() +{ + BaseClass::PerformLayout(); + + int x, y, w, h; + GetClientArea( x, y, w, h ); + + int itemh; + + int needY = 4; + + for ( int i = 0; i < GetNumHintItems(); i++ ) + { + ITFHintItem *item = GetHintItem( i ); + if ( item ) + { + itemh = item->GetHeight(); + + item->SetPosition( x, y + 2 ); + item->SetItemNumber( i + 1 ); + + if ( i == 0 ) + { + item->SetVisible( true ); + needY += itemh + 2; + } + else + { + item->SetVisible( false ); + } + } + } + + needY += 8; + + if ( m_pClearLabel ) + { + m_pClearLabel->SetBounds( x, y + needY + 2, w, 14 ); + } + + if ( m_pCaption ) + { + m_pCaption->SetBounds( x, BORDER, w, CAPTION ); + } + + needY += 14 + BORDER; + + int needPixels = needY - h; + + int trueW, trueH; + GetSize( trueW, trueH ); + + SetSize( trueW, trueH + needPixels ); +} + +//----------------------------------------------------------------------------- +// Purpose: Install completion function +// Input : pfn - +//----------------------------------------------------------------------------- +void C_TFBaseHint::SetCompletionFunction( HINTCOMPLETIONFUNCTION pfn ) +{ + m_pfnCompletion = pfn; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_TFBaseHint::CheckForCompletion( void ) +{ + if ( m_pfnCompletion ) + { + bool complete = (*m_pfnCompletion)( this ); + if ( complete ) + { + SetCompleted( true ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_TFBaseHint::OnTick() +{ + if ( !IsVisible() ) + return; + +// MoveToFront(); + + // Check for completion of entire hint + CheckForCompletion(); + + bool setactive = false; + int numactive = 0; + // Remove obsolete items + int i; + for ( i = m_Hints.Size() - 1; i >= 0; i-- ) + { + ITFHintItem *item = m_Hints[ i ]; + if ( !item ) + continue; + + if ( item->GetCompleted() ) + { + RemoveHintItem( i ); + } + else + { + numactive++; + } + } + + // Mark first one as active + // Perform think + for ( i = 0; i < m_Hints.Size(); i++ ) + { + ITFHintItem *item = m_Hints[ i ]; + if ( !item ) + continue; + + if ( !setactive ) + { + item->SetActive( true ); + setactive = true; + } + else + { + item->SetActive( false ); + } + + // Think, too + if ( item->GetActive() ) + { + item->Think(); + } + } + + // No more active items + if ( !numactive ) + { + SetCompleted( true ); + } + + // Keep moving window to correct position + AnimatePosition(); + +/* + static float nextchange = 0.0f; + + if ( gpGlobals->curtime < nextchange ) + return; + + nextchange = gpGlobals->curtime + 1.0f; + + int w, h; + GetSize( w, h ); + + int x = random->RandomInt( 0, ScreenWidth() - w ); + int y = random->RandomInt( 0, ScreenHeight() - h ); + + SetDesiredPosition( x, y, 0.9f ); +*/ +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int +//----------------------------------------------------------------------------- +int C_TFBaseHint::GetID( void ) +{ + return m_nID; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : id - +//----------------------------------------------------------------------------- +void C_TFBaseHint::SetID( int id ) +{ + m_nID = id; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int +//----------------------------------------------------------------------------- +int C_TFBaseHint::GetPriority( void ) +{ + return m_nPriority; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : priority - +//----------------------------------------------------------------------------- +void C_TFBaseHint::SetPriority( int priority ) +{ + m_nPriority = priority; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int +//----------------------------------------------------------------------------- +int C_TFBaseHint::GetEntity( void ) +{ + return m_nEntity; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : C_BaseEntity +//----------------------------------------------------------------------------- +C_BaseEntity *C_TFBaseHint::GetBaseEntity( void ) +{ + return m_nEntity != -1 ? cl_entitylist->GetEnt( m_nEntity ) : NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : entity - +//----------------------------------------------------------------------------- +void C_TFBaseHint::SetEntity( int entity ) +{ + m_nEntity = entity; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *entity - +//----------------------------------------------------------------------------- +void C_TFBaseHint::SetBaseEntity( C_BaseEntity *entity ) +{ + m_nEntity = entity ? entity->index : -1; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool C_TFBaseHint::GetCompleted( void ) +{ + return m_bCompleted; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : completed - +//----------------------------------------------------------------------------- +void C_TFBaseHint::SetCompleted( bool completed ) +{ + m_bCompleted = completed; + // Hide the window right away if it's finished + SetVisible( !completed ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *item - +//----------------------------------------------------------------------------- +void C_TFBaseHint::AddHintItem( ITFHintItem *item ) +{ + m_Hints.AddToTail( item ); + InvalidateLayout(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : index - +//----------------------------------------------------------------------------- +void C_TFBaseHint::RemoveHintItem( int index ) +{ + ITFHintItem *item = GetHintItem( index ); + if ( item ) + { + m_Hints.Remove( index ); + item->DeleteThis(); + InvalidateLayout(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int +//----------------------------------------------------------------------------- +int C_TFBaseHint::GetNumHintItems( void ) +{ + return m_Hints.Size(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : deleteitems - +//----------------------------------------------------------------------------- +void C_TFBaseHint::RemoveAllHintItems( bool deleteitems ) +{ + while ( m_Hints.Size() > 0 ) + { + ITFHintItem *item = m_Hints[ 0 ]; + m_Hints.Remove( 0 ); + if ( deleteitems ) + { + item->DeleteThis(); + } + } + + InvalidateLayout(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : index - +//----------------------------------------------------------------------------- +ITFHintItem *C_TFBaseHint::GetHintItem( int index ) +{ + if ( index < 0 || index >= m_Hints.Size() ) + { + return NULL; + } + + return m_Hints[ index ]; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : x - +// y - +// movementtime - +//----------------------------------------------------------------------------- +void C_TFBaseHint::SetDesiredPosition( int x, int y, float movementtime /*=0.3f*/ ) +{ + m_bMoving = true; + + m_flMoveRemaining = movementtime; + m_flMoveTotal = movementtime; + + int ox, oy; + GetPos( ox, oy ); + + m_nMoveStart[ 0 ] = ox; + m_nMoveStart[ 1 ] = oy; + + m_nMoveEnd[ 0 ] = x; + m_nMoveEnd[ 1 ] = y; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : float +//----------------------------------------------------------------------------- +float C_TFBaseHint::GetMovementFraction( void ) +{ + float frac = 0.0f; + + if ( m_flMoveTotal > 0.0f ) + { + frac = 1.0f - ( m_flMoveRemaining / m_flMoveTotal ); + } + + float squared = frac * frac; + + frac = 3 * squared - 2 * frac * squared; + + // Simple spline + frac = clamp( frac, 0.0f, 1.0f ); + + return frac; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_TFBaseHint::AnimatePosition( void ) +{ + if ( !m_bMoving ) + return; + + m_flMoveRemaining -= gpGlobals->frametime; + if ( m_flMoveRemaining <= 0.0f ) + { + m_bMoving = false; + SetPos( m_nMoveEnd[ 0 ], m_nMoveEnd[ 1 ] ); + return; + } + + float frac = GetMovementFraction(); + + int dx = m_nMoveEnd[ 0 ] - m_nMoveStart[ 0 ]; + int dy = m_nMoveEnd[ 1 ] - m_nMoveStart[ 1 ]; + + int x, y; + + x = m_nMoveStart[ 0 ] + ( int )( frac * dx ); + y = m_nMoveStart[ 1 ] + ( int )( frac * dy ); + + SetPos( x, y ); +} + +//----------------------------------------------------------------------------- +// Purpose: Helper to center a panel +// Input : *panel - +// Output : static void +//----------------------------------------------------------------------------- +static void PositionHintNoTarget( C_TFBaseHint *panel ) +{ + int w, h; + panel->GetSize( w, h ); + int y = ( ScreenHeight() - h ) / 2; + + panel->SetDesiredPosition( ScreenWidth() - w - 10, y ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *panel - +//----------------------------------------------------------------------------- +void C_TFBaseHint::SetHintTarget( vgui::Panel *panel ) +{ + m_hTarget = panel; + + if ( panel ) + { + int hintW, hintH; + + GetSize( hintW, hintH ); + + int x, y, w, h; + panel->GetBounds( x, y, w, h ); + + // Try and position ourselves up and to left of target item? + x = x - ( hintW - w ); + y = y - ( hintH ) - 40; + + // Don't let it hang off screen + if ( x < 3 ) + { + x = 3; + } + else if ( x + hintW + 3 >= ScreenWidth() ) + { + int over = ( x + hintW + 3 - ScreenWidth() ); + + x -= over; + } + + if ( y < 3 ) + { + y = 3; + } + else if ( y + hintH >= ScreenHeight() ) + { + int over = ( y + hintH + 3 - ScreenHeight() ); + + y -= over; + } + + SetDesiredPosition( x, y ); + } + else + { + PositionHintNoTarget( this ); + } + + // Tell hint items that there is a new target + for ( int i = 0 ; i < GetNumHintItems(); i++ ) + { + ITFHintItem *item = GetHintItem( i ); + item->SetHintTarget( panel ); + } +} diff --git a/game/client/tf2/c_tf_basehint.h b/game/client/tf2/c_tf_basehint.h new file mode 100644 index 0000000..3263673 --- /dev/null +++ b/game/client/tf2/c_tf_basehint.h @@ -0,0 +1,147 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_TF_BASEHINT_H +#define C_TF_BASEHINT_H +#ifdef _WIN32 +#pragma once +#endif + +#include <vgui_controls/Panel.h> +#include <vgui_controls/PHandle.h> +#include "utlvector.h" + +class C_BaseTFPlayer; +class C_BaseEntity; +class ITFHintItem; +class KeyValues; +namespace vgui +{ + class Label; +} + +class C_TFBaseHint; + +typedef bool (*HINTCOMPLETIONFUNCTION)( C_TFBaseHint *hint ); + +#define TFBASEHINT_DEFAULT_WIDTH 400 +#define TFBASEHINT_DEFAULT_HEIGHT 300 + +//----------------------------------------------------------------------------- +// Purpose: Base TF Hint UI Element +// hints must position themselves and are responsible for any "sub objects" +//----------------------------------------------------------------------------- +class C_TFBaseHint : public vgui::Panel +{ + typedef vgui::Panel BaseClass; +public: + enum + { + BORDER = 2, + CAPTION = 17 + }; + + // Factory for hints + static C_TFBaseHint *CreateHint( int id, const char *subsection, int entity ); + + // Construction + C_TFBaseHint( int id, int priority, int entity, HINTCOMPLETIONFUNCTION pfn = NULL ); + virtual ~C_TFBaseHint( void ); + + // Initialization + virtual void ParseFromData( KeyValues *pkv ); + + // Redraw self + virtual void PaintBackground(); + virtual void PerformLayout(); + virtual void GetClientArea( int&x, int& y, int& w, int &h ); + virtual void SetTitle( const char *title ); + + // Panel will move itself to spot over movementtime + virtual void SetDesiredPosition( int x, int y, float movementtime = 0.3f ); + + // Target element for hint + virtual void SetHintTarget( vgui::Panel *panel ); + + // Scheme + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + + // Think + virtual void OnTick(); + // Derived classes should set m_bCompleted here for entire hint + virtual void CheckForCompletion( void ); + + // Data access + virtual int GetID( void ); + virtual void SetID( int id ); + + virtual int GetPriority( void ); + virtual void SetPriority( int priority ); + + virtual int GetEntity( void ); + virtual C_BaseEntity *GetBaseEntity( void ); + virtual void SetEntity( int entity ); + virtual void SetBaseEntity( C_BaseEntity *entity ); + + // Install a function used to determine if the global hint requirements have + // been met + virtual bool GetCompleted( void ); + virtual void SetCompleted( bool completed ); + virtual void SetCompletionFunction( HINTCOMPLETIONFUNCTION pfn ); + + // Accessors for hint items themselves + virtual void AddHintItem( ITFHintItem *item ); + virtual void RemoveHintItem( int index ); + virtual int GetNumHintItems( void ); + virtual void RemoveAllHintItems( bool deleteitems ); + virtual ITFHintItem *GetHintItem( int index ); + +protected: + // Move current position toward desirec position + virtual void AnimatePosition( void ); + virtual float GetMovementFraction( void ); + + // In the process of moving + bool m_bMoving; + + // Amount of move time remaining + float m_flMoveRemaining; + // Total move time + float m_flMoveTotal; + // Start/end positions for panel movement + int m_nMoveStart[2]; + int m_nMoveEnd[2]; + +private: + // ID of the hint + int m_nID; + // Priority of the hint + int m_nPriority; + // Associated entity + int m_nEntity; + // Has the hint been completed + bool m_bCompleted; + // Object hint is associated with + void *m_pObject; + // No mouse + vgui::HCursor m_CursorNone; + // "Press [Esc]..." + vgui::Label *m_pClearLabel; + // Window caption + vgui::Label *m_pCaption; + + // Safe handle to target object + vgui::PHandle m_hTarget; + + // Completion function + HINTCOMPLETIONFUNCTION m_pfnCompletion; + + // List of items + CUtlVector< ITFHintItem * > m_Hints; +}; + +#endif // C_TF_BASEHINT_H diff --git a/game/client/tf2/c_tf_class_commando.cpp b/game/client/tf2/c_tf_class_commando.cpp new file mode 100644 index 0000000..4d5e78c --- /dev/null +++ b/game/client/tf2/c_tf_class_commando.cpp @@ -0,0 +1,136 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_tf_class_commando.h" +#include "usercmd.h" + +//============================================================================= +// +// Commando Data Table +// +BEGIN_RECV_TABLE_NOBASE( C_PlayerClassCommando, DT_PlayerClassCommandoData ) + RecvPropInt ( RECVINFO( m_ClassData.m_bCanBullRush ) ), + RecvPropInt ( RECVINFO( m_ClassData.m_bBullRush ) ), + RecvPropVector ( RECVINFO( m_ClassData.m_vecBullRushDir ) ), + RecvPropVector ( RECVINFO( m_ClassData.m_vecBullRushViewDir ) ), + RecvPropVector ( RECVINFO( m_ClassData.m_vecBullRushViewGoalDir ) ), + RecvPropFloat ( RECVINFO( m_ClassData.m_flBullRushTime ) ), + RecvPropFloat ( RECVINFO( m_ClassData.m_flDoubleTapForwardTime ) ), +END_RECV_TABLE() + +BEGIN_PREDICTION_DATA_NO_BASE( C_PlayerClassCommando ) + + DEFINE_PRED_TYPEDESCRIPTION( m_ClassData, PlayerClassCommandoData_t ), + +END_PREDICTION_DATA() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PlayerClassCommando::C_PlayerClassCommando( C_BaseTFPlayer *pPlayer ) : + C_PlayerClass( pPlayer ) +{ + m_ClassData.m_bCanBullRush = false; + m_ClassData.m_bBullRush = false; + m_ClassData.m_vecBullRushDir.Init(); + m_ClassData.m_vecBullRushViewDir.Init(); + m_ClassData.m_vecBullRushViewGoalDir.Init(); + m_ClassData.m_flBullRushTime = COMMANDO_TIME_INVALID; + m_ClassData.m_flDoubleTapForwardTime = COMMANDO_TIME_INVALID; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PlayerClassCommando::~C_PlayerClassCommando() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PlayerClassCommando::ClassThink( void ) +{ + CheckBullRushState(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PlayerClassCommando::PostClassThink( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PlayerClassCommando::ClassPreDataUpdate( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PlayerClassCommando::ClassOnDataChanged( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PlayerClassCommando::CreateMove( float flInputSampleTime, CUserCmd *pCmd ) +{ + if ( m_ClassData.m_bBullRush ) + { + pCmd->viewangles = m_ClassData.m_vecBullRushViewDir; + QAngle angles = m_ClassData.m_vecBullRushViewDir; + engine->SetViewAngles( angles ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_PlayerClassCommando::CanGetInVehicle( void ) +{ + if ( m_ClassData.m_bBullRush ) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PlayerClassCommando::CheckBullRushState( void ) +{ + if ( m_ClassData.m_bBullRush ) + { + InterpolateBullRushViewAngles(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PlayerClassCommando::InterpolateBullRushViewAngles( void ) +{ + // Determine the fraction. + if ( m_ClassData.m_flBullRushTime < COMMANDO_BULLRUSH_VIEWDELTA_TEST ) + { + m_ClassData.m_vecBullRushViewDir = m_ClassData.m_vecBullRushViewGoalDir; + return; + } + + float flFraction = 1.0f - ( ( m_ClassData.m_flBullRushTime - COMMANDO_BULLRUSH_VIEWDELTA_TEST ) / COMMANDO_BULLRUSH_VIEWDELTA_TIME ); + + QAngle angCurrent; + InterpolateAngles( m_ClassData.m_vecBullRushViewDir, m_ClassData.m_vecBullRushViewGoalDir, angCurrent, flFraction ); + + NormalizeAngles( angCurrent ); + m_ClassData.m_vecBullRushViewDir = angCurrent; +} diff --git a/game/client/tf2/c_tf_class_commando.h b/game/client/tf2/c_tf_class_commando.h new file mode 100644 index 0000000..9ce42de --- /dev/null +++ b/game/client/tf2/c_tf_class_commando.h @@ -0,0 +1,50 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_TF_CLASS_COMMANDO_H +#define C_TF_CLASS_COMMANDO_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_tf_playerclass.h" +#include "dt_recv.h" + +class C_PlayerClassCommando : public C_PlayerClass +{ +public: + + DECLARE_CLASS( C_PlayerClassCommando, C_PlayerClass ); + + DECLARE_PREDICTABLE(); + + C_PlayerClassCommando( C_BaseTFPlayer *pPlayer ); + virtual ~C_PlayerClassCommando(); + + PlayerClassCommandoData_t *GetClassData( void ) { return &m_ClassData; } + + void ClassThink( void ); + void PostClassThink( void ); + void ClassPreDataUpdate( void ); + void ClassOnDataChanged( void ); + + void CreateMove( float flInputSampleTime, CUserCmd *pCmd ); + + // Vehicles + bool CanGetInVehicle( void ); + + PlayerClassCommandoData_t m_ClassData; + +private: + + void CheckBullRushState( void ); + void InterpolateBullRushViewAngles( void ); +}; + +EXTERN_RECV_TABLE( DT_PlayerClassCommandoData ) + +#endif // C_TF_CLASS_COMMANDO_H
\ No newline at end of file diff --git a/game/client/tf2/c_tf_class_defender.cpp b/game/client/tf2/c_tf_class_defender.cpp new file mode 100644 index 0000000..e375aaf --- /dev/null +++ b/game/client/tf2/c_tf_class_defender.cpp @@ -0,0 +1,36 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_tf_class_defender.h" + +//============================================================================= +// +// Defender Data Table +// +BEGIN_RECV_TABLE_NOBASE( C_PlayerClassDefender, DT_PlayerClassDefenderData ) +END_RECV_TABLE() + +BEGIN_PREDICTION_DATA_NO_BASE( C_PlayerClassDefender ) + + DEFINE_PRED_TYPEDESCRIPTION( m_ClassData, PlayerClassDefenderData_t ), + +END_PREDICTION_DATA() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PlayerClassDefender::C_PlayerClassDefender( C_BaseTFPlayer *pPlayer ) : + C_PlayerClass( pPlayer ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PlayerClassDefender::~C_PlayerClassDefender() +{ +} diff --git a/game/client/tf2/c_tf_class_defender.h b/game/client/tf2/c_tf_class_defender.h new file mode 100644 index 0000000..a6cb73a --- /dev/null +++ b/game/client/tf2/c_tf_class_defender.h @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_TF_CLASS_DEFENDER_H +#define C_TF_CLASS_DEFENDER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_tf_playerclass.h" +#include "dt_recv.h" + +class C_PlayerClassDefender : public C_PlayerClass +{ + + DECLARE_CLASS( C_PlayerClassDefender, C_PlayerClass ); + +public: + + DECLARE_PREDICTABLE(); + + C_PlayerClassDefender( C_BaseTFPlayer *pPlayer ); + virtual ~C_PlayerClassDefender(); + + PlayerClassDefenderData_t *GetClassData( void ) { return &m_ClassData; } + +protected: + + PlayerClassDefenderData_t m_ClassData; +}; + +EXTERN_RECV_TABLE( DT_PlayerClassDefenderData ) + +#endif // C_TF_CLASS_DEFENDER_H
\ No newline at end of file diff --git a/game/client/tf2/c_tf_class_escort.cpp b/game/client/tf2/c_tf_class_escort.cpp new file mode 100644 index 0000000..84e7907 --- /dev/null +++ b/game/client/tf2/c_tf_class_escort.cpp @@ -0,0 +1,36 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_tf_class_escort.h" + +//============================================================================= +// +// Escort Data Table +// +BEGIN_RECV_TABLE_NOBASE( C_PlayerClassEscort, DT_PlayerClassEscortData ) +END_RECV_TABLE() + +BEGIN_PREDICTION_DATA_NO_BASE( C_PlayerClassEscort ) + + DEFINE_PRED_TYPEDESCRIPTION( m_ClassData, PlayerClassEscortData_t ), + +END_PREDICTION_DATA() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PlayerClassEscort::C_PlayerClassEscort( C_BaseTFPlayer *pPlayer ) : + C_PlayerClass( pPlayer ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PlayerClassEscort::~C_PlayerClassEscort() +{ +}
\ No newline at end of file diff --git a/game/client/tf2/c_tf_class_escort.h b/game/client/tf2/c_tf_class_escort.h new file mode 100644 index 0000000..c906764 --- /dev/null +++ b/game/client/tf2/c_tf_class_escort.h @@ -0,0 +1,37 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_TF_CLASS_ESCORT_H +#define C_TF_CLASS_ESCORT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_tf_playerclass.h" +#include "dt_recv.h" + +class C_PlayerClassEscort : public C_PlayerClass +{ + + DECLARE_CLASS( C_PlayerClassEscort, C_PlayerClass ); + +public: + + C_PlayerClassEscort( C_BaseTFPlayer *pPlayer ); + virtual ~C_PlayerClassEscort(); + + DECLARE_PREDICTABLE(); + PlayerClassEscortData_t *GetClassData( void ) { return &m_ClassData; } + +protected: + + PlayerClassEscortData_t m_ClassData; +}; + +EXTERN_RECV_TABLE( DT_PlayerClassEscortData ) + +#endif // C_TF_CLASS_ESCORT_H
\ No newline at end of file diff --git a/game/client/tf2/c_tf_class_infiltrator.cpp b/game/client/tf2/c_tf_class_infiltrator.cpp new file mode 100644 index 0000000..129cdcc --- /dev/null +++ b/game/client/tf2/c_tf_class_infiltrator.cpp @@ -0,0 +1,36 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_tf_class_infiltrator.h" + +//============================================================================= +// +// Infiltrator Data Table +// +BEGIN_RECV_TABLE_NOBASE( C_PlayerClassInfiltrator, DT_PlayerClassInfiltratorData ) +END_RECV_TABLE() + +BEGIN_PREDICTION_DATA_NO_BASE( C_PlayerClassInfiltrator ) + + DEFINE_PRED_TYPEDESCRIPTION( m_ClassData, PlayerClassInfiltratorData_t ), + +END_PREDICTION_DATA() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PlayerClassInfiltrator::C_PlayerClassInfiltrator( C_BaseTFPlayer *pPlayer ) : + C_PlayerClass( pPlayer ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PlayerClassInfiltrator::~C_PlayerClassInfiltrator() +{ +}
\ No newline at end of file diff --git a/game/client/tf2/c_tf_class_infiltrator.h b/game/client/tf2/c_tf_class_infiltrator.h new file mode 100644 index 0000000..d91f0cc --- /dev/null +++ b/game/client/tf2/c_tf_class_infiltrator.h @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_TF_CLASS_INFILTRATOR_H +#define C_TF_CLASS_INFILTRATOR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_tf_playerclass.h" +#include "dt_recv.h" + +class C_PlayerClassInfiltrator : public C_PlayerClass +{ + + DECLARE_CLASS( C_PlayerClassInfiltrator, C_PlayerClass ); + +public: + + C_PlayerClassInfiltrator( C_BaseTFPlayer *pPlayer ); + virtual ~C_PlayerClassInfiltrator(); + + DECLARE_PREDICTABLE(); + + PlayerClassInfiltratorData_t *GetClassData( void ) { return &m_ClassData; } + +protected: + + PlayerClassInfiltratorData_t m_ClassData; +}; + +EXTERN_RECV_TABLE( DT_PlayerClassInfiltratorData ) + +#endif // C_TF_CLASS_INFILTRATOR_H
\ No newline at end of file diff --git a/game/client/tf2/c_tf_class_medic.cpp b/game/client/tf2/c_tf_class_medic.cpp new file mode 100644 index 0000000..3015929 --- /dev/null +++ b/game/client/tf2/c_tf_class_medic.cpp @@ -0,0 +1,37 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_tf_class_medic.h" + +//============================================================================= +// +// Medic Data Table +// +BEGIN_RECV_TABLE_NOBASE( C_PlayerClassMedic, DT_PlayerClassMedicData ) +END_RECV_TABLE() + +BEGIN_PREDICTION_DATA_NO_BASE( C_PlayerClassMedic ) + + DEFINE_PRED_TYPEDESCRIPTION( m_ClassData, PlayerClassMedicData_t ), + +END_PREDICTION_DATA() + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PlayerClassMedic::C_PlayerClassMedic( C_BaseTFPlayer *pPlayer ) : + C_PlayerClass( pPlayer ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PlayerClassMedic::~C_PlayerClassMedic() +{ +}
\ No newline at end of file diff --git a/game/client/tf2/c_tf_class_medic.h b/game/client/tf2/c_tf_class_medic.h new file mode 100644 index 0000000..dffaa02 --- /dev/null +++ b/game/client/tf2/c_tf_class_medic.h @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_TF_CLASS_MEDIC_H +#define C_TF_CLASS_MEDIC_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_tf_playerclass.h" +#include "dt_recv.h" + +class C_PlayerClassMedic : public C_PlayerClass +{ + + DECLARE_CLASS( C_PlayerClassMedic, C_PlayerClass ); + +public: + + C_PlayerClassMedic( C_BaseTFPlayer *pPlayer ); + virtual ~C_PlayerClassMedic(); + + DECLARE_PREDICTABLE(); + + PlayerClassMedicData_t *GetClassData( void ) { return &m_ClassData; } + +protected: + + PlayerClassMedicData_t m_ClassData; +}; + +EXTERN_RECV_TABLE( DT_PlayerClassMedicData ) + +#endif // C_TF_CLASS_MEDIC_H
\ No newline at end of file diff --git a/game/client/tf2/c_tf_class_pyro.cpp b/game/client/tf2/c_tf_class_pyro.cpp new file mode 100644 index 0000000..c8600db --- /dev/null +++ b/game/client/tf2/c_tf_class_pyro.cpp @@ -0,0 +1,44 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_tf_class_pyro.h" + +//============================================================================= +// +// Medic Data Table +// +BEGIN_RECV_TABLE_NOBASE( C_PlayerClassPyro, DT_PlayerClassPyroData ) +END_RECV_TABLE() + +BEGIN_PREDICTION_DATA_NO_BASE( C_PlayerClassPyro ) + + DEFINE_PRED_TYPEDESCRIPTION( m_ClassData, PlayerClassPyroData_t ), + +END_PREDICTION_DATA() + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PlayerClassPyro::C_PlayerClassPyro( C_BaseTFPlayer *pPlayer ) : + C_PlayerClass( pPlayer ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PlayerClassPyro::~C_PlayerClassPyro() +{ +} + + +PlayerClassPyroData_t* C_PlayerClassPyro::GetClassData() +{ + return &m_ClassData; +} + diff --git a/game/client/tf2/c_tf_class_pyro.h b/game/client/tf2/c_tf_class_pyro.h new file mode 100644 index 0000000..64365f4 --- /dev/null +++ b/game/client/tf2/c_tf_class_pyro.h @@ -0,0 +1,41 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_TF_CLASS_PYRO_H +#define C_TF_CLASS_PYRO_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "c_tf_playerclass.h" +#include "dt_recv.h" + + +class C_PlayerClassPyro : public C_PlayerClass +{ +public: + + DECLARE_CLASS( C_PlayerClassPyro, C_PlayerClass ); + DECLARE_PREDICTABLE(); + + + C_PlayerClassPyro( C_BaseTFPlayer *pPlayer ); + virtual ~C_PlayerClassPyro(); + + PlayerClassPyroData_t *GetClassData(); + + +protected: + + PlayerClassPyroData_t m_ClassData; +}; + +EXTERN_RECV_TABLE( DT_PlayerClassPyroData ) + + +#endif // C_TF_CLASS_PYRO_H diff --git a/game/client/tf2/c_tf_class_recon.cpp b/game/client/tf2/c_tf_class_recon.cpp new file mode 100644 index 0000000..0a615ce --- /dev/null +++ b/game/client/tf2/c_tf_class_recon.cpp @@ -0,0 +1,54 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_tf_class_recon.h" + +//============================================================================= +// +// Recon Data Table +// +BEGIN_RECV_TABLE_NOBASE( C_PlayerClassRecon, DT_PlayerClassReconData ) + RecvPropInt ( RECVINFO( m_ClassData.m_nJumpCount ) ), + RecvPropFloat ( RECVINFO( m_ClassData.m_flSuppressionJumpTime ) ), + RecvPropFloat ( RECVINFO( m_ClassData.m_flSuppressionImpactTime ) ), + RecvPropFloat ( RECVINFO( m_ClassData.m_flStickTime ) ), + RecvPropFloat ( RECVINFO( m_ClassData.m_flActiveJumpTime ) ), + RecvPropFloat ( RECVINFO( m_ClassData.m_flImpactDist ) ), + RecvPropVector ( RECVINFO( m_ClassData.m_vecImpactNormal ) ), + RecvPropVector ( RECVINFO( m_ClassData.m_vecUnstickVelocity ) ), + RecvPropInt ( RECVINFO( m_ClassData.m_bTrailParticles ) ), +END_RECV_TABLE() + +BEGIN_PREDICTION_DATA_NO_BASE( C_PlayerClassRecon ) + + DEFINE_PRED_TYPEDESCRIPTION( m_ClassData, PlayerClassReconData_t ), + +END_PREDICTION_DATA() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PlayerClassRecon::C_PlayerClassRecon( C_BaseTFPlayer *pPlayer ) : + C_PlayerClass( pPlayer ) +{ + m_ClassData.m_nJumpCount = 0; + m_ClassData.m_flSuppressionJumpTime = -99999; + m_ClassData.m_flSuppressionImpactTime = -99999; + m_ClassData.m_flActiveJumpTime = -99999; + m_ClassData.m_flStickTime = -99999; + m_ClassData.m_flImpactDist = -99999; + m_ClassData.m_vecImpactNormal.Init(); + m_ClassData.m_vecUnstickVelocity.Init(); + m_ClassData.m_bTrailParticles = false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PlayerClassRecon::~C_PlayerClassRecon() +{ +} diff --git a/game/client/tf2/c_tf_class_recon.h b/game/client/tf2/c_tf_class_recon.h new file mode 100644 index 0000000..46d8438 --- /dev/null +++ b/game/client/tf2/c_tf_class_recon.h @@ -0,0 +1,37 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_TF_CLASS_RECON_H +#define C_TF_CLASS_RECON_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_tf_playerclass.h" +#include "TFClassData_Shared.h" +#include "dt_recv.h" + +class C_PlayerClassRecon : public C_PlayerClass +{ + + DECLARE_CLASS( C_PlayerClassRecon, C_PlayerClass ); + +public: + + C_PlayerClassRecon( C_BaseTFPlayer *pPlayer ); + virtual ~C_PlayerClassRecon(); + + DECLARE_PREDICTABLE(); + + PlayerClassReconData_t *GetClassData( void ) { return &m_ClassData; } + + PlayerClassReconData_t m_ClassData; +}; + +EXTERN_RECV_TABLE( DT_PlayerClassReconData ) + +#endif // C_TF_CLASS_RECON_H
\ No newline at end of file diff --git a/game/client/tf2/c_tf_class_sapper.cpp b/game/client/tf2/c_tf_class_sapper.cpp new file mode 100644 index 0000000..cc84859 --- /dev/null +++ b/game/client/tf2/c_tf_class_sapper.cpp @@ -0,0 +1,53 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_tf_class_sapper.h" + +//============================================================================= +// +// Sapper Data Table +// +BEGIN_RECV_TABLE_NOBASE( C_PlayerClassSapper, DT_PlayerClassSapperData ) + RecvPropFloat( RECVINFO(m_flDrainedEnergy) ), +END_RECV_TABLE() + +BEGIN_PREDICTION_DATA_NO_BASE( C_PlayerClassSapper ) + + DEFINE_PRED_TYPEDESCRIPTION( m_ClassData, PlayerClassSapperData_t ), + +END_PREDICTION_DATA() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PlayerClassSapper::C_PlayerClassSapper( C_BaseTFPlayer *pPlayer ) : + C_PlayerClass( pPlayer ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PlayerClassSapper::~C_PlayerClassSapper() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +float C_PlayerClassSapper::GetDrainedEnergy( void ) +{ + return m_flDrainedEnergy; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PlayerClassSapper::DeductDrainedEnergy( float flEnergy ) +{ + m_flDrainedEnergy = MAX( 0, m_flDrainedEnergy - flEnergy ); +} diff --git a/game/client/tf2/c_tf_class_sapper.h b/game/client/tf2/c_tf_class_sapper.h new file mode 100644 index 0000000..a3f7287 --- /dev/null +++ b/game/client/tf2/c_tf_class_sapper.h @@ -0,0 +1,45 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_TF_CLASS_TECHNICIAN_H +#define C_TF_CLASS_TECHNICIAN_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_tf_playerclass.h" +#include "dt_recv.h" + +class C_PlayerClassSapper : public C_PlayerClass +{ + + DECLARE_CLASS( C_PlayerClassSapper, C_PlayerClass ); + +public: + + C_PlayerClassSapper( C_BaseTFPlayer *pPlayer ); + virtual ~C_PlayerClassSapper(); + + DECLARE_PREDICTABLE(); + + PlayerClassSapperData_t* GetClassData( void ) { return &m_ClassData; } + + // Energy handling + float GetDrainedEnergy( void ); + void DeductDrainedEnergy( float flEnergy ); + +protected: + + PlayerClassSapperData_t m_ClassData; + +public: + float m_flDrainedEnergy; +}; + +EXTERN_RECV_TABLE( DT_PlayerClassSapperData ) + +#endif // C_TF_CLASS_TECHNICIAN_H
\ No newline at end of file diff --git a/game/client/tf2/c_tf_class_sniper.cpp b/game/client/tf2/c_tf_class_sniper.cpp new file mode 100644 index 0000000..e2a0449 --- /dev/null +++ b/game/client/tf2/c_tf_class_sniper.cpp @@ -0,0 +1,36 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_tf_class_sniper.h" + +//============================================================================= +// +// Sniper Data Table +// +BEGIN_RECV_TABLE_NOBASE( C_PlayerClassSniper, DT_PlayerClassSniperData ) +END_RECV_TABLE() + +BEGIN_PREDICTION_DATA_NO_BASE( C_PlayerClassSniper ) + + DEFINE_PRED_TYPEDESCRIPTION( m_ClassData, PlayerClassSniperData_t ), + +END_PREDICTION_DATA() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PlayerClassSniper::C_PlayerClassSniper( C_BaseTFPlayer *pPlayer ) : + C_PlayerClass( pPlayer ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PlayerClassSniper::~C_PlayerClassSniper() +{ +}
\ No newline at end of file diff --git a/game/client/tf2/c_tf_class_sniper.h b/game/client/tf2/c_tf_class_sniper.h new file mode 100644 index 0000000..078624d --- /dev/null +++ b/game/client/tf2/c_tf_class_sniper.h @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_TF_CLASS_SNIPER_H +#define C_TF_CLASS_SNIPER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_tf_playerclass.h" +#include "dt_recv.h" + +class C_PlayerClassSniper : public C_PlayerClass +{ + + DECLARE_CLASS( C_PlayerClassSniper, C_PlayerClass ); + +public: + + C_PlayerClassSniper( C_BaseTFPlayer *pPlayer ); + virtual ~C_PlayerClassSniper(); + + DECLARE_PREDICTABLE(); + + PlayerClassSniperData_t *GetClassData( void ) { return &m_ClassData; } + +protected: + + PlayerClassSniperData_t m_ClassData; +}; + +EXTERN_RECV_TABLE( DT_PlayerClassSniperData ) + +#endif // C_TF_CLASS_SNIPER_H
\ No newline at end of file diff --git a/game/client/tf2/c_tf_class_support.cpp b/game/client/tf2/c_tf_class_support.cpp new file mode 100644 index 0000000..ea85891 --- /dev/null +++ b/game/client/tf2/c_tf_class_support.cpp @@ -0,0 +1,36 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_tf_class_support.h" + +//============================================================================= +// +// Support Data Table +// +BEGIN_RECV_TABLE_NOBASE( C_PlayerClassSupport, DT_PlayerClassSupportData ) +END_RECV_TABLE() + +BEGIN_PREDICTION_DATA_NO_BASE( C_PlayerClassSupport ) + + DEFINE_PRED_TYPEDESCRIPTION( m_ClassData, PlayerClassSupportData_t ), + +END_PREDICTION_DATA() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PlayerClassSupport::C_PlayerClassSupport( C_BaseTFPlayer *pPlayer ) : + C_PlayerClass( pPlayer ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PlayerClassSupport::~C_PlayerClassSupport() +{ +}
\ No newline at end of file diff --git a/game/client/tf2/c_tf_class_support.h b/game/client/tf2/c_tf_class_support.h new file mode 100644 index 0000000..27817cb --- /dev/null +++ b/game/client/tf2/c_tf_class_support.h @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_TF_CLASS_SUPPORT_H +#define C_TF_CLASS_SUPPORT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_tf_playerclass.h" +#include "dt_recv.h" + +class C_PlayerClassSupport : public C_PlayerClass +{ + + DECLARE_CLASS( C_PlayerClassSupport, C_PlayerClass ); + +public: + + C_PlayerClassSupport( C_BaseTFPlayer *pPlayer ); + virtual ~C_PlayerClassSupport(); + + DECLARE_PREDICTABLE(); + + PlayerClassSupportData_t *GetClassData( void ) { return &m_ClassData; } + +protected: + + PlayerClassSupportData_t m_ClassData; +}; + +EXTERN_RECV_TABLE( DT_PlayerClassSupportData ) + +#endif // C_TF_CLASS_SUPPORT_H
\ No newline at end of file diff --git a/game/client/tf2/c_tf_flare.cpp b/game/client/tf2/c_tf_flare.cpp new file mode 100644 index 0000000..7b8b806 --- /dev/null +++ b/game/client/tf2/c_tf_flare.cpp @@ -0,0 +1,342 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Flare effects +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "dlight.h" +#include "cmodel.h" +#include "view.h" +#include "clientsideeffects.h" +#include "clienteffectprecachesystem.h" +#include "particles_simple.h" +#include "particlemgr.h" +#include "IEFx.h" +#include "fx.h" + +//Precahce the effects +CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectFlares ) +CLIENTEFFECT_MATERIAL( "effects/redflare" ) +CLIENTEFFECT_MATERIAL( "effects/yellowflare" ) +CLIENTEFFECT_MATERIAL( "effects/yellowflare_noz" ) +CLIENTEFFECT_REGISTER_END() + +class C_SignalFlare : public C_BaseAnimating, CSimpleEmitter +{ + + DECLARE_CLASS( C_SignalFlare, C_BaseAnimating ); + +public: + + DECLARE_CLIENTCLASS(); + + C_SignalFlare( void ); + ~C_SignalFlare( void ); + + void OnDataChanged( DataUpdateType_t updateType ); + void Update( float timeDelta ); + void NotifyDestroyParticle( Particle* pParticle ); + void RestoreResources( void ); + + float m_flDuration; + float m_flScale; + bool m_bLight; + bool m_bSmoke; + +private: + C_SignalFlare( const C_SignalFlare & ); + + SimpleParticle *m_pParticle[2]; +}; + +IMPLEMENT_CLIENTCLASS_DT( C_SignalFlare, DT_SignalFlare, CSignalFlare ) + RecvPropFloat( RECVINFO( m_flDuration ) ), + RecvPropFloat( RECVINFO( m_flScale ) ), + RecvPropInt( RECVINFO( m_bLight ) ), + RecvPropInt( RECVINFO( m_bSmoke ) ), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +C_SignalFlare::C_SignalFlare( void ) : CSimpleEmitter( "C_SignalFlare" ) +{ + m_pParticle[0] = NULL; + m_pParticle[1] = NULL; + m_flDuration = 0.0f; + + m_bLight = true; + m_bSmoke = true; + + SetDynamicallyAllocated( false ); +} + + +//----------------------------------------------------------------------------- +// Destructor +//----------------------------------------------------------------------------- +C_SignalFlare::~C_SignalFlare( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : bool - +//----------------------------------------------------------------------------- +void C_SignalFlare::OnDataChanged( DataUpdateType_t updateType ) +{ + if ( updateType == DATA_UPDATE_CREATED ) + { + SetSortOrigin( GetAbsOrigin() ); + } + + BaseClass::OnDataChanged( updateType ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_SignalFlare::RestoreResources( void ) +{ + if ( m_pParticle[0] == NULL ) + { + m_pParticle[0] = (SimpleParticle *) AddParticle( sizeof( SimpleParticle ), GetPMaterial( "effects/redflare" ), GetAbsOrigin() ); + + if ( m_pParticle[0] != NULL ) + { + m_pParticle[0]->m_uchColor[0] = m_pParticle[0]->m_uchColor[1] = m_pParticle[0]->m_uchColor[2] = 0; + m_pParticle[0]->m_flRoll = random->RandomInt( 0, 360 ); + m_pParticle[0]->m_flRollDelta = random->RandomFloat( 1.0f, 4.0f ); + m_pParticle[0]->m_flLifetime = 0.0f; + m_pParticle[0]->m_flDieTime = 10.0f; + } + else + { + assert(0); + } + } + + if ( m_pParticle[1] == NULL ) + { + m_pParticle[1] = (SimpleParticle *) AddParticle( sizeof( SimpleParticle ), GetPMaterial( "effects/yellowflare_noz" ), GetAbsOrigin() ); + + if ( m_pParticle[1] != NULL ) + { + m_pParticle[1]->m_uchColor[0] = m_pParticle[1]->m_uchColor[1] = m_pParticle[1]->m_uchColor[2] = 0; + m_pParticle[1]->m_flRoll = random->RandomInt( 0, 360 ); + m_pParticle[1]->m_flRollDelta = random->RandomFloat( 1.0f, 4.0f ); + m_pParticle[1]->m_flLifetime = 0.0f; + m_pParticle[1]->m_flDieTime = 10.0f; + } + else + { + assert(0); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pParticle - +//----------------------------------------------------------------------------- +void C_SignalFlare::NotifyDestroyParticle( Particle *pParticle ) +{ + if ( pParticle == m_pParticle[0] ) + { + m_pParticle[0] = NULL; + } + + if ( pParticle == m_pParticle[1] ) + { + m_pParticle[1] = NULL; + } + + CSimpleEmitter::NotifyDestroyParticle( pParticle ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : timeDelta - +//----------------------------------------------------------------------------- +void C_SignalFlare::Update( float timeDelta ) +{ + CSimpleEmitter::Update( timeDelta ); + + //Make sure our stored resources are up to date + RestoreResources(); + + //Don't do this if the console is down + if ( timeDelta <= 0.0f ) + return; + + float fColor; + float baseScale = m_flScale; + + //Account for fading out + if ( ( m_flDuration != -1.0f ) && ( ( m_flDuration - gpGlobals->curtime ) <= 10.0f ) ) + { + baseScale *= ( ( m_flDuration - gpGlobals->curtime ) / 10.0f ); + } + + //Clamp the scale if vanished + if ( baseScale < 0.01f ) + { + baseScale = 0.0f; + + if ( m_pParticle[0] != NULL ) + { + m_pParticle[0]->m_flDieTime = gpGlobals->curtime; + m_pParticle[0]->m_uchStartSize = m_pParticle[0]->m_uchEndSize = 0; + m_pParticle[0]->m_uchColor[0] = 0; + m_pParticle[0]->m_uchColor[1] = 0; + m_pParticle[0]->m_uchColor[2] = 0; + } + + if ( m_pParticle[1] != NULL ) + { + m_pParticle[1]->m_flDieTime = gpGlobals->curtime; + m_pParticle[1]->m_uchStartSize = m_pParticle[1]->m_uchEndSize = 0; + m_pParticle[1]->m_uchColor[0] = 0; + m_pParticle[1]->m_uchColor[1] = 0; + m_pParticle[1]->m_uchColor[2] = 0; + } + + return; + } + + // + // Dynamic light + // + + if ( m_bLight ) + { + dlight_t *dl= effects->CL_AllocDlight( index ); + + dl->origin = GetAbsOrigin(); + dl->color.r = 255; + dl->color.g = dl->color.b = random->RandomInt( 32, 64 ); + dl->radius = baseScale * random->RandomFloat( 110.0f, 128.0f ); + dl->die = gpGlobals->curtime; + } + + // + // Smoke + // + + if ( m_bSmoke ) + { + Vector smokeOrg = GetAbsOrigin(); + + Vector flareScreenDir = ( smokeOrg - CurrentViewOrigin() ); + VectorNormalize( flareScreenDir ); + + smokeOrg = smokeOrg + ( flareScreenDir * 2.0f ); + smokeOrg[2] += baseScale * 4.0f; + + SimpleParticle *sParticle = (SimpleParticle *) AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[1], smokeOrg ); + + if ( sParticle == NULL ) + return; + + sParticle->m_flLifetime = 0.0f; + sParticle->m_flDieTime = 1.0f; + + sParticle->m_vecVelocity = Vector( random->RandomFloat( -16.0f, 16.0f ), random->RandomFloat( -16.0f, 16.0f ), random->RandomFloat( 8.0f, 16.0f ) + 32.0f ); + + fColor = random->RandomInt( 64, 128 ); + + sParticle->m_uchColor[0] = fColor+64; + sParticle->m_uchColor[1] = fColor; + sParticle->m_uchColor[2] = fColor; + sParticle->m_uchStartAlpha = random->RandomInt( 16, 32 ); + sParticle->m_uchEndAlpha = 0; + sParticle->m_uchStartSize = random->RandomInt( 2, 4 ); + sParticle->m_uchEndSize = sParticle->m_uchStartSize * 6.0f; + sParticle->m_flRoll = random->RandomInt( 0, 360 ); + sParticle->m_flRollDelta = random->RandomFloat( -2.0f, 2.0f ); + } + + //Check for LOS + if ( EffectOccluded( GetAbsOrigin() ) ) + { + if ( m_pParticle[0] != NULL ) + { + m_pParticle[0]->m_uchColor[0] *= 0.5f; + m_pParticle[0]->m_uchColor[1] *= 0.5f; + m_pParticle[0]->m_uchColor[2] *= 0.5f; + } + + if ( m_pParticle[1] != NULL ) + { + m_pParticle[1]->m_uchColor[0] *= 0.25f; + m_pParticle[1]->m_uchColor[1] *= 0.25f; + m_pParticle[1]->m_uchColor[2] *= 0.25f; + } + + return; + } + + // + // Outer glow + // + + Vector offset; + + //Cause the base of the effect to shake + offset.Random( -0.5f * baseScale, 0.5f * baseScale ); + offset += GetAbsOrigin(); + + if ( m_pParticle[0] != NULL ) + { + m_pParticle[0]->m_Pos = offset; + m_pParticle[0]->m_flLifetime = 0.0f; + m_pParticle[0]->m_flDieTime = 2.0f; + + m_pParticle[0]->m_vecVelocity.Init(); + + fColor = random->RandomInt( 100.0f, 128.0f ); + + m_pParticle[0]->m_uchColor[0] = fColor; + m_pParticle[0]->m_uchColor[1] = fColor; + m_pParticle[0]->m_uchColor[2] = fColor; + m_pParticle[0]->m_uchStartAlpha = fColor; + m_pParticle[0]->m_uchEndAlpha = fColor; + m_pParticle[0]->m_uchStartSize = baseScale * (float) random->RandomInt( 32, 48 ); + m_pParticle[0]->m_uchEndSize = m_pParticle[0]->m_uchStartSize; + m_pParticle[0]->m_flRollDelta = 0.0f; + + if ( random->RandomInt( 0, 4 ) == 3 ) + { + m_pParticle[0]->m_flRoll += random->RandomInt( 2, 8 ); + } + } + + // + // Inner core + // + + //Cause the base of the effect to shake + offset.Random( -1.0f * baseScale, 1.0f * baseScale ); + offset += GetAbsOrigin(); + + if ( m_pParticle[1] != NULL ) + { + m_pParticle[1]->m_Pos = offset; + m_pParticle[1]->m_flLifetime = 0.0f; + m_pParticle[1]->m_flDieTime = 2.0f; + + m_pParticle[1]->m_vecVelocity.Init(); + + fColor = 255; + + m_pParticle[1]->m_uchColor[0] = fColor; + m_pParticle[1]->m_uchColor[1] = fColor; + m_pParticle[1]->m_uchColor[2] = fColor; + m_pParticle[1]->m_uchStartAlpha = fColor; + m_pParticle[1]->m_uchEndAlpha = fColor; + m_pParticle[1]->m_uchStartSize = baseScale * (float) random->RandomInt( 2, 4 ); + m_pParticle[1]->m_uchEndSize = m_pParticle[0]->m_uchStartSize; + m_pParticle[1]->m_flRoll = random->RandomInt( 0, 360 ); + } +} diff --git a/game/client/tf2/c_tf_hintmanager.cpp b/game/client/tf2/c_tf_hintmanager.cpp new file mode 100644 index 0000000..6aeec17 --- /dev/null +++ b/game/client/tf2/c_tf_hintmanager.cpp @@ -0,0 +1,427 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_tf_hintmanager.h" +#include "c_tf_basehint.h" +#include <KeyValues.h> +#include "filesystem.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +// Global off switch for hint system +static ConVar tf2_hintsystem( "tf2_hintsystem", "0", 0, "Enable interface hints in TF2." ); +static C_TFHintManager *g_pHintManager = NULL; + +#define HINT_DISPLAY_STATS_FILE "scripts/hintdisplaystats.txt" + +static float g_flLastEscapeKeyTime = -1.0f; +//----------------------------------------------------------------------------- +// Purpose: Helper to create panel in center and then shift toward right edge of screen +// Input : *panel - +// Output : static void +//----------------------------------------------------------------------------- +static void PositionPanel( C_TFBaseHint *panel ) +{ + int w, h; + panel->GetSize( w, h ); + + int x = ( ScreenWidth() - w ) / 2; + int y = ( ScreenHeight() - h ) / 2; + + panel->SetPos( x, y ); + + panel->SetDesiredPosition( ScreenWidth() - w - 10, y - 75 ); +} + +IMPLEMENT_CLIENTCLASS_DT_NOBASE(C_TFHintManager, DT_TFHintManager, CTFHintManager) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_TFHintManager::C_TFHintManager( void ) +{ + g_pHintManager = this; + + m_pkvHintSystem = new KeyValues( "HintSystem" ); + if ( m_pkvHintSystem ) + { + bool valid = m_pkvHintSystem->LoadFromFile( filesystem, "scripts//hintsystem.txt" ); + if ( !valid ) + { + m_pkvHintSystem->deleteThis(); + m_pkvHintSystem = NULL; + } + } + + m_pkvHintDisplayStats = new KeyValues( "HintDisplayStats" ); + if ( m_pkvHintDisplayStats ) + { + m_pkvHintDisplayStats->LoadFromFile( filesystem, HINT_DISPLAY_STATS_FILE ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : KeyValues +//----------------------------------------------------------------------------- +KeyValues *C_TFHintManager::GetHintKeyValues( void ) +{ + return m_pkvHintSystem; +} + +KeyValues *C_TFHintManager::GetHintDisplayStats( void ) +{ + return m_pkvHintDisplayStats; +} + +void C_TFHintManager::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + // Think right away + if ( updateType == DATA_UPDATE_CREATED ) + SetNextClientThink( 0.0f ); +} + +//----------------------------------------------------------------------------- +// Purpose: Remove complete hints, and activate next highest priority hint +//----------------------------------------------------------------------------- +void C_TFHintManager::ClientThink( void ) +{ + SetNextClientThink( gpGlobals->curtime + 1.0 ); + + int i; + int highestPriority = -1; + C_TFBaseHint *best = NULL; + bool anyVisible = false; + + // See if any of the hints are completed, otherwise, store off the highest priority one + for ( i = m_aHints.Size() - 1; i >= 0; i-- ) + { + C_TFBaseHint *hint = m_aHints[ i ]; + + // See if it should just be deleted + if ( hint && hint->GetCompleted() ) + { + m_aHints.Remove( i ); + delete hint; + continue; + } + + if ( hint->IsVisible() ) + { + anyVisible = true; + } + + if ( !best || ( hint->GetPriority() > highestPriority ) ) + { + highestPriority = hint->GetPriority(); + best = hint; + } + } + + // Last hint finished, show next best one + if ( !anyVisible ) + { + // Now hide all but best one + for ( i = 0; i < m_aHints.Size(); i++ ) + { + C_TFBaseHint *hint = m_aHints[ i ]; + hint->SetVisible( hint == best ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : playerIndex - +// hintID - +// priority - +// entityIndex - +//----------------------------------------------------------------------------- +C_TFBaseHint *C_TFHintManager::AddHint( int hintID, const char *subsection, int entityIndex, int maxduplicates ) +{ + if ( !tf2_hintsystem.GetBool() ) + return NULL; + + // Don't add the same hint more than once unless maxduplicates >= 1 has been specifically requested + int count = CountInstancesOfHintID( hintID ); + if ( count > maxduplicates ) + { + return NULL; + } + + C_TFBaseHint *hint = C_TFBaseHint::CreateHint( hintID, subsection, entityIndex ); + if ( hint ) + { + // Force it to compute it's exact size + hint->PerformLayout(); + + PositionPanel( hint ); + + m_aHints.AddToTail( hint ); + } + + return hint; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_TFHintManager::ClearHints( void ) +{ + for ( int i = 0; i < m_aHints.Size(); i++ ) + { + C_TFBaseHint *hint = m_aHints[ i ]; + delete hint; + } + + m_aHints.RemoveAll(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : playerIndex - +// hintID - +//----------------------------------------------------------------------------- +void C_TFHintManager::CompleteHint( int hintID, bool visibleOnly ) +{ + for ( int i = m_aHints.Size() - 1; i >= 0; i-- ) + { + C_TFBaseHint *hint = m_aHints[ i ]; + if ( !hint ) + continue; + + if ( hint->GetID() != hintID ) + continue; + + if ( visibleOnly && !hint->IsVisible() ) + continue; + + delete hint; + m_aHints.Remove( i ); + return; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : playerIndex - +// hintID - +// Output : Number of instances in list +//----------------------------------------------------------------------------- +int C_TFHintManager::CountInstancesOfHintID( int hintID ) +{ + int c = 0; + for ( int i = m_aHints.Size() - 1; i >= 0; i-- ) + { + C_TFBaseHint *hint = m_aHints[ i ]; + if ( hint && hint->GetID() == hintID ) + { + c++; + } + } + + return c; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : playerIndex - +// Output : int +//----------------------------------------------------------------------------- +int C_TFHintManager::GetCurrentHintID( void ) +{ + for ( int i = m_aHints.Size() - 1; i >= 0; i-- ) + { + C_TFBaseHint *hint = m_aHints[ i ]; + if ( hint && hint->IsVisible() ) + { + return hint->GetID(); + } + } + + return TF_HINT_UNDEFINED; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_TFHintManager::ResetDisplayStats( void ) +{ + if ( !m_pkvHintDisplayStats ) + { + Assert( 0 ); + return; + } + + KeyValues *kv = m_pkvHintDisplayStats->GetFirstSubKey(); + while ( kv ) + { + KeyValues *subKey = kv->GetFirstSubKey(); + if ( subKey && stricmp( subKey->GetName(), "times_shown") ) + { + while ( subKey ) + { + subKey->SetString( "times_shown", "0" ); + subKey = subKey->GetNextKey(); + } + } + else + { + kv->SetString( "times_shown", "0" ); + } + + kv = kv->GetNextKey(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : hintid - +// 100 - +// 1 - +// -1 - +//----------------------------------------------------------------------------- +C_TFBaseHint *CreateGlobalHint( int hintid, const char *subsection /*=NULL*/, int entity /*= -1*/, int maxduplicates /*=0*/ ) +{ + if ( !g_pHintManager ) + { + return NULL; + } + + return g_pHintManager->AddHint( hintid, subsection, entity, maxduplicates ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : hintid - +// 100 - +// 1 - +// -1 - +//----------------------------------------------------------------------------- +C_TFBaseHint *CreateGlobalHint_Panel( vgui::Panel *targetPanel, int hintid, const char *subsection /*=NULL*/, int entity /*= -1*/, int maxduplicates /*=0*/ ) +{ + C_TFBaseHint *hint = CreateGlobalHint( hintid, subsection, entity, maxduplicates ); + if ( hint ) + { + // Find an appropriate position near the panel + hint->SetHintTarget( targetPanel ); + } + return hint; +} + + +//----------------------------------------------------------------------------- +// Purpose: Trap the escape key when a hint is showing +// Output : Returns true if the escape key was swallowed by the hint system +//----------------------------------------------------------------------------- + +// Hitting escape twice withing this amount of seconds will clear all hints pending +#define ENTER_DOUBLETAP_TIME 1.0f + +bool HintSystemEscapeKey( void ) +{ + if ( !g_pHintManager ) + return false; + + int hintID = g_pHintManager->GetCurrentHintID(); + if ( hintID != TF_HINT_UNDEFINED ) + { + bool killall = false; + + float curtime = gpGlobals->curtime; + float dt = curtime - g_flLastEscapeKeyTime; + + if ( dt < ENTER_DOUBLETAP_TIME ) + { + killall = true; + } + + g_flLastEscapeKeyTime = curtime; + + if ( killall ) + { + g_pHintManager->ClearHints(); + } + else + { + g_pHintManager->CompleteHint( hintID, true ); + } + // Swallow the escape key + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : hindid - +//----------------------------------------------------------------------------- +void DestroyGlobalHint( int hintid ) +{ + if ( !g_pHintManager ) + return; + + g_pHintManager->CompleteHint( hintid, false ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : KeyValues +//----------------------------------------------------------------------------- +KeyValues *GetHintKeyValues( void ) +{ + if ( !g_pHintManager ) + return NULL; + + return g_pHintManager->GetHintKeyValues(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : KeyValues +//----------------------------------------------------------------------------- +KeyValues *GetHintDisplayStats( void ) +{ + if ( !g_pHintManager ) + return NULL; + + return g_pHintManager->GetHintDisplayStats(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void ResetDisplayStats( void ) +{ + if ( g_pHintManager ) + { + g_pHintManager->ResetDisplayStats(); + } +} + +static ConCommand tf2_hintreset( "tf2_hintreset", ResetDisplayStats, 0, FCVAR_CHEAT ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_TFHintManager::~C_TFHintManager( void ) +{ + ClearHints(); + g_pHintManager = NULL; + m_pkvHintSystem->deleteThis(); + if ( m_pkvHintDisplayStats ) + { + m_pkvHintDisplayStats->SaveToFile( filesystem, HINT_DISPLAY_STATS_FILE ); + } + m_pkvHintDisplayStats->deleteThis(); +}
\ No newline at end of file diff --git a/game/client/tf2/c_tf_hintmanager.h b/game/client/tf2/c_tf_hintmanager.h new file mode 100644 index 0000000..d96d80b --- /dev/null +++ b/game/client/tf2/c_tf_hintmanager.h @@ -0,0 +1,87 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_TF_HINTMANAGER_H +#define C_TF_HINTMANAGER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "shareddefs.h" + +class C_TFBaseHint; +class KeyValues; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_TFHintManager : public C_BaseEntity +{ + DECLARE_CLASS( C_TFHintManager, C_BaseEntity ); +public: + DECLARE_CLIENTCLASS(); + + C_TFHintManager( void ); + ~C_TFHintManager( void ); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + + // Override think method + virtual void ClientThink( void ); + + // Add hint to list + C_TFBaseHint *AddHint( int hintID, const char *subsection, int entityIndex, int maxduplicates ); + + // Clear hints + void ClearHints( void ); + // Complete specified hint + void CompleteHint( int hintID, bool visibleOnly ); + // Determine ID of hint currently being shown to player + int GetCurrentHintID( void ); + + KeyValues *GetHintKeyValues( void ); + KeyValues *GetHintDisplayStats( void ); + + // Zero out all counters + void ResetDisplayStats( void ); + +private: + // See how many of the type of hint are already being shown + int CountInstancesOfHintID( int hintID ); + + // Hint list + CUtlVector< C_TFBaseHint * > m_aHints; + + KeyValues *m_pkvHintSystem; + KeyValues *m_pkvHintDisplayStats; +}; + + +#include "tf_hints.h" + +class C_TFBaseHint; +namespace vgui +{ + class Panel; +} +class KeyValues; + +// Use this when you want to allow an unlimited number of a certain type of hint +// Just a huge number of simultaneous duplicates allowed +#define HINTTYPE_NOLIMIT 5000 + +C_TFBaseHint *CreateGlobalHint( int hintid, const char *subsection = NULL, int entity = -1, int maxduplicates = 0 ); +C_TFBaseHint *CreateGlobalHint_Panel( vgui::Panel *targetPanel, int hintid, const char *subsection = NULL, int entity = -1, int maxduplicates = 0 ); +void DestroyGlobalHint( int hintid ); +KeyValues *GetHintKeyValues( void ); +KeyValues *GetHintDisplayStats( void ); + +// Returns true if hint system swallowed escape key +bool HintSystemEscapeKey( void ); + + +#endif // C_TF_HINTMANAGER_H diff --git a/game/client/tf2/c_tf_hints.cpp b/game/client/tf2/c_tf_hints.cpp new file mode 100644 index 0000000..b12ff20 --- /dev/null +++ b/game/client/tf2/c_tf_hints.cpp @@ -0,0 +1,1468 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_tf_basehint.h" +#include "tf_hints.h" +#include "hintitemorderbase.h" +#include "iclientmode.h" +#include "clientmode_commander.h" +#include "hud_technologytreedoc.h" +#include "paneleffect.h" +#include "techtree.h" +#include "hintitemobjectbase.h" +#include "c_order.h" +#include "c_basetfplayer.h" +#include "weapon_selection.h" +#include <KeyValues.h> +#include "c_weapon_builder.h" +#include "VGuiMatSurface/IMatSystemSurface.h" +#include "c_tf_hints.h" +#include "c_hint_events.h" +#include "c_tf_hintmanager.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +// Class Hierarchy +// CHintItemBase -- base class for hint items +// CHintItemOrderBase -- base class for hints derived from orders ( know how to draw +// a white line from the hint to the order panel ) +// CHintItemObjectBase -- base class for hints that care about another object ( stores the object type name ) +// CHintGotoObject -- Contains logic that relates to the other object +// CHintWaitBuilding +// CHintChangeToCommander -- first level hint, doesn't rely on object, but does rely on UI manipulation +// CHintChooseAnyTechnology -- doesn't try to draw line to order since it's in tactical view? +// + + +//----------------------------------------------------------------------------- +// Purpose: Change to commander view hint +//----------------------------------------------------------------------------- +class CHintChangeToCommander : public CHintItemOrderBase +{ + DECLARE_CLASS( CHintChangeToCommander, CHintItemOrderBase ); + +public: + CHintChangeToCommander( vgui::Panel *parent, const char *panelName ); + virtual void Think( void ); +}; + +DECLARE_HINTITEMFACTORY( CHintChangeToCommander ) + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *parent - +// *panelName - +// *text - +// itemwidth - +//----------------------------------------------------------------------------- +CHintChangeToCommander::CHintChangeToCommander( vgui::Panel *parent, const char *panelName ) +: BaseClass( parent, panelName ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Set completed flag if we've made it to commander mode +// Output : virtual void +//----------------------------------------------------------------------------- +void CHintChangeToCommander::Think( void ) +{ + BaseClass::Think(); + + if ( g_pClientMode == ClientModeCommander() ) + { + m_bCompleted = true; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHintGotoObject : public CHintItemObjectBase +{ + DECLARE_CLASS( CHintGotoObject, CHintItemObjectBase ); + +public: + CHintGotoObject( vgui::Panel *parent, const char *panelName ); + virtual void Think( void ); + +private: + enum + { + MAX_OBJECT_TYPE = 128, + }; + + EFFECT_HANDLE m_ArrowEffect; + + float m_flNextDistanceCheck; + IClientMode *m_pPreviousMode; +}; + +DECLARE_HINTITEMFACTORY( CHintGotoObject ) + +#define ZONE_DISTANCE_CHECK_INTERVAL 0.5f + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *parent - +// *panelName - +//----------------------------------------------------------------------------- +CHintGotoObject::CHintGotoObject( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, panelName ) +{ + m_ArrowEffect = CreateArrowEffect( this, parent, NULL ); + + m_flNextDistanceCheck = 0.0f; + + m_pPreviousMode = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHintGotoObject::Think( void ) +{ + BaseClass::Think(); + + ClientModeTFBase *basemode = ( ClientModeTFBase * )g_pClientMode; + CMinimapPanel *minimap = basemode->GetMinimap(); + + CPanelEffect *e = g_pTF2RootPanel->FindEffect( m_ArrowEffect ); + if ( e && minimap ) + { + e->SetPanelOther( minimap ); + } + + // Check right away if we switch modes + if ( g_pClientMode != m_pPreviousMode ) + { + m_flNextDistanceCheck = 0.0f; + m_pPreviousMode = g_pClientMode; + } + + if ( gpGlobals->curtime < m_flNextDistanceCheck ) + { + return; + } + + m_flNextDistanceCheck = gpGlobals->curtime + ZONE_DISTANCE_CHECK_INTERVAL; + + // The order contains the resource zone target + C_TFBaseHint *hint = static_cast< C_TFBaseHint * >( GetParent() ); + if ( hint ) + { + C_Order *order = dynamic_cast< C_Order * >( ClientEntityList().GetEnt( hint->GetEntity() ) ); + if ( order ) + { + C_BaseEntity *pTarget = ClientEntityList().GetEnt( order->GetTarget() ); + if ( IsObjectOfType( pTarget ) ) + { + Vector zonecenter = pTarget->WorldSpaceCenter( ); + + if ( e && minimap ) + { + float mapx, mapy; + + // Convert target center to map position + CMinimapPanel::MinimapPanel()->WorldToMinimap( MINIMAP_CLIP, zonecenter, mapx, mapy ); + + e->SetUsingOffset( true, (int)mapx, (int)mapy ); + } + + Vector delta; + + C_BaseTFPlayer *local = C_BaseTFPlayer::GetLocalPlayer(); + if ( local ) + { + delta = local->GetAbsOrigin() - zonecenter; + if ( delta.Length() < 256.0f ) + { + m_bCompleted = true; + } + } + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHintDeployWeapon : public CHintItemOrderBase +{ + DECLARE_CLASS( CHintDeployWeapon, CHintItemOrderBase ); + +public: + CHintDeployWeapon( vgui::Panel *parent, const char *panelName ); + + virtual void Think( void ); + + virtual void SetWeaponType( const char *type ); + virtual char const *GetWeaponType( void ); + + virtual char const *GetKeyName( void ); + + virtual void SetPrintName( const char *name ); + virtual char const *GetPrintName( void ); + + virtual void ParseItem( KeyValues *pKeyValues ); + + virtual bool CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring ); + +private: + enum + { + MAX_WEAPON_TYPE = 128, + MAX_WEAPON_NAME = 128, + }; + + char m_szWeaponType[ MAX_WEAPON_TYPE ]; + char m_szPrintName[ MAX_WEAPON_NAME ]; +}; + +DECLARE_HINTITEMFACTORY( CHintDeployWeapon ) + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *parent - +// *panelName - +//----------------------------------------------------------------------------- +CHintDeployWeapon::CHintDeployWeapon( vgui::Panel *parent, const char *panelName ) +: BaseClass( parent, panelName ) +{ + SetWeaponType( "" ); + SetPrintName( "" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *instring - +// keylength - +// **ppOutstring - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CHintDeployWeapon::CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring ) +{ + if ( !Q_strnicmp( instring, "keyname", strlen( "keyname" ) ) ) + { + *keylength = strlen( "keyname" ); + *ppOutstring = GetKeyName(); + return true; + } + else if ( !Q_strnicmp( instring, "printname", strlen( "printname" ) ) ) + { + *keylength = strlen( "printname" ); + *ppOutstring = GetPrintName(); + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *type - +//----------------------------------------------------------------------------- +void CHintDeployWeapon::SetWeaponType( const char *type ) +{ + Q_strncpy( m_szWeaponType, type, MAX_WEAPON_TYPE ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : char const +//----------------------------------------------------------------------------- +const char *CHintDeployWeapon::GetWeaponType( void ) +{ + return m_szWeaponType; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *name - +//----------------------------------------------------------------------------- +void CHintDeployWeapon::SetPrintName( const char *name ) +{ + Q_strncpy( m_szPrintName, name, MAX_WEAPON_NAME ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : char const +//----------------------------------------------------------------------------- +const char *CHintDeployWeapon::GetPrintName( void ) +{ + return m_szPrintName; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : char const +//----------------------------------------------------------------------------- +const char *CHintDeployWeapon::GetKeyName( void ) +{ + static char keyname[ 128 ]; + + keyname[ 0 ] = 0; + + CBaseHudWeaponSelection *pHudSelection = GetHudWeaponSelection(); + if ( pHudSelection ) + { + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + if ( player ) + { + for ( int slot = 0; slot < MAX_WEAPON_SLOTS; slot++ ) + { + C_BaseCombatWeapon *weapon = pHudSelection->GetFirstPos( slot ); + if ( !weapon ) + continue; + + if ( !stricmp( weapon->GetName(), GetWeaponType() ) ) + { + Q_snprintf( keyname, sizeof( keyname ), GetKeyNameForBinding( VarArgs( "slot%i", slot + 1 ) ) ); + break; + } + } + } + } + + return keyname; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pKeyValues - +//----------------------------------------------------------------------------- +void CHintDeployWeapon::ParseItem( KeyValues *pKeyValues ) +{ + BaseClass::ParseItem( pKeyValues ); + + const char *type = pKeyValues->GetString( "weapon", "" ); + if ( type ) + { + SetWeaponType( type ); + } + + const char *printname = pKeyValues->GetString( "printname", "" ); + if ( printname ) + { + SetPrintName( printname ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHintDeployWeapon::Think( void ) +{ + BaseClass::Think(); + + C_BaseTFPlayer *player = C_BaseTFPlayer::GetLocalPlayer(); + if ( !player ) + return; + + // Get the weapon selection Hud Element + CBaseHudWeaponSelection *pHudSelection = GetHudWeaponSelection(); + // Make sure it's not still active + if ( pHudSelection->IsActive() ) + return; + + C_BaseCombatWeapon *weapon = GetActiveWeapon(); + if ( !weapon ) + return; + + if ( !stricmp( weapon->GetClientClass()->m_pNetworkName, "CWeaponBuilder" ) ) + { + m_bCompleted = true; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHintStartPlacing : public CHintItemOrderBase +{ + DECLARE_CLASS( CHintStartPlacing, CHintItemOrderBase ); + +public: + CHintStartPlacing( vgui::Panel *parent, const char *panelName ); + + virtual void Think( void ); +private: +}; + +DECLARE_HINTITEMFACTORY( CHintStartPlacing ) + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *parent - +// *panelName - +//----------------------------------------------------------------------------- +CHintStartPlacing::CHintStartPlacing( vgui::Panel *parent, const char *panelName ) +: BaseClass( parent, panelName ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHintStartPlacing::Think( void ) +{ + BaseClass::Think(); + + C_WeaponBuilder *builder = dynamic_cast< C_WeaponBuilder * >( GetActiveWeapon() ); + if ( builder && builder->IsPlacingObject() ) + { + m_bCompleted = true; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHintStartBuilding : public CHintItemOrderBase +{ + DECLARE_CLASS( CHintStartBuilding, CHintItemOrderBase ); + +public: + CHintStartBuilding( vgui::Panel *parent, const char *panelName ); + + virtual void Think( void ); +private: +}; + +DECLARE_HINTITEMFACTORY( CHintStartBuilding ) + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *parent - +// *panelName - +//----------------------------------------------------------------------------- +CHintStartBuilding::CHintStartBuilding( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, panelName ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHintStartBuilding::Think( void ) +{ + BaseClass::Think(); + + C_WeaponBuilder *builder = dynamic_cast< C_WeaponBuilder * >( GetActiveWeapon() ); + if ( builder && builder->IsBuildingObject() ) + { + m_bCompleted = true; + } +} + +#define CHECK_FOR_BUILDING_INTERVAL 1.0f + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHintWaitBuilding : public CHintItemObjectBase +{ + DECLARE_CLASS( CHintWaitBuilding, CHintItemObjectBase ); + +public: + CHintWaitBuilding( vgui::Panel *parent, const char *panelName ); + + virtual void Think( void ); +private: + + float m_flNextCheck; +}; + + +DECLARE_HINTITEMFACTORY( CHintWaitBuilding ) + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *parent - +// *panelName - +//----------------------------------------------------------------------------- +CHintWaitBuilding::CHintWaitBuilding( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, panelName ) +{ + m_flNextCheck = 0.0f; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHintWaitBuilding::Think( void ) +{ + BaseClass::Think(); + + if ( !GetActive() ) + return; + + C_BaseTFPlayer *player = C_BaseTFPlayer::GetLocalPlayer(); + if ( !player ) + return; + + if ( gpGlobals->curtime < m_flNextCheck ) + return; + + m_flNextCheck = gpGlobals->curtime + CHECK_FOR_BUILDING_INTERVAL; + + // Find resource zone + ClientEntityHandle_t e = ClientEntityList().FirstHandle(); + for ( ; e != ClientEntityList().InvalidHandle(); e = ClientEntityList().NextHandle( e ) ) + { + C_BaseEntity *ent = C_BaseEntity::Instance( e ); + if ( !ent ) + continue; + + if ( IsObjectOfType( ent ) ) + { + C_BaseObject *obj = static_cast< C_BaseObject * >( ent ); + + Assert( obj ); + + if ( obj->GetTeamNumber() == player->GetTeamNumber() && obj->IsOwnedByLocalPlayer() ) + { + m_bCompleted = true; + break; + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHintBuilderSelection : public CHintItemOrderBase +{ + DECLARE_CLASS( CHintBuilderSelection, CHintItemOrderBase ); + +public: + CHintBuilderSelection( vgui::Panel *parent, const char *panelName ); + + virtual void Think( void ); + virtual void SetSelection( const char *type ); + virtual char const *GetSelection( void ); + + virtual void ParseItem( KeyValues *pKeyValues ); + + virtual bool CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring ); + +private: + enum + { + MAX_SELECTION_NAME = 128, + }; + + char m_szSelection[ MAX_SELECTION_NAME ]; +}; + +DECLARE_HINTITEMFACTORY( CHintBuilderSelection ) + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *parent - +// *panelName - +//----------------------------------------------------------------------------- +CHintBuilderSelection::CHintBuilderSelection( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, panelName ) +{ + SetSelection( "" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *instring - +// keylength - +// **ppOutstring - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CHintBuilderSelection::CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring ) +{ + if ( !Q_strnicmp( instring, "selection", strlen( "selection" ) ) ) + { + *keylength = strlen( "selection" ); + *ppOutstring = GetSelection(); + return true; + } + + return BaseClass::CheckKeyAndValue( instring, keylength, ppOutstring ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *selection - +//----------------------------------------------------------------------------- +void CHintBuilderSelection::SetSelection( const char *selection ) +{ + Q_strncpy( m_szSelection, selection, MAX_SELECTION_NAME ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : char const +//----------------------------------------------------------------------------- +const char *CHintBuilderSelection::GetSelection( void ) +{ + return m_szSelection; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pKeyValues - +//----------------------------------------------------------------------------- +void CHintBuilderSelection::ParseItem( KeyValues *pKeyValues ) +{ + BaseClass::ParseItem( pKeyValues ); + + const char *selection = pKeyValues->GetString( "selection", "" ); + if ( selection ) + { + SetSelection( selection ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHintBuilderSelection::Think( void ) +{ + BaseClass::Think(); + + C_BaseTFPlayer *player = C_BaseTFPlayer::GetLocalPlayer(); + if ( !player ) + return; + + C_WeaponBuilder *builder = dynamic_cast< C_WeaponBuilder * >( GetActiveWeapon() ); + if ( !builder ) + return; + + const char *selection = builder->GetCurrentSelectionObjectName(); + if ( !selection ) + return; + + if ( !stricmp( selection, GetSelection() ) ) + { + m_bCompleted = true; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHintBuilderStartAction : public CHintItemOrderBase +{ + DECLARE_CLASS( CHintBuilderStartAction, CHintItemOrderBase ); + +public: + CHintBuilderStartAction( vgui::Panel *parent, const char *panelName ); + + virtual void Think( void ); + virtual void SetAction( const char *type ); + virtual char const *GetAction( void ); + + virtual void ParseItem( KeyValues *pKeyValues ); + + virtual bool CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring ); + +private: + enum + { + MAX_ACTION_NAME = 128, + }; + + char m_szAction[ MAX_ACTION_NAME ]; +}; + +DECLARE_HINTITEMFACTORY( CHintBuilderStartAction ) + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *parent - +// *panelName - +//----------------------------------------------------------------------------- +CHintBuilderStartAction::CHintBuilderStartAction( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, panelName ) +{ + SetAction( "" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *instring - +// keylength - +// **ppOutstring - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CHintBuilderStartAction::CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring ) +{ + if ( !Q_strnicmp( instring, "action", strlen( "action" ) ) ) + { + *keylength = strlen( "action" ); + *ppOutstring = GetAction(); + return true; + } + + return BaseClass::CheckKeyAndValue( instring, keylength, ppOutstring ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *action - +//----------------------------------------------------------------------------- +void CHintBuilderStartAction::SetAction( const char *action ) +{ + Q_strncpy( m_szAction, action, MAX_ACTION_NAME ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : char const +//----------------------------------------------------------------------------- +const char *CHintBuilderStartAction::GetAction( void ) +{ + return m_szAction; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pKeyValues - +//----------------------------------------------------------------------------- +void CHintBuilderStartAction::ParseItem( KeyValues *pKeyValues ) +{ + BaseClass::ParseItem( pKeyValues ); + + const char *action = pKeyValues->GetString( "action", "" ); + if ( action ) + { + SetAction( action ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHintBuilderStartAction::Think( void ) +{ + BaseClass::Think(); + + C_BaseTFPlayer *player = C_BaseTFPlayer::GetLocalPlayer(); + if ( !player ) + return; + + C_WeaponBuilder *builder = dynamic_cast< C_WeaponBuilder * >( GetActiveWeapon() ); + if ( !builder ) + return; +} + +//----------------------------------------------------------------------------- +// Purpose: A fake hud element used to force the weapon hud element to draw when it's +// not actually active +//----------------------------------------------------------------------------- +class CHudWeaponFlashHelper : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudWeaponFlashHelper, vgui::Panel ); +public: + CHudWeaponFlashHelper( const char *name ); + + virtual void Init( void ); + virtual bool ShouldDraw( void ); + virtual void Paint(); + virtual void ApplySchemeSettings( vgui::IScheme *scheme ); + + // Associate a weapon + void SetFlashWeapon( C_BaseCombatWeapon *weapon ); + + // Start/stop flashing + void StartFlashing( void ); + void StopFlashing( void ); + + // Get position of weapon icon + void GetWeaponIconBounds( C_BaseCombatWeapon *weapon, int& x, int& y, int& w, int& h ); + + // Is player using the regular weapon selection UI? + bool IsWeaponSelectionActive( void ); + +private: + + // Currently flashing + bool m_bFlashing; + + // The weapon to highlight + EHANDLE m_hWeapon; + + // The actual weapon selection hud element + CBaseHudWeaponSelection *m_pWeaponSelection; +}; + +DECLARE_HUDELEMENT( CHudWeaponFlashHelper ) + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *name - +//----------------------------------------------------------------------------- +CHudWeaponFlashHelper::CHudWeaponFlashHelper( const char *name ) + : CHudElement( name ), BaseClass( NULL, "HudWeaponFlashHelper" ) +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + + m_bFlashing = false; + m_pWeaponSelection = NULL; + + SetHiddenBits( HIDEHUD_MISCSTATUS | HIDEHUD_PLAYERDEAD ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudWeaponFlashHelper::Init( void ) +{ + CHudElement::Init(); + + m_pWeaponSelection = GetHudWeaponSelection(); + Assert( m_pWeaponSelection ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CHudWeaponFlashHelper::ShouldDraw( void ) +{ + return ( CHudElement::ShouldDraw() && m_bFlashing && m_pWeaponSelection ); +} + +void CHudWeaponFlashHelper::ApplySchemeSettings( vgui::IScheme *scheme ) +{ + BaseClass::ApplySchemeSettings( scheme ); + + SetPaintBackgroundEnabled( false ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudWeaponFlashHelper::Paint() +{ + // Stop immediately if user starts to choose weapons + if ( m_pWeaponSelection->IsActive() ) + { + StopFlashing(); + return; + } + + if ( g_pClientMode == ClientModeCommander() ) + return; + + C_BaseCombatWeapon *w = ( C_BaseCombatWeapon * )( (C_BaseEntity *)m_hWeapon ); + if ( !w ) + return; + + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + // Redo drawing of Weapon Menu + m_pWeaponSelection->DrawWList( pPlayer, w, true, EFFECT_R, EFFECT_G, EFFECT_B, EFFECT_A ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *weapon - +//----------------------------------------------------------------------------- +void CHudWeaponFlashHelper::SetFlashWeapon( C_BaseCombatWeapon *weapon ) +{ + m_hWeapon = weapon; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudWeaponFlashHelper::StartFlashing( void ) +{ + m_bFlashing = true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudWeaponFlashHelper::StopFlashing( void ) +{ + m_bFlashing = false; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *weapon - +// x - +// y - +// w - +// h - +//----------------------------------------------------------------------------- +void CHudWeaponFlashHelper::GetWeaponIconBounds( C_BaseCombatWeapon *weapon, int& x, int& y,int& w, int& h ) +{ + x = y = w = h = 0; + + if ( !m_pWeaponSelection || !weapon ) + return; + + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + { + return; + } + + wrect_t outrect; + if ( !m_pWeaponSelection->ComputeRect( pPlayer, weapon, &outrect ) ) + return; + + x = outrect.left; + y = outrect.top; + w = outrect.right - outrect.left; + h = outrect.bottom - outrect.top; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CHudWeaponFlashHelper::IsWeaponSelectionActive( void ) +{ + if ( m_pWeaponSelection && m_pWeaponSelection->IsActive() ) + return true; + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Change to commander view hint +//----------------------------------------------------------------------------- +class CHintHudWeaponFlash : public CHintItemBase +{ + DECLARE_CLASS( CHintHudWeaponFlash, CHintItemBase ); + +public: + CHintHudWeaponFlash( vgui::Panel *parent, const char *panelName ); + ~CHintHudWeaponFlash( void ); + + virtual void SetKeyValue( const char *key, const char *value ); + + void SetWeaponName( const char *name ); + char const *GetWeaponName( void ); + + virtual bool CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring ); + + virtual void SetActive( bool bActive ); + + virtual void Think( void ); + +private: + C_BaseCombatWeapon *GetWeaponOfType( const char *type ); + + enum + { + MAX_WEAPON_NAME = 128, + }; + + bool m_bWeaponSet; + + EHANDLE m_hWeapon; + + char m_szWeaponName[ MAX_WEAPON_NAME ]; + + CHudWeaponFlashHelper *m_pWeaponFlashHelper; + + EFFECT_HANDLE m_hLineEffect; +}; + +DECLARE_HINTITEMFACTORY( CHintHudWeaponFlash ) + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *parent - +// *panelName - +// *text - +// itemwidth - +//----------------------------------------------------------------------------- +CHintHudWeaponFlash::CHintHudWeaponFlash( vgui::Panel *parent, const char *panelName ) +: BaseClass( parent, panelName ) +{ + m_bWeaponSet = false; + SetWeaponName( "" ); + m_pWeaponFlashHelper = NULL; + m_hLineEffect = EFFECT_INVALID_HANDLE; + + CreateFlashEffect( this, parent ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CHintHudWeaponFlash::~CHintHudWeaponFlash( void ) +{ + if ( m_pWeaponFlashHelper ) + { + m_pWeaponFlashHelper->StopFlashing(); + m_pWeaponFlashHelper->SetFlashWeapon( NULL ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *instring - +// keylength - +// **ppOutstring - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CHintHudWeaponFlash::CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring ) +{ + if ( !Q_strnicmp( instring, "weapon", strlen( "weapon" ) ) ) + { + *keylength = strlen( "weapon" ); + *ppOutstring = GetWeaponName(); + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : char const +//----------------------------------------------------------------------------- +C_BaseCombatWeapon *CHintHudWeaponFlash::GetWeaponOfType( const char *type ) +{ + CBaseHudWeaponSelection *pHudSelection = GetHudWeaponSelection(); + if ( !pHudSelection ) + return NULL; + + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + if ( player ) + { + for ( int slot = 0; slot < MAX_WEAPON_SLOTS; slot++ ) + { + for ( int iPos = 0; iPos < MAX_WEAPON_POSITIONS; iPos++ ) + { + C_BaseCombatWeapon *weapon = pHudSelection->GetWeaponInSlot( slot, iPos ); + if ( !weapon ) + continue; + + if ( !stricmp( weapon->GetName(), type ) ) + { + return weapon; + } + } + } + } + + return NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *key - +// *value - +//----------------------------------------------------------------------------- +void CHintHudWeaponFlash::SetKeyValue( const char *key, const char *value ) +{ + BaseClass::SetKeyValue( key, value ); + + if ( !stricmp( key, "weapon" ) ) + { + SetWeaponName( value ); + + ComputeTitle(); + } + else if ( !stricmp( key, "weapontype" ) ) + { + // Find the weapon itself + C_BaseCombatWeapon *w = GetWeaponOfType( value ); + if ( w ) + { + m_hWeapon = w; + + // Create open up hud effect, etc. + m_pWeaponFlashHelper = GET_HUDELEMENT( CHudWeaponFlashHelper ); + if ( m_pWeaponFlashHelper ) + { + m_pWeaponFlashHelper->SetFlashWeapon( w ); + + int x, y, wide, tall; + + m_pWeaponFlashHelper->GetWeaponIconBounds( w, x, y, wide, tall ); + + C_TFBaseHint *hint = static_cast< C_TFBaseHint * >( GetParent() ); + + m_hLineEffect = CreateAxialLineEffectToRect( this, hint, x, y, wide, tall ); + + hint->SetDesiredPosition( x, y + tall + 50 ); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHintHudWeaponFlash::Think( void ) +{ + BaseClass::Think(); + + if ( !m_pWeaponFlashHelper ) + return; + + if ( m_pWeaponFlashHelper->IsWeaponSelectionActive() ) + { + m_bCompleted = true; + } + + bool incommander = ( g_pClientMode == ClientModeCommander() ); + + CPanelEffect *effect = g_pTF2RootPanel->FindEffect( m_hLineEffect ); + if ( effect ) + { + effect->SetVisible( !incommander ); + + C_BaseCombatWeapon *w = static_cast< C_BaseCombatWeapon * >( ( C_BaseEntity * )m_hWeapon ); + + // Update target rectangle + if ( w ) + { + int x, y, wide, tall; + + m_pWeaponFlashHelper->GetWeaponIconBounds( w, x, y, wide, tall ); + + effect->SetTargetRect( x, y, wide, tall ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : bActive - +//----------------------------------------------------------------------------- +void CHintHudWeaponFlash::SetActive( bool bActive ) +{ + BaseClass::SetActive( bActive ); + + if ( !m_pWeaponFlashHelper ) + return; + + if ( bActive ) + { + m_pWeaponFlashHelper->StartFlashing(); + } + else + { + m_pWeaponFlashHelper->StopFlashing(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *name - +//----------------------------------------------------------------------------- +void CHintHudWeaponFlash::SetWeaponName( const char *name ) +{ + Q_strncpy( m_szWeaponName, name, MAX_WEAPON_NAME ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : char const +//----------------------------------------------------------------------------- +const char *CHintHudWeaponFlash::GetWeaponName( void ) +{ + return m_szWeaponName; +} + + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +struct FUNCTIONLIST_t +{ + const char *name; + HINTCOMPLETIONFUNCTION pfn; +}; + +static FUNCTIONLIST_t g_CompletionFunctions[]= +{ + { NULL, NULL }, +}; + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *name - +// Output : HINTCOMPLETIONFUNCTION +//----------------------------------------------------------------------------- +HINTCOMPLETIONFUNCTION LookupCompletionFunction( const char *name ) +{ + int i = 0; + while ( 1 ) + { + FUNCTIONLIST_t *f = &g_CompletionFunctions[ i ]; + if ( !f->name ) + break; + + if ( !stricmp( f->name, name ) ) + { + return f->pfn; + } + i++; + } + + return NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +struct HINTITEM_t +{ + const char *name; + CHintItemBase *( *pfn )( vgui::Panel *parent, const char *name ); +}; + +static HINTITEM_t g_HintItems[]= +{ + { "CHintChangeToCommander", GET_HINTITEMFACTORY_NAME( CHintChangeToCommander ) }, + { "CHintGotoObject", GET_HINTITEMFACTORY_NAME( CHintGotoObject ) }, + { "CHintDeployWeapon", GET_HINTITEMFACTORY_NAME( CHintDeployWeapon ) }, + { "CHintStartPlacing", GET_HINTITEMFACTORY_NAME( CHintStartPlacing ) }, + { "CHintStartBuilding", GET_HINTITEMFACTORY_NAME( CHintStartBuilding ) }, + { "CHintWaitBuilding", GET_HINTITEMFACTORY_NAME( CHintWaitBuilding ) }, + { "CHintBuilderSelection", GET_HINTITEMFACTORY_NAME( CHintBuilderSelection ) }, + { "CHintBuilderStartAction", GET_HINTITEMFACTORY_NAME( CHintBuilderStartAction ) }, + { "CHintHudWeaponFlash", GET_HINTITEMFACTORY_NAME( CHintHudWeaponFlash ) }, + { NULL, NULL }, +}; + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *parent - +// *name - +// Output : CHintItemBase +//----------------------------------------------------------------------------- +CHintItemBase *CreateHintItem( vgui::Panel *parent, const char *name ) +{ + int i = 0; + while ( 1 ) + { + HINTITEM_t *hi = &g_HintItems[ i ]; + if ( !hi->name ) + break; + + if ( !stricmp( hi->name, name ) ) + { + if ( hi->pfn ) + { + return (*hi->pfn)( parent, name ); + } + else + { + Assert( !"Missing function pointer in CreateHintItem table!" ); + return NULL; + } + } + i++; + } + + return NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +CHintData g_HintDatas[] = +{ + // Vote + { "TF_HINT_VOTEFORTECHNOLOGY", TF_HINT_VOTEFORTECHNOLOGY, 0, NULL, -1 }, + + // Build + { "TF_HINT_BUILDRESOURCEPUMP", TF_HINT_BUILDRESOURCEPUMP, 0, HintEventFn_BuildObject, OBJ_RESOURCEPUMP }, + { "TF_HINT_BUILDSENTRYGUN_PLASMA", TF_HINT_BUILDSENTRYGUN_PLASMA, 0, HintEventFn_BuildObject, OBJ_SENTRYGUN_PLASMA }, + + // Object interaction + { "TF_HINT_REPAIROBJECT", TF_HINT_REPAIROBJECT, 0, NULL, -1 }, + + // Technology discovery + { "TF_HINT_NEWTECHNOLOGY", TF_HINT_NEWTECHNOLOGY, 0, NULL, -1 }, + { "TF_HINT_WEAPONRECEIVED", TF_HINT_WEAPONRECEIVED, 0, NULL, -1 }, + + // Sentinal + { NULL, 0, 0, NULL, -1 }, +}; + + +int GetNumHintDatas() +{ + return ARRAYSIZE( g_HintDatas ); +} + + +CHintData* GetHintData( int i ) +{ + return &g_HintDatas[i]; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : id - +// Output : char const +//----------------------------------------------------------------------------- +const char *LookupHintName( int id ) +{ + int i = 0; + while ( 1 ) + { + CHintData *h = &g_HintDatas[ i ]; + if ( !h->name ) + break; + + if ( h->id == id ) + { + return h->name; + } + + i++; + } + + return NULL; +} + +DECLARE_HINTFACTORY( C_TFBaseHint ) + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +typedef struct +{ + const char *name; + C_TFBaseHint *( *pfn )( int id, int entity ); +} +HINT_t; + +static HINT_t g_Hints[]= +{ + { "C_TFBaseHint", GET_HINTFACTORY_NAME( C_TFBaseHint ) }, + { NULL, NULL }, +}; + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *name - +// id - +// entity - +// Output : C_TFBaseHint +//----------------------------------------------------------------------------- +C_TFBaseHint *FactoryCreateHint( const char *name, int id, int entity ) +{ + int i = 0; + while ( 1 ) + { + HINT_t *hi = &g_Hints[ i ]; + if ( !hi->name ) + break; + + if ( !stricmp( hi->name, name ) ) + { + if ( hi->pfn ) + { + return (*hi->pfn)( id, entity ); + } + else + { + Assert( !"Missing function pointer in FactoryCreateHint table!" ); + return NULL; + } + } + i++; + } + + return NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: Generic factory for hints +// Input : id - +// entity - +// Output : C_TFBaseHint +//----------------------------------------------------------------------------- +C_TFBaseHint *C_TFBaseHint::CreateHint( int id, const char *subsection, int entity ) +{ + C_TFBaseHint *hint = NULL; + const char *hintname = LookupHintName( id ); + if ( !hintname ) + return NULL; + + // See if we should see this hint any more + KeyValues *pkvStats = GetHintDisplayStats(); + if ( pkvStats ) + { + KeyValues *pkvStatSection = pkvStats->FindKey( hintname, true ); + if ( pkvStatSection ) + { + if ( subsection && subsection[0] ) + { + pkvStatSection = pkvStatSection->FindKey( subsection, true ); + } + } + + if ( !pkvStatSection ) + { + Assert( !"C_TFBaseHint::CreateHint: Problem creating hint subsection" ); + return NULL; + } + + int times_shown = pkvStatSection->GetInt( "times_shown", 0 ); + pkvStatSection->SetString( "times_shown", VarArgs( "%i", times_shown ) ); + + int times_max = pkvStatSection->GetInt( "times_max", 3 ); + pkvStatSection->SetString( "times_max", VarArgs( "%i", times_max ) ); + + if ( times_shown >= times_max ) + return NULL; + + // Remember that we've seen it again + times_shown++; + pkvStatSection->SetString( "times_shown", VarArgs( "%i", times_shown ) ); + } + + // Ask Hint manager API for key values + KeyValues *pkvHintSystem = GetHintKeyValues(); + if ( pkvHintSystem ) + { + // + // Parse the list of hints looking for name + KeyValues *pkvHint = pkvHintSystem->FindKey( hintname ); + if ( pkvHint ) + { + // Use classname string to construct hint + const char *defaultclass = "C_TFBaseHint"; + const char *classname = pkvHint->GetString( "classname" ); + if ( !classname || !classname[ 0 ] || !stricmp( classname, "default" ) ) + { + classname = defaultclass; + } + + hint = FactoryCreateHint( classname, id, entity ); + if ( hint ) + { + hint->ParseFromData( pkvHint ); + } + } + } + + return hint; +} diff --git a/game/client/tf2/c_tf_hints.h b/game/client/tf2/c_tf_hints.h new file mode 100644 index 0000000..57615bf --- /dev/null +++ b/game/client/tf2/c_tf_hints.h @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_TF_HINTS_H +#define C_TF_HINTS_H +#ifdef _WIN32 +#pragma once +#endif + + +class C_HintEvent_Base; +class CHintData; + +// The HINTNAME_t structures are where data and code are registered for each hint type. +typedef void (*HintEventFn)( CHintData *pData, C_HintEvent_Base *pHint ); + + +class CHintData +{ +public: + char *name; + int id; + int timesseen; + + HintEventFn m_pEventFn; + int m_ObjectType; // If this is a hint about an object, this is the object type. +}; + + +extern int GetNumHintDatas(); +extern CHintData* GetHintData( int i ); + + +#endif // C_TF_HINTS_H diff --git a/game/client/tf2/c_tf_playerclass.cpp b/game/client/tf2/c_tf_playerclass.cpp new file mode 100644 index 0000000..b907539 --- /dev/null +++ b/game/client/tf2/c_tf_playerclass.cpp @@ -0,0 +1,65 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Auto Repair +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_tf_class_commando.h" +#include "c_tf_class_defender.h" +#include "c_tf_class_escort.h" +#include "c_tf_class_infiltrator.h" +#include "c_tf_class_medic.h" +#include "c_tf_class_recon.h" +#include "c_tf_class_sniper.h" +#include "c_tf_class_support.h" +#include "c_tf_class_sapper.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PlayerClass::C_PlayerClass( C_BaseTFPlayer *pPlayer ) +{ + // Save peer. + m_pPlayer = pPlayer; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PlayerClass::~C_PlayerClass() +{ +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PlayerClass *C_PlayerClass::Create( C_BaseTFPlayer *pPlayer, int iClassType ) +{ + // Create the class type + switch ( iClassType ) + { + case TFCLASS_COMMANDO: { return ( new C_PlayerClassCommando( pPlayer ) ); } + case TFCLASS_DEFENDER: { return ( new C_PlayerClassDefender( pPlayer ) ); } + case TFCLASS_ESCORT: { return ( new C_PlayerClassEscort( pPlayer ) ); } + case TFCLASS_INFILTRATOR: { return ( new C_PlayerClassInfiltrator( pPlayer ) ); } + case TFCLASS_MEDIC: { return ( new C_PlayerClassMedic( pPlayer ) ); } + case TFCLASS_RECON: { return ( new C_PlayerClassRecon( pPlayer ) ); } + case TFCLASS_SNIPER: { return ( new C_PlayerClassSniper( pPlayer ) ); } + case TFCLASS_SUPPORT: { return ( new C_PlayerClassSupport( pPlayer ) ); } + case TFCLASS_SAPPER: { return ( new C_PlayerClassSapper( pPlayer ) ); } + default: { return NULL; } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PlayerClass::Destroy( C_PlayerClass *pPlayerClass ) +{ + if ( pPlayerClass ) + { + delete pPlayerClass; + } +} diff --git a/game/client/tf2/c_tf_playerclass.h b/game/client/tf2/c_tf_playerclass.h new file mode 100644 index 0000000..36e4317 --- /dev/null +++ b/game/client/tf2/c_tf_playerclass.h @@ -0,0 +1,50 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Auto Repair +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_TF_PLAYERCLASS_H +#define C_TF_PLAYERCLASS_H +#ifdef _WIN32 +#pragma once +#endif + +class C_BaseTFPlayer; +class CUserCmd; + +class C_PlayerClass +{ +public: + + DECLARE_CLASS_NOBASE( C_PlayerClass ); + + C_PlayerClass( C_BaseTFPlayer *pPlayer ); + ~C_PlayerClass(); + + static C_PlayerClass *Create( C_BaseTFPlayer *pPlayer, int iClassType ); + static void Destroy( C_PlayerClass *pPlayerClass ); + + virtual void PreClassThink( void ) {}; + virtual void ClassThink( void ) {}; + virtual void PostClassThink( void ) {}; + + virtual void ClassPreDataUpdate( void ) {}; + virtual void ClassOnDataChanged( void ) {}; + + virtual void CreateMove( float flInputSampleTime, CUserCmd *pCmd ) {}; + + // Vehicles + virtual bool CanGetInVehicle( void ) { return true; } + +protected: + + C_BaseTFPlayer *m_pPlayer; // reference to player (peer) +}; + + +#include "TFClassData_Shared.h" + + +#endif // C_TF_PLAYERCLASS_H
\ No newline at end of file diff --git a/game/client/tf2/c_tfcarrier.cpp b/game/client/tf2/c_tfcarrier.cpp new file mode 100644 index 0000000..c516861 --- /dev/null +++ b/game/client/tf2/c_tfcarrier.cpp @@ -0,0 +1,30 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client's CObjectSentrygun +// +// $NoKeywords: $ +//=============================================================================// +#include "c_base.h +#include "bone_setup.h" +#include "CommanderOverlay.h" +#include "c_ai_basenpc.h" +#include "c_tfcarrier.h" + +IMPLEMENT_CLIENTCLASS_DT(C_TFCarrier, DT_TFCarrier, CTFCarrier) + RecvPropInt(RECVINFO(m_iHealth)), + RecvPropInt(RECVINFO(m_iMaxHealth)), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_TFCarrier::C_TFCarrier() +{ + CONSTRUCT_MINIMAP_PANEL( "minimap_helicopter", MINIMAP_COLLECTORS ); +} + +void C_TFCarrier::SetDormant( bool inside ) +{ + BaseClass::SetDormant( bDormant ); + ENTITY_PANEL_ACTIVATE( "helicopter", !bDormant ); +} diff --git a/game/client/tf2/c_tfcarrier.h b/game/client/tf2/c_tfcarrier.h new file mode 100644 index 0000000..d49d60a --- /dev/null +++ b/game/client/tf2/c_tfcarrier.h @@ -0,0 +1,43 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_TFCARRIER_H +#define C_TFCARRIER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_rescollector.h" +#include "hud_minimap.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_TFCarrier : public C_AI_BaseNPC +{ + DECLARE_CLASS( C_TFCarrier, C_AI_BaseNPC ); + +public: + DECLARE_CLIENTCLASS(); + DECLARE_ENTITY_PANEL(); + DECLARE_MINIMAP_PANEL( ); + + C_TFCarrier(); + + virtual void SetDormant( bool bDormant ); + virtual int GetHealth() const { return m_iHealth; } + virtual int GetMaxHealth() const { return m_iMaxHealth; } + +public: + int m_iHealth; + int m_iMaxHealth; + +private: + C_TFCarrier( const C_TFCarrier & ); +}; + +#endif // C_TFCARRIER_H diff --git a/game/client/tf2/c_tfplayerlocaldata.h b/game/client/tf2/c_tfplayerlocaldata.h new file mode 100644 index 0000000..d863ae2 --- /dev/null +++ b/game/client/tf2/c_tfplayerlocaldata.h @@ -0,0 +1,50 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Defines the player specific data that is sent only to the player +// to whom it belongs. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_TFPLAYERLOCALDATA_H +#define C_TFPLAYERLOCALDATA_H +#ifdef _WIN32 +#pragma once +#endif + +#include "techtree.h" +#include "c_baseobject.h" + +//----------------------------------------------------------------------------- +// Purpose: Player specific data ( sent only to local player, too ) +//----------------------------------------------------------------------------- +class CTFPlayerLocalData +{ +public: + DECLARE_PREDICTABLE(); + + int m_nInTacticalView; + + bool m_bKnockedDown; + QAngle m_vecKnockDownDir; + + bool m_bThermalVision; + + int m_iIDEntIndex; + + // Resource chunk carrying counts + int m_iResourceAmmo[ RESOURCE_TYPES ]; // 0 = Normal resources, 1 = Processed resources + + // Resource bank + int m_iBankResources; // Current amounts of resource in my bank + + // Objects + CUtlVector< CHandle<C_BaseObject> > m_aObjects; + + // Object sapper placement handling + bool m_bAttachingSapper; + float m_flSapperAttachmentFrac; + bool m_bForceMapOverview; +}; + +#endif // C_TFPLAYERLOCALDATA_H diff --git a/game/client/tf2/c_tfplayerresource.cpp b/game/client/tf2/c_tfplayerresource.cpp new file mode 100644 index 0000000..edd4292 --- /dev/null +++ b/game/client/tf2/c_tfplayerresource.cpp @@ -0,0 +1,30 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: TF's custom C_PlayerResource +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_tfplayerresource.h" +#include "hud.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +IMPLEMENT_CLIENTCLASS_DT(C_TFPlayerResource, DT_TFPlayerResource, CTFPlayerResource) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_TFPlayerResource::C_TFPlayerResource() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_TFPlayerResource::~C_TFPlayerResource() +{ +}
\ No newline at end of file diff --git a/game/client/tf2/c_tfplayerresource.h b/game/client/tf2/c_tfplayerresource.h new file mode 100644 index 0000000..210b106 --- /dev/null +++ b/game/client/tf2/c_tfplayerresource.h @@ -0,0 +1,30 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: TF's custom C_PlayerResource +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_TFPLAYERRESOURCE_H +#define C_TFPLAYERRESOURCE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "shareddefs.h" +#include "c_playerresource.h" + +class C_TFPlayerResource : public C_PlayerResource +{ + DECLARE_CLASS( C_TFPlayerResource, C_PlayerResource ); +public: + DECLARE_CLIENTCLASS(); + + C_TFPlayerResource(); + virtual ~C_TFPlayerResource(); + +public: +}; + + +#endif // C_TFPLAYERRESOURCE_H diff --git a/game/client/tf2/c_tfteam.cpp b/game/client/tf2/c_tfteam.cpp new file mode 100644 index 0000000..b1adecd --- /dev/null +++ b/game/client/tf2/c_tfteam.cpp @@ -0,0 +1,217 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client side C_TFTeam class +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_tfteam.h" +#include "c_basetfplayer.h" +#include "engine/IEngineSound.h" +#include "hud.h" +#include "recvproxy.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +#define ATTACK_NOTIFICATION_TIME 10.0f + +#define MESSAGESTRINGID_RESOURCESHARVESTED (IMessageChars::MESSAGESTRINGID_BASE+0) + +//----------------------------------------------------------------------------- +// Purpose: RecvProxy that converts the Team's object UtlVector to entindexes +//----------------------------------------------------------------------------- +void RecvProxy_ObjectList( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + C_TFTeam *pTeam = (C_TFTeam*)pStruct; + CBaseHandle *pHandle = (CBaseHandle*)(&(pTeam->m_aObjects[ pData->m_iElement ])); + RecvProxy_IntToEHandle( pData, pStruct, pHandle ); +} + + +void RecvProxyArrayLength_TeamObjects( void *pStruct, int objectID, int currentArrayLength ) +{ + C_TFTeam *pTeam = (C_TFTeam*)pStruct; + + if ( pTeam->m_aObjects.Count() != currentArrayLength ) + { + pTeam->m_aObjects.SetSize( currentArrayLength ); + } +} + + +IMPLEMENT_CLIENTCLASS_DT(C_TFTeam, DT_TFTeam, CTFTeam) + RecvPropFloat( RECVINFO(m_fResources) ), + RecvPropFloat( RECVINFO(m_fPotentialResources) ), + RecvPropInt( RECVINFO(m_bHaveZone) ), + + RecvPropArray2( + RecvProxyArrayLength_TeamObjects, + RecvPropInt( "object_array_element", 0, SIZEOF_IGNORE, 0, RecvProxy_ObjectList ), + MAX_OBJECTS_PER_TEAM, + 0, + "object_array" + ), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_TFTeam::C_TFTeam() +{ + m_LastAttackNotificationTime = -10000; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_TFTeam::~C_TFTeam() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_TFTeam::NotifyBaseUnderAttack( const Vector &vecPosition, bool bPlaySound, bool bForce ) +{ + float currentTime = gpGlobals->curtime; + if ( bForce || (currentTime - m_LastAttackNotificationTime > ATTACK_NOTIFICATION_TIME) ) + { + m_LastAttackNotificationTime = currentTime; + + if (GetLocalTeam() == this) + { + // Play a sound. + if (bPlaySound) + { + CLocalPlayerFilter filter; + C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "TFTeam.NotifyBaseUnderAttack" ); + } + + MinimapCreateTempTrace( "minimap_under_attack", MINIMAP_PERSONAL_ORDERS, vecPosition ); + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +float C_TFTeam::GetTeamResources( void ) +{ + return m_fResources; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +float C_TFTeam::GetPotentialTeamResources( void ) +{ + return m_fPotentialResources; +} + + +//----------------------------------------------------------------------------- +// Purpose: Return true if this team controls a zone of the specified resource type +//----------------------------------------------------------------------------- +bool C_TFTeam::GetHaveZone( void ) +{ + return m_bHaveZone; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int C_TFTeam::GetNumObjects( int iObjectType ) +{ + // Asking for a count of a specific object type? + if ( iObjectType > 0 ) + { + int iCount = 0; + for ( int i = 0; i < GetNumObjects(); i++ ) + { + CBaseObject *pObject = GetObject(i); + if ( pObject && pObject->GetType() == iObjectType ) + { + iCount++; + } + } + return iCount; + } + + return m_aObjects.Count(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_BaseObject *C_TFTeam::GetObject( int iIndex ) +{ + Assert( iIndex >= 0 && iIndex < m_aObjects.Size() ); + return static_cast<C_BaseObject*>((C_BaseEntity*)m_aObjects[iIndex]); +} + +bool C_TFTeam::IsObjectValid( int iIndex ) +{ + Assert( iIndex >= 0 && iIndex < m_aObjects.Size() ); + return ((C_BaseEntity const*)m_aObjects[iIndex] != NULL); +} + + +//----------------------------------------------------------------------------- +// Purpose: Receive a spawn message from the server +//----------------------------------------------------------------------------- +void C_TFTeam::ReceiveMessage( int classID, bf_read &msg ) +{ + if ( classID != GetClientClass()->m_ClassID ) + { + // message is for subclass + BaseClass::ReceiveMessage( classID, msg ); + return; + } + + int iAmount = msg.ReadLong(); + + int iYPos; + + // Use appropriate string based on client's team + char sResourceString[256]; + if ( GetLocalTeam() == this ) + { + itoa(iAmount, sResourceString, 10 ); + Q_strncat( sResourceString, " RESOURCES HARVESTED!", sizeof(sResourceString), COPY_ALL_CHARACTERS ); + iYPos = ScreenHeight() / 4; + } + else + { + char sAmount[256]; + itoa(iAmount, sAmount, 10 ); + Q_strncpy( sResourceString, "ENEMY TEAM HAS HARVESTED ", sizeof(sResourceString) ); + Q_strncat( sResourceString, sAmount, sizeof(sResourceString), COPY_ALL_CHARACTERS ); + Q_strncat( sResourceString, " RESOURCES!", sizeof(sResourceString), COPY_ALL_CHARACTERS ); + iYPos = (ScreenHeight() / 4) + 32; + } + + // Clear out any old strings with this ID. + messagechars->RemoveStringsByID( MESSAGESTRINGID_RESOURCESHARVESTED ); + + // Print the string + int width, height; + messagechars->GetStringLength( g_hFontTrebuchet24, &width, &height, sResourceString ); + messagechars->DrawStringForTime( + 5.0, + g_hFontTrebuchet24, + (ScreenWidth() - width) / 2, + iYPos, + 192, + 192, + 192, + 255, + sResourceString, + MESSAGESTRINGID_RESOURCESHARVESTED ); +} + diff --git a/game/client/tf2/c_tfteam.h b/game/client/tf2/c_tfteam.h new file mode 100644 index 0000000..7ee6d61 --- /dev/null +++ b/game/client/tf2/c_tfteam.h @@ -0,0 +1,62 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client side CTFTeam class +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_TFTEAM_H +#define C_TFTEAM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_team.h" +#include "shareddefs.h" +#include "techtree.h" +#include "imessagechars.h" + +class C_BaseEntity; +class C_BaseObject; +class CBaseTechnology; + +//----------------------------------------------------------------------------- +// Purpose: TF's Team manager +//----------------------------------------------------------------------------- +class C_TFTeam : public C_Team +{ + DECLARE_CLASS( C_TFTeam, C_Team ); +public: + DECLARE_CLIENTCLASS(); + + C_TFTeam(); + virtual ~C_TFTeam(); + + // Data Access + virtual float GetTeamResources( void ); + virtual float GetPotentialTeamResources( void ); + virtual bool GetHaveZone( void ); + + // Objects, note GetObject can return NULL! + int GetNumObjects( int iObjectType = -1 ); + C_BaseObject *GetObject( int iIndex ); + bool IsObjectValid( int iIndex ); + + void NotifyBaseUnderAttack( const Vector &vecPosition, bool bPlaySound = true, bool bForce = false ); + + virtual void ReceiveMessage( int classID, bf_read &msg ); + +public: + // Resource UI data + bool m_bHaveZone; + + float m_fResources; // Current amounts of resources + float m_fPotentialResources; // Potential amounts of each resource when all harvesters have returned + + float m_LastAttackNotificationTime; + + CUtlVector< EHANDLE > m_aObjects; +}; + + +#endif // C_TFTEAM_H diff --git a/game/client/tf2/c_vehicle_battering_ram.cpp b/game/client/tf2/c_vehicle_battering_ram.cpp new file mode 100644 index 0000000..e4c68e1 --- /dev/null +++ b/game/client/tf2/c_vehicle_battering_ram.cpp @@ -0,0 +1,208 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_basefourwheelvehicle.h" +#include "tf_movedata.h" +#include "ObjectControlPanel.h" +#include <vgui_controls/Label.h> +#include "vgui_bitmapbutton.h" + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_VehicleBatteringRam : public C_BaseTFFourWheelVehicle +{ + DECLARE_CLASS( C_VehicleBatteringRam, C_BaseTFFourWheelVehicle ); +public: + DECLARE_CLIENTCLASS(); + + C_VehicleBatteringRam(); + +public: + // IClientVehicle overrides + virtual bool IsPassengerUsingStandardWeapons( int nRole ); + virtual void UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd ); + +private: + C_VehicleBatteringRam( const C_VehicleBatteringRam & ); // not defined, not accessible +}; + +IMPLEMENT_CLIENTCLASS_DT(C_VehicleBatteringRam, DT_VehicleBatteringRam, CVehicleBatteringRam) +END_RECV_TABLE() + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_VehicleBatteringRam::C_VehicleBatteringRam() +{ +} + + +//----------------------------------------------------------------------------- +// Does the player use his normal weapons while in this mode? +//----------------------------------------------------------------------------- +bool C_VehicleBatteringRam::IsPassengerUsingStandardWeapons( int nRole ) +{ + return (nRole > 1); +} + +//----------------------------------------------------------------------------- +// Clamps the view angles while manning the gun +//----------------------------------------------------------------------------- +void C_VehicleBatteringRam::UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd ) +{ + int nRole = GetPassengerRole( pLocalPlayer ); + + // Restrict the view of the 1st passenger + if (nRole == 1) + { + RestrictView( nRole, -90, 90, pCmd->viewangles ); + } +} + +//----------------------------------------------------------------------------- +// Control screen +//----------------------------------------------------------------------------- +class CVehicleBatteringRamControlPanel : public CObjectControlPanel +{ + DECLARE_CLASS( CVehicleBatteringRamControlPanel, CObjectControlPanel ); + +public: + CVehicleBatteringRamControlPanel( vgui::Panel *parent, const char *panelName ); + virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); + virtual void OnTick(); + virtual void OnCommand( const char *command ); + +private: + void GetInRam( void ); + +private: + vgui::Label *m_pDriverLabel; + vgui::Label *m_pPassengerLabel; + vgui::Button *m_pOccupyButton; +}; + + +DECLARE_VGUI_SCREEN_FACTORY( CVehicleBatteringRamControlPanel, "vehicle_battering_ram_control_panel" ); + + +//----------------------------------------------------------------------------- +// Constructor: +//----------------------------------------------------------------------------- +CVehicleBatteringRamControlPanel::CVehicleBatteringRamControlPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, "CVehicleBatteringRamControlPanel" ) +{ +} + + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- +bool CVehicleBatteringRamControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ) +{ + m_pDriverLabel = new vgui::Label( this, "DriverReadout", "" ); + m_pPassengerLabel = new vgui::Label( this, "PassengerReadout", "" ); + m_pOccupyButton = new CBitmapButton( this, "OccupyButton", "Occupy" ); + + if (!BaseClass::Init(pKeyValues, pInitData)) + return false; + + return true; +} + + +//----------------------------------------------------------------------------- +// Frame-based update +//----------------------------------------------------------------------------- +void CVehicleBatteringRamControlPanel::OnTick() +{ + BaseClass::OnTick(); + + C_BaseObject *pObj = GetOwningObject(); + if (!pObj) + return; + + Assert( dynamic_cast<C_VehicleBatteringRam*>(pObj) ); + C_VehicleBatteringRam *pRam = static_cast<C_VehicleBatteringRam*>(pObj); + + char buf[256]; + // Update the currently manned player label + if ( pRam->GetDriverPlayer() ) + { + Q_snprintf( buf, sizeof( buf ), "Driven by %s", pRam->GetDriverPlayer()->GetPlayerName() ); + m_pDriverLabel->SetText( buf ); + m_pDriverLabel->SetVisible( true ); + } + else + { + m_pDriverLabel->SetVisible( false ); + } + + int nPassengerCount = pRam->GetPassengerCount(); + int nMaxPassengerCount = pRam->GetMaxPassengerCount(); + + Q_snprintf( buf, sizeof( buf ), "Passengers %d/%d", nPassengerCount >= 1 ? nPassengerCount - 1 : 0, nMaxPassengerCount - 1 ); + m_pPassengerLabel->SetText( buf ); + + // Update the get in button + if ( pRam->IsPlayerInVehicle( C_BaseTFPlayer::GetLocalPlayer() ) ) + { + m_pOccupyButton->SetEnabled( false ); + return; + } + + if ( pRam->GetOwner() == C_BaseTFPlayer::GetLocalPlayer() ) + { + if (nPassengerCount == nMaxPassengerCount) + { + // Owners can boot other players to get in + C_BaseTFPlayer *pPlayer = static_cast<C_BaseTFPlayer*>(pRam->GetPassenger( VEHICLE_ROLE_DRIVER )); + Q_snprintf( buf, sizeof( buf ), "Get In (Ejecting %s)", pPlayer->GetPlayerName() ); + m_pDriverLabel->SetText( buf ); + m_pOccupyButton->SetEnabled( true ); + } + else + { + m_pOccupyButton->SetText( "Get In" ); + m_pOccupyButton->SetEnabled( true ); + } + } + else + { + m_pOccupyButton->SetText( "Get In" ); + m_pOccupyButton->SetEnabled( pRam->GetPassengerCount() < pRam->GetMaxPassengerCount() ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Handle clicking on the Occupy button +//----------------------------------------------------------------------------- +void CVehicleBatteringRamControlPanel::GetInRam( void ) +{ + C_BaseObject *pObj = GetOwningObject(); + if (pObj) + { + pObj->SendClientCommand( "toggle_use" ); + } +} + +//----------------------------------------------------------------------------- +// Button click handlers +//----------------------------------------------------------------------------- +void CVehicleBatteringRamControlPanel::OnCommand( const char *command ) +{ + if (!Q_strnicmp(command, "Occupy", 7)) + { + GetInRam(); + return; + } + + BaseClass::OnCommand(command); +} + diff --git a/game/client/tf2/c_vehicle_flatbed.cpp b/game/client/tf2/c_vehicle_flatbed.cpp new file mode 100644 index 0000000..0457d91 --- /dev/null +++ b/game/client/tf2/c_vehicle_flatbed.cpp @@ -0,0 +1,183 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_basefourwheelvehicle.h" +#include "tf_movedata.h" +#include "ObjectControlPanel.h" +#include <vgui_controls/Label.h> +#include <vgui_controls/Button.h> + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_VehicleFlatbed : public C_BaseTFFourWheelVehicle +{ + DECLARE_CLASS( C_VehicleFlatbed, C_BaseTFFourWheelVehicle ); +public: + DECLARE_CLIENTCLASS(); + + C_VehicleFlatbed(); + +private: + C_VehicleFlatbed( const C_VehicleFlatbed & ); // not defined, not accessible + +}; + + +IMPLEMENT_CLIENTCLASS_DT(C_VehicleFlatbed, DT_VehicleFlatbed, CVehicleFlatbed) +END_RECV_TABLE() + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_VehicleFlatbed::C_VehicleFlatbed() +{ +} + + +//----------------------------------------------------------------------------- +// Control screen +//----------------------------------------------------------------------------- +class CVehicleFlatbedControlPanel : public CObjectControlPanel +{ + DECLARE_CLASS( CVehicleFlatbedControlPanel, CObjectControlPanel ); + +public: + CVehicleFlatbedControlPanel( vgui::Panel *parent, const char *panelName ); + virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); + virtual void OnTick(); + virtual void OnCommand( const char *command ); + +private: + void GetInRam( void ); + +private: + vgui::Label *m_pDriverLabel; + vgui::Label *m_pPassengerLabel; + vgui::Button *m_pOccupyButton; +}; + + +DECLARE_VGUI_SCREEN_FACTORY( CVehicleFlatbedControlPanel, "vehicle_battering_ram_control_panel" ); + + +//----------------------------------------------------------------------------- +// Constructor: +//----------------------------------------------------------------------------- +CVehicleFlatbedControlPanel::CVehicleFlatbedControlPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, "CVehicleBatteringRamControlPanel" ) +{ +} + + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- +bool CVehicleFlatbedControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ) +{ + m_pDriverLabel = new vgui::Label( this, "DriverReadout", "" ); + m_pPassengerLabel = new vgui::Label( this, "PassengerReadout", "" ); + m_pOccupyButton = new vgui::Button( this, "OccupyButton", "Occupy" ); + + if (!BaseClass::Init(pKeyValues, pInitData)) + return false; + + return true; +} + + +//----------------------------------------------------------------------------- +// Frame-based update +//----------------------------------------------------------------------------- +void CVehicleFlatbedControlPanel::OnTick() +{ + BaseClass::OnTick(); + + C_BaseObject *pObj = GetOwningObject(); + if (!pObj) + return; + + Assert( dynamic_cast<C_VehicleFlatbed*>(pObj) ); + C_VehicleFlatbed *pRam = static_cast<C_VehicleFlatbed*>(pObj); + + char buf[256]; + // Update the currently manned player label + if ( pRam->GetDriverPlayer() ) + { + Q_snprintf( buf, sizeof( buf ), "Driven by %s", pRam->GetDriverPlayer()->GetPlayerName() ); + m_pDriverLabel->SetText( buf ); + m_pDriverLabel->SetVisible( true ); + } + else + { + m_pDriverLabel->SetVisible( false ); + } + + int nPassengerCount = pRam->GetPassengerCount(); + int nMaxPassengerCount = pRam->GetMaxPassengerCount(); + + Q_snprintf( buf, sizeof( buf ), "Passengers %d/%d", nPassengerCount >= 1 ? nPassengerCount - 1 : 0, nMaxPassengerCount - 1 ); + m_pPassengerLabel->SetText( buf ); + + // Update the get in button + if ( pRam->IsPlayerInVehicle( C_BaseTFPlayer::GetLocalPlayer() ) ) + { + m_pOccupyButton->SetEnabled( false ); + return; + } + + if ( pRam->GetOwner() == C_BaseTFPlayer::GetLocalPlayer() ) + { + if (nPassengerCount == nMaxPassengerCount) + { + // Owners can boot other players to get in + C_BaseTFPlayer *pPlayer = static_cast<C_BaseTFPlayer*>(pRam->GetPassenger( VEHICLE_ROLE_DRIVER )); + Q_snprintf( buf, sizeof( buf ), "Get In (Ejecting %s)", pPlayer->GetPlayerName() ); + m_pDriverLabel->SetText( buf ); + m_pOccupyButton->SetEnabled( true ); + } + else + { + m_pOccupyButton->SetText( "Get In" ); + m_pOccupyButton->SetEnabled( true ); + } + } + else + { + m_pOccupyButton->SetText( "Get In" ); + m_pOccupyButton->SetEnabled( pRam->GetPassengerCount() < pRam->GetMaxPassengerCount() ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Handle clicking on the Occupy button +//----------------------------------------------------------------------------- +void CVehicleFlatbedControlPanel::GetInRam( void ) +{ + C_BaseObject *pObj = GetOwningObject(); + if (pObj) + { + pObj->SendClientCommand( "toggle_use" ); + } +} + +//----------------------------------------------------------------------------- +// Button click handlers +//----------------------------------------------------------------------------- +void CVehicleFlatbedControlPanel::OnCommand( const char *command ) +{ + if (!Q_strnicmp(command, "Occupy", 7)) + { + GetInRam(); + return; + } + + BaseClass::OnCommand(command); +} + diff --git a/game/client/tf2/c_vehicle_mortar.cpp b/game/client/tf2/c_vehicle_mortar.cpp new file mode 100644 index 0000000..844c544 --- /dev/null +++ b/game/client/tf2/c_vehicle_mortar.cpp @@ -0,0 +1,869 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_basefourwheelvehicle.h" +#include "tf_movedata.h" +#include "ObjectControlPanel.h" +#include <vgui_controls/Label.h> +#include <vgui_controls/Button.h> +#include "vehicle_mortar_shared.h" +#include "vgui_rotation_slider.h" +#include <vgui/ISurface.h> +#include "vgui_basepanel.h" +#include "ground_line.h" +#include "hud_minimap.h" +#include "vgui_bitmapimage.h" +#include "iusesmortarpanel.h" + +// How long it waits after you've changed the mortar's yaw to draw using the server's value. +#define CLIENT_MORTAR_YAW_COUNTDOWN 0.5 + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_VehicleMortar : public C_BaseTFFourWheelVehicle, public IUsesMortarPanel +{ + DECLARE_CLASS( C_VehicleMortar, C_BaseTFFourWheelVehicle ); +public: + DECLARE_CLIENTCLASS(); + + C_VehicleMortar(); + + virtual void ReceiveMessage( int classID, bf_read &msg ); + + // Fire off a mortar. + void FireMortar(); + + virtual void ClientThink(); + +// C_BaseEntity overrides. +public: + virtual void GetBoneControllers(float controllers[MAXSTUDIOBONECTRLS]); + +// IUsesMortarPanel +public: + // Get the data from this mortar needed by the panel + virtual void GetMortarData( float *flClientMortarYaw, bool *bAllowedToFire, float *flPower, float *flFiringPower, float *flFiringAccuracy, int *iFiringState ); + virtual void SendYawCommand( void ); + virtual void ForceClientYawCountdown( float flTime ); + virtual void ClickFire( void ); + +public: + // Mortar firing info. + int m_iFiringState; // One of the MORTAR_ defines. + bool m_bMortarReloading; + float m_flPower; + bool m_bAllowedToFire; + + // Parameters for the next shot. + float m_flFiringPower; + float m_flFiringAccuracy; + + float m_flMortarYaw; // What direction the mortar is aimed in. + float m_flMortarPitch; + + // This is what is used on the client to draw the ground line and orient the mortar. + // It is usually copied right over from m_flClientMortarYaw (which comes from the server), + // but this is also used when rotating the mortar so you can see the line move smoothly. + float m_flClientMortarYaw; + + // This is set to about 1/4 seconds when you rotate the mortar line so you use the client's + // (smooth, non-lagged) yaw changes instead of the server's. + float m_flForceClientYawCountdown; + +private: + C_VehicleMortar( const C_VehicleMortar & ); // not defined, not accessible + +}; + + +IMPLEMENT_CLIENTCLASS_DT(C_VehicleMortar, DT_VehicleMortar, CVehicleMortar) + RecvPropFloat( RECVINFO( m_flMortarYaw ) ), + RecvPropFloat( RECVINFO( m_flMortarPitch ) ), + RecvPropBool( RECVINFO( m_bAllowedToFire ) ) +END_RECV_TABLE() + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +C_VehicleMortar::C_VehicleMortar() +{ + m_iFiringState = MORTAR_IDLE; + m_bMortarReloading = false; + m_flPower = 0; + + m_flMortarYaw = 0; + m_flClientMortarYaw = 0; + m_flMortarPitch = 0; + m_flForceClientYawCountdown = 0; + m_bAllowedToFire = true; + + SetNextClientThink( CLIENT_THINK_ALWAYS ); +} + + +void C_VehicleMortar::ReceiveMessage( int classID, bf_read &msg ) +{ + if ( classID != GetClientClass()->m_ClassID ) + { + // message is for subclass + BaseClass::ReceiveMessage( classID, msg ); + return; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_VehicleMortar::ClickFire() +{ + switch( m_iFiringState ) + { + case MORTAR_IDLE: + m_iFiringState = MORTAR_CHARGING_POWER; + break; + + case MORTAR_CHARGING_POWER: + m_flFiringPower = m_flPower; + m_iFiringState = MORTAR_CHARGING_ACCURACY; + break; + + case MORTAR_CHARGING_ACCURACY: + m_flFiringAccuracy = m_flPower; + m_iFiringState = MORTAR_IDLE; + + FireMortar(); + break; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_VehicleMortar::FireMortar() +{ + char cmd[512]; + Q_snprintf( cmd, sizeof( cmd ), "FireMortar %.2f %.2f", m_flFiringPower, m_flFiringAccuracy ); + SendClientCommand( cmd ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_VehicleMortar::SendYawCommand( void ) +{ + char szbuf[48]; + Q_snprintf( szbuf, sizeof( szbuf ), "MortarYaw %0.2f\n", m_flClientMortarYaw ); + SendClientCommand( szbuf ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_VehicleMortar::ForceClientYawCountdown( float flTime ) +{ + m_flForceClientYawCountdown = flTime; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_VehicleMortar::GetMortarData( float *flClientMortarYaw, bool *bAllowedToFire, float *flPower, float *flFiringPower, float *flFiringAccuracy, int *iFiringState ) +{ + *flClientMortarYaw = m_flClientMortarYaw; + *bAllowedToFire = m_bAllowedToFire; + *flPower = m_flPower; + *flFiringPower = m_flFiringPower; + *flFiringAccuracy = m_flFiringAccuracy; + *iFiringState = m_iFiringState; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_VehicleMortar::ClientThink() +{ + m_flForceClientYawCountdown -= gpGlobals->frametime; + if ( m_flForceClientYawCountdown <= 0 ) + { + m_flClientMortarYaw = m_flMortarYaw; + } +} + + +void C_VehicleMortar::GetBoneControllers( float controllers[MAXSTUDIOBONECTRLS]) +{ + BaseClass::GetBoneControllers( controllers); + + controllers[0] = anglemod( m_flClientMortarYaw ) / 360.0; + controllers[1] = anglemod( m_flMortarPitch ) / 360.0; +} + + +//----------------------------------------------------------------------------- +// CMortarMinimapPanel +//----------------------------------------------------------------------------- +CMortarMinimapPanel::CMortarMinimapPanel( vgui::Panel *pParent, const char *pElementName ) + : CMinimapPanel( pElementName ) +{ + SetParent( pParent ); + + m_bMouseDown = false; + m_bFireButtonDown = false; + m_LastX = m_LastY = -1; + + m_nTextureId = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_nTextureId, "hud/minimap/mortar_slider", true, false ); + + m_nTextureId_CantFire = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_nTextureId_CantFire, "hud/minimap/mortar_slider_cantfire", true, false ); +} + + +CMortarMinimapPanel::~CMortarMinimapPanel() +{ +} + +void CMortarMinimapPanel::InitMortarMinimap( C_BaseEntity *pMortar ) +{ + BaseClass::Init( NULL ); + + m_hMortar = pMortar; + + m_MortarButtonUp.Init( GetVPanel(), "hud/minimap/icon_mortarbutton_up" ); + m_MortarButtonDown.Init( GetVPanel(), "hud/minimap/icon_mortarbutton_dn" ); + m_MortarButtonCantFire.Init( GetVPanel(), "hud/minimap/icon_mortarbutton_cantfire" ); + + m_MortarDirectionImage.Init( GetVPanel(), "hud/minimap/icon_player_arrow" ); + m_MortarDirectionImage.SetColor( Color( 0, 255, 0, 255 ) ); +} + + +C_BaseEntity *CMortarMinimapPanel::GetMortar() const +{ + return (C_BaseEntity*)m_hMortar; +} + + +void CMortarMinimapPanel::Paint() +{ + BaseClass::Paint(); + + C_BaseEntity *pMortar = GetMortar(); + IUsesMortarPanel *pMortarInterface = dynamic_cast< IUsesMortarPanel* >( pMortar ); + if ( pMortar && pMortarInterface ) + { + float flClientMortarYaw, flPower, flFiringPower, flFiringAccuracy; + int iFiringState; + bool bAllowedToFire; + pMortarInterface->GetMortarData( &flClientMortarYaw, &bAllowedToFire, &flPower, &flFiringPower, &flFiringAccuracy, &iFiringState ); + + float yaw = flClientMortarYaw + 90; + + float x, y; + if ( WorldToMinimap( MINIMAP_CLAMP, pMortar->GetAbsOrigin(), x, y ) ) + { + int size = 20; + + BitmapImage *pImage = &m_MortarButtonCantFire; + if ( bAllowedToFire ) + { + if ( m_bFireButtonDown ) + pImage = &m_MortarButtonDown; + else + pImage = &m_MortarButtonUp; + } + + pImage->DoPaint( x-size/2, y-size/2, size, size, yaw ); + + size = 40; + m_MortarDirectionImage.DoPaint( x-size/2, y-size/2, size, size, pMortar->GetAbsAngles()[YAW] + 90 ); + + + // Draw the power bar. + float flAngle = pMortar->GetAbsAngles()[YAW] + flClientMortarYaw; + Vector vForward( -sin( DEG2RAD( flAngle ) ), cos( DEG2RAD( flAngle ) ), 0 ); + Vector vRight( vForward.y, -vForward.x, 0 ); + + Vector vStartPoint = pMortar->GetAbsOrigin(); + Vector vEndPoint = vStartPoint + vForward * MORTAR_RANGE_MAX_INITIAL; + Vector vInaccuracy = vEndPoint + vRight * (MORTAR_RANGE_MAX_INITIAL * MORTAR_INACCURACY_MAX_INITIAL); + + Vector2D vStart2D, vEnd2D, vInaccuracy2D; + WorldToMinimap( MINIMAP_ALWAYS_ACCEPT, vStartPoint, vStart2D.x, vStart2D.y ); + WorldToMinimap( MINIMAP_ALWAYS_ACCEPT, vEndPoint, vEnd2D.x, vEnd2D.y ); + WorldToMinimap( MINIMAP_ALWAYS_ACCEPT, vInaccuracy, vInaccuracy2D.x, vInaccuracy2D.y ); + + Vector2D vDir = vEnd2D - vStart2D; + Vector2DNormalize( vDir ); + + + // These variables control the look. + float flLength = (vEnd2D - vStart2D).Length(); + float flZeroT = 1.0f / 5; + float flZero = flLength * flZeroT; + + float flFirePower = MAX( flPower, flFiringPower ); + + float flStartFatness = 2; + float flEndFatness = flStartFatness; + + float flScalePower = flFiringAccuracy; + if ( iFiringState != MORTAR_IDLE ) + flScalePower = flPower; + + Vector2D vInaccuracyDir = vInaccuracy2D - vEnd2D; + flEndFatness *= vInaccuracyDir.Length() * flScalePower * 0.4; + flEndFatness = MAX( fabs( flEndFatness ), flStartFatness ); + + Vector2D vPerp( vDir.y, -vDir.x ); + Vector2DNormalize( vPerp ); + + Vector2D vStartPerp = vPerp * flStartFatness; + Vector2D vEndPerp = vPerp * flEndFatness; + + + // Draw the red-black power bars. + vgui::ISurface *pSurface = vgui::surface(); + if ( bAllowedToFire ) + pSurface->DrawSetTexture( m_nTextureId ); + else + pSurface->DrawSetTexture( m_nTextureId_CantFire ); + + Vector2D vZeroPerp; + Vector2DLerp( vStartPerp, vEndPerp, flZero / flLength, vZeroPerp ); + + // Draw a black->red bar from zero to our current power. + float flFirePowerDistance = RemapVal( flFirePower, 0, 1, flZero, flLength ); + Vector2D vPowerPerp; + Vector2DLerp( vStartPerp, vEndPerp, RemapVal( flFirePowerDistance, flZero, flLength, flZeroT, 1 ), vPowerPerp ); + + vgui::Vertex_t verts[4]; + verts[0].Init( vStart2D + vDir * flZero - vZeroPerp ); + verts[1].Init( verts[0].m_Position + vZeroPerp * 2 ); + + verts[2].Init( vStart2D + vDir * flFirePowerDistance + vPowerPerp, Vector2D( flFirePower, 0 ) ); + verts[3] = verts[2]; + verts[3].m_Position -= vPowerPerp * 2; + + pSurface->DrawSetColor( 255, 255, 255, 255 ); + pSurface->DrawTexturedPolygon( 4, verts ); + + + // Draw the power slider. + pSurface->DrawSetTexture( -1 ); + + + vgui::Vertex_t line[2]; + line[0].Init( vStart2D + vDir * flFirePowerDistance - vPowerPerp ); + line[1].Init( line[0].m_Position + vPowerPerp * 2 ); + pSurface->DrawTexturedLine( line[0], line[1] ); + + + + // Draw a white outline. + pSurface->DrawSetColor( 255, 255, 255, 255 ); + vgui::Vertex_t pts[4] = + { + vgui::Vertex_t( vStart2D - vStartPerp ), + vgui::Vertex_t( vStart2D + vStartPerp ), + vgui::Vertex_t( vEnd2D + vEndPerp ), + vgui::Vertex_t( vEnd2D - vEndPerp ) + }; + pSurface->DrawTexturedPolyLine( pts, 4 ); + + + // Draw the zero line. + line[0].Init( vStart2D + vDir * flZero - vZeroPerp ); + line[1].Init( line[0].m_Position + vZeroPerp * 2 ); + pSurface->DrawTexturedLine( line[0], line[1] ); + } + } +} + + +void CMortarMinimapPanel::OnMousePressed( vgui::MouseCode code ) +{ + BaseClass::OnMousePressed( code ); + + if (code != vgui::MOUSE_LEFT) + return; + + C_BaseEntity *pMortar = GetMortar(); + IUsesMortarPanel *pMortarInterface = dynamic_cast< IUsesMortarPanel* >( pMortar ); + if ( !pMortar || !pMortarInterface ) + return; + + float flClientMortarYaw, flPower, flFiringPower, flFiringAccuracy; + int iFiringState; + bool bAllowedToFire; + pMortarInterface->GetMortarData( &flClientMortarYaw, &bAllowedToFire, &flPower, &flFiringPower, &flFiringAccuracy, &iFiringState ); + + // See if they clicked the "fire" button. + float x, y; + if ( WorldToMinimap( MINIMAP_ALWAYS_ACCEPT, pMortar->GetAbsOrigin(), x, y ) && + (Vector2D( x, y ) - Vector2D( m_LastX, m_LastY )).Length() <= 8 ) + { + if ( bAllowedToFire ) + { + // Treat it like they clicked the fire button. + m_bFireButtonDown = true; + pMortarInterface->ClickFire(); + } + } + else + { + pMortarInterface->ForceClientYawCountdown( 5000000 ); + } + + m_bMouseDown = true; +} + + +void CMortarMinimapPanel::OnCursorMoved( int x, int y ) +{ + m_LastX = x; + m_LastY = y; + + if ( !m_bMouseDown || m_bFireButtonDown ) + return; + + C_BaseEntity *pMortar = GetMortar(); + IUsesMortarPanel *pMortarInterface = dynamic_cast< IUsesMortarPanel* >( pMortar ); + if ( !pMortar || !pMortarInterface ) + return; + + float flClientMortarYaw, flPower, flFiringPower, flFiringAccuracy; + int iFiringState; + bool bAllowedToFire; + pMortarInterface->GetMortarData( &flClientMortarYaw, &bAllowedToFire, &flPower, &flFiringPower, &flFiringAccuracy, &iFiringState ); + + float mortarX, mortarY; + if ( WorldToMinimap( MINIMAP_ALWAYS_ACCEPT, pMortar->GetAbsOrigin(), mortarX, mortarY ) ) + { + float flAngle = atan2( x - mortarX, mortarY - y ); + flClientMortarYaw = -anglemod( flAngle * 180.0f / M_PI + pMortar->GetAbsAngles()[YAW] ); + } +} + + +void CMortarMinimapPanel::OnMouseReleased( vgui::MouseCode code ) +{ + BaseClass::OnMouseReleased( code ); + + if ( code != vgui::MOUSE_LEFT ) + return; + + m_bMouseDown = false; + + if ( m_bFireButtonDown ) + { + m_bFireButtonDown = false; + } + else + { + C_BaseEntity *pMortar = GetMortar(); + IUsesMortarPanel *pMortarInterface = dynamic_cast< IUsesMortarPanel* >( pMortar ); + if ( pMortar && pMortarInterface ) + { + pMortarInterface->SendYawCommand(); + pMortarInterface->ForceClientYawCountdown( CLIENT_MORTAR_YAW_COUNTDOWN ); + } + } +} + + +//----------------------------------------------------------------------------- +// Control screen +//----------------------------------------------------------------------------- +class CVehicleMortarControlPanel : public CObjectControlPanel +{ + DECLARE_CLASS( CVehicleMortarControlPanel, CObjectControlPanel ); + +public: + + CVehicleMortarControlPanel( vgui::Panel *parent, const char *panelName ); + virtual ~CVehicleMortarControlPanel(); + + virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); + virtual void OnCommand( const char *command ); + C_VehicleMortar* GetMortar() const; + + +protected: + + virtual vgui::Panel* TickCurrentPanel(); + + +private: + + void OnTickMainPanel(); + void OnTickDeployPanel( float flDeployTime ); + void OnTickGunnerPanel(); + + void GetInRam( void ); + + void StartDeploying(); + void StopDismantling(); + bool IsDeploying() const; + bool IsUndeploying() const; + bool IsDeployed() const; + +private: + vgui::Label *m_pDriverLabel; + vgui::Label *m_pPassengerLabel; + vgui::Button *m_pOccupyButton; + vgui::Button *m_pCancelDeployButton; + + vgui::Label *m_pDeployMessageLabel; // says "Deployed in" or "Undeployed in" + vgui::Label *m_pDeployTimeLabel; // says "N seconds" + + vgui::EditablePanel *m_pDeployPanel; + vgui::EditablePanel *m_pGunnerPanel; + + CMortarMinimapPanel *m_pMinimapPanel; + + vgui::Label *m_pReloadingLabel; +}; + + +DECLARE_VGUI_SCREEN_FACTORY( CVehicleMortarControlPanel, "vehicle_mortar_control_panel" ); + + +//----------------------------------------------------------------------------- +// Constructor: +//----------------------------------------------------------------------------- +CVehicleMortarControlPanel::CVehicleMortarControlPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, "CVehicleMortarControlPanel" ) +{ + m_pDeployPanel = new CCommandChainingPanel( this, "DeployPanel" ); + m_pDeployPanel->SetZPos( -1 ); + + m_pGunnerPanel = new CCommandChainingPanel( this, "GunnerPanel" ); + m_pGunnerPanel->SetZPos( -1 ); + + m_pMinimapPanel = new CMortarMinimapPanel( m_pGunnerPanel, "MinimapPanel" ); + m_pMinimapPanel->SetZPos( 10 ); + m_pMinimapPanel->Init( NULL ); +} + + +CVehicleMortarControlPanel::~CVehicleMortarControlPanel() +{ + delete m_pMinimapPanel; +} + + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- +bool CVehicleMortarControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ) +{ + m_pDriverLabel = new vgui::Label( this, "DriverReadout", "" ); + m_pPassengerLabel = new vgui::Label( this, "PassengerReadout", "" ); + m_pOccupyButton = new vgui::Button( this, "OccupyButton", "Occupy" ); + + m_pDeployMessageLabel = new vgui::Label( m_pDeployPanel, "DeployMessage", "" ); + m_pDeployTimeLabel = new vgui::Label( m_pDeployPanel, "DeployTime", "" ); + m_pCancelDeployButton = new vgui::Button( m_pDeployPanel, "CancelDeployButton", "" ); + + m_pReloadingLabel = new vgui::Label( m_pGunnerPanel, "ReloadingLabel", "" ); + + // Make sure all named panels are created up above because BaseClass::Init initializes them + // all from their keyvalues. + if ( !BaseClass::Init( pKeyValues, pInitData ) ) + return false; + + // Init subpanels. + int x, y, w, h; + GetBounds( x, y, w, h ); + + m_pMinimapPanel->LevelInit( engine->GetLevelName() ); + m_pMinimapPanel->SetVisible( true ); + m_pMinimapPanel->InitMortarMinimap( GetMortar() ); + + m_pDeployPanel->SetBounds( x, y, w, h ); + m_pDeployPanel->SetVisible( false ); + + m_pGunnerPanel->SetBounds( x, y, w, h ); + m_pGunnerPanel->SetVisible( false ); + + m_pReloadingLabel->SetVisible( false ); + return true; +} + + +//----------------------------------------------------------------------------- +// Frame-based update +//----------------------------------------------------------------------------- + +vgui::Panel* CVehicleMortarControlPanel::TickCurrentPanel() +{ + C_VehicleMortar *pMortar = GetMortar(); + if ( !pMortar ) + return BaseClass::TickCurrentPanel(); + + if ( IsUndeploying() ) + { + OnTickDeployPanel( pMortar->GetDeployFinishTime() ); + return m_pDeployPanel; + } + else if ( IsDeploying() ) + { + OnTickDeployPanel( pMortar->GetDeployFinishTime() ); + return m_pDeployPanel; + } + else if ( IsDeployed() ) + { + OnTickGunnerPanel(); + return m_pGunnerPanel; + } + else + { + OnTickMainPanel(); + return BaseClass::TickCurrentPanel(); + } +} + + +C_VehicleMortar* CVehicleMortarControlPanel::GetMortar() const +{ + return dynamic_cast< C_VehicleMortar* >( GetOwningObject() ); +} + + +void CVehicleMortarControlPanel::OnTickMainPanel() +{ + C_BaseObject *pObj = GetOwningObject(); + if (!pObj) + return; + + ShowOwnerLabel( true ); + ShowHealthLabel( true ); + + Assert( dynamic_cast<C_VehicleMortar*>(pObj) ); + C_VehicleMortar *pRam = static_cast<C_VehicleMortar*>(pObj); + + char buf[256]; + // Update the currently manned player label + if ( pRam->GetDriverPlayer() ) + { + Q_snprintf( buf, sizeof( buf ), "Driven by %s", pRam->GetDriverPlayer()->GetPlayerName() ); + m_pDriverLabel->SetText( buf ); + m_pDriverLabel->SetVisible( true ); + } + else + { + m_pDriverLabel->SetVisible( false ); + } + + int nPassengerCount = pRam->GetPassengerCount(); + int nMaxPassengerCount = pRam->GetMaxPassengerCount(); + + Q_snprintf( buf, sizeof( buf ), "Passengers %d/%d", nPassengerCount >= 1 ? nPassengerCount - 1 : 0, nMaxPassengerCount - 1 ); + m_pPassengerLabel->SetText( buf ); + + // Update the get in button + if ( pRam->IsPlayerInVehicle( C_BaseTFPlayer::GetLocalPlayer() ) ) + { + m_pOccupyButton->SetEnabled( false ); + return; + } + + if ( pRam->GetOwner() == C_BaseTFPlayer::GetLocalPlayer() ) + { + if (nPassengerCount == nMaxPassengerCount) + { + // Owners can boot other players to get in + C_BaseTFPlayer *pPlayer = static_cast<C_BaseTFPlayer*>(pRam->GetPassenger( VEHICLE_ROLE_DRIVER )); + Q_snprintf( buf, sizeof( buf ), "Get In (Ejecting %s)", pPlayer->GetPlayerName() ); + m_pDriverLabel->SetText( buf ); + m_pOccupyButton->SetEnabled( true ); + } + else + { + m_pOccupyButton->SetText( "Get In" ); + m_pOccupyButton->SetEnabled( true ); + } + } + else + { + m_pOccupyButton->SetText( "Get In" ); + m_pOccupyButton->SetEnabled( pRam->GetPassengerCount() < pRam->GetMaxPassengerCount() ); + } +} + + +void CVehicleMortarControlPanel::OnTickDeployPanel( float flDeployTime ) +{ + ShowDismantleButton( false ); + + // Update the countdown. + int nSec = (int)(flDeployTime - gpGlobals->curtime + 0.5f); + if (nSec < 0) + nSec = 0; + + char buf[256]; + int nLen = Q_snprintf( buf, sizeof( buf ), "%d second", nSec ); + if (nSec != 1) + { + buf[nLen] = 's'; + ++nLen; + buf[nLen] = 0; + } + + m_pDeployTimeLabel->SetText( buf ); +} + + +void CVehicleMortarControlPanel::OnTickGunnerPanel() +{ + C_VehicleMortar *pMortar = GetMortar(); + if ( !pMortar ) + return; + + ShowOwnerLabel( false ); + ShowHealthLabel( false ); + + m_pMinimapPanel->Repaint(); + + // If it's reloading, tell the player + m_pReloadingLabel->SetVisible( pMortar->m_bMortarReloading ); + if ( pMortar->m_bMortarReloading ) + { + return; + } + + float flAccuracySpeed = (1.0 / MORTAR_CHARGE_ACCURACY_RATE); + + // Handle power charging + switch( pMortar->m_iFiringState ) + { + case MORTAR_IDLE: + pMortar->m_flPower = 0; + break; + + case MORTAR_CHARGING_POWER: + pMortar->m_flPower = MIN( pMortar->m_flPower + ( (1.0 / MORTAR_CHARGE_POWER_RATE) * gpGlobals->frametime), 1 ); + pMortar->m_flFiringPower = 0; + pMortar->m_flFiringAccuracy = 0; + if ( pMortar->m_flPower >= 1.0 ) + { + // Hit Max, start going down + pMortar->m_flFiringPower = pMortar->m_flPower; + pMortar->m_iFiringState = MORTAR_CHARGING_ACCURACY; + } + break; + + case MORTAR_CHARGING_ACCURACY: + // Calculate accuracy speed + if ( pMortar->m_flFiringPower > 0.5 ) + { + // Shots over halfway suffer an increased speed to the accuracy power, making accurate shots harder + float flAdjustedPower = (pMortar->m_flFiringPower - 0.5) * 3.0; + flAccuracySpeed += (pMortar->m_flFiringPower * flAdjustedPower); + } + + pMortar->m_flPower = MAX( pMortar->m_flPower - ( flAccuracySpeed * gpGlobals->frametime), -0.25f); + if ( pMortar->m_flPower <= -0.25 ) + { + // Hit Min, fire mortar + pMortar->m_flFiringAccuracy = pMortar->m_flPower; + pMortar->m_iFiringState = MORTAR_IDLE; + + pMortar->FireMortar(); + } + break; + + default: + break; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Handle clicking on the Occupy button +//----------------------------------------------------------------------------- +void CVehicleMortarControlPanel::GetInRam( void ) +{ + SendToServerObject( "toggle_use" ); +} + +//----------------------------------------------------------------------------- +// Starts/stops deploying +//----------------------------------------------------------------------------- + +bool CVehicleMortarControlPanel::IsDeploying() const +{ + C_VehicleMortar *pMortar = GetMortar(); + if ( !pMortar ) + return false; + + return !IsDeployed() && pMortar->GetDeployFinishTime() > 0.0f; +} + +bool CVehicleMortarControlPanel::IsUndeploying() const +{ + C_VehicleMortar *pMortar = GetMortar(); + if ( !pMortar ) + return false; + + return IsDeployed() && pMortar->GetDeployFinishTime() > 0.0f; +} + +bool CVehicleMortarControlPanel::IsDeployed() const +{ + C_VehicleMortar *pMortar = GetMortar(); + if ( pMortar ) + return pMortar->GetVehicleModeDeploy() == VEHICLE_MODE_DEPLOYED; + else + return false; +} + +//----------------------------------------------------------------------------- +// Button click handlers +//----------------------------------------------------------------------------- +void CVehicleMortarControlPanel::OnCommand( const char *command ) +{ + C_VehicleMortar *pMortar = GetMortar(); + if ( !pMortar ) + return; + + if (!Q_strnicmp(command, "Occupy", 7)) + { + GetInRam(); + return; + } + else if ( !Q_stricmp( command, "Deploy" ) ) + { + m_pDeployMessageLabel->SetText( "Deployed in" ); + m_pCancelDeployButton->SetVisible( true ); + + SendToServerObject( "Deploy" ); // Tell the server. + } + else if ( !Q_stricmp( command, "CancelDeploy" ) ) + { + SendToServerObject( command ); + } + else if ( !Q_stricmp( command, "Undeploy" ) ) + { + m_pDeployMessageLabel->SetText( "Undeployed in" ); + m_pCancelDeployButton->SetVisible( false ); + + SendToServerObject( "Undeploy" ); // Tell the server. + } + else if ( !Q_stricmp( command, "FireMortar" ) ) + { + pMortar->ClickFire(); + } + + BaseClass::OnCommand(command); +} + diff --git a/game/client/tf2/c_vehicle_motorcycle.cpp b/game/client/tf2/c_vehicle_motorcycle.cpp new file mode 100644 index 0000000..441e74d --- /dev/null +++ b/game/client/tf2/c_vehicle_motorcycle.cpp @@ -0,0 +1,184 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_basefourwheelvehicle.h" +#include "tf_movedata.h" +#include "ObjectControlPanel.h" +#include <vgui_controls/Label.h> +#include <vgui_controls/Button.h> + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_VehicleMotorcycle : public C_BaseTFFourWheelVehicle +{ + DECLARE_CLASS( C_VehicleMotorcycle, C_BaseTFFourWheelVehicle ); +public: + DECLARE_CLIENTCLASS(); + + C_VehicleMotorcycle(); + +private: + C_VehicleMotorcycle( const C_VehicleMotorcycle & ); // not defined, not accessible + +}; + + +IMPLEMENT_CLIENTCLASS_DT(C_VehicleMotorcycle, DT_VehicleMotorcycle, CVehicleMotorcycle) +END_RECV_TABLE() + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_VehicleMotorcycle::C_VehicleMotorcycle() +{ +} + + + +//----------------------------------------------------------------------------- +// Control screen +//----------------------------------------------------------------------------- +class CVehicleMotorcycleControlPanel : public CObjectControlPanel +{ + DECLARE_CLASS( CVehicleMotorcycleControlPanel, CObjectControlPanel ); + +public: + CVehicleMotorcycleControlPanel( vgui::Panel *parent, const char *panelName ); + virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); + virtual void OnTick(); + virtual void OnCommand( const char *command ); + +private: + void GetInCycle( void ); + +private: + vgui::Label *m_pDriverLabel; + vgui::Label *m_pPassengerLabel; + vgui::Button *m_pOccupyButton; +}; + + +DECLARE_VGUI_SCREEN_FACTORY( CVehicleMotorcycleControlPanel, "vehicle_wagon_control_panel" ); + + +//----------------------------------------------------------------------------- +// Constructor: +//----------------------------------------------------------------------------- +CVehicleMotorcycleControlPanel::CVehicleMotorcycleControlPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, "CVehicleMotorcycleControlPanel" ) +{ +} + + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- +bool CVehicleMotorcycleControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ) +{ + m_pDriverLabel = new vgui::Label( this, "DriverReadout", "" ); + m_pPassengerLabel = new vgui::Label( this, "PassengerReadout", "" ); + m_pOccupyButton = new vgui::Button( this, "OccupyButton", "Occupy" ); + + if (!BaseClass::Init(pKeyValues, pInitData)) + return false; + + return true; +} + + +//----------------------------------------------------------------------------- +// Frame-based update +//----------------------------------------------------------------------------- +void CVehicleMotorcycleControlPanel::OnTick() +{ + BaseClass::OnTick(); + + C_BaseObject *pObj = GetOwningObject(); + if (!pObj) + return; + + Assert( dynamic_cast<C_VehicleMotorcycle*>(pObj) ); + C_VehicleMotorcycle *pCycle = static_cast<C_VehicleMotorcycle*>(pObj); + + char buf[256]; + // Update the currently manned player label + if ( pCycle->GetDriverPlayer() ) + { + Q_snprintf( buf, sizeof( buf ), "Driven by %s", pCycle->GetDriverPlayer()->GetPlayerName() ); + m_pDriverLabel->SetText( buf ); + m_pDriverLabel->SetVisible( true ); + } + else + { + m_pDriverLabel->SetVisible( false ); + } + + int nPassengerCount = pCycle->GetPassengerCount(); + int nMaxPassengerCount = pCycle->GetMaxPassengerCount(); + + Q_snprintf( buf, sizeof( buf ), "Passengers %d/%d", nPassengerCount >= 1 ? nPassengerCount - 1 : 0, nMaxPassengerCount - 1 ); + m_pPassengerLabel->SetText( buf ); + + // Update the get in button + if ( pCycle->IsPlayerInVehicle( C_BaseTFPlayer::GetLocalPlayer() ) ) + { + m_pOccupyButton->SetEnabled( false ); + return; + } + + if ( pCycle->GetOwner() == C_BaseTFPlayer::GetLocalPlayer() ) + { + if (nPassengerCount == nMaxPassengerCount) + { + // Owners can boot other players to get in + C_BaseTFPlayer *pPlayer = static_cast<C_BaseTFPlayer*>(pCycle->GetPassenger( VEHICLE_ROLE_DRIVER )); + Q_snprintf( buf, sizeof( buf ), "Get In (Ejecting %s)", pPlayer->GetPlayerName() ); + m_pDriverLabel->SetText( buf ); + m_pOccupyButton->SetEnabled( true ); + } + else + { + m_pOccupyButton->SetText( "Get In" ); + m_pOccupyButton->SetEnabled( true ); + } + } + else + { + m_pOccupyButton->SetText( "Get In" ); + m_pOccupyButton->SetEnabled( pCycle->GetPassengerCount() < pCycle->GetMaxPassengerCount() ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Handle clicking on the Occupy button +//----------------------------------------------------------------------------- +void CVehicleMotorcycleControlPanel::GetInCycle( void ) +{ + C_BaseObject *pObj = GetOwningObject(); + if (pObj) + { + pObj->SendClientCommand( "toggle_use" ); + } +} + +//----------------------------------------------------------------------------- +// Button click handlers +//----------------------------------------------------------------------------- +void CVehicleMotorcycleControlPanel::OnCommand( const char *command ) +{ + if (!Q_strnicmp(command, "Occupy", 7)) + { + GetInCycle(); + return; + } + + BaseClass::OnCommand(command); +} + diff --git a/game/client/tf2/c_vehicle_siege_tower.cpp b/game/client/tf2/c_vehicle_siege_tower.cpp new file mode 100644 index 0000000..d82c28a --- /dev/null +++ b/game/client/tf2/c_vehicle_siege_tower.cpp @@ -0,0 +1,261 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Siege Tower Vechicle +// +//=============================================================================// + +#include "cbase.h" +#include "c_basefourwheelvehicle.h" +#include "tf_movedata.h" +#include "ObjectControlPanel.h" +#include <vgui_controls/Label.h> +#include "vgui_bitmapbutton.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_VehicleSiegeTower : public C_BaseTFFourWheelVehicle +{ + DECLARE_CLASS( C_VehicleSiegeTower, C_BaseTFFourWheelVehicle ); + +public: + + DECLARE_CLIENTCLASS(); + + C_VehicleSiegeTower(); + +// C_BaseEntity overrides. +public: + +// virtual void DebugMessages( void ); + +private: + + C_VehicleSiegeTower( const C_VehicleSiegeTower & ); // not defined, not accessible +}; + +IMPLEMENT_CLIENTCLASS_DT( C_VehicleSiegeTower, DT_VehicleSiegeTower, CVehicleSiegeTower ) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_VehicleSiegeTower::C_VehicleSiegeTower() +{ +} + +#if 0 +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_VehicleSiegeTower::DebugMessages( void ) +{ + Msg( "Seq: %d, Play: %f, Cycle: %f, Anim %f, Done: %d\n", GetSequence(), m_flPlaybackRate, GetCycle(), m_flAnimTime, + ( int )m_fSequenceFinished ); +} +#endif + +//----------------------------------------------------------------------------- +// Control screen +//----------------------------------------------------------------------------- +class CVehicleSiegeTowerControlPanel : public CObjectControlPanel +{ + DECLARE_CLASS( CVehicleSiegeTowerControlPanel, CObjectControlPanel ); + +public: + + CVehicleSiegeTowerControlPanel( vgui::Panel *parent, const char *panelName ); + virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); + virtual void OnTick(); + virtual void OnCommand( const char *command ); + +private: + + void GetInTower( void ); + +private: + + vgui::Label *m_pDriverLabel; + vgui::Label *m_pPassengerLabel; + vgui::Button *m_pOccupyButton; +}; + +DECLARE_VGUI_SCREEN_FACTORY( CVehicleSiegeTowerControlPanel, "vehicle_siege_tower_control_panel" ); + +//----------------------------------------------------------------------------- +// Constructor: +//----------------------------------------------------------------------------- +CVehicleSiegeTowerControlPanel::CVehicleSiegeTowerControlPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, "CVehicleSiegeTowerControlPanel" ) +{ +} + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- +bool CVehicleSiegeTowerControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ) +{ + m_pDriverLabel = new vgui::Label( this, "DriverReadout", "" ); + m_pPassengerLabel = new vgui::Label( this, "PassengerReadout", "" ); + m_pOccupyButton = new CBitmapButton( this, "OccupyButton", "Occupy" ); + + if ( !BaseClass::Init( pKeyValues, pInitData ) ) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// Frame-based update +//----------------------------------------------------------------------------- +void CVehicleSiegeTowerControlPanel::OnTick() +{ + BaseClass::OnTick(); + + C_BaseObject *pObj = GetOwningObject(); + if ( !pObj ) + return; + + Assert( dynamic_cast<C_VehicleSiegeTower*>( pObj ) ); + C_VehicleSiegeTower *pTower = static_cast<C_VehicleSiegeTower*>( pObj ); + + char buf[256]; + // Update the currently manned player label + if ( pTower->GetDriverPlayer() ) + { + Q_snprintf( buf, sizeof( buf ), "Driven by %s", pTower->GetDriverPlayer()->GetPlayerName() ); + m_pDriverLabel->SetText( buf ); + m_pDriverLabel->SetVisible( true ); + } + else + { + m_pDriverLabel->SetVisible( false ); + } + + int nPassengerCount = pTower->GetPassengerCount(); + int nMaxPassengerCount = pTower->GetMaxPassengerCount(); + + Q_snprintf( buf, sizeof( buf ), "Passengers %d/%d", nPassengerCount >= 1 ? nPassengerCount - 1 : 0, nMaxPassengerCount - 1 ); + m_pPassengerLabel->SetText( buf ); + + // Update the get in button + if ( pTower->IsPlayerInVehicle( C_BaseTFPlayer::GetLocalPlayer() ) ) + { + m_pOccupyButton->SetEnabled( false ); + return; + } + + if ( pTower->GetOwner() == C_BaseTFPlayer::GetLocalPlayer() ) + { + if ( nPassengerCount == nMaxPassengerCount ) + { + // Owners can boot other players to get in + C_BaseTFPlayer *pPlayer = static_cast<C_BaseTFPlayer*>( pTower->GetPassenger( VEHICLE_ROLE_DRIVER ) ); + Q_snprintf( buf, sizeof( buf ), "Get In (Ejecting %s)", pPlayer->GetPlayerName() ); + m_pDriverLabel->SetText( buf ); + m_pOccupyButton->SetEnabled( true ); + } + else + { + m_pOccupyButton->SetText( "Get In" ); + m_pOccupyButton->SetEnabled( true ); + } + } + else + { + m_pOccupyButton->SetText( "Get In" ); + m_pOccupyButton->SetEnabled( pTower->GetPassengerCount() < pTower->GetMaxPassengerCount() ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Handle clicking on the Occupy button +//----------------------------------------------------------------------------- +void CVehicleSiegeTowerControlPanel::GetInTower( void ) +{ + C_BaseObject *pObj = GetOwningObject(); + if ( pObj ) + { + pObj->SendClientCommand( "toggle_use" ); + } +} + +//----------------------------------------------------------------------------- +// Button click handlers +//----------------------------------------------------------------------------- +void CVehicleSiegeTowerControlPanel::OnCommand( const char *command ) +{ + if ( !Q_strnicmp( command, "Occupy", 7 ) ) + { + GetInTower(); + return; + } + + BaseClass::OnCommand( command ); +} + +//============================================================================= +// +// Siege Ladder +// + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_ObjectSiegeLadder : public C_BaseAnimating +{ + DECLARE_CLASS( C_ObjectSiegeLadder, C_BaseAnimating ); + +public: + + DECLARE_CLIENTCLASS(); + + C_ObjectSiegeLadder(); + +private: + C_ObjectSiegeLadder( const C_ObjectSiegeLadder& ); // not defined, not accessible +}; + +IMPLEMENT_CLIENTCLASS_DT( C_ObjectSiegeLadder, DT_ObjectSiegeLadder, CObjectSiegeLadder ) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ObjectSiegeLadder::C_ObjectSiegeLadder() +{ +} + + +//============================================================================= +// +// Siege Platform +// + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_ObjectSiegePlatform : public C_BaseAnimating +{ + DECLARE_CLASS( C_ObjectSiegePlatform, C_BaseAnimating ); + +public: + + DECLARE_CLIENTCLASS(); + + C_ObjectSiegePlatform(); + +private: + C_ObjectSiegePlatform( const C_ObjectSiegePlatform& ); // not defined, not accessible +}; + +IMPLEMENT_CLIENTCLASS_DT( C_ObjectSiegePlatform, DT_ObjectSiegePlatform, CObjectSiegePlatform ) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ObjectSiegePlatform::C_ObjectSiegePlatform() +{ +} + diff --git a/game/client/tf2/c_vehicle_tank.cpp b/game/client/tf2/c_vehicle_tank.cpp new file mode 100644 index 0000000..be29039 --- /dev/null +++ b/game/client/tf2/c_vehicle_tank.cpp @@ -0,0 +1,150 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "c_basefourwheelvehicle.h" +#include "tf_movedata.h" +#include "ObjectControlPanel.h" +#include <vgui_controls/Label.h> +#include <vgui_controls/Button.h> +#include "vgui_rotation_slider.h" +#include <vgui/ISurface.h> +#include "vgui_basepanel.h" +#include "ground_line.h" +#include "hud_minimap.h" +#include "vgui_bitmapimage.h" +#include "view.h" +#include "c_basetempentity.h" +#include "particles_simple.h" +#include "in_buttons.h" + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_VehicleTank : public C_BaseTFFourWheelVehicle +{ + DECLARE_CLASS( C_VehicleTank, C_BaseTFFourWheelVehicle ); +public: + DECLARE_CLIENTCLASS(); + + C_VehicleTank(); + + + virtual void ClientThink(); + + virtual void OnItemPostFrame( CBaseTFPlayer *pDriver ); + +// C_BaseEntity overrides. +public: + virtual void GetBoneControllers(float controllers[MAXSTUDIOBONECTRLS]); + +private: + C_VehicleTank( const C_VehicleTank & ); // not defined, not accessible + + float m_flClientYaw; + float m_flClientPitch; + + // Sent by the server. This is what we render with. + float m_flTurretYaw; + float m_flTurretPitch; +}; + + +IMPLEMENT_CLIENTCLASS_DT( C_VehicleTank, DT_VehicleTank, CVehicleTank ) + RecvPropFloat( RECVINFO( m_flTurretYaw ) ), + RecvPropFloat( RECVINFO( m_flTurretPitch ) ) +END_RECV_TABLE() + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +C_VehicleTank::C_VehicleTank() +{ + m_flClientYaw = 0; + m_flClientPitch = 0; + m_flTurretYaw = 0; + m_flTurretPitch = 0; +} + + +void C_VehicleTank::ClientThink() +{ + if ( GetPassenger( VEHICLE_ROLE_DRIVER ) == C_BasePlayer::GetLocalPlayer() ) + { + // Cast a ray out of the view to see where the player is looking. + trace_t trace; + UTIL_TraceLine( + MainViewOrigin(), + MainViewOrigin() + MainViewForward() * 100000, + MASK_OPAQUE, NULL, + COLLISION_GROUP_NONE, + &trace ); + + if ( trace.fraction < 1 ) + { + // Figure out what angles our turret needs to be at in order to hit the target. + + Vector vFireOrigin; + QAngle dummy; + GetAttachment( LookupAttachment( "barrel" ), vFireOrigin, dummy ); + + // Get a direction vector that points at the target. + Vector vTo = trace.endpos - vFireOrigin; + + // Transform it into the tank's local space. + matrix3x4_t tankToWorld; + AngleMatrix( GetAbsAngles(), tankToWorld ); + + Vector vLocalTo; + VectorITransform( vTo, tankToWorld, vLocalTo ); + + // Now figure out what the angles are in local space. + QAngle localAngles; + VectorAngles( vLocalTo, localAngles ); + + // Make the angles adhere to the definition in CVehicleTank's header. + m_flClientYaw = localAngles[YAW] - 90; + m_flClientPitch = anglemod( -localAngles[PITCH] ); + + + char cmd[512]; + Q_snprintf( cmd, sizeof( cmd ), "TurretAngles %.2f %.2f", m_flClientYaw, m_flClientPitch ); + SendClientCommand( cmd ); + } + } + + BaseClass::ClientThink(); +} + + +void C_VehicleTank::GetBoneControllers( float controllers[MAXSTUDIOBONECTRLS]) +{ + BaseClass::GetBoneControllers( controllers ); + + controllers[0] = anglemod( m_flTurretYaw ) / 360.0; + controllers[1] = anglemod( m_flTurretPitch ) / 360.0; +} + +//----------------------------------------------------------------------------- +// Here's where we deal with weapons +//----------------------------------------------------------------------------- +void C_VehicleTank::OnItemPostFrame( CBaseTFPlayer *pDriver ) +{ + if ( GetPassengerRole(pDriver) != VEHICLE_ROLE_DRIVER ) + return; + + if ( pDriver->m_nButtons & IN_ATTACK ) + { + } + else if ( pDriver->m_nButtons & (IN_ATTACK2 | IN_SPEED) ) + { + BaseClass::OnItemPostFrame( pDriver ); + } +} + diff --git a/game/client/tf2/c_vehicle_tank.h b/game/client/tf2/c_vehicle_tank.h new file mode 100644 index 0000000..7033962 --- /dev/null +++ b/game/client/tf2/c_vehicle_tank.h @@ -0,0 +1,14 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef C_VEHICLE_TANK_H +#define C_VEHICLE_TANK_H +#ifdef _WIN32 +#pragma once +#endif + + +#endif // C_VEHICLE_TANK_H diff --git a/game/client/tf2/c_vehicle_teleport_station.cpp b/game/client/tf2/c_vehicle_teleport_station.cpp new file mode 100644 index 0000000..c2cf88a --- /dev/null +++ b/game/client/tf2/c_vehicle_teleport_station.cpp @@ -0,0 +1,168 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_basefourwheelvehicle.h" +#include "tf_movedata.h" +#include "ObjectControlPanel.h" +#include <vgui_controls/Label.h> +#include <vgui_controls/Button.h> +#include "c_vehicle_teleport_station.h" + + + +IMPLEMENT_CLIENTCLASS_DT(C_VehicleTeleportStation, DT_VehicleTeleportStation, CVehicleTeleportStation) +END_RECV_TABLE() + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_VehicleTeleportStation::C_VehicleTeleportStation() +{ +} + + +//----------------------------------------------------------------------------- +// Control screen +//----------------------------------------------------------------------------- +class CVehicleTeleportStationControlPanel : public CObjectControlPanel +{ + DECLARE_CLASS( CVehicleTeleportStationControlPanel, CObjectControlPanel ); + +public: + CVehicleTeleportStationControlPanel( vgui::Panel *parent, const char *panelName ); + virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); + virtual void OnTick(); + virtual void OnCommand( const char *command ); + +private: + void GetInVehicle( void ); + +private: + vgui::Label *m_pDriverLabel; + vgui::Label *m_pPassengerLabel; + vgui::Button *m_pOccupyButton; +}; + + +DECLARE_VGUI_SCREEN_FACTORY( CVehicleTeleportStationControlPanel, "vehicle_teleport_station_control_panel" ); + + +//----------------------------------------------------------------------------- +// Constructor: +//----------------------------------------------------------------------------- +CVehicleTeleportStationControlPanel::CVehicleTeleportStationControlPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, "CVehicleTeleportStationControlPanel" ) +{ +} + + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- +bool CVehicleTeleportStationControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ) +{ + m_pDriverLabel = new vgui::Label( this, "DriverReadout", "" ); + m_pPassengerLabel = new vgui::Label( this, "PassengerReadout", "" ); + m_pOccupyButton = new vgui::Button( this, "OccupyButton", "Occupy" ); + + if (!BaseClass::Init(pKeyValues, pInitData)) + return false; + + return true; +} + + +//----------------------------------------------------------------------------- +// Frame-based update +//----------------------------------------------------------------------------- +void CVehicleTeleportStationControlPanel::OnTick() +{ + BaseClass::OnTick(); + + C_BaseObject *pObj = GetOwningObject(); + if (!pObj) + return; + + Assert( dynamic_cast<C_VehicleTeleportStation*>(pObj) ); + C_VehicleTeleportStation *pVehicle = static_cast<C_VehicleTeleportStation*>(pObj); + + char buf[256]; + // Update the currently manned player label + if ( pVehicle->GetDriverPlayer() ) + { + Q_snprintf( buf, sizeof( buf ), "Driven by %s", pVehicle->GetDriverPlayer()->GetPlayerName() ); + m_pDriverLabel->SetText( buf ); + m_pDriverLabel->SetVisible( true ); + } + else + { + m_pDriverLabel->SetVisible( false ); + } + + int nPassengerCount = pVehicle->GetPassengerCount(); + int nMaxPassengerCount = pVehicle->GetMaxPassengerCount(); + + Q_snprintf( buf, sizeof( buf ), "Passengers %d/%d", nPassengerCount >= 1 ? nPassengerCount - 1 : 0, nMaxPassengerCount - 1 ); + m_pPassengerLabel->SetText( buf ); + + // Update the get in button + if ( pVehicle->IsPlayerInVehicle( C_BaseTFPlayer::GetLocalPlayer() ) ) + { + m_pOccupyButton->SetEnabled( false ); + return; + } + + if ( pVehicle->GetOwner() == C_BaseTFPlayer::GetLocalPlayer() ) + { + if (nPassengerCount == nMaxPassengerCount) + { + // Owners can boot other players to get in + C_BaseTFPlayer *pPlayer = static_cast<C_BaseTFPlayer*>(pVehicle->GetPassenger( VEHICLE_ROLE_DRIVER )); + Q_snprintf( buf, sizeof( buf ), "Get In (Ejecting %s)", pPlayer->GetPlayerName() ); + m_pDriverLabel->SetText( buf ); + m_pOccupyButton->SetEnabled( true ); + } + else + { + m_pOccupyButton->SetText( "Get In" ); + m_pOccupyButton->SetEnabled( true ); + } + } + else + { + m_pOccupyButton->SetText( "Get In" ); + m_pOccupyButton->SetEnabled( pVehicle->GetPassengerCount() < pVehicle->GetMaxPassengerCount() ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Handle clicking on the Occupy button +//----------------------------------------------------------------------------- +void CVehicleTeleportStationControlPanel::GetInVehicle( void ) +{ + C_BaseObject *pObj = GetOwningObject(); + if (pObj) + { + pObj->SendClientCommand( "toggle_use" ); + } +} + +//----------------------------------------------------------------------------- +// Button click handlers +//----------------------------------------------------------------------------- +void CVehicleTeleportStationControlPanel::OnCommand( const char *command ) +{ + if (!Q_strnicmp(command, "Occupy", 7)) + { + GetInVehicle(); + return; + } + + BaseClass::OnCommand(command); +} + diff --git a/game/client/tf2/c_vehicle_teleport_station.h b/game/client/tf2/c_vehicle_teleport_station.h new file mode 100644 index 0000000..4796660 --- /dev/null +++ b/game/client/tf2/c_vehicle_teleport_station.h @@ -0,0 +1,33 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef C_VEHICLE_TELEPORT_STATION_H +#define C_VEHICLE_TELEPORT_STATION_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "c_basefourwheelvehicle.h" + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_VehicleTeleportStation : public C_BaseTFFourWheelVehicle +{ + DECLARE_CLASS( C_VehicleTeleportStation, C_BaseTFFourWheelVehicle ); +public: + DECLARE_CLIENTCLASS(); + + C_VehicleTeleportStation(); + +private: + C_VehicleTeleportStation( const C_VehicleTeleportStation & ); // not defined, not accessible +}; + + +#endif // C_VEHICLE_TELEPORT_STATION_H diff --git a/game/client/tf2/c_vehicle_wagon.cpp b/game/client/tf2/c_vehicle_wagon.cpp new file mode 100644 index 0000000..475e9f3 --- /dev/null +++ b/game/client/tf2/c_vehicle_wagon.cpp @@ -0,0 +1,183 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_basefourwheelvehicle.h" +#include "tf_movedata.h" +#include "ObjectControlPanel.h" +#include <vgui_controls/Label.h> +#include <vgui_controls/Button.h> + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_VehicleWagon : public C_BaseTFFourWheelVehicle +{ + DECLARE_CLASS( C_VehicleWagon, C_BaseTFFourWheelVehicle ); +public: + DECLARE_CLIENTCLASS(); + + C_VehicleWagon(); + +private: + C_VehicleWagon( const C_VehicleWagon & ); // not defined, not accessible + +}; + + +IMPLEMENT_CLIENTCLASS_DT(C_VehicleWagon, DT_VehicleWagon, CVehicleWagon) +END_RECV_TABLE() + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_VehicleWagon::C_VehicleWagon() +{ +} + + +//----------------------------------------------------------------------------- +// Control screen +//----------------------------------------------------------------------------- +class CVehicleWagonControlPanel : public CObjectControlPanel +{ + DECLARE_CLASS( CVehicleWagonControlPanel, CObjectControlPanel ); + +public: + CVehicleWagonControlPanel( vgui::Panel *parent, const char *panelName ); + virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); + virtual void OnTick(); + virtual void OnCommand( const char *command ); + +private: + void GetInRam( void ); + +private: + vgui::Label *m_pDriverLabel; + vgui::Label *m_pPassengerLabel; + vgui::Button *m_pOccupyButton; +}; + + +DECLARE_VGUI_SCREEN_FACTORY( CVehicleWagonControlPanel, "vehicle_wagon_control_panel" ); + + +//----------------------------------------------------------------------------- +// Constructor: +//----------------------------------------------------------------------------- +CVehicleWagonControlPanel::CVehicleWagonControlPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, "CVehicleBatteringRamControlPanel" ) +{ +} + + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- +bool CVehicleWagonControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ) +{ + m_pDriverLabel = new vgui::Label( this, "DriverReadout", "" ); + m_pPassengerLabel = new vgui::Label( this, "PassengerReadout", "" ); + m_pOccupyButton = new vgui::Button( this, "OccupyButton", "Occupy" ); + + if (!BaseClass::Init(pKeyValues, pInitData)) + return false; + + return true; +} + + +//----------------------------------------------------------------------------- +// Frame-based update +//----------------------------------------------------------------------------- +void CVehicleWagonControlPanel::OnTick() +{ + BaseClass::OnTick(); + + C_BaseObject *pObj = GetOwningObject(); + if (!pObj) + return; + + Assert( dynamic_cast<C_VehicleWagon*>(pObj) ); + C_VehicleWagon *pWagon = static_cast<C_VehicleWagon*>(pObj); + + char buf[256]; + // Update the currently manned player label + if ( pWagon->GetDriverPlayer() ) + { + Q_snprintf( buf, sizeof( buf ), "Driven by %s", pWagon->GetDriverPlayer()->GetPlayerName() ); + m_pDriverLabel->SetText( buf ); + m_pDriverLabel->SetVisible( true ); + } + else + { + m_pDriverLabel->SetVisible( false ); + } + + int nPassengerCount = pWagon->GetPassengerCount(); + int nMaxPassengerCount = pWagon->GetMaxPassengerCount(); + + Q_snprintf( buf, sizeof( buf ), "Passengers %d/%d", nPassengerCount >= 1 ? nPassengerCount - 1 : 0, nMaxPassengerCount - 1 ); + m_pPassengerLabel->SetText( buf ); + + // Update the get in button + if ( pWagon->IsPlayerInVehicle( C_BaseTFPlayer::GetLocalPlayer() ) ) + { + m_pOccupyButton->SetEnabled( false ); + return; + } + + if ( pWagon->GetOwner() == C_BaseTFPlayer::GetLocalPlayer() ) + { + if (nPassengerCount == nMaxPassengerCount) + { + // Owners can boot other players to get in + C_BaseTFPlayer *pPlayer = static_cast<C_BaseTFPlayer*>(pWagon->GetPassenger( VEHICLE_ROLE_DRIVER )); + Q_snprintf( buf, sizeof( buf ), "Get In (Ejecting %s)", pPlayer->GetPlayerName() ); + m_pDriverLabel->SetText( buf ); + m_pOccupyButton->SetEnabled( true ); + } + else + { + m_pOccupyButton->SetText( "Get In" ); + m_pOccupyButton->SetEnabled( true ); + } + } + else + { + m_pOccupyButton->SetText( "Get In" ); + m_pOccupyButton->SetEnabled( pWagon->GetPassengerCount() < pWagon->GetMaxPassengerCount() ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Handle clicking on the Occupy button +//----------------------------------------------------------------------------- +void CVehicleWagonControlPanel::GetInRam( void ) +{ + C_BaseObject *pObj = GetOwningObject(); + if (pObj) + { + pObj->SendClientCommand( "toggle_use" ); + } +} + +//----------------------------------------------------------------------------- +// Button click handlers +//----------------------------------------------------------------------------- +void CVehicleWagonControlPanel::OnCommand( const char *command ) +{ + if (!Q_strnicmp(command, "Occupy", 7)) + { + GetInRam(); + return; + } + + BaseClass::OnCommand(command); +} + diff --git a/game/client/tf2/c_walker_base.cpp b/game/client/tf2/c_walker_base.cpp new file mode 100644 index 0000000..004e9c6 --- /dev/null +++ b/game/client/tf2/c_walker_base.cpp @@ -0,0 +1,20 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "c_walker_base.h" + + +IMPLEMENT_CLIENTCLASS_DT( C_WalkerBase, DT_WalkerBase, CWalkerBase ) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_WalkerBase::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); +} diff --git a/game/client/tf2/c_walker_base.h b/game/client/tf2/c_walker_base.h new file mode 100644 index 0000000..62205bf --- /dev/null +++ b/game/client/tf2/c_walker_base.h @@ -0,0 +1,33 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef C_WALKER_BASE_H +#define C_WALKER_BASE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "basetfvehicle.h" +#include "client_class.h" + + +class C_WalkerBase : public C_BaseTFVehicle +{ +public: + DECLARE_CLIENTCLASS(); + DECLARE_CLASS( C_WalkerBase, C_BaseTFVehicle ); + + C_WalkerBase() {} + + virtual void OnDataChanged( DataUpdateType_t updateType ); + +private: + C_WalkerBase( const C_WalkerBase &other ) {} +}; + + +#endif // C_WALKER_BASE_H diff --git a/game/client/tf2/c_walker_ministrider.cpp b/game/client/tf2/c_walker_ministrider.cpp new file mode 100644 index 0000000..5608c1c --- /dev/null +++ b/game/client/tf2/c_walker_ministrider.cpp @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "c_walker_ministrider.h" +#include "beamdraw.h" +#include "view.h" + + +extern ConVar vehicle_free_pitch, vehicle_free_roll; + + +IMPLEMENT_CLIENTCLASS_DT( C_WalkerMiniStrider, DT_WalkerMiniStrider, CWalkerMiniStrider ) +END_RECV_TABLE() + + +C_WalkerMiniStrider::C_WalkerMiniStrider() +{ +} + + +C_WalkerMiniStrider::~C_WalkerMiniStrider() +{ +} + + +void C_WalkerMiniStrider::ClientThink() +{ +} + + +void C_WalkerMiniStrider::SetupMove( CBasePlayer *pPlayer, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move ) +{ +} + diff --git a/game/client/tf2/c_walker_ministrider.h b/game/client/tf2/c_walker_ministrider.h new file mode 100644 index 0000000..9ff51d8 --- /dev/null +++ b/game/client/tf2/c_walker_ministrider.h @@ -0,0 +1,63 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef C_WALKER_MINISTRIDER_H +#define C_WALKER_MINISTRIDER_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "c_walker_base.h" +#include "c_rope.h" + + +#define STRIDER_BEAM_LIFETIME 1.0 +#define STRIDER_BEAM_MATERIAL "sprites/physbeam" +#define STRIDER_BEAM_WIDTH 25 +#define STRIDER_NUM_ROPES 6 + + +class CStriderBeamEffect +{ +public: + Vector m_vHitPos; + float m_flStartTime; +}; + + +class C_WalkerMiniStrider : public C_WalkerBase +{ +public: + DECLARE_CLIENTCLASS(); + DECLARE_CLASS( C_WalkerMiniStrider, C_WalkerBase ); + + C_WalkerMiniStrider(); + virtual ~C_WalkerMiniStrider(); + + +// IClientThinkable. +public: + virtual void ClientThink(); + + +// C_BaseEntity. +public: + + virtual bool ShouldPredict() { return false; } + virtual void SetupMove( CBasePlayer *pPlayer, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move ); + + +// C_BaseAnimating. +public: + + +private: + C_WalkerMiniStrider( const C_WalkerMiniStrider &other ) {} +}; + + +#endif // C_WALKER_MINISTRIDER_H diff --git a/game/client/tf2/c_walker_strider.cpp b/game/client/tf2/c_walker_strider.cpp new file mode 100644 index 0000000..a723125 --- /dev/null +++ b/game/client/tf2/c_walker_strider.cpp @@ -0,0 +1,218 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "c_walker_strider.h" +#include "beamdraw.h" +#include "clienteffectprecachesystem.h" + +extern ConVar vehicle_free_pitch, vehicle_free_roll; + + +CLIENTEFFECT_REGISTER_BEGIN( PrecacheWalkerStrider ) +CLIENTEFFECT_MATERIAL( STRIDER_BEAM_MATERIAL ) +CLIENTEFFECT_REGISTER_END() + + +IMPLEMENT_CLIENTCLASS_DT( C_WalkerStrider, DT_WalkerStrider, CWalkerStrider ) + RecvPropInt( RECVINFO( m_bCrouched ) ) +END_RECV_TABLE() +LINK_ENTITY_TO_CLASS( walker_strider, C_WalkerStrider ); + + +ConVar cl_brush_ropes( "cl_brush_ropes", "0" ); + + +C_WalkerStrider::C_WalkerStrider() +{ + m_bCrouched = false; +} + + +C_WalkerStrider::~C_WalkerStrider() +{ + for ( int i=0; i < STRIDER_NUM_ROPES; i++ ) + { + if ( m_hRopes[i].Get() ) + m_hRopes[i]->Release(); + } +} + + +float sideDist = 90; +float downDist = -400; +#include "studio.h" +bool C_WalkerStrider::GetAttachment( int iAttachment, matrix3x4_t &attachmentToWorld ) +{ + // + // + // This is a TOTAL hack, but we don't have any nodes that work well at all for mounted guns. + // + // + CStudioHdr *pStudioHdr = GetModelPtr( ); + if ( !pStudioHdr || iAttachment < 1 || iAttachment > pStudioHdr->GetNumAttachments() ) + { + return false; + } + + Vector vLocalPos( 0, 0, 0 ); + const mstudioattachment_t &pAttachment = pStudioHdr->pAttachment( iAttachment-1 ); + if ( stricmp( pAttachment.pszName(), "build_point_left_gun" ) == 0 ) + { + vLocalPos.y = sideDist; + } + else if ( stricmp( pAttachment.pszName(), "build_point_right_gun" ) == 0 ) + { + vLocalPos.y = -sideDist; + } + else if ( stricmp( pAttachment.pszName(), "ThirdPersonCameraOrigin" ) == 0 ) + { + } + else + { + // Ok, it's not one of our magical attachments. Use the regular attachment setup stuff. + return BaseClass::GetAttachment( iAttachment, attachmentToWorld ); + } + + if ( m_bCrouched ) + { + vLocalPos.z += downDist; + } + + // Now build the output matrix. + matrix3x4_t localMatrix; + SetIdentityMatrix( localMatrix ); + PositionMatrix( vLocalPos, localMatrix ); + + ConcatTransforms( EntityToWorldTransform(), localMatrix, attachmentToWorld ); + return true; +} + + +void C_WalkerStrider::ReceiveMessage( int classID, bf_read &msg ) +{ + if ( classID != GetClientClass()->m_ClassID ) + { + // message is for subclass + BaseClass::ReceiveMessage( classID, msg ); + return; + } + + Vector vHitPos; + msg.ReadBitVec3Coord( vHitPos ); + + CStriderBeamEffect eff; + eff.m_vHitPos = vHitPos; + eff.m_flStartTime = gpGlobals->curtime; + m_BeamEffects.AddToTail( eff ); +} + + +float flTestSlack = 280; +float flTestSlack2 = 380; + +void C_WalkerStrider::OnDataChanged( DataUpdateType_t type ) +{ + BaseClass::OnDataChanged( type ); + + if ( type == DATA_UPDATE_CREATED ) + { + if ( cl_brush_ropes.GetInt() ) + { + // Create some ropes and hang them off certain attachments. + int indices[7] = + { + LookupAttachment( "kneeL" ), + LookupAttachment( "kneeR" ), + LookupAttachment( "kneeB" ), + + LookupAttachment( "MiniGun" ), + LookupAttachment( "left foot" ), + LookupAttachment( "right foot" ), + LookupAttachment( "back foot" ) + }; + + m_hRopes[0] = C_RopeKeyframe::Create( this, this, indices[0], indices[1] ); + m_hRopes[1] = C_RopeKeyframe::Create( this, this, indices[0], indices[2] ); + m_hRopes[2] = C_RopeKeyframe::Create( this, this, indices[1], indices[2] ); + + for ( int i=0; i < 3; i++ ) + { + if ( m_hRopes[i].Get() ) + m_hRopes[i]->SetSlack( flTestSlack ); + } + + + m_hRopes[3] = C_RopeKeyframe::Create( this, this, indices[3], indices[4] ); + m_hRopes[4] = C_RopeKeyframe::Create( this, this, indices[3], indices[5] ); + m_hRopes[5] = C_RopeKeyframe::Create( this, this, indices[3], indices[6] ); + + for ( i=3; i < 6; i++ ) + { + if ( m_hRopes[i].Get() ) + m_hRopes[i]->SetSlack( flTestSlack2 ); + } + } + } +} + + +void C_WalkerStrider::ClientThink() +{ + // Retire beam effects. + int iNext; + for ( int i=m_BeamEffects.Head(); i != m_BeamEffects.InvalidIndex(); i=iNext ) + { + iNext = m_BeamEffects.Next( i ); + + if ( gpGlobals->curtime >= (m_BeamEffects[i].m_flStartTime + STRIDER_BEAM_LIFETIME) ) + { + m_BeamEffects.Remove( i ); + } + } +} + + +int C_WalkerStrider::DrawModel( int flags ) +{ + BaseClass::DrawModel( flags ); + + IMaterial *pMaterial = materials->FindMaterial( STRIDER_BEAM_MATERIAL, TEXTURE_GROUP_CLIENT_EFFECTS ); + + Vector vGunPos; + QAngle vAngles; + BaseClass::GetAttachment( LookupAttachment( "BigGun" ), vGunPos, vAngles ); + + // Draw our beam effects. + FOR_EACH_LL( m_BeamEffects, i ) + { + CStriderBeamEffect *pEff = &m_BeamEffects[i]; + + float flAlpha = (gpGlobals->curtime - pEff->m_flStartTime) / STRIDER_BEAM_LIFETIME; + flAlpha = 1.0 - clamp( flAlpha, 0, 1 ); + + CBeamSegDraw segDraw; + segDraw.Start( 2, pMaterial ); + + CBeamSeg seg; + seg.m_vColor.Init( 1, 0, 0 ); + seg.m_flWidth = STRIDER_BEAM_WIDTH; + seg.m_flAlpha = flAlpha; + + seg.m_flTexCoord = 0; + seg.m_vPos = vGunPos; + segDraw.NextSeg( &seg ); + + seg.m_flTexCoord = 1; + seg.m_vPos = pEff->m_vHitPos; + segDraw.NextSeg( &seg ); + + segDraw.End(); + } + + return 1; +} + diff --git a/game/client/tf2/c_walker_strider.h b/game/client/tf2/c_walker_strider.h new file mode 100644 index 0000000..924e4a9 --- /dev/null +++ b/game/client/tf2/c_walker_strider.h @@ -0,0 +1,71 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef C_WALKER_STRIDER_H +#define C_WALKER_STRIDER_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "c_walker_base.h" +#include "c_rope.h" + + +#define STRIDER_BEAM_LIFETIME 1.0 +#define STRIDER_BEAM_MATERIAL "sprites/physbeam" +#define STRIDER_BEAM_WIDTH 25 +#define STRIDER_NUM_ROPES 6 + + +class CStriderBeamEffect +{ +public: + Vector m_vHitPos; + float m_flStartTime; +}; + + +class C_WalkerStrider : public C_WalkerBase +{ +public: + DECLARE_CLIENTCLASS(); + DECLARE_CLASS( C_WalkerStrider, C_WalkerBase ); + + C_WalkerStrider(); + virtual ~C_WalkerStrider(); + + +// IClientThinkable. +public: + virtual void ClientThink(); + + +// C_BaseEntity. +public: + virtual void ReceiveMessage( int classID, bf_read &msg ); + virtual void OnDataChanged( DataUpdateType_t type ); + virtual bool ShouldPredict() { return false; } + + +// C_BaseAnimating. +public: + virtual bool GetAttachment( int iAttachment, matrix3x4_t &attachmentToWorld ); + virtual int DrawModel( int flags ); + + +private: + C_WalkerStrider( const C_WalkerStrider &other ) {} + + bool m_bCrouched; + + CUtlLinkedList<CStriderBeamEffect,int> m_BeamEffects; + + CHandle<C_RopeKeyframe> m_hRopes[STRIDER_NUM_ROPES]; +}; + + +#endif // C_WALKER_STRIDER_H diff --git a/game/client/tf2/c_weapon__stubs_tf2.cpp b/game/client/tf2/c_weapon__stubs_tf2.cpp new file mode 100644 index 0000000..6378813 --- /dev/null +++ b/game/client/tf2/c_weapon__stubs_tf2.cpp @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#include "cbase.h" +#include "c_tf_basecombatweapon.h" +#include "c_weapon__stubs.h" +#include "weapon_basecombatobject.h" + +// TODO for 12/22/02 +// weapon_limpetmine +// weapon_builder: don't do yet, waiting for Robin to change out UI + + +STUB_WEAPON_CLASS( foo_weapon_machinegun, MachineGun, C_BaseCombatWeapon ); +STUB_WEAPON_CLASS( foo_weapon_select_fire_machinegun, SelectFireMachineGun, C_MachineGun ); +STUB_WEAPON_CLASS( foo_weapon_basebludgeonweapon, BaseBludgeonWeapon, C_BaseCombatWeapon ); + +STUB_WEAPON_CLASS( cycler_weapon, WeaponCycler, C_BaseCombatWeapon ); + +STUB_WEAPON_CLASS( weapon_assault_rifle, WeaponAssaultRifle, C_TFMachineGun ); +STUB_WEAPON_CLASS( weapon_laserdesignator, WeaponLaserDesignator, C_BaseTFCombatWeapon ); +STUB_WEAPON_CLASS( weapon_laserrifle, WeaponLaserRifle, C_BaseTFCombatWeapon ); +STUB_WEAPON_CLASS( weapon_obj_empgenerator, WeaponObjEMPGenerator, C_WeaponBaseCombatObject ); +STUB_WEAPON_CLASS( weapon_placedcharge, WeaponPlacedCharge, C_BaseTFCombatWeapon ); +STUB_WEAPON_CLASS( weapon_plasmarifle, WeaponPlasmaRifle, C_TFMachineGun ); +STUB_WEAPON_CLASS( weapon_shotgun, WeaponShotgun, C_TFMachineGun ); +STUB_WEAPON_CLASS( weapon_sapper_shotgun, WeaponSapperShotgun, C_WeaponShotgun ); +STUB_WEAPON_CLASS( weapon_cubemap, WeaponCubemap, C_BaseCombatWeapon );
\ No newline at end of file diff --git a/game/client/tf2/c_weapon_builder.cpp b/game/client/tf2/c_weapon_builder.cpp new file mode 100644 index 0000000..edb69ab --- /dev/null +++ b/game/client/tf2/c_weapon_builder.cpp @@ -0,0 +1,380 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client's CWeaponBuilder class +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "in_buttons.h" +#include "clientmode_tfnormal.h" +#include "engine/IEngineSound.h" +#include "c_weapon_builder.h" +#include "c_weapon__stubs.h" +#include "iinput.h" +#include "ObjectControlPanel.h" +#include <vgui/IVGui.h> + +#define BUILD_ICON_SCALE 0.75 + +#define BUILD_ICON_BOTTOM_OFFSET YRES(160) + +//----------------------------------------------------------------------------- +// Purpose: Draw a material on a quad +//----------------------------------------------------------------------------- +void DrawQuadMaterial( IMaterial *pMaterial, int iX, int iY, int iWidth, int iHeight, + unsigned char r = 255, unsigned char g = 255, unsigned char b = 255, unsigned char a = 255, + float flTextureLeft = 0.0, float flTextureRight = 1.0, bool bRotated = false ) +{ + IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL, pMaterial ); + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); + + meshBuilder.Color4ub( r, g, b, a ); + if ( bRotated ) + { + meshBuilder.TexCoord2f( 0,flTextureLeft,1 ); + } + else + { + meshBuilder.TexCoord2f( 0,flTextureLeft,0 ); + } + meshBuilder.Position3f( iX,iY,0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( r, g, b, a ); + if ( bRotated ) + { + meshBuilder.TexCoord2f( 0,flTextureLeft,0 ); + } + else + { + meshBuilder.TexCoord2f( 0,flTextureRight,0 ); + } + meshBuilder.Position3f( iX+iWidth, iY, 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( r, g, b, a ); + if ( bRotated ) + { + meshBuilder.TexCoord2f( 0,flTextureRight,0 ); + } + else + { + meshBuilder.TexCoord2f( 0,flTextureRight,1 ); + } + meshBuilder.Position3f( iX+iWidth, iY+iHeight, 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( r, g, b, a ); + if ( bRotated ) + { + meshBuilder.TexCoord2f( 0,flTextureRight,1 ); + } + else + { + meshBuilder.TexCoord2f( 0,flTextureLeft,1 ); + } + meshBuilder.Position3f( iX, iY+iHeight, 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.End(); + pMesh->Draw(); +} + +STUB_WEAPON_CLASS_IMPLEMENT( weapon_builder, C_WeaponBuilder ); + +IMPLEMENT_CLIENTCLASS_DT(C_WeaponBuilder, DT_WeaponBuilder, CWeaponBuilder) + RecvPropInt( RECVINFO(m_iBuildState) ), + RecvPropInt( RECVINFO(m_iCurrentObject) ), + RecvPropInt( RECVINFO(m_iCurrentObjectState) ), + RecvPropEHandle( RECVINFO(m_hObjectBeingBuilt) ), + RecvPropTime( RECVINFO(m_flStartTime) ), + RecvPropTime( RECVINFO(m_flTotalTime) ), + RecvPropArray + ( + RecvPropInt( RECVINFO(m_bObjectValidity[0])), m_bObjectValidity + ), + RecvPropArray + ( + RecvPropInt( RECVINFO(m_bObjectBuildability[0])), m_bObjectBuildability + ), +END_RECV_TABLE() + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_WeaponBuilder::C_WeaponBuilder() +{ + m_iBuildState = 0; + m_iCurrentObject = BUILDER_INVALID_OBJECT; + m_iCurrentObjectState = 0; + m_flStartTime = 0; + m_flTotalTime = 0; + + m_pIconFireToSelect.Init( "Hud/build/firetobuild", TEXTURE_GROUP_VGUI ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_WeaponBuilder::~C_WeaponBuilder() +{ +} + +//----------------------------------------------------------------------------- +// A couple helper methods for drawing builder status +//----------------------------------------------------------------------------- +static void DrawTextIcon( IMaterial* pMaterial, int parentWidth, int parentHeight, float r = 1.0f, float g = 1.0f, float b = 1.0f ) +{ + if ( !pMaterial ) + return; + + // We're in build selection mode, so draw the current build icon + int iWidth = pMaterial->GetMappingWidth(); + int iHeight = pMaterial->GetMappingHeight(); + int iX = (parentWidth - iWidth) / 2; + int iY = (parentHeight - 216); + DrawQuadMaterial( pMaterial, iX, iY, iWidth, iHeight, r * 255, g * 255, b * 255 ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : char const +//----------------------------------------------------------------------------- +const char *C_WeaponBuilder::GetCurrentSelectionObjectName( void ) +{ + if ( m_iCurrentObject == -1 || (m_iBuildState == BS_SELECTING) ) + return ""; + + return GetObjectInfo( m_iCurrentObject )->m_pBuilderWeaponName; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_WeaponBuilder::Redraw() +{ + BaseClass::Redraw(); + + // Don't draw if we're hiding the weapons, or the player's dead + if ( gHUD.IsHidden( HIDEHUD_WEAPONSELECTION | HIDEHUD_PLAYERDEAD ) ) + return; + C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + if (!pPlayer) + return; + + vgui::Panel *pParent = GetClientModeNormal()->GetViewport(); + int parentWidth, parentHeight; + pParent->GetSize(parentWidth, parentHeight); + + // If we're in placement mode, draw the placement icon + switch( m_iBuildState ) + { + case BS_PLACING: + case BS_PLACING_INVALID: + break; + + default: + { + if( !inv_demo.GetInt() ) + { + DrawTextIcon( m_pIconFireToSelect, parentWidth, parentHeight ); + } + break; + } + break; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool C_WeaponBuilder::IsPlacingObject( void ) +{ + if ( m_iBuildState == BS_PLACING || m_iBuildState == BS_PLACING_INVALID ) + return true; + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool C_WeaponBuilder::IsBuildingObject( void ) +{ + if ( m_iBuildState == BS_BUILDING ) + return true; + return false; +} + +#include "vgui_bitmapimage.h" +#include "vgui_bitmappanel.h" + + +//----------------------------------------------------------------------------- +// Control screen +//----------------------------------------------------------------------------- +class CHumanPDAPanel : public CVGuiScreenPanel +{ + DECLARE_CLASS( CHumanPDAPanel, CVGuiScreenPanel ); + +public: + CHumanPDAPanel( vgui::Panel *parent, const char *panelName ); + ~CHumanPDAPanel(); + virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); + virtual void OnTick(); + +private: + C_BaseCombatWeapon *GetOwningWeapon(); + + vgui::Label *m_pObjectName; + vgui::Label *m_pObjectCost; + vgui::Label *m_pObjectOnTeamCount; + vgui::Label *m_pObjectPlacementDetails; + + CBitmapPanel *m_pBitmapPanel; + + BitmapImage *m_pObjectImage; + + int m_nLastObjectID; + int m_nLastObjectCount; + int m_nLastObjectCost; + +}; + + +DECLARE_VGUI_SCREEN_FACTORY( CHumanPDAPanel, "human_pda" ); + + +//----------------------------------------------------------------------------- +// Constructor: +//----------------------------------------------------------------------------- +CHumanPDAPanel::CHumanPDAPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, "CHumanPDAPanel", vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/PDAControlPanelScheme.res", "TFBase" ) ) +{ + m_pObjectImage = NULL; + + m_pObjectName = new vgui::Label( this, "ObjectName", "" ); + m_pObjectCost = new vgui::Label( this, "ObjectCost", "" ); + m_pObjectOnTeamCount = new vgui::Label( this, "ObjectOnTeamCount", "" ); + m_pObjectPlacementDetails = new vgui::Label( this, "ObjectPlacementDetails", "" ); + + m_pBitmapPanel = new CBitmapPanel( this, "ObjectImage" ); + m_pObjectImage = new BitmapImage(); + m_pObjectImage->UsePanelRenderSize( m_pBitmapPanel->GetVPanel() ); + m_pBitmapPanel->SetImage( m_pObjectImage ); + + m_nLastObjectID = -1; + m_nLastObjectCount = -1; + m_nLastObjectCost = -1; +} + +CHumanPDAPanel::~CHumanPDAPanel() +{ + if ( m_pObjectImage ) + { + delete m_pObjectImage; + } +} + + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- +bool CHumanPDAPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ) +{ + + // Make sure we get ticked... + vgui::ivgui()->AddTickSignal( GetVPanel() ); + + if (!BaseClass::Init(pKeyValues, pInitData)) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// Returns the object it's attached to +//----------------------------------------------------------------------------- +C_BaseCombatWeapon *CHumanPDAPanel::GetOwningWeapon() +{ + C_BaseEntity *pScreenEnt = GetEntity(); + if (!pScreenEnt) + return NULL; + + C_BaseEntity *pOwner = pScreenEnt->GetOwnerEntity(); + if (!pOwner) + return NULL; + + C_BaseViewModel *pViewModel = dynamic_cast< C_BaseViewModel * >( pOwner ); + if ( !pViewModel ) + return NULL; + + return pViewModel->GetOwningWeapon(); +} + +//----------------------------------------------------------------------------- +// Frame-based update +//----------------------------------------------------------------------------- +void CHumanPDAPanel::OnTick() +{ + BaseClass::OnTick(); + + SetVisible( true ); + + char buf[256]; + + C_BaseCombatWeapon *weapon = GetOwningWeapon(); + if ( !weapon ) + return; + + C_WeaponBuilder *builder = dynamic_cast< C_WeaponBuilder * >( weapon ); + if ( !builder ) + return; + + CBaseTFPlayer *pOwner = ToBaseTFPlayer( builder->GetOwner() ); + if ( !pOwner ) + return; + + // FIXME: Check build state?? + + int objectType = builder->m_iCurrentObject; + CObjectInfo const *info = GetObjectInfo( objectType ); + if ( !info ) + return; + + int numOwned = pOwner->GetNumObjects(objectType); + int iCost = CalculateObjectCost( objectType, numOwned, pOwner->GetTeamNumber() ); + + if ( m_nLastObjectID == objectType && + m_nLastObjectCount == numOwned && + m_nLastObjectCost == iCost) + return; + + m_nLastObjectID = objectType; + m_nLastObjectCount = numOwned; + m_nLastObjectCost = iCost; + + Q_snprintf( buf, sizeof( buf ), "hud/menu/%s", info->m_pClassName ); + m_pObjectImage->SetImageFile( buf ); + m_pObjectImage->SetColor( GetFgColor() ); + + Q_snprintf( buf, sizeof( buf ), "%s", info->m_pStatusName ); + m_pObjectName->SetText( buf ); + + Q_snprintf( buf, sizeof( buf ), "Cost: %i", iCost ); + m_pObjectCost->SetText( buf ); + + Q_snprintf( buf, sizeof( buf ), "You own: %i", numOwned ); + m_pObjectOnTeamCount->SetText( buf ); + + Q_snprintf( buf, sizeof( buf ), "%s", info->m_pBuilderPlacementString ? info->m_pBuilderPlacementString : "" ); + m_pObjectPlacementDetails->SetText( buf ); + //m_pObjectPlacementDetails->SizeToContents(); +} diff --git a/game/client/tf2/c_weapon_builder.h b/game/client/tf2/c_weapon_builder.h new file mode 100644 index 0000000..127e2b2 --- /dev/null +++ b/game/client/tf2/c_weapon_builder.h @@ -0,0 +1,63 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_WEAPON_BUILDER_H +#define C_WEAPON_BUILDER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_tf_basecombatweapon.h" +#include "weapon_combat_usedwithshieldbase.h" + +//============================================================================= +// Purpose: Client version of CWeaponBuiler +//============================================================================= +class C_WeaponBuilder : public C_WeaponCombatUsedWithShieldBase +{ + DECLARE_CLASS( C_WeaponBuilder, C_WeaponCombatUsedWithShieldBase ); +public: + DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); + + C_WeaponBuilder(); + ~C_WeaponBuilder(); + + virtual void Redraw(); + virtual bool VisibleInWeaponSelection( void ) { return false; } + + virtual bool IsPlacingObject( void ); + virtual bool IsBuildingObject( void ); + + virtual const char *GetCurrentSelectionObjectName( void ); + + C_BaseObject *GetPlacementModel( void ) { return m_hObjectBeingBuilt.Get(); } + +public: + // Builder Data + int m_iBuildState; + unsigned int m_iCurrentObject; + int m_iCurrentObjectState; + float m_flStartTime; + float m_flTotalTime; + vgui::HFont m_hFont; + + // Our placement model + CHandle<C_BaseObject> m_hObjectBeingBuilt; + + // Objects that this builder can build + bool m_bObjectValidity[ OBJ_LAST ]; + // Buildability of each object + bool m_bObjectBuildability[ OBJ_LAST ]; + + // Materials + CMaterialReference m_pIconFireToSelect; + +private: + C_WeaponBuilder( const C_WeaponBuilder & ); +}; +#endif // C_WEAPON_BUILDER_H diff --git a/game/client/tf2/c_weapon_chargeableplasma.cpp b/game/client/tf2/c_weapon_chargeableplasma.cpp new file mode 100644 index 0000000..22e2471 --- /dev/null +++ b/game/client/tf2/c_weapon_chargeableplasma.cpp @@ -0,0 +1,358 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "iefx.h" +#include "dlight.h" +#include "engine/IEngineSound.h" +#include "view.h" +#include "beamdraw.h" +#include "clienteffectprecachesystem.h" +#include "weapon_combat_usedwithshieldbase.h" +#include "c_weapon__stubs.h" +#include <vgui/ISurface.h> + +#define BALL_GROW_TIME 1.5 + +// Precache the effects +CLIENTEFFECT_REGISTER_BEGIN( PrecacheWeaponCombat_ChargeablePlasma ) +CLIENTEFFECT_MATERIAL( "sprites/chargeball_team1" ) +CLIENTEFFECT_MATERIAL( "sprites/chargeball_team2" ) +CLIENTEFFECT_REGISTER_END() + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_WeaponCombat_ChargeablePlasma : public C_WeaponCombatUsedWithShieldBase +{ + DECLARE_CLASS( C_WeaponCombat_ChargeablePlasma, C_WeaponCombatUsedWithShieldBase ); + +public: + DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); + + C_WeaponCombat_ChargeablePlasma( void ); + ~C_WeaponCombat_ChargeablePlasma( void ); + + virtual void PreDataUpdate( DataUpdateType_t updateType ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL ); + virtual void DrawCrosshair( void ); + virtual void ClientThink( ); + virtual int DrawModel( int flags ); + virtual void ViewModelDrawn( C_BaseViewModel *pBaseViewModel ); + virtual void NotifyShouldTransmit( ShouldTransmitState_t state ); + virtual bool IsTransparent( ); + +private: + void StartCharging(); + void StopCharging(); + void DrawChargingEffect( float flSize, C_BaseAnimating *pAttachedEnt ); + +private: + bool m_bCharging; + bool m_bLastCharging; + float m_flPower; + float m_flChargeStartTime; + CMaterialReference m_hMaterial; + +private: + C_WeaponCombat_ChargeablePlasma( const C_WeaponCombat_ChargeablePlasma & ); +}; + +STUB_WEAPON_CLASS_IMPLEMENT( weapon_combat_chargeableplasma, C_WeaponCombat_ChargeablePlasma ); + +IMPLEMENT_CLIENTCLASS_DT( C_WeaponCombat_ChargeablePlasma, DT_WeaponCombat_ChargeablePlasma, CWeaponCombat_ChargeablePlasma ) + RecvPropInt( RECVINFO(m_bCharging) ), +END_RECV_TABLE() + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_WeaponCombat_ChargeablePlasma::C_WeaponCombat_ChargeablePlasma( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_WeaponCombat_ChargeablePlasma::~C_WeaponCombat_ChargeablePlasma( void ) +{ + Holster( NULL ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_WeaponCombat_ChargeablePlasma::PreDataUpdate( DataUpdateType_t updateType ) +{ + BaseClass::PreDataUpdate( updateType ); + + m_bLastCharging = m_bCharging; +} + + +void C_WeaponCombat_ChargeablePlasma::NotifyShouldTransmit( ShouldTransmitState_t state ) +{ + BaseClass::NotifyShouldTransmit(state); + + if (state == SHOULDTRANSMIT_START) + { + if (m_bCharging) + StartCharging(); + } + else if (state == SHOULDTRANSMIT_END) + { + if (m_bCharging) + StopCharging(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_WeaponCombat_ChargeablePlasma::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + switch( updateType ) + { + case DATA_UPDATE_CREATED: + // So we can update our lights + if ( GetTeamNumber() == 1 ) + m_hMaterial.Init( "sprites/chargeball_team1" ); + else + m_hMaterial.Init( "sprites/chargeball_team2" ); + + break; + + case DATA_UPDATE_DATATABLE_CHANGED: + if ( m_bCharging != m_bLastCharging ) + { + if ( m_bCharging ) + { + StartCharging(); + } + else + { + StopCharging(); + } + } + break; + }; + + if (WeaponState() == WEAPON_IS_ACTIVE) + { + // Start thinking so we can manipulate the light + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } + else + { + SetNextClientThink( CLIENT_THINK_NEVER ); + } +} + + +//----------------------------------------------------------------------------- +// Deal with dynamic lighting +//----------------------------------------------------------------------------- +void C_WeaponCombat_ChargeablePlasma::ClientThink( ) +{ + BaseClass::ClientThink(); + + C_BaseTFPlayer *pPlayer = (C_BaseTFPlayer *)GetOwner(); + if ( !pPlayer || (pPlayer->GetHealth() <= 0)) + { + SetNextClientThink( CLIENT_THINK_NEVER ); + return; + } + + if (!m_bCharging) + return; + + // Determine the ball size... + m_flPower = (gpGlobals->curtime - m_flChargeStartTime) / BALL_GROW_TIME; + m_flPower = clamp( m_flPower, 0, 1 ); + + // FIXME: dl->origin should be based on the attachment point + dlight_t *dl = effects->CL_AllocDlight( entindex() ); + dl->origin = GetRenderOrigin(); + + if (GetTeamNumber() == 1) + { + dl->color.r = 40; + dl->color.g = 60; + dl->color.b = 250; + } + else + { + dl->color.r = 250; + dl->color.g = 60; + dl->color.b = 40; + } + + dl->color.exponent = 5; + dl->radius = 20 * m_flPower + 10; + dl->die = gpGlobals->curtime + 0.01; +} + + +//----------------------------------------------------------------------------- +// Purpose: Remove the ball if we're switching away +//----------------------------------------------------------------------------- +bool C_WeaponCombat_ChargeablePlasma::Holster( C_BaseCombatWeapon *pSwitchingTo ) +{ + StopCharging(); + + return BaseClass::Holster( pSwitchingTo ); +} + +void C_WeaponCombat_ChargeablePlasma::StartCharging() +{ + CLocalPlayerFilter filter; + EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "WeaponCombat_ChargeablePlasma.Charging" ); + m_flChargeStartTime = gpGlobals->curtime; +} + + +void C_WeaponCombat_ChargeablePlasma::StopCharging() +{ + StopSound( SOUND_FROM_LOCAL_PLAYER, "WeaponCombat_ChargeablePlasma.Charging" ); + m_bCharging = false; +} + + +//----------------------------------------------------------------------------- +// We're transparent because we draw a transparent charging effect +//----------------------------------------------------------------------------- +bool C_WeaponCombat_ChargeablePlasma::IsTransparent( ) +{ + if (m_bCharging) + return true; + return BaseClass::IsTransparent(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Draws the charging effect +//----------------------------------------------------------------------------- +void C_WeaponCombat_ChargeablePlasma::DrawChargingEffect( float flSize, C_BaseAnimating *pAttachedEnt ) +{ + if (!pAttachedEnt) + return; + + Vector vecOrigin; + QAngle vecAngles; + int iAttachment = pAttachedEnt->LookupAttachment( "muzzle" ); + if ( pAttachedEnt->GetAttachment( iAttachment, vecOrigin, vecAngles ) ) + { + color32 color = { 255, 255, 255, 255 }; + materials->Bind( m_hMaterial, (IClientRenderable*)this ); + DrawSprite( vecOrigin, flSize, flSize, color ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Draws the model +//----------------------------------------------------------------------------- +int C_WeaponCombat_ChargeablePlasma::DrawModel( int flags ) +{ + int retval = BaseClass::DrawModel( flags ); + if (retval == 0) + return 0; + + if (m_bCharging && IsCarrierAlive()) + { + // Draw the charging effect + float flSize = 20 * m_flPower + 10; + + DrawChargingEffect( flSize, this ); + } + return retval; +} + + +//----------------------------------------------------------------------------- +// Purpose: Draws the model +//----------------------------------------------------------------------------- +void C_WeaponCombat_ChargeablePlasma::ViewModelDrawn( C_BaseViewModel *pBaseViewModel ) +{ + if (!m_bCharging) + return; + + // Draw the charging effect + float flSize = 12 * m_flPower + 6; + + if ( m_iClip1 > 0 ) + { + DrawChargingEffect( flSize, pBaseViewModel ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Draw targeting reticle +//----------------------------------------------------------------------------- +void C_WeaponCombat_ChargeablePlasma::DrawCrosshair( void ) +{ + BaseClass::DrawCrosshair(); + + // Find enemy players in front of me + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + trace_t tr; + Vector vecStart, vecEnd; + VectorMA( CurrentViewOrigin(), 1500, CurrentViewForward(), vecEnd ); + VectorMA( CurrentViewOrigin(), 48, CurrentViewForward(), vecStart ); + UTIL_TraceLine( vecStart, vecEnd, MASK_SOLID, NULL, COLLISION_GROUP_NONE, &tr ); + + if ( tr.DidHitNonWorldEntity() ) + { + C_BaseEntity *pEntity = tr.m_pEnt; + if ( pEntity && pEntity->IsPlayer() && !pPlayer->InSameTeam( pEntity ) ) + { + // Draw a reticle + vgui::Color clr = gHUD.m_clrYellowish; + clr[3] = 128; + + // Calculate circle size + int iRatio = 30; + + // Draw the circle + int iDegrees = 0; + Vector vecPoint, vecLastPoint(0,0,0); + vecPoint.z = 0.0f; + for ( int i = 0; i < 360; i++ ) + { + float flRadians = DEG2RAD( iDegrees ); + iDegrees += (360 / 360); + + float ca = cos( flRadians ); + float sa = sin( flRadians ); + + // Rotate it around the circle + vecPoint.x = (int)((ScreenWidth() / 2) + (iRatio * sa)); + vecPoint.y = (int)((ScreenHeight() / 2) - (iRatio * ca)); + + // Draw the point, if it's not on the previous point, to avoid smaller circles being brighter + if ( vecLastPoint != vecPoint ) + { + vgui::surface()->DrawSetColor( clr ); + vgui::surface()->DrawFilledRect( vecPoint.x, vecPoint.y, vecPoint.x + 1, vecPoint.y + 1 ); + } + + vecLastPoint = vecPoint; + } + } + } +} + diff --git a/game/client/tf2/c_weapon_mortar.cpp b/game/client/tf2/c_weapon_mortar.cpp new file mode 100644 index 0000000..ecae3b9 --- /dev/null +++ b/game/client/tf2/c_weapon_mortar.cpp @@ -0,0 +1,634 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client's CWeaponMortar class +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "hudelement.h" +#include "in_buttons.h" +#include "ground_line.h" +#include "clientmode_tfnormal.h" +#include "vgui_basepanel.h" +#include "c_tf_basecombatweapon.h" +#include "engine/IEngineSound.h" +#include "iinput.h" +#include "imessagechars.h" +#include "c_weapon__stubs.h" + +//============================================================================= +// Purpose: Hud Element for Mortar firing +//============================================================================= +class CHudMortar : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudMortar, vgui::Panel ); + +public: + DECLARE_MULTIPLY_INHERITED(); + + CHudMortar( const char *pElementName ); + virtual void Paint( void ); + + float m_flPower; + float m_flFiringPower; + float m_flFiringAccuracy; + float m_flReset; +}; + +DECLARE_HUDELEMENT( CHudMortar ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CHudMortar::CHudMortar( const char *pElementName ) : + CHudElement( pElementName ), vgui::Panel( NULL, pElementName ) +{ + m_flPower = 0; + m_flFiringPower = 0; + m_flFiringAccuracy = 0; + m_flReset = 0; + SetPaintBackgroundEnabled( false ); + SetAutoDelete( false ); + SetName( "mortar" ); + + SetHiddenBits( HIDEHUD_PLAYERDEAD ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudMortar::Paint() +{ + // Clear out markers + if ( m_flReset && m_flReset < gpGlobals->curtime ) + { + m_flFiringPower = 0; + m_flFiringAccuracy = 0; + m_flReset = 0; + } + + int w, h; + GetSize( w, h ); + + // Use an eighth of the height for each side + int iOffset = h / 8; + int iBarHeight = h - (2 * iOffset); + int iZero = (w / 5); + int iMarker = iZero + (m_flPower * (w - iZero)); + int iPower = iZero + (m_flFiringPower * (w - iZero)); + int iAccuracy = iZero + (m_flFiringAccuracy * (w - iZero)); + + // Shade the bar + int alpha = 205; + int colorAmt = 255; + int nSegs = 20; + + int i; + for(i=0; i < nSegs; i++) + { + int left = iZero + (i*w) / nSegs; + int right = iZero + ((i+1)*w) / nSegs; + + // Don't draw past the marker + if ( m_flFiringPower && right > iPower ) + right = iPower; + else if ( !m_flFiringPower && right > iMarker ) + right = iMarker; + + vgui::surface()->DrawSetColor( ((i + 5) * colorAmt) / nSegs, 0, 0, alpha ); + vgui::surface()->DrawFilledRect( left, iOffset, right, iBarHeight); + } + + // Shade back from zero + nSegs = 10; + for(i=0; i < nSegs; i++) + { + int left = (i*iZero) / nSegs; + int right = ((i+1)*iZero) / nSegs; + + if ( m_flFiringAccuracy && left < iAccuracy ) + left = iAccuracy; + else if ( !m_flFiringAccuracy && left < iMarker ) + left = iMarker; + + vgui::surface()->DrawSetColor( ((nSegs - i) * colorAmt) / nSegs, 0, 0, alpha ); + vgui::surface()->DrawFilledRect(left, iOffset, right, iBarHeight); + } + + // Draw the zero marker + vgui::surface()->DrawSetColor(255,255,255,255); + vgui::surface()->DrawFilledRect(iZero-2, iOffset, iZero+2, iBarHeight); + + // Draw the marker + vgui::surface()->DrawSetColor(255,255,255,255); + vgui::surface()->DrawFilledRect(iMarker-1, 0, iMarker+1, h); + + // Draw the power mark if we've set one + if ( m_flFiringPower ) + { + vgui::surface()->DrawSetColor(255,255,255,255); + vgui::surface()->DrawFilledRect(iPower-1, iOffset, iPower+1, iBarHeight); + } + + // Draw the accuracy mark if we've set one + if ( m_flFiringAccuracy ) + { + vgui::surface()->DrawSetColor(255,255,255,255); + vgui::surface()->DrawFilledRect(iAccuracy-1, iOffset, iAccuracy+1, iBarHeight); + } + + // Draw box + vgui::surface()->DrawSetColor(255,255,255,255); + vgui::surface()->DrawOutlinedRect(0, iOffset, w, iBarHeight); +} + +static ConVar g_CVMortarGroundLineUpdateInterval( "mortar_groundlineupdateinterval", "0.1", 0, "Number of seconds, mininum, between ground line position updates." ); + + +//============================================================================= +// Purpose: Client version of CWeaponMortar +//============================================================================= +class C_WeaponMortar : public C_BaseTFCombatWeapon +{ +public: + DECLARE_CLASS( C_WeaponMortar, C_BaseTFCombatWeapon ); + DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); + + C_WeaponMortar(); + ~C_WeaponMortar(); + + void FireMortar( void ); + + virtual void PreDataUpdate( DataUpdateType_t updateType ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void HandleInput( void ); + virtual void Redraw(); + virtual void OverrideMouseInput( float *x, float *y ); + + // Deploy / Holster + virtual bool Deploy( void ); + virtual bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL ); + + // Mortar Data + bool m_bCarried; + bool m_bMortarReloading; + Vector m_vecMortarOrigin; + Vector m_vecMortarAngles; + float m_flPrevMortarServerYaw; + float m_flMortarYaw; + float m_flPrevMortarYaw; + + // Input Handling + float m_flNextClick; + float m_flAccuracySpeed; + int m_iFiringState; + bool m_bRotating; + + CGroundLine *m_pGroundLine; + CGroundLine *m_pDarkLine; + CHudMortar *m_pPowerBar; + IMaterial *m_pRotateIcon; + + vgui::HFont m_hFontText; + +private: + C_WeaponMortar( const C_WeaponMortar & ); + + float m_flLastGroundlineUpdateTime; + +}; + +STUB_WEAPON_CLASS_IMPLEMENT( weapon_mortar, C_WeaponMortar ); + +IMPLEMENT_CLIENTCLASS_DT(C_WeaponMortar, DT_WeaponMortar, CWeaponMortar) + RecvPropInt( RECVINFO(m_bCarried) ), + RecvPropInt( RECVINFO(m_bMortarReloading) ), + RecvPropVector( RECVINFO(m_vecMortarOrigin) ), + RecvPropVector( RECVINFO(m_vecMortarAngles) ), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_WeaponMortar::C_WeaponMortar() +{ + m_bCarried = true; + m_bMortarReloading = false; + m_iFiringState = MORTAR_IDLE; + m_flNextClick = 0; + m_flAccuracySpeed = 0; + m_bRotating = false; + m_pGroundLine = NULL; + m_pDarkLine = NULL; + m_flMortarYaw = 0; + m_flPrevMortarYaw = -1; + + m_pRotateIcon = materials->FindMaterial( "Hud/mortar/mortar_rotate", TEXTURE_GROUP_VGUI ); + m_pRotateIcon->IncrementReferenceCount(); + + m_pPowerBar = GET_HUDELEMENT( CHudMortar ); + + m_flLastGroundlineUpdateTime = 0.0f; + + m_hFontText = g_hFontTrebuchet24; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_WeaponMortar::~C_WeaponMortar() +{ + m_pPowerBar->SetParent( (vgui::Panel *)NULL ); + + if ( m_pRotateIcon != NULL ) + { + m_pRotateIcon->DecrementReferenceCount(); + m_pRotateIcon = NULL; + } + + if ( m_pGroundLine ) + { + delete m_pGroundLine; + } + if ( m_pDarkLine ) + { + delete m_pDarkLine; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_WeaponMortar::PreDataUpdate( DataUpdateType_t updateType ) +{ + BaseClass::PreDataUpdate(updateType); + + m_flPrevMortarServerYaw = m_vecMortarAngles.y; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_WeaponMortar::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged(updateType); + + // If the mortar's being carried by some other player, don't make a ground line + if ( !IsCarriedByLocalPlayer() ) + return; + + // Draw power chart if the mortar is deployed + if ( !m_bCarried && !m_bMortarReloading ) + { + vgui::Panel *pParent = GetClientModeNormal()->GetViewport(); + int parentWidth, parentHeight; + pParent->GetSize(parentWidth, parentHeight); + + int iWidth = 256; + int iHeight = 40; + int iX = (parentWidth - iWidth) / 2; + int iY = (parentHeight - 200); + + // Only show the power bar if the mortar's the active weapon + if ( IsActiveByLocalPlayer() ) + { + m_pPowerBar->SetBounds( iX, iY, iWidth, iHeight ); + m_pPowerBar->SetParent(pParent); + } + else + { + m_pPowerBar->SetParent( (vgui::Panel *)NULL ); + } + + if ( !m_bRotating && m_flPrevMortarServerYaw != m_vecMortarAngles.y ) + { + m_flMortarYaw = m_vecMortarAngles.y; + } + + // Create the Ground lines + if ( !m_pGroundLine ) + { + m_pGroundLine = new CGroundLine(); + m_pGroundLine->Init( "player/support/mortarline" ); + } + if ( !m_pDarkLine ) + { + m_pDarkLine = new CGroundLine(); + m_pDarkLine->Init( "player/support/mortarline" ); + } + } + else + { + m_pPowerBar->SetParent( (vgui::Panel *)NULL ); + + if ( m_pGroundLine ) + { + delete m_pGroundLine; + m_pGroundLine = NULL; + } + if ( m_pDarkLine ) + { + delete m_pDarkLine; + m_pDarkLine = NULL; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_WeaponMortar::HandleInput( void ) +{ + // If it's being carried, ignore input + if ( m_bCarried ) + return; + // If the player's dead, ignore input + C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + if ( pPlayer == NULL ) + return; + if ( pPlayer->GetHealth() < 1 ) + return; + + // Ignore input if it's reloading + if ( m_bMortarReloading ) + return; + + // Secondary fire rotates the mortar + if ( gHUD.m_iKeyBits & IN_ATTACK2 ) + { + if ( pPlayer->HasPowerup(POWERUP_EMP) ) + { + CLocalPlayerFilter filter; + EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "WeaponMortar.EMPed" ); + return; + } + m_bRotating = true; + + gHUD.m_iKeyBits &= ~IN_ATTACK2; + + // Prevent firing while rotating + m_pPowerBar->SetParent( (vgui::Panel *)NULL ); + return; + } + else + { + if ( m_bRotating ) + { + // Bring up the firing bar again + vgui::Panel *pParent = GetClientModeNormal()->GetViewport(); + m_pPowerBar->SetParent(pParent); + m_bRotating = false; + } + } + + // Primary fire launches mortars + if (gHUD.m_iKeyBits & IN_ATTACK) + { + if ( pPlayer->HasPowerup(POWERUP_EMP) ) + { + CLocalPlayerFilter filter; + EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "WeaponMortar.EMPed" ); + return; + } + + if ( m_flNextClick <= gpGlobals->curtime ) + { + // Play click animation + // SendWeaponAnim( ACT_SLAM_DETONATOR_DETONATE ); + + // Switch states + switch( m_iFiringState ) + { + case MORTAR_IDLE: + m_iFiringState = MORTAR_CHARGING_POWER; + break; + case MORTAR_CHARGING_POWER: + m_pPowerBar->m_flFiringPower = m_pPowerBar->m_flPower; + m_iFiringState = MORTAR_CHARGING_ACCURACY; + break; + case MORTAR_CHARGING_ACCURACY: + m_pPowerBar->m_flFiringAccuracy = m_pPowerBar->m_flPower; + m_iFiringState = MORTAR_IDLE; + + FireMortar(); + break; + default: + break; + } + + input->ClearInputButton( IN_ATTACK ); + gHUD.m_iKeyBits &= ~IN_ATTACK; + + m_flNextClick = gpGlobals->curtime + 0.05; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_WeaponMortar::Redraw() +{ + BaseClass::Redraw(); + + // If the player's dead, abort + C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + if ( pPlayer == NULL ) + return; + if ( pPlayer->GetHealth() < 1 ) + { + m_iFiringState = MORTAR_IDLE; + m_bCarried = true; + return; + } + + // If it's reloading, tell the player + if ( m_bMortarReloading ) + { + int width, height; + messagechars->GetStringLength( m_hFontText, &width, &height, "Mortar is reloading..." ); + messagechars->DrawString( m_hFontText, (ScreenWidth() - width) / 2, YRES(350), 192, 192, 192, 255, "Mortar is reloading...", IMessageChars::MESSAGESTRINGID_NONE ); + return; + } + + // Handle power charging + switch( m_iFiringState ) + { + case MORTAR_IDLE: + m_pPowerBar->m_flPower = 0; + break; + case MORTAR_CHARGING_POWER: + m_pPowerBar->m_flPower = MIN( m_pPowerBar->m_flPower + ( (1.0 / MORTAR_CHARGE_POWER_RATE) * gpGlobals->curtimeDelta), 1.0f); + m_pPowerBar->m_flFiringPower = 0; + m_pPowerBar->m_flFiringAccuracy = 0; + if ( m_pPowerBar->m_flPower >= 1.0 ) + { + // Hit Max, start going down + m_pPowerBar->m_flFiringPower = m_pPowerBar->m_flPower; + m_iFiringState = MORTAR_CHARGING_ACCURACY; + m_flNextClick = gpGlobals->curtime + 0.25; + } + break; + case MORTAR_CHARGING_ACCURACY: + // Calculate accuracy speed + m_flAccuracySpeed = (1.0 / MORTAR_CHARGE_ACCURACY_RATE); + if ( m_pPowerBar->m_flFiringPower > 0.5 ) + { + // Shots over halfway suffer an increased speed to the accuracy power, making accurate shots harder + float flAdjustedPower = (m_pPowerBar->m_flFiringPower - 0.5) * 3.0; + m_flAccuracySpeed += (m_pPowerBar->m_flFiringPower * flAdjustedPower); + } + + m_pPowerBar->m_flPower = MAX( m_pPowerBar->m_flPower - ( m_flAccuracySpeed * gpGlobals->curtimeDelta), -0.25f); + if ( m_pPowerBar->m_flPower <= -0.25 ) + { + // Hit Min, fire mortar + m_pPowerBar->m_flFiringAccuracy = m_pPowerBar->m_flPower; + m_iFiringState = MORTAR_IDLE; + + FireMortar(); + m_flNextClick = gpGlobals->curtime + 0.25; + } + break; + default: + break; + } + + // Draw the rotate icon if the player's rotating the mortar + if ( m_bRotating ) + { + vgui::Panel *pParent = GetClientModeNormal()->GetViewport(); + int parentWidth, parentHeight; + pParent->GetSize(parentWidth, parentHeight); + int iWidth = 64; + int iHeight = 64; + int iX = (parentWidth - iWidth) / 2; + int iY = (parentHeight - 216); + + IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL, m_pRotateIcon ); + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); + + meshBuilder.Color3f( 1.0, 1.0, 1.0 ); + meshBuilder.TexCoord2f( 0,0,0 ); + meshBuilder.Position3f( iX,iY,0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color3f( 1.0, 1.0, 1.0 ); + meshBuilder.TexCoord2f( 0,1,0 ); + meshBuilder.Position3f( iX+iWidth, iY, 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color3f( 1.0, 1.0, 1.0 ); + meshBuilder.TexCoord2f( 0,1,1 ); + meshBuilder.Position3f( iX+iWidth, iY+iHeight, 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color3f( 1.0, 1.0, 1.0 ); + meshBuilder.TexCoord2f( 0,0,1 ); + meshBuilder.Position3f( iX, iY+iHeight, 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.End(); + pMesh->Draw(); + } + + // Update the ground line if it's moved + if ( !m_bCarried && (m_flPrevMortarYaw != m_flMortarYaw ) && + gpGlobals->curtime > m_flLastGroundlineUpdateTime + g_CVMortarGroundLineUpdateInterval.GetFloat() ) + { + // Create the Ground line start & end points + Vector vecForward; + AngleVectors( QAngle( 0, m_flMortarYaw, 0 ), &vecForward ); + Vector vecStart = m_vecMortarOrigin + (vecForward * MORTAR_RANGE_MIN); + + float flRange = MORTAR_RANGE_MAX_INITIAL; + if ( pPlayer->HasNamedTechnology( "mortar_range" ) ) + flRange = MORTAR_RANGE_MAX_UPGRADED; + Vector vecEnd = m_vecMortarOrigin + (vecForward * flRange); + + m_pDarkLine->SetParameters( m_vecMortarOrigin, vecStart, Vector( 0.1,0.1,0.1 ), Vector( 0.1,0.1,0.1 ), 0.5, 22 ); + m_pGroundLine->SetParameters( vecStart, vecEnd, Vector(0,1,0), Vector(1,0,0), 0.5, 22 ); + + m_flPrevMortarYaw = m_flMortarYaw; + + m_flLastGroundlineUpdateTime = gpGlobals->curtime; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Capture mouse input for mortar rotation +//----------------------------------------------------------------------------- +void C_WeaponMortar::OverrideMouseInput( float *x, float *y ) +{ + if ( !m_bRotating ) + return; + + float flX = ( *x ) * 0.05f; + + m_flMortarYaw = anglemod(m_flMortarYaw - flX); + + *x = 0.0f; + *y = 0.0f; +} + +//----------------------------------------------------------------------------- +// Purpose: Weapon's been deployed +//----------------------------------------------------------------------------- +bool C_WeaponMortar::Deploy( void ) +{ + if ( m_pDarkLine ) + { + m_pDarkLine->SetVisible( true ); + } + if ( m_pGroundLine ) + { + m_pGroundLine->SetVisible( true ); + } + + return BaseClass::Deploy(); +} + +//----------------------------------------------------------------------------- +// Purpose: Weapon's been holstered +//----------------------------------------------------------------------------- +bool C_WeaponMortar::Holster( C_BaseCombatWeapon *pSwitchingTo ) +{ + if ( m_pDarkLine ) + { + m_pDarkLine->SetVisible( false ); + } + if ( m_pGroundLine ) + { + m_pGroundLine->SetVisible( false ); + } + + return BaseClass::Holster( pSwitchingTo ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_WeaponMortar::FireMortar( void ) +{ + // Clamp inaccuracy + float flTempAcc = m_pPowerBar->m_flFiringAccuracy; + if ( flTempAcc > 0.25 ) + flTempAcc = 0.25; + else if ( flTempAcc < -0.25 ) + flTempAcc = -0.25; + + // HACKHACK: This is an amazingly bad way to do it. Replace this when the + // client DLL can insert commands into the usercmds + char szbuf[48]; + Q_snprintf( szbuf, sizeof( szbuf ), "mortar %0.2f %0.2f %0.2f\n", m_pPowerBar->m_flFiringPower, flTempAcc, m_flMortarYaw ); + engine->ClientCmd(szbuf); + + // Tell the power bar to reset soon + m_pPowerBar->m_flReset = gpGlobals->curtime + 1.0; +}
\ No newline at end of file diff --git a/game/client/tf2/c_weapon_twohandedcontainer.cpp b/game/client/tf2/c_weapon_twohandedcontainer.cpp new file mode 100644 index 0000000..8ff85c5 --- /dev/null +++ b/game/client/tf2/c_weapon_twohandedcontainer.cpp @@ -0,0 +1,166 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client's Support "weapon" +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "weapon_twohandedcontainer.h" + +//----------------------------------------------------------------------------- +// Purpose: Draws little viewmodel attachments +//----------------------------------------------------------------------------- +void C_WeaponTwoHandedContainer::ViewModelDrawn( C_BaseViewModel *pBaseViewModel ) +{ + BaseClass::ViewModelDrawn( pBaseViewModel ); + + if (pBaseViewModel->ViewModelIndex() != 0) + { + if ( m_hRightWeapon ) + { + m_hRightWeapon->ViewModelDrawn(pBaseViewModel); + } + } + else + { + if ( m_hLeftWeapon ) + { + m_hLeftWeapon->ViewModelDrawn(pBaseViewModel); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_WeaponTwoHandedContainer::OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, + const QAngle& angles, int event, const char *options ) +{ + bool bRight = m_hRightWeapon->OnFireEvent( pViewModel, origin, angles, event, options ); + bool bLeft = m_hLeftWeapon->OnFireEvent( pViewModel, origin, angles, event, options ); + + return ( bRight || bLeft ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_WeaponTwoHandedContainer::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + // Did we just receive a new weapon? + bool rightchanged = m_hOldRightWeapon.Get() != m_hRightWeapon.Get() ? true : false; + bool leftchanged = m_hOldLeftWeapon.Get() != m_hLeftWeapon.Get() ? true : false; + + if ( rightchanged || leftchanged ) + { + /* + // Tell weapons that they're being holstered + if ( m_hRightWeapon != NULL && rightchanged ) + { + m_hRightWeapon->Holster( NULL ); + } + if ( m_hLeftWeapon != NULL && leftchanged ) + { + m_hLeftWeapon->Holster( NULL ); + } + */ + + HookWeaponEntities(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_WeaponTwoHandedContainer::HookWeaponEntities( void ) +{ + m_hOldRightWeapon = m_hRightWeapon; + m_hOldLeftWeapon = m_hLeftWeapon; +} + +//----------------------------------------------------------------------------- +// Purpose: Never draw the container +//----------------------------------------------------------------------------- +bool C_WeaponTwoHandedContainer::ShouldDraw( void ) +{ + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: This weapon is the active weapon, and it should now draw anything +// it wants to. This gets called every frame. +//----------------------------------------------------------------------------- +void C_WeaponTwoHandedContainer::Redraw() +{ + BaseClass::Redraw(); + + if ( m_hRightWeapon.Get() ) + { + m_hRightWeapon->Redraw(); + } + if ( m_hLeftWeapon.Get() ) + { + m_hLeftWeapon->Redraw(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Draw both weapon's ammo's +//----------------------------------------------------------------------------- +void C_WeaponTwoHandedContainer::DrawAmmo() +{ + // Just tell our active weapon to draw it's ammo, since our offhand doesn't use it + if ( m_hLeftWeapon ) + { + m_hLeftWeapon->DrawAmmo(); + } + if ( m_hRightWeapon.Get() ) + { + m_hRightWeapon->DrawAmmo(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Let each weapon handle input +//----------------------------------------------------------------------------- +void C_WeaponTwoHandedContainer::HandleInput( void ) +{ + BaseClass::HandleInput(); + + if ( m_hRightWeapon ) + { + m_hRightWeapon->HandleInput(); + } + if ( m_hLeftWeapon ) + { + m_hLeftWeapon->HandleInput(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Let each weapon handle input +//----------------------------------------------------------------------------- +void C_WeaponTwoHandedContainer::OverrideMouseInput( float *x, float *y ) +{ + BaseClass::OverrideMouseInput( x,y ); + + if ( m_hRightWeapon ) + { + m_hRightWeapon->OverrideMouseInput( x,y ); + } + if ( m_hLeftWeapon ) + { + m_hLeftWeapon->OverrideMouseInput( x,y ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool C_WeaponTwoHandedContainer::VisibleInWeaponSelection( void ) +{ + return false; +} diff --git a/game/client/tf2/clientmode_commander.cpp b/game/client/tf2/clientmode_commander.cpp new file mode 100644 index 0000000..64fb9b7 --- /dev/null +++ b/game/client/tf2/clientmode_commander.cpp @@ -0,0 +1,725 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//===========================================================================// +#include "cbase.h" +#include "hud_chat.h" +#include "clientmode_commander.h" +#include "vgui_int.h" +#include "ivmodemanager.h" +#include "iinput.h" +#include "kbutton.h" +#include "usercmd.h" +#include "c_basetfplayer.h" +#include "view_shared.h" +#include "in_main.h" +#include "commanderoverlaypanel.h" +#include "iviewrender.h" +#include <vgui/IInput.h> +#include <vgui/IPanel.h> + + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +enum +{ + VISIBLE_STATIC_PROP_HEIGHT = 7500 +}; + +extern Vector g_vecRenderOrigin; +extern QAngle g_vecRenderAngles; + +static ConVar Commander_SlueSpeed( "commander_speed", "800.0", 0 ); +static ConVar Commander_MouseSpeed( "commander_mousespeed", "200.0", 0 ); +static ConVar Commander_RightMoveSpeedScale( "commander_rightmovespeedscale", "2.0", 0 ); +static ConVar Commander_InvertMouse( "commander_invertmouse", "1.0", 0 ); + +// Public version of the commander mode; +IClientMode *ClientModeCommander() +{ + // TF2 Commander View Mode + static CClientModeCommander g_ClientModeCommander; + return &g_ClientModeCommander; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *commander - +//----------------------------------------------------------------------------- +void CCommanderViewportPanel::SetCommanderView( CClientModeCommander *commander ) +{ + m_pCommanderView = commander; + + if ( m_pOverlayPanel ) + { + m_pOverlayPanel->SetCommanderView( m_pCommanderView ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : CCommanderOverlayPanel +//----------------------------------------------------------------------------- +CCommanderOverlayPanel *CCommanderViewportPanel::GetCommanderOverlayPanel( void ) +{ + return m_pOverlayPanel; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CCommanderViewportPanel::CCommanderViewportPanel( void ) : + m_CursorCommander( vgui::dc_arrow ), + m_CursorRightMouseMove(vgui::dc_hand) +{ + m_pOverlayPanel = new CCommanderOverlayPanel(); + m_pOverlayPanel->SetParent( this ); + + SetPaintEnabled( false ); + SetPaintBorderEnabled( false ); + SetPaintBackgroundEnabled( false ); + + SetCursor( m_CursorCommander ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CCommanderViewportPanel::~CCommanderViewportPanel( void ) +{ +} + +//----------------------------------------------------------------------------- +// call these when commander view is enabled/disabled +//----------------------------------------------------------------------------- + + +void CCommanderViewportPanel::Enable() +{ + vgui::VPANEL pRoot = VGui_GetClientDLLRootPanel(); + + SetCursor(m_CursorCommander); + vgui::surface()->SetCursor( m_CursorCommander ); + + // Make the viewport fill the root panel. + if ( pRoot) + { + int wide, tall; + vgui::ipanel()->GetSize(pRoot, wide, tall); + SetBounds(0, 0, wide, tall); + } + + C_BaseEntity *ent = cl_entitylist->GetEnt( 0 ); + + if ( m_pOverlayPanel && ent ) + { + m_pOverlayPanel->Enable(); + } + + SetVisible( true ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCommanderViewportPanel::Disable() +{ + if ( m_pOverlayPanel ) + { + m_pOverlayPanel->Disable(); + } + + SetVisible( false ); +} + +void CCommanderViewportPanel::MinimapClicked( const Vector& clickWorldPos ) +{ + // Don't use Z... our current z is what we want + Vector actualOrigin, offset; + VectorCopy( clickWorldPos, actualOrigin ); + actualOrigin.z = m_pOverlayPanel->TacticalOrigin().z; + + m_pOverlayPanel->ActualToVisibleOffset( offset ); + VectorSubtract( actualOrigin, offset, actualOrigin ); + m_pOverlayPanel->BoundOrigin( actualOrigin ); + m_pOverlayPanel->TacticalOrigin() = actualOrigin; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CClientModeCommander::CClientModeCommander() : BaseClass() +{ + m_pClear = NULL; + m_pSkyBox = NULL; + m_ScaledSlueSpeed = 10; + m_Log_BaseEto2 = 1.4427f; // factor to convert from a logarithm of base E to base 2. + + m_pViewport = new CCommanderViewportPanel; + GetCommanderViewport()->SetCommanderView( this ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CClientModeCommander::~CClientModeCommander() +{ + +} + +CCommanderViewportPanel *CClientModeCommander::GetCommanderViewport() +{ + Assert( m_pViewport ); + return static_cast< CCommanderViewportPanel * >( m_pViewport ); +} + +//----------------------------------------------------------------------------- +// Purpose: Called once at dll load time +//----------------------------------------------------------------------------- +void CClientModeCommander::Init( void ) +{ + BaseClass::Init(); + GetCommanderViewport()->RequestFocus(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : vgui::Panel +//----------------------------------------------------------------------------- +vgui::Panel *CClientModeCommander::GetMinimapParent( void ) +{ + return GetCommanderOverlayPanel(); +} + +//----------------------------------------------------------------------------- +// Inherited from IMinimapClient +//----------------------------------------------------------------------------- +void CClientModeCommander::MinimapClicked( const Vector& clickWorldPos ) +{ + if ( GetCommanderViewport() ) + { + GetCommanderViewport()->MinimapClicked( clickWorldPos ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CCommanderOverlayPanel *CClientModeCommander::GetCommanderOverlayPanel( void ) +{ + if ( GetCommanderViewport() ) + { + return GetCommanderViewport()->GetCommanderOverlayPanel(); + } + return NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +void CClientModeCommander::Enable() +{ + // HACK: Find a better place for these + m_pClear = (ConVar *)cvar->FindVar( "gl_clear" ); + m_pSkyBox = (ConVar *)cvar->FindVar( "r_drawskybox" ); + + HudCommanderOverlayMgr()->Enable( true ); + + BaseClass::Enable(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CClientModeCommander::Disable() +{ + BaseClass::Disable(); + + ::input->ResetMouse(); + + HudCommanderOverlayMgr()->Enable( false ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +void CClientModeCommander::Update() +{ + if ( !engine->IsInGame() ) + { + // Disable commander view + modemanager->SwitchMode( false, false ); + return; + } + + ClientModeTFBase::Update(); + + Vector mins, maxs; + GetCommanderViewport()->GetCommanderOverlayPanel()->GetVisibleArea( mins, maxs ); + MapData().SetVisibleArea( mins, maxs ); + + HudCommanderOverlayMgr()->Tick( ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CClientModeCommander::Layout() +{ + BaseClass::Layout(); + + // Force it to recompute it's boundaries + GetCommanderViewport()->GetCommanderOverlayPanel()->Disable(); + GetCommanderViewport()->GetCommanderOverlayPanel()->Enable(); +} + +//----------------------------------------------------------------------------- +// Purpose: The mode can choose to not draw fog +//----------------------------------------------------------------------------- +bool CClientModeCommander::ShouldDrawFog( void ) +{ + return false; +} + + +//----------------------------------------------------------------------------- +// Purpose: Checks map bounds and determines ideal height for tactical view +// Input : fov - +// zoom - +// Output : float +//----------------------------------------------------------------------------- +float CClientModeCommander::GetHeightForMap( float zoom ) +{ + Vector mins, maxs; + MapData().GetMapBounds( mins, maxs ); + return maxs.z + TACTICAL_ZOFFSET; +} + + +bool CClientModeCommander::GetOrthoParameters(CViewSetup *pSetup) +{ + Vector vCenter; + float xSize, ySize; + GetCommanderViewport()->GetCommanderOverlayPanel()->GetOrthoRenderBox(vCenter, xSize, ySize); + + pSetup->m_bOrtho = true; + pSetup->m_OrthoLeft = -xSize; + pSetup->m_OrthoTop = -ySize; + pSetup->m_OrthoRight = xSize; + pSetup->m_OrthoBottom = ySize; + + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *angles - +//----------------------------------------------------------------------------- +void CClientModeCommander::OverrideView( CViewSetup *pSetup ) +{ + // Turn off vis when in commander mode + view->DisableVis(); + VectorCopy( GetCommanderViewport()->GetCommanderOverlayPanel()->TacticalAngles(), pSetup->angles ); + VectorCopy( GetCommanderViewport()->GetCommanderOverlayPanel()->TacticalOrigin(), pSetup->origin ); +} + +//----------------------------------------------------------------------------- +// Purpose: Scale commander slue speed based on viewport zoom factor +// Output : float +//----------------------------------------------------------------------------- +float CClientModeCommander::GetScaledSlueSpeed( void ) +{ + return m_ScaledSlueSpeed; +} + +//----------------------------------------------------------------------------- +// Purpose: Convert move to scaled move +// Input : in - +// Output : float +//----------------------------------------------------------------------------- +float CClientModeCommander::Commander_ResampleMove( float in ) +{ + float sign; + float move; + + if ( !in ) + return 0.0; + + sign = in > 0.0 ? 1.0 : -1.0; + + move = GetScaledSlueSpeed(); + + return move * sign; +} + +//----------------------------------------------------------------------------- +// Purpose: Zero out any movement in the command +// Input : *cmd - +//----------------------------------------------------------------------------- +void CClientModeCommander::ResetCommand( CUserCmd *cmd ) +{ + cmd->buttons = 0; + cmd->forwardmove = 0; + cmd->sidemove = 0; + cmd->upmove = 0; + cmd->viewangles.Init(); +} + +//----------------------------------------------------------------------------- +// Purpose: TF2 commander mode movement logic +//----------------------------------------------------------------------------- +void CClientModeCommander::IsometricMove( CUserCmd *cmd ) +{ + int i; + Vector wishvel; + float fmove, smove; + Vector forward, right, up; + + AngleVectors ( cmd->viewangles, &forward, &right, &up); // Determine movement angles + + // Copy movement amounts + fmove = cmd->forwardmove; + smove = cmd->sidemove; + + // No up / down movement + forward.Init(1, 0, 0); + right.Init(0, -1, 0); + + wishvel.Init(); + + // Determine x and y parts of velocity + for (i=0; i < 3; i++) + { + wishvel[i] = forward[i]*fmove + right[i]*smove; + } + + GetCommanderViewport()->GetCommanderOverlayPanel()->TacticalOrigin() += TICK_INTERVAL * wishvel; + GetCommanderViewport()->GetCommanderOverlayPanel()->BoundOrigin( GetCommanderViewport()->GetCommanderOverlayPanel()->TacticalOrigin() ); +} + +#define WINDOWED_KEEPMOVING_PIXELS 300 +//----------------------------------------------------------------------------- +// Purpose: +// Input : frametime - +// *cmd - +//----------------------------------------------------------------------------- +void CClientModeCommander::CreateMove( float flInputSampleTime, CUserCmd *cmd ) +{ + int mx, my; + int realx, realy; + //int sidex, sidey; + + cmd->upmove = 0; + + // Figure out the speed scale so their perceptual movement speed stays the same. + m_ScaledSlueSpeed = Commander_SlueSpeed.GetFloat() * GetCommanderViewport()->GetCommanderOverlayPanel()->WorldUnitsPerPixel(); + m_ScaledMouseSpeed = Commander_MouseSpeed.GetFloat() * GetCommanderViewport()->GetCommanderOverlayPanel()->WorldUnitsPerPixel(); + + // Translate WASD while in commander mode... + float temp = cmd->forwardmove; + // Swap forward/right + cmd->forwardmove = cmd->sidemove; + // Invert right/left + cmd->sidemove = -temp; + + // Normalize nonzero inputs to scaled speed + if ( cmd->forwardmove ) + { + cmd->forwardmove = ( cmd->forwardmove > 0 ) ? GetScaledSlueSpeed() : -GetScaledSlueSpeed(); + } + if ( cmd->sidemove ) + { + cmd->sidemove = ( cmd->sidemove > 0 ) ? GetScaledSlueSpeed() : -GetScaledSlueSpeed(); + } + + // Sample mouse + ::input->GetFullscreenMousePos( &mx, &my, &realx, &realy ); + + if( GetCommanderViewport()->GetCommanderOverlayPanel()->IsRightMouseMapMoving() || ( in_commandermousemove.state & 1 ) ) + { + cmd->forwardmove = m_ScaledMouseSpeed * (mx - m_LastMouseX); + cmd->sidemove = m_ScaledMouseSpeed * (my - m_LastMouseY); + + if ( Commander_InvertMouse.GetInt() ) + { + cmd->forwardmove *= -1.0f; + cmd->sidemove *= -1.0f; + } + + //input->SetFullscreenMousePos( m_LastMouseX, m_LastMouseY ); + mx = m_LastMouseX; + my = m_LastMouseY; + } + /* + else if ( input->IsFullscreenMouse() ) + { + if ( abs( realx - mx ) < WINDOWED_KEEPMOVING_PIXELS && + abs( realy - my ) < WINDOWED_KEEPMOVING_PIXELS ) + { + sidex = 2; + sidey = 2; + + // Check Size of viewport + if ( mx < sidex ) + { + cmd->forwardmove = -GetScaledSlueSpeed(); + } + else if ( mx > ( ScreenWidth() - sidex )) + { + cmd->forwardmove = GetScaledSlueSpeed(); + } + + if ( my < sidey ) + { + cmd->sidemove = -GetScaledSlueSpeed(); + } + else if ( my > ( ScreenHeight() - sidey ) ) + { + cmd->sidemove = GetScaledSlueSpeed(); + } + } + } + */ + + m_LastMouseX = mx; + m_LastMouseY = my; + + // Look straight down + cmd->viewangles.x = 90; // 45; + cmd->viewangles.y = 90; //45fmod( 3.0* 360 * (gpGlobals->curtime * 0.01), 360 ); + cmd->viewangles.z = 0; + + GetCommanderViewport()->GetCommanderOverlayPanel()->TacticalAngles() = cmd->viewangles; + + IsometricMove( cmd ); + + // Reset command + ResetCommand( cmd ); +} + +//----------------------------------------------------------------------------- +// Purpose: Makes sure the mouse is over the same world position as it started +//----------------------------------------------------------------------------- + +void CClientModeCommander::MoveMouse( Vector& worldPos ) +{ + Vector worldCenter; + float wworld, hworld; + GetCommanderViewport()->GetCommanderOverlayPanel()->GetOrthoRenderBox(worldCenter, wworld, hworld); + wworld *= 2; hworld *= 2; + + Vector worldDelta; + VectorSubtract( worldPos, worldCenter, worldDelta ); + + int w, h; + GetCommanderViewport()->GetSize( w, h ); + + int mx, my; + mx = (worldDelta.x / wworld + 0.5f) * w; + my = (0.5f - worldDelta.y / hworld) * h; + + // Clamp + if (mx < 0) mx = 0; else if (mx > w) mx = w; + if (my < 0) my = 0; else if (my > h) my = h; + + //input->SetFullscreenMousePos( mx, my ); + + m_LastMouseX = mx; + m_LastMouseY = my; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *newmap - +//----------------------------------------------------------------------------- +void CClientModeCommander::LevelInit( const char *newmap ) +{ + BaseClass::LevelInit( newmap ); + + HudCommanderOverlayMgr()->LevelShutdown(); + MapData().LevelInit( newmap ); + GetCommanderViewport()->GetCommanderOverlayPanel()->LevelInit( newmap ); + HudCommanderOverlayMgr()->LevelInit( ); + + GetCommanderViewport()->Enable(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CClientModeCommander::LevelShutdown( void ) +{ + GetCommanderViewport()->Disable(); + + MapData().LevelShutdown(); + + HudCommanderOverlayMgr()->LevelShutdown(); + + GetCommanderViewport()->GetCommanderOverlayPanel()->LevelShutdown(); + + BaseClass::LevelShutdown(); +} + +//----------------------------------------------------------------------------- +// returns the viewport panel +//----------------------------------------------------------------------------- +vgui::Panel *CClientModeCommander::GetViewport() +{ + return m_pViewport; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CClientModeCommander::ShouldDrawEntity(C_BaseEntity *pEnt) +{ + return MapData().IsEntityVisibleToTactical(pEnt); +} + +bool CClientModeCommander::ShouldDrawDetailObjects( ) +{ + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Always draw the local player while in commander mode +//----------------------------------------------------------------------------- +bool CClientModeCommander::ShouldDrawLocalPlayer( C_BasePlayer *pPlayer ) +{ + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CClientModeCommander::ShouldDrawViewModel( void ) +{ + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Return false to disable crosshair +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CClientModeCommander::ShouldDrawCrosshair( void ) +{ + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Adjust engine rendering viewport rectangle if needed +// Input : x - +// y - +// width - +// height - +//----------------------------------------------------------------------------- +void CClientModeCommander::AdjustEngineViewport( int& x, int& y, int& width, int& height ) +{ +} + + +//----------------------------------------------------------------------------- +// Should I draw particles +//----------------------------------------------------------------------------- + +bool CClientModeCommander::ShouldDrawParticles( ) +{ + Vector vCenter; + float xSize, ySize; + GetCommanderViewport()->GetCommanderOverlayPanel()->GetOrthoRenderBox(vCenter, xSize, ySize); + + // Activate/deactivate particles rendering based on zoom level + float maxSize = MAX( xSize, ySize ); + return (maxSize < VISIBLE_STATIC_PROP_HEIGHT); +} + + +//----------------------------------------------------------------------------- +// Purpose: When in commander mode, force gl_clear and don't draw the skybox +//----------------------------------------------------------------------------- + +void CClientModeCommander::PreRender( CViewSetup *pSetup ) +{ + if ( !m_pClear || !m_pSkyBox ) + return; + + m_fOldClear = m_pClear->GetFloat(); + m_pClear->SetValue( 1.0f ); + pSetup->clearColor = !!m_pClear->GetInt(); + + m_fOldSkybox = m_pSkyBox->GetFloat(); + m_pSkyBox->SetValue( 0.0f ); + + GetOrthoParameters(pSetup); + render->DrawTopView( true ); + Vector2D mins = pSetup->origin.AsVector2D(); + Vector2D maxs = pSetup->origin.AsVector2D(); + mins.x += pSetup->m_OrthoLeft; + maxs.x += pSetup->m_OrthoRight; + mins.y += pSetup->m_OrthoTop; + maxs.y += pSetup->m_OrthoBottom; + render->TopViewBounds( mins, maxs ); + + // Activate/deactivate static prop + particles rendering based on zoom level + Vector2D size; + Vector2DSubtract( maxs, mins, size ); + float maxSize = MAX( size.x, size.y ); + bool showStaticProps = (maxSize < VISIBLE_STATIC_PROP_HEIGHT); + ClientLeafSystem()->DrawStaticProps(showStaticProps); + ClientLeafSystem()->DrawSmallEntities(showStaticProps); + + BaseClass::PreRender(pSetup); +} + +void CClientModeCommander::PostRenderWorld() +{ + render->DrawTopView( false ); + ClientLeafSystem()->DrawStaticProps(true); + ClientLeafSystem()->DrawSmallEntities(true); +} + +//----------------------------------------------------------------------------- +// Purpose: Restore cvar values +//----------------------------------------------------------------------------- +void CClientModeCommander::PostRender( void ) +{ + if ( !m_pClear || !m_pSkyBox ) + return; + + m_pClear->SetValue( m_fOldClear ); + m_pSkyBox->SetValue( m_fOldSkybox ); + + BaseClass::PostRender(); +} + +//----------------------------------------------------------------------------- +// Purpose: Swallow mouse wheel when in this view +// Input : down - +// keynum - +// *pszCurrentBinding - +// Output : int +//----------------------------------------------------------------------------- +int CClientModeCommander::KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ) +{ + switch ( keynum ) + { + case MOUSE_WHEEL_UP: + case MOUSE_WHEEL_DOWN: + // Swallow + return 0; + } + + // Allow engine to process + return BaseClass::KeyInput( down, keynum, pszCurrentBinding ); +} + diff --git a/game/client/tf2/clientmode_commander.h b/game/client/tf2/clientmode_commander.h new file mode 100644 index 0000000..871dd0c --- /dev/null +++ b/game/client/tf2/clientmode_commander.h @@ -0,0 +1,146 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( CLIENTMODE_COMMANDER_H ) +#define CLIENTMODE_COMMANDER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "clientmode_tfbase.h" +#include <vgui/Cursor.h> +#include "hud_minimap.h" +#include <vgui_controls/Panel.h> + +class IMaterial; +class CCommanderViewportPanel; +class Vector; +class CCommanderOverlayPanel; +namespace vgui +{ + class Panel; + class AnimationController; +} + +class CClientModeCommander : public ClientModeTFBase, public IMinimapClient +{ + DECLARE_CLASS( CClientModeCommander, ClientModeTFBase ); + +// IClientMode overrides. +public: + + CClientModeCommander(); + virtual ~CClientModeCommander(); + + virtual void Init( void ); + + virtual void Enable(); + virtual void Disable(); + + virtual void Update(); + virtual void Layout(); + + virtual bool ShouldDrawFog( void ); + virtual void OverrideView( CViewSetup *pSetup ); + virtual void CreateMove( float flInputSampleTime, CUserCmd *cmd ); + virtual void LevelInit( const char *newmap ); + virtual void LevelShutdown( void ); + virtual bool ShouldDrawEntity(C_BaseEntity *pEnt); + virtual bool ShouldDrawDetailObjects( ); + virtual bool ShouldDrawLocalPlayer( C_BasePlayer *pPlayer ); + virtual bool ShouldDrawViewModel( void ); + virtual bool ShouldDrawCrosshair( void ); + virtual bool ShouldDrawParticles( ); + + virtual void AdjustEngineViewport( int& x, int& y, int& width, int& height ); + virtual void PreRender( CViewSetup *pSetup ); + virtual void PostRenderWorld(); + virtual void PostRender( void ); + virtual vgui::Panel *GetViewport(); + virtual vgui::AnimationController *GetViewportAnimationController() { return NULL; } + + // Input + virtual int KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ); + + // Makes the mouse sit over a particular world location + void MoveMouse( Vector& worldPos ); + + // Inherited from IMinimapClient + virtual void MinimapClicked( const Vector& clickWorldPos ); + + CCommanderOverlayPanel *GetCommanderOverlayPanel( void ); + + virtual vgui::Panel *GetMinimapParent( void ); + +private: + float GetScaledSlueSpeed( void ); + void ResetCommand( CUserCmd *cmd ); + float Commander_ResampleMove( float in ); + void IsometricMove( CUserCmd *cmd ); + float GetHeightForMap( float zoom ); + + // Fills in ortho parameters (and near/far Z) in pSetup for how the commander mode renders the world. + bool GetOrthoParameters(CViewSetup *pSetup); + + CCommanderViewportPanel *GetCommanderViewport(); + +private: + + ConVar* m_pClear; + ConVar* m_pSkyBox; + float m_fOldClear; + float m_fOldSkybox; + + int m_LastMouseX; + int m_LastMouseY; + + float m_ScaledMouseSpeed; + float m_ScaledSlueSpeed; + float m_Log_BaseEto2; // scales logarithms from base E to base 2. +}; + + +//----------------------------------------------------------------------------- +// The panel responsible for rendering the 3D view in orthographic mode +//----------------------------------------------------------------------------- +class CCommanderViewportPanel : public CBaseViewport +{ + typedef CBaseViewport BaseClass; + +// Panel overrides. +public: + CCommanderViewportPanel( void ); + virtual ~CCommanderViewportPanel( void ); + + void Enable( void ); + void Disable( void ); + void SetCommanderView( CClientModeCommander *commander ); + void MinimapClicked( const Vector& clickWorldPos ); + + CCommanderOverlayPanel *GetCommanderOverlayPanel( void ); + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ) + { + BaseClass::ApplySchemeSettings( pScheme ); + + gHUD.InitColors( pScheme ); + } + +private: + + CCommanderOverlayPanel *m_pOverlayPanel; + CClientModeCommander *m_pCommanderView; + + vgui::HCursor m_CursorCommander; + vgui::HCursor m_CursorRightMouseMove; + +}; + +IClientMode *ClientModeCommander(); + +#endif // CLIENTMODE_COMMANDER_H
\ No newline at end of file diff --git a/game/client/tf2/clientmode_tfbase.cpp b/game/client/tf2/clientmode_tfbase.cpp new file mode 100644 index 0000000..e702129 --- /dev/null +++ b/game/client/tf2/clientmode_tfbase.cpp @@ -0,0 +1,223 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// +#include "cbase.h" +#include "clientmode_tfbase.h" +#include "hud.h" +#include "c_tf_basecombatweapon.h" +#include "keydefs.h" +#include "c_tf_hintmanager.h" +#include <vgui_controls/Controls.h> +#include <vgui/IScheme.h> +#include "filesystem.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +CMinimapPanel *ClientModeTFBase::m_pMinimap = NULL; +vgui::HScheme g_hVGuiObjectScheme = 0; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +ClientModeTFBase::ClientModeTFBase( void ) +{ + m_bInitialized = false; + + m_pCVDrawFullSkybox = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +ClientModeTFBase::~ClientModeTFBase( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : CMinimapPanel +//----------------------------------------------------------------------------- +CMinimapPanel *ClientModeTFBase::GetMinimap( void ) +{ + return m_pMinimap; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +// FIXME: Remove if this ever becomes true for HL2 (I expect it will) +ConVar r_radiosity ( "r_radiosity", "2" ); // do full radiosity calc? +// FIXME: Remove when we reactivate detail props +extern ConVar r_DrawDetailProps; + +void ClientModeTFBase::Init() +{ + BaseClass::Init(); + C_BaseTFCombatWeapon::CreateCrosshairPanels(); + + // FIXME: For playtests, turn off detail props. They're causing perf problems + r_DrawDetailProps.SetValue("0"); + + // Turn lighting into a mode where we use better computation for the ambient + // cube on static props, and a cheap one for dynamic entities. + r_radiosity.SetValue("3"); + + if ( !m_pMinimap ) + { + m_pMinimap = GET_HUDELEMENT( CMinimapPanel ); + } + + // Load up the object control panel scheme + g_hVGuiObjectScheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ObjectControlPanelScheme.res", "TFBase" ); + if (!g_hVGuiObjectScheme) + { + Warning( "Couldn't load control panel scheme!\n" ); + } + + // Load the objects.txt file. + LoadObjectInfos( ::filesystem ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void ClientModeTFBase::Shutdown() +{ + C_BaseTFCombatWeapon::DestroyCrosshairPanels(); + BaseClass::Shutdown(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void ClientModeTFBase::Enable( void ) +{ + BaseClass::Enable(); + + // Hook the minimap traces into the minimap + if ( GetMinimap() ) + { + GetMinimap()->Activate(); + } +} + +void ClientModeTFBase::LevelInit( const char *newmap ) +{ + BaseClass::LevelInit( newmap ); + + // Tell the radar to load the radar's overlay map + //g_Radar.LoadMap( newmap ); + if ( GetMinimap() ) + { + GetMinimap()->LevelInit( newmap ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void ClientModeTFBase::LevelShutdown( void ) +{ + BaseClass::LevelShutdown(); + + if ( GetMinimap() ) + { + GetMinimap()->LevelShutdown(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pSetup - +//----------------------------------------------------------------------------- +void ClientModeTFBase::PreRender( CViewSetup *pSetup ) +{ + Initialize(); + + if ( !m_pCVDrawFullSkybox ) + { + assert( 0 ); + return; + } + + m_flOldDrawFullSkybox = m_pCVDrawFullSkybox->GetFloat(); + + m_pCVDrawFullSkybox->SetValue( 1 ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void ClientModeTFBase::PostRender( void ) +{ + C_BaseTFPlayer *pl = C_BaseTFPlayer::GetLocalPlayer(); + if ( pl ) + { + pl->UpdateTargetReticles(); + } + + if ( !m_pCVDrawFullSkybox ) + { + assert( 0 ); + return; + } + + m_pCVDrawFullSkybox->SetValue( m_flOldDrawFullSkybox ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void ClientModeTFBase::Initialize( void ) +{ + if ( m_bInitialized ) + return; + m_bInitialized = true; + + m_pCVDrawFullSkybox = (ConVar *)cvar->FindVar( "r_drawfullskybox" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void ClientModeTFBase::Update( void ) +{ + BaseClass::Update(); + + MapData().Update(); +} + +//----------------------------------------------------------------------------- +// Purpose: We've received a keypress from the engine. Return 1 if the engine is allowed to handle it. +//----------------------------------------------------------------------------- +int ClientModeTFBase::KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ) +{ + if ( engine->Con_IsVisible() == false ) + { + // Let hint system snag first escape key release + if ( down && ( keynum == KEY_ENTER ) && HintSystemEscapeKey() ) + { + return 0; + } + + // Has the player hit one of his Order keys? + if ( pszCurrentBinding && strncmp( pszCurrentBinding, "order", 5 ) == 0 ) + { + if ( down ) + { + //int iOrderNumber = (pszCurrentBinding[6] - '0') - 1; + //GetHudOrderList()->SelectOrder( iOrderNumber ); + } + return 0; + } + } + + return BaseClass::KeyInput( down, keynum, pszCurrentBinding ); +} + diff --git a/game/client/tf2/clientmode_tfbase.h b/game/client/tf2/clientmode_tfbase.h new file mode 100644 index 0000000..f0f5c2a --- /dev/null +++ b/game/client/tf2/clientmode_tfbase.h @@ -0,0 +1,68 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CLIENTMODE_TFBASE_H +#define CLIENTMODE_TFBASE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "clientmode_shared.h" + +class ConVar; +class CMinimapPanel; + +namespace vgui +{ + typedef unsigned long HScheme; +} + + +// This class defines the base clientmode behavior in TF. Classes that derive from +// it and override functions should forward them to the base class. +class ClientModeTFBase : public ClientModeShared +{ + DECLARE_CLASS( ClientModeTFBase, ClientModeShared ); +public: + ClientModeTFBase( void ); + virtual ~ClientModeTFBase( void ); + + virtual void Init(); + virtual void Shutdown(); + + virtual void Enable(); + + virtual void PreRender( CViewSetup *pSetup ); + virtual void PostRender(); + virtual void Update(); + + virtual void LevelInit( const char *newmap ); + virtual void LevelShutdown( void ); + + // Input + virtual int KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ); + + virtual CMinimapPanel *GetMinimap( void ); + + virtual vgui::Panel *GetMinimapParent( void ) = 0; + +private: + void Initialize( void ); + + bool m_bInitialized; + + ConVar *m_pCVDrawFullSkybox; + + float m_flOldDrawFullSkybox; + + static CMinimapPanel *m_pMinimap; +}; + + +extern vgui::HScheme g_hVGuiObjectScheme; + +#endif // CLIENTMODE_TFBASE_H diff --git a/game/client/tf2/clientmode_tfnormal.cpp b/game/client/tf2/clientmode_tfnormal.cpp new file mode 100644 index 0000000..f766e4e --- /dev/null +++ b/game/client/tf2/clientmode_tfnormal.cpp @@ -0,0 +1,173 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Normal HUD mode +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud_chat.h" +#include "clientmode_tfnormal.h" +#include "clientmode.h" +#include "hud.h" +#include "iinput.h" +#include "c_basetfplayer.h" +#include "hud_timer.h" +#include "usercmd.h" +#include "in_buttons.h" +#include "c_tf_playerclass.h" +#include "engine/IEngineSound.h" +#include <vgui/IInput.h> +#include <vgui/IPanel.h> +#include <vgui_controls/AnimationController.h> + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +//----------------------------------------------------------------------------- +// Purpose: Instance the singleton and expose the interface to it. +// Output : IClientMode +//----------------------------------------------------------------------------- +IClientMode *GetClientModeNormal( void ) +{ + static ClientModeTFNormal g_ClientModeNormal; + return &g_ClientModeNormal; +} + +ClientModeTFNormal::ClientModeTFNormal() +{ + m_pViewport = new Viewport(); + m_pViewport->Start( gameuifuncs, gameeventmanager ); +} + +ClientModeTFNormal::Viewport::Viewport() +{ + // use a custom scheme for the hud + m_bHumanScheme = true; + vgui::HScheme scheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ClientSchemeHuman.res", "HudScheme"); + SetScheme(scheme); +} + +void ClientModeTFNormal::Viewport::OnThink() +{ + BaseClass::OnThink(); + + // See if scheme should change + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if(!pPlayer) + return; + int team = pPlayer->GetTeamNumber(); + if ( !team ) + return; + + bool human = ( team == TEAM_HUMANS ) ? true : false; + if ( human != m_bHumanScheme ) + { + ReloadScheme(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void ClientModeTFNormal::Viewport::ReloadScheme() +{ + // See if scheme should change + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + + if(!pPlayer) + return; + + const char *schemeFile = NULL; + + int team = pPlayer->GetTeamNumber(); + if ( team ) + { + m_bHumanScheme = ( team == TEAM_HUMANS ) ? true : false; + + if ( m_bHumanScheme ) + { + schemeFile = "resource/ClientSchemeHuman.res"; + } + else + { + schemeFile = "resource/ClientSchemeAlien.res"; + } + } + +// BaseClass::ReloadScheme( schemeFile ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : vgui::Panel +//----------------------------------------------------------------------------- +vgui::Panel *ClientModeTFNormal::GetMinimapParent( void ) +{ + return GetViewport(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void ClientModeTFNormal::Update() +{ + BaseClass::Update(); + HudCommanderOverlayMgr()->Tick( ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : frametime - +// *cmd - +//----------------------------------------------------------------------------- +void ClientModeTFNormal::CreateMove( float flInputSampleTime, CUserCmd *cmd ) +{ + // Let the player override the view. + C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + if(!pPlayer) + return; + + // Let the player at it + pPlayer->CreateMove( flInputSampleTime, cmd ); + + // Handle knockdowns + if ( pPlayer->CheckKnockdownAngleOverride() ) + { + QAngle ang; + pPlayer->GetKnockdownAngles( ang ); + + cmd->viewangles = ang; + engine->SetViewAngles( ang ); + + cmd->forwardmove = cmd->sidemove = cmd->upmove = 0; + // Only keep score if it's down + cmd->buttons &= ( IN_SCORE ); + } + + if ( pPlayer->GetPlayerClass() ) + { + C_PlayerClass *pPlayerClass = pPlayer->GetPlayerClass(); + pPlayerClass->CreateMove( flInputSampleTime, cmd ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool ClientModeTFNormal::ShouldDrawViewModel( void ) +{ + C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + if(!pPlayer) + return false; + + return pPlayer->ShouldDrawViewModel(); +} + + + + + diff --git a/game/client/tf2/clientmode_tfnormal.h b/game/client/tf2/clientmode_tfnormal.h new file mode 100644 index 0000000..a2b4a34 --- /dev/null +++ b/game/client/tf2/clientmode_tfnormal.h @@ -0,0 +1,64 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#include <vgui/Cursor.h> +#include "clientmode_tfbase.h" +#include <vgui_controls/EditablePanel.h> + +namespace vgui +{ + class AnimationController; +} + + +class ClientModeTFNormal : public ClientModeTFBase +{ +DECLARE_CLASS( ClientModeTFNormal, ClientModeTFBase ); + +private: + + class Viewport : public CBaseViewport + { + typedef CBaseViewport BaseClass; + // Panel overrides. + public: + Viewport(); + virtual ~Viewport() {} + + virtual void OnThink(); + void ReloadScheme(); + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ) + { + BaseClass::ApplySchemeSettings( pScheme ); + + gHUD.InitColors( pScheme ); + + SetPaintBackgroundEnabled( false ); + } + + virtual void CreateDefaultPanels( void ) { /* don't create any panels yet*/ }; + + private: + bool m_bHumanScheme; + }; + +// IClientMode overrides. +public: + + virtual void Update(); + virtual void CreateMove( float flInputSampleTime, CUserCmd *cmd ); + virtual bool ShouldDrawViewModel( void ); + + virtual vgui::Panel *GetMinimapParent( void ); + + ClientModeTFNormal(); +}; + +extern IClientMode *GetClientModeNormal();
\ No newline at end of file diff --git a/game/client/tf2/commanderoverlay.cpp b/game/client/tf2/commanderoverlay.cpp new file mode 100644 index 0000000..3dbed6e --- /dev/null +++ b/game/client/tf2/commanderoverlay.cpp @@ -0,0 +1,220 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "CommanderOverlay.h" +#include "utlsymbol.h" + +//----------------------------------------------------------------------------- +// Purpose: Singleton class responsible for managing overlay elements +//----------------------------------------------------------------------------- + +class CHudCommanderOverlayMgrImp : public IHudCommanderOverlayMgr +{ +public: + // constructor, destructor + CHudCommanderOverlayMgrImp(); + virtual ~CHudCommanderOverlayMgrImp(); + + // Call this when the game starts up + shuts down + virtual void GameInit(); + virtual void GameShutdown(); + + // Call this when the level starts up + shuts down + virtual void LevelInit( ); + virtual void LevelShutdown(); + + // add an overlay element to the commander mode + virtual OverlayHandle_t AddOverlay( char const* pOverlayName, C_BaseEntity* pEntity, vgui::Panel *pParent ); + + // removes a particular overlay + virtual void RemoveOverlay( OverlayHandle_t handle ); + + // Call this once a frame... + virtual void Tick( ); + + // Call this when commander mode is enabled or disabled + virtual void Enable( bool enable ); + +private: + struct OverlayPanel_t + { + unsigned short m_Team; + CUtlSymbol m_Name; + vgui::Panel *m_pPanel; + vgui::Panel *m_pParentPanel; + EHANDLE m_hEntity; + }; + + // Create, destroy panels + void CreatePanel( int overlay ); + void DestroyPanel( int overlay ); + + // No copy constructor + CHudCommanderOverlayMgrImp( const CHudCommanderOverlayMgrImp& ); + + // List of actual overlays currently in service + // Linked list used so handle ids don't change + CUtlLinkedList< OverlayPanel_t, unsigned short > m_Overlays; +}; + + +//----------------------------------------------------------------------------- +// Returns the singleton commander overlay interface +//----------------------------------------------------------------------------- +IHudCommanderOverlayMgr* HudCommanderOverlayMgr() +{ + static CHudCommanderOverlayMgrImp s_OverlayImp; + return &s_OverlayImp; +} + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +CHudCommanderOverlayMgrImp::CHudCommanderOverlayMgrImp() +{ +} + +CHudCommanderOverlayMgrImp::~CHudCommanderOverlayMgrImp() +{ +} + + +//----------------------------------------------------------------------------- +// Call this when the game starts up or shuts down... +//----------------------------------------------------------------------------- +#define OVERLAY_FILE "scripts/commander_overlays.txt" + +void CHudCommanderOverlayMgrImp::GameInit() +{ + // Read in all overlay metaclasses... + PanelMetaClassMgr()->LoadMetaClassDefinitionFile( OVERLAY_FILE ); +} + +void CHudCommanderOverlayMgrImp::GameShutdown() +{ +} + + +//----------------------------------------------------------------------------- +// Call this when the level starts up + shuts down +//----------------------------------------------------------------------------- +void CHudCommanderOverlayMgrImp::LevelInit( ) +{ +} + + +void CHudCommanderOverlayMgrImp::LevelShutdown() +{ + // Remove all panels.... + for( unsigned short i = m_Overlays.Head(); i != m_Overlays.InvalidIndex(); i = m_Overlays.Next(i) ) + { + DestroyPanel(i); + } + m_Overlays.RemoveAll(); +} + + +//----------------------------------------------------------------------------- +// Create, destroy panel... +//----------------------------------------------------------------------------- +void CHudCommanderOverlayMgrImp::CreatePanel( int overlay ) +{ + Assert( m_Overlays.IsValidIndex(overlay) ); + OverlayPanel_t& panel = m_Overlays[overlay]; + + // Chain keyvalues with name Team# + char pTeamName[6] = "Team "; + pTeamName[4] = '0' + panel.m_Team; + + vgui::Panel *pPanel = PanelMetaClassMgr()->CreatePanelMetaClass( + panel.m_Name.String(), 0, panel.m_hEntity.Get(), panel.m_pParentPanel, pTeamName ); + m_Overlays[overlay].m_pPanel = pPanel; +} + +void CHudCommanderOverlayMgrImp::DestroyPanel( int overlay ) +{ + Assert( m_Overlays.IsValidIndex(overlay) ); + OverlayPanel_t& panel = m_Overlays[overlay]; + if (panel.m_pPanel) + { + PanelMetaClassMgr()->DestroyPanelMetaClass( panel.m_pPanel ); + m_Overlays[overlay].m_pPanel = NULL; + } +} + + +//----------------------------------------------------------------------------- +// add an overlay element to the commander mode +//----------------------------------------------------------------------------- +OverlayHandle_t CHudCommanderOverlayMgrImp::AddOverlay( + char const* pOverlayInstance, C_BaseEntity* pEntity, vgui::Panel *pParent ) +{ + OverlayPanel_t newPanel; + newPanel.m_Name = pOverlayInstance; + newPanel.m_pPanel = NULL; + newPanel.m_Team = (unsigned short)~0; + newPanel.m_hEntity = pEntity; + newPanel.m_pParentPanel = pParent; + return m_Overlays.AddToTail( newPanel ); +} + + +//----------------------------------------------------------------------------- +// removes a particular overlay +//----------------------------------------------------------------------------- +void CHudCommanderOverlayMgrImp::RemoveOverlay( OverlayHandle_t handle ) +{ + if ((handle == OVERLAY_HANDLE_INVALID) || (!m_Overlays.IsValidIndex(handle)) ) + return; + + // Deallocate the panel + DestroyPanel( handle ); + + // Remove it from our list + m_Overlays.Remove( handle ); +} + + +//----------------------------------------------------------------------------- +// make our sprites visible when we are enabled +//----------------------------------------------------------------------------- +void CHudCommanderOverlayMgrImp::Enable( bool enable ) +{ +} + + +//----------------------------------------------------------------------------- +// Call this once a frame... +//----------------------------------------------------------------------------- +void CHudCommanderOverlayMgrImp::Tick( ) +{ + if ( !engine->IsInGame() ) + return; + + // Iterate through all overlays + for( unsigned short i = m_Overlays.Head(); i != m_Overlays.InvalidIndex(); i = m_Overlays.Next(i) ) + { + // Kill panels attached to dead entities... + if (!m_Overlays[i].m_hEntity) + { + DestroyPanel( i ); + continue; + } + + // make sure the panels are up-to-date based on current entity team + if (m_Overlays[i].m_Team != m_Overlays[i].m_hEntity->GetTeamNumber()) + { + // Destroy the old team panel, create the new team panel + DestroyPanel( i ); + m_Overlays[i].m_Team = m_Overlays[i].m_hEntity->GetTeamNumber(); + CreatePanel( i ); + } + } +} + diff --git a/game/client/tf2/commanderoverlay.h b/game/client/tf2/commanderoverlay.h new file mode 100644 index 0000000..c477c8c --- /dev/null +++ b/game/client/tf2/commanderoverlay.h @@ -0,0 +1,153 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// + +#if !defined( COMMANDEROVERLAY_H ) +#define COMMANDEROVERLAY_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "panelmetaclassmgr.h" + + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class C_BaseEntity; +class KeyValues; + + +//----------------------------------------------------------------------------- +// Overlay handle +//----------------------------------------------------------------------------- + +typedef unsigned short OverlayHandle_t; +enum +{ + OVERLAY_HANDLE_INVALID = (OverlayHandle_t)~0 +}; + +//----------------------------------------------------------------------------- +// Purpose: Singleton class responsible for managing overlay elements +//----------------------------------------------------------------------------- +class IHudCommanderOverlayMgr +{ +public: +// // Call this when the game starts up + shuts down + virtual void GameInit() = 0; + virtual void GameShutdown() = 0; + + // Call this when the level starts up + shuts down + virtual void LevelInit( ) = 0; + virtual void LevelShutdown() = 0; + + // add an overlay element to the commander mode, returns a handle to it + virtual OverlayHandle_t AddOverlay( char const* pOverlayName, C_BaseEntity* pEntity, vgui::Panel *pParent = NULL ) = 0; + + // removes a particular overlay + virtual void RemoveOverlay( OverlayHandle_t handle ) = 0; + + // Call this once a frame... + virtual void Tick( ) = 0; + + // Call this when commander mode is enabled or disabled + virtual void Enable( bool enable ) = 0; + +protected: + // Don't delete me! + virtual ~IHudCommanderOverlayMgr() {} +}; + + +//----------------------------------------------------------------------------- +// Returns the singleton commander overlay interface +//----------------------------------------------------------------------------- +IHudCommanderOverlayMgr* HudCommanderOverlayMgr(); + + +//----------------------------------------------------------------------------- +// Helper class for entities to join the list of entities to render on screen +//----------------------------------------------------------------------------- +class CPanelRegistration +{ +public: + CPanelRegistration( ) : m_Overlay(OVERLAY_HANDLE_INVALID) {} + + ~CPanelRegistration() + { + HudCommanderOverlayMgr()->RemoveOverlay( m_Overlay ); + } + + void Activate( C_BaseEntity* pEntity, char const* pOverlayName, bool active ) + { + if( active ) + { + AddOverlay( pEntity, pOverlayName ); + } + else + { + RemoveOverlay(); + } + } + + void Activate( C_BaseEntity* pEntity, char const* pOverlayName, vgui::Panel *pParent, int sortOrder, bool active ) + { + if( active ) + { + AddOverlay( pEntity, pOverlayName, pParent ); + } + else + { + RemoveOverlay(); + } + } + + + void AddOverlay( C_BaseEntity *pEntity, const char *pOverlayName, vgui::Panel *pParent = NULL ) + { + RemoveOverlay(); + m_Overlay = HudCommanderOverlayMgr()->AddOverlay( pOverlayName, pEntity, pParent ); + } + + void RemoveOverlay() + { + if( m_Overlay != OVERLAY_HANDLE_INVALID ) + { + HudCommanderOverlayMgr()->RemoveOverlay( m_Overlay ); + m_Overlay = OVERLAY_HANDLE_INVALID; + } + } + + +private: + OverlayHandle_t m_Overlay; +}; + + +//----------------------------------------------------------------------------- +// Macros for help with simple registration of panels +// Put DECLARE_ENTITY_PANEL() in your class definition +// and ENTITY_PANEL_ACTIVATE( "name" ) in the entity's SetDormant call +//----------------------------------------------------------------------------- +#define DECLARE_ENTITY_PANEL() CPanelRegistration m_OverlayPanel +#define ENTITY_PANEL_ACTIVATE( _pOverlayName, _active ) m_OverlayPanel.Activate( this, _pOverlayName, _active ) + + +//----------------------------------------------------------------------------- +// Helper macro to make overlay factories one line of code. Use like this: +// DECLARE_OVERLAY_FACTORY( CEntityImagePanel, "image" ); +//----------------------------------------------------------------------------- +#define DECLARE_OVERLAY_FACTORY( _PanelClass, _nameString ) \ + DECLARE_PANEL_FACTORY( _PanelClass, C_BaseEntity, _nameString ) + +#define DECLARE_OVERLAY_POINT_FACTORY( _PanelClass, _nameString ) \ + DECLARE_PANEL_FACTORY( _PanelClass, void, _nameString ) + + +#endif // COMMANDEROVERLAY_H
\ No newline at end of file diff --git a/game/client/tf2/commanderoverlaypanel.cpp b/game/client/tf2/commanderoverlaypanel.cpp new file mode 100644 index 0000000..5ef2914 --- /dev/null +++ b/game/client/tf2/commanderoverlaypanel.cpp @@ -0,0 +1,1018 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +//----------------------------------------------------------------------------- +// The panel responsible for rendering the 3D view in orthographic mode +//----------------------------------------------------------------------------- +#include "cbase.h" +#include <vgui/VGUI.h> +#include <vgui_controls/Controls.h> +#include <vgui/IVGui.h> +#include <vgui/IInput.h> +#include <vgui/ISurface.h> +#include "clientmode_commander.h" +#include "vgui_int.h" +#include "iinput.h" +#include "kbutton.h" +#include "hud_minimap.h" +#include "usercmd.h" +#include "mapdata.h" +#include "c_basetfplayer.h" +#include "view.h" +#include "view_shared.h" +#include "CommanderOverlay.h" +#include "C_TfTeam.h" +#include <vgui/MouseCode.h> +#include <vgui/KeyCode.h> +#include <vgui/IPanel.h> +#include "commanderoverlaypanel.h" +#include "PixelWriter.h" +#include "materialsystem/imaterialvar.h" +#include "materialsystem/itexture.h" +#include "vtf/vtf.h" +#include "engine/ivdebugoverlay.h" + + +static inline int AlphaMapIndex(int x, int y) +{ + return y * FOG_ALPHAMAP_SIZE + x; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *commander - +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::SetCommanderView( CClientModeCommander *commander ) +{ + m_pCommanderView = commander; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CCommanderOverlayPanel::CCommanderOverlayPanel( void ) : + vgui::Panel( NULL, "CommanderOverlayPanel" ), + m_CursorCommander(vgui::dc_arrow), + m_CursorRightMouseMove(vgui::dc_hand) +{ + MakePopup(); + + SetPaintBackgroundEnabled( false ); + m_left.m_bMouseDown = false; + m_left.m_nXStart = 0; + m_left.m_nYStart = 0; + + m_right.m_bMouseDown = false; + m_right.m_nXStart = 0; + m_right.m_nYStart = 0; + + m_fZoom = 0; + + m_flPreviousMaxWorldWidth = 0.0f; + SetVisible( false ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CCommanderOverlayPanel::~CCommanderOverlayPanel( void ) +{ +} + + +//----------------------------------------------------------------------------- +// Initialize rendering origin +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::InitializeRenderOrigin() +{ + // Initializes the rendering origin + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + if ( player ) + { + m_vecTacticalOrigin = player->GetAbsOrigin(); + } + else + { + MapData().GetMapOrigin( m_vecTacticalOrigin ); + } + + Vector mins, maxs; + MapData().GetMapBounds( mins, maxs ); + m_vecTacticalOrigin.z = maxs.z + TACTICAL_ZOFFSET; + m_vecTacticalAngles.Init( 90, 90, 0 ); + BoundOrigin( m_vecTacticalOrigin ); +} + + +//----------------------------------------------------------------------------- +// Computes the view range: +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::ComputeZoomRange() +{ + // This is + m_MinWorldWidth = TACTICAL_MIN_VIEWABLE_SIZE; + + // Get the world size + Vector mins, maxs, size; + MapData().GetMapBounds( mins, maxs ); + VectorSubtract( maxs, mins, size ); + float worldAspect = size[0] / size[1]; + +// size[ 0 ] *= 1.05f; +// size[ 1 ] *= 1.05f; + + // Find out the panel aspect ratio + int w, h; + GetVisibleSize( w, h ); + + float panelAspect = (float)w / (float)h; + + // Store off old zoom + m_flPreviousMaxWorldWidth = m_MaxWorldWidth; + + if (panelAspect > worldAspect) + { + // In this case, to see the whole map, + // we'll have black areas on the left + right sides + // Make sure we choose a width big enough to display the entire height + m_MaxWorldWidth = size[1] * panelAspect; + } + else + { + // In this case, to see the whole map, + // we'll have black areas on the top + bottom + // Make sure we choose a width big enough to display the entire height + m_MaxWorldWidth = size[0]; + } + + // if flipping open/close the tech tree, preserver relative zoom amount + if ( m_flPreviousMaxWorldWidth ) + { + float ratio = m_MaxWorldWidth / m_flPreviousMaxWorldWidth; + + m_fZoom *= ratio; + } +} + +//----------------------------------------------------------------------------- +// Call when the map changes +//----------------------------------------------------------------------------- + +void CCommanderOverlayPanel::LevelInit( char const* pMapName ) +{ + // Always look at the entire map to start with + m_fZoom = 0; + m_flPreviousMaxWorldWidth = 0.0f; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::LevelShutdown( void ) +{ +} + +//----------------------------------------------------------------------------- +// call these when commander view is enabled/disabled +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::Enable() +{ + vgui::VPANEL pRoot = VGui_GetClientDLLRootPanel(); + + SetCursor(m_CursorCommander); + SetVisible( true ); + + // Make the viewport fill the root panel. + if( pRoot) + { + int wide, tall; + vgui::ipanel()->GetSize(pRoot, wide, tall); + + // subtract out the technology UI size + tall -= 0;// xxx200 + + SetBounds(0, 0, wide, tall); + } + + // Cache the orthographic view size range + ComputeZoomRange(); + + // Start out looking at the whole world + if (m_fZoom == 0) + m_fZoom = m_MaxWorldWidth; + + // clamp + if (m_fZoom < m_MinWorldWidth) + m_fZoom = m_MinWorldWidth; + else if (m_fZoom > m_MaxWorldWidth) + m_fZoom = m_MaxWorldWidth; + + // Figure out where the camera is + InitializeRenderOrigin(); + + vgui::ivgui()->AddTickSignal( GetVPanel() ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::Disable() +{ + SetVisible( false ); + // FIXME: Need a removeTickSignal! +// vgui::ivgui()->removeTickSignal( GetVPanel() ); +} + + +//----------------------------------------------------------------------------- +// called when we're ticked... +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::OnTick() +{ + if (!IsLocalPlayerInTactical() || !engine->IsInGame()) + return; +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns up to 32 players encoded as a bit per player in a 32 bit unsigned +// Output : unsigned int +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::GetSelectedPlayerBitField( CBitVec< MAX_PLAYERS >& bits ) +{ + CMapPlayers *pPlayer; + + bits.ClearAll(); + + // draw all the visible players + for ( int playerNum = 0; playerNum < MAX_PLAYERS; playerNum++ ) + { + pPlayer = &MapData().m_Players[ playerNum ]; + if ( pPlayer->m_bSelected ) + { + bits.Set( playerNum ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Counts how many players are selected +// Output : int +//----------------------------------------------------------------------------- +int CCommanderOverlayPanel::CountSelectedPlayers( void ) +{ + CMapPlayers *pPlayer; + + // bitfield variable + int count = 0; + + // draw all the visible players + for ( int playerNum = 0; playerNum < MAX_PLAYERS; playerNum++ ) + { + pPlayer = &MapData().m_Players[ playerNum ]; + if ( pPlayer->m_bSelected ) + { + count++; + } + } + + return count; +} + +//----------------------------------------------------------------------------- +// Purpose: Called when a key is pressed +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::OnKeyPressed(vgui::KeyCode code) +{ + switch(code) + { + case vgui::KEY_SPACE: + if (m_fZoom != m_MaxWorldWidth) + { + ChangeZoomLevel(m_MaxWorldWidth); + } + else + { + Vector mouseWorldPos; + CenterOnMouse( mouseWorldPos ); + + ChangeZoomLevel(TACTICAL_SPACEBAR_VIEWABLE_SIZE); + + // Place mouse over me + m_pCommanderView->MoveMouse( mouseWorldPos ); + } + break; + + default: + break; + } +} + +//----------------------------------------------------------------------------- +// Purpose: when space is hit, show the entire view +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::ChangeZoomLevel( float newZoom ) +{ + // Make sure the mouse remains over the thing it started over + + // Figure out worldspace movement based on picking ray + Vector rayOrigin, rayForward; + + int mx, my; + GetMousePos( mx, my ); + + // Need to convert from screen space back to a worldspace ray + CreatePickingRay( + mx, my, + ScreenWidth(), ScreenHeight(), + CurrentViewOrigin(), + CurrentViewAngles(), + rayOrigin, + rayForward ); + + m_fZoom = newZoom; + + BoundOrigin( m_vecTacticalOrigin ); + + // move mouse to center and zero out any delta + m_pCommanderView->MoveMouse( rayOrigin ); +// RequestFocus(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CCommanderOverlayPanel::IsRightMouseMapMoving( void ) +{ + return m_right.m_bMouseDown; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::RightMouseMapMove( void ) +{ + /* + // Figure out worldspace movement based on picking ray + Vector rayForward; + Vector vecEndPosCurrent, vecEndPosPrevious; + + // Need to convert from screen space back to a worldspace ray + CreatePickingRay( + m_right.m_nXCurrent, m_right.m_nYCurrent, + ScreenWidth(), ScreenHeight(), + g_vecRenderOrigin, + g_vecRenderAngles, + vecEndPosCurrent, + rayForward ); + + engine->Con_NPrintf( 8, "x %i y %i hit %.3f %.3f", + m_right.m_nXCurrent, m_right.m_nYCurrent, vecEndPosCurrent.x, vecEndPosCurrent.y ); + */ + + if ( !m_right.m_bMouseDown ) + return; + + /* + // See if there is a delta in the current and previous mouse positions + // + int dx, dy; + + dx = m_right.m_nXCurrent - m_right.m_nXPrev; + dy = m_right.m_nYCurrent - m_right.m_nYPrev; + + // No relative move + if ( !dx && !dy ) + return; + + // Figure out worldspace movement based on picking ray + Vector rayForward; + Vector vecEndPosCurrent, vecEndPosPrevious; + + // Need to convert from screen space back to a worldspace ray + CreatePickingRay( + m_right.m_nXCurrent, m_right.m_nYCurrent, + ScreenWidth(), ScreenHeight(), + g_vecRenderOrigin, + g_vecRenderAngles, + vecEndPosCurrent, + rayForward ); + + // Now create ray from old position + // Need to convert from screen space back to a worldspace ray + CreatePickingRay( + m_right.m_nXPrev, m_right.m_nYPrev, + ScreenWidth(), ScreenHeight(), + g_vecRenderOrigin, + g_vecRenderAngles, + vecEndPosPrevious, + rayForward ); + + // Remove z component + vecEndPosPrevious.z = 0.0; + vecEndPosCurrent.z = 0.0; + + // Compute offset + Vector viewDelta; + VectorSubtract( vecEndPosCurrent, vecEndPosPrevious, viewDelta ); + + viewDelta.z = 0.0f; + + VectorAdd( m_vecTacticalOrigin, viewDelta, m_vecTacticalOrigin ); + + m_pCommanderView->BoundOrigin( m_vecTacticalOrigin ); + */ +} + + +//----------------------------------------------------------------------------- +// Purpose: Right mouse button down +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::RightMousePressed( void ) +{ + if ( m_left.m_bMouseDown || m_right.m_bMouseDown ) + return; + + SetCursor(m_CursorRightMouseMove); + + StartMovingMouse( m_right ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::RightMouseReleased( void ) +{ + if ( !m_right.m_bMouseDown ) + return; + + m_right.m_bMouseDown = false; + int mx, my; + GetMousePos( mx, my ); + UpdateMousePos( mx, my, m_right ); + + // Final move + RightMouseMapMove(); + + vgui::input()->SetMouseCapture( NULL ); + + SetCursor(m_CursorCommander); + + // If the player's dead, and doesn't have the special sniper upgrade + // then check for respawn stations.... + C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + if (!pPlayer) + return; + + // If the player's dead, abort + if ( pPlayer->PlayerClass() == TFCLASS_SNIPER ) + { + // Sniper's can request a respawn point when dead + // + Vector rayOrigin, rayForward; + Vector vecEndPos; + + // Need to convert from screen space back to a worldspace ray + CreatePickingRay( + m_right.m_nXCurrent, m_right.m_nYCurrent, + ScreenWidth(), ScreenHeight(), + CurrentViewOrigin(), + CurrentViewAngles(), + rayOrigin, + rayForward ); + + // Now do the trace + trace_t tr; + + vecEndPos = rayOrigin + rayForward * MAX_TRACE_LENGTH; + + UTIL_TraceLine( rayOrigin, vecEndPos, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &tr ); + + // Didn't hit anything + if ( tr.fraction == 1.0 ) + return; + + char cmd[ 128 ]; + Q_snprintf( cmd, sizeof( cmd ), "respawnpoint %i %i %i\n", + (int)tr.endpos.x, + (int)tr.endpos.y, + (int)tr.endpos.z ); + + engine->ServerCmd( cmd ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : x - +// y - +// mouse - +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::UpdateMousePos( int x, int y, MouseDown_t& mouse ) +{ + // store previous + mouse.m_nXPrev = mouse.m_nXCurrent; + mouse.m_nYPrev = mouse.m_nYCurrent; + // update current + mouse.m_nXCurrent = x; + mouse.m_nYCurrent = y; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : x - +// y - +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::OnCursorMoved(int x, int y) +{ + UpdateMousePos( x, y, m_left ); + UpdateMousePos( x, y, m_right ); + + RightMouseMapMove(); +// RequestFocus(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : x - +// y - +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::GetMousePos( int& x, int& y ) +{ + vgui::input()->GetCursorPos( x, y ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : mouse - +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::StartMovingMouse( MouseDown_t& mouse ) +{ + mouse.m_bMouseDown = true; + GetMousePos( mouse.m_nXStart, mouse.m_nYStart ); + + mouse.m_nXCurrent = mouse.m_nXPrev = mouse.m_nXStart; + mouse.m_nYCurrent = mouse.m_nYPrev = mouse.m_nYStart; + + vgui::input()->SetMouseCapture( GetVPanel() ); +} + +//----------------------------------------------------------------------------- +// Purpose: Left mouse button down +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::LeftMousePressed( void ) +{ + if ( m_left.m_bMouseDown || m_right.m_bMouseDown ) + return; + + StartMovingMouse( m_left ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : code - +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::OnMousePressed(vgui::MouseCode code) +{ + switch ( code ) + { + case vgui::MOUSE_LEFT: + LeftMousePressed(); + break; + case vgui::MOUSE_RIGHT: + RightMousePressed(); + break; + default: + BaseClass::OnMousePressed( code ); + return; + } + +// RequestFocus(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : x0 - +// y0 - +// x1 - +// y1 - +// true - +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::SelectPlayersInRectangle( int x0, int y0, int x1, int y1, bool clearOldSelections /*= true*/ ) +{ + int num_selected = 0; + + // Assume zero players in selection + if ( clearOldSelections ) + { + m_bHaveActiveSelection = false; + } + else + { + // Count # selected + num_selected = CountSelectedPlayers(); + } + + CMapPlayers *pPlayer; + C_BaseTFPlayer *tf2player; + + // See which players on my team are within the rectangle in screen space + // + for ( int playerNum = 1; playerNum <= MAX_PLAYERS; playerNum++ ) + { + pPlayer = &MapData().m_Players[ playerNum - 1 ]; + + if ( clearOldSelections ) + { + pPlayer->m_bSelected = false; + } + + if ( playerNum > gpGlobals->maxClients ) + { + continue; + } + + tf2player = dynamic_cast<C_BaseTFPlayer *>( cl_entitylist->GetEnt( playerNum ) ); + if ( !tf2player ) + { + continue; + } + + // Check pvs on this guy + // If the entity was in the commander's PVS then show it on the minimap, too + // + if ( ArePlayersOnSameTeam( engine->GetLocalPlayer(), playerNum ) == false ) + { + continue; + } + + // Check their actual draw position + int drawX, drawY; + Vector pos, screen; + + pos = tf2player->GetAbsOrigin(); + + // Transform + debugoverlay->ScreenPosition( pos, screen ); + + // FIXME: Get the player icon size from where?!? + drawX = screen.x - 32; + drawY = screen.y - 40; + int intersectX = 64; + int intersectY = 64; + + // Check for intersection ( with slop ) + if ( drawX + intersectX < x0 ) + continue; + if ( drawX > x1 ) + continue; + if ( drawY + intersectY < y0 ) + continue; + if ( drawY > y1 ) + continue; + + // Already selected? + if ( !pPlayer->m_bSelected ) + { + // Add to selected list + pPlayer->m_bSelected = true; + num_selected++; + } + } + + if ( num_selected != 0 ) + { + m_bHaveActiveSelection = true; + } +} + +//----------------------------------------------------------------------------- +// Returns the visible area (not including the tech tree) +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::GetVisibleSize( int& w, int& h ) +{ + GetSize( w, h ); + + // FIXME: Hack to make the map appear above the tech tree + h -= 200; +} + +//----------------------------------------------------------------------------- +// Returns the visible area (not including the tech tree) +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::GetVisibleArea( Vector& mins, Vector& maxs ) +{ + float w, h; + GetVisibleOrthoSize( w, h ); + + ActualToVisibleOffset( mins ); + mins += m_vecTacticalOrigin; + maxs = mins; + mins.x -= w; maxs.x +=w; + mins.y -= h; maxs.y +=h; +} + +//----------------------------------------------------------------------------- +// Purpose: User let go of left mouse button +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::LeftMouseReleased( void ) +{ + if ( !m_left.m_bMouseDown ) + return; + + m_left.m_bMouseDown = false; + + int mx, my; + GetMousePos( mx, my ); + UpdateMousePos( mx, my, m_left ); + + vgui::input()->SetMouseCapture( NULL ); + + // Normalize the rectangle + int x0, y0, x1, y1; + x0 = MIN( m_left.m_nXStart, m_left.m_nXCurrent ); + x1 = MAX( m_left.m_nXStart, m_left.m_nXCurrent ); + y0 = MIN( m_left.m_nYStart, m_left.m_nYCurrent ); + y1 = MAX( m_left.m_nYStart, m_left.m_nYCurrent ); + + bool clearOldStates = true; + if ( vgui::input()->IsKeyDown( vgui::KEY_LCONTROL ) ) + { + clearOldStates = false; + } + + SelectPlayersInRectangle( x0, y0, x1, y1, clearOldStates ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::GetOrthoRenderBox(Vector &vCenter, float &xSize, float &ySize) +{ + vCenter = m_vecTacticalOrigin; + + // min and max depends on the current zoom level + int w, h; + GetParent()->GetSize( w, h ); + + xSize = m_fZoom; + ySize = xSize * ( (float)h / (float)w ); + + xSize *= 0.5f; + ySize *= 0.5f; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::GetVisibleOrthoSize(float &xSize, float &ySize) +{ + // min and max depends on the current zoom level + int w, h; + GetVisibleSize( w, h ); + xSize = m_fZoom; + ySize = xSize * ( (float)h / (float)w ); + + xSize *= 0.5f; + ySize *= 0.5f; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +float CCommanderOverlayPanel::WorldUnitsPerPixel() +{ + int w, h; + GetParent()->GetSize( w, h ); + return m_fZoom / w; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::ActualToVisibleOffset( Vector& offset ) +{ + // FIXME: This doesn't work arbitrarily; we assume the visible + // part is on the top of the screen.. + int w, h, wact, hact; + GetVisibleSize( w, h ); + GetParent()->GetSize( wact, hact ); + + float worldUnitsPerPixel = m_fZoom / wact; + float dWorldY = (hact - h) * 0.5f * worldUnitsPerPixel; + offset.Init( 0, dWorldY, 0 ); +} + +//----------------------------------------------------------------------------- +// Purpose: Make sure origin is inside map x, y bounds ( not z ) +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::BoundOrigin( Vector& camera ) +{ + // We're going to do this entire computation assuming the camera + // is in the center of the viewable area, which it isn't. At the + // end, we'll need to apply a fixup to deal with that + + Vector mins, maxs, halfsize; + MapData().GetMapBounds( mins, maxs ); + VectorSubtract( maxs, mins, halfsize ); + halfsize *= 0.5f; + + // avoid black edges... + float dim[2]; + GetVisibleOrthoSize( dim[0], dim[1] ); + + // Compute the position of the center of the visible area based on + // the new suggested camera position + Vector actualToVisible, newVisCenter; + ActualToVisibleOffset( actualToVisible ); + VectorAdd( camera, actualToVisible, newVisCenter ); + + // Only bound x & y + for ( int i = 0; i < 2; i++ ) + { + if (dim[i] > halfsize[i]) + { + newVisCenter[i] = mins[i] + halfsize[i]; + } + else + { + newVisCenter[ i ] = MAX( newVisCenter[i], mins[i] + dim[i] ); + newVisCenter[ i ] = MIN( newVisCenter[i], maxs[i] - dim[i] ); + } + } + + // Remember: The viewport takes up the entire screen; but the visible + // area only takes up the top half of the screen. Therefore, we need to + // set the origin so that the center of what we want lies at the + // center of the visible region + VectorSubtract( newVisCenter, actualToVisible, camera ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Given mouse/screen positions as well as the current +// render origin and angles, returns a unit vector through the mouse position +// that can be used to trace into the world under the mouse click pixel. +// Input : fov - +// mousex - +// mousey - +// screenwidth - +// screenheight - +// vecRenderAngles - +// c_x - +// vpn - +// vup - +// 360.0 - +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::CreatePickingRay( int mousex, int mousey, + int screenwidth, int screenheight, + const Vector& vecRenderOrigin, + const QAngle& vecRenderAngles, + Vector &rayOrigin, + Vector &rayDirection + ) +{ + Vector vCenter; + float xSize, ySize; + GetOrthoRenderBox(vCenter, xSize, ySize); + + float xPos = RemapVal(mousex, 0, screenwidth, vCenter.x-xSize, vCenter.x+xSize); + float yPos = RemapVal(mousey, 0, screenheight, vCenter.y+ySize, vCenter.y-ySize); // (flip screen y) + rayOrigin.Init(xPos, yPos, vCenter.z); + rayDirection.Init(0, 0, -1); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::OnMouseReleased(vgui::MouseCode code) +{ + switch ( code ) + { + case vgui::MOUSE_LEFT: + LeftMouseReleased(); + break; + case vgui::MOUSE_RIGHT: + RightMouseReleased(); + break; + default: + BaseClass::OnMouseReleased( code ); + return; + } + +// RequestFocus(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::CenterOnMouse( Vector& mouseWorldPos ) +{ + // Figure out worldspace movement based on picking ray + Vector rayForward; + Vector centerOrigin; + + int mx, my; + GetMousePos( mx, my ); + + // Need to convert from screen space back to a worldspace ray + CreatePickingRay( + mx, my, + ScreenWidth(), ScreenHeight(), + CurrentViewOrigin(), + CurrentViewAngles(), + mouseWorldPos, + rayForward ); + + CreatePickingRay( + ScreenWidth()/2, ScreenHeight()/2, + ScreenWidth(), ScreenHeight(), + CurrentViewOrigin(), + CurrentViewAngles(), + centerOrigin, + rayForward ); + + Vector offset; + VectorSubtract( mouseWorldPos, centerOrigin, offset ); + offset.z = 0.0f; + VectorAdd( m_vecTacticalOrigin, offset, m_vecTacticalOrigin ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : delta - +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::OnMouseWheeled(int delta) +{ + // Figure out worldspace movement based on picking ray + Vector rayOrigin; + + CenterOnMouse( rayOrigin ); + + // Gotta do the zoom after picking the ray, or it'll use the wrong zoom factor + // for computing the picking ray + if ( delta < 0 ) + { + m_fZoom *= 1.25f; + } + else if ( delta > 0 ) + { + m_fZoom /= 1.25f; + } + + m_fZoom = MIN( m_fZoom, m_MaxWorldWidth ); + m_fZoom = MAX( m_fZoom, m_MinWorldWidth ); + + BoundOrigin( m_vecTacticalOrigin ); + + // move mouse to center and zero out any delta + m_pCommanderView->MoveMouse( rayOrigin ); + +// RequestFocus(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCommanderOverlayPanel::Paint() +{ + if ( !m_left.m_bMouseDown ) + return; + + // Update mouse position, so we don't get the 1 frame lag + int mx, my; + GetMousePos( mx, my ); + UpdateMousePos( mx, my, m_left ); + + int x0, x1, y0, y1; + // Make sure it's normalized + x0 = MIN( m_left.m_nXStart, m_left.m_nXCurrent ); + x1 = MAX( m_left.m_nXStart, m_left.m_nXCurrent ); + y0 = MIN( m_left.m_nYStart, m_left.m_nYCurrent ); + y1 = MAX( m_left.m_nYStart, m_left.m_nYCurrent ); + + // Draw selection rectangle + vgui::surface()->DrawSetColor( 200, 220, 250, 192 ); + vgui::surface()->DrawOutlinedRect( x0, y0, x1, y1 ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +float CCommanderOverlayPanel::GetZoom( void ) +{ + return (m_fZoom - m_MinWorldWidth) / (m_MaxWorldWidth - m_MinWorldWidth); +} diff --git a/game/client/tf2/commanderoverlaypanel.h b/game/client/tf2/commanderoverlaypanel.h new file mode 100644 index 0000000..382732a --- /dev/null +++ b/game/client/tf2/commanderoverlaypanel.h @@ -0,0 +1,143 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef COMMANDEROVERLAYPANEL_H +#define COMMANDEROVERLAYPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "CommanderOverlay.h" +#include <vgui_controls/Panel.h> + +#define TACTICAL_ZOFFSET 100 +#define TACTICAL_MIN_VIEWABLE_SIZE 1000 +#define TACTICAL_SPACEBAR_VIEWABLE_SIZE 4000 + +#define FOG_ALPHAMAP_SIZE 64 + +class C_TFTeam; +class IVTFTexture; +class ITexture; + +class CCommanderOverlayPanel : public vgui::Panel +{ + typedef vgui::Panel BaseClass; +// Panel overrides. +public: + CCommanderOverlayPanel( void ); + virtual ~CCommanderOverlayPanel( void ); + + virtual void Paint(); + + virtual void OnMousePressed(vgui::MouseCode code); + virtual void OnMouseReleased(vgui::MouseCode code); + virtual void OnCursorMoved(int x, int y); + virtual void OnMouseWheeled(int delta); + virtual void OnKeyPressed(vgui::KeyCode code); + + // Call on enable + void Enable(); + void Disable(); + + // called when we're ticked (updates our state)... + void OnTick(); + + // Call when the map changes + void LevelInit( char const* pMapName ); + void LevelShutdown( void ); + + // Returns the visible area (not including the tech tree) + void GetVisibleSize( int& w, int& h ); + + // Returns the visible area in world units + void GetVisibleArea( Vector& mins, Vector& maxs ); + + // Returns the number of world units per pixel + float WorldUnitsPerPixel(); + + // Fill in the rectangle that the view is rendered from. + // It is looking down negative Z, and goes from [vCenter.x-xSize, vCenter.y-ySize] to [vCenter.x+xSize, vCenter.y+ySize]. + void GetOrthoRenderBox(Vector &vCenter, float &xSize, float &ySize); + void GetVisibleOrthoSize(float &xSize, float &ySize); + void ActualToVisibleOffset( Vector& offset ); + + void BoundOrigin( Vector& camera ); + + void CreatePickingRay( int mousex, int mousey, + int screenwidth, int screenheight, + const Vector& vecRenderOrigin, + const QAngle& vecRenderAngles, + Vector &rayOrigin, + Vector &rayDirection + ); + + Vector& TacticalOrigin() { return m_vecTacticalOrigin; } + QAngle& TacticalAngles() { return m_vecTacticalAngles; } + + float GetZoom( void ); + + void SetCommanderView( CClientModeCommander *commander ); + bool IsRightMouseMapMoving( void ); + +private: + struct MouseDown_t + { + bool m_bMouseDown; + int m_nXStart; + int m_nYStart; + int m_nXCurrent; + int m_nYCurrent; + int m_nXPrev; + int m_nYPrev; + }; + + // Compute render origin + void InitializeRenderOrigin(); + + // Methods relating to zoom + void ComputeZoomRange(); + + void LeftMousePressed( void ); + void LeftMouseReleased( void ); + void RightMousePressed( void ); + void RightMouseReleased( void ); + void RightMouseMapMove( void ); + + // Shows the entire view + void ChangeZoomLevel( float newZoom ); + + // Centers the view on the mouse + void CenterOnMouse( Vector& mouseWorldPos ); + + int CountSelectedPlayers( void ); + void GetSelectedPlayerBitField( CBitVec< MAX_PLAYERS >& bits ); + void SelectPlayersInRectangle( int x0, int y0, int x1, int y1, bool clearOldSelections = true ); + + void GetMousePos( int& x, int& y ); + void StartMovingMouse( MouseDown_t& mouse ); + void UpdateMousePos( int x, int y, MouseDown_t& mouse ); + + // camera origin + Vector m_vecTacticalOrigin; + QAngle m_vecTacticalAngles; + + MouseDown_t m_left, m_right; + + float m_fZoom; // 0 = sitting at world maxs.z. 1 = at maxs.z + (maxs.z-mins.z)*2. + float m_MinWorldWidth; + float m_MaxWorldWidth; + bool m_bHaveActiveSelection; + float m_flPreviousMaxWorldWidth; + + CClientModeCommander *m_pCommanderView; + + vgui::HCursor m_CursorCommander; + vgui::HCursor m_CursorRightMouseMove; +}; + +#endif // COMMANDEROVERLAYPANEL_H diff --git a/game/client/tf2/env_objecteffects.cpp b/game/client/tf2/env_objecteffects.cpp new file mode 100644 index 0000000..4342a46 --- /dev/null +++ b/game/client/tf2/env_objecteffects.cpp @@ -0,0 +1,137 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// +#include "cbase.h" +#include "particles_simple.h" +#include "particlemgr.h" +#include "particle_collision.h" +#include "env_objecteffects.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CObjectSmokeParticles::Setup( const Vector &origin, const Vector *direction, float angularSpread, float minSpeed, float maxSpeed, float gravity, float dampen, int flags ) +{ + // See if we've specified a direction + m_ParticleCollision.Setup( origin, direction, angularSpread, minSpeed, maxSpeed, gravity, dampen ); +} + +void CObjectSmokeParticles::SimulateParticles( CParticleSimulateIterator *pIterator ) +{ + float timeDelta = pIterator->GetTimeDelta(); + + ObjectSmokeParticle *pParticle = (ObjectSmokeParticle*)pIterator->GetFirst(); + while ( pParticle ) + { + //Update velocity + UpdateVelocity( pParticle, timeDelta ); + pParticle->m_Pos += (pParticle->m_vecVelocity * timeDelta); + pParticle->m_vecVelocity += pParticle->m_vecAcceleration * 2 * timeDelta; + + //Should this particle die? + pParticle->m_flLifetime += timeDelta; + UpdateRoll( pParticle, timeDelta ); + + if ( pParticle->m_flLifetime >= pParticle->m_flDieTime ) + pIterator->RemoveParticle( pParticle ); + + pParticle = (ObjectSmokeParticle*)pIterator->GetNext(); + } +} + + +void CObjectSmokeParticles::RenderParticles( CParticleRenderIterator *pIterator ) +{ + const ObjectSmokeParticle *pParticle = (const ObjectSmokeParticle *)pIterator->GetFirst(); + while ( pParticle ) + { + //Render + Vector tPos; + + TransformParticle( ParticleMgr()->GetModelView(), pParticle->m_Pos, tPos ); + float sortKey = (int) tPos.z; + + //Render it + RenderParticle_ColorSizeAngle( + pIterator->GetParticleDraw(), + tPos, + UpdateColor( pParticle ), + UpdateAlpha( pParticle ) * GetAlphaDistanceFade( tPos, m_flNearClipMin, m_flNearClipMax ), + UpdateScale( pParticle ), + pParticle->m_flRoll ); + + pParticle = (const ObjectSmokeParticle *)pIterator->GetNext( sortKey ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CObjectFireParticles::Setup( const Vector &origin, const Vector *direction, float angularSpread, float minSpeed, float maxSpeed, float gravity, float dampen, int flags ) +{ +} + +void CObjectFireParticles::SimulateParticles( CParticleSimulateIterator *pIterator ) +{ + float timeDelta = pIterator->GetTimeDelta(); + + ObjectFireParticle *pParticle = (ObjectFireParticle*)pIterator->GetFirst(); + while ( pParticle ) + { + // Lost our parent? + if ( !pParticle->m_hParent ) + { + pIterator->RemoveParticle( pParticle ); + } + else + { + // Update position to match our parent + Vector vecFire; + QAngle angFire; + if ( pParticle->m_hParent->GetAttachment( pParticle->m_iAttachmentPoint, vecFire, angFire ) ) + { + pParticle->m_Pos = vecFire; + } + + // Should this particle die? + pParticle->m_flLifetime += timeDelta; + + UpdateRoll( pParticle, timeDelta ); + + if ( pParticle->m_flLifetime >= pParticle->m_flDieTime ) + pIterator->RemoveParticle( pParticle ); + } + + pParticle = (ObjectFireParticle*)pIterator->GetNext(); + } +} + + +void CObjectFireParticles::RenderParticles( CParticleRenderIterator *pIterator ) +{ + const ObjectFireParticle *pParticle = (const ObjectFireParticle *)pIterator->GetFirst(); + while ( pParticle ) + { + // Render + Vector tPos; + TransformParticle( ParticleMgr()->GetModelView(), pParticle->m_Pos, tPos ); + float sortKey = (int) tPos.z; + + // Render it + RenderParticle_ColorSizeAngle( + pIterator->GetParticleDraw(), + tPos, + UpdateColor( pParticle ), + UpdateAlpha( pParticle ) * GetAlphaDistanceFade( tPos, m_flNearClipMin, m_flNearClipMax ), + UpdateScale( pParticle ), + pParticle->m_flRoll + ); + + pParticle = (const ObjectFireParticle *)pIterator->GetNext( sortKey ); + } +} + + diff --git a/game/client/tf2/env_objecteffects.h b/game/client/tf2/env_objecteffects.h new file mode 100644 index 0000000..9457145 --- /dev/null +++ b/game/client/tf2/env_objecteffects.h @@ -0,0 +1,73 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ENV_OBJECTEFFECTS_H +#define ENV_OBJECTEFFECTS_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Purpose: Object smoke particles. They float upward. +//----------------------------------------------------------------------------- +class ObjectSmokeParticle : public SimpleParticle +{ +public: + Vector m_vecAcceleration; +}; + +//----------------------------------------------------------------------------- +// Purpose: Object smoke particle emitter. +//----------------------------------------------------------------------------- +class CObjectSmokeParticles : public CSimpleEmitter +{ +public: + + CObjectSmokeParticles( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {} + static CSmartPtr<CObjectSmokeParticles> Create( const char *pDebugName ) {return new CObjectSmokeParticles( pDebugName );} + + virtual void SimulateParticles( CParticleSimulateIterator *pIterator ); + virtual void RenderParticles( CParticleRenderIterator *pIterator ); + + //Setup for point emission + virtual void Setup( const Vector &origin, const Vector *direction, float angularSpread, float minSpeed, float maxSpeed, float gravity, float dampen, int flags = 0 ); + + CParticleCollision m_ParticleCollision; + +private: + CObjectSmokeParticles( const CObjectSmokeParticles & ); // not defined, not accessible +}; + +//----------------------------------------------------------------------------- +// Purpose: Object fire particles. They know how to attach themselves to heirarchy. +//----------------------------------------------------------------------------- +class ObjectFireParticle : public SimpleParticle +{ +public: + EHANDLE m_hParent; + int m_iAttachmentPoint; +}; + +//----------------------------------------------------------------------------- +// Purpose: Object smoke particle emitter. +//----------------------------------------------------------------------------- +class CObjectFireParticles : public CSimpleEmitter +{ +public: + CObjectFireParticles( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {} + static CSmartPtr<CObjectFireParticles> Create( const char *pDebugName ) {return new CObjectFireParticles( pDebugName );} + + virtual void SimulateParticles( CParticleSimulateIterator *pIterator ); + virtual void RenderParticles( CParticleRenderIterator *pIterator ); + + //Setup for point emission + virtual void Setup( const Vector &origin, const Vector *direction, float angularSpread, float minSpeed, float maxSpeed, float gravity, float dampen, int flags = 0 ); + +private: + CObjectFireParticles( const CObjectFireParticles & ); // not defined, not accessible +}; + +#endif // ENV_OBJECTEFFECTS_H diff --git a/game/client/tf2/fx_tf2_blood.cpp b/game/client/tf2/fx_tf2_blood.cpp new file mode 100644 index 0000000..6b7e13a --- /dev/null +++ b/game/client/tf2/fx_tf2_blood.cpp @@ -0,0 +1,347 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A blood spray effect to expose successful hits. +// +//=============================================================================// + +#include "cbase.h" +#include "clienteffectprecachesystem.h" +#include "fx_sparks.h" +#include "iefx.h" +#include "c_te_effect_dispatch.h" +#include "particles_ez.h" +#include "decals.h" +#include "engine/IEngineSound.h" +#include "fx_quad.h" +#include "engine/ivdebugoverlay.h" +#include "shareddefs.h" +#include "fx_blood.h" +#include "tf_shareddefs.h" +#include "view.h" +#include "c_basetfplayer.h" + +CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectTF2BloodSpray ) +CLIENTEFFECT_MATERIAL( "effects/blood_gore" ) +CLIENTEFFECT_MATERIAL( "effects/blood_drop" ) +CLIENTEFFECT_MATERIAL( "effects/blood_puff" ) +CLIENTEFFECT_REGISTER_END() + +//----------------------------------------------------------------------------- +// Purpose: +// Input : origin - +// normal - +// scale - +//----------------------------------------------------------------------------- +void FX_TF2_BloodSpray( const Vector &origin, const Vector &normal, float scale, unsigned char r, unsigned char g, unsigned char b, int flags ) +{ + if ( UTIL_IsLowViolence() ) + return; + + //debugoverlay->AddLineOverlay( origin, origin + normal * 72, 255, 255, 255, true, 10 ); + + float spread = 0.2f; + Vector color = Vector( r / 255.0f, g / 255.0f, b / 255.0f ); + float colorRamp; + Vector offset; + int i; + + Vector offDir; + Vector right; + Vector up; + Vector vecNormal = normal; + + // Get the distance to the view + float flDistance = (origin - MainViewOrigin()).Length(); + float flLODDistance = 0.25 * (flDistance / 512); + float flDistanceScale = 1.0 + flLODDistance; + + if (vecNormal != Vector(0, 0, 1) ) + { + right = vecNormal.Cross( Vector(0, 0, 1) ); + up = right.Cross( vecNormal ); + } + else + { + right = Vector(0, 0, 1); + up = right.Cross( vecNormal ); + } + + // If the normal's too close to being along the view, push it out + Vector vecForward, vecRight; + AngleVectors( MainViewAngles(), &vecForward, &vecRight, NULL ); + float flDot = DotProduct( vecNormal, vecForward ); + if ( fabs(flDot) > 0.5 ) + { + float flPush = random->RandomFloat(0.5, 1.5) + flLODDistance; + float flRightDot = DotProduct( vecNormal, vecRight ); + // If we're up close, randomly move it around. If we're at a distance, always push it to the side + // Up close, this can move it back towards the view, but the random chance still looks better + if ( ( flDistance >= 512 && flRightDot > 0 ) || ( flDistance < 512 && RandomFloat(0,1) > 0.5 ) ) + { + // Turn it to the right + vecNormal += (vecRight * flPush); + } + else + { + // Turn it to the left + vecNormal -= (vecRight * flPush); + } + } + + // + // Dump out drops + // + // Don't bother with these over midrange distance + if (flags & FX_BLOODSPRAY_DROPS && ( flDistance < 1500 ) ) + { + TrailParticle *tParticle; + + CSmartPtr<CTrailParticles> pTrailEmitter = CTrailParticles::Create( "blooddrops" ); + if ( !pTrailEmitter ) + return; + + pTrailEmitter->SetSortOrigin( origin ); + + // Partial gravity on blood drops. + pTrailEmitter->SetGravity( 600.0 ); + + // Enable simple collisions with nearby surfaces. + pTrailEmitter->Setup(origin, &vecNormal, 1, 10, 100, 600, 0.2, 0 ); + + PMaterialHandle hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_drop" ); + + // + // Long stringy drops of blood. + // + for ( i = 0; i < 7; i++ ) + { + // Originate from within a circle 'scale' inches in diameter. + offset = origin; + offset += right * random->RandomFloat( -0.5f, 0.5f ) * scale; + offset += up * random->RandomFloat( -0.5f, 0.5f ) * scale; + + tParticle = (TrailParticle *) pTrailEmitter->AddParticle( sizeof(TrailParticle), hMaterial, offset ); + + if ( tParticle == NULL ) + break; + + tParticle->m_flLifetime = 0.0f; + + offDir = vecNormal + RandomVector( -0.3f, 0.3f ); + + tParticle->m_vecVelocity = offDir * random->RandomFloat( 4.0f * scale, 40.0f * scale ); + tParticle->m_vecVelocity[2] += random->RandomFloat( 4.0f, 16.0f ) * scale; + + tParticle->m_flWidth = random->RandomFloat( 0.5f, 1.0f ) * scale * (flDistanceScale * 1.25); + tParticle->m_flLength = random->RandomFloat( 0.02f, 0.03f ) * scale * (flDistanceScale * 1.25); + tParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f ); + + // Ramp up the brightness as it gets farther away + colorRamp = random->RandomFloat( 0.5f, 0.75f ) + flLODDistance; + FloatToColor32( tParticle->m_color, MIN( 1.0, color[0] * colorRamp ), MIN( 1.0, color[1] * colorRamp ), MIN( 1.0, color[2] * colorRamp ), 1.0f ); + } + + // + // Shorter droplets. + // + // Only do these at short range + if ( flDistance < 512 ) + { + for ( i = 0; i < 10; i++ ) + { + // Originate from within a circle 'scale' inches in diameter. + offset = origin; + offset += right * random->RandomFloat( -0.5f, 0.5f ) * scale; + offset += up * random->RandomFloat( -0.5f, 0.5f ) * scale; + + tParticle = (TrailParticle *) pTrailEmitter->AddParticle( sizeof(TrailParticle), hMaterial, offset ); + + if ( tParticle == NULL ) + break; + + tParticle->m_flLifetime = 0.0f; + + offDir = vecNormal + RandomVector( -1.0f, 1.0f ); + offDir[2] += random->RandomFloat(0, 1.0f); + + tParticle->m_vecVelocity = offDir * random->RandomFloat( 2.0f * scale, 25.0f * scale ); + tParticle->m_vecVelocity[2] += random->RandomFloat( 4.0f, 16.0f ) * scale; + + tParticle->m_flWidth = random->RandomFloat( 0.25f, 0.375f ) * scale * flDistanceScale; + tParticle->m_flLength = random->RandomFloat( 0.0025f, 0.005f ) * scale * flDistanceScale; + tParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f ); + + colorRamp = random->RandomFloat( 0.5f, 0.75f ) + flLODDistance; + FloatToColor32( tParticle->m_color, MIN( 1.0, color[0] * colorRamp ), MIN( 1.0, color[1] * colorRamp ), MIN( 1.0, color[2] * colorRamp ), 1.0f ); + } + } + } + + if ((flags & FX_BLOODSPRAY_GORE) || (flags & FX_BLOODSPRAY_CLOUD)) + { + CSmartPtr<CBloodSprayEmitter> pSimple = CBloodSprayEmitter::Create( "bloodgore" ); + if ( !pSimple ) + return; + + pSimple->SetSortOrigin( origin ); + pSimple->SetGravity( 0 ); + + PMaterialHandle hMaterial; + + // + // Tight blossom of blood at the center. + // + if (flags & FX_BLOODSPRAY_GORE) + { + hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_gore" ); + + SimpleParticle *pParticle; + + for ( i = 0; i < 6; i++ ) + { + // Originate from within a circle 'scale' inches in diameter. + offset = origin + ( 0.5 * scale * vecNormal ); + offset += right * random->RandomFloat( -0.5f, 0.5f ) * scale; + offset += up * random->RandomFloat( -0.5f, 0.5f ) * scale; + + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, offset ); + + if ( pParticle != NULL ) + { + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = 0.3f; + + spread = 0.2f; + pParticle->m_vecVelocity.Random( -spread, spread ); + pParticle->m_vecVelocity += vecNormal * random->RandomInt( 10, 100 ); + //VectorNormalize( pParticle->m_vecVelocity ); + + colorRamp = random->RandomFloat( 0.75f, 1.0f ) + flLODDistance; + + pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f; + pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f; + pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f; + + pParticle->m_uchStartSize = random->RandomFloat( scale, scale * 4 ) * flDistanceScale; + pParticle->m_uchEndSize = pParticle->m_uchStartSize * 2 * flDistanceScale; + + pParticle->m_uchStartAlpha = random->RandomInt( 200, 255 ); + pParticle->m_uchEndAlpha = 0; + + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = random->RandomFloat( -4.0f, 4.0f ); + } + } + } + + // + // Diffuse cloud just in front of the exit wound. + // + if (flags & FX_BLOODSPRAY_CLOUD) + { + hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_puff" ); + + SimpleParticle *pParticle; + + for ( i = 0; i < 6; i++ ) + { + // Originate from within a circle '2 * scale' inches in diameter. + offset = origin + ( scale * vecNormal * 0.5 ); + offset += right * random->RandomFloat( -1, 1 ) * scale; + offset += up * random->RandomFloat( -1, 1 ) * scale; + + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, offset ); + + if ( pParticle != NULL ) + { + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = random->RandomFloat( 0.5f, 0.8f); + + spread = 0.5f; + pParticle->m_vecVelocity.Random( -spread, spread ); + pParticle->m_vecVelocity += vecNormal * random->RandomInt( 100, 200 ); + + colorRamp = random->RandomFloat( 0.5f, 0.75f ) + flLODDistance; + + pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f; + pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f; + pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f; + + pParticle->m_uchStartSize = random->RandomFloat( scale * 0.5, scale ) * flDistanceScale; + pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4 * flDistanceScale; + + pParticle->m_uchStartAlpha = random->RandomInt( 80, 128 ); + pParticle->m_uchEndAlpha = 0; + + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = random->RandomFloat( -4.0f, 4.0f ); + } + } + } + } + + // TODO: Play a sound? + //CLocalPlayerFilter filter; + //C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, CHAN_VOICE, "Physics.WaterSplash", 1.0, ATTN_NORM, 0, 100, &origin ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : bloodtype - +// r - +// g - +// b - +//----------------------------------------------------------------------------- +void GetBloodColorForTeam( int iTeam, unsigned char &r, unsigned char &g, unsigned char &b ) +{ + if ( iTeam == TEAM_ALIENS ) + { + r = 0; + g = 255; + b = 0; + } + else if ( iTeam == TEAM_HUMANS ) + { + // Humans + r = 255; + g = 0; + b = 0; + } + else + { + // NPCs? + r = 200; + g = 0; + b = 0; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Intercepts the blood spray message. +//----------------------------------------------------------------------------- +void TF2BloodSprayCallback( const CEffectData &data ) +{ + unsigned char r = 0; + unsigned char g = 0; + unsigned char b = 0; + + // Get the entity we've hit + C_BaseEntity *pEntity = ClientEntityList().GetEnt( data.m_nEntIndex ); + if ( pEntity ) + { + GetBloodColorForTeam( pEntity->GetTeamNumber(), r, g, b ); + if ( pEntity->IsPlayer() ) + { + C_BaseTFPlayer *pPlayer = (C_BaseTFPlayer *)pEntity; + pPlayer->PainSound(); + } + } + else + { + GetBloodColorForTeam( 0, r, g, b ); + } + FX_TF2_BloodSpray( data.m_vOrigin, data.m_vNormal, data.m_flScale, r, g, b, data.m_fFlags ); +} + +DECLARE_CLIENT_EFFECT( "tf2blood", TF2BloodSprayCallback ); diff --git a/game/client/tf2/fx_tf2_buildeffects.cpp b/game/client/tf2/fx_tf2_buildeffects.cpp new file mode 100644 index 0000000..086ba82 --- /dev/null +++ b/game/client/tf2/fx_tf2_buildeffects.cpp @@ -0,0 +1,737 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Effects played when objects are building +// +//=============================================================================// + +#include "cbase.h" +#include "clienteffectprecachesystem.h" +#include "fx_sparks.h" +#include "iefx.h" +#include "c_te_effect_dispatch.h" +#include "particles_ez.h" +#include "decals.h" +#include "engine/IEngineSound.h" +#include "fx_quad.h" +#include "engine/ivdebugoverlay.h" +#include "shareddefs.h" +#include "tf_shareddefs.h" +#include "c_impact_effects.h" +#include "fx.h" +#include "iviewrender_beams.h" +#include "view.h" +#include "IEffects.h" +#include "c_tracer.h" + +CLIENTEFFECT_REGISTER_BEGIN( PrecacheTF2EffectBuild ) +CLIENTEFFECT_MATERIAL( "effects/blood" ) +CLIENTEFFECT_MATERIAL( "effects/human_build_warp" ) +CLIENTEFFECT_MATERIAL( "effects/tesla_glow_noz" ) +CLIENTEFFECT_MATERIAL( "particle/particle_smokegrenade" ) +CLIENTEFFECT_MATERIAL( "effects/human_tracers/human_sparksprite_A1" ) +CLIENTEFFECT_MATERIAL( "effects/human_tracers/human_sparktracer_A_" ) +CLIENTEFFECT_MATERIAL( "effects/alien_tracers/alien_pbtracer_A_" ) +CLIENTEFFECT_MATERIAL( "effects/alien_tracers/alien_pbsprite_A1" ) +CLIENTEFFECT_REGISTER_END() + + +//----------------------------------------------------------------------------- +// Purpose: Build impact +//----------------------------------------------------------------------------- +void FX_BuildImpact( const Vector &origin, const QAngle &vecAngles, const Vector &vecNormal, float flScale, bool bGround = false, CBaseEntity *pIgnore = NULL ) +{ + Vector offset; + float spread = 0.1f; + + CSmartPtr<CDustParticle> pSimple = CDustParticle::Create( "dust" ); + pSimple->SetSortOrigin( origin ); + + SimpleParticle *pParticle; + + Vector color( 0.35, 0.35, 0.35 ); + float colorRamp; + + // If we're hitting the ground, try and get the ground color + if ( bGround ) + { + trace_t tr; + UTIL_TraceLine( origin, origin + Vector(0,0,-32), MASK_SHOT, pIgnore, COLLISION_GROUP_NONE, &tr ); + GetColorForSurface( &tr, &color ); + } + + int iNumPuffs = 8; + for ( int i = 0; i < iNumPuffs; i++ ) + { + QAngle vecTemp = vecAngles; + vecTemp[YAW] += (360 / iNumPuffs) * i; + Vector vecForward; + AngleVectors( vecTemp, &vecForward ); + + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], origin ); + + if ( pParticle != NULL ) + { + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = RandomFloat( 0.5f, 1.0f ); + + pParticle->m_vecVelocity.Random( -spread, spread ); + pParticle->m_vecVelocity += ( vecForward * RandomFloat( 1.0f, 6.0f ) ); + + VectorNormalize( pParticle->m_vecVelocity ); + + float fForce = RandomFloat( 500, 750 ); + + // scaled + pParticle->m_vecVelocity *= fForce * flScale; + + colorRamp = RandomFloat( 0.75f, 1.25f ); + pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f; + pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f; + pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f; + + // scaled + pParticle->m_uchStartSize = flScale * RandomInt( 15, 20 ); + + // scaled + pParticle->m_uchEndSize = flScale * pParticle->m_uchStartSize * 4; + + pParticle->m_uchStartAlpha = RandomInt( 32, 255 ); + pParticle->m_uchEndAlpha = 0; + + pParticle->m_flRoll = RandomInt( 0, 360 ); + pParticle->m_flRollDelta = RandomFloat( -8.0f, 8.0f ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Large dust impact +//----------------------------------------------------------------------------- +void BuildImpactCallback( const CEffectData &data ) +{ + Vector vecOrigin = data.m_vOrigin; + QAngle vecAngles = data.m_vAngles; + Vector vecNormal = data.m_vNormal; + + FX_BuildImpact( vecOrigin, vecAngles, vecNormal, 1 ); + + // Randomly play sparks + if ( RandomFloat() > 0.35 ) + { + // Angle them up + vecAngles[PITCH] = -90; + Vector vecForward; + AngleVectors( vecAngles, &vecForward ); + + // Sparks + FX_Sparks( vecOrigin, 2, 4, vecForward, 2.5, 48, 64 ); + } +} + +DECLARE_CLIENT_EFFECT( "BuildImpact", BuildImpactCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Small dust impact +//----------------------------------------------------------------------------- +void BuildImpactSmallCallback( const CEffectData &data ) +{ + Vector vecOrigin = data.m_vOrigin; + QAngle vecAngles = data.m_vAngles; + Vector vecNormal = data.m_vNormal; + + FX_BuildImpact( vecOrigin, vecAngles, vecNormal, 0.65 ); +} + +DECLARE_CLIENT_EFFECT( "BuildImpactSmall", BuildImpactSmallCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Large dust impact to be used only when something's landed on the ground +//----------------------------------------------------------------------------- +void BuildImpactGroundCallback( const CEffectData &data ) +{ + Vector vecOrigin = data.m_vOrigin; + QAngle vecAngles = data.m_vAngles; + Vector vecNormal = data.m_vNormal; + int iEntIndex = data.m_nEntIndex; + + C_BaseEntity *pEntity = ClientEntityList().GetEnt( iEntIndex ); + FX_BuildImpact( vecOrigin, vecAngles, vecNormal, 1, true, pEntity ); +} + +DECLARE_CLIENT_EFFECT( "BuildImpactGround", BuildImpactGroundCallback ); + + +//----------------------------------------------------------------------------- +// Purpose: Create a tesla effect between two points +//----------------------------------------------------------------------------- +void TF2_FX_BuildTesla( C_BaseEntity *pEntity, Vector &vecOrigin, Vector &vecEnd ) +{ + BeamInfo_t beamInfo; + beamInfo.m_nType = TE_BEAMTESLA; + beamInfo.m_vecStart = vecOrigin; + beamInfo.m_vecEnd = vecEnd; + beamInfo.m_pszModelName = "sprites/physbeam.vmt"; + beamInfo.m_flHaloScale = 0.0; + beamInfo.m_flLife = RandomFloat( 0.3, 0.55 ); + beamInfo.m_flWidth = 5.0; + beamInfo.m_flEndWidth = 1; + beamInfo.m_flFadeLength = 0.3; + beamInfo.m_flAmplitude = 16; + beamInfo.m_flBrightness = 200.0; + beamInfo.m_flSpeed = 0.0; + beamInfo.m_nStartFrame = 0.0; + beamInfo.m_flFrameRate = 1.0; + beamInfo.m_flRed = 255.0; + beamInfo.m_flGreen = 255.0; + beamInfo.m_flBlue = 255.0; + beamInfo.m_nSegments = 20; + beamInfo.m_bRenderable = true; + beamInfo.m_nFlags = FBEAM_ONLYNOISEONCE; + + beams->CreateBeamPoints( beamInfo ); +} + +//----------------------------------------------------------------------------- +// Purpose: Tesla effect +//----------------------------------------------------------------------------- +void TF2_BuildTeslaCallback( const CEffectData &data ) +{ + Vector vecOrigin = data.m_vOrigin; + QAngle vecAngles = data.m_vAngles; + int iEntIndex = data.m_nEntIndex; + C_BaseEntity *pEntity = ClientEntityList().GetEnt( iEntIndex ); + + // Send out beams around us + int iNumBeamsAround = 4; + int iNumRandomBeams = 2; + int iTotalBeams = iNumBeamsAround + iNumRandomBeams; + float flYawOffset = RandomFloat(0,360); + for ( int i = 0; i < iTotalBeams; i++ ) + { + // Make a couple of tries at it + int iTries = -1; + Vector vecForward; + trace_t tr; + do + { + iTries++; + + // Some beams are deliberatly aimed around the point, the rest are random. + if ( i < iNumBeamsAround ) + { + QAngle vecTemp = vecAngles; + vecTemp[YAW] += anglemod( flYawOffset + ((360 / iTotalBeams) * i) ); + AngleVectors( vecTemp, &vecForward ); + + // Randomly angle it up or down + vecForward.z = RandomFloat( -1, 1 ); + } + else + { + vecForward = RandomVector( -1, 1 ); + } + + UTIL_TraceLine( vecOrigin, vecOrigin + (vecForward * 192), MASK_SHOT, pEntity, COLLISION_GROUP_NONE, &tr ); + } while ( tr.fraction >= 1.0 && iTries < 3 ); + + Vector vecEnd = tr.endpos - (vecForward * 8); + + // Only spark & glow if we hit something + if ( tr.fraction < 1.0 ) + { + if ( !EffectOccluded( tr.endpos ) ) + { + // Move it towards the camera + Vector vecFlash = tr.endpos; + Vector vecForward; + AngleVectors( MainViewAngles(), &vecForward ); + vecFlash -= (vecForward * 8); + + g_pEffects->EnergySplash( vecFlash, -vecForward, false ); + + // End glow + CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "dust" ); + pSimple->SetSortOrigin( vecFlash ); + SimpleParticle *pParticle; + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "effects/tesla_glow_noz" ), vecFlash ); + if ( pParticle != NULL ) + { + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = RandomFloat( 0.5, 1 ); + pParticle->m_vecVelocity = vec3_origin; + Vector color( 1,1,1 ); + float colorRamp = RandomFloat( 0.75f, 1.25f ); + pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f; + pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f; + pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f; + pParticle->m_uchStartSize = RandomFloat( 6,13 ); + pParticle->m_uchEndSize = pParticle->m_uchStartSize - 2; + pParticle->m_uchStartAlpha = 255; + pParticle->m_uchEndAlpha = 10; + pParticle->m_flRoll = RandomFloat( 0,360 ); + pParticle->m_flRollDelta = 0; + } + } + } + + // Build the tesla + TF2_FX_BuildTesla( pEntity, vecOrigin, tr.endpos ); + } +} + +DECLARE_CLIENT_EFFECT( "TF2BuildTesla", TF2_BuildTeslaCallback ); + +//----------------------------------------------------------------------------- +// Purpose: WarpParticle emitter +// This is a particle that scales up to its max size in WARPEMMITER_MIDPOINT +// of it's lifetime, the drops back to its initial size by the end of its life. +// Alpha scales the same way. +//----------------------------------------------------------------------------- +#define WARPEMMITER_MIDPOINT 0.6 + +class CWarpParticleEmitter : public CSimpleEmitter +{ +public: + + CWarpParticleEmitter( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {} + + //Create + static CWarpParticleEmitter *Create( const char *pDebugName="dust" ) + { + return new CWarpParticleEmitter( pDebugName ); + } + + // Scale + virtual float UpdateScale( const SimpleParticle *pParticle ) + { + float tLifeTime = pParticle->m_flLifetime / pParticle->m_flDieTime; + + // Ramp up for the first 75% of my life, then reduce for the rest + if ( tLifeTime < WARPEMMITER_MIDPOINT ) + { + tLifeTime = RemapVal( tLifeTime, 0, WARPEMMITER_MIDPOINT, 0, 1.0 ); + return (float)pParticle->m_uchStartSize + ( (float)pParticle->m_uchEndSize - (float)pParticle->m_uchStartSize ) * tLifeTime; + } + + tLifeTime -= WARPEMMITER_MIDPOINT; + tLifeTime = RemapVal( tLifeTime, 0, 1 - WARPEMMITER_MIDPOINT, 0, 1.0 ); + return (float)pParticle->m_uchEndSize - ( (float)pParticle->m_uchEndSize - (float)pParticle->m_uchStartSize ) * tLifeTime; + } + + //Alpha + virtual float UpdateAlpha( const SimpleParticle *pParticle ) + { + float tLifeTime = pParticle->m_flLifetime / pParticle->m_flDieTime; + float flAlpha = 0; + + // Ramp up for the first 75% of my life, then reduce for the rest + if ( tLifeTime < WARPEMMITER_MIDPOINT ) + { + tLifeTime = RemapVal( tLifeTime, 0, WARPEMMITER_MIDPOINT, 0, 1.0 ); + flAlpha = (float)pParticle->m_uchStartAlpha + ( (float)pParticle->m_uchEndAlpha - (float)pParticle->m_uchStartAlpha ) * tLifeTime; + } + else + { + tLifeTime -= WARPEMMITER_MIDPOINT; + tLifeTime = RemapVal( tLifeTime, 0, 1 - WARPEMMITER_MIDPOINT, 0, 1.0 ); + flAlpha = (float)pParticle->m_uchEndAlpha - ( (float)pParticle->m_uchEndAlpha - (float)pParticle->m_uchStartAlpha ) * tLifeTime; + } + + flAlpha = flAlpha / 255; + return flAlpha; + } + +private: + CWarpParticleEmitter( const CWarpParticleEmitter & ); // not defined, not accessible +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void FX_BuildWarp( Vector &vecOrigin, QAngle &vecAngles, float flScale ) +{ + if ( EffectOccluded( vecOrigin ) ) + return; + + CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "dust" ); + pSimple->SetSortOrigin( vecOrigin ); + + SimpleParticle *pParticle; + + Vector color( 1, 1, 1 ); + float colorRamp; + + // Big flash + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "effects/blueflare2" ), vecOrigin ); + if ( pParticle != NULL ) + { + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = 0.5; + pParticle->m_vecVelocity = vec3_origin; + colorRamp = RandomFloat( 0.75f, 1.25f ); + pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f; + pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f; + pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f; + pParticle->m_uchStartSize = RandomFloat( 10,15 ); + pParticle->m_uchEndSize = pParticle->m_uchStartSize * 8 * flScale; + pParticle->m_uchStartAlpha = 48; + pParticle->m_uchEndAlpha = 0; + pParticle->m_flRoll = 0; + pParticle->m_flRollDelta = 0; + } + + // Bright light + // Move it towards the camera + Vector vecForward; + AngleVectors( MainViewAngles(), &vecForward ); + vecOrigin -= (vecForward * 8); + CSmartPtr<CWarpParticleEmitter> pWarpEmitter = CWarpParticleEmitter::Create( "dust" ); + pWarpEmitter->SetSortOrigin( vecOrigin ); + + pParticle = (SimpleParticle *) pWarpEmitter->AddParticle( sizeof( SimpleParticle ), pWarpEmitter->GetPMaterial( "effects/human_build_warp" ), vecOrigin ); + if ( pParticle != NULL ) + { + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = 0.4; + pParticle->m_vecVelocity = vec3_origin; + + colorRamp = RandomFloat( 0.75f, 1.25f ); + pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f; + pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f; + pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f; + + pParticle->m_uchStartSize = RandomInt( 10,13 ) * flScale; + pParticle->m_uchEndSize = pParticle->m_uchStartSize * 9; + + pParticle->m_uchStartAlpha = 32; + pParticle->m_uchEndAlpha = 192; + + pParticle->m_flRoll = 0; + pParticle->m_flRollDelta = 0; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Warp effect +//----------------------------------------------------------------------------- +void BuildWarpCallback( const CEffectData &data ) +{ + Vector vecOrigin = data.m_vOrigin; + QAngle vecAngles = data.m_vAngles; + + // Warp effect + FX_BuildWarp( vecOrigin, vecAngles, 2 ); + g_pEffects->EnergySplash( vecOrigin, Vector(0,0,1), false ); +} + +DECLARE_CLIENT_EFFECT( "BuildWarp", BuildWarpCallback ); + + +//----------------------------------------------------------------------------- +// Purpose: Small Warp effect +//----------------------------------------------------------------------------- +void BuildWarpSmallCallback( const CEffectData &data ) +{ + Vector vecOrigin = data.m_vOrigin; + QAngle vecAngles = data.m_vAngles; + + // Warp effect + FX_BuildWarp( vecOrigin, vecAngles, 1.5 ); + g_pEffects->EnergySplash( vecOrigin, Vector(0,0,1), false ); +} + +DECLARE_CLIENT_EFFECT( "BuildWarpSmall", BuildWarpSmallCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Spark effects +//----------------------------------------------------------------------------- +void BuildSparksCallback( const CEffectData &data ) +{ + Vector vecOrigin = data.m_vOrigin; + QAngle vecAngles = data.m_vAngles; + + // Angle them up + vecAngles[PITCH] = -90; + Vector vecForward; + AngleVectors( vecAngles, &vecForward ); + + // Sparks + FX_Sparks( vecOrigin, 2, 4, vecForward, 2.5, 48, 64 ); +} + +DECLARE_CLIENT_EFFECT( "BuildSparks", BuildSparksCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Red Spark effects +//----------------------------------------------------------------------------- +void BuildSparksRedCallback( const CEffectData &data ) +{ + Vector vecOrigin = data.m_vOrigin; + QAngle vecAngles = data.m_vAngles; + + // Angle them up + vecAngles[PITCH] = -90; + Vector vecForward; + AngleVectors( vecAngles, &vecForward ); + + // Sparks + FX_Sparks( vecOrigin, 2, 4, vecForward, 2.5, 48, 64, "effects/spark2" ); +} + +DECLARE_CLIENT_EFFECT( "BuildSparksRed", BuildSparksRedCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Electric sparks effect +//----------------------------------------------------------------------------- +void BuildSparksElectricCallback( const CEffectData &data ) +{ + Vector vecOrigin = data.m_vOrigin; + Vector vecNormal = data.m_vNormal; + + // Sparks + FX_ElectricSpark( vecOrigin, 2, 4, &vecNormal ); +} + +DECLARE_CLIENT_EFFECT( "BuildSparksElectric", BuildSparksElectricCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Metal sparks effect +//----------------------------------------------------------------------------- +void BuildSparksMetalCallback( const CEffectData &data ) +{ + Vector vecOrigin = data.m_vOrigin; + Vector vecNormal = data.m_vNormal; + + // Sparks + FX_MetalSpark( vecOrigin, vecNormal, vecNormal, 2 ); +} + +DECLARE_CLIENT_EFFECT( "BuildSparksMetal", BuildSparksMetalCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Metal scrape effect +//----------------------------------------------------------------------------- +void BuildMetalScrapeCallback( const CEffectData &data ) +{ + Vector vecOrigin = data.m_vOrigin; + Vector vecNormal = data.m_vNormal; + + // Sparks + FX_MetalScrape( vecOrigin, vecNormal ); +} + +DECLARE_CLIENT_EFFECT( "BuildMetalScrape", BuildMetalScrapeCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Warp effect that looks like it's sucking things to it +//----------------------------------------------------------------------------- +void FX_BuildWarpSuck( Vector &vecOrigin, QAngle &vecAngles, float flScale ) +{ + CSmartPtr<CTrailParticles> pEmitter = CTrailParticles::Create( "BuildWarpSuck" ); + PMaterialHandle hParticleMaterial = pEmitter->GetPMaterial( "effects/bluespark" ); + pEmitter->Setup( (Vector &) vecOrigin, + NULL, + 0.0, + 0, + 64, + 0, + 0, + bitsPARTICLE_TRAIL_VELOCITY_DAMPEN | bitsPARTICLE_TRAIL_FADE ); + + // Add particles + int iNumParticles = 60; + for ( int i = 0; i < iNumParticles; i++ ) + { + Vector vOffset = RandomVector( -1, 1 ); + VectorNormalize( vOffset ); + float flDistance = RandomFloat( 16, 64 ) * flScale; + Vector vPos = vecOrigin + (vOffset * flDistance); + + TrailParticle *pParticle = (TrailParticle *) pEmitter->AddParticle( sizeof(TrailParticle), hParticleMaterial, vPos ); + if ( pParticle ) + { + float flSpeed = RandomFloat(8,16) * (flScale * flScale * flScale); + pParticle->m_vecVelocity = vOffset * -flSpeed; + pParticle->m_flDieTime = MIN( 3, (flDistance / flSpeed) + RandomFloat(0.0, 0.2) ); + pParticle->m_flLifetime = 0; + pParticle->m_flWidth = RandomFloat( 2, 3 ) * flScale; + pParticle->m_flLength = RandomFloat( 1, 2 ) * flScale; + + Color32Init( pParticle->m_color, 255, 255, 255, 255 ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Warp effect that looks like it's sucking things to it +//----------------------------------------------------------------------------- +void BuildWarpSuckCallback( const CEffectData &data ) +{ + Vector vecOrigin = data.m_vOrigin; + QAngle vecAngles = data.m_vAngles; + + FX_BuildWarpSuck( vecOrigin, vecAngles, 1.0 ); +} + +DECLARE_CLIENT_EFFECT( "BuildWarpSuck", BuildWarpSuckCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Bigger Warp effect that looks like it's sucking things to it +//----------------------------------------------------------------------------- +void BuildWarpSuckBigCallback( const CEffectData &data ) +{ + Vector vecOrigin = data.m_vOrigin; + QAngle vecAngles = data.m_vAngles; + + FX_BuildWarpSuck( vecOrigin, vecAngles, 2.0 ); +} + +DECLARE_CLIENT_EFFECT( "BuildWarpSuckBig", BuildWarpSuckBigCallback ); + +//----------------------------------------------------------------------------- +// Purpose: GasSpurt Emitter +// This is an emitter that keeps spitting out particles for its lifetime +// It won't create particles if it's not in view, so it's best when short lived +//----------------------------------------------------------------------------- +class CGasSpurtEmitter : public CSimpleEmitter +{ + typedef CSimpleEmitter BaseClass; +public: + CGasSpurtEmitter( const char *pDebugName ) : CSimpleEmitter( pDebugName ) + { + m_flDeathTime = 0; + m_flLastParticleSpawnTime = 0; + } + + // Create + static CGasSpurtEmitter *Create( const char *pDebugName="gasspurt" ) + { + return new CGasSpurtEmitter( pDebugName ); + } + + void SetLifeTime( float flTime ) + { + m_flDeathTime = gpGlobals->curtime + flTime; + } + + void SetSpurtAngle( QAngle &vecAngles ) + { + AngleVectors( vecAngles, &m_vecSpurtForward ); + } + + void SetSpurtColor( const Vector4D &pColor ) + { + for ( int i = 0; i <= 3; i++ ) + { + m_SpurtColor[i] = pColor[i]; + } + } + + void SetSpawnRate( float flRate ) + { + m_flSpawnRate = flRate; + } + + void CreateSpurtParticles( void ) + { + SimpleParticle *pParticle; + + // Smoke + int numParticles = RandomInt( 1,2 ); + for ( int i = 0; i < numParticles; i++ ) + { + pParticle = (SimpleParticle *) AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], m_vSortOrigin ); + if ( pParticle == NULL ) + break; + + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = RandomFloat( 0.5, 1.0 ); + + // Random velocity around the angles forward + Vector vecVelocity; + vecVelocity.Random( -0.1f, 0.1f ); + vecVelocity += m_vecSpurtForward; + VectorNormalize( vecVelocity ); + vecVelocity *= RandomFloat( 16.0f, 64.0f ); + pParticle->m_vecVelocity = vecVelocity; + + // Randomize the color a little + int color[3][2]; + for( int i = 0; i < 3; ++i ) + { + color[i][0] = MAX( 0, m_SpurtColor[i] - 64 ); + color[i][1] = MIN( 255, m_SpurtColor[i] + 64 ); + } + pParticle->m_uchColor[0] = random->RandomInt( color[0][0], color[0][1] ); + pParticle->m_uchColor[1] = random->RandomInt( color[1][0], color[1][1] ); + pParticle->m_uchColor[2] = random->RandomInt( color[2][0], color[2][1] ); + + pParticle->m_uchStartAlpha = m_SpurtColor[3]; + pParticle->m_uchEndAlpha = 0; + pParticle->m_uchStartSize = RandomInt( 1, 2 ); + pParticle->m_uchEndSize = pParticle->m_uchStartSize*3; + pParticle->m_flRoll = RandomFloat( 0, 360 ); + pParticle->m_flRollDelta = RandomFloat( -4.0f, 4.0f ); + } + + m_flLastParticleSpawnTime = gpGlobals->curtime + m_flSpawnRate; + } + + virtual void SimulateParticles( CParticleSimulateIterator *pIterator ) + { + Particle *pParticle = (Particle*)pIterator->GetFirst(); + while ( pParticle ) + { + // If our lifetime isn't up, create more particles + if ( m_flDeathTime > gpGlobals->curtime ) + { + if ( m_flLastParticleSpawnTime <= gpGlobals->curtime ) + { + CreateSpurtParticles(); + } + } + + pParticle = (Particle*)pIterator->GetNext(); + } + + BaseClass::SimulateParticles( pIterator ); + } + + +private: + float m_flDeathTime; + float m_flLastParticleSpawnTime; + float m_flSpawnRate; + Vector m_vecSpurtForward; + Vector4D m_SpurtColor; + + CGasSpurtEmitter( const CGasSpurtEmitter & ); // not defined, not accessible +}; + +//----------------------------------------------------------------------------- +// Purpose: Small hose gas spurt +//----------------------------------------------------------------------------- +void FX_BuildGasSpurt( Vector &vecOrigin, QAngle &vecAngles, float flLifeTime, const Vector4D &pColor ) +{ + CSmartPtr<CGasSpurtEmitter> pSimple = CGasSpurtEmitter::Create( "FX_Smoke" ); + pSimple->SetSortOrigin( vecOrigin ); + pSimple->SetLifeTime( flLifeTime ); + pSimple->SetSpurtAngle( vecAngles ); + pSimple->SetSpurtColor( pColor ); + pSimple->SetSpawnRate( 0.03 ); + pSimple->CreateSpurtParticles(); +} + +//----------------------------------------------------------------------------- +// Purpose: Green hose gas spurt +//----------------------------------------------------------------------------- +void GasGreenCallback( const CEffectData &data ) +{ + Vector vecOrigin = data.m_vOrigin; + QAngle vecAngles = data.m_vAngles; + + Vector4D color( 50,192,50,255 ); + FX_BuildGasSpurt( vecOrigin, vecAngles, 1.0, color ); +} + +DECLARE_CLIENT_EFFECT( "GasGreen", GasGreenCallback ); diff --git a/game/client/tf2/fx_tf2_impacts.cpp b/game/client/tf2/fx_tf2_impacts.cpp new file mode 100644 index 0000000..e22c70d --- /dev/null +++ b/game/client/tf2/fx_tf2_impacts.cpp @@ -0,0 +1,453 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Game-specific impact effect hooks +// +//=============================================================================// +#include "cbase.h" +#include "fx_impact.h" +#include "decals.h" +#include "IEffects.h" +#include "c_breakableprop.h" +#include "tempent.h" +#include "c_te_legacytempents.h" +#include "tf_shareddefs.h" +#include "fx.h" + +void ImpactCreateHurtShards( Vector &vecOrigin, trace_t &tr, Vector &shotDir, int iMaterial, bool bLarge, bool bBlood ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void MakeHurt( const CEffectData &data, bool bBlood ) +{ + trace_t tr; + Vector vecOrigin, vecStart, vecShotDir; + int iMaterial, iDamageType, iHitbox; + short nSurfaceProp; + C_BaseEntity *pEntity = ParseImpactData( data, &vecOrigin, &vecStart, &vecShotDir, nSurfaceProp, iMaterial, iDamageType, iHitbox ); + + if ( !pEntity ) + return; + + // If we hit, perform our custom effects and play the sound + if ( Impact( vecOrigin, vecStart, iMaterial, iDamageType, iHitbox, pEntity, tr ) ) + { + // Throw out shards to show the player he's hurting it + ImpactCreateHurtShards( vecOrigin, tr, vecShotDir, iMaterial, false, bBlood ); + + // Check for custom effects based on the Decal index + PerformCustomEffects( vecOrigin, tr, vecShotDir, iMaterial, 1.0 ); + } + + PlayImpactSound( pEntity, tr, vecOrigin, nSurfaceProp ); +} + +//----------------------------------------------------------------------------- +// Purpose: Impact for: +// Bullets hitting targets that CAN be hurt +//----------------------------------------------------------------------------- +void ImpactCallback( const CEffectData &data ) +{ + MakeHurt( data, true ); +} + +DECLARE_CLIENT_EFFECT( "Impact", ImpactCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Bloodless Impact for: +// Bullets hitting targets that CAN be hurt +//----------------------------------------------------------------------------- +void ImpactNoBloodCallback( const CEffectData &data ) +{ + MakeHurt( data, false ); +} + +DECLARE_CLIENT_EFFECT( "ImpactNoBlood", ImpactNoBloodCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Impact for: +// Bullets hitting targets that CANNOT be hurt +//----------------------------------------------------------------------------- +void ImpactUnhurtCallback( const CEffectData &data ) +{ + trace_t tr; + Vector vecOrigin, vecStart, vecShotDir; + int iMaterial, iDamageType, iHitbox; + short nSurfaceProp; + C_BaseEntity *pEntity = ParseImpactData( data, &vecOrigin, &vecStart, &vecShotDir, nSurfaceProp, iMaterial, iDamageType, iHitbox ); + + if ( !pEntity ) + return; + + // If we hit, perform our custom effects and play the sound + // Don't decal team members, but decal everything else + + bool bShouldDecal = !( pEntity && pEntity->IsPlayer() ); + if ( Impact( vecOrigin, vecStart, iMaterial, iDamageType, iHitbox, pEntity, tr, bShouldDecal ? 0 : IMPACT_NODECAL ) ) + { + // Check for custom effects based on the Decal index + PerformCustomEffects( vecOrigin, tr, vecShotDir, iMaterial, 0 ); + } + + PlayImpactSound( pEntity, tr, vecOrigin, nSurfaceProp ); +} + +DECLARE_CLIENT_EFFECT( "ImpactUnhurt", ImpactUnhurtCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Impact for: +// Bullets hitting player's handheld shields +//----------------------------------------------------------------------------- +void ImpactShieldCallback( const CEffectData &data ) +{ + trace_t tr; + Vector vecOrigin, vecStart, vecShotDir; + int iMaterial, iDamageType, iHitbox; + short nSurfaceProp; + ParseImpactData( data, &vecOrigin, &vecStart, &vecShotDir, nSurfaceProp, iMaterial, iDamageType, iHitbox ); + + // Don't call Impact() because we don't want to decal the player + Vector reflect = -vecShotDir; + reflect[0] += random->RandomFloat( -0.5f, 0.5f ); + reflect[1] += random->RandomFloat( -0.5f, 0.5f ); + reflect[2] += random->RandomFloat( 0, 0.5f ); + FX_MetalSpark( vecOrigin, reflect, -vecShotDir, 3 ); +} + +DECLARE_CLIENT_EFFECT( "ImpactShield", ImpactShieldCallback ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void MakePlasmaHurt( const CEffectData &data, bool bBlood ) +{ + trace_t tr; + Vector vecOrigin, vecStart, vecShotDir; + int iMaterial, iDamageType, iHitbox; + short nSurfaceProp; + C_BaseEntity *pEntity = ParseImpactData( data, &vecOrigin, &vecStart, &vecShotDir, nSurfaceProp, iMaterial, iDamageType, iHitbox ); + + if ( !pEntity ) + return; + + // If we hit, play our splash + if ( Impact( vecOrigin, vecStart, iMaterial, iDamageType, iHitbox, pEntity, tr ) ) + { + // Throw out shards to show the player he's hurting it + ImpactCreateHurtShards( vecOrigin, tr, vecShotDir, iMaterial, false, bBlood ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Impact for: +// Plasma hitting targets that CAN be hurt +//----------------------------------------------------------------------------- +void ImpactPlasmaCallback( const CEffectData &data ) +{ + MakePlasmaHurt( data, true ); +} + +DECLARE_CLIENT_EFFECT( "PlasmaHurt", ImpactPlasmaCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Impact for: +// Plasma hitting targets that CAN be hurt +//----------------------------------------------------------------------------- +void ImpactPlasmaNoBloodCallback( const CEffectData &data ) +{ + MakePlasmaHurt( data, false ); +} + +DECLARE_CLIENT_EFFECT( "PlasmaHurtNoBlood", ImpactPlasmaNoBloodCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Impact for: +// Plasma hitting targets that CANNOT be hurt +//----------------------------------------------------------------------------- +void ImpactPlasmaUnhurtCallback( const CEffectData &data ) +{ + trace_t tr; + Vector vecOrigin, vecStart, vecShotDir; + int iMaterial, iDamageType, iHitbox; + short nSurfaceProp; + C_BaseEntity *pEntity = ParseImpactData( data, &vecOrigin, &vecStart, &vecShotDir, nSurfaceProp, iMaterial, iDamageType, iHitbox ); + + if ( !pEntity ) + return; + + // If we hit, play our splash + + bool bShouldDecal = !( pEntity && pEntity->IsPlayer() ); + if ( Impact( vecOrigin, vecStart, iMaterial, iDamageType, iHitbox, pEntity, tr, bShouldDecal ? 0 : IMPACT_NODECAL ) ) + { + g_pEffects->EnergySplash( vecOrigin, tr.plane.normal, false ); + } +} + +DECLARE_CLIENT_EFFECT( "PlasmaUnhurt", ImpactPlasmaUnhurtCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Impact for: +// Plasma hitting player's handheld shields +//----------------------------------------------------------------------------- +void ImpactPlasmaShieldCallback( const CEffectData &data ) +{ + trace_t tr; + Vector vecOrigin, vecStart, vecShotDir; + int iMaterial, iDamageType, iHitbox; + short nSurfaceProp; + ParseImpactData( data, &vecOrigin, &vecStart, &vecShotDir, nSurfaceProp, iMaterial, iDamageType, iHitbox ); + + // Bounce sparks away from the shield + // Don't call Impact() because we don't want to decal the player + Vector offset = vecOrigin - ( vecShotDir * 1.0f ); + Vector vecDir = -vecShotDir + Vector(0,0,1.5); + g_pEffects->Sparks( offset, 2, 2, &vecDir ); +} + +DECLARE_CLIENT_EFFECT( "PlasmaShield", ImpactPlasmaShieldCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Impact for: +// Strider hitting anything +//----------------------------------------------------------------------------- +void ImpactStriderCallback( const CEffectData &data ) +{ + trace_t tr; + Vector vecOrigin, vecStart, vecShotDir; + int iMaterial, iDamageType, iHitbox; + short nSurfaceProp; + C_BaseEntity *pEntity = ParseImpactData( data, &vecOrigin, &vecStart, &vecShotDir, nSurfaceProp, iMaterial, iDamageType, iHitbox ); + + if ( !pEntity ) + return; + + // If we hit, play our splash + if ( Impact( vecOrigin, vecStart, iMaterial, iDamageType, iHitbox, pEntity, tr ) ) + { + PerformCustomEffects( vecOrigin, tr, vecShotDir, iMaterial, 5 ); + } +} + +DECLARE_CLIENT_EFFECT( "Strider", ImpactStriderCallback ); + + +//===================================================================================== +// SHARDS. +// Models for small impact tempents (not vphysics simulated) +//-------------------------------------------------------------------- +// WOOD +//-------------------------------------------------------------------- +#define WOOD_SHARDS 5 +const char *ImpactHurtShards_Wood_Small_Models[ WOOD_SHARDS ] = +{ +"models/props_debris/wood_shard_001.mdl", +"models/props_debris/wood_shard_002.mdl", +"models/props_debris/wood_shard_003.mdl", +"models/props_debris/wood_shard_004.mdl", +"models/props_debris/wood_shard_005.mdl", +}; +// Model pointers for the above +model_t *ImpactHurtShards_Wood_Small[ WOOD_SHARDS ]; + +//-------------------------------------------------------------------- +// FOLIAGE +//-------------------------------------------------------------------- +#define FOLIAGE_SHARDS 5 +const char *ImpactHurtShards_Foliage_Small_Models[ FOLIAGE_SHARDS ] = +{ +"models/props_debris/foliage_shard_001.mdl", +"models/props_debris/foliage_shard_002.mdl", +"models/props_debris/foliage_shard_003.mdl", +"models/props_debris/foliage_shard_004.mdl", +"models/props_debris/foliage_shard_005.mdl", +}; +// Model pointers for the above +model_t *ImpactHurtShards_Foliage_Small[ FOLIAGE_SHARDS ]; + +//-------------------------------------------------------------------- +// CONCRETE +//-------------------------------------------------------------------- +#define CONCRETE_SHARDS 1 +const char *ImpactHurtShards_Concrete_Small_Models[ CONCRETE_SHARDS ] = +{ +"models/props_debris/metal_shard_001.mdl", +}; +// Model pointers for the above +model_t *ImpactHurtShards_Concrete_Small[ CONCRETE_SHARDS ]; + +//-------------------------------------------------------------------- +// METAL +//-------------------------------------------------------------------- +#define METAL_SHARDS 6 +const char *ImpactHurtShards_Metal_Small_Models[ METAL_SHARDS ] = +{ +"models/props_debris/metal_shard_001.mdl", +"models/props_debris/metal_shard_002.mdl", +"models/props_debris/metal_shard_003.mdl", +"models/props_debris/metal_shard_004.mdl", +"models/props_debris/metal_shard_005.mdl", +"models/props_debris/metal_shard_006.mdl", +}; +// Model pointers for the above +model_t *ImpactHurtShards_Metal_Small[ METAL_SHARDS ]; + +//----------------------------------------------------------------------------- +// Purpose: Precache all our shards +//----------------------------------------------------------------------------- +void PrecacheImpactShards(void *pUser) +{ + int i; + + // Wood + for ( i = 0; i < WOOD_SHARDS; i++ ) + { + const char *sFile = ImpactHurtShards_Wood_Small_Models[i]; + ImpactHurtShards_Wood_Small[i] = (model_t *)engine->LoadModel( sFile ); + } + + // Foliage + for ( i = 0; i < FOLIAGE_SHARDS; i++ ) + { + const char *sFile = ImpactHurtShards_Foliage_Small_Models[i]; + ImpactHurtShards_Foliage_Small[i] = (model_t *)engine->LoadModel( sFile ); + } + + // Concrete + for ( i = 0; i < CONCRETE_SHARDS; i++ ) + { + const char *sFile = ImpactHurtShards_Concrete_Small_Models[i]; + ImpactHurtShards_Concrete_Small[i] = (model_t *)engine->LoadModel( sFile ); + } + + // Metal + for ( i = 0; i < METAL_SHARDS; i++ ) + { + const char *sFile = ImpactHurtShards_Metal_Small_Models[i]; + ImpactHurtShards_Metal_Small[i] = (model_t *)engine->LoadModel( sFile ); + } +} +PRECACHE_REGISTER_FN(PrecacheImpactShards); + +//----------------------------------------------------------------------------- +// Purpose: Throw out shards from the impact point to show we can hurt the target +//----------------------------------------------------------------------------- +void ImpactCreateHurtShards( Vector &vecOrigin, trace_t &tr, Vector &shotDir, int iMaterial, bool bLarge, bool bBlood ) +{ + // Throw out the effect if any of these are true + if ( tr.surface.flags & (SURF_SKY|SURF_NODRAW|SURF_HINT|SURF_SKIP) ) + return; + + float flShardSpread = 0.5; + + Vector vecSpawnOrigin = vecOrigin; + + int iNumGibs = random->RandomInt( 1, 2 ); + for ( int i = 0; i < iNumGibs; i++ ) + { + QAngle vecAngles; + vecAngles[0] = random->RandomFloat(-255, 255); + vecAngles[1] = random->RandomFloat(-255, 255); + vecAngles[2] = random->RandomFloat(-255, 255); + Vector vecForceDir; + float spreadOfs = random->RandomFloat( 3.0f, 4.0f ); + vecForceDir[0] = -shotDir[0] + random->RandomFloat( -(flShardSpread*spreadOfs), (flShardSpread*spreadOfs) ); + vecForceDir[1] = -shotDir[1] + random->RandomFloat( -(flShardSpread*spreadOfs), (flShardSpread*spreadOfs) ); + vecForceDir[2] = -shotDir[2] + random->RandomFloat( -(flShardSpread*spreadOfs), (flShardSpread*spreadOfs) ); + // Add some extra vertical height + vecForceDir[2] += random->RandomFloat( 0, 5 ); + vecForceDir *= random->RandomFloat( 30.0,60.0 ); + + model_t *pModel = NULL; + int iFlags = ( FTENT_COLLIDEWORLD | FTENT_FADEOUT | FTENT_GRAVITY ); + + // Select the right chunk for the job + switch ( iMaterial ) + { + case CHAR_TEX_WOOD: + iFlags |= FTENT_ROTATE; + pModel = ImpactHurtShards_Wood_Small[ random->RandomInt(0,WOOD_SHARDS-1) ]; + break; + + case CHAR_TEX_FOLIAGE: + pModel = ImpactHurtShards_Foliage_Small[ random->RandomInt(0,FOLIAGE_SHARDS-1) ]; + break; + + case CHAR_TEX_METAL: + case CHAR_TEX_VENT: + case CHAR_TEX_GRATE: + + case CHAR_TEX_CONCRETE: + default: + pModel = ImpactHurtShards_Metal_Small[ random->RandomInt(0,METAL_SHARDS-1) ]; + break; + + case CHAR_TEX_FLESH: + // Spray some blood out + if ( !bBlood ) + return; + + CEffectData data; + data.m_vOrigin = vecOrigin; + data.m_vNormal = tr.plane.normal; + data.m_flScale = 4; + data.m_fFlags = FX_BLOODSPRAY_ALL; + data.m_nEntIndex = tr.m_pEnt ? tr.m_pEnt->entindex() : 0; + DispatchEffect( "tf2blood", data ); + return; + break; + /* + case CHAR_TEX_CONCRETE: + default: + pModel = ImpactHurtShards_Concrete_Small[ random->RandomInt(0,CONCRETE_SHARDS-1) ]; + break; + */ + } + Assert( pModel ); + + // ROBIN: Removed until optimized + return; + + // Throw it out + tempents->SpawnTempModel( pModel, vecSpawnOrigin, vecAngles, vecForceDir, random->RandomFloat(0.5,1.5), iFlags ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Throw out breakable, vphysics gibs from the surface we hit +//----------------------------------------------------------------------------- +void ImpactCreateHurtGibs( Vector &vecOrigin, trace_t &tr, Vector &shotDir, int iMaterial, bool bLarge ) +{ + // Throw out the effect if any of these are true + if ( tr.surface.flags & (SURF_SKY|SURF_NODRAW|SURF_HINT|SURF_SKIP) ) + return; + + Vector vecSpawnOrigin = vecOrigin - (shotDir * 32); + float flGibSpread = 0.8; + + // Custom TF2 impact effects + if ( iMaterial == CHAR_TEX_FOLIAGE ) + { + int iNumGibs = random->RandomInt( 1, 2 ); + for ( int i = 0; i < iNumGibs; i++ ) + { + AngularImpulse angVel; + angVel.Random( -400.0f, 400.0f ); + Vector vecForceDir; + float spreadOfs = random->RandomFloat( 3.0f, 4.0f ); + vecForceDir[0] = -shotDir[0] + random->RandomFloat( -(flGibSpread*spreadOfs), (flGibSpread*spreadOfs) ); + vecForceDir[1] = -shotDir[1] + random->RandomFloat( -(flGibSpread*spreadOfs), (flGibSpread*spreadOfs) ); + vecForceDir[2] = -shotDir[2] + random->RandomFloat( -(flGibSpread*spreadOfs), (flGibSpread*spreadOfs) ); + // Add some extra vertical height + vecForceDir[2] += 5; + vecForceDir *= random->RandomFloat( 10.0,30.0 ); + + //C_BreakableProp *pProp = new C_BreakableProp; + //pProp->CreateClientsideProp( ImpactHurtGibs_Wood_Small[ random->RandomInt(0,NUM_WOOD_GIBS_SMALL-1) ], vecSpawnOrigin, vecForceDir, angVel ); + } + } + else + { + PerformCustomEffects( vecOrigin, tr, shotDir, iMaterial, 1 ); + } +} diff --git a/game/client/tf2/fx_tf2_tracers.cpp b/game/client/tf2/fx_tf2_tracers.cpp new file mode 100644 index 0000000..b91552b --- /dev/null +++ b/game/client/tf2/fx_tf2_tracers.cpp @@ -0,0 +1,105 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Game-specific impact effect hooks +// +//=============================================================================// +#include "cbase.h" +#include "fx.h" +#include "c_te_effect_dispatch.h" +#include "clienteffectprecachesystem.h" +#include "clientsideeffects.h" + +// Precache the effects +CLIENTEFFECT_REGISTER_BEGIN( PrecacheTF2TracerEffects ) +CLIENTEFFECT_MATERIAL( "effects/human_bullet" ) +CLIENTEFFECT_MATERIAL( "effects/alien_laser" ) +CLIENTEFFECT_REGISTER_END() + +Vector GetTracerOrigin( const CEffectData &data ); + +//----------------------------------------------------------------------------- +// Purpose: Human's laser rifle Tracer +//----------------------------------------------------------------------------- +void HLaserTracerCallback( const CEffectData &data ) +{ + float flVelocity = data.m_flScale; + Vector vecStart = GetTracerOrigin( data ); + Vector vecEnd = data.m_vOrigin; + Vector shotDir; + + // Get out shot direction and length + VectorSubtract( vecEnd, vecStart, shotDir ); + float totalDist = VectorNormalize( shotDir ); + + // Don't make small tracers + if ( totalDist <= 32 ) + return; + + float length = MAX( 64, random->RandomFloat( 200.0f, 256.0f ) ); + flVelocity = random->RandomFloat( 5000, 7000 ); + float life = ( totalDist + length ) / flVelocity; + float flWidth = random->RandomFloat( 2.0, 2.5 ); + + // Add it + FX_AddDiscreetLine( vecStart, shotDir, flVelocity, length, totalDist, flWidth, life, "effects/human_bullet" ); +} + +DECLARE_CLIENT_EFFECT( "HLaserTracer", HLaserTracerCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Alien's laser rifle Tracer +//----------------------------------------------------------------------------- +void ALaserTracerCallback( const CEffectData &data ) +{ + float flVelocity = data.m_flScale; + Vector vecStart = GetTracerOrigin( data ); + Vector vecEnd = data.m_vOrigin; + Vector shotDir; + + // Get out shot direction and length + VectorSubtract( vecEnd, vecStart, shotDir ); + float totalDist = VectorNormalize( shotDir ); + + // Don't make small tracers + if ( totalDist <= 32 ) + return; + + float length = MAX( 64, random->RandomFloat( 512.0f, 768.0f ) ); + flVelocity = random->RandomFloat( 5000, 7000 ); + float life = ( totalDist + length ) / flVelocity; + float flWidth = random->RandomFloat( 2.0, 3.0 ); + + // Add it + FX_AddDiscreetLine( vecStart, shotDir, flVelocity, length, totalDist, flWidth, life, "effects/alien_laser" ); +} + +DECLARE_CLIENT_EFFECT( "ALaserTracer", ALaserTracerCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Alien's minigun tracer +//----------------------------------------------------------------------------- +void MinigunTracerCallback( const CEffectData &data ) +{ + float flVelocity = data.m_flScale; + Vector vecStart = GetTracerOrigin( data ); + Vector vecEnd = data.m_vOrigin; + Vector shotDir; + + // Get out shot direction and length + VectorSubtract( vecEnd, vecStart, shotDir ); + float totalDist = VectorNormalize( shotDir ); + + // Don't make small tracers + if ( totalDist <= 32 ) + return; + + float length = MAX( 64, random->RandomFloat( 200.0f, 256.0f ) ); + flVelocity = random->RandomFloat( 5000, 7000 ); + float life = ( totalDist + length ) / flVelocity; + float flWidth = random->RandomFloat( 1.5, 2.0 ); + + // Add it + FX_AddDiscreetLine( vecStart, shotDir, flVelocity, length, totalDist, flWidth, life, "effects/alien_laser" ); +} + +DECLARE_CLIENT_EFFECT( "MinigunTracer", MinigunTracerCallback ); diff --git a/game/client/tf2/ground_line.cpp b/game/client/tf2/ground_line.cpp new file mode 100644 index 0000000..b59cb33 --- /dev/null +++ b/game/client/tf2/ground_line.cpp @@ -0,0 +1,418 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "ground_line.h" +#include "mathlib/vplane.h" +#include "beamdraw.h" +#include "bitvec.h" +#include "clientmode_commander.h" +#include <vgui_controls/Controls.h> +#include <vgui/ISurface.h> +#include "clienteffectprecachesystem.h" +#include "tier0/vprof.h" + +#define MAX_DOWN_DIST 300 +#define MAX_UP_DIST 300 +#define XY_PER_SEGMENT 100 + +CLIENTEFFECT_REGISTER_BEGIN( PrecacheGroundLine ) +CLIENTEFFECT_MATERIAL( "player/support/mortarline" ) +CLIENTEFFECT_REGISTER_END() + +static CUtlLinkedList< CGroundLine*, unsigned short > s_GroundLines; + +// ---------------------------------------------------------------------- // +// Helpers. +// ---------------------------------------------------------------------- // + +VPlane VPlaneFromCPlane(const cplane_t &plane) +{ + if(plane.signbits) + return VPlane(-plane.normal, -plane.dist); + else + return VPlane(plane.normal, plane.dist); +} + + +Vector ClipEndPos(const Vector &vStart, const Vector &vEnd, float clipDist, VPlane *pPlane) +{ + trace_t trace; + + UTIL_TraceLine(vStart, vEnd, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &trace); + if(trace.fraction < 1) + { + *pPlane = VPlaneFromCPlane(trace.plane); + return trace.endpos + pPlane->m_Normal * clipDist; + } + else + { + pPlane->m_Normal.Init(0,0,1); + pPlane->m_Dist = DotProduct(pPlane->m_Normal, vEnd); + return vEnd; + } +} + +// Tries to find the closest surface point to the specified point. +Vector FindBestSurfacePoint(const Vector &vPos) +{ + static float stepDist = 500; + static float flHeightAboveGround = 20; + + // First, find an inside point. + + // Test upwards. + trace_t trace; + UTIL_TraceLine( + Vector(vPos[0], vPos[1], vPos[2] + stepDist), + vPos, + MASK_SOLID_BRUSHONLY, + NULL, + COLLISION_GROUP_NONE, + &trace); + if(trace.fraction < 1 && trace.fraction != 0) + { + return Vector(trace.endpos[0], trace.endpos[1], trace.endpos[2] + flHeightAboveGround ); + } + + // Test down. + UTIL_TraceLine( + vPos, + Vector(vPos[0], vPos[1], vPos[2] - stepDist), + MASK_SOLID_BRUSHONLY, + NULL, + COLLISION_GROUP_NONE, + &trace); + if(trace.fraction < 1 && trace.fraction != 0) + { + return Vector(trace.endpos[0], trace.endpos[1], trace.endpos[2] + flHeightAboveGround ); + } + + return vPos; +} + + +// Tries to find the place in the world geometry which blocks vStart from the line segment (vEnd1, vEnd2). +// Uses a binary search so your error is |vEnd2 - vEnd1| ^ (1 / nIterations) +bool BinSearchSegments(const Vector &vStart, const Vector &vEnd1, const Vector &vEnd2, int nIterations, Vector *out) +{ + trace_t trace; + + // If what was passed into us already intersects then there's nothing we can do. + UTIL_TraceLine(vStart, vEnd2, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &trace); + if(trace.fraction < 1) + return false; + + Vector vecs[2] = {vEnd1, vEnd2}; + int iIntersect = 0; // Which vector intersects. + for(int i=0; i < nIterations; i++) + { + // Test the midpoint. + Vector mid = (vecs[0] + vecs[1]) * 0.5f; + UTIL_TraceLine(vStart, mid, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &trace); + if(trace.fraction < 1) + vecs[iIntersect] = mid; + else + vecs[!iIntersect] = mid; + } + + *out = (vecs[0] + vecs[1]) * 0.5f; + return true; +} + +// Tries to snap the point to its underlying plane's z. +Vector SnapToPlane(const Vector &v) +{ +return v; + + trace_t trace; + UTIL_TraceLine(Vector(v[0], v[1], v[2] + 50), Vector(v[0], v[1], v[2] - 50), + MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &trace); + if(trace.fraction < 1) + return Vector(v[0], v[1], trace.endpos[2] + 3); + else + return v; +} + + + +// ---------------------------------------------------------------------- // +// CGroundLine implementation. +// ---------------------------------------------------------------------- // + +CGroundLine::CGroundLine() +: BaseClass( NULL, "CGroundLine" ) +{ + m_pMaterial = NULL; + + m_ListHandle = s_GroundLines.AddToHead( this ); + SetParent( CMinimapPanel::MinimapRootPanel() ); + + m_nPoints = 0; + SetVisible( true ); + SetPaintBackgroundEnabled( false ); +} + + +CGroundLine::~CGroundLine() +{ + s_GroundLines.Remove( m_ListHandle ); + + m_vStart.Init(); + m_vEnd.Init(); + m_LineWidth = 1; +} + + +bool CGroundLine::Init(const char *pMaterialName) +{ + m_pMaterial = materials->FindMaterial(pMaterialName, TEXTURE_GROUP_CLIENT_EFFECTS); + return !!m_pMaterial; +} + + +void CGroundLine::SetParameters( + const Vector &vStart, + const Vector &vEnd, + const Vector &vStartColor, // Color values 0-1 + const Vector &vEndColor, + float alpha, + float lineWidth + ) +{ + m_vStart = vStart; + m_vEnd = vEnd; + m_vStartColor = vStartColor; + m_vEndColor = vEndColor; + m_Alpha = alpha; + m_LineWidth = lineWidth; + + Vector vTo( vEnd.x - vStart.x, vEnd.y - vStart.y, 0 ); + float flXYLen = vTo.Length(); + + // Recalculate our segment list. + unsigned int nSteps = (int)flXYLen / XY_PER_SEGMENT; + nSteps = clamp( nSteps, 8, MAX_GROUNDLINE_SEGMENTS ) & ~1; + unsigned int nMaxSteps = nSteps / 2; + + // First generate the sequence. We generate every other point here so it can insert fixup points to prevent + // it from crossing world geometry. + Vector pt[MAX_GROUNDLINE_SEGMENTS]; + Vector vStep = (Vector(m_vEnd[0], m_vEnd[1], 0) - Vector(m_vStart[0], m_vStart[1], 0)) / (nMaxSteps-1); + + pt[0] = FindBestSurfacePoint(m_vStart); + + unsigned int i; + for(i=1; i < nMaxSteps; i++) + pt[i<<1] = FindBestSurfacePoint(pt[(i-1)<<1] + vStep); + + + CBitVec<MAX_GROUNDLINE_SEGMENTS> pointsUsed; + pointsUsed.ClearAll(); + + // Now try to make sure they don't intersect the geometry. + for(i=0; i < nMaxSteps-1; i++) + { + Vector &a = pt[i<<1]; + Vector &b = pt[(i+1)<<1]; + + trace_t trace; + UTIL_TraceLine(a, b, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &trace); + if(trace.fraction < 1) + { + int cIndex = (i<<1)+1; + Vector &c = pt[cIndex]; + + // Ok, this line segment intersects the world. Do a binary search to try to find the + // point of intersection. + Vector hi, lo; + if(a.z < b.z) + { + hi = b; + lo = a; + } + else + { + hi = a; + lo = b; + } + + if(BinSearchSegments(lo, hi, Vector(lo[0],lo[1],hi[2]), 15, &c)) + { + pointsUsed.Set( cIndex ); + } + else if(BinSearchSegments(lo, hi, Vector(hi[0],hi[1],hi[2]+500), 15, &c)) + { + pointsUsed.Set( cIndex ); + } + } + } + + // Export the points. + m_nPoints = 0; + for(i=0; i < nSteps; i++) + { + // Every other point is always active. + if( pointsUsed.Get( i ) || !(i & 1) ) + { + m_Points[m_nPoints] = pt[i]; + ++m_nPoints; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Set the visibility of the groundline +//----------------------------------------------------------------------------- +void CGroundLine::SetVisible( bool bVisible ) +{ + m_bVisible = bVisible; +} + +//----------------------------------------------------------------------------- +// Purpose: Return true if the groundline's visible +//----------------------------------------------------------------------------- +bool CGroundLine::IsVisible( void ) +{ + return m_bVisible; +} + +void CGroundLine::DrawAllGroundLines() +{ + VPROF("CGroundLine::DrawAllGroundLines()"); + unsigned short i; + for( i = s_GroundLines.Head(); i != s_GroundLines.InvalidIndex(); i = s_GroundLines.Next(i) ) + { + s_GroundLines[i]->Draw(); + } +} + +void CGroundLine::Draw() +{ + if ( !m_pMaterial || m_nPoints < 2 ) + return; + if ( !IsVisible() ) + return; + + float flAlpha = m_Alpha; + if( g_pClientMode == ClientModeCommander() ) + { + flAlpha = 1; // draw bright.. + } + + CBeamSegDraw beamDraw; + beamDraw.Start( m_nPoints, m_pMaterial ); + + for( unsigned int i=0; i < m_nPoints; i++ ) + { + float t = (float)i / (m_nPoints - 1); + + CBeamSeg seg; + seg.m_vPos = m_Points[i]; + VectorLerp( m_vStartColor, m_vEndColor, t, seg.m_vColor ); + seg.m_flTexCoord = 0; + seg.m_flWidth = m_LineWidth; + seg.m_flAlpha = m_Alpha; + + beamDraw.NextSeg( &seg ); + } + + beamDraw.End(); +} + + +static inline bool ClipLine( float &x1, float &y1, float &x2, float &y2, float xClip, float sign ) +{ + if( x1*sign < (xClip-0.001f)*sign ) + { + if( x2*sign > (xClip+0.001f)*sign ) + { + float t = (xClip-x1) / (x2 - x1); + x1 = x1 + (x2 - x1) * t; + y1 = y1 + (y2 - y1) * t; + } + else + { + return false; + } + } + else if( x2*sign < (xClip-0.001f)*sign ) + { + if( x1*sign > (xClip+0.001f)*sign ) + { + float t = (xClip-x1) / (x2 - x1); + x2 = x1 + (x2 - x1) * t; + y2 = y1 + (y2 - y1) * t; + } + else + { + return false; + } + } + + return true; +} + + +void CGroundLine::Paint( ) +{ + vgui::Panel *pPanel = GetParent(); + int wide, tall; + pPanel->GetSize( wide, tall ); + + float tPrev = 0; + float xPrev, yPrev; + CMinimapPanel::MinimapPanel()->WorldToMinimap( MINIMAP_NOCLIP, m_vStart, xPrev, yPrev ); + + int nSegs = 20; + for( int iSeg=1; iSeg <= nSegs; iSeg++ ) + { + float t = (float)iSeg / nSegs; + + Vector v3DPos; + VectorLerp( m_vStart, m_vEnd, t, v3DPos ); + + float x, y; + CMinimapPanel::MinimapPanel()->WorldToMinimap( MINIMAP_NOCLIP, v3DPos, x, y ); + + // Clip the line segment on X, then Y. + if( ClipLine( xPrev, yPrev, x, y, 0, 1 ) && + ClipLine( xPrev, yPrev, x, y, wide, -1 ) && + ClipLine( yPrev, xPrev, y, x, 0, 1 ) && + ClipLine( yPrev, xPrev, y, x, tall, -1 ) ) + { + Vector vColor; + VectorLerp( m_vStartColor, m_vEndColor, t, vColor ); + vColor *= 255.9f; + + vgui::surface()->DrawSetColor( + (unsigned char)RoundFloatToInt( vColor.x ), + (unsigned char)RoundFloatToInt( vColor.y ), + (unsigned char)RoundFloatToInt( vColor.z ), + 255 ); + + vgui::surface()->DrawLine( xPrev, yPrev, x, y ); + } + + tPrev = t; + xPrev = x; + yPrev = y; + } + + // Draw a marker at the endpoint. + float xEnd, yEnd; + if( CMinimapPanel::MinimapPanel()->WorldToMinimap( MINIMAP_NOCLIP, m_vEnd, xEnd, yEnd ) ) + { + int ix = RoundFloatToInt( xEnd ); + int iy = RoundFloatToInt( yEnd ); + int rectSize=1; + + vgui::surface()->DrawSetColor( 255, 255, 255, 255 ); + vgui::surface()->DrawOutlinedRect( ix-rectSize, iy-rectSize, ix+rectSize, iy+rectSize ); + } +} + + diff --git a/game/client/tf2/ground_line.h b/game/client/tf2/ground_line.h new file mode 100644 index 0000000..4164977 --- /dev/null +++ b/game/client/tf2/ground_line.h @@ -0,0 +1,80 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef GROUND_LINE_H +#define GROUND_LINE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "mathlib/vector.h" +#include "hud_minimap.h" + + +class IMaterial; + + +#define MAX_GROUNDLINE_SEGMENTS 100 + + +// This class will lay out a line of a specified width along the ground. It follows +// the contour of the ground as well as it can. +class CGroundLine : public vgui::Panel +{ + typedef vgui::Panel BaseClass; + +public: + CGroundLine(); + ~CGroundLine(); + + // One-time initialization. + bool Init(const char *pMaterialName); + + // Setup the line's rendering parameters. + void SetParameters( + const Vector &vStart, + const Vector &vEnd, + const Vector &vStartColor, // Color values 0-1 + const Vector &vEndColor, // Color values 0-1 + float alpha, + float lineWidth + ); + + // Called by the renderer when it's time to render the ground lines. + static void DrawAllGroundLines(); + + // Set the visibility + void SetVisible( bool bVisible ); + bool IsVisible( void ); + +private: + + // Draw a line along the ground. + void Draw(); + void Paint(); + +private: + // Rendering parameters. + IMaterial *m_pMaterial; + Vector m_vStartColor; + Vector m_vEndColor; + float m_Alpha; + Vector m_vStart; + Vector m_vEnd; + float m_LineWidth; + bool m_bVisible; + + // Points along the line. + Vector m_Points[MAX_GROUNDLINE_SEGMENTS]; + unsigned int m_nPoints; + + unsigned short m_ListHandle; +}; + + +#endif // GROUND_LINE_H diff --git a/game/client/tf2/hintitembase.cpp b/game/client/tf2/hintitembase.cpp new file mode 100644 index 0000000..e098306 --- /dev/null +++ b/game/client/tf2/hintitembase.cpp @@ -0,0 +1,425 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hintitembase.h" +#include <vgui_controls/Controls.h> +#include <vgui_controls/Label.h> +#include <vgui/IVGui.h> +#include <vgui/ISurface.h> +#include <vgui/IScheme.h> +#include <vgui/ILocalize.h> +#include <KeyValues.h> +#include "PanelEffect.h" + +//----------------------------------------------------------------------------- +// Purpose: Constructor +// Input : *parent - +// *panelName - +// *text - +// itemwidth - +//----------------------------------------------------------------------------- +CHintItemBase::CHintItemBase( vgui::Panel *parent, const char *panelName ) +: BaseClass( parent, panelName ), m_pObject( NULL ) +{ + m_pLabel = new vgui::Label( this, "TFTextHint", "" ); + m_pLabel->SetContentAlignment( vgui::Label::a_west ); + + // m_pIndex = new vgui::Label( this, "TFTextHintIndex", "" ); + // m_pIndex->setContentAlignment( vgui::Label::a_west ); + // m_pIndex->SetBounds( 20, 0, 20, 20 ); + // m_nIndex = 0; + + m_bCompleted = false; + m_bActive = false; + m_flActivateTime = 0.0f; + + vgui::ivgui()->AddTickSignal( GetVPanel() ); + + SetFormatString( "" ); + + m_bAutoComplete = false; + m_flAutoCompleteTime = 0.0f; + + m_hSmallFont = m_hMarlettFont = 0; +} + + +//----------------------------------------------------------------------------- +// Scheme settings +//----------------------------------------------------------------------------- +void CHintItemBase::ApplySchemeSettings(vgui::IScheme *pScheme) +{ + BaseClass::ApplySchemeSettings(pScheme); + + m_hSmallFont = pScheme->GetFont( "DefaultVerySmall" ); + m_hMarlettFont = pScheme->GetFont( "Marlett" ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pKeyValues - +//----------------------------------------------------------------------------- +void CHintItemBase::ParseItem( KeyValues *pKeyValues ) +{ + if ( !pKeyValues ) + return; + + const char *title = pKeyValues->GetString( "title", "" ); + if ( title ) + { + SetText( title ); + } + + const char *fmt = pKeyValues->GetString( "formatstring", "" ); + if ( fmt ) + { + SetFormatString( fmt ); + } + + const char *autocomplete = pKeyValues->GetString( "autocomplete" ); + if ( autocomplete && autocomplete[ 0 ] ) + { + SetAutoComplete( ( float ) atof( autocomplete ) ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : elapsed_time - +//----------------------------------------------------------------------------- +void CHintItemBase::SetAutoComplete( float elapsed_time ) +{ + m_bAutoComplete = true; + m_flAutoCompleteTime = elapsed_time; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : newWide - +// newTall - +//----------------------------------------------------------------------------- +void CHintItemBase::OnSizeChanged( int newWide, int newTall ) +{ + m_pLabel->SetBounds( 20, 0, GetWide() - 20, newTall ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *text - +//----------------------------------------------------------------------------- +void CHintItemBase::SetText( const char *text ) +{ + m_pLabel->SetText( text ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *fmt - +//----------------------------------------------------------------------------- +void CHintItemBase::SetFormatString( const char *fmt ) +{ + Q_strncpy( m_szFormatString, fmt, MAX_TEXT_LENGTH ); + m_bUseFormatString = fmt[ 0 ] ? true : false; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : char const +//----------------------------------------------------------------------------- +const char *CHintItemBase::GetFormatString( void ) +{ + Assert( m_bUseFormatString ); + return m_szFormatString; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *instring - +// keylength - +// **ppOutstring - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CHintItemBase::CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring ) +{ + Assert( m_bUseFormatString ); + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHintItemBase::ComputeTitle( void ) +{ + if ( !m_bUseFormatString ) + return; + + char fixed[ MAX_TEXT_LENGTH ]; + + char *in, *out; + in = m_szFormatString; + out = fixed; + + while ( *in ) + { + if ( *in == '!' && *(in+1) == '!' ) + { + in += 2; + + int length; + const char *text; + + if ( CheckKeyAndValue( in, &length, &text ) ) + { + const char *t = text; + while ( *t ) + { + *out++ = *t++; + } + + in += length; + } + } + else + { + *out++ = *in++; + } + } + + *out = 0; + + SetText( fixed ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *binding - +// Output : const char +//----------------------------------------------------------------------------- +const char *CHintItemBase::GetKeyNameForBinding( const char *binding ) +{ + const char *keyname = engine->Key_LookupBinding( binding ); + if ( keyname ) + { + return keyname; + } + + // Return original string if not bound to a key + return binding; +} + +//----------------------------------------------------------------------------- +// Purpose: Delete's the hint object +//----------------------------------------------------------------------------- +void CHintItemBase::DeleteThis( void ) +{ + // Remove any associated effects + DestroyPanelEffects( this ); + + delete this; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : incolor - +// frac - +// Output : static int +//----------------------------------------------------------------------------- +static int TextHintColorMod( int incolor, float frac ) +{ + int maxcolor = incolor + (int)( ( 255.0f - (float)incolor ) / 2.0f ); + int midcolor = ( maxcolor + incolor ) / 2; + int range = maxcolor - midcolor; + + int clr = midcolor + range * frac; + + clr = clamp( clr, 0, 255 ); + return clr; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHintItemBase::PaintBackground() +{ + // force label color + if ( m_pLabel ) + { + m_pLabel->SetFgColor( Color( 0, 0, 0, 255 ) ); + m_pLabel->SetBgColor( Color( 0, 0, 0, 0 ) ); + } + + int w, h; + + GetSize( w, h ); + + float f2 = 0.0f; + + float dt = gpGlobals->curtime - m_flActivateTime; + + if ( dt < 5.0f ) + { + f2 = fmod( gpGlobals->curtime, 1.0f ); + } + + int r = 80; + int g = 105; + int b = 90; + + vgui::surface()->DrawSetTextFont( m_hMarlettFont ); + vgui::surface()->DrawSetTextColor( r, g, b, 255 ); + vgui::surface()->DrawSetTextPos( 2 + 3 * f2, 3 ); + + wchar_t ch[2]; + g_pVGuiLocalize->ConvertANSIToUnicode( "4", ch, sizeof( ch ) ); + vgui::surface()->DrawPrintText( ch, 1 ); + + if ( m_bAutoComplete ) + { + vgui::surface()->DrawSetTextColor( 0, 0, 0, 63 ); + vgui::surface()->DrawSetTextFont( m_hSmallFont ); + + char sz[ 32 ]; + + int len = Q_snprintf( sz, sizeof( sz ), "%i", (int)( m_flAutoCompleteTime + 0.5f ) ); + + int x = w - len * 10 - 2; + int y = 6; + + wchar_t szconverted[ 32 ]; + g_pVGuiLocalize->ConvertANSIToUnicode( sz, szconverted, sizeof(szconverted) ); + + vgui::surface()->DrawSetTextPos( x, y ); + vgui::surface()->DrawPrintText( szconverted, wcslen( szconverted ) ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CHintItemBase::GetCompleted( void ) +{ + return m_bCompleted; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : active - +//----------------------------------------------------------------------------- +void CHintItemBase::SetActive( bool active ) +{ + bool changed = m_bActive != active; + + m_bActive = active; + + if ( !changed ) + return; + + if ( m_bActive ) + { + m_flActivateTime = gpGlobals->curtime; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CHintItemBase::GetActive( void ) +{ + return m_bActive; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CHintItemBase::ShouldRenderPanelEffects( void ) +{ + // By default, render active item's effects. + // A hint could have it's effects always render, though + return GetActive(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHintItemBase::Think( void ) +{ + // Check for completion + if ( m_bAutoComplete && GetActive() ) + { + m_flAutoCompleteTime -= gpGlobals->frametime; + if ( m_flAutoCompleteTime <= 0.0f ) + { + m_bCompleted = true; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int +//----------------------------------------------------------------------------- +int CHintItemBase::GetHeight( void ) +{ + return GetTall(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : x - +// y - +//----------------------------------------------------------------------------- +void CHintItemBase::SetPosition( int x, int y ) +{ + SetPos( x, y ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : index - +//----------------------------------------------------------------------------- +void CHintItemBase::SetItemNumber( int index ) +{ +/* +m_nIndex = index; + + char sz[ 32 ]; + Q_snprintf( sz, sizeof( sz ), "%i", m_nIndex ); + + m_pIndex->setText( sz ); + */ +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : visible - +//----------------------------------------------------------------------------- +void CHintItemBase::SetVisible( bool visible ) +{ + BaseClass::SetVisible( visible ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *panel - +//----------------------------------------------------------------------------- +void CHintItemBase::SetHintTarget( vgui::Panel *panel ) +{ + m_pObject = panel; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *key - +// *value - +//----------------------------------------------------------------------------- +void CHintItemBase::SetKeyValue( const char *key, const char *value ) +{ +} diff --git a/game/client/tf2/hintitembase.h b/game/client/tf2/hintitembase.h new file mode 100644 index 0000000..78878ea --- /dev/null +++ b/game/client/tf2/hintitembase.h @@ -0,0 +1,113 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HINTITEMBASE_H +#define HINTITEMBASE_H +#ifdef _WIN32 +#pragma once +#endif + +#include <vgui_controls/Panel.h> +#include "itfhintitem.h" + +class C_TFBaseHint; +class CHintItemBase; + +namespace vgui +{ + class Label; +} + +#define DECLARE_HINTITEMFACTORY( className ) \ + CHintItemBase *Create_##className##( vgui::Panel *parent, const char *panelName ) \ + { return new className( parent, panelName ); } + +#define GET_HINTITEMFACTORY_NAME( className ) Create_##className + +#define DECLARE_HINTFACTORY( className ) \ + C_TFBaseHint *Create_##className##( int id, int entity ) \ + { return new className( id, 0, entity, NULL ); } + +#define GET_HINTFACTORY_NAME( className ) Create_##className + +//----------------------------------------------------------------------------- +// Purpose: A hint that shows up as a single line o text +//----------------------------------------------------------------------------- +class CHintItemBase : public vgui::Panel, public ITFHintItem +{ + DECLARE_CLASS_GAMEROOT( CHintItemBase, vgui::Panel ); + +public: + CHintItemBase( vgui::Panel *parent, const char *panelName ); + + // Draw some extra stuff in the Bg + virtual void PaintBackground(); + virtual void OnSizeChanged( int newWide, int newTall ); + virtual void SetText( const char *text ); + + virtual void SetFormatString( const char *fmt ); + virtual const char *GetFormatString( void ); + // If using format string + virtual bool CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring ); + virtual void ComputeTitle( void ); + + virtual void SetAutoComplete( float elapsed_time ); + + // Scheme settings + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + + // Helper + virtual const char *GetKeyNameForBinding( const char *binding ); + + // Implement ITFHintItem + virtual void ParseItem( KeyValues *pKeyValues ); + virtual bool GetCompleted( void ); + virtual void SetActive( bool active ); + virtual bool GetActive( void ); + virtual void Think( void ); + virtual int GetHeight( void ); + virtual void SetPosition( int x, int y ); + virtual void DeleteThis( void ); + virtual void SetItemNumber( int index ); + virtual void SetVisible( bool visible ); + virtual void SetHintTarget( vgui::Panel *panel ); + virtual bool ShouldRenderPanelEffects( void ); + virtual void SetKeyValue( const char *key, const char *value ); +protected: + enum + { + MAX_TEXT_LENGTH = 256, + }; + + // Has the hint item been completed + bool m_bCompleted; + // Is the hint item active + bool m_bActive; + // Text of hint + vgui::Label *m_pLabel; + // Depends on type of hint + vgui::Panel *m_pObject; + // Time the hint was activated + float m_flActivateTime; + + // vgui::Label *m_pIndex; + // Index of hint + //int m_nIndex; + + bool m_bUseFormatString; + char m_szFormatString[ MAX_TEXT_LENGTH ]; + + bool m_bAutoComplete; + float m_flAutoCompleteTime; + + vgui::HFont m_hSmallFont; + vgui::HFont m_hMarlettFont; +}; + +CHintItemBase *CreateHintItem( vgui::Panel *parent, const char *name ); + +#endif // HINTITEMBASE_H diff --git a/game/client/tf2/hintitemobjectbase.cpp b/game/client/tf2/hintitemobjectbase.cpp new file mode 100644 index 0000000..b5b0c5c --- /dev/null +++ b/game/client/tf2/hintitemobjectbase.cpp @@ -0,0 +1,79 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hintitemobjectbase.h" +#include <KeyValues.h> +#include "c_obj_resourcepump.h" +#include "c_func_resource.h" + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *parent - +// *panelName - +//----------------------------------------------------------------------------- +CHintItemObjectBase::CHintItemObjectBase( vgui::Panel *parent, const char *panelName ) +: BaseClass( parent, panelName ) +{ + SetObjectType( "" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pKeyValues - +//----------------------------------------------------------------------------- +void CHintItemObjectBase::ParseItem( KeyValues *pKeyValues ) +{ + BaseClass::ParseItem( pKeyValues ); + + const char *type = pKeyValues->GetString( "type", "" ); + if ( type ) + { + SetObjectType( type ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *object - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CHintItemObjectBase::IsObjectOfType( C_BaseEntity *object ) +{ + if ( !stricmp( GetObjectType(), "Resource Zone" ) ) + { + return dynamic_cast< C_ResourceZone *>( object ) ? true : false; + } + else if ( !stricmp( GetObjectType(), "Resource Pump" ) ) + { + return dynamic_cast< C_ObjectResourcePump * >( object) ? true : false; + } + else if ( !stricmp( GetObjectType(), "BaseObject" ) ) + { + return dynamic_cast< C_BaseObject * >( object) ? true : false; + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *type - +//----------------------------------------------------------------------------- +void CHintItemObjectBase::SetObjectType( const char *type ) +{ + Q_strncpy( m_szObjectType, type, MAX_OBJECT_TYPE ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : char const +//----------------------------------------------------------------------------- +const char *CHintItemObjectBase::GetObjectType( void ) +{ + return m_szObjectType; +}
\ No newline at end of file diff --git a/game/client/tf2/hintitemobjectbase.h b/game/client/tf2/hintitemobjectbase.h new file mode 100644 index 0000000..a55fd9f --- /dev/null +++ b/game/client/tf2/hintitemobjectbase.h @@ -0,0 +1,43 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HINTITEMOBJECTBASE_H +#define HINTITEMOBJECTBASE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "hintitemorderbase.h" + +class C_BaseEntity; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHintItemObjectBase : public CHintItemOrderBase +{ + DECLARE_CLASS( CHintItemObjectBase, CHintItemOrderBase ); + +public: + CHintItemObjectBase( vgui::Panel *parent, const char *panelName ); + + virtual void ParseItem( KeyValues *pKeyValues ); + // Is the object of type m_szObjectType + virtual bool IsObjectOfType( C_BaseEntity *object ); + virtual void SetObjectType( const char *type ); + virtual char const *GetObjectType( void ); + +private: + enum + { + MAX_OBJECT_TYPE = 128, + }; + + char m_szObjectType[ MAX_OBJECT_TYPE ]; +}; + +#endif // HINTITEMOBJECTBASE_H diff --git a/game/client/tf2/hintitemorderbase.cpp b/game/client/tf2/hintitemorderbase.cpp new file mode 100644 index 0000000..6b3073d --- /dev/null +++ b/game/client/tf2/hintitemorderbase.cpp @@ -0,0 +1,71 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hintitemorderbase.h" +#include "paneleffect.h" + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *parent - +// *panelName - +//----------------------------------------------------------------------------- +CHintItemOrderBase::CHintItemOrderBase( vgui::Panel *parent, const char *panelName ) +: BaseClass( parent, panelName ) +{ + m_bEffects = false; + m_LineEffect = EFFECT_INVALID_HANDLE; + m_FlashEffect = EFFECT_INVALID_HANDLE; + + DrawAxialLineToOrder(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHintItemOrderBase::DrawAxialLineToOrder( void ) +{ + // Derived class already set up effects + if ( m_bEffects ) + return; + + m_bEffects = true; + + // Flash for vote order + m_FlashEffect = CreateFlashEffect( this, NULL ); + // Flash the hint panel itself + CreateFlashEffect( this, GetParent() ); + // Point from hint to vote order panel + m_LineEffect = CreateAxialLineEffect( this, GetParent(), NULL ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *panel - +//----------------------------------------------------------------------------- +void CHintItemOrderBase::SetHintTarget( vgui::Panel *panel ) +{ + BaseClass::SetHintTarget( panel ); + + if ( !m_bEffects ) + return; + + // Update effect target + if ( !panel || !g_pTF2RootPanel ) + return; + + CPanelEffect *e = g_pTF2RootPanel->FindEffect( m_LineEffect ); + if ( e ) + { + e->SetPanelOther( panel ); + } + + e = g_pTF2RootPanel->FindEffect( m_FlashEffect ); + if ( e ) + { + e->SetPanel( panel ); + } +}
\ No newline at end of file diff --git a/game/client/tf2/hintitemorderbase.h b/game/client/tf2/hintitemorderbase.h new file mode 100644 index 0000000..d548c38 --- /dev/null +++ b/game/client/tf2/hintitemorderbase.h @@ -0,0 +1,37 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HINTITEMORDERBASE_H +#define HINTITEMORDERBASE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "hintitembase.h" +#include "c_tf2rootpanel.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHintItemOrderBase : public CHintItemBase +{ + DECLARE_CLASS( CHintItemOrderBase, CHintItemBase ); +public: + CHintItemOrderBase( vgui::Panel *parent, const char *panelName ); + + virtual void DrawAxialLineToOrder( void ); + + virtual void SetHintTarget( vgui::Panel *panel ); + +protected: + bool m_bEffects; + + EFFECT_HANDLE m_LineEffect; + EFFECT_HANDLE m_FlashEffect; +}; + +#endif // HINTITEMORDERBASE_H diff --git a/game/client/tf2/hud_ammo.cpp b/game/client/tf2/hud_ammo.cpp new file mode 100644 index 0000000..637a20f --- /dev/null +++ b/game/client/tf2/hud_ammo.cpp @@ -0,0 +1,265 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "hud_numeric.h" +#include "hud_ammo.h" +#include "hud.h" +#include "iclientmode.h" +#include <vgui_controls/AnimationController.h> +#include <KeyValues.h> + +//----------------------------------------------------------------------------- +// Singleton +//----------------------------------------------------------------------------- +static CHudAmmo g_HudAmmo; +CHudAmmo* GetHudAmmo() +{ + return &g_HudAmmo; +} + + +//----------------------------------------------------------------------------- +// Accessor methods to set various state associated with the ammo display +//----------------------------------------------------------------------------- +void CHudAmmo::SetPrimaryAmmo( int nAmmoType, int nTotalAmmo, int nClipCount, int nMaxClipCount ) +{ + m_nAmmoType1 = nAmmoType; + m_nTotalAmmo1 = nTotalAmmo; + m_nMaxClip1 = nMaxClipCount; + m_nClip1 = nClipCount; +} + +void CHudAmmo::SetSecondaryAmmo( int nAmmoType, int nTotalAmmo, int nClipCount, int nMaxClipCount ) +{ + m_nAmmoType2 = nAmmoType; + m_nTotalAmmo2 = nTotalAmmo; + m_nMaxClip2 = nMaxClipCount; + m_nClip2 = nClipCount; +} + +bool CHudAmmo::ShouldShowPrimaryClip() const +{ + if ( m_nAmmoType1 <= 0 ) + return false; + + if ( m_nClip1 < 0 ) + return false; + + return true; +} + +bool CHudAmmo::ShouldShowSecondary() const +{ + if ( m_nAmmoType2 <= 0 ) + return false; + + if ( m_nTotalAmmo2 <= 0 ) + return false; + + return true; +} + +void CHudAmmo::ShowHideHudControls() +{ + bool showClip = ShouldShowPrimaryClip(); + bool showSecondary = ShouldShowSecondary(); + + if ( showClip ) + { + if ( showSecondary ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "ShowPrimaryAmmoClipShowSecondaryAmmo" ); + } + else + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "ShowPrimaryAmmoClipHideSecondaryAmmo" ); + } + } + else + { + if ( showSecondary ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HidePrimaryAmmoClipShowSecondaryAmmo" ); + } + else + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HidePrimaryAmmoClipHideSecondaryAmmo" ); + } + } +} + +class CHudAmmoPrimary : public CHudNumeric +{ + DECLARE_CLASS_SIMPLE( CHudAmmoPrimary, CHudNumeric ); +public: + CHudAmmoPrimary( const char *pElementName ) : CHudNumeric( pElementName, "HudAmmoPrimary" ) + { + SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD ); + } + + virtual const char *GetLabelText() { return m_szAmmoLabel; } + virtual const char *GetPulseEvent( bool increment ) { return increment ? "PrimaryAmmoIncrement" : "PrimaryAmmoDecrement"; } + + virtual bool GetValue( char *val, int maxlen ) + { + if ( GetHudAmmo()->m_nAmmoType1 <= 0 ) + return false; + + int count = ( GetHudAmmo()->m_nClip1 >= 0 ) ? GetHudAmmo()->m_nClip1 : GetHudAmmo()->m_nTotalAmmo1; + Q_snprintf( val, maxlen, "%i", count ); + return true; + } + + virtual Color GetColor() + { + // Get our ratio bar information + float ammoPerc = 1.0f - ( (float) GetHudAmmo()->m_nClip1 ) / ( (float) GetHudAmmo()->m_nMaxClip1 ); + bool ammoCaution = ( ammoPerc >= CLIP_PERC_THRESHOLD ); + + if ( ammoCaution ) + return m_TextColorCritical; + + return m_TextColor; + } + + virtual void ApplySchemeSettings(vgui::IScheme *scheme) + { + BaseClass::ApplySchemeSettings( scheme ); + + SetPaintBackgroundEnabled( true ); + } + +private: + CPanelAnimationStringVar( 128, m_szAmmoLabel, "AmmoLabel", "Ammo" ); +}; + +DECLARE_HUDELEMENT( CHudAmmoPrimary ); + +class CHudAmmoPrimaryClip : public CHudNumeric +{ + DECLARE_CLASS_SIMPLE( CHudAmmoPrimaryClip, CHudNumeric ); + +public: + CHudAmmoPrimaryClip( const char *pElementName ) : BaseClass( pElementName, "HudAmmoPrimaryClip" ) + { + SetDrawLabel( false ); + + m_nPrevVisible = -1; + + SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD ); + } + + virtual const char *GetLabelText() { return m_szAmmoClipLabel; } + virtual const char *GetPulseEvent( bool increment ) { return increment ? "PrimaryAmmoClipIncrement" : "PrimaryAmmoClipDecrement"; } + + virtual bool GetValue( char *val, int maxlen ) + { + int iret = _GetValue( val, maxlen ) ? 1 : 0; + + if ( iret != m_nPrevVisible ) + { + GetHudAmmo()->ShowHideHudControls(); + m_nPrevVisible = iret; + } + + return true; + } + + virtual bool _GetValue( char *val, int maxlen ) + { + Q_snprintf( val, maxlen, "" ); + + if ( !GetHudAmmo()->ShouldShowPrimaryClip() ) + return false; + + int count = GetHudAmmo()->m_nTotalAmmo1; + Q_snprintf( val, maxlen, "%i", count ); + return true; + } + + virtual Color GetColor() + { + if ( GetHudAmmo()->ShouldShowPrimaryClip() ) + { + if ( GetHudAmmo()->m_nTotalAmmo1 <= GetHudAmmo()->m_nMaxClip1 ) + { + return m_TextColorCritical; + } + } + + return m_TextColor; + } + +private: + int m_nPrevVisible; + CPanelAnimationStringVar( 128, m_szAmmoClipLabel, "AmmoClipLabel", "PrimaryAmmoClip" ); +}; + +DECLARE_HUDELEMENT( CHudAmmoPrimaryClip ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHudAmmoSecondary : public CHudNumeric +{ + DECLARE_CLASS_SIMPLE( CHudAmmoSecondary, CHudNumeric ); + +public: + CHudAmmoSecondary( const char *pElementName ) : CHudNumeric( pElementName, "HudAmmoSecondary" ) + { + SetDrawLabel( false ); + + m_nPrevVisible = -1; + + SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD ); + } + + virtual const char *GetLabelText() { return m_szAmmoSecondaryLabel; } + virtual const char *GetPulseEvent( bool increment ) { return increment ? "SecondaryAmmoIncrement" : "SecondaryAmmoDecrement"; } + + virtual bool GetValue( char *val, int maxlen ) + { + int iret = _GetValue( val, maxlen ) ? 1 : 0; + + if ( iret != m_nPrevVisible ) + { + // Shift primary and clip left/right as needed + GetHudAmmo()->ShowHideHudControls(); + m_nPrevVisible = iret; + } + + return iret ? true : false; + } + + virtual bool _GetValue( char *val, int maxlen ) + { + if ( !GetHudAmmo()->ShouldShowSecondary() ) + return false; + + int count = GetHudAmmo()->m_nTotalAmmo2; + Q_snprintf( val, maxlen, "%i", count ); + return true; + } + + virtual Color GetColor() + { + if ( GetHudAmmo()->m_nAmmoType2 > 0 && + GetHudAmmo()->m_nTotalAmmo2 == 1 ) + { + return m_TextColorCritical; + } + + return m_TextColor; + } + +private: + int m_nPrevVisible; + CPanelAnimationStringVar( 128, m_szAmmoSecondaryLabel, "AmmoSecondaryLabel", "AmmoSecondary" ); +}; + +DECLARE_HUDELEMENT( CHudAmmoSecondary ); diff --git a/game/client/tf2/hud_ammo.h b/game/client/tf2/hud_ammo.h new file mode 100644 index 0000000..0c24d08 --- /dev/null +++ b/game/client/tf2/hud_ammo.h @@ -0,0 +1,52 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef HUD_AMMO_H +#define HUD_AMMO_H + +#ifdef _WIN32 +#pragma once +#endif + +// This is *like* a hud element, but isn't actually a hud element. +// It's meant to be called from hud drawing methods in various places in the code +class CHudAmmo +{ +public: + // Accessor methods to set various state associated with the ammo display + void SetPrimaryAmmo( int nAmmoType, int nTotalAmmo, int nClipCount = -1, int nMaxClipCount = -1 ); + void SetSecondaryAmmo( int nAmmoType, int nTotalAmmo, int nClipCount = -1, int nMaxClipCount = -1 ); + + bool ShouldShowPrimaryClip() const; + bool ShouldShowSecondary() const; + + void ShowHideHudControls(); + +private: + int m_nClip1; + int m_nMaxClip1; + int m_nTotalAmmo1; + int m_nAmmoType1; + + int m_nClip2; + int m_nMaxClip2; + int m_nTotalAmmo2; + int m_nAmmoType2; + +friend class CHudAmmoPrimary; +friend class CHudAmmoPrimaryClip; +friend class CHudAmmoSecondary; +}; + +//----------------------------------------------------------------------------- +// Singleton... +//----------------------------------------------------------------------------- +CHudAmmo* GetHudAmmo(); + +#endif // HUD_AMMO_H + diff --git a/game/client/tf2/hud_commander_statuspanel.cpp b/game/client/tf2/hud_commander_statuspanel.cpp new file mode 100644 index 0000000..46cb908 --- /dev/null +++ b/game/client/tf2/hud_commander_statuspanel.cpp @@ -0,0 +1,414 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Flyover/Tooltip hint area for commander +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include <stdarg.h> +#include "hud_commander_statuspanel.h" +#include "techtree.h" +#include <vgui/IVGui.h> +#include "VGuiMatSurface/IMatSystemSurface.h" +#include <vgui_controls/Controls.h> +#include <vgui/ISurface.h> +#include <vgui/IScheme.h> + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +static CCommanderStatusPanel *g_pCommanderStatusPanel = NULL; + +// +#define ALPHA_ADJUST_TIME 0.1f +#define MAX_FILLED_INFO_ALPHA 127.0f + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CCommanderStatusPanel::CCommanderStatusPanel( void ) : + BaseClass( NULL, "CCommanderStatusPanel" ) +{ + m_hFont = m_hFontText = 0; + m_nLeftEdge = 0; + m_nBottomEdge = 0; + +// m_pBorder = new vgui::LineBorder( 2, vgui::Color( 127, 127, 127, 255 ) ); +// setBorder( m_pBorder ); + + SetBgColor( Color( 0, 0, 0, 100 ) ); + + // we need updating + vgui::ivgui()->AddTickSignal( GetVPanel() ); + + InternalClear(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CCommanderStatusPanel::~CCommanderStatusPanel( void ) +{ +// delete m_pBorder; +} + +//----------------------------------------------------------------------------- +// Scheme settings +//----------------------------------------------------------------------------- +void CCommanderStatusPanel::ApplySchemeSettings(vgui::IScheme *pScheme) +{ + BaseClass::ApplySchemeSettings(pScheme); + + m_hFont = pScheme->GetFont( "Trebuchet20" ); + // FIXME: Outline, weight 1000 + m_hFontText = pScheme->GetFont( "Trebuchet18" ); + // FIXME: Outline, weight 700 +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCommanderStatusPanel::OnTick() +{ + // Simulate alpha + float dt = gpGlobals->frametime; + float maxmove = 1.0f / ALPHA_ADJUST_TIME; + float moverequested = dt * maxmove; + + float remaining = m_flGoalAlpha - m_flCurrentAlpha; + if ( fabs( remaining ) < 0.01f ) + { + if ( m_flCurrentAlpha < 0.01f ) + { + InternalClear(); + return; + } + } + + if ( moverequested > fabs( remaining ) ) + { + moverequested = fabs( remaining ); + } + + if ( remaining > 0.0f ) + { + m_flCurrentAlpha += moverequested; + } + else + { + m_flCurrentAlpha -= moverequested; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCommanderStatusPanel::Paint() +{ + if ( m_flCurrentAlpha <= 0.0f ) + return; + + int wide, tall; + GetSize( wide, tall ); + + int x = 2; + int y = 2; + + wide -= 4; + tall -= 4; + + int alpha = 255.0f * m_flCurrentAlpha; + + if ( m_Type == TYPE_INFO && m_nTitlePos != -1 ) + { + m_szText[ m_nTitlePos ] = 0; + + g_pMatSystemSurface->DrawColoredTextRect( m_hFont, x, y, wide, tall, 220, 220, 255, alpha, "%s", m_szText ); + + m_szText[ m_nTitlePos ] = '\n'; + + y += vgui::surface()->GetFontTall( m_hFont ); + tall -= vgui::surface()->GetFontTall( m_hFont ); + + // Start after title + g_pMatSystemSurface->DrawColoredTextRect( m_hFontText, x, y, wide, tall, 255, 255, 255, alpha, "%s", &m_szText[ m_nTitlePos + 1 ] ); + + if ( m_bShowTechnology && m_pTechnology ) + { + int x = 0; + int y = tall; + int size; + int r, g, b; + r = g = 192; + b = 255; + + float fResourceCost = m_pTechnology->GetResourceCost(); + float fResourceLevel = m_pTechnology->GetResourceLevel(); + + int techLevel = m_pTechnology->GetLevel(); + x = 5; + g_pMatSystemSurface->DrawColoredText( m_hFontText, x, y, r, g, b, alpha, "Level <%i>", techLevel ); + + x = wide - 5; + + if ( m_pTechnology->GetActive() ) + { + size = g_pMatSystemSurface->DrawTextLen( m_hFontText, "Already owned" ); + + x -= size; + + g_pMatSystemSurface->DrawColoredText( m_hFontText, x, y, r, g, b, alpha, "Already owned" ); + } + else + { + if ( !fResourceCost ) + { + size = g_pMatSystemSurface->DrawTextLen( m_hFontText, "Cost: Free" ); + + x -= size; + + g_pMatSystemSurface->DrawColoredText( m_hFontText, x, y, r, g, b, alpha, "Cost: Free" ); + } + else + { + int sizecost = g_pMatSystemSurface->DrawTextLen( m_hFontText, "WWW: 000 (000)" ) + 5; + + size = g_pMatSystemSurface->DrawTextLen( m_hFontText, "Cost: " ); + + x = wide - size - 4 * sizecost; + + r = 255; + g = 255; + b = 255; + g_pMatSystemSurface->DrawColoredText( m_hFontText, x, y, r, g, b, alpha, "Cost: " ); + + x += size; + + char szCostString[64]; + + // Draw cost string backward to right justify it + if ( fResourceCost ) + { + if ( fResourceLevel ) + Q_snprintf( szCostString, sizeof( szCostString ), "A: %i (%i)", (int)fResourceLevel, (int)fResourceCost ); + else + Q_snprintf( szCostString, sizeof( szCostString ), "A: %i", (int)fResourceCost ); + g_pMatSystemSurface->DrawColoredText( m_hFontText, x, y, sResourceColor.r, sResourceColor.g, sResourceColor.b, alpha, "%s", szCostString ); + sizecost = g_pMatSystemSurface->DrawTextLen( m_hFontText, "%s", szCostString ) + 2; + } + x += sizecost; + } + } + } + } + else + { + g_pMatSystemSurface->DrawColoredTextRect( m_hFont, + x, + y + tall - vgui::surface()->GetFontTall( m_hFont ) - 4, + wide, + vgui::surface()->GetFontTall( m_hFont ) + 2, + 220, 220, 255, alpha, + "%s", + m_szText ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCommanderStatusPanel::PaintBackground() +{ + if ( m_flCurrentAlpha <= 0.0f ) + return; + + if ( m_Type == TYPE_INFO ) + { + int alpha = MAX_FILLED_INFO_ALPHA * m_flCurrentAlpha; + + SetBgColor( Color( 0, 0, 0, alpha ) ); + + alpha += ( 255 - alpha ) / 2; + +// m_pBorder->SetColor( vgui::Color( 120, 120, 180, alpha ) ); + } + else + { + SetBgColor( Color( 0, 0, 0, 0 ) ); +// m_pBorder->SetColor( vgui::Color( 0, 0, 0, 0 ) ); + } + BaseClass::PaintBackground(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCommanderStatusPanel::Clear( void ) +{ + m_flGoalAlpha = 0.0f; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *fmt - +// ... - +//----------------------------------------------------------------------------- +void CCommanderStatusPanel::SetText( STATUSTYPE type, const char *fmt, ... ) +{ + va_list argptr; + va_start( argptr, fmt ); + _vsnprintf(m_szText, MAX_STATUS_TEXT, fmt, argptr); + va_end(argptr); + m_szText[ MAX_STATUS_TEXT - 1 ] = 0; + + m_Type = type; + SetVisible( true ); + + m_nTitlePos = -1; + + if ( m_Type == TYPE_INFO ) + { + // Search for first \n + char *p = m_szText; + while ( *p && *p != '\n' ) + { + p++; + } + + if ( *p == '\n' ) + { + m_nTitlePos = p - m_szText; + } + } + + m_flCurrentAlpha = MAX( m_flCurrentAlpha, 0.01f ); + m_flGoalAlpha = 1.0f; + m_bShowTechnology = false; + m_pTechnology = NULL; + + RecomputeBounds(); +} + +void CCommanderStatusPanel::SetTechnology( CBaseTechnology *technology ) +{ + m_bShowTechnology = true; + m_pTechnology = technology; +} + +void CCommanderStatusPanel::InternalClear( void ) +{ + m_Type = TYPE_UNKNOWN; + m_szText[ 0 ] = 0; + m_nTitlePos = -1; + + m_flCurrentAlpha = 0.0f; + m_flGoalAlpha = 0.0f; + + m_bShowTechnology = false; + m_pTechnology = NULL; + + SetVisible( false ); + SetPaintBackgroundEnabled( false ); + SetPaintBorderEnabled( false ); +} + +void CCommanderStatusPanel::RecomputeBounds( void ) +{ + int maxlines = 5; + int lineheight = vgui::surface()->GetFontTall( m_hFont ); + + int height; + height = lineheight + ( maxlines - 1 ) * vgui::surface()->GetFontTall( m_hFontText ); + height += 4; // 2 pixels top and bottom + + SetBounds( m_nLeftEdge, m_nBottomEdge - height, ScreenWidth() * 0.6, height ); + SetPaintBackgroundEnabled( true ); + SetPaintBorderEnabled( true ); +} + +void CCommanderStatusPanel::SetLeftBottom( int l, int b ) +{ + m_nLeftEdge = l; + m_nBottomEdge = b; + + RecomputeBounds(); +} + +////////////////////////////////////////// +// +// Status Panel Creation/Destruction and public api +// +////////////////////////////////////////// +void StatusCreate( vgui::Panel *parent, int treetoprow ) +{ + Assert( !g_pCommanderStatusPanel ); + g_pCommanderStatusPanel = new CCommanderStatusPanel(); + g_pCommanderStatusPanel->SetAutoDelete( false ); + g_pCommanderStatusPanel->SetParent( parent ); + g_pCommanderStatusPanel->SetLeftBottom( 0, treetoprow - 10 ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : treeetoprow - +//----------------------------------------------------------------------------- +void StatusSetTopRow( int treetoprow ) +{ + Assert( g_pCommanderStatusPanel ); + g_pCommanderStatusPanel->SetLeftBottom( 0, treetoprow - 10 ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void StatusDestroy( void ) +{ + delete g_pCommanderStatusPanel; + g_pCommanderStatusPanel = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : type - +// *fmt - +// ... - +//----------------------------------------------------------------------------- +void StatusPrint( STATUSTYPE type, const char *fmt, ... ) +{ + char text[ CCommanderStatusPanel::MAX_STATUS_TEXT ]; + + va_list argptr; + va_start( argptr, fmt ); + _vsnprintf(text, CCommanderStatusPanel::MAX_STATUS_TEXT, fmt, argptr); + va_end(argptr); + text[ CCommanderStatusPanel::MAX_STATUS_TEXT - 1 ] = 0; + + if ( g_pCommanderStatusPanel ) + { + g_pCommanderStatusPanel->SetText( type, text ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void StatusClear( void ) +{ + if ( g_pCommanderStatusPanel ) + { + g_pCommanderStatusPanel->Clear(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *technology - +//----------------------------------------------------------------------------- +void StatusTechnology( CBaseTechnology *technology ) +{ + if ( g_pCommanderStatusPanel ) + { + g_pCommanderStatusPanel->SetTechnology(technology ); + } +}
\ No newline at end of file diff --git a/game/client/tf2/hud_commander_statuspanel.h b/game/client/tf2/hud_commander_statuspanel.h new file mode 100644 index 0000000..9acc888 --- /dev/null +++ b/game/client/tf2/hud_commander_statuspanel.h @@ -0,0 +1,93 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef COMMANDER_STATUSPANEL_H +#define COMMANDER_STATUSPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include <vgui_controls/Panel.h> + +typedef enum +{ + TYPE_UNKNOWN = 0, + TYPE_INFO, // More invloved, with box and grayed background + // If it has a \n, the lines after the first aren't as large + TYPE_INFONOTITLE, // Don't treat first line with a \n specially + TYPE_HINT // Single line flyover +} STATUSTYPE; + +namespace vgui +{ + class LineBorder; +} + +class CBaseTechnology; + +//----------------------------------------------------------------------------- +// Purpose: The status line appears along the bottom of the screen and shows +// tooltip style help +//----------------------------------------------------------------------------- +class CCommanderStatusPanel : public vgui::Panel +{ +public: + typedef vgui::Panel BaseClass; + + enum { MAX_STATUS_TEXT = 4096 }; + + + CCommanderStatusPanel( void ); + virtual ~CCommanderStatusPanel( void ); + + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + + virtual void Paint(); + virtual void PaintBackground(); + virtual void OnTick(); + + // Set status text + virtual void SetText( STATUSTYPE type, PRINTF_FORMAT_STRING const char *fmt, ... ); + virtual void SetTechnology( CBaseTechnology *technology ); + virtual void Clear(); + + virtual void SetLeftBottom( int l, int b ); + +private: + void RecomputeBounds( void ); + void InternalClear(); + +private: + float m_flCurrentAlpha; + float m_flGoalAlpha; + + int m_nLeftEdge; + int m_nBottomEdge; + + vgui::HFont m_hFont; + vgui::HFont m_hFontText; + vgui::LineBorder *m_pBorder; + + // Position of the first '\n' character + char m_nTitlePos; + + + STATUSTYPE m_Type; + char m_szText[ MAX_STATUS_TEXT ]; + bool m_bShowTechnology; + CBaseTechnology *m_pTechnology; +}; + +void StatusCreate( vgui::Panel *parent, int treetoprow ); +void StatusDestroy( void ); +void StatusSetTopRow( int treetoprow ); + +void StatusPrint( STATUSTYPE type, PRINTF_FORMAT_STRING const char *fmt, ... ); +void StatusTechnology( CBaseTechnology *technology ); +void StatusClear( void ); + +#endif // COMMANDER_STATUSPANEL_H diff --git a/game/client/tf2/hud_damageindicator.cpp b/game/client/tf2/hud_damageindicator.cpp new file mode 100644 index 0000000..40cbc55 --- /dev/null +++ b/game/client/tf2/hud_damageindicator.cpp @@ -0,0 +1,322 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Hud element that indicates the direction of damage taken by the player +// +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "text_message.h" +#include "hud_macros.h" +#include "iclientmode.h" +#include "view.h" +#include <KeyValues.h> +#include <vgui_controls/AnimationController.h> +#include <vgui/ISurface.h> +#include "VGuiMatSurface/IMatSystemSurface.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/imesh.h" +#include "materialsystem/imaterialvar.h" +#include "IEffects.h" +#include "hudelement.h" + +using namespace vgui; + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHudDamageIndicator : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudDamageIndicator, vgui::Panel ); +public: + CHudDamageIndicator( const char *pElementName ); + void Init( void ); + void VidInit( void ); + void Reset( void ); + virtual bool ShouldDraw( void ); + + // Handler for our message + void MsgFunc_Damage( bf_read &msg ); + +private: + virtual void OnThink(); + virtual void Paint(); + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + + // Painting + void GetDamagePosition( const Vector &vecDelta, float flRadius, int *xpos, int *ypos, float *flRotation ); + void DrawDamageIndicator(int x0, int y0, int x1, int y1, float alpha, float flRotation ); + +private: + // Indication times + + CPanelAnimationVarAliasType( float, m_flMinimumWidth, "MinimumWidth", "10", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flMaximumWidth, "MaximumWidth", "100", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flMinimumHeight, "MinimumHeight", "20", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flMaximumHeight, "MaximumHeight", "100", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flStartRadius, "StartRadius", "140", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flEndRadius, "EndRadius", "120", "proportional_float" ); + + CPanelAnimationVar( float, m_iMaximumDamage, "MaximumDamage", "50" ); + CPanelAnimationVar( float, m_flMinimumTime, "MinimumTime", "1" ); + CPanelAnimationVar( float, m_flMaximumTime, "MaximumTime", "6" ); + CPanelAnimationVar( float, m_flTravelTime, "TravelTime", ".1" ); + CPanelAnimationVar( float, m_flFadeOutPercentage, "FadeOutPercentage", "0.7" ); + CPanelAnimationVar( float, m_flNoise, "Noise", "0.1" ); + + // List of damages we've taken + struct damage_t + { + int iScale; + float flLifeTime; + float flStartTime; + Vector vecDelta; // Damage origin relative to the player + }; + CUtlVector<damage_t> m_vecDamages; +}; + +DECLARE_HUDELEMENT( CHudDamageIndicator ); +DECLARE_HUD_MESSAGE( CHudDamageIndicator, Damage ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CHudDamageIndicator::CHudDamageIndicator( const char *pElementName ) : + CHudElement( pElementName ), BaseClass(NULL, "DamageIndicator") +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + + SetHiddenBits( HIDEHUD_HEALTH ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudDamageIndicator::Init( void ) +{ + HOOK_HUD_MESSAGE( CHudDamageIndicator, Damage ); + Reset(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudDamageIndicator::Reset( void ) +{ + m_vecDamages.Purge(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudDamageIndicator::VidInit( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudDamageIndicator::OnThink() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CHudDamageIndicator::ShouldDraw( void ) +{ + if ( !CHudElement::ShouldDraw() ) + return false; + + // Don't draw if we don't have any damage to indicate + if ( !m_vecDamages.Count() ) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Convert a damage position in world units to the screen's units +//----------------------------------------------------------------------------- +void CHudDamageIndicator::GetDamagePosition( const Vector &vecDelta, float flRadius, int *xpos, int *ypos, float *flRotation ) +{ + // Player Data + Vector playerPosition = MainViewOrigin(); + QAngle playerAngles = MainViewAngles(); + + Vector forward, right, up(0,0,1); + AngleVectors (playerAngles, &forward, NULL, NULL ); + forward.z = 0; + VectorNormalize(forward); + CrossProduct( up, forward, right ); + float front = DotProduct(vecDelta, forward); + float side = DotProduct(vecDelta, right); + *xpos = flRadius * -side; + *ypos = flRadius * -front; + + // Get the rotation (yaw) + *flRotation = atan2(*xpos,*ypos) + M_PI; + *flRotation *= 180 / M_PI; + + float yawRadians = -(*flRotation) * M_PI / 180.0f; + float ca = cos( yawRadians ); + float sa = sin( yawRadians ); + + // Rotate it around the circle + *xpos = (int)((ScreenWidth() / 2) + (flRadius * sa)); + *ypos = (int)((ScreenHeight() / 2) - (flRadius * ca)); +} + +//----------------------------------------------------------------------------- +// Purpose: Draw a single damage indicator +//----------------------------------------------------------------------------- +void CHudDamageIndicator::DrawDamageIndicator(int x0, int y0, int x1, int y1, float alpha, float flRotation ) +{ + IMaterial *pMat = materials->FindMaterial( "hud/health/indicator", TEXTURE_GROUP_VGUI ); + CMatRenderContextPtr pRenderContext( materials ); + IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMat ); + + // Get the corners, since they're being rotated + int wide = x1 - x0; + int tall = y1 - y0; + Vector2D vecCorners[4]; + Vector2D center( x0 + (wide * 0.5f), y0 + (tall * 0.5f) ); + float yawRadians = -flRotation * M_PI / 180.0f; + Vector2D axis[2]; + axis[0].x = cos(yawRadians); + axis[0].y = sin(yawRadians); + axis[1].x = -axis[0].y; + axis[1].y = axis[0].x; + Vector2DMA( center, -0.5f * wide, axis[0], vecCorners[0] ); + Vector2DMA( vecCorners[0], -0.5f * tall, axis[1], vecCorners[0] ); + Vector2DMA( vecCorners[0], wide, axis[0], vecCorners[1] ); + Vector2DMA( vecCorners[1], tall, axis[1], vecCorners[2] ); + Vector2DMA( vecCorners[0], tall, axis[1], vecCorners[3] ); + + // Draw the sucker + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); + + int iAlpha = alpha * 255; + meshBuilder.Color4ub( 255,255,255, iAlpha ); + meshBuilder.TexCoord2f( 0,0,0 ); + meshBuilder.Position3f( vecCorners[0].x,vecCorners[0].y,0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( 255,255,255, iAlpha ); + meshBuilder.TexCoord2f( 0,1,0 ); + meshBuilder.Position3f( vecCorners[1].x,vecCorners[1].y,0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( 255,255,255, iAlpha ); + meshBuilder.TexCoord2f( 0,1,1 ); + meshBuilder.Position3f( vecCorners[2].x,vecCorners[2].y,0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( 255,255,255, iAlpha ); + meshBuilder.TexCoord2f( 0,0,1 ); + meshBuilder.Position3f( vecCorners[3].x,vecCorners[3].y,0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.End(); + pMesh->Draw(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudDamageIndicator::Paint() +{ + // Iterate backwards, because we might remove them as we go + int iSize = m_vecDamages.Count(); + for (int i = iSize-1; i >= 0; i--) + { + // Scale size to the damage + int clampedDamage = clamp( m_vecDamages[i].iScale, 0, m_iMaximumDamage ); + + int iWidth = RemapVal(clampedDamage, 0, m_iMaximumDamage, m_flMinimumWidth, m_flMaximumWidth) * 0.5; + int iHeight = RemapVal(clampedDamage, 0, m_iMaximumDamage, m_flMinimumHeight, m_flMaximumHeight) * 0.5; + + // Find the place to draw it + int xpos, ypos; + float flRotation; + float flTimeSinceStart = ( gpGlobals->curtime - m_vecDamages[i].flStartTime ); + float flRadius = RemapVal( MIN( flTimeSinceStart, m_flTravelTime ), 0, m_flTravelTime, m_flStartRadius, m_flEndRadius ); + GetDamagePosition( m_vecDamages[i].vecDelta, flRadius, &xpos, &ypos, &flRotation ); + + // Calculate life left + float flLifeLeft = ( m_vecDamages[i].flLifeTime - gpGlobals->curtime ); + if ( flLifeLeft > 0 ) + { + float flPercent = flTimeSinceStart / (m_vecDamages[i].flLifeTime - m_vecDamages[i].flStartTime); + float alpha; + if ( flPercent <= m_flFadeOutPercentage ) + { + alpha = 1.0; + } + else + { + alpha = 1.0 - RemapVal( flPercent, m_flFadeOutPercentage, 1.0, 0.0, 1.0 ); + } + DrawDamageIndicator( xpos-iWidth, ypos-iHeight, xpos+iWidth, ypos+iHeight, alpha, flRotation ); + } + else + { + m_vecDamages.Remove(i); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Message handler for Damage message +//----------------------------------------------------------------------------- +void CHudDamageIndicator::MsgFunc_Damage( bf_read &msg ) +{ + damage_t damage; + damage.iScale = msg.ReadByte(); + if ( damage.iScale > m_iMaximumDamage ) + { + damage.iScale = m_iMaximumDamage; + } + Vector vecOrigin; + vecOrigin.x = msg.ReadFloat(); + vecOrigin.y = msg.ReadFloat(); + vecOrigin.z = msg.ReadFloat(); + damage.flStartTime = gpGlobals->curtime; + damage.flLifeTime = gpGlobals->curtime + RemapVal(damage.iScale, 0, m_iMaximumDamage, m_flMinimumTime, m_flMaximumTime); + + if ( vecOrigin == vec3_origin ) + { + vecOrigin = MainViewOrigin(); + } + + damage.vecDelta = (vecOrigin - MainViewOrigin()); + VectorNormalize( damage.vecDelta ); + + // Add some noise + damage.vecDelta[0] += random->RandomFloat( -m_flNoise, m_flNoise ); + damage.vecDelta[1] += random->RandomFloat( -m_flNoise, m_flNoise ); + damage.vecDelta[2] += random->RandomFloat( -m_flNoise, m_flNoise ); + VectorNormalize( damage.vecDelta ); + + m_vecDamages.AddToTail( damage ); +} + +//----------------------------------------------------------------------------- +// Purpose: hud scheme settings +//----------------------------------------------------------------------------- +void CHudDamageIndicator::ApplySchemeSettings(vgui::IScheme *pScheme) +{ + BaseClass::ApplySchemeSettings(pScheme); + SetPaintBackgroundEnabled(false); + + // set our size + int screenWide, screenTall; + int x, y; + GetPos(x, y); + GetHudSize(screenWide, screenTall); + SetBounds(0, y, screenWide, screenTall - y); +} diff --git a/game/client/tf2/hud_deathnotice.cpp b/game/client/tf2/hud_deathnotice.cpp new file mode 100644 index 0000000..3810bb4 --- /dev/null +++ b/game/client/tf2/hud_deathnotice.cpp @@ -0,0 +1,378 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Draws TF2's death notices +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud_macros.h" +#include "hudelement.h" +#include "c_playerresource.h" +#include "iclientmode.h" +#include <vgui_controls/Controls.h> +#include <vgui_controls/Panel.h> +#include <vgui/ISurface.h> +#include <vgui/ILocalize.h> +#include <game/client/iviewport.h> +#include <KeyValues.h> +#include "c_baseplayer.h" +#include "c_team.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +static ConVar hud_deathnotice_time( "hud_deathnotice_time", "6", 0 ); + +// Player entries in a death notice +struct DeathNoticePlayer +{ + char szName[MAX_PLAYER_NAME_LENGTH]; + int iEntIndex; +}; + +// Contents of each entry in our list of death notices +struct DeathNoticeItem +{ + DeathNoticePlayer Killer; + DeathNoticePlayer Victim; + DeathNoticePlayer Assist; + CHudTexture *iconDeath; + int iSuicide; + int iTeamKill; + float flDisplayTime; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHudDeathNotice : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudDeathNotice, vgui::Panel ); +public: + CHudDeathNotice( const char *pElementName ); + void Init( void ); + void VidInit( void ); + virtual bool ShouldDraw( void ); + virtual void Paint( void ); + virtual void ApplySchemeSettings( vgui::IScheme *scheme ); + + void SetColorForNoticePlayer( C_BasePlayer *pPlayer, int iTeamNumber ); + void RetireExpiredDeathNotices( void ); + void MsgFunc_DeathMsg( bf_read &msg ); + +private: + + CPanelAnimationVarAliasType( float, m_flLineHeight, "LineHeight", "15", "proportional_float" ); + + CPanelAnimationVar( float, m_flMaxDeathNotices, "MaxDeathNotices", "4" ); + CPanelAnimationVar( bool, m_bRightJustify, "RightJustify", "1" ); + + CPanelAnimationVar( Color, m_clrFriendlyText, "FriendlyTextColor", "FriendlyTextColor" ); + CPanelAnimationVar( Color, m_clrEnemyText, "EnemyTextColor", "EnemyTextColor" ); + CPanelAnimationVar( Color, m_clrMyKillsText, "MyKillsTextColor", "MyKillsTextColor" ); + + CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "HudNumbersTimer" ); + + // Texture for skull symbol + CHudTexture *m_iconD_skull; + + CUtlVector<DeathNoticeItem> m_DeathNotices; +}; + +using namespace vgui; + +DECLARE_HUDELEMENT( CHudDeathNotice ); +// DECLARE_HUD_MESSAGE( CHudDeathNotice, DeathMsg ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CHudDeathNotice::CHudDeathNotice( const char *pElementName ) : + CHudElement( pElementName ), BaseClass( NULL, "HudDeathNotice" ) +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + + SetHiddenBits( HIDEHUD_MISCSTATUS ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudDeathNotice::ApplySchemeSettings( IScheme *scheme ) +{ + BaseClass::ApplySchemeSettings( scheme ); + SetPaintBackgroundEnabled( false ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudDeathNotice::Init( void ) +{ +//FIXME!!!! +//HOOK_MESSAGE( DeathMsg ); + +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudDeathNotice::VidInit( void ) +{ + m_iconD_skull = gHUD.GetIcon( "d_skull" ); + m_DeathNotices.Purge(); +} + +//----------------------------------------------------------------------------- +// Purpose: Draw if we've got at least one death notice in the queue +//----------------------------------------------------------------------------- +bool CHudDeathNotice::ShouldDraw( void ) +{ + return ( CHudElement::ShouldDraw() && ( m_DeathNotices.Count() ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudDeathNotice::SetColorForNoticePlayer( C_BasePlayer *pPlayer, int iTeamNumber ) +{ + // Set the right color + if ( pPlayer == C_BasePlayer::GetLocalPlayer() ) + { + surface()->DrawSetTextColor( m_clrMyKillsText ); + } + else if ( GetLocalTeam() && GetLocalTeam()->GetTeamNumber() == iTeamNumber ) + { + surface()->DrawSetTextColor( m_clrFriendlyText ); + } + else + { + surface()->DrawSetTextColor( m_clrEnemyText ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudDeathNotice::Paint() +{ + surface()->DrawSetTextFont( m_hTextFont ); + surface()->DrawSetTextColor( m_clrFriendlyText ); + + int iCount = m_DeathNotices.Count(); + for ( int i = 0; i < iCount; i++ ) + { + CHudTexture *icon = m_DeathNotices[i].iconDeath; + if ( !icon ) + continue; + + wchar_t victim[ 256 ]; + wchar_t killer[ 256 ]; + wchar_t assist[ 256 ]; + + g_pVGuiLocalize->ConvertANSIToUnicode( m_DeathNotices[i].Victim.szName, victim, sizeof( victim ) ); + g_pVGuiLocalize->ConvertANSIToUnicode( m_DeathNotices[i].Killer.szName, killer, sizeof( killer ) ); + g_pVGuiLocalize->ConvertANSIToUnicode( m_DeathNotices[i].Assist.szName, assist, sizeof( assist ) ); + + // Get the team numbers for the players involved + C_BasePlayer *pKiller = static_cast<C_BasePlayer*>(cl_entitylist->GetEnt( m_DeathNotices[i].Killer.iEntIndex )); + int iKillerTeam = pKiller ? pKiller->GetTeamNumber() : 0; + C_BasePlayer *pAssist = NULL; + if ( m_DeathNotices[i].Assist.iEntIndex ) + { + pAssist = static_cast<C_BasePlayer*>(cl_entitylist->GetEnt( m_DeathNotices[i].Assist.iEntIndex )); + } + C_BasePlayer *pVictim = static_cast<C_BasePlayer*>(cl_entitylist->GetEnt( m_DeathNotices[i].Victim.iEntIndex )); + int iVictimTeam = pVictim ? pVictim->GetTeamNumber() : 0; + + // Get the local position for this notice + int len = UTIL_ComputeStringWidth( m_hTextFont, victim ); + int y = (m_flLineHeight * i); + int x; + if ( m_bRightJustify ) + { + x = GetWide() - len - icon->Width() - 5; + } + else + { + x = 0; + } + + // Only draw killers name if it wasn't a suicide + if ( !m_DeathNotices[i].iSuicide ) + { + if ( m_bRightJustify ) + { + x -= UTIL_ComputeStringWidth( m_hTextFont, killer ); + if ( pAssist ) + { + x -= UTIL_ComputeStringWidth( m_hTextFont, L" + " ); + x -= UTIL_ComputeStringWidth( m_hTextFont, killer ); + } + } + + SetColorForNoticePlayer( pKiller, iKillerTeam ); + + // Draw killer's name + surface()->DrawSetTextPos( x, y ); + surface()->DrawUnicodeString( killer ); + surface()->DrawGetTextPos( x, y ); + + // Did we have an assistant? + if ( pAssist ) + { + // Draw the conjuction + const wchar_t *sAnd = L" + "; + surface()->DrawSetTextPos( x, y ); + surface()->DrawUnicodeString( sAnd ); + surface()->DrawUnicodeString( assist ); + surface()->DrawGetTextPos( x, y ); + } + } + + Color iconColor( 255, 80, 0, 255 ); + if ( m_DeathNotices[i].iTeamKill ) + { + // display it in sickly green + iconColor = Color( 10, 240, 10, 255 ); + } + + // Draw death weapon + icon->DrawSelf( x, y, iconColor ); + x += icon->Width(); + + SetColorForNoticePlayer( pVictim, iVictimTeam ); + + // Draw victims name + surface()->DrawSetTextPos( x, y ); + surface()->DrawUnicodeString( victim ); + } + + // Now retire any death notices that have expired + RetireExpiredDeathNotices(); +} + +//----------------------------------------------------------------------------- +// Purpose: This message handler may be better off elsewhere +//----------------------------------------------------------------------------- +void CHudDeathNotice::RetireExpiredDeathNotices( void ) +{ + // Loop backwards because we might remove one + int iSize = m_DeathNotices.Size(); + for ( int i = iSize-1; i >= 0; i-- ) + { + if ( m_DeathNotices[i].flDisplayTime < gpGlobals->curtime ) + { + m_DeathNotices.Remove(i); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Server's told us that someone's died +//----------------------------------------------------------------------------- +void CHudDeathNotice::MsgFunc_DeathMsg( bf_read &msg ) +{ + if (!g_PR) + return; + + int killer = msg.ReadByte(); + int assist = msg.ReadByte(); + int victim = msg.ReadByte(); + + char killedwith[32]; + char fullkilledwith[128]; + msg.ReadString( killedwith, sizeof(killedwith) ); + + if ( killedwith && *killedwith ) + { + Q_snprintf( fullkilledwith, sizeof(fullkilledwith), "d_%s", killedwith ); + } + else + { + fullkilledwith[0] = 0; + } + + // Do we have too many death messages in the queue? + if ( m_DeathNotices.Count() > 0 && + m_DeathNotices.Count() >= (int)m_flMaxDeathNotices ) + { + // Remove the oldest one in the queue, which will always be the first + m_DeathNotices.Remove(0); + } + + // Get the names of the players + const char *killer_name = g_PR->GetPlayerName( killer ); + const char *assist_name = g_PR->GetPlayerName( assist ); + const char *victim_name = g_PR->GetPlayerName( victim ); + if ( !killer_name ) + killer_name = ""; + if ( !assist_name ) + assist_name = ""; + if ( !victim_name ) + victim_name = ""; + + // Make a new death notice + DeathNoticeItem deathMsg; + deathMsg.Killer.iEntIndex = killer; + deathMsg.Assist.iEntIndex = assist; + deathMsg.Victim.iEntIndex = victim; + Q_strncpy( deathMsg.Killer.szName, killer_name, MAX_PLAYER_NAME_LENGTH ); + Q_strncpy( deathMsg.Assist.szName, assist_name, MAX_PLAYER_NAME_LENGTH ); + Q_strncpy( deathMsg.Victim.szName, victim_name, MAX_PLAYER_NAME_LENGTH ); + deathMsg.flDisplayTime = gpGlobals->curtime + hud_deathnotice_time.GetFloat(); + deathMsg.iSuicide = ( !killer || killer == victim ); + deathMsg.iTeamKill = ( !strcmp( fullkilledwith, "d_teammate" ) ); + + // Try and find the death identifier in the icon list + deathMsg.iconDeath = gHUD.GetIcon( fullkilledwith ); + if ( !deathMsg.iconDeath ) + { + // Can't find it, so use the default skull & crossbones icon + deathMsg.iconDeath = m_iconD_skull; + } + + // Add it to our list of death notices + m_DeathNotices.AddToTail( deathMsg ); + + char sDeathMsg[512]; + + // Record the death notice in the console + if ( deathMsg.iSuicide ) + { + if ( !strcmp( fullkilledwith, "d_world" ) ) + { + Q_snprintf( sDeathMsg, sizeof( sDeathMsg ), "%s died.\n", deathMsg.Victim.szName ); + } + else + { + Q_snprintf( sDeathMsg, sizeof( sDeathMsg ), "%s suicided.\n", deathMsg.Victim.szName ); + } + } + else if ( deathMsg.iTeamKill ) + { + Q_snprintf( sDeathMsg, sizeof( sDeathMsg ), "%s teamkilled %s", deathMsg.Killer.szName, deathMsg.Victim.szName ); + } + else + { + if ( assist ) + { + Q_snprintf( sDeathMsg, sizeof( sDeathMsg ), "%s and %s killed %s", deathMsg.Killer.szName, deathMsg.Assist.szName, deathMsg.Victim.szName ); + } + else + { + Q_snprintf( sDeathMsg, sizeof( sDeathMsg ), "%s killed %s", deathMsg.Killer.szName, deathMsg.Victim.szName ); + } + } + + if ( fullkilledwith && *fullkilledwith && (*fullkilledwith > 13 ) && strcmp( fullkilledwith, "d_world" ) && !deathMsg.iTeamKill ) + { + Q_strncat( sDeathMsg, VarArgs( " with %s.\n", fullkilledwith+2 ), sizeof( sDeathMsg ), COPY_ALL_CHARACTERS ); + } + + Msg( sDeathMsg ); +} + + + diff --git a/game/client/tf2/hud_emp.cpp b/game/client/tf2/hud_emp.cpp new file mode 100644 index 0000000..f97fa3a --- /dev/null +++ b/game/client/tf2/hud_emp.cpp @@ -0,0 +1,195 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "hudelement.h" +#include <vgui_controls/Panel.h> +#include "c_basetfplayer.h" +#include "tf_shareddefs.h" +#include "iclientmode.h" +#include "clientmode_tfnormal.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/imesh.h" +#include "materialsystem/imaterialvar.h" +#include <vgui_controls/Controls.h> +#include <vgui/ISurface.h> +#include "clienteffectprecachesystem.h" + +// EMP level positions +#define HUDEMP_LEFT ((ScreenWidth() / 2)- XRES(40)) +#define HUDEMP_WIDTH XRES(16) +#define HUDEMP_TOP YRES(210) +#define HUDEMP_HEIGHT YRES(16) + +// Changes per second +#define HUDEMP_FRAMERATE 30.0f + +CLIENTEFFECT_REGISTER_BEGIN( PrecacheHudDamage ) +CLIENTEFFECT_MATERIAL( "Hud/emp/emp_damage" ) +CLIENTEFFECT_REGISTER_END() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool GetEMPDamage() +{ + C_BaseTFPlayer *pPlayer; + pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + if ( !pPlayer ) + return false; + + return pPlayer->HasPowerup(POWERUP_EMP) ? true : false; +} + +//----------------------------------------------------------------------------- +// Purpose: Icon showing EMP damage is occuring +//----------------------------------------------------------------------------- +class CHudEMP : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudEMP, vgui::Panel ); + +public: + DECLARE_MULTIPLY_INHERITED(); + + CHudEMP( const char *pElementName ); + ~CHudEMP(); + + // vgui::Panel overrides. + virtual void Paint( void ); + + // CHudElement overrides. + virtual bool ShouldDraw( void ); + virtual void Init( void ); + +protected: + IMaterial *m_pEMPIcon; + IMaterialVar *m_pFrameVar; + + float m_flNextFrameChange; + int m_nNumFrames; +}; + +//DECLARE_HUDELEMENT( CHudEMP, CHudEMP ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CHudEMP::CHudEMP( const char *pElementName ) : + CHudElement( pElementName ), vgui::Panel( NULL, pElementName ) +{ + m_pEMPIcon = NULL; + m_pFrameVar = NULL; + m_flNextFrameChange = 0.0f; + m_nNumFrames = 1; + //SetPaintBackgroundEnabled( false ); + SetAutoDelete( false ); + SetName( "emp" ); + + SetHiddenBits( HIDEHUD_HEALTH ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CHudEMP::~CHudEMP( void ) +{ + if ( m_pEMPIcon ) + { + m_pEMPIcon->DecrementReferenceCount(); + m_pEMPIcon = NULL; + } + SetParent( (vgui::Panel *)NULL ); +} + +//----------------------------------------------------------------------------- +// Purpose: Attach the jetpack bar to the main panel +//----------------------------------------------------------------------------- +void CHudEMP::Init( void ) +{ + if ( !m_pEMPIcon ) + { + m_pEMPIcon = materials->FindMaterial( "Hud/emp/emp_damage", TEXTURE_GROUP_VGUI ); + assert( m_pEMPIcon ); + m_pEMPIcon->IncrementReferenceCount(); + + m_pFrameVar = m_pEMPIcon->FindVar( "$frame", NULL, false ); + m_nNumFrames = m_pEMPIcon->GetNumAnimationFrames(); + } + + SetPos( HUDEMP_LEFT, HUDEMP_TOP ); + SetSize( HUDEMP_WIDTH, HUDEMP_HEIGHT ); + + vgui::Panel *pParent = GetClientModeNormal()->GetViewport(); + SetParent(pParent); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CHudEMP::ShouldDraw( void ) +{ + return ( CHudElement::ShouldDraw() && GetEMPDamage() ); +} + +//----------------------------------------------------------------------------- +// Purpose: Draw the jetpack level +//----------------------------------------------------------------------------- +void CHudEMP::Paint() +{ + // Rush label + int iX, iY; + GetPos( iX, iY ); + int iWidth = XRES(16); + int iHeight = YRES(16); + + if ( m_pFrameVar ) + { + float curtime = gpGlobals->curtime; + + if ( curtime >= m_flNextFrameChange ) + { + m_flNextFrameChange = curtime + ( 1.0f / HUDEMP_FRAMERATE ); + + int frame = m_pFrameVar->GetIntValue(); + frame++; + if ( frame >= m_nNumFrames ) + { + frame = 0; + } + m_pFrameVar->SetIntValue(frame); + } + } + + IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL, m_pEMPIcon ); + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); + + meshBuilder.Color3f( 1.0, 1.0, 1.0 ); + meshBuilder.TexCoord2f( 0,0,0 ); + meshBuilder.Position3f( iX,iY,0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color3f( 1.0, 1.0, 1.0 ); + meshBuilder.TexCoord2f( 0,1,0 ); + meshBuilder.Position3f( iX+iWidth, iY, 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color3f( 1.0, 1.0, 1.0 ); + meshBuilder.TexCoord2f( 0,1,1 ); + meshBuilder.Position3f( iX+iWidth, iY+iHeight, 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color3f( 1.0, 1.0, 1.0 ); + meshBuilder.TexCoord2f( 0,0,1 ); + meshBuilder.Position3f( iX, iY+iHeight, 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.End(); + pMesh->Draw(); +} + diff --git a/game/client/tf2/hud_health.cpp b/game/client/tf2/hud_health.cpp new file mode 100644 index 0000000..474bc90 --- /dev/null +++ b/game/client/tf2/hud_health.cpp @@ -0,0 +1,217 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: TF2's Hud health display +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "hud_numeric.h" +#include "c_basetfplayer.h" +#include "basetfvehicle.h" +#include <vgui_controls/AnimationController.h> +#include <KeyValues.h> +#include "iclientmode.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: Local player health +//----------------------------------------------------------------------------- +class CHudHealth : public CHudNumeric +{ + DECLARE_CLASS_SIMPLE( CHudHealth, CHudNumeric ); + +public: + CHudHealth( const char *pElementName ); + + virtual const char *GetLabelText() { return m_szHealthLabel; } + virtual const char *GetPulseEvent( bool increment ) { return increment ? "HealthIncrement" : "HealthDecrement"; } + virtual bool GetValue( char *val, int maxlen ); + + virtual Color GetColor(); + virtual Color GetBoxColor(); + +private: + bool GetHealth( int& value ); + + CPanelAnimationStringVar( 128, m_szHealthLabel, "HealthLabel", "Health" ); +}; + +DECLARE_HUDELEMENT( CHudHealth ); + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CHudHealth::CHudHealth( const char *pElementName ) : + CHudNumeric( pElementName, "HudHealth" ) +{ + SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD | HIDEHUD_NEEDSUIT ); +} + +bool CHudHealth::GetHealth( int& value ) +{ + C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + if ( !pPlayer ) + return false; + + value = pPlayer->GetHealth(); + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : value - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CHudHealth::GetValue( char *val, int maxlen ) +{ + int value = 0; + if ( !GetHealth( value ) ) + return false; + + Q_snprintf( val, maxlen, "%i", value ); + return true; +} + +Color CHudHealth::GetColor() +{ + int value = 0; + if ( !GetHealth( value ) || value > 25 ) + return m_TextColor; + + return m_TextColorCritical; +} + +Color CHudHealth::GetBoxColor() +{ + int value = 0; + if ( !GetHealth( value ) || value > 25 ) + return m_BoxColor; + return m_BoxColorCritical; +} + +//----------------------------------------------------------------------------- +// Purpose: Local player's vehicle health, if in one +//----------------------------------------------------------------------------- +class CHudVehicleHealth : public CHudNumeric +{ + DECLARE_CLASS_SIMPLE( CHudVehicleHealth, CHudNumeric ); + +public: + CHudVehicleHealth( const char *pElementName ); + + virtual const char *GetLabelText() { return m_szVehicleHealthLabel; } + virtual const char *GetPulseEvent( bool increment ) { return increment ? "HealthVehicleIncrement" : "HealthVehicleDecrement"; } + virtual bool GetValue( char *val, int maxlen ); + + virtual Color GetColor(); + virtual Color GetBoxColor(); + +private: + bool GetHealth( int& value ); + + CPanelAnimationVar( float, m_flLingerTime, "exit_vehicle_linger_time", "2.0" ); + + bool m_bPrevHealth; + float m_flLingerFinish; + int m_nLastHealth; + + CPanelAnimationStringVar( 128, m_szVehicleHealthLabel, "VehicleHealthLabel", "Vehicle Health" ); +}; + +DECLARE_HUDELEMENT( CHudVehicleHealth ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CHudVehicleHealth::CHudVehicleHealth( const char *pElementName ) : + CHudNumeric( pElementName, "HudVehicleHealth" ) +{ + m_bPrevHealth = false; + m_flLingerFinish = 0.0f; + m_flLingerTime = 2.0f; + m_nLastHealth = 0; + + SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD ); +} + +bool CHudVehicleHealth::GetHealth( int& value ) +{ + C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + if ( pPlayer ) + { + // Draw the vehicle health: + C_BaseTFVehicle *pVehicleEnt = ( C_BaseTFVehicle* )pPlayer->GetVehicle(); + if( pVehicleEnt ) + { + value = pVehicleEnt->GetHealth(); + m_nLastHealth = value; + bool changed = m_bPrevHealth != true; + + if ( changed ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HealthVehicleEnterVehicle" ); + } + + m_bPrevHealth = true; + return true; + } + } + + bool changed = m_bPrevHealth != false; + if ( changed ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HealthVehicleExitVehicle" ); + m_flLingerFinish = gpGlobals->curtime + m_flLingerTime; + } + + m_bPrevHealth = false; + + if ( gpGlobals->curtime < m_flLingerFinish ) + { + value = m_nLastHealth; + return true; + } + + m_flLingerFinish = 0.0f; + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : value - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CHudVehicleHealth::GetValue( char *val, int maxlen ) +{ + int value = 0; + bool show = GetHealth( value ); + if ( !show ) + { + return false; + } + + Q_snprintf( val, maxlen, "%i", value ); + return true; +} + +Color CHudVehicleHealth::GetColor() +{ + int value = 0; + if ( !GetHealth( value ) || value > 75 ) + return m_TextColor; + + return m_TextColorCritical; +} + +Color CHudVehicleHealth::GetBoxColor() +{ + int value = 0; + if ( !GetHealth( value ) || value > 75 ) + return m_BoxColor; + return m_BoxColorCritical; +} 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." ); + + + + diff --git a/game/client/tf2/hud_minimap.h b/game/client/tf2/hud_minimap.h new file mode 100644 index 0000000..a0c6ab1 --- /dev/null +++ b/game/client/tf2/hud_minimap.h @@ -0,0 +1,272 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( HUD_MINIMAP_H ) +#define HUD_MINIMAP_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/vector.h" +#include "cdll_client_int.h" +#include "hudelement.h" +#include "utllinkedlist.h" +#include "CommanderOverlay.h" +#include "MapData.h" + +class BitmapImage; +class CTextHelpPanel; + +//----------------------------------------------------------------------------- +// This interfaces gets called when a click occurs in the minimap +//----------------------------------------------------------------------------- +class IMinimapClient +{ +public: + virtual void MinimapClicked( const Vector& clickWorldPos ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Ways to perform WorldToMinimap +//----------------------------------------------------------------------------- +enum MinimapPosType_t +{ + MINIMAP_NOCLIP = 0, // Don't draw things off the minimap + MINIMAP_CLAMP, // Clamp the position to lie within the minimap + MINIMAP_CLIP, // Clip the vector from minimap center to object + // to the minimap bounds and put the object on the edge + MINIMAP_ALWAYS_ACCEPT // Just do the scaling and return a value - don't worry about clipping. +}; + + +//----------------------------------------------------------------------------- +// Purpose: On the left side of the screen is an overview map and a highlight +// rectangle showing the current viewport +// +// NOTE: The minimap panel is architected in such a way as to view some global +// state. There can be many instances of the minimap panel +//----------------------------------------------------------------------------- +class CMinimapPanel : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CMinimapPanel, vgui::Panel ); + +public: + enum + { + STABLE = 0, + GROWING, + SHRINKING + }; + + CMinimapPanel( const char *pElementName ); + virtual ~CMinimapPanel( void ); + + void Init( IMinimapClient* pClient = NULL ); + + virtual void LevelInit( const char *mapname ); + virtual void LevelShutdown( void ); + + virtual void ApplySchemeSettings( vgui::IScheme *scheme ); + + virtual void OnMousePressed(vgui::MouseCode code); + + virtual void Paint(); + + virtual void OnTick(); + virtual void OnThink(); + + virtual void OnSizeChanged( int w, int h ); + + // Converts a world-space position to a coordinate in minimap panel space + bool WorldToMinimap( MinimapPosType_t posType, const Vector &pos, float& outx, float& outy ); + + // The following methods deal with management of the minimap data + static vgui::Panel *MinimapRootPanel(); + static CMinimapPanel *MinimapPanel(); + + // Call this when the minimap panel is going to be drawn... + void Activate(); + + // 0 is minimized and won't draw zoom details, 1.0 is fully maximized + bool ShouldDrawZoomDetails( int& alpha ); + + bool InternalWorldToMinimap( MinimapPosType_t posType, const Vector &pos, const Vector& origin, float zoomscale, float& outx, float& outy ); + + static void Zoom_Minimap_f( void ); + void ZoomIn( void ); + + void ToggleMinimap( void ); + void SetMinimapZoom( bool bZoom); + + virtual void ProcessInput( void ); + + float GetAdjustedZoom( void ); + float GetTrueZoom( void ); + + // Handler for our message + void MsgFunc_MinimapPulse( bf_read &msg ); + +private: + void SetBackgroundMaterials( char const* pMaterialName ); + + void GetMapOriginAndScale( Vector& origin, float& scale ); + + void SetBackgroundViewport( float minx, float miny, float maxx, float maxy, bool includedetails ); + void PaintActOverlays( int teamIndex, int alpha ); + void AdjustNormalizedPositionForAspectRatio( float& x, float& y ); + + void DrawVisibleArea( void ); + + void ComputeMapOrigin( Vector& origin ); + + void InitOverlays( const char *materialrootname ); + void ShutdownOverlays( void ); + + vgui::Panel *GetTextPaintPanel( void ); + + void InvokeOnTickOnChildren( vgui::Panel *parent ); + + bool m_DrawVisibleArea; + IMinimapClient *m_pClient; + + CPanelAnimationVar( float, m_flExpansionFrac, "ExpansionFrac", "0" ); + CPanelAnimationVar( float, m_flDetailsAlpha, "DetailsAlpha", "0" ); + CPanelAnimationVar( float, m_flMapScale, "MapScale", "2000" ); + CPanelAnimationVar( float, m_flZoomAmount, "ZoomAmount", "1.0" ); + CPanelAnimationVar( float, m_flCenterOnPlayer, "CenterOnPlayer", "1" ); + + CPanelAnimationVar( float, m_flInsetPixels, "InsetPixels", "16" ); + + float m_flPrevZoomAmount; + + CPanelAnimationVar( Color, m_BackgroundColor, "BackgroundColor", "Black" ); + CPanelAnimationVar( Color, m_BorderColor, "BorderColor", "FgColor" ); + + int m_nZoomLevel; + bool m_bMinimapZoomed; + int m_nCurrentAct; + + float m_flZoomAdjust; // Adjustment needed to get map to fit exactly into box in one dimension assuming + // m_flZoomAmount == 1.0f + + + enum + { + NUM_WIDTHS = 2, + }; + + + // Calculated once per frame and cached + Vector m_vecCurrentOrigin; + Vector m_vecMapCenter; + float m_flMapAspectRatio; + float m_flViewportAspectRatio; + // map aspect / viewport aspect + float m_flAspectAdjustment; + + float m_flNormalizedXScale; + float m_flNormalizedYScale; + float m_flNormalizedXOffset; + float m_flNormalizedYOffset; + + + // These are the wordspace corners of the minimap + float m_flWorldSpaceBounds[ 4 ]; + // These are the above, except clamped to actual world mins/maxs + float m_flClippedWorldSpaceBounds[ 4 ]; + // These are used to clamp the map origin to keep the zoomed map from scrolling off screen + float m_flWorldSpaceInsets[ 4 ]; + + enum + { + MAX_ACTS = 16, + MAX_ACT_TEAMS = 2 + }; + + struct Overlays + { + bool m_bInUse; + BitmapImage *m_pOverlay; + BitmapImage *m_pText; + }; + + BitmapImage *m_pBackground[ MAX_ACT_TEAMS ]; + Overlays m_rgOverlays[ MAX_ACT_TEAMS ][ MAX_ACTS ]; + + CTextHelpPanel *m_pTextPanel; + vgui::Panel *m_pBackgroundPanel; +}; + + +//----------------------------------------------------------------------------- +// minimap render order +//----------------------------------------------------------------------------- +enum +{ + MINIMAP_GROUND_LINES = 0, + MINIMAP_RESOURCE_ZONES, + MINIMAP_OBJECTS, + MINIMAP_SPY_CAMERAS, + MINIMAP_COLLECTORS, + MINIMAP_MAP_GOALS, + MINIMAP_PLAYERS, + MINIMAP_LOCAL_PLAYER, + MINIMAP_SNIPER_RESPAWN, + MINIMAP_PERSONAL_ORDERS +}; + + +//----------------------------------------------------------------------------- +// Instantiate a temporary trace (position based, or entity based) +//----------------------------------------------------------------------------- +void MinimapCreateTempTrace( const char* pMetaClassName, int sortOrder, const Vector &vecPosition ); +void MinimapCreateTempTrace( const char* pMetaClassName, int sortOrder, C_BaseEntity *pEntity, const Vector &vecOffset ); + + +//----------------------------------------------------------------------------- +// Helper macro to make overlay factories one line of code. Use like this: +// DECLARE_MINIMAP_FACTORY( CEntityImagePanel, "image" ); +//----------------------------------------------------------------------------- +struct MinimapInitData_t +{ + C_BaseEntity *m_pEntity; + Vector m_vecPosition; // relative to m_pEntity if it's specified, otherwise absolute position + + MinimapInitData_t() : m_pEntity(NULL), m_vecPosition( 0, 0, 0 ) {} + MinimapInitData_t( C_BaseEntity *pEntity ) : m_pEntity(pEntity), m_vecPosition( 0, 0, 0 ) {} +}; + +#define DECLARE_MINIMAP_FACTORY( _PanelClass, _nameString ) \ + DECLARE_PANEL_FACTORY( _PanelClass, MinimapInitData_t, _nameString ) + + +//----------------------------------------------------------------------------- +// Macros for help with simple registration of minimap +// Put DECLARE_MINIMAP_PANEL() in your class definition +// and CONSTRUCT_MINIMAP_PANEL( "panelname", SORT_ORDER ) in your class constructor +//----------------------------------------------------------------------------- +#define DECLARE_MINIMAP_PANEL( ) DECLARE_METACLASS_PANEL( m_MinimapTrace ) +#define CONSTRUCT_MINIMAP_PANEL( _name, _sortorder ) \ + MinimapInitData_t _traceInit( this ); \ + CONSTRUCT_METACLASS_PANEL( m_MinimapTrace, _name, CMinimapPanel::MinimapRootPanel(), _sortorder, &_traceInit ) +#define DESTRUCT_MINIMAP_PANEL( ) \ + DESTRUCT_METACLASS_PANEL( m_MinimapTrace ) +#define IS_MINIMAP_PANEL_DEFINED( ) ( m_MinimapTrace.GetPanel() != NULL ) + +// Kind of a hack; assumes all minimap panels inherit from CMinimapTracePanel, but that's reasonable.. +#define SET_MINIMAP_PANEL_VISIBILITY( _visible ) \ + do \ + { \ + if (m_MinimapTrace.GetPanel()) \ + { \ + static_cast<CMinimapTracePanel*>(m_MinimapTrace.GetPanel())->SetTraceVisibility( _visible ); \ + } \ + } while (0) + +#endif // HUD_MINIMAP_H
\ No newline at end of file diff --git a/game/client/tf2/hud_numeric.cpp b/game/client/tf2/hud_numeric.cpp new file mode 100644 index 0000000..3d2937c --- /dev/null +++ b/game/client/tf2/hud_numeric.cpp @@ -0,0 +1,978 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "hud_numeric.h" +#include "iclientmode.h" +#include <KeyValues.h> +#include <vgui/ISurface.h> +#include <vgui/IScheme.h> +#include <vgui_controls/AnimationController.h> +#include "ctype.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pElementName - +// *panelName - +//----------------------------------------------------------------------------- +CHudNumeric::CHudNumeric( const char *pElementName, const char *panelName ) + : CHudElement( pElementName ), BaseClass( NULL, panelName ) +{ + // Make sure we have the lookups built + BuildPrintablesList(); + + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + + SetActive( true ); + SetAutoDelete( false ); + + m_nTextLen = 0; + Q_memset( m_szPreviousValue, 0, sizeof( m_szPreviousValue ) ); + Q_memset( m_szLatchedValue, 0, sizeof( m_szLatchedValue ) ); + + m_bDrawLabel = true; + m_bSendPulses = true; + m_bPulseForced = true; + + m_flRotaryTime = 0.0f; + m_flRotaryStartTime = 0.0f; + m_flActualCharactersPerSecond = 7.0f; +} + +bool CHudNumeric::s_bPrintablesBuilt; +CUtlRBTree< int, int > CHudNumeric::m_Printables( 0, 0, DefLessFunc( int ) ); + +//----------------------------------------------------------------------------- +// Purpose: Builds a list of printable characters +//----------------------------------------------------------------------------- +void CHudNumeric::BuildPrintablesList( void ) +{ + if ( s_bPrintablesBuilt ) + return; + + s_bPrintablesBuilt = true; + int i; + for ( i = 0; i < 256; i++ ) + { + if ( isalnum( i ) ) // isprint or isgraph? + { + m_Printables.Insert( i ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Find the index of a printable character +// Input : ch - +// Output : int +//----------------------------------------------------------------------------- +int CHudNumeric::FindPrintableIndex( int ch ) +{ + int idx = m_Printables.Find( ch ); + return idx; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *scheme - +//----------------------------------------------------------------------------- +void CHudNumeric::ApplySchemeSettings(IScheme *scheme) +{ + BaseClass::ApplySchemeSettings(scheme); + + m_flActualCharactersPerSecond = (float)m_flDesiredCharactersPerSecond; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CHudNumeric::IsRotating( void ) const +{ + if ( gpGlobals->curtime >= m_flRotaryStartTime && + gpGlobals->curtime <= ( m_flRotaryStartTime + m_flRotaryTime ) ) + { + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : frac - +// startchar - +// endchar - +// prevchar - +// nextchar - +// subfrac - +//----------------------------------------------------------------------------- +void CHudNumeric::GetRotatedChar( float frac, char startchar, char endchar, char& prevchar, char& nextchar, float& subfrac ) +{ + // Recast into database of printable characters + int startidx = FindPrintableIndex( startchar ); + int endidx = FindPrintableIndex( endchar ); + + float diff = ( float )endidx - ( float )startidx; + + // No delta + if ( diff == 0.0f || + startidx == m_Printables.InvalidIndex() || + endidx == m_Printables.InvalidIndex() ) + { + prevchar = startchar; + nextchar = startchar; + subfrac = 0.0f; + + return; + } + + bool reverse = false; + // Going backwards is same as forward except frac is reversed + if ( diff < 0.0f ) + { + reverse = true; + frac = 1.0f - frac; + int temp = startidx; + startidx = endidx; + endidx = temp; + diff = -diff; + } + + float foutindex = (float)startidx; + int outindex; + float fnextindex; + int nextindex; + + int maxdelta = (int)diff; + + if ( m_nRotaryMaxDelta != 0 ) + { + maxdelta = MIN( m_nRotaryMaxDelta, maxdelta ); + } + + // Quantize steps + // Map frac into maxdelta discrete intervals + float indicesperstep = diff / (float)maxdelta; + float fnumstepstaken = clamp( frac * (float)maxdelta, 0.0f, (float)( maxdelta -0.001f ) ); + int numstepstaken = (int)(fnumstepstaken); + + foutindex = (float)startidx + (float)numstepstaken * indicesperstep; + foutindex = clamp( foutindex, (float)startidx, (float)endidx ); + + outindex = ( int )foutindex; + + fnextindex = (float)startidx + (float)( numstepstaken + 1 ) * indicesperstep; + fnextindex = clamp( fnextindex, (float)startidx, (float)endidx ); + + nextindex = (int)fnextindex; + + subfrac = fnumstepstaken - (float)numstepstaken; + + if ( !m_Printables.IsValidIndex( outindex ) || + !m_Printables.IsValidIndex( nextindex ) ) + { + prevchar = startchar; + nextchar = startchar; + subfrac = 0.0f; + return; + } + + if ( reverse ) + { + subfrac = 1.0f - subfrac; + prevchar = m_Printables[ nextindex ]; + nextchar = m_Printables[ outindex ]; + } + else + { + prevchar = m_Printables[ outindex ]; + nextchar = m_Printables[ nextindex ]; + } +} + +void CHudNumeric::PaintRotatedCharacterHoriz( int x, int y, vgui::HFont& font, int prevchar, int nextchar, float frac ) +{ + frac = 3 * frac * frac - 2 * frac * frac * frac; + + int abcA, abcB, abcC; + surface()->GetCharABCwide( font, prevchar, abcA, abcB, abcC ); + // int fontTall = surface()->GetFontTall( font ); + + CharRenderInfo info; + if ( frac < 0.5f ) + { + surface()->DrawSetTextPos( x, y ); + + // Paint the right half of the prevchar still + if ( surface()->DrawGetUnicodeCharRenderInfo( prevchar, info ) ) + { + // Shift tex coord and y position half way down glyph + info.verts[0].m_Position.x = Lerp( 0.5f, info.verts[0].m_Position.x, info.verts[1].m_Position.x ); + info.verts[0].m_TexCoord.x = Lerp( 0.5f, info.verts[0].m_TexCoord.x, info.verts[1].m_TexCoord.x ); + surface()->DrawRenderCharFromInfo( info ); + } + + surface()->DrawSetTextPos( x, y ); + + // Paint up to frac from left of next char + if ( surface()->DrawGetUnicodeCharRenderInfo( nextchar, info ) ) + { + // Shift tex coord and y position part way up glyph + info.verts[1].m_Position.x = Lerp( frac, info.verts[0].m_Position.x, info.verts[1].m_Position.x ); + info.verts[1].m_TexCoord.x = Lerp( frac, info.verts[0].m_TexCoord.x, info.verts[1].m_TexCoord.x ); + surface()->DrawRenderCharFromInfo( info ); + } + + // Paint divider + + surface()->DrawSetTextPos( x, y ); + + // Paint from frac to 0.5 of prevchar on the left + if ( surface()->DrawGetUnicodeCharRenderInfo( prevchar, info ) ) + { + // Shift tex coord and y position half way up glyph + vgui::Vertex_t save[2]; + + save[0] = info.verts[0]; + save[1] = info.verts[1]; + + info.verts[0].m_Position.x = Lerp( frac, save[0].m_Position.x, save[1].m_Position.x ); + //info.verts[0].m_TexCoord.x = Lerp( frac, save[0].m_TexCoord.x, save[1].m_TexCoord.x ); + + info.verts[1].m_Position.x = Lerp( 0.5f, save[0].m_Position.x, save[1].m_Position.x ); + info.verts[1].m_TexCoord.x = Lerp( 0.5f, save[0].m_TexCoord.x, save[1].m_TexCoord.x ); + + surface()->DrawRenderCharFromInfo( info ); + } + } + else if ( frac > 0.5f ) + { + surface()->DrawSetTextPos( x, y ); + + // Paint entire left half of next char + if ( surface()->DrawGetUnicodeCharRenderInfo( nextchar, info ) ) + { + // Shift tex coord and y position half way down glyph + info.verts[1].m_Position.x = Lerp( 0.5f, info.verts[0].m_Position.x, info.verts[1].m_Position.x ); + info.verts[1].m_TexCoord.x = Lerp( 0.5f, info.verts[0].m_TexCoord.x, info.verts[1].m_TexCoord.x ); + surface()->DrawRenderCharFromInfo( info ); + } + + surface()->DrawSetTextPos( x, y ); + + // paint a bit of the previous char at far right + if ( surface()->DrawGetUnicodeCharRenderInfo( prevchar, info ) ) + { + // Shift tex coord and y position part way up glyph + info.verts[0].m_Position.x = Lerp( frac, info.verts[0].m_Position.x, info.verts[1].m_Position.x ); + info.verts[0].m_TexCoord.x = Lerp( frac, info.verts[0].m_TexCoord.x, info.verts[1].m_TexCoord.x ); + surface()->DrawRenderCharFromInfo( info ); + } + + // Paint divider + + surface()->DrawSetTextPos( x, y ); + + // Paint from 0.5 to frac of next char + if ( surface()->DrawGetUnicodeCharRenderInfo( nextchar, info ) ) + { + vgui::Vertex_t save[2]; + + save[0] = info.verts[0]; + save[1] = info.verts[1]; + + info.verts[0].m_Position.x = Lerp( 0.5f, save[0].m_Position.x, save[1].m_Position.x ); + info.verts[0].m_TexCoord.x = Lerp( 0.5f, save[0].m_TexCoord.x, save[1].m_TexCoord.x ); + + info.verts[1].m_Position.x = Lerp( frac, save[0].m_Position.x, save[1].m_Position.x ); + //info.verts[1].m_TexCoord.x = Lerp( frac, save[0].m_TexCoord.x, save[1].m_TexCoord.x ); + + surface()->DrawRenderCharFromInfo( info ); + } + } + + x += ( abcA + abcB + abcC ); + surface()->DrawSetTextPos( x, y ); +} + +void CHudNumeric::PaintRotatedCharacterSpeedomter( int x, int y, vgui::HFont& font, int prevchar, int nextchar, float frac ) +{ + frac = 3 * frac * frac - 2 * frac * frac * frac; + + int abcA, abcB, abcC; + surface()->GetCharABCwide( font, prevchar, abcA, abcB, abcC ); + // int fontTall = surface()->GetFontTall( font ); + + CharRenderInfo info; + if ( frac <= 0.0f ) + { + surface()->DrawSetTextPos( x, y ); + + // Paint the whole previous char + if ( surface()->DrawGetUnicodeCharRenderInfo( prevchar, info ) ) + { + surface()->DrawRenderCharFromInfo( info ); + } + } + else if ( frac >= 1.0f ) + { + surface()->DrawSetTextPos( x, y ); + + // Paint the whole previous char + if ( surface()->DrawGetUnicodeCharRenderInfo( nextchar, info ) ) + { + surface()->DrawRenderCharFromInfo( info ); + } + } + else + { + // Draw part of previous and part of next + surface()->DrawSetTextPos( x, y ); + + if ( surface()->DrawGetUnicodeCharRenderInfo( prevchar, info ) ) + { + // Shift tex coord and y position part way up glyph + info.verts[1].m_Position.y = Lerp( frac, info.verts[0].m_Position.y, info.verts[1].m_Position.y ); + info.verts[1].m_TexCoord.y = Lerp( frac, info.verts[0].m_TexCoord.y, info.verts[1].m_TexCoord.y ); + surface()->DrawRenderCharFromInfo( info ); + } + + // Paint divider + + surface()->DrawSetTextPos( x, y ); + + if ( surface()->DrawGetUnicodeCharRenderInfo( nextchar, info ) ) + { + // Shift tex coord and y position part way up glyph + info.verts[0].m_Position.y = Lerp( frac, info.verts[0].m_Position.y, info.verts[1].m_Position.y ); + info.verts[0].m_TexCoord.y = Lerp( frac, info.verts[0].m_TexCoord.y, info.verts[1].m_TexCoord.y ); + surface()->DrawRenderCharFromInfo( info ); + } + } + + x += ( abcA + abcB + abcC ); + surface()->DrawSetTextPos( x, y ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : x - +// y - +// font - +// prevchar - +// nextchar - +// frac - +//----------------------------------------------------------------------------- +void CHudNumeric::PaintRotatedCharacter( int x, int y, HFont& font, int prevchar, int nextchar, float frac ) +{ + frac = SimpleSpline( frac ); + + int abcA[2], abcB[2], abcC[2]; + surface()->GetCharABCwide( font, prevchar, abcA[0], abcB[0], abcC[0] ); + surface()->GetCharABCwide( font, nextchar, abcA[1], abcB[1], abcC[1] ); + + int w0 = abcA[0] + abcB[0] + abcC[0]; + int w1 = abcA[1] + abcB[1] + abcC[1]; + + int cellwidth = MAX( w0, w1 ); + + int fontTall = surface()->GetFontTall( font ); + + int dividery = y + clamp( Lerp( frac, 0, fontTall ), 2, fontTall - 2 ); + + int xprev = x; + int xnext = x; + + int diff = abs( abcB[0] - abcB[1] ) * 0.5f; + + if ( diff != 0 ) + { + // Prev is wider than next, push next right a bit + if ( w0 > w1 ) + { + xnext += diff; + } + else + { + xprev += diff; + } + } + + CharRenderInfo info; + if ( frac < 0.5f ) + { + surface()->DrawSetTextPos( xprev, y ); + + // Paint the bottom half of the prevchar still + if ( surface()->DrawGetUnicodeCharRenderInfo( prevchar, info ) ) + { + // Shift tex coord and y position half way down glyph + info.verts[0].m_Position.y = Lerp( 0.5f, info.verts[0].m_Position.y, info.verts[1].m_Position.y ); + info.verts[0].m_TexCoord.y = Lerp( 0.5f, info.verts[0].m_TexCoord.y, info.verts[1].m_TexCoord.y ); + surface()->DrawRenderCharFromInfo( info ); + } + + surface()->DrawSetTextPos( xnext, y ); + + // Paint up to frac from top of prev char + if ( surface()->DrawGetUnicodeCharRenderInfo( nextchar, info ) ) + { + // Shift tex coord and y position part way up glyph + info.verts[1].m_Position.y = Lerp( frac, info.verts[0].m_Position.y, info.verts[1].m_Position.y ); + info.verts[1].m_TexCoord.y = Lerp( frac, info.verts[0].m_TexCoord.y, info.verts[1].m_TexCoord.y ); + surface()->DrawRenderCharFromInfo( info ); + } + + // Paint divider + if ( frac > 0.0f ) + { + surface()->DrawSetColor( m_CharBgBorder ); + surface()->DrawLine( x - abcA[0] + 1, dividery, x + abcB[0] + abcC[0] - 1, dividery ); + } + + surface()->DrawSetTextPos( xprev, y ); + + // Paint from frac to 0.5 of nextchar on the top + if ( surface()->DrawGetUnicodeCharRenderInfo( prevchar, info ) ) + { + // Shift tex coord and y position half way up glyph + vgui::Vertex_t save[2]; + + save[0] = info.verts[0]; + save[1] = info.verts[1]; + + info.verts[0].m_Position.y = Lerp( frac, save[0].m_Position.y, save[1].m_Position.y ); + //info.verts[0].m_TexCoord.y = Lerp( frac, save[0].m_TexCoord.y, save[1].m_TexCoord.y ); + + info.verts[1].m_Position.y = Lerp( 0.5f, save[0].m_Position.y, save[1].m_Position.y ); + info.verts[1].m_TexCoord.y = Lerp( 0.5f, save[0].m_TexCoord.y, save[1].m_TexCoord.y ); + + surface()->DrawRenderCharFromInfo( info ); + } + } + else if ( frac >= 0.5f ) + { + surface()->DrawSetTextPos( xnext, y ); + + // Paint entire top half of next char + if ( surface()->DrawGetUnicodeCharRenderInfo( nextchar, info ) ) + { + // Shift tex coord and y position half way down glyph + info.verts[1].m_Position.y = Lerp( 0.5f, info.verts[0].m_Position.y, info.verts[1].m_Position.y ); + info.verts[1].m_TexCoord.y = Lerp( 0.5f, info.verts[0].m_TexCoord.y, info.verts[1].m_TexCoord.y ); + surface()->DrawRenderCharFromInfo( info ); + } + + surface()->DrawSetTextPos( xprev, y ); + + // paint a bit of the previous char at the bottom + if ( surface()->DrawGetUnicodeCharRenderInfo( prevchar, info ) ) + { + // Shift tex coord and y position part way up glyph + info.verts[0].m_Position.y = Lerp( frac, info.verts[0].m_Position.y, info.verts[1].m_Position.y ); + info.verts[0].m_TexCoord.y = Lerp( frac, info.verts[0].m_TexCoord.y, info.verts[1].m_TexCoord.y ); + surface()->DrawRenderCharFromInfo( info ); + } + + // Paint divider + if ( frac < 1.0f ) + { + surface()->DrawSetColor( m_CharBgBorder ); + surface()->DrawLine( x - abcA[0] + 1, dividery, x + abcB[0] + abcC[0] - 1, dividery ); + } + + surface()->DrawSetTextPos( xnext, y ); + + // Paint from 0.5 to frac of next char + if ( surface()->DrawGetUnicodeCharRenderInfo( nextchar, info ) ) + { + // Shift tex coord and y position half way up glyph + vgui::Vertex_t save[2]; + + save[0] = info.verts[0]; + save[1] = info.verts[1]; + + info.verts[0].m_Position.y = Lerp( 0.5f, save[0].m_Position.y, save[1].m_Position.y ); + info.verts[0].m_TexCoord.y = Lerp( 0.5f, save[0].m_TexCoord.y, save[1].m_TexCoord.y ); + + info.verts[1].m_Position.y = Lerp( frac, save[0].m_Position.y, save[1].m_Position.y ); + //info.verts[1].m_TexCoord.y = Lerp( frac, save[0].m_TexCoord.y, save[1].m_TexCoord.y ); + + surface()->DrawRenderCharFromInfo( info ); + } + } + + x += cellwidth; + surface()->DrawSetTextPos( x, y ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *prev - +// *next - +// Output : float +//----------------------------------------------------------------------------- +float CHudNumeric::MaxCharacterDiff( const char *prev, const char *next ) +{ + float maxdiff = 0.0f; + + int textlen = Q_strlen( next ); + int prevlen = Q_strlen( prev ); + int ch; + for ( ch = 0; ch < textlen; ch++ ) + { + int charfromend = textlen - ch; + char c = next[ ch ]; + char prevc = prev[ MAX( 0, prevlen - charfromend ) ]; + if ( prevc == 0 ) + { + int tempindex = FindPrintableIndex( c ); + if ( tempindex != m_Printables.InvalidIndex() ) + { + tempindex = MAX( 0, tempindex - 3 ); + prevc = m_Printables[ tempindex ]; + } + else + { + prevc = c; + } + } + + float diff = (float)fabs( FindPrintableIndex( c ) - FindPrintableIndex( prevc ) ); + + if ( diff > maxdiff ) + { + maxdiff = diff; + } + } + + float maxdelta = maxdiff; + + if ( m_nRotaryMaxDelta != 0 ) + { + maxdelta = MIN( (float)m_nRotaryMaxDelta, maxdelta ); + } + + return maxdelta; +} + +int CHudNumeric::ComputePixelsRequired( vgui::HFont& font, const char *text, int textlen ) +{ + int pixels = 0; + for ( int ch = 0; ch < textlen; ch++ ) + { + char c = text[ ch ]; + pixels += surface()->GetCharacterWidth( font, c ); + } + return pixels; +} + +void CHudNumeric::DrawCharacterBackground( const char *text, int textlen, HFont& font, int x, int y ) +{ + int abcA, abcB, abcC; + int fontTall = surface()->GetFontTall( font ); + + int ch; + int curx = x - ComputePixelsRequired( font, text, textlen ); + for ( ch = 0; ch < textlen; ch++ ) + { + char c = text[ ch ]; + + surface()->GetCharABCwide( font, c, abcA, abcB, abcC ); + + curx += abcA; + + surface()->DrawSetColor( m_CharBg ); + surface()->DrawFilledRect( curx - abcA, y + 2, curx + abcB + abcC, y + fontTall - 2 ); + + if ( m_bDrawCharacterBackgroundBorder ) + { + surface()->DrawSetColor( m_CharBgBorder ); + surface()->DrawOutlinedRect( curx - abcA, y + 2, curx + abcB + abcC, y + fontTall - 2 ); + } + + curx += ( abcB + abcC ); + } +} + +void CHudNumeric::DrawCharacterForeground( const char *text, int textlen, HFont& font, int x, int y ) +{ + if ( m_nRotaryEffect == ROTARY_EFFECT_NONE || + m_nRotaryEffect == ROTARY_EFFECT_SPEEDOMETER ) + return; + + int abcA, abcB, abcC; + int fontTall = surface()->GetFontTall( font ); + + int ch; + int curx = x - ComputePixelsRequired( font, text, textlen ); + for ( ch = 0; ch < textlen; ch++ ) + { + char c = text[ ch ]; + + surface()->GetCharABCwide( font, c, abcA, abcB, abcC ); + + curx += abcA; + + switch ( m_nRotaryEffect ) + { + default: + case ROTARY_EFFECT_VERTICAL_ALARM: + { + surface()->DrawSetColor( m_CharFg ); + surface()->DrawLine( curx - abcA + 1, y + fontTall / 2, curx + abcB + abcC - 1, y + fontTall / 2 ); + } + break; + case ROTARY_EFFECT_HORIZONTAL_ALARM: + { + surface()->DrawSetColor( m_CharFg ); + int avex = curx + ( - abcA + abcB + abcC ) / 2; + surface()->DrawLine( avex, y + 2, avex, y + fontTall - 2 ); + } + break; + } + + curx += ( abcB + abcC ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *text - +// textlen - +// font - +// x - +// y - +//----------------------------------------------------------------------------- +void CHudNumeric::PaintStringRotary( float t, const char *text, int textlen, HFont& font, int x, int y ) +{ + surface()->DrawSetTextFont( font ); + int ch; + + int prevlen = Q_strlen( m_szLatchedValue ); + + // Compute pixels actually required + int pixels = 0; + + for ( ch = 0; ch < textlen; ch++ ) + { + int charfromend = textlen - ch; + char c = text[ ch ]; + char prevc = m_szLatchedValue[ MAX( 0, prevlen - charfromend ) ]; + if ( prevc == 0 ) + { + int tempindex = FindPrintableIndex( c ); + if ( tempindex != m_Printables.InvalidIndex() ) + { + tempindex = MAX( 0, tempindex - 3 ); + prevc = m_Printables[ tempindex ]; + } + else + { + prevc = c; + } + } + + float diff = (float)fabs( FindPrintableIndex( c ) - FindPrintableIndex( prevc ) ); + + if ( m_nRotaryMaxDelta != 0 ) + { + diff = MIN( (float)m_nRotaryMaxDelta, diff ); + } + + float dt = diff / m_flActualCharactersPerSecond; + + float frac = 1.0f; + if ( dt > 0.0f ) + { + frac = t / MIN( dt, m_flRotaryTime ); + } + frac = clamp( frac, 0.0f, 1.0f ); + + float s; + char chstart, chend; + GetRotatedChar( frac, prevc, c, chstart, chend, s ); + + int w0 = surface()->GetCharacterWidth( font, chstart ); + int w1 = surface()->GetCharacterWidth( font, chend ); + + pixels += MAX( w0, w1 ); + } + + surface()->DrawSetTextPos( x - pixels, y ); + + // Now render + for ( ch = 0; ch < textlen; ch++ ) + { + int charfromend = textlen - ch; + char c = text[ ch ]; + char prevc = m_szLatchedValue[ MAX( 0, prevlen - charfromend ) ]; + if ( prevc == 0 ) + { + int tempindex = FindPrintableIndex( c ); + if ( tempindex != m_Printables.InvalidIndex() ) + { + tempindex = MAX( 0, tempindex - 3 ); + prevc = m_Printables[ tempindex ]; + } + else + { + prevc = c; + } + } + + float diff = (float)fabs( FindPrintableIndex( c ) - FindPrintableIndex( prevc ) ); + + if ( m_nRotaryMaxDelta != 0 ) + { + diff = MIN( (float)m_nRotaryMaxDelta, diff ); + } + + float dt = diff / m_flActualCharactersPerSecond; + + float frac = 1.0f; + if ( dt > 0.0f ) + { + frac = t / MIN( dt, m_flRotaryTime ); + } + frac = clamp( frac, 0.0f, 1.0f ); + + float s; + char chstart, chend; + GetRotatedChar( frac, prevc, c, chstart, chend, s ); + int outx, outy; + surface()->DrawGetTextPos( outx, outy ); + switch ( m_nRotaryEffect ) + { + default: + case ROTARY_EFFECT_VERTICAL_ALARM: + { + PaintRotatedCharacter( outx, outy, font, chstart, chend, s ); + } + break; + case ROTARY_EFFECT_HORIZONTAL_ALARM: + { + PaintRotatedCharacterHoriz( outx, outy, font, chstart, chend, s ); + } + break; + case ROTARY_EFFECT_SPEEDOMETER: + { + PaintRotatedCharacterSpeedomter( outx, outy, font, chstart, chend, s ); + } + break; + } + + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *text - +// textlen - +// font - +// x - +// y - +//----------------------------------------------------------------------------- +void CHudNumeric::PaintString( const char *text, int textlen, HFont& font, int x, int y ) +{ + if ( m_nRotaryEffect != ROTARY_EFFECT_NONE && + IsRotating() && + m_flRotaryTime > 0.0f ) + { + float rotation_time = gpGlobals->curtime - m_flRotaryStartTime; + + PaintStringRotary( rotation_time, text, textlen, font, x, y ); + + return; + } + PaintStringNormal( text, textlen, font, x, y ); +} + +void CHudNumeric::PaintStringNormal( const char *text, int textlen, vgui::HFont& font, int x, int y ) +{ + surface()->DrawSetTextFont( font ); + int ch; + surface()->DrawSetTextPos( x - ComputePixelsRequired( font, text, textlen ), y ); + + for ( ch = 0; ch < textlen; ch++ ) + { + char c = text[ ch ]; + surface()->DrawUnicodeChar( c ); + } +} + +void CHudNumeric::PaintBackground( void ) +{ + char value[ MAX_VALUE_LENGTH ]; + + if ( !GetValue( value, sizeof( value ) ) ) + return; + + float alpha = m_flAlphaOverride / 255.0f; + + Color boxColor = GetBoxColor(); + boxColor[3] *= alpha; + + SetBgColor( boxColor ); + + BaseClass::PaintBackground(); + + if ( !m_bUseIcon ) + return; + + CHudTexture *tex = m_hIcon; + if ( !tex ) + return; + + Color iconColor = m_IconColor; + iconColor[3] *= alpha; + + tex->DrawSelf( m_flIconXPos, m_flIconYPos, m_flIconWidth, m_flIconHeight, iconColor ); +} + +void CHudNumeric::PaintValue( const char *value, int textlen, int wide, int tall, Color& clr ) +{ + float alpha = m_flAlphaOverride / 255.0f; + + Color boxColor = GetBoxColor(); + boxColor[3] *= alpha; + + SetBgColor( boxColor ); + + Color useColor = clr; + useColor[3] *= alpha; + + surface()->DrawSetTextColor( useColor ); + + int x = wide - label_xpos_right; + int y = label_ypos; + + if ( m_bDrawLabel ) + { + // Label + PaintStringNormal( GetLabelText(), Q_strlen( GetLabelText() ), m_hLabelFont, x, y ); + } + + x = wide - value_xpos_right; + y = value_ypos; + + if ( m_nRotaryEffect != ROTARY_EFFECT_NONE && + (bool)m_bDrawCharacterBackground ) + { + DrawCharacterBackground( value, textlen, m_hTextFont, x, y ); + } + + PaintString( value, textlen, m_hTextFont, x, y ); + + if ( m_nRotaryEffect != ROTARY_EFFECT_NONE && + (bool)m_bDrawCharacterForeground ) + { + DrawCharacterForeground( value, textlen, m_hTextFont, x, y ); + } + + // draw the overbright blur + for (float fl = m_flBlur; fl > 0.0f; fl -= 1.0f) + { + if (fl >= 1.0f) + { + PaintString( value, textlen, m_hTextFontPulsing, x, y ); + } + else + { + // draw a percentage of the last one + Color col = useColor; + col[3] *= fl; + surface()->DrawSetTextColor(col); + PaintString( value, textlen, m_hTextFontPulsing, x, y ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : vgui::Color +//----------------------------------------------------------------------------- +Color CHudNumeric::GetColor() +{ + return m_TextColor; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : vgui::Color +//----------------------------------------------------------------------------- +Color CHudNumeric::GetBoxColor() +{ + return m_BoxColor; +} + +//----------------------------------------------------------------------------- +// Purpose: Redraw +//----------------------------------------------------------------------------- +void CHudNumeric::Paint( void ) +{ + char value[ MAX_VALUE_LENGTH ]; + + if ( !GetValue( value, sizeof( value ) ) ) + return; + + int w, h; + GetSize( w, h ); + + bool dopulse = ( Q_strcmp( value, m_szPreviousValue ) != 0 ) || ( m_bPulseForced ); + bool increment = false; + if ( dopulse ) + { + if ( atof( m_szPreviousValue ) <= atof( value ) ) + { + increment = true; + } + + Q_strncpy( m_szLatchedValue, m_szPreviousValue, sizeof( m_szLatchedValue ) ); + m_nTextLen = Q_strlen( value ); + + m_flRotaryStartTime = gpGlobals->curtime; + float maxdiff = MaxCharacterDiff( m_szLatchedValue, value ); + float timerequired = maxdiff / m_flDesiredCharactersPerSecond; + m_flActualCharactersPerSecond = (float)m_flDesiredCharactersPerSecond; + m_flRotaryTime = MIN( m_flRotaryTimeMax, timerequired ); + if ( m_flRotaryTime < timerequired ) + { + // Speed up rotation since we're moving so far + m_flActualCharactersPerSecond = ( timerequired / m_flRotaryTime ) * m_flDesiredCharactersPerSecond; + } + } + + Q_strncpy( m_szPreviousValue, value, sizeof( m_szPreviousValue ) ); + + Color clr = GetColor(); + PaintValue( value, m_nTextLen, w, h, clr ); + + if ( dopulse && m_bSendPulses ) + { + // Start with a short pulse + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( GetPulseEvent( increment ) ); + + m_bPulseForced = false; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Derived class has forced a pulse +//----------------------------------------------------------------------------- +void CHudNumeric::ForcePulse( void ) +{ + m_bPulseForced = true; +} diff --git a/game/client/tf2/hud_numeric.h b/game/client/tf2/hud_numeric.h new file mode 100644 index 0000000..20db7f5 --- /dev/null +++ b/game/client/tf2/hud_numeric.h @@ -0,0 +1,140 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HUD_NUMERIC_H +#define HUD_NUMERIC_H +#ifdef _WIN32 +#pragma once +#endif + +#include "hudelement.h" +#include <vgui_controls/Panel.h> + +class CHudNumeric : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudNumeric, vgui::Panel ); + +public: + + CHudNumeric( const char *pElementName, const char *panelName ); + + void SetDrawLabel( bool draw ) { m_bDrawLabel = draw; } + void SetDoPulses( bool dopulses ) { m_bSendPulses = dopulses; } + void ForcePulse( void ); + + void SetRotaryEffect( int rotary ) { m_nRotaryEffect = rotary; } + void SetRotaryTimeMax( float maxTime ) { m_flRotaryTimeMax = maxTime; } + void SetRotaryCharsPerSecond( float cps ) { m_flDesiredCharactersPerSecond = cps; } + + // vgui::Panel overrides. + virtual void Paint( void ); + virtual void PaintBackground( void ); + + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + + virtual const char *GetLabelText() = 0; + virtual const char *GetPulseEvent( bool increment ) = 0; + virtual bool GetValue( char *val, int maxlen ) = 0; + + virtual Color GetColor(); + virtual Color GetBoxColor(); + + static void BuildPrintablesList( void ); + static int FindPrintableIndex( int ch ); + +protected: + enum + { + ROTARY_EFFECT_NONE = 0, + ROTARY_EFFECT_VERTICAL_ALARM, + ROTARY_EFFECT_HORIZONTAL_ALARM, + ROTARY_EFFECT_SPEEDOMETER + }; + + enum + { + MAX_VALUE_LENGTH = 128, + }; + + void PaintValue( const char *value, int textlen, int wide, int tall, Color& clr ); + void PaintString( const char *text, int textlen, vgui::HFont& font, int x, int y ); + void PaintStringNormal( const char *text, int textlen, vgui::HFont& font, int x, int y ); + + void PaintStringRotary( float t, const char *text, int textlen, vgui::HFont& font, int x, int y ); + + void GetRotatedChar( float frac, char startchar, char endchar, + char& prevchar, char& nextchar, float& subfrac ); + void PaintRotatedCharacter( int x, int y, vgui::HFont& font, int prevchar, int nextchar, float frac ); + void PaintRotatedCharacterHoriz( int x, int y, vgui::HFont& font, int prevchar, int nextchar, float frac ); + void PaintRotatedCharacterSpeedomter( int x, int y, vgui::HFont& font, int prevchar, int nextchar, float frac ); + + bool IsRotating( void ) const; + + float MaxCharacterDiff( const char *prev, const char *next ); + void DrawCharacterBackground( const char *text, int textlen, vgui::HFont& font, int x, int y ); + void DrawCharacterForeground( const char *text, int textlen, vgui::HFont& font, int x, int y ); + + int ComputePixelsRequired( vgui::HFont& font, const char *text, int textlen ); + + int m_nTextLen; + char m_szPreviousValue[ MAX_VALUE_LENGTH ]; + char m_szLatchedValue[ MAX_VALUE_LENGTH ]; + + bool m_bDrawLabel; + bool m_bSendPulses; + bool m_bPulseForced; + + float m_flRotaryTime; + float m_flRotaryStartTime; + float m_flActualCharactersPerSecond; + + static CUtlRBTree< int, int > m_Printables; + static bool s_bPrintablesBuilt; + + CPanelAnimationVar( int, m_nRotaryEffect, "Rotary", "0" ); + CPanelAnimationVar( int, m_nRotaryMaxDelta, "RotaryMaxDelta", "0" ); + CPanelAnimationVar( float, m_flRotaryTimeMax, "RotaryMaxTime", "2.0" ); + CPanelAnimationVar( float, m_flDesiredCharactersPerSecond, "RotarySpeed", "7.0" ); + + CPanelAnimationVar( bool, m_bDrawCharacterBackground, "DrawCharacterBackground", "false" ); + CPanelAnimationVar( bool, m_bDrawCharacterForeground, "DrawCharacterForeground", "false" ); + CPanelAnimationVar( bool, m_bDrawCharacterBackgroundBorder, "DrawCharacterBackgroundBorder", "false" ); + + CPanelAnimationVar( float, m_flBlur, "Blur", "0" ); + CPanelAnimationVar( float, m_flAlphaOverride, "Alpha", "255" ); + + CPanelAnimationVar( Color, m_TextColor, "TextColor", "NumericText" ); + CPanelAnimationVar( Color, m_TextColorWarning, "TextColorWarning", "NumericTextWarning" ); + CPanelAnimationVar( Color, m_TextColorCritical, "TextColorCritical", "NumericTextCritical" ); + + CPanelAnimationVar( Color, m_BoxColor, "BoxColor", "NumericBox" ); + CPanelAnimationVar( Color, m_BoxColorWarning, "BoxColorWarning", "NumericBoxWarning" ); + CPanelAnimationVar( Color, m_BoxColorCritical, "BoxColorCritical", "NumericBoxCritical" ); + + CPanelAnimationVar( Color, m_CharBg, "CharBackground", "NumericCharBg" ); + CPanelAnimationVar( Color, m_CharBgBorder, "CharBackgroundBorder", "NumericCharBgBorder" ); + CPanelAnimationVar( Color, m_CharFg, "CharForeground", "NumericCharFg" ); + + CPanelAnimationVar( vgui::HFont, m_hLabelFont, "LabelFont", "HudNumbersLabelFont" ); + CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "HudNumbersSmall" ); + CPanelAnimationVar( vgui::HFont, m_hTextFontPulsing, "TextFontPulsing", "HudNumbersSmallGlow" ); + + CPanelAnimationVarAliasType( float, label_ypos, "label_ypos", "2", "proportional_float" ); + CPanelAnimationVarAliasType( float, label_xpos_right, "label_xpos_right", "5", "proportional_float" ); + CPanelAnimationVarAliasType( float, value_ypos, "value_ypos", "12", "proportional_float" ); + CPanelAnimationVarAliasType( float, value_xpos_right, "value_xpos_right", "5", "proportional_float" ); + + CPanelAnimationVar( bool, m_bUseIcon, "UseIcon", "false" ); + CPanelAnimationVarAliasType( float, m_flIconWidth, "IconWidth", "60", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flIconHeight, "IconHeight", "30", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flIconXPos, "IconXPos", "10", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flIconYPos, "IconYPos", "4", "proportional_float" ); + CPanelAnimationVar( CHudTextureHandle, m_hIcon, "IconTexture", "" ); + CPanelAnimationVar( Color, m_IconColor, "IconColor", "NumericText" ); +}; + +#endif // HUD_NUMERIC_H diff --git a/game/client/tf2/hud_orders.cpp b/game/client/tf2/hud_orders.cpp new file mode 100644 index 0000000..30f2ec3 --- /dev/null +++ b/game/client/tf2/hud_orders.cpp @@ -0,0 +1,278 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Order window +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud_orders.h" +#include "hud.h" +#include "c_basetfplayer.h" +#include "clientmode_tfnormal.h" +#include "VGUI_BasePanel.h" +#include <vgui/IScheme.h> + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudLabel::SetSelected( bool bSelected ) +{ + m_bSelected = bSelected; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CHudOrderList *GetHudOrderList( void ) +{ + return GET_HUDELEMENT( CHudOrderList ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CHudOrder::CHudOrder( int x,int y,int wide,int tall ) : vgui::Panel( NULL, "CHudOrder") +{ + SetBounds( x, y, wide, tall ); + SetAutoDelete( false ); + m_pOrder = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CHudOrder::~CHudOrder( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudOrder::Init( void ) +{ + SetSize( ORDERS_ELEMENT_WIDTH, ORDERS_ELEMENT_HEIGHT ); +} + +//----------------------------------------------------------------------------- +// Purpose: Called every frame +//----------------------------------------------------------------------------- +void CHudOrder::Paint( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudOrder::SetOrder( C_Order *pOrder ) +{ + // If we had an order, tell it to clean up + if ( m_pOrder ) + { + m_pOrder->DestroyStatus(); + } + + m_pOrder = pOrder; + + // Tell the order to create it's elements + if ( m_pOrder ) + { + m_pOrder->CreateStatus( this ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_Order *CHudOrder::GetOrder( void ) +{ + return m_pOrder; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudOrder::UpdateOrder( void ) +{ + if ( m_pOrder == NULL ) + return; +} + +//----------------------------------------------------------------------------- +// Purpose: Our order has been deleted. +//----------------------------------------------------------------------------- +void CHudOrder::OrderRemoved( void ) +{ + m_pOrder = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudOrder::ApplySchemeSettings(vgui::IScheme *pScheme) +{ + Panel::ApplySchemeSettings(pScheme); + + if ( m_pOrder && m_pOrder->IsPersonalOrder() ) + { + SetBgColor( GetSchemeColor("HudStatusSelectedBgColor", pScheme) ); + } + else + { + SetBgColor( GetSchemeColor("HudStatusBgColor", pScheme) ); + } +} + +//================================================================================================================ +// LARGE STATUS PANEL. +//================================================================================================================ +// Purpose: +//----------------------------------------------------------------------------- +CHudOrderList::CHudOrderList( const char *pElementName ) : + CHudElement( pElementName ), vgui::Panel( NULL, "HudOrderList" ) +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + + SetPaintBackgroundEnabled( false ); + for (int i = 0; i < MAX_HUD_ORDERS; i++) + { + m_pOrderPanels[i] = NULL; + m_pOrderLabels[i] = NULL; + } + + SetHiddenBits( HIDEHUD_MISCSTATUS | HIDEHUD_PLAYERDEAD ); +} + +DECLARE_HUDELEMENT( CHudOrderList ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CHudOrderList::~CHudOrderList( void ) +{ + for (int i = 0; i < MAX_HUD_ORDERS; i++) + { + if ( m_pOrderPanels[i] ) + { + delete m_pOrderPanels[i]; + delete m_pOrderLabels[i]; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudOrderList::LevelInit( void ) +{ + SetPos( ORDERS_LEFT, ORDERS_TOP ); + SetSize( ORDERS_WIDTH, ORDERS_HEIGHT ); + + for ( int i = 0; i < MAX_HUD_ORDERS; i++ ) + { + m_pOrderPanels[i] = new CHudOrder( ORDERS_ELEMENT_LEFT - ORDERS_LEFT, ORDERS_ELEMENT_HEIGHT * i, ORDERS_ELEMENT_WIDTH, ORDERS_ELEMENT_HEIGHT ); + m_pOrderPanels[i]->Init(); + + m_pOrderLabels[i] = new CHudLabel( NULL, "orderlabels", " " ); + m_pOrderLabels[i]->SetBounds( 0, ORDERS_ELEMENT_HEIGHT * i, ORDERS_ELEMENT_LEFT - ORDERS_LEFT, ORDERS_ELEMENT_HEIGHT ); + m_pOrderLabels[i]->SetContentAlignment( vgui::Label::a_northwest ); + m_pOrderLabels[i]->SetTextInset( 4, 0 ); + + // Start all of them hidden + m_pOrderPanels[i]->SetParent( (vgui::Panel *)NULL ); + m_pOrderLabels[i]->SetParent( (vgui::Panel *)NULL ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudOrderList::LevelShutdown( void ) +{ + for ( int i = 0; i < MAX_HUD_ORDERS; i++ ) + { + delete m_pOrderPanels[i]; + m_pOrderPanels[i] = NULL; + delete m_pOrderLabels[i]; + m_pOrderLabels[i] = NULL; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudOrderList::OnThink( void ) +{ + // Call update for all active objects + for (int i = 0; i < MAX_HUD_ORDERS; i++) + { + if ( m_pOrderPanels[i] && m_pOrderPanels[i]->GetOrder() ) + { + m_pOrderPanels[i]->UpdateOrder(); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudOrderList::Paint( void ) +{ +// vgui::surface()->DrawSetColor( 255,0,0, 64 ); +// vgui::surface()->DrawOutlinedRect( 0,0, GetWide(), GetTall() ); +} + +//----------------------------------------------------------------------------- +// Purpose: Insert the specified order into the slot +//----------------------------------------------------------------------------- +void CHudOrderList::InsertOrder( C_Order *pOrder, int iSlot ) +{ + // Personal Orders don't have selection keys + if ( pOrder->IsPersonalOrder() ) + { + m_pOrderLabels[iSlot]->SetText(""); + } + else + { + // Check the key binding + char binding[64]; + Q_snprintf(binding, sizeof( binding ), "order %d", iSlot+1); + const char *pBinding = engine->Key_LookupBinding( binding ); + if ( pBinding && strcmp(pBinding,"") ) + { + m_pOrderLabels[iSlot]->SetText( pBinding ); + } + } + + // Only insert it if it's not there already + if ( m_pOrderPanels[iSlot]->GetOrder() != pOrder ) + { + m_pOrderPanels[iSlot]->SetOrder( pOrder ); + m_pOrderPanels[iSlot]->SetParent( this ); + m_pOrderLabels[iSlot]->SetParent( this ); + m_pOrderLabels[iSlot]->SetSelected( pOrder->IsPersonalOrder() ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: We've received a new order, or a modified old one. Figure out what to do. +//----------------------------------------------------------------------------- +void CHudOrderList::RecalculateOrderList( void ) +{ + C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + + // Does this player have a personal order? + C_Order *pOrder = pPlayer->PersonalOrder(); + if( pOrder ) + { + // Highlight the selected order (and the personal order always) + m_pOrderPanels[0]->SetBgColor( Color( 0,0,0, 192) ); + m_pOrderLabels[0]->SetBgColor( Color( 0,0,0, 192) ); + } +} + diff --git a/game/client/tf2/hud_orders.h b/game/client/tf2/hud_orders.h new file mode 100644 index 0000000..4015b30 --- /dev/null +++ b/game/client/tf2/hud_orders.h @@ -0,0 +1,87 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Order window +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ORDERS_H +#define ORDERS_H +#ifdef _WIN32 +#pragma once +#endif + +#include <vgui_controls/Panel.h> +#include <vgui_controls/Label.h> +#include "c_order.h" +#include "hudelement.h" + +class CHudLabel; + +#define MAX_HUD_ORDERS 1 // Number of orders to show in the HUD + +//----------------------------------------------------------------------------- +// Purpose: Panel used to display the status for an order +//----------------------------------------------------------------------------- +class CHudOrder : public vgui::Panel +{ +public: + CHudOrder( int x,int y,int wide,int tall ); + ~CHudOrder( void ); + + virtual void Init( void ); + virtual void Paint( void ); + + // Order handling + virtual void SetOrder( C_Order *pOrder ); + virtual C_Order *GetOrder( void ); + virtual void UpdateOrder( void ); + virtual void OrderRemoved( void ); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + +private: + C_Order *m_pOrder; // Order that this panel holds +}; + +//----------------------------------------------------------------------------- +// Purpose: Panel that holds all the individual order panels +//----------------------------------------------------------------------------- +class CHudOrderList : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudOrderList, vgui::Panel ); +public: + DECLARE_MULTIPLY_INHERITED(); + + CHudOrderList( const char *pElementName ); + ~CHudOrderList( void ); + + virtual void LevelInit( void ); + virtual void LevelShutdown( void ); + virtual void OnThink( void ); + virtual void Paint( void ); + + // Order handling + void RecalculateOrderList( void ); + void InsertOrder( C_Order *pOrder, int iSlot ); + +private: + CHudOrder *m_pOrderPanels[ MAX_HUD_ORDERS ]; + CHudLabel *m_pOrderLabels[ MAX_HUD_ORDERS ]; +}; + +extern CHudOrderList *GetHudOrderList( void ); + +// Position & Size +// X +#define ORDERS_LEFT (ScreenWidth() - 5 - XRES(112)) +#define ORDERS_RIGHT (ScreenWidth() - 5 ) +#define ORDERS_WIDTH (ORDERS_RIGHT - ORDERS_LEFT) +#define ORDERS_ELEMENT_LEFT XRES(32) +#define ORDERS_ELEMENT_WIDTH (ORDERS_RIGHT - ORDERS_ELEMENT_LEFT) +// Y +#define ORDERS_BOTTOM YRES(412) +#define ORDERS_ELEMENT_HEIGHT YRES(32) +#define ORDERS_TOP (ORDERS_BOTTOM - (ORDERS_ELEMENT_HEIGHT * MAX_HUD_ORDERS)) +#define ORDERS_HEIGHT (ORDERS_BOTTOM - ORDERS_TOP) + +#endif // ORDER_H diff --git a/game/client/tf2/hud_resources.cpp b/game/client/tf2/hud_resources.cpp new file mode 100644 index 0000000..8b0a1ca --- /dev/null +++ b/game/client/tf2/hud_resources.cpp @@ -0,0 +1,131 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Hud display of the local player's resource counts +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud_numeric.h" +#include "c_basetfplayer.h" +#include "hud_macros.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHudResources : public CHudNumeric +{ + DECLARE_CLASS_SIMPLE( CHudResources, CHudNumeric ) +public: + CHudResources( const char *pElementName ); + + virtual const char *GetLabelText() { return m_szResourcesLabel; } + virtual const char *GetPulseEvent( bool increment ) { return increment ? "ResourceIncrement" : "ResourceDecrement"; } + virtual bool GetValue( char *val, int maxlen ); + +private: + bool GetResourceCount( int& value ); + + CPanelAnimationStringVar( 128, m_szResourcesLabel, "ResourcesLabel", "Resources" ); +}; + +DECLARE_HUDELEMENT( CHudResources ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CHudResources::CHudResources( const char *pElementName ) : CHudNumeric( pElementName, "HudResources") +{ + SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD ); +} + +bool CHudResources::GetValue( char *val, int maxlen ) +{ + int bank = 0; + if ( !GetResourceCount( bank ) ) + return false; + + Q_snprintf( val, maxlen, "%i", bank ); + return true; +} + +bool CHudResources::GetResourceCount( int& value ) +{ + C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + if ( !pPlayer ) + return false; + if ( pPlayer->GetTeamNumber() == 0) + return false; + + value = pPlayer->m_TFLocal.m_iBankResources; + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHudResourcesPickup : public CHudNumeric +{ + DECLARE_CLASS_SIMPLE( CHudResourcesPickup, CHudNumeric ) +public: + CHudResourcesPickup( const char *pElementName ); + + virtual void Init( void ); + virtual const char *GetLabelText() { return m_szResourcesPickupLabel; } + virtual const char *GetPulseEvent( bool increment ) { return "ResourcePickup"; } + virtual bool GetValue( char *val, int maxlen ); + + // Handler for our message + void MsgFunc_PickupRes( bf_read &msg ); + +private: + int m_iPickupAmount; + + CPanelAnimationStringVar( 128, m_szResourcesPickupLabel, "ResourcesPickupLabel", "" ); +}; + +DECLARE_HUDELEMENT( CHudResourcesPickup ); +DECLARE_HUD_MESSAGE( CHudResourcesPickup, PickupRes ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CHudResourcesPickup::CHudResourcesPickup( const char *pElementName ) : CHudNumeric( pElementName, "HudResourcesPickup") +{ + m_iPickupAmount = 0; + + SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudResourcesPickup::Init( void ) +{ + HOOK_HUD_MESSAGE( CHudResourcesPickup, PickupRes ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CHudResourcesPickup::GetValue( char *val, int maxlen ) +{ + if ( !m_iPickupAmount ) + return false; + + Q_snprintf( val, maxlen, "+%i", m_iPickupAmount ); + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Message handler for PickupRes message +//----------------------------------------------------------------------------- +void CHudResourcesPickup::MsgFunc_PickupRes( bf_read &msg ) +{ + m_iPickupAmount = msg.ReadByte(); + + ForcePulse(); +}
\ No newline at end of file diff --git a/game/client/tf2/hud_target_id.cpp b/game/client/tf2/hud_target_id.cpp new file mode 100644 index 0000000..46abca8 --- /dev/null +++ b/game/client/tf2/hud_target_id.cpp @@ -0,0 +1,230 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: HUD Target ID element +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "hudelement.h" +#include "imessagechars.h" +#include "c_basetfplayer.h" +#include "c_playerresource.h" +#include "vgui_EntityPanel.h" +#include "vgui_healthbar.h" +#include "commanderoverlay.h" +#include "c_baseobject.h" +#include "iclientmode.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define PLAYER_HINT_DISTANCE 150 +#define PLAYER_HINT_DISTANCE_SQ (PLAYER_HINT_DISTANCE*PLAYER_HINT_DISTANCE) + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CTargetID : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CTargetID, vgui::Panel ); + +public: + CTargetID( const char *pElementName ); + void Init( void ); + virtual void ApplySchemeSettings( vgui::IScheme *scheme ); + virtual void Paint( void ); + void VidInit( void ); + +private: + vgui::HFont m_hFont; + int m_iLastEntIndex; + float m_flLastChangeTime; + char m_sIDString[ MAX_ID_STRING ]; +}; + +DECLARE_HUDELEMENT( CTargetID ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTargetID::CTargetID( const char *pElementName ) : + CHudElement( pElementName ), BaseClass( NULL, "TargetID" ) +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + + m_hFont = g_hFontTrebuchet24; + m_flLastChangeTime = 0; + m_iLastEntIndex = 0; + m_sIDString[0] = 0; + + SetHiddenBits( HIDEHUD_MISCSTATUS ); +} + +//----------------------------------------------------------------------------- +// Purpose: Setup +//----------------------------------------------------------------------------- +void CTargetID::Init( void ) +{ +}; + +void CTargetID::ApplySchemeSettings( vgui::IScheme *scheme ) +{ + BaseClass::ApplySchemeSettings( scheme ); + + SetPaintBackgroundEnabled( false ); +} + +//----------------------------------------------------------------------------- +// Purpose: clear out string etc between levels +//----------------------------------------------------------------------------- +void CTargetID::VidInit() +{ + CHudElement::VidInit(); + + m_flLastChangeTime = 0; + m_iLastEntIndex = 0; + m_sIDString[0] = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Draw function for the element +//----------------------------------------------------------------------------- +void CTargetID::Paint() +{ + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + // No id if still choosing class + if ( C_BaseTFPlayer::GetLocalPlayer()->GetClass() == TFCLASS_UNDECIDED ) + return; + + // Get our target's ent index + int iEntIndex = C_BaseTFPlayer::GetLocalPlayer()->GetIDTarget(); + // Didn't find one? + if ( !iEntIndex ) + { + // Check to see if we should clear our ID + if ( m_flLastChangeTime && (gpGlobals->curtime > (m_flLastChangeTime + 0.5)) ) + { + m_flLastChangeTime = 0; + m_sIDString[0] = 0; + m_iLastEntIndex = 0; + } + else + { + // Keep re-using the old one + iEntIndex = m_iLastEntIndex; + } + } + else + { + m_flLastChangeTime = gpGlobals->curtime; + } + + // Is this an entindex sent by the server? + if ( iEntIndex ) + { + C_BaseTFPlayer *pPlayer = static_cast<C_BaseTFPlayer*>(cl_entitylist->GetEnt( iEntIndex )); + C_BaseTFPlayer *pLocalPlayer = C_BaseTFPlayer::GetLocalPlayer(); + + // Some entities we always want to check, cause the text may change + // even while we're looking at it + // Is it a player? + if ( IsPlayerIndex( iEntIndex ) ) + { + if ( pPlayer->InSameTeam(pLocalPlayer) ) + { + // Check distance to other player, and if the player is on the same team + float flDistSq = pPlayer->GetRenderOrigin().DistToSqr( pLocalPlayer->GetRenderOrigin() ); + if ( flDistSq < PLAYER_HINT_DISTANCE_SQ ) + { + Q_snprintf( m_sIDString, sizeof(m_sIDString), "%s\nHealth: %.0f percent\nUse to donate resources", + pPlayer->GetPlayerName(), ((float)pPlayer->GetHealth() / (float)pPlayer->GetMaxHealth() ) * 100 ); + } + else + { + Q_snprintf( m_sIDString, sizeof(m_sIDString), "%s\nHealth: %.0f percent", + pPlayer->GetPlayerName(), ((float)pPlayer->GetHealth() / (float)pPlayer->GetMaxHealth() ) * 100 ); + } + } + else if (( pPlayer->GetHealth() == 0) && (pLocalPlayer->GetClass() == TFCLASS_INFILTRATOR) ) + { + Q_snprintf( m_sIDString, sizeof(m_sIDString), "%s\nUse to disguise as this player", pPlayer->GetPlayerName() ); + } + else + { + m_sIDString[0] = 0; + m_iLastEntIndex = 0; + } + } + else + { + // Objects + C_BaseEntity *pEnt = cl_entitylist->GetEnt( iEntIndex ); + if ( !pEnt || !pEnt->InSameTeam(pLocalPlayer) ) + { + // This can happen because the object was destroyed + m_sIDString[0] = 0; + m_iLastEntIndex = 0; + } + else + { + // Don't check validity if it's sent by the server + Q_strncpy( m_sIDString, pEnt->GetIDString(), sizeof(m_sIDString) ); + m_iLastEntIndex = iEntIndex; + } + } + } + + // Draw our ID string + if ( m_sIDString[0] ) + { + int width, height; + int ypos = YRES(300); + + // Messagechars can't handle multiple line strings, so parse out the \n's and give it one line at a time + char *ch = m_sIDString; + while ( *ch ) + { + // Find the next newline + char *next_line; + for ( next_line = ch; *next_line != '\n' && *next_line != 0; next_line++ ) + { + } + + // Stomp the newline + char *top = next_line; + if ( *top == '\n' ) + { + *top = 0; + } + else + { + top = NULL; + } + + // Draw the line + messagechars->GetStringLength( m_hFont, &width, &height, ch ); + messagechars->DrawString( m_hFont, (ScreenWidth() - width) / 2, ypos, 255, 255, 245, 255, ch, IMessageChars::MESSAGESTRINGID_NONE ); + + ypos += height; + + // Restore the newline + if ( top ) + { + *top = '\n'; + } + + // Move to the next line + ch = next_line; + if ( *ch == '\n' ) + { + ch++; + } + } + } +} diff --git a/game/client/tf2/hud_targetreticle.cpp b/game/client/tf2/hud_targetreticle.cpp new file mode 100644 index 0000000..5f4349c --- /dev/null +++ b/game/client/tf2/hud_targetreticle.cpp @@ -0,0 +1,183 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Target reticle hud element +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "c_basetfplayer.h" +#include "tf_shareddefs.h" +#include "iclientmode.h" +#include "clientmode_tfnormal.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/imesh.h" +#include "hud_targetreticle.h" +#include "model_types.h" +#include "view_scene.h" +#include "view.h" +#include <vgui/Cursor.h> +#include <vgui_controls/Controls.h> +#include <vgui/ISurface.h> + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTargetReticle::CTargetReticle( void ) +: BaseClass( NULL, "CTargetReticle" ), + m_CursorNone(vgui::dc_none) +{ + SetCursor( m_CursorNone ); + + SetPaintBackgroundEnabled( false ); + SetAutoDelete( false ); + m_hTargetEntity = NULL; + m_pTargetLabel = NULL; + m_iReticleId = 0; + m_iReticleLeftId = 0; + m_iReticleRightId = 0; + m_iRenderTextureId = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTargetReticle::~CTargetReticle() +{ + if ( m_pTargetLabel != NULL ) + { + delete m_pTargetLabel; + m_pTargetLabel = NULL; + } + + SetParent( (vgui::Panel *)NULL ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTargetReticle::Init( C_BaseEntity *pEntity, const char *sName ) +{ + vgui::Panel *pParent = GetClientModeNormal()->GetViewport(); + SetParent( pParent ); + SetCursor( pParent->GetCursor() ); + + if ( !m_pTargetLabel ) + { + m_pTargetLabel = new vgui::Label( pParent, "TargetLabel", "Unnamed" ); + m_pTargetLabel->SetPos( 0, 0 ); + m_pTargetLabel->SetFgColor( Color( 255, 170, 0, 255 ) ); + m_pTargetLabel->SetPaintBackgroundEnabled( false ); + m_pTargetLabel->SetAutoDelete( false ); + m_pTargetLabel->SetCursor( m_CursorNone ); + } + + SetSize( XRES(32),YRES(32) ); + m_hTargetEntity = pEntity; + m_pTargetLabel->SetText( sName ); + + int contentW, contentH; + m_pTargetLabel->GetContentSize( contentW, contentH ); + m_pTargetLabel->SetWide( contentW ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_BaseEntity *CTargetReticle::GetTarget( void ) +{ + return m_hTargetEntity; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTargetReticle::Update( void ) +{ + if ( !m_hTargetEntity ) + { + C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + pPlayer->Remove_Target( this ); + return; + } + + // Load our textures.. + if ( !m_iReticleId ) + { + m_iReticleId = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_iReticleId, "Hud/target_reticle" , true, false); + } + + if ( !m_iReticleLeftId ) + { + m_iReticleLeftId = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_iReticleLeftId, "Hud/target_reticle_left", true, false ); + } + + if ( !m_iReticleRightId ) + { + m_iReticleRightId = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_iReticleRightId, "Hud/target_reticle_right" , true, false); + } + + int iX, iY; + GetTargetInScreenSpace( m_hTargetEntity, iX, iY ); + + int halfWidth = GetWide() / 2; + halfWidth = MAX( halfWidth, m_pTargetLabel->GetWide() / 2 ); + + m_iRenderTextureId = m_iReticleId; + if( iX < halfWidth || iX > ScreenWidth()-halfWidth ) + { + // It's off the screen. See what side it's on. + Vector vCenter = m_hTargetEntity->WorldSpaceCenter( ); + + if( CurrentViewRight().Dot( vCenter - CurrentViewOrigin() ) > 0 ) + { + m_iRenderTextureId = m_iReticleRightId; + iX = ScreenWidth() - halfWidth; + } + else + { + m_iRenderTextureId = m_iReticleLeftId; + iX = halfWidth; + } + + // Put Y in the center of the screen. + iY = ScreenHeight() / 2; + } + + // Move the icon there + SetPos( iX - (GetWide() / 2), iY - (GetTall() / 2) ); + + // Center the text under it + m_pTargetLabel->SetPos( iX - (m_pTargetLabel->GetWide() / 2), iY + (GetTall() / 2) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTargetReticle::Paint() +{ + if ( !m_hTargetEntity || !m_iRenderTextureId ) + return; + + C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + if ( pPlayer == NULL || pPlayer->GetHealth() < 1 ) + return; + + // Show hide label based on EMP state + bool suppress_reticle = pPlayer->HasPowerup(POWERUP_EMP); + + m_pTargetLabel->SetVisible( suppress_reticle ? false : true ); + + // Don't draw the reticle either + if ( suppress_reticle ) + return; + + vgui::surface()->DrawSetTexture( m_iRenderTextureId ); + vgui::surface()->DrawSetColor( 255, 255, 255, 255 ); + vgui::surface()->DrawTexturedRect( 0, 0, GetWide(), GetTall() ); +} + diff --git a/game/client/tf2/hud_targetreticle.h b/game/client/tf2/hud_targetreticle.h new file mode 100644 index 0000000..dfee449 --- /dev/null +++ b/game/client/tf2/hud_targetreticle.h @@ -0,0 +1,53 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Targeting reticle +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TARGETRETICLE_H +#define TARGETRETICLE_H +#ifdef _WIN32 +#pragma once +#endif + +#include <vgui_controls/Panel.h> +#include <vgui_controls/Label.h> +#include <vgui/Cursor.h> + +class IMaterial; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CTargetReticle : public vgui::Panel +{ + typedef vgui::Panel BaseClass; +public: + CTargetReticle( void ); + ~CTargetReticle(); + + void Update(); + + // vgui::Panel overrides. + virtual void Paint( void ); + + void Init( C_BaseEntity *pEntity, const char *sName ); + C_BaseEntity* GetTarget( void ); + + +protected: + + EHANDLE m_hTargetEntity; + vgui::Label *m_pTargetLabel; + + int m_iReticleId; + int m_iReticleLeftId; // When it's hanging off the edge of the screen. + int m_iReticleRightId; + + int m_iRenderTextureId; + + vgui::HCursor m_CursorNone; +}; + +#endif // TARGETRETICLE_H diff --git a/game/client/tf2/hud_technologytreedoc.cpp b/game/client/tf2/hud_technologytreedoc.cpp new file mode 100644 index 0000000..5ec1859 --- /dev/null +++ b/game/client/tf2/hud_technologytreedoc.cpp @@ -0,0 +1,175 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud_technologytreedoc.h" +#include "hud.h" +#include "hud_macros.h" +#include "techtree.h" +#include "iclientmode.h" +#include "hud_commander_statuspanel.h" +#include "clientmode_commander.h" +#include "commanderoverlaypanel.h" +#include "tf_hints.h" +#include "c_tf_hintmanager.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +static CTechnologyTreeDoc s_TechnologyTreeDoc; + +// Hook network messages +DECLARE_MESSAGE( s_TechnologyTreeDoc, Technology ) + +// Create object singleton on stack +CTechnologyTreeDoc& GetTechnologyTreeDoc() +{ + return s_TechnologyTreeDoc; +} + + +//----------------------------------------------------------------------------- +// Purpose: Construction +//----------------------------------------------------------------------------- +CTechnologyTreeDoc::CTechnologyTreeDoc( void ) +{ + m_pTree = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: Destruction +//----------------------------------------------------------------------------- +CTechnologyTreeDoc::~CTechnologyTreeDoc( void ) +{ + delete m_pTree; +} + +//----------------------------------------------------------------------------- +// Purpose: Initialize the panel +//----------------------------------------------------------------------------- +void CTechnologyTreeDoc::Init( void ) +{ + ReloadTechTree(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTechnologyTreeDoc::LevelInit( void ) +{ + if ( m_pTree ) + { + m_pTree->SetPreferredTechnology( NULL ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTechnologyTreeDoc::LevelShutdown( void ) +{ + if ( m_pTree ) + { + m_pTree->SetPreferredTechnology( NULL ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTechnologyTreeDoc::ReloadTechTree( void ) +{ + // FIXME, CTechnologyTreeDoc should be an entity /MO + HOOK_HUD_MESSAGE( s_TechnologyTreeDoc, Technology ); + + // Reconstruct the tech tree + delete m_pTree; + + // FIXME: If we reactivate this, we'll need to revisit team number here... + m_pTree = new CTechnologyTree( ::filesystem, 0); + Assert( m_pTree ); + + m_pTree->SetPreferredTechnology( NULL ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Receive hud update message from server +// Input : *pszName - +// iSize - +// *pbuf - +// Output : int +//----------------------------------------------------------------------------- +int CTechnologyTreeDoc::MsgFunc_Technology(bf_read &msg) +{ + int index; + int available; + int voters; + float resourcelevel; + bool preferred; + + // Which tech + index = msg.ReadByte(); + // Available to this team? + available = msg.ReadByte(); + // # of players indicating this as their preferred tech for new spending + voters = msg.ReadByte(); + + preferred = ( voters & 0x80 ) ? true : false; + voters &= 0x7f; + + resourcelevel = (float)msg.ReadShort(); + + // Look it up by index + CBaseTechnology *item = m_pTree->GetTechnology( index ); + if ( item ) + { + bool wasactive = item->GetActive(); + + bool justactivated = !wasactive && available; + + // Set data elements + item->SetActive( available ? true : false ); + item->SetVoters( voters ); + item->SetResourceLevel( resourcelevel ); + + // If this is the tech I am voting for, clear my vote + if ( preferred ) + { + // Sets the flag on the item, too + m_pTree->SetPreferredTechnology( item ); + } + else + { + // Force deselection in case there is no active preference on the server any more + item->SetPreferred( false ); + } + + if ( justactivated && item->GetLevel() > 0 && !item->GetHintsGiven( TF_HINT_NEWTECHNOLOGY ) ) + { + // So we only give this hint once this game, even if we respawn, etc. + item->SetHintsGiven( TF_HINT_NEWTECHNOLOGY, true ); + // Note, only show a max of three or 4 newtechnology hints at a time + CreateGlobalHint( TF_HINT_NEWTECHNOLOGY, item->GetPrintName(), index, 3 ); + } + } + + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: Add a file of technologies to the technology tree +//----------------------------------------------------------------------------- +void CTechnologyTreeDoc::AddTechnologyFile( char *sFilename ) +{ + // Add the technologies to the tech list + if ( m_pTree ) + { + // FIXME: If we reactivate this, we'll need to revisit team number here... + m_pTree->AddTechnologyFile( ::filesystem, 0, sFilename ); + } +} diff --git a/game/client/tf2/hud_technologytreedoc.h b/game/client/tf2/hud_technologytreedoc.h new file mode 100644 index 0000000..c9d74a4 --- /dev/null +++ b/game/client/tf2/hud_technologytreedoc.h @@ -0,0 +1,49 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( TF_TECHNOLOGYTREEDOC_H ) +#define TF_TECHNOLOGYTREEDOC_H +#ifdef _WIN32 +#pragma once +#endif + +// Forward declarations +class CTechnologyTree; + +//----------------------------------------------------------------------------- +// Purpose: Container for views into technology tree +//----------------------------------------------------------------------------- +class CTechnologyTreeDoc +{ +public: + // Construction + CTechnologyTreeDoc( void ); + virtual ~CTechnologyTreeDoc( void ); + + virtual void Init( void ); + virtual void ReloadTechTree( void ); + + virtual void LevelInit( void ); + virtual void LevelShutdown( void ); + + inline CTechnologyTree *GetTechnologyTree() {return m_pTree;} + + void AddTechnologyFile( char *sFilename ); + + // Network input + int MsgFunc_Technology( bf_read &msg ); + int MsgFunc_Resource( bf_read &msg ); + +private: + // The underlying technology data tree + CTechnologyTree *m_pTree; +}; + +// Expose Document to rest of dll +extern CTechnologyTreeDoc& GetTechnologyTreeDoc(); + + +#endif // TF_TECHNOLOGYTREEDOC_H
\ No newline at end of file diff --git a/game/client/tf2/hud_timer.cpp b/game/client/tf2/hud_timer.cpp new file mode 100644 index 0000000..a5b6b6a --- /dev/null +++ b/game/client/tf2/hud_timer.cpp @@ -0,0 +1,298 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: HUD Timer +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "hud_macros.h" +#include "hud_numeric.h" +#include "c_basetfplayer.h" +#include "hud_timer.h" +#include "iclientmode.h" +#include <vgui_controls/AnimationController.h> + +#define MIN_TIMER_ALPHA 192 + +using namespace vgui; + +DECLARE_HUDELEMENT( CHudTimer ); +DECLARE_HUD_MESSAGE( CHudTimer, StartTimer ); +DECLARE_HUD_MESSAGE( CHudTimer, SetTimer ); +DECLARE_HUD_MESSAGE( CHudTimer, UpdateTimer ); + +//----------------------------------------------------------------------------- +// Purpose: Create the Timer +//----------------------------------------------------------------------------- +CHudTimer::CHudTimer( const char *pElementName ) : CHudNumeric( pElementName, "HudTimer" ) +{ + SetDrawLabel( false ); + SetDoPulses( false ); + + SetHiddenBits( HIDEHUD_MISCSTATUS ); +} + +//----------------------------------------------------------------------------- +// Purpose: Reset Timer values +//----------------------------------------------------------------------------- +void CHudTimer::Init( void ) +{ + m_iAlpha = MIN_TIMER_ALPHA; + m_flCurrentTime = 0.0; + m_flStartTime = 0.0; + m_flPrevTimeSlice = 0.0; + m_iPaused = false; + m_bFixedTime = true; +} + +//----------------------------------------------------------------------------- +// Purpose: Set the Timer's start time, and tells the timer to go into fixed time mode. +//----------------------------------------------------------------------------- +void CHudTimer::SetFixedTimer( float flStartTime, float flTimeLimit ) +{ + Init(); + + // Setup the Timer values + m_flStartTime = flStartTime; + m_flTimeLimit = flTimeLimit; + m_bFixedTime = true; +} + +//----------------------------------------------------------------------------- +// Purpose: Set the Timer to a Time, and tells the timer to go into no fixed time mode. +//----------------------------------------------------------------------------- +void CHudTimer::SetNoFixedTimer( float flTime ) +{ + Init(); + + // Setup the Timer values + m_flStartTime = m_flCurrentTime = flTime; + m_bFixedTime = false; + + // Timer starts paused + StopTimer(); +} + +//----------------------------------------------------------------------------- +// Purpose: Updates the Timer to a specific timer without doing anything else +//----------------------------------------------------------------------------- +void CHudTimer::UpdateTimer( float flTime ) +{ + m_flCurrentTime = flTime; + m_flPrevTimeSlice = gpGlobals->curtime; +} + +//----------------------------------------------------------------------------- +// Purpose: Start the Timer +//----------------------------------------------------------------------------- +void CHudTimer::StartTimer( void ) +{ + // Ignore start / stop if I'm in fixed time mode + if ( m_bFixedTime ) + return; + if ( !m_iPaused ) + return; + + // Start timer + m_flPrevTimeSlice = gpGlobals->curtime; + m_iPaused = false; + + // Start with a short pulse + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("TimerPulse"); +} + +//----------------------------------------------------------------------------- +// Purpose: Stop the Timer, without resetting it +//----------------------------------------------------------------------------- +void CHudTimer::StopTimer( void ) +{ + // Ignore start / stop if I'm in fixed time mode + if ( m_bFixedTime ) + return; + if ( m_iPaused ) + return; + + // Pause timer values + m_iPaused = true; + + // Stop with a short pulse + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("TimerPulse"); +} + +//----------------------------------------------------------------------------- +// Purpose: Get back a color for the timer from a Green <-> Yellow <-> Red ramp +//----------------------------------------------------------------------------- +Color CHudTimer::GetColor( void ) +{ + Color clr = Color( 0, 0, 0, 0 ); + + float flPercentagePassed = 1 - (m_flCurrentTime / m_flTimeLimit); + + if ( flPercentagePassed < 0.75 ) + { + clr = m_TextColor; + } + else if ( flPercentagePassed < 0.9 ) + { + clr = m_TextColorWarning; + } + else + { + clr = m_TextColorCritical; + } + + // Handle pulses ( which brighten the timer & change the font ) + clr[3] = clamp( MIN_TIMER_ALPHA + ( m_flBlur ) * 128, 0, 255 ); + + // Low timer always overrides to make it bright + if ( flPercentagePassed > 0.99 ) + { + clr[3] = 255; + } + + return clr; +} + +//----------------------------------------------------------------------------- +// Purpose: Get back a color for the timer from a Green <-> Yellow <-> Red ramp +//----------------------------------------------------------------------------- +Color CHudTimer::GetBoxColor() +{ + Color boxColor = Color( 0, 0, 0, 0 ); + + float flPercentagePassed = 1 - (m_flCurrentTime / m_flTimeLimit); + if ( flPercentagePassed < 0.75 ) + { + boxColor = m_BoxColor; + } + else if ( flPercentagePassed < 0.9 ) + { + boxColor = m_BoxColorWarning; + } + else + { + boxColor = m_BoxColorCritical; + } + + return boxColor; +} + +bool CHudTimer::GetValue( char *value, int maxlen ) +{ + if ( m_flStartTime == 0.0 ) + return false; + + // Convert time to Minutes and Seconds (prevent negative times) + int iTimerMinutes = MAX( 0, ((int)m_flCurrentTime) / 60 ); + int iTimerSeconds = MAX( 0, ((int)m_flCurrentTime) % 60 ); + + Q_snprintf( value, maxlen, "%02d:%.2d", iTimerMinutes, iTimerSeconds ); + return true; +} + +void CHudTimer::OnThink( void ) +{ + if ( m_flStartTime == 0.0 ) + return; + + // If we're in fixed time mode, calculate the current time + if ( m_bFixedTime ) + { + // Don't paint at all if we have no timelimit + if ( !m_flTimeLimit ) + return; + + m_flCurrentTime = gpGlobals->curtime - m_flStartTime; + + // If we have a timelimit, count down + if ( m_flTimeLimit ) + { + m_flCurrentTime = m_flTimeLimit - m_flCurrentTime; + } + + CheckForPulse(); + } + + // Increment the time if the Timer's going, and we're not in fixed time mode. + if ( !m_iPaused && !m_bFixedTime ) + { + m_flCurrentTime -= gpGlobals->curtime - m_flPrevTimeSlice; + m_flPrevTimeSlice = gpGlobals->curtime; + + // Hit the end? + if ( m_flCurrentTime <= 0.0 ) + { + StopTimer(); + m_flCurrentTime = 0.0; + } + } + + m_flLastTime = m_flCurrentTime; +} + +//----------------------------------------------------------------------------- +// Purpose: Check to see if the Timer should pulse +//----------------------------------------------------------------------------- +void CHudTimer::CheckForPulse( void ) +{ + int pulseInterval = 60; + if ( m_flCurrentTime <= 60 ) + { + pulseInterval = 10; + } + + // See if we've crossed a minute boundary + int iLastTimerMinutes = ((int)m_flLastTime) / pulseInterval; + // will we get there in next half second + int iTimerMinutes = ((int)m_flCurrentTime - 0.5f ) / pulseInterval; + if ( iLastTimerMinutes != iTimerMinutes ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("TimerPulse"); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Message Handler for the Timer Set +//----------------------------------------------------------------------------- +int CHudTimer::MsgFunc_SetTimer(bf_read &msg) +{ + float flTimeToSetTo = msg.ReadBitCoord(); + SetNoFixedTimer( flTimeToSetTo ); + + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: Message Handler for the Timer Update +// Updates are like sets, but they don't re-evaluate the start time +// They're used to just ensure the Client Timers don't get too far out of synch with the server's timer +//----------------------------------------------------------------------------- +int CHudTimer::MsgFunc_UpdateTimer(bf_read &msg) +{ + float flTimeToSetTo = msg.ReadBitCoord(); + UpdateTimer( flTimeToSetTo ); + + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: Message Handler for the Timer Start/Stop +//----------------------------------------------------------------------------- +int CHudTimer::MsgFunc_StartTimer( bf_read &msg ) +{ + if ( msg.ReadByte() ) + { + // Start the Timer + StartTimer(); + } + else + { + // Pause the Timer + StopTimer(); + } + + return 1; +}
\ No newline at end of file diff --git a/game/client/tf2/hud_timer.h b/game/client/tf2/hud_timer.h new file mode 100644 index 0000000..b7645ad --- /dev/null +++ b/game/client/tf2/hud_timer.h @@ -0,0 +1,70 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HUD_TIMER_H +#define HUD_TIMER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "hud_numeric.h" +#include <vgui_controls/Panel.h> + + +//----------------------------------------------------------------------------- +// Purpose: TF2 Countdown Timer +//----------------------------------------------------------------------------- +class CHudTimer : public CHudNumeric +{ + DECLARE_CLASS_SIMPLE( CHudTimer, CHudNumeric ) +public: + CHudTimer( const char *pElementName ); + + virtual void Init( void ); + virtual void OnThink( void ); + + virtual const char *GetLabelText() { return m_szTimerLabel; } + virtual const char *GetPulseEvent( bool increment ) { return ""; } + virtual bool GetValue( char *val, int maxlen ); + + virtual Color GetColor(); + virtual Color GetBoxColor(); + + // Handling + void SetNoFixedTimer( float flTime ); + void SetFixedTimer( float flStartTime, float flTimeLimit ); + void UpdateTimer( float flTime ); + void StartTimer( void ); + void StopTimer( void ); + void CheckForPulse( void ); + int MsgFunc_SetTimer( bf_read &msg ); + int MsgFunc_StartTimer( bf_read &msg ); + int MsgFunc_UpdateTimer( bf_read &msg ); + +public: + int m_iAlpha; + int m_iPaused; + float m_flCurrentTime; + float m_flStartTime; + float m_flPrevTimeSlice; + float m_flPulseTime; + float m_flTimeLimit; + float m_flLastTime; + + // The Timer has two modes of operation: + // m_bFixedTime == true: Timer can't be paused. Time displayed is an offset from the originally specified start time. + // m_bFixedTime == false: Timer can be stopped & started. Time displayed is calculated on the client, and regularly updated by the server + // to ensure it doesn't get too far off the server's time. + bool m_bFixedTime; + +private: + float m_flOpenCloseTime; + + CPanelAnimationStringVar( 128, m_szTimerLabel, "TimerLabel", "" ); +}; + +#endif // HUD_TIMER_H diff --git a/game/client/tf2/hud_vehicle_role.cpp b/game/client/tf2/hud_vehicle_role.cpp new file mode 100644 index 0000000..2ba956d --- /dev/null +++ b/game/client/tf2/hud_vehicle_role.cpp @@ -0,0 +1,80 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "hud_vehicle_role.h" +#include "iclientmode.h" +#include <vgui_controls/Controls.h> +#include <vgui/ISurface.h> +#include <KeyValues.h> + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +DECLARE_HUDELEMENT( CVehicleRoleHudElement ); + +using namespace vgui; + +CVehicleRoleHudElement::CVehicleRoleHudElement( const char *pElementName ) : + CHudElement( pElementName ), BaseClass( NULL, "VehicleRoleHudElement" ) +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + + m_iRole = -1; + + SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD ); +} + +void CVehicleRoleHudElement::ApplySchemeSettings( IScheme *scheme ) +{ + BaseClass::ApplySchemeSettings( scheme ); + + m_hTextFont = scheme->GetFont( "Trebuchet24" ); + + SetPaintBackgroundEnabled( false ); +} + + +void CVehicleRoleHudElement::ShowVehicleRole( int iRole ) +{ + m_iRole = iRole; +} + + +void CVehicleRoleHudElement::Paint() +{ + if ( m_iRole == -1 ) + return; + + surface()->DrawSetTextFont( m_hTextFont ); + surface()->DrawSetTextColor( GetFgColor() ); + + char str[512]; + if ( m_iRole == VEHICLE_ROLE_DRIVER ) + { + Q_strncpy( str, "Driver", sizeof( str ) ); + } + else + { + Q_snprintf( str, sizeof( str ), "Passenger %d", m_iRole ); + } + + int pixels = UTIL_ComputeStringWidth( m_hTextFont, str ); + int x = ( GetWide() - pixels ) / 2; + + surface()->DrawSetTextPos( x, 0 ); + + char *p = str; + while ( *p ) + { + surface()->DrawUnicodeChar( *p ); + p++; + } +} + + diff --git a/game/client/tf2/hud_vehicle_role.h b/game/client/tf2/hud_vehicle_role.h new file mode 100644 index 0000000..ddee87f --- /dev/null +++ b/game/client/tf2/hud_vehicle_role.h @@ -0,0 +1,34 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef HUD_VEHICLE_ROLE_H +#define HUD_VEHICLE_ROLE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "hudelement.h" +#include <vgui_controls/Controls.h> +#include <vgui_controls/Panel.h> + +class CVehicleRoleHudElement : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CVehicleRoleHudElement, vgui::Panel ); +public: + CVehicleRoleHudElement( const char *pElementName ); + virtual void ApplySchemeSettings( vgui::IScheme *scheme ); + virtual void Paint( void ); + + // Set which role to display on the hud. + void ShowVehicleRole( int iRole ); +private: + int m_iRole; + vgui::HFont m_hTextFont; +}; + + +#endif // HUD_VEHICLE_ROLE_H diff --git a/game/client/tf2/hud_weaponselection.cpp b/game/client/tf2/hud_weaponselection.cpp new file mode 100644 index 0000000..4b21750 --- /dev/null +++ b/game/client/tf2/hud_weaponselection.cpp @@ -0,0 +1,1671 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#include "cbase.h" +#include "weapon_selection.h" +#include "iclientmode.h" +#include "basetfcombatweapon_shared.h" +#include "weapon_objectselection.h" +#include <KeyValues.h> +#include <vgui/IScheme.h> +#include <vgui/ISurface.h> +#include <vgui/ISystem.h> +#include <vgui_controls/AnimationController.h> +#include <vgui_controls/Panel.h> +#include "keydefs.h" + +#include <vgui/IVGui.h> + +#include "weapon_twohandedcontainer.h" +#ifdef CLIENT_DLL +#include "c_weapon_builder.h" +#include "iinput.h" +#else +#include "weapon_builder.h" +#endif + +using namespace vgui; + +class CHudWeaponSelection; + +typedef enum +{ + IMAGE_BACKGROUND = 0, + IMAGE_CURRENT, + IMAGE_INVALID +} WeaponBoxType_t; + +enum +{ + HUMAN_WEAPON_SELECTION = 0, + ALIEN_WEAPON_SELECTION, +}; + +struct CSlotInfo +{ + bool active; + bool valid; + CHudTexture const *icon; + bool drawAmmo; + float ammoPerc; + bool ammoCaution; + char printname[ 128 ]; + CHandle< C_BaseCombatWeapon > weapon; +}; + +struct CWeaponMenuItem +{ + // If true, it's a dummy item + bool buildslot; + int priority; + int hotkey; + int openbuildmenu; + bool isvalidmenuitem; + CHandle< C_BaseCombatWeapon > weapon; +}; + +class WeaponMenu +{ +public: + WeaponMenu() : items( 0, 0, WeaponLessFunc ) + { + m_bIsBuildMenu = false; + m_nActiveItem = 0; + } + + void SetActiveItem( int item ) + { + bool changed = ( m_nActiveItem != item ); + + m_nActiveItem = item; + + if ( !changed ) + return; + + const char *prefix = m_bIsBuildMenu ? "WeaponHiliteBuildMenu" : "WeaponHiliteWeaponMenu"; + + if ( m_nActiveItem >= 1 ) + { + char slotSequence[ 128 ]; + Q_snprintf( slotSequence, sizeof( slotSequence ), "%s%i", prefix, m_nActiveItem ); + + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( slotSequence ); + } + } + + int GetActiveItem() + { + return m_nActiveItem; + } + + static bool WeaponLessFunc( const CWeaponMenuItem& w1, const CWeaponMenuItem& w2 ) + { + return w1.priority < w2.priority; + } + + CUtlRBTree< CWeaponMenuItem, int > items; + int m_nActiveItem; + bool m_bIsBuildMenu; +}; + +class CHudWeaponItemPanel : public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudWeaponItemPanel, vgui::Panel ); + +public: + CHudWeaponItemPanel( vgui::Panel *parent, const char *panelName ); + + CPanelAnimationVarAliasType( float, m_flIconWidth, "IconWidth", "60", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flIconHeight, "IconHeight", "30", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flIconXPos, "IconXPos", "10", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flIconYPos, "IconYPos", "4", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flTextXPos, "TextXPos", "10", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flTextYPos, "TextYPos", "35", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flAmmoBarX, "AmmoBarX", "75", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flAmmoBarWide, "AmmoBarWide", "4", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flSelectionNumberXPos, "SelectionNumberXPos", "4", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flSelectionNumberYPos, "SelectionNumberYPos", "4", "proportional_float" ); + + CPanelAnimationVarAliasType( float, m_flPriceXEndPos, "PriceXEndPos", "4", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flPriceYEndPos, "PriceYEndPos", "4", "proportional_float" ); + + CPanelAnimationVar( float, m_flGrowFraction, "GrowFraction", "1.0" ); + + bool m_bInUse; + + bool m_bDrawNumbers; + int m_nSlotNumber; + bool m_bBuildMenu; + + // Copies of data + CSlotInfo info; + CWeaponMenuItem menuItem; + + virtual void Paint(); + + virtual void ApplySchemeSettings( vgui::IScheme *scheme ); + + void SetupIcons(); + + enum + { + NUM_SLOT_TEAMS = 2, + NUM_MENU_TYPES = 3, + }; + + CHudTexture *m_BackgroundIcons[ NUM_SLOT_TEAMS ][ NUM_MENU_TYPES ]; + +private: + void TranslateColor( float percent, Color& clr ); + void DrawBox( bool isbuildmenu, int x, int y, int wide, int tall, bool isactive, bool isvalid, float normalizedAlpha, int number ); + int GetTeamIndex(); + void OnWeaponSelectionDrawn( CHudWeaponSelection *selection, C_WeaponObjectSelection *weapon, bool bCurrentlySelected, + int wide, int tall, Color& clr ); +}; + +//----------------------------------------------------------------------------- +// Purpose: tf2 weapon selection hud element +//----------------------------------------------------------------------------- +class CHudWeaponSelection : public CBaseHudWeaponSelection, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudWeaponSelection, vgui::Panel ); + +public: + + CHudWeaponSelection(const char *pElementName ); + + virtual bool ShouldDraw( void ); + + virtual void VidInit(void); + + virtual void CycleToNextWeapon( void ); + virtual void CycleToPrevWeapon( void ); + virtual void SwitchToLastWeapon( void ); + + virtual C_BaseCombatWeapon *GetWeaponInSlot( int iSlot, int iSlotPos ); + virtual void SelectWeaponSlot( int iSlot ); + + virtual void OnWeaponPickup( C_BaseCombatWeapon *pWeapon ); + + virtual void SelectWeapon( void ); + + virtual C_BaseCombatWeapon *GetSelectedWeapon( void ); + + virtual void OpenSelection( void ); + + virtual int KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ); + + virtual void HideSelection( void ); + +protected: + virtual void OnTick(); + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + virtual void ApplySettings( KeyValues *resourceData ); +private: + + // Offensive + // Defensive + // General Purpose + enum + { + BUILD_OFFENSIVE = 0, + BUILD_DEFENSIVE, + BUILD_GENERAL_PURPOSE, + + NUM_BUILD_MENUS, + }; + + enum + { + MAX_WEAPON_MENU_ITEMS = 7, + MAX_BUILD_MENU_ITEMS = 6, + }; + + void SetupWeaponMenu( WeaponMenu& menu, C_BaseCombatWeapon *activeItem, bool drawNumbers ); + void SetupBuildMenu( WeaponMenu& menu, C_BaseCombatWeapon *activeItem ); + + void DrawBox( bool isbuildmenu, int x, int y, int wide, int tall, bool current, bool isvalid, float normalizedAlpha, int number ); + + void TranslateColor( float percent, Color& clr ); + + void ShowBuildMenu( int buildmenu ); + void ShowBuildMenu( WeaponMenu& buildMenu ); + void HideBuildMenu( void ); + WeaponMenu& GetActiveMenu(); + int GetLowIndex( WeaponMenu& menu ); + void WrapIndexToRange( int& index, int low, int high ); + int FindSlotForHotKey( WeaponMenu& menu, int hotkey ); + int FindNextSelectableWeaponInMenu( WeaponMenu& menu, int startindex, int direction ); + int CountSelectableItems( WeaponMenu& menu ); + CWeaponMenuItem *GetFirstSelectableWeapon( WeaponMenu& menu ); + const char *GetBuildMenuName( int slot ); + const char *GetBuildMenuMaterial( int slot ); + + void SelectBuildMenuSlot( WeaponMenu& buildMenu ); + + void CreateWeaponItemPanels(); + + void ClearBuildMenu(); + void RebuildMenus(); + void AssignSlots( WeaponMenu& menu, int firstindex ); + void CollapseSingleItemBuildMenus(); + + void GetSlotInfo( const CWeaponMenuItem *w, C_BaseCombatWeapon *active, CSlotInfo& info ); + + int GetTeamIndex(); + + void SetupIcons(); + + CPanelAnimationVar( float, m_flAlphaOverride, "Alpha", "255.0" ); + CPanelAnimationVar( float, m_flSelectionAlphaOverride, "SelectionAlpha", "255.0" ); + + CPanelAnimationVar( Color, m_TextColor, "TextColor", "SelectionTextFg" ); + CPanelAnimationVar( Color, m_InvalidActiveColor, "InvalidActiveColor", "InvalidActiveSlotFg" ); + CPanelAnimationVar( Color, m_InvalidActiveTextColor, "InvalidActiveTextColor", "InvalidActiveSlotText" ); + CPanelAnimationVar( Color, m_InvalidColor, "InvalidColor", "InvalidSlotFg" ); + CPanelAnimationVar( Color, m_InvalidTextColor, "InvalidTextColor", "InvalidSlotText" ); + CPanelAnimationVar( Color, m_OtherColor, "OtherColor", "OtherSlotFg" ); + CPanelAnimationVar( Color, m_OtherTextColor, "OtherTextColor", "OtherSlotText" ); + CPanelAnimationVar( Color, m_AmmoNormalColor, "AmmoNormalColor", "AmmoNormal" ); + CPanelAnimationVar( Color, m_AmmoCautionColor, "AmmoCautionColor", "AmmoCaution" ); + + CPanelAnimationVar( vgui::HFont, m_hNumberFont, "NumberFont", "HudSelectionNumbers" ); + CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "HudSelectionText" ); + CPanelAnimationVar( vgui::HFont, m_hTextFontSmall, "TextFontSmall", "HudSelectionTextSmall" ); + CPanelAnimationVar( vgui::HFont, m_hPriceFont, "PriceFont", "HudSelectionTextSmall" ); + + CPanelAnimationVar( float, m_flGrowFraction, "GrowFraction", "0.0" ); + + CHandle<C_BaseCombatWeapon> m_hLastPickedUpWeapon; + bool m_bInSelectionMode; + int m_nLastBuildTick; + bool m_bInBuildMenu; + int m_nActiveBuildMenu; + + WeaponMenu *m_PreviousBuildMenu; + + WeaponMenu m_Weapons; + WeaponMenu m_BuildObjects[ NUM_BUILD_MENUS ]; + + CHudWeaponItemPanel *m_pWeaponPanels[ MAX_WEAPON_MENU_ITEMS ]; + CHudWeaponItemPanel *m_pBuildPanels[ MAX_BUILD_MENU_ITEMS ]; + + CWeaponMenuItem *FindWeapon( WeaponMenu& menu, int hotkey ); + + friend class CHudWeaponItemPanel; +}; + +DECLARE_HUDELEMENT( CHudWeaponSelection ); + +void CHudWeaponSelection::VidInit(void) +{ + CBaseHudWeaponSelection::VidInit(); + + SetupIcons(); +} + +void CHudWeaponSelection::SetupIcons() +{ + int i; + + for ( i = 0; i < MAX_WEAPON_MENU_ITEMS; i++ ) + { + m_pWeaponPanels[ i ]->SetupIcons(); + } + + for ( i = 0; i < MAX_BUILD_MENU_ITEMS; i++ ) + { + m_pBuildPanels[ i ]->SetupIcons(); + } +} + + +void CHudWeaponSelection::AssignSlots( WeaponMenu& menu, int firstindex ) +{ + int slot = firstindex; + + for ( int i = menu.items.FirstInorder(); i != menu.items.InvalidIndex(); i = menu.items.NextInorder( i ) ) + { + CWeaponMenuItem *w = &menu.items[ i ]; + w->hotkey = slot++; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudWeaponSelection::CreateWeaponItemPanels() +{ + int i; + char sz[ 128 ]; + for ( i = 0; i < MAX_WEAPON_MENU_ITEMS; i++ ) + { + Q_snprintf( sz, sizeof( sz ), "WeaponMenu%i", i + 1 ); + m_pWeaponPanels[ i ] = new CHudWeaponItemPanel( this, sz ); + m_pWeaponPanels[ i ]->m_nSlotNumber = i; + m_pWeaponPanels[ i ]->m_bBuildMenu = false; + } + + for ( i = 0; i < MAX_BUILD_MENU_ITEMS; i++ ) + { + Q_snprintf( sz, sizeof( sz ), "BuildMenu%i", i + 1 ); + m_pBuildPanels[ i ] = new CHudWeaponItemPanel( this, sz ); + m_pBuildPanels[ i ]->m_nSlotNumber = i; + m_pBuildPanels[ i ]->m_bBuildMenu = true; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudWeaponSelection::RebuildMenus() +{ + int i; + + if ( gpGlobals->tickcount == m_nLastBuildTick ) + return; + + m_nLastBuildTick = gpGlobals->tickcount; + + + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + if ( !player ) + return; + + m_Weapons.items.RemoveAll(); + for ( i = 0; i < NUM_BUILD_MENUS; i++ ) + { + m_BuildObjects[ i ].items.RemoveAll(); + } + + CWeaponMenuItem item; + + int c = MAX_WEAPONS; + for ( i = 0; i < c; i++ ) + { + C_BaseCombatWeapon *pWeapon = player->GetWeapon( i ); + if ( !pWeapon ) + { + continue; + } + + if ( !pWeapon->VisibleInWeaponSelection() ) + { + continue; + } + + item.priority = pWeapon->GetSlot() * 10 + pWeapon->GetPosition(); + item.buildslot = false; + item.openbuildmenu = -1; + item.weapon = pWeapon; + item.isvalidmenuitem = true; + + if ( dynamic_cast< C_WeaponObjectSelection * >( pWeapon ) ) + { + // HACK + int firstbuildslot = 4; + int whichBuildMenu = clamp( pWeapon->GetSlot() - firstbuildslot, 0, NUM_BUILD_MENUS - 1 ); + + m_BuildObjects[ whichBuildMenu ].items.Insert( item ); + } + else + { + m_Weapons.items.Insert( item ); + } + } + + while ( m_Weapons.items.Count() < 3 ) + { + // Add build item menus + item.priority = 999; + item.buildslot = false; + item.openbuildmenu = -1; + item.weapon = NULL; + item.isvalidmenuitem = false; + m_Weapons.items.Insert( item ); + + m_Weapons.m_bIsBuildMenu = false; + } + + for ( i = 0; i < NUM_BUILD_MENUS; i++ ) + { + // Add build item menus + item.priority = 999; + item.buildslot = true; + item.openbuildmenu = i; + item.weapon = NULL; + item.isvalidmenuitem = CountSelectableItems( m_BuildObjects[ i ] ) > 0 ? true : false; + m_Weapons.items.Insert( item ); + + // Assign build menu slots + AssignSlots( m_BuildObjects[ i ], 0 ); + + m_BuildObjects[ i ].m_bIsBuildMenu = true; + } + + // Now walk in order and assign hotkeys + AssignSlots( m_Weapons, 1 ); + + // Merge single item build menus into main menu + CollapseSingleItemBuildMenus(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudWeaponSelection::CollapseSingleItemBuildMenus() +{ + for ( int i = 0; i < NUM_BUILD_MENUS; i++ ) + { + int count = m_BuildObjects[ i ].items.Count(); + + // Not an issue + if ( count > 1 ) + continue; + + CWeaponMenuItem *mainItem = FindWeapon( m_Weapons, 4 + i ); + if ( !mainItem ) + continue; + + // It's empty, need to make main item a disabled slot + if ( count == 0 ) + { + // Add build item menus + mainItem->isvalidmenuitem = false; + } + else + { + // Only one item in sub menu, copy it over + CWeaponMenuItem *buildItem = &m_BuildObjects[ i ].items[ 0 ]; + mainItem->buildslot = false; + mainItem->openbuildmenu = -1; + mainItem->isvalidmenuitem = true; + mainItem->weapon = buildItem->weapon; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudWeaponSelection::ClearBuildMenu() +{ + for ( int i = 0; i < MAX_BUILD_MENU_ITEMS; i++ ) + { + m_pBuildPanels[ i ]->m_bInUse = false; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CHudWeaponSelection::CHudWeaponSelection(const char *pElementName ) : + CBaseHudWeaponSelection(pElementName), BaseClass(NULL, "HudWeaponSelection") +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + + m_nLastBuildTick = -1; + + m_hNumberFont = NULL; + m_bInSelectionMode = false; + + CreateWeaponItemPanels(); + + vgui::ivgui()->AddTickSignal( GetVPanel() ); +} + +void CHudWeaponSelection::ShowBuildMenu( int buildmenu ) +{ + bool wasinbuild = m_bInBuildMenu; + + int mainItem = buildmenu + 4; + m_Weapons.SetActiveItem( mainItem ); + + m_bInBuildMenu = true; + m_nActiveBuildMenu = buildmenu; + GetActiveMenu().SetActiveItem( GetLowIndex( GetActiveMenu() ) ); + + if ( !wasinbuild ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponOpenBuildSubMenu"); + + switch ( buildmenu ) + { + default: + case BUILD_OFFENSIVE: + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponOpenBuildOffensive"); + break; + case BUILD_DEFENSIVE: + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponOpenBuildDefensive"); + break; + case BUILD_GENERAL_PURPOSE: + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponOpenBuildGeneral"); + break; + } + } +} + +void CHudWeaponSelection::ShowBuildMenu( WeaponMenu& buildMenu ) +{ + int c = m_Weapons.items.Count(); + for ( int i = 0; i < c; i++ ) + { + CWeaponMenuItem *item = &m_Weapons.items[ i ]; + if ( !item || !item->buildslot ) + continue; + + WeaponMenu &menu = m_BuildObjects[ item->openbuildmenu ]; + if ( &menu == &buildMenu ) + { + ShowBuildMenu( item->openbuildmenu ); + return; + } + } + + Assert( 0 ); +} + +void CHudWeaponSelection::HideBuildMenu( void ) +{ + bool wasinbuild = m_bInBuildMenu; + + GetActiveMenu().SetActiveItem( GetLowIndex( GetActiveMenu() ) ); + m_bInBuildMenu = false; + + if ( wasinbuild ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponCloseBuildSubMenu"); + } + + m_nActiveBuildMenu = -1; +} + +WeaponMenu& CHudWeaponSelection::GetActiveMenu() +{ + return m_bInBuildMenu ? m_BuildObjects[ m_nActiveBuildMenu ] : m_Weapons; +} + +int CHudWeaponSelection::GetLowIndex( WeaponMenu& menu ) +{ + if ( menu.items.Count() == 0 ) + return 1; + + int lowindex = menu.items[ menu.items.FirstInorder() ].hotkey; + return lowindex; +} + +void CHudWeaponSelection::WrapIndexToRange( int& index, int low, int high ) +{ + int delta = ( high - low ) + 1; + while ( index < low ) + { + index += delta; + } + + while ( index > high ) + { + index -= delta; + } +} + +int CHudWeaponSelection::FindSlotForHotKey( WeaponMenu& menu, int hotkey ) +{ + int count = menu.items.Count(); + for ( int i = 0; i < count;i++ ) + { + if ( menu.items[ i ].hotkey == hotkey ) + return i; + } + + return 0; +} + +int CHudWeaponSelection::FindNextSelectableWeaponInMenu( WeaponMenu& menu, int startindex, int direction ) +{ + direction = direction > 0 ? 1 : -1; + + int count = menu.items.Count(); + int lowindex = GetLowIndex( menu ); + int highindex = lowindex + count - 1; + + for ( int offset = 1; offset <= count; offset++ ) + { + int current = startindex + offset * direction; + + WrapIndexToRange( current, lowindex, highindex ); + + //int slot = FindSlotForHotKey( menu, current ); + + //C_BaseCombatWeapon *w = menu.items[ slot ].weapon; + //if ( w && !w->CanBeSelected() ) + // continue; + + return current; + } + + return startindex; +} + +int CHudWeaponSelection::CountSelectableItems( WeaponMenu& menu ) +{ + int count = 0; + int c = menu.items.Count(); + for ( int i = 0; i < c; i++ ) + { + C_BaseCombatWeapon *w = menu.items[ i ].weapon; + if ( w && w->CanBeSelected() ) + { + count++; + } + } + return count; +} + +CWeaponMenuItem *CHudWeaponSelection::GetFirstSelectableWeapon( WeaponMenu& menu ) +{ + int c = menu.items.Count(); + for ( int i = 0; i < c; i++ ) + { + C_BaseCombatWeapon *w = menu.items[ i ].weapon; + if ( w && w->CanBeSelected() ) + { + return &menu.items[ i ]; + } + } + return NULL; +} + +const char *CHudWeaponSelection::GetBuildMenuName( int slot ) +{ + switch ( slot ) + { + default: + case BUILD_OFFENSIVE: + return "Offensive Object"; + case BUILD_DEFENSIVE: + return "Defensive Object"; + case BUILD_GENERAL_PURPOSE: + return "General Purpose"; + } + + return "General Purpose"; +} + +const char *CHudWeaponSelection::GetBuildMenuMaterial( int slot ) +{ + switch ( slot ) + { + default: + case BUILD_OFFENSIVE: + return "weapon_selection_offensive"; + case BUILD_DEFENSIVE: + return "weapon_selection_defensive"; + case BUILD_GENERAL_PURPOSE: + return "weapon_selection_general"; + } + + return "hud/menu/weapon_selection_general"; +} + +//----------------------------------------------------------------------------- +// Purpose: sets up display for showing weapon pickup +//----------------------------------------------------------------------------- +void CHudWeaponSelection::OnWeaponPickup( C_BaseCombatWeapon *pWeapon ) +{ + // Nothing in TF2 +} + +//----------------------------------------------------------------------------- +// Purpose: returns true if the panel should draw +//----------------------------------------------------------------------------- +bool CHudWeaponSelection::ShouldDraw() +{ + C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + if ( !pPlayer || pPlayer->GetPlayerClass() == NULL ) + { + if ( IsInSelectionMode() ) + { + HideSelection(); + } + return false; + } + + bool bret = CBaseHudWeaponSelection::ShouldDraw(); + + if ( !bret ) + return false; + + return ( m_bSelectionVisible || ( m_flGrowFraction > 0.0f ) ) ? true : false; +} + +void CHudWeaponSelection::TranslateColor( float percent, Color& clr ) +{ + if ( percent >= 1.0f ) + return; + + if ( percent <= 0.75f ) + { + clr = Color( 0, 0, 0, 0 ); + } + else + { + float frac = ( percent - 0.75f ) / 0.25f; + + clr = Color( clr[0] * frac, + clr[1] * frac, + clr[2] * frac, + clr[3] * frac ); + } +} + +void CHudWeaponSelection::GetSlotInfo( const CWeaponMenuItem *w, C_BaseCombatWeapon *active, CSlotInfo& info ) +{ + if ( w->buildslot ) + { + info.active = !m_bInBuildMenu && ( GetActiveMenu().GetActiveItem() == w->hotkey ); + info.valid = w->isvalidmenuitem; + info.icon = gHUD.GetIcon( GetBuildMenuMaterial( w->openbuildmenu ) ); + info.drawAmmo = false; + info.ammoCaution = false; + Q_snprintf( info.printname, sizeof( info.printname ), GetBuildMenuName( w->openbuildmenu ) ); + info.weapon = NULL; + } + else if ( !w->weapon ) + { + info.active =false; + info.valid = false; + info.icon = NULL; + info.drawAmmo = false; + info.ammoCaution = false; + info.printname[0]=0; + info.weapon = NULL; + } + else + { + C_BaseCombatWeapon *pWeapon = w->weapon; + Assert( pWeapon ); + + info.active = active == pWeapon; + info.valid = pWeapon->CanBeSelected(); + info.icon = info.active ? pWeapon->GetSpriteActive() : pWeapon->GetSpriteInactive(); + + info.drawAmmo = false; + info.ammoPerc = 1.0f; + // Don't know the max ammo, so if I don't use clips, just go red on no ammo left + if ( pWeapon->UsesClipsForAmmo1() || pWeapon->HasAmmo() ) + { + info.ammoPerc = 1.0f - ( (float) pWeapon->Clip1() ) / ( (float)pWeapon->GetMaxClip1() ); + info.drawAmmo = true; + } + info.ammoCaution = ( info.ammoPerc >= CLIP_PERC_THRESHOLD ) ? true : false; + + Q_snprintf( info.printname, sizeof( info.printname ), "%s", pWeapon->GetPrintName() ); + info.weapon = pWeapon; + } + + strupr(info.printname); +} + +void CHudWeaponSelection::SetupWeaponMenu( WeaponMenu& menu, C_BaseCombatWeapon *activeItem, bool drawNumbers ) +{ + int panelPosition = 0; + for ( int item = menu.items.FirstInorder(); item != menu.items.InvalidIndex() && panelPosition < MAX_WEAPON_MENU_ITEMS; item = menu.items.NextInorder( item ) ) + { + CWeaponMenuItem *w = &menu.items[ item ]; + Assert( w ); + + CSlotInfo info; + GetSlotInfo( w, activeItem, info ); + + CHudWeaponItemPanel *panel = m_pWeaponPanels[ panelPosition++ ]; + if ( !panel ) + { + Assert( 0 ); + continue; + } + + panel->m_bInUse = true; + panel->info = info; + panel->menuItem = *w; + panel->m_bDrawNumbers = drawNumbers; + } + + for ( ; panelPosition < MAX_WEAPON_MENU_ITEMS; ) + { + CHudWeaponItemPanel *panel = m_pWeaponPanels[ panelPosition++ ]; + panel->m_bInUse = false; + } +} + +void CHudWeaponSelection::SetupBuildMenu( WeaponMenu& menu, C_BaseCombatWeapon *activeItem ) +{ + int panelPosition = 0; + for ( int item = menu.items.FirstInorder(); item != menu.items.InvalidIndex() && panelPosition < MAX_BUILD_MENU_ITEMS; item = menu.items.NextInorder( item ) ) + { + CWeaponMenuItem *w = &menu.items[ item ]; + Assert( w ); + + CSlotInfo info; + GetSlotInfo( w, activeItem, info ); + + CHudWeaponItemPanel *panel = m_pBuildPanels[ panelPosition++ ]; + if ( !panel ) + { + Assert( 0 ); + continue; + } + + panel->m_bInUse = true; + panel->info = info; + panel->menuItem = *w; + panel->m_bDrawNumbers = false; + } + + for ( ; panelPosition < MAX_BUILD_MENU_ITEMS; ) + { + CHudWeaponItemPanel *panel = m_pBuildPanels[ panelPosition++ ]; + panel->m_bInUse = false; + } +} + +void CHudWeaponSelection::OnTick() +{ + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + RebuildMenus(); + + int x, y; + GetPos(x, y); + + C_BaseCombatWeapon *wpn = GetSelectedWeapon(); + + // Draw main menu + SetupWeaponMenu( m_Weapons, wpn, true ); + + CWeaponMenuItem *item = FindWeapon( GetActiveMenu(), GetActiveMenu().GetActiveItem() ); + + WeaponMenu* otherMenu = NULL; + int buildMenuNumber= 0; + + // Drawing build menu + if ( m_bInBuildMenu ) + { + otherMenu = &m_BuildObjects[ m_nActiveBuildMenu ]; + buildMenuNumber = m_nActiveBuildMenu; + } + else if ( item && item->buildslot && item->hotkey == GetActiveMenu().GetActiveItem() ) + { + otherMenu = &m_BuildObjects[ item->openbuildmenu ]; + buildMenuNumber = item->openbuildmenu; + } + else if ( m_nActiveBuildMenu >= 0 ) + { + otherMenu = &m_BuildObjects[ m_nActiveBuildMenu ]; + buildMenuNumber = m_nActiveBuildMenu; + } + + if ( otherMenu ) + { + SetupBuildMenu( *otherMenu, wpn ); + } + else + { + ClearBuildMenu(); + } + + if ( otherMenu != m_PreviousBuildMenu ) + { + m_PreviousBuildMenu = otherMenu; + + if ( otherMenu ) + { + switch ( buildMenuNumber ) + { + default: + case BUILD_OFFENSIVE: + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponOpenBuildOffensive"); + break; + case BUILD_DEFENSIVE: + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponOpenBuildDefensive"); + break; + case BUILD_GENERAL_PURPOSE: + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponOpenBuildGeneral"); + break; + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: hud scheme settings +//----------------------------------------------------------------------------- +void CHudWeaponSelection::ApplySchemeSettings(vgui::IScheme *pScheme) +{ + BaseClass::ApplySchemeSettings(pScheme); + SetPaintBackgroundEnabled(false); +} + +//----------------------------------------------------------------------------- +// Purpose: Select the next item in the weapon list +//----------------------------------------------------------------------------- +void CHudWeaponSelection::CycleToNextWeapon( void ) +{ + // Get the local player. + C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + if ( !pPlayer || !pPlayer->GetPlayerClass() ) + return; + + // Make it active + bool justopened = false; + if ( !IsInSelectionMode() ) + { + OpenSelection(); + justopened = true; + } + + RebuildMenus(); + + WeaponMenu& menu = GetActiveMenu(); + int c = menu.items.Count(); + if ( c != 0 && !justopened ) + { + GetActiveMenu().SetActiveItem( FindNextSelectableWeaponInMenu( menu, GetActiveMenu().GetActiveItem(), +1 ) ); + } + + // Play the "cycle to next weapon" sound + pPlayer->EmitSound( "Player.WeaponSelectionMoveSlot" ); +} + +//----------------------------------------------------------------------------- +// Purpose: Selects the previous item in the menu +//----------------------------------------------------------------------------- +void CHudWeaponSelection::CycleToPrevWeapon( void ) +{ + C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + if ( !pPlayer || !pPlayer->GetPlayerClass() ) + return; + + // Make it active + bool justopened = false; + if ( !IsInSelectionMode() ) + { + OpenSelection(); + justopened = true; + } + + RebuildMenus(); + + WeaponMenu& menu = GetActiveMenu(); + int c = menu.items.Count(); + if ( c != 0 && !justopened ) + { + GetActiveMenu().SetActiveItem( FindNextSelectableWeaponInMenu( menu, GetActiveMenu().GetActiveItem(), -1 ) ); + } + + // Play the "cycle to next weapon" sound + pPlayer->EmitSound( "Player.WeaponSelectionMoveSlot" ); +} + +//----------------------------------------------------------------------------- +// Purpose: Switches the last weapon the player was using +//----------------------------------------------------------------------------- +void CHudWeaponSelection::SwitchToLastWeapon( void ) +{ + // Get the player's last weapon + C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + // If we're currently using the builder weapon, switch to the weapon we were + // using before we started using it. + C_BaseCombatWeapon *pActiveWeapon = pPlayer->GetActiveWeapon(); + // Handle the twohanded weapon container + CWeaponTwoHandedContainer *pContainer = dynamic_cast< CWeaponTwoHandedContainer * >( pActiveWeapon ); + if ( pContainer ) + { + pActiveWeapon = pContainer->GetLeftWeapon(); + } + + if ( dynamic_cast< C_WeaponBuilder* >( pActiveWeapon ) ) + { + ::input->MakeWeaponSelection( pPlayer->GetLastWeaponBeforeObject() ); + return; + } + + // Switch to previous weapon normally + ::input->MakeWeaponSelection( pPlayer->GetLastWeapon() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CWeaponMenuItem *CHudWeaponSelection::FindWeapon( WeaponMenu& menu, int hotkey ) +{ + RebuildMenus(); + + int c = menu.items.Count(); + + for ( int i = 0; i < c; i++ ) + { + CWeaponMenuItem *item = &menu.items[ i ]; + if ( item->hotkey == hotkey ) + return item; + } + + return NULL; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_BaseCombatWeapon *CHudWeaponSelection::GetWeaponInSlot( int iSlot, int iSlotPos ) +{ + CWeaponMenuItem *item = FindWeapon( GetActiveMenu(), iSlot ); + if ( item ) + { + return item->weapon; + } + + return NULL; +} + +C_BaseCombatWeapon *CHudWeaponSelection::GetSelectedWeapon( void ) +{ + RebuildMenus(); + + return GetWeaponInSlot( GetActiveMenu().GetActiveItem(), 0 ); +} + +void CHudWeaponSelection::SelectBuildMenuSlot( WeaponMenu& buildMenu ) +{ + // Get the local player. + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + int numSelectable = CountSelectableItems( buildMenu ); + + if ( numSelectable >= 1 ) + { + // Single item, just fast switch to it + CWeaponMenuItem *fastSwitchItem = GetFirstSelectableWeapon( buildMenu ); + C_BaseCombatWeapon *w = fastSwitchItem ? fastSwitchItem->weapon : NULL; + + Assert( w && w->CanBeSelected() ); + if ( 0 && numSelectable == 1 && w && w->CanBeSelected() ) + { + ShowBuildMenu( buildMenu ); + + m_hSelectedWeapon = w; + GetActiveMenu().SetActiveItem( fastSwitchItem->hotkey ); + + // There's only one active item in bucket, so change directly to weapon + SetWeaponSelected(); + engine->ClientCmd( "cancelselect\n" ); + } + else + { + // Play the "open weapon selection" sound + pPlayer->EmitSound( "Player.WeaponSelectionOpen" ); + + ShowBuildMenu( buildMenu ); + } + } + else + { + pPlayer->EmitSound( "Player.DenyWeaponSelection" ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Weapon selection code +//----------------------------------------------------------------------------- +void CHudWeaponSelection::SelectWeaponSlot( int iSlot ) +{ + // Get the local player. + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + // Make sure the player's allowed to switch weapons + if ( pPlayer->IsAllowedToSwitchWeapons() == false ) + return; + + // Make it active + if ( !IsInSelectionMode() ) + { + OpenSelection(); + } + + RebuildMenus(); + CWeaponMenuItem *item = FindWeapon( GetActiveMenu(), iSlot ); + + C_BaseCombatWeapon *weapon = item ? item->weapon : NULL; + + if ( item && item->buildslot ) + { + SelectBuildMenuSlot( m_BuildObjects[ item->openbuildmenu ] ); + return; + } + + if ( m_bInBuildMenu ) + { + CWeaponMenuItem *mainItem = FindWeapon( m_Weapons, iSlot ); + if ( mainItem ) + { + if ( mainItem->buildslot ) + { + if ( mainItem->openbuildmenu == m_nActiveBuildMenu ) + { + CycleToNextWeapon(); + } + else + { + SelectBuildMenuSlot( m_BuildObjects[ mainItem->openbuildmenu ] ); + } + } + else if ( mainItem->weapon ) + { + // Play the "open weapon selection" sound + pPlayer->EmitSound( "Player.WeaponSelectionOpen" ); + + m_bInBuildMenu = false; + m_hSelectedWeapon = mainItem->weapon; + GetActiveMenu().SetActiveItem( mainItem->hotkey ); + + // Check for fast weapon switch mode + if ( GetSelectedWeapon() && GetSelectedWeapon()->CanBeSelected() ) + { + // There's only one active item in bucket, so change directly to weapon + SetWeaponSelected(); + engine->ClientCmd( "cancelselect\n" ); + return; + } + } + } + return; + } + + if ( item && weapon ) + { + // Play the "open weapon selection" sound + pPlayer->EmitSound( "Player.WeaponSelectionOpen" ); + + if ( !weapon->CanBeSelected() ) + { + if ( GetActiveMenu().GetActiveItem() == item->hotkey ) + { + pPlayer->EmitSound( "Player.DenyWeaponSelection" ); + } + } + + m_hSelectedWeapon = weapon; + GetActiveMenu().SetActiveItem( item->hotkey ); + + // Check for fast weapon switch mode + if ( GetSelectedWeapon() && GetSelectedWeapon()->CanBeSelected() ) + { + // There's only one active item in bucket, so change directly to weapon + SetWeaponSelected(); + engine->ClientCmd( "cancelselect\n" ); + return; + } + } + else + { + pPlayer->EmitSound( "Player.DenyWeaponSelection" ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Player has chosen to draw the currently selected weapon +//----------------------------------------------------------------------------- +void CHudWeaponSelection::SelectWeapon( void ) +{ + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + if ( !player ) + return; + + CWeaponMenuItem *item = FindWeapon( GetActiveMenu(), GetActiveMenu().GetActiveItem() ); + if ( !item ) + { + engine->ClientCmd( "cancelselect\n" ); + return; + } + + if ( item->buildslot ) + { + SelectBuildMenuSlot( m_BuildObjects[ item->openbuildmenu ] ); + return; + } + + CBaseHudWeaponSelection::SelectWeapon(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : down - +// keynum - +// *pszCurrentBinding - +//----------------------------------------------------------------------------- +int CHudWeaponSelection::KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ) +{ + if ( !down ) + return 1; + + if ( keynum != KEY_ESCAPE ) + return 1; + + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + if ( !player ) + return 1; + + if ( !IsInSelectionMode() ) + return 1; + + if ( !m_bInBuildMenu ) + { + engine->ClientCmd( "cancelselect\n" ); + return 0; + } + + // Play the "open weapon selection" sound + player->EmitSound( "Player.WeaponSelectionOpen" ); + + HideBuildMenu(); + + // Swallow the key + return 0; +} + +void CHudWeaponSelection::OpenSelection( void ) +{ + HideBuildMenu(); + m_nActiveBuildMenu = -1; + + CBaseHudWeaponSelection::OpenSelection(); + + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponOpenWeaponMenu"); +} + +void CHudWeaponSelection::HideSelection( void ) +{ + CBaseHudWeaponSelection::HideSelection(); + + if ( m_bInBuildMenu ) + { + HideBuildMenu(); + } + + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponCloseWeaponMenu"); +} + +int CHudWeaponSelection::GetTeamIndex() +{ + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if(!pPlayer) + return HUMAN_WEAPON_SELECTION; + int team = pPlayer->GetTeamNumber(); + if ( !team ) + return HUMAN_WEAPON_SELECTION; + + bool human = ( team == TEAM_HUMANS ) ? true : false; + return human ? HUMAN_WEAPON_SELECTION : ALIEN_WEAPON_SELECTION; +} + +//----------------------------------------------------------------------------- +// Purpose: serializes settings from a resource data container +//----------------------------------------------------------------------------- +void CHudWeaponSelection::ApplySettings( KeyValues *resourceData ) +{ + BaseClass::ApplySettings( resourceData ); + + // loop through all the keys, applying them wherever + for (KeyValues *controlKeys = resourceData->GetFirstSubKey(); controlKeys != NULL; controlKeys = controlKeys->GetNextKey()) + { + // Skip keys that are atomic.. + if (controlKeys->GetDataType() != KeyValues::TYPE_NONE) + continue; + + Panel *panel = FindChildByName( controlKeys->GetName() ); + if ( !panel ) + continue; + + // apply the settings + panel->ApplySettings(controlKeys); + } +} + + + + + + + + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *parent - +// *panelName - +//----------------------------------------------------------------------------- +CHudWeaponItemPanel::CHudWeaponItemPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, panelName ) +{ + m_bInUse = false; + m_bDrawNumbers = false; + m_nSlotNumber = 0; + + // Copies of data + memset( &info, 0, sizeof( info ) ); + memset( &menuItem, 0, sizeof( menuItem ) ); + + memset( m_BackgroundIcons, 0, sizeof( m_BackgroundIcons ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *scheme - +//----------------------------------------------------------------------------- +void CHudWeaponItemPanel::ApplySchemeSettings( vgui::IScheme *scheme ) +{ + BaseClass::ApplySchemeSettings( scheme ); + SetPaintBackgroundEnabled( false ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudWeaponItemPanel::Paint() +{ + if ( !m_bInUse ) + return; + + CHudWeaponSelection *selection = static_cast< CHudWeaponSelection * >( GetParent() ); + if ( !selection ) + return; + + int wide, tall; + GetSize( wide, tall ); + + float transparencyfrac = m_flGrowFraction; + + float sizefracw = m_flGrowFraction; + float sizefrach = m_flGrowFraction; + float sizefrac = m_flGrowFraction; + + bool buildMenu = m_bBuildMenu; + + bool isactive = info.active; + bool isvalid = info.valid; + + Color iconColor = selection->GetFgColor(); + Color textColor = selection->m_TextColor; + if ( isactive ) + { + if ( !isvalid ) + { + iconColor = selection->m_InvalidActiveColor; + textColor = selection->m_InvalidActiveTextColor; + } + } + else + { + if ( isvalid ) + { + iconColor = selection->m_OtherColor; + textColor = selection->m_OtherTextColor; + } + else + { + iconColor = selection->m_InvalidColor; + textColor = selection->m_InvalidTextColor; + } + } + + Color ammoColor = info.ammoCaution ? selection->m_AmmoCautionColor : selection->m_AmmoNormalColor; + + TranslateColor( transparencyfrac, iconColor ); + TranslateColor( transparencyfrac, textColor ); + TranslateColor( transparencyfrac, ammoColor ); + + // Draw box + DrawBox( buildMenu, 0, 0, wide, tall, isactive, isvalid, m_flGrowFraction * 255, m_bDrawNumbers ? menuItem.hotkey : -1 ); + + // icons use old system, drawing in screen space + int iconXPos = m_flIconXPos; + int iconYPos = m_flIconYPos; + int iconWide = m_flIconWidth; + int iconTall = m_flIconHeight; + + if ( info.icon ) + { + info.icon->DrawSelf( sizefracw * iconXPos, sizefrach * iconYPos, sizefracw * iconWide, sizefrach * iconTall, + iconColor ); + } + + surface()->DrawSetTextColor( textColor ); + HFont textFont = sizefrac < 1.0 ? selection->m_hTextFontSmall : selection->m_hTextFont; + surface()->DrawSetTextFont( textFont ); + //int slen = UTIL_ComputeStringWidth( textFont, info.printname ); + int charCount = Q_strlen( info.printname ); + + int textYPos = m_flTextYPos; + int textXPos = m_flTextXPos; + + surface()->DrawSetTextPos( sizefracw * textXPos, sizefrach * textYPos ); + for (char *pch = info.printname; charCount > 0; pch++, charCount--) + { + surface()->DrawUnicodeChar(*pch); + } + + if ( info.drawAmmo ) + { + int ammoBarX = m_flAmmoBarX; + int ammoBarWide = m_flAmmoBarWide; + + // Draw the clip ratio bar + gHUD.DrawProgressBar( + sizefracw * ammoBarX, sizefrach * iconYPos, + sizefracw * ammoBarWide, sizefrach * iconTall, info.ammoPerc, + ammoColor, CHud::HUDPB_VERTICAL ); + } + + // Let the weapon draw stuff too + if ( info.weapon ) + { + C_WeaponObjectSelection *selectionWeapon = dynamic_cast< C_WeaponObjectSelection * >( info.weapon.Get() ); + if ( selectionWeapon ) + { + OnWeaponSelectionDrawn( selection, selectionWeapon, isactive, wide, tall, textColor ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: We've just been drawn in the weapon selection +//----------------------------------------------------------------------------- +void CHudWeaponItemPanel::OnWeaponSelectionDrawn( CHudWeaponSelection *selection, C_WeaponObjectSelection *weapon, + bool bCurrentlySelected, int wide, int tall, Color& clr ) +{ + CBaseTFPlayer *pOwner = ToBaseTFPlayer( weapon->GetOwner() ); + if ( !pOwner ) + return; + + // Draw our resource cost + int fontHeight = vgui::surface()->GetFontTall( selection->m_hPriceFont ); + int iCost = CalculateObjectCost( weapon->GetSubType(), pOwner->GetNumObjects(weapon->GetSubType()), pOwner->GetTeamNumber() ); + + int x = wide - m_flPriceXEndPos; + int y = tall - m_flPriceYEndPos - fontHeight; + + char text[ 32 ]; + Q_snprintf( text, sizeof( text ), "%i", iCost ); + + // Compute pixels needed so we can right justify it + int pixels = 0; + char *pch; + for (pch = text; *pch != 0; pch++) + { + pixels += vgui::surface()->GetCharacterWidth( selection->m_hPriceFont, *pch ); + } + + vgui::surface()->DrawSetTextFont( selection->m_hPriceFont ); + vgui::surface()->DrawSetTextPos( x - pixels, y ); + vgui::surface()->DrawSetTextColor( clr ); + for ( pch = text; *pch; pch++ ) + { + vgui::surface()->DrawUnicodeChar(*pch); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : percent - +// clr - +//----------------------------------------------------------------------------- +void CHudWeaponItemPanel::TranslateColor( float percent, Color& clr ) +{ + if ( percent >= 1.0f ) + return; + + if ( percent <= 0.75f ) + { + clr = Color( 0, 0, 0, 0 ); + } + else + { + float frac = ( percent - 0.75f ) / 0.25f; + + clr = Color( clr[0] * frac, + clr[1] * frac, + clr[2] * frac, + clr[3] * frac ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: draws a selection box +//----------------------------------------------------------------------------- +void CHudWeaponItemPanel::DrawBox( bool isbuildmenu, int x, int y, int wide, int tall, bool isactive, bool isvalid, float normalizedAlpha, int number ) +{ + CHudWeaponSelection *selection = static_cast< CHudWeaponSelection * >( GetParent() ); + if ( !selection ) + { + Assert( 0 ); + return; + } + + int team = GetTeamIndex(); + + Color boxColor = Color( 255, 255, 255, 255 ); + boxColor[3] *= ( normalizedAlpha / 255.0f ); + + Color numberColor = selection->m_TextColor; + + CHudTexture *texture; + + texture = m_BackgroundIcons[ team ][ (int)IMAGE_BACKGROUND ]; + if ( texture ) + { + texture->DrawSelf( x, y, wide, tall, boxColor ); + } + + if ( isactive ) + { + if ( !isvalid ) + { + texture = m_BackgroundIcons[ team ][ (int)IMAGE_INVALID ]; + if ( texture ) + { + texture->DrawSelf( x, y, wide, tall, boxColor ); + } + + numberColor = selection->m_InvalidActiveColor; + } + else + { + texture = m_BackgroundIcons[ team ][ (int)IMAGE_CURRENT ]; + if ( texture ) + { + texture->DrawSelf( x, y, wide, tall, boxColor ); + } + + numberColor = selection->m_OtherColor; + } + } + else + { + if ( !isvalid ) + { + numberColor = selection->m_InvalidColor; + } + else + { + numberColor = selection->m_OtherColor; + } + } + + // draw the number + if (number >= 0) + { + numberColor[3] *= ( normalizedAlpha / 255.0f ); + surface()->DrawSetTextColor(numberColor); + surface()->DrawSetTextFont(selection->m_hNumberFont); + wchar_t wch = '0' + number; + surface()->DrawSetTextPos(x + m_flSelectionNumberXPos, y + m_flSelectionNumberYPos); + surface()->DrawUnicodeChar(wch); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int +//----------------------------------------------------------------------------- +int CHudWeaponItemPanel::GetTeamIndex() +{ + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if(!pPlayer) + return HUMAN_WEAPON_SELECTION; + int team = pPlayer->GetTeamNumber(); + if ( !team ) + return HUMAN_WEAPON_SELECTION; + + bool human = ( team == TEAM_HUMANS ) ? true : false; + return human ? HUMAN_WEAPON_SELECTION : ALIEN_WEAPON_SELECTION; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudWeaponItemPanel::SetupIcons() +{ + memset( m_BackgroundIcons, 0, sizeof( m_BackgroundIcons ) ); + + const char *menutypestr = m_bBuildMenu ? "build" : "selection"; + + for ( int team = 0; team < NUM_SLOT_TEAMS; team++ ) + { + const char *teamtype = team == 0 ? "human" : "alien"; + + for ( int type = 0; type < NUM_MENU_TYPES; type++ ) + { + const char *slottype = type == 0 ? "background" : type == 1 ? "current" : "invalid"; + + char sz[ 256 ]; + Q_snprintf( sz, sizeof( sz ), "%s_weapon_%s_%s_%i", + teamtype, menutypestr, slottype, m_nSlotNumber + 1 ); + + m_BackgroundIcons[ team ][ type ] = gHUD.GetIcon( sz );; + } + } +} diff --git a/game/client/tf2/infiltratorcamomaterialproxy.cpp b/game/client/tf2/infiltratorcamomaterialproxy.cpp new file mode 100644 index 0000000..9d099fe --- /dev/null +++ b/game/client/tf2/infiltratorcamomaterialproxy.cpp @@ -0,0 +1,84 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "proxyentity.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/imaterialvar.h" +#include "materialsystem/imaterialsystem.h" +#include "c_basetfplayer.h" +#include "c_tf_basecombatweapon.h" + +class CInfiltratorCamoMaterialProxy : public CEntityMaterialProxy +{ +public: + CInfiltratorCamoMaterialProxy(); + virtual ~CInfiltratorCamoMaterialProxy(); + virtual bool Init( IMaterial *pMaterial, KeyValues* pKeyValues ); + virtual void OnBind( C_BaseEntity *pC_BaseEntity ); + +private: + IMaterialVar *m_CamoVar; +}; + +CInfiltratorCamoMaterialProxy::CInfiltratorCamoMaterialProxy() +{ + m_CamoVar = NULL; +} + +CInfiltratorCamoMaterialProxy::~CInfiltratorCamoMaterialProxy() +{ +} + + +bool CInfiltratorCamoMaterialProxy::Init( IMaterial *pMaterial, KeyValues* pKeyValues ) +{ + bool foundVar; + + m_CamoVar = pMaterial->FindVar( "$alpha", &foundVar, false ); + if( !foundVar ) + { + m_CamoVar = NULL; + return false; + } + return true; +} + +void CInfiltratorCamoMaterialProxy::OnBind( C_BaseEntity *pEnt ) +{ + if( !m_CamoVar ) + return; + + C_BaseTFPlayer *player = dynamic_cast< C_BaseTFPlayer * >( pEnt ); + if ( player ) + { + float amount = 1 - player->ComputeCamoEffectAmount(); + m_CamoVar->SetFloatValue( amount ); + } + else + { + // Weapon model? + C_BaseTFCombatWeapon *pWeapon = dynamic_cast< C_BaseTFCombatWeapon * >( pEnt ); + if ( pWeapon ) + { + float amount = 1 - ((C_BaseTFPlayer *)pWeapon->GetOwner())->ComputeCamoEffectAmount(); + m_CamoVar->SetFloatValue( amount ); + } + else + { + C_BaseViewModel *pViewmodel = dynamic_cast< C_BaseViewModel * >( pEnt ); + if ( pViewmodel ) + { + // Get the local player's values + player = C_BaseTFPlayer::GetLocalPlayer(); + float amount = 1 - player->ComputeCamoEffectAmount(); + m_CamoVar->SetFloatValue( amount ); + } + } + } +} + +EXPOSE_INTERFACE( CInfiltratorCamoMaterialProxy, IMaterialProxy, "InfiltratorCamo" IMATERIAL_PROXY_INTERFACE_VERSION ); diff --git a/game/client/tf2/itfhintitem.h b/game/client/tf2/itfhintitem.h new file mode 100644 index 0000000..218b1f7 --- /dev/null +++ b/game/client/tf2/itfhintitem.h @@ -0,0 +1,58 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ITFHINTITEM_H +#define ITFHINTITEM_H +#ifdef _WIN32 +#pragma once +#endif + +namespace vgui +{ + class Panel; +} + +class KeyValues; + +//----------------------------------------------------------------------------- +// Purpose: All TF Hint Item Panels multiply inheret from this interface +//----------------------------------------------------------------------------- +class ITFHintItem +{ +public: + virtual void ParseItem( KeyValues *pKeyValues ) = 0; + + // Delete the hint + virtual void DeleteThis( void ) = 0; + + // Returns true if the hint criteria have been met + virtual bool GetCompleted( void ) = 0; + // Mark the hint as active + virtual void SetActive( bool active ) = 0; + // Determine if the hint is the current, active hint + virtual bool GetActive( void ) = 0; + // Allow hint to run code + virtual void Think( void ) = 0; + // Determine height of hint + virtual int GetHeight( void ) = 0; + // Set screen position of hint + virtual void SetPosition( int x, int y ) = 0; + // Tell hint where it sits in current list of hints + virtual void SetItemNumber( int index ) = 0; + // Set the hint visible/invisible + virtual void SetVisible( bool visible ) = 0; + // Change the target (Panel) of the hint + virtual void SetHintTarget( vgui::Panel *panel ) = 0; + // Return true if hint should render this frame (default returns true if GetActive() is true) + virtual bool ShouldRenderPanelEffects( void ) = 0; + // Allow item to change title text + virtual void ComputeTitle( void ) = 0; + // Allow outside influence over keyvalues + virtual void SetKeyValue( const char *key, const char *value ) = 0; +}; + +#endif // ITFHINTITEM_H diff --git a/game/client/tf2/iusesmortarpanel.h b/game/client/tf2/iusesmortarpanel.h new file mode 100644 index 0000000..3a3e23f --- /dev/null +++ b/game/client/tf2/iusesmortarpanel.h @@ -0,0 +1,69 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef IUSESMORTARPANEL_H +#define IUSESMORTARPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "hud_minimap.h" + +// Derive from this if your entity wants to use the mortar firing panel +class IUsesMortarPanel +{ +public: + // Get the data from this mortar needed by the panel + virtual void GetMortarData( float *flClientMortarYaw, bool *bAllowedToFire, float *flPower, float *flFiringPower, float *flFiringAccuracy, int *iFiringState ) = 0; + + // Tell the server the mortar's been rotated + virtual void SendYawCommand( void ) = 0; + + // Panel's overriding client yaw + virtual void ForceClientYawCountdown( float flTime ) = 0; + + // Start firing + virtual void ClickFire( void ) = 0; +}; + +// Mortar firing panel +class CMortarMinimapPanel : public CMinimapPanel +{ +public: + + DECLARE_CLASS( CMortarMinimapPanel, CMinimapPanel ); + + CMortarMinimapPanel( vgui::Panel *pParent, const char *pElementName ); + virtual ~CMortarMinimapPanel(); + + void InitMortarMinimap( C_BaseEntity *pMortar ); + C_BaseEntity *GetMortar() const; + + virtual void Paint(); + + void OnMousePressed( vgui::MouseCode code ); + void OnCursorMoved( int x, int y ); + void OnMouseReleased( vgui::MouseCode code ); + + +public: + + EHANDLE m_hMortar; + BitmapImage m_MortarButtonUp; + BitmapImage m_MortarButtonDown; + BitmapImage m_MortarButtonCantFire; + BitmapImage m_MortarDirectionImage; + + bool m_bMouseDown; + bool m_bFireButtonDown; + int m_LastX, m_LastY; + + // The red-black fade material for the slider. + int m_nTextureId; + int m_nTextureId_CantFire; +}; + +#endif // IUSESMORTARPANEL_H diff --git a/game/client/tf2/mapdata.cpp b/game/client/tf2/mapdata.cpp new file mode 100644 index 0000000..cc1c3c5 --- /dev/null +++ b/game/client/tf2/mapdata.cpp @@ -0,0 +1,372 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "mapdata.h" +#include "hud.h" +#include "hud_macros.h" +#include <KeyValues.h> +#include "playeroverlay.h" +#include "iclientmode.h" +#include "hud_technologytreedoc.h" +#include "C_World.h" +#include "c_basetfplayer.h" +#include "c_team.h" +#include "c_tfteam.h" +#include "c_func_resource.h" +#include "vgui_bitmapimage.h" +#include "C_Shield.h" +#include "c_obj_respawn_station.h" + +bool IsEntityVisibleToTactical( int iLocalTeamNumber, int iLocalTeamPlayers, + int iLocalTeamObjects, int iEntIndex, const char *pEntName, int pEntTeamNumber, const Vector &pEntOrigin ); + +// All of the parsing occurs mapdata_parse.cpp +bool ParseMinimapData( const char *filename, MinimapData_t *pMinimap, CMapZones *pZones, CMapTeamColors *pTeamColors, KeyValues *pKV ); + + +//----------------------------------------------------------------------------- +// Gets at the singleton map data +//----------------------------------------------------------------------------- + +static CMapData g_MapData; +CMapData& MapData() +{ + // Singleton object + return g_MapData; +} + +IMapData *g_pMapData = &g_MapData; + +DECLARE_COMMAND( g_MapData, ForceMapReload ); + +//----------------------------------------------------------------------------- +// Purpose: This is a total hack, but should allow reloading the mapfile.txt stuff on the fly +//----------------------------------------------------------------------------- +void CMapData::UserCmd_ForceMapReload( void ) +{ + if ( m_szMap[0] ) + { + LevelInit( m_szMap ); + // Force other data to reinit itself + GetTechnologyTreeDoc().Init(); + + // Force any needed viewport fixups + g_pClientMode->Disable(); + g_pClientMode->Enable(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CMapData::CMapData( void ) +{ + m_szMap[0]=0; + + int i, j; + m_Minimap.m_szBackgroundMaterial[0] = 0; + + for ( i = 0; i < MAX_ZONES; i++ ) + { + m_Zones[ i ].m_pZoneImage = NULL; + m_Zones[ i ].m_nControllingTeam = -1; + } + + for ( i = 0; i < MAX_PLAYERS; i++ ) + { + m_Players[ i ].m_pImage = NULL; + m_Players[ i ].m_nTeam = 0; + m_Players[ i ].m_bSelected = false; + m_Players[ i ].m_nSquadNumber = 0; + + } + + for ( i = 0; i <= MAX_MAP_TEAMS; i++ ) + { + m_TeamColors[ i ].m_pImage = NULL; + + for ( j = 0; j < MAX_CLASSES; j++ ) + { + if ( m_TeamColors[ i ].m_ClassColors[ j ].m_pClassImage ) + { + m_TeamColors[ i ].m_ClassColors[ j ].m_pClassImage = NULL; + } + } + } + + UseDefaults(); +} + +HOOK_COMMAND( forcemapreload, ForceMapReload ); + +//----------------------------------------------------------------------------- +// Purpose: One time init +//----------------------------------------------------------------------------- +void CMapData::Init( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Delete all dynamic images, but leave rest of data structures +//----------------------------------------------------------------------------- +void CMapData::Clear( void ) +{ + int i, j; + + // Delete old zones... + for ( i = 0; i < MAX_ZONES; i++ ) + { + delete m_Zones[ i ].m_pZoneImage; + m_Zones[ i ].m_pZoneImage = NULL; + } + + for ( i = 0; i <= MAX_MAP_TEAMS; i++ ) + { + delete m_TeamColors[ i ].m_pImage; + m_TeamColors[ i ].m_pImage = NULL; + + for ( j = 0; j < MAX_CLASSES; j++ ) + { + delete m_TeamColors[ i ].m_ClassColors[ j ].m_pClassImage; + m_TeamColors[ i ].m_ClassColors[ j ].m_pClassImage = NULL; + } + } + + m_Minimap.m_szBackgroundMaterial[0] = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CMapData::~CMapData( void ) +{ + Clear(); +} + +//----------------------------------------------------------------------------- +// Purpose: Set a team's default colors +//----------------------------------------------------------------------------- +void CMapData::SetTeamDefaultColor( int iTeamNumber, int r, int g, int b ) +{ + m_TeamColors[ iTeamNumber ].m_clrBlip.SetColor( r,g,b, 0 ); + m_TeamColors[ iTeamNumber ].m_clrTeam.SetColor( r,g,b, 128 ); + + for ( int j = 0; j < MAX_CLASSES; j++ ) + { + m_TeamColors[ iTeamNumber ].m_ClassColors->m_clrClass.SetColor( r,g,b, 0 ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Fill in placeholder colors, etc. +//----------------------------------------------------------------------------- +void CMapData::UseDefaults( void ) +{ + // Init colors for all teams + SetTeamDefaultColor( 1, 255, 0, 0 ); + SetTeamDefaultColor( 2, 0, 0, 255 ); + SetTeamDefaultColor( 3, 0, 0, 0 ); + SetTeamDefaultColor( 4, 0, 0, 0 ); + SetTeamDefaultColor( 5, 0, 0, 0 ); + SetTeamDefaultColor( 6, 0, 0, 0 ); + SetTeamDefaultColor( 7, 0, 0, 0 ); + SetTeamDefaultColor( 8, 0, 0, 0 ); + + m_Minimap.m_szBackgroundMaterial[0] = 0; +} + + +//----------------------------------------------------------------------------- +// Get the bounding box of the world +//----------------------------------------------------------------------------- +void CMapData::GetMapBounds(Vector &mins, Vector& maxs) +{ + C_BaseEntity *ent = cl_entitylist->GetEnt( 0 ); + C_World* pWorld = dynamic_cast<C_World*>(ent); + if (pWorld) + { + VectorCopy( pWorld->m_WorldMins, mins ); + VectorCopy( pWorld->m_WorldMaxs, maxs ); + + // Backward compatability... + if ((mins.LengthSqr() == 0.0f) && (maxs.LengthSqr() == 0.0f)) + { + mins.Init( -6500, -6500, -6500 ); + maxs.Init( 6500, 6500, 6500 ); + } + } + else + { + Assert(0); + mins.Init( 0, 0, 0 ); + maxs.Init( 1, 1, 1 ); + } +} + +void CMapData::GetMapOrigin(Vector &org) +{ + Vector mins, maxs; + GetMapBounds( mins, maxs ); + VectorAdd( mins, maxs, org ); + VectorMultiply( org, 0.5, org ); +} + +void CMapData::GetMapSize(Vector &size) +{ + Vector mins, maxs; + GetMapBounds( mins, maxs ); + VectorSubtract( maxs, mins, size ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CMapData::Get3DSkyboxOrigin( Vector &vecOrigin ) +{ + // NOTE: If the player hasn't been created yet -- this doesn't work!!! + // We need to pass the data along in the map - requires a tool change. + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pPlayer ) + { + CPlayerLocalData *pLocalData = &pPlayer->m_Local; + VectorCopy( pLocalData->m_skybox3d.origin, vecOrigin ); + } + else + { + // Debugging! + Assert( 0 ); + vecOrigin.Init(); + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +float CMapData::Get3DSkyboxScale( void ) +{ + // NOTE: If the player hasn't been created yet -- this doesn't work!!! + // We need to pass the data along in the map - requires a tool change. + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pPlayer ) + { + CPlayerLocalData *pLocalData = &pPlayer->m_Local; + return pLocalData->m_skybox3d.scale; + } + else + { + // Debugging! + Assert( 0 ); + return ( 1.0f ); + } +} + +//----------------------------------------------------------------------------- +// What's my visible area? +//----------------------------------------------------------------------------- +void CMapData::SetVisibleArea( const Vector& mins, const Vector& maxs ) +{ + m_VisibleMins = mins; + m_VisibleMaxs = maxs; +} + +void CMapData::GetVisibleArea( Vector& mins, Vector& maxs ) +{ + mins = m_VisibleMins; + maxs = m_VisibleMaxs; +} + + +//----------------------------------------------------------------------------- +// Purpose: The client is about to change maps +// Input : *map - name of the new map +//----------------------------------------------------------------------------- +void CMapData::LevelInit( const char *map ) +{ + Q_strncpy( m_szMap, map, MINIMAP_STRING_SIZE ); + + // Clear leftover data + Clear(); + + // The name of the background material for the map is well-defined + Q_snprintf( m_Minimap.m_szBackgroundMaterial, MINIMAP_MATERIAL_STRING_SIZE, + "hud/minimap/%s/%s", map, map ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMapData::LevelShutdown( void ) +{ + Clear(); +} + + +//----------------------------------------------------------------------------- +// Update fog of war +//----------------------------------------------------------------------------- +void CMapData::Update( void ) +{ +} + + +//----------------------------------------------------------------------------- +// Is entity visible to tactical? +//----------------------------------------------------------------------------- +bool CMapData::IsEntityVisibleToTactical( C_BaseEntity* pEnt ) const +{ + C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + if (!pPlayer) + return false; + + // If the local player hasn't chosen a class or a team, nothing's visible + if ((pPlayer->GetClass() == TFCLASS_UNDECIDED) || (pPlayer->GetTeamNumber() == 0)) + return false; + + C_TFTeam *pTeam = (C_TFTeam *)pPlayer->GetTeam(); + if (!pTeam) + return false; + + // Local player is always visible, as long as he's chosen a class. + if (pEnt == pPlayer) + return true; + + int iNumberObjects = 0; + int iNumberPlayers = 0; + if ( pTeam ) + { + iNumberObjects = pTeam->GetNumObjects(); + iNumberPlayers = pTeam->Get_Number_Players(); + } + + int localteam = pPlayer->GetTeamNumber(); + + // If on our team, not on a team, or is a resource zone, can't be cloaked + if ( !pEnt->GetTeamNumber() || pEnt->GetTeamNumber() == localteam ) + { + return true; + } + + // NOTE: The global IsEntityVisibleToTactical returns true in situations + // where the entity would otherwise not be visible + bool bRet = ::IsEntityVisibleToTactical( localteam, iNumberPlayers, + iNumberObjects, pEnt->entindex(), pEnt->GetClassname(), pEnt->GetTeamNumber(), pEnt->GetAbsOrigin() ); + + if ( bRet ) + { + return true; + } + + // Make sure it's within a well-defined radius of the local player... + Vector2D dist; + Vector2DSubtract( pEnt->GetAbsOrigin().AsVector2D(), pPlayer->GetAbsOrigin().AsVector2D(), dist ); + + // Cloaked by this object? + if ( dist.LengthSqr() > LOCAL_PLAYER_SCANNER_RANGE * LOCAL_PLAYER_SCANNER_RANGE ) + return false; + + // On other team, and not cloaked by technician + return true; +} diff --git a/game/client/tf2/mapdata.h b/game/client/tf2/mapdata.h new file mode 100644 index 0000000..a251b9b --- /dev/null +++ b/game/client/tf2/mapdata.h @@ -0,0 +1,128 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( MAPDATA_H ) +#define MAPDATA_H +#ifdef _WIN32 +#pragma once +#endif + +#include <vgui_controls/Panel.h> +#include <vgui/IImage.h> +#include "mathlib/vector.h" +#include "mapdata_shared.h" +#include "sharedinterface.h" + +#define MAX_ZONES 32 +#define MAX_CLASSES 32 +#define MAX_MAP_TEAMS 8 +#define MINIMAP_MATERIAL_STRING_SIZE 64 +#define MINIMAP_STRING_SIZE 128 + +class Vector; +class C_BaseEntity; +class BitmapImage; + +class CMapClassColors +{ +public: + BitmapImage *m_pClassImage; + Color m_clrClass; +}; + +class CMapTeamColors +{ +public: + CMapClassColors m_ClassColors[ MAX_CLASSES ]; + + BitmapImage *m_pImage; + Color m_clrBlip; + Color m_clrTeam; +}; + +class CMapPlayers +{ +public: + int m_nTeam; + bool m_bVisible; + bool m_bSelected; + int m_nSquadNumber; + int m_nXPos, m_nYPos; + + BitmapImage *m_pImage; + Color m_clrPlayer; +}; + +class CMapZones +{ +public: + int m_nControllingTeam; + + BitmapImage *m_pZoneImage; +}; + +struct MinimapData_t +{ + char m_szBackgroundMaterial[MINIMAP_MATERIAL_STRING_SIZE]; +}; + +class CMapData : public IMapData +{ +public: + CMapData( void ); + virtual ~CMapData( void ); + + void Init( void ); + void Clear( void ); + void LevelInit( const char *map ); + void LevelShutdown( void ); + + void Update( ); + bool IsEntityVisibleToTactical( C_BaseEntity* pEnt ) const; + + void UseDefaults( void ); + void SetTeamDefaultColor( int iTeamNumber, int r, int g, int b ); + + void UserCmd_ForceMapReload( void ); + + // map dimensions + void GetMapBounds(Vector& mins, Vector& maxs); + void GetMapOrigin(Vector& org); + void GetMapSize(Vector& size); + + // 3d skybox + void Get3DSkyboxOrigin( Vector &vecOrigin ); + float Get3DSkyboxScale( void ); + + // Indicates the area currently visible in commander mode + void SetVisibleArea( const Vector& mins, const Vector& maxs ); + void GetVisibleArea( Vector& mins, Vector& maxs ); + +public: + CMapZones m_Zones[ MAX_ZONES ]; + CMapPlayers m_Players[ MAX_PLAYERS ]; + CMapTeamColors m_TeamColors[ MAX_MAP_TEAMS+1 ]; + MinimapData_t m_Minimap; + +private: + char m_szMap[ MINIMAP_STRING_SIZE ]; + + // World size + visible size in commander mode + Vector m_WorldMins; + Vector m_WorldMaxs; + Vector m_VisibleMins; + Vector m_VisibleMaxs; +}; + + +//----------------------------------------------------------------------------- +// Gets at the singleton map data +//----------------------------------------------------------------------------- +CMapData& MapData(); + + +#endif // MAPDATA_H
\ No newline at end of file diff --git a/game/client/tf2/minimap_players.cpp b/game/client/tf2/minimap_players.cpp new file mode 100644 index 0000000..dcf1cbb --- /dev/null +++ b/game/client/tf2/minimap_players.cpp @@ -0,0 +1,250 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "c_basetfplayer.h" +#include "minimap_trace.h" +#include "vgui_entityimagepanel.h" +#include <KeyValues.h> +#include "vgui_bitmapimage.h" +#include "ViewConeImage.h" +#include "VGuiMatSurface/IMatSystemSurface.h" +#include "shareddefs.h" +#include "voice_status.h" +#include "iclientvehicle.h" + +//----------------------------------------------------------------------------- +// Minimap panel representing players +//----------------------------------------------------------------------------- +class CMinimapPlayerPanel : public CMinimapTracePanel +{ + DECLARE_CLASS( CMinimapPlayerPanel, CMinimapTracePanel ); + +public: + CMinimapPlayerPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, "CMinimapPlayerPanel" ) + { + } + + virtual bool Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData ); + virtual void Paint( ); + virtual void OnTick( ); + +private: + // Parse class image data from the file + bool InitClassImages( KeyValues* pKeyValues, MinimapInitData_t* pInitData ); + + CTeamBitmapImage m_DeadImage; + CTeamBitmapImage m_AliveImage; + CTeamBitmapImage m_LocalAliveImage; + CTeamBitmapImage m_ArrowImage; + CTeamBitmapImage m_pClassAliveImages[TFCLASS_CLASS_COUNT]; + BitmapImage m_VoiceImage; + bool m_bHasClassImage[TFCLASS_CLASS_COUNT]; + int m_LocalOffsetX, m_LocalOffsetY; + int m_LocalSizeX, m_LocalSizeY; + int m_VoiceOffsetX, m_VoiceOffsetY; + int m_VoiceSizeX, m_VoiceSizeY; + float m_flVoiceAlpha; +}; + +DECLARE_MINIMAP_FACTORY( CMinimapPlayerPanel, "minimap_player_panel" ); + + +//----------------------------------------------------------------------------- +// Parse class image data from the file +//----------------------------------------------------------------------------- +bool CMinimapPlayerPanel::InitClassImages( KeyValues* pKeyValues, MinimapInitData_t* pInitData ) +{ + memset( m_bHasClassImage, 0, TFCLASS_CLASS_COUNT * sizeof(bool) ); + + for (int i = 1; i < TFCLASS_CLASS_COUNT; ++i) + { + KeyValues *pClassSection = pKeyValues->FindKey( GetTFClassInfo(i)->m_pClassName ); + if (!pClassSection) + continue; + + m_bHasClassImage[i] = true; + if (!InitializeTeamImage( pKeyValues, GetTFClassInfo( i )->m_pClassName, this, pInitData->m_pEntity, &m_pClassAliveImages[i] )) + return false; + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Parse data from the file +//----------------------------------------------------------------------------- +bool CMinimapPlayerPanel::Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData ) +{ + // Must be applied to players + Assert( dynamic_cast< C_BaseTFPlayer * >( pInitData->m_pEntity ) ); + + if (!BaseClass::Init( pKeyValues, pInitData )) + return false; + + if (!InitializeTeamImage( pKeyValues, "localaliveimage", this, pInitData->m_pEntity, &m_LocalAliveImage)) + return false; + + if (!InitializeTeamImage( pKeyValues, "aliveimage", this, pInitData->m_pEntity, &m_AliveImage )) + return false; + + if (!InitializeTeamImage( pKeyValues, "arrowimage", this, pInitData->m_pEntity, &m_ArrowImage )) + return false; + + if (!InitializeTeamImage( pKeyValues, "deadimage", this, pInitData->m_pEntity, &m_DeadImage )) + return false; + + if (!InitializeImage( pKeyValues, "voiceimage", this, &m_VoiceImage )) + return false; + + // Load class-specific images + if (!InitClassImages( pKeyValues, pInitData ) ) + return false; + + // Modify the size if this is the local player + if (!ParseCoord(pKeyValues, "localplayeroffset", m_LocalOffsetX, m_LocalOffsetY)) + return false; + + if (!ParseCoord(pKeyValues, "localplayersize", m_LocalSizeX, m_LocalSizeY )) + return false; + + if (!ParseCoord(pKeyValues, "voiceoffset", m_VoiceOffsetX, m_VoiceOffsetY )) + return false; + + if (!ParseCoord(pKeyValues, "voicesize", m_VoiceSizeX, m_VoiceSizeY )) + return false; + + m_flVoiceAlpha = 0.0f; + SetCursor( NULL ); + + return true; +} + + +//----------------------------------------------------------------------------- +// Render +//----------------------------------------------------------------------------- +void CMinimapPlayerPanel::OnTick( ) +{ + // Modify position and size if we're the local player + // It's too bad, but we can't do this during Init() because + // C_BaseTFPlayer::GetLocalPlayer() doesn't return the correct value at that time + if ( C_BaseTFPlayer::GetLocalPlayer() == GetEntity() ) + { + m_OffsetX = m_LocalOffsetX; + m_OffsetY = m_LocalOffsetY; + + m_SizeW = m_LocalSizeX; + m_SizeH = m_LocalSizeY; + + // Make sure the local player draws on top + SetZPos( MINIMAP_LOCAL_PLAYER ); + + SetSize( m_LocalSizeX, m_LocalSizeY ); + } + + BaseClass::OnTick(); +} + + +//----------------------------------------------------------------------------- +// Render +//----------------------------------------------------------------------------- +void CMinimapPlayerPanel::Paint( ) +{ + if ( gHUD.IsHidden( HIDEHUD_MISCSTATUS ) ) + return; + + C_BaseEntity* pEntity = GetEntity(); + Assert( pEntity ); + + // Don't render players if they aren't on a team + if( pEntity->GetTeamNumber() == 0 ) + return; + + C_BaseTFPlayer *local = C_BaseTFPlayer::GetLocalPlayer(); + C_BaseTFPlayer *pPlayer = static_cast< C_BaseTFPlayer * >( pEntity ); + Assert( pPlayer ); + + if (!m_bClipToMap) + g_pMatSystemSurface->DisableClipping( true ); + + // Set the fade amount (only for alive players)... +// m_AliveImage.SetAlpha( pPlayer->GetOverlayAlpha() ); +// m_LocalAliveImage.SetAlpha( pPlayer->GetOverlayAlpha() ); + + bool isLocalPlayer = ( pEntity == local ); + + bool isAlive = pPlayer->GetHealth() > 0 ? true : false; + if ( isAlive ) + { + if ( pPlayer->IsPlayerDead() ) + { + isAlive = false; + } + } + + float yaw = pPlayer->EyeAngles().y; + if ( pPlayer->InLocalTeam() && GetClientVoiceMgr()->IsPlayerSpeaking( pPlayer->entindex() ) && + GetClientVoiceMgr()->IsPlayerAudible( pPlayer->entindex() ) ) + { + m_flVoiceAlpha = 1.0f; + } + else if (m_flVoiceAlpha != 0.0f) + { + m_flVoiceAlpha *= 0.8f; + if (m_flVoiceAlpha < 0.005) + m_flVoiceAlpha = 0.0f; + } + + if ( m_flVoiceAlpha != 0.0f ) + { + int x = (int)(m_VoiceOffsetX - m_OffsetX + 0.5f); + int y = (int)(m_VoiceOffsetY - m_OffsetY + 0.5f); + + g_pMatSystemSurface->DisableClipping( true ); + m_VoiceImage.DoPaint( x, y, m_VoiceSizeX, m_VoiceSizeY, 0, m_flVoiceAlpha ); + if (m_bClipToMap) + g_pMatSystemSurface->DisableClipping( false ); + } + + // Draw dead guys with a different icon + if ( isAlive ) + { + if (isLocalPlayer) + { + m_LocalAliveImage.Paint( ); + m_ArrowImage.Paint( yaw ); + } + else + { + int nPlayerClass = pPlayer->GetClass(); + if (pPlayer->InLocalTeam() && m_bHasClassImage[nPlayerClass]) + { + m_pClassAliveImages[nPlayerClass].Paint( ); + m_ArrowImage.Paint( yaw ); + } + else + { + m_AliveImage.Paint( ); + m_ArrowImage.Paint( yaw ); + } + } + } + else + { + m_DeadImage.Paint(); + } + + g_pMatSystemSurface->DisableClipping( false ); +} + + + + diff --git a/game/client/tf2/minimap_resourcezone.cpp b/game/client/tf2/minimap_resourcezone.cpp new file mode 100644 index 0000000..56bbdc9 --- /dev/null +++ b/game/client/tf2/minimap_resourcezone.cpp @@ -0,0 +1,95 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "c_func_resource.h" +#include "vgui_bitmapimage.h" +#include <KeyValues.h> +#include "minimap_trace.h" +#include "techtree.h" +#include "shareddefs.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +class CMinimapResourceZonePanel : public CMinimapTracePanel +{ + DECLARE_CLASS( CMinimapResourceZonePanel, CMinimapTracePanel ); + +public: + CMinimapResourceZonePanel( vgui::Panel *parent, const char *panelName ); + virtual ~CMinimapResourceZonePanel(); + + virtual bool Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData ); + virtual void Paint( ); + +private: + BitmapImage *m_ppImage; +}; + +DECLARE_MINIMAP_FACTORY( CMinimapResourceZonePanel, "minimap_resource_zone_panel" ); + + +CMinimapResourceZonePanel::CMinimapResourceZonePanel( vgui::Panel *parent, const char *panelName ) +: BaseClass( parent, "CMinimapResourceZonePanel" ) +{ + m_ppImage = NULL; +} + +CMinimapResourceZonePanel::~CMinimapResourceZonePanel() +{ + if ( m_ppImage ) + { + delete m_ppImage; + m_ppImage = NULL; + } +} + +bool CMinimapResourceZonePanel::Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData ) +{ + // Can only be applied to resource zones... + C_ResourceZone* pResource = dynamic_cast<C_ResourceZone*>( pInitData->m_pEntity ); + if (!pResource) + return false; + + if (!BaseClass::Init(pKeyValues, pInitData)) + return false; + + // Read in the images for the resource zone... + // Default to null + m_ppImage = NULL; + + char const* pMaterialName = pKeyValues->GetString( "material" ); + if ( !pMaterialName || !pMaterialName[ 0 ] ) + return false; + + // modulation color + Color color; + if (!ParseRGBA( pKeyValues, "color", color )) + color.SetColor( 255, 255, 255, 255 ); + + // hook in the bitmap + m_ppImage = new BitmapImage( GetVPanel(), pMaterialName ); + m_ppImage->SetColor( color ); + + return true; +} + +void CMinimapResourceZonePanel::Paint( ) +{ + if ( gHUD.IsHidden( HIDEHUD_MISCSTATUS ) ) + return; + + // Paint the image for the zone type + if ( m_ppImage ) + { + m_ppImage->Paint(); + } +} + + + diff --git a/game/client/tf2/minimap_trace.cpp b/game/client/tf2/minimap_trace.cpp new file mode 100644 index 0000000..c75afa3 --- /dev/null +++ b/game/client/tf2/minimap_trace.cpp @@ -0,0 +1,323 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "minimap_trace.h" +#include "c_basetfplayer.h" +#include "mapdata.h" +#include "model_types.h" +#include "clientmode_tfnormal.h" +#include <vgui/IVGui.h> +#include "vgui_bitmapimage.h" +#include <KeyValues.h> +#include "VGuiMatSurface/IMatSystemSurface.h" +#include "shareddefs.h" +#include "engine/ivmodelinfo.h" + +//----------------------------------------------------------------------------- +// Constructor, destructor +//----------------------------------------------------------------------------- +CMinimapTracePanel::CMinimapTracePanel( vgui::Panel *parent, const char *panelName) + : BaseClass( parent, "CMinimapTracePanel" ) +{ + m_pEntity = NULL; + SetPaintBackgroundEnabled( false ); + m_bCanScale = true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CMinimapTracePanel::~CMinimapTracePanel() +{ +} + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- +bool CMinimapTracePanel::Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData ) +{ + // NOTE: Can't use a EHANDLE here because the EHANDLE for pEntity is set up + // when AddEntity is called; this gets called before that happens + m_pEntity = pInitData->m_pEntity; + m_vecPosition = pInitData->m_vecPosition; + + int w, h; + if (!ParseCoord(pKeyValues, "offset", m_OffsetX, m_OffsetY)) + return false; + + if (!ParseCoord(pKeyValues, "size", w, h )) + return false; + + // Lifetime of the minimap trace + float flLifeTime = pKeyValues->GetFloat("lifetime", -1.0f); + if (flLifeTime > 0.0f) + m_flDeletionTime = gpGlobals->curtime + flLifeTime; + else + m_flDeletionTime = -1.0f; + + // Optional parameters + m_bVisibleWhenZoomedIn = (pKeyValues->GetInt( "detail", 0 ) == 0 ); + m_bClampToMap = (pKeyValues->GetInt( "clamp", 0 ) != 0); + m_bClipToMap = (pKeyValues->GetInt( "noclip", 0 ) == 0); + m_bCanScale = (pKeyValues->GetInt( "noscale", 0 ) == 0); + m_bVisible = true; + + m_SizeW = w; + m_SizeH = h; + + SetSize( w, h ); + + return true; +} + + +//----------------------------------------------------------------------------- +// Entity accessor +//----------------------------------------------------------------------------- +C_BaseEntity* CMinimapTracePanel::GetEntity() +{ + return m_pEntity; +} + +void CMinimapTracePanel::SetEntity( C_BaseEntity* pEntity ) +{ + m_pEntity = pEntity; +} + +//----------------------------------------------------------------------------- +// Sets the position of the trace in world space +//----------------------------------------------------------------------------- +void CMinimapTracePanel::SetPosition( const Vector &vecPosition ) +{ + m_vecPosition = vecPosition; +} + + +//----------------------------------------------------------------------------- +// Computes the entity position +//----------------------------------------------------------------------------- +bool CMinimapTracePanel::GetEntityPosition( float &x, float &y ) +{ + C_BaseEntity *pEntity = GetEntity(); + + Vector pos; + if (!pEntity) + { + pos = m_vecPosition; + } + else + { + if (pEntity == C_BaseTFPlayer::GetLocalPlayer()) + { + // Use the predicted position... + pos = pEntity->GetAbsOrigin(); + } + else if ( !pEntity->GetModel() || modelinfo->GetModelType( pEntity->GetModel() ) != mod_brush ) + { + // If it's not a brush model, use the origin + pos = pEntity->GetRenderOrigin(); + } + else + { + Vector mins, maxs; + pEntity->GetRenderBounds( mins, maxs ); + pos = (mins + maxs) * 0.5f; + } + + // Position is an offset when there's an entity + pos += m_vecPosition; + } + + return CMinimapPanel::MinimapPanel()->WorldToMinimap( m_bClampToMap ? MINIMAP_CLIP : MINIMAP_NOCLIP, pos, x, y ); +} + + +//----------------------------------------------------------------------------- +// Causes the minimap panel to not be visible +//----------------------------------------------------------------------------- +void CMinimapTracePanel::SetTraceVisibility( bool bVisible ) +{ + m_bVisible = bVisible; +} + + +//----------------------------------------------------------------------------- +// Call this before rendering to see if the entity should be rendered +// and to get the rendering position +//----------------------------------------------------------------------------- +bool CMinimapTracePanel::ComputeVisibility( ) +{ + if (!m_bVisible) + return false; + + C_BaseEntity* pEntity = GetEntity(); + + // No entity? We must be a positional trace + if (!pEntity) + return true; + + // Don't draw if it's not in the PVS + if ( pEntity->IsDormant() ) + return false; + + // Check visible to tactical + if( !MapData().IsEntityVisibleToTactical(pEntity) ) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// called when we're ticked... +//----------------------------------------------------------------------------- +void CMinimapTracePanel::OnTick() +{ + // Don't do anything when not in a game + if ( !engine->IsInGame() ) + { + SetVisible( false ); + return; + } + + // Update our current position + float sx, sy; + bool onMap = GetEntityPosition( sx, sy ); + + int ofsx, ofsy; + ofsx = m_OffsetX; + ofsy = m_OffsetY; + + if ( m_bCanScale ) + { + int w, h; + GetSize( w, h ); + + float scale = CMinimapPanel::MinimapPanel()->GetTrueZoom(); + if ( 1 || scale != 1.0f ) + { + ofsx *= scale; + ofsy *= scale; + + int sizew = m_SizeW * scale; + int sizeh = m_SizeH * scale; + + SetPos( (int)(sx + ofsx + 0.5f), (int)(sy + ofsy + 0.5f)); + SetSize( sizew, sizeh ); + } + else + { + SetPos( (int)(sx + ofsx + 0.5f), (int)(sy + ofsy + 0.5f)); + } + } + else + { + SetPos( (int)(sx + ofsx + 0.5f), (int)(sy + ofsy + 0.5f)); + } + + // Update our visibility + if (!onMap) + SetVisible( false ); + else + SetVisible( ComputeVisibility( ) ); + + if ((m_flDeletionTime >= 0.0f) && (gpGlobals->curtime >= m_flDeletionTime)) + { + MarkForDeletion(); + } +} + + +//----------------------------------------------------------------------------- +// Computes a panel alpha based on zoom level... +//----------------------------------------------------------------------------- +float CMinimapTracePanel::ComputePanelAlpha() +{ + if (m_bVisibleWhenZoomedIn) + return 1.0f; + + int a; + if (!CMinimapPanel::MinimapPanel()) + return 0.0f; + + if (!CMinimapPanel::MinimapPanel()->ShouldDrawZoomDetails( a )) + return 0.0f; + + return a / 255.0f; +} + + +//----------------------------------------------------------------------------- +// +// A standard minimap panel that displays a bitmap +// +//----------------------------------------------------------------------------- +DECLARE_MINIMAP_FACTORY( CMinimapTraceBitmapPanel, "minimap_image_panel" ); + + +//----------------------------------------------------------------------------- +// Sets the bitmap and size +//----------------------------------------------------------------------------- +bool CMinimapTraceBitmapPanel::Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData ) +{ + if (!BaseClass::Init(pKeyValues, pInitData)) + return false; + + return m_Image.Init( GetVPanel(), pKeyValues ); +} + + +//----------------------------------------------------------------------------- +// Performs the rendering... +//----------------------------------------------------------------------------- +void CMinimapTraceBitmapPanel::Paint( ) +{ + if ( gHUD.IsHidden( HIDEHUD_MISCSTATUS ) ) + return; + + if (!m_bClipToMap) + g_pMatSystemSurface->DisableClipping( true ); + m_Image.DoPaint( GetVPanel(), 0, ComputePanelAlpha() ); + g_pMatSystemSurface->DisableClipping( false ); +} + + + +//----------------------------------------------------------------------------- +// +// A standard minimap renderable that displays a bitmap that changes when team changes +// +//----------------------------------------------------------------------------- +DECLARE_MINIMAP_FACTORY( CMinimapTraceTeamBitmapPanel, "minimap_team_image_panel" ); + + +//----------------------------------------------------------------------------- +// Sets the bitmap and size +//----------------------------------------------------------------------------- +bool CMinimapTraceTeamBitmapPanel::Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData ) +{ + if (!BaseClass::Init(pKeyValues, pInitData)) + return false; + + return m_TeamImage.Init( this, pKeyValues, pInitData->m_pEntity ); +} + + +//----------------------------------------------------------------------------- +// Performs the rendering... +//----------------------------------------------------------------------------- +void CMinimapTraceTeamBitmapPanel::Paint( ) +{ + if ( gHUD.IsHidden( HIDEHUD_MISCSTATUS ) ) + return; + + if (!m_bClipToMap) + g_pMatSystemSurface->DisableClipping( true ); + m_TeamImage.SetAlpha( ComputePanelAlpha() ); + m_TeamImage.Paint(); + g_pMatSystemSurface->DisableClipping( false ); +} diff --git a/game/client/tf2/minimap_trace.h b/game/client/tf2/minimap_trace.h new file mode 100644 index 0000000..cc644cf --- /dev/null +++ b/game/client/tf2/minimap_trace.h @@ -0,0 +1,153 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef MINIMAP_ENTITY_H +#define MINIMAP_ENTITY_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "hud_minimap.h" +#include "TeamBitmapImage.h" +#include "vgui_bitmapimage.h" +#include <vgui_controls/Panel.h> + + +// FIXME: Need to put the team color somewhere... +// Get the team color... +extern int g_TeamColor[3][3]; + + +//----------------------------------------------------------------------------- +// A base minimap panel meant to be attached to an entity. +// NOTE: paint() will never be called unless the entity is currently valid +//----------------------------------------------------------------------------- +class C_BaseEntity; + +class CMinimapTracePanel : public vgui::Panel +{ + DECLARE_CLASS_GAMEROOT( CMinimapTracePanel, vgui::Panel ); + +public: + CMinimapTracePanel( vgui::Panel *parent, const char *panelName ); + virtual ~CMinimapTracePanel(); + + bool Init( KeyValues* pKeyValues, MinimapInitData_t* pMinimapData ); + + // Causes the minimap panel to not be visible + void SetTraceVisibility( bool bVisible ); + + // called when we're ticked... + virtual void OnTick( void ); + +protected: + // Can be overridden; it's called once a frame and returns true if the + // object is visible to the minimap or not. X and Y are the position of the + // entity in minimap space + virtual bool ComputeVisibility( ); + + // Computes a panel alpha based on zoom level... + float ComputePanelAlpha(); + + // Called by derived classes before drawing to determine if the entity is visible. + // Also sets the vgui surface color based on the team. + bool BeginRender( CMinimapPanel* pPanel, float &x, float &y, int &team ) { return false; } + + // Computes the entity position in minimap panel coordinates + bool GetEntityPosition( float &x, float &y ); + + // Sets the position of the trace in world space + void SetPosition( const Vector &vecPosition ); + + // Entity accessors + C_BaseEntity* GetEntity(); + void SetEntity( C_BaseEntity* pEntity ); + +protected: + // Bitmap positional offset + int m_OffsetX; + int m_OffsetY; + + int m_SizeW; + int m_SizeH; + + // Indicates we should clip to the map + bool m_bClipToMap; + + bool m_bCanScale; + +private: + // Indicates if we're faded out when zoomed in + bool m_bVisibleWhenZoomedIn; + + // Indicates we should always draw, even if we're off the map + bool m_bClampToMap; + + // Are we invisible because the entity wants us invisible? + bool m_bVisible; + + // This is the entity to which we're attached + C_BaseEntity *m_pEntity; + + // This is the location of the panel in world space + Vector m_vecPosition; + + // lifetime of the minimap panel + float m_flDeletionTime; +}; + + +//----------------------------------------------------------------------------- +// A standard minimap panel that displays a bitmap +//----------------------------------------------------------------------------- +class CMinimapTraceBitmapPanel : public CMinimapTracePanel +{ + DECLARE_CLASS( CMinimapTraceBitmapPanel, CMinimapTracePanel ); + +public: + CMinimapTraceBitmapPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass ( parent, panelName ) + { + } + + // Sets the bitmap and size + virtual bool Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData ); + + // Performs the rendering... + virtual void Paint(); + +protected: + BitmapImage m_Image; +}; + + +//----------------------------------------------------------------------------- +// A standard minimap panel that displays a bitmap based on entity team +//----------------------------------------------------------------------------- +class CMinimapTraceTeamBitmapPanel : public CMinimapTracePanel +{ + DECLARE_CLASS( CMinimapTraceTeamBitmapPanel, CMinimapTracePanel ); + +public: + CMinimapTraceTeamBitmapPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass ( parent, panelName ) + { + } + + // Sets the bitmap and size + virtual bool Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData ); + + // Performs the rendering... + virtual void Paint(); + +protected: + CTeamBitmapImage m_TeamImage; +}; + + +#endif // MINIMAP_ENTITY_H diff --git a/game/client/tf2/overlay_orders.cpp b/game/client/tf2/overlay_orders.cpp new file mode 100644 index 0000000..ff8f830 --- /dev/null +++ b/game/client/tf2/overlay_orders.cpp @@ -0,0 +1,25 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "vgui_entityimagepanel.h" +#include "CommanderOverlay.h" + + + +class COrderStatusPanel : public CEntityImagePanel +{ + DECLARE_CLASS( COrderStatusPanel, CEntityImagePanel ); +public: + COrderStatusPanel( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, "COrderStatusPanel" ) + { + } +}; + + +DECLARE_OVERLAY_FACTORY( COrderStatusPanel, "personal_order" ); diff --git a/game/client/tf2/panel_effects.cpp b/game/client/tf2/panel_effects.cpp new file mode 100644 index 0000000..505d2d6 --- /dev/null +++ b/game/client/tf2/panel_effects.cpp @@ -0,0 +1,1094 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "hud.h" +#include "c_tf2rootpanel.h" +#include "paneleffect.h" +#include <vgui_controls/Controls.h> +#include <vgui/ISurface.h> + +#define EFFECT_FLASH_TIME 0.7f + +#define EFFECT_R 100 +#define EFFECT_G 150 +#define EFFECT_B 220 +#define EFFECT_A 255 + +#define ARROW_R 130 +#define ARROW_G 190 +#define ARROW_B 240 +#define ARROW_A 255 + +#define AXIALLINE_R 220 +#define AXIALLINE_G 220 +#define AXIALLINE_B 255 +#define AXIALLINE_A 255 + +//----------------------------------------------------------------------------- +// Purpose: Helper for drawing line segments +//----------------------------------------------------------------------------- +class CConnectingLine +{ +public: + int m_ptStart[ 2 ]; + int m_ptEnd[ 2 ]; +}; + +//----------------------------------------------------------------------------- +// Purpose: Fill in the intersection between the two rectangles. +// Input : *pRect1 - +// *pRect2 - +// *pOut - +// Output : inline bool +//----------------------------------------------------------------------------- +inline bool GetRectIntersection( wrect_t const *pRect1, wrect_t const *pRect2, wrect_t *pOut ) +{ + pOut->left = MAX( pRect1->left, pRect2->left ); + pOut->right = MIN( pRect1->right, pRect2->right ); + if( pOut->left >= pOut->right ) + return false; + + pOut->bottom = MIN( pRect1->bottom, pRect2->bottom ); + pOut->top = MAX( pRect1->top, pRect2->top ); + if( pOut->top >= pOut->bottom ) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Edge to use +//----------------------------------------------------------------------------- +typedef enum +{ + TOPCENTER = 0, + RIGHTCENTER, + BOTTOMCENTER, + LEFTCENTER +} LINEEDGE_t; + +//----------------------------------------------------------------------------- +// Purpose: +// Input : x - +// y - +// rect - +// edge - +// border - +//----------------------------------------------------------------------------- +static void GetCenterPoint( int& x, int& y, const wrect_t& rect, LINEEDGE_t edge, int border ) +{ + int xcenter; + int ycenter; + + xcenter = ( rect.left + rect.right ) / 2; + ycenter = ( rect.top + rect.bottom ) / 2; + + switch ( edge ) + { + default: + case TOPCENTER: + x = xcenter; + y = rect.top - border; + break; + case RIGHTCENTER: + x = rect.right + border; + y = ycenter; + break; + case BOTTOMCENTER: + x = xcenter; + y = rect.bottom + border; + break; + case LEFTCENTER: + x = rect.left - border; + y = ycenter; + break; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Given two rectangles, finds a direct line between the two rectangles, unless +// they overlap, in which case no line is output. +// Input : x1 - +// y1 - +// w1 - +// h1 - +// x2 - +// y2 - +// w2 - +// h2 - +// output - +//----------------------------------------------------------------------------- +static void FindConnectingLines_Straight( + int x1, int y1, int w1, int h1, + int x2, int y2, int w2, int h2, + CUtlVector< CConnectingLine >& output ) +{ + // Reset output + output.RemoveAll(); + + // If the rectangles intersect, no line needed + wrect_t r1; + r1.left = x1; + r1.top = y1; + r1.right = x1 + w1; + r1.bottom = y1 + h1; + + wrect_t r2; + r2.left = x2; + r2.top = y2; + r2.right = x2 + w2; + r2.bottom = y2 + h2; + + wrect_t dummy; + + if ( GetRectIntersection( &r1, &r2, &dummy ) ) + return; + + int center1[2]; + int center2[2]; + + center1[ 0 ] = x1 + w1/2; + center1[ 1 ] = y1 + h1/2; + + center2[ 0 ] = x2 + w2/2; + center2[ 1 ] = y2 + h2/2; + + int gaph; + int gapv; + + LINEEDGE_t edge1 = TOPCENTER; + LINEEDGE_t edge2 = BOTTOMCENTER; + + // Top + gaph = MAX( r2.left - r1.right, r1.left - r2.right ); + gapv = MAX( r1.top - r2.bottom, r2.top - r1.bottom ); + + if ( gapv > gaph ) + { + // vertical + if ( ( r1.top - r2.bottom ) > ( r2.top - r1.bottom ) ) + { + edge2 = BOTTOMCENTER; + edge1 = TOPCENTER; + } + else + { + edge2 = TOPCENTER; + edge1 = BOTTOMCENTER; + } + } + else + { + if ( ( r1.left - r2.right ) > ( r2.left - r1.right ) ) + { + // horizontal + edge2 = RIGHTCENTER; + edge1 = LEFTCENTER; + } + else + { + edge2 = LEFTCENTER; + edge1 = RIGHTCENTER; + } + } + + int pt1[ 2 ]; + int pt2[ 2 ]; + + GetCenterPoint( pt1[ 0 ], pt1[ 1 ], r1, edge1, 3 ); + GetCenterPoint( pt2[ 0 ], pt2[ 1 ], r2, edge2, 3 ); + + CConnectingLine line; + line.m_ptStart[ 0 ] = pt1[ 0 ]; + line.m_ptStart[ 1 ] = pt1[ 1 ]; + line.m_ptEnd[ 0 ] = pt2[ 0 ]; + line.m_ptEnd[ 1 ] = pt2[ 1 ]; + + output.AddToTail( line ); +} + +//----------------------------------------------------------------------------- +// Purpose: Given two non-intersecting rectangles, finds one, two or three segments +// which connect the midpoints of two of the sides of the items together with only +// axial lines. +// Input : x1 - +// y1 - +// w1 - +// h1 - +// x2 - +// y2 - +// w2 - +// h2 - +// output - +//----------------------------------------------------------------------------- +static void FindConnectingLines_Axial( + int x1, int y1, int w1, int h1, + int x2, int y2, int w2, int h2, + CUtlVector< CConnectingLine >& output ) +{ + // Reset output + output.RemoveAll(); + + // If the rectangles intersect, no line needed + wrect_t r1; + r1.left = x1; + r1.top = y1; + r1.right = x1 + w1; + r1.bottom = y1 + h1; + + wrect_t r2; + r2.left = x2; + r2.top = y2; + r2.right = x2 + w2; + r2.bottom = y2 + h2; + wrect_t dummy; + + if ( GetRectIntersection( &r1, &r2, &dummy ) ) + return; + + int center1[2]; + int center2[2]; + + center1[ 0 ] = x1 + w1/2; + center1[ 1 ] = y1 + h1/2; + + center2[ 0 ] = x2 + w2/2; + center2[ 1 ] = y2 + h2/2; + + int gaph; + int gapv; + + LINEEDGE_t edge1 = TOPCENTER; + LINEEDGE_t edge2 = BOTTOMCENTER; + + // Top + gaph = MAX( r2.left - r1.right, r1.left - r2.right ); + gapv = MAX( r1.top - r2.bottom, r2.top - r1.bottom ); + + if ( gapv > gaph ) + { + // vertical + if ( ( r1.top - r2.bottom ) > ( r2.top - r1.bottom ) ) + { + edge2 = BOTTOMCENTER; + edge1 = TOPCENTER; + } + else + { + edge2 = TOPCENTER; + edge1 = BOTTOMCENTER; + } + } + else + { + if ( ( r1.left - r2.right ) > ( r2.left - r1.right ) ) + { + // horizontal + edge2 = RIGHTCENTER; + edge1 = LEFTCENTER; + } + else + { + edge2 = LEFTCENTER; + edge1 = RIGHTCENTER; + } + } + + int pt1[ 2 ]; + int pt2[ 2 ]; + + GetCenterPoint( pt1[ 0 ], pt1[ 1 ], r1, edge1, 3 ); + GetCenterPoint( pt2[ 0 ], pt2[ 1 ], r2, edge2, 3 ); + + CConnectingLine line; + + int mid[ 2 ]; + int size1[ 2 ]; + int size2[ 2 ]; + + mid[ 0 ] = ( pt1[ 0 ] + pt2[ 0 ] ) / 2; + mid[ 1 ] = ( pt1[ 1 ] + pt2[ 1 ] ) / 2; + + size1[ 0 ] = r1.right - r1.left; + size1[ 1 ] = r1.bottom - r1.top; + + size2[ 0 ] = r2.right - r2.left; + size2[ 1 ] = r2.bottom - r2.top; + + float sizefrac = 0.25f; + + if ( edge1 == TOPCENTER || edge1 == BOTTOMCENTER ) + { + int dx = abs( mid[ 0 ] - pt1[ 0 ] ); + if ( dx < ( sizefrac * size1[ 0 ] ) && + dx < ( sizefrac * size2[ 0 ] ) ) + { + // Gap is small, just use midpoint to align both + line.m_ptStart[ 0 ] = mid[ 0 ]; + line.m_ptStart[ 1 ] = pt1[ 1 ]; + line.m_ptEnd[ 0 ] = mid[ 0 ]; + line.m_ptEnd[ 1 ] = pt2[ 1 ]; + + output.AddToTail( line ); + } + else + { + // Draw an L + line.m_ptStart[ 0 ] = pt1[ 0 ]; + line.m_ptStart[ 1 ] = pt1[ 1 ]; + line.m_ptEnd[ 0 ] = pt1[ 0 ]; + line.m_ptEnd[ 1 ] = mid[ 1 ]; + + output.AddToTail( line ); + + line.m_ptStart[ 0 ] = pt1[ 0 ]; + line.m_ptStart[ 1 ] = mid[ 1 ]; + line.m_ptEnd[ 0 ] = pt2[ 0 ]; + line.m_ptEnd[ 1 ] = mid[ 1 ]; + + output.AddToTail( line ); + + line.m_ptStart[ 0 ] = pt2[ 0 ]; + line.m_ptStart[ 1 ] = mid[ 1 ]; + line.m_ptEnd[ 0 ] = pt2[ 0 ]; + line.m_ptEnd[ 1 ] = pt2[ 1 ]; + + output.AddToTail( line ); + } + } + else + { + int dy = abs( mid[ 1 ] - pt1[ 1 ] ); + if ( dy < ( sizefrac * size1[ 1] ) && + dy < ( sizefrac * size2[ 1 ] ) ) + { + // Gap is small, just use midpoint to align both + line.m_ptStart[ 0 ] = pt1[ 0 ]; + line.m_ptStart[ 1 ] = mid[ 1 ]; + line.m_ptEnd[ 0 ] = pt2[ 0 ]; + line.m_ptEnd[ 1 ] = mid[ 1 ]; + + output.AddToTail( line ); + } + else + { + // Draw an L + line.m_ptStart[ 0 ] = pt1[ 0 ]; + line.m_ptStart[ 1 ] = pt1[ 1 ]; + line.m_ptEnd[ 0 ] = mid[ 0 ]; + line.m_ptEnd[ 1 ] = pt1[ 1 ]; + + output.AddToTail( line ); + + line.m_ptStart[ 0 ] = mid[ 0 ]; + line.m_ptStart[ 1 ] = pt1[ 1 ]; + line.m_ptEnd[ 0 ] = mid[ 0 ]; + line.m_ptEnd[ 1 ] = pt2[ 1 ]; + + output.AddToTail( line ); + + line.m_ptStart[ 0 ] = mid[ 0 ]; + line.m_ptStart[ 1 ] = pt2[ 1 ]; + line.m_ptEnd[ 0 ] = pt2[ 0 ]; + line.m_ptEnd[ 1 ] = pt2[ 1 ]; + + output.AddToTail( line ); + } + } + +} + +//----------------------------------------------------------------------------- +// Purpose: Map input panel rectangle into space of output panel and return extents in xywh +// Input : x - +// y - +// w - +// h - +// *output - +// *input - +//----------------------------------------------------------------------------- +void PanelToPanelRectangle( int& x, int& y, int& w, int& h, vgui::Panel *output, vgui::Panel *input ) +{ + input->GetSize( w, h ); + w += 2; + h += 2; + + x = y = 0; + input->LocalToScreen( x, y ); + output->ScreenToLocal( x, y ); + + x--; + y--; +} + +//----------------------------------------------------------------------------- +// Purpose: Cycle between in/2 and in centered at 3/4in +// Input : in - +// f - ranges from -1 to 1 +// Output : static int +//----------------------------------------------------------------------------- +static int EffectResampleColor( int in, float f ) +{ + int base = in / 2; + int midpoint = ( in + base ) / 2; + float range = (float)( in - midpoint ); + + int color = midpoint + (int)( f * range ); + return clamp( color, 0, 255 ); +} + +//----------------------------------------------------------------------------- +// Purpose: Border flashing effect +//----------------------------------------------------------------------------- +class CFlashBorderPanelEffect : public CPanelEffect +{ + DECLARE_CLASS( CFlashBorderPanelEffect, CPanelEffect ); +public: + + CFlashBorderPanelEffect( ITFHintItem *owner ); + virtual void doPaint( vgui::Panel *panel ); +}; + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *owner - +//----------------------------------------------------------------------------- +CFlashBorderPanelEffect::CFlashBorderPanelEffect( ITFHintItem *owner ) + : CPanelEffect( owner ) +{ + // Mark type field + SetType( FLASHBORDER ); +} + +//----------------------------------------------------------------------------- +// Purpose: Paint the effect +// Input : *panel - +//----------------------------------------------------------------------------- +void CFlashBorderPanelEffect::doPaint( vgui::Panel *panel ) +{ + vgui::Panel *p = m_hPanel; + if ( !p || !IsVisibleIncludingParent( p ) ) + return; + + int w, h; + p->GetSize( w, h ); + + // Convert top,left to local coordinates + int x = 0, y = 0; + p->LocalToScreen( x, y ); + panel->ScreenToLocal( x, y ); + + x--; + y--; + w+=2; + h+=2; + + float frac = fmod( gpGlobals->curtime, EFFECT_FLASH_TIME ); + frac *= 2 * M_PI; + frac = cos( frac ); + + int r, g, b; + + r = EffectResampleColor( m_r, frac ); + g = EffectResampleColor( m_g, frac ); + b = EffectResampleColor( m_b, frac ); + + vgui::surface()->DrawSetColor( r, g, b, m_a ); + + for ( int gap = 0; gap < 3; gap++ ) + { + vgui::surface()->DrawOutlinedRect( x - gap, y - gap, x + w + gap, y + h + gap ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Creates an arry from m_hPanel to m_hOtherPanel +//----------------------------------------------------------------------------- +class CArrowPanelEffect : public CPanelEffect +{ + DECLARE_CLASS( CArrowPanelEffect, CPanelEffect ); +public: + + CArrowPanelEffect( ITFHintItem *owner ); + + virtual void doPaint( vgui::Panel *panel ); + + void SetDrawBorder( bool drawborder ); + void SetFlashing( bool flashing ); + +protected: + void DrawArrow( int startx, int starty, int endx, int endy, int r, int g, int b, int a ); + void DrawLine( int startx, int starty, int endx, int endy, int r, int g, int b, int a ); + void ComputeBestPoint( int& px, int &py, vgui::Panel *output, vgui::Panel *from, vgui::Panel *to ); + +protected: + + bool m_bDrawBorder; + bool m_bFlashing; +}; + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *owner - +//----------------------------------------------------------------------------- +CArrowPanelEffect::CArrowPanelEffect( ITFHintItem *owner ) + : CPanelEffect( owner ) +{ + SetType( ARROW ); + + m_bDrawBorder = true; + m_bFlashing = true; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : drawborder - +//----------------------------------------------------------------------------- +void CArrowPanelEffect::SetDrawBorder( bool drawborder ) +{ + m_bDrawBorder = drawborder; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flashing - +//----------------------------------------------------------------------------- +void CArrowPanelEffect::SetFlashing( bool flashing ) +{ + m_bFlashing = flashing; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : startx - +// starty - +// endx - +// endy - +// r - +// g - +// b - +// a - +//----------------------------------------------------------------------------- +void CArrowPanelEffect::DrawArrow( int startx, int starty, int endx, int endy, int r, int g, int b, int a ) +{ + vgui::surface()->DrawSetColor( r, g, b, a ); + + // Draw an arrow + + Vector start( startx, starty, 0.0f ); + Vector end( endx, endy, 0.0f ); + + Vector delta = end - start; + + Vector right; + + right.x = delta.y; + right.y = -delta.x; + right.z = 0.0f; + + VectorNormalize( right ); + Vector base; + + float length = VectorNormalize( delta ); + + float size = MIN( length / 2.0f, 15.0f ); + + base = start + ( length - size ) * delta; + + Vector baseLeft = base + size * 0.25f * right; + Vector baseRight = base - size * 0.25f * right; + + vgui::surface()->DrawLine( end.x, end.y, baseLeft.x, baseLeft.y ); + vgui::surface()->DrawLine( end.x, end.y, baseRight.x, baseRight.y ); + + base = start + ( length - size + size * 0.3f ) * delta; + + vgui::surface()->DrawLine( base.x, base.y, baseLeft.x, baseLeft.y ); + vgui::surface()->DrawLine( base.x, base.y, baseRight.x, baseRight.y ); + + vgui::surface()->DrawLine( startx, starty, base.x, base.y ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : startx - +// starty - +// endx - +// endy - +// r - +// g - +// b - +// a - +//----------------------------------------------------------------------------- +void CArrowPanelEffect::DrawLine( int startx, int starty, int endx, int endy, int r, int g, int b, int a ) +{ + vgui::surface()->DrawSetColor( r, g, b, a ); + vgui::surface()->DrawLine( startx, starty, endx, endy ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *panel - +//----------------------------------------------------------------------------- +void CArrowPanelEffect::doPaint( vgui::Panel *panel ) +{ + vgui::Panel *from = m_hPanel; + if ( !from || !IsVisibleIncludingParent( from ) ) + return; + + int r, g, b; + // Determine flash amount + if ( m_bFlashing ) + { + float frac = fmod( gpGlobals->curtime, EFFECT_FLASH_TIME ); + frac *= 2 * M_PI; + frac = cos( frac ); + + // Resample color + + r = EffectResampleColor( m_r, frac ); + g = EffectResampleColor( m_g, frac ); + b = EffectResampleColor( m_b, frac ); + } + else + { + r = m_r; + g = m_g; + b = m_b; + } + + int startx, starty, startw, starth; + int endx, endy, endw, endh; + + PanelToPanelRectangle( startx, starty, startw, starth, panel, from ); + + if ( !GetTargetRectangle( panel, endx, endy, endw, endh ) ) + return; + + CUtlVector< CConnectingLine > lines; + + FindConnectingLines_Straight( startx, starty, startw, starth, endx, endy, endw, endh, lines ); + + int i; + + if ( m_bDrawBorder ) + { + for ( i = 0; i < lines.Size(); i++ ) + { + CConnectingLine *l = &lines[ i ]; + + // Make it thicker + int hstep = 0; + int vstep = 0; + + if ( abs( l->m_ptEnd[ 1 ] - l->m_ptStart[ 1 ] ) > abs( l->m_ptEnd[ 0 ] - l->m_ptStart[ 0 ] ) ) + { + // Taller so draw horizontally + hstep = 1; + } + else + { + vstep = 1; + } + + // Draw a black border + for ( int x = -1; x <= 1 + hstep; x ++ ) + { + for ( int y = -1; y <= 1 + vstep; y ++ ) + { + if ( !x && !y ) + continue; + + if ( i == lines.Size() - 1 ) + { + DrawArrow( l->m_ptStart[ 0 ] + x, l->m_ptStart[1] + y, l->m_ptEnd[0] + x, l->m_ptEnd[1] + y, 0, 0, 0, m_a ); + } + else + { + DrawLine( l->m_ptStart[ 0 ] + x, l->m_ptStart[1] + y, l->m_ptEnd[0] + x, l->m_ptEnd[1] + y, 0, 0, 0, m_a ); + } + } + } + } + } + + for ( i = 0; i < lines.Size(); i++ ) + { + CConnectingLine *l = &lines[ i ]; + + // Make it thicker + int hstep = 0; + int vstep = 0; + + if ( abs( l->m_ptEnd[ 1 ] - l->m_ptStart[ 1 ] ) > abs( l->m_ptEnd[ 0 ] - l->m_ptStart[ 0 ] ) ) + { + // Taller so draw horizontally + hstep = 1; + } + else + { + vstep = 1; + } + + if ( i == lines.Size() - 1 ) + { + // Draw arrow + DrawArrow( l->m_ptStart[ 0 ], l->m_ptStart[ 1 ], l->m_ptEnd[ 0 ], l->m_ptEnd[ 1 ], r, g, b, m_a ); + // Draw a second time, but thicker + DrawArrow( l->m_ptStart[ 0 ] + hstep, l->m_ptStart[ 1 ] + vstep, l->m_ptEnd[ 0 ] + hstep, l->m_ptEnd[ 1 ] + vstep, r, g, b, m_a ); + } + else + { + // Draw arrow + DrawLine( l->m_ptStart[ 0 ], l->m_ptStart[ 1 ], l->m_ptEnd[ 0 ], l->m_ptEnd[ 1 ], r, g, b, m_a ); + // Draw a second time, but thicker + DrawLine( l->m_ptStart[ 0 ] + hstep, l->m_ptStart[ 1 ] + vstep, l->m_ptEnd[ 0 ] + hstep, l->m_ptEnd[ 1 ] + vstep, r, g, b, m_a ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : px - +// &py - +// *output - +// *from - +// *to - +//----------------------------------------------------------------------------- +void CArrowPanelEffect::ComputeBestPoint( int& px, int &py, vgui::Panel *output, vgui::Panel *from, vgui::Panel *to ) +{ + int fw, fh; + int tw, th; + from->GetSize( fw, fh ); + to->GetSize( tw, th ); + + // Convert top,left to local coordinates + int fx = 0, fy = 0; + int tx = 0, ty = 0; + from->LocalToScreen( fx, fy ); + output->ScreenToLocal( fx, fy ); + + to->LocalToScreen( tx, ty ); + output->ScreenToLocal( tx, ty ); + + fx--; + fy--; + tx--; + ty--; + fw+=2; + fh+=2; + tw+=2; + th+=2; + + int type = 0; + + // is to totally below from + if ( ty > ( fy + fh ) ) + { + type = 0; + } + // is to totally above from + else if ( ty + th < fy ) + { + type = 2; + } + // is to totally to the left of from + else if ( tx + tw < fx ) + { + type = 3; + } + // is to totally to the rigth of from + else if ( tx > fx + fw ) + { + type = 1; + } + else + { + type = 2; + } + + int border = 1; + + switch ( type ) + { + // unknown, just use object center point + default: + case 4: + // + px = fx + fw / 2; + py = fy + fh / 2; + break; + //bottom + case 0: + px = fx + fw / 2; + py = fy + fh + border; + break; + // right + case 1: + px = fx + fw + border; + py = fy + fh / 2; + break; + // top + case 2: + px = fx + fw / 2; + py = fy - border; + break; + // left + case 3: + px = fx - border; + py = fy + fh / 2; + break; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Creates an axial line effect between the two specified panels +//----------------------------------------------------------------------------- +class CAxialLinePanelEffect : public CArrowPanelEffect +{ +DECLARE_CLASS( CAxialLinePanelEffect, CArrowPanelEffect ); +public: + CAxialLinePanelEffect( ITFHintItem *owner ); + + virtual void doPaint( vgui::Panel *panel ); +}; + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *owner - +//----------------------------------------------------------------------------- +CAxialLinePanelEffect::CAxialLinePanelEffect( ITFHintItem *owner ) +: CArrowPanelEffect( owner ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *panel - +//----------------------------------------------------------------------------- +void CAxialLinePanelEffect::doPaint( vgui::Panel *panel ) +{ + vgui::Panel *from = m_hPanel; + if ( !from || !IsVisibleIncludingParent( from ) ) + return; + + int r, g, b; + + if ( m_bFlashing ) + { + // Determine flash amount + float frac = fmod( gpGlobals->curtime, EFFECT_FLASH_TIME ); + frac *= 2 * M_PI; + frac = cos( frac ); + + // Resample color + r = EffectResampleColor( m_r, frac ); + g = EffectResampleColor( m_g, frac ); + b = EffectResampleColor( m_b, frac ); + } + else + { + r = m_r; + g = m_g; + b = m_b; + } + + int startx, starty, startw, starth; + int endx, endy, endw, endh; + + PanelToPanelRectangle( startx, starty, startw, starth, panel, from ); + + if ( !GetTargetRectangle( panel, endx, endy, endw, endh ) ) + return; + + CUtlVector< CConnectingLine > lines; + + FindConnectingLines_Axial( startx, starty, startw, starth, endx, endy, endw, endh, lines ); + + int i; + + if ( m_bDrawBorder ) + { + for ( i = 0; i < lines.Size(); i++ ) + { + CConnectingLine *l = &lines[ i ]; + + // Draw a black border + for ( int x = -1; x <= 1; x ++ ) + { + for ( int y = -1; y <= 1; y ++ ) + { + if ( !x && !y ) + continue; + + DrawLine( l->m_ptStart[ 0 ] + x, l->m_ptStart[1] + y, l->m_ptEnd[0] + x, l->m_ptEnd[1] + y, 0, 0, 0, m_a ); + } + } + } + } + + // Draw actual lines + for ( i = 0; i < lines.Size(); i++ ) + { + CConnectingLine *l = &lines[ i ]; + DrawLine( l->m_ptStart[ 0 ], l->m_ptStart[ 1 ], l->m_ptEnd[ 0 ], l->m_ptEnd[ 1 ], r, g, b, m_a ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *owner - +// *target - +// Output : EFFECT_HANDLE +//----------------------------------------------------------------------------- +EFFECT_HANDLE CreateFlashEffect( ITFHintItem *owner, vgui::Panel *target ) +{ + if ( !g_pTF2RootPanel ) + return EFFECT_INVALID_HANDLE; + + CFlashBorderPanelEffect *e = new CFlashBorderPanelEffect( owner ); + + e->SetColor( EFFECT_R, EFFECT_G, EFFECT_B, EFFECT_A ); + // e->SetEndTime( gpGlobals->curtime + 15.0f ); + e->SetPanel( target ); + + g_pTF2RootPanel->AddEffect( e ); + + return e->GetHandle(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *owner - +// *from - +// *to - +// Output : EFFECT_HANDLE +//----------------------------------------------------------------------------- +EFFECT_HANDLE CreateArrowEffect( ITFHintItem *owner, vgui::Panel *from, vgui::Panel *to ) +{ + if ( !g_pTF2RootPanel ) + return EFFECT_INVALID_HANDLE; + + CArrowPanelEffect *e = new CArrowPanelEffect( owner ); + + e->SetColor( ARROW_R, ARROW_G, ARROW_B, ARROW_A ); + e->SetPanel( from ); + e->SetPanelOther( to ); + + g_pTF2RootPanel->AddEffect( e ); + + return e->GetHandle(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *owner - +// *from - +// *to - +// Output : EFFECT_HANDLE +//----------------------------------------------------------------------------- +EFFECT_HANDLE CreateAxialLineEffect( ITFHintItem *owner, vgui::Panel *from, vgui::Panel *to ) +{ + if ( !g_pTF2RootPanel ) + return EFFECT_INVALID_HANDLE; + + CAxialLinePanelEffect *e = new CAxialLinePanelEffect( owner ); + + e->SetColor( AXIALLINE_R, AXIALLINE_G, AXIALLINE_B, AXIALLINE_A ); + e->SetPanel( from ); + e->SetPanelOther( to ); + + e->SetFlashing( false ); + e->SetDrawBorder( false ); + + g_pTF2RootPanel->AddEffect( e ); + + return e->GetHandle(); +} + +EFFECT_HANDLE CreateArrowEffectToPoint( ITFHintItem *owner, vgui::Panel *from, int x, int y ) +{ + if ( !g_pTF2RootPanel ) + return EFFECT_INVALID_HANDLE; + + CArrowPanelEffect *e = new CArrowPanelEffect( owner ); + + e->SetColor( ARROW_R, ARROW_G, ARROW_B, ARROW_A ); + e->SetPanel( from ); + e->SetTargetPoint( x, y ); + + g_pTF2RootPanel->AddEffect( e ); + + return e->GetHandle(); +} + +EFFECT_HANDLE CreateAxialLineEffectToPoint( ITFHintItem *owner, vgui::Panel *from, int x, int y ) +{ + if ( !g_pTF2RootPanel ) + return EFFECT_INVALID_HANDLE; + + CAxialLinePanelEffect *e = new CAxialLinePanelEffect( owner ); + + e->SetColor( AXIALLINE_R, AXIALLINE_G, AXIALLINE_B, AXIALLINE_A ); + e->SetPanel( from ); + e->SetTargetPoint( x, y ); + + e->SetFlashing( false ); + e->SetDrawBorder( false ); + + g_pTF2RootPanel->AddEffect( e ); + + return e->GetHandle(); +} + +EFFECT_HANDLE CreateArrowEffectToRect( ITFHintItem *owner, vgui::Panel *from, int x, int y, int w, int h ) +{ + if ( !g_pTF2RootPanel ) + return EFFECT_INVALID_HANDLE; + + CArrowPanelEffect *e = new CArrowPanelEffect( owner ); + + e->SetColor( ARROW_R, ARROW_G, ARROW_B, ARROW_A ); + e->SetPanel( from ); + e->SetTargetRect( x, y, w, h ); + + g_pTF2RootPanel->AddEffect( e ); + + return e->GetHandle(); +} + +EFFECT_HANDLE CreateAxialLineEffectToRect( ITFHintItem *owner, vgui::Panel *from, int x, int y, int w, int h ) +{ + if ( !g_pTF2RootPanel ) + return EFFECT_INVALID_HANDLE; + + CAxialLinePanelEffect *e = new CAxialLinePanelEffect( owner ); + + e->SetColor( AXIALLINE_R, AXIALLINE_G, AXIALLINE_B, AXIALLINE_A ); + e->SetPanel( from ); + e->SetTargetRect( x, y, w, h ); + + e->SetFlashing( false ); + e->SetDrawBorder( false ); + + g_pTF2RootPanel->AddEffect( e ); + + return e->GetHandle(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *owner - +//----------------------------------------------------------------------------- +void DestroyPanelEffects( ITFHintItem *owner ) +{ + if ( !g_pTF2RootPanel ) + return; + + g_pTF2RootPanel->DestroyPanelEffects( owner ); +}
\ No newline at end of file diff --git a/game/client/tf2/paneleffect.cpp b/game/client/tf2/paneleffect.cpp new file mode 100644 index 0000000..8db00b1 --- /dev/null +++ b/game/client/tf2/paneleffect.cpp @@ -0,0 +1,414 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "PanelEffect.h" +#include "vgui_int.h" +#include <vgui_controls/Panel.h> +#include <vgui/IPanel.h> + +void PanelToPanelRectangle( int& x, int& y, int& w, int& h, vgui::Panel *output, vgui::Panel *input ); + +// Global panel counter for effects +EFFECT_HANDLE CPanelEffect::m_nHandleCount = 0; + +//----------------------------------------------------------------------------- +// Purpose: Base panel effect +// Input : *owner - +//----------------------------------------------------------------------------- +CPanelEffect::CPanelEffect( ITFHintItem *owner ) + : m_pOwner( owner ) +{ + // Assign it a unique handle index + m_Handle = ++m_nHandleCount; + + SetType( UNKNOWN ); + SetPanel( NULL ); + SetPanelOther( NULL ); + SetColor( 0, 0, 0, 255 ); + SetEndTime( 0.0f ); + SetShouldRemove( false ); + SetUsingOffset( false, 0, 0 ); + SetTargetType( ENDPOINT_UNKNOWN ); + SetVisible( true ); + + m_ptX = 0; + m_ptY = 0; + m_rectX = 0; + m_rectY = 0; + m_rectW = 0; + m_rectH = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CPanelEffect::~CPanelEffect() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *owner - +//----------------------------------------------------------------------------- +void CPanelEffect::SetOwner( ITFHintItem *owner ) +{ + m_pOwner = owner; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : ITFHintItem +//----------------------------------------------------------------------------- +ITFHintItem *CPanelEffect::GetOwner( void ) +{ + return m_pOwner; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : EFFECT_HANDLE +//----------------------------------------------------------------------------- +EFFECT_HANDLE CPanelEffect::GetHandle( void ) +{ + return m_Handle; +} + +//----------------------------------------------------------------------------- +// Purpose: Override for specific painting effects +// Input : *panel - +//----------------------------------------------------------------------------- +void CPanelEffect::doPaint( vgui::Panel *panel ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Default think checks for panels that have a specific lifetime +//----------------------------------------------------------------------------- +void CPanelEffect::Think( void ) +{ + if ( !m_flEndTime ) + return; + + if ( gpGlobals->curtime > m_flEndTime ) + { + SetShouldRemove( true ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CPanelEffect::ShouldRemove( void ) +{ + return m_bShouldRemove; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : remove - +//----------------------------------------------------------------------------- +void CPanelEffect::SetShouldRemove( bool remove ) +{ + m_bShouldRemove = remove; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : type - +//----------------------------------------------------------------------------- +void CPanelEffect::SetType( int type ) +{ + m_nType = type; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int +//----------------------------------------------------------------------------- +int CPanelEffect::GetType( void ) +{ + return m_nType; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *panel - +//----------------------------------------------------------------------------- +void CPanelEffect::SetPanel( vgui::Panel *panel ) +{ + m_hPanel = panel; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : vgui::Panel +//----------------------------------------------------------------------------- +vgui::Panel *CPanelEffect::GetPanel( void ) +{ + return m_hPanel; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *panel - +//----------------------------------------------------------------------------- +void CPanelEffect::SetPanelOther( vgui::Panel *panel ) +{ + SetTargetType( ENDPOINT_PANEL ); + m_hOtherPanel = panel; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : vgui::Panel +//----------------------------------------------------------------------------- +vgui::Panel *CPanelEffect::GetPanelOther( void ) +{ + return m_hOtherPanel; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : r - +// g - +// b - +// a - +//----------------------------------------------------------------------------- +void CPanelEffect::SetColor( int r, int g, int b, int a ) +{ + m_r = r; + m_g = g; + m_b = b; + m_a = a; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : r - +// g - +// b - +// a - +//----------------------------------------------------------------------------- +void CPanelEffect::GetColor( int& r, int& g, int& b, int& a ) +{ + r = m_r; + g = m_g; + b = m_b; + a = m_a; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : time - +//----------------------------------------------------------------------------- +void CPanelEffect::SetEndTime( float time ) +{ + m_flEndTime = time; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : float +//----------------------------------------------------------------------------- +float CPanelEffect::GetEndTime( void ) +{ + return m_flEndTime; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : active - +// x - +// y - +//----------------------------------------------------------------------------- +void CPanelEffect::SetUsingOffset( bool active, int x, int y ) +{ + m_bEndpointIsCoordinate = active; + m_nOffset[ 0 ] = x; + m_nOffset[ 1 ] = y; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CPanelEffect::GetUsingOffset( void ) +{ + return m_bEndpointIsCoordinate; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : x - +// y - +//----------------------------------------------------------------------------- +void CPanelEffect::GetOffset( int& x, int& y ) +{ + x = m_nOffset[ 0 ]; + y = m_nOffset[ 1 ]; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns false if the panel is not visible or is the child of a not visible +// parent +// assumes panel hierarchy stops at the client .dll root panel +// If parent is some other panel, then this will return false +// Input : *panel - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CPanelEffect::IsVisibleIncludingParent( vgui::Panel *panel ) +{ + vgui::VPANEL p = panel->GetVPanel(); + while ( p ) + { + if ( !vgui::ipanel()->IsVisible(p) ) + return false; + + if ( p == VGui_GetClientDLLRootPanel() ) + { + return true; + } + + p = vgui::ipanel()->GetParent(p); + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int +//----------------------------------------------------------------------------- +int CPanelEffect::GetTargetType( void ) +{ + return m_TargetType; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : type - +//----------------------------------------------------------------------------- +void CPanelEffect::SetTargetType( int type ) +{ + m_TargetType = type; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *outpanel - +// int&x - +// int&y - +// int&w - +// int&h - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CPanelEffect::GetTargetRectangle( vgui::Panel *outpanel, int&x, int&y, int&w, int&h ) +{ + x = y = 0; + w = h = 1; + + switch ( m_TargetType ) + { + default: + return false; + break; + case ENDPOINT_PANEL: + { + vgui::Panel *to = m_hOtherPanel; + if ( !to ) + return false; + + if ( !IsVisibleIncludingParent( to ) ) + { + return false; + } + + PanelToPanelRectangle( x, y, w, h, outpanel, to ); + + // Using an offset into a panel + if ( GetUsingOffset() ) + { + int ofsx, ofsy; + + GetOffset( ofsx, ofsy ); + + x = x + ofsx-3; + w = 6; + y = y + ofsy-3; + h = 6; + } + } + break; + case ENDPOINT_RECTANGLE: + { + x = m_rectX; + y = m_rectY; + w = m_rectW; + h = m_rectH; + } + break; + case ENDPOINT_POINT: + { + x = m_ptX; + y = m_ptY; + w = 1; + h = 1; + } + break; + } + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : x - +// y - +//----------------------------------------------------------------------------- +void CPanelEffect::SetTargetPoint( int x, int y ) +{ + SetTargetType( ENDPOINT_POINT ); + m_ptX = x; + m_ptY = y; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : x - +// y - +// w - +// h - +//----------------------------------------------------------------------------- +void CPanelEffect::SetTargetRect( int x, int y, int w, int h ) +{ + SetTargetType( ENDPOINT_RECTANGLE ); + m_rectX = x; + m_rectY = y; + m_rectW = w; + m_rectH = h; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : visible - +//----------------------------------------------------------------------------- +void CPanelEffect::SetVisible( bool visible ) +{ + m_bVisible = visible; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CPanelEffect::GetVisible( void ) +{ + return m_bVisible; +} + diff --git a/game/client/tf2/paneleffect.h b/game/client/tf2/paneleffect.h new file mode 100644 index 0000000..a5860a7 --- /dev/null +++ b/game/client/tf2/paneleffect.h @@ -0,0 +1,166 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PANELEFFECT_H +#define PANELEFFECT_H +#ifdef _WIN32 +#pragma once +#endif + +namespace vgui +{ + class Panel; +} + +class ITFHintItem; + +#include <vgui_controls/PHandle.h> + +// Serial under of effect, for safe lookup +typedef unsigned int EFFECT_HANDLE; +#define EFFECT_INVALID_HANDLE (EFFECT_HANDLE)(~0) +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CPanelEffect +{ +public: + DECLARE_CLASS_NOBASE( CPanelEffect ); + + enum + { + UNKNOWN = 0, + FLASHBORDER, + ARROW, + }; + + enum + { + ENDPOINT_UNKNOWN = 0, + ENDPOINT_PANEL, + ENDPOINT_POINT, + ENDPOINT_RECTANGLE, + ENDPOINT_ENTITY, + }; + + + CPanelEffect( ITFHintItem *owner ); + virtual ~CPanelEffect(); + + virtual void doPaint( vgui::Panel *panel ); + + virtual void Think( void ); + + virtual bool ShouldRemove( void ); + virtual void SetShouldRemove( bool remove ); + + virtual EFFECT_HANDLE GetHandle( void ); + + virtual void SetType( int type ); + virtual int GetType( void ); + + virtual void SetPanel( vgui::Panel *panel ); + virtual vgui::Panel *GetPanel( void ); + + virtual void SetPanelOther( vgui::Panel *panel ); + virtual vgui::Panel *GetPanelOther( void ); + + virtual void SetTargetPoint( int x, int y ); + virtual void SetTargetRect( int x, int y, int w, int h ); + + virtual void SetColor( int r, int g, int b, int a ); + virtual void GetColor( int& r, int& g, int& b, int& a ); + + virtual void SetEndTime( float time ); + virtual float GetEndTime( void ); + + virtual void SetOwner( ITFHintItem *owner ); + virtual ITFHintItem *GetOwner( void ); + + virtual void SetUsingOffset( bool active, int x, int y ); + virtual bool GetUsingOffset( void ); + virtual void GetOffset( int& x, int& y ); + + virtual int GetTargetType( void ); + virtual void SetTargetType( int type ); + virtual bool GetTargetRectangle( vgui::Panel *outpanel, int&x, int&y, int&w, int&h ); + + virtual void SetVisible( bool visible ); + virtual bool GetVisible( void ); + +private: + + static EFFECT_HANDLE m_nHandleCount; + +protected: + + virtual bool IsVisibleIncludingParent( vgui::Panel *panel ); + + EFFECT_HANDLE m_Handle; + + ITFHintItem *m_pOwner; + + // Data + + // type of effect + int m_nType; + + // effect targets + vgui::PHandle m_hPanel; + vgui::PHandle m_hOtherPanel; + + // effect color + int m_r, m_g, m_b, m_a; + + float m_flEndTime;// 0.0f for no end time + + // true if we should offset endpoint of arrow/lines into m_hOtherPanel by m_nOffset amount + bool m_bEndpointIsCoordinate; + // x, y offset into destination panel + int m_nOffset[ 2 ]; + + bool m_bShouldRemove; + + int m_TargetType; + int m_ptX; + int m_ptY; + int m_rectX; + int m_rectY; + int m_rectW; + int m_rectH; + + bool m_bVisible; +}; + +#define EFFECT_FLASH_TIME 0.7f + +#define EFFECT_R 100 +#define EFFECT_G 150 +#define EFFECT_B 220 +#define EFFECT_A 255 + +#define ARROW_R 130 +#define ARROW_G 190 +#define ARROW_B 240 +#define ARROW_A 255 + +#define AXIALLINE_R 220 +#define AXIALLINE_G 220 +#define AXIALLINE_B 255 +#define AXIALLINE_A 255 + +// Panel effect APIs +void DestroyPanelEffects( ITFHintItem *owner ); +EFFECT_HANDLE CreateFlashEffect( ITFHintItem *owner, vgui::Panel *target ); +EFFECT_HANDLE CreateArrowEffect( ITFHintItem *owner, vgui::Panel *from, vgui::Panel *to ); +EFFECT_HANDLE CreateAxialLineEffect( ITFHintItem *owner, vgui::Panel *from, vgui::Panel *to ); +EFFECT_HANDLE CreateArrowEffectToPoint( ITFHintItem *owner, vgui::Panel *from, int x, int y ); +EFFECT_HANDLE CreateAxialLineEffectToPoint( ITFHintItem *owner, vgui::Panel *from, int x, int y ); +EFFECT_HANDLE CreateArrowEffectToRect( ITFHintItem *owner, vgui::Panel *from, int x, int y, int w, int h ); +EFFECT_HANDLE CreateAxialLineEffectToRect( ITFHintItem *owner, vgui::Panel *from, int x, int y, int w, int h ); + +#endif // PANELEFFECT_H diff --git a/game/client/tf2/playerandobjectenumerator.cpp b/game/client/tf2/playerandobjectenumerator.cpp new file mode 100644 index 0000000..a037b6d --- /dev/null +++ b/game/client/tf2/playerandobjectenumerator.cpp @@ -0,0 +1,69 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "playerandobjectenumerator.h" +#include "tf_shareddefs.h" + +// Enumator class for ragdolls being affected by explosive forces +CPlayerAndObjectEnumerator::CPlayerAndObjectEnumerator( float radius ) +{ + m_flRadiusSquared = radius * radius; + m_Objects.RemoveAll(); + m_pLocal = C_BasePlayer::GetLocalPlayer(); +} + +int CPlayerAndObjectEnumerator::GetObjectCount() +{ + return m_Objects.Size(); +} + +C_BaseEntity *CPlayerAndObjectEnumerator::GetObject( int index ) +{ + if ( index < 0 || index >= GetObjectCount() ) + return NULL; + + return m_Objects[ index ]; +} + +// Actual work code +IterationRetval_t CPlayerAndObjectEnumerator::EnumElement( IHandleEntity *pHandleEntity ) +{ + if ( !m_pLocal ) + return ITERATION_STOP; + + C_BaseEntity *pEnt = ClientEntityList().GetBaseEntityFromHandle( pHandleEntity->GetRefEHandle() ); + if ( pEnt == NULL ) + return ITERATION_CONTINUE; + + if ( pEnt == m_pLocal ) + return ITERATION_CONTINUE; + + if ( !pEnt->IsPlayer() && + !pEnt->IsBaseObject() ) + { + return ITERATION_CONTINUE; + } + + // Ignore vehicles, since they have vcollide collisions that's push me away + if ( pEnt->GetCollisionGroup() == COLLISION_GROUP_VEHICLE ) + return ITERATION_CONTINUE; + + // If it's solid to player movement, don't steer around it since we'll just bump into it + if ( pEnt->GetCollisionGroup() == TFCOLLISION_GROUP_OBJECT_SOLIDTOPLAYERMOVEMENT ) + return ITERATION_CONTINUE; + + Vector deltaPos = pEnt->GetAbsOrigin() - m_pLocal->GetAbsOrigin(); + if ( deltaPos.LengthSqr() > m_flRadiusSquared ) + return ITERATION_CONTINUE; + + CHandle< C_BaseEntity > h; + h = pEnt; + m_Objects.AddToTail( h ); + + return ITERATION_CONTINUE; +}
\ No newline at end of file diff --git a/game/client/tf2/playerandobjectenumerator.h b/game/client/tf2/playerandobjectenumerator.h new file mode 100644 index 0000000..0f6fa2d --- /dev/null +++ b/game/client/tf2/playerandobjectenumerator.h @@ -0,0 +1,44 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PLAYERANDOBJECTENUMERATOR_H +#define PLAYERANDOBJECTENUMERATOR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" +#include "ehandle.h" +#include "ispatialpartition.h" + +class C_BaseEntity; +class C_BasePlayer; + +// Enumator class for finding other players and objects close to the +// local player +class CPlayerAndObjectEnumerator : public IPartitionEnumerator +{ + DECLARE_CLASS_NOBASE( CPlayerAndObjectEnumerator ); +public: + //Forced constructor + CPlayerAndObjectEnumerator( float radius ); + + //Actual work code + virtual IterationRetval_t EnumElement( IHandleEntity *pHandleEntity ); + + int GetObjectCount(); + C_BaseEntity *GetObject( int index ); + +public: + //Data members + float m_flRadiusSquared; + + CUtlVector< CHandle< C_BaseEntity > > m_Objects; + C_BasePlayer *m_pLocal; +}; + +#endif // PLAYERANDOBJECTENUMERATOR_H diff --git a/game/client/tf2/playeroverlay.cpp b/game/client/tf2/playeroverlay.cpp new file mode 100644 index 0000000..1ef91ae --- /dev/null +++ b/game/client/tf2/playeroverlay.cpp @@ -0,0 +1,368 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "playeroverlay.h" +#include "playeroverlayhealth.h" +#include "playeroverlayname.h" +#include "playeroverlayclass.h" +#include "playeroverlayselected.h" +#include "playeroverlaysquad.h" +#include "hud_minimap.h" +#include "c_basetfplayer.h" +#include "mapdata.h" +#include "c_playerresource.h" +#include "c_team.h" +#include "commanderoverlay.h" +#include <KeyValues.h> +#include <vgui/IVGui.h> + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Class factory +//----------------------------------------------------------------------------- + +DECLARE_OVERLAY_FACTORY( CHudPlayerOverlay, "player" ); + + +// THE ACTUAL OVERLAY + +//----------------------------------------------------------------------------- +// Purpose: +// Output : +//----------------------------------------------------------------------------- +CHudPlayerOverlay::CHudPlayerOverlay( vgui::Panel *parent, const char *panelName ) +: BaseClass( parent, "CHudPlayerOverlay" ) +{ + m_pHealth = 0; + m_pName = 0; + m_pClass = 0; + m_pSquad = 0; + m_pSelected = 0; + + SetAutoDelete( false ); + + m_hPlayer = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : +//----------------------------------------------------------------------------- +CHudPlayerOverlay::~CHudPlayerOverlay( void ) +{ + Clear(); +} + +void CHudPlayerOverlay::Clear( void ) +{ + delete m_pHealth; + delete m_pName; + delete m_pClass; + delete m_pSelected; + delete m_pSquad; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CHudPlayerOverlay::Init( KeyValues* pInitData, C_BaseEntity* pEntity ) +{ + Clear(); + + m_hPlayer = dynamic_cast< C_BaseTFPlayer * >( pEntity ); + if (!m_hPlayer.Get()) + return false; + + if (!BaseClass::Init( pInitData, pEntity )) + return false; + + if (!ParseRGBA(pInitData, "fgcolor", m_fgColor )) + return false; + + if (!ParseRGBA(pInitData, "bgcolor", m_bgColor )) + return false; + + if (!ParseCoord(pInitData, "offset", m_OffsetX, m_OffsetY )) + return false; + + int w, h; + if (!ParseCoord(pInitData, "size", w, h )) + return false; + + SetSize( w, h ); + SetVisible( false ); + + m_iOrgWidth = w; + m_iOrgHeight = h; + m_iOrgOffsetX = m_OffsetX; + m_iOrgOffsetY = m_OffsetY; + + const char *mouseover = pInitData->GetString( "mousehint", "" ); + if ( mouseover && mouseover[ 0 ] ) + { + Q_strncpy( m_szMouseOverText, mouseover, sizeof( m_szMouseOverText ) ); + } + + m_pHealth = new CHudPlayerOverlayHealth( this ); + KeyValues* pHealthValue = pInitData->FindKey("HealthBar"); + if (!m_pHealth->Init( pHealthValue )) + return false; + + m_pHealth->SetVisible( false ); + m_pHealth->SetParent( this ); + + m_pName = new CHudPlayerOverlayName( this, "" ); + KeyValues* pNameValue = pInitData->FindKey("Name"); + if (!m_pName->Init( pNameValue )) + return false; + + m_pName->SetVisible( false ); + m_pName->SetParent( this ); + + m_pClass = new CHudPlayerOverlayClass( this ); + KeyValues* pClassValue = pInitData->FindKey("Class"); + if (!m_pClass->Init( pClassValue )) + return false; + + m_pClass->SetVisible( false ); + m_pClass->SetParent( this ); + + m_pSquad = new CHudPlayerOverlaySquad( this, "" ); + KeyValues* pSquadValue = pInitData->FindKey("Squad"); + if (!m_pSquad->Init( pSquadValue )) + return false; + + m_pSquad->SetVisible( false ); + m_pSquad->SetParent( this ); + + m_pSelected = new CHudPlayerOverlaySelected( this ); + KeyValues* pSelectedValue = pInitData->FindKey("Selection"); + if (!m_pSelected->Init( pSelectedValue )) + return false; + + m_pSelected->SetVisible( false ); + m_pSelected->SetParent( this ); + + // Um, is there a better way? + m_PlayerNum = GetEntity() ? GetEntity()->index : 0; + if (m_PlayerNum == 0) + return false; + + return true; +} + +void CHudPlayerOverlay::Hide( void ) +{ + SetVisible( false ); + if ( m_pHealth ) + { + m_pHealth->SetVisible( false); + } + + if ( m_pName ) + { + m_pName->SetVisible( false ); + } + + if ( m_pClass ) + { + m_pClass->SetVisible( false ); + } + + if ( m_pSquad ) + { + m_pSquad->SetVisible( false ); + } + + if ( m_pSelected ) + { + m_pSelected->SetVisible( false ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : playerNum - +//----------------------------------------------------------------------------- + +void CHudPlayerOverlay::OnTick( ) +{ + BaseClass::OnTick(); + + if (!IsLocalPlayerInTactical() || !engine->IsInGame()) + { + Hide(); + return; + } + + // Don't draw if I'm not visible in the tactical map + if ( MapData().IsEntityVisibleToTactical( GetEntity() ) == false ) + { + Hide(); + return; + } + + // Don't draw it if I'm on team 0 (haven't decided on a team) + C_BaseTFPlayer *pPlayer = m_hPlayer.Get(); + if (!pPlayer || (pPlayer->GetTeamNumber() == 0) || (pPlayer->GetClass() == TFCLASS_UNDECIDED)) + { + Hide(); + return; + } + + SetVisible( true ); + + const char *pName = g_PR->GetPlayerName( m_PlayerNum ); + if ( pName ) + { + m_pName->SetName( pName ); + } + else + { + Hide(); + return; + } + + Vector pos, screen; + + C_BaseTFPlayer *tf2player = dynamic_cast<C_BaseTFPlayer *>( GetEntity() ); + int iteam = 0; + int iclass = 0; + if ( tf2player ) + { + iteam = tf2player->GetTeamNumber(); + iclass = tf2player->PlayerClass(); + + // FIXME: Get max health for player + m_pHealth->SetHealth( (float)tf2player->GetHealth() / (float)100.0f ); + } + + m_pClass->SetImage( 0 ); + if ( iteam != 0 && iclass != TFCLASS_UNDECIDED ) + m_pClass->SetTeamAndClass( iteam, iclass ); + + // Update our position on screen + int sx, sy; + GetEntityPosition( sx, sy ); + + // Set the position + SetPos( (int)(sx + m_OffsetX + 0.5f), (int)(sy + m_OffsetY + 0.5f)); + + // Add it in + m_pHealth->SetVisible( true ); + m_pName->SetVisible( true ); + m_pClass->SetVisible( true ); + + if ( MapData().m_Players[ m_PlayerNum - 1 ].m_bSelected ) + { + m_pSelected->SetVisible( true ); + } + else + { + m_pSelected->SetVisible( false ); + } + + if ( MapData().m_Players[ m_PlayerNum - 1 ].m_nSquadNumber != 0 ) + { + char sz[ 32 ]; + Q_snprintf( sz, sizeof( sz ), "%i", MapData().m_Players[ m_PlayerNum - 1 ].m_nSquadNumber ); + + m_pSquad->SetSquad( sz ); + m_pSquad->SetVisible( true ); + } + else + { + m_pSquad->SetVisible( false ); + } + + // Hide details if it's an enemy + if ( ArePlayersOnSameTeam( engine->GetLocalPlayer(), m_PlayerNum ) == false ) + { + m_pHealth->SetVisible( false ); + m_pName->SetVisible( false ); + m_pSelected->SetVisible( false ); + m_pSquad->SetVisible( false ); + + // Only show class icon + m_pClass->SetVisible( true ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudPlayerOverlay::Paint() +{ + // Don't draw if I'm not visible in the tactical map + if ( MapData().IsEntityVisibleToTactical( GetEntity() ) == false ) + return; + + // Don't draw if if I haven't chosen a class... + + SetFgColor( m_fgColor ); + SetBgColor( m_bgColor ); + + BaseClass::Paint(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *panel - +// fg - +// bg - +//----------------------------------------------------------------------------- +void CHudPlayerOverlay::SetColorLevel( vgui::Panel *panel, Color& fg, Color& bg ) +{ + float frac = GetAlphaFrac(); + + if ( frac == 1.0f ) + { + panel->SetFgColor( fg ); + panel->SetBgColor( bg ); + return; + } + + Color foreground; + Color background; + + foreground = fg; + background = bg; + + int r, g, b, a; + foreground.GetColor( r, g, b, a ); + foreground.SetColor( r, g, b, (int)( ( float )a * frac ) ); + + panel->SetFgColor( foreground ); + + background.GetColor( r, g, b, a ); + background.SetColor( r, g, b, (int)( ( float )a * frac ) ); + + panel->SetBgColor( background ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int +//----------------------------------------------------------------------------- +float CHudPlayerOverlay::GetAlphaFrac( void ) +{ + // + // return fmod( gpGlobals->curtime, 1.0f ); + + C_BaseTFPlayer *local = C_BaseTFPlayer::GetLocalPlayer(); + if ( !local ) + return 1.0; + + C_BaseTFPlayer *pPlayer = m_hPlayer.Get(); + if (!pPlayer || (pPlayer->GetTeamNumber() == local->GetTeamNumber()) ) + return 1.0f; + + return pPlayer->GetOverlayAlpha(); +} diff --git a/game/client/tf2/playeroverlay.h b/game/client/tf2/playeroverlay.h new file mode 100644 index 0000000..3864a6f --- /dev/null +++ b/game/client/tf2/playeroverlay.h @@ -0,0 +1,68 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( PLAYEROVERLAY_H ) +#define PLAYEROVERLAY_H +#ifdef _WIN32 +#pragma once +#endif + +#include <vgui/VGUI.h> + +#include "vgui_entitypanel.h" + +class CHudPlayerOverlayName; +class CHudPlayerOverlayHealth; +class CHudPlayerOverlayClass; +class CHudPlayerOverlaySquad; +class CHudPlayerOverlaySelected; +class KeyValues; +class C_BaseTFPlayer; +//----------------------------------------------------------------------------- +// Purpose: Container for overlay elements +//----------------------------------------------------------------------------- + +class CHudPlayerOverlay : public CEntityPanel +{ +public: + DECLARE_CLASS( CHudPlayerOverlay, CEntityPanel ); + + CHudPlayerOverlay( vgui::Panel *parent, const char *panelName ); + virtual ~CHudPlayerOverlay( void ); + + virtual void Clear( void ); + + virtual bool Init( KeyValues* pInitData, C_BaseEntity* pEntity ); + virtual void OnTick( ); + + virtual void Hide( void ); + + virtual void Paint(); + + // Global fade amount + float GetAlphaFrac( void ); + void SetColorLevel( vgui::Panel *panel, Color& fg, Color& bg ); + +private: + CHudPlayerOverlayName *m_pName; + CHudPlayerOverlayHealth *m_pHealth; + CHudPlayerOverlayClass *m_pClass; + CHudPlayerOverlaySquad *m_pSquad; + CHudPlayerOverlaySelected *m_pSelected; + + int m_OffsetX, m_OffsetY; + int m_PlayerNum; + + Color m_fgColor; + Color m_bgColor; + + // These are only associated with tf players + CHandle<C_BaseTFPlayer> m_hPlayer; +}; + + +#endif // PLAYEROVERLAY_H
\ No newline at end of file diff --git a/game/client/tf2/playeroverlayclass.cpp b/game/client/tf2/playeroverlayclass.cpp new file mode 100644 index 0000000..12684eb --- /dev/null +++ b/game/client/tf2/playeroverlayclass.cpp @@ -0,0 +1,269 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "playeroverlayclass.h" +#include "playeroverlay.h" +#include <KeyValues.h> +#include "commanderoverlay.h" +#include "clientmode_tfnormal.h" +#include "tf_shareddefs.h" +#include "hud_commander_statuspanel.h" +#include "vgui_bitmapimage.h" +#include "igamesystem.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +//----------------------------------------------------------------------------- +// Class info. Only load it once. +//----------------------------------------------------------------------------- + +CHudPlayerOverlayClass::CMapClassColors** CHudPlayerOverlayClass::s_ppClassInfo = 0; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CCleanupPlayerOverlayClass : public CAutoGameSystem +{ +public: + virtual void Shutdown() + { + if ( !CHudPlayerOverlayClass::s_ppClassInfo ) + return; + + for (int i = 0; i <= MAX_TF_TEAMS; ++i) + { + for ( int j = 0; j < TFCLASS_CLASS_COUNT; j++ ) + { + delete CHudPlayerOverlayClass::s_ppClassInfo[i][j].m_pClassImage; + } + delete[] CHudPlayerOverlayClass::s_ppClassInfo[i]; + } + delete[] CHudPlayerOverlayClass::s_ppClassInfo; + } +}; + +static CCleanupPlayerOverlayClass g_CleanupPlayerOverlayClass; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +CHudPlayerOverlayClass::CHudPlayerOverlayClass( CHudPlayerOverlay *baseOverlay ) +: BaseClass( NULL, "CHudPlayerOverlayClass" ) +{ + m_pBaseOverlay = baseOverlay; + + m_pImage = NULL; + SetPaintBackgroundEnabled( false ); + + // Send mouse inputs (but not cursorenter/exit for now) up to parent + SetReflectMouse( true ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +CHudPlayerOverlayClass::~CHudPlayerOverlayClass( void ) +{ + delete m_pImage; +} + + +//----------------------------------------------------------------------------- +// Parse class icons +//----------------------------------------------------------------------------- + +bool CHudPlayerOverlayClass::ParseTeamClassInfo( KeyValues *pClassIcons, const char *classname, CMapClassColors *pClassColors ) +{ + const char *classimage; + KeyValues *pClass; + pClass = pClassIcons->FindKey( classname ); + if ( !pClass ) + return false; + + classimage = pClass->GetString( "material" ); + if ( classimage && classimage[ 0 ] ) + { + pClassColors->m_pClassImage = new BitmapImage( NULL, classimage ); + } + else + { + return( false ); + } + + return ParseRGBA( pClass, "color", pClassColors->m_clrClass ); +} + +bool CHudPlayerOverlayClass::ParseTeamClassIcons( CMapClassColors *pT, KeyValues *pTeam ) +{ + if ( !ParseTeamClassInfo( pTeam, "Recon", &pT[ TFCLASS_RECON ] ) ) + return false; + if ( !ParseTeamClassInfo( pTeam, "Sniper", &pT[ TFCLASS_SNIPER ] ) ) + return false; + if ( !ParseTeamClassInfo( pTeam, "Commando", &pT[ TFCLASS_COMMANDO ] ) ) + return false; + if ( !ParseTeamClassInfo( pTeam, "Support", &pT[ TFCLASS_SUPPORT ] ) ) + return false; + if ( !ParseTeamClassInfo( pTeam, "Medic", &pT[ TFCLASS_MEDIC ] ) ) + return false; + if ( !ParseTeamClassInfo( pTeam, "Escort", &pT[ TFCLASS_ESCORT ] ) ) + return false; + if ( !ParseTeamClassInfo( pTeam, "Defender", &pT[ TFCLASS_DEFENDER ] ) ) + return false; + if ( !ParseTeamClassInfo( pTeam, "Sapper", &pT[ TFCLASS_SAPPER ] ) ) + return false; + if ( !ParseTeamClassInfo( pTeam, "Infiltrator", &pT[ TFCLASS_INFILTRATOR ] ) ) + return false; + return true; +} + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- + +bool CHudPlayerOverlayClass::InitClassInfo( KeyValues* pKeyValues ) +{ + if (s_ppClassInfo) + return true; + + char teamkey[ 128 ]; + s_ppClassInfo = new CMapClassColors*[MAX_TF_TEAMS+1]; + for (int i = 0; i <= MAX_TF_TEAMS; ++i) + { + s_ppClassInfo[i] = new CMapClassColors[TFCLASS_CLASS_COUNT]; + Q_snprintf( teamkey, sizeof( teamkey ), "Team%i", i ); + KeyValues *pTeam = pKeyValues->FindKey( teamkey ); + if (pTeam) + { + if (!ParseTeamClassIcons( s_ppClassInfo[i], pTeam )) + return false; + } + } + + return true; +} + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- + +bool CHudPlayerOverlayClass::Init( KeyValues* pKeyValues ) +{ + if (!pKeyValues) + return false; + + int x, y, w, h; + if (!ParseRect(pKeyValues, "friendlyposition", x, y, w, h )) + return false; + + if (!InitClassInfo( pKeyValues )) + return false; + + SetPos( x, y ); + SetSize( w, h ); + + SetImage( 0 ); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pImage - Class specific image +//----------------------------------------------------------------------------- +void CHudPlayerOverlayClass::SetImage( BitmapImage *pImage ) +{ + m_pImage = pImage; + if (m_pImage) + { + // Make sure the image size is correct + int w,h; + GetSize(w,h); + } +} + +void CHudPlayerOverlayClass::SetTeamAndClass( int team, int playerclass ) +{ + if (!s_ppClassInfo) + return; + + CMapClassColors *pCC = &s_ppClassInfo[ team ][ playerclass ]; + if ( pCC ) + { + int r, g, b, a; + pCC->m_clrClass.GetColor( r, g, b, a ); + SetColor( r, g, b, a ); + SetImage( pCC->m_pClassImage ); + } +} + +//----------------------------------------------------------------------------- +// If this guy changes size, so must the associated image +//----------------------------------------------------------------------------- + +void CHudPlayerOverlayClass::SetSize( int w, int h ) +{ + // chain... + Panel::SetSize( w, h ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : r - +// g - +// b - +// a - +//----------------------------------------------------------------------------- +void CHudPlayerOverlayClass::SetColor( int r, int g, int b, int a ) +{ + m_r = r; + m_g = g; + m_b = b; + m_a = a; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudPlayerOverlayClass::Paint( void ) +{ + int w, h; + + m_pBaseOverlay->SetColorLevel( this, m_fgColor, m_bgColor ); + + GetSize( w, h ); + vgui::surface()->DrawSetColor( m_r, m_g, m_b, m_a * m_pBaseOverlay->GetAlphaFrac() ); + + if ( !m_pImage ) + return; + + Color color; + color.SetColor( m_r, m_g, m_b, m_a * m_pBaseOverlay->GetAlphaFrac() ); + m_pImage->SetColor( color ); + m_pImage->DoPaint( GetVPanel() ); +} + +void CHudPlayerOverlayClass::OnCursorEntered() +{ + if ( m_pBaseOverlay->GetMouseOverText() ) + { + StatusPrint( TYPE_HINT, "%s", m_pBaseOverlay->GetMouseOverText() ); + } +} + +void CHudPlayerOverlayClass::OnCursorExited() +{ + if ( m_pBaseOverlay->GetMouseOverText() ) + { + StatusClear(); + } +}
\ No newline at end of file diff --git a/game/client/tf2/playeroverlayclass.h b/game/client/tf2/playeroverlayclass.h new file mode 100644 index 0000000..ab4483d --- /dev/null +++ b/game/client/tf2/playeroverlayclass.h @@ -0,0 +1,72 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#if !defined( PLAYEROVERLAYCLASS_H ) +#define PLAYEROVERLAYCLASS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui_basepanel.h" + +class BitmapImage; +class KeyValues; +class CHudPlayerOverlay; + +class CHudPlayerOverlayClass : public CBasePanel +{ +public: + DECLARE_CLASS( CHudPlayerOverlayClass, CBasePanel ); + + CHudPlayerOverlayClass( CHudPlayerOverlay *baseOverlay ); + virtual ~CHudPlayerOverlayClass( void ); + + bool Init( KeyValues* pKeyValues ); + + void SetColor( int r, int g, int b, int a ); + void SetImage( BitmapImage *pImage ); + void SetTeamAndClass( int team, int playerclass ); + + // Keeps the image size correct + virtual void SetSize( int w, int h ); + + virtual void Paint( void ); + + virtual void OnCursorEntered(); + virtual void OnCursorExited(); + +private: + class CMapClassColors + { + public: + CMapClassColors() : m_pClassImage(0) {} + + BitmapImage *m_pClassImage; + Color m_clrClass; + }; + + // Initialize class info only once + static bool InitClassInfo( KeyValues* pKeyValues ); + static bool ParseTeamClassInfo( KeyValues *pClassIcons, const char *classname, CMapClassColors *pClassColors ); + static bool ParseTeamClassIcons( CMapClassColors *pT, KeyValues *pTeam ); + + static CMapClassColors** s_ppClassInfo; + + int m_r, m_g, m_b, m_a; + BitmapImage *m_pImage; + + Color m_fgColor; + Color m_bgColor; + + CHudPlayerOverlay *m_pBaseOverlay; + + friend class CCleanupPlayerOverlayClass; +}; + +#endif // PLAYEROVERLAYCLASS_H
\ No newline at end of file diff --git a/game/client/tf2/playeroverlayhealth.cpp b/game/client/tf2/playeroverlayhealth.cpp new file mode 100644 index 0000000..0ae023e --- /dev/null +++ b/game/client/tf2/playeroverlayhealth.cpp @@ -0,0 +1,123 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "playeroverlayhealth.h" +#include "playeroverlay.h" +#include "CommanderOverlay.h" +#include "hud_commander_statuspanel.h" +//----------------------------------------------------------------------------- +// Purpose: +// Output : +//----------------------------------------------------------------------------- +CHudPlayerOverlayHealth::CHudPlayerOverlayHealth( CHudPlayerOverlay *baseOverlay ) +: BaseClass( NULL, "CHudPlayerOverlayHealth" ) +{ + m_pBaseOverlay = baseOverlay; + + SetHealth( 0 ); + + SetPaintBackgroundEnabled( false ); + // Send mouse inputs (but not cursorenter/exit for now) up to parent + SetReflectMouse( true ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : +//----------------------------------------------------------------------------- +CHudPlayerOverlayHealth::~CHudPlayerOverlayHealth( void ) +{ +} + +//----------------------------------------------------------------------------- +// Parse values from the file +//----------------------------------------------------------------------------- + +bool CHudPlayerOverlayHealth::Init( KeyValues* pInitData ) +{ + if (!pInitData) + return false; + + if (!ParseRGBA(pInitData, "fgcolor", m_fgColor )) + return false; + + if (!ParseRGBA(pInitData, "bgcolor", m_bgColor )) + return false; + + int x, y, w, h; + if (!ParseRect(pInitData, "position", x, y, w, h )) + return false; + SetPos( x, y ); + SetSize( w, h ); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : health - +//----------------------------------------------------------------------------- + +void CHudPlayerOverlayHealth::SetHealth( float health ) +{ + m_Health = health; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudPlayerOverlayHealth::Paint( void ) +{ + int w, h; + + GetSize( w, h ); + + m_pBaseOverlay->SetColorLevel( this, m_fgColor, m_bgColor ); + + // Use a color related to health value.... + vgui::surface()->DrawSetColor( 0, 255, 0, 255 * m_pBaseOverlay->GetAlphaFrac() ); + + int drawwidth; + + float frac = m_Health; + frac = MIN( 1.0, m_Health ); + frac = MAX( 0.0, m_Health ); + + drawwidth = frac * w; + + vgui::surface()->DrawFilledRect( 0, 0, drawwidth, h/2 ); + + // This is the hurt part + if (w != drawwidth) + { + vgui::surface()->DrawSetColor( 255, 64, 64, 255 * m_pBaseOverlay->GetAlphaFrac() ); + vgui::surface()->DrawFilledRect( drawwidth, 0, w, h/2 ); + } +} + +void CHudPlayerOverlayHealth::OnCursorEntered() +{ + if ( m_pBaseOverlay->GetMouseOverText() ) + { + StatusPrint( TYPE_HINT, "%s", m_pBaseOverlay->GetMouseOverText() ); + } +} + +void CHudPlayerOverlayHealth::OnCursorExited() +{ + if ( m_pBaseOverlay->GetMouseOverText() ) + { + StatusClear(); + } +}
\ No newline at end of file diff --git a/game/client/tf2/playeroverlayhealth.h b/game/client/tf2/playeroverlayhealth.h new file mode 100644 index 0000000..9dc7edd --- /dev/null +++ b/game/client/tf2/playeroverlayhealth.h @@ -0,0 +1,47 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( PLAYEROVERLAYHEALTH_H ) +#define PLAYEROVERLAYHEALTH_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui_basepanel.h" + +class KeyValues; + +class CHudPlayerOverlay; + +class CHudPlayerOverlayHealth : public CBasePanel +{ +public: + DECLARE_CLASS( CHudPlayerOverlayHealth, CBasePanel ); + + CHudPlayerOverlayHealth( CHudPlayerOverlay *baseOverlay ); + virtual ~CHudPlayerOverlayHealth( void ); + + bool Init( KeyValues* pInitData ); + void SetHealth( float health ); + + virtual void Paint( void ); + + virtual void OnCursorEntered(); + virtual void OnCursorExited(); + +private: + float m_Health; + + Color m_fgColor; + Color m_bgColor; + + CHudPlayerOverlay *m_pBaseOverlay; + +}; + +#endif // PLAYEROVERLAYHEALTH_H
\ No newline at end of file diff --git a/game/client/tf2/playeroverlayname.cpp b/game/client/tf2/playeroverlayname.cpp new file mode 100644 index 0000000..8d3f602 --- /dev/null +++ b/game/client/tf2/playeroverlayname.cpp @@ -0,0 +1,183 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include <KeyValues.h> +#include "playeroverlay.h" +#include "playeroverlayname.h" +#include <KeyValues.h> +#include "commanderoverlay.h" +#include "hud_commander_statuspanel.h" +#include <vgui/IVGui.h> +#include <vgui/IScheme.h> +//----------------------------------------------------------------------------- +// Purpose: +// Input : *name - +//----------------------------------------------------------------------------- +CHudPlayerOverlayName::CHudPlayerOverlayName( CHudPlayerOverlay *baseOverlay, const char *name ) : +vgui::Label( (vgui::Panel *)NULL, "OverlayName", name ) +{ + m_pBaseOverlay = baseOverlay; + + Q_strncpy( m_szName, name, sizeof( m_szName ) ); + + SetPaintBackgroundEnabled( false ); + + // Send mouse inputs (but not cursorenter/exit for now) up to parent + SetReflectMouse( true ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CHudPlayerOverlayName::~CHudPlayerOverlayName( void ) +{ +} + +bool CHudPlayerOverlayName::Init( KeyValues* pInitData ) +{ + if (!pInitData) + return false; + + if (!ParseRGBA(pInitData, "fgcolor", m_fgColor )) + return false; + + if (!ParseRGBA(pInitData, "bgcolor", m_bgColor )) + return false; + + int x, y, w, h; + if (!ParseRect(pInitData, "position", x, y, w, h )) + return false; + SetPos( x, y ); + SetSize( w, h ); + + SetContentAlignment( vgui::Label::a_west ); + + return true; +} + +void CHudPlayerOverlayName::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + SetFont( pScheme->GetFont( "primary" ) ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *name - +//----------------------------------------------------------------------------- +void CHudPlayerOverlayName::SetName( const char *name ) +{ + Q_strncpy( m_szName, name, sizeof( m_szName ) ); + SetText( name ); +} + +void CHudPlayerOverlayName::Paint() +{ + m_pBaseOverlay->SetColorLevel( this, m_fgColor, m_bgColor ); + + BaseClass::Paint(); +} + +void CHudPlayerOverlayName::SetReflectMouse( bool reflect ) +{ + m_bReflectMouse = true; +} + +void CHudPlayerOverlayName::OnCursorMoved(int x,int y) +{ + if ( !m_bReflectMouse ) + return; + + if ( !GetParent() ) + return; + + LocalToScreen( x, y ); + + vgui::ivgui()->PostMessage( + GetParent()->GetVPanel(), + new KeyValues( "CursorMoved", "xpos", x, "ypos", y ), + GetVPanel() ); +} + +void CHudPlayerOverlayName::OnMousePressed(vgui::MouseCode code) +{ + if ( !m_bReflectMouse ) + return; + + if ( !GetParent() ) + return; + + vgui::ivgui()->PostMessage( + GetParent()->GetVPanel(), + new KeyValues( "MousePressed", "code", code ), + GetVPanel() ); +} + +void CHudPlayerOverlayName::OnMouseDoublePressed(vgui::MouseCode code) +{ + if ( !m_bReflectMouse ) + return; + + if ( !GetParent() ) + return; + + vgui::ivgui()->PostMessage( + GetParent()->GetVPanel(), + new KeyValues( "MouseDoublePressed", "code", code ), + GetVPanel() ); +} + +void CHudPlayerOverlayName::OnMouseReleased(vgui::MouseCode code) +{ + if ( !m_bReflectMouse ) + return; + + if ( !GetParent() ) + return; + + vgui::ivgui()->PostMessage( + GetParent()->GetVPanel(), + new KeyValues( "MouseReleased", "code", code ), + GetVPanel() ); +} + +void CHudPlayerOverlayName::OnMouseWheeled(int delta) +{ + if ( !m_bReflectMouse ) + return; + + if ( !GetParent() ) + return; + + vgui::ivgui()->PostMessage( + GetParent()->GetVPanel(), + new KeyValues( "MouseWheeled", "delta", delta ), + GetVPanel() ); +} + +void CHudPlayerOverlayName::OnCursorEntered() +{ + if ( m_pBaseOverlay->GetMouseOverText() ) + { + StatusPrint( TYPE_HINT, "%s", m_pBaseOverlay->GetMouseOverText() ); + } +} + +void CHudPlayerOverlayName::OnCursorExited() +{ + if ( m_pBaseOverlay->GetMouseOverText() ) + { + StatusClear(); + } +}
\ No newline at end of file diff --git a/game/client/tf2/playeroverlayname.h b/game/client/tf2/playeroverlayname.h new file mode 100644 index 0000000..4fe7a4f --- /dev/null +++ b/game/client/tf2/playeroverlayname.h @@ -0,0 +1,59 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( PLAYEROVERLAYNAME_H ) +#define PLAYEROVERLAYNAME_H +#ifdef _WIN32 +#pragma once +#endif + +#include <vgui_controls/Label.h> + +class KeyValues; +class CHudPlayerOverlay; +class CHudPlayerOverlayName : public vgui::Label +{ +public: + typedef vgui::Label BaseClass; + + CHudPlayerOverlayName( CHudPlayerOverlay *baseOverlay, const char *name ); + virtual ~CHudPlayerOverlayName( void ); + + bool Init( KeyValues* pInitData ); + + void SetName( const char *name ); + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void Paint(); + + virtual void SetReflectMouse( bool reflect ); + // If reflect mouse is true, then pass these up to parent + virtual void OnCursorMoved(int x,int y); + virtual void OnMousePressed(vgui::MouseCode code); + virtual void OnMouseDoublePressed(vgui::MouseCode code); + virtual void OnMouseReleased(vgui::MouseCode code); + virtual void OnMouseWheeled(int delta); + + virtual void OnCursorEntered(); + virtual void OnCursorExited(); +private: + + char m_szName[ 64 ]; + Color m_fgColor; + Color m_bgColor; + + CHudPlayerOverlay *m_pBaseOverlay; + + bool m_bReflectMouse; +}; + +#endif // PLAYEROVERLAYNAME_H
\ No newline at end of file diff --git a/game/client/tf2/playeroverlayselected.cpp b/game/client/tf2/playeroverlayselected.cpp new file mode 100644 index 0000000..f52912a --- /dev/null +++ b/game/client/tf2/playeroverlayselected.cpp @@ -0,0 +1,130 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "playeroverlay.h" +#include "playeroverlayselected.h" +#include <KeyValues.h> +#include "commanderoverlay.h" +#include "hud_commander_statuspanel.h" +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CHudPlayerOverlaySelected::CHudPlayerOverlaySelected( CHudPlayerOverlay *baseOverlay ) + : BaseClass( NULL, "CHudPlayerOverlaySelected" ) +{ + m_pBaseOverlay = baseOverlay; + + int i; + for ( i = 0; i < 4; i++ ) + { + m_pImages[ i ] = NULL; + } + + SetPaintBackgroundEnabled( false ); + + // Send mouse inputs (but not cursorenter/exit for now) up to parent + SetReflectMouse( true ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CHudPlayerOverlaySelected::~CHudPlayerOverlaySelected( void ) +{ +} + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- + +bool CHudPlayerOverlaySelected::Init( KeyValues* pInitData ) +{ + if (!pInitData) + return false; + + if (!ParseRGBA(pInitData, "fgcolor", m_fgColor )) + return false; + + if (!ParseRGBA(pInitData, "bgcolor", m_bgColor )) + return false; + + int x, y, w, h; + if (!ParseRect(pInitData, "position", x, y, w, h )) + return false; + SetPos( x, y ); + SetSize( w, h ); + + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: NOTE: This is not hooked up yet. +// Input : pImage -- the four corner images +//----------------------------------------------------------------------------- +void CHudPlayerOverlaySelected::SetImages( BitmapImage *pImage[4] ) +{ + int i; + for ( i = 0 ; i < 4; i++ ) + { + m_pImages[ i ] = pImage[ i ]; + } +} + +//----------------------------------------------------------------------------- +// Purpose: FIXME: Use materials for corners, not just procedural drawing? +//----------------------------------------------------------------------------- +void CHudPlayerOverlaySelected::Paint( void ) +{ + int w, h; + + m_pBaseOverlay->SetColorLevel( this, m_fgColor, m_bgColor ); + + GetSize( w, h ); + int r, g, b, a; + Color clr = GetFgColor(); + clr.GetColor( r, g, b, a ); + vgui::surface()->DrawSetColor( r, g, b, a ); + + // Draw corners + int inSetSize = 6; + int thickness = 2; + + vgui::surface()->DrawFilledRect( 0, 0, inSetSize, thickness ); + vgui::surface()->DrawFilledRect( 0, 0, thickness, inSetSize ); + + vgui::surface()->DrawFilledRect( w-inSetSize, 0, w, thickness ); + vgui::surface()->DrawFilledRect( w-thickness, 0, w, inSetSize ); + + vgui::surface()->DrawFilledRect( w-inSetSize, h-thickness, w, h ); + vgui::surface()->DrawFilledRect( w-thickness, h-inSetSize, w, h ); + + vgui::surface()->DrawFilledRect( 0, h-thickness, inSetSize, h ); + vgui::surface()->DrawFilledRect( 0, h-inSetSize, thickness, h ); +} + +void CHudPlayerOverlaySelected::OnCursorEntered() +{ + if ( m_pBaseOverlay->GetMouseOverText() ) + { + StatusPrint( TYPE_HINT, "%s", m_pBaseOverlay->GetMouseOverText() ); + } +} + +void CHudPlayerOverlaySelected::OnCursorExited() +{ + if ( m_pBaseOverlay->GetMouseOverText() ) + { + StatusClear(); + } +}
\ No newline at end of file diff --git a/game/client/tf2/playeroverlayselected.h b/game/client/tf2/playeroverlayselected.h new file mode 100644 index 0000000..723b2ee --- /dev/null +++ b/game/client/tf2/playeroverlayselected.h @@ -0,0 +1,46 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( PLAYEROLVERLAYSELECTED_H ) +#define PLAYEROLVERLAYSELECTED_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui_basepanel.h" + +class BitmapImage; +class KeyValues; +class CHudPlayerOverlay; +class CHudPlayerOverlaySelected : public CBasePanel +{ +public: + DECLARE_CLASS( CHudPlayerOverlaySelected, CBasePanel ); + + CHudPlayerOverlaySelected( CHudPlayerOverlay *baseOverlay ); + virtual ~CHudPlayerOverlaySelected( void ); + + bool Init( KeyValues* pInitData ); + + void SetImages( BitmapImage *pImage[4] ); + + virtual void Paint( void ); + + virtual void OnCursorEntered(); + virtual void OnCursorExited(); + + +private: + BitmapImage *m_pImages[4]; + + Color m_fgColor; + Color m_bgColor; + CHudPlayerOverlay *m_pBaseOverlay; +}; + +#endif // PLAYEROLVERLAYSELECTED_H
\ No newline at end of file diff --git a/game/client/tf2/playeroverlaysquad.cpp b/game/client/tf2/playeroverlaysquad.cpp new file mode 100644 index 0000000..f646706 --- /dev/null +++ b/game/client/tf2/playeroverlaysquad.cpp @@ -0,0 +1,187 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include <KeyValues.h> +#include "playeroverlay.h" +#include "playeroverlaysquad.h" +#include <KeyValues.h> +#include "panelmetaclassmgr.h" +#include "hud_commander_statuspanel.h" +#include <vgui/IScheme.h> +#include <vgui/IVGui.h> + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *name - +//----------------------------------------------------------------------------- +CHudPlayerOverlaySquad::CHudPlayerOverlaySquad( CHudPlayerOverlay *baseOverlay, const char *squadname ) : +vgui::Label( (vgui::Panel *)NULL, "OverlaySquad", squadname ) +{ + m_pBaseOverlay = baseOverlay; + + Q_strncpy( m_szSquad, squadname, sizeof( m_szSquad ) ); + + SetPaintBackgroundEnabled( false ); + + // Send mouse inputs (but not cursorenter/exit for now) up to parent + SetReflectMouse( true ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CHudPlayerOverlaySquad::~CHudPlayerOverlaySquad( void ) +{ +} + + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- +bool CHudPlayerOverlaySquad::Init( KeyValues* pInitData ) +{ + if (!pInitData) + return false; + + SetContentAlignment( vgui::Label::a_west ); + + if (!ParseRGBA(pInitData, "fgcolor", m_fgColor )) + return false; + + if (!ParseRGBA(pInitData, "bgcolor", m_bgColor)) + return false; + + int x, y, w, h; + if (!ParseRect(pInitData, "position", x, y, w, h )) + return false; + SetPos( x, y ); + SetSize( w, h ); + + return true; +} + +void CHudPlayerOverlaySquad::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + SetFont( pScheme->GetFont( "primary" ) ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *name - +//----------------------------------------------------------------------------- +void CHudPlayerOverlaySquad::SetSquad( const char *squadname ) +{ + Q_strncpy( m_szSquad, squadname, sizeof( m_szSquad ) ); + SetText( squadname ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudPlayerOverlaySquad::Paint() +{ + m_pBaseOverlay->SetColorLevel( this, m_fgColor, m_bgColor ); + + BaseClass::Paint(); +} + +void CHudPlayerOverlaySquad::SetReflectMouse( bool reflect ) +{ + m_bReflectMouse = true; +} + +void CHudPlayerOverlaySquad::OnCursorMoved(int x,int y) +{ + if ( !m_bReflectMouse ) + return; + + if ( !GetParent() ) + return; + + LocalToScreen( x, y ); + + vgui::ivgui()->PostMessage( + GetParent()->GetVPanel(), + new KeyValues( "CursorMoved", "xpos", x, "ypos", y ), + GetVPanel() ); +} + +void CHudPlayerOverlaySquad::OnMousePressed(vgui::MouseCode code) +{ + if ( !m_bReflectMouse ) + return; + + if ( !GetParent() ) + return; + + vgui::ivgui()->PostMessage( + GetParent()->GetVPanel(), + new KeyValues( "MousePressed", "code", code ), + GetVPanel() ); +} + +void CHudPlayerOverlaySquad::OnMouseDoublePressed(vgui::MouseCode code) +{ + if ( !m_bReflectMouse ) + return; + + if ( !GetParent() ) + return; + + vgui::ivgui()->PostMessage( + GetParent()->GetVPanel(), + new KeyValues( "MouseDoublePressed", "code", code ), + GetVPanel() ); +} + +void CHudPlayerOverlaySquad::OnMouseReleased(vgui::MouseCode code) +{ + if ( !m_bReflectMouse ) + return; + + if ( !GetParent() ) + return; + + vgui::ivgui()->PostMessage( + GetParent()->GetVPanel(), + new KeyValues( "MouseReleased", "code", code ), + GetVPanel() ); +} + +void CHudPlayerOverlaySquad::OnMouseWheeled(int delta) +{ + if ( !m_bReflectMouse ) + return; + + if ( !GetParent() ) + return; + + vgui::ivgui()->PostMessage( + GetParent()->GetVPanel(), + new KeyValues( "MouseWheeled", "delta", delta ), + GetVPanel() ); +} + + +void CHudPlayerOverlaySquad::OnCursorEntered() +{ + if ( m_pBaseOverlay->GetMouseOverText() ) + { + StatusPrint( TYPE_HINT, "%s", m_pBaseOverlay->GetMouseOverText() ); + } +} + +void CHudPlayerOverlaySquad::OnCursorExited() +{ + if ( m_pBaseOverlay->GetMouseOverText() ) + { + StatusClear(); + } +}
\ No newline at end of file diff --git a/game/client/tf2/playeroverlaysquad.h b/game/client/tf2/playeroverlaysquad.h new file mode 100644 index 0000000..b097c59 --- /dev/null +++ b/game/client/tf2/playeroverlaysquad.h @@ -0,0 +1,54 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( PLAYEROVERLAYSQUAD_H ) +#define PLAYEROVERLAYSQUAD_H +#ifdef _WIN32 +#pragma once +#endif + +#include <vgui_controls/Label.h> + +class KeyValues; +class CHudPlayerOverlay; +class CHudPlayerOverlaySquad : public vgui::Label +{ +public: + typedef vgui::Label BaseClass; + + CHudPlayerOverlaySquad( CHudPlayerOverlay *baseOverlay, const char *squadname ); + virtual ~CHudPlayerOverlaySquad( void ); + + bool Init( KeyValues* pInitData ); + + void SetSquad( const char *squadname ); + + virtual void Paint(); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void SetReflectMouse( bool reflect ); + // If reflect mouse is true, then pass these up to parent + virtual void OnCursorMoved(int x,int y); + virtual void OnMousePressed(vgui::MouseCode code); + virtual void OnMouseDoublePressed(vgui::MouseCode code); + virtual void OnMouseReleased(vgui::MouseCode code); + virtual void OnMouseWheeled(int delta); + + virtual void OnCursorEntered(); + virtual void OnCursorExited(); + +private: + + char m_szSquad[ 64 ]; + Color m_fgColor; + Color m_bgColor; + CHudPlayerOverlay *m_pBaseOverlay; + + bool m_bReflectMouse; +}; + +#endif // PLAYEROVERLAYSQUAD_H
\ No newline at end of file diff --git a/game/client/tf2/proxy_objpower.cpp b/game/client/tf2/proxy_objpower.cpp new file mode 100644 index 0000000..e9f36a9 --- /dev/null +++ b/game/client/tf2/proxy_objpower.cpp @@ -0,0 +1,56 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Proxy to hook into an object's powered state +// +//=============================================================================// + +#include "cbase.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/imaterialsystem.h" +#include <KeyValues.h> +#include "materialsystem/imaterialvar.h" +#include "C_BaseTFPlayer.h" +#include "functionproxy.h" +#include "c_baseobject.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +class CTFObjectPowerProxy : public CResultProxy +{ +public: + virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); + virtual void OnBind( void *pEnt ); +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CTFObjectPowerProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) +{ + if ( !CResultProxy::Init( pMaterial, pKeyValues ) ) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFObjectPowerProxy::OnBind( void *pArg ) +{ + C_BaseEntity *pEntity = BindArgToEntity( pArg ); + if (!pEntity) + return; + + C_BaseObject *pObject = dynamic_cast<C_BaseObject*>( pEntity ); + Assert( pObject ); + + float flPoweredState = (float)(!pObject->IsBuilding() && !pObject->IsPlacing() && pObject->IsPowered()); + + Assert( m_pResult ); + SetFloatResult( flPoweredState ); +} + + +EXPOSE_INTERFACE( CTFObjectPowerProxy, IMaterialProxy, "TFObjectPower" IMATERIAL_PROXY_INTERFACE_VERSION ); diff --git a/game/client/tf2/proxy_shield.cpp b/game/client/tf2/proxy_shield.cpp new file mode 100644 index 0000000..214a579 --- /dev/null +++ b/game/client/tf2/proxy_shield.cpp @@ -0,0 +1,313 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/imaterialsystem.h" +#include <KeyValues.h> +#include "materialsystem/imaterialvar.h" +#include "C_BaseTFPlayer.h" +#include "functionproxy.h" +#include "C_PlayerResource.h" +#include "Weapon_CombatShield.h" + +// for the 2/5/03 demo +#include "c_demo_entities.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +//----------------------------------------------------------------------------- +// Shield proxy base class +//----------------------------------------------------------------------------- +class CTFShieldProxy : public CResultProxy +{ +protected: + C_WeaponCombatShield *BindArgToShield( void *pArg ); +}; + + +//----------------------------------------------------------------------------- +// Gets the shield +//----------------------------------------------------------------------------- +C_WeaponCombatShield *CTFShieldProxy::BindArgToShield( void *pArg ) +{ + C_BaseEntity *pEntity = BindArgToEntity( pArg ); + if (!pEntity) + return NULL; + + if (dynamic_cast<C_BaseViewModel*>(pEntity)) + { + // If this is the view model, snack the state from the local player... + C_BaseTFPlayer* pPlayer = C_BaseTFPlayer::GetLocalPlayer(); + return pPlayer->GetShield(); + } + + if ( dynamic_cast<C_BaseTFPlayer*>(pEntity) ) + { + C_BaseTFPlayer* pPlayer = dynamic_cast<C_BaseTFPlayer*>( pEntity ); + return pPlayer->GetShield(); + } + + return dynamic_cast<C_WeaponCombatShield*>( pEntity ); +} + + +//============================================================================= +// +// TF Shield raising proxy. +// +class CTFShieldRaiseProxy : public CTFShieldProxy +{ +public: + + virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); + virtual void OnBind( void *pEnt ); + +private: + CFloatInput m_Factor; +}; + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool CTFShieldRaiseProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) +{ + if ( !CResultProxy::Init( pMaterial, pKeyValues ) ) + return false; + + // Init shield raise times. + if ( !m_Factor.Init( pMaterial, pKeyValues, "scale", 1 ) ) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CTFShieldRaiseProxy::OnBind( void *pArg ) +{ + float flTimeSinceRaised = 0.0f; + C_WeaponCombatShield *pShield = BindArgToShield( pArg ); + if (pShield) + { + flTimeSinceRaised = pShield->GetRaisingTime(); + } + + // Return the time in seconds from when we started raising. + SetFloatResult( flTimeSinceRaised * m_Factor.GetFloat() ); +} + +EXPOSE_INTERFACE( CTFShieldRaiseProxy, IMaterialProxy, "TFShieldRaise" IMATERIAL_PROXY_INTERFACE_VERSION ); + +//============================================================================= +// +// TF Shield lowering proxy. +// +class CTFShieldLowerProxy : public CTFShieldProxy +{ +public: + + virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); + virtual void OnBind( void *pEnt ); + +private: + CFloatInput m_Factor; +}; + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool CTFShieldLowerProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) +{ + if ( !CResultProxy::Init( pMaterial, pKeyValues ) ) + return false; + + // Init shield raise times. + if ( !m_Factor.Init( pMaterial, pKeyValues, "scale", 1 ) ) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CTFShieldLowerProxy::OnBind( void *pArg ) +{ + float flTimeSinceLowered = 0.0f; + C_WeaponCombatShield *pShield = BindArgToShield( pArg ); + if ( pShield ) + { + flTimeSinceLowered = pShield->GetLoweringTime(); + } + else + { + // NOTE: This is for the Feb 5 03 demo only + C_BaseEntity *pEntity = BindArgToEntity( pArg ); + C_Cycler_TF2Commando *pDemoCommando = dynamic_cast<C_Cycler_TF2Commando*>( pEntity ); + if (pDemoCommando) + { + flTimeSinceLowered = pDemoCommando->GetShieldLowerTime(); + } + } + + // Return the time in seconds from when we started lowering. + Assert( m_pResult ); + SetFloatResult( flTimeSinceLowered * m_Factor.GetFloat() ); + +// Msg( "Lowering = %f\n", flTimeSinceLowered ); +} + +EXPOSE_INTERFACE( CTFShieldLowerProxy, IMaterialProxy, "TFShieldLower" IMATERIAL_PROXY_INTERFACE_VERSION ); + +//============================================================================= +// +// TF Shield raising proxy. +// +class CTFShieldVisibilityProxy : public CTFShieldProxy +{ +public: + virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); + virtual void OnBind( void *pEnt ); + +private: + CFloatInput m_RaiseFactor; + CFloatInput m_LowerFactor; +}; + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool CTFShieldVisibilityProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) +{ + if ( !CResultProxy::Init( pMaterial, pKeyValues ) ) + return false; + + // Init shield raise times. + if ( !m_RaiseFactor.Init( pMaterial, pKeyValues, "raisescale", 1 ) ) + return false; + + if ( !m_LowerFactor.Init( pMaterial, pKeyValues, "lowerscale", 1 ) ) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CTFShieldVisibilityProxy::OnBind( void *pArg ) +{ + float flAlpha = 0.0f; + C_WeaponCombatShield *pShield = BindArgToShield( pArg ); + if ( pShield ) + { + if (pShield->GetRaisingTime() != 0.0f) + { + flAlpha = pShield->GetRaisingTime() * m_RaiseFactor.GetFloat(); + flAlpha = clamp( flAlpha, 0, 1 ); + } + else + { + flAlpha = 1.0f - pShield->GetLoweringTime() * m_LowerFactor.GetFloat(); + flAlpha = clamp( flAlpha, 0, 1 ); + } + } + + // Return the time in seconds from when we started lowering. + Assert( m_pResult ); + SetFloatResult( flAlpha ); +} + +EXPOSE_INTERFACE( CTFShieldVisibilityProxy, IMaterialProxy, "TFShieldVisibility" IMATERIAL_PROXY_INTERFACE_VERSION ); + + +//============================================================================= +// +// TF Shield active proxy. +// +class CTFShieldActiveProxy : public CTFShieldProxy +{ +public: + + virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); + virtual void OnBind( void *pEnt ); +}; + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool CTFShieldActiveProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) +{ + if ( !CResultProxy::Init( pMaterial, pKeyValues ) ) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CTFShieldActiveProxy::OnBind( void *pArg ) +{ + bool bIsShieldUp = false; + C_WeaponCombatShield *pShield = BindArgToShield( pArg ); + if ( pShield ) + { + bIsShieldUp = ( pShield->IsUp() == 1.0f ); + } + else + { + // NOTE: This is for the Feb 5 03 demo only + C_BaseEntity *pEntity = BindArgToEntity( pArg ); + C_Cycler_TF2Commando *pDemoCommando = dynamic_cast<C_Cycler_TF2Commando*>( pEntity ); + if (pDemoCommando) + { + bIsShieldUp = pDemoCommando->IsShieldActive(); + } + } + + Assert( m_pResult ); + SetFloatResult( ( float )bIsShieldUp ); + +// Msg( "Active = %d\n", bIsShieldUp ); +} + +EXPOSE_INTERFACE( CTFShieldActiveProxy, IMaterialProxy, "TFShieldActive" IMATERIAL_PROXY_INTERFACE_VERSION ); + +//============================================================================= +// +// TF Shield health proxy. +// +class CTFShieldHealthProxy : public CTFShieldProxy +{ +public: + + virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); + virtual void OnBind( void *pEnt ); +}; + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool CTFShieldHealthProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) +{ + if ( !CResultProxy::Init( pMaterial, pKeyValues ) ) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CTFShieldHealthProxy::OnBind( void *pArg ) +{ + float flShieldHealth = 1; + C_WeaponCombatShield *pShield = BindArgToShield( pArg ); + if ( pShield ) + { + flShieldHealth = pShield->GetShieldHealth(); + } + + Assert( m_pResult ); + SetFloatResult( flShieldHealth ); +} + +EXPOSE_INTERFACE( CTFShieldHealthProxy, IMaterialProxy, "TFShieldHealth" IMATERIAL_PROXY_INTERFACE_VERSION ); diff --git a/game/client/tf2/proxy_sunroof.cpp b/game/client/tf2/proxy_sunroof.cpp new file mode 100644 index 0000000..894bfbc --- /dev/null +++ b/game/client/tf2/proxy_sunroof.cpp @@ -0,0 +1,72 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/imaterialsystem.h" +#include <KeyValues.h> +#include "materialsystem/imaterialvar.h" +#include "C_BaseTFPlayer.h" +#include "functionproxy.h" +#include "C_PlayerResource.h" +#include "Weapon_CombatShield.h" + +// for the 2/5/03 demo +#include "c_demo_entities.h" +#include "c_basefourwheelvehicle.h" + +//============================================================================= +// +// TF Shield raising proxy. +// +class CTFSunroofProxy : public CResultProxy +{ +public: + + virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); + virtual void OnBind( void *pEnt ); + +private: + + CFloatInput m_Factor; +}; + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +bool CTFSunroofProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) +{ + if ( !CResultProxy::Init( pMaterial, pKeyValues ) ) + return false; + + // Init shield raise times. + //if ( !m_Factor.Init( pMaterial, pKeyValues, "scale", 1 ) ) + // return false; + + return true; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CTFSunroofProxy::OnBind( void *pArg ) +{ + C_BaseEntity *pEntity = BindArgToEntity( pArg ); + C_BaseTFFourWheelVehicle* pVehicle = dynamic_cast<C_BaseTFFourWheelVehicle*>(pEntity); + if( !pVehicle ) + return; + + if( pVehicle->GetPassengerCount() ) + { + SetFloatResult(0.f); + } + else + { + SetFloatResult(1.f); + } +} + +EXPOSE_INTERFACE( CTFSunroofProxy, IMaterialProxy, "TFSunroof" IMATERIAL_PROXY_INTERFACE_VERSION ); diff --git a/game/client/tf2/resourcezoneoverlay.cpp b/game/client/tf2/resourcezoneoverlay.cpp new file mode 100644 index 0000000..97a7d51 --- /dev/null +++ b/game/client/tf2/resourcezoneoverlay.cpp @@ -0,0 +1,249 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Revision: $ +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include <VGUI_EntityPanel.h> +#include <KeyValues.h> +#include "commanderoverlay.h" +#include "clientmode_tfnormal.h" +#include "tf_shareddefs.h" +#include "shareddefs.h" +#include "c_func_resource.h" +#include "techtree.h" +#include "c_basetfplayer.h" +#include "vgui_HealthBar.h" +#include "vgui_bitmapimage.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +class CResourceZoneOverlay : public CEntityPanel +{ + DECLARE_CLASS( CResourceZoneOverlay, CEntityPanel ); + +public: + CResourceZoneOverlay( vgui::Panel *parent, const char *panelName ); + virtual ~CResourceZoneOverlay( void ); + + bool Init( KeyValues* pKeyValues, C_BaseEntity* pEntity ); + bool InitResourceBitmaps( KeyValues* pKeyValues ); + + void SetColor( int r, int g, int b, int a ); + void SetImage( BitmapImage *pImage ); + + virtual void OnTick(); + + virtual void Paint( void ); + virtual void PaintBackground( void ) {} + +private: + class CResourceBitmaps + { + public: + CResourceBitmaps() : m_pImage(0) {} + + BitmapImage *m_pImage; + Color m_Color; + }; + + struct Rect_t + { + int x, y, w, h; + }; + + bool ParseSingleResourceBitmap( KeyValues *pKeyValues, + const char *pResourceName, CResourceBitmaps *pResourceBitmap ); + bool ParseTeamResourceBitmaps( CResourceBitmaps *pT, KeyValues *pTeam ); + + int m_r, m_g, m_b, m_a; + CHealthBarPanel m_UsageBar; + Rect_t m_Icon; + C_ResourceZone *m_pResourceZone; + CResourceBitmaps m_pResourceBitmap; + BitmapImage *m_pImage; + +}; + + +//----------------------------------------------------------------------------- +// Class factory +//----------------------------------------------------------------------------- + +DECLARE_OVERLAY_FACTORY( CResourceZoneOverlay, "resourcezone" ); + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +CResourceZoneOverlay::CResourceZoneOverlay( vgui::Panel *parent, const char *panelName ) +: BaseClass( parent, "CResourceZoneOverlay" ) +{ + m_pImage = 0; + SetPaintBackgroundEnabled( false ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +CResourceZoneOverlay::~CResourceZoneOverlay( void ) +{ + if ( m_pResourceBitmap.m_pImage ) + { + delete m_pResourceBitmap.m_pImage; + } +} + + +//----------------------------------------------------------------------------- +// Parse class icons +//----------------------------------------------------------------------------- + +bool CResourceZoneOverlay::ParseSingleResourceBitmap( KeyValues *pKeyValues, + const char *pResourceName, CResourceBitmaps *pResourceBitmap ) +{ + const char *image; + KeyValues *pResource; + pResource = pKeyValues->FindKey( pResourceName ); + if ( !pResource ) + return false; + + image = pResource->GetString( "material" ); + if ( image && image[ 0 ] ) + { + pResourceBitmap->m_pImage = new BitmapImage( GetVPanel(), image ); + } + else + { + return( false ); + } + + return ParseRGBA( pResource, "color", pResourceBitmap->m_Color ); +} + +bool CResourceZoneOverlay::ParseTeamResourceBitmaps( CResourceBitmaps *pT, KeyValues *pTeam ) +{ + if ( !ParseSingleResourceBitmap( pTeam, "Alpha", pT ) ) + return false; + return true; +} + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- + +bool CResourceZoneOverlay::InitResourceBitmaps( KeyValues* pKeyValues ) +{ +// char teamkey[ 128 ]; +// for (int i = 0; i < 3; ++i) +// { +// Q_snprintf( teamkey, sizeof( teamkey ), "Team%i", i ); +// KeyValues *pTeam = pKeyValues->getSection( teamkey ); +// if (pTeam) + { + if (!ParseTeamResourceBitmaps( &m_pResourceBitmap, pKeyValues )) + return false; + } +// } + + return true; +} + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- + +bool CResourceZoneOverlay::Init( KeyValues* pKeyValues, C_BaseEntity* pEntity ) +{ + if (!BaseClass::Init( pKeyValues, pEntity)) + return false; + + if (!pKeyValues) + return false; + + // We gotta be attached to a resource zone + m_pResourceZone = dynamic_cast<C_ResourceZone*>(GetEntity()); + if (!m_pResourceZone) + return false; + + KeyValues* pUsage = pKeyValues->FindKey("Usage"); + if (!m_UsageBar.Init( pUsage )) + return false; + m_UsageBar.SetParent( this ); + + // get the icon info... + if (!ParseRect( pKeyValues, "iconposition", m_Icon.x, m_Icon.y, m_Icon.w, m_Icon.h )) + return false; + + if (!InitResourceBitmaps( pKeyValues )) + return false; + + SetImage( 0 ); + SetColor( m_pResourceBitmap.m_Color[0], m_pResourceBitmap.m_Color[1], m_pResourceBitmap.m_Color[2], m_pResourceBitmap.m_Color[3] ); + + // we need updating + return true; +} + + +//----------------------------------------------------------------------------- +// called when we're ticked... +//----------------------------------------------------------------------------- + +void CResourceZoneOverlay::OnTick() +{ + // Update position + CEntityPanel::OnTick(); + + SetImage( m_pResourceBitmap.m_pImage ); + int r, g, b, a; + m_pResourceBitmap.m_Color.GetColor( r, g, b, a ); + SetColor( r, g, b, a ); + + m_UsageBar.SetHealth( m_pResourceZone->m_flClientResources ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pImage - Class specific image +//----------------------------------------------------------------------------- + +void CResourceZoneOverlay::SetImage( BitmapImage *pImage ) +{ + m_pImage = pImage; +} + +//----------------------------------------------------------------------------- +// Sets the draw color +//----------------------------------------------------------------------------- + +void CResourceZoneOverlay::SetColor( int r, int g, int b, int a ) +{ + m_r = r; + m_g = g; + m_b = b; + m_a = a; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +void CResourceZoneOverlay::Paint( void ) +{ + if ( !m_pImage ) + return; + + ComputeAndSetSize(); + + Color color; + color.SetColor( m_r, m_g, m_b, m_a ); + m_pImage->SetPos( m_Icon.x, m_Icon.y ); + m_pImage->SetColor( color ); + m_pImage->DoPaint( GetVPanel() ); +}
\ No newline at end of file diff --git a/game/client/tf2/teammaterialproxy.cpp b/game/client/tf2/teammaterialproxy.cpp new file mode 100644 index 0000000..9fcc923 --- /dev/null +++ b/game/client/tf2/teammaterialproxy.cpp @@ -0,0 +1,71 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "proxyentity.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/imaterialvar.h" +#include "c_team.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// $sineVar : name of variable that controls the alpha level (float) +class CTeamMaterialProxy : public CEntityMaterialProxy +{ +public: + CTeamMaterialProxy(); + virtual ~CTeamMaterialProxy(); + virtual bool Init( IMaterial *pMaterial, KeyValues* pKeyValues ); + virtual void OnBind( C_BaseEntity *pEnt ); + +private: + IMaterialVar* m_FrameVar; +}; + + +//----------------------------------------------------------------------------- +// Constructor, destructor +//----------------------------------------------------------------------------- + +CTeamMaterialProxy::CTeamMaterialProxy() +{ + m_FrameVar = 0; +} + +CTeamMaterialProxy::~CTeamMaterialProxy() +{ +} + + +//----------------------------------------------------------------------------- +// Init baby... +//----------------------------------------------------------------------------- +bool CTeamMaterialProxy::Init( IMaterial *pMaterial, KeyValues* pKeyValues ) +{ + bool foundVar; + m_FrameVar = pMaterial->FindVar( "$frame", &foundVar, false ); + if( !foundVar ) + m_FrameVar = 0; + return true; +} + +//----------------------------------------------------------------------------- +// Set the appropriate texture... +//----------------------------------------------------------------------------- +void CTeamMaterialProxy::OnBind( C_BaseEntity *pEnt ) +{ + if( !m_FrameVar ) + return; + + int team = pEnt->GetRenderTeamNumber(); + team--; + + // Use that as an animated frame number + m_FrameVar->SetIntValue( team ); +} + +EXPOSE_INTERFACE( CTeamMaterialProxy, IMaterialProxy, "TeamTexture" IMATERIAL_PROXY_INTERFACE_VERSION ); diff --git a/game/client/tf2/tf_clientmode.cpp b/game/client/tf2/tf_clientmode.cpp new file mode 100644 index 0000000..5f125b2 --- /dev/null +++ b/game/client/tf2/tf_clientmode.cpp @@ -0,0 +1,188 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "hud_macros.h" +#include "clientmode_tfnormal.h" +#include "clientmode.h" +#include "clientmode_commander.h" +#include "ivmodemanager.h" +#include "hud_timer.h" +#include "hud_technologytreedoc.h" +#include "CommanderOverlay.h" +#include "c_tf2rootpanel.h" +#include "c_info_act.h" + +// default FOV for TF2 +ConVar default_fov( "default_fov", "90", FCVAR_CHEAT ); + +//----------------------------------------------------------------------------- +// Purpose: Handles switching to/from commander mode +//----------------------------------------------------------------------------- +class CTFModeManager : public IVModeManager +{ +public: + virtual void Init( void ); + virtual void SwitchMode( bool commander, bool force ); + virtual void LevelInit( const char *newmap ); + virtual void LevelShutdown( void ); + + CTFModeManager( void ); + virtual ~CTFModeManager( void ); + + void UserCmd_Commander( void ); + void UserCmd_Normal( void ); + +}; + +static CTFModeManager g_ModeManager; +IVModeManager *modemanager = ( IVModeManager * )&g_ModeManager; + +// The current client mode. Always ClientModeNormal in HL. +IClientMode *g_pClientMode = NULL; + +DECLARE_COMMAND( g_ModeManager, Commander ); +DECLARE_COMMAND( g_ModeManager, Normal ); + +HOOK_COMMAND( commander, Commander ); +HOOK_COMMAND( normal, Normal ); + +void __MsgFunc_ActBegin(bf_read &msg); +void __MsgFunc_ActEnd(bf_read &msg); + +#define MINIMAP_FILE "scripts/minimap_overlays.txt" +#define SCREEN_FILE "scripts/vgui_screens.txt" + +//----------------------------------------------------------------------------- +// Purpose: Intialize the mode manager +//----------------------------------------------------------------------------- +void CTFModeManager::Init( void ) +{ + g_pClientMode = ClientModeCommander(); + g_pClientMode = GetClientModeNormal(); + + // These define the panels that can be used by the engine + PanelMetaClassMgr()->LoadMetaClassDefinitionFile( MINIMAP_FILE ); + PanelMetaClassMgr()->LoadMetaClassDefinitionFile( SCREEN_FILE ); + + // FIXME: Turn these into client systems + HudCommanderOverlayMgr()->GameInit(); + MapData().Init(); + GetTechnologyTreeDoc().Init(); + + HOOK_MESSAGE( ActBegin ); + HOOK_MESSAGE( ActEnd ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : +//----------------------------------------------------------------------------- +CTFModeManager::CTFModeManager( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : +//----------------------------------------------------------------------------- +CTFModeManager::~CTFModeManager( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFModeManager::UserCmd_Commander( void ) +{ + engine->ServerCmd( "tactical 1\n" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFModeManager::UserCmd_Normal( void ) +{ + engine->ServerCmd( "tactical 0\n" ); +} + +//----------------------------------------------------------------------------- +// Purpose: Switch to / from commander mode ( won't change if current mode is already +// correct +// Input : commander - +//----------------------------------------------------------------------------- +void CTFModeManager::SwitchMode( bool commander, bool force ) +{ + if ( commander && ( ( g_pClientMode != ClientModeCommander() ) || force ) ) + { + g_pClientMode->Disable(); + g_pClientMode = ClientModeCommander(); + g_pClientMode->Enable(); + } + else if ( !commander && ( ( g_pClientMode != GetClientModeNormal() ) || force ) ) + { + g_pClientMode->Disable(); + g_pClientMode = GetClientModeNormal(); + g_pClientMode->Enable(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *newmap - +//----------------------------------------------------------------------------- +void CTFModeManager::LevelInit( const char *newmap ) +{ + GetTechnologyTreeDoc().LevelInit(); + g_pTF2RootPanel->LevelInit(); + + CHudTimer *timer = GET_HUDELEMENT( CHudTimer ); + if ( timer ) + { + timer->Init(); + } + + // Tell all modes about the map change + ClientModeCommander()->LevelInit( newmap ); + GetClientModeNormal()->LevelInit( newmap ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFModeManager::LevelShutdown( void ) +{ + GetClientModeNormal()->LevelShutdown(); + ClientModeCommander()->LevelShutdown(); + + g_pTF2RootPanel->LevelShutdown(); + GetTechnologyTreeDoc().LevelShutdown(); +} + +//----------------------------------------------------------------------------- +// Purpose: A new act has just begun +//----------------------------------------------------------------------------- +void __MsgFunc_ActBegin(bf_read &msg) +{ + int iActNumber = (char)msg.ReadByte(); + float flStartTime = msg.ReadFloat(); + + StartAct( iActNumber, flStartTime ); +} + +//----------------------------------------------------------------------------- +// Purpose: An act has just ended +//----------------------------------------------------------------------------- +void __MsgFunc_ActEnd(bf_read &msg) +{ + CHudTimer *timer = GET_HUDELEMENT( CHudTimer ); + if ( timer ) + { + timer->SetNoFixedTimer( 0.0f ); + } +} diff --git a/game/client/tf2/tf_in_main.cpp b/game/client/tf2/tf_in_main.cpp new file mode 100644 index 0000000..f7ccd63 --- /dev/null +++ b/game/client/tf2/tf_in_main.cpp @@ -0,0 +1,36 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: TF2 specific input handling +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "kbutton.h" +#include "input.h" + +//----------------------------------------------------------------------------- +// Purpose: TF Input interface +//----------------------------------------------------------------------------- +class CTFInput : public CInput +{ +public: + int GetButtonBits( int ); +}; + +static CTFInput g_Input; + +// Expose this interface +IInput *input = ( IInput * )&g_Input; + + +//----------------------------------------------------------------------------- +// Purpose: Remove Jump from the input bits +//----------------------------------------------------------------------------- +int CTFInput::GetButtonBits( int bResetState ) +{ + int iBits = CInput::GetButtonBits( bResetState ); + + //iBits &= ~IN_JUMP; + + return iBits; +} diff --git a/game/client/tf2/tf_prediction.cpp b/game/client/tf2/tf_prediction.cpp new file mode 100644 index 0000000..8ab5608 --- /dev/null +++ b/game/client/tf2/tf_prediction.cpp @@ -0,0 +1,245 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "prediction.h" +#include "tf_movedata.h" +#include "c_basetfplayer.h" +#include "c_tf_class_recon.h" +#include "c_tf_class_commando.h" + +static CTFMoveData g_TFMoveData; +CMoveData *g_pMoveData = &g_TFMoveData; + + +class CTFPrediction : public CPrediction +{ +DECLARE_CLASS( CTFPrediction, CPrediction ); + +public: + virtual void SetupMove( C_BasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move ); + virtual void FinishMove( C_BasePlayer *player, CUserCmd *ucmd, CMoveData *move ); + +private: + + void SetupMoveRecon( CUserCmd *ucmd, C_BaseTFPlayer *pTFPlayer, IMoveHelper *pHelper, + CTFMoveData *pTFMove ); + void SetupMoveCommando( CUserCmd *ucmd, C_BaseTFPlayer *pTFPlayer, IMoveHelper *pHelper, + CTFMoveData *pTFMove ); + + void FinishMoveRecon( CTFMoveData *pTFMove, C_BaseTFPlayer *pTFPlayer ); + void FinishMoveCommando( CTFMoveData *pTFMove, C_BaseTFPlayer *pTFPlayer ); +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFPrediction::SetupMove( C_BasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, + CMoveData *move ) +{ + // Call the default SetupMove code. + BaseClass::SetupMove( player, ucmd, pHelper, move ); + + // + // Convert to TF2 data. + // + C_BaseTFPlayer *pTFPlayer = static_cast<C_BaseTFPlayer*>( player ); + Assert( pTFPlayer ); + + CTFMoveData *pTFMove = static_cast<CTFMoveData*>( move ); + Assert( pTFMove ); + + // + // Handle player class specific setup. + // + pTFMove->m_nClassID = pTFPlayer->PlayerClass(); + switch( pTFPlayer->GetClass() ) + { + case TFCLASS_RECON: + { + SetupMoveRecon( ucmd, pTFPlayer, pHelper, pTFMove ); + break; + } + case TFCLASS_COMMANDO: + { + SetupMoveCommando( ucmd, pTFPlayer, pHelper, pTFMove ); + break; + } + default: + { +// pTFMove->m_nClassID = TFCLASS_UNDECIDED; + break; + } + } + + // + // Player movement data. + // + + // Copy the position delta. + pTFMove->m_vecPosDelta = pTFPlayer->m_vecPosDelta; + + // Copy the momentum data. + pTFMove->m_iMomentumHead = pTFPlayer->m_iMomentumHead; + for ( int iMomentum = 0; iMomentum < CTFMoveData::MOMENTUM_MAXSIZE; iMomentum++ ) + { + pTFMove->m_aMomentum[iMomentum] = pTFPlayer->m_aMomentum[iMomentum]; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFPrediction::SetupMoveRecon( CUserCmd *ucmd, C_BaseTFPlayer *pTFPlayer, IMoveHelper *pHelper, + CTFMoveData *pTFMove ) +{ + C_PlayerClassRecon *pRecon = static_cast<C_PlayerClassRecon*>( pTFPlayer->GetPlayerClass() ); + if ( pRecon ) + { + PlayerClassReconData_t *pReconData = pRecon->GetClassData(); + if ( pReconData ) + { + pTFMove->ReconData().m_nJumpCount = pReconData->m_nJumpCount; + pTFMove->ReconData().m_flSuppressionJumpTime = pReconData->m_flSuppressionJumpTime; + pTFMove->ReconData().m_flSuppressionImpactTime = pReconData->m_flSuppressionImpactTime; + pTFMove->ReconData().m_flActiveJumpTime = pReconData->m_flActiveJumpTime; + pTFMove->ReconData().m_flStickTime = pReconData->m_flStickTime; + pTFMove->ReconData().m_flImpactDist = pReconData->m_flImpactDist; + pTFMove->ReconData().m_vecImpactNormal = pReconData->m_vecImpactNormal; + pTFMove->ReconData().m_vecUnstickVelocity = pReconData->m_vecUnstickVelocity; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFPrediction::SetupMoveCommando( CUserCmd *ucmd, C_BaseTFPlayer *pTFPlayer, IMoveHelper *pHelper, + CTFMoveData *pTFMove ) +{ + C_PlayerClassCommando *pCommando = static_cast<C_PlayerClassCommando*>( pTFPlayer->GetPlayerClass() ); + if ( pCommando ) + { + PlayerClassCommandoData_t *pCommandoData = pCommando->GetClassData(); + if ( pCommandoData ) + { + pTFMove->CommandoData().m_bCanBullRush = pCommandoData->m_bCanBullRush; + pTFMove->CommandoData().m_bBullRush = pCommandoData->m_bBullRush; + pTFMove->CommandoData().m_vecBullRushDir = pCommandoData->m_vecBullRushDir; + pTFMove->CommandoData().m_vecBullRushViewDir = pCommandoData->m_vecBullRushViewDir; + pTFMove->CommandoData().m_vecBullRushViewGoalDir = pCommandoData->m_vecBullRushViewGoalDir; + pTFMove->CommandoData().m_flBullRushTime = pCommandoData->m_flBullRushTime; + pTFMove->CommandoData().m_flDoubleTapForwardTime = pCommandoData->m_flDoubleTapForwardTime; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFPrediction::FinishMove( C_BasePlayer *player, CUserCmd *ucmd, CMoveData *move ) +{ + // Call the default FinishMove code. + BaseClass::FinishMove( player, ucmd, move ); + + // + // Convert to TF2 data. + // + C_BaseTFPlayer *pTFPlayer = static_cast<C_BaseTFPlayer*>( player ); + Assert( pTFPlayer ); + + CTFMoveData *pTFMove = static_cast<CTFMoveData*>( move ); + Assert( pTFMove ); + + // + // Handle player class specific setup. + // + switch( pTFPlayer->PlayerClass() ) + { + case TFCLASS_RECON: + { + FinishMoveRecon( pTFMove, pTFPlayer ); + break; + } + case TFCLASS_COMMANDO: + { + FinishMoveCommando( pTFMove, pTFPlayer ); + break; + } + default: + { + break; + } + } + + // + // Player movement data. + // + + // Copy the position delta. + pTFPlayer->m_vecPosDelta = pTFMove->m_vecPosDelta; + + // Copy the momentum data back (the movement may have updated it!). + pTFPlayer->m_iMomentumHead = pTFMove->m_iMomentumHead; + for ( int iMomentum = 0; iMomentum < CTFMoveData::MOMENTUM_MAXSIZE; iMomentum++ ) + { + pTFPlayer->m_aMomentum[iMomentum] = pTFMove->m_aMomentum[iMomentum]; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFPrediction::FinishMoveRecon( CTFMoveData *pTFMove, C_BaseTFPlayer *pTFPlayer ) +{ + C_PlayerClassRecon *pRecon = static_cast<C_PlayerClassRecon*>( pTFPlayer->GetPlayerClass() ); + if ( pRecon ) + { + PlayerClassReconData_t *pReconData = pRecon->GetClassData(); + if ( pReconData ) + { + pReconData->m_nJumpCount = pTFMove->ReconData().m_nJumpCount; + pReconData->m_flSuppressionJumpTime = pTFMove->ReconData().m_flSuppressionJumpTime; + pReconData->m_flSuppressionImpactTime = pTFMove->ReconData().m_flSuppressionImpactTime; + pReconData->m_flActiveJumpTime = pTFMove->ReconData().m_flActiveJumpTime; + pReconData->m_flStickTime = pTFMove->ReconData().m_flStickTime; + pReconData->m_flImpactDist = pTFMove->ReconData().m_flImpactDist; + pReconData->m_vecImpactNormal = pTFMove->ReconData().m_vecImpactNormal; + pReconData->m_vecUnstickVelocity = pTFMove->ReconData().m_vecUnstickVelocity; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFPrediction::FinishMoveCommando( CTFMoveData *pTFMove, C_BaseTFPlayer *pTFPlayer ) +{ + C_PlayerClassCommando *pCommando = static_cast<C_PlayerClassCommando*>( pTFPlayer->GetPlayerClass() ); + if ( pCommando ) + { + PlayerClassCommandoData_t *pCommandoData = pCommando->GetClassData(); + if ( pCommandoData ) + { + pCommandoData->m_bCanBullRush = pTFMove->CommandoData().m_bCanBullRush; + pCommandoData->m_bBullRush = pTFMove->CommandoData().m_bBullRush; + pCommandoData->m_vecBullRushDir = pTFMove->CommandoData().m_vecBullRushDir; + pCommandoData->m_vecBullRushViewDir = pTFMove->CommandoData().m_vecBullRushViewDir; + pCommandoData->m_vecBullRushViewGoalDir = pTFMove->CommandoData().m_vecBullRushViewGoalDir; + pCommandoData->m_flBullRushTime = pTFMove->CommandoData().m_flBullRushTime; + pCommandoData->m_flDoubleTapForwardTime = pTFMove->CommandoData().m_flDoubleTapForwardTime; + } + } +} + +// Expose interface to engine +// Expose interface to engine +static CTFPrediction g_Prediction; + +EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CTFPrediction, IPrediction, VCLIENT_PREDICTION_INTERFACE_VERSION, g_Prediction ); + +CPrediction *prediction = &g_Prediction; + diff --git a/game/client/tf2/vgui_healthbar.cpp b/game/client/tf2/vgui_healthbar.cpp new file mode 100644 index 0000000..83e9768 --- /dev/null +++ b/game/client/tf2/vgui_healthbar.cpp @@ -0,0 +1,134 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "vgui_HealthBar.h" +#include "CommanderOverlay.h" +#include <vgui_controls/Controls.h> +#include <vgui/ISurface.h> + +//----------------------------------------------------------------------------- +// Purpose: +// Output : +//----------------------------------------------------------------------------- +CHealthBarPanel::CHealthBarPanel( vgui::Panel *pParent ) : vgui::Panel(pParent, "CHealthBarPanel" ) +{ + SetHealth( 0.0f ); + SetPaintBackgroundEnabled( false ); + SetVertical( false ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CHealthBarPanel::~CHealthBarPanel( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Parse values from the file +//----------------------------------------------------------------------------- +bool CHealthBarPanel::Init( KeyValues* pInitData ) +{ + if (!pInitData) + return false; + + if (!ParseRGBA(pInitData, "okcolor", m_Ok )) + return false; + + if (!ParseRGBA(pInitData, "badcolor", m_Bad )) + return false; + + int x, y, w, h; + if (!ParseRect(pInitData, "position", x, y, w, h )) + return false; + SetPos( x, y ); + SetSize( w, h ); + SetCursor( NULL ); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHealthBarPanel::SetGoodColor( int r, int g, int b, int a ) +{ + m_Ok.SetColor( r,g,b,a ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHealthBarPanel::SetBadColor( int r, int g, int b, int a ) +{ + m_Bad.SetColor( r,g,b,a ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHealthBarPanel::SetHealth( float health ) +{ + m_Health = health; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHealthBarPanel::SetVertical( bool bVertical ) +{ + m_bVertical = bVertical; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHealthBarPanel::Paint( void ) +{ + int w, h; + GetSize( w, h ); + + float frac; + frac = MIN( 1.0, m_Health ); + frac = MAX( 0.0, m_Health ); + + vgui::surface()->DrawSetColor( 255,255,255,255 ); + vgui::surface()->DrawOutlinedRect( 0,0, w,h ); + + int drawwidth = frac * w; + int drawheight = frac * h; + + // Draw the Ok section + vgui::surface()->DrawSetColor( m_Ok[0], m_Ok[1], m_Ok[2], m_Ok[3] ); + if ( m_bVertical ) + { + vgui::surface()->DrawFilledRect( 0, h - drawheight, w, h ); + } + else + { + vgui::surface()->DrawFilledRect( 0, 0, drawwidth, h ); + } + + vgui::surface()->DrawSetColor( m_Bad[0], m_Bad[1], m_Bad[2], m_Bad[3] ); + // Draw the Bad section + if ( m_bVertical ) + { + if (h != drawheight) + { + vgui::surface()->DrawFilledRect( 0, 0, w, h - drawheight ); + } + } + else + { + if (w != drawwidth) + { + vgui::surface()->DrawFilledRect( drawwidth, 0, w, h ); + } + } +}
\ No newline at end of file diff --git a/game/client/tf2/vgui_healthbar.h b/game/client/tf2/vgui_healthbar.h new file mode 100644 index 0000000..4b68f26 --- /dev/null +++ b/game/client/tf2/vgui_healthbar.h @@ -0,0 +1,46 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#ifndef VGUI_HEALTHBAR_H +#define VGUI_HEALTHBAR_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include <vgui_controls/Panel.h> + +class KeyValues; + +class CHealthBarPanel : public vgui::Panel +{ +public: + CHealthBarPanel( vgui::Panel *pParent = NULL ); + virtual ~CHealthBarPanel( void ); + + // Setup + bool Init( KeyValues* pInitData ); + void SetGoodColor( int r, int g, int b, int a ); + void SetBadColor( int r, int g, int b, int a ); + void SetVertical( bool bVertical ); + + // Health is expected to go from 0 to 1 + void SetHealth( float health ); + + virtual void Paint( void ); + virtual void PaintBackground( void ) {} + +private: + float m_Health; + Color m_Ok; + Color m_Bad; + bool m_bVertical; // True if this bar should be vertical +}; + +#endif // VGUI_HEALTHBAR_H
\ No newline at end of file diff --git a/game/client/tf2/vgui_rootpanel_tf2.cpp b/game/client/tf2/vgui_rootpanel_tf2.cpp new file mode 100644 index 0000000..b6bc6c9 --- /dev/null +++ b/game/client/tf2/vgui_rootpanel_tf2.cpp @@ -0,0 +1,41 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "vgui_int.h" +#include "ienginevgui.h" +#include "c_tf2rootpanel.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +C_TF2RootPanel *g_pTF2RootPanel = NULL; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void VGUI_CreateClientDLLRootPanel( void ) +{ + g_pTF2RootPanel = new C_TF2RootPanel( enginevgui->GetPanel( PANEL_CLIENTDLL ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void VGUI_DestroyClientDLLRootPanel( void ) +{ + delete g_pTF2RootPanel; + g_pTF2RootPanel = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: Game specific root panel +// Output : vgui::Panel +//----------------------------------------------------------------------------- +vgui::VPANEL VGui_GetClientDLLRootPanel( void ) +{ + return g_pTF2RootPanel->GetVPanel(); +}
\ No newline at end of file diff --git a/game/client/tf2/vgui_rotation_slider.cpp b/game/client/tf2/vgui_rotation_slider.cpp new file mode 100644 index 0000000..e1ee1e6 --- /dev/null +++ b/game/client/tf2/vgui_rotation_slider.cpp @@ -0,0 +1,74 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include <vgui/MouseCode.h> +#include "vgui_rotation_slider.h" + + +CRotationSlider::CRotationSlider( vgui::Panel *pParent, const char *pName ) : + BaseClass( pParent, pName ) +{ + AddActionSignalTarget( this ); + SetRange( -180, 180 ); + SetTickCaptions("-180", "180"); + SetValue( 0 ); + m_flYaw = 0; +} + +void CRotationSlider::SetControlledObject( C_BaseObject *pObject ) +{ + m_hObject.Set( pObject ); +} + +//----------------------------------------------------------------------------- +// When the slider is activated, deactivated, or moves +//----------------------------------------------------------------------------- +void CRotationSlider::OnMousePressed( vgui::MouseCode code ) +{ + BaseClass::OnMousePressed( code ); + + if (code != vgui::MOUSE_LEFT) + return; + + C_BaseObject *pObj = m_hObject.Get(); + if (pObj) + { + m_flInitialYaw = pObj->GetAbsAngles().y; + pObj->PreviewYaw( m_flInitialYaw ); + pObj->ActivateYawPreview( true ); + } +} + +void CRotationSlider::OnSliderMoved( int position ) +{ + C_BaseObject *pObj = m_hObject.Get(); + if (pObj && pObj->IsPreviewingYaw()) + { + m_flYaw = anglemod(position); + pObj->PreviewYaw( m_flInitialYaw - m_flYaw ); + } +} + +void CRotationSlider::OnMouseReleased( vgui::MouseCode code ) +{ + BaseClass::OnMouseReleased( code ); + + if (code != vgui::MOUSE_LEFT) + return; + + C_BaseObject *pObj = m_hObject.Get(); + if (pObj) + { + char szbuf[48]; + Q_snprintf( szbuf, sizeof( szbuf ), "yaw %0.2f\n", m_flInitialYaw - m_flYaw ); + pObj->SendClientCommand( szbuf ); + pObj->ActivateYawPreview( false ); + SetValue(0); + m_flYaw = 0; + } +} diff --git a/game/client/tf2/vgui_rotation_slider.h b/game/client/tf2/vgui_rotation_slider.h new file mode 100644 index 0000000..549068a --- /dev/null +++ b/game/client/tf2/vgui_rotation_slider.h @@ -0,0 +1,43 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VGUI_ROTATION_SLIDER_H +#define VGUI_ROTATION_SLIDER_H +#ifdef _WIN32 +#pragma once +#endif + + +#include <vgui_controls/Slider.h> +#include "c_baseobject.h" + + +//----------------------------------------------------------------------------- +// +// Slider for object control +// +//----------------------------------------------------------------------------- +class CRotationSlider : public vgui::Slider +{ + DECLARE_CLASS_SIMPLE( CRotationSlider, vgui::Slider ); + +public: + CRotationSlider( vgui::Panel *pParent, const char *pName ); + void SetControlledObject( C_BaseObject *pObject ); + + virtual void OnMousePressed( vgui::MouseCode code ); + virtual void OnMouseReleased( vgui::MouseCode code ); + MESSAGE_FUNC_INT( OnSliderMoved, "SliderMoved", position ); + +private: + CHandle<C_BaseObject> m_hObject; + float m_flInitialYaw; + float m_flYaw; +}; + + +#endif // VGUI_ROTATION_SLIDER_H diff --git a/game/client/tf2/ztestmaterialproxy.cpp b/game/client/tf2/ztestmaterialproxy.cpp new file mode 100644 index 0000000..102cd34 --- /dev/null +++ b/game/client/tf2/ztestmaterialproxy.cpp @@ -0,0 +1,64 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "materialsystem/imaterialproxy.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/imaterialvar.h" + +// $sineVar : name of variable that controls the alpha level (float) +class CzTestMaterialProxy : public IMaterialProxy +{ +public: + CzTestMaterialProxy(); + virtual ~CzTestMaterialProxy(); + virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); + virtual void OnBind( void *pC_BaseEntity ); + virtual void Release( void ) { delete this; } +private: + C_BaseEntity *BindArgToEntity( void *pArg ); + + IMaterialVar *m_AlphaVar; +}; + +CzTestMaterialProxy::CzTestMaterialProxy() +{ + m_AlphaVar = NULL; +} + +CzTestMaterialProxy::~CzTestMaterialProxy() +{ +} + +C_BaseEntity *CzTestMaterialProxy::BindArgToEntity( void *pArg ) +{ + IClientRenderable *pRend = (IClientRenderable *)pArg; + return pRend->GetIClientUnknown()->GetBaseEntity(); +} + +bool CzTestMaterialProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) +{ + bool foundVar; + m_AlphaVar = pMaterial->FindVar( "$alpha", &foundVar, false ); + return foundVar; +} + +void CzTestMaterialProxy::OnBind( void *pC_BaseEntity ) +{ + C_BaseEntity *pEnt = BindArgToEntity( pC_BaseEntity ); + if( !pEnt ) + { + return; + } + + if (m_AlphaVar) + { + m_AlphaVar->SetFloatValue( pEnt->m_clrRender.a ); + } + +} + +EXPOSE_INTERFACE( CzTestMaterialProxy, IMaterialProxy, "zTest" IMATERIAL_PROXY_INTERFACE_VERSION ); |