Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
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.
 
 
 
 
 
 

869 lines
24 KiB

//========= 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);
}