Lead Programmer for Half-Rats: Parasomnia and Gameplay/Linux programmer for Zombie Panic! Source. Used to work on Arrangement (previously ArrangeMode) as an Audio/Gameplay programmer.

RSS My Blogs

In this first blog article, I'm gonna post a series of hints & tips about programming for the Gold Source engine. I see many modders diving into the source code and start panicking a lot when they do something so I hope this article will help people when they are starting programming for the Gold Source engine. Keep in mind that those series of tips & hints come from my personal experience from the past year working on many HL1 mods like Half-Counter/Plasma/Far Crab/ARRANGEMENT/Revenge of Love, they may work or they may not work for you, feel free to discuss about it in the comments.

Number 1 : Patience and perseverance will help achieve what you want to do

This is very important to any people involved into IT software development. In the world of Half-Life 1 programming, don't expect your fresh new weapon to function properly within the next 5 minutes of having written the first line of code. Here's an example: back into the Half-Counter days (my very first HL1 mod), it took me 2 days to code and bug fix a CS-like Colt M4A1 with a silencer. Thanks to the experience and the new weapon system created by HAWK0044, it takes very less to implement a new weapon within ARRANGEMENT (if we don't take in account "validating" the weapon which is testing, make sure it's balanced...).

Here I talked about a "minor" modification which is adding a new weapon, but what about a "major" modification? As you may already know, ARRANGEMENT features a new audio engine powered by FMOD Studio. Creating the engine's bare bones took me around half a year, the implementation within ARRANGEMENT was done in almost a week followed by another 6 months of improvements and bug fixing which makes a total of around a year for an amazing powerful audio engine.

Morale: Don't expect your code to work properly as it should within the next 5 minutes. Don't pretend that your code will always work the first time. Don't expect to do everything in 10 minutes.

Number 2 : First things first, learn C and C++ programming then you may proceed

The Gold Source engine is written in old C/C++. The differences between the old and modern C++ are the standards and some stuff that you won't need so much. This is a MUST before diving into the Half-Life source code. How can you cook a delicious meal if you don't know how to use the oven? How can you drive a car if you don't know how to pass the next/previous gear? Well this is the same.

Start by writing basic C applications (console only will be fine), once you are confident enough with the C language, you can do the same with C++. I don't ask you to be the master of C/C++ and/or learn the whole language, but if I start asking questions about "oriented object programming", "classes", "methods", "functions", you should be able to answer me.

Morale: Don't burn steps. Don't start modifying the Half-Life source code if you don't know how to program with the C/C++ languages.

Number 3 : Know your working environment, learn how Gold Source works in general

In others words, if I ask you something like "What is the format used for maps by the Gold Source engine?", "How a Half-Life BSP tree look like (in general)?", "What is the event system within Gold Source?", you should be able to answer me. It is very important to know how the engine works in general before you start changing stuff around.

Take this very basic example: you know NOTHING about cars and you managed to be hired as a mechanic, the boss order you to a fix a client's car. What are you going to do? A) Attempt to fix the car (yolo style), make it worse and be fired. B) Learn how the car work, fix it, give it back to the client and get paid.

The B option seems to be more appropriate and this is the same with Gold Source programming.

Morale: Don't mod Gold Source if you don't know how it works in general.

Number 4 : Gearing up, get the appropriate source code and the tools

There are many forks (variants) of the Half-Life source code, and depending on what you want your mod to be like, you have to choose the proper source code and the tools. Do you want to use Xash3D? Then use a Xash3D source code. Is the Xash3D source code I'm gonna use designed for a specific compiler (for instance: modified source code for Visual Studio 2010 support)? Then I'll need to download and install the free Express version of VS 2010. You get the idea.

