QuakeZone
MOD Coding Tutorials
Quake II Coding Tutorials!

Introduction
Code
Notes
Exercises
Quake II Coding Tutorials

Blister Rockets

Introduction Introduction

This tutorial describes how to add blister rockets to your mod. First of all, the player toggles the bister state on with a button. He/she then fires a rocket, and when he/she presses another key, the 'blister' key, the rocket divides up into 4 that fly off in the 4 compass points.

This tutorial also describes how to generically add different rocket firing modes, and to cater for the different number of rockets that might be required. For this purpose, the code from the tutorial on Rocket Types must already have been implemented.

Code Code


g_local.h

Add the following line to the end of the client_persistant_t struct:
	qboolean    blister_state;		// PJT - blister rocket state
Add the following line to the end of the gclient_s struct:
	qboolean    blister;			// PJT blister command made: 1=YES, 0=NO
Add the following line to the end of the edict_s struct:
	qboolean	can_blister;	// PJT - blister rockets

g_weapon.c

Add the following variables to start of procedure rocket_think:
	vec3_t 		forward, backward, right, left, up;  // PJT - vectors for blister
	qboolean	tmp;				     // PJT - blister - store client state	
Then add the following code to the end of procedure rocket_think:
// PJT - blister rocket
	if (!self->owner) return;
	if (!self->owner->client) return;

	if ((self->owner->client->blister) && (self->can_blister))
	{
		// define vectors for 4 compass points
		VectorSet(forward,0,1,0);
		VectorSet(right,1,0,0);
		VectorSet(backward,0,-1,0);
		VectorSet(left,-1,0,0);
		self->can_blister = false;
		// create 4 new missiles in other 4 compass points
		// future change - add small random variation for more realism
		tmp = self->owner->client->pers.blister_state;
		self->owner->client->pers.blister_state = false;		// stop child rockets from blistering
		fire_rocket(self->owner, self->s.origin, forward,  100, 30, 120, 120);
		fire_rocket(self->owner, self->s.origin, right,    100, 30, 120, 120);
		fire_rocket(self->owner, self->s.origin, left,     100, 30, 120, 120);
		fire_rocket(self->owner, self->s.origin, backward, 100, 30, 120, 120);
		self->owner->client->pers.blister_state = tmp;
		// dont forget to turn blister command off!
		self->owner->client->blister = false;
		// destroy original rocket
		G_FreeEdict (self);
	}
// PJT
Then, in procedure fire_rocket, add the following code at the indicated location:
	rocket->s.modelindex = gi.modelindex ("models/objects/rocket/tris.md2");

	// PJT blister rockets - for clients only
	rocket->can_blister = 0;
	if (self->client)
		rocket->can_blister = self->client->pers.blister_state;	// PJT - only 'parent' rockets can blister
	// PJT

p_weapon.c

In procedure Rocket_Count (which was created in the Nuclear Rockets/Rocket Types tutorial), add the following code at the indicated location:
	// rockets for particular type
	count = 1;
	switch (ent->client->pers.nuke_state)
	{
		case 0:		// standard
			count = 1;
			break;
		case 1:		// nukes
			count = 20;
			break;
		// any other rocket types added here
	}

	// rockets for each fire mode
	if (ent->client->pers.blister_state) count *= 4;	// PJT - blister rockets
	// add rocket multipliers for other rocket fire modes here, to determine
	// whether player has enough rockets
Add the following code at the start of procedure Weapon_RocketLauncher_Fire as indicated:
	ent->client->blister = 0;		// PJT blister rockets
	damage = 100 + (int)(random() * 20.0);

g_cmds.c

In procedure ClientCommand add the following lines near the end of the procedure at the indicated location:
// PJT - blister rockets: 1. set blister status
	else if (Q_stricmp (cmd, "blister_on") == 0)
		Cmd_Blister_on_f (ent);
//                        2. issue blister command
	else if (Q_stricmp (cmd, "blister") == 0)
		Cmd_Blister_f (ent);
// PJT

 	else if (Q_stricmp (cmd, "gameversion") == 0)
 		gi.cprintf (ent, PRINT_HIGH, "%s : %s\n", GAMEVERSION, __DATE__);
Then, at the end of the file, add the following code:
//PJT blister missiles

/*
=================
Cmd_Blister_on_f
PJT: whole new function for adjusting blister missile state
=================
*/
void Cmd_Blister_on_f (edict_t *ent)
{
	int		i;

	i = ent->client->pers.blister_state;

	switch (i)
	{
	case 1:
		ent->client->pers.blister_state = 0;
		break;
	case 0:
	default:
		ent->client->pers.blister_state = 1;
		break;
	}
}
// PJT

/*
=================
Cmd_Blister_on_f
PJT: whole new function for adjusting blister missile state
=================
*/
void Cmd_Blister_f (edict_t *ent)
{
	int		i;

	i = ent->client->pers.blister_state;

	switch (i)
	{
	case 0:
		gi.cprintf (ent, PRINT_HIGH, "Blister missiles are not enabled\n");
		break;
	case 1:
	default:
		ent->client->blister = 1;
		break;
	}
}
// PJT

Finally bind keys to "blister_on" and "blister" while playing, or add the binds to your .cfg file. To activate blister status, press the key bound to "blister_on". To blister a rocket in flight, press the key bound to "blister".

Notes Notes to code


g_local.h
  • the "blister_state" flag in the client structure indicates if the player can fire blister rockets
  • the "blister" flag in the client structure indicates when a player wants to blister a rocket in flight
  • the "can_blister" flag in the edict structure indicates whether a particular rocket can be blistered

g_weapon.c
  • the rocket_think procedure is called every Quake frame for a rocket in flight:
    • see if the rocket's "can_blister" flag is set on (i.e. it is a rocket that has not yet blistered) and the player has issued the blister command (check rocket owner's blister flag in client struct)
    • define 4 vectors to represent 4 compass points
    • fire a rocket in each of these directions from the current rocket's origin
    • this is a bit of the fudge - when these 4 rockets are 'fired', temporarily turn off the player's blister status so that these new rockets cannot blister
    • turn off the blister command so only 1 rocket can blister at any one time
    • destroy the original rocket
  • the fire_rocket procedure is called, well you can guess when.....
    • if the player has already issued a blister command before firing a rocket, this is turned off
    • ability of rocket to blister is determined from blister status of player - this is used by the fudge above

p_weapon.c
  • the procedure Rocket_Count was created in the Nuclear Rockets tutorial to see if the player has enough rockets to fire:
    • the rocket count for the current rocket type is multiplied by 4 for blister rockets
    • other multipliers can be applied for different fire modes, to accumulate the number of rockets required (e.g. to fire Nuclear Blister rockets requires 20 x 4 = 80 rockets)
  • procedure Weapon_RocketLauncher_Fire is called just before calling fire_rocket:
    • if the player has already issued a blister command before firing a rocket, this is turned off
    • if you are coding new fire modes which involve multiple rockets (e.g. spiral rockets), the code to fire the extra rockets must be called from this procedure

g_cmds.c
  • procedure ClientCommand processes a command entered by the client (duh) - the relevant procedures are called when the player toggles his blister status or issues a blister command
  • procedure Cmd_Blister_on_f toggles the player's blister status
  • procedure Cmd_Blister_f sets the flag in the client structure when the player wants to blister a rocket, unless the player's blister status is set to off

Different Fire Modes
  • if you have different fire modes that can be combined, you will have to consider repeating code:
    • for example, you want to mix blister rockets and homing missiles
    • put the blister code in a separate procedure
    • call this procedure from both rocket_think (for normal rockets) and homing_think (for homing missiles)
  • there is a separate tutorial to display current fire modes (blister, homing, etc) and current rocket type (standard, nuke, etc) on the palyer's HUD status bar
Exercises Exercises

  • instead of setting a flag in the client structure to blister a rocket, when the blister command is issued, search all the rockets currently in flight, and blister the first one that is found that belongs to the player and has the can_blister flag set


Page last updated 25th October 2000