home *** CD-ROM | disk | FTP | other *** search
- //=============================================================================
- // Blaze Gun version 1.1
- //
- // 11/27/96 by Jonathan E. Wright <nelno@interpath.com>
- //
- // all original code, not based on anything except the original Quake C
- // code from id software.
- //=============================================================================
-
- // How it works:
- // The flame is simply your basic flame model turned 90 degress on it's side
- // when it is shot. When it impacts something that has health > 0 and DAMAGE_AIM
- // it sets it's location to that entity's origin, and it's next think becomes
- // blaze_stick. blaze_stick is responsible for following the burning entity,
- // checking for water, determining if there is another entity nearby to burn
- // and burning the entity every so often. The time counter for each burn is kept
- // in the flame's attack_finished field, so the entity does not have to be burnt
- // each time the flame follows it. When the entity dies, or the flame is submersed
- // in water the flame is removed and no more damage is done from that flame.
-
- // if you have solid bodies that are respawnable (ie. in the BodyQue) you
- // need to call blaze_switchentity when the bodies are copied or else a
- // respawned entity can come back with flames on it.
-
- /*
- ================
- macros
- ================
- */
- $frame nailatt1 nailatt2
-
- /*
- ================
- function prototypes
- ================
- */
-
- void () player_run;
- void () BecomeExplosion;
- void () SuperDamageSound;
-
- /*
- ================
- global vars
- ================
- */
-
- // keeps track of the number of flames so that a maximum of flames
- // will not be exceeded, causing Quake to bog down
-
- float current_flames;
-
- /*
- ============
- functions
- ============
- */
-
- void () blaze_precache =
- {
- precache_model2 ("progs/flame2.mdl");
- precache_sound2 ("blaze/flhit1.wav");
- precache_sound2 ("blaze/flshot1.wav");
- precache_sound2 ("blaze/flhiss1.wav");
- };
-
- /*
- ===============
- blaze_extinguishentity
-
- called when a respawnable entity is removed without being killed (ie.
- when Cujo is deactivated). Prevents the respawned entity from burning.
- ===============
- */
-
- void (entity old_ent) blaze_extinguishentity =
- {
- local entity head, temp;
-
- head = nextent (world);
-
- while (head)
- {
- head = find (head, classname, "fire");
-
- if ((head != world) && (head.enemy == old_ent))
- {
- temp = nextent (head);
- remove (head);
- head = temp;
- }
- else if (head != world) head = nextent (head);
- }
- };
-
-
- /*
- ===============
- blaze_switchentity
-
- called when an entities corpse is copied to the body que, prevents the
- respawning entity from being still engulfed in flames while the body
- can still burn
- ===============
- */
-
- void (entity old_ent, entity new_ent) blaze_switchentity =
- {
- local entity head;
-
- head = nextent (world);
-
- while (head)
- {
- head = find (head, classname, "fire");
-
- if ((head != world) && (head.enemy == old_ent))
- {
- head.enemy = new_ent;
- setorigin (head, new_ent.origin);
- }
- else if (head != world) head = nextent (head);
- }
- };
-
- /*
- ===============
- blaze_spread
-
- called by blaze_stick.
-
- creates a new flame entity which will stick to and burn entity "fuel"
- ===============
- */
-
- void () blaze_stick;
-
- void (entity fuel) blaze_spread =
- {
- local entity new_flame;
-
- // don't catch the same entity on fire again!
- // don't catch anything that can't take damage
- if ((fuel.takedamage != DAMAGE_AIM) || (current_flames >= 30))
- {
- return;
- }
- else if ((fuel.classname == "player") && (random () > 0.75))
- {
- return;
- }
- else if (random () > 0.5)
- {
- return;
- }
-
- current_flames = current_flames + 1;
-
- if (fuel.classname == "player")
- {
- bprint (fuel.netname);
- bprint (" is on fire!!\n");
- }
- else if (fuel.classname == "cujo")
- sprint (fuel.owner, "Your dog is aflame!!\n");
-
- new_flame = spawn ();
-
- // set the sucker on fire!
- new_flame.enemy = fuel;
- new_flame.solid = SOLID_NOT;
- new_flame.angles_x = 0;
-
- new_flame.movetype = MOVETYPE_NONE;
- new_flame.effects = EF_DIMLIGHT;
- new_flame.takedamage = DAMAGE_NO;
- new_flame.classname = "fire";
- new_flame.targetname = "";
-
- new_flame.think = blaze_stick;
- new_flame.nextthink = time;
-
- // always points back to the player who fired the original flame
- // so monsters get mad at player, not at flames!
- new_flame.owner = self.owner;
-
- setmodel (new_flame, "progs/flame2.mdl");
- setsize (new_flame, '2 2 2', '2 2 2');
- setorigin (new_flame, fuel.origin);
- };
-
- /*
- ===============
- blaze_findfuel
-
- called by blaze_stick
-
- searches for the closest entity within a certain radius. If a qualifying entity is
- found, and a random chance met, the entity is caught on fire by calling blaze_spread.
-
- Notice there is a greater chance for players to be caught on fire, since they tend to
- move around quite a bit more than monsters, and are less likely to remain near a flame
- ===============
- */
-
- void (float dist) blaze_findfuel =
- {
- local entity head;
- local entity fuel;
- local float lastd;
-
- // anything dist units away can catch flame
- head = findradius (self.origin, dist);
- fuel = world;
-
- while (head)
- {
- if ((head != self.enemy) && (head.takedamage == DAMAGE_AIM))
- {
- // find the distance to the current entity, so we can choose the closest
- // entity within the radius
- lastd = vlen (self.origin - head.origin);
- if (lastd < dist)
- {
- fuel = head;
- dist = lastd;
- }
- }
- head = head.chain;
- }
-
- if ((fuel != world) && (random () < 0.1))
- {
- blaze_spread (fuel);
- }
- };
-
- /*
- ===============
- blaze_stick
-
- called every frame as the flame's think function. responsible for control
- the flame once it has attached to an entity -- not in flight from the blaze gun!
-
- checks for water submersion each frame
- ===============
- */
-
- void () burn_entity;
-
- void () blaze_stick =
- {
- local vector org;
- local vector fuelsize, xv, yv, zv;
- local float pc;
- local float average_width;
-
- pc = pointcontents (self.origin);
- if ((pc == CONTENT_WATER) || (pc == CONTENT_SLIME))
- {
- // water extinguished the flame
- sound (self, CHAN_WEAPON, "blaze/flhiss1.wav", 1, ATTN_NORM);
- // reset inflictor so enities don't keep going for water
- self.enemy.dmg_inflictor = self.enemy;
- current_flames = current_flames - 1;
- remove (self);
- return;
- }
-
- // a dead player -- put out the flames before they respawn!
- // changed to flame search in CopyBodyToQue
- /*
- if (self.enemy.deadflag == DEAD_RESPAWNABLE))
- {
- current_flames = current_flames - 1;
- remove (self);
- return;
- }
- */
-
- fuelsize = self.enemy.size;
-
- // it's really the average of x_width and y_width * 2;
- average_width = (fuelsize_x + fuelsize_y) * 0.5;
- blaze_findfuel (average_width);
-
- // make the flames dance, baby! dance!
-
- if (self.enemy.classname == "monster_shambler")
- pc = 0.4;
- else
- pc = 0.1;
-
- fuelsize_x = fuelsize_x * pc * random ();
- if (random () < 0.5)
- fuelsize_x = fuelsize_x * -1;
- fuelsize_y = fuelsize_y * pc * random ();
- if (random () < 0.5)
- fuelsize_y = fuelsize_y * -1;
- fuelsize_z = fuelsize_z * pc * random ();
- if ((random () < 0.5) && (self.enemy.classname != "monster_shambler"))
- fuelsize_z = fuelsize_z * -1;
-
- org = self.enemy.origin + fuelsize;
- setorigin (self, org);
-
- if (self.velocity == '0 0 0') self.avelocity = '0 0 0';
-
- self.think = blaze_stick;
- self.nextthink = time;
-
- // targetname is used as a flag here to determine if the entity
- // has already been determined to be dead and the attack_finished time
- // already increased -- without the flag, the flames won't burn out
- // because the attack_finished time will always be increasing
-
- if ((self.enemy.health <= 0) && (self.targetname == "") &&
- (self.enemy.classname != "monster_zombie"))
- // (self.enemy.classname != "player"))
- {
- self.attack_finished = 7 * random () + time;
- self.targetname = "already_dead";
- // bprint (self.enemy.classname);
- // bprint (" is dead and burning\n");
- }
-
- if (self.attack_finished <= time) burn_entity ();
- };
-
- /*
- ===============
- burn_entity -- called by the flame
-
- called each time attack_finished <= time, currently every second
- responsible for damaging the entity the flame is attached to
-
- zombies are a special case and recieve quite a bit more damage than
- a normal monster or player so that a few flames and sometimes a single
- flame, can gib them
- ===============
- */
-
- void () burn_entity =
- {
- if ((self.enemy.health <= 0) || (self.enemy.deadflag == DEAD_RESPAWNABLE))
- {
- current_flames = current_flames - 1;
- remove (self);
- return;
- }
-
- if (self.enemy.classname != "monster_zombie")
- T_Damage (self.enemy, self, self.owner, 6 * random () + 1);
- else
- T_Damage (self.enemy, self, self.owner, 50 * random () + 10);
-
- if (self.enemy.classname == "player")
- centerprint (self.enemy, "You're on fire!\nFind some water!");
-
- // self.think = blaze_stick;
- // self.nextthink = time;
- self.attack_finished = time + 1;
- };
-
- /*
- ===============
- blaze_watercheck
-
- called as the flame's thin function from the time it is fired until it hits
- and is removed or catches and entity on fire
- ===============
- */
-
- void() blaze_watercheck =
- {
- local float pc;
-
- pc = pointcontents (self.origin);
- if ((pc == CONTENT_WATER) || (pc == CONTENT_SLIME) || (self.attack_finished <= time))
- {
- sound (self, CHAN_WEAPON, "blaze/flhiss1.wav", 1, ATTN_NORM);
- // reset inflictor so enities don't keep going for water
- remove (self);
-
- // make the little grey particles
- WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
- WriteByte (MSG_BROADCAST, TE_GUNSHOT);
- WriteCoord (MSG_BROADCAST, self.origin_x);
- WriteCoord (MSG_BROADCAST, self.origin_y);
- WriteCoord (MSG_BROADCAST, self.origin_z);
-
- return;
- }
-
- self.think = blaze_watercheck;
- self.nextthink = time;
- };
-
- /*
- ===============
- blaze_touch
-
- the touch function of an in-flight flame. responsible for setting an
- entity aflame when it hits it (if the random chance is met)
- ===============
- */
-
- void() blaze_touch =
- {
- local vector org;
- local float pc;
-
- pc = pointcontents (self.origin);
- if (pc == CONTENT_SKY)
- {
- remove (self);
- return;
- }
- else if ((pc == CONTENT_WATER) || (pc == CONTENT_SLIME))
- {
- remove (self);
- return;
- }
-
- sound (self, CHAN_WEAPON, "blaze/flhit1.wav", 1, ATTN_NORM);
-
- org = self.origin - 8*normalize(self.velocity);
-
- if ((other.health) && (other.takedamage == DAMAGE_AIM))
- T_Damage (other, self, self.owner, 15);
- else
- {
- // makes a little debris appear for one frame
- WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
- WriteByte (MSG_BROADCAST, TE_GUNSHOT);
- WriteCoord (MSG_BROADCAST, org_x);
- WriteCoord (MSG_BROADCAST, org_y);
- WriteCoord (MSG_BROADCAST, org_z);
- }
-
- // does some radius damage, < 1/3 that of a rocket
- T_RadiusDamage (self, self.owner, 35, other);
-
- // debugging purposes
- /*
- bprint ("health=");
- bprint (ftos (other.health));
- if (other.takedamage == DAMAGE_AIM)
- bprint (", DAMAGE_AIM\n");
- else
- bprint (", no damage\n");
- */
- if ((other.health) && (other.takedamage == DAMAGE_AIM))
- {
- if ((random () < 0.6) && (current_flames < 30))
- {
- // set the sucker on fire!
- self.enemy = other;
- // used for debugging deathmatch respawns
- // self.enemy = self.owner;
- self.solid = SOLID_NOT;
- self.movetype = MOVETYPE_NONE;
- self.origin = self.enemy.origin;
- self.think = blaze_stick;
- self.nextthink = time;
- self.attack_finished = time + 1;
- self.classname = "fire";
- self.targetname = "";
- // point flame upright
- self.angles_x = 0;
- current_flames = current_flames + 1;
-
- return;
- }
- }
-
- BecomeExplosion ();
- };
-
-
- /*
- ===============
- blaze_launch
-
- the main firing routine, determines where the flame shoots from and where it will
- go to, determines it's velocity, etc.
- ===============
- */
-
- void(float ox) blaze_launch =
- {
- local entity old;
- local vector start, finish, dir;
- local float pc;
-
- start = self.origin + '0 0 16' + v_right*ox;
-
- makevectors (self.v_angle);
-
- if (self.ammo_nails < 1)
- {
- self.weapon = W_BestWeapon ();
- W_SetCurrentAmmo ();
- return;
- }
-
- self.currentammo = self.ammo_nails = self.ammo_nails - 1;
- makevectors (self.v_angle); // is this still used
-
- finish = start + v_forward*600;
- dir = finish - start;
-
- // launch the flame
- sound (self, CHAN_WEAPON, "blaze/flshot1.wav", 1, ATTN_NORM);
-
- dir = normalize(dir);
-
- newmis = spawn();
- newmis.owner = self;
- newmis.movetype = MOVETYPE_TOSS;
- newmis.solid = SOLID_BBOX;
- newmis.effects = EF_DIMLIGHT;
- newmis.takedamage = DAMAGE_NO;
- newmis.classname = "blaze_shot";
-
- setmodel (newmis, "progs/flame2.mdl");
- setsize (newmis, '2 2 2', '2 2 2');
-
- setorigin (newmis, start);
-
- // add player's velocity to the flames velocity for maximum effect
- newmis.velocity = (self.velocity * 0.5) + (dir * 1000);
- newmis.angles = vectoangles(newmis.velocity);
- // turn the flame on it's side, widest end away from player
- newmis.angles_x = newmis.angles_x + 90;
-
- // give the player a little kickback
- self.velocity = self.velocity - (dir * 125);
-
- // will burn for 8 seconds
- newmis.attack_finished = time + 8;
- // continously check for water
- newmis.nextthink = time + 0.1;
- newmis.think = blaze_watercheck;
- newmis.touch = blaze_touch;
-
- // launch_flame (start, dir);
- self.punchangle_x = -2;
- };
-
- void () blaze_attack1 = [$nailatt1, blaze_attack2]
- {
- self.effects = self.effects | EF_MUZZLEFLASH;
-
- if (!self.button0)
- {
- player_run ();
- return;
- }
-
- self.weaponframe = self.weaponframe + 1;
- if (self.weaponframe == 9) self.weaponframe = 1;
-
- SuperDamageSound();
-
- blaze_launch (4);
-
- self.attack_finished = time + 0.2;
- };
-
- //============================================================================
-
- void () blaze_attack2 = [$nailatt1, blaze_attack3]
- {
- if (!self.button0)
- {
- player_run ();
- return;
- }
-
- self.weaponframe = self.weaponframe + 1;
- if (self.weaponframe == 9) self.weaponframe = 1;
-
- self.attack_finished = time + 0.2;
- };
-
- //============================================================================
-
- void () blaze_attack3 = [$nailatt2, blaze_attack4]
- {
- self.effects = self.effects | EF_MUZZLEFLASH;
-
- if (!self.button0)
- {
- player_run ();
- return;
- }
-
- self.weaponframe = self.weaponframe + 1;
- if (self.weaponframe == 9) self.weaponframe = 1;
-
- SuperDamageSound();
-
- blaze_launch (-4);
-
- self.attack_finished = time + 0.2;
- };
-
- //============================================================================
-
- void () blaze_attack4 = [$nailatt2, blaze_attack1]
- {
- if (!self.button0)
- {
- player_run ();
- return;
- }
-
- self.weaponframe = self.weaponframe + 1;
- if (self.weaponframe == 9) self.weaponframe = 1;
-
- self.attack_finished = time + 0.2;
- };
-