The Place to Start


Shotgun w/ slugs and buckshot 
Dr.Death
Intermediate


Shotgun w/ slugs and buckshot
New Code
Old Code

This is my first tutorial, so I would like it if you contact me,
telling me what I did completely wrong and what is realy cool!

This tutorial is about how to create a Shotgun with two types of
ammo (slugs and buckshot). I included the slugs in a way, that
you can still shoot with both barrels.

I wrote this tutorial especially for people who want to have
weapons with two types of ammo , but want to use a clip in
both cases.(Another idea might be a MP5 with normal and HE
ammo)

Read this(the comments explain the important changes)
and then replace shotgun.cpp with it:

// BEGIN SHOTGUN.CPP
/*******3Mode shotgun*******
 * Copyright 1999 Dr.Death *
 ***************************/

// essential weapon includes


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

// special deathmatch shotgun spreads
#define VECTOR_CONE_DM_SHOTGUN  Vector( 0.08716, 0.04362, 0.00  )// 10 degrees by 5 degrees
#define VECTOR_CONE_DM_DOUBLESHOTGUN Vector( 0.17365, 0.04362, 0.00 ) // 20 degrees by 5 degrees

enum shotgun_e {
        SHOTGUN_IDLE = 0,
        SHOTGUN_FIRE,
        SHOTGUN_FIRE2,
        SHOTGUN_RELOAD,
        SHOTGUN_PUMP,
        SHOTGUN_START_RELOAD,
        SHOTGUN_DRAW,
        SHOTGUN_HOLSTER,
        SHOTGUN_IDLE4,
        SHOTGUN_IDLE_DEEP
};

class CShotgun : public CBasePlayerWeapon
{
public:
        int             Save( CSave &save );
        int             Restore( CRestore &restore );
        static  TYPEDESCRIPTION m_SaveData[];

        void Spawn( void );
        void Precache( void );
        int iItemSlot( ) { return 3; }
        int GetItemInfo(ItemInfo *p);
        int AddToPlayer( CBasePlayer *pPlayer );

        void PrimaryAttack( void );
        void SecondaryAttack( void );
        BOOL Deploy( );
        void Reload( void );
        void WeaponIdle( void );
        int m_fInReload;
        float m_flNextReload;
        int m_iShell;
        float m_flPumpTime;

        // New additions to CShotgun
        void SingleBarrelShot(); // use this if in slug or single barrel shot mode
        void DoubleBarrelShot(); // use this if in double barrel
        int m_iShotgunMode; // we have to use an int not a bool because we have 3 modes
        int m_iOldClip; // I don't have to use a member but i did

};
LINK_ENTITY_TO_CLASS( weapon_shotgun, CShotgun );

TYPEDESCRIPTION CShotgun::m_SaveData[] =
{
        DEFINE_FIELD( CShotgun, m_flNextReload, FIELD_TIME ),
        DEFINE_FIELD( CShotgun, m_fInReload, FIELD_INTEGER ),
        DEFINE_FIELD( CShotgun, m_flNextReload, FIELD_TIME ),
        // DEFINE_FIELD( CShotgun, m_iShell, FIELD_INTEGER ),
        DEFINE_FIELD( CShotgun, m_flPumpTime, FIELD_TIME ),
};
IMPLEMENT_SAVERESTORE( CShotgun, CBasePlayerWeapon );

void CShotgun::Spawn( )
{
        Precache( );
        m_iId = WEAPON_SHOTGUN;
        SET_MODEL(ENT(pev), "models/w_shotgun.mdl");

        m_iDefaultAmmo = SHOTGUN_DEFAULT_GIVE;

        FallInit();// get ready to fall
}


