Introduction to Half-Life coding

A Tutorial for Half-Life

Updates

TutorialParentSubmitterStats
  • Addition New section: Finding your way around the SDK [BIG]
  • Addition Slightly more info about Solo's fork [small]
  • Tweak Changed a 'planned tutorials' line near the very bottom [small]

I almost think that this is the tutorial in its final form. I might start posting it on other sites as well, and start a series on this.

[BIG] - big change
[small] - small change

v1.0 Release 2 19d

"Hello world!" in GoldSrc

1. Introduction to HL Coding

Programming is powerful. It's one of the mightiest things there are about PCs. And just like that, it's powerful in Half-Life.

Want a new trigger_ or func_ entity for your map? Maybe a new weapon, NPC, or completely changing some mechanisms? HL coding is the answer to that.

I wrote this tutorial with absolute beginners in mind, so there may be explanations for things that are obvious or self-explanatory, or are the very basics. 
If you are one of those, I highly, highly and highly recommend you to learn C++ programming first. It will be annoying and a bit hard at first (so will HL coding), but you'll get used to it after a few weeks or so. Still, I hope that what I write here will be enough to understand, and later it'll make sense.

With that said, let's begin:

1.1. Tools and source code

If you're new to HL modding in general, you might be thinking to yourself: "Half-Life is so old that I'll have to use the old software to develop for it."

No. Community members are still making modern tools for it (J.A.C.K. and Sledge for mapping, HL Texture Tools for texturing, new export/import plugins for Blender and 3ds Max etc.), and some people take a step further and improve its SDK code.

Solokiller's fork of Half-Life SDK 2.4 is what we'll use in this tutorial. You can find it here. It's compatible with VS2017, and it has a couple of features, such as some parts written in C being replaced by C++. 
Speaking of VS2017, our IDE will be Visual Studio 2017.

? IDE
An IDE is essentially an all-in-one tool for developing your program. Think of it as a very upgraded version of a text editor.

The mistake I made years ago was that I downloaded HL SDK 2.3, whose project file couldn't be converted to newer Visual Studio versions than 2008. I thought it would work only with Visual Studio 6.0 (1998), so I installed that instead. I also didn't have any prior C++ knowledge, and that led to many issues later on, hence I recommended you to stop and learn the basics first.

Lastly, "SDK" and "source code" aren't the same things. An SDK is a set of programs and tools for developing something for its respected software. Source code is the original code of a software, and it generally comes with an SDK. But since the actual SDK's tools are outdated as hell, I'll refer to the source code as the SDK. Keep that in mind.

Either way, let's download the HL SDK 2.4 code.



Click Clone or download:



Click Download ZIP. However, if you want to use somebody else's repository, you can find them here.
Or do whatever you want. :)

Once it's done downloading, you'll want to extract the ZIP file's contents somewhere.

I usually put it under Workfolders/Half-Life/SourceCodes/, but if you're lazy enough, you can just extract the whole thing to your desktop. Understand that choosing the latter will result in one giant mess in the end. So I tell you: be organised, and make sure everything's tidy!



Now, once that is done, let's install Visual Studio 2017.


Download the Community edition. In the past, there was the so-called Express version, and Community just replaced it.

And then open the downloaded .exe file.


Hopefully your Internet connection isn't as bad as mine. :P


For what we're going to do, just check Desktop development with C++.

You can also enable XP support under Individual components if you wish.

1.2. Opening the HL SDK code

It's a good idea to make a copy of the halflife-master-updated folder and rename it to something else. You might end up editing the code so much that you don't know what the original was like, yet you need the original one to start a new project.

Open the copied folder:


As you can see, there are all sorts of folders in there. The one we're interested in is projects. Open projects, and open the vs2017 inside of it.



Open projects.sln.

That is the main solution file. It will contain the projects which we'll work on: the main DLL (hldll -> hl.dll) and the client DLL (hl_cdll -> client.dll).

When everything loads, your window will look like this:

(maybe not 100% exactly, since my Output window is in the bottom-left corner, I placed it there myself)

Here are our projects:


We'll be working with hl_cdll and hldll. 

For starters, let's make a func_wall say "Hello, world!". Yes, you've read it right. A func_wall, when it gets triggered, will say "Hello world!" in the console.

? whyEvery first-time programmer's task is to make a hello world program. After all, this is a relatively simple thing to do even in GoldSrc.

If you double-click hldll:


No need to touch References and External Dependencies. External Dependencies are needed for the code to work and compile properly, since it uses something from them.

We'll work with header (.h) and source files (.cpp). Source files contain code, simple as that. Header files, think of them as a way of communication between two source files. They can be used for more than that though.

