Weapon Limits

From Valve Developer Community
Jump to navigation Jump to search

This tutorial is for restricting the weapons players can carry at once, a little like the Bioshock series.

Prerequisits

This tutorial was made in Source 2013 Singleplayer Source 2013 Singleplayer branch. Different branches may require different coding.

Step 1: Enable built-in weapon limit

In hl2_player.cpp, you should see this line of code around line 74:

// This switches between the single primary weapon, and multiple weapons with buckets approach (jdw)
#define HL2_SINGLE_PRIMARY_WEAPON_MODE 0;

Change the 0 to a 1 to enable this mode.

What this does is enable some code that restricts you to only being able to pick up one primary weapon. This code includes:

void CHL2_Player::Weapon_Equip( CBaseCombatWeapon *pWeapon )
{
	if ( pWeapon->GetSlot() == WEAPON_PRIMARY_SLOT)
	{
		Weapon_DropSlot(WEAPON_PRIMARY_SLOT);
	}
bool CHL2_Player::BumpWeapon( CBaseCombatWeapon *pWeapon )
{

	CBaseCombatCharacter *pOwner = pWeapon->GetOwner();

	// Can I have this weapon type?
	if ( pOwner || !Weapon_CanUse( pWeapon ) || !g_pGameRules->CanHavePlayerItem( this, pWeapon ) )
	{
		if ( gEvilImpulse101 )
		{
			UTIL_Remove( pWeapon );
		}
		return false;
	}

	// ----------------------------------------
	// If I already have it just take the ammo
	// ----------------------------------------
	if (Weapon_OwnsThisType( pWeapon->GetClassname(), pWeapon->GetSubType())) 
	{
		//Only remove the weapon if we attained ammo from it
		if ( Weapon_EquipAmmoOnly( pWeapon ) == false )
			return false;

		// Only remove me if I have no ammo left
		// Can't just check HasAnyAmmo because if I don't use clips, I want to be removed, 
		if ( pWeapon->UsesClipsForAmmo1() && pWeapon->HasPrimaryAmmo() )
			return false;

		UTIL_Remove( pWeapon );
		return false;
	}
	// -------------------------
	// Otherwise take the weapon
	// -------------------------
	else 
	{
		//Make sure we're not trying to take a new weapon type we already have
		if ( Weapon_SlotOccupied( pWeapon ) )
		{
			CBaseCombatWeapon *pActiveWeapon = Weapon_GetSlot( WEAPON_PRIMARY_SLOT );

			if ( pActiveWeapon != NULL && pActiveWeapon->HasAnyAmmo() == false && Weapon_CanSwitchTo( pWeapon ) )
			{
				Weapon_Equip( pWeapon );
				return true;
			}

			//Attempt to take ammo if this is the gun we're holding already
			if ( Weapon_OwnsThisType( pWeapon->GetClassname(), pWeapon->GetSubType() ) )
			{
				Weapon_EquipAmmoOnly( pWeapon );
			}

			return false;
		}

		pWeapon->CheckRespawn();

		pWeapon->AddSolidFlags( FSOLID_NOT_SOLID );
		pWeapon->AddEffects( EF_NODRAW );

		Weapon_Equip( pWeapon );

		EmitSound( "HL2Player.PickupWeapon" );
		
		return true;
	}

bool CHL2_Player::ClientCommand( const CCommand &args )

	//Drop primary weapon
	if ( !Q_stricmp( args[0], "DropPrimary" ) )
	{
		Weapon_DropSlot( WEAPON_PRIMARY_SLOT );
		return true;
	}

void CHL2_Player::PlayerUse ( void )

                //Check for weapon pick-up
		if ( m_afButtonPressed & IN_USE )
		{
			CBaseCombatWeapon *pWeapon = dynamic_cast<CBaseCombatWeapon *>(pUseEntity);

			if ( ( pWeapon != NULL ) && ( Weapon_CanSwitchTo( pWeapon ) ) )
			{
				//Try to take ammo or swap the weapon
				if ( Weapon_OwnsThisType( pWeapon->GetClassname(), pWeapon->GetSubType() ) )
				{
					Weapon_EquipAmmoOnly( pWeapon );
				}
				else
				{
					Weapon_DropSlot( pWeapon->GetSlot() );
					Weapon_Equip( pWeapon );
				}

				usedSomething = true;
			}
		}

Step 2: Restrict more weapon types

Weapon types are defined by the slot they are in, as shown in hl2_player.h around line 48:

//----------------------------------------------------
// Definitions for weapon slots
//----------------------------------------------------
#define	WEAPON_MELEE_SLOT		0
#define	WEAPON_SECONDARY_SLOT		1
#define	WEAPON_PRIMARY_SLOT		2
#define	WEAPON_EXPLOSIVE_SLOT		3
#define	WEAPON_TOOL_SLOT		4

This means that weapons not in the 2nd (shown in-game as the 3rd) slot will not be restricted. Let's change that.

First method: Change the weapons' slots

Go to your mod's script folder and scroll down until you see the weapon_X.txt files. For example, let's look in the weapon_shotgun.txt file:

// Shotgun

WeaponData
{
	// Weapon data is loaded by both the Game and Client DLLs.
	"printname"	"#HL2_Shotgun"
	"viewmodel"				"models/weapons/v_shotgun.mdl"
	"playermodel"			"models/weapons/w_shotgun.mdl"
	"anim_prefix"			"shotgun"
	"bucket"				"3"
	"bucket_position"		"0"
	"bucket_360"			"1"
	"bucket_position_360"	"1"

The "bucket" number is what we want. This is the slot on the X axis the gun is on the weapon selection UI and what determines what type of weapon it is. Change the "bucket" number to "2" to make it a "Primary" weapon. Now, when you try to pick up that weapon in-game, you'll have to drop your current primary weapon to pick up that one. It's also a good idea to change the "bucket_position" tag to 0 too so that there isn't any unnecessary space in the weapon selection UI.

Second method: Add the weapon's slot to the... greylist.

To do this, find this again in hl2_player.cpp:

void CHL2_Player::Weapon_Equip( CBaseCombatWeapon *pWeapon )
{
#if HL2_SINGLE_PRIMARY_WEAPON_MODE
	if ( pWeapon->GetSlot() == WEAPON_PRIMARY_SLOT)
	{
		Weapon_DropSlot(WEAPON_PRIMARY_SLOT);
	}
#endif

Now add this above or below the WEAPON_PRIMARY_SLOT statement:

        if ( pWeapon->GetSlot() == WEAPON_X_SLOT)
	{
		Weapon_DropSlot(WEAPON_X_SLOT);
	}

Replace X with whatever slot you want:

0 in-code/1 in-game = MELEE (crowbar)

1/2 = SECONDARY (pistol)

2/3 = PRIMARY (smg & pulse gun) [this is already included in the code so you don't have to include it again]

3/4 = EXPLOSIVE (grenades)

4/5 = TOOL (bugbait)

Now you can only pick up one of the weapons in that slot. Trying to pick up another weapon in that slot will drop your current one and pick up the new one.