Quake DeveLS - Kamikaze Mode

Author: WonderSlug
Difficulty: Medium

Banzai??...As in little trees??

Well in commemoration of the Nagano Olympics Ive come up with a little Kamikaze Mode mod. (Well not really im just writing this up while watching the opening of the games.. and they kinda go good together)

Where the idea really came from was, a friend I work with said it would be cool to have something like in "Predator" where the alien activates the self destruct weapon and blows the forest to bits. (Thank Hockenhiem for the idea.) In talking about it we thought I would be a great team tactic in CTF. Imagine a heavily defended base and just you and a bud attacking. You activate Kamikaze mode charge in and blow the base clean (yourself as well but thats kinda the point) ...your bud comes in right after the carnage, grabs the flag and takes it home for the capture.

Well thats the theory as least.

Code you Kill Yourself By.

Ok lets start by creating two files and adding them to the project...
kamikaze.h and kamikaze.c... first lets start with the header file..

Place this code in the kamikaze.h file

/* 
kamikaze.h
by....Wonderslug
*/

/*  Amount of Damage caused */
#define	KAMIKAZE_DAMAGE			300

/* Radius of blast */
#define	KAMIKAZE_DAMAGE_RADUIS	800 // Quake Units

/* Count down time */
#define KAMIKAZE_BLOW_TIME		 50 // 1/10 seconds

void		Start_Kamikaze_Mode(edict_t *the_doomed_one); // setup and start self destruct mode
qboolean		Kamikaze_Active(edict_t *the_doomed_one);
void		Kamikaze_Explode(edict_t *the_doomed_one);
void		Kamikaze_Cancel(edict_t *the_spared_one);

This is just a couple of defines that define how much damage and how far out the blast goes, as well as the amount of time before the blast.

Ok now place the following code in the kamikaze.c

/* kamikaze.c
  All functions for independent kamikaze
  by....Wonderslug
*/



#include        "g_local.h"
#include		"kamikaze.h"

/*
Function: Start_Kamikaze_Mode

  Places the edict passed to it into Kamikaze Mode
  (probably best to pass a player to it)

  Warns everyone that so and so is a kamikaze...

*/
void Start_Kamikaze_Mode(edict_t *the_doomed_one){
	
	/* see if we are already in  kamikaze mode*/
	if (the_doomed_one->client->kamikaze_mode & 1)  {
		gi.cprintf(the_doomed_one, PRINT_MEDIUM, "Already in Kamikaze Mode!! Kiss you butt Goodbye!");
		return;		    
	}
	
	/* dont run if in god mode  */
	if (the_doomed_one->flags & FL_GODMODE){
		gi.cprintf(the_doomed_one, PRINT_MEDIUM, "Can't Kamikaze in God Mode, Whats the Point?");
		return;
	}
	/* not in kamikaze mode yet */
	the_doomed_one->client->kamikaze_mode = 1;

	/*  Give us only so long */
	the_doomed_one->client->kamikaze_timeleft = KAMIKAZE_BLOW_TIME;
	the_doomed_one->client->kamikaze_framenum = level.framenum + the_doomed_one->client->kamikaze_timeleft;

	/* Warn the World */
	gi.bprintf (PRINT_MEDIUM,"%s is a Kamikaze - BANZAI!!\n", the_doomed_one->client->pers.netname);
    gi.sound( the_doomed_one, CHAN_WEAPON, gi.soundindex("makron/rail_up.wav"), 1, ATTN_NONE, 0 );

	return;
}

/* 
Function: Kamikaze_Active
	Are we in Kamikaze Mode? 
	a helper function to see if we are running in Kamikaze Mode

*/
qboolean Kamikaze_Active(edict_t *the_doomed_one){
	return (the_doomed_one->client->kamikaze_mode);
}


/* 
Function: Kamikaze_Cancel
  Canceled for Some Reason
  Call if Player is killed before time is up
*/
void Kamikaze_Cancel(edict_t *the_spared_one){
	/* not in kamikaze mode yet */
	the_spared_one->client->kamikaze_mode = 0;
	/* Give us only so long */
	the_spared_one->client->kamikaze_timeleft = 0;
	the_spared_one->client->kamikaze_framenum = 0;
	
	return;
}

