QuakeZone
MOD Coding Tutorials
Quake II Coding Tutorials!

Introduction
Code
Notes
Exercises
Quake II Coding Tutorials

Positron Rockets

Introduction Introduction

Seen the positron blaster in LOX? This tutorial applies the same sort of effect to rockets for deadly killing power. Note that this tutorial requires the Nuclear Rockets tutorial (or at least the relevant bits of) for implementing different rocket types.

Thanks to the guys from jblabs for the positron model from Lox.

Code Code


g_local.h

Add the following define at the indicated place:
#define MOD_TARGET_BLASTER      33 // <-- insert after this line
#define MOD_POSITRON            34 // PJT - positron rockets


g_weapon.c

Add the following new procedure just before procedure rocket_think:
// PJT - positron rockets - explosion

void positron_explode (edict_t *self)
{
	edict_t	*ent;
	float	points;
	vec3_t	v;
	float	dist;

	// comment out damage - done in touch function
	// if (self->s.frame == 0) - do for all frames
	{
		// the positron effect
		ent = NULL;
		while ((ent = findradius(ent, self->s.origin, self->dmg_radius)) != NULL)
		{
			if (!ent->takedamage)
				continue;
			// let owner take damage
			//if (ent == self->owner)
			//	continue;
			if (!CanDamage (ent, self))
				continue;
			if (!CanDamage (ent, self->owner))
				continue;

			VectorAdd (ent->mins, ent->maxs, v);
			VectorMA (ent->s.origin, 0.5, v, v);
			VectorSubtract (self->s.origin, v, v);
			dist = VectorLength(v);
			points = self->radius_dmg * (1.0 - sqrt(dist/self->dmg_radius));
			if (ent == self->owner)
				points = points * 0.5;

			gi.WriteByte (svc_temp_entity);
			gi.WriteByte (TE_ROCKET_EXPLOSION);
			gi.WritePosition (ent->s.origin);
			gi.multicast (ent->s.origin, MULTICAST_PHS);
			T_Damage (ent, self, self->owner, self->velocity, ent->s.origin, vec3_origin, (int)points, 0, 0, MOD_POSITRON); // last 0 was DAMAGE_ENERGY
		}
	}
	//*/

	self->nextthink = level.time + FRAMETIME;
	self->s.frame++;
	self->dmg_radius = self->dmg_radius * 1.25;
	if (self->s.frame == 16)
		self->think = G_FreeEdict;
}
// PJT
Then add the following new procedure just after procedure rocket_think:
// PJT - positron rocket impact

void rocket_touch_positron (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
	// if (other == self->owner)   : allow impact on rocket firer!
	//	return;

	if (surf && (surf->flags & SURF_SKY))
	{
		G_FreeEdict (self);
		return;
	}

	if (self->owner->client)
		PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT);

	// core explosion - prevents firing it into the wall/floor
	if (other->takedamage)
		T_Damage (other, self, self->owner, self->velocity, self->s.origin, plane->normal, 200, 0, 0, MOD_BFG_BLAST);
	T_RadiusDamage(self, self->owner, 200, other, 100, MOD_POSITRON);

	gi.sound (self, CHAN_VOICE, gi.soundindex ("weapons/bfg__x1b.wav"), 1, ATTN_NORM, 0);
	self->solid = SOLID_BBOX;  // SOLID_NOT;
	self->touch = NULL;
	VectorMA (self->s.origin, -1 * FRAMETIME, self->velocity, self->s.origin);
	VectorClear (self->velocity);
	self->s.modelindex = gi.modelindex ("models/positron/tris.md2");
	self->s.frame = 0;
	self->s.sound = 0;
	self->s.effects &= ~EF_ANIM_ALLFAST;
	self->think = positron_explode;
	self->nextthink = level.time + FRAMETIME;
	self->enemy = other;
	self->radius_dmg = 100;
	self->dmg_radius = 10;
	// self->touch = positron_touch;

	gi.WriteByte (svc_temp_entity);
	gi.WriteByte (TE_ROCKET_EXPLOSION);
	gi.WritePosition (self->s.origin);
	gi.multicast (self->s.origin, MULTICAST_PVS);
}
// PJT
Then, in procedure fire_rocket, within the following code (amendment to that code added in the Nuclear Rokcet tutorial) add the code for positron rockets as indicated:
	rocket->owner = self;	\\ <- Nuclear Rocket rocket types code inserted here

	// PJT - determine rocket type
	if (self->client)
	{
		rocket->touch = rocket_touch;
    	switch(self->client->pers.nuke_state)
		{
		case 0:		// standard
			rocket->touch = rocket_touch;
			break;
		case 1:		// nukes
			rocket->touch = rocket_touch_nuke;
			rocket->s.renderfx = RF_SHELL_GREEN + RF_SHELL_BLUE + RF_SHELL_RED; 	// make nuke rockets white.
  			rocket->s.effects |= EF_COLOR_SHELL;
			break;
		case 2:		// zylon gas (e.g.)

			// insert Zylon gas code (e.g.) here
			
		// ** <-- positron code starts here
		case 3:		// positron rockets
			rocket->touch = rocket_touch_positron;
			rocket->s.renderfx = RF_SHELL_RED; 	// make positron rockets red.
  			rocket->s.effects |= EF_COLOR_SHELL;
			break;
		// ** <-- positron code ends here

		case 4:		// PJT - earthquake rockets (e.g.)
			
			// insert earthquake code (e.g.) here

		}
	}
	else
		rocket->touch = rocket_touch;
	// PJT

