aboutsummaryrefslogtreecommitdiffstats
path: root/src/jake2/game/Fire.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jake2/game/Fire.java')
-rw-r--r--src/jake2/game/Fire.java1106
1 files changed, 524 insertions, 582 deletions
diff --git a/src/jake2/game/Fire.java b/src/jake2/game/Fire.java
index 73a6f18..c5a426e 100644
--- a/src/jake2/game/Fire.java
+++ b/src/jake2/game/Fire.java
@@ -1,591 +1,533 @@
/*
-Copyright (C) 1997-2001 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 the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-*/
+ * Copyright (C) 1997-2001 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 the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
// Created on 04.12.2003 by RST.
-// $Id: Fire.java,v 1.3 2004-09-10 19:02:53 salomo Exp $
-
+// $Id: Fire.java,v 1.4 2004-09-22 19:22:02 salomo Exp $
package jake2.game;
import jake2.Defines;
+import jake2.Globals;
import jake2.util.Lib;
import jake2.util.Math3D;
-public class Fire
-{
- /*
- =================
- fire_hit
-
- Used for all impact (hit/punch/slash) attacks
- =================
- */
- public static boolean fire_hit(edict_t self, float[] aim, int damage, int kick)
- {
- trace_t tr;
- float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 };
- float[] v = { 0, 0, 0 };
- float[] point = { 0, 0, 0 };
- float range;
- float[] dir = { 0, 0, 0 };
-
- //see if enemy is in range
- Math3D.VectorSubtract(self.enemy.s.origin, self.s.origin, dir);
- range = Math3D.VectorLength(dir);
- if (range > aim[0])
- return false;
-
- if (aim[1] > self.mins[0] && aim[1] < self.maxs[0])
- {
- // the hit is straight on so back the range up to the edge of their bbox
- range -= self.enemy.maxs[0];
- }
- else
- {
- // this is a side hit so adjust the "right" value out to the edge of their bbox
- if (aim[1] < 0)
- aim[1] = self.enemy.mins[0];
- else
- aim[1] = self.enemy.maxs[0];
- }
-
- Math3D.VectorMA(self.s.origin, range, dir, point);
-
- tr = GameBase.gi.trace(self.s.origin, null, null, point, self, Defines.MASK_SHOT);
- if (tr.fraction < 1)
- {
- if (0 == tr.ent.takedamage)
- return false;
- // if it will hit any client/monster then hit the one we wanted to hit
- if ((tr.ent.svflags & Defines.SVF_MONSTER) != 0 || (tr.ent.client != null))
- tr.ent = self.enemy;
- }
-
- Math3D.AngleVectors(self.s.angles, forward, right, up);
- Math3D.VectorMA(self.s.origin, range, forward, point);
- Math3D.VectorMA(point, aim[1], right, point);
- Math3D.VectorMA(point, aim[2], up, point);
- Math3D.VectorSubtract(point, self.enemy.s.origin, dir);
-
- // do the damage
- GameUtil.T_Damage(
- tr.ent,
- self,
- self,
- dir,
- point,
- GameBase.vec3_origin,
- damage,
- kick / 2,
- Defines.DAMAGE_NO_KNOCKBACK,
- Defines.MOD_HIT);
-
- if (0 == (tr.ent.svflags & Defines.SVF_MONSTER) && (null == tr.ent.client))
- return false;
-
- // do our special form of knockback here
- Math3D.VectorMA(self.enemy.absmin, 0.5f, self.enemy.size, v);
- Math3D.VectorSubtract(v, point, v);
- Math3D.VectorNormalize(v);
- Math3D.VectorMA(self.enemy.velocity, kick, v, self.enemy.velocity);
- if (self.enemy.velocity[2] > 0)
- self.enemy.groundentity = null;
- return true;
- }
- /*
- =================
- fire_lead
-
- This is an internal support routine used for bullet/pellet based weapons.
- =================
- */
- public static void fire_lead(
- edict_t self,
- float[] start,
- float[] aimdir,
- int damage,
- int kick,
- int te_impact,
- int hspread,
- int vspread,
- int mod)
- {
- trace_t tr;
- float[] dir = { 0, 0, 0 };
- float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 };
- float[] end = { 0, 0, 0 };
- float r;
- float u;
- float[] water_start = { 0, 0, 0 };
- boolean water = false;
- int content_mask = Defines.MASK_SHOT | Defines.MASK_WATER;
-
- tr = GameBase.gi.trace(self.s.origin, null, null, start, self, Defines.MASK_SHOT);
- if (!(tr.fraction < 1.0))
- {
- Math3D.vectoangles(aimdir, dir);
- Math3D.AngleVectors(dir, forward, right, up);
-
- r = Lib.crandom() * hspread;
- u = Lib.crandom() * vspread;
- Math3D.VectorMA(start, 8192, forward, end);
- Math3D.VectorMA(end, r, right, end);
- Math3D.VectorMA(end, u, up, end);
-
- if ((GameBase.gi.pointcontents.pointcontents(start) & Defines.MASK_WATER) != 0)
- {
- water = true;
- Math3D.VectorCopy(start, water_start);
- content_mask &= ~Defines.MASK_WATER;
- }
-
- tr = GameBase.gi.trace(start, null, null, end, self, content_mask);
-
- // see if we hit water
- if ((tr.contents & Defines.MASK_WATER) != 0)
- {
- int color;
-
- water = true;
- Math3D.VectorCopy(tr.endpos, water_start);
-
- if (0 == Math3D.VectorCompare(start, tr.endpos))
- {
- if ((tr.contents & Defines.CONTENTS_WATER) != 0)
- {
- if (Lib.strcmp(tr.surface.name, "*brwater") == 0)
- color = Defines.SPLASH_BROWN_WATER;
- else
- color = Defines.SPLASH_BLUE_WATER;
- }
- else if ((tr.contents & Defines.CONTENTS_SLIME) != 0)
- color = Defines.SPLASH_SLIME;
- else if ((tr.contents & Defines.CONTENTS_LAVA) != 0)
- color = Defines.SPLASH_LAVA;
- else
- color = Defines.SPLASH_UNKNOWN;
-
- if (color != Defines.SPLASH_UNKNOWN)
- {
- GameBase.gi.WriteByte(Defines.svc_temp_entity);
- GameBase.gi.WriteByte(Defines.TE_SPLASH);
- GameBase.gi.WriteByte(8);
- GameBase.gi.WritePosition(tr.endpos);
- GameBase.gi.WriteDir(tr.plane.normal);
- GameBase.gi.WriteByte(color);
- GameBase.gi.multicast(tr.endpos, Defines.MULTICAST_PVS);
- }
-
- // change bullet's course when it enters water
- Math3D.VectorSubtract(end, start, dir);
- Math3D.vectoangles(dir, dir);
- Math3D.AngleVectors(dir, forward, right, up);
- r = Lib.crandom() * hspread * 2;
- u = Lib.crandom() * vspread * 2;
- Math3D.VectorMA(water_start, 8192, forward, end);
- Math3D.VectorMA(end, r, right, end);
- Math3D.VectorMA(end, u, up, end);
- }
-
- // re-trace ignoring water this time
- tr = GameBase.gi.trace(water_start, null, null, end, self, Defines.MASK_SHOT);
- }
- }
-
- // send gun puff / flash
- if (!((tr.surface != null) && 0 != (tr.surface.flags & Defines.SURF_SKY)))
- {
- if (tr.fraction < 1.0)
- {
- if (tr.ent.takedamage != 0)
- {
- GameUtil.T_Damage(
- tr.ent,
- self,
- self,
- aimdir,
- tr.endpos,
- tr.plane.normal,
- damage,
- kick,
- Defines.DAMAGE_BULLET,
- mod);
- }
- else
- {
- if (!"sky".equals(tr.surface.name))
- {
- GameBase.gi.WriteByte(Defines.svc_temp_entity);
- GameBase.gi.WriteByte(te_impact);
- GameBase.gi.WritePosition(tr.endpos);
- GameBase.gi.WriteDir(tr.plane.normal);
- GameBase.gi.multicast(tr.endpos, Defines.MULTICAST_PVS);
-
- if (self.client != null)
- GameWeapon.PlayerNoise(self, tr.endpos, Defines.PNOISE_IMPACT);
- }
- }
- }
- }
-
- // if went through water, determine where the end and make a bubble trail
- if (water)
- {
- float[] pos = { 0, 0, 0 };
-
- Math3D.VectorSubtract(tr.endpos, water_start, dir);
- Math3D.VectorNormalize(dir);
- Math3D.VectorMA(tr.endpos, -2, dir, pos);
- if ((Game.gi.pointcontents.pointcontents(pos) & Defines.MASK_WATER) != 0)
- Math3D.VectorCopy(pos, tr.endpos);
- else
- tr = GameBase.gi.trace(pos, null, null, water_start, tr.ent, Defines.MASK_WATER);
-
- Math3D.VectorAdd(water_start, tr.endpos, pos);
- Math3D.VectorScale(pos, 0.5f, pos);
-
- GameBase.gi.WriteByte(Defines.svc_temp_entity);
- GameBase.gi.WriteByte(Defines.TE_BUBBLETRAIL);
- GameBase.gi.WritePosition(water_start);
- GameBase.gi.WritePosition(tr.endpos);
- GameBase.gi.multicast(pos, Defines.MULTICAST_PVS);
- }
- }
- /*
- =================
- fire_bullet
-
- Fires a single round. Used for machinegun and chaingun. Would be fine for
- pistols, rifles, etc....
- =================
- */
- public static void fire_bullet(
- edict_t self,
- float[] start,
- float[] aimdir,
- int damage,
- int kick,
- int hspread,
- int vspread,
- int mod)
- {
- fire_lead(self, start, aimdir, damage, kick, Defines.TE_GUNSHOT, hspread, vspread, mod);
- }
- /*
- =================
- fire_shotgun
-
- Shoots shotgun pellets. Used by shotgun and super shotgun.
- =================
- */
- public static void fire_shotgun(
- edict_t self,
- float[] start,
- float[] aimdir,
- int damage,
- int kick,
- int hspread,
- int vspread,
- int count,
- int mod)
- {
- int i;
-
- for (i = 0; i < count; i++)
- fire_lead(self, start, aimdir, damage, kick, Defines.TE_SHOTGUN, hspread, vspread, mod);
- }
-
- public static void fire_blaster(edict_t self, float[] start, float[] dir, int damage, int speed, int effect, boolean hyper)
- {
- edict_t bolt;
- trace_t tr;
-
- Math3D.VectorNormalize(dir);
-
- bolt = GameUtil.G_Spawn();
- bolt.svflags = Defines.SVF_DEADMONSTER;
- // yes, I know it looks weird that projectiles are deadmonsters
- // what this means is that when prediction is used against the object
- // (blaster/hyperblaster shots), the player won't be solid clipped against
- // the object. Right now trying to run into a firing hyperblaster
- // is very jerky since you are predicted 'against' the shots.
- Math3D.VectorCopy(start, bolt.s.origin);
- Math3D.VectorCopy(start, bolt.s.old_origin);
- Math3D.vectoangles(dir, bolt.s.angles);
- Math3D.VectorScale(dir, speed, bolt.velocity);
- bolt.movetype = Defines.MOVETYPE_FLYMISSILE;
- bolt.clipmask = Defines.MASK_SHOT;
- bolt.solid = Defines.SOLID_BBOX;
- bolt.s.effects |= effect;
- Math3D.VectorClear(bolt.mins);
- Math3D.VectorClear(bolt.maxs);
- bolt.s.modelindex = GameBase.gi.modelindex("models/objects/laser/tris.md2");
- bolt.s.sound = GameBase.gi.soundindex("misc/lasfly.wav");
- bolt.owner = self;
- bolt.touch = GameWeaponAdapters.blaster_touch;
- bolt.nextthink = GameBase.level.time + 2;
- bolt.think = GameUtilAdapters.G_FreeEdictA;
- bolt.dmg = damage;
- bolt.classname = "bolt";
- if (hyper)
- bolt.spawnflags = 1;
- GameBase.gi.linkentity(bolt);
-
- if (self.client != null)
- GameWeapon.check_dodge(self, bolt.s.origin, dir, speed);
-
- tr = GameBase.gi.trace(self.s.origin, null, null, bolt.s.origin, bolt, Defines.MASK_SHOT);
- if (tr.fraction < 1.0)
- {
- Math3D.VectorMA(bolt.s.origin, -10, dir, bolt.s.origin);
- bolt.touch.touch(bolt, tr.ent, GameBase.dummyplane, null);
- }
- }
- /*
- =================
- fire_grenade
- =================
- */
-
- public static void fire_grenade(
- edict_t self,
- float[] start,
- float[] aimdir,
- int damage,
- int speed,
- float timer,
- float damage_radius)
- {
- edict_t grenade;
- float[] dir = { 0, 0, 0 };
- float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 };
-
- Math3D.vectoangles(aimdir, dir);
- Math3D.AngleVectors(dir, forward, right, up);
-
- grenade = GameUtil.G_Spawn();
- Math3D.VectorCopy(start, grenade.s.origin);
- Math3D.VectorScale(aimdir, speed, grenade.velocity);
- Math3D.VectorMA(grenade.velocity, 200f + Lib.crandom() * 10.0f, up, grenade.velocity);
- Math3D.VectorMA(grenade.velocity, Lib.crandom() * 10.0f, right, grenade.velocity);
- Math3D.VectorSet(grenade.avelocity, 300, 300, 300);
- grenade.movetype = Defines.MOVETYPE_BOUNCE;
- grenade.clipmask = Defines.MASK_SHOT;
- grenade.solid = Defines.SOLID_BBOX;
- grenade.s.effects |= Defines.EF_GRENADE;
- Math3D.VectorClear(grenade.mins);
- Math3D.VectorClear(grenade.maxs);
- grenade.s.modelindex = GameBase.gi.modelindex("models/objects/grenade/tris.md2");
- grenade.owner = self;
- grenade.touch = GameWeaponAdapters.Grenade_Touch;
- grenade.nextthink = GameBase.level.time + timer;
- grenade.think = GameWeaponAdapters.Grenade_Explode;
- grenade.dmg = damage;
- grenade.dmg_radius = damage_radius;
- grenade.classname = "grenade";
-
- GameBase.gi.linkentity(grenade);
- }
- public static void fire_grenade2(
- edict_t self,
- float[] start,
- float[] aimdir,
- int damage,
- int speed,
- float timer,
- float damage_radius,
- boolean held)
- {
- edict_t grenade;
- float[] dir = { 0, 0, 0 };
- float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 };
-
- Math3D.vectoangles(aimdir, dir);
- Math3D.AngleVectors(dir, forward, right, up);
-
- grenade = GameUtil.G_Spawn();
- Math3D.VectorCopy(start, grenade.s.origin);
- Math3D.VectorScale(aimdir, speed, grenade.velocity);
- Math3D.VectorMA(grenade.velocity, 200f + Lib.crandom() * 10.0f, up, grenade.velocity);
- Math3D.VectorMA(grenade.velocity, Lib.crandom() * 10.0f, right, grenade.velocity);
- Math3D.VectorSet(grenade.avelocity, 300f, 300f, 300f);
- grenade.movetype = Defines.MOVETYPE_BOUNCE;
- grenade.clipmask = Defines.MASK_SHOT;
- grenade.solid = Defines.SOLID_BBOX;
- grenade.s.effects |= Defines.EF_GRENADE;
- Math3D.VectorClear(grenade.mins);
- Math3D.VectorClear(grenade.maxs);
- grenade.s.modelindex = GameBase.gi.modelindex("models/objects/grenade2/tris.md2");
- grenade.owner = self;
- grenade.touch = GameWeaponAdapters.Grenade_Touch;
- grenade.nextthink = GameBase.level.time + timer;
- grenade.think = GameWeaponAdapters.Grenade_Explode;
- grenade.dmg = damage;
- grenade.dmg_radius = damage_radius;
- grenade.classname = "hgrenade";
- if (held)
- grenade.spawnflags = 3;
- else
- grenade.spawnflags = 1;
- grenade.s.sound = GameBase.gi.soundindex("weapons/hgrenc1b.wav");
-
- if (timer <= 0.0)
- GameWeaponAdapters.Grenade_Explode.think(grenade);
- else
- {
- GameBase.gi.sound(self, Defines.CHAN_WEAPON, GameBase.gi.soundindex("weapons/hgrent1a.wav"), 1, Defines.ATTN_NORM, 0);
- GameBase.gi.linkentity(grenade);
- }
- }
- public static void fire_rocket(
- edict_t self,
- float[] start,
- float[] dir,
- int damage,
- int speed,
- float damage_radius,
- int radius_damage)
- {
- edict_t rocket;
-
- rocket = GameUtil.G_Spawn();
- Math3D.VectorCopy(start, rocket.s.origin);
- Math3D.VectorCopy(dir, rocket.movedir);
- Math3D.vectoangles(dir, rocket.s.angles);
- Math3D.VectorScale(dir, speed, rocket.velocity);
- rocket.movetype = Defines.MOVETYPE_FLYMISSILE;
- rocket.clipmask = Defines.MASK_SHOT;
- rocket.solid = Defines.SOLID_BBOX;
- rocket.s.effects |= Defines.EF_ROCKET;
- Math3D.VectorClear(rocket.mins);
- Math3D.VectorClear(rocket.maxs);
- rocket.s.modelindex = GameBase.gi.modelindex("models/objects/rocket/tris.md2");
- rocket.owner = self;
- rocket.touch = GameWeaponAdapters.rocket_touch;
- rocket.nextthink = GameBase.level.time + 8000 / speed;
- rocket.think = GameUtilAdapters.G_FreeEdictA;
- rocket.dmg = damage;
- rocket.radius_dmg = radius_damage;
- rocket.dmg_radius = damage_radius;
- rocket.s.sound = GameBase.gi.soundindex("weapons/rockfly.wav");
- rocket.classname = "rocket";
-
- if (self.client != null)
- GameWeapon.check_dodge(self, rocket.s.origin, dir, speed);
-
- GameBase.gi.linkentity(rocket);
- }
- /*
- =================
- fire_rail
- =================
- */
- public static void fire_rail(edict_t self, float[] start, float[] aimdir, int damage, int kick)
- {
- float[] from = { 0, 0, 0 };
- float[] end = { 0, 0, 0 };
- trace_t tr = null;
- edict_t ignore;
- int mask;
- boolean water;
-
- Math3D.VectorMA(start, 8192f, aimdir, end);
- Math3D.VectorCopy(start, from);
- ignore = self;
- water = false;
- mask = Defines.MASK_SHOT | Defines.CONTENTS_SLIME | Defines.CONTENTS_LAVA;
- while (ignore != null)
- {
- tr = GameBase.gi.trace(from, null, null, end, ignore, mask);
-
- if ((tr.contents & (Defines.CONTENTS_SLIME | Defines.CONTENTS_LAVA)) != 0)
- {
- mask &= ~(Defines.CONTENTS_SLIME | Defines.CONTENTS_LAVA);
- water = true;
- }
- else
- {
- //ZOID--added so rail goes through SOLID_BBOX entities (gibs, etc)
- if ((tr.ent.svflags & Defines.SVF_MONSTER) != 0 || (tr.ent.client != null) || (tr.ent.solid == Defines.SOLID_BBOX))
- ignore = tr.ent;
- else
- ignore = null;
-
- if ((tr.ent != self) && (tr.ent.takedamage != 0))
- GameUtil.T_Damage(tr.ent, self, self, aimdir, tr.endpos, tr.plane.normal, damage, kick, 0, Defines.MOD_RAILGUN);
- }
-
- Math3D.VectorCopy(tr.endpos, from);
- }
-
- // send gun puff / flash
- GameBase.gi.WriteByte(Defines.svc_temp_entity);
- GameBase.gi.WriteByte(Defines.TE_RAILTRAIL);
- GameBase.gi.WritePosition(start);
- GameBase.gi.WritePosition(tr.endpos);
- GameBase.gi.multicast(self.s.origin, Defines.MULTICAST_PHS);
- // gi.multicast (start, MULTICAST_PHS);
- if (water)
- {
- GameBase.gi.WriteByte(Defines.svc_temp_entity);
- GameBase.gi.WriteByte(Defines.TE_RAILTRAIL);
- GameBase.gi.WritePosition(start);
- GameBase.gi.WritePosition(tr.endpos);
- GameBase.gi.multicast(tr.endpos, Defines.MULTICAST_PHS);
- }
-
- if (self.client != null)
- GameWeapon.PlayerNoise(self, tr.endpos, Defines.PNOISE_IMPACT);
- }
- public static void fire_bfg(edict_t self, float[] start, float[] dir, int damage, int speed, float damage_radius)
- {
- edict_t bfg;
-
- bfg = GameUtil.G_Spawn();
- Math3D.VectorCopy(start, bfg.s.origin);
- Math3D.VectorCopy(dir, bfg.movedir);
- Math3D.vectoangles(dir, bfg.s.angles);
- Math3D.VectorScale(dir, speed, bfg.velocity);
- bfg.movetype = Defines.MOVETYPE_FLYMISSILE;
- bfg.clipmask = Defines.MASK_SHOT;
- bfg.solid = Defines.SOLID_BBOX;
- bfg.s.effects |= Defines.EF_BFG | Defines.EF_ANIM_ALLFAST;
- Math3D.VectorClear(bfg.mins);
- Math3D.VectorClear(bfg.maxs);
- bfg.s.modelindex = GameBase.gi.modelindex("sprites/s_bfg1.sp2");
- bfg.owner = self;
- bfg.touch = GameWeaponAdapters.bfg_touch;
- bfg.nextthink = GameBase.level.time + 8000 / speed;
- bfg.think = GameUtilAdapters.G_FreeEdictA;
- bfg.radius_dmg = damage;
- bfg.dmg_radius = damage_radius;
- bfg.classname = "bfg blast";
- bfg.s.sound = GameBase.gi.soundindex("weapons/bfg__l1a.wav");
-
- bfg.think = GameWeaponAdapters.bfg_think;
- bfg.nextthink = GameBase.level.time + Defines.FRAMETIME;
- bfg.teammaster = bfg;
- bfg.teamchain = null;
-
- if (self.client != null)
- GameWeapon.check_dodge(self, bfg.s.origin, dir, speed);
-
- GameBase.gi.linkentity(bfg);
- }
-}
+public class Fire {
+ /*
+ * ================= fire_hit
+ *
+ * Used for all impact (hit/punch/slash) attacks =================
+ */
+ public static boolean fire_hit(edict_t self, float[] aim, int damage,
+ int kick) {
+ trace_t tr;
+ float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 };
+ float[] v = { 0, 0, 0 };
+ float[] point = { 0, 0, 0 };
+ float range;
+ float[] dir = { 0, 0, 0 };
+
+ //see if enemy is in range
+ Math3D.VectorSubtract(self.enemy.s.origin, self.s.origin, dir);
+ range = Math3D.VectorLength(dir);
+ if (range > aim[0])
+ return false;
+
+ if (aim[1] > self.mins[0] && aim[1] < self.maxs[0]) {
+ // the hit is straight on so back the range up to the edge of their
+ // bbox
+ range -= self.enemy.maxs[0];
+ } else {
+ // this is a side hit so adjust the "right" value out to the edge of
+ // their bbox
+ if (aim[1] < 0)
+ aim[1] = self.enemy.mins[0];
+ else
+ aim[1] = self.enemy.maxs[0];
+ }
+
+ Math3D.VectorMA(self.s.origin, range, dir, point);
+
+ tr = GameBase.gi.trace(self.s.origin, null, null, point, self,
+ Defines.MASK_SHOT);
+ if (tr.fraction < 1) {
+ if (0 == tr.ent.takedamage)
+ return false;
+ // if it will hit any client/monster then hit the one we wanted to
+ // hit
+ if ((tr.ent.svflags & Defines.SVF_MONSTER) != 0
+ || (tr.ent.client != null))
+ tr.ent = self.enemy;
+ }
+
+ Math3D.AngleVectors(self.s.angles, forward, right, up);
+ Math3D.VectorMA(self.s.origin, range, forward, point);
+ Math3D.VectorMA(point, aim[1], right, point);
+ Math3D.VectorMA(point, aim[2], up, point);
+ Math3D.VectorSubtract(point, self.enemy.s.origin, dir);
+
+ // do the damage
+ GameUtil.T_Damage(tr.ent, self, self, dir, point, Globals.vec3_origin,
+ damage, kick / 2, Defines.DAMAGE_NO_KNOCKBACK, Defines.MOD_HIT);
+
+ if (0 == (tr.ent.svflags & Defines.SVF_MONSTER)
+ && (null == tr.ent.client))
+ return false;
+
+ // do our special form of knockback here
+ Math3D.VectorMA(self.enemy.absmin, 0.5f, self.enemy.size, v);
+ Math3D.VectorSubtract(v, point, v);
+ Math3D.VectorNormalize(v);
+ Math3D.VectorMA(self.enemy.velocity, kick, v, self.enemy.velocity);
+ if (self.enemy.velocity[2] > 0)
+ self.enemy.groundentity = null;
+ return true;
+ }
+
+ /*
+ * ================= fire_lead
+ *
+ * This is an internal support routine used for bullet/pellet based weapons.
+ * =================
+ */
+ public static void fire_lead(edict_t self, float[] start, float[] aimdir,
+ int damage, int kick, int te_impact, int hspread, int vspread,
+ int mod) {
+ trace_t tr;
+ float[] dir = { 0, 0, 0 };
+ float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 };
+ float[] end = { 0, 0, 0 };
+ float r;
+ float u;
+ float[] water_start = { 0, 0, 0 };
+ boolean water = false;
+ int content_mask = Defines.MASK_SHOT | Defines.MASK_WATER;
+
+ tr = GameBase.gi.trace(self.s.origin, null, null, start, self,
+ Defines.MASK_SHOT);
+ if (!(tr.fraction < 1.0)) {
+ Math3D.vectoangles(aimdir, dir);
+ Math3D.AngleVectors(dir, forward, right, up);
+
+ r = Lib.crandom() * hspread;
+ u = Lib.crandom() * vspread;
+ Math3D.VectorMA(start, 8192, forward, end);
+ Math3D.VectorMA(end, r, right, end);
+ Math3D.VectorMA(end, u, up, end);
+
+ if ((GameBase.gi.pointcontents.pointcontents(start) & Defines.MASK_WATER) != 0) {
+ water = true;
+ Math3D.VectorCopy(start, water_start);
+ content_mask &= ~Defines.MASK_WATER;
+ }
+
+ tr = GameBase.gi.trace(start, null, null, end, self, content_mask);
+
+ // see if we hit water
+ if ((tr.contents & Defines.MASK_WATER) != 0) {
+ int color;
+
+ water = true;
+ Math3D.VectorCopy(tr.endpos, water_start);
+
+ if (0 == Math3D.VectorCompare(start, tr.endpos)) {
+ if ((tr.contents & Defines.CONTENTS_WATER) != 0) {
+ if (Lib.strcmp(tr.surface.name, "*brwater") == 0)
+ color = Defines.SPLASH_BROWN_WATER;
+ else
+ color = Defines.SPLASH_BLUE_WATER;
+ } else if ((tr.contents & Defines.CONTENTS_SLIME) != 0)
+ color = Defines.SPLASH_SLIME;
+ else if ((tr.contents & Defines.CONTENTS_LAVA) != 0)
+ color = Defines.SPLASH_LAVA;
+ else
+ color = Defines.SPLASH_UNKNOWN;
+
+ if (color != Defines.SPLASH_UNKNOWN) {
+ GameBase.gi.WriteByte(Defines.svc_temp_entity);
+ GameBase.gi.WriteByte(Defines.TE_SPLASH);
+ GameBase.gi.WriteByte(8);
+ GameBase.gi.WritePosition(tr.endpos);
+ GameBase.gi.WriteDir(tr.plane.normal);
+ GameBase.gi.WriteByte(color);
+ GameBase.gi.multicast(tr.endpos, Defines.MULTICAST_PVS);
+ }
+
+ // change bullet's course when it enters water
+ Math3D.VectorSubtract(end, start, dir);
+ Math3D.vectoangles(dir, dir);
+ Math3D.AngleVectors(dir, forward, right, up);
+ r = Lib.crandom() * hspread * 2;
+ u = Lib.crandom() * vspread * 2;
+ Math3D.VectorMA(water_start, 8192, forward, end);
+ Math3D.VectorMA(end, r, right, end);
+ Math3D.VectorMA(end, u, up, end);
+ }
+
+ // re-trace ignoring water this time
+ tr = GameBase.gi.trace(water_start, null, null, end, self,
+ Defines.MASK_SHOT);
+ }
+ }
+
+ // send gun puff / flash
+ if (!((tr.surface != null) && 0 != (tr.surface.flags & Defines.SURF_SKY))) {
+ if (tr.fraction < 1.0) {
+ if (tr.ent.takedamage != 0) {
+ GameUtil.T_Damage(tr.ent, self, self, aimdir, tr.endpos,
+ tr.plane.normal, damage, kick,
+ Defines.DAMAGE_BULLET, mod);
+ } else {
+ if (!"sky".equals(tr.surface.name)) {
+ GameBase.gi.WriteByte(Defines.svc_temp_entity);
+ GameBase.gi.WriteByte(te_impact);
+ GameBase.gi.WritePosition(tr.endpos);
+ GameBase.gi.WriteDir(tr.plane.normal);
+ GameBase.gi.multicast(tr.endpos, Defines.MULTICAST_PVS);
+
+ if (self.client != null)
+ GameWeapon.PlayerNoise(self, tr.endpos,
+ Defines.PNOISE_IMPACT);
+ }
+ }
+ }
+ }
+
+ // if went through water, determine where the end and make a bubble
+ // trail
+ if (water) {
+ float[] pos = { 0, 0, 0 };
+
+ Math3D.VectorSubtract(tr.endpos, water_start, dir);
+ Math3D.VectorNormalize(dir);
+ Math3D.VectorMA(tr.endpos, -2, dir, pos);
+ if ((GameBase.gi.pointcontents.pointcontents(pos) & Defines.MASK_WATER) != 0)
+ Math3D.VectorCopy(pos, tr.endpos);
+ else
+ tr = GameBase.gi.trace(pos, null, null, water_start, tr.ent,
+ Defines.MASK_WATER);
+
+ Math3D.VectorAdd(water_start, tr.endpos, pos);
+ Math3D.VectorScale(pos, 0.5f, pos);
+
+ GameBase.gi.WriteByte(Defines.svc_temp_entity);
+ GameBase.gi.WriteByte(Defines.TE_BUBBLETRAIL);
+ GameBase.gi.WritePosition(water_start);
+ GameBase.gi.WritePosition(tr.endpos);
+ GameBase.gi.multicast(pos, Defines.MULTICAST_PVS);
+ }
+ }
+
+ /*
+ * ================= fire_bullet
+ *
+ * Fires a single round. Used for machinegun and chaingun. Would be fine for
+ * pistols, rifles, etc.... =================
+ */
+ public static void fire_bullet(edict_t self, float[] start, float[] aimdir,
+ int damage, int kick, int hspread, int vspread, int mod) {
+ fire_lead(self, start, aimdir, damage, kick, Defines.TE_GUNSHOT,
+ hspread, vspread, mod);
+ }
+
+ /*
+ * ================= fire_shotgun
+ *
+ * Shoots shotgun pellets. Used by shotgun and super shotgun.
+ * =================
+ */
+ public static void fire_shotgun(edict_t self, float[] start,
+ float[] aimdir, int damage, int kick, int hspread, int vspread,
+ int count, int mod) {
+ int i;
+
+ for (i = 0; i < count; i++)
+ fire_lead(self, start, aimdir, damage, kick, Defines.TE_SHOTGUN,
+ hspread, vspread, mod);
+ }
+
+ public static void fire_blaster(edict_t self, float[] start, float[] dir,
+ int damage, int speed, int effect, boolean hyper) {
+ edict_t bolt;
+ trace_t tr;
+
+ Math3D.VectorNormalize(dir);
+
+ bolt = GameUtil.G_Spawn();
+ bolt.svflags = Defines.SVF_DEADMONSTER;
+ // yes, I know it looks weird that projectiles are deadmonsters
+ // what this means is that when prediction is used against the object
+ // (blaster/hyperblaster shots), the player won't be solid clipped
+ // against
+ // the object. Right now trying to run into a firing hyperblaster
+ // is very jerky since you are predicted 'against' the shots.
+ Math3D.VectorCopy(start, bolt.s.origin);
+ Math3D.VectorCopy(start, bolt.s.old_origin);
+ Math3D.vectoangles(dir, bolt.s.angles);
+ Math3D.VectorScale(dir, speed, bolt.velocity);
+ bolt.movetype = Defines.MOVETYPE_FLYMISSILE;
+ bolt.clipmask = Defines.MASK_SHOT;
+ bolt.solid = Defines.SOLID_BBOX;
+ bolt.s.effects |= effect;
+ Math3D.VectorClear(bolt.mins);
+ Math3D.VectorClear(bolt.maxs);
+ bolt.s.modelindex = GameBase.gi
+ .modelindex("models/objects/laser/tris.md2");
+ bolt.s.sound = GameBase.gi.soundindex("misc/lasfly.wav");
+ bolt.owner = self;
+ bolt.touch = GameWeapon.blaster_touch;
+ bolt.nextthink = GameBase.level.time + 2;
+ bolt.think = GameUtil.G_FreeEdictA;
+ bolt.dmg = damage;
+ bolt.classname = "bolt";
+ if (hyper)
+ bolt.spawnflags = 1;
+ GameBase.gi.linkentity(bolt);
+
+ if (self.client != null)
+ GameWeapon.check_dodge(self, bolt.s.origin, dir, speed);
+
+ tr = GameBase.gi.trace(self.s.origin, null, null, bolt.s.origin, bolt,
+ Defines.MASK_SHOT);
+ if (tr.fraction < 1.0) {
+ Math3D.VectorMA(bolt.s.origin, -10, dir, bolt.s.origin);
+ bolt.touch.touch(bolt, tr.ent, GameBase.dummyplane, null);
+ }
+ }
+
+ /*
+ * ================= fire_grenade =================
+ */
+
+ public static void fire_grenade(edict_t self, float[] start,
+ float[] aimdir, int damage, int speed, float timer,
+ float damage_radius) {
+ edict_t grenade;
+ float[] dir = { 0, 0, 0 };
+ float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 };
+
+ Math3D.vectoangles(aimdir, dir);
+ Math3D.AngleVectors(dir, forward, right, up);
+
+ grenade = GameUtil.G_Spawn();
+ Math3D.VectorCopy(start, grenade.s.origin);
+ Math3D.VectorScale(aimdir, speed, grenade.velocity);
+ Math3D.VectorMA(grenade.velocity, 200f + Lib.crandom() * 10.0f, up,
+ grenade.velocity);
+ Math3D.VectorMA(grenade.velocity, Lib.crandom() * 10.0f, right,
+ grenade.velocity);
+ Math3D.VectorSet(grenade.avelocity, 300, 300, 300);
+ grenade.movetype = Defines.MOVETYPE_BOUNCE;
+ grenade.clipmask = Defines.MASK_SHOT;
+ grenade.solid = Defines.SOLID_BBOX;
+ grenade.s.effects |= Defines.EF_GRENADE;
+ Math3D.VectorClear(grenade.mins);
+ Math3D.VectorClear(grenade.maxs);
+ grenade.s.modelindex = GameBase.gi
+ .modelindex("models/objects/grenade/tris.md2");
+ grenade.owner = self;
+ grenade.touch = GameWeapon.Grenade_Touch;
+ grenade.nextthink = GameBase.level.time + timer;
+ grenade.think = GameWeapon.Grenade_Explode;
+ grenade.dmg = damage;
+ grenade.dmg_radius = damage_radius;
+ grenade.classname = "grenade";
+
+ GameBase.gi.linkentity(grenade);
+ }
+
+ public static void fire_grenade2(edict_t self, float[] start,
+ float[] aimdir, int damage, int speed, float timer,
+ float damage_radius, boolean held) {
+ edict_t grenade;
+ float[] dir = { 0, 0, 0 };
+ float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 };
+
+ Math3D.vectoangles(aimdir, dir);
+ Math3D.AngleVectors(dir, forward, right, up);
+
+ grenade = GameUtil.G_Spawn();
+ Math3D.VectorCopy(start, grenade.s.origin);
+ Math3D.VectorScale(aimdir, speed, grenade.velocity);
+ Math3D.VectorMA(grenade.velocity, 200f + Lib.crandom() * 10.0f, up,
+ grenade.velocity);
+ Math3D.VectorMA(grenade.velocity, Lib.crandom() * 10.0f, right,
+ grenade.velocity);
+ Math3D.VectorSet(grenade.avelocity, 300f, 300f, 300f);
+ grenade.movetype = Defines.MOVETYPE_BOUNCE;
+ grenade.clipmask = Defines.MASK_SHOT;
+ grenade.solid = Defines.SOLID_BBOX;
+ grenade.s.effects |= Defines.EF_GRENADE;
+ Math3D.VectorClear(grenade.mins);
+ Math3D.VectorClear(grenade.maxs);
+ grenade.s.modelindex = GameBase.gi
+ .modelindex("models/objects/grenade2/tris.md2");
+ grenade.owner = self;
+ grenade.touch = GameWeapon.Grenade_Touch;
+ grenade.nextthink = GameBase.level.time + timer;
+ grenade.think = GameWeapon.Grenade_Explode;
+ grenade.dmg = damage;
+ grenade.dmg_radius = damage_radius;
+ grenade.classname = "hgrenade";
+ if (held)
+ grenade.spawnflags = 3;
+ else
+ grenade.spawnflags = 1;
+ grenade.s.sound = GameBase.gi.soundindex("weapons/hgrenc1b.wav");
+
+ if (timer <= 0.0)
+ GameWeapon.Grenade_Explode.think(grenade);
+ else {
+ GameBase.gi.sound(self, Defines.CHAN_WEAPON, GameBase.gi
+ .soundindex("weapons/hgrent1a.wav"), 1, Defines.ATTN_NORM,
+ 0);
+ GameBase.gi.linkentity(grenade);
+ }
+ }
+
+ public static void fire_rocket(edict_t self, float[] start, float[] dir,
+ int damage, int speed, float damage_radius, int radius_damage) {
+ edict_t rocket;
+
+ rocket = GameUtil.G_Spawn();
+ Math3D.VectorCopy(start, rocket.s.origin);
+ Math3D.VectorCopy(dir, rocket.movedir);
+ Math3D.vectoangles(dir, rocket.s.angles);
+ Math3D.VectorScale(dir, speed, rocket.velocity);
+ rocket.movetype = Defines.MOVETYPE_FLYMISSILE;
+ rocket.clipmask = Defines.MASK_SHOT;
+ rocket.solid = Defines.SOLID_BBOX;
+ rocket.s.effects |= Defines.EF_ROCKET;
+ Math3D.VectorClear(rocket.mins);
+ Math3D.VectorClear(rocket.maxs);
+ rocket.s.modelindex = GameBase.gi
+ .modelindex("models/objects/rocket/tris.md2");
+ rocket.owner = self;
+ rocket.touch = GameWeapon.rocket_touch;
+ rocket.nextthink = GameBase.level.time + 8000 / speed;
+ rocket.think = GameUtil.G_FreeEdictA;
+ rocket.dmg = damage;
+ rocket.radius_dmg = radius_damage;
+ rocket.dmg_radius = damage_radius;
+ rocket.s.sound = GameBase.gi.soundindex("weapons/rockfly.wav");
+ rocket.classname = "rocket";
+
+ if (self.client != null)
+ GameWeapon.check_dodge(self, rocket.s.origin, dir, speed);
+
+ GameBase.gi.linkentity(rocket);
+ }
+
+ /*
+ * ================= fire_rail =================
+ */
+ public static void fire_rail(edict_t self, float[] start, float[] aimdir,
+ int damage, int kick) {
+ float[] from = { 0, 0, 0 };
+ float[] end = { 0, 0, 0 };
+ trace_t tr = null;
+ edict_t ignore;
+ int mask;
+ boolean water;
+
+ Math3D.VectorMA(start, 8192f, aimdir, end);
+ Math3D.VectorCopy(start, from);
+ ignore = self;
+ water = false;
+ mask = Defines.MASK_SHOT | Defines.CONTENTS_SLIME
+ | Defines.CONTENTS_LAVA;
+ while (ignore != null) {
+ tr = GameBase.gi.trace(from, null, null, end, ignore, mask);
+
+ if ((tr.contents & (Defines.CONTENTS_SLIME | Defines.CONTENTS_LAVA)) != 0) {
+ mask &= ~(Defines.CONTENTS_SLIME | Defines.CONTENTS_LAVA);
+ water = true;
+ } else {
+ //ZOID--added so rail goes through SOLID_BBOX entities (gibs,
+ // etc)
+ if ((tr.ent.svflags & Defines.SVF_MONSTER) != 0
+ || (tr.ent.client != null)
+ || (tr.ent.solid == Defines.SOLID_BBOX))
+ ignore = tr.ent;
+ else
+ ignore = null;
+
+ if ((tr.ent != self) && (tr.ent.takedamage != 0))
+ GameUtil.T_Damage(tr.ent, self, self, aimdir, tr.endpos,
+ tr.plane.normal, damage, kick, 0,
+ Defines.MOD_RAILGUN);
+ }
+
+ Math3D.VectorCopy(tr.endpos, from);
+ }
+
+ // send gun puff / flash
+ GameBase.gi.WriteByte(Defines.svc_temp_entity);
+ GameBase.gi.WriteByte(Defines.TE_RAILTRAIL);
+ GameBase.gi.WritePosition(start);
+ GameBase.gi.WritePosition(tr.endpos);
+ GameBase.gi.multicast(self.s.origin, Defines.MULTICAST_PHS);
+ // gi.multicast (start, MULTICAST_PHS);
+ if (water) {
+ GameBase.gi.WriteByte(Defines.svc_temp_entity);
+ GameBase.gi.WriteByte(Defines.TE_RAILTRAIL);
+ GameBase.gi.WritePosition(start);
+ GameBase.gi.WritePosition(tr.endpos);
+ GameBase.gi.multicast(tr.endpos, Defines.MULTICAST_PHS);
+ }
+
+ if (self.client != null)
+ GameWeapon.PlayerNoise(self, tr.endpos, Defines.PNOISE_IMPACT);
+ }
+
+ public static void fire_bfg(edict_t self, float[] start, float[] dir,
+ int damage, int speed, float damage_radius) {
+ edict_t bfg;
+
+ bfg = GameUtil.G_Spawn();
+ Math3D.VectorCopy(start, bfg.s.origin);
+ Math3D.VectorCopy(dir, bfg.movedir);
+ Math3D.vectoangles(dir, bfg.s.angles);
+ Math3D.VectorScale(dir, speed, bfg.velocity);
+ bfg.movetype = Defines.MOVETYPE_FLYMISSILE;
+ bfg.clipmask = Defines.MASK_SHOT;
+ bfg.solid = Defines.SOLID_BBOX;
+ bfg.s.effects |= Defines.EF_BFG | Defines.EF_ANIM_ALLFAST;
+ Math3D.VectorClear(bfg.mins);
+ Math3D.VectorClear(bfg.maxs);
+ bfg.s.modelindex = GameBase.gi.modelindex("sprites/s_bfg1.sp2");
+ bfg.owner = self;
+ bfg.touch = GameWeapon.bfg_touch;
+ bfg.nextthink = GameBase.level.time + 8000 / speed;
+ bfg.think = GameUtil.G_FreeEdictA;
+ bfg.radius_dmg = damage;
+ bfg.dmg_radius = damage_radius;
+ bfg.classname = "bfg blast";
+ bfg.s.sound = GameBase.gi.soundindex("weapons/bfg__l1a.wav");
+
+ bfg.think = GameWeapon.bfg_think;
+ bfg.nextthink = GameBase.level.time + Defines.FRAMETIME;
+ bfg.teammaster = bfg;
+ bfg.teamchain = null;
+
+ if (self.client != null)
+ GameWeapon.check_dodge(self, bfg.s.origin, dir, speed);
+
+ GameBase.gi.linkentity(bfg);
+ }
+} \ No newline at end of file