Need to start some were in modding right? Why not try the Half-Life modding Kit. This Kit is designed to have all the tools you need to start your own Half-Life mod, simple mods can be made or advance ones like Base Defense with this small set of tools. If you want to start modding Half-Life you should try this.

Post tutorial Report RSS Coding Custom Weapons Part 1 Of 3 Server Side

I think this is a tutorial that a lot of people have been waiting for, in this tutorial I will teach you how to make a Day Of Defeat style Colt M1911. We will also create a custom ammo and custom accuracy for the Colt. This is just the server side coding so it will not fully work without the second part of the tutorial for client side.

Posted by on - Advanced Server Side Coding

Custom weapons can bring a lot of attention to a mod, even something as simple as a new machine gun or even a Opposing Force weapon brought back. You can really make any type of weapon you want in Gold Source if you know how, I how ever don't so we are just going to make a basic Colt M1911, the same one I will be using in the Warfare Engine for the next version of Half-Life Modding Kit. I heavily based the code on the Glock code but it is different in its final state than the Glock. So lets get started.

First we need something to work in, create a new .cpp file in your hl.dsp I called mine coltm1911.cpp to make it easy but the name does not matter. Now we need to tell the new file what to include add this at the top (I wanted to add the code snipet boxes but it keeps bugging so I could not)


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


All this little piece of code does is tells the file what to include, notice it does include monssters.h, I am not sure why but it could be for the damage. Next we need the animations, they must be in the order they are in when you view the model, use Jeds Model Viewer to check it out

enum colt_e {
COLT_IDLE,
COLT_SHOOT1,
COLT_SHOOT2,
COLT_RELOAD,
COLT_RELOAD_NOSHOOT,
COLT_DRAW,
COLT_SHOOT_EMPTY,
COLT_EMPTY_IDLE
};

Next we need to link the code to your fgd so add this

LINK_ENTITY_TO_CLASS( weapon_colt, CColt );

If you don't know what this means weapon_colt is what the weapons spawn name is, like weapon_mp5 allowing you to spawn it in the game or place it in hammer editor, it does have to be unique. The CColt is what it is called in the code, it can be anything as long as it starts with the C and is unique. Now lets create the weapon spawn


