Welcome, Guest! Login | Register

Creating full Half-Life weapons [Print this Article]
Posted by: Persuter
Date posted: Mar 18 2003
User Rating: 4 out of 5.0
Number of views: 16602
Number of comments: 10
Description: both client and server side detailed
(Disclaimer: I know this works for SDK 2.2, I don't know about SDK 2.3. It should work, but please email me at persuter@planethalflife.com if you find differently.)

This tutorial's aim is not to particularly explain HOW to program a weapon; that will be different for each weapon. Instead, this tutorial will provide a checklist for all the little niggling details that are required before your server-side and client-side weapon code can work in Half-Life.

For this tutorial, I will create an example gun, called, usefully enough, CExampleGun. You will see that there are many different names for it. I will highlight my added code with bold face.

We'll start off by explaining the stuff you need to do on the server side:

Go to func_break.cpp, around line 62, you will add your weapon to the list of things a breakable can spawn.

 QUOTE  
const char *CBreakable::pSpawnObjects[] =
{
NULL, // 0
"item_battery", // 1
"item_healthkit", // 2
"weapon_9mmhandgun",// 3
"ammo_9mmclip", // 4
"weapon_9mmAR", // 5
"ammo_9mmAR", // 6
"ammo_ARgrenades", // 7
"weapon_shotgun", // 8
"ammo_buckshot", // 9
"weapon_crossbow", // 10
"ammo_crossbow", // 11
"weapon_357", // 12
"ammo_357",  // 13
"weapon_rpg", // 14
"ammo_rpgclip", // 15
"ammo_gaussclip", // 16
"weapon_handgrenade",// 17
"weapon_tripmine", // 18
"weapon_satchel", // 19
"weapon_snark", // 20
"weapon_hornetgun", // 21
"weapon_example", // 22
};


Next, go to weapons.cpp, and around line 340, add a UTIL_PrecacheOtherWeapon for your weapon.

 QUOTE  
// glock
UTIL_PrecacheOtherWeapon( "weapon_9mmhandgun" );
UTIL_PrecacheOther( "ammo_9mmclip" );

// mp5
UTIL_PrecacheOtherWeapon( "weapon_9mmAR" );
UTIL_PrecacheOther( "ammo_9mmAR" );
UTIL_PrecacheOther( "ammo_ARgrenades" );

// example weapon
UTIL_PrecacheOtherWeapon( "weapon_example" );



Next, go to line 89 in weapons.h, and add your weapon's define name.

 QUOTE  
#define WEAPON_TRIPMINE  13
#define WEAPON_SATCHEL  14
#define WEAPON_SNARK  15
#define  WEAPON_EXAMPLE  16


You may also, though it is not necessary, add defines for your weapon's weight, default ammo, max ammo, and so forth below that. In general, this is something you want to do for most weapons, but since it's dependent on each weapon (some weapons don't have ammo at all, for example), I'm not going to go through all the possibilities here.

Next, go to the very bottom of weapons.h, and add your weapon's class. It should look something like this.

 QUOTE  
class CExampleGun : public CBasePlayerWeapon
{
public:

void Spawn( void );
void Precache( void );
int iItemSlot( void ) { return 4; }
int GetItemInfo(ItemInfo *p);

void PrimaryAttack( void );
void SecondaryAttack( void );
BOOL Deploy( void );
void WeaponIdle( void );
int AddToPlayer( CBasePlayer* );

virtual BOOL UseDecrement( void )

#if defined( CLIENT_WEAPONS )
return TRUE;
#else
return FALSE;
#endif
}

private:
unsigned short m_usExampleFire;
 
};


All of those functions and the unsigned short are necessary. Other functions and variables will probably be necessary for any particular weapon, but obviously we cannot go through that here. You will have to change iItemSlot's return value to whatever HUD slot you want it in. In this case, we have put it in the fourth slot, where the egon, gauss, rocket launcher, and so forth go.

Next, we create a file called example.cpp (name it something else for your own weapon). Most of the functions you'll have to figure out, but your cpp file should start out with something like the following. Check how the other weapons are done to finish it off.

 QUOTE  
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "weapons.h"
#include "nodes.h"
#include "player.h"

LINK_ENTITY_TO_CLASS( weapon_example, CExampleGun );

void CExampleGun::Spawn( )
{
pev->classname = MAKE_STRING("weapon_example"); // hack to allow for old names
Precache( );
SET_MODEL(ENT(pev), "models/w_9mmAR.mdl"); // This should be your own weapon model
m_iId = WEAPON_EXAMPLE;

m_iDefaultAmmo = 50; // this could be replaced with EXAMPLE_DEFAULT_GIVE if you had defined it

FallInit();// get ready to fall down.

}


void CExampleGun::Precache( void )
{

// Again, you must replace these precache models and sounds with your own models and sounds
PRECACHE_MODEL("models/v_9mmAR.mdl");
PRECACHE_MODEL("models/w_9mmAR.mdl");
PRECACHE_MODEL("models/p_9mmAR.mdl");

PRECACHE_SOUND("items/9mmclip1.wav");

PRECACHE_SOUND("items/clipinsert1.wav");
PRECACHE_SOUND("items/cliprelease1.wav");

PRECACHE_SOUND ("weapons/hks1.wav");
PRECACHE_SOUND ("weapons/hks2.wav"); PRECACHE_SOUND ("weapons/hks3.wav");

// this is to hook your client-side event
m_usExampleFire = PRECACHE_EVENT( 1, "events/example.sc" );
}

int CExampleGun::GetItemInfo(ItemInfo *p)
{
p->pszName = STRING(pev->classname);
p->pszAmmo1 = "9mm";
p->iMaxAmmo1 = 200;
p->iMaxClip = -1; // means that there is no clip
p->iSlot = 3;
p->iPosition = 4;
p->iFlags = 0;
p->iId = m_iId = WEAPON_EXAMPLE;
p->iWeight = MP5_WEIGHT; // weight is for autoswitching, so it doesn't really matter much
p->pszAmmo2 = NULL; // no secondary ammo
p->iMaxAmmo2 = -1;
 
return 1;
}

int CExampleGun::AddToPlayer( CBasePlayer *pPlayer )
{
if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) )
{
MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev );
  WRITE_BYTE( m_iId );
