Adding New Ammotypes

From Valve Developer Community
Jump to navigation Jump to search
English (en)Deutsch (de)Translate (Translate)
Todo: Rewrite this page in correct english, some sections are too confusing.

Introduction

This tutorial will teach you on how to create your own ammunition types for your weapons.

What you need:

  • A basic knowledge of C++
  • Knowing how to build the DLLs

Important Note

If you plan on adding multiple new ammo types, you can reach a limit which will cause your ammo to fail to be picked up. This can be solved by changing the following values in 🖿shareddefs.h.h to be higher than in stock Half-Life 2 HL2:

Unedited:

#define	MAX_AMMO_TYPES	32		// ???
#define MAX_AMMO_SLOTS  32		// not really slots

Edited:

#define	MAX_AMMO_TYPES	128		// ???
#define MAX_AMMO_SLOTS  128		// not really slots

Defining the Ammunition

First you will need to define the Ammunition in the Game Rules

To do this, first navigate to 🖿hl2mp_gamerules.cpp.cpp/🖿hl2_gamerules.cpp.cpp in the server project then navigate to the function CAmmoDef *GetAmmoDef().

In this function, the necessary ammo types are defined in the table like structure, beginning with def.AddAmmoTypes.

At the bottom of these defines, add a new row and add your own, following the same structure (Copy, paste and edit will work). As an example, the following line will be used:

def.AddAmmoType("SMG2",	DMG_BULLET, TRACER_LINE_AND_WHIZ, "sk_plr_dmg_smg2", "sk_npc_dmg_smg2", "sk_max_smg2", BULLET_IMPULSE(200, 1225), 0 );

With this line, a new ammo type 'SMG2' is defined.

Explanation of def.AddAmmoType:

def.AddAmmoType(
const char *name //The name of the new ammo type (For use in weapon script). e.g "SMG2"
int damageType //The damage type(s) this ammo will have. e.g "DMG_BULLET . For more than one damage type, use a | seperator ( DMG_BULLET | DMG_SNIPER )
int tracerType //The trace type to use. Possible of TRACER_NONE, TRACER_LINE and TRACER_LINE_AND_WIZZ
int plr_dmg //An skill (sk_) convar to allow for dynamic modification of the damage this ammo will do if fired from the player. Define all necessary sk_ variables in the ConVar listing around line 100, or type a number here. e.g. sk_plr_dmg_smg2
int npc_dmg //The same as above except the damage dealt when an NPC uses this ammo
int carry //The max ammount of ammo allowed. Can be a number or a sk_ convar. e.g. sk_max_smg2
float physicsForceImpulse //The force of the ammunition. Can be a number, calculation or you can use the function BULLET_IMPULSE(grain, ftpersec) to convert real world units to ingame units easily.
int nFlags //Specific flags. Possible being AMMO_FORCE_DROP_IF_CARRIED (If the player is hit, he drops whatever physics prop he was holding) and AMMO_INTERPRET_PLRDAMAGE_AS_DAMAGE_TO_PLAYER (Makes the plr_dmg varable damage to player instead of from). Both of these can be used using a | seperator
)

They are all you should need.

Adding an ammobox entity

Now a Item (Entity) must be provided, be waived thus one the ammunition (new type of ammunition) can.


In the file 🖿item_ammo.cpp.cpp, the classes and the implementations are defined.

The item entity is also defined and implemented there.


For our example, this is the code of the SMG1 copied and renamed :

// ========================================================================
//	>> BoxMRounds
// ========================================================================
class CItem_BoxMRounds : public CItem
{
public:
	DECLARE_CLASS( CItem_BoxMRounds, CItem );

	void Spawn( void )
	{ 
		Precache( );
		SetModel( "models/items/boxmrounds.mdl");
		BaseClass::Spawn( );
	}
	void Precache( void )
	{
		PrecacheModel ("models/items/boxmrounds.mdl");
	}
	bool MyTouch( CBasePlayer *pPlayer )
	{
		if (ITEM_GiveAmmo( pPlayer, SIZE_AMMO_SMG1, "SMG1"))
		{
			if ( g_pGameRules->ItemShouldRespawn( this ) == GR_ITEM_RESPAWN_NO )
			{
				UTIL_Remove(this);	
			}
			return true;
		}
		return false;
	}
};
LINK_ENTITY_TO_CLASS(item_box_mrounds, CItem_BoxMRounds);
LINK_ENTITY_TO_CLASS(item_ammo_smg1, CItem_BoxMRounds);

// ========================================================================
//	>> LargeBoxMRounds
// ========================================================================
class CItem_LargeBoxMRounds : public CItem
{
public:
	DECLARE_CLASS( CItem_LargeBoxMRounds, CItem );

	void Spawn( void )
	{ 
		Precache( );
		SetModel( "models/items/boxmrounds.mdl");
		BaseClass::Spawn( );
	}
	void Precache( void )
	{
		PrecacheModel ("models/items/boxmrounds.mdl");
	}
	bool MyTouch( CBasePlayer *pPlayer )
	{
		if (ITEM_GiveAmmo( pPlayer, SIZE_AMMO_SMG1_LARGE, "SMG1"))
		{
			if ( g_pGameRules->ItemShouldRespawn( this ) == GR_ITEM_RESPAWN_NO )
			{
				UTIL_Remove(this);	
			}
			return true;
		}
		return false;
	}
};
LINK_ENTITY_TO_CLASS(item_large_box_mrounds, CItem_LargeBoxMRounds);
LINK_ENTITY_TO_CLASS(item_ammo_smg1_large, CItem_LargeBoxMRounds);

Our classes are called instead of :

  • CItem_SmallBoxSMG1
  • CItem_BigBoxSMG1

These are called instead :

  • CItem_SmallBoxSMG2
  • CItem_BigBoxSMG2

When everything is installed you have to change 2 more things. These changes affect both classes in the CSMG2 bool MyTouch( CBasePlayer *pPlayer ) method.

There, we must change the query if (ITEM_GiveAmmo( pPlayer, SIZE_AMMO_SMG1_LARGE, "SMG1")). There are two things to change.

And although we must define SIZE_AMMO_SMG1_ either new, for the SMG2, or can directly define the size of recordable ammunition.

If one wishes to define itself, it only needs to insert the relevant number of balls that should be add to the touch. If you want to define it but then you have to open the 🖿items.h.h. There, you just have to install two new defines.

The second is just the name be changed from SMG1 to SMG2 (your ammo types) must be.


Now, the Spawn and the Precache methods must be changed.

There must be the name of the model( with its path) specified. If you want to change the models nich then let these methods.

Thus we have the classes and methods. Now the code for the entity itself follows


For this you have to use the LINK_ENTITY_TO_CLASS macro to link the class with its engine name.


Now the entity must be added into the FGD of the mod.

For this you have to open the FGD and write in the following:

@PointClass base(Item) studio("models/items/boxmrounds.mdl")= item_ammo_smg2 : "Box of SMG2 ammo" []

The Item base class already includes all of the necessary keyvalues, only its model (Filemodels/items/boxmrounds.mdl) must be changed so that it can correctly be previewed in Hammer Hammer.

The item is then called item_ammo_smg2 and contains the description "Box of SMG2 ammo".

Implementing ammunition into a weapon

Problem:

  • Valve has txt files of the weapons coded

We must therefore create a gun.


If you already have coded your own weapon, then you must open the weapon Fileweapon_name.txt.

If not, open Fileweapon_smg1.txt


There must be only the line :

"primary_ammo"			"SMG1"

Replace it with :

"primary_ammo"			"SMG2"