Welcome, Guest! Login | Register

Custom DrawHudString [Print this Article]
Posted by: X-0ut
Date posted: Jun 28 2003
User Rating: 5 out of 5.0
Number of views: 5541
Number of comments: 1
Description:
This tutorial will alter the existing DrawHudString function in the CHud Class, we will be adding the ability for colored text and different draw modes.
Once this tutorial is complete, you can use it for any hud text you want - you could have multicolored weapon displays, custom display messages.
The alltered DrawHudString in itself is very simple and straight forward, so I will be including an example on how to use, I will be showing you have to give players the ability to type in different colors and modes.Like so:
user posted image
Lets start by opening hud.h and finding the CHud class, we need to alter the prototype of the DrawHudString function from this:
 CODE  

int DrawHudString(int x, int y, int iMaxX, char *szString, int r, int g, int b);

To this:
 CODE  

int DrawHudString(int x, int y, int iMaxX, char *szString, int r, int g, int b, int effect = 0);

We have simply added an extra integer as part of the function, effect will allow us to draw using different modes.

Now we can actually get to our custom DrawHudString function, open hud_redraw.cpp and find said function, might aswell go ahead and remove it completely - we will be replacing it.
 CODE  

///CUSTOM TEXT TUT BEGIN///
int CHud :: DrawHudString(int xpos, int ypos, int iMaxX, char *szIt, int r, int g, int b, int effect )
{

    // draw the string until we hit the null character or a newline character
    for (; *szIt != 0 && *szIt != '\n'; szIt++ )
    {

So far thats self explanatory, we have our new declaration of the DrawHudString function, and a pointer to the paramaters needed for our text output.
Next we will be checking for codes in the string pointer, this will allow us to have different colors/modes:
 CODE  

FoundCode://Foundcode label will allow us to check of multiple codes are used in a row
        if(*szIt=='^')//used for color determination
        {
            char* szTemp;
            szTemp = szIt;
            szTemp++;
            bool bGotCode=false;
            switch(*szTemp)
            {
            case '1'://white
                r=g=b=255;
                bGotCode = true;
                break;
            case '2'://red
                r=255;
                g=b=0;
                bGotCode = true;
                break;
            case '3'://green
                g=255;
                r=b=0;
                bGotCode = true;
                break;
            case '4'://blue
                b=255;
                r=g=0;
                bGotCode = true;
                break;
            case '5'://yellow
                r=g=255;
                b=0;
                bGotCode = true;
                break;
            case '6'://purple
                r=b=255;
                g=0;
                bGotCode = true;
                break;
            case '7'://cyan
                g=b=255;
                r=0;
                bGotCode = true;
                break;
            case '8'://grey(only works with additive mode)
                r=g=b=125;
                bGotCode = true;
                break;
            case '9'://effect 0
                effect = 0;
                bGotCode = true;
                break;
            case '0'://effect 1
                effect = 1;
                bGotCode = true;
                break;
            }

            //we got a code so skip past (dont want to draw the color/effect combo)
            if(bGotCode)
            {
                szIt+=2;
                //incase we find another color
                if(*szIt=='^')
                    goto FoundCode;//restart the code determination
            }
        }

Woah...Ok so what does that do? - Firstly we check if there is an ^ at this point in the string, if there is we can then enter the switch cascade and determine if a color is wanting to be used.
We dont want to actually draw the codes, so we increment the string ahead of them and check if there is another code used, if so we restart the checking once again.
 CODE  

int next = xpos + gHUD.m_scrinfo.charWidths[ *szIt ]; // variable-width fonts look cool
if ( next > iMaxX )
    return xpos;

That piece of code checks the string has not passed its maximum length by adding the position of the character with its own width.

Next we will draw each character in the string one at a time.
 CODE  

//we need to call different drawing modes dependant of the effect we want to use//
if(effect==0)//normal text(alas with color)
{
    char szChar[2];
    szChar[0] = *szIt;
    szChar[1] = 0;
    gEngfuncs.pfnDrawSetTextColor( r, g, b );
    DrawConsoleString( xpos, ypos, szChar );
}

Here we are checking our effect type paramater, this will use the standard text type - with color user posted image.
We simply store the current character in szChar, set the color with pfnDrawSetTextColor( r, g, b ) and finally draw it with DrawConsoleString( xpos, ypos, &szChar );.
 CODE  

else if(effect==1)//additive text
{
    TextMessageDrawChar( xpos, ypos, *szIt, r, g, b );
}
xpos = next;        

Again, just checking the effect paramater, in this instance we are checking for a second effect type which will allow us to draw in additive mode using TextMessageDrawChar( xpos, ypos, *szIt, r, g, b );
xpos is now moved along to the next space, so we can continue the loop, drawing the next character in its correct position.
 CODE  

    }//end of string loop

    return xpos;
}
///CUSTOM TEXT TUT END///