void CColt::Spawn( )
{
pev->classname = MAKE_STRING("weapon_colt");
Precache( );
m_iId = WEAPON_COLT;
SET_MODEL(ENT(pev), "models/w_colt.mdl");

m_iDefaultAmmo = COLT_DEFAULT_GIVE;

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

This is pretty simple to explain. The pev->classname = MAKE_STRING("weapon_colt"); is telling the game if there is a weapon_colt spawn this weapon, the m_iId = WEAPON_COLT; tells the gun the ID of the weapon which we will cover in a little. SET_MODEL(ENT(pev), "models/w_colt.mdl"); Tells the code which model to use. The m_iDefaultAmmo = COLT_DEFAULT_GIVE; tells the code to give you the default amount of ammo when you pick the gun up which we will cover in a little and finally FallInit(); tells the gun to fall when it spawns so it does not float around. However you probably could remove this to make some neat situations though I never tried it. Next add this line of code

void CColt::Precache( void )
{
PRECACHE_MODEL("models/v_colt.mdl");
PRECACHE_MODEL("models/w_colt.mdl");
PRECACHE_MODEL("models/p_colt.mdl");

m_iShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell

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

m_usFireColt1 = PRECACHE_EVENT( 1, "events/colt.sc" );
m_usFireColt2 = PRECACHE_EVENT( 1, "events/colt2.sc" );
}

This is one of the most important lines of code in the game, without it anytime you spawn the gun you will be kicked out of the game. This is all of the models, sounds and events that the gun uses so the code knows what to precache. Now lets get on to the weapon information

int CColt::GetItemInfo(ItemInfo *p)
{
p->pszName = STRING(pev->classname);
p->pszAmmo1 = "ammo_45";
p->iMaxAmmo1 = _45_MAX_CARRY;
p->pszAmmo2 = NULL;
p->iMaxAmmo2 = -1;
p->iMaxClip = COLT_MAX_CLIP;
p->iSlot = 1;
p->iPosition = 3;
p->iFlags = 0;
p->iId = m_iId = WEAPON_COLT;
p->iWeight = COLT_WEIGHT;

return 1;


This is pretty simple to explain to, p->pszAmmo1 = "ammo_45"; tells the code that the primary ammo is 45 cal which is a custom ammo we will code in a little. p->iMaxAmmo1 = _45_MAX_CARRY; tells the gun to see how much 45 cal ammo the gun can carry, this is not to be confused with its magazine size. p->pszAmmo2 = NULL; and p->iMaxAmmo2 = -1; tells the code there is no secondary ammo. p->iMaxClip = COLT_MAX_CLIP; tells the code to find out how much the Magazine can hold (I know it says clip but that is not what it is, it is a magazine) p->iSlot = 1; is a little harder to explain, but this is which hud slot it will be with the other weapons, like how the crowbar has its own slot, the pistols share a menu i guess is the best way to put it 0 is the crowbar menu, 1 is the pistols and so on. p->iPosition = 3; tells the gun which slot to put it in in the menu you selected, it does have to be unique, I do not know what will happen if it is not. p->iFlags = 0; tells the gun if there are any flags, I do have a list of them that I will post later I just have to find were I put it. p->iId = m_iId = WEAPON_COLT; tells the gun its ID and the p->iWeight = COLT_WEIGHT; tells the gun to find its weight. Next we will do the deploy

BOOL CColt::Deploy( )
{
pev->body = 1;
return DefaultDeploy( "models/v_colt.mdl", "models/p_colt.mdl", COLT_DRAW, "onehanded", /*UseDecrement() ? 1 : 0*/ 0 );
}

Here pev->body = 1; tells the gun to use this body of the model, some models have different bodies others do not, I don't think the Colt did but I put it that way for some reason, "models/v_colt.mdl", "models/p_colt.mdl" tells the code to use these models that we precached already, COLT_DRAW is the animation that will play when this happens, onehanded I have been told this is a set of animations that the gun will use, I am not sure though I do have another list I have to find that has all the options. Now lets get on to the attacks, I do not want any secondary attack so I just told it to void

void CColt::SecondaryAttack( void )
{

void;

}

I will make a better tutorial covering Secondary Attacks in the Modding Kit and on my website were I can get better formatting than here but this tells the gun to do nothing when the player initiates the secondary attack. Guns such as the Mp5 use the Secondary Attack to do something special like launch a grenade. Now lets do the primary attack, not as simple


void CColt::PrimaryAttack( void )
{
//Start Presscode
if(! ( m_pPlayer->m_afButtonPressed & IN_ATTACK ) )
return;
// Well this is the function for that 1 pres 1 shoot etc

GlockFire( 0.1, 0.15, TRUE );
//End Presscode
}

void CColt::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim )
{
if (m_iClip <= 0)
{
if (m_fFireOnEmpty)
{
PlayEmptySound();
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.2;
}

Don't worry this is not the whole Primary attack just part of it, I thought it will be easier to split it up like this. I do not quite know what the top part of this code does but I think it is telling the code to initiate this attack when the button is pressed, I do know GlockFire( 0.1, 0.15, TRUE ); is something to do with the gun fireing. The bottom part is telling the code if the magazine equals zero play a empty or dry fire sound, and this little piece m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.2; tells the gun when the player can shoot again, you can use this for snipers or other guns to slow how fast the player can shoot.


m_iClip--;

m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH;

int flags;

#if defined( CLIENT_WEAPONS )
flags = FEV_NOTHOST;
#else
flags = 0;
#endif

This tells the code to initiate the Muzzle flash sprite and to initiate any flags we have selected i think #if defined( CLIENT_WEAPONS ) tells the code to go to the client side were the is some very important code we will be covering in Part 2.

// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );

{
// non-silenced
m_pPlayer->m_iWeap /> m pPlayer->m_iWeap /> }

The m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); is telling the Player model which animation to use, and the bottom were it is labeled non-silenced is for the Half-Life original glock which was planned to have a silencer, the non-hd model still has its animations and body parts for the silencer to if you ever want to make it. But this non-important piece just tells it to change the volume and flash size if there is a silencer.


Vector vecSrc = m_pPlayer->GetGunPosition( );
Vector vecAiming;

if ( fUseAutoAim )

{
vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES );
}
else
{
vecAiming = gpGlobals->v_forward;
}

Vector vecDir;
vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, VECTOR_CONE_COLT,/* Vector( flSpread, flSpread, flSpread ), */ 8192, BULLET_PLAYER_9MM, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed );

PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), fUseAutoAim ? m_usFireColt1 : m_usFireColt2, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, ( m_iClip == 0 ) ? 1 : 0, 0 );

m flNextPrimaryAttack = m_flNextSec + flCycleTime;


This tells the gun the accuracy which you could change by making your own vector which we will cover in a little, just replace the VECTOR_CONE_COLT with what ever you want. This also tells the gun to fire and to check the cycle time (next time you can fire again)

if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0)
// HEV suit - indicate out of ammo condition
m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);

m flTimeWeap + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
}

This I think will tell the HEV Suit to tell the player that you have exhausted all of your ammo. Now lets do the reload code

void CColt::Reload( void )
{
if ( m_pPlayer->ammo_45 <= 0 )
return;

int iResult;

if (m_iClip == 0)
iResult = DefaultReload( 9, COLT_RELOAD, 1.5 );
else
iResult = DefaultReload( 9, COLT_RELOAD_NOSHOOT, 1.5 );

if (iResult)
{
m_flTimeWeap + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
}
}

The if ( m_pPlayer->ammo_45 <= 0 ) tells the gun that if there is no ammo left do nothing. The iResult = DefaultReload( 9, COLT_RELOAD, 1.5 ); tells the gun when there is 0 bullets in the magazine reload the gun playing the animation with the gun slide back (most pistols when the last shot is fired kick the slide back and lock it until the user releases the slide) The iResult = DefaultReload( 9, COLT_RELOAD_NOSHOOT, 1.5 ); tells the gun that if the magazine has 1 or more bullets to play the animation with the slide in place. Now for the final piece of gun code


void CColt::WeaponIdle( void )
{
ResetEmptySound( );

m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES );

if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() )
return;

// only idle if the slid isn't back
if (m_iClip != 0)
{
int iAnim;
float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0.0, 1.0 );

if (flRand <= 0.3 + 0 * 0.75)
{
iAnim = COLT_IDLE;
m_flTimeWeap + 49.0 / 16;
}
else if (flRand <= 0.6 + 0 * 0.875)
{
iAnim = COLT_IDLE;
m_flTimeWeap + 60.0 / 16.0;
}
else
{
iAnim = COLT_IDLE;
m_flTimeWeap + 40.0 / 16.0;
}
SendWeaponAnim( iAnim, 1 );
}
}


This is pretty self explanatory, the if (m_iClip != 0) like the not says only idle if the slide is in place, this is because most guns do not have a idle animations with a slide out of place And the duplicate colt idles can be removed, I just thought it was easier to leave them this way. Now one last piece of code for this file and we are done with it, for this part of the tutorial.


class CColtAmmo : public CBasePlayerAmmo
{
void Spawn( void )
{
Precache( );
SET_MODEL(ENT(pev), "models/w_coltclip.mdl");
CBasePlayerAmmo::Spawn( );
}
void Precache( void )
{
PRECACHE_MODEL ("models/w_coltclip.mdl");
PRECACHE_SOUND("items/9mmclip1.wav");
}
BOOL AddAmmo( CBaseEntity *pOther )
{
if (pOther->GiveAmmo( AMMO_COLTCLIP_GIVE, "ammo_45", _45_MAX_CARRY ) != -1)
{
EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM);
return TRUE;
}
return FALSE;
}
};
LINK_ENTITY_TO_CLASS( ammo_coltclip, CColtAmmo );

This is the weapon magazine for the colt, like the MP5 magazines you find around, I won't explain much such I covered most of it with the weapon. Just if (pOther->GiveAmmo( AMMO_COLTCLIP_GIVE, "ammo_45", _45_MAX_CARRY ) != -1) tells the gun to give the amount of colt ammo, to give 45 cal, and to see how much you can carry. This does not have to be done in this file, in fact I do have a separate file for a few ammo clips. Lets do the easy stuff first, go to func_break.cpp You should see a bunch of items, weapons and ammo as soon as you pull up this file, go to the very last one

"weapon_hornetgun", // 21 and add this

"weapon_colt",
"ammo_coltclip"

I do not know if this is actually important, in fact I have had a few guns without it and they worked fine. But I would never cut corners in coding, do it right so you don't get bugs. Now go to weapons.cpp and search for UTIL_PrecacheOtherWeapon( "weapon_9mmAR" ); Around this area add this code

// colt
UTIL_PrecacheOtherWeapon( "weapon_colt" );
UTIL_PrecacheOther( "ammo_coltclip" );

This is very important piece of code, I forgot it on a weapon before and when you spawn it without this piece it will give you and error like weapon precache can only be done in the precache section. Now lets get are new Ammo 45 cal registered in the code, in cbase.h search int ammo_9mm; and under that add

ammo_45;

This simply tells the code there is a new ammo type, next go to client.cpp and search for cd->vuser2.x = pl->ammo_hornets; and under that add this line

cd->vuser2.y = pl->ammo_45;

I do not know what this line does but I do know that you need it. Now finally in player.cpp search for ammo_357 = AmmoInventory( GetAmmoIndex( "357" ) ); and under that add

ammo_45 = AmmoInventory( GetAmmoIndex( "ammo_45" ) );

I think this line tells the code to count for how much 45 cal ammo you have, I am not sure though. Now lets finish up, in weapons.h we have a lot of coding to do. I am going to do it in order, most of it you can just scroll along with so I won't tell you to search for anything. First look for #define WEAPON_SNARK 15 and under that add

#define WEAPON_COLT 16

This does have to be unique number and it can go up to 32 (Suit is weapon 31) This tells the code that the ID is 16. Next look for #define TRIPMINE_WEIGHT -10 and other that add

#define COLT_WEIGHT 5

This is the switching weight for the weapon, this will affect how fast it switches, the higher the slower. Now lets register how much 45 cal ammo you can carry look for #define M203_GRENADE_MAX_CARRY 10 and under that add

#define _45_MAX_CARRY 100

Now Scroll down a little farther till you see #define SNARK_MAX_CLIP WEAPON_NOCLIP and under that add

#define COLT_MAX_CLIP 9

This is telling the code how much ammo is in the magazine, change it to what ever you want I think a standard Colt M1911 45 Cal holds 9 shots but I am not sure. You can also think maybe you have a extended mag for you Glock or you have the Shell limiter on the shotguns (in a pump shotgun there is a little rod you can remove most of the time made of wood, that will limit the amount of shells you can insert. My shotgun held 2 in the reserve and when I removed it it held 6) You can really think about a lot of possible things. Or you can just have a 99 round 357 I just have fun with what you do. Next scroll down till you see #define HIVEHAND_DEFAULT_GIVE 8 and under that add

#define COLT_DEFAULT_GIVE 9

This tells the code when the Colt it Picked up give the player 9 shots of 45, I like to keep it so when you pick up a gun you get a full magazine but you could have it so there is like a room were there was a big fight so the guns have been shot leaving the magazines with less ammo. Scroll down a little farther and you will see #define AMMO_SNARKBOX_GIVE 5 Under that add

#define AMMO_COLTCLIP_GIVE COLT_MAX_CLIP

This tells the code when you pick up a colt magazine to give you the fully loaded magazine which we set as 9 shots now search for unsigned short m_usFireGlock2; and under that code entry add


class CColt : public CBasePlayerWeapon
{
public:
void Spawn( void );
void Precache( void );
int iItemSlot( void ) { return 2; }
int GetItemInfo(ItemInfo *p);

void PrimaryAttack( void );
void SecondaryAttack( void );
void GlockFire( float flSpread, float flCycleTime, BOOL fUseAutoAim );
BOOL Deploy( void );
void Reload( void );
void WeaponIdle( void );

virtual BOOL UseDecrement( void )
{
#if defined( CLIENT_WEAPONS )
return TRUE;
#else
return FALSE;
#endif
}

private:
int m_iShell;

unsigned short m_usFireColt1;
unsigned short m_usFireColt2;
};

This is just basically a preache for the weapon events. But we almost forgot to add one thing, the custom accuracy search for #define VECTOR_CONE_20DEGREES Vector( 0.17365, 0.17365, 0.17365 ) and under that add

#define VECTOR_CONE_COLT Vector( 0.00273, 0.00273, 0.00273 )

the lower the numbers the more accurate the gun is, I think these digits are horizontal spread, vertical spread, and something else but I don't know. This will make the gun fire almost perfect shots I am still adjusting it the way i like it. Now if you did every thing correctly, (and if I put it on here correctly) you should be able to compile your gun and spawn it in but it should just be boring with now animations. We will cover that in are next tutorial. I hoped this helped you it took me a Hour in and a Half to make this tutorial (ironically longer than it took to code the whole weapon) If you need any help just message me Like I said I will make a better version and post it on my website were formatting will be easier. Sorry it took a while to get this up just ran in to trouble with moddbs website, I will get the client side up next.



Post comment Comments
badsniper365 Author
badsniper365 - - 204 comments

Well finally got this third of the tutorial up hope it helps

Reply Good karma+4 votes
filetmignon1993
filetmignon1993 - - 4 comments

where must i put all these edited files in order to compile them? btw thanks for making this tutorial, i´ve researched for years about modding guns and couldn´t find anything as clear as this... :)

Reply Good karma Bad karma+2 votes
badsniper365 Author
badsniper365 - - 204 comments

Sorry for the late reply but I am guessing you have the sdk 2.3 right? If so there should be a file in there called hl.dsp open this with Visual Studio 6, or 10. You can not use the new visual studios.
After you open it it will bring up kind of a microsoft word program but you can see all the files that will be in the dll on the side, some were on the top bar should be a compile button. If not I think it is F9 key or F7 key, I get them mixed up because hammer editor uses one studio uses the other
Your welcome, I made this because I had to search a while for a tutorial that I could understand and then I still had to get help from a few other people

Reply Good karma+1 vote
filetmignon1993
filetmignon1993 - - 4 comments

Thank you very much.

Reply Good karma Bad karma+1 vote
Guest
Guest - - 689,303 comments

FYI you can also use return; instead of void; in the secondary attack function.

Reply Good karma Bad karma+1 vote
Johanazo
Johanazo - - 7 comments

From the hammer editor, by modifying the .fgd, can a new weapon be placed on a new map?

Reply Good karma Bad karma+1 vote
Post a comment

Your comment will be anonymous unless you join the community. Or sign in with your social account: