Making DOOM 3 Mods : Weapon Scripts
Weapon scripts can do everything that map scripts can, they just don't have as many objects to fondle.

The most confusing thing about a weapon script is probably the fact that it's an object of type idWeapon. That means you don't have to specify an object name when you send an event, because it sends the event to itself. Seasoned C++ programmers will recognize it as the hidden this pointer.

Normally you would say $something.hide(); but when the function is defined in an object, you can just say hide(); and it will automatically know what the object is. In the case of a weapon script, the object is the weapon itself. You will see this again when looking at AI scripts (the object will be the monster).

Let's analyze the weapon_pistol.script for a bit. Right after the #define section, we forward declare the weapon_pistol object, and say it's going to inherit from weapon_base. The inheritance allows us to put some common functions in weapon_base and have them available to all weapons. We specify what variables and functions are going to be in our weapon. After the object definition, we find declarations for all the functions we said we were going to have.

When a weapon is selected (with an impulse command or by picking it up), the init function is called on the weapon object. Generally this will read some default values from the weapon entityDef and set the weapon state to "Raise".

Weapon States

The weaponState function is the key to driving the weapon code. This function controls transitioning from various weapon states, which are defined by member functions in the weapon object. The first parameter is the name of the state to switch to (which should be a function name), the second parameter is the number of frames over which to blend the animation during the state change.

A good example of a state change is in weapon_pistol::Reload. The function starts the reload animation and waits for it to finish. It then adds some bullets to the clip and transitions to the Idle state. The animDone function takes a blend count as the second argument. In this case the blend count is 4, so it will return true when there are only 4 frames left in the animation to play. We pass this same value to the weaponState function so it knows that there are still 4 frames left to play in the current animation. The weaponState function stores this information so when the idle animation starts playing, the first 4 frames are blended with the last 4 frames of the previous animation (which was reload).

This animation blending allows smooth transitions between completely different animations without really ugly jerky movements.

Handy Weapon Functions
getOwnerReturns the player entity holding this weapon
nextWeaponCycles to the next weapon in the player inventory
weaponState [state], [blend](Described above)
useAmmo [amount]Subtracts ammo from the clip
addToClip [amount]Adds ammo to the clip
ammoInClipReturns how much ammo is in the clip
ammoAvailableReturns how many shots are left
totalAmmoCountReturns how much ammo is left
clipSizeReturns the size of a clip
weaponOutOfAmmoTells the game code that the weapon is out of ammo
weaponReadyTells the game code that the weapon is ready to fire
weaponReloadingTells the game code that the weapon is reloading
weaponHolsteredTells the game code that the weapon is lowered
weaponRisingTells the game code that the weapon is rising
weaponLoweringTells the game code that the weapon is lowering
flashlight [enable]Enable or disable a constant muzzle flash
launchProjectiles [numProjectiles],
[spread], [fuseOffset],
[launchPower], [dmgPower]
Launches the projectile defined by "def_projectile" in the weapon entityDef. It also subtracts the appropriate amount of ammo from the clip, sets up the muzzle flash and smoke, alerts nearby AI, kicks the view back, and resets shader parms 4 and 5 (diversity and timeOffset).

numProjectiles specifies how many projectiles are launched.
spread specifies the spread angle (in degrees).
fuseOffset specifies how far in the fuse should start (for grenades this is how long you held the fire button).
launchPower is a value that is multiplied by the projectile velocity (so 1.0 is normal velocity for the projectile). The grenades use this to make it so holding down the button longer makes them go faster.
dmgPower is like launchPower but for the damage.

createProjectile Creates and returns a new projectile entity defined by "def_projectile". It doesn't actually do anything with the projectile except return it. You'll probably want to use launchProjectiles almost every time. This function is currently only used by the hand grenade to have something to attach the sound to.
ejectBrassRandomly tosses some debris entities defined by the "def_ejectBrass" key in the weapon entityDef.
meleeChecks for entities within "melee_distance" range and does whatever is defined by "def_melee". This includes pushing, stealing, and damaging the other entity (as well as performing the sound). Returns true if something was hit.
getWorldModelReturns the entity for the actual animated weapon model.
Currently only used by the chaingun to spin the barrel on the model.
allowDrop [allow]Pass true to prevent the player from dropping the weapon.
Currently only used when the BFG overcharges.
isInvisibleReturns true if the player has the invisibility powerup
autoReloadReturns true if the player has "ui_autoReload" set.
netReloadThis function will cause the server send a reload event to the clients. The reload event signals WEAPON_NETRELOAD, which the weapon script catches to reload on the client side. This is needed so you can see when other clients are reloading their weapons. It should always be called before changing to the "Reload" weaponState.
netEndReloadSimilar to netReload, but called when the weapon is finished reloading.
Currently only used by the shotgun (because you can abort a reload).

Copyright © 2004 id software