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

701 lines
19 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "iclientmode.h"
#include "c_dod_player.h"
#include <vgui/IScheme.h>
#include <vgui/ISurface.h>
#include <vgui_controls/AnimationController.h>
#include "dod_hud_playerstatus_ammo.h"
#include "ihudlcd.h"
float GetScale( int nIconWidth, int nIconHeight, int nWidth, int nHeight )
{
float flScale = 1.0;
if ( nIconWidth == nWidth && nIconHeight <= nHeight ) // no scaling necessary
{
return flScale;
}
else if ( nIconHeight == nHeight && nIconWidth <= nWidth ) // no scaling necessary
{
return flScale;
}
else if ( nIconWidth < nWidth && nIconHeight < nHeight ) // scale the image up
{
float scaleW = 0.0, scaleH = 0.0;
if ( nIconWidth < nWidth )
{
scaleW = (float)nWidth / (float)nIconWidth;
}
if ( nIconHeight < nHeight )
{
scaleH = (float)nHeight / (float)nIconHeight;
}
if ( scaleW != 0.0 && scaleH != 0.0 )
{
if ( scaleW < scaleH )
{
flScale = scaleW;
}
else
{
flScale = scaleH;
}
}
else if ( scaleW != 0.0 )
{
flScale = scaleW;
}
else
{
flScale = scaleH;
}
}
else // scale the image down
{
float scaleW = 0.0, scaleH = 0.0;
if ( nIconWidth > nWidth )
{
scaleW = (float)nWidth / (float)nIconWidth;
}
if ( nIconHeight > nHeight )
{
scaleH = (float)nHeight / (float)nIconHeight;
}
if ( scaleW != 0.0 && scaleH != 0.0 )
{
if ( scaleW < scaleH )
{
flScale = scaleW;
}
else
{
flScale = scaleH;
}
}
else if ( scaleW != 0.0 )
{
flScale = scaleW;
}
else
{
flScale = scaleH;
}
}
return flScale;
}
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CDoDHudAmmo::CDoDHudAmmo( vgui::Panel *parent, const char *name ) : vgui::Panel( parent, name )
{
m_iAdditiveWhiteID = vgui::surface()->CreateNewTextureID();
vgui::surface()->DrawSetTextureFile( m_iAdditiveWhiteID, "vgui/white_additive", true, false );
m_clrIcon = Color( 255, 255, 255, 255 );
hudlcd->SetGlobalStat( "(ammo_primary)", "0" );
hudlcd->SetGlobalStat( "(ammo_secondary)", "0" );
hudlcd->SetGlobalStat( "(weapon_print_name)", "" );
hudlcd->SetGlobalStat( "(weapon_name)", "" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDoDHudAmmo::Init( void )
{
m_iAmmo = -1;
m_iAmmo2 = -1;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDoDHudAmmo::ApplySchemeSettings( vgui::IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
m_clrTextColor = pScheme->GetColor( "HudAmmoCount", GetFgColor() );
m_clrTextXColor = pScheme->GetColor( "HudPanelBorder", GetFgColor() );
}
//-----------------------------------------------------------------------------
// Purpose: called every frame to get ammo info from the weapon
//-----------------------------------------------------------------------------
void CDoDHudAmmo::OnThink()
{
C_BaseCombatWeapon *wpn = GetActiveWeapon();
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
hudlcd->SetGlobalStat( "(weapon_print_name)", wpn ? wpn->GetPrintName() : " " );
hudlcd->SetGlobalStat( "(weapon_name)", wpn ? wpn->GetName() : " " );
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
m_bUsesClips = wpn->UsesClipsForAmmo1();
m_hCurrentActiveWeapon = wpn;
}
}
//-----------------------------------------------------------------------------
// Purpose: Updates ammo display
//-----------------------------------------------------------------------------
void CDoDHudAmmo::SetAmmo( int ammo, bool playAnimation )
{
if ( ammo != m_iAmmo )
{
m_iAmmo = ammo;
}
}
//-----------------------------------------------------------------------------
// Purpose: Updates 2nd ammo display
//-----------------------------------------------------------------------------
void CDoDHudAmmo::SetAmmo2( int ammo2, bool playAnimation )
{
if ( ammo2 != m_iAmmo2 )
{
m_iAmmo2 = ammo2;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDoDHudAmmo::DrawAmmoCount( int count )
{
char buf[16];
Q_snprintf( buf, sizeof(buf), "x" );
DrawText( buf, clip_count_text_xpos, clip_count_text_ypos, m_clrTextXColor );
Q_snprintf( buf, sizeof(buf), " %d", count );
DrawText( buf, clip_count_text_xpos, clip_count_text_ypos, m_clrTextColor );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDoDHudAmmo::PaintGrenadeAmmo( CWeaponDODBase *pWpn )
{
const CHudTexture *pAmmoIcon = pWpn->GetSpriteAmmo();
Assert( pAmmoIcon );
int xpos = small_icon_xpos, ypos = small_icon_ypos;
int w = small_icon_width, t = small_icon_height;
int nIconWidth = 0, nIconHeight = 0;
float scale = 1.0f;
if ( pAmmoIcon )
{
nIconWidth = pAmmoIcon->Width();
nIconHeight = pAmmoIcon->Height();
scale = GetScale( nIconWidth, nIconHeight, w, t );
nIconWidth *= scale;
nIconHeight *= scale;
if ( nIconWidth < small_icon_width - XRES(2) ) // 2 is our buffer for when we need to re-calculate the xpos
{
xpos = small_icon_xpos + small_icon_width / 2.0 - nIconWidth / 2.0;
}
if ( nIconHeight < small_icon_height - YRES(2) ) // 2 is our buffer for when we need to re-calculate the ypos
{
ypos = small_icon_ypos + small_icon_height / 2.0 - nIconHeight / 2.0;
}
if ( m_iAmmo > 0 )
{
pAmmoIcon->DrawSelf( xpos, ypos, nIconWidth, nIconHeight, m_clrIcon );
DrawAmmoCount( m_iAmmo );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDoDHudAmmo::PaintRifleGrenadeAmmo( CWeaponDODBase *pWpn )
{
const CHudTexture *pAmmoIcon = pWpn->GetSpriteAmmo();
Assert( pAmmoIcon );
int xpos = small_icon_xpos, ypos = small_icon_ypos;
int w = small_icon_width, t = small_icon_height;
int nIconWidth = 0, nIconHeight = 0;
float scale = 1.0f;
if ( pAmmoIcon )
{
nIconWidth = pAmmoIcon->Width();
nIconHeight = pAmmoIcon->Height();
scale = GetScale( nIconWidth, nIconHeight, w, t );
nIconWidth *= scale;
nIconHeight *= scale;
if ( nIconWidth < small_icon_width - XRES(2) ) // 2 is our buffer for when we need to re-calculate the xpos
{
xpos = small_icon_xpos + small_icon_width / 2.0 - nIconWidth / 2.0;
}
if ( nIconHeight < small_icon_height - YRES(2) ) // 2 is our buffer for when we need to re-calculate the ypos
{
ypos = small_icon_ypos + small_icon_height / 2.0 - nIconHeight / 2.0;
}
int ammo = m_iAmmo + m_iAmmo2;
if ( ammo > 0 )
{
pAmmoIcon->DrawSelf( xpos, ypos, nIconWidth, nIconHeight, m_clrIcon );
DrawAmmoCount( ammo );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDoDHudAmmo::PaintBazookaAmmo( CWeaponDODBase *pWpn )
{
int panelX, panelY, panelW, panelT;
GetBounds( panelX, panelY, panelW, panelT );
const CHudTexture *pTubeIcon = pWpn->GetSpriteAmmo2();
const CHudTexture *pRocketIcon = pWpn->GetSpriteAmmo();
const CHudTexture *pExtraIcon = pWpn->GetSpriteAutoaim();
Assert( pTubeIcon );
Assert( pRocketIcon );
Assert( pExtraIcon );
int xpos = 0, ypos = 0;
int nIconWidth = 0, nIconHeight = 0;
float scale = 1.0f;
if ( pTubeIcon && pRocketIcon )
{
nIconWidth = pTubeIcon->Width();
nIconHeight = pTubeIcon->Height();
xpos = large_icon_xpos;
ypos = large_icon_ypos;
// mad hax
int width = large_icon_width + XRES(10);
scale = GetScale( nIconWidth, nIconHeight, width, large_icon_height );
nIconWidth *= scale;
nIconHeight *= scale;
if ( nIconWidth < large_icon_width - XRES(2) ) // 2 is our buffer for when we need to re-calculate the xpos
{
xpos = small_icon_xpos + small_icon_width / 2.0 - nIconWidth / 2.0;
}
if ( nIconHeight < large_icon_height - YRES(2) ) // 2 is our buffer for when we need to re-calculate the ypos
{
ypos = small_icon_ypos + small_icon_height / 2.0 - nIconHeight / 2.0;
}
pTubeIcon->DrawSelf( xpos, ypos, nIconWidth, nIconHeight, m_clrIcon );
// If our clip is full, draw the rocket
if( pRocketIcon )
{
if( m_iAmmo > 0 )
{
pRocketIcon->DrawSelf( xpos, ypos, nIconWidth, nIconHeight, m_clrIcon );
}
}
}
// Draw the extra rockets
if( m_iAmmo2 > 0 && pExtraIcon )
{
// Align the extra clip on the same baseline as the large clip
xpos = extra_clip_xpos;
ypos = extra_clip_ypos;
nIconWidth = pExtraIcon->Width();
nIconHeight = pExtraIcon->Height();
if ( nIconWidth > extra_clip_width || nIconHeight > extra_clip_height )
{
scale = GetScale( nIconWidth, nIconHeight, extra_clip_width, extra_clip_height );
nIconWidth *= scale;
nIconHeight *= scale;
}
if ( nIconWidth < extra_clip_width - XRES(2) ) // 2 is our buffer for when we need to re-calculate the ypos
{
xpos = extra_clip_xpos + extra_clip_width / 2.0 - nIconWidth / 2.0;
}
if ( nIconHeight < extra_clip_height - YRES(2) ) // 2 is our buffer for when we need to re-calculate the ypos
{
ypos = extra_clip_ypos + extra_clip_height / 2.0 - nIconHeight / 2.0;
}
pExtraIcon->DrawSelf( xpos, ypos, pExtraIcon->Width() * scale, pExtraIcon->Height() * scale, m_clrIcon );
DrawAmmoCount( m_iAmmo2 );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDoDHudAmmo::PaintMGAmmo( CWeaponDODBase *pWpn )
{
int panelX, panelY, panelW, panelT;
GetBounds( panelX, panelY, panelW, panelT );
const CHudTexture *pFullClip = pWpn->GetSpriteAmmo();
const CHudTexture *pExtraClip = pWpn->GetSpriteAmmo2();
Assert( pFullClip );
Assert( pExtraClip );
int xpos = 0, ypos = 0;
int nIconWidth = 0, nIconHeight = 0;
float scale = 1.0f;
if ( pFullClip )
{
nIconWidth = pFullClip->Width();
nIconHeight = pFullClip->Height();
xpos = large_icon_xpos;
ypos = large_icon_ypos;
scale = GetScale( nIconWidth, nIconHeight, large_icon_width, large_icon_height );
nIconWidth *= scale;
nIconHeight *= scale;
if ( nIconWidth < large_icon_width - XRES(2) ) // 2 is our buffer for when we need to re-calculate the xpos
{
xpos = small_icon_xpos + small_icon_width / 2.0 - nIconWidth / 2.0;
}
if ( nIconHeight < large_icon_height - YRES(2) ) // 2 is our buffer for when we need to re-calculate the ypos
{
ypos = small_icon_ypos + small_icon_height / 2.0 - nIconHeight / 2.0;
}
pFullClip->DrawSelf( xpos, ypos, nIconWidth, nIconHeight, m_clrIcon );
char buf[16];
Q_snprintf( buf, sizeof(buf), "%d", m_iAmmo );
DrawText( buf, xpos + nIconWidth - ( (float)nIconWidth / 3.0 ), ypos + nIconHeight - ( (float)nIconHeight / 3.0 ), m_clrTextColor );
}
//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( clips > 0 && pExtraClip )
{
//align the extra clip on the same baseline as the large clip
xpos = extra_clip_xpos;
ypos = extra_clip_ypos;
nIconWidth = pExtraClip->Width();
nIconHeight = pExtraClip->Height();
if ( nIconWidth > extra_clip_width || nIconHeight > extra_clip_height )
{
scale = GetScale( nIconWidth, nIconHeight, extra_clip_width, extra_clip_height );
nIconWidth *= scale;
nIconHeight *= scale;
}
if ( nIconWidth < extra_clip_width - XRES(2) ) // 2 is our buffer for when we need to re-calculate the ypos
{
xpos = extra_clip_xpos + extra_clip_width / 2.0 - nIconWidth / 2.0;
}
if ( nIconHeight < extra_clip_height - YRES(2) ) // 2 is our buffer for when we need to re-calculate the ypos
{
ypos = extra_clip_ypos + extra_clip_height / 2.0 - nIconHeight / 2.0;
}
pExtraClip->DrawSelf( xpos, ypos, pExtraClip->Width() * scale, pExtraClip->Height() * scale, m_clrIcon );
DrawAmmoCount( clips );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDoDHudAmmo::PaintGunAmmo( CWeaponDODBase *pWpn )
{
int panelX, panelY, panelW, panelT;
GetBounds( panelX, panelY, panelW, panelT );
//regular gun
const CHudTexture *pEmptyClip = pWpn->GetSpriteAmmo();
const CHudTexture *pFullClip = pWpn->GetSpriteAmmo2();
const CHudTexture *pExtraClip = pWpn->GetSpriteAutoaim();
Assert( pEmptyClip );
Assert( pFullClip );
Assert( pExtraClip );
int xpos = 0, ypos = 0;
int nIconWidth = 0, nIconHeight = 0;
float scale = 1.0f;
if ( pFullClip && pEmptyClip )
{
nIconWidth = pFullClip->Width();
nIconHeight = pFullClip->Height();
xpos = large_icon_xpos;
ypos = large_icon_ypos;
scale = GetScale( nIconWidth, nIconHeight, large_icon_width, large_icon_height );
nIconWidth *= scale;
nIconHeight *= scale;
if ( nIconWidth < large_icon_width - XRES(2) ) // 2 is our buffer for when we need to re-calculate the xpos
{
xpos = small_icon_xpos + small_icon_width / 2.0 - nIconWidth / 2.0;
}
if ( nIconHeight < large_icon_height - YRES(2) ) // 2 is our buffer for when we need to re-calculate the ypos
{
ypos = small_icon_ypos + small_icon_height / 2.0 - nIconHeight / 2.0;
}
pFullClip->DrawSelf( xpos, ypos, nIconWidth, nIconHeight, m_clrIcon );
// 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;
int yPosOffset = nOffset * scale;
pEmptyClip->DrawSelfCropped( xpos, ypos + yPosOffset, 0, nOffset, pEmptyClip->Width(), pEmptyClip->Height() - nOffset, nIconWidth, nIconHeight - yPosOffset, m_clrIcon );
}
// 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( clips > 0 && pExtraClip )
{
//align the extra clip on the same baseline as the large clip
xpos = extra_clip_xpos;
ypos = extra_clip_ypos;
nIconWidth = pExtraClip->Width();
nIconHeight = pExtraClip->Height();
if ( nIconWidth > extra_clip_width || nIconHeight > extra_clip_height )
{
scale = GetScale( nIconWidth, nIconHeight, extra_clip_width, extra_clip_height );
nIconWidth *= scale;
nIconHeight *= scale;
}
if ( nIconWidth < extra_clip_width - XRES(2) ) // 2 is our buffer for when we need to re-calculate the ypos
{
xpos = extra_clip_xpos + extra_clip_width / 2.0 - nIconWidth / 2.0;
}
if ( nIconHeight < extra_clip_height - YRES(2) ) // 2 is our buffer for when we need to re-calculate the ypos
{
ypos = extra_clip_ypos + extra_clip_height / 2.0 - nIconHeight / 2.0;
}
pExtraClip->DrawSelf( xpos, ypos, pExtraClip->Width() * scale, pExtraClip->Height() * scale, m_clrIcon );
DrawAmmoCount( clips );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDoDHudAmmo::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;
case WPN_TYPE_CAMERA:
break;
default:
PaintGunAmmo( pWpn );
break;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDoDHudAmmo::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);
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDoDHudAmmo::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;
}