So, let's go to Source Files/dlls/bmodels.cpp. Its name stands for "brush models". func_wall is defined there.



Now, do not get scared of the huge amount of stuff that's in here.
? // and /* */
The code marked in green are comments. When code is being compiled, comments are ignored. 

// this is a comment
/* this is a multi 
   line comment */



This is the class definition of CFuncWall. It inherits variables and functions from CBaseEntity.
? classIt's essentially like a blueprint for each instance. For example, CFuncWall is for instances of func_wall, i.e. for each object created with this class. It contains variables and functions, and one class can inherit these from another class.

Under public, you can see 3 functions: Spawn, Use, ObjectCaps.
Spawn is a function that's called when the entity spawns in the map.
Use is called when the entity is triggered by another entity. You might think that this is called when the object is used by the player. Nope, not in this case.


This is a function that links the entity func_wall to its class, CFuncWall. When you code your own entity, you'll have to write this. Notice how it's written outside of the class definition.


Here is the Use function for func_wall. What it essentially does, is changing the frame variable.
This means if you have a toggleable texture, it'll toggle it:


So, let's edit this thing.
Add the following line after the pev->frame line, or before the if line:
ALERT( at_console, "\nHello world!" );

A function can have parameters a.k.a. arguments, in this case it has two: an alert type, and the message contents themselves.
ALERT basically outputs messages like those. It's actually a different way of writing this:
g_engfuncs.pfnAlertMessage
This was done for convenience. These other "utilities" are defined in enginecallback.h.

The Use function should now look like this:


You can experiment with this. Put up multiple messages, or try an ALERT_TYPE other than "at_console". There are 6 in total:

at_notice - same as below, but it prefixes the message with NOTE:
at_console - prints into the console, shown if developer level is 1 or higher.
at_aiconsole - same as above, but only shown if developer level is 2.
at_warning - prefixes the message with WARNING:
at_error - prefixes the message with ERROR:
at_logged - prints to the server console only in multiplayer game

These are defined in eiface.h, which serves as an engine interface for the SDK.

1.3. Your first DLL

Now that this part is over, we can compile the code.
? compileCompiling is a process of translating the code in one programming language, to the language that the PC can understand (machine language), and later linking all that into an executable file. In this case, we're compiling DLL files.


Go to Build, and press Build hldll.


If everything goes fine, it should write "1 succeeded" at least. First time's a charm. If it didn't, well, feel free to ask here. HL coders are still around, even if they're rarer than they were 10 years ago.

It'll also say where it saved the DLL file. In this case, it's projects/vs2017/Debug/hldll/. Go to that folder:


You could copy this straight into your valve/dlls folder, but don't do that. Instead, we'll create a new mod. (this tutorial being for beginners, I decided to include this too)

Create a new folder in Half-Life, in the same directory where hl.exe and the rest are located:


The folder structure inside the mod is quite simple.


Here's an example. Some files will be automatically generated. All you have to do is copy the following from the valve directory: cl_dlls, dlls, liblist.gam.
liblist.gam defines the libraries (DLLs) that the mod will use, its title and other info.

After you've copied that, let's open liblist.gam. You can open it with Notepad or any other text editor.

// Valve Game Info file
//  These are key/value pairs.  Certain mods will use different settings.
//
game "Half-Life"
startmap "c0a0"
trainmap "t0a0"
mpentity "info_player_deathmatch"
gamedll "dlls\hl.dll"
gamedll_linux "dlls/hl.so"
gamedll_osx "dlls/hl.dylib"
secure "1"
type "singleplayer_only"
The game string defines the window title, and the game title you see in your Steam library. Yes, you can do "[insert own name here]: The Game" and your friends will start messaging you asking about what you're playing.
Change it so that it differs from Half-Life, or anything else you have in your Steam library.

And finally, copy hl.dll into the dlls folder. It would be a good idea to actually make a map, where you trigger a func_wall with an entity.

1.4. Testing

Open up the mod, and launch the map. Also set developer to 1.


Success. Keep in mind that this will affect literally every single func_wall there exists. 

1.5. Finding your way around the SDK

1.5.1. 1.

It's useful to always look at definitions of variables and functions.