Thats our complete custom DrawHudString, as promised I will now give an example on how to use it to give the player the ability to use color in speech/messagemode.
Theres going to be a few modifications to saytext.cpp, so open it up and find the Draw function, firstly comment out the original drawing code:
 CODE  

gEngfuncs.pfnDrawSetTextColor( g_pflNameColors[i][0], g_pflNameColors[i][1], g_pflNameColors[i][2] );
int x = DrawConsoleString( LINE_START, y, buf );

// color is reset after each string draw
DrawConsoleString( x, y, g_szLineBuffer[i] + g_iNameLengths[i] );

And replace it with our new drawing code:
 CODE  

//Here we will draw the players name//
//X will hold the length of the text//
//so we can draw any following text //
// in its correct position//
int x = gHUD.DrawHudString( LINE_START, y,320, buf ,255, 255, 0, 0 );
gHUD.DrawHudString( LINE_START+x, y,320, g_szLineBuffer[i] + g_iNameLengths[i] ,255, 255, 0, 0 );

See how easy our new text is to use? We have simply removed the original text drawing code and replaced it with a call to our new DrawHudString.
While your still in the Draw function, dont forget to alter the other line that draws using the normal code, from this:
 CODE  

DrawConsoleString( LINE_START, y, g_szLineBuffer[i] );

to this:
 CODE  

gHUD.DrawHudString( LINE_START, y, 320, g_szLineBuffer[i] ,255, 255, 0, 0 );

Unfortunately altering the way saytext works can be a royal pain in the @!% due to the fact that the line gets split after so many characters have been reached, our color codes would have a nasty side effect so we need to fix this.
Still in saytext.cpp find the aptly titled function EnsureTextFitsInOneLineAndWrapIfHaveTo.
In the function you will see a piece of code that handles valves colorcode detection:
 CODE  

// check for a color change, if so skip past it
if ( x[0] == '/' && x[1] == '(' )
{
    x += 2;
    // skip forward until past mode specifier
    while ( *x != 0 && *x != ')' )
        x++;
    if ( *x != 0 )
        x++;
    if ( *x == 0 )
        break;
}

Directly after that we need to add our own colorcode detection so that the line wont be wrapped due to it:
 CODE  

///CUSTOM TEXT TUT BEGIN///
    //skip past codes//
FoundCode:
    bool bFoundCode = false;
    if(*x =='^')
    {
        char*temp;
        temp = x;
        temp++;
        switch(*temp)
        {
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
        case '0':
            x+=2;
            bFoundCode = true;
        }
        //check incase 2 codes in a row
        if(bFoundCode)
        {
            if(*x =='^')
                goto FoundCode;
        }
    }
///CUSTOM TEXT TUT END///

Crude, but effective, we simply skip past any colorcodes we may find.
There is one small other modification to make before this can be used, for some reason valves colorcodes completely break our custom DrawHudString so to fix this we will simply remove them.
Open the serverside workspace and client.cpp, in the Host_Say function we will simply remove the colorcodes, find this piece of code and alter it accordingly:
 CODE  

// turn on color set 2  (color on,  no sound)
if ( teamonly )
    sprintf( text, "(TEAM) %s: ", STRING( pEntity->v.netname ) );
//  sprintf( text, "%c(TEAM) %s: ", 2, STRING( pEntity->v.netname ) );
else
    sprintf( text, "%s: " , STRING( pEntity->v.netname ) );
//  sprintf( text, "%c%s: ", 2, STRING( pEntity->v.netname ) );

I have commented out the original lines, make yours the same.

Thats it you can now talk in different colors and modes, ingame to use this new style simply type a colorcode ("^" followed by digit) in your text like so "I want this text to be ^2red ^5yellow ^3green".
It really is that simple, as a bonus I have thrown in a different effect which can be used like this "standard code ^0additive code", you can even use combinations of color&effect together.

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

You have to register to rate this article.
User Comments Showing comments 1-1

Posted By: MrBozo on Feb 20 2004 at 15:03:52
Nice, just a few glitches I had when implementing it:

int next = xpos + gHUD.m_scrinfo.charWidths[ *szIt ]; // variable-width fonts look cool

that works for the text you draw with TextMessageDrawChar. But for the text you draw with DrawConsoleString it's not right. You have to use ConsoleStringLen(szChar) to get the width of the char/string.

Also you might want to use floats to define your r,g,b, somehow pfnDrawSetTextColor's parameters are floats.


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!