void CShotgun::Precache( void )
{
        PRECACHE_MODEL("models/v_shotgun.mdl");
        PRECACHE_MODEL("models/w_shotgun.mdl");
        PRECACHE_MODEL("models/p_shotgun.mdl");

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

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

        PRECACHE_SOUND ("weapons/dbarrel1.wav");//shotgun
        PRECACHE_SOUND ("weapons/sbarrel1.wav");//shotgun

        PRECACHE_SOUND ("weapons/reload1.wav"); // shotgun reload
        PRECACHE_SOUND ("weapons/reload3.wav"); // shotgun reload

        PRECACHE_SOUND ("weapons/357_cock1.wav"); // gun empty sound
        PRECACHE_SOUND ("weapons/scock1.wav");  // cock gun
}

int CShotgun::AddToPlayer( CBasePlayer *pPlayer )
{
        if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) )
        {
                MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev );
                        WRITE_BYTE( m_iId );
                MESSAGE_END();
                m_iShotgunMode = 0; // we don't want a shotgun without declared mode
                return TRUE;
        }
        return FALSE;
}


int CShotgun::GetItemInfo(ItemInfo *p)
{
        p->pszName = STRING(pev->classname);
        p->pszAmmo1 = "buckshot";
        p->iMaxAmmo1 = BUCKSHOT_MAX_CARRY;
	// you might want to replace this by 62
	p->pszAmmo2 = "slugs";
	// new slug ammo type
	p->iMaxAmmo2 = BUCKSHOT_MAX_CARRY;
	// you might want to replace this by 62
        p->iMaxClip = SHOTGUN_MAX_CLIP;
        p->iSlot = 2;
        p->iPosition = 1;
        p->iFlags = 0;
        p->iId = m_iId = WEAPON_SHOTGUN;
        p->iWeight = SHOTGUN_WEIGHT;

        return 1;
}



BOOL CShotgun::Deploy( )
{
        return DefaultDeploy( "models/v_shotgun.mdl", "models/p_shotgun.mdl", SHOTGUN_DRAW, "shotgun" );
}


void CShotgun::PrimaryAttack()
{
        // chose the right shooting mode
        if( m_iShotgunMode == 0 )
        {
                SingleBarrelShot();
        }
        else if( m_iShotgunMode == 1 )
        {
                DoubleBarrelShot();
        }
        else
        {
                SingleBarrelShot();
        }
}

void CShotgun::SecondaryAttack( void )
{
        // this is important because this is the ammo type switching part
        if(m_iShotgunMode == 0 ) // check what mode we are in
        {
                m_iShotgunMode = 1; //Change mode to 1 i.E. Buckshot/Double Barrel
                SendWeaponAnim( SHOTGUN_PUMP ); // show this animation so that we now that we changed the mode
                EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/scock1.wav", 1, ATTN_NORM, 0, 95 + RANDOM_LONG(0,0x1f));
        }
        else if(m_iShotgunMode == 1 )
        {
                m_iShotgunMode = 2;
                m_iOldClip = m_iClip; //Change to Slugs
                // this is important
                m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] += m_iOldClip; 
		//put old clip back into the ammo reservoir
                if(m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] > BUCKSHOT_MAX_CARRY)
                        m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] = BUCKSHOT_MAX_CARRY; 
		// just to make sure that we don't have to much ammo
                m_iClip = 0; 
		//set clip to 0 weapon will reload automatically(if you don't now how this works look at the weaponidle function
                SendWeaponAnim( SHOTGUN_PUMP ); //same as before
                EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/scock1.wav", 1, ATTN_NORM, 0, 95 + RANDOM_LONG(0,0x1f));
        }
        else
        {
                m_iShotgunMode = 0;
                // same as before only the other way round
                m_iOldClip = m_iClip;
                m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] += m_iOldClip;
                if(m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] > BUCKSHOT_MAX_CARRY)
                        m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] = BUCKSHOT_MAX_CARRY;
                m_iClip = 0;
                SendWeaponAnim( SHOTGUN_PUMP );
                EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/scock1.wav", 1, ATTN_NORM, 0, 95 + RANDOM_LONG(0,0x1f));
        }
        m_flNextPrimaryAttack = gpGlobals->time + 0.75;
        m_flNextSecondaryAttack = gpGlobals->time + 0.75; 
	// we have to declare this or else we will be changing modes 10 times a second

}