void Kamikaze_Explode(edict_t *the_doomed_one){


    /* A whole Lotta Damage */
    T_RadiusDamage (the_doomed_one, the_doomed_one, KAMIKAZE_DAMAGE, NULL, KAMIKAZE_DAMAGE_RADUIS);

     /* BANG ! and show the clients */
     gi.WriteByte (svc_temp_entity);
     gi.WriteByte (TE_EXPLOSION1);
     gi.WritePosition(the_doomed_one -> s.origin);
     gi.multicast (the_doomed_one->s.origin, MULTICAST_PVS);
}

This is all the major functions for the kamikaze starting, canceling, seeing if we are in kamikaze mode, and of course the end explosion.

Now we have to add in some variables to be carried around by the client... so open up g_local.h and go to line line 827. This is the gclient_t structure. Place the following code in there.

Replace this

  float		respawn_time;		// can respawn when time > this
} gclient_t;

With this
  float		respawn_time;		// can respawn when time > this

  /* WonderSlug --Added For Kamikaze Mode */
  int		kamikaze_mode;
  float		kamikaze_framenum;
  float		kamikaze_timeleft;
  /* WonderSlug End */
} gclient_t;

These are just some variables to carry information about when to blow up and if we are in the mode to go boom as well.

Next open up g_cmds.c and place this bit of code around line 636 in the ClientCommand function
Replace this

  else if (Q_stricmp (cmd, "wave") == 0)
    Cmd_Wave_f (ent);
  else if (Q_stricmp (cmd, "gameversion") == 0)

With this
  else if (Q_stricmp (cmd, "wave") == 0)
    Cmd_Wave_f (ent);
  /* WonderSlug -- Start Kamikaze Mode */	
  else if (Q_stricmp (cmd, "kamikaze") == 0)
				Start_Kamikaze_Mode(ent);
  /* WonderSlug End */
  else if (Q_stricmp (cmd, "gameversion") == 0)

What this does is let us bind a convenient key to the kamikaze command.

Now open up the file p_client.c and at the very bottom of the ClientThink function place the following code at line 1072

Replace this

      client->weapon_thunk = true;
      Think_Weapon (ent);
    }
  }


With This...
      client->weapon_thunk = true;
      Think_Weapon (ent);
    }
  }
  /* WonderSlug ----Code to go boom */
  if ((ent->client->kamikaze_framenum <= level.framenum) && (ent->client->kamikaze_mode & 1))
	  Kamikaze_Explode(ent);
  /* WonderSlug End */


This is the code to blow up once we reach the timelimit.

Now still p_client.c go to line 147 and place the following in the player_die function
Replace this

  VectorClear (self->avelocity);

  self->takedamage = DAMAGE_YES;

With This...
  /* WonderSlug */
  Kamikaze_Cancel(self);		/* No Kamikaze Now!!*/
  /* end wonderlsug */
  VectorClear (self->avelocity);

  self->takedamage = DAMAGE_YES;

Now if we die while in Kamikaze mode we dont blow up....gotta give the defenders a chance.

Now open the file p_hud.c and on line 362 in the G_SetStats function place the following code. Replace this

  if (ent->client->quad_framenum > level.framenum)
  {
    ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_quad");
    ent->client->ps.stats[STAT_TIMER] = (ent->client->quad_framenum - level.framenum)/10;
  }
  else if (ent->client->invincible_framenum > level.framenum)

With This...
  if (ent->client->quad_framenum > level.framenum)
  {
    ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_quad");
    ent->client->ps.stats[STAT_TIMER] = (ent->client->quad_framenum - level.framenum)/10;
  }
  	/* WonderSlug Kamikaze */
  else if (ent->client->kamikaze_framenum > level.framenum)  {
	ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_quad");
	ent->client->ps.stats[STAT_TIMER] = ent->client->kamikaze_timeleft/10;
  }
	/* WonderSlug End */
  else if (ent->client->invincible_framenum > level.framenum)

