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