Adding New Ammotypes
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 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 (models/items/boxmrounds.mdl
) must be changed so that it can correctly be previewed in 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 weapon_name.txt
.
If not, open weapon_smg1.txt
There must be only the line :
"primary_ammo" "SMG1"
Replace it with :
"primary_ammo" "SMG2"