Welcome, Guest! Login | Register

Attaching VGUIScreens to viewmodels [Print this Article]
Posted by: Crazy01
Date posted: Jan 27 2005
User Rating: 5 out of 5.0
Number of views: 11688
Number of comments: 2
Description: An article explaining how to attach dynamic vguiscreens to a weapons viewmodel.
Introduction

Hello folks!
My name is Ask Jensen, I'm danish, and I'll be your guide today.
This is my very first article, like EVER, so please bare with me. If I'm wrong about anything (which I'm pretty sure I am) feel free to contact me.
Let's get started!


Purpose

The purpose of this article is to find out how Source lets you create an attached VGUIScreen on a weapons view model. We'll start with browsing the code finding out how things work and will end up creating a dynamic screen on the RPG telling us how much ammo we have left.


What is where now?

Okay. Where to start? A good place would be where our weapons view model is set, so open up baseviewmodel_shared.cpp in the game_shared directory and look at the end of the CBaseViewModel::SetWeaponModel() function:
 CODE (C++) 
void CBaseViewModel::SetWeaponModel( const char *modelname, CBaseCombatWeapon *weapon )
{
...
    if ( str != m_sVMName )
    {
        // Msg( "SetWeaponModel %s at %f\n", modelname, gpGlobals->curtime );
        m_sVMName = str;
        SetModel( STRING( m_sVMName ) );

        // Create any vgui control panels associated with the weapon
        SpawnControlPanels();

        bool showControlPanels = weapon && weapon->ShouldShowControlPanels();
        SetControlPanelsActive( showControlPanels );
    }
#endif
}

Yay! I was right! ;) See the function SpawnControlPanels()? That has to have something to do with it.
Let's take a look at that:
 CODE (C++) 
void CBaseViewModel::SpawnControlPanels()
{
#if defined( VGUI_CONTROL_PANELS )

Aha! We need to have VGUI_CONTROL_PANELS defined to get this working, let's go ahead and do that. Go to line 86 and add it:
 CODE (C++) 
#ifdef TF2_DLL
#define VGUI_CONTROL_PANELS
#endif

// Ask: VGUI Control panels in HL2
#ifdef HL2_DLL
#define VGUI_CONTROL_PANELS
#endif


Okay. Back to SpawnControlPanels():
 CODE (C++) 
void CBaseViewModel::SpawnControlPanels()
{
#if defined( VGUI_CONTROL_PANELS )
    char buf[64];

    // Destroy existing panels
    DestroyControlPanels();

    CBaseCombatWeapon *weapon = m_hWeapon.Get();

    if ( weapon == NULL )
    {
        return;
    }

    // FIXME: Deal with dynamically resizing control panels?

    // If we're attached to an entity, spawn control panels on it instead of use
    CBaseAnimating *pEntityToSpawnOn = this;
    char *pOrgLL = "controlpanel%d_ll";
    char *pOrgUR = "controlpanel%d_ur";
    char *pAttachmentNameLL = pOrgLL;
    char *pAttachmentNameUR = pOrgUR;

The first few lines are pretty obvious; first we destroy all current panels and then check to see if we have a weapon.
Then look what's next. pOrgLL and pOrgUR are both pointers to strings of the format "controlpanel[number]_ll" and "controlpanel[number]_ur". We'll need this later on.
 CODE (C++) 
    Assert( pEntityToSpawnOn );

    // Lookup the attachment point...
    int nPanel;
    for ( nPanel = 0; true; ++nPanel )
    {
        Q_snprintf( buf, sizeof( buf ), pAttachmentNameLL, nPanel );
        int nLLAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf);
        if (nLLAttachmentIndex <= 0)
        {
            // Try and use my panels then
            pEntityToSpawnOn = this;
            Q_snprintf( buf, sizeof( buf ), pOrgLL, nPanel );
            nLLAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf);
            if (nLLAttachmentIndex <= 0)
                return;
        }

        Q_snprintf( buf, sizeof( buf ), pAttachmentNameUR, nPanel );
        int nURAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf);
        if (nURAttachmentIndex <= 0)
        {
            // Try and use my panels then
            Q_snprintf( buf, sizeof( buf ), pOrgUR, nPanel );
            nURAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf);
            if (nURAttachmentIndex <= 0)
                return;
        }

