game-source/ParoxysmII/source/nq/sectrig.qc
2004-02-12 05:38:54 +00:00

841 lines
21 KiB
C++

//POX v1.1 - seperated second trigger stuff from weapons.qc to clean it up a bit.
//Re-wrote some stuff before applying the new weapons to POXworld
//POX v1.1 moved prototypes from weapons.qc for use here
void (entity targ, entity inflictor, entity attacker, float damage) T_Damage;
void () player_run;
void (entity bomb, entity attacker, float rad, entity ignore) T_RadiusDamage;
void (vector org, vector vel, float damage) SpawnBlood;
void () SuperDamageSound;
void (float shotcount, vector dir, vector spread) FireBullets2;
void (entity who,float damage) spawn_touchblood;
void (float weapon, entity me) getmodel; // VisWeap MOD: prototype this here, so W_SetCurrentAmmo can use it.
//void(float teem) create_bot; //add bot function
//void() bot_missile_think; //New missile think for bots (bug fix)
.float no_obj; //fixes problem with 'hanging' mines on breakable objects destroyed by something else
.float saw_on; //helps keep track of which BoneSaw animation to play
float SECOND_TRIGGER = 15; // Impulse constant for second trigger (more readable than 15)
.float st_rocketload; // used to time out the rhino's trigger during reload
.float prime_tshot; // this bit is set when the t-shot is primed for a triple barrel fire
.float st_tshotload; // used to time out the t-shot's trigger during reload
//.float shrap_detonate; //pOx - 1.4 - moved to bot_pox.qc
.float shrap_time; //holds the bombs time out (2 minutes then boom) - just in case owner died
void(vector org) launch_shrapnel; //Predeclare
void() player_shot1;
void() player_gshot1;
void() player_plasma1;
void() player_plasma2;
void() player_mplasma1;
void() player_nail1;
void() player_rocket1;
void() player_rocketload1;
void() player_grenade1;
void() player_reshot1;
void() player_tshot1;
void() player_shrap1;
void() player_bonesaw1;
void() player_bonesaw3;
//Some nitty-gritty from weapons.qc ...
float() crandom =
{
return 2 * (random () - 0.5);
};
vector() wall_velocity =
{
local vector vel;
vel = normalize (self.velocity);
vel = normalize (vel + v_up * (random () - 0.5)
+ v_right * (random () - 0.5));
vel += 2 * trace_plane_normal;
vel *= 200;
return vel;
};
void() s_explode1 = [0, s_explode2] {};
void() s_explode2 = [1, s_explode3] {};
void() s_explode3 = [2, s_explode4] {};
void() s_explode4 = [3, s_explode5] {};
void() s_explode5 = [4, s_explode6] {};
void() s_explode6 = [5, SUB_Remove] {};
void() BecomeExplosion =
{
self.movetype = MOVETYPE_NONE;
self.velocity = '0 0 0';
self.touch = SUB_Null;
setmodel (self, "progs/s_explod.spr");
self.solid = SOLID_NOT;
s_explode1 ();
};
/*
================
Triple Barrel Shot for T-shot
Close Range Gibber - long range spread
================
*/
void() W_FireTShot =
{
local vector dir;
sound (self ,CHAN_WEAPON, "weapons/ts3fire.wav", 1, ATTN_NORM);
self.punchangle_x = -4;
//Added weapon kickback (as long as you're not in mid air)
if (self.flags & FL_ONGROUND)
self.velocity = self.velocity + v_forward * -80;
self.currentammo = self.ammo_shells -= 3;
dir = aim (self, 100000);
//POX - 1.01b2 - increased spread, reduced amount
//POX - 1.1 - made FireBullets2 (twice the damge, half the pellets + 1 :)
FireBullets2 (12, dir, '0.16 0.1 0'); //make priming this thing worth while!
};
//=============================================================================
//Start MegaPlasmaBurst - Used by PlasmaGun's Second Trigger
//=============================================================================
void() T_MplasmaTouch =
{
local float damg;
if (other == self.owner)
return; // don't explode on owner
//POX v1.11
if (self.voided)
return;
self.voided = 1;
if (pointcontents (self.origin) == CONTENT_SKY) {
remove (self);
return;
}
damg = 120 + random () * 20;
T_RadiusDamage (self, self.owner, damg, world);
sound (self, CHAN_WEAPON, "weapons/mplasex.wav", 1, ATTN_NORM);
self.origin -= 8 * normalize (self.velocity);
WriteBytes (MSG_BROADCAST, SVC_TEMPENTITY, TE_EXPLOSION);
WriteCoordV (MSG_BROADCAST, self.origin);
remove (self);
};
//launch_megaplasma
void() launch_megaplasma =
{
local vector dir;
self.currentammo = self.ammo_cells -= 9;
sound (self, CHAN_WEAPON, "weapons/mplasma.wav", 1, ATTN_NORM);
self.punchangle_x = -8;
//Added weapon kickback (as long as you're not in mid air)
if (self.flags & FL_ONGROUND)
self.velocity += v_forward * -270;
newmis = spawn ();
newmis.voided = 0;
newmis.owner = self;
newmis.movetype = MOVETYPE_FLYMISSILE;
newmis.solid = SOLID_BBOX;
newmis.classname = "megaplasma";
newmis.effects |= EF_BRIGHTFIELD | EF_BRIGHTLIGHT;
// set speed
dir = aim (self, 1000);
newmis.velocity = dir * 0.01;
newmis.avelocity = '300 300 300';
newmis.angles = vectoangles (newmis.velocity);
newmis.velocity = normalize (newmis.velocity);
newmis.velocity *= 950;
newmis.touch = T_MplasmaTouch;
// set duration
newmis.think = SUB_Remove;
newmis.nextthink = time + 5;
setmodel (newmis, "progs/plasma.mdl");
setsize (newmis, '0 0 0', '0 0 0');
setorigin (newmis, self.origin + v_forward * 12 + '0 0 12');
};
//End MegaPlasmaBurst
//=============================================================================
//=============================================================================
//
// START PumkinBall CODE - Used by SuperShotgun's Second Trigger (Impact Grenades)
//
//=============================================================================
void() T_PballTouch =
{
local float damg;
if (other == self.owner)
return; // don't explode on owner
//POX v1.11
if (self.voided)
return;
self.voided = 1;
if (pointcontents (self.origin) == CONTENT_SKY) {
remove (self);
return;
}
damg = 100 + random () * 20;
T_RadiusDamage (self, self.owner, damg, world);
// sound (self, CHAN_WEAPON, "weapons/r_exp3.wav", 1, ATTN_NORM);
self.origin -= 8 * normalize (self.velocity);
WriteBytes (MSG_BROADCAST, SVC_TEMPENTITY, TE_EXPLOSION);
WriteCoordV (MSG_BROADCAST, self.origin);
BecomeExplosion ();
};
/*
================
W_FirePball
================
*/
void() W_FirePball =
{
self.currentammo = --self.ammo_rockets;
sound (self, CHAN_AUTO, "weapons/gren2.wav", 1, ATTN_NORM);
self.punchangle_x = -4;
//Added weapon kickback (as long as you're not in mid air)
if (self.flags & FL_ONGROUND)
self.velocity += v_forward * -150;
newmis = spawn ();
newmis.voided = 0;
newmis.owner = self;
newmis.movetype = MOVETYPE_TOSS;
newmis.solid = SOLID_BBOX;
newmis.classname = "impactgrenade";
// set newmis speed
makevectors (self.v_angle);
newmis.velocity = v_forward * 700 + v_up * 200 + crandom () * v_right * 10
+ crandom () * v_up * 10;
newmis.angles = vectoangles (newmis.velocity);
newmis.touch = T_PballTouch;
// set newmis duration
newmis.nextthink = time + 2.5;
setmodel (newmis, "progs/grenade.mdl");
setsize (newmis, '0 0 0', '0 0 0');
setorigin (newmis, self.origin + v_forward*4);
};
// END PumkinBall CODE
//=============================================================================
//=============================================================================
//
// START MINE CODE (based on hipnotic's proximity mine - uh... hacked to death)
// Used for the Grenade Launcher's Second Trigger
// This is some laughable, sick code
// But it works.
//
//=============================================================================
void() M_DamExplode =
{
//POX v1.11
if (self.voided)
return;
self.voided = 1;
T_RadiusDamage (self, self.owner, 95, world);
WriteBytes (MSG_BROADCAST, SVC_TEMPENTITY, TE_EXPLOSION);
WriteCoordV (MSG_BROADCAST, self.origin);
remove (self);
};
//explode imediately! (for doors, plats and breakable objects
void() MineImExplode =
{
self.takedamage = DAMAGE_NO;
self.deathtype = "exploding";
self.owner = self.lastowner;
M_DamExplode ();
};
void() MineExplode =
{
self.takedamage = DAMAGE_NO;
self.deathtype = "exploding";
// gives a more organic explosion when multiple mines explode at once
self.nextthink = time + random () * 0.15;
self.owner = self.lastowner;
self.think = M_DamExplode;
};
void() MineTouch =
{
if (other == self) {
return;
}
if (other.solid == SOLID_TRIGGER) {
sound (self, CHAN_AUTO, "weapons/bounce.wav", 1, ATTN_NORM);
return;
}
if (other.classname == "grenade") {
sound (self, CHAN_AUTO, "weapons/bounce2.wav", 1, ATTN_NORM);
self.nextthink = time + 1;
return;
}
if (other.classname == "mine") {
sound (self, CHAN_AUTO, "weapons/bounce2.wav", 1, ATTN_NORM);
self.nextthink = time + 1;
return;
}
if (other.classname == "minearm") {
sound (self, CHAN_AUTO, "weapons/bounce2.wav", 1, ATTN_NORM);
self.nextthink = time + 1;
return;
}
if (other.classname == "minearmed") {
sound (self, CHAN_AUTO, "weapons/bounce.wav", 1, ATTN_NORM);
self.classname = "minearm";
self.nextthink = time + 1;
return;
}
if (other.classname == "player" || other.classname == "bot") {
sound (self, CHAN_BODY, "weapons/minedet.wav", 1, ATTN_NORM);
MineExplode ();
self.nextthink = time + 0.4;
return;
}
if (other.takedamage == DAMAGE_AIM){
MineExplode ();
self.think ();
return;
}
self.movetype = MOVETYPE_NONE;
self.classname = "minearm";
self.spawnmaster = other;
self.nextthink = time + 0.1;
};
void() MineArm =
{
local entity head;
local float detonate;
if (self.classname == "minearm") {
sound (self, CHAN_WEAPON, "weapons/armed.wav", 1, ATTN_NORM);
setsize (self, '-3 -3 -3', '3 3 3');
self.owner = world;
self.takedamage = DAMAGE_YES;
self.skin = 1;
self.classname = "minearmed";
self.effects |= EF_MUZZLEFLASH;
}
if ((time > self.delay) || (self.spawnmaster.no_obj == TRUE)) {
sound (self, CHAN_BODY, "weapons/minedet.wav", 1, ATTN_NORM);
MineImExplode ();
// self.nextthink = time + 0.4;
return;
}
// No click or delay when velocity triggers mine (so they don't float when doors open)
// Although the 'organic' explosion' part in the detonate code might leave it hanging...
if (vlen(self.spawnmaster.velocity) > 0) {
MineImExplode ();
return;
}
// Mines explode on touch, but for some reason most monsters don't detonate them (?)
// So had to use a findradius function to look for monsters, it's a small radius though
// Ogres still don't always detonate mines (?)
head = findradius (self.origin, 39);
detonate = 0;
if (self.health < 0)
detonate = 1;
while (head) {
if ((head != self) && (head.health > 0)
&& ((head.flags & (FL_CLIENT|FL_MONSTER))
|| (head.classname == "bot"))
&& (head.classname != self.classname)) {
detonate = 1;
}
traceline (self.origin, head.origin, TRUE, self);
if (trace_fraction != 1.0)
detonate = 0;
if (detonate==1) {
sound (self, CHAN_BODY, "weapons/minedet.wav", 1, ATTN_NORM);
MineExplode ();
self.nextthink = time + 0.25; //POX v1.11 reduced getaway time
return;
}
head = head.chain;
}
self.nextthink = time + 0.1;
};
void() W_FireMine =
{
self.currentammo = --self.ammo_rockets;
sound (self, CHAN_AUTO, "weapons/gren.wav", 1, ATTN_NORM);
self.punchangle_x = -2;
//Added weapon kickback (as long as you're not in mid air)
if (self.flags & FL_ONGROUND)
self.velocity = self.velocity + v_forward * -100;
newmis = spawn ();
newmis.voided = 0;
newmis.owner = self;
newmis.lastowner = self;
newmis.movetype = MOVETYPE_TOSS;
newmis.solid = SOLID_BBOX;
newmis.classname = "mine";
newmis.takedamage = DAMAGE_NO;
newmis.health = 1;
//POX v1.2 - mines don't bleed....
newmis.nobleed = TRUE;
// set missile speed
makevectors (self.v_angle);
if (self.v_angle_x)
newmis.velocity = v_forward * 600 + v_up * 200
+ crandom () * v_right * 10 + crandom () * v_up * 10;
else {
newmis.velocity = aim (self, 10000);
newmis.velocity = newmis.velocity * 600;
newmis.velocity_z = 200;
}
newmis.avelocity = '100 600 100';
newmis.angles = vectoangles (newmis.velocity);
newmis.touch = MineTouch;
// set missile duration
newmis.nextthink = time + 0.2;
newmis.delay = time + 15;
newmis.think = MineArm;
newmis.th_die = MineExplode;
setmodel (newmis, "progs/grenade.mdl");
setorigin (newmis, self.origin + v_forward*4);
setsize (newmis, '-1 -1 -1', '0 0 0');
};
// END MINE CODE
//=============================================================================
//=============================================================================
//
// Shrapnel Bomb - Nailgun Second Trigger (1 rocket + 30 nails, remotely detonated)
//
//=============================================================================
//----------------------------------------------------------
//These functions launch a single spike in a random direction
void() spikenal_touch =
{
// if (other.solid == SOLID_TRIGGER)
// return; // trigger field, do nothing
if (pointcontents(self.origin) == CONTENT_SKY) {
remove (self);
return;
}
//POX v1.11
if (self.voided)
return;
self.voided = 1;
// hit something that bleeds
if (other.takedamage) {
spawn_touchblood (other, 9);
T_Damage (other, self, self.owner, 12);
remove (self);
} else if (random () > 0.9) {
WriteBytes (MSG_BROADCAST, SVC_TEMPENTITY, TE_SPIKE);
WriteCoordV (MSG_BROADCAST, self.origin);
remove (self);
}
};
//POX - Get a random vector for Shrapnel
vector() VelocityForShrapnel =
{
local vector v;
v_x = 200 * crandom ();
v_y = 200 * crandom ();
v_z = 200 * crandom ();
if (random () > 0.5)
v_z *= -1;
v *= 6;
return v;
};
//POX - Shrapnel = fast, bouncy spikes with a short life
void(vector org) launch_shrapnel =
{
newmis = spawn ();
newmis.owner = self.owner;
newmis.voided = 0;
newmis.movetype = MOVETYPE_BOUNCE;
newmis.solid = SOLID_BBOX;
newmis.touch = spikenal_touch;
newmis.classname = "spikenal";
newmis.velocity = VelocityForShrapnel ();
newmis.avelocity_x = random () * 800;
newmis.avelocity_y = random () * 800;
newmis.avelocity_z = random () * 800;
newmis.think = SUB_Remove;
newmis.nextthink = time + 3;
setmodel (newmis, "progs/mwrub1.mdl");
setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
setorigin (newmis, org);
};
//----------------------------------------------------------
//and now the bomb code...
void() ShrapnelExplode =
{
local float n;
//POX v1.11
if (self.voided)
return;
self.voided = 1;
//POX - 1.0b1 - A LOT less Shrapnel!
launch_shrapnel (self.origin);
launch_shrapnel (self.origin);
launch_shrapnel (self.origin);
launch_shrapnel (self.origin);
launch_shrapnel (self.origin);
T_RadiusDamage (self, self.owner, 160, world);
if (self.owner != world)
self.owner.shrap_detonate = FALSE;//Enable next launch
WriteBytes (MSG_BROADCAST, SVC_TEMPENTITY, TE_EXPLOSION);
WriteCoordV (MSG_BROADCAST, self.origin);
BecomeExplosion ();
};
void() ShrapnelDetonate =
{
sound (self, CHAN_BODY, "weapons/minedet.wav", 1, ATTN_NORM);
self.think = ShrapnelExplode;
self.nextthink = time + 0.1;
};
//Wait for a detonation impulse or time up
void() ShrapnelThink =
{
if (self.shrap_time < time)
ShrapnelDetonate();
if (self.owner == world)
return;
// Owner died so change to world and wait for detonate
if (self.owner.health <= 0) {
self.owner.shrap_detonate = FALSE;//Enable next launch
self.owner = world;
self.nextthink = self.shrap_time;
self.think = ShrapnelDetonate;
return;
}
if (self.owner.shrap_detonate == 2)
ShrapnelDetonate ();
else
self.nextthink = time + 0.1;
};
void() ShrapnelTouch =
{
local float r;
r = random ();
if (other == self.owner)
return; // don't explode on owner
if (other.takedamage == DAMAGE_AIM) {
ShrapnelDetonate ();
return;
}
//pick a bounce sound
if (r < 0.75)
sound (self, CHAN_VOICE, "weapons/bounce.wav", 1, ATTN_NORM);
else
sound (self, CHAN_VOICE, "weapons/bounce2.wav", 1, ATTN_NORM);
if (self.velocity == '0 0 0')
self.avelocity = '0 0 0';
};
// End shrapnel bomb
//=============================================================================
void() W_FireShrapnel =
{
self.ammo_rockets--;
self.currentammo = self.ammo_nails -= 30;
sound (self, CHAN_WEAPON, "weapons/gren2.wav", 1, ATTN_NORM);
self.punchangle_x = -7;
// Added weapon kickback (as long as you're not in mid air)
if (self.flags & FL_ONGROUND)
self.velocity = self.velocity + v_forward * -115;
newmis = spawn ();
newmis.voided = 0;
newmis.owner = self;
newmis.movetype = MOVETYPE_BOUNCE;
newmis.solid = SOLID_BBOX;
newmis.classname = "shrapnel";
newmis.shrap_time = time + 120;
// set newmis speed
makevectors (self.v_angle);
if (self.v_angle_x) {
newmis.velocity = v_forward * 600 + v_up * 200
+ crandom () * v_right * 10 + crandom () * v_up * 10;
} else {
newmis.velocity = aim (self, 10000);
newmis.velocity = newmis.velocity * 600;
newmis.velocity_z = 200;
}
newmis.avelocity = '300 300 300';
newmis.angles = vectoangles(newmis.velocity);
newmis.touch = ShrapnelTouch;
// set newmis duration
newmis.nextthink = time + 0.1;
newmis.think = ShrapnelThink;
setmodel (newmis, "progs/grenade.mdl");
newmis.skin = 2;
setsize (newmis, '0 0 0', '0 0 0');
setorigin (newmis, self.origin);
};
/*
============
W_SecondTrigger
Second Trigger Impulses
POX v1.1 - seperated this from weapons.qc - cleaned it up a bit
============
*/
void() W_SecondTrigger =
{
// check for NailGun's second Trigger
if (self.weapon == IT_SUPER_NAILGUN) {
if (!self.shrap_detonate) { // Check if a bomb is already set
// check for nails and rockets
if ((self.ammo_nails < 30) || (self.ammo_rockets < 1)) {
sound (self, CHAN_AUTO, "weapons/mfire1.wav", 1, ATTN_NORM);
sprint (self, "Not enough ammo...\n");
} else if (self.st_shrapnel < time) {
self.weaponframe = 0;
SuperDamageSound ();
self.st_shrapnel = time + 0.1; // Allow a fast detonate
player_shrap1 ();
W_FireShrapnel ();
self.shrap_detonate = TRUE;
} else {
sound (self, CHAN_AUTO, "weapons/mfire1.wav", 1, ATTN_NORM);
}
} else {
sound (self, CHAN_AUTO, "weapons/shrapdet.wav", 1, ATTN_NORM);
SuperDamageSound ();
self.st_shrapnel = time + 0.7; // Time out before next launch
self.shrap_detonate = 2; //Tell the bomb to blow!
}
}
// check for t-shot prime
if (self.weapon == IT_TSHOT) {
if (self.prime_tshot == TRUE) { // already primed
SUB_Null ();
} else if (self.ammo_shells < 3) { // not enough ammo
SUB_Null ();
} else {
self.st_tshotload = time + 0.9; //give the reload a chance to happen
// make a reload sound!
sound (self, CHAN_WEAPON, "weapons/tsload.wav", 1, ATTN_NORM);
player_reshot1 (); // play prime animation
self.prime_tshot = TRUE; //set the prime bit
}
}
if (self.weapon == IT_ROCKET_LAUNCHER) { // check for rhino reload
if (self.reload_rocket == 0) { // already reloaded
SUB_Null;
} else if (self.ammo_rockets < 1) { // if no rockets go away
SUB_Null;
} else {
self.st_rocketload = time + 0.6; //give the reload a chance to happen
sound (self, CHAN_WEAPON, "weapons/rhinore.wav", 1, ATTN_NORM);
player_rocketload1 (); //play reload animation
self.reload_rocket = 0; //reset reload bit
}
}
// check for Plasmagun second Trigger
if (self.weapon == IT_PLASMAGUN) {
// check for cells
if (self.ammo_cells < 9) {
sound (self, CHAN_AUTO, "weapons/mfire2.wav", 1, ATTN_NORM);
} else if (self.st_mplasma < time) {
if (self.waterlevel > 1) { //explode under water
sound (self, CHAN_WEAPON, "weapons/mplasex.wav", 1, ATTN_NORM);
self.ammo_cells = 0;
W_SetCurrentAmmo ();
T_RadiusDamage (self, self, 250, world);
return;
}
self.weaponframe = 0;
SuperDamageSound ();
self.st_mplasma = time + 1.9;
player_mplasma1 ();
launch_megaplasma ();
} else {
SUB_Null;
}
}
// check for Super Shotgun second Trigger
if (self.weapon == IT_COMBOGUN) {
// check for rockets
if (self.ammo_rockets < 1) {
self.items &= ~(IT_SHELLS);
self.items |= IT_ROCKETS;
self.currentammo = self.ammo_rockets;
self.which_ammo = 1;
sound (self, CHAN_AUTO, "weapons/mfire1.wav", 1, ATTN_NORM);
} else if (self.st_pball < time) {
self.items &= ~(IT_SHELLS);
self.items |= IT_ROCKETS;
self.currentammo = self.ammo_rockets;
self.which_ammo = 1;
player_gshot1 ();
SuperDamageSound ();
W_FirePball ();
self.st_pball = time + 0.9;
} else {
sound (self, CHAN_AUTO, "weapons/mfire1.wav", 1, ATTN_NORM);
}
}
// check for GrenadeLauncher second Trigger
if (self.weapon == IT_GRENADE_LAUNCHER) {
// check for rockets
if (self.ammo_rockets < 1) {
sound (self, CHAN_AUTO, "weapons/mfire1.wav", 1, ATTN_NORM);
} else if ((self.st_mine < time) && (self.st_grenade < time)) {
//pOx 1.4 - combine timeouts for mines & grenades
player_grenade1 ();
W_FireMine ();
// big delay between refires helps keep the # of mines down in a deathmatch game
self.st_mine = time + 1.25;
} else {
sound (self, CHAN_AUTO, "weapons/mfire1.wav", 1, ATTN_NORM);
}
}
self.impulse = 0;
};