From now on, I'm going to assume that you have the chosen the official Half-Life SDK from Valve's GitHub. The common mistake that I see is people downloading the most recent Visual Studio (which is 2015 at the time I'm writing this). There are 2 problems with this: 1) You will have to modify (or use an existing) the SDK to make it work with VS 2015 compilers. 2) The source code has been designed for VS 2010 compilers and I think you should stick to VS 2010 to avoid possible new bugs/differences.

Morale: Don't use a hammer to screw. Don't use a shotgun if your enemy is at long range. Don't wear an urban camo if you are operating in the desert...

Number 5 : "OMFG, **** YOU COMPILE ERRORS, GOOGLE HELP ME!!!", the popular reflex that you should kill right now

Many programmers at their beginning have done the same (me included). When you have a compile error, one of the bad reflex is to copy/paste the error and Google the problem. If you have this reflex, kill it. In 90% of the cases, the solution to your error is written into the error itself. Here are some basic examples (I would to thank LastLifeOfficial for those):

1>c:\users\toshiba\desktop\d\p90.cpp(32) : error C2065: 'CP90AmmoClip' : undeclared identifier
1>c:\users\toshiba\desktop\d\p90.cpp(32) : error C2059: syntax error : ')'
1>c:\users\toshiba\desktop\d\p90.cpp(39) : error C2065: 'P90_MODEL_WORLD' : undeclared identifier
1>c:\users\toshiba\desktop\d\p90.cpp(48) : error C2065: 'P90_MODEL_1STPERSON' : undeclared identifier
1>c:\users\toshiba\desktop\d\p90.cpp(49) : error C2065: 'P90_MODEL_3RDPERSON' : undeclared identifier
1>c:\users\toshiba\desktop\d\p90.cpp(50) : error C2065: 'P90_MODEL_WORLD' : undeclared identifier
1>c:\users\toshiba\desktop\d\p90.cpp(55) : error C2065: 'P90_SOUND_SHOOT1' : undeclared identifier
1>c:\users\toshiba\desktop\d\p90.cpp(56) : error C2065: 'P90_SOUND_SHOOT2' : undeclared identifier
1>c:\users\toshiba\desktop\d\p90.cpp(68) : error C2065: 'P90_MAX_AMMO' : undeclared identifier
1>c:\users\toshiba\desktop\d\p90.cpp(72) : error C2065: 'P90_SLOT' : undeclared identifier
1>c:\users\toshiba\desktop\d\p90.cpp(73) : error C2065: 'P90_POSITION' : undeclared identifier
1>c:\users\toshiba\desktop\d\p90.cpp(96) : error C2065: 'P90_MODEL_1STPERSON' : undeclared identifier
1>c:\users\toshiba\desktop\d\p90.cpp(96) : error C2065: 'P90_MODEL_3RDPERSON' : undeclared identifier
1>c:\users\toshiba\desktop\d\p90.cpp(97) : error C2065: 'P90_DEPLOY' : undeclared identifier
1>c:\users\toshiba\desktop\d\p90.cpp(150) : error C2065: 'AUTOAIM_1DEGREES' : undeclared identifier
1>c:\users\toshiba\desktop\d\p90.cpp(166) : error C2059: syntax error : ')'
1>c:\users\toshiba\desktop\d\p90.cpp(169) : error C2065: 'P90_FIRE_DELAY' : undeclared identifier
1>c:\users\toshiba\desktop\d\p90.cpp(172) : error C2065: 'P90_FIRE_DELAY' : undeclared identifier
1>c:\users\toshiba\desktop\d\p90.cpp(172) : error C2065: 'P90_FIRE_DELAY' : undeclared identifier
1>c:\users\toshiba\desktop\d\p90.cpp(178) : error C2065: 'P90_RELOADLAST' : undeclared identifier
1>c:\users\toshiba\desktop\d\p90.cpp(178) : error C2065: 'P90_RELOAD_TIME' : undeclared identifier
1>c:\users\toshiba\desktop\d\p90.cpp(206) : error C2653: 'CP90AmmoClip' : is not a class or namespace name
1>c:\users\toshiba\desktop\d\p90.cpp(208) : error C3861: 'Precache': identifier not found
1>c:\users\toshiba\desktop\d\p90.cpp(209) : error C2065: 'pev' : undeclared identifier
1>c:\users\toshiba\desktop\d\p90.cpp(210) : error C2352: 'CBasePlayerAmmo::Spawn' : illegal call of non-static member function
1> c:\users\toshiba\desktop\d\src_dll\dlls\weapons.h(368) : see declaration of 'CBasePlayerAmmo::Spawn'
1>c:\users\toshiba\desktop\d\p90.cpp(214) : error C2653: 'CP90AmmoClip' : is not a class or namespace name
1>c:\users\toshiba\desktop\d\p90.cpp(221) : error C2653: 'CP90AmmoClip' : is not a class or namespace name
1>c:\users\toshiba\desktop\d\p90.cpp(224) : error C2065: 'P90_MAX_AMMO' : undeclared identifier
1>c:\users\toshiba\desktop\d\p90.cpp(227) : error C2065: 'pev' : undeclared identifier

He didn't knew how to fix them and I assumed he didn't looked properly at the error messages and/or didn't learned C/C++ programming (@LastLifeOfficial: if you read this, no offense intended) he asked me how he could fix those errors and I replied with the following:

Maybe you missed "class" in front of "CP90AmmoClip", it should be "class CP90AmmoClip : public CBasePlayerAmmo". This is causing all the issues with CP90AmmoClip, pev and Precache. Take a look at "CGlockAmmo" in "hl_wpn_glock.cpp" or "CMP5AmmoClip" in "mp5.cpp", copy/paste and tweak for your P90.

You may have forgotten to make those defines at the beginning of "p90.cpp" or in "weapons.h" like this:

#define P90_MODEL_1STPERSON "models/weapons/v_p90.mdl"

And the errors were fixed and he was happy that everything was working. In some situations, a "rebuild" (cleaning the solution and building it again) may solve one or more problems. I also warned him on the fact that looking at the error messages are enough to get the solution to the problem and learning C/C++ might help in the future.

I also want to make sure that everyone makes the difference between an error and a warning. An error is a problem in your code that prevent compilation (like the examples above). A warning is potentially a problem in your code that don't prevent compilation but can produce an unexpected behavior like a bug or an in-game crash. If you are using the Half-Life 1 SDK from GitHub, you will see the warnings C4028 (mismatch < or > with unsigned/signed variable), C4058 (variable declaration in loop is used outside of it, assuming the last iteration for the rest of the code), C4996 (POSIX declarations blahblah, use _function instead of function or add define CRT_THINGY). The first two can be easily fixed and the last one can be ignored (otherwise you will break the code for Linux and OSX).

Morale: Don't open your web browser, copy/paste in Google your compile errors as soon as you've got one. Look at the error for the solution, attempt to fix it yourself and learn from your mistakes. Make the difference between an "error" and a "warning".

Number 6: Keep it small and optimized, avoid usage of librairies and platform specific code if possible

In most of the C++ programming tutorials, you learn how to use the STD library. In Gold Source programming, avoid that if you can. In some situations, you may be forced to use the STD library or another one for a specific task.

Example 1: Your mod need to communicate through the Steam API to check if the player is member in a specific Steam group OR query a database on a server to check if the player is a donor or not, you may need to use the CURL or MySQL library, in that case, it's fine.

Example 2: Your mod is using the PARANOIA's renderer which means using OpenGL libraries, it's fine.

Example 3: Your mod need a music system to replace the CD system of Half-Life which means using FMOD/OpenAL/WWise librairies, it's fine.

Example 4: You are making an advanced inventory system and need to store the items in a list and you consider using lists from the STD library. WRONG, consider using arrays if you can.

Example 5 : You have trouble manipulating text in strings with basic char, char array and char pointer, and you use the string type from the STD library. WRONG, look at how functions/methods for string manipulation like "strstr", "sprintf" works...

Try to respect the "standards" of Gold Source programming, look at how Valve has coded Half-Life and try to do the same. Everything I said about librairies also applies to using platform specific code (the famous "#ifdef WIN32"), avoid using Windows specific code if possible, use it only if it's a must (querying Windows's registry for instance).

