Barrel 'o Shark

 

 

philip
profile | email

posted 11-20-98 11:38 AM CT (US)
Title: Barrel 'o Shark
Difficulty: Moderate
By: Philip (aka Maj.Bitch)
Email: peblair@gv.net
Date: 11-18-98
Note: Please give credit where credit is due.
======================================================

I just did a DepthCharge tutorial a few days ago where
you toss out a barrel into the water and it self detonates
into a hugh fireball killing everybody in the water with
it. Well, I was thinking... What if the geniuses back at
Space Marine Weapons Research came up with a way of packing one
of those Shark entities into a barrel for you and then they made
it available to all marines? Which means you now have one in
your weapons arsenal! (You remember the nasty shark entity from
single player Q2 which swims around under the water and bites
your ass with its big sharp teeth??) Well, the weapons designers
(me) coded this one up in less than 1 hour and it worked the first
time I ran it!! Now THATS Scary!!!

Introducing the Shark Barrel Weapon Add-On!!

How it works:

You pay the cost of 10 grenades and you hit your aliased key and
a barrel gets tossed in your forward looking direction and
bounces around until coming to a rest somewhere. The barrel has
a water sensor built into it so if the barrel comes to rest on
dry ground (or on anything other than water) it immediately self
destructs into a fireball and killing the shark hiding inside
(with the usual spray of shark guts splattered about).. And,
since you were such a dumbass not to toss your shark barrel into
water somewhere, there is no radius damage from the self exploding
barrel (so nobody nearby gets injured from the self destruct
explosion) and you just lost the 10 grenades you just paid!
So, be sure to be standing in front of water or in the water
yourself, before you toss out your shark barrel..(although
you'd better make a quick exit after the barrel explodes and
releases the shark!)

Okay, once the barrel senses that it is in water, a 5 second
timer is set before the outer shell of the barrel blows apart and
releases the shark inside! The shark is active for an entire
2 minutes in BRUTAL AI MODE, seeking out everybody and anything
which ventures into the water!! The shark can be killed by
a player who will then pick up 2 frags for killing the shark.
You can kill the shark (in self defense) but won't get any frags
for it.. Although, you get all the frags for the shark kills
during its 2 minute lifespan of search and destroy.. If you've
got more than 10 grenades (like 20 or 30) then toss in 2 or 3 barrels
and really control those waterholes and underwater passageways!!

GREAT for tossing into the water and flushing out those players
hanging out in the water railing everybody's ass!

GREAT for a teamplay kind of setup also!!
Okay, let's get started!

===============================================================
============================================================
Lets open you g_weapons.c file and add these helper routines
and the source code somewhere near 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..

Okay, add the following text to the top of your g_weapons.c file.

------------------ START HERE ------------------------

//======================================================
// 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 b1=ent->client->ps.pmove.pm_type!=PM_DEAD;
qboolean b2=ent->deadflag != DEAD_DEAD;
qboolean b3=ent->health > 0;
return (b3 || b2 || b1);
}

//======================================================
// 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);
}

//======================================================
void G_Spawn_Explosion(int type, vec3_t start, vec3_t origin ) {
gi.WriteByte(svc_temp_entity);
gi.WriteByte(type);
gi.WritePosition(start);
gi.multicast(origin, MULTICAST_PVS);
}


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

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, "shark") == 0)
Cmd_SharkBarrel_f(ent);
else if .....

This will activate your Shark Barrel weapon.

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

Add this prototype declaration to the top of you g_cmds.c
file:

void Cmd_SharkBarrel_f(edict_t *ent);

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

Okay, now find your ClientObituary() function in p_client.c
and add this code to the top as indicated:

void ClientObituary(......)
{
int mod;
char *message;
char *message2;
qboolean ff;

---------- ADD THIS CODE RIGHT HERE ------------------

// Was attacker the Shark in DM?
if (deathmatch->value)
if ((G_EntExists(attacker))&&(G_EntExists(victim)))
if (Q_stricmp(attacker->classname, "XShark")==0)
// Shark's activator still exists?
if (G_EntExists(attacker->activator)) {
// Assign shark's kills to activator's score!!
gi.bprintf(PRINT_MEDIUM,"%s was swallowed by %s's Shark\n",
victim->client->pers.netname,
attacker->activator->client->pers.netname);
attacker->activator->client->resp.score += 1;
return; }

------------ REST OF CODE CONTINUES ON -------------------

if (coop->value && attacker->client)


This will make sure that the frags from the Sharks' kills
will be assigned to the shark's activator...

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

Find your Killed() function in your g_combat.c file and
add the following lines as shown:

void Killed(......)
{
if (targ->health < -999)
targ->health = -999;

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

if (deathmatch->value)
// Was this a Shark which just got killed?
if (Q_stricmp(targ->classname, "XShark")==0)
if (G_EntExists(attacker) && (attacker!=targ->activator)) {
gi.centerprintf(attacker,"2 Frags for killing Shark!\n");
attacker->client->resp.score += 2; }

-------------------------------------------------------------

This will award the 2 frags to the player who takes out one
of the shark entities.

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

Create a new file called p_shark.c and paste in the following
code from start to stop as indicated:

--------------------- START HERE ------------------
#include "g_local.h"
#include "m_player.h"

#define POWER1_SOUND gi.soundindex("misc/power1.wav")

//======================================================
//=========== BARREL OF SHARK ROUTINES =================
//======================================================

//======================================================
// timer->owner => ent;
// timer->activator => shark;
//======================================================
void Shark_Explode(edict_t *timer) {
vec3_t zvec={0,0,0};

// Have Shark died already?
if (!timer->activator) {
G_FreeEdict(timer);
return; }

// Maximally damage the Shark entity...
T_Damage(timer->activator, timer->owner, timer->owner, zvec, timer->activator->s.origin, NULL, timer->activator->max_health*2, 1, 0, MOD_SPLASH);
// Spawn an explosion fireball..
G_Spawn_Explosion(TE_EXPLOSION2, timer->activator->s.origin, timer->activator->s.origin);
// Do grenade-type radius damage to anybody nearby
T_RadiusDamage(timer->activator, timer->owner, 40, NULL, 200, MOD_SPLASH);

// Free timer entity.
G_FreeEdict(timer);
}

//=========================================================
void Spawn_Shark(edict_t *barrel) {
edict_t *shark;
edict_t *timer;
int temp;

//------------------------------
// Spawn basic Shark entity
//------------------------------

shark = G_Spawn();
shark->classname = "XShark"; // Used for Killed()
shark->activator = barrel->activator; // Link back to Owner.
VectorCopy(barrel->s.origin, shark->s.origin);
gi.linkentity(shark);

//------------------------------
// Change some Global States
//------------------------------

skill->value=3; // Toggle Advanced AI.
temp=deathmatch->value; // Temp storage..
deathmatch->value=0; // Must = 0 to bypass quick-exit in Monster Code

//------------------------------
// Activate the Shark Entity
//------------------------------

SP_monster_flipper(shark); // Create the Shark Monster

// Toggle AI for Kill Everything Mode
shark->monsterinfo.aiflags &= AI_BRUTAL;

// Make shark a bit harder to kill.
shark->health *= 1.5;

// Restore to previous value.
deathmatch->value=temp;

// Play powerup sound to tossing ent.
gi.sound(barrel->activator, CHAN_VOICE, POWER1_SOUND, 1, ATTN_IDLE, 0);

//---------------------------
// Spawn Timer Entity.
//---------------------------

timer=G_Spawn();
timer->owner=barrel->activator;
timer->activator=shark; // Link to Shark
timer->takedamage=DAMAGE_NO;
timer->movetype=MOVETYPE_NONE;
timer->solid = SOLID_NOT;
VectorClear(timer->s.origin);
VectorClear(timer->mins);
VectorClear(timer->maxs);
timer->think=Shark_Explode;
timer->nextthink=level.time + 120.0; // 2 mins to Auto Self-Destruct
gi.linkentity(timer);

G_FreeEdict(barrel); // Make the barrel go away!
}

//======================================================
void SharkBarrel_Touch(edict_t *a, edict_t *b, cplane_t *c, csurface_t *d)
{}

//======================================================
void SharkBarrel_Explode(edict_t *barrel) {

// Not touchable until stopped moving.
if ((VectorLength(barrel->velocity) > 1)
|| (level.time < barrel->delay)) {
barrel->nextthink = level.time + 5.0;
return; }

// If Barrel in water then explode.
if (gi.pointcontents(barrel->s.origin) & CONTENTS_WATER) {
G_Spawn_Explosion(TE_EXPLOSION2, barrel->s.origin, barrel->s.origin);
barrel->think=Spawn_Shark;
// Shark appears after fireball finishes..
barrel->nextthink = level.time + 1.0; }
else {
// Barrel self destructs if NOT in water!!
G_Spawn_Explosion(TE_EXPLOSION2, barrel->s.origin, barrel->s.origin);
// Toss some Shark guts around!
ThrowGib(barrel, "models/objects/gibs/sm_meat/tris.md2", 20, GIB_ORGANIC);
ThrowGib(barrel, "models/objects/gibs/bone/tris.md2", 30, GIB_ORGANIC);
ThrowGib(barrel, "models/objects/gibs/sm_meat/tris.md2", 50, GIB_ORGANIC);
// Make barrel go away..
G_FreeEdict(barrel); }
}

//======================================================
void Toss_SharkBarrel(edict_t *ent) {
edict_t *barrel=NULL;
vec3_t torigin;
vec3_t forward, right, up;

// Toss barrel in forwar direction
VectorCopy(ent->s.origin,torigin);
AngleVectors(ent->client->v_angle, forward, right, up);
VectorMA(torigin, 50, forward, torigin);
if (gi.pointcontents(torigin) & MASK_SHOT) {
gi.cprintf(ent,PRINT_HIGH,"Cannot project into Solid!\n");
return; }

barrel = G_Spawn();
barrel->owner=NULL; // Owner can be attacked too!
barrel->activator=ent; // Link back to owner.
barrel->movetype=MOVETYPE_BOUNCE;
barrel->solid = SOLID_BBOX;
VectorCopy(up, barrel->s.angles);
VectorSet(barrel->mins, -10, -10, 0);
VectorSet(barrel->maxs, 10, 20, 30);
VectorClear(barrel->velocity);
VectorScale(forward, 600, barrel->velocity);
VectorMA(barrel->velocity, 200+crandom()*10.0, up, barrel->velocity);
VectorMA(barrel->velocity, crandom()*10.0, right, barrel->velocity);
VectorClear(barrel->avelocity);
VectorCopy(torigin,barrel->s.origin);
barrel->model = "models/objects/barrels/tris.md2";
gi.setmodel(barrel, barrel->model);
barrel->delay=5.0;
barrel->touch=SharkBarrel_Touch;
barrel->think=SharkBarrel_Explode;
barrel->nextthink = level.time + 1.0;

gi.linkentity(barrel);
}

//======================================================
// Pay the Piper for the Shark Barrel
//======================================================
void Cmd_SharkBarrel_f(edict_t *ent) {
int index;

// Don't allow dead/respawning players to do this!
if (!G_ClientInGame(ent)) return;

index = ITEM_INDEX(FindItem("grenades"));
if (ent->client->pers.inventory[index] < 10){
gi.centerprintf(ent, "Shark Barrel costs 10 grenades!\n");
return; }
else {
ent->client->pers.inventory[index] -= 10;
Toss_SharkBarrel(ent); }
}

--------------------- STOP HERE -------------------

===============================================================
Lastly..

Remember to bind a key in your Autoexec.cfg file as shown
by example below:

bind s "shark"

That's it!! Have the shark KILL THE BASTARDS FOR YOU!

Have Fun!!

philip