void CShotgun::SingleBarrelShot()
{
        // don't fire underwater
        if (m_pPlayer->pev->waterlevel == 3)
        {
                PlayEmptySound( );
                m_flNextPrimaryAttack = gpGlobals->time + 0.15;
                return;
        }

        if (m_iClip < 0)
        {
                Reload( );//Modified reload function to use up the right ammo type chek it out !
                if (m_iClip == 0)
                        PlayEmptySound( );
                return;
        }

        m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME;
        m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH;

        m_iClip--;

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

        SendWeaponAnim( SHOTGUN_FIRE );

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

        UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle );

        Vector  vecShellVelocity = m_pPlayer->pev->velocity
                                                         + gpGlobals->v_right * RANDOM_FLOAT(50,70)
                                                         + gpGlobals->v_up * RANDOM_FLOAT(100,150)
                                                         + gpGlobals->v_forward * 25;

        EjectBrass ( m_pPlayer->pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_up * -12 + 
	gpGlobals->v_forward * 20 + gpGlobals->v_right * 4 , vecShellVelocity, pev->angles.y, m_iShell, TE_BOUNCE_SHOTSHELL);

        EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/sbarrel1.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM, 0, 93 + RANDOM_LONG(0,0x1f));


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

        if( m_iShotgunMode == 0 )
        {
                m_pPlayer->FireBullets( 12, vecSrc, vecAiming, VECTOR_CONE_DM_SHOTGUN, 1536, BULLET_PLAYER_BUCKSHOT, 0 );
                // Using more bullets to make shotgun cooler
        }
        else
        {
                m_pPlayer->FireBullets( 1, vecSrc, vecAiming, VECTOR_CONE_8DEGREES, 2048, BULLET_PLAYER_SLUGS, 0 ); 
		// should perhaps lower the cone size
                // fire a slug
        }

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

                if (m_iClip != 0)
                        m_flPumpTime = gpGlobals->time + 0.5;
        }
        else // this is just a little bit diffrent
        {
                if (!m_iClip && m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] < 0)
                        // HEV suit - indicate out of ammo condition
                        m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);

                if (m_iClip != 0)
                        m_flPumpTime = gpGlobals->time + 0.5;
        }

        m_flNextPrimaryAttack = gpGlobals->time + 0.75;
        m_flNextSecondaryAttack = gpGlobals->time + 0.75;

        if (m_iClip != 0)
                m_flTimeWeaponIdle = gpGlobals->time + 5.0;
        else
                m_flTimeWeaponIdle = 0.75;

        m_fInReload = 0;

        m_pPlayer->pev->punchangle.x -= 5;
}

