Weapon script

From Valve Developer Community
Jump to: navigation, search

While it is entirely possible to define a weapon's properties entirely in C++, Valve tend to use weapon scripts instead. These allow changes to be applied by a server restart, with no need to shut the game down and recompile its code binaries.

This provides a few advantages to the end-user and developer, respectively:

  • By having code in the public realm, end-users can modify certain aspects to their liking. If you wish to support mods via this method in your own mod, giving the user more options will likely be welcomed.
  • It allows the developer to edit the code, and merely reboot the server or game to see the changes; this speeds up iteration time, as the binaries do not need to be recompiled to test minor changes.

Weapons scripts should be located at game\scripts\<classname>.txt, and everything inside should be a child of a single weapondata table key.

A weapon's scripted values are accessed from its GetWpnData() function in C++.

Standard keys

These are the keyvalues that will be read by CBaseCombatWeapon. All weapons support them. Script keys are on the left, C++ variables on the right.

Note:Boolean values are represented as 1/0.
Note:Unless a specific key has whitespace in it, "quote marks" are not required to be used.
Note:The majority of the keys and values are case-insensitive, and as such proper capitalization such as CamelCase or full-lowercase is entirely up to personal preferences.

Viewmodel and UI

printname / szPrintName
The friendly name shown to players in the UI; max 80 characters.
Can use a localization key, as well as a definite string; however, localization keys are case-insensitive, while defined strings are not.
viewmodel / szViewModel
Path to the viewmodel seen by the player holding the weapon. Relative to the game root, so be sure to include the models\ folder. Max 80 characters. Not providing a viewmodel and selecting the weapon will cause the game to crash.
bucket / iSlot
The HUD weapon selection in the X axis. 0 being the melee weapons by default.
bucket_position / iPosition
The HUD weapon selection in the Y axis. 0 Being the pistol in the (1) X axis by default.
weight / iWeight
Used to determine the weapon's importance when the game auto-selects one.
The weight used in the name is often erroneously misunderstood to mean weight as a mass, but is actually the weight as a priority (A literary example being, "he's pulling his weight around").
Higher priority weapons will be selected before others when a weapon runs out of ammo, and a replacement is auto-selected by the game based on this value.
autoswitchto / bAutoSwitchTo
Whether to switch to this gun on running out of ammo for another. Defaults true.
Combined with the previous weight command can set the order of precedent for auto-selection.
An example of this is the initial appearance of the Magnum in the map d1_canals_08 in Half-Life 2; when the player walks within pickup range of the .357, the weight value of the Magnum (being the highest in HL2 at 7) combined with this boolean ensures it is automatically selected for the scripted sequence that follows.
autoswitchfrom / bAutoSwitchFrom
Whether to switch away from this weapon when picking up another weapon or ammo. Defaults true.
showusagehint / bShowUsageHint
Show on-screen hints about how to use the weapon. Defaults false.
BuiltRightHanded / m_bBuiltRightHanded
Weapon viewmodel is right-handed. Defaults true. Used in Counter-Strike: Source to differentiate weapon models that are modeled as such from the rest.
AllowFlipping / m_bAllowFlipping
Allow the viewmodel to be mirrored if the user wants left handed weapons. Defaults true.

Worldmodel

playermodel / szWorldModel
Path to the weapon's regular model that is seen in the world. Relative to the game root, so be sure to include the \models folder. Max 80 characters.
anim_prefix / szAnimationPrefix
Prefix of the animations that should be played by characters wielding this weapon (e.g. prefix_idle, prefix_reload). Max 16 characters. Does not appear to have any effect when changed in Half-Life 2, however.

Console/Controller Mode-Specific Variables (New with Source 2007)

Support for some controller features were added with the release of The Orange Box for the Xbox 360, which aimed to take advantage of the force feedback (rumble) system of modern controllers; as well as slightly modified weapon bucket commands, due to the console version using a modified HUD and weapon selection system, via the directional pad (d-pad). To enable this mode, the following console command must be set: hud_fastswitch 2

A visual reference on the bucket layout for the controller-style inventory.
bucket_360
The HUD weapon selection on one of the four directional pad buttons. Only supports integers from 0 to 3 (See image).
bucket_position_360
The HUD weapon selection priority in the four buckets themselves. Weapons shown in the image start at 0, and increment by one each.
rumble / iRumbleEffect
Which rumble effect to use when fired when playing with a controller. Works on consoles, as well as when using Xbox controllers on PC.
The table below includes an overview of some of the default rumble settings. Of note is that only three rumble effects may be active at any given time (unless changed in the compiled code).

Rumble Settings

rumble -1 / RUMBLE_INVALID
The fallback if a rumble isn't valid.
rumble 0 / RUMBLE_STOP_ALL
Cease all current rumbling effects.
rumble 1 / RUMBLE_PISTOL
Used on the Pistol.
When used, firing too quickly will prevent the rumble from activating at all.
rumble 2 / RUMBLE_357
Used on the Magnum.
Similar to the previous, but firing speed has no ability to stop the rumble from activating.
rumble 3 / RUMBLE_SMG1
Used on the SMG.
An initial shake, followed by a rapid fall-off of feedback after a few rounds are fired. Using on a weapon like the Pistol will prevent the rumble from activating if fired too quickly.
rumble 4 / RUMBLE_AR2
Used on the AR2.
An initial shake, followed by a slight fall-off of feedback but maintains most of the "punch" of the first shot.
rumble 5 / RUMBLE_SHOTGUN_SINGLE
Used on the Shotgun for single-shot.
A fairly large feedback pulse, that consistently maintains the force with every subsequent follow-up shot, even in automatic.
rumble 6 / RUMBLE_SHOTGUN_DOUBLE
Used on the Shotgun for double-shot.
Feels identical to the normal shotgun rumble effect.
rumble 7 / RUMBLE_AR2_ALT_FIRE
Used on the AR2 for the energy ball alt-fire.
Over the course of the AR2 alt-fire animation, quickly builds a rumble, and then releases at the point of firing the ball.
rumble 8 / RUMBLE_RPG_MISSILE
Used when firing an RPG rocket.
rumble 9 / RUMBLE_CROWBAR_SWING
Used when swinging the Crowbar, regardless of if it hit anything.
rumble 10 / RUMBLE_AIRBOAT_GUN
Used when firing the Airboat gauss cannon.
rumble 11 / RUMBLE_JEEP_ENGINE_LOOP
Used for the Jeep engine idle.
rumble 12 / RUMBLE_FLAT_LEFT
Used for the Jeep.
rumble 13 / RUMBLE_FLAT_RIGHT
Defined, but unused in the Source SDK 2013 code.
rumble 14 / RUMBLE_FLAT_BOTH
Used for the rumble effects when using the Crane.
rumble 15 / RUMBLE_DMG_LOW
When taking light damage; defined/unused.
rumble 16 / RUMBLE_DMG_MED
When taking medium damage; defined/unused.
rumble 17 / RUMBLE_DMG_HIGH
When taking high damage; defined/unused.
rumble 18 / RUMBLE_FALL_LONG
When taking a lethal amount of fall damage.
rumble 19 / RUMBLE_FALL_SHORT
When taking a non-lethal amount of fall damage.
rumble 20 / RUMBLE_PHYSCANNON_OPEN
When the Gravity Gun claws open.
rumble 21 / RUMBLE_PHYSCANNON_PUNT
In speculation: when punting something with the Gravity Gun
In implementation: defined/unused.
rumble 22 / RUMBLE_PHYSCANNON_LOW
In speculation: when using a low amount of force on an object.
In implementation: when punting something with the Gravity Gun.
rumble 23 / RUMBLE_PHYSCANNON_MEDIUM
In speculation: when using a medium amount of force on an object; defined/unused.
rumble 24 / RUMBLE_PHYSCANNON_HIGH
In speculation: when using a high amount of force on an object; defined/unused.
rumble 25 / RUMBLE_PORTALGUN_LEFT
When firing the blue portal with the Portal Gun; defined/unused.
rumble 26 / RUMBLE_PORTALGUN_RIGHT
When firing the orange portal with the Portal Gun; defined/unused.
rumble 27 / RUMBLE_PORTAL_PLACEMENT_FAILURE
When the Portal Gun fails to place down a portal; defined/unused.

Ammunition

clip_size / iMaxClip1
clip2_size / iMaxClip2
Magazine size for primary and secondary magazines, respectively.
Putting -1 for either of these values will disregard the size of the magazine.
default_clip / iDefaultClip1
default_clip2 / iDefaultClip2
Amount of ammo in the weapon when it spawns. When set to 0, the gun will spawn with no additional ammo, and will be unloaded.
primary_ammo / szAmmo1
secondary_ammo / szAmmo2
The AmmoDef name of the hitscan ammunition this weapon fires for the primary and secondary/alt-fire modes, respectively. Both default to "None". Max 32 characters each.
MeleeWeapon / m_bMeleeWeapon
Weapon is a melee-style weapon, such as a crowbar, knife, fists, etc. Defaults false.

