Software nerdchow.com

A simpler smoke grenade tutorial
SmokeGrenade.cpp

smoke grenade

a ceejbot project

A smoke grenade

You can download complete source for the smoke grenade here: SmokeGrenade.cpp. You might want to have the source open in a window next to this page to refer to as you read.

Difficulty rating: easy. This relies heavily on existing Halflife grenade code and has almost nothing original.

This smoke grenade works like the other Halflife grenades and satchel charges. It has two pieces: the weapon object that players can pick up and hold, and the thrown grenade object. The first inherits from CBasePlayerWeapon and appears in player inventory. The second inherits from CBaseMonster and is an in-game entity independent of the player. It tumbles until its timer runs out, then detonates.

class CSmokeGrenade

Here's the first class:

class CSmokeGrenade : public CBasePlayerWeapon
	{
	public:
	void Spawn( void );
	void Precache( void );
	int iItemSlot( void ) { return 5; }
	int GetItemInfo(ItemInfo *p);

	void PrimaryAttack( void );
	BOOL Deploy( void );
	BOOL CanHolster( void );
	void Holster( void );
	void WeaponIdle( void );

	float m_flStartThrow;
	float m_flReleaseThrow;
	};
LINK_ENTITY_TO_CLASS( weapon_smokegrenade, CSmokeGrenade );

This class declaration looks just like all the other weapons you've ever written, with the addition of two variables. We need to keep track of when we started throwing the grenade, because that's when it's primed. And then we keep track of the fact that we've released the throw, so we can follow through on the throw animation and take out another grenade. The LINK_ENTITY line allows you to add smoke grenades to your maps using the name "weapon_smokegrenade".

Spawn()
Called when a grenade pickup appears in the world. Sets the model and number to be given to the player who picks it up.

Precache()
Tells the server to precache the models and sounds used by the weapon.

iItemSlot()
Which HUD slot this weapon appears in.

GetItemInfo()
Fills out a struct with weapon info to send to the client. The client uses the information to display your weapon in the HUD weapon selector.

PrimaryAttack()
Pulls the pin and goes into the windup to throw. Fastball or curve?

Deploy()
Takes out the grenade and announces its models to the world.

CanHolster()
You can't holster a primed grenade.

Holster()
Puts the grenades away and takes out another weapon. If the player has no more grenades, removes the weapon from the list of available weapons. This part might look odd, but it's because grenades don't work like guns. Guns stick around but are just unselectable without ammo. Grenades vanish from the player's weapon list entirely when the player runs out of "ammo".

WeaponIdle()
The exciting stuff begins here, where the player actually throws the grenade. Scan down to about line 180, a few lines into WeaponIdle(). Here, we set up the vectors for the throw by looking at where the player is facing and how fast the player is moving. We set the detonation time two seconds into the future. Then we actually throw on line 202:

CSmoker::ShootTimed( m_pPlayer->pev, vecSrc, vecThrow, time);

This spawns a CSmoker object and sends it on its way, leaving the player free to take out another weapon or throw another grenade.

class CSmoker

Here is the declaration of the class that actually spews the smoke. It inherits from class CGrenade, which in turn inherits from class CBaseMonster. You can find the original grenade monster declared in weapons.h and implemented in ggrenade.cpp. Like other Halflife monsters, it has think routines that are called repeatedly as time passes. This is how we implement the timed explosion.

class CSmoker : public CGrenade
{
public:
	void Spawn( void );

	static CSmoker *ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time );

	void BounceTouch( CBaseEntity *pOther );
	void TumbleThink( void );
	void SmokeThink(void);
	void SputterOut(void);
	
	virtual void BounceSound( void );
	virtual int	BloodColor( void ) { return DONT_BLEED; }
	virtual void Killed( entvars_t *pevAttacker, int iGib );
	
	BOOL m_Detonated;
	BOOL m_fRegisteredSound;
	float m_SmokeTime;
};
LINK_ENTITY_TO_CLASS( smoking_grenade, CSmoker);

ShootTimed() creates a smoker and throws it out into the world. The smoker calls TumbleThink() while it's waiting to blow. Then when its timer expires, it switches to SmokeThink() and starts spewing. (It's fun to hold this grenade for a second before throwing-- it'll detonate in the air and smoke as it flies.) As a final touch, it emits a small smoke cloud and leaves a dark stain behind in SputterOut().

The animation action is all in SmokeThink(). Take a look. First it checks to see if we've finished smoking. If so, we stop making noise and sputter out. Otherwise, we make a hissing sound and animate a big smoke sprite. Try changing the size of the smoke cloud or changing the sprite used. There are several sprites in the basic HalfLife pak file that work pretty well.

Tweaking

At the top of the file are some #defines for parameters you might want to tweak. Current C++ practice is to make these consts and put them in your class definition, but I've left them as #defines.

WEAPON_SMOKEGRENADE 19 Just make sure this doesn't collide with your mod's other weapons.
SMOKETIME 16 Time it spends smoking.
SMOKEG_FIRE_DELAY 2.0 Time from priming to detonation.
SMOKEG_SLOT 4 Slot 4 is where standard HL puts its grenades.
SMOKEG_POSITION 4 Make sure this doesn't collide with other weapons in the slot.
SMOKEG_WEIGHT 25 If your mod uses weights, set this.
SMOKEG_MODEL_1STPERSON "models/v_grenade.mdl"
SMOKEG_MODEL_3RDPERSON "models/p_grenade.mdl"
SMOKEG_MODEL_WORLD "models/w_grenade.mdl"
Your mod's modelers will make replacements for these, which are the standard Halflife grenade models.
SMOKEG_SOUND_VOLUME 0.25
SMOKEG_BODYHIT_VOLUME 128
SMOKEG_WALLHIT_VOLUME 512
Adjust the volume parameters to suit your custom sound effects.
SMOKEG_DEFAULT_GIVE 5 How many are in a grenade pickup.
SMOKEG_CLIPSIZE 1 Leave at 1.
SMOKEG_MAX_AMMO 10 The maximum number a player can carry.

Add it to the HUD

In your mod's sprites directory, create a file named weapon_smokegrenade.txt. Paste into it the generic HalfLife grenade info:

6
weapon                  320 320hud1     160     0       80      20
weapon_s                320 320hud1     160     20      80      20
ammo                    320 320hud2     36      34      18      18
weapon                  640 640hud3     0       0       170     45
weapon_s                640 640hud6     0       0       170     45
ammo                    640 640hud7     48      96      24      24

Finishing up

This smoke grenade uses the existing HL grenade model and a smoke sprite already in the game. You'll want to create your own models and sprite. And you might want to write a volume effect for the smoke instead of using a 2D sprite. Other variations include doing a small amount of damage every second to somebody standing in the smoke cloud. Or making them cough and screw up their aim for a few seconds after smoke exposure.



Top | Blog | Journal | Software
Part of the world wide web since 1994. Made with Macintosh.
Copyright 1994-2008 C J Silverio.