What this does is add the countdown on the screen just like the Quad damage... im fact we are using the quad damage symbol because i could ot think of one for blowing yourself up.

Now still in p_hud.c go to line 25 and add the following code into the MoveClientToIntermission function.
Replace this

     // clean up powerup info
  ent->client->quad_framenum = 0;

With This...
      // clean up powerup info
  /* Wonderslug  Cancel Kamikaze if going to new level */
  ent->client->kamikaze_framenum = 0;
  /* WonderSlug End */
  ent->client->quad_framenum = 0;

This is just to clean up the timing when moving to a new level.

Time so add some visible effects...open up p_view.c and in the G_SetClientEffects function on line 763 add in the following code. Replace this

      // show cheaters!!!
  if (ent->flags & FL_GODMODE)
  {
    ent->s.effects |= EF_COLOR_SHELL;
    ent->s.renderfx |= (RF_SHELL_RED|RF_SHELL_GREEN|RF_SHELL_BLUE);
  }

With This...
      // show cheaters!!! and Kamikazes!!!
  if ((ent->flags & FL_GODMODE) || (ent->client->kamikaze_mode & 1))
  {
    ent->s.effects |= EF_COLOR_SHELL;
    ent->s.renderfx |= (RF_SHELL_RED|RF_SHELL_GREEN|RF_SHELL_BLUE);
  }

Now the Kamikaze has a nice white glow to others...The defenders need to know who there biggest threat is..again it cant be one sided. Now if your using God mode on your multi player server you deserve to be confused.

Still in p_view.c go to line 424 in the SV_CalcBlend function and insert this code
Replace this

  if (ent->client->quad_framenum > level.framenum)
  {
    remaining = ent->client->quad_framenum - level.framenum;
    if (remaining == 30)	// beginning to fade
      gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage2.wav"), 1, ATTN_NORM, 0);
    if (remaining > 30 || (remaining & 4) )
      SV_AddBlend (0, 0, 1, 0.08, ent->client->ps.blend);
  }
  else if (ent->client->invincible_framenum > level.framenum)

With This...
  if (ent->client->quad_framenum > level.framenum)
  {
    remaining = ent->client->quad_framenum - level.framenum;
    if (remaining == 30)	// beginning to fade
      gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage2.wav"), 1, ATTN_NORM, 0);
    if (remaining > 30 || (remaining & 4) )
      SV_AddBlend (0, 0, 1, 0.08, ent->client->ps.blend);
  }
  /* Wonderslug   make screen go colored  */
  else if (ent->client->kamikaze_framenum > level.framenum){
	  remaining = ent->client->kamikaze_framenum - level.framenum;
	  ent->client->kamikaze_timeleft = remaining;
	  if (remaining == 30)
			gi.sound(ent, CHAN_ITEM, gi.soundindex("items/protect2.wav"), 1, ATTN_NORM, 0);
	  if (remaining > 30 || (remaining & 4))
			SV_AddBlend (0, 0, 1, 0.08, ent->client->ps.blend);
  }
  /* Wonderslug End */
  else if (ent->client->invincible_framenum > level.framenum)

Now here we have the code to make the screen go a little different color when we are in Kamikaze mode. It also does the waring on the last couple of seconds.

All thats left now is to go back and place

#include "kamikaze.h"
in all the c files we have just messed with. You dont need to place it in the g_local.h. These files are

Just place it up at the top along with the other includes.

You should now be ready to Rock and Blow Up.. bind a key to the "cmd kamikaze" and your off to die for the common goal...or if in deathmatch just to take out a lot of people... I recommend using it close to at least one enemy..you still lose a frag for nuking yourself...but if you take one along with you it balances out.

So Go forth....and Die for the Greater Good!!!

BANZAI!!!! and avoid the Salt!! -=WonderSlug

Tutorial by WonderSlug .

This site, and all content and graphics displayed on it,
are ©opyrighted to the Quake DeveLS team. All rights received.
Got a suggestion? Comment? Question? Hate mail? Send it to us!
Oh yeah, this site is best viewed in 16 Bit or higher, with the resolution on 800*600.
Thanks to Planet Quake for their great help and support with hosting.
Best viewed with Netscape 4