An example of the previous from the default weapon_smg1.txt in HL2:

clip_size 45
default_clip 45
primary_ammo smg1

clip2_size -1
default_clip2 -1
secondary_ammo smg1_grenade

SoundData

The sounddata subkey defines the sounds that should play when the weapon fires a bullet, fires dry, reloads, and so on. CBaseCombatWeapon will understand (but not necessarily use) the following:

  • empty
  • single_shot
  • single_shot_npc
  • double_shot
  • double_shot_npc
  • burst
  • reload
  • reload_npc
  • melee_miss
  • melee_hit
  • melee_hit_world
  • special1
  • special2
  • special3
  • taunt
  • deploy
Note:The sound script entries used for these are case-insensitive, and as such, using Weapon_SMG1.Single or weapon_smg1.single will return the same result. Keep this in mind when writing sound scripts that case is not solely used to differentiate sounds.

An example from the default HL2 weapon_smg1.txt file:

sounddata
{

	// When the player reloads
	reload weapon_smg1.reload
	
	// When an NPC reloads
	reload_npc weapon_smg1.npc_reload

	// Dry-fire
	empty weapon_smg1.empty

	// When the player fires
	single_shot weapon_smg1.single

	// When an NPC fires
	single_shot_npc weapon_smg1.npc_single

	// When a player fire both barrels / alt-fire
	double_shot weapon_smg1.double 

	// Single-shot fire mode selection; unused
	special1 weapon_smg1.special1

	// Burst fire mode selection; unused
	special2 weapon_smg1.special2

	// Burst fire sound; unused
	burst weapon_smg1.burst

}

TextureData

To define the HUD bucket icons, crosshairs, and ammo icons used by a weapon, you must edit the texturedata table.

There are primarily two main ways of editing HUD icons: custom fonts, and traditional bitmap images. For more information, see the related article.

Arguments

Within the texturedata table, as defined in weapon_resource.cpp by default there are several values. The values used in the scripts are first, followed by the values as represented in C++ after the slash:

crosshair / iconCrosshair
Used for the main crosshair that appears on the screen while using this weapon.
autoaim / iconAutoaim
Used when the crosshair is on a target class, to change the crosshair style and colours.
Falls back to crosshair if not defined.
zoom / iconZoomedCrosshair
Used while zoomed in with the scope on the Crossbow; falls back to crosshair if not defined.
zoom_autoaim / iconZoomedAutoaim
Used for the crosshair while zoomed in; falls back to zoom if not defined.
weapon / iconInactive
The weapon icon that appears when the HUD is drawn, but the weapon is not selected.
weapon_s / iconActive
An additional icon that is overlaid on top of the weapon icon, to provide a glow effect when the weapon is selected, hence the _s suffix. This is also reflected in the C++ class names for it and the former.
weapon_small / iconSmall
Used for a variant of the standard weapon font class that is half the size of the original.
ammo / iconAmmo
An icon used when picking up primary ammo that appears on the side of the screen.
ammo2 / iconAmmo2
An icon used when picking up secondary/alt-fire ammo that appears on the side of the screen. Examples of this are AR2 balls and SMG grenades.

Defining Glyphs

For each of these definitions, there are two ways to define a glyph for use by default.

The first involves the use of fonts, as defined in the resource/clientscheme.res file included with every stand-alone Source game. The article linked abouve dictates how to use this. The second method, is to use bitmap images, such as sprites to define the glyphs.

Font-Specific Method

font <string>
The name of a font class defined in the clientscheme.res file. In Half-Life 2, they are usually a variation of the name WeaponIcons for weapon glyphs.
The font class name entry in clientsceheme.res is case-insensitive, and as such, using WeaponIcons or weaponicons will return the same result. Keep this in mind when writing font classes that case is not solely used to differentiate them.
character <string>
The specific font character to use on the sheet itself. For example, in HL2, on the WeaponIcons font, a is the character used for the SMG.
The character specified is case-sensitive, as using A in place of the former changes the glyph to a Lambda symbol used in the Half-Life 2 branding. This allows font sheets to have not just 26 different glyphs across the alphabet, but doubles it for lowercase and uppercase.

Bitmap-Specific Method

