Welcome, Guest! Login | Register

HUD Countdown Timer [Print this Article]
Posted by: hopper
Date posted: Aug 10 2003
User Rating: N/A
Number of views: 6624
Number of comments: 0
Description: add a server controlled hud countdown
HUD Countdown Tutorial.
by Hopper. hopper@mind-body-power.net

All code in this tutorial was made by me. I didn't use anyone else's stuff. This stuff is common sense... I don't care if you cut and paste the code in here. If you do, please give me some credit. Please don't post this tut to other sites and take credit for it yourself.

This is my first tutorial, so let me know if there are any problems with it. It was made with the sdk v2.3 and Vis Studio.net. There may be some bugs because I havent tested it to death yet, but for the testing I have done it works quite well.

Now for the good stuff:
Making a countdown timer that is started and stopped from the server.


Overview:
This tut will walk you through the steps required to make a countdown timer on the client's hud. The basic idea is that we will make a message on the server side that will tell the client side to either start or stop the timer. When the client gets the start timer message, it will start the countdown. The timer will continue until 0, or until it gets a message from the server telling it to stop counting down.

Code:

Server side modifications:

1. First we need to make a new message. This message will be sent to the client when we want to start and stop the countdown.

First we make the message. Go into Player.cpp and to about line 190. There you will see the following code:
 CODE  


int gmsgSetFOV = 0;
int gmsgShowMenu = 0;
int gmsgGeigerRange = 0;


Right after that stuff, add the following code:

// Countdown message declaration
 CODE  


int gmsgCountdown = 0;



Next, you want to go down about 50 lines to where all of the messages are registered with the engine. Look for the following code:

 CODE  


gmsgShake = REG_USER_MSG("ScreenShake", sizeof(ScreenShake));
gmsgFade = REG_USER_MSG("ScreenFade", sizeof(ScreenFade));
gmsgAmmoX = REG_USER_MSG("AmmoX", 2);



Under that stuff, add the following:

 CODE  


// register Countdown message with the engine
gmsgCountdown = REG_USER_MSG("Countdown",6);



This code is going to register our message and assign it a unique integer value that the engine will use to identify it in the client dll. The 6 is how many bytes the message will sending. I'll talk about how you could change it later.

Ok, that's it for Player.cpp On to the next step...

2. This part is the real important part... I'm basically going to show you the syntax for sending this message, but I want to leave this general enough that you can customize it for your own mod. With that in mind, I'm not going to show you where to put the message or anything... that's for you to figure out. I will however give you some ideas.

First, put this code above the function you are going to use this code in:

 CODE  


extern int gmsgCountdown;   // takes care of "undeclared identifier compiler
            // errors and name mangling issues


then, put this where you want to call the countdown

 CODE  


MESSAGE_BEGIN( MSG_ALL, gmsgCountdown );            
WRITE_SHORT( START_COUNTING );    
WRITE_SHORT( flDelay );  
WRITE_SHORT( 0 );
MESSAGE_END();

MESSAGE_BEGIN( MSG_ALL, gmsgCountdown );            
WRITE_SHORT( STOP_COUNTING );
WRITE_SHORT( 0 );
WRITE_SHORT( 0 );
MESSAGE_END();



Ok, there you go... You just stick that code in the spot that you want to send the message. You have to #define the START_COUNTING and the STOP_COUNTING values to the same values that we will use on the client side. The best way to do it is #define them in a header file that is included on both the client and server side, so that if you need to change them or add new values, they will automatically update on both sides. Also, the flDelay variable should be set to the length of time the countdown should run.

Now, about where to stick these:
If your countdown is related to the gamerules, and you're using it for a capture the flag type system where after you capture the flag you want a time delay where the capturing team has to defend the flag before they get a point... you should stick some logic into the void CHalfLifeTeamplay :: Think ( void ) function that controls when to start and when to stop the timer. On a more basic level, you could also call it straight from your Touch() function on your flag... but that isnt always what you want to do if your system is more complex than just one flag.

Alright, now we're done working in the server side stuff... on to the client.


Client Side Modifications:

1. The first thing we have to do is set up the message function. This is kind of complicated so just follow directions closely.

First, go into Hud.cpp.

Find the following code:

 CODE  


int __MsgFunc_Concuss(const char *pszName, int iSize, void *pbuf)
{
    return gHUD.MsgFunc_Concuss( pszName, iSize, pbuf );
}



After it, add the following code:

 CODE  


int __MsgFunc_Countdown(const char *pszName, int iSize, void *pbuf)
{
    return gHUD.MsgFunc_Countdown( pszName, iSize, pbuf );
}



2. Next, go a bit further down and find the CHud::Init() function. It has all of the HOOK_MESSAGE functions in it. Find the following code:

 CODE  


HOOK_MESSAGE( SetFOV );
HOOK_MESSAGE( Concuss );



After that stuff, add the following:
 CODE  


HOOK_MESSAGE( Countdown );



3. Next, you have to go into the hud.h file and find the CHud class declaration at the bottom.
In there, find the following code:
 CODE  


void _cdecl MsgFunc_ViewMode( const char *pszName, int iSize, void *pbuf );
int _cdecl MsgFunc_SetFOV(const char *pszName,  int iSize, void *pbuf);
int  _cdecl MsgFunc_Concuss( const char *pszName, int iSize, void *pbuf );



After that stuff, add the following:
 CODE  


int  _cdecl MsgFunc_Countdown( const char *pszName, int iSize, void *pbuf );