void CShotgun::DoubleBarrelShot()  // this is the same as the old SecondaryFire( void )
{
        // don't fire underwater
        if (m_pPlayer->pev->waterlevel == 3)
        {
                PlayEmptySound( );
                m_flNextPrimaryAttack = gpGlobals->time + 0.15;
                return;
        }

        if (m_iClip < 1)
        {
                Reload( );
                PlayEmptySound( );
                return;
        }

        m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME;
        m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH;

        m_iClip -= 2;

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

        SendWeaponAnim( SHOTGUN_FIRE2 );

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

        UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle );

        Vector vecShellVelocity = m_pPlayer->pev->velocity
                + gpGlobals->v_right * RANDOM_FLOAT(50,70)
                + gpGlobals->v_up * RANDOM_FLOAT(100,150)
                + gpGlobals->v_forward * 25;
        EjectBrass ( m_pPlayer->pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_up * -12 + gpGlobals->v_forward 
		* 20 + gpGlobals->v_right * 4 , vecShellVelocity, pev->angles.y, m_iShell, TE_BOUNCE_SHOTSHELL);
        vecShellVelocity = m_pPlayer->pev->velocity
                + gpGlobals->v_right * RANDOM_FLOAT(50,70)
                + gpGlobals->v_up * RANDOM_FLOAT(100,150)
                + gpGlobals->v_forward * 25;
        EjectBrass ( m_pPlayer->pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_up * -12 + gpGlobals->v_forward 
		* 20 + gpGlobals->v_right * 4 , vecShellVelocity, pev->angles.y, m_iShell, TE_BOUNCE_SHOTSHELL);

        EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/dbarrel1.wav", RANDOM_FLOAT(0.98, 1.0), ATTN_NORM, 0, 85 + RANDOM_LONG(0,0x1f));

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

        m_pPlayer->FireBullets( 24, vecSrc, vecAiming, VECTOR_CONE_DM_DOUBLESHOTGUN, 1536, BULLET_PLAYER_BUCKSHOT, 0 );
        // Slugs should only have single fire
        //m_pPlayer->FireBullets( 2, vecSrc, vecAiming, VECTOR_CONE_5DEGREES, 2048, BULLET_PLAYER_SLUGS, 0 );

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

        if (m_iClip != 0)
                m_flPumpTime = gpGlobals->time + 0.95;

        m_flNextPrimaryAttack = gpGlobals->time + 1.5;
        m_flNextSecondaryAttack = gpGlobals->time + 1.5;
        if (m_iClip != 0)
                m_flTimeWeaponIdle = gpGlobals->time + 6.0;
        else
                m_flTimeWeaponIdle = 1.5;

        m_fInReload = 0;

        m_pPlayer->pev->punchangle.x -= 10;
}

void CShotgun::Reload( void )
{
        if(m_iShotgunMode == 0 || m_iShotgunMode == 1) 
		// we do want to check the right ammo values
        {
                if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] < 0 || m_iClip == SHOTGUN_MAX_CLIP)
                        return;
        }
        else
        {
                if (m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] < 0 || m_iClip == SHOTGUN_MAX_CLIP)
                        return;
        }

        if (m_flNextReload > gpGlobals->time)
                return;

        // don't reload until recoil is done
        if (m_flNextPrimaryAttack > gpGlobals->time)
                return;

        // check to see if we're ready to reload
        if (m_fInReload == 0)
        {
                SendWeaponAnim( SHOTGUN_START_RELOAD );
                m_fInReload = 1;
                m_pPlayer->m_flNextAttack = gpGlobals->time + 0.6;
                m_flTimeWeaponIdle = gpGlobals->time + 0.6;
                m_flNextPrimaryAttack = gpGlobals->time + 1.0;
                m_flNextSecondaryAttack = gpGlobals->time + 1.0;
                return;
        }
        else if (m_fInReload == 1)
        {
                if (m_flTimeWeaponIdle > gpGlobals->time)
                        return;
                // was waiting for gun to move to side
                m_fInReload = 2;

                if (RANDOM_LONG(0,1))
                        EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/reload1.wav", 1, ATTN_NORM, 0, 85 + RANDOM_LONG(0,0x1f));
                else
                        EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/reload3.wav", 1, ATTN_NORM, 0, 85 + RANDOM_LONG(0,0x1f));

                SendWeaponAnim( SHOTGUN_RELOAD );

                m_flNextReload = gpGlobals->time + 0.5;
                m_flTimeWeaponIdle = gpGlobals->time + 0.5;
        }
        else
        {
                // Add them to the clip
                m_iClip += 1;
                if(m_iShotgunMode == 0 || m_iShotgunMode == 1) // we don't want to use up buckshot if we fire slugs
                {
                        m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= 1;
                }
                else
                {
                        m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] -= 1;
                }
                m_fInReload = 1;
        }

}