In this for loop, we search the attachment points on the viewmodel entity for any points named controlpanel[int]_ll and controlpanel0[int]_ur which you míght have guessed define the screens lower left and upper right corners. An example of another attachment point could be the muzzleflash. This point defines where on the model we should create our muzzleflash effect. Attachment points are defined in the model files, I'll show you how to add them later on. First let's see what happens next:
 CODE (C++) 
        const char *pScreenName;
        weapon->GetControlPanelInfo( nPanel, pScreenName );
        if (!pScreenName)
            continue;

        const char *pScreenClassname;
        weapon->GetControlPanelClassName( nPanel, pScreenClassname );
        if ( !pScreenClassname )
            continue;

The code itself is pretty self-explanatory. We call the functions CBaseCombatWeapon::GetControlPanelInfo() and CBaseCombatWeapon::GetControlPanelClassName() passing the nPanel integer and expecting pScreenName and pScreenClassname to be filled. Let's look up the functions in basecombatweapon_shared.cpp (line 1848):
 CODE (C++) 
//-----------------------------------------------------------------------------
// Returns information about the various control panels
//-----------------------------------------------------------------------------
void CBaseCombatWeapon::GetControlPanelInfo( int nPanelIndex, const char *&pPanelName )
{
    pPanelName = NULL;
}

//-----------------------------------------------------------------------------
// Returns information about the various control panels
//-----------------------------------------------------------------------------
void CBaseCombatWeapon::GetControlPanelClassName( int nPanelIndex, const char *&pPanelName )
{
    pPanelName = "vgui_screen";
}

Okay, so GetControlPanelInfo sets pPanelName to NULL. Nothing weird about that. We could just define our GetControlPanelInfo() function in our RPG to set pPanelName to the name we want. GetControlPanelClassName on the other hand sets pPanelName (which in SpawnControlPanels() is named pScreenClassName) to "vgui_screen". But what are these names for?
Let's go back to the SpawnControlPanels() function:
 CODE (C++) 
        // Compute the screen size from the attachment points...
        ...

        float flWidth = lrlocal.x;
        float flHeight = lrlocal.y;

        CVGuiScreen *pScreen = CreateVGuiScreen( pScreenClassname, pScreenName, pEntityToSpawnOn, this, nLLAttachmentIndex );
        pScreen->ChangeTeam( GetTeamNumber() );
        pScreen->SetActualSize( flWidth, flHeight );
        pScreen->SetActive( false );
        pScreen->MakeVisibleOnlyToTeammates( false );
   
        ...
    }
#endif
}

First there's just alot of math to figure out our screen size and then all the action comes. We create a CVGuiScreen passing the pScreenClassname and pScreenName we got from our weapon, the entity to spawn on (our weapon) and so on. The rest is pretty much self-explanatory. That's all we have in SpawnControlPanels(). Let's see what happens when we call CreateVGuiScreen().
Open up vguiscreen.cpp line 349 in the dlls folder:
 CODE (C++) 
CVGuiScreen *CreateVGuiScreen( const char *pScreenClassname, const char *pScreenType, CBaseEntity *pAttachedTo, CBaseEntity *pOwner, int nAttachmentIndex )
{
    Assert( pAttachedTo );
    CVGuiScreen *pScreen = (CVGuiScreen *)CBaseEntity::Create( pScreenClassname, vec3_origin, vec3_angle, pAttachedTo );

    pScreen->SetPanelName( pScreenType );
    pScreen->FollowEntity( pAttachedTo );
    pScreen->SetOwnerEntity( pOwner );
    pScreen->SetAttachmentIndex( nAttachmentIndex );

    return pScreen;
}

