Adding a Grenade Counter to the HUD

From Valve Developer Community
Jump to navigation Jump to search

This is a tutorial for adding a special HUD element that will show how much grenades the player has. This feature combines really well with Quick_Grenade tutorial. This tutorial was inspired by Mobility Mod for Half-Life 2.
Code in this tutorial is based on official valve's flashlight code from src/game/client/hl2/hud_flashlight.cpp.
Has been tested on current Source Engine 2013 singleplayer codebase.

Requirements

  • Knowledge of how to copy and paste text

Creating a grenade counter HUD element

First of all, create a new .cpp file in src/game/client/hl2/, For example: src/game/client/hl2/hud_grenades.cpp.
And paste this code there:

//=============================================================================//
//
// Purpose: HUD element that shows grenade count
//
//=============================================================================//

#include "cbase.h"
#include "hudelement.h"
#include "hud_numericdisplay.h"
#include <vgui_controls/Panel.h>
#include "hud.h"
#include "hud_suitpower.h"
#include "hud_macros.h"
#include "iclientmode.h"
#include <vgui_controls/AnimationController.h>
#include <vgui/ISurface.h>
#include "c_basehlplayer.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

extern ConVar sk_max_grenade;

//-----------------------------------------------------------------------------
// Purpose: Shows the flashlight icon
//-----------------------------------------------------------------------------
class CHudGrenades : public CHudElement, public vgui::Panel
{
	DECLARE_CLASS_SIMPLE( CHudGrenades, vgui::Panel );

public:
	CHudGrenades( const char *pElementName );
	virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
	void OnThink( void );

protected:
	virtual void Paint();
	void UpdateGrenades();

private:
	
	CPanelAnimationVar( vgui::HFont, m_hFont, "Font", "WeaponIconsSmall" );
	CPanelAnimationVarAliasType( float, m_IconX, "icon_xpos", "4", "proportional_float" );
	CPanelAnimationVarAliasType( float, m_IconY, "icon_ypos", "4", "proportional_float" );
	
	CPanelAnimationVarAliasType( float, m_flBarInsetX, "BarInsetX", "2", "proportional_float" );
	CPanelAnimationVarAliasType( float, m_flBarInsetY, "BarInsetY", "18", "proportional_float" );

	CPanelAnimationVarAliasType( float, m_flBarWidth, "BarWidth", "28", "proportional_float" );
	CPanelAnimationVarAliasType( float, m_flBarHeight, "BarHeight", "2", "proportional_float" );
	CPanelAnimationVarAliasType( float, m_flBarChunkWidth, "BarChunkWidth", "2", "proportional_float" );
	CPanelAnimationVarAliasType( float, m_flBarChunkGap, "BarChunkGap", "2", "proportional_float" );

	int m_iGrenades;
};	

using namespace vgui;

#ifdef HL2_EPISODIC
DECLARE_HUDELEMENT( CHudGrenades );
#endif // HL2_EPISODIC

//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CHudGrenades::CHudGrenades( const char *pElementName ) : CHudElement( pElementName ), BaseClass( NULL, "HudGrenades" )
{
	vgui::Panel *pParent = g_pClientMode->GetViewport();
	SetParent( pParent );

	SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD | HIDEHUD_NEEDSUIT );
}

void CHudGrenades::OnThink( void )
{
	UpdateGrenades();
}

//-----------------------------------------------------------------------------
// Purpose:
// Input  : *pScheme -
//-----------------------------------------------------------------------------
void CHudGrenades::ApplySchemeSettings( vgui::IScheme *pScheme )
{
	BaseClass::ApplySchemeSettings(pScheme);
}

void CHudGrenades::UpdateGrenades()
{
	C_BasePlayer* pPlayer = C_BasePlayer::GetLocalPlayer();

	if (pPlayer)
    {
		if (pPlayer->Weapon_OwnsThisType( "weapon_frag" ))
			m_iGrenades = pPlayer->GetAmmoCount( "grenade" );
	}
}

//-----------------------------------------------------------------------------
// Purpose: draws the flashlight icon
//-----------------------------------------------------------------------------
void CHudGrenades::Paint()
{
#ifdef HL2_EPISODIC
	C_BaseHLPlayer *pPlayer = (C_BaseHLPlayer *)C_BasePlayer::GetLocalPlayer();
	if ( !pPlayer )
		return;

	// Only paint if we're using the new flashlight code
	if ( m_iGrenades == 0 || pPlayer->IsInAVehicle() )
	{
		SetPaintBackgroundEnabled( false );
		return;
	}

	SetPaintBackgroundEnabled( true );

	// get bar chunks
	int chunkCount = sk_max_grenade.GetInt();
	int enabledChunks = m_iGrenades;

	Color clrGrenades;
	clrGrenades = gHUD.m_clrNormal;
	clrGrenades[3] = 80;

    wchar_t pState = 'v';

	surface()->DrawSetTextFont( m_hFont );
	surface()->DrawSetTextColor( clrGrenades );
	surface()->DrawSetTextPos( m_IconX, m_IconY );
	surface()->DrawUnicodeChar( pState );

	// draw the suit power bar
	surface()->DrawSetColor( clrGrenades );
	int xpos = m_flBarInsetX, ypos = m_flBarInsetY;
	for (int i = 0; i < enabledChunks; i++)
	{
		surface()->DrawFilledRect( xpos, ypos, xpos + m_flBarChunkWidth, ypos + m_flBarHeight );
		xpos += (m_flBarChunkWidth + m_flBarChunkGap);
	}
	
	// Be even more transparent than we already are
	clrGrenades[3] = clrGrenades[3] / 16;

	// draw the exhausted portion of the bar.
	surface()->DrawSetColor( clrGrenades );
	for (int i = enabledChunks; i < chunkCount; i++)
	{
		surface()->DrawFilledRect( xpos, ypos, xpos + m_flBarChunkWidth, ypos + m_flBarHeight );
		xpos += (m_flBarChunkWidth + m_flBarChunkGap);
	}
#endif // HL2_EPISODIC
}
Note.pngNote: If you are working on HL2 and not on EPISODIC, you need to remove all HL2_EPISODIC ifdef's and corresponding endif's and your code will fork fine.


Then open your client_episodic.vpc or client_hl2.vpc and enter the new file there:

			$File	"hl2\hud_damageindicator.cpp"
			$File	"hl2\hud_flashlight.cpp"
            $File   "hl2\hud_grenades.cpp" // <---- New file
			$File	"hl2\hud_locator.cpp"
			$File	"hl2\hud_health.cpp"

Then you need to rebuild your solution and compile it.

Then locate HudLayout.res in your your_mod/scripts and at the end add this:

HudGrenades
	{
		"fieldName" "HudFragCount"
		"visible" "1"
		"PaintBackgroundType"	"2"
		"xpos"	"r270"		[$WIN32]
		"ypos"	"444"		[$WIN32]
		"xpos_hidef"	"306"		[$X360]		// aligned to left
		"xpos_lodef"	"c-18"		[$X360]		// centered in screen
		"ypos"	"428"		[$X360]				
		"tall"  "24"
		"wide"	"36"
		"font"	"WeaponIconsSmall"
		
		"icon_xpos"	"8"
		"icon_ypos" "-8"
		
		"BarInsetX" "5"
		"BarInsetY" "18"
		"BarWidth" "25"
		"BarHeight" "2"
		"BarChunkWidth" "5"
		"BarChunkGap" "1"
	}

And that's the result you can expect:

HUD Grenade Counter tutorial results.png


Credits

Editing/Usage

You are free to use and edit this code in your projects as much as you want.