//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 reload_rocket; // keeps count of rockets fired .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; //decides whether to launch or detonate the shrapnelbomb .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 = vel + 2*trace_plane_normal; vel = 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 = 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 = self.origin - 8*normalize(self.velocity); WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); WriteByte (MSG_BROADCAST, TE_EXPLOSION); WriteCoord (MSG_BROADCAST, self.origin_x); WriteCoord (MSG_BROADCAST, self.origin_y); WriteCoord (MSG_BROADCAST, self.origin_z); remove(self); }; //launch_megaplasma void() launch_megaplasma = { local vector dir; self.currentammo = self.ammo_cells = 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 = 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 = 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 = self.origin - 8*normalize(self.velocity); WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); WriteByte (MSG_BROADCAST, TE_EXPLOSION); WriteCoord (MSG_BROADCAST, self.origin_x); WriteCoord (MSG_BROADCAST, self.origin_y); WriteCoord (MSG_BROADCAST, self.origin_z); BecomeExplosion (); }; /* ================ W_FirePball ================ */ void() W_FirePball = { self.currentammo = self.ammo_rockets = self.ammo_rockets - 1; sound (self, CHAN_AUTO, "weapons/ssgrnde.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* -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); WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); WriteByte (MSG_BROADCAST, TE_EXPLOSION); WriteCoord (MSG_BROADCAST, self.origin_x); WriteCoord (MSG_BROADCAST, self.origin_y); WriteCoord (MSG_BROADCAST, self.origin_z); remove (self); }; /* ================ MineExplode ================ */ //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"; self.nextthink = time + random()*0.15; //gives a more organic explosion when multiple mines explode at once self.owner = self.lastowner; self.think = M_DamExplode; }; /* ================ MineTouch ================ */ 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; }; /* ================ MineArm ================ */ 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; }; /* ================ W_FireMine ================ */ void() W_FireMine = { self.currentammo = self.ammo_rockets = self.ammo_rockets - 1; sound (self, CHAN_AUTO, "weapons/ssgrnde.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) { WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); WriteByte (MSG_BROADCAST, TE_SPIKE); WriteCoord (MSG_BROADCAST, self.origin_x); WriteCoord (MSG_BROADCAST, self.origin_y); WriteCoord (MSG_BROADCAST, self.origin_z); 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 = v_z - (v_z*2); v = 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 = { //POX v1.11 if (self.voided) return; self.voided = 1; //Toss the nails (this function is with the spike stuff since it uses the same touch) //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 WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); WriteByte (MSG_BROADCAST, TE_EXPLOSION); WriteCoord (MSG_BROADCAST, self.origin_x); WriteCoord (MSG_BROADCAST, self.origin_y); WriteCoord (MSG_BROADCAST, self.origin_z); 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 //============================================================================= /* ================ W_FireShrapnel ================ */ void() W_FireShrapnel = { self.ammo_rockets = self.ammo_rockets - 1; self.currentammo = self.ammo_nails = self.ammo_nails - 30; sound (self, CHAN_WEAPON, "weapons/grenade.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_WEAPON, "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) { //already primed if (self.prime_tshot == TRUE) SUB_Null (); //not enough ammo else if (self.ammo_shells < 3) { 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 } } // check for rhino reload if (self.weapon == IT_ROCKET_LAUNCHER) { //already reloaded if (self.reload_rocket == 0) SUB_Null (); //if no rockets go away else if (self.ammo_rockets < 1) { 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_WEAPON, "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_WEAPON, "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_WEAPON, "weapons/mfire1.wav", 1, ATTN_NORM); } else if (self.st_mine < time) { 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_WEAPON, "weapons/mfire1.wav", 1, ATTN_NORM); } self.impulse = 0; };