p_weapon.c

Insert the folloing code into procedure Rocket_Count as indicated (this procedure was created in the Nuclear Rockets tutorial):

		case 1:		// nukes
			count = 20;
			break;
		// insert code from here
		case 2:		// zylon gas
			count = 1;
			break;
		case 3:		// positron rockets
			count = 10;
			break;
		case 4:		// earthquake rockets
			count = 10;
			break;
		// end of insert

g_cmds.c

Replace procedure Cmd_Nukes_f, that was created with the Nuclear Rockets tutorial, with the following:

/*
=================
Cmd_Nukes_f
PJT: whole new function for switching rocket type
rewritten for zylon gas rockets
add new rocket types in here
=================
*/
void Cmd_Nukes_f (edict_t *ent)
{
	int		i;

	// update pointer
	i = ent->client->pers.nuke_state;
	i++;
	if (i>4) i = 0;		\\ <-- alter for actual number of rocket types you use
	ent->client->pers.nuke_state = i;

	// any special handling for rocket types
	// user display of selected rocket type now done in p_hud.c
	switch (i)
	{
	case 0:			// standard rockets
	default:
		break;
	case 1:			// nukes
		gi.sound(ent, CHAN_AUTO, gi.soundindex("misc/power1.wav"), 1, ATTN_NORM, 0);
		break;
	case 2: 		// zylon gas (e.g.)
		// insert any special code here
		break;
		
	case 3:			// positron rockets - no special processing
		break;
	case 4:			// earthquake rockets (e.g.)
		// insert any special code here
		break;
	}
}
// PJT	

model

Extract the model for the positron explosion from the LOX Pak files, available from jblabs. Use a Pak file extracter such as QPED to extract the model files skin0.pcx and tris.md2 into a folder called models/positron within your game folder.



p_client.c

Add the following code to ClientObituary at the indicated positions:

First:

	case MOD_TARGET_BLASTER:
		message = "got blasted";
		break;
	// PJT - positron rocket
      	case MOD_POSITRON:
          	message="had his atoms re-arranged";
          	break;
	// PJT
then:
			case MOD_HELD_GRENADE:
				message = "tried to put the pin back in";
				break;
			// PJT - positron rockets
			case MOD_POSITRON:
				message = "could not avoid his own positron rocket";
				break;
			// PJT
and finally:
			case MOD_BLASTER:
				message = "was blasted by";
				break;
			// PJT positron rockets
			case MOD_POSITRON:
				message = "did not see";
				message2 = "'s positron rocket";
				break;
			// PJT
Notes Notes to code


g_weapon.c
  • this define is a flag used to determine which player death message to show

g_weapon.c
  • procedure fire_rocket does exactly what it says........
    • if the client flag pers.nuke_state is set to "positron rockets" value, make rocket_touch_positron the "touch" (or impact) procedure, and give the rocket a red glow
  • procedure rocket_touch_positron is called when a positron rocket hits something:
    • destroys the rocket if it has hit sky
    • plays a sound if has hit player who fired it
    • causes damage against the target, and damage within a radius of 200 units
    • the rocket model is converted into an exploding fireball, and its velocity stopped
    • procedure positron_explode now becomes the "think" routine to create the fireball
  • procedure positron_explode processes the exploding fireball from a positron rocket:
    • finds all entities within the damage radius, and if they can take damage calculates the dmage and gives it, and creates an explosion effect
    • goes to the next frame of the positron explosion
    • increases the damage radius in line with the expanding fireball
    • destroys the fireball when the last animation frame is reached

p_weapon.c
  • procedure Rocket_Count was added in the Nuclear Rockets tutorial to make sure the player has enough rockets to fire the currently selected type:
    • the number of rockets for positron rocket firing is now inserted

g_cmds.c
  • procedure Cmd_Nukes_f was added in the Nuclear Rockets tutorial to switch between different rocket types:
    • although no specific code is requied for positron rockets, need to make certain maximum value of nuke_state is large enough for positron value

p_client.c
  • procedure ClientObituary determines an appropriate death message to display - it has now been amended for positron rockets
Exercises Exercises

  • create your own rocket type


Page last updated 26th October 2000