MESSAGE_END();
return TRUE;
}
return FALSE;
}


One note: p->iSlot MUST be one less than whatever you put in iItemSlot. If it isn't, your weapon will not display in the HUD.

OK, that's the server-side done. We now turn our attention to the client-side.

First, go into FileView (in the left window), and in the Source Files folder you will see a folder marked hl. Right-click that folder, click \"Add Files To Folder\", and find example.cpp (it should be in the dlls directory of your source code). Double-click on example.cpp. Your weapon code is now included in the client-side.

Open ev_hldm.cpp (it's also in the hl folder) and go down to about line 67, and add the following line (the function can be called anything):

 QUOTE  
void EV_EgonStop( struct event_args_s *args );
void EV_HornetGunFire( struct event_args_s *args );
void EV_TripmineFire( struct event_args_s *args );
void EV_SnarkFire( struct event_args_s *args );
void EV_ExampleFire( struct event_args_s *args );


Now go down in the file and you'll see the definitions of all these functions. Add your own in there. Again, check how the other weapons are done to have an idea about how to write yours.

Now, open up hl_weapons.cpp. Go to line 64, and add the following line:

 QUOTE  
CHandGrenade g_HandGren;
CSatchel g_Satchel;
CTripmine g_Tripmine;
CSqueak g_Snark;
CExampleGun g_ExampleGun


Now go down to line 637, same file, and add the following line:

 QUOTE  
HUD_PrepEntity( &g_HandGren , &player );
HUD_PrepEntity( &g_Satchel , &player );
HUD_PrepEntity( &g_Tripmine , &player );
HUD_PrepEntity( &g_Snark , &player );
HUD_PrepEntity( &g_ExampleGun , &player );


Finally, go down to line 761, same file, and add the following lines:

 QUOTE  
case WEAPON_TRIPMINE:
  pWeapon = &g_Tripmine;
  break;

case WEAPON_SNARK:
  pWeapon = &g_Snark;
  break;

case WEAPON_EXAMPLE:
  pWeapon = &g_ExampleGun;
  break;


Now go to hl_events.cpp, in the hl folder, go to line 40, and add the following line:

 QUOTE  
void EV_EgonStop( struct event_args_s *args );
void EV_HornetGunFire( struct event_args_s *args );
void EV_TripmineFire( struct event_args_s *args );
void EV_SnarkFire( struct event_args_s *args );
void EV_ExampleFire( struct event_args_s *args );


(Yes, that's the same as the declaration you made in ev_hldm.cpp.)

Now go down to line 88, same file, and add the following line:

 QUOTE  
gEngfuncs.pfnHookEvent( "events/egon_stop.sc", EV_EgonStop );
gEngfuncs.pfnHookEvent( "events/firehornet.sc", EV_HornetGunFire );
gEngfuncs.pfnHookEvent( "events/tripfire.sc", EV_TripmineFire );
gEngfuncs.pfnHookEvent( "events/snarkfire.sc", EV_SnarkFire );
gEngfuncs.pfnHookEvent( "events/example.sc", EV_ExampleFire );


Note that the sc file mentioned above must be the same you used in PRECACHE_EVENT in the shared weapons code.

OK, now just comes some file housekeeping. First, go into your mod's directory. Go into the events directory (if there isn't one, create one), and create a new file called example.sc. It can be totally empty, it just needs to be there. Next, go into the sprites directory and create a new text file called weapon_example.txt. I'm not wholly sure about EXACTLY how this file works, so I'll just give you an example one. There are tutorials elsewhere on the web about what exactly it is. This is just the sprite text file for the MP5, I use it for testing.

 CODE  
// mp5

12  // number of sprites
weapon  320 320hud1 0   120 80  20
weapon_s 320 320hud1    0   140 80  20
ammo    320 320hud2 0   16  18  18
ammo2   320 320hud2 36  16  18  18
crosshair 320 crosshairs    0   48  24  24
autoaim     320 crosshairs  48  72  24  24
weapon  640 640hud1 0   135 170 45
weapon_s 640 640hud4    0   135 170 45
ammo    640 640hud7 0   72  24  24
ammo2   640 640hud7 48  72  24  24
crosshair 640 crosshairs    0   48  24  24
autoaim     640 crosshairs  48  72  24  24


OK, you should be done! For simplicity, I'm going to repeat this tutorial in the following checklist so once you get used to doing these things, you can simply go through the checklist. It's in kind of a funky order, and the line numbers are slightly different, but it should work fine (this is the actual checklist I use).

 QUOTE  
HL dll:

func_break.cpp line 62

Add weapon entity name to breakables list

weapons.cpp line 341

Add weapon entity name to PrecacheOtherWeapon list

weapons.h line 82

Add weapon define name and any other defines you want

weapons.h end

Create weapon class declaration.

example.cpp 

Program weapon.


CL dll:

Add HL directory weapon file to hl folder in project. 

ev_hldm.cpp line 67

Add client-side event to list

ev_hldm.cpp line 740 (approx)

Code client-side event

hl/hl_weapons.cpp line 756

Add weapon in switch statement

line 630

Add weapon to HUD_PrepEntity

line 66

Add global variable

hl/hl_events.cpp line 82

Add hookevent

line 41

Add client-side event to list (again)

Go into <mod name>/events and add event file.

Go into <mod name>/sprites and add weapon_<weapon name>.txt

Rate This Article
This article is currently rated: 4 out of 5.0 (6 Votes)

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

Posted By: [NL]Mox on Jan 05 2004 at 11:48:13
I think this tutorial misses the parts about ammo and inflicting damage...
But its real nice, there are a lot of questions in forums about this. I'll link to this page more often :)Edited by [NL]Mox on Jan 05 2004, 11:49:05

Posted By: Persuter on Jan 07 2004 at 20:07:02
I did not put in how to create new types of ammo, true, but that's because not everyone wants to do that. (Indeed, it's oftentimes irrelevant what with the obsession with tactical mods today. :D) As for inflicting damage, I'm assuming you mean the Primary Attack and Secondary Attack function. I deliberately didn't include that, nor most of the actual weapon source code, because this is a tutorial about the rest of what needs to be done, not the actual programming of the weapon.

