Ratapult Weapon

 

 

philip
profile | email

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

A few days ago I posted the Satellite Dish Nuke Lobber
tutorial wherein a nuke bomb was lobbed out of the center
of the satellite dish (over the wall) into enemy territory.

Well, remember a few years ago a company came out with a
device they called the "Ratapult" which was used by big
outdoor construction sites or warehouse lots to catch rats.
Well, the ratapult was a big catapult type device placed on
one end of the site and there was this hugh dumpster with
an open top strategically placed across the site. You see
where I'm going with this? The ratapult had a little flat
plate on the end of the catapult's arm where you'd put some
rat bait or cheese or something like that on and when the
rat came along and stepped on the plate to get to the food,
the catapult's arm swung into action and launched the rat
clear across the construction site through the air and right
into the dumpster!! Well, I don't know how successful they
were with their sales and stuff after the animal rights
activists got on their ass!! Anyway.. This is a Ratapult!!

Again, I was thinking... What if you really needed to
harass your enemy but you wanted them pre-occuppied for
some time (so that you could get to something that they
had which you or your team wanted). Well, one good way
to harass the hell out of the enemy is to lob into their
backyard one of those parasite "doggy" entities from Q2
single player. You remember those nasty dog-type creatures
with the razor sharp tongues about 14 feet long which
lashed out at you causing you major grief? And, the little
bastards were difficult to kill too if I remember my single
player experiences! So, the weapons designer at our beloved
Space Marine Weapons Research facility (yours truly) modified
the Satellite weapon to lob one of these doggy entities!

So, this is how it works.. You face in the direction which
you want the doggy projected. Hit your aliased key and a
rather large satellite dish appears a few yards in front of
you facing in the same direction which you are facing (so be
sure to be facing in the direction of the enemy BEFORE you
hit your aliased key because there is no stopping the doggy
launch after the dish is in place and you don't want one of
these pain-in-the-ass parasite bastards roaming around and
harassing/killing off your own people!!!) Okay let's assume
you are not a grunt and you can at least face in the direction
of the enemy before you hit your aliased key..

Okay, once the dish is in place then a 5 second timer is set
and then (with the accompanying sound of the BFG fire sounds)
one of these doggy monsters comes flying out of the center of
the satellite dish and lobbed way forward and into the air!
They go pretty far!! Check it out for yourself!! And, the
doggy doesn't seem to sustain any damage from hitting walls
and cliffs and stuff and ricocheting around before it settles
down on some surface somewhere. (Interesting...) After the
doggy is successfully lobbed into the air, the satellite dish
quietly disappears...

Once deep inside of enemy territory, the doggy will sit quietly
until it detects a player and then will chase that player down
and try to kill it. Of course the doggy can be killed by the
player (but with the dog's enhanced health, they'll really have
their work cut out for them and they better have some really
powerful weapons in their possession or some damn good place
to run and hide)!! Meanwhile, you guys sneak in and launch
a surprise raid while the dog keeps'em busy! Fire off several
of these nasty pups and then raid'em!

The dog has a lifespan of 2 minutes afterwhich time it self
detonate!! You get the all the frag points for kills made by
the dog during it's life and the killer of the dog gets 1 frag
for taking the bastard pup out of action!

The cost of one of these dogs is 20 powercells.. Cheap!! So
figure out where to place your satellite dishes and get them
puppies airborne and deep into enemy territory!!

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

This will activate your Ratapult weapon.

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

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

void Cmd_Ratapult_f(edict_t *ent);

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

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

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 the Doggy Monster which just got killed?
if (Q_stricmp(targ->classname, "XDoggy")==0)
if (G_EntExists(attacker) && (attacker!=targ->activator)) {
gi.centerprintf(attacker,"1 Frag for killing the Doggy!\n");
attacker->client->resp.score += 1; }

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

This will award the 1 frag to the player who takes out one
of the doggie entities.

============================================================
Find your ClientObituary() function and add this code at
the very top..

// --------------------------------------------------------
// Are we in DM Mode?
if (deathmatch->value)
// Make sure both attacker and victim still in game!
if ((G_EntExists(attacker))&&(G_EntExists(self)))
// Was the attacker the doggie?
if (Q_stricmp(attacker->classname, "XDoggy")==0)
// Dog's activator still exists?
if (G_EntExists(attacker->activator)) {
// Assign dog's kills to activator's score!!
gi.bprintf(PRINT_MEDIUM,"%s was eaten by %s's Doggy\n",
self->client->pers.netname,
attacker->activator->client->pers.netname);
attacker->activator->client->resp.score += 1;
return; }