void CShotgun::WeaponIdle( void )
{

        if(m_iShotgunMode == 0 || m_iShotgunMode == 1) 
		// we need this because we would check the wrong values if didn't use this
        {
                ResetEmptySound( );

                m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES );

                if (m_flPumpTime && m_flPumpTime time)
                {
                        // play pumping sound
                        EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/scock1.wav", 1, ATTN_NORM, 0, 95 + RANDOM_LONG(0,0x1f));
                        m_flPumpTime = 0;
                }

                if (m_flTimeWeaponIdle time)
                {
                        if (m_iClip == 0 && m_fInReload == 0 && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType])
                        {
                                Reload( );
                        }
                        else if (m_fInReload != 0)
                        {
                                if (m_iClip != 8 && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType])
                                {
                                        Reload( );
                                }
                                else
                                {
                                        // reload debounce has timed out
                                        SendWeaponAnim( SHOTGUN_PUMP );

                                        // play cocking sound
                        EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/scock1.wav", 1, ATTN_NORM, 0, 95 + RANDOM_LONG(0,0x1f));
                                        m_fInReload = 0;
                                        m_flTimeWeaponIdle = gpGlobals->time + 1.5;
                                }
                        }
                        else
                        {
                                int iAnim;
                                float flRand = RANDOM_FLOAT(0, 1);
                                if (flRand < 0.8)
                                {
                                        iAnim = SHOTGUN_IDLE_DEEP;
                                        m_flTimeWeaponIdle = gpGlobals->time + (60.0/12.0);// * RANDOM_LONG(2, 5);
                                }
                                else if (flRand < 0.95)
                                {
                                        iAnim = SHOTGUN_IDLE;
                                        m_flTimeWeaponIdle = gpGlobals->time + (20.0/9.0);
                                }
                                else
                                {
                                        iAnim = SHOTGUN_IDLE4;
                                        m_flTimeWeaponIdle = gpGlobals->time + (20.0/9.0);
                                }
                                SendWeaponAnim( iAnim );
                        }
                }
        }
        else // same as before but replaced Primary by Secondary and vice versa
        {
                ResetEmptySound( );

                m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES );

                if (m_flPumpTime && m_flPumpTime time)
                {
                        // play pumping sound
                        EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/scock1.wav", 1, ATTN_NORM, 0, 95 + RANDOM_LONG(0,0x1f));
                        m_flPumpTime = 0;
                }

                if (m_flTimeWeaponIdle time)
                {
                        if (m_iClip == 0 && m_fInReload == 0 && m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType])
                        {
                                Reload( );
                        }
                        else if (m_fInReload != 0)
                        {
                                if (m_iClip != 8 && m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType])
                                {
                                        Reload( );
                                }
                                else
                                {
                                        // reload debounce has timed out
                                        SendWeaponAnim( SHOTGUN_PUMP );

                                        // play cocking sound
                        EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/scock1.wav", 1, ATTN_NORM, 0, 95 + RANDOM_LONG(0,0x1f));
                                        m_fInReload = 0;
                                        m_flTimeWeaponIdle = gpGlobals->time + 1.5;
                                }
                        }
                        else
                        {
                                int iAnim;
                                float flRand = RANDOM_FLOAT(0, 1);
                                if (flRand < 0.8)
                                {
                                        iAnim = SHOTGUN_IDLE_DEEP;
                                        m_flTimeWeaponIdle = gpGlobals->time + (60.0/12.0);// * RANDOM_LONG(2, 5);
                                }
                                else if (flRand < 0.95)
                                {
                                        iAnim = SHOTGUN_IDLE;
                                        m_flTimeWeaponIdle = gpGlobals->time + (20.0/9.0);
                                }
                                else
                                {
                                        iAnim = SHOTGUN_IDLE4;
                                        m_flTimeWeaponIdle = gpGlobals->time + (20.0/9.0);
                                }
                                SendWeaponAnim( iAnim );
                        }
                }
        }
}



class CShotgunAmmo : public CBasePlayerAmmo
{
        void Spawn( void )
        {
                Precache( );
                SET_MODEL(ENT(pev), "models/w_shotbox.mdl");
                CBasePlayerAmmo::Spawn( );
        }
        void Precache( void )
        {
                PRECACHE_MODEL ("models/w_shotbox.mdl");
                PRECACHE_SOUND("items/9mmclip1.wav");
        }
        BOOL AddAmmo( CBaseEntity *pOther )
        {
                if (pOther->GiveAmmo( AMMO_BUCKSHOTBOX_GIVE, "buckshot", BUCKSHOT_MAX_CARRY ) != -1)
                {
                        EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM);
                        return TRUE;
                }
                return FALSE;
        }
};
LINK_ENTITY_TO_CLASS( ammo_buckshot, CShotgunAmmo );

class CShotgunSlugs : public CBasePlayerAmmo // this is the slug ammo
{
        void Spawn( void )
        {
                Precache( );
                SET_MODEL(ENT(pev), "models/w_shotbox.mdl"); // you should use a custom model
                CBasePlayerAmmo::Spawn( );
        }
        void Precache( void ) // won't work if we don't precache
        {
                PRECACHE_MODEL ("models/w_shotbox.mdl");
                PRECACHE_SOUND("items/9mmclip1.wav");
        }
        BOOL AddAmmo( CBaseEntity *pOther )
        {
                if (pOther->GiveAmmo( AMMO_BUCKSHOTBOX_GIVE, "slugs", BUCKSHOT_MAX_CARRY ) != -1) // give us the ammo
                {
                        EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM);
                        return TRUE;
                }
                return FALSE;
        }
};
LINK_ENTITY_TO_CLASS( ammo_slugs, CShotgunSlugs );
//END SHOTGUN.CPP


Now we have to make some minor changes to combat.cpp , weapons.cpp and weapons.h

These are the changes to combat.cpp:
------------------------------------
Add this after line 1494:

case BULLET_PLAYER_SLUGS:
        // make distance based!
        pEntity->TraceAttack(pevAttacker, 30, vecDir, &tr, DMG_BULLET);
        if ( !tracer )
        {
                // TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
                DecalGunshot( &tr, iBulletType );
        }
        break;
------------------------------------


These are the changes to weapons.cpp:
-------------------------------------
Add this after line 178 ( directly after BULLET_PLAYER_BUCKSHOT: ):


case BULLET_PLAYER_SLUGS:
-------------------------------------


These are the changes to weapons.h:
-----------------------------------
In line 173 you will find this:

typedef enum
{
        BULLET_NONE = 0,
        BULLET_PLAYER_9MM, // glock
        BULLET_PLAYER_MP5, // mp5
        BULLET_PLAYER_357, // python
        BULLET_PLAYER_BUCKSHOT, // shotgun
        BULLET_PLAYER_CROWBAR, // crowbar swipe

        BULLET_MONSTER_9MM,
        BULLET_MONSTER_MP5,
        BULLET_MONSTER_12MM,
} Bullet;

Replace it with this:

typedef enum
{
        BULLET_NONE = 0,
        BULLET_PLAYER_9MM, // glock
        BULLET_PLAYER_MP5, // mp5
        BULLET_PLAYER_357, // python
        BULLET_PLAYER_BUCKSHOT, // shotgun
        BULLET_PLAYER_CROWBAR, // crowbar swipe

        BULLET_MONSTER_9MM,
        BULLET_MONSTER_MP5,
        BULLET_MONSTER_12MM,

        BULLET_PLAYER_SLUGS,
} Bullet;

------------------------------------

Now compile and run (don't forget liblist.gam)

Thats it ! We have now created a Shotgun w/ slugs !
But if you want to have better ammo display in the
HUD you still have to make some changes.
(You will find out how to do this in the smokegrenade
tutorial that you can find in the Half-Life
Programming Zone)

This is the end of my first tutorial and perhaps
I will make some more!
And if you liked it tell me

PS:
To have a "blast those guys to hell" MP-5
Just replace line 198 with this:

m_pPlayer->FireBullets(8, vecSrc, vecAiming, VECTOR_CONE_6DEGREES, 8192, BULLET_PLAYER_MP5, 4 );

Any questions or suggestions should be sent to me: muellerroemer@planet-interkom.de