You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
389 lines
12 KiB
389 lines
12 KiB
//========= 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); |
|
} |
|
|
|
|