
Posted by Maj.Bitch
(209.130.218.*) on April 17, 1999 at 19:49:39:
Title: Super Grenade Launcher
Difficulty: Easy
By: Philip (aka Maj.Bitch)
Email: peblair@inreach.com
Date: 4-17-99
Note: Please give credit where credit is due.
======================================================
I was tired of the grenade launcher lobbing a grenade
forward (and not very far) so I decided to make a combination
rocketlauncher and grenade launcher called the Super
Grenade Launcher which has the added feature of when the
rocket hits a wall, it bursts into 5 grenades which bounce
around in different directions and explode at random
intervals. Its fun combining various weapon features!
What it does:
You hit the aliased key and your normal grenade launcher
becomes a Super Grenade Launcher (with the normal ENABLED
message showing on your HUD). If you have 5 grenades in
your inventory then, when you fire your new weapon, a
rocket comes shooting out the front of your launcher and
acts just like a regular rocket. If it hits somebody then
they get the normal rocket hit damage. But.. if your rocket
hits a world surface (which is what you want it to do) then
without any explosive fireball, the rocket bursts into 5
grenades which bounce off the impact surface and go bouncing
around. A total of 5 grenades come flying out and each one
has its own separate random timer so they all explode at
random intervals. 5 grenades are then deducted from your
inventory. If you don't have the 5 grenades then the weapon
acts just like a regular grenade launcher.
GREAT for firing down a long corridor or into a large open
area which is relatively far away (but still can be reached
by a rocket) so that the burst of 5 grenades (which'll come
flying out of the rocket's impact with the world) will cover
a larger area for more frags!
Okay, let's get started!
========================================================
Add the following new variable to your gclient struct..
int rgrenade; // SuperGrenadeLauncher 1=ON, 0=OFF
========================================================
Add this new MOD flag to the other MOD flags..
#define MOD_DEATHPAK 50 // MegaHealth DeathPak
#define MOD_HANGED 51 // Hangman Weapon
#define MOD_RGRENADE 52 // NEW FLAG HERE..
Be sure that its the next incremented number..
========================================================
Next, let's go into Client_Obituary() and add the following
new MOD death messages..
case MOD_RAILBOMB:
message="was railbombed";
break;
case MOD_ZYLON_GAS:
message="inhaled Zylon gas";
break;
//----- ADD THIS RIGHT HERE ----------
case MOD_RGRENADE:
message="caught a rocket grenade";
break;
//------------------------------------
Further down in this same function add:
case MOD_BFG_BLAST:
message="should have used a smaller gun";
break;
case MOD_HGRENADE:
message="caught a homing grenade";
break;
//----- ADD THIS RIGHT HERE ----------
case MOD_RGRENADE:
message="caught a rocket grenade";
break;
//------------------------------------
And, further down in this same function add:
case MOD_HANGED:
message="was hanged by";
message2="'s rope";
break;
//----- ADD THIS RIGHT HERE ----------
case MOD_RGRENADE:
message="was shredded by";
message2="'s rocket grenade";
break;
//------------------------------------
These will be the messages displayed on the HUD when a
player gets killed by this new weapon.
Feel free to change these messages to what you feel is
more appropriate for your particular mod..
========================================================
Okay, let's open your g_cmds.c file and at the bottom
of your Client_Command() function add this:
else if (!Q_stricmp(cmd, "hgrenade")) {
ent->client->hgrenade=abs(ent->client->hgrenade-1);
gi_centerprintf(ent,"HOMING GRENADES %s!\n",ent->client->hgrenade<1?"DISABLED":"ENABLED");}
//------- ADD THIS RIGHT HERE ----------------
else if (!Q_stricmp(cmd, "rgrenade")) {
ent->client->rgrenade=abs(ent->client->rgrenade-1);
gi_centerprintf(ent,"SUPER GRENADELAUNCHER %s!\n",ent->client->rgrenade<1?"DISABLED":"ENABLED");}
//--------------------------------------------
else if (!Q_stricmp(cmd, "tgrenade")) {
ent->client->Tgrenade=abs(ent->client->Tgrenade-1);
gi_centerprintf(ent,"TELEPORT GRENADES %s!\n",ent->client->Tgrenade<1?"DISABLED":"ENABLED");}
else if (!Q_stricm
This will allow the console to turn this new feature ON/OFF.
========================================================
Open your p_client.c file and at the bottom of your
InitClientPersistent() function add this new line:
client->laserdrone=OFF; // default to OFF
client->Tgrenade=OFF; // default to OFF
client->is_trapped=OFF; // default to OFF
//-------- NEW LINE GOES HERE ----------------
client->rgrenade=OFF; // default to OFF
//--------------------------------------------
client->pers.connected=true;
This will turn the feature OFF when the player enters the game.
========================================================
Okay, now open your g_weapon.c file and find your
fire_grenade() function. Add the lines as shown:
void fire_grenade(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius) {
edict_t *grenade;
vec3_t dir, right, up;
//-----------
NEW LINES GO RIGHT HERE -----------------
// Is Super GrenadeLauncher Enabled?
if (self->client->rgrenade==ON)
if
(self->client->pers.inventory[ITEM_INDEX(item_grenades)] >=5) {
// Deduct the 5 grenades and
fire!!
self->client->pers.inventory[ITEM_INDEX(item_grenades)]
-= 5;
fire_rocketgrenade(self, start,
aimdir, 100+random()*50, 550+50*skill->value, 150, 100+random()*50);
return; }
//----------------------------------------------------
Also, you need to add this to the bottom of this same function:
self->client->pers.inventory[ITEM_INDEX(item_grenades)] -= 1;
This will activate the fire_rocketgrenade() function if the
player has turned this feature ON. Also, at the bottom we
needed to add the grenade deduction here because we are going
to have to comment it out in another function..
========================================================
Now go into your weapon_grenadelauncher_fire() function and
comment out the single line which deducts the grenade from
the player's inventory. We had to move this single line else
we'd have an extra grenade being deducted by mistake. OR,
you can leave it all the same and just change the deduction
for the rocketgrenade from 5 to 4. That'll do the same thing
if you are confused..
========================================================
Now, let's add these new functions in your g_weapons.c
file at a point above the fire_grenade() function:
//============================================================
// Create numgrenades and toss them out in random directions!
// numgrenades variable: // REBUILT - (Maj.Bitch)
//============================================================
void spawn_into_grenades(vec3_t origin, int numgrenades, int modflag) {
trace_t tr;
gitem_t *item=NULL;
edict_t *grenade=NULL;
vec3_t offset;
int i,j;
vec3_t spray[]={ { 25, 00, 40 },
{ 17, -17, 40 },
{ 00, -25, 40 },
{ -17, -17, 40 },
{ -25, 00, 40 },
{ -17, -17, 40 },
{ -25, 00, 40 },
{ -17, 17, 40 },
{ 00, 25, 40 },
{ 17, 17, 40 }};
vec3_t dir, forward, right, up;
VectorClear(offset);
for (j=1; j<=numgrenades; j++) {
i=(j>10)?j%10+1:j;
grenade = G_Spawn();
grenade->owner=world; // This
allows owner to get damaged!
VectorSet(offset, spray[i-1][0],
spray[i-1][1], spray[i-1][2]);
offset[0]+=(crandom()*16.0)-8.0;
offset[1]+=(crandom()*16.0)-8.0;
offset[2]+=(crandom()*16.0)-8.0;
vectoangles(offset, dir);
AngleVectors(dir, forward, right,
up);
VectorSet(grenade->mins, -8, -8,
-8);
VectorSet(grenade->maxs, 8, 8,
8);
G_ProjectSource(origin, offset,
forward, right, grenade->s.origin);
tr=gi.trace(origin, grenade->mins, grenade->maxs,
grenade->s.origin, NULL, CONTENTS_SOLID);
VectorCopy(tr.endpos,
grenade->s.origin);
VectorScale(offset, crandom()*10.0,
grenade->velocity);
grenade->velocity[2]=300;
grenade->movetype=MOVETYPE_BOUNCE;
grenade->classname="grenade";
grenade->spawnflags=(modflag)?modflag:MOD_GRENADE;
item=item_grenades;
grenade->clipmask=MASK_SHOT;
grenade->solid=SOLID_BBOX;
BitOR(grenade->s.effects,EF_GRENADE);
grenade->dmg=40;
grenade->dmg_radius=120;
grenade->model =
"models/objects/grenade/tris.md2";
grenade->s.modelindex=gi.modelindex(grenade->model);
grenade->touch=Grenade_Touch;
grenade->think=Grenade_Explode;
grenade->nextthink =
level.time+5.0+(random()*10.0);
gi.linkentity(grenade); }
}
//============================================================
void rocketgrenade_touch(edict_t *ent, edict_t *other, cplane_t *plane,
csurface_t *surf) {
vec3_t origin;
if (surf &&
BitCmp(surf->flags,SURF_SKY)) {
G_FreeEdict(ent);
return; }
// calculate position for the explosion
entity
VectorMA(ent->s.origin, -0.02,
ent->velocity, origin);
// Did the rocketgrenade crash into a
player?
if (other->takedamage)
T_Damage(other, ent, ent->owner,
ent->velocity, ent->s.origin, plane->normal, ent->dmg, 0, 0,
MOD_ROCKET);
else {
// Spawn into 5 grenades at impact!
spawn_into_grenades(ent->s.origin,5,MOD_RGRENADE);
G_FreeEdict(ent); // Free the
rocket..
return; }
// Do normal rocket explosion at point of
impact.
G_Spawn_Explosion((ent->waterlevel!=0)?TE_ROCKET_EXPLOSION_WATER:TE_ROCKET_EXPLOSION,
origin, origin);
// Signal Monsters that you've made a big
noise!!
PlayerNoise(ent->owner,
ent->s.origin, PNOISE_IMPACT);
// Do normal radius damage...
T_RadiusDamage(ent, ent->owner,
ent->radius_dmg, other, ent->dmg_radius, MOD_R_SPLASH);
G_FreeEdict(ent);
}
//============================================================
void fire_rocketgrenade(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, float damage_radius, int radius_damage) {
edict_t *rocket;
rocket=G_Spawn();
VectorCopy(start,
rocket->s.origin);
VectorCopy(dir, rocket->movedir);
vectoangles(dir, rocket->s.angles);
VectorScale(dir, speed,
rocket->velocity);
rocket->movetype=MOVETYPE_FLYMISSILE;
rocket->clipmask=MASK_SHOT;
rocket->solid=SOLID_BBOX;
BitOR(rocket->s.effects,EF_ROCKET);
VectorClear(rocket->mins);
VectorClear(rocket->maxs);
rocket->s.modelindex=gi.modelindex("models/objects/rocket/tris.md2");
rocket->owner=self;
rocket->touch=rocketgrenade_touch;
rocket->nextthink=level.time+8000/speed;
rocket->think=G_FreeEdict;
rocket->dmg=damage;
rocket->radius_dmg=radius_damage;
rocket->dmg_radius=damage_radius;
rocket->s.sound=gi.soundindex("weapons/rockfly.wav");
rocket->classname="rocket";
if (!deathmatch->value &&
self->client)
check_dodge(self,
rocket->s.origin, dir, speed);
gi.linkentity(rocket);
}
These are the functions that'll do all the work for you.
========================================================
Lastly, be sure to bind a key in your autoexec.cfg file
as shown below by example:
bind h "rgrenade"
This'll turn this new feature ON/OFF when you hit this key.
========================================================
Okay, that's it!! Get yourself a bunch of grenades and pull
out your new super grenade launcher and fire this baby into
a wall above the crowd! Remember, if you hit another player
directly, it acts just like a regular rocket (but it just
cost you 5 grenades).. Fire above their heads and into a
wall or some other world surface!
Now get out there and BLOW THE BASTARDS BACK TO HELL!
Have Fun!
Maj.Bitch