4. Now, before we set up the message function, I want to add some variables to the Chud class so that we can use them to control the drawing of the countdown. So, go into hud.h and find the following code ( in the CHud class declaration ):

 CODE  


HSPRITE         m_hsprCursor;
float m_flTime;    // the current client time
float m_fOldTime;  // the time at which the HUD was last redrawn
double m_flTimeDelta; // the difference between flTime and fOldTime



After that stuff, add the following code:

 CODE  


float m_flCountdownStartTime;   // stores the time our countdown started
float m_flTimeLeft;         // time to put on HUD
int m_iCountdownDuration;       // duration of the countdown
bool m_bCountdown;          // countdown active?



Although you don't need to, it is good programming practice to initialize these values... So, you could go into the hud.cpp file and file the constructor for that class and initialize the values. Make the int's and floats equal to 0 and the set the bool to false.

5. Now that we have that done, lets make our message function. Go into hud_msg.cpp and go to the very bottom of the file. Add the following code:

 CODE  


#define START_COUNTING 1    //should agree with server side values
#define STOP_COUNTING 0    

int CHud :: MsgFunc_Countdown( const char *pszName, int iSize, void *pbuf )
{
    BEGIN_READ( pbuf, iSize );

    int iAction = READ_SHORT();
    int iDuration = READ_SHORT();

    if( iAction == 1 )  //start the countdown
    {
        m_bCountdown = true;
        m_flCountdownStartTime = m_flTime;
        m_iCountdownDuration = iDuration;
        }
    else                //end the countdown
    {
        m_bCountdown = false;
        m_flCountdownStartTime = 0;
        m_iCountdownDuration = 0;
        }

    return 1;
    }



Basically what we're doing here is setting the parameters for the countdown depending on whether we are starting it or stopping it. The READ_SHORT() macros simply get the first and second short's that we sent in the message. If you wanted to send additional info in that third short, just add another READ_SHORT() statement.


6. Now that we have that done we can go take care of actually putting the countdown on the screen.

First, go to the hud_redraw.cpp. Find the CHud::Think() function. This is where we will figure out what time to write to the hud. Find the following code:

 CODE  


// think about default fov
if ( m_iFOV == 0 )
{  // only let players adjust up in fov,  and only if they are not overriden by something else
    m_iFOV = max( default_fov->value, 90 );  
}



After that stuff, add the following:
 CODE  


//Figure out how much time is left (if we are counting)
if( m_bCountdown )
{
    m_flTimeLeft = m_flCountdownStartTime + m_iCountdownDuration - m_flTime;
    if( m_flTimeLeft < 0)   // if we get to less than 0, we want to stop
        m_bCountdown = false;
    }



In the above code, the m_flTime is the current time client side. m_flTimeLeft is going to be the amount of time left until the timer stops.


7. Ok, finally you need to go into the CHud::Redraw() function. Its right below the Think() function.
Find the following code:
 CODE  


    // are we in demo mode? do we need to draw the logo in the top corner?
    if (m_iLogo)
    {
        int x, y, i;

        if (m_hsprLogo == 0)
            m_hsprLogo = LoadSprite("sprites/%d_logo.spr");

        SPR_Set(m_hsprLogo, 250, 250, 250 );
       
        x = SPR_Width(m_hsprLogo, 0);
        x = ScreenWidth - x;
        y = SPR_Height(m_hsprLogo, 0)/2;

        // Draw the logo at 20 fps
        int iFrame = (int)(flTime * 20) % MAX_LOGO_FRAMES;
        i = grgLogoFrame[iFrame] - 1;

        SPR_DrawAdditive(i, x, y, NULL);
    }



Right below that stuff, add the following code:
 CODE  


    //Draw the Countdown
    if( m_bCountdown )
    {
        int rVal = 100;
        int gVal = 100;
        int bVal = 100;
        if( m_flTimeLeft < 10 )
            rVal = 255;     //red text when less than 10 sec left

        DrawHudNumber( 20, 20, 200, m_flTimeLeft, rVal, gVal, bVal );

        }  


As it is right now, the timer will be drawn to the upper left corner of the screen, it will be lightish and partially transparent till it hits 10 seconds to go... then it will turn to a reddish color.

FINAL THOUGHTS:


This is all fine and dandy if you want a timer, but if you want the timer to be counting down to an event, you have to set up the event to run on a timed schedule also. The implementation is similar to the way we figure out how much time is left in the countdown. On the server side, you can access the current time and set a start time and all that. In fact, you can just modify the timed round code to work for you. Its all in the Think() function in the various gamerules files. Be creative.

The message we are sending is only 4 bytes long (2 shorts). However, we set up
the message to send 6 bytes. This is in case you want to send some additional info across. Since this kind of message doesn't get sent too often, there wont be an issue with bandwidth.

Check the DrawHudNumber function to see what the input parameters are for. You can customize it a lot if you want.

Common problems:
If you are getting undeclared identifier errors, check to make sure you are using all the same names for the functions. ( myFunc, is not myfunc ) Also, make sure you have the extern's that I put in there.

Well, that is it... That should work. This is my first tut so if I missed anything, let me know. If you get any errors that are crazy and insane let me know, I might have left something out of the tut.

-Hopper

btw, check out the mod im workin on... we're hammering out the details till HL2 comes out. http://www.mind-body-power.net

Rate This Article
This article has not yet been rated.

You have to register to rate this article.
User Comments

No User Comments

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: 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
 
Particle Engine tutorial part 5
Half-Life | Coding | Client Side Tutorials
By: Persuter | Aug 02 2009
 

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

Wavelength version: 3.0.0.9
Valid XHTML 1.0! Valid CSS!