//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // //=============================================================================// #include "cbase.h" #include "iclientmode.h" #include "c_dod_player.h" #include #include #include #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; }