P.S. This article works fine for 2.3.Edited by Persuter on Feb 09 2004, 16:52:26

Posted By: Bryan on Mar 12 2004 at 17:31:41
I think it would be very useful to others if you went over using ammo and inflicting damage.

but it is a very good tutorial gj.Edited by Bryan on Mar 12 2004, 17:31:55

Posted By: jim_the_coder on Mar 16 2004 at 17:50:53
(Indeed, it's oftentimes irrelevant what with the obsession with tactical mods today. :D) I would've thought you would know better than to encourage more CS clones!

Posted By: Persuter on Mar 17 2004 at 06:18:55
Well in all seriousness there's no reason to add new types of ammo these days.

Posted By: meastro on May 31 2004 at 17:20:43
if you want a tutorial that does take that up i an tutorial visit www.wired-mod.tk

Posted By: Persuter on Jun 05 2004 at 20:05:32
Not to rain on your parade but there is no such article on your site.

Posted By: MIFUNE on May 04 2005 at 23:39:06
I´ve tried to do somethin similar to this in my MOD, I tried to make the weapon fires right and left guns ( it´s twohanded) if you press right or left mousebutton, even when it worked (copy-paste of MP5´s code) I cannot make the muzzleflash appears in the right gun, and the shells ejected are only the ones from the right gun, and appears in the middle of the screen!!!

what´s the problem then?

Posted By: cossack13 on Nov 10 2005 at 08:27:29
EDIT:FixedEdited by cossack13 on Oct 26 2006, 12:13:33

Posted By: MIFUNE on Dec 31 2005 at 04:49:53
Errr...cossack, do as I, learn a bit more C++ before going any far in MOD creation, believe me, you must do it. The tutorial works fine if you take a deeper look to it; the errors you receive are self explanatory ( missing declarations of functions and classes, etc. not sure at a 100% ), this tutorial helped me to fix my MOD´s weapons. :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: 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 (7 guests)
About - Credits - Contact Us

Wavelength version: 3.0.0.9
Valid XHTML 1.0! Valid CSS!