Railbomb Grenades Add-On

 

 

philip
profile | email

posted 11-03-98 2:37 AM CT (US)
Title: Railbomb Grenades Add-On
Difficulty: Easy
By: Philip (aka Maj.Bitch)
Email: peblair@gv.net
Date: 11-02-98
Note: Please give credit where credit is due.
======================================================

This tutorial is a modification of the principles put forth
in my previously posted tutorial (Airial Laserdrone Unit).
This add-on adds additional firepower to your grenade. READ ON!

When you want to activate your RailBomb, you hit your aliased
key and a message comes on the screen letting you know that your
grenades are now Railbombs. The grenade launches and bounces
around just like a regular grenade and even explodes just like
a regular grenade (distributing damage, etc) but out of the
explosion fireball comes railgun slugs (known as railtrails)
which are fired at ALL visible players within a 1000 unit radius.
This happens almost instantly!! COOL EFFECTS when multiple rails
come flying out of the fireball! So, if there are a bunch
players outside the explosion fireball damage radius (who think
that they've escaped from the grenade's explosion) but they are
within the 1000 unit search-n-fire radius of the grenade's
fireball, then they get railed!! Haha! They think they got
away from your grenade's explosion!! FOOLS!! If there are no
visible players within the defined radius, then no slugs are
fired from the grenade and the grenade explodes and acts just
like a regular grenade! Nobody will know the difference! And,
it doesn't cost you any cells or frags to convert your grenades
to railbombs!! Hit your aliased key and ALL your grenades are
converted to railbombs until you hit your aliased key again to
toggle them all off. Fire as many of these babies you want to!!

Okay, let's get started..

============================================================
We need to add a new variable to your gclient_s struct. So,
at the bottom of that struct, add this:

int railbomb; // 1=ON, 0=OFF

This will be used to toggle the railbomb ON/OFF

============================================================

We need to add another MOD_* obituary flag. So, inside of
your g_local.h add the MOD_RAILBOMB flag as the next integer
in the numerical sequence as shown by example:

#define MOD_CLUSTER_BOMBS 0x00000024 // Cluster Airstrike
#define MOD_ZYLON_GAS 0x00000025 // Gas Grenade
#define MOD_RAILSTRIKE 0x00000026 // BFG Nuke Airstrike
#define MOD_BFG_NUKE 0x00000027 // Railgun Airstrike
#define MOD_DECOY 0x00000028 // Decoy Blast
#define MOD_LASERDRONE 0x00000029 // LaserDrone Weapon
#define MOD_RAILBOMB 0x00000030 // NEW FLAG HERE
#define MOD_FRIENDLY_FIRE 0x10000000 // DON'T TOUCH THIS ONE!!

============================================================

Lets open you g_weapons.c file and add these helper routines
to the top of the file.

NOTE: I've used these helper routines in many of my previous
tutorials so you may already have them someplace in your source.
If you already do have them, then you don't need them anymore.
Your compiler should warn you that you've already got these
functions previously defined..

//======================================================
// True if Ent is valid, has client, and edict_t inuse.
//======================================================
qboolean G_EntExists(edict_t *ent) {
return ((ent) && (ent->client) && (ent->inuse));
}

//======================================================
// True if ent is not DEAD or DEAD or DEAD (and BURIED!)
//======================================================
qboolean G_ClientNotDead(edict_t *ent) {
qboolean buried=true;
qboolean b1=ent->client->ps.pmove.pm_type!=PM_DEAD;
qboolean b2=ent->deadflag != DEAD_DEAD;
qboolean b3=ent->health > 0;
return (b3||b2||b1)&&(buried);
}

//======================================================
// True if ent is not DEAD and not just did a Respawn.
//======================================================
qboolean G_ClientInGame(edict_t *ent) {
if (!G_EntExists(ent)) return false;
if (!G_ClientNotDead(ent)) return false;
return (ent->client->respawn_time + 5.0 < level.time);
}

//======================================================
//======================================================
//======================================================
/*
Spawns a trail of (type) from {start} to {end} and Broadcasts to all
in Potentially Visible Set from vector (origin)

TE_BFG_LASER - Spawns a green laser
TE_BUBBLETRAIL - Spawns a trail of bubbles
TE_PLASMATRAIL - NOT IMPLEMENTED IN ENGINE
TE_RAILTRAIL - Spawns a blue spiral trail filled with white smoke
*/
//======================================================
void G_Spawn_Trails(int type, vec3_t start, vec3_t endpos, vec3_t origin ) {
gi.WriteByte(svc_temp_entity);
gi.WriteByte(type);
gi.WritePosition(start);
gi.WritePosition(endpos);
gi.multicast(origin, MULTICAST_PVS);
}

============================================================
============================================================
============================================================

Okay, let's make some obituaries for your gameplay. Find your
ClientObituary() function in your p_client.c file and add the
following:

---------- FIND THESE LINES HERE -------------

case MOD_TARGET_BLASTER:
message="got blasted";
break;
------------ ADD THESE LINES HERE ------------
case MOD_RAILBOMB:
message="was railbombed";
break;

Further down in this same function:

-------------- FIND THESE LINES -----------

case MOD_G_SPLASH:
if (IsFemale(victim))
message="tripped on her own grenade";
else
message="tripped on his own grenade";
break;

----------- ADD THESE LINES HERE -------------
case MOD_RAILBOMB:
if (IsFemale(victim))
message="got riveted by her railbomb";
else
message="got riveted by his railbomb";
break;

Still further down in this same function:

---------- FIND THESE LINES HERE -------------

case MOD_TELEFRAG:
message="tried to invade";
message2="'s personal space";
break;

--------- ADD THESE LINES HERE ---------------

case MOD_RAILBOMB:
message="was riveted by";
message2="'s railbomb";
break;

Remember: You should feel free to change these client
obituaries to whatever you think is more appropriate for
your particular mod..

============================================================

Okay, go into InitClientPersistant() function in your p_client.c
file and add this line near the bottom:

client->railbomb=0; // default to OFF.

This will set the default to OFF each time the player enters
the game..

============================================================

Also in your p_client.c file, go into Player_Die() function
and add this line too:

self->client->railbomb=0; // Turn OFF.

This will turn off the railbombs when the player dies..

============================================================

Open up your g_cmds.c file and go near the bottom of your
ClientCommand() function and add the following as shown
by example..

---------- IF-ELSE STATEMENTS --------
else if (Q_stricmp(cmd, "decoy") == 0 )
SP_Decoy(ent);
else if (Q_stricmp(cmd, "drone") == 0 )
Cmd_LaserDrone_f(ent);
else if (Q_stricmp(cmd, "teleport") == 0)
Cmd_Teleport_f(ent);
----------- ADD THESE LINES ------
else if (Q_stricmp(cmd, "railbomb") == 0) {
ent->client->railbomb=abs(ent->client->railbomb-1);
gi.centerprintf(ent,"RAILBOMBS %s!\n",ent->client->railbomb<1?"DISABLED":_x0022_ENABLED_x0022__x0029__x003b__x007d_>
else if .....

This will toggle the railbombs on/off with a single stroke
of the player's aliased key.

============================================================
Open up your g_weapons.c file and find your grenade_explode()
function and add the lines as shown..

void Grenade_Explode(edict_t *ent) {


----- FIND THE FIREBALL EXPLOSION CODE ------------
------ SHOULD LOOK SOMETHING LIKE THIS -------

gi.WritePosition(origin);
gi.multicast(ent->s.origin, MULTICAST_PHS);

-------- ADD THESE LINES RIGHT AFTER IT! ---------

// Railbomb only if activated by real Player..
if (G_EntExists(ent->owner))
if (ent->owner->client->railbomb)
Railbomb(ent);

This will activate the Railbomb's search-n-rail function
if the railbomb flag is set by the grenade's owner...

============================================================

Lastly, in your g_weapons.c file, at a point just above the
grenade_explode() function, add this new function:

//==================================================================
// Fires Rail Slugs into all visible players within 1000 unit radius
//==================================================================
void Railbomb(edict_t *grenade) {
edict_t *ent=NULL;
trace_t tr;
vec3_t dummy=(0,0,0);
vec3_t start,end;
int i;

grenade->viewheight = 16; // required for visible() function??.

// Find (and rail) ALL visible ents within 1000 unit radius...
for(i=0;i < game.maxclients;i++) {
ent=g_edicts+i+1;
if (!G_ClientInGame(ent)) continue;
if (ent==grenade) continue;
if (!ent->takedamage) continue;
if (!visible(grenade,ent)) continue;
if (!G_Within_Radius(grenade->s.origin, ent->s.origin, 1000)) continue;
VectorCopy(grenade->s.origin, start);
VectorCopy(ent->s.origin, end);
end[2]+=8;
tr=gi.trace(start, ent->mins, ent->maxs, end, NULL, MASK_SHOT);
G_Spawn_Trails(TE_RAILTRAIL, start, tr.endpos, tr.endpos);
if (G_EntExists(tr.ent) && (tr.ent->takedamage))
T_Damage(tr.ent, grenade->owner, grenade->owner, dummy, start, dummy, grenade->dmg, 1, 0, MOD_RAILBOMB);
} // end for

// return gracefully to grenade_explode() function..
}

NOTE: The farther the potential target is from the origin
of the grenade the less accurate the trace function gets!!
So, at farther and farther distances, the grenade tends to
miss. But, it's deadly accurate up close and personal!

============================================================
Be sure to add the following to your Autoexec.cfg file as
shown by example..

bind r "railbomb"

That's it!!

If your grenade's explosion doesn't kill the bastards then
THE RAIL SLUGS COMING OUT OF THE FIREBALL WILL!!

Have Fun!!

Philip

philip
profile | email

posted 11-03-98 12:29 PM CT (US)
The present Railbomb think function causes the firing of railtrails at ALL visible entities within the 1000 unit radius. But, you can EXCLUDE yourself (the owner of the Railbomb) by adding the following line. Also, teamplay mods will have to configure this one line to fit their particular team definitions (if they wish to exclude other team members from getting railed too!)..

void Railbomb(edict_t *grenade) {
: edict_t *ent=NULL;
: trace_t tr;
: vec3_t dummy=(0,0,0);
: vec3_t start,end;
: int i;

: grenade->viewheight = 16; // required for visible() function??.

: // Find (and rail) ALL visible ents within 1000 unit radius...
: for(i=0;i < game.maxclients;i++) {
: ent=g_edicts+i+1;
: if (!G_ClientInGame(ent)) continue;
: if (ent==grenade) continue;
if (ent==grenade->owner) continue; <== ADD THIS LINE HERE
: if (!ent->takedamage) continue;
: if (!visible(grenade,ent)) continue;
: if (!G_Within_Radius(grenade->s.origin, ent->s.origin, 1000)) continue;
: VectorCopy(grenade->s.origin, start);
: VectorCopy(ent->s.origin, end);
: end[2]+=8;
: tr=gi.trace(start, ent->mins, ent->maxs, end, NULL, MASK_SHOT);
: G_Spawn_Trails(TE_RAILTRAIL, start, tr.endpos, tr.endpos);
: if (G_EntExists(tr.ent) && (tr.ent->takedamage))
: T_Damage(tr.ent, grenade->owner, grenade->owner, dummy, start, dummy, grenade->dmg, 1, 0, MOD_RAILBOMB);
: } // end for

: // return gracefully to grenade_explode() function..
: }


: Have Fun!!

: Philip

philip
profile | email

posted 11-03-98 5:55 PM CT (US)
Forgot to include the G_WithinRadius() function, so here it is..

//======================================================
// True if start and end are within radius distance.
//======================================================
qboolean G_Within_Radius(vec3_t start, vec3_t end, float rad) {
vec3_t eorg={0,0,0};
int j;
for (j=0; j<3; j++)>
eorg[j]=abs(start[j]-end[j]);
return (VectorLength(eorg) < rad);
}

Put this in your code at a point above its first use in your g_weapons.c file..

philip