file <path/to/image>
The path to the image, relative to materials/, so the initial root folder name is not needed.
x <integer>
The lateral (X-axis) position of the desired glyph on the sprite sheet.
y <integer>
The longitudinal (Y-axis) position of the desired glyph on the sprite sheet.
width <integer>
How wide to render the selected area of the sheet, in pixels.
height <integer>
How tall to render the selected area of the sheet, in pixels.

Example

An example from the default scripts/weapon_smg1.txt found in Half-Life 2:

texturedata
{

	weapon
	{
		font weaponicons
		character a
	}

	weapon_s
	{
		font weaponiconsselected
		character a
	}

	ammo
	{
		font weaponicons
		character r
	}

	ammo2
	{
		font weaponicons
		character t
	}


	crosshair
	{
		font crosshairs
		character Q
	}

	autoaim
	{
		file sprites/crosshairs
		x 0
		y 48
		width 24
		height 24
	}

}

Flags

The following base-2 keyvalue flags are used to imbue the weapon with any combination of the following effects. To combine multiple effects, add the integer assigned to the effects you wish to use together in the weapon script.

For example:

item_flags 38

Would give the weapon the ITEM_FLAG_DOHITLOCATIONDMG, ITEM_FLAG_NOAUTOSWITCHEMPTY, and ITEM_FLAG_NOAUTORELOAD flags (32 + 4 + 2, respectively).

1 / ITEM_FLAG_SELECTONEMPTY
If a player runs out of ammo in their current weapon, and the ITEM_FLAG_NOAUTOSWITCHEMPTY is not assigned to that weapon, select a weapon that has this flag. Note: the 'weight' value assigned to the weapons with this flag affect switch priority.
2 / ITEM_FLAG_NOAUTORELOAD
Weapon does not automatically reload.
4 / ITEM_FLAG_NOAUTOSWITCHEMPTY
Weapon does not automatically switch to another weapon when empty.
8 / ITEM_FLAG_LIMITINWORLD
Weapon is limited in world.
16 / ITEM_FLAG_EXHAUSTIBLE
A player can totally exhaust their ammo supply and lose this weapon. The Frag Grenade has this flag.
32 / ITEM_FLAG_DOHITLOCATIONDMG
This weapon takes hit location into account when applying damage.
64 / ITEM_FLAG_NOAMMOPICKUPS
Don't draw ammo pickup sprites/sounds when ammo is received.
128 / ITEM_FLAG_NOITEMPICKUP
Don't draw weapon pickup when this weapon is picked up by the player.

Parsing new keys

You will at some point probably want to parse additional keys from a weapon script. You may want to simply because important values like cycle time (how long between each bullet) and bullets per shot are not read from scripts by Valve's code.

Doing it is incredibly easy:

#include "cbase.h"
#include "weapon_parse.h"
#include "KeyValues.h"

class MyWeaponParse : public FileWeaponInfo_t
{
public:
	DECLARE_CLASS_GAMEROOT( MyWeaponParse, FileWeaponInfo_t );

	void Parse( ::KeyValues* pKeyValuesData, const char* szWeaponName )
	{
		BaseClass::Parse( pKeyValuesData, szWeaponName );

		m_flCycleTime	= pKeyValuesData->GetFloat( "CycleTime", 0.15 );
		m_iBullets	= pKeyValuesData->GetInt( "Bullets", 1 );
	}

	float	m_flCycleTime;
	int	m_iBullets;
};

// This function probably exists somewhere in your mod already.
FileWeaponInfo_t* CreateWeaponInfo()
{
	return new MyWeaponParse;
}

From outside the weapon

To load weapon script keys from outside the weapon class (e.g. for VGUI use):

Tip:See KeyValues for other ways to access data from a FileWeaponInfo_t object.

Client:

const FileWeaponInfo_t &weaponInfo = C_BasePlayer::GetLocalPlayer()->GetActiveWeapon()->GetWpnData();
wchar_t* wepname = g_pVGuiLocalize->Find(weaponInfo.szPrintName); // Loading a localised string

Server:

// TODO

Encryption

To prevent server operators from changing the behaviour of your weapons, you can ICE encrypt them. This isn't totally secure as your ICE key can be extracted from your mod's binaries by anyone with enough knowledge, but it will head off most tampering.

To implement encryption, choose a secret eight-character alphanumeric key and run your weapon scripts through VICE with it. Then create const unsigned char* GetEncryptionKey() in your GameRules class and have it return the key.

Once your mod starts loading ICE-encrypted files (.ctx) it will not load normal .txt files, even if a CTX is missing.