For example, we can peek at ALERT's definition, and we'll see that it's just a macro of one of the engine functions:
#define ALERT			(*g_engfuncs.pfnAlertMessage)
And we can do the same thing for at_console, see where the others are defined:
typedef enum
{
at_notice,
at_console, // same as at_notice, but forces a ConPrintf, not a message box
at_aiconsole, // same as at_console, but only shown if developer level is 2!
at_warning,
at_error,
at_logged // Server print to console ( only in multiplayer games ).
} ALERT_TYPE;
As you can see, they're nothing special. A typedef is basically giving a name to an enumeration and calls it ALERT_TYPE. at_notice is 0, at_console is 1, at_aiconsole is 2 etc.
This gives you the ability to do stuff like this:
ALERT_TYPE something;
something = at_notice; ALERT( something, "\nHello world!" );
It's almost the same as doing this:
int something;
something = 0;
ALERT( something, "\nHello world!" );
Except the point of ALERT_TYPE is to replace these numbers with a more memorable name.

1.5.2. 2.

Explore the header and source files. You'll always find something interesting, whether it's funny comments, or useful keyvalues. In const.h, you can find constants for the effects keyvalue:
// entity effects
#define EF_BRIGHTFIELD 1 // swirling cloud of particles
#define EF_MUZZLEFLASH 2 // single frame ELIGHT on entity attachment 0
#define EF_BRIGHTLIGHT 4 // DLIGHT centered at entity origin
#define EF_DIMLIGHT 8 // player flashlight
You can do stuff with this, like adding an effects keyvalue to a solid entity (turn off SmartEdit), and give it a value of 1, for example. You should see something familiar if you placed NPCs in the wrong places in your maps:

(from left to right: 1, 8, 64)

Of course, I'm talking about the far left one. Don't forget to add an origin brush to your func_wall entities or else these effects will spawn in the world origin, 0,0,0.
However, this wouldn't be a good idea for some specific entities, since they set this keyvalue for themselves and are probably expecting it to be of a certain value. So be careful.

1.5.3. 3.

If you aren't sure how an entity does something, like triggering another entity, then just search for that entity class and look at its functions.

Go to Class View and let's find env_explosion's way of dynamically changing the explosion sprite, for example:

Double-click it. 
It's in explode.cpp. (sounds funny TBH)


This is how it dynamically changes its sprite scale depending on the explosion magnitude. You can alter this behaviour if you wish.

1.6. What next?

There are many sites which do have coding tutorials laying around.

ModDB - https://www.moddb.com/games/half-life/tutorials?fi...
TheWavelength - http://articles.thewavelength.net/index.php?site=s...
The Whole Half-Life - https://twhl.info/wiki/page/category:Goldsource_Tu...
Sourcemodding - https://www.sourcemodding.com/tutorials/goldsrc/pr...

In the near future, I'll write more of these, including:
  • semi-auto and auto pistol (modifying the existing HL weapon)
  • env_explosion with more customisation options
  • trigger_timer, and later a parametric env_viewsway, and a custom FGD

Happy coding! :)
Sign up to access this!

Embed

Share banner
Image URL
HTML embed code
BB embed code
Markdown embed code

Credits

Original Authors
Admer456 avatar
Admer456 username pic Joined 4y ago
Offline
15,004 points Ranked 308th
28 medals 1 legendary 5 rare
  • Submitted 30 Tutorials Medal icon
  • Submitted 15 Tutorials Medal icon
  • Returned 1000 times Medal icon
  • Reached 50 subscribers Medal icon
  • Received thanks 50 times Medal icon
  • 10 submissions featured Medal icon
Writer
Valve
Authors of the original HL SDK, Half-Life and GoldSrc
Special Thanks
Solokiller
for his fork of the HL SDK
Shepard62700FR
for his free programming lessons at the TWHL Discord :P

Submitter

Admer456 avatar
Admer456 username pic Joined 4y ago
Gone. :3
15,004 points Ranked 308th
28 medals 1 legendary 5 rare
  • Submitted 30 Tutorials Medal icon
  • Submitted 15 Tutorials Medal icon
  • Returned 1000 times Medal icon
  • Reached 50 subscribers Medal icon
  • Received thanks 50 times Medal icon
  • 10 submissions featured Medal icon

Admer456 avatar
Admer456

Creator
Sign up to access this!
Sign up to access this!
Sign up to access this!

Game

Sign up to access this!

Category

Details

Difficulty Level
Beginner

Attributes

Share

  • Share on Reddit
  • Share on Twitter
  • Share on Facebook
  • Share on Google+
  • Today's Pick Nov 27 2018
  • 402 Views
  • 7 Posts
  • 20dSubmitted
  • 19dModified
  • 19dUpdated

Scores

91 bScore
10 Rating

5 voters

Sign up to access this!

More from Submitter

WiPs by Submitter

More Other/Misc Tutorials

bcp.crwdcntrl.net tracking pixel