source-engine/game/client/dod/dod_hud_ammo.cpp
2022-04-16 12:05:19 +03:00

509 lines
13 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "hud.h"
#include "hudelement.h"
#include "hud_macros.h"
#include "hud_bitmapnumericdisplay.h"
#include "iclientmode.h"
#include "c_dod_player.h"
#include "ihudlcd.h"
#include <vgui/ISurface.h>
#include <vgui_controls/AnimationController.h>
//-----------------------------------------------------------------------------
// Purpose: Displays current ammunition level
//-----------------------------------------------------------------------------
class CHudAmmo : public CHudElement, public vgui::Panel
{
DECLARE_CLASS_SIMPLE( CHudAmmo, vgui::Panel );
public:
CHudAmmo( const char *pElementName );
void Init( void );
void VidInit( void );
void SetAmmo(int ammo, bool playAnimation);
void SetAmmo2(int ammo2, bool playAnimation);
protected:
virtual void OnThink();
virtual void Paint( void );
virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
private:
void DrawText( char *text, int x, int y, Color clrText );
void DrawNumbers( int num, int x, int y );
void PaintGrenadeAmmo( CWeaponDODBase *pWpn );
void PaintBazookaAmmo( CWeaponDODBase *pWpn );
void PaintMGAmmo( CWeaponDODBase *pWpn );
void PaintGunAmmo( CWeaponDODBase *pWpn );
void PaintRifleGrenadeAmmo( CWeaponDODBase *pWpn );
CHandle< C_BaseCombatWeapon > m_hCurrentActiveWeapon;
int m_iAmmo;
int m_iAmmo2;
bool m_bUsesClips;
int m_iAdditiveWhiteID;
CPanelAnimationVarAliasType( float, digit2_xpos, "digit2_xpos", "0", "proportional_float" );
CPanelAnimationVarAliasType( float, digit2_ypos, "digit2_ypos", "0", "proportional_float" );
CPanelAnimationVarAliasType( float, bar_xpos, "bar_xpos", "0", "proportional_float" );
CPanelAnimationVarAliasType( float, bar_ypos, "bar_ypos", "0", "proportional_float" );
CPanelAnimationVarAliasType( float, bar_width, "bar_width", "2", "proportional_float" );
CPanelAnimationVarAliasType( float, bar_height, "bar_height", "2", "proportional_float" );
CPanelAnimationVarAliasType( float, icon_xpos, "icon_xpos", "0", "proportional_float" );
CPanelAnimationVarAliasType( float, icon_ypos, "icon_ypos", "0", "proportional_float" );
CPanelAnimationVar( vgui::HFont, m_hNumberFont, "NumberFont", "HudSelectionNumbers" );
Color m_clrIcon;
CHudTexture *m_pMGNumbers[10];
};
//DECLARE_HUDELEMENT( CHudAmmo );
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CHudAmmo::CHudAmmo( const char *pElementName ) : vgui::Panel( NULL, "HudAmmo" ), CHudElement( pElementName )
{
SetParent( g_pClientMode->GetViewport() );
m_iAdditiveWhiteID = vgui::surface()->CreateNewTextureID();
vgui::surface()->DrawSetTextureFile( m_iAdditiveWhiteID, "vgui/white_additive" , true, false);
SetActive( true );
m_clrIcon = Color(255,255,255,255);
SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD | HIDEHUD_WEAPONSELECTION );
hudlcd->SetGlobalStat( "(ammo_primary)", "0" );
hudlcd->SetGlobalStat( "(ammo_secondary)", "0" );
hudlcd->SetGlobalStat( "(weapon_print_name)", "" );
hudlcd->SetGlobalStat( "(weapon_name)", "" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudAmmo::Init( void )
{
m_iAmmo = -1;
m_iAmmo2 = -1;
}
void CHudAmmo::ApplySchemeSettings(vgui::IScheme *pScheme)
{
BaseClass::ApplySchemeSettings(pScheme);
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudAmmo::VidInit( void )
{
}
//-----------------------------------------------------------------------------
// Purpose: called every frame to get ammo info from the weapon
//-----------------------------------------------------------------------------
void CHudAmmo::OnThink()
{
C_BaseCombatWeapon *wpn = GetActiveWeapon();
hudlcd->SetGlobalStat( "(weapon_print_name)", wpn ? wpn->GetPrintName() : " " );
hudlcd->SetGlobalStat( "(weapon_name)", wpn ? wpn->GetName() : " " );
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
if (!wpn || !player || !wpn->UsesPrimaryAmmo())
{
hudlcd->SetGlobalStat( "(ammo_primary)", "n/a" );
hudlcd->SetGlobalStat( "(ammo_secondary)", "n/a" );
SetPaintEnabled(false);
SetPaintBackgroundEnabled(false);
return;
}
else
{
SetPaintEnabled(true);
SetPaintBackgroundEnabled(true);
}
// get the ammo in our clip
int ammo1 = wpn->Clip1();
int ammo2;
if (ammo1 < 0)
{
// we don't use clip ammo, just use the total ammo count
ammo1 = player->GetAmmoCount(wpn->GetPrimaryAmmoType());
ammo2 = 0;
}
else
{
// we use clip ammo, so the second ammo is the total ammo
ammo2 = player->GetAmmoCount(wpn->GetPrimaryAmmoType());
}
hudlcd->SetGlobalStat( "(ammo_primary)", VarArgs( "%d", ammo1 ) );
hudlcd->SetGlobalStat( "(ammo_secondary)", VarArgs( "%d", ammo2 ) );
if (wpn == m_hCurrentActiveWeapon)
{
// same weapon, just update counts
SetAmmo(ammo1, true);
SetAmmo2(ammo2, true);
}
else
{
// diferent weapon, change without triggering
SetAmmo(ammo1, false);
SetAmmo2(ammo2, false);
// update whether or not we show the total ammo display
if (wpn->UsesClipsForAmmo1())
{
m_bUsesClips = true;
}
else
{
m_bUsesClips = false;
}
m_hCurrentActiveWeapon = wpn;
}
}
//-----------------------------------------------------------------------------
// Purpose: Updates ammo display
//-----------------------------------------------------------------------------
void CHudAmmo::SetAmmo(int ammo, bool playAnimation)
{
if (ammo != m_iAmmo)
{
m_iAmmo = ammo;
}
}
//-----------------------------------------------------------------------------
// Purpose: Updates 2nd ammo display
//-----------------------------------------------------------------------------
void CHudAmmo::SetAmmo2(int ammo2, bool playAnimation)
{
if (ammo2 != m_iAmmo2)
{
m_iAmmo2 = ammo2;
}
}
void CHudAmmo::PaintGrenadeAmmo( CWeaponDODBase *pWpn )
{
const CHudTexture *pAmmoIcon = pWpn->GetSpriteAmmo();
Assert( pAmmoIcon );
int x,y,w,h;
GetBounds( x, y, w, h );
if (m_iAmmo > 0 && pAmmoIcon )
{
int xpos = w - 2 * pAmmoIcon->Width();
int ypos = h - pAmmoIcon->Height();
pAmmoIcon->DrawSelf( xpos, ypos, pAmmoIcon->Width(), pAmmoIcon->Height(), m_clrIcon );
char buf[16];
Q_snprintf( buf, sizeof(buf), "x %d", m_iAmmo );
DrawText( buf, xpos + pAmmoIcon->Width(), ypos + pAmmoIcon->Height() / 2, m_clrIcon );
}
}
void CHudAmmo::PaintRifleGrenadeAmmo( CWeaponDODBase *pWpn )
{
const CHudTexture *pAmmoIcon = pWpn->GetSpriteAmmo();
Assert( pAmmoIcon );
int x,y,w,h;
GetBounds( x, y, w, h );
int ammo = m_iAmmo + m_iAmmo2;
if (ammo > 0 && pAmmoIcon )
{
int xpos = w - 2 * pAmmoIcon->Width();
int ypos = h - pAmmoIcon->Height();
pAmmoIcon->DrawSelf( xpos, ypos, pAmmoIcon->Width(), pAmmoIcon->Height(), m_clrIcon );
char buf[16];
Q_snprintf( buf, sizeof(buf), "x %d", ammo );
DrawText( buf, xpos + pAmmoIcon->Width(), ypos + pAmmoIcon->Height() / 2, m_clrIcon );
}
}
void CHudAmmo::PaintBazookaAmmo( CWeaponDODBase *pWpn )
{
const CHudTexture *pTubeIcon = pWpn->GetSpriteAmmo2();
const CHudTexture *pRocketIcon = pWpn->GetSpriteAmmo();
const CHudTexture *pExtraIcon = pWpn->GetSpriteAutoaim();
Assert( pTubeIcon );
Assert( pRocketIcon );
Assert( pExtraIcon );
int xpos = 0;
int ypos = 0;
int x, y, w, h;
GetBounds(x,y,w,h);
//Draw the rocket tube
if( pTubeIcon )
{
xpos = w - 2 * pTubeIcon->Width();
ypos = h - pTubeIcon->Height();
pTubeIcon->DrawSelf( xpos, ypos, m_clrIcon );
}
//If our clip is full, draw the rocket
if( pRocketIcon )
{
if( m_iAmmo > 0 )
pRocketIcon->DrawSelf( xpos, ypos, m_clrIcon );
xpos += pRocketIcon->Width() + 10;
ypos += pRocketIcon->Height();
}
char buf[16];
Q_snprintf( buf, sizeof(buf), "%d %d", m_iAmmo, m_iAmmo2 );
DrawText( buf, xpos, ypos, m_clrIcon );
//Draw the extra rockets
if( m_iAmmo2 > 0 && pExtraIcon )
{
ypos -= pExtraIcon->Height();
pExtraIcon->DrawSelf( xpos, ypos, m_clrIcon );
xpos += pExtraIcon->Width();
char buf[16];
Q_snprintf( buf, sizeof(buf), "x %d", m_iAmmo2 );
DrawText( buf, xpos, ypos + ( pExtraIcon->Height() * 0.75 ), m_clrIcon );
}
}
void CHudAmmo::PaintMGAmmo( CWeaponDODBase *pWpn )
{
const CHudTexture *pFullClip = pWpn->GetSpriteAmmo();
const CHudTexture *pExtraClip = pWpn->GetSpriteAmmo2();
int xpos = 0;
int ypos = 0;
int x, y, w, h;
GetBounds(x,y,w,h);
if( pFullClip )
{
xpos = w - pFullClip->Width() * 3;
ypos = h - pFullClip->Height();
pFullClip->DrawSelf( xpos, ypos, m_clrIcon );
//Haxoration! The box that contains the numbers must be in the same position
// in both the webley and mg34/mg42/30cal sprites.
DrawNumbers( m_iAmmo, xpos + 36, ypos + pFullClip->Height() - 16 );
xpos += pFullClip->Width();
ypos += pFullClip->Height();
}
//how many full or partially full clips do we have?
int clips = m_iAmmo2 / pWpn->GetMaxClip1();
//account for the partial clip, if it exists
if( clips * pWpn->GetMaxClip1() < m_iAmmo2 )
clips++;
if( pExtraClip && clips > 0 )
{
ypos -= pExtraClip->Height();
pExtraClip->DrawSelf( xpos, ypos, m_clrIcon );
char buf[16];
Q_snprintf( buf, sizeof(buf), "x %d", clips );
DrawText( buf, xpos + pExtraClip->Width(), ypos + pExtraClip->Height() / 2, m_clrIcon );
}
}
void CHudAmmo::PaintGunAmmo( CWeaponDODBase *pWpn )
{
//regular gun
const CHudTexture *pEmptyClip = pWpn->GetSpriteAmmo();
const CHudTexture *pFullClip = pWpn->GetSpriteAmmo2();
const CHudTexture *pExtraClip = pWpn->GetSpriteAutoaim();
Assert( pEmptyClip );
Assert( pFullClip );
Assert( pExtraClip );
int x, y, w, h;
GetBounds( x, y, w, h );
int xpos = 0;
int ypos = 0;
if( pFullClip )
{
xpos = w - 3 * pFullClip->Width();
ypos = h - pFullClip->Height() * 1.2;
//Always draw the empty clip
pFullClip->DrawSelf( xpos, ypos, Color(255,255,255,255) );
}
if( pEmptyClip )
{
// base percent is how much of the bullet clip to always draw.
// total cropped height of the bullet sprite will be
// base percent + bullet height * bullets
float flBasePercent = (float)pWpn->GetDODWpnData().m_iHudClipBaseHeight / (float)pWpn->GetDODWpnData().m_iHudClipHeight;
float flBulletHeightPercent = (float)pWpn->GetDODWpnData().m_iHudClipBulletHeight / (float)pWpn->GetDODWpnData().m_iHudClipHeight;
float flHeight = (float)pEmptyClip->Height();
//Now we draw the bullets inside based on how full our clip is
float flDrawHeight = flHeight * ( 1.0 - ( flBasePercent + flBulletHeightPercent * m_iAmmo ) );
int nOffset = (int)flDrawHeight;
pEmptyClip->DrawSelfCropped( xpos, ypos + nOffset, 0, nOffset, pEmptyClip->Width(), pEmptyClip->Height() - nOffset, Color(255,255,255,255) );
ypos += pEmptyClip->Height();
xpos += pEmptyClip->Width() + 10;
}
//how many full or partially full clips do we have?
int clips = m_iAmmo2 / pWpn->GetMaxClip1();
//account for the partial clip, if it exists
if( clips * pWpn->GetMaxClip1() < m_iAmmo2 )
clips++;
if( pExtraClip && clips > 0 )
{
//align the extra clip on the same baseline as the large clip
ypos -= pExtraClip->Height();
pExtraClip->DrawSelf( xpos, ypos, Color(255,255,255,255) );
char buf[16];
Q_snprintf( buf, sizeof(buf), "x %d", clips );
DrawText( buf, xpos + pExtraClip->Width(), ypos + pExtraClip->Height() / 2, m_clrIcon );
}
}
void CHudAmmo::Paint( void )
{
C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer();
if( !pPlayer )
return;
CWeaponDODBase *pWpn = pPlayer->GetActiveDODWeapon();
if( !pWpn )
return;
switch( pWpn->GetDODWpnData().m_WeaponType )
{
case WPN_TYPE_GRENADE:
PaintGrenadeAmmo(pWpn);
break;
case WPN_TYPE_RIFLEGRENADE:
PaintRifleGrenadeAmmo(pWpn);
break;
case WPN_TYPE_BAZOOKA:
PaintBazookaAmmo(pWpn);
break;
case WPN_TYPE_MG:
PaintMGAmmo(pWpn);
break;
default:
PaintGunAmmo(pWpn);
break;
}
}
void CHudAmmo::DrawText( char *text, int x, int y, Color clrText )
{
vgui::surface()->DrawSetTextColor( clrText );
vgui::surface()->DrawSetTextFont( m_hNumberFont );
vgui::surface()->DrawSetTextPos( x, y );
for (char *pch = text; *pch != 0; pch++)
{
vgui::surface()->DrawUnicodeChar(*pch);
}
}
void CHudAmmo::DrawNumbers( int num, int x, int y )
{
if( !m_pMGNumbers[0] )
{
int i;
for( i=0;i<10;i++ )
{
char buf[8];
Q_snprintf( buf, sizeof(buf), "mg_%d", i );
m_pMGNumbers[i] = gHUD.GetIcon( buf );
}
}
Assert( num < 1000 );
int xpos = x;
int ypos = y;
int num_working = num;
int iconWidth = m_pMGNumbers[0]->Width();
int hundreds = num_working / 100;
num_working -= hundreds * 100;
m_pMGNumbers[hundreds]->DrawSelf( xpos, ypos, m_clrIcon );
xpos += iconWidth;
int tens = num_working / 10;
num_working -= tens * 10;
m_pMGNumbers[tens]->DrawSelf( xpos, ypos, m_clrIcon );
xpos += iconWidth;
m_pMGNumbers[num_working]->DrawSelf( xpos, ypos, m_clrIcon );
xpos += iconWidth;
}