QuakeZone
MOD Coding Tutorials
Quake II Coding Tutorials!

Introduction
Code
Notes
Exercises
Quake II Coding Tutorials

Earthquake Rockets

Introduction Introduction

This tutorial describes how to create earthquake rockets. Select earthquake rockets, fire into the floor or wall, wait a few seconds and....hey, presto, an earthquake you created.

Note that the earthquake code is taken (with thanks!) from a Quakestyle tutorial - go to the Tutorials Links page and follow the link to the Quakestyle Tutorials page.

This code requires that Nuclear Rockets tutorial (or at least the parts that allow different rocket types) to have already been done.

Code Code


g_local.h

Add the following cvar server variables at the indicated place:
extern	cvar_t	*sv_maplist;	// <-- insert lines after here

// PJT - quake rockets
extern cvar_t *sv_qkdelay;			// time between rocket impact and start of quake
extern cvar_t *sv_qkduration;			// minimum duration of quake
extern cvar_t *sv_qkradius;			// radius of quake
extern cvar_t *sv_qkrichter;			// amplitude of quake (10.0 = velocity 1000)
// PJT
At the end of the edict_s structure, add the following lines:
	int			quake_timer;	// PJT - quake rockets - timer for quake duration
	int			quake_wait;	// PJT - quake rockets - timer for playing sound

g_weapon.c

Add the following variables to the top of the file, after the #include statement:

// PJT - quake rockets
cvar_t *sv_qkdelay;		// see g_local.h for definitions
cvar_t *sv_qkduration;
cvar_t *sv_qkradius;
cvar_t *sv_qkrichter;
// PJT	
Add the following new procedure just before the procedure rocket_touch:
// PJT - quake rocket

void rocket_think_quake (edict_t *self)
{
int 	i;
edict_t *ent;
vec3_t	v;

	// remove rocket if timer expired
	if (level.time > self->quake_timer)
	{
		G_FreeEdict (ent);
		return;
	}

	// update sound
  	if (self->quake_wait < level.time)
	{
    		gi.positioned_sound(self->s.origin, self, CHAN_AUTO, gi.soundindex("world/quake.wav"), 1.0, ATTN_NONE, 0);
    		self->quake_wait = level.time + 0.5;
    	}

	// shake all clients
  	for(i=0;i < game.maxclients;i++)
	{
    	// retrieve entity
		ent=g_edicts+i+1;

		// ignore if not active, or in air
		if (!G_ClientInGame(ent)) continue;
    		if (!ent->groundentity) continue;

		// ignore if out of range
		sv_qkradius = gi.cvar ("sv_qkradius", "1000", 0);
		VectorSubtract (ent->s.origin, self->s.origin, v);
		if (VectorLength(v) > sv_qkradius->value) continue;

		// random velocity
		sv_qkrichter = gi.cvar ("sv_qkrichter", "10", 0);
		ent->groundentity = NULL;
    		ent->velocity[0] += crandom()*(sv_qkrichter->value*100);
    		ent->velocity[1] += crandom()*(sv_qkrichter->value*100);
    		ent->velocity[2] = (sv_qkrichter->value*100)*(100.0/ent->mass);
    	}

	// next think
	self->nextthink = level.time + 0.1;
	self->think     = rocket_think_quake;

}

// PJT
Add the following new procedure just after the procedure rocket_touch:
// PJT - earthquake rockets

/*
=================
rocket_touch_quake
=================
*/
void rocket_touch_quake (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
{

	// can damage owner!!
	if (other == ent->owner)
		return;

	// remove if hits sky
	if (surf && (surf->flags & SURF_SKY))
	{
		G_FreeEdict (ent);
		return;
	}

	// normal explosion if hits player
	if (other->client)
	{
		rocket_touch(ent, other, plane, surf);
		return;
	}

	// normal explosion if hots decoy
	if (Q_stricmp(other->classname, "decoy") == 0)
	{
		rocket_touch(ent, other, plane, surf);
		return;
	}

 	// Quake Rockets only if activated by real Player..
  	if (G_EntExists(ent->owner))
	{
		sv_qkdelay 	  = gi.cvar ("sv_qkdelay", "5", 0);
		sv_qkduration 	  = gi.cvar ("sv_qkduration", "10", 0);
		VectorClear (ent->velocity);
    		ent->quake_timer  = level.time + sv_qkdelay->value + 
				    sv_qkduration->value +(random()*sv_qkduration->value);
		ent->nextthink    = level.time + sv_qkdelay->value;
		ent->think        = rocket_think_quake;
		ent->s.sound	  = 0;
    	return;
	}

	G_FreeEdict (ent);

}

// PJT
Insert the earthquake rocket code into procedure fire_rocket, in the code added in the Nuclear Rocket tutorial, as indicated:
	rocket->owner = self;

	// 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
			
			// nke code here

			break;
		case 2:		// zylon gas

			// zylon gas code here
	
			break;
		case 3:		// positron rockets
			
			// positron rocket code here			

			break;
		// PJT <-- earthquake rocket code starts here
		case 4:		// PJT - earthquake rockets
			rocket->touch = rocket_touch_quake;
			rocket->s.renderfx = RF_SHELL_RED + RF_SHELL_GREEN; 	// make positron rockets yellow
  			rocket->s.effects |= EF_COLOR_SHELL;
			break;
		// PJT <-- end of earthquake rocket code
		}
	}
	else
		rocket->touch = rocket_touch;
	// PJT