Okay, so here we first create a new "vgui_screen" (ahh, so that's the classname ;) entity pScreen, and then call SetPanelName( pScreenType ) which we know as the pScreenName we got from CBaseCombatWeapon::GetControlPanelInfo(). Let's see what happens with that:
 CODE (C++) 
void CVGuiScreen::SetPanelName( const char *pPanelName )
{
    m_nPanelName = g_pStringTableVguiScreen->AddString( pPanelName );
}

So here we add our pPanelName to g_pStringTableVguiScreen. A find in files reveals that g_pStringTableVguiScreen is a network string table named "VguiScreen" created in CServerGameDLL::CreateNetworkStringTables() (GameInterface.cpp line 946 in the dlls folder). On the client side this string table is set up in CHLClient::InstallStringTableCallback() (cdll_client_int.cpp line 988 in the cl_dlls folder):
 CODE (C++) 
//-----------------------------------------------------------------------------
// Purpose: Hook up any callbacks here, the table definition has been parsed but
//  no data has been added yet
//-----------------------------------------------------------------------------
void CHLClient::InstallStringTableCallback( const char *tableName )
{
    // Here, cache off string table IDs
    if (!Q_strcasecmp(tableName, "VguiScreen"))
    {
        // Look up the id
        g_StringTableVguiScreen = networkstringtable->FindTable( tableName );

        // When the material list changes, we need to know immediately
        g_StringTableVguiScreen->SetStringChangedCallback( NULL, OnVguiScreenTableChanged );
    }

What this mean is that when our VGUIScreen is created, OnVguiScreenTableChanged() is called. This function can be found right above InstallStringTableCallback():
 CODE (C++) 
//-----------------------------------------------------------------------------
// Called when the string table for VGUI changes
//-----------------------------------------------------------------------------
void OnVguiScreenTableChanged( void *object, INetworkStringTable *stringTable, int stringNumber, const char *newString, void const *newData )
{
    // Make sure this puppy is precached
    vgui::Panel *pPanel = PanelMetaClassMgr()->CreatePanelMetaClass( newString, 100, NULL, NULL );
    if ( pPanel )
    {
        PanelMetaClassMgr()->DestroyPanelMetaClass( pPanel );
    }
}

Here's something interresting! If we do a find in files on "PanelMetaClassMgr()" we find this in hl2_clientmode.cpp line 46:
 CODE (C++) 
void CHLModeManager::Init( void )
{
    g_pClientMode = GetClientModeNormal();
    PanelMetaClassMgr()->LoadMetaClassDefinitionFile( SCREEN_FILE );
}

So PanelMetaClassMgr() loads the file SCREEN_FILE and puts the data inside the PanelMetaClassMgr. SCREEN_FILE is defined as "scripts/vgui_screens.txt". Here's the inside of vgui_screens.txt which is located in SourceMods\<your_mod_name>\scripts\:
 CODE  
"VGUI_Screens"
{
    // This name here can be referenced from within a
    // vgui_screen entity to select this vgui panel
    "vgui_test_screen"
    {
        // The type indicates which type of panel to create
        // Coders will add new types as time goes by.
        // "vgui_screen_panel" is a generic panel type which can
        // read in .res files that have been built by VGUI's build mode dialog.
        "type"          "vgui_screen_panel"

        // These describe the dimensions of the screen *in pixels*
        "pixelswide"    480
        "pixelshigh"    240

        // This is the name of the .res file to load up and apply to the vgui panel
        "resfile"       "scripts/screens/vgui_test_screen.res"
    }

    "teleport_countdown_screen"
    {
        // Defined in c_info_teleporter_countdown.cpp
        "type"          "teleport_countdown_screen"

        // These describe the dimensions of the screen *in pixels*
        "pixelswide"    480
        "pixelshigh"    240

        // This is the name of the .res file to load up and apply to the vgui panel
        "resfile"       "scripts/screens/teleport_countdown_screen.res"
    }
}

So what does all this mean then? Well, vgui_screens.txt is where the screens are defined. So to use the "vgui_test_screen" on the RPG, CWeaponRPG::GetControlPanelInfo() should set pScreenName to "vgui_test_screen". As you can see, teleport_countdown_screen uses the type "teleport_countdown_screen" defined in c_info_teleporter_countdown.cpp (line 100):
 CODE (C++) 
DECLARE_VGUI_SCREEN_FACTORY( CTeleportCountdownScreen, "teleport_countdown_screen" );

CTeleportCountdownScreen is derived from CVGuiScreenPanel and uses it's OnTick() function to update a label on the screen telling us how much time is left until teleportation. This is exactly what we want to do with our RPG; Have the VGUIScreen update the ammo count. We'll just make our own screen type then!
The resfile is a layout file that has vgui elements inside it. We'll look into that later.


Recap


So to create a VGUIScreen on our RPG we need to:
  • Create two attachment points on the RPG view model: controlpanel0_ll and controlpanel0_ur
  • Add the GetControlPanelInfo() function to CWeaponRPG
  • Add the screen to vgui_screens.txt
  • Create our layout (.res) file
  • Create a new screen type for our RPG to use.



Modifying the RPG model

Lucky for us valve included the RPG model's source in the SDK, so we don't even have to brush up our modeling skills (Yea! Like I have any). Start up the model viewer that came with the SDK (it's in the "Source SDK" menu that's under "tools" in the "Play games" part of Steam). (NOTE: Make sure the Current Game drop down in the Source SDK tool is set to your mod before launching model viewer!)
When it's loaded, go to File->Load Model... Then go to weapons\v_RPG.mdl.
You should now see the RPG model infront of you. Go to the "Attachments" tab.

user posted image

There's a list of attachments already. By clicking through them, you can see that they're all attached to "muzzle".
Now, how do we create our own? We can't do that in here. But what we can do is find out where to place the two points. Select 0 on the list of attachments. Try changing the numbers in the Translation tekstbox. See the point move? Now, try and place the point where you would want you upper right corner. I used the value -10.00 8.00 0.00. Now change the Rotate numbers so the green line is pointing up, the red is pointing right and the blue pointing towards the player: -90 0 0.
We have our first attachment point! Now, copy the text in the field named QC string and save it. It should read: $attachment "0" "muzzle" -10.00 8.00 0.00 rotate -90 0 0

user posted image

Now we need to find the lower left attachment point. Let's make the screen 8x8, so the lower left translation should be -10.00 0.00 -8.00. Again, we need the QC string, so copy that from the textbox. We're done with the model viewer, so you can close it down.

Next, we need to actually modify the RPG model. Go to your steam folder\SteamApps\<steam-account>\sourcesdk_content\hl2\modelsrc\weapons\v_rocket_launcher\
The files you see are the source files for the RPG model. Open the V_Rocket_launcher.qc file. After the $attachment points paste your QC strings you just got from the model viewer, but change the 0 to "controlpanel0_ur" and "controlpanel0_ll" like so:
 CODE  
// attachment points
$attachment 0 "muzzle" 0 0 0
$attachment "laser" "muzzle" -9.00 -5.00 0.50
$attachment "laser_end" "muzzle" 100.00 -5.00 0.50

// Ask: attachment points for vguiscreen
$attachment "controlpanel0_ur" "muzzle" -10.00 8.00 0.00 rotate -90 0 0
$attachment "controlpanel0_ll" "muzzle" -10.00 0.00 -8.00 rotate -90 0 0

Now we need to compile the RPG with the new attachment points.

Open up command promt and go to your SteamApps\<steam-account>\sourcesdk\bin folder.
now type in:
 CODE  
studiomdl ..\..\sourcesdk_content\hl2\modelsrc\weapons\v_rocket_launcher\V_Rocket_launcher.qc

The model should now compile, and if Steam is set up correctly your compiled models should be in your <modname>\models\Weapons\ directory. To check if everything went well, launch model viewer again, load up the RPG model and check if the attachment points are there. If not, try going through the steps again, if so:
Wohoo! We now have the model ready for our VGUIScreen!


Adding GetControlPanelInfo() to CWeaponRPG

This is pretty simple. In weapon_rpg.h (in the dlls\hl2_dll\ folder) around line 182 under Drop() add:
 CODE (C++) 
    virtual void Drop( const Vector &vecVelocity );

    // Ask: Get the name of our attached vguiscreen
    void    GetControlPanelInfo( int nPanelIndex, const char *&pPanelName);

    int     GetMinBurst() { return 1; }

and in weapon_rpg.cpp (also under Drop()) add:
 CODE (C++) 
//-----------------------------------------------------------------------------
// Purpose: Ask: Get the name of our attached vguiscreen
//-----------------------------------------------------------------------------
void CWeaponRPG::GetControlPanelInfo( int nPanelIndex, const char *&pPanelName )
{
    pPanelName = "rpg_screen";
}

That's it. The name of the VGUIScreen we'll add in vgui_screens.txt will be "rpg_screen".


Adding the screen to vgui_screens.txt

Open up vgui_screens.txt (It's in your mod's folder under scripts).
Add a new screen under teleport_countdown_screen like this:
 CODE  
    "rpg_screen"
    {
        // Ask: This is the vguiscreen attached to the RPG
        // this type is defined in c_rpg_screen.cpp
        "type"          "rpg_screen"

        // These describe the dimensions of the screen *in pixels*
        "pixelswide"    480
        "pixelshigh"    240

        // This is the name of the .res file to load up and apply to the vgui panel
        "resfile"       "scripts/screens/rpg_screen.res"
    }

There isn't very much to be explained here. We'll create the new screen type "rpg_screen" for the RPG later on. First we need to create the .res file.


Creating the layout (.res) file

Go to the screens directory in your scripts folder. There's already two files there; vgui_test_screen.res and teleport_countdown_screen.res. Let's take a look at vgui_test_screen.res:
 CODE  
"screen_basic.res"
{
    "Background"
    {
        "ControlName"   "MaterialImage"
        "fieldName"     "Background"
        "xpos"          "0"
        "ypos"          "0"
        "zpos"          "-2"
        "wide"          "480"
        "tall"          "240"

        "material"      "vgui/screens/vgui_bg"
    }

    "OwnerReadout"
    {
        "ControlName"   "Label"
        "fieldName"     "OwnerReadout"
        "xpos"          "10"
        "ypos"          "20"
        "wide"          "240"
        "tall"          "34"
        "autoResize"    "0"
        "pinCorner"     "0"
        "visible"       "1"
        "enabled"       "1"
        "tabPosition"   "0"
        "labelText"     "No Owner"
        "textAlignment" "center"
        "dulltext"      "0"
        "paintBackground" "0"
    }

    "HealthReadout"
    {
        "ControlName"   "Label"
        "fieldName"     "HealthReadout"
        "xpos"          "240"
        "ypos"          "20"
        "wide"          "240"
        "tall"          "34"
        "autoResize"    "0"
        "pinCorner"     "0"
        "visible"       "1"
        "enabled"       "1"
        "tabPosition"   "0"
        "labelText"     "Health: 100%"
        "textAlignment" "center"
        "dulltext"      "0"
        "paintBackground" "0"
    }

    "DismantleButton"
    {
            "ControlName"   "MaterialButton"
            "fieldName"     "Dismantle"
        ...
    }
}

As you can see, there are 4 controls in here. A MaterialImage, two Labels and a MaterialButton (If you're unsure about what I'm talking about, have a look at the Source SDK documentation here). I suggest we change this file to suit our needs. First, change line 1 from "screen_basic.res" to "rpg_screen.res". Then remove the MaterialButton "DismantleButton". We now have "Background", "OwnerReadout" and "HealthReadout" left. The background is simply an image, so let's keep that in. Change the "OwnerReadout"'s name and fieldName to "AmmoReadout" and the labelText to "Ammo:". This will just be a static label. Change the "HealthReadout"'s name and fieldName to "AmmoCountReadout" and the labelText to "0", save the file as "rpg_screen.res" in your scripts\screens\ folder. It should now look like this:
 CODE  
"rpg_screen.res"
{
    "Background"
    {
        "ControlName"   "MaterialImage"
        "fieldName"     "Background"
        "xpos"          "0"
        "ypos"          "0"
        "zpos"          "-2"
        "wide"          "480"
        "tall"          "240"

        "material"      "vgui/screens/vgui_bg"
    }

    "AmmoReadout"
    {
        "ControlName"   "Label"
        "fieldName"     "AmmoReadout"
        "xpos"          "10"
        "ypos"          "20"
        "wide"          "240"
        "tall"          "34"
        "autoResize"    "0"
        "pinCorner"     "0"
        "visible"       "1"
        "enabled"       "1"
        "tabPosition"   "0"
        "labelText"     "Ammo:"
        "textAlignment" "center"
        "dulltext"      "0"
        "paintBackground" "0"
    }

    "AmmoCountReadout"
    {
        "ControlName"   "Label"
        "fieldName"     "AmmoCountReadout"
        "xpos"          "240"
        "ypos"          "20"
        "wide"          "240"
        "tall"          "34"
        "autoResize"    "0"
        "pinCorner"     "0"
        "visible"       "1"
        "enabled"       "1"
        "tabPosition"   "0"
        "labelText"     "0"
        "textAlignment" "center"
        "dulltext"      "0"
        "paintBackground" "0"
    }
}

We now have our layout ready for our VGUIScreen. But this is all static. We still need to make the screen type that sets the AmmoCountReadout label to the number of missiles left.


Creating the "rpg_screen" screen type

Create a new file in your cl_dll\hl2_hud\ directory named c_rpg_screen.cpp and add it to your client project. Write the following:
 CODE (C++) 
//=============================================================================//
//
// Purpose: Ask: This is a screen we'll use for the RPG
//
//=============================================================================//
#include "cbase.h"

#include "C_VGuiScreen.h"
#include <vgui/IVGUI.h>
#include <vgui_controls/Controls.h>
#include <vgui_controls/Label.h>
#include "clientmode_hlnormal.h"

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

Not much to explain here. Just the includes we'll need in our code.
 CODE (C++) 
//-----------------------------------------------------------------------------
//
// In-game vgui panel which shows the RPG's ammo count
//
//-----------------------------------------------------------------------------
class CRPGScreen : public CVGuiScreenPanel
{
    DECLARE_CLASS( CRPGScreen, CVGuiScreenPanel );

public:
    CRPGScreen( vgui::Panel *parent, const char *panelName );

    virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
    virtual void OnTick();

private:
    vgui::Label *m_pAmmoCount;
};

Our RPGScreen class. Notice that under private we define our m_pAmmoCount pointer as a vgui::Label. This will be the label we'll update.
 CODE (C++) 
//-----------------------------------------------------------------------------
// Standard VGUI panel for objects
//-----------------------------------------------------------------------------
DECLARE_VGUI_SCREEN_FACTORY( CRPGScreen, "rpg_screen" );


//-----------------------------------------------------------------------------
// Constructor:
//-----------------------------------------------------------------------------
CRPGScreen::CRPGScreen( vgui::Panel *parent, const char *panelName )
    : BaseClass( parent, panelName, g_hVGuiCombineScheme )
{
}

Here we let Source know that the "rpg_screen" screen type is actually our CRPGScreen. As you can see in the constructor, we use the g_hVGuiCombineScheme scheme for our rpg_screen.res file. We could create our own, but this is alright for now.
 CODE (C++) 
//-----------------------------------------------------------------------------
// Initialization
//-----------------------------------------------------------------------------
bool CRPGScreen::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
{
    // Load all of the controls in
    if ( !BaseClass::Init(pKeyValues, pInitData) )
        return false;

    // Make sure we get ticked...
    vgui::ivgui()->AddTickSignal( GetVPanel() );

    // Ask: Here we find a pointer to our AmmoCountReadout Label and store it in m_pAmmoCount
    m_pAmmoCount =  dynamic_cast<vgui::Label*>(FindChildByName( "AmmoCountReadout" ));

    return true;
}

As you can see, we get ahold of our Label in here. We also make sure we get ticked so we can update the Label.
 CODE (C++) 
//-----------------------------------------------------------------------------
// Ask: Let's update the label, shall we?
//-----------------------------------------------------------------------------
void CRPGScreen::OnTick()
{
    BaseClass::OnTick();

    // Get our player
    CBasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
    if ( !pPlayer )
        return;

    // Get the players active weapon
    CBaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon();

    // If pWeapon is NULL or it doesn't use primary ammo, don't update our screen
    if ( !pWeapon || !pWeapon->UsesPrimaryAmmo() )
        return;

    // Our RPG isn't clip-based, so we need to check the player's arsenal of rockets
    int ammo1 = pPlayer->GetAmmoCount( pWeapon->GetPrimaryAmmoType() );

    // If our Label exist
    if ( m_pAmmoCount )
    {
        char buf[32];
        Q_snprintf( buf, sizeof( buf ), "%d", ammo1 );
        // Set the Labels text to the number of missiles we have left.
        m_pAmmoCount->SetText( buf );
    }
}

As the commenting say, we first get the local play, then its weapon, get the number of rockets and then update our label.
And we're done! Compile and run your mod. If all went well your RPG now has a screen telling us how much ammo we have left!

user posted image

Okay, not the prettiest in the world, but it's a start :)


Contact

If you have any ideas / comments feel free to contact me on ask.jensen@gmail.com
Have fun!
/ Ask Jensen AKA Crazy01

Rate This Article
This article is currently rated: 5 out of 5.0 (1 Votes)

You have to register to rate this article.
Related Files
Zip FileFilename: mdl_2.jpg
File Size: 18.1 KB
Zip FileFilename: mdl_3.jpg
File Size: 22.7 KB
Zip FileFilename: ingame.jpg
File Size: 17.6 KB

User Comments Showing comments 1-2

Posted By: Pongles on Feb 01 2005 at 16:59:06
heh, nice.

Posted By: Winston on Feb 04 2005 at 18:56:03
Cool thanks mate - I got around to doing this and ran up against a bit of a brick wall and promptly abandoned it in favour of over-animating the hud - can get it going again now :D


You must register to post a comment. If you have already registered, you must login.

Latest Articles
3rd person View in Multiplayer
Half-Life 2 | Coding | Client Side Tutorials
How to enable it in HL2DM

By: cct | Nov 13 2006

Making a Camera
Half-Life 2 | Level Design
This camera is good for when you join a map, it gives you a view of the map before you join a team

By: slackiller | Mar 05 2006

Making a camera , Part 2
Half-Life 2 | Level Design
these cameras are working monitors that turn on when a button is pushed.

By: slackiller | Mar 04 2006

Storing weapons on ladder
Half-Life 2 | Coding | Snippets
like Raven Sheild or BF2

By: British_Bomber | Dec 24 2005

Implementation of a string lookup table
Half-Life 2 | Coding | Snippets
A string lookup table is a set of functions that is used to convert strings to pre-defined values

By: deathz0rz | Nov 13 2005


Latest Comments
knock knock
General | News
By: MIFUNE | Dec 31 2017
 
knock knock
General | News
By: omega | Dec 22 2016
 
knock knock
General | News
By: MIFUNE | Oct 10 2015
 
New HL HUD Message System
Half-Life | Coding | Shared Tutorials
By: chbrules | Dec 31 2011
 
knock knock
General | News
By: Whistler | Nov 05 2011
 
Particle Engine tutorial part 4
Half-Life | Coding | Client Side Tutorials
By: darkPhoenix | Feb 18 2010
 
Particle Engine tutorial part 2
Half-Life | Coding | Client Side Tutorials
By: darkPhoenix | Feb 11 2010
 
Particle Engine tutorial part 3
Half-Life | Coding | Client Side Tutorials
By: darkPhoenix | Feb 11 2010
 
Game Movement Series #2: Analog Jumping and Floating
Half-Life 2 | Coding | Shared Tutorials
By: mars3554 | Oct 26 2009
 
Particle Engine tutorial part 5
Half-Life | Coding | Client Side Tutorials
By: Deadpool | Aug 02 2009
 

Site Info
297 Approved Articless
8 Pending Articles
3940 Registered Members
0 People Online (3 guests)
About - Credits - Contact Us

Wavelength version: 3.0.0.9
Valid XHTML 1.0! Valid CSS!