Morale: Only use librairies if you can't accomplish a specific task without it. Always make cross-compatible code by avoiding platform specific code as much as possible.

Number 7 : Start from small, to achieve bigger

In other words, don't start creating a physics engine or converting Gold Source into Unreal Engine 4 if you don't know how to make a minor modification like tweaking/adding a weapon/monster and such. This also applies to mods as well.

Many people want to create a very complex mod like for instance a racing mod or a RPG mod or an ARMA style mod with shiny new particles effects and all that kind of stuff without having gained enough experience with the Half-Life source code first.

Start with small things first, tweak values around the source code and see what are the differences. Then add new stuff and see how it works. Try to set yourself some challenges like "Today, I'm gonna code a Opposing Force like Sniper Rifle", "I'm gonna code a prone mechanic to the player", and then, you will be able to set bigger challenges like "I'm gonna code a Deus Ex like conversation system" or "more complex hit detection system like HL: Invasion".

Morale: Start by making minor modifications to gain experience that allow you to do bigger modifications in the future.

Number 8 : Code, test, debug, test more, debug more, MOAR TEST, MOAR DEBUG aka the "epic win cycle"

This is very important and I can't stress it enough: debugging and testing helps a lot. You have powerful debugging tools and it's a shame to not use them. Remember that debugging will tell you where your errors are and not how to fix them.

The first form of debugging is printing messages into the console, it is very easy and can be done this way (depending on which project you are coding):

// Small snippet for the client project
gEngfuncs.Con_Printf( "Attempting to get pointer to the player\n" );

cl_entity_t *pPlayer = gEngfuncs.GetLocalPlayer();
if ( pPlayer == NULL )
    gEngfuncs.Con_Printf( "Failed to get pointer to player!\n" );
else
    gEngfuncs.Con_Printf( "I have the pointer to the player!\n" );

// Small snippet for the server project
ALERT( at_console, "Attempting to find \"monster_barney\"\n" );
CBaseEntity *pBarney = NULL;
while ( (pBarney = UTIL_FindEntityByClassname( NULL, "monster_barney" )) != NULL )
{
    ALERT( at_console, "I\'ve found a Barney!\n" );
    ALERT( at_console; "His position is X = %f, Y = %f, Z = %f\n", pBarney->pev->origin.x, pBarney->pev->origin.y, pBarney->pev->origin.z );
}

The second form of debugging is setting breakpoints in your code, run the debug, replicate the steps to have the bug/crash and once the breakpoint is reached, step into the code and look what is right and what is wrong. If your C/C++ tutorials are good, they should teach you how to do that.

Testing is also very important, don't hesitate to test for minutes or even hours even for small things like weapons, items... Sometimes, having beta-testers can also be helpful to track bugs that you wouldn't find out by yourself. Something worth a note: test in "normal cases" scenarios, something that work in a map might not work in another or that something could break if you are dying/dead and/or during a map transition. Something that work with the "kill" command may not work with a "normal" death...

Morale: Don't be afraid to make a huge amount of tests even for a small things, use debugging tools a lot and test in normal cases scenarios (aka don't force situations).

Number 9 : Don't make your eyes and those you might ask to help you bleed, always keep your code organized and clean

When I see code written like this:

void mymonster::TraceAttack(entvars_t *a, float da, Vector di, TraceResult *tr, int bdt)
{if(ptr->iHitgroup==HITGROUP_CHEST || ptr->iHitgroup==HITGROUP_STOMACH)
{if(bdt & (DMG_BULLET|DMG_SLASH|DMG_BLAST))
{da = da / 2;}
else if(ptr->iHitgroup==10)
{if(bdt & (DMG_BULLET|DMG_SLASH|DMG_BLAST))
{da -= 20;
if (da <= 0)
{UTIL_Ricochet(ptr->vecEndPos,1.0);da=0.01;}
ptr->iHitgroup = HITGROUP_HEAD;}}
CTalkMonster::TraceAttack(a, da, di, bdt);}

I don't want to read it, it hurt my eyes and I think it hurt yours too, how can you even find if there is a bug there? How you can even read something like that? This is the same code but written properly:

// TraceAttack - Trace the attack and react to it
void CBarniel::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType )
{
    // Where I have received the attack?
    switch ( ptr->iHitgroup )
    {
        case HITGROUP_CHEST:
        case HITGROUP_STOMACH:
            // Divide the damage by 2 if it's a bullet, explosion or blade attack because I have a kevlar
            if ( bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_BLAST) )
                flDamage = flDamage / 2;
            break;
        case 10: // Right in my helmet
            // Is that a bullet, blade or blunt damage?
            if ( bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_CLUB) )
            {
                // Reduce the damage a lot and make a ricochet if my helmet fully protected me
                flDamage -= 20;
                if ( flDamage <= 0 )
                {
                    UTIL_Ricochet( ptr->vecEndPos, 1.0 );
                    flDamage = 0.01;
                }
            }
            // Consider it was a headshot
            ptr->iHitgroup = HITGROUP_HEAD;
            break;
    }
    CTalkMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType );
}

See how much clearer it is to read the code? I admit that some comments aren't necessary because we clearly see what some parts of the code does, but see how the indentation, the explicit variables names made incredible differences with the bad looking code. So always keep an habit of writing code that is good and clear to read.

Morale: For yourself and for other people that might read your code in order to help you, always keep it clean, organized and simple. Messy/unreadable code will just hurt people eyes and they may ignore you.

Number 10 : Copying/pasting code will not make you a programmer

This is also one of the common mistake of any modder for any engine/game/mod, they see tutorials or code about something they are interested in to add in their mod, they copy/paste the code, they test and they are crying "OMFG IT'S NOT WORKING!!!" or "HOW DO I ADD THIS STUFF?!?!".

Copy/paste is something that anyone can do very easily, I've learned copy/paste at the age of 2. Even older people who have trouble doing basic stuff like printing/scanning documents, starting some complex applications, installing/uninstalling softwares know how to copy/paste.

Copying/pasting code is something that you should ban, especially if the code was designed for another SDK and/or it is known to be bugged/non-working. Instead, look at the code and understand what it does and how it works, and then try to make your own code with what you have learned from the other people. Don't (re)type every line of code of the original author as it would be the same as copy/paste.

Copying/pasting existing code in the SDK is fine as long as you understand the code that you are going to copy/paste. For instance, copy/paste the Glock code to make an USP is fine as you have understood what the Glock code does.

Morale: Ban the "copy/paste code from tutorials/source code" syndrome, look at how other people achieved and how you can do the same without reproducing the original author's code. The only situation where copying/pasting code is fine is from existing code as long as you've understood the original code.

Bonus for multiplayer mods : Friendly penguins say : "Love us, or your multiplayer mod will die" aka support Linux or face the consequences

Windows is not the only operating system to exist in the world, there are many more and Linux is one of them. Why Linux? Because it's the most popular operating system for servers of any kind in the world. Google/Facebook/Twitter servers are powered by Linux, Android is powered by Linux, most of embedded systems like GPS, radios are powered by Linux. And I will conclude that most of Valve's games servers provided by the community are running under Linux. Some enterprises/people/entities prefer Linux (or OSX) rather than Windows, in my university, Windows XP is only present for students learning foreign languages, everything else (IT/maths/chemistry) is powered by Linux/OSX.

Many multiplayer mods (not all of them) were released without at least dedicated server support for Linux and they've failed to have many community servers for that reason. If you want to have a huge boost of community servers for your multiplayer mod, you will have to support Linux.

There are many ways to have Linux on your computer, either by "dual-booting" or using a virtual machine (with "Oracle VirtualBox" or "VMWare"), Google is your friend. Learn how Linux works and what are the differences between programming for Linux/Windows. And once you are ready, start porting your mod on Linux.

Morale: Don't think Windows is the only operating system in the world because it is very popular, Linux is the most used operating system for servers and you are taking huge risks if you don't support it.

Bonus : Solo or working with other developers, learn and use version control software like Git

For years, sharing codes has been a huge pain, between conflicts, compile errors and all. This is why version control software (VCS) have been created.

Valve have been using and I think they still uses a paid solution called Perforce (P4), but there are also free very known alternatives like SVN, Git. I'm going to redirect you to this one hour and half YouTube video which is an introduction to Git and how powerful it can be to you alone and/or if you are in a team of multiple programmers.

In ARRANGEMENT's case, we use Git and it has saved and helped many of the programmers in a ton of different situations.

Morale: While not mandatory, a version control software can save your life (and your mod's life too) in many situations, solo like in a team.

Start a group Groups
Anime Fans of modDB

Anime Fans of modDB

2,417 members Fans & Clans

This group has been formed to gather the people who enjoy Japanese anime and all of its facets, to salute the people from the land of the Rising Sun.

Anime Fans of DBolical

Anime Fans of DBolical

484 members Fans & Clans

Rules for the group can be read on the front part of the group, questions can be sent to Kark-Jocke or you can comment at the front page of the group.

Linux Gamers

Linux Gamers

2,971 members Fans & Clans

The group for gamers dedicated to Linux. No matter if game developers or game players all are welcome interested in Linux as a gaming platform.

J.A.C.K.: My Favorite Level Editor

J.A.C.K.: My Favorite Level Editor

118 members Fans & Clans

You are an old-school level designer, or just decided to become one, but tired of limitations of Valve Hammer Editor? Radiant seems to be too complex...

Half-Life Opposing Force Fans

Half-Life Opposing Force Fans

208 members Fans & Clans

A group for all those Opposing force fans that are still around. Everyone that at least likes Opposing force are welcome. No spaming, or posting silly...

France

France

292 members Geographic

Pour tous les Français et toutes les personnes qui aiment la France, sa culture et sa langue !

DB Testing

DB Testing

307 members Official

Would you like to help us test new designs and features we are rolling out across the network? Apply to join this group for access.

Cat lovers

Cat lovers

617 members Fans & Clans

This is a group for everyone who likes cats, and wanna have a look at some cute/funny cats.

Comments  (0 - 10 of 14)
Blue199
Blue199

Hey man, glad to see you're still alive. How's stuff? :)

Reply Good karma Bad karma+1 vote
Kark-Jocke
Kark-Jocke

❆❅❆ I'm here now to wish you a Merry Christmas shepard62fr ( Moddb.com ) ❆❅❆

Reply Good karma Bad karma+1 vote
Kachibrach
Kachibrach

From which title is character on your avatar?

Reply Good karma Bad karma+1 vote
shepard62fr Creator
shepard62fr

Lilith Asami from Trinity Seven

Reply Good karma+1 vote
Kark-Jocke
Kark-Jocke

✯ I wish you a happy new year! shepard62fr ( Moddb.com ) ✯

Reply Good karma Bad karma+1 vote
EXE.EXE
EXE.EXE

Welcome to my friends list

Reply Good karma Bad karma+1 vote
[_-=MTB=-_]
[_-=MTB=-_]

Nice tips about programming Goldsrc... :)

I wish im A proggammer :/

Reply Good karma Bad karma+1 vote
shepard62fr Creator
shepard62fr

Thanks, I don't want beginners to repeat the same mistakes I did when I was like them ^^

I started learning programming at the age of 10 and since then, it became my hobby and it later became my future job (assuming I'm successful in my studies which is kinda hard because I'm aiming for the highest diploma).

Reply Good karma+2 votes
Kark-Jocke
Kark-Jocke

Welcome to my friends list: shepard62fr
I like your avatar, are you a anime fan?

Reply Good karma Bad karma+1 vote
shepard62fr Creator
shepard62fr

Late reply is late, sorry ^^

Yeah, but I don't have the time to watch them anymore with all those projects to make ^^

Reply Good karma+1 vote
Kark-Jocke
Kark-Jocke

I work to much that I have almost no time for fun anymore X_x

Reply Good karma Bad karma+1 vote
Post a comment
Sign in or join with:

Only registered members can share their thoughts. So come on! Join the community today (totally free - or sign in with your social account on the right) and join in the conversation.