p_weapon.c

Within procedure Rocket_Count (which was created in the Nuclear Rockets tutorial) insert the earthquake rockets code as indicated:
	switch (ent->client->pers.nuke_state)
	{
	
		......	

		case 3:
			...
			break;		

		// PJT <-- earthquake rockets code starts here
		case 4:		// earthquake rockets
			count = 10;
			break;
		// PJT <-- end of insert
	}

g_cmds.c

Within procedure Cmd_Nukes_f (which was created in the Nuclear Rockets tutorial) insert the earthquake rockets code as indicated:
	switch (i)
	{
	case 0:			// standard rockets

		.......

	case 3:			// positron rockets
		break;
	// PJT <-- eathquake rockets code starts here
	case 4:			// earthquake rockets
		break;
	// PJT <-- end of insert
	}

cmds.cfg

Add the following server commands to your .cfg file:
	set sv_qkdelay		5
	set sv_qkduration	10
	set sv_qkradius		1000
	set sv_qkrichter	5.0
Notes Notes to code


g_local.h
  • the 4 cvar_t variables correspond to the 4 server files in the .cfg file (see below) - they are external variables that point to the local variables in q_weapon.c
  • the 2 timers in the edict_s structure (which is part of the rocket's entity structure) are used to do timings for the duration of the earthquake, and to continuously play the earthquake sound

g_weapon.c
  • the 4 cvar variables again correspond to those in g_local.h
  • procedure fire_rocket is amended to let glowing-yellow earthquake rockets rip forth on request, an addition to the code originally inserted in the Nuclear Rockets tutorial
  • procedure rocket_touch_quake is called when an earthquake rocket hits something:
    • the rocket will just pas throught the player that fired the rocket
    • if the rocket hits a sky surface, it disappears
    • if the rocket hits another player or a decoy (if they are in your mod), the rocket impacts just like a normal rocket
    • otherwise its rokc and roll time - the delay and duration of the 'quake are obtained from server variables, the rocket stops moving, rocket_think_quake is made the new "think" routine to get the earthquake going, and the 'quake timer is started
  • the rocket_think_quake procedure is the main earthquake procedure:
    • when an earthquake rocket has hit something, it is the new "think" routine
    • it is called every Quake frame while the earthquake is active
    • if the earthquake timer has expired, the rocket destroys itself, thus ending the earthquake
    • if the sound timer has expired, the sound is played again, giving a continuous earthquake noise
    • server variables are checked for the strength and radius of the 'quake
    • in each Quake frame, all clients are quickly scanned
    • any clients inactive, in the air or out of range are bypassed
    • all active clients in range are given a random velocity vector to simulate a 'quake

p_weapon.c
  • procedure Rocket_Count, originally inserted in the Nuclear Rockets tutorial, is amended to include the number of rockets required to fire earthquake rockets

g_cmds.c
  • procedure Cmd_Nuke_f, originally inserted in the Nuclear Rockets tutorial, is amended to cater for earthquake rockets
  • although there is no special processing required here for this type of rocket, make sure the client->pers.nuke_state value for 'quake rockets is allowed for

cmds.cfg
  • sv_qkdelay is seconds from rokcet impact to start of 'quake (how fast can you run?)
  • sv_qkduration is minimum duration in seconds of 'quake
  • sv_qkradius is 'quake radius in Quake units
  • sv_qkrichter is strength of 'quake (10.0 is probably maximum sensible value)
Exercises Exercises

  • add your own rocket types
  • in single player mode only (for network lag reasons) simulate falling masonry during an earthquake
  • if you could also simulate the earth opening up, lava flows or volcanoes as well I would be seriously impressed


Page last updated 26th October 2000