aboutsummaryrefslogtreecommitdiffstats
path: root/qw-qc/weapons.qc
diff options
context:
space:
mode:
authorTravis Bradshaw <travis.bradshaw@idsoftware.com>2012-01-31 16:03:17 -0600
committerTravis Bradshaw <travis.bradshaw@idsoftware.com>2012-01-31 16:03:17 -0600
commitbf4ac424ce754894ac8f1dae6a3981954bc9852d (patch)
treeff4a31bc2a3ae18eb8fa5bbca9a9bab90f0d11ab /qw-qc/weapons.qc
parent0023db327bc1db00068284b70e1db45857aeee35 (diff)
downloadquake-pum-bf4ac424ce754894ac8f1dae6a3981954bc9852d.tar.gz
Just kind of shoving the QuakeWorld QuakeC source in here.
Diffstat (limited to 'qw-qc/weapons.qc')
-rw-r--r--qw-qc/weapons.qc1427
1 files changed, 1427 insertions, 0 deletions
diff --git a/qw-qc/weapons.qc b/qw-qc/weapons.qc
new file mode 100644
index 0000000..7d3dde8
--- /dev/null
+++ b/qw-qc/weapons.qc
@@ -0,0 +1,1427 @@
+/*
+ weapons.qc
+
+ weapon and weapon hit functions
+
+ Copyright (C) 1996-1997 Id Software, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to:
+
+ Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330
+ Boston, MA 02111-1307, USA
+
+*/
+
+void (entity targ, entity inflictor, entity attacker, float damage) T_Damage;
+void () player_run;
+void(entity bomb, entity attacker, float rad, entity ignore, string dtype) T_RadiusDamage;
+void(vector org, float damage) SpawnBlood;
+void() SuperDamageSound;
+
+
+// called by worldspawn
+void() W_Precache =
+{
+ precache_sound ("weapons/r_exp3.wav"); // new rocket explosion
+ precache_sound ("weapons/rocket1i.wav"); // spike gun
+ precache_sound ("weapons/sgun1.wav");
+ precache_sound ("weapons/guncock.wav"); // player shotgun
+ precache_sound ("weapons/ric1.wav"); // ricochet (used in c code)
+ precache_sound ("weapons/ric2.wav"); // ricochet (used in c code)
+ precache_sound ("weapons/ric3.wav"); // ricochet (used in c code)
+ precache_sound ("weapons/spike2.wav"); // super spikes
+ precache_sound ("weapons/tink1.wav"); // spikes tink (used in c code)
+ precache_sound ("weapons/grenade.wav"); // grenade launcher
+ precache_sound ("weapons/bounce.wav"); // grenade bounce
+ precache_sound ("weapons/shotgn2.wav"); // super shotgun
+};
+
+float() crandom =
+{
+ return 2*(random() - 0.5);
+};
+
+/*
+================
+W_FireAxe
+================
+*/
+void() W_FireAxe =
+{
+ local vector source;
+ local vector org;
+
+ makevectors (self.v_angle);
+ source = self.origin + '0 0 16';
+ traceline (source, source + v_forward*64, FALSE, self);
+ if (trace_fraction == 1.0)
+ return;
+
+ org = trace_endpos - v_forward*4;
+
+ if (trace_ent.takedamage)
+ {
+ trace_ent.axhitme = 1;
+ SpawnBlood (org, 20);
+ if (deathmatch > 3)
+ T_Damage (trace_ent, self, self, 75);
+ else
+ T_Damage (trace_ent, self, self, 20);
+ }
+ else
+ { // hit wall
+ sound (self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM);
+
+ WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
+ WriteByte (MSG_MULTICAST, TE_GUNSHOT);
+ WriteByte (MSG_MULTICAST, 3);
+ WriteCoord (MSG_MULTICAST, org_x);
+ WriteCoord (MSG_MULTICAST, org_y);
+ WriteCoord (MSG_MULTICAST, org_z);
+ multicast (org, MULTICAST_PVS);
+ }
+};
+
+
+//============================================================================
+
+
+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;
+};
+
+
+/*
+================
+SpawnMeatSpray
+================
+*/
+void(vector org, vector vel) SpawnMeatSpray =
+{
+ local entity missile;
+ local vector org;
+
+ missile = spawn ();
+ missile.owner = self;
+ missile.movetype = MOVETYPE_BOUNCE;
+ missile.solid = SOLID_NOT;
+
+ makevectors (self.angles);
+
+ missile.velocity = vel;
+ missile.velocity_z = missile.velocity_z + 250 + 50*random();
+
+ missile.avelocity = '3000 1000 2000';
+
+// set missile duration
+ missile.nextthink = time + 1;
+ missile.think = SUB_Remove;
+
+ setmodel (missile, "progs/zom_gib.mdl");
+ setsize (missile, '0 0 0', '0 0 0');
+ setorigin (missile, org);
+};
+
+/*
+================
+SpawnBlood
+================
+*/
+void(vector org, float damage) SpawnBlood =
+{
+ WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
+ WriteByte (MSG_MULTICAST, TE_BLOOD);
+ WriteByte (MSG_MULTICAST, 1);
+ WriteCoord (MSG_MULTICAST, org_x);
+ WriteCoord (MSG_MULTICAST, org_y);
+ WriteCoord (MSG_MULTICAST, org_z);
+ multicast (org, MULTICAST_PVS);
+};
+
+/*
+================
+spawn_touchblood
+================
+*/
+void(float damage) spawn_touchblood =
+{
+ local vector vel;
+
+ vel = wall_velocity () * 0.2;
+ SpawnBlood (self.origin + vel*0.01, damage);
+};
+
+/*
+==============================================================================
+
+MULTI-DAMAGE
+
+Collects multiple small damages into a single damage
+
+==============================================================================
+*/
+
+entity multi_ent;
+float multi_damage;
+
+vector blood_org;
+float blood_count;
+
+vector puff_org;
+float puff_count;
+
+void() ClearMultiDamage =
+{
+ multi_ent = world;
+ multi_damage = 0;
+ blood_count = 0;
+ puff_count = 0;
+};
+
+void() ApplyMultiDamage =
+{
+ if (!multi_ent)
+ return;
+ T_Damage (multi_ent, self, self, multi_damage);
+};
+
+void(entity hit, float damage) AddMultiDamage =
+{
+ if (!hit)
+ return;
+
+ if (hit != multi_ent)
+ {
+ ApplyMultiDamage ();
+ multi_damage = damage;
+ multi_ent = hit;
+ }
+ else
+ multi_damage = multi_damage + damage;
+};
+
+void() Multi_Finish =
+{
+ if (puff_count)
+ {
+ WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
+ WriteByte (MSG_MULTICAST, TE_GUNSHOT);
+ WriteByte (MSG_MULTICAST, puff_count);
+ WriteCoord (MSG_MULTICAST, puff_org_x);
+ WriteCoord (MSG_MULTICAST, puff_org_y);
+ WriteCoord (MSG_MULTICAST, puff_org_z);
+ multicast (puff_org, MULTICAST_PVS);
+ }
+
+ if (blood_count)
+ {
+ WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
+ WriteByte (MSG_MULTICAST, TE_BLOOD);
+ WriteByte (MSG_MULTICAST, blood_count);
+ WriteCoord (MSG_MULTICAST, blood_org_x);
+ WriteCoord (MSG_MULTICAST, blood_org_y);
+ WriteCoord (MSG_MULTICAST, blood_org_z);
+ multicast (puff_org, MULTICAST_PVS);
+ }
+};
+
+/*
+==============================================================================
+BULLETS
+==============================================================================
+*/
+
+/*
+================
+TraceAttack
+================
+*/
+void(float damage, vector dir) TraceAttack =
+{
+ local vector vel, org;
+
+ vel = normalize(dir + v_up*crandom() + v_right*crandom());
+ vel = vel + 2*trace_plane_normal;
+ vel = vel * 200;
+
+ org = trace_endpos - dir*4;
+
+ if (trace_ent.takedamage)
+ {
+ blood_count = blood_count + 1;
+ blood_org = org;
+ AddMultiDamage (trace_ent, damage);
+ }
+ else
+ {
+ puff_count = puff_count + 1;
+ }
+};
+
+/*
+================
+FireBullets
+
+Used by shotgun, super shotgun, and enemy soldier firing
+Go to the trouble of combining multiple pellets into a single damage call.
+================
+*/
+void(float shotcount, vector dir, vector spread) FireBullets =
+{
+ local vector direction;
+ local vector src;
+
+ makevectors(self.v_angle);
+
+ src = self.origin + v_forward*10;
+ src_z = self.absmin_z + self.size_z * 0.7;
+
+ ClearMultiDamage ();
+
+ traceline (src, src + dir*2048, FALSE, self);
+ puff_org = trace_endpos - dir*4;
+
+ while (shotcount > 0)
+ {
+ direction = dir + crandom()*spread_x*v_right + crandom()*spread_y*v_up;
+ traceline (src, src + direction*2048, FALSE, self);
+ if (trace_fraction != 1.0)
+ TraceAttack (4, direction);
+
+ shotcount = shotcount - 1;
+ }
+ ApplyMultiDamage ();
+ Multi_Finish ();
+};
+
+/*
+================
+W_FireShotgun
+================
+*/
+void() W_FireShotgun =
+{
+ local vector dir;
+
+ sound (self, CHAN_WEAPON, "weapons/guncock.wav", 1, ATTN_NORM);
+
+ msg_entity = self;
+ WriteByte (MSG_ONE, SVC_SMALLKICK);
+
+ if (deathmatch != 4 )
+ self.currentammo = self.ammo_shells = self.ammo_shells - 1;
+
+ dir = aim (self, 100000);
+ FireBullets (6, dir, '0.04 0.04 0');
+};
+
+
+/*
+================
+W_FireSuperShotgun
+================
+*/
+void() W_FireSuperShotgun =
+{
+ local vector dir;
+
+ if (self.currentammo == 1)
+ {
+ W_FireShotgun ();
+ return;
+ }
+
+ sound (self ,CHAN_WEAPON, "weapons/shotgn2.wav", 1, ATTN_NORM);
+
+ msg_entity = self;
+ WriteByte (MSG_ONE, SVC_BIGKICK);
+
+ if (deathmatch != 4)
+ self.currentammo = self.ammo_shells = self.ammo_shells - 2;
+ dir = aim (self, 100000);
+ FireBullets (14, dir, '0.14 0.08 0');
+};
+
+
+/*
+==============================================================================
+
+ROCKETS
+
+==============================================================================
+*/
+
+void() T_MissileTouch =
+{
+ local float damg;
+
+// if (deathmatch == 4)
+// {
+// if ( ((other.weapon == 32) || (other.weapon == 16)))
+// {
+// if (random() < 0.1)
+// {
+// if (other != world)
+// {
+// // bprint (PRINT_HIGH, "Got here\n");
+// other.deathtype = "blaze";
+// T_Damage (other, self, self.owner, 1000 );
+// T_RadiusDamage (self, self.owner, 1000, other);
+// }
+// }
+// }
+// }
+
+ if (other == self.owner)
+ return; // don't explode on owner
+
+ if (self.voided) {
+ return;
+ }
+ self.voided = 1;
+
+ if (pointcontents(self.origin) == CONTENT_SKY)
+ {
+ remove(self);
+ return;
+ }
+
+ damg = 100 + random()*20;
+
+ if (other.health)
+ {
+ other.deathtype = "rocket";
+ T_Damage (other, self, self.owner, damg );
+ }
+
+ // don't do radius damage to the other, because all the damage
+ // was done in the impact
+
+
+ T_RadiusDamage (self, self.owner, 120, other, "rocket");
+
+// sound (self, CHAN_WEAPON, "weapons/r_exp3.wav", 1, ATTN_NORM);
+ self.origin = self.origin - 8 * normalize(self.velocity);
+
+ WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
+ WriteByte (MSG_MULTICAST, TE_EXPLOSION);
+ WriteCoord (MSG_MULTICAST, self.origin_x);
+ WriteCoord (MSG_MULTICAST, self.origin_y);
+ WriteCoord (MSG_MULTICAST, self.origin_z);
+ multicast (self.origin, MULTICAST_PHS);
+
+ remove(self);
+};
+
+
+
+/*
+================
+W_FireRocket
+================
+*/
+void() W_FireRocket =
+{
+ if (deathmatch != 4)
+ self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
+
+ sound (self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM);
+
+ msg_entity = self;
+ WriteByte (MSG_ONE, SVC_SMALLKICK);
+
+ newmis = spawn ();
+ newmis.owner = self;
+ newmis.movetype = MOVETYPE_FLYMISSILE;
+ newmis.solid = SOLID_BBOX;
+
+// set newmis speed
+
+ makevectors (self.v_angle);
+ newmis.velocity = aim(self, 1000);
+ newmis.velocity = newmis.velocity * 1000;
+ newmis.angles = vectoangles(newmis.velocity);
+
+ newmis.touch = T_MissileTouch;
+ newmis.voided = 0;
+
+// set newmis duration
+ newmis.nextthink = time + 5;
+ newmis.think = SUB_Remove;
+ newmis.classname = "rocket";
+
+ setmodel (newmis, "progs/missile.mdl");
+ setsize (newmis, '0 0 0', '0 0 0');
+ setorigin (newmis, self.origin + v_forward*8 + '0 0 16');
+};
+
+/*
+===============================================================================
+LIGHTNING
+===============================================================================
+*/
+
+void(entity from, float damage) LightningHit =
+{
+ WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
+ WriteByte (MSG_MULTICAST, TE_LIGHTNINGBLOOD);
+ WriteCoord (MSG_MULTICAST, trace_endpos_x);
+ WriteCoord (MSG_MULTICAST, trace_endpos_y);
+ WriteCoord (MSG_MULTICAST, trace_endpos_z);
+ multicast (trace_endpos, MULTICAST_PVS);
+
+ T_Damage (trace_ent, from, from, damage);
+};
+
+/*
+=================
+LightningDamage
+=================
+*/
+void(vector p1, vector p2, entity from, float damage) LightningDamage =
+{
+ local entity e1, e2;
+ local vector f;
+
+ f = p2 - p1;
+ normalize (f);
+ f_x = 0 - f_y;
+ f_y = f_x;
+ f_z = 0;
+ f = f*16;
+
+ e1 = e2 = world;
+
+ traceline (p1, p2, FALSE, self);
+
+ if (trace_ent.takedamage)
+ {
+ LightningHit (from, damage);
+ if (self.classname == "player")
+ {
+ if (other.classname == "player")
+ trace_ent.velocity_z = trace_ent.velocity_z + 400;
+ }
+ }
+ e1 = trace_ent;
+
+ traceline (p1 + f, p2 + f, FALSE, self);
+ if (trace_ent != e1 && trace_ent.takedamage)
+ {
+ LightningHit (from, damage);
+ }
+ e2 = trace_ent;
+
+ traceline (p1 - f, p2 - f, FALSE, self);
+ if (trace_ent != e1 && trace_ent != e2 && trace_ent.takedamage)
+ {
+ LightningHit (from, damage);
+ }
+};
+
+
+void() W_FireLightning =
+{
+ local vector org;
+ local float cells;
+
+ if (self.ammo_cells < 1)
+ {
+ self.weapon = W_BestWeapon ();
+ W_SetCurrentAmmo ();
+ return;
+ }
+
+// explode if under water
+ if (self.waterlevel > 1)
+ {
+ if (deathmatch > 3)
+ {
+ if (random() <= 0.5)
+ {
+ self.deathtype = "selfwater";
+ T_Damage (self, self, self.owner, 4000 );
+ }
+ else
+ {
+ cells = self.ammo_cells;
+ self.ammo_cells = 0;
+ W_SetCurrentAmmo ();
+ T_RadiusDamage (self, self, 35*cells, world, "");
+ return;
+ }
+ }
+ else
+ {
+ cells = self.ammo_cells;
+ self.ammo_cells = 0;
+ W_SetCurrentAmmo ();
+ T_RadiusDamage (self, self, 35*cells, world,"");
+ return;
+ }
+ }
+
+ if (self.t_width < time)
+ {
+ sound (self, CHAN_WEAPON, "weapons/lhit.wav", 1, ATTN_NORM);
+ self.t_width = time + 0.6;
+ }
+ msg_entity = self;
+ WriteByte (MSG_ONE, SVC_SMALLKICK);
+
+ if (deathmatch != 4)
+ self.currentammo = self.ammo_cells = self.ammo_cells - 1;
+
+ org = self.origin + '0 0 16';
+
+ traceline (org, org + v_forward*600, TRUE, self);
+
+ WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
+ WriteByte (MSG_MULTICAST, TE_LIGHTNING2);
+ WriteEntity (MSG_MULTICAST, self);
+ WriteCoord (MSG_MULTICAST, org_x);
+ WriteCoord (MSG_MULTICAST, org_y);
+ WriteCoord (MSG_MULTICAST, org_z);
+ WriteCoord (MSG_MULTICAST, trace_endpos_x);
+ WriteCoord (MSG_MULTICAST, trace_endpos_y);
+ WriteCoord (MSG_MULTICAST, trace_endpos_z);
+ multicast (org, MULTICAST_PHS);
+
+ LightningDamage (self.origin, trace_endpos + v_forward*4, self, 30);
+};
+
+
+//=============================================================================
+
+
+void() GrenadeExplode =
+{
+ if (self.voided) {
+ return;
+ }
+ self.voided = 1;
+
+ T_RadiusDamage (self, self.owner, 120, world, "grenade");
+
+ WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
+ WriteByte (MSG_MULTICAST, TE_EXPLOSION);
+ WriteCoord (MSG_MULTICAST, self.origin_x);
+ WriteCoord (MSG_MULTICAST, self.origin_y);
+ WriteCoord (MSG_MULTICAST, self.origin_z);
+ multicast (self.origin, MULTICAST_PHS);
+
+ remove (self);
+};
+
+void() GrenadeTouch =
+{
+ if (other == self.owner)
+ return; // don't explode on owner
+ if (other.takedamage == DAMAGE_AIM)
+ {
+ GrenadeExplode();
+ return;
+ }
+ sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); // bounce sound
+ if (self.velocity == '0 0 0')
+ self.avelocity = '0 0 0';
+};
+
+/*
+================
+W_FireGrenade
+================
+*/
+void() W_FireGrenade =
+{
+ if (deathmatch != 4)
+ self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
+
+ sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
+
+ msg_entity = self;
+ WriteByte (MSG_ONE, SVC_SMALLKICK);
+
+ newmis = spawn ();
+ newmis.voided=0;
+ newmis.owner = self;
+ newmis.movetype = MOVETYPE_BOUNCE;
+ newmis.solid = SOLID_BBOX;
+ newmis.classname = "grenade";
+
+// 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 = GrenadeTouch;
+
+// set newmis duration
+ if (deathmatch == 4)
+ {
+ newmis.nextthink = time + 2.5;
+ self.attack_finished = time + 1.1;
+// self.health = self.health - 1;
+ T_Damage (self, self, self.owner, 10 );
+ }
+ else
+ newmis.nextthink = time + 2.5;
+
+ newmis.think = GrenadeExplode;
+
+ setmodel (newmis, "progs/grenade.mdl");
+ setsize (newmis, '0 0 0', '0 0 0');
+ setorigin (newmis, self.origin);
+};
+
+
+//=============================================================================
+
+void() spike_touch;
+void() superspike_touch;
+
+
+/*
+===============
+launch_spike
+
+Used for both the player and the ogre
+===============
+*/
+void(vector org, vector dir) launch_spike =
+{
+ newmis = spawn ();
+ newmis.voided=0;
+ newmis.owner = self;
+ newmis.movetype = MOVETYPE_FLYMISSILE;
+ newmis.solid = SOLID_BBOX;
+
+ newmis.angles = vectoangles(dir);
+
+ newmis.touch = spike_touch;
+ newmis.classname = "spike";
+ newmis.think = SUB_Remove;
+ newmis.nextthink = time + 6;
+ setmodel (newmis, "progs/spike.mdl");
+ setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
+ setorigin (newmis, org);
+
+ newmis.velocity = dir * 1000;
+};
+
+void() W_FireSuperSpikes =
+{
+ local vector dir;
+ local entity old;
+
+ sound (self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM);
+ self.attack_finished = time + 0.2;
+ if (deathmatch != 4)
+ self.currentammo = self.ammo_nails = self.ammo_nails - 2;
+ dir = aim (self, 1000);
+ launch_spike (self.origin + '0 0 16', dir);
+ newmis.touch = superspike_touch;
+ setmodel (newmis, "progs/s_spike.mdl");
+ setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
+ msg_entity = self;
+ WriteByte (MSG_ONE, SVC_SMALLKICK);
+};
+
+void(float ox) W_FireSpikes =
+{
+ local vector dir;
+ local entity old;
+
+ makevectors (self.v_angle);
+
+ if (self.ammo_nails >= 2 && self.weapon == IT_SUPER_NAILGUN)
+ {
+ W_FireSuperSpikes ();
+ return;
+ }
+
+ if (self.ammo_nails < 1)
+ {
+ self.weapon = W_BestWeapon ();
+ W_SetCurrentAmmo ();
+ return;
+ }
+
+ sound (self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM);
+ self.attack_finished = time + 0.2;
+ if (deathmatch != 4)
+ self.currentammo = self.ammo_nails = self.ammo_nails - 1;
+ dir = aim (self, 1000);
+ launch_spike (self.origin + '0 0 16' + v_right*ox, dir);
+
+ msg_entity = self;
+ WriteByte (MSG_ONE, SVC_SMALLKICK);
+};
+
+
+
+.float hit_z;
+void() spike_touch =
+{
+local float rand;
+ if (other == self.owner)
+ return;
+
+ if (self.voided) {
+ return;
+ }
+ self.voided = 1;
+
+ if (other.solid == SOLID_TRIGGER)
+ return; // trigger field, do nothing
+
+ if (pointcontents(self.origin) == CONTENT_SKY)
+ {
+ remove(self);
+ return;
+ }
+
+// hit something that bleeds
+ if (other.takedamage)
+ {
+ spawn_touchblood (9);
+ other.deathtype = "nail";
+ T_Damage (other, self, self.owner, 9);
+ }
+ else
+ {
+ WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
+ if (self.classname == "wizspike")
+ WriteByte (MSG_MULTICAST, TE_WIZSPIKE);
+ else if (self.classname == "knightspike")
+ WriteByte (MSG_MULTICAST, TE_KNIGHTSPIKE);
+ else
+ WriteByte (MSG_MULTICAST, TE_SPIKE);
+ WriteCoord (MSG_MULTICAST, self.origin_x);
+ WriteCoord (MSG_MULTICAST, self.origin_y);
+ WriteCoord (MSG_MULTICAST, self.origin_z);
+ multicast (self.origin, MULTICAST_PHS);
+ }
+
+ remove(self);
+
+};
+
+void() superspike_touch =
+{
+local float rand;
+ if (other == self.owner)
+ return;
+
+ if (self.voided) {
+ return;
+ }
+ self.voided = 1;
+
+
+ if (other.solid == SOLID_TRIGGER)
+ return; // trigger field, do nothing
+
+ if (pointcontents(self.origin) == CONTENT_SKY)
+ {
+ remove(self);
+ return;
+ }
+
+// hit something that bleeds
+ if (other.takedamage)
+ {
+ spawn_touchblood (18);
+ other.deathtype = "supernail";
+ T_Damage (other, self, self.owner, 18);
+ }
+ else
+ {
+ WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
+ WriteByte (MSG_MULTICAST, TE_SUPERSPIKE);
+ WriteCoord (MSG_MULTICAST, self.origin_x);
+ WriteCoord (MSG_MULTICAST, self.origin_y);
+ WriteCoord (MSG_MULTICAST, self.origin_z);
+ multicast (self.origin, MULTICAST_PHS);
+ }
+
+ remove(self);
+
+};
+
+
+/*
+===============================================================================
+
+PLAYER WEAPON USE
+
+===============================================================================
+*/
+
+void() W_SetCurrentAmmo =
+{
+ player_run (); // get out of any weapon firing states
+
+ self.items = self.items - ( self.items & (IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS) );
+
+ if (self.weapon == IT_AXE)
+ {
+ self.currentammo = 0;
+ self.weaponmodel = "progs/v_axe.mdl";
+ self.weaponframe = 0;
+ }
+ else if (self.weapon == IT_SHOTGUN)
+ {
+ self.currentammo = self.ammo_shells;
+ self.weaponmodel = "progs/v_shot.mdl";
+ self.weaponframe = 0;
+ self.items = self.items | IT_SHELLS;
+ }
+ else if (self.weapon == IT_SUPER_SHOTGUN)
+ {
+ self.currentammo = self.ammo_shells;
+ self.weaponmodel = "progs/v_shot2.mdl";
+ self.weaponframe = 0;
+ self.items = self.items | IT_SHELLS;
+ }
+ else if (self.weapon == IT_NAILGUN)
+ {
+ self.currentammo = self.ammo_nails;
+ self.weaponmodel = "progs/v_nail.mdl";
+ self.weaponframe = 0;
+ self.items = self.items | IT_NAILS;
+ }
+ else if (self.weapon == IT_SUPER_NAILGUN)
+ {
+ self.currentammo = self.ammo_nails;
+ self.weaponmodel = "progs/v_nail2.mdl";
+ self.weaponframe = 0;
+ self.items = self.items | IT_NAILS;
+ }
+ else if (self.weapon == IT_GRENADE_LAUNCHER)
+ {
+ self.currentammo = self.ammo_rockets;
+ self.weaponmodel = "progs/v_rock.mdl";
+ self.weaponframe = 0;
+ self.items = self.items | IT_ROCKETS;
+ }
+ else if (self.weapon == IT_ROCKET_LAUNCHER)
+ {
+ self.currentammo = self.ammo_rockets;
+ self.weaponmodel = "progs/v_rock2.mdl";
+ self.weaponframe = 0;
+ self.items = self.items | IT_ROCKETS;
+ }
+ else if (self.weapon == IT_LIGHTNING)
+ {
+ self.currentammo = self.ammo_cells;
+ self.weaponmodel = "progs/v_light.mdl";
+ self.weaponframe = 0;
+ self.items = self.items | IT_CELLS;
+ }
+ else
+ {
+ self.currentammo = 0;
+ self.weaponmodel = "";
+ self.weaponframe = 0;
+ }
+};
+
+float() W_BestWeapon =
+{
+ local float it;
+
+ it = self.items;
+
+ if (self.waterlevel <= 1 && self.ammo_cells >= 1 && (it & IT_LIGHTNING) )
+ return IT_LIGHTNING;
+ else if(self.ammo_nails >= 2 && (it & IT_SUPER_NAILGUN) )
+ return IT_SUPER_NAILGUN;
+ else if(self.ammo_shells >= 2 && (it & IT_SUPER_SHOTGUN) )
+ return IT_SUPER_SHOTGUN;
+ else if(self.ammo_nails >= 1 && (it & IT_NAILGUN) )
+ return IT_NAILGUN;
+ else if(self.ammo_shells >= 1 && (it & IT_SHOTGUN) )
+ return IT_SHOTGUN;
+
+/*
+ if(self.ammo_rockets >= 1 && (it & IT_ROCKET_LAUNCHER) )
+ return IT_ROCKET_LAUNCHER;
+ else if(self.ammo_rockets >= 1 && (it & IT_GRENADE_LAUNCHER) )
+ return IT_GRENADE_LAUNCHER;
+
+*/
+
+ return IT_AXE;
+};
+
+float() W_CheckNoAmmo =
+{
+ if (self.currentammo > 0)
+ return TRUE;
+
+ if (self.weapon == IT_AXE)
+ return TRUE;
+
+ self.weapon = W_BestWeapon ();
+
+ W_SetCurrentAmmo ();
+
+// drop the weapon down
+ return FALSE;
+};
+
+/*
+============
+W_Attack
+
+An attack impulse can be triggered now
+============
+*/
+void() player_axe1;
+void() player_axeb1;
+void() player_axec1;
+void() player_axed1;
+void() player_shot1;
+void() player_nail1;
+void() player_light1;
+void() player_rocket1;
+
+void() W_Attack =
+{
+ local float r;
+
+ if (!W_CheckNoAmmo ())
+ return;
+
+ makevectors (self.v_angle); // calculate forward angle for velocity
+ self.show_hostile = time + 1; // wake monsters up
+
+ if (self.weapon == IT_AXE)
+ {
+ self.attack_finished = time + 0.5;
+ sound (self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM);
+ r = random();
+ if (r < 0.25)
+ player_axe1 ();
+ else if (r<0.5)
+ player_axeb1 ();
+ else if (r<0.75)
+ player_axec1 ();
+ else
+ player_axed1 ();
+ }
+ else if (self.weapon == IT_SHOTGUN)
+ {
+ player_shot1 ();
+ self.attack_finished = time + 0.5;
+ W_FireShotgun ();
+ }
+ else if (self.weapon == IT_SUPER_SHOTGUN)
+ {
+ player_shot1 ();
+ self.attack_finished = time + 0.7;
+ W_FireSuperShotgun ();
+ }
+ else if (self.weapon == IT_NAILGUN)
+ {
+ player_nail1 ();
+ }
+ else if (self.weapon == IT_SUPER_NAILGUN)
+ {
+ player_nail1 ();
+ }
+ else if (self.weapon == IT_GRENADE_LAUNCHER)
+ {
+ player_rocket1();
+ self.attack_finished = time + 0.6;
+ W_FireGrenade();
+ }
+ else if (self.weapon == IT_ROCKET_LAUNCHER)
+ {
+ player_rocket1();
+ self.attack_finished = time + 0.8;
+ W_FireRocket();
+ }
+ else if (self.weapon == IT_LIGHTNING)
+ {
+ self.attack_finished = time + 0.1;
+ sound (self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM);
+ player_light1();
+ }
+};
+
+/*
+============
+W_ChangeWeapon
+
+============
+*/
+void() W_ChangeWeapon =
+{
+ local float it, am, fl;
+
+ it = self.items;
+ am = 0;
+
+ if (self.impulse == 1)
+ {
+ fl = IT_AXE;
+ }
+ else if (self.impulse == 2)
+ {
+ fl = IT_SHOTGUN;
+ if (self.ammo_shells < 1)
+ am = 1;
+ }
+ else if (self.impulse == 3)
+ {
+ fl = IT_SUPER_SHOTGUN;
+ if (self.ammo_shells < 2)
+ am = 1;
+ }
+ else if (self.impulse == 4)
+ {
+ fl = IT_NAILGUN;
+ if (self.ammo_nails < 1)
+ am = 1;
+ }
+ else if (self.impulse == 5)
+ {
+ fl = IT_SUPER_NAILGUN;
+ if (self.ammo_nails < 2)
+ am = 1;
+ }
+ else if (self.impulse == 6)
+ {
+ fl = IT_GRENADE_LAUNCHER;
+ if (self.ammo_rockets < 1)
+ am = 1;
+ }
+ else if (self.impulse == 7)
+ {
+ fl = IT_ROCKET_LAUNCHER;
+ if (self.ammo_rockets < 1)
+ am = 1;
+ }
+ else if (self.impulse == 8)
+ {
+ fl = IT_LIGHTNING;
+ if (self.ammo_cells < 1)
+ am = 1;
+ }
+
+ self.impulse = 0;
+
+ if (!(self.items & fl))
+ { // don't have the weapon or the ammo
+ sprint (self, PRINT_HIGH, "no weapon.\n");
+ return;
+ }
+
+ if (am)
+ { // don't have the ammo
+ sprint (self, PRINT_HIGH, "not enough ammo.\n");
+ return;
+ }
+
+//
+// set weapon, set ammo
+//
+ self.weapon = fl;
+ W_SetCurrentAmmo ();
+};
+
+/*
+============
+CheatCommand
+============
+*/
+void() CheatCommand =
+{
+// if (deathmatch || coop)
+ return;
+
+ self.ammo_rockets = 100;
+ self.ammo_nails = 200;
+ self.ammo_shells = 100;
+ self.items = self.items |
+ IT_AXE |
+ IT_SHOTGUN |
+ IT_SUPER_SHOTGUN |
+ IT_NAILGUN |
+ IT_SUPER_NAILGUN |
+ IT_GRENADE_LAUNCHER |
+ IT_ROCKET_LAUNCHER |
+ IT_KEY1 | IT_KEY2;
+
+ self.ammo_cells = 200;
+ self.items = self.items | IT_LIGHTNING;
+
+ self.weapon = IT_ROCKET_LAUNCHER;
+ self.impulse = 0;
+ W_SetCurrentAmmo ();
+};
+
+/*
+============
+CycleWeaponCommand
+
+Go to the next weapon with ammo
+============
+*/
+void() CycleWeaponCommand =
+{
+ local float it, am;
+
+ it = self.items;
+ self.impulse = 0;
+
+ while (1)
+ {
+ am = 0;
+
+ if (self.weapon == IT_LIGHTNING)
+ {
+ self.weapon = IT_AXE;
+ }
+ else if (self.weapon == IT_AXE)
+ {
+ self.weapon = IT_SHOTGUN;
+ if (self.ammo_shells < 1)
+ am = 1;
+ }
+ else if (self.weapon == IT_SHOTGUN)
+ {
+ self.weapon = IT_SUPER_SHOTGUN;
+ if (self.ammo_shells < 2)
+ am = 1;
+ }
+ else if (self.weapon == IT_SUPER_SHOTGUN)
+ {
+ self.weapon = IT_NAILGUN;
+ if (self.ammo_nails < 1)
+ am = 1;
+ }
+ else if (self.weapon == IT_NAILGUN)
+ {
+ self.weapon = IT_SUPER_NAILGUN;
+ if (self.ammo_nails < 2)
+ am = 1;
+ }
+ else if (self.weapon == IT_SUPER_NAILGUN)
+ {
+ self.weapon = IT_GRENADE_LAUNCHER;
+ if (self.ammo_rockets < 1)
+ am = 1;
+ }
+ else if (self.weapon == IT_GRENADE_LAUNCHER)
+ {
+ self.weapon = IT_ROCKET_LAUNCHER;
+ if (self.ammo_rockets < 1)
+ am = 1;
+ }
+ else if (self.weapon == IT_ROCKET_LAUNCHER)
+ {
+ self.weapon = IT_LIGHTNING;
+ if (self.ammo_cells < 1)
+ am = 1;
+ }
+
+ if ( (self.items & self.weapon) && am == 0)
+ {
+ W_SetCurrentAmmo ();
+ return;
+ }
+ }
+
+};
+
+
+/*
+============
+CycleWeaponReverseCommand
+
+Go to the prev weapon with ammo
+============
+*/
+void() CycleWeaponReverseCommand =
+{
+ local float it, am;
+
+ it = self.items;
+ self.impulse = 0;
+
+ while (1)
+ {
+ am = 0;
+
+ if (self.weapon == IT_LIGHTNING)
+ {
+ self.weapon = IT_ROCKET_LAUNCHER;
+ if (self.ammo_rockets < 1)
+ am = 1;
+ }
+ else if (self.weapon == IT_ROCKET_LAUNCHER)
+ {
+ self.weapon = IT_GRENADE_LAUNCHER;
+ if (self.ammo_rockets < 1)
+ am = 1;
+ }
+ else if (self.weapon == IT_GRENADE_LAUNCHER)
+ {
+ self.weapon = IT_SUPER_NAILGUN;
+ if (self.ammo_nails < 2)
+ am = 1;
+ }
+ else if (self.weapon == IT_SUPER_NAILGUN)
+ {
+ self.weapon = IT_NAILGUN;
+ if (self.ammo_nails < 1)
+ am = 1;
+ }
+ else if (self.weapon == IT_NAILGUN)
+ {
+ self.weapon = IT_SUPER_SHOTGUN;
+ if (self.ammo_shells < 2)
+ am = 1;
+ }
+ else if (self.weapon == IT_SUPER_SHOTGUN)
+ {
+ self.weapon = IT_SHOTGUN;
+ if (self.ammo_shells < 1)
+ am = 1;
+ }
+ else if (self.weapon == IT_SHOTGUN)
+ {
+ self.weapon = IT_AXE;
+ }
+ else if (self.weapon == IT_AXE)
+ {
+ self.weapon = IT_LIGHTNING;
+ if (self.ammo_cells < 1)
+ am = 1;
+ }
+
+ if ( (it & self.weapon) && am == 0)
+ {
+ W_SetCurrentAmmo ();
+ return;
+ }
+ }
+
+};
+
+
+/*
+============
+ServerflagsCommand
+
+Just for development
+============
+*/
+void() ServerflagsCommand =
+{
+ serverflags = serverflags * 2 + 1;
+};
+
+
+/*
+============
+ImpulseCommands
+
+============
+*/
+void() ImpulseCommands =
+{
+ if (self.impulse >= 1 && self.impulse <= 8)
+ W_ChangeWeapon ();
+
+ if (self.impulse == 9)
+ CheatCommand ();
+ if (self.impulse == 10)
+ CycleWeaponCommand ();
+ if (self.impulse == 11)
+ ServerflagsCommand ();
+ if (self.impulse == 12)
+ CycleWeaponReverseCommand ();
+
+ self.impulse = 0;
+};
+
+/*
+============
+W_WeaponFrame
+
+Called every frame so impulse events can be handled as well as possible
+============
+*/
+void() W_WeaponFrame =
+{
+ if (time < self.attack_finished)
+ return;
+
+ ImpulseCommands ();
+
+// check for attack
+ if (self.button0)
+ {
+ SuperDamageSound ();
+ W_Attack ();
+ }
+};
+
+/*
+========
+SuperDamageSound
+
+Plays sound if needed
+========
+*/
+void() SuperDamageSound =
+{
+ if (self.super_damage_finished > time)
+ {
+ if (self.super_sound < time)
+ {
+ self.super_sound = time + 1;
+ sound (self, CHAN_BODY, "items/damage3.wav", 1, ATTN_NORM);
+ }
+ }
+ return;
+};
+
+