// --------------------------------------------------------

This will make sure that the Doggies owner gets the frags
for the dog's kills!

============================================================
Add all these new routines to the bottom of your g_spawn.c
file and you should be okay..

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

//======================================================
//============ PARASITE 'DOGGIES' LOBBER ===============
//======================================================

//======================================================
// timer->owner => ent;
// timer->activator => doggy;

//======================================================
void Doggy_Explode(edict_t *timer) {
vec3_t zvec={0,0,0};

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

// Maximally damage the Doggy entity...
T_Damage(timer->activator, timer->owner, timer->owner, zvec, timer->activator->s.origin, NULL, 500, 1, 0, MOD_SPLASH);

// Spawn an explosion fireball..
G_Spawn_Explosion(TE_EXPLOSION2, timer->activator->s.origin, timer->activator->s.origin);

// Do radius damage to anybody nearby
T_RadiusDamage(timer->activator, timer->owner, 60, NULL, 300, MOD_SPLASH);

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

//======================================================
void Lob_Doggy(edict_t *dish){
edict_t *doggy, *timer;
vec3_t forward,up;
int temp;

AngleVectors(dish->s.angles, forward, NULL, up);

// Create basic entity stuff...
doggy=G_Spawn();
doggy->classname = "XDoggy"; // Used for Killed() & ClientObit()
doggy->activator=dish->activator; // Link back to Owner.
dish->activator->goalentity=doggy; // Owner Linked to doggy.
VectorCopy(dish->s.origin, doggy->s.origin);
gi.linkentity(doggy);

//------------------------------
// 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 Doggy Entity
//------------------------------

SP_monster_parasite(doggy); // Create the doggy Monster

// Physically throw the doggy over the wall!
VectorMA(doggy->s.origin, 50, up, doggy->s.origin);
VectorMA(doggy->s.origin, 25, forward, doggy->s.origin);
VectorCopy(dish->s.angles, doggy->s.angles);
VectorCopy(forward, doggy->movedir);
VectorClear(doggy->velocity);
VectorMA(doggy->velocity, 2000+(rand()%500), forward, doggy->velocity);
VectorMA(doggy->velocity, 800+(rand()%800), up, doggy->velocity);

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

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

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

gi.sound(dish, CHAN_VOICE, gi.soundindex("weapons/bfg__l1a.wav"), 1, ATTN_IDLE, 0);

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

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

dish->think=G_FreeEdict;
dish->nextthink=level.time + 6.0; // Give time for gi.sound() to finish.
}

//======================================================
void Position_Satellite_Dish(edict_t *ent){
edict_t *dish=NULL;
vec3_t forward;

AngleVectors(ent->s.angles, forward, NULL, NULL);

dish=G_Spawn();
dish->owner=NULL;
dish->activator=ent; // Link to Owner..
dish->movetype=MOVETYPE_TOSS;
dish->clipmask=MASK_SHOT;
dish->solid=SOLID_BBOX;
dish->takedamage=DAMAGE_NO;
dish->s.effects=0;
VectorCopy(ent->s.angles, dish->s.angles);
VectorCopy(ent->s.origin, dish->s.origin);
VectorMA(dish->s.origin, 80, forward, dish->s.origin);
VectorClear(dish->velocity);
VectorSet(dish->mins,-20,-20,0);
VectorSet(dish->maxs, 20, 20,30);
dish->s.modelindex=gi.modelindex("models/objects/satellite/tris.md2");

dish->touch=NULL;
dish->think=Lob_Doggy;
dish->nextthink=level.time + 5.0; // 5 Seconds to Lob time...

gi.linkentity(dish);
}

//==========================================================
void Cmd_Ratapult(edict_t *ent) {
int index;

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

index = ITEM_INDEX(FindItem("cells"));
if (ent->client->pers.inventory[index] < 20){
gi.centerprintf(ent, "Parasite Lobber costs 20 cells!\n");
return; }
else {
ent->client->pers.inventory[index] -= 20;
Position_Satellite_Dish(ent); }
}

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

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

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

bind d "doggy"

That's it!! Lob these puppies into their backyard and
let them KILL THE BASTARDS FOR YOU!

Have Fun!!

philip