
Quake DeveLS - BFG -Suit
Author: Anozireth
Difficulty: Medium
Time for
some carnage...
This patch will give the
player a "BFG suit" when they pick up the power armor. Basically, it
puts the player inside the BFG ball and beams emeinate from him to anything
they can damage. The bfg_armor_think function is largely based on the original
bfg_think. also, whem the player is inside the ball, their screen will be
tinted green.
First, lets put the two
main functions, bfg_armor_think and Use_BFGArmor in place. In g_weapon.c, at
the end of the file add:
/*======================================================================BFG Armor This will be a bitch....======================================================================*/ //self is bfg ballvoid bfg_armor_think (edict_t *self){// This function is just bfg_think with some small changes// after all, this is supposed to behave like da bfg edict_t *ent; edict_t *ignore; vec3_t point; vec3_t dir; vec3_t start; vec3_t end; int dmg; trace_t tr; if(self->bfg_armor_done < level.time) { self->owner->client->bfg_blend = 0; G_FreeEdict(self); return; } dmg = 15; VectorCopy (self->owner->s.origin, self->s.origin); // make it look like player is inside ball // Make owner screen a little green (hey, it rhymes!) //SV_AddBlend (0, 1, 0, 0.3, self->owner->client->ps.blend); self->owner->client->bfg_blend = 1; ent = NULL; while ((ent = findradius(ent, self->s.origin, 512)) != NULL) // Make sure we get plenty o bastards { if (ent == self) // kant kill ourselves continue; if (ent == self->owner) // or our master continue; if (!ent->takedamage) // or powerups, medkits etc.. continue; if (!(ent->svflags & SVF_MONSTER) && (!ent->client) && (strcmp(ent->classname, "misc_explobox") != 0)) // If it wont blow up or die, ignore it continue; VectorMA (ent->absmin, 0.5, ent->size, point); VectorSubtract (point, self->s.origin, dir); VectorNormalize (dir); ignore = self; VectorCopy (self->s.origin, start); VectorMA (start, 2048, dir, end); while(1) { tr = gi.trace (start, NULL, NULL, end, ignore, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_DEADMONSTER); if (!tr.ent) break; // hurt it if we can if ((tr.ent->takedamage) && !(tr.ent->flags & FL_IMMUNE_LASER) && (tr.ent != self->owner)) T_Damage (tr.ent, self, self->owner, dir, tr.endpos, vec3_origin, dmg, 1, DAMAGE_ENERGY, MOD_BFG_LASER); // if we hit something that's not a monster or player we're done if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client)) { gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_LASER_SPARKS); gi.WriteByte (4); gi.WritePosition (tr.endpos); gi.WriteDir (tr.plane.normal); gi.WriteByte (self->s.skinnum); gi.multicast (tr.endpos, MULTICAST_PVS); break; } ignore = tr.ent; VectorCopy (tr.endpos, start); } gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_BFG_LASER); gi.WritePosition (self->s.origin); gi.WritePosition (tr.endpos); gi.multicast (self->s.origin, MULTICAST_PHS); } self->nextthink = level.time + FRAMETIME;} void Use_BFGArmor (edict_t *self){// this function is fire_bfg simplifed edict_t *bfg; if(self->client->pers.inventory[ITEM_INDEX(FindItem("cells"))] < 50) return; bfg = G_Spawn(); VectorCopy (self->s.origin, bfg->s.origin); bfg->movetype = MOVETYPE_NONE; bfg->solid = SOLID_NOT; bfg->s.effects |= EF_BFG | EF_ANIM_ALLFAST; bfg->s.modelindex = gi.modelindex ("sprites/s_bfg1.sp2"); bfg->owner = self; bfg->bfg_armor_done = level.time + 1; bfg->nextthink = level.time + FRAMETIME; bfg->think = bfg_armor_think; bfg->classname = "bfg armor blast"; //bfg->s.sound = gi.soundindex ("weapons/bfg__l1a.wav"); gi.linkentity (bfg); self->client->pers.inventory[ITEM_INDEX(FindItem("cells"))] -=50;}
OK, now
that was a lot. Now, here's what they do: bfg_armor_think starts off by placing
the ball at the player origin. It then blends the player's screen a little for
effect. Then, it shoots out all the beams. Use_BFGArmor makes sure you have
enough cells (50), then spawns the ball and subtracts 50 cells.
On to the next step,
picking it up. In g_items.c, around line 19 add:
// BFG suitvoid Use_BFGArmor (edict_t *self); This is just the prototype for the function. Now on line 724 of g_items.c in Pickup_PowerArmor add: other->client->pers.inventory[ITEM_INDEX(FindItem("Bfg armor"))]++; That will give it to us when we get the power armor. Now, to make it an item, on line 1243 add: /*=================BFG armor=================*/ { "item_bfg_armor", Pickup_PowerArmor, Use_BFGArmor, NULL, NULL, "misc/ar3_pkup.wav", "models/items/armor/shield/tris.md2", EF_ROTATE, NULL,/* icon */ "i_powershield",/* pickup */ "BFG Armor",/* width */ 60, 50, "Cells", IT_WEAPON, NULL, 0,/* precache */ "misc/power2.wav misc/power1.wav" },
There, now
it is officially an item. Now, we need a new variable in the gclient_s
structure. so on line 862 of g_local.h insert:
int bfg_blend;
This is a
reference for the screen blending function. Now we need another in the edict
struct, so on line 985add:
float bfg_armor_done;
Now, about
that blend function, in p_view.c at line 422 insert:
// BFG armor if(ent->client->bfg_blend) SV_AddBlend (0, 1, 0, 0.3, ent->client->ps.blend); // BFG armor
This will
give us the green screen so it looks like we're in the ball. OK, you're done!
Go try it out, it practically vaporizes any smaller enemy or poorly armored
foe(after all, it does do 150pts damage/sec.) You can select it like any other
inventory item to use it.
This Tutorial was written
by Tom Nicholson (aka. Anozireth). I
am 15 and live in Seattle, WA.
|
This site, and all
content and graphics displayed on it, |