Quake II RTX doxygen  1.0 dev
g_weapon.c File Reference
#include "g_local.h"

Go to the source code of this file.

Functions

static void check_dodge (edict_t *self, vec3_t start, vec3_t dir, int speed)
 
qboolean fire_hit (edict_t *self, vec3_t aim, int damage, int kick)
 
static void fire_lead (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int te_impact, int hspread, int vspread, int mod)
 
void fire_bullet (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int mod)
 
void fire_shotgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int count, int mod)
 
void blaster_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
 
void fire_blaster (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int effect, qboolean hyper)
 
void Grenade_Explode (edict_t *ent)
 
void Grenade_Touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
 
void fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius)
 
void fire_grenade2 (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius, qboolean held)
 
void rocket_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
 
void fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, int radius_damage)
 
void fire_rail (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick)
 
void bfg_explode (edict_t *self)
 
void bfg_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
 
void bfg_think (edict_t *self)
 
void fire_bfg (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius)
 
void flare_sparks (edict_t *self)
 
void flare_think (edict_t *self)
 
void flare_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
 
void fire_flaregun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius)
 

Function Documentation

◆ bfg_explode()

void bfg_explode ( edict_t *  self)

Definition at line 675 of file g_weapon.c.

676 {
677  edict_t *ent;
678  float points;
679  vec3_t v;
680  float dist;
681 
682  if (self->s.frame == 0) {
683  // the BFG effect
684  ent = NULL;
685  while ((ent = findradius(ent, self->s.origin, self->dmg_radius)) != NULL) {
686  if (!ent->takedamage)
687  continue;
688  if (ent == self->owner)
689  continue;
690  if (!CanDamage(ent, self))
691  continue;
692  if (!CanDamage(ent, self->owner))
693  continue;
694 
695  VectorAdd(ent->mins, ent->maxs, v);
696  VectorMA(ent->s.origin, 0.5, v, v);
697  VectorSubtract(self->s.origin, v, v);
698  dist = VectorLength(v);
699  points = self->radius_dmg * (1.0 - sqrt(dist / self->dmg_radius));
700  if (ent == self->owner)
701  points = points * 0.5;
702 
703  gi.WriteByte(svc_temp_entity);
704  gi.WriteByte(TE_BFG_EXPLOSION);
705  gi.WritePosition(ent->s.origin);
706  gi.multicast(ent->s.origin, MULTICAST_PHS);
707  T_Damage(ent, self, self->owner, self->velocity, ent->s.origin, vec3_origin, (int)points, 0, DAMAGE_ENERGY, MOD_BFG_EFFECT);
708  }
709  }
710 
711  self->nextthink = level.time + FRAMETIME;
712  self->s.frame++;
713  if (self->s.frame == 5)
714  self->think = G_FreeEdict;
715 }

Referenced by bfg_touch().

◆ bfg_think()

void bfg_think ( edict_t *  self)

Definition at line 755 of file g_weapon.c.

756 {
757  edict_t *ent;
758  edict_t *ignore;
759  vec3_t point;
760  vec3_t dir;
761  vec3_t start;
762  vec3_t end;
763  int dmg;
764  trace_t tr;
765 
766  if (deathmatch->value)
767  dmg = 5;
768  else
769  dmg = 10;
770 
771  ent = NULL;
772  while ((ent = findradius(ent, self->s.origin, 256)) != NULL) {
773  if (ent == self)
774  continue;
775 
776  if (ent == self->owner)
777  continue;
778 
779  if (!ent->takedamage)
780  continue;
781 
782  if (!(ent->svflags & SVF_MONSTER) && (!ent->client) && (strcmp(ent->classname, "misc_explobox") != 0))
783  continue;
784 
785  VectorMA(ent->absmin, 0.5, ent->size, point);
786 
787  VectorSubtract(point, self->s.origin, dir);
788  VectorNormalize(dir);
789 
790  ignore = self;
791  VectorCopy(self->s.origin, start);
792  VectorMA(start, 2048, dir, end);
793  while (1) {
794  tr = gi.trace(start, NULL, NULL, end, ignore, CONTENTS_SOLID | CONTENTS_MONSTER | CONTENTS_DEADMONSTER);
795 
796  if (!tr.ent)
797  break;
798 
799  // hurt it if we can
800  if ((tr.ent->takedamage) && !(tr.ent->flags & FL_IMMUNE_LASER) && (tr.ent != self->owner))
801  T_Damage(tr.ent, self, self->owner, dir, tr.endpos, vec3_origin, dmg, 1, DAMAGE_ENERGY, MOD_BFG_LASER);
802 
803  // if we hit something that's not a monster or player we're done
804  if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client)) {
805  gi.WriteByte(svc_temp_entity);
806  gi.WriteByte(TE_LASER_SPARKS);
807  gi.WriteByte(4);
808  gi.WritePosition(tr.endpos);
809  gi.WriteDir(tr.plane.normal);
810  gi.WriteByte(self->s.skinnum);
811  gi.multicast(tr.endpos, MULTICAST_PVS);
812  break;
813  }
814 
815  ignore = tr.ent;
816  VectorCopy(tr.endpos, start);
817  }
818 
819  gi.WriteByte(svc_temp_entity);
820  gi.WriteByte(TE_BFG_LASER);
821  gi.WritePosition(self->s.origin);
822  gi.WritePosition(tr.endpos);
823  gi.multicast(self->s.origin, MULTICAST_PHS);
824  }
825 
826  self->nextthink = level.time + FRAMETIME;
827 }

Referenced by fire_bfg().

◆ bfg_touch()

void bfg_touch ( edict_t *  self,
edict_t *  other,
cplane_t *  plane,
csurface_t *  surf 
)

Definition at line 717 of file g_weapon.c.

718 {
719  if (other == self->owner)
720  return;
721 
722  if (surf && (surf->flags & SURF_SKY)) {
723  G_FreeEdict(self);
724  return;
725  }
726 
727  if (self->owner->client)
728  PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT);
729 
730  // core explosion - prevents firing it into the wall/floor
731  if (other->takedamage)
732  T_Damage(other, self, self->owner, self->velocity, self->s.origin, plane->normal, 200, 0, 0, MOD_BFG_BLAST);
733  T_RadiusDamage(self, self->owner, 200, other, 100, MOD_BFG_BLAST);
734 
735  gi.sound(self, CHAN_VOICE, gi.soundindex("weapons/bfg__x1b.wav"), 1, ATTN_NORM, 0);
736  self->solid = SOLID_NOT;
737  self->touch = NULL;
738  VectorMA(self->s.origin, -1 * FRAMETIME, self->velocity, self->s.origin);
739  VectorClear(self->velocity);
740  self->s.modelindex = gi.modelindex("sprites/s_bfg3.sp2");
741  self->s.frame = 0;
742  self->s.sound = 0;
743  self->s.effects &= ~EF_ANIM_ALLFAST;
744  self->think = bfg_explode;
745  self->nextthink = level.time + FRAMETIME;
746  self->enemy = other;
747 
748  gi.WriteByte(svc_temp_entity);
749  gi.WriteByte(TE_BFG_BIGEXPLOSION);
750  gi.WritePosition(self->s.origin);
751  gi.multicast(self->s.origin, MULTICAST_PVS);
752 }

Referenced by fire_bfg().

◆ blaster_touch()

void blaster_touch ( edict_t *  self,
edict_t *  other,
cplane_t *  plane,
csurface_t *  surf 
)

Definition at line 284 of file g_weapon.c.

285 {
286  int mod;
287 
288  if (other == self->owner)
289  return;
290 
291  if (surf && (surf->flags & SURF_SKY)) {
292  G_FreeEdict(self);
293  return;
294  }
295 
296  if (self->owner->client)
297  PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT);
298 
299  if (other->takedamage) {
300  if (self->spawnflags & 1)
301  mod = MOD_HYPERBLASTER;
302  else
303  mod = MOD_BLASTER;
304  T_Damage(other, self, self->owner, self->velocity, self->s.origin, plane->normal, self->dmg, 1, DAMAGE_ENERGY, mod);
305  } else {
306  gi.WriteByte(svc_temp_entity);
307  gi.WriteByte(TE_BLASTER);
308  gi.WritePosition(self->s.origin);
309  if (!plane)
310  gi.WriteDir(vec3_origin);
311  else
312  gi.WriteDir(plane->normal);
313  gi.multicast(self->s.origin, MULTICAST_PVS);
314  }
315 
316  G_FreeEdict(self);
317 }

Referenced by fire_blaster().

◆ check_dodge()

static void check_dodge ( edict_t *  self,
vec3_t  start,
vec3_t  dir,
int  speed 
)
static

Definition at line 30 of file g_weapon.c.

31 {
32  vec3_t end;
33  vec3_t v;
34  trace_t tr;
35  float eta;
36 
37  // easy mode only ducks one quarter the time
38  if (skill->value == 0) {
39  if (random() > 0.25)
40  return;
41  }
42  VectorMA(start, 8192, dir, end);
43  tr = gi.trace(start, NULL, NULL, end, self, MASK_SHOT);
44  if ((tr.ent) && (tr.ent->svflags & SVF_MONSTER) && (tr.ent->health > 0) && (tr.ent->monsterinfo.dodge) && infront(tr.ent, self)) {
45  VectorSubtract(tr.endpos, start, v);
46  eta = (VectorLength(v) - tr.ent->maxs[0]) / speed;
47  tr.ent->monsterinfo.dodge(tr.ent, self, eta);
48  }
49 }

Referenced by fire_bfg(), fire_blaster(), and fire_rocket().

◆ fire_bfg()

void fire_bfg ( edict_t *  self,
vec3_t  start,
vec3_t  dir,
int  damage,
int  speed,
float  damage_radius 
)

Definition at line 830 of file g_weapon.c.

831 {
832  edict_t *bfg;
833 
834  bfg = G_Spawn();
835  VectorCopy(start, bfg->s.origin);
836  VectorCopy(dir, bfg->movedir);
837  vectoangles(dir, bfg->s.angles);
838  VectorScale(dir, speed, bfg->velocity);
839  bfg->movetype = MOVETYPE_FLYMISSILE;
840  bfg->clipmask = MASK_SHOT;
841  bfg->solid = SOLID_BBOX;
842  bfg->s.effects |= EF_BFG | EF_ANIM_ALLFAST;
843  VectorClear(bfg->mins);
844  VectorClear(bfg->maxs);
845  bfg->s.modelindex = gi.modelindex("sprites/s_bfg1.sp2");
846  bfg->owner = self;
847  bfg->touch = bfg_touch;
848  bfg->nextthink = level.time + 8000 / speed;
849  bfg->think = G_FreeEdict;
850  bfg->radius_dmg = damage;
851  bfg->dmg_radius = damage_radius;
852  bfg->classname = "bfg blast";
853  bfg->s.sound = gi.soundindex("weapons/bfg__l1a.wav");
854 
855  bfg->think = bfg_think;
856  bfg->nextthink = level.time + FRAMETIME;
857  bfg->teammaster = bfg;
858  bfg->teamchain = NULL;
859 
860  if (self->client)
861  check_dodge(self, bfg->s.origin, dir, speed);
862 
863  gi.linkentity(bfg);
864 }

Referenced by monster_fire_bfg(), and weapon_bfg_fire().

◆ fire_blaster()

void fire_blaster ( edict_t *  self,
vec3_t  start,
vec3_t  dir,
int  damage,
int  speed,
int  effect,
qboolean  hyper 
)

Definition at line 319 of file g_weapon.c.

320 {
321  edict_t *bolt;
322  trace_t tr;
323 
324  VectorNormalize(dir);
325 
326  bolt = G_Spawn();
327  bolt->svflags = SVF_DEADMONSTER;
328  // yes, I know it looks weird that projectiles are deadmonsters
329  // what this means is that when prediction is used against the object
330  // (blaster/hyperblaster shots), the player won't be solid clipped against
331  // the object. Right now trying to run into a firing hyperblaster
332  // is very jerky since you are predicted 'against' the shots.
333  VectorCopy(start, bolt->s.origin);
334  VectorCopy(start, bolt->s.old_origin);
335  vectoangles(dir, bolt->s.angles);
336  VectorScale(dir, speed, bolt->velocity);
337  bolt->movetype = MOVETYPE_FLYMISSILE;
338  bolt->clipmask = MASK_SHOT;
339  bolt->solid = SOLID_BBOX;
340  bolt->s.effects |= effect;
341  VectorClear(bolt->mins);
342  VectorClear(bolt->maxs);
343  bolt->s.modelindex = gi.modelindex("models/objects/laser/tris.md2");
344  bolt->s.sound = gi.soundindex("misc/lasfly.wav");
345  bolt->owner = self;
346  bolt->touch = blaster_touch;
347  bolt->nextthink = level.time + 2;
348  bolt->think = G_FreeEdict;
349  bolt->dmg = damage;
350  bolt->classname = "bolt";
351  if (hyper)
352  bolt->spawnflags = 1;
353  gi.linkentity(bolt);
354 
355  if (self->client)
356  check_dodge(self, bolt->s.origin, dir, speed);
357 
358  tr = gi.trace(self->s.origin, NULL, NULL, bolt->s.origin, bolt, MASK_SHOT);
359  if (tr.fraction < 1.0) {
360  VectorMA(bolt->s.origin, -10, dir, bolt->s.origin);
361  bolt->touch(bolt, tr.ent, NULL, NULL);
362  }
363 }

Referenced by Blaster_Fire(), monster_fire_blaster(), and use_target_blaster().

◆ fire_bullet()

void fire_bullet ( edict_t *  self,
vec3_t  start,
vec3_t  aimdir,
int  damage,
int  kick,
int  hspread,
int  vspread,
int  mod 
)

Definition at line 255 of file g_weapon.c.

256 {
257  fire_lead(self, start, aimdir, damage, kick, TE_GUNSHOT, hspread, vspread, mod);
258 }

Referenced by Chaingun_Fire(), Machinegun_Fire(), and monster_fire_bullet().

◆ fire_flaregun()

void fire_flaregun ( edict_t *  self,
vec3_t  start,
vec3_t  aimdir,
int  damage,
int  speed,
float  timer,
float  damage_radius 
)

Definition at line 956 of file g_weapon.c.

959 {
960  edict_t *flare;
961  vec3_t dir;
962  vec3_t forward, right, up;
963 
964  vectoangles(aimdir, dir);
965  AngleVectors(dir, forward, right, up);
966 
967  flare = G_Spawn();
968  VectorCopy(start, flare->s.origin);
969  VectorScale(aimdir, speed, flare->velocity);
970  VectorSet(flare->avelocity, 300, 300, 300);
971  flare->movetype = MOVETYPE_BOUNCE;
972  flare->clipmask = MASK_SHOT;
973  flare->solid = SOLID_BBOX;
974 
975  const float size = 4;
976  VectorSet(flare->mins, -size, -size, -size);
977  VectorSet(flare->maxs, size, size, size);
978 
979  flare->s.modelindex = gi.modelindex("models/objects/flare/tris.md2");
980  flare->owner = self;
981  flare->touch = flare_touch;
982  flare->nextthink = FRAMETIME;
983  flare->think = flare_think;
984  flare->radius_dmg = damage;
985  flare->dmg_radius = damage_radius;
986  flare->classname = "flare";
987  flare->timestamp = level.time + 15.0; //live for 15 seconds
988  gi.linkentity(flare);
989 }

Referenced by weapon_flaregun_fire().

◆ fire_grenade()

void fire_grenade ( edict_t *  self,
vec3_t  start,
vec3_t  aimdir,
int  damage,
int  speed,
float  timer,
float  damage_radius 
)

Definition at line 450 of file g_weapon.c.

451 {
452  edict_t *grenade;
453  vec3_t dir;
454  vec3_t forward, right, up;
455 
456  vectoangles(aimdir, dir);
457  AngleVectors(dir, forward, right, up);
458 
459  grenade = G_Spawn();
460  VectorCopy(start, grenade->s.origin);
461  VectorScale(aimdir, speed, grenade->velocity);
462  VectorMA(grenade->velocity, 200 + crandom() * 10.0, up, grenade->velocity);
463  VectorMA(grenade->velocity, crandom() * 10.0, right, grenade->velocity);
464  VectorSet(grenade->avelocity, 300, 300, 300);
465  grenade->movetype = MOVETYPE_BOUNCE;
466  grenade->clipmask = MASK_SHOT;
467  grenade->solid = SOLID_BBOX;
468  grenade->s.effects |= EF_GRENADE;
469  VectorClear(grenade->mins);
470  VectorClear(grenade->maxs);
471  grenade->s.modelindex = gi.modelindex("models/objects/grenade/tris.md2");
472  grenade->owner = self;
473  grenade->touch = Grenade_Touch;
474  grenade->nextthink = level.time + timer;
475  grenade->think = Grenade_Explode;
476  grenade->dmg = damage;
477  grenade->dmg_radius = damage_radius;
478  grenade->classname = "grenade";
479 
480  gi.linkentity(grenade);
481 }

Referenced by monster_fire_grenade(), and weapon_grenadelauncher_fire().

◆ fire_grenade2()

void fire_grenade2 ( edict_t *  self,
vec3_t  start,
vec3_t  aimdir,
int  damage,
int  speed,
float  timer,
float  damage_radius,
qboolean  held 
)

Definition at line 483 of file g_weapon.c.

484 {
485  edict_t *grenade;
486  vec3_t dir;
487  vec3_t forward, right, up;
488 
489  vectoangles(aimdir, dir);
490  AngleVectors(dir, forward, right, up);
491 
492  grenade = G_Spawn();
493  VectorCopy(start, grenade->s.origin);
494  VectorScale(aimdir, speed, grenade->velocity);
495  VectorMA(grenade->velocity, 200 + crandom() * 10.0, up, grenade->velocity);
496  VectorMA(grenade->velocity, crandom() * 10.0, right, grenade->velocity);
497  VectorSet(grenade->avelocity, 300, 300, 300);
498  grenade->movetype = MOVETYPE_BOUNCE;
499  grenade->clipmask = MASK_SHOT;
500  grenade->solid = SOLID_BBOX;
501  grenade->s.effects |= EF_GRENADE;
502  VectorClear(grenade->mins);
503  VectorClear(grenade->maxs);
504  grenade->s.modelindex = gi.modelindex("models/objects/grenade2/tris.md2");
505  grenade->owner = self;
506  grenade->touch = Grenade_Touch;
507  grenade->nextthink = level.time + timer;
508  grenade->think = Grenade_Explode;
509  grenade->dmg = damage;
510  grenade->dmg_radius = damage_radius;
511  grenade->classname = "hgrenade";
512  if (held)
513  grenade->spawnflags = 3;
514  else
515  grenade->spawnflags = 1;
516  grenade->s.sound = gi.soundindex("weapons/hgrenc1b.wav");
517 
518  if (timer <= 0.0)
519  Grenade_Explode(grenade);
520  else {
521  gi.sound(self, CHAN_WEAPON, gi.soundindex("weapons/hgrent1a.wav"), 1, ATTN_NORM, 0);
522  gi.linkentity(grenade);
523  }
524 }

Referenced by weapon_grenade_fire().

◆ fire_hit()

qboolean fire_hit ( edict_t *  self,
vec3_t  aim,
int  damage,
int  kick 
)

Definition at line 59 of file g_weapon.c.

60 {
61  trace_t tr;
62  vec3_t forward, right, up;
63  vec3_t v;
64  vec3_t point;
65  float range;
66  vec3_t dir;
67 
68  //see if enemy is in range
69  VectorSubtract(self->enemy->s.origin, self->s.origin, dir);
70  range = VectorLength(dir);
71  if (range > aim[0])
72  return qfalse;
73 
74  if (aim[1] > self->mins[0] && aim[1] < self->maxs[0]) {
75  // the hit is straight on so back the range up to the edge of their bbox
76  range -= self->enemy->maxs[0];
77  } else {
78  // this is a side hit so adjust the "right" value out to the edge of their bbox
79  if (aim[1] < 0)
80  aim[1] = self->enemy->mins[0];
81  else
82  aim[1] = self->enemy->maxs[0];
83  }
84 
85  VectorMA(self->s.origin, range, dir, point);
86 
87  tr = gi.trace(self->s.origin, NULL, NULL, point, self, MASK_SHOT);
88  if (tr.fraction < 1) {
89  if (!tr.ent->takedamage)
90  return qfalse;
91  // if it will hit any client/monster then hit the one we wanted to hit
92  if ((tr.ent->svflags & SVF_MONSTER) || (tr.ent->client))
93  tr.ent = self->enemy;
94  }
95 
96  AngleVectors(self->s.angles, forward, right, up);
97  VectorMA(self->s.origin, range, forward, point);
98  VectorMA(point, aim[1], right, point);
99  VectorMA(point, aim[2], up, point);
100  VectorSubtract(point, self->enemy->s.origin, dir);
101 
102  // do the damage
103  T_Damage(tr.ent, self, self, dir, point, vec3_origin, damage, kick / 2, DAMAGE_NO_KNOCKBACK, MOD_HIT);
104 
105  if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client))
106  return qfalse;
107 
108  // do our special form of knockback here
109  VectorMA(self->enemy->absmin, 0.5, self->enemy->size, v);
110  VectorSubtract(v, point, v);
111  VectorNormalize(v);
112  VectorMA(self->enemy->velocity, kick, v, self->enemy->velocity);
113  if (self->enemy->velocity[2] > 0)
114  self->enemy->groundentity = NULL;
115  return qtrue;
116 }

Referenced by berserk_attack_club(), berserk_attack_spike(), brain_hit_left(), brain_hit_right(), brain_tentacle_attack(), ChickSlash(), flipper_bite(), floater_wham(), flyer_slash_left(), flyer_slash_right(), GaldiatorMelee(), infantry_smack(), mutant_hit_left(), and mutant_hit_right().

◆ fire_lead()

static void fire_lead ( edict_t *  self,
vec3_t  start,
vec3_t  aimdir,
int  damage,
int  kick,
int  te_impact,
int  hspread,
int  vspread,
int  mod 
)
static

Definition at line 126 of file g_weapon.c.

127 {
128  trace_t tr;
129  vec3_t dir;
130  vec3_t forward, right, up;
131  vec3_t end;
132  float r;
133  float u;
134  vec3_t water_start;
135  qboolean water = qfalse;
136  int content_mask = MASK_SHOT | MASK_WATER;
137 
138  tr = gi.trace(self->s.origin, NULL, NULL, start, self, MASK_SHOT);
139  if (!(tr.fraction < 1.0)) {
140  vectoangles(aimdir, dir);
141  AngleVectors(dir, forward, right, up);
142 
143  r = crandom() * hspread;
144  u = crandom() * vspread;
145  VectorMA(start, 8192, forward, end);
146  VectorMA(end, r, right, end);
147  VectorMA(end, u, up, end);
148 
149  if (gi.pointcontents(start) & MASK_WATER) {
150  water = qtrue;
151  VectorCopy(start, water_start);
152  content_mask &= ~MASK_WATER;
153  }
154 
155  tr = gi.trace(start, NULL, NULL, end, self, content_mask);
156 
157  // see if we hit water
158  if (tr.contents & MASK_WATER) {
159  int color;
160 
161  water = qtrue;
162  VectorCopy(tr.endpos, water_start);
163 
164  if (!VectorCompare(start, tr.endpos)) {
165  if (tr.contents & CONTENTS_WATER) {
166  if (strcmp(tr.surface->name, "*brwater") == 0)
167  color = SPLASH_BROWN_WATER;
168  else
169  color = SPLASH_BLUE_WATER;
170  } else if (tr.contents & CONTENTS_SLIME)
171  color = SPLASH_SLIME;
172  else if (tr.contents & CONTENTS_LAVA)
173  color = SPLASH_LAVA;
174  else
175  color = SPLASH_UNKNOWN;
176 
177  if (color != SPLASH_UNKNOWN) {
178  gi.WriteByte(svc_temp_entity);
179  gi.WriteByte(TE_SPLASH);
180  gi.WriteByte(8);
181  gi.WritePosition(tr.endpos);
182  gi.WriteDir(tr.plane.normal);
183  gi.WriteByte(color);
184  gi.multicast(tr.endpos, MULTICAST_PVS);
185  }
186 
187  // change bullet's course when it enters water
188  VectorSubtract(end, start, dir);
189  vectoangles(dir, dir);
190  AngleVectors(dir, forward, right, up);
191  r = crandom() * hspread * 2;
192  u = crandom() * vspread * 2;
193  VectorMA(water_start, 8192, forward, end);
194  VectorMA(end, r, right, end);
195  VectorMA(end, u, up, end);
196  }
197 
198  // re-trace ignoring water this time
199  tr = gi.trace(water_start, NULL, NULL, end, self, MASK_SHOT);
200  }
201  }
202 
203  // send gun puff / flash
204  if (!((tr.surface) && (tr.surface->flags & SURF_SKY))) {
205  if (tr.fraction < 1.0) {
206  if (tr.ent->takedamage) {
207  T_Damage(tr.ent, self, self, aimdir, tr.endpos, tr.plane.normal, damage, kick, DAMAGE_BULLET, mod);
208  } else {
209  if (strncmp(tr.surface->name, "sky", 3) != 0) {
210  gi.WriteByte(svc_temp_entity);
211  gi.WriteByte(te_impact);
212  gi.WritePosition(tr.endpos);
213  gi.WriteDir(tr.plane.normal);
214  gi.multicast(tr.endpos, MULTICAST_PVS);
215 
216  if (self->client)
217  PlayerNoise(self, tr.endpos, PNOISE_IMPACT);
218  }
219  }
220  }
221  }
222 
223  // if went through water, determine where the end and make a bubble trail
224  if (water) {
225  vec3_t pos;
226 
227  VectorSubtract(tr.endpos, water_start, dir);
228  VectorNormalize(dir);
229  VectorMA(tr.endpos, -2, dir, pos);
230  if (gi.pointcontents(pos) & MASK_WATER)
231  VectorCopy(pos, tr.endpos);
232  else
233  tr = gi.trace(pos, NULL, NULL, water_start, tr.ent, MASK_WATER);
234 
235  VectorAdd(water_start, tr.endpos, pos);
236  VectorScale(pos, 0.5, pos);
237 
238  gi.WriteByte(svc_temp_entity);
239  gi.WriteByte(TE_BUBBLETRAIL);
240  gi.WritePosition(water_start);
241  gi.WritePosition(tr.endpos);
242  gi.multicast(pos, MULTICAST_PVS);
243  }
244 }

Referenced by fire_bullet(), and fire_shotgun().

◆ fire_rail()

void fire_rail ( edict_t *  self,
vec3_t  start,
vec3_t  aimdir,
int  damage,
int  kick 
)

Definition at line 615 of file g_weapon.c.

616 {
617  vec3_t from;
618  vec3_t end;
619  trace_t tr;
620  edict_t *ignore;
621  int mask;
622  qboolean water;
623 
624  VectorMA(start, 8192, aimdir, end);
625  VectorCopy(start, from);
626  ignore = self;
627  water = qfalse;
628  mask = MASK_SHOT | CONTENTS_SLIME | CONTENTS_LAVA;
629  while (ignore) {
630  tr = gi.trace(from, NULL, NULL, end, ignore, mask);
631 
632  if (tr.contents & (CONTENTS_SLIME | CONTENTS_LAVA)) {
633  mask &= ~(CONTENTS_SLIME | CONTENTS_LAVA);
634  water = qtrue;
635  } else {
636  //ZOID--added so rail goes through SOLID_BBOX entities (gibs, etc)
637  if ((tr.ent->svflags & SVF_MONSTER) || (tr.ent->client) ||
638  (tr.ent->solid == SOLID_BBOX))
639  ignore = tr.ent;
640  else
641  ignore = NULL;
642 
643  if ((tr.ent != self) && (tr.ent->takedamage))
644  T_Damage(tr.ent, self, self, aimdir, tr.endpos, tr.plane.normal, damage, kick, 0, MOD_RAILGUN);
645  }
646 
647  VectorCopy(tr.endpos, from);
648  }
649 
650  // send gun puff / flash
651  gi.WriteByte(svc_temp_entity);
652  gi.WriteByte(TE_RAILTRAIL);
653  gi.WritePosition(start);
654  gi.WritePosition(tr.endpos);
655  gi.multicast(self->s.origin, MULTICAST_PHS);
656 // gi.multicast (start, MULTICAST_PHS);
657  if (water) {
658  gi.WriteByte(svc_temp_entity);
659  gi.WriteByte(TE_RAILTRAIL);
660  gi.WritePosition(start);
661  gi.WritePosition(tr.endpos);
662  gi.multicast(tr.endpos, MULTICAST_PHS);
663  }
664 
665  if (self->client)
666  PlayerNoise(self, tr.endpos, PNOISE_IMPACT);
667 }

Referenced by monster_fire_railgun(), and weapon_railgun_fire().

◆ fire_rocket()

void fire_rocket ( edict_t *  self,
vec3_t  start,
vec3_t  dir,
int  damage,
int  speed,
float  damage_radius,
int  radius_damage 
)

Definition at line 577 of file g_weapon.c.

578 {
579  edict_t *rocket;
580 
581  rocket = G_Spawn();
582  VectorCopy(start, rocket->s.origin);
583  VectorCopy(dir, rocket->movedir);
584  vectoangles(dir, rocket->s.angles);
585  VectorScale(dir, speed, rocket->velocity);
586  rocket->movetype = MOVETYPE_FLYMISSILE;
587  rocket->clipmask = MASK_SHOT;
588  rocket->solid = SOLID_BBOX;
589  rocket->s.effects |= EF_ROCKET;
590  VectorClear(rocket->mins);
591  VectorClear(rocket->maxs);
592  rocket->s.modelindex = gi.modelindex("models/objects/rocket/tris.md2");
593  rocket->owner = self;
594  rocket->touch = rocket_touch;
595  rocket->nextthink = level.time + 8000 / speed;
596  rocket->think = G_FreeEdict;
597  rocket->dmg = damage;
598  rocket->radius_dmg = radius_damage;
599  rocket->dmg_radius = damage_radius;
600  rocket->s.sound = gi.soundindex("weapons/rockfly.wav");
601  rocket->classname = "rocket";
602 
603  if (self->client)
604  check_dodge(self, rocket->s.origin, dir, speed);
605 
606  gi.linkentity(rocket);
607 }

Referenced by monster_fire_rocket(), turret_breach_fire(), and Weapon_RocketLauncher_Fire().

◆ fire_shotgun()

void fire_shotgun ( edict_t *  self,
vec3_t  start,
vec3_t  aimdir,
int  damage,
int  kick,
int  hspread,
int  vspread,
int  count,
int  mod 
)

Definition at line 268 of file g_weapon.c.

269 {
270  int i;
271 
272  for (i = 0; i < count; i++)
273  fire_lead(self, start, aimdir, damage, kick, TE_SHOTGUN, hspread, vspread, mod);
274 }

Referenced by monster_fire_shotgun(), weapon_shotgun_fire(), and weapon_supershotgun_fire().

◆ flare_sparks()

void flare_sparks ( edict_t *  self)

Definition at line 870 of file g_weapon.c.

871 {
872  vec3_t dir;
873  vec3_t forward, right, up;
874  // Spawn some sparks. This isn't net-friendly at all, but will
875  // be fine for single player.
876  //
877  gi.WriteByte(svc_temp_entity);
878  gi.WriteByte(TE_FLARE);
879 
880  gi.WriteShort(self - g_edicts);
881  // if this is the first tick of flare, set count to 1 to start the sound
882  gi.WriteByte( self->timestamp - level.time < 14.75 ? 0 : 1);
883 
884  gi.WritePosition(self->s.origin);
885 
886  // If we are still moving, calculate the normal to the direction
887  // we are travelling.
888  //
889  if (VectorLength(self->velocity) > 0.0)
890  {
891  vectoangles(self->velocity, dir);
892  AngleVectors(dir, forward, right, up);
893 
894  gi.WriteDir(up);
895  }
896  // If we're stopped, just write out the origin as our normal
897  //
898  else
899  {
900  gi.WriteDir(vec3_origin);
901  }
902  gi.multicast(self->s.origin, MULTICAST_PVS);
903 }

Referenced by flare_think().

◆ flare_think()

void flare_think ( edict_t *  self)

Definition at line 928 of file g_weapon.c.

929 {
930  // self->timestamp is 15 seconds after the flare was spawned.
931  //
932  if (level.time > self->timestamp)
933  {
934  G_FreeEdict(self);
935  return;
936  }
937 
938  // We're still active, so lets shoot some sparks.
939  //
940  flare_sparks(self);
941 
942  // We'll think again in .2 seconds
943  //
944  self->nextthink = level.time + 0.2;
945 }

Referenced by fire_flaregun().

◆ flare_touch()

void flare_touch ( edict_t *  ent,
edict_t *  other,
cplane_t *  plane,
csurface_t *  surf 
)

Definition at line 947 of file g_weapon.c.

949 {
950  // Flares don't weigh that much, so let's have them stop
951  // the instant they whack into anything.
952  //
953  VectorClear(ent->velocity);
954 }

Referenced by fire_flaregun().

◆ Grenade_Explode()

void Grenade_Explode ( edict_t *  ent)

Definition at line 371 of file g_weapon.c.

372 {
373  vec3_t origin;
374  int mod;
375 
376  if (ent->owner->client)
377  PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT);
378 
379  //FIXME: if we are onground then raise our Z just a bit since we are a point?
380  if (ent->enemy) {
381  float points;
382  vec3_t v;
383  vec3_t dir;
384 
385  VectorAdd(ent->enemy->mins, ent->enemy->maxs, v);
386  VectorMA(ent->enemy->s.origin, 0.5, v, v);
387  VectorSubtract(ent->s.origin, v, v);
388  points = ent->dmg - 0.5 * VectorLength(v);
389  VectorSubtract(ent->enemy->s.origin, ent->s.origin, dir);
390  if (ent->spawnflags & 1)
391  mod = MOD_HANDGRENADE;
392  else
393  mod = MOD_GRENADE;
394  T_Damage(ent->enemy, ent, ent->owner, dir, ent->s.origin, vec3_origin, (int)points, (int)points, DAMAGE_RADIUS, mod);
395  }
396 
397  if (ent->spawnflags & 2)
398  mod = MOD_HELD_GRENADE;
399  else if (ent->spawnflags & 1)
400  mod = MOD_HG_SPLASH;
401  else
402  mod = MOD_G_SPLASH;
403  T_RadiusDamage(ent, ent->owner, ent->dmg, ent->enemy, ent->dmg_radius, mod);
404 
405  VectorMA(ent->s.origin, -0.02, ent->velocity, origin);
406  gi.WriteByte(svc_temp_entity);
407  if (ent->waterlevel) {
408  if (ent->groundentity)
409  gi.WriteByte(TE_GRENADE_EXPLOSION_WATER);
410  else
411  gi.WriteByte(TE_ROCKET_EXPLOSION_WATER);
412  } else {
413  if (ent->groundentity)
414  gi.WriteByte(TE_GRENADE_EXPLOSION);
415  else
416  gi.WriteByte(TE_ROCKET_EXPLOSION);
417  }
418  gi.WritePosition(origin);
419  gi.multicast(ent->s.origin, MULTICAST_PHS);
420 
421  G_FreeEdict(ent);
422 }

Referenced by fire_grenade(), fire_grenade2(), and Grenade_Touch().

◆ Grenade_Touch()

void Grenade_Touch ( edict_t *  ent,
edict_t *  other,
cplane_t *  plane,
csurface_t *  surf 
)

Definition at line 424 of file g_weapon.c.

425 {
426  if (other == ent->owner)
427  return;
428 
429  if (surf && (surf->flags & SURF_SKY)) {
430  G_FreeEdict(ent);
431  return;
432  }
433 
434  if (!other->takedamage) {
435  if (ent->spawnflags & 1) {
436  if (random() > 0.5)
437  gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/hgrenb1a.wav"), 1, ATTN_NORM, 0);
438  else
439  gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/hgrenb2a.wav"), 1, ATTN_NORM, 0);
440  } else {
441  gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/grenlb1b.wav"), 1, ATTN_NORM, 0);
442  }
443  return;
444  }
445 
446  ent->enemy = other;
447  Grenade_Explode(ent);
448 }

Referenced by fire_grenade(), and fire_grenade2().

◆ rocket_touch()

void rocket_touch ( edict_t *  ent,
edict_t *  other,
cplane_t *  plane,
csurface_t *  surf 
)

Definition at line 532 of file g_weapon.c.

533 {
534  vec3_t origin;
535  int n;
536 
537  if (other == ent->owner)
538  return;
539 
540  if (surf && (surf->flags & SURF_SKY)) {
541  G_FreeEdict(ent);
542  return;
543  }
544 
545  if (ent->owner->client)
546  PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT);
547 
548  // calculate position for the explosion entity
549  VectorMA(ent->s.origin, -0.02, ent->velocity, origin);
550 
551  if (other->takedamage) {
552  T_Damage(other, ent, ent->owner, ent->velocity, ent->s.origin, plane->normal, ent->dmg, 0, 0, MOD_ROCKET);
553  } else {
554  // don't throw any debris in net games
555  if (!deathmatch->value && !coop->value) {
556  if ((surf) && !(surf->flags & (SURF_WARP | SURF_TRANS33 | SURF_TRANS66 | SURF_FLOWING))) {
557  n = rand() % 5;
558  while (n--)
559  ThrowDebris(ent, "models/objects/debris2/tris.md2", 2, ent->s.origin);
560  }
561  }
562  }
563 
564  T_RadiusDamage(ent, ent->owner, ent->radius_dmg, other, ent->dmg_radius, MOD_R_SPLASH);
565 
566  gi.WriteByte(svc_temp_entity);
567  if (ent->waterlevel)
568  gi.WriteByte(TE_ROCKET_EXPLOSION_WATER);
569  else
570  gi.WriteByte(TE_ROCKET_EXPLOSION);
571  gi.WritePosition(origin);
572  gi.multicast(ent->s.origin, MULTICAST_PHS);
573 
574  G_FreeEdict(ent);
575 }

Referenced by fire_rocket().

gi
game_import_t gi
Definition: g_main.c:23
deathmatch
cvar_t * deathmatch
Definition: g_main.c:33
flare_touch
void flare_touch(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
Definition: g_weapon.c:947
MOD_BFG_BLAST
#define MOD_BFG_BLAST
Definition: g_local.h:470
G_Spawn
edict_t * G_Spawn(void)
Definition: g_utils.c:391
MOD_GRENADE
#define MOD_GRENADE
Definition: g_local.h:463
FRAMETIME
#define FRAMETIME
Definition: g_local.h:75
DAMAGE_ENERGY
#define DAMAGE_ENERGY
Definition: g_local.h:649
DAMAGE_RADIUS
#define DAMAGE_RADIUS
Definition: g_local.h:647
check_dodge
static void check_dodge(edict_t *self, vec3_t start, vec3_t dir, int speed)
Definition: g_weapon.c:30
MOVETYPE_FLYMISSILE
@ MOVETYPE_FLYMISSILE
Definition: g_local.h:195
MOD_RAILGUN
#define MOD_RAILGUN
Definition: g_local.h:468
MOD_HG_SPLASH
#define MOD_HG_SPLASH
Definition: g_local.h:473
Grenade_Touch
void Grenade_Touch(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
Definition: g_weapon.c:424
bfg_touch
void bfg_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
Definition: g_weapon.c:717
g_edicts
edict_t * g_edicts
Definition: g_main.c:31
rocket_touch
void rocket_touch(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
Definition: g_weapon.c:532
ThrowDebris
void ThrowDebris(edict_t *self, char *modelname, float speed, vec3_t origin)
Definition: g_misc.c:269
T_Damage
void T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, int damage, int knockback, int dflags, int mod)
Definition: g_combat.c:358
other
@ other
Definition: ogg.c:63
Grenade_Explode
void Grenade_Explode(edict_t *ent)
Definition: g_weapon.c:371
infront
qboolean infront(edict_t *self, edict_t *other)
Definition: g_ai.c:293
DAMAGE_NO_KNOCKBACK
#define DAMAGE_NO_KNOCKBACK
Definition: g_local.h:650
bfg_explode
void bfg_explode(edict_t *self)
Definition: g_weapon.c:675
vec3_origin
vec3_t vec3_origin
Definition: shared.c:21
DAMAGE_BULLET
#define DAMAGE_BULLET
Definition: g_local.h:651
vectoangles
void vectoangles(vec3_t vec, vec3_t angles)
Definition: g_utils.c:330
MOD_BFG_LASER
#define MOD_BFG_LASER
Definition: g_local.h:469
findradius
edict_t * findradius(edict_t *from, vec3_t org, float rad)
Definition: g_utils.c:75
G_FreeEdict
void G_FreeEdict(edict_t *e)
Definition: g_utils.c:421
flare_sparks
void flare_sparks(edict_t *self)
Definition: g_weapon.c:870
MOD_HIT
#define MOD_HIT
Definition: g_local.h:489
MOD_HANDGRENADE
#define MOD_HANDGRENADE
Definition: g_local.h:472
forward
static vec3_t forward
Definition: p_view.c:27
svc_temp_entity
#define svc_temp_entity
Definition: g_local.h:38
crandom
#define crandom()
Definition: g_local.h:505
origin
static vec3_t origin
Definition: mesh.c:27
random
#define random()
Definition: g_local.h:504
AngleVectors
void AngleVectors(vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
Definition: shared.c:23
MOD_G_SPLASH
#define MOD_G_SPLASH
Definition: g_local.h:464
MOD_R_SPLASH
#define MOD_R_SPLASH
Definition: g_local.h:466
PNOISE_IMPACT
#define PNOISE_IMPACT
Definition: g_local.h:181
CanDamage
qboolean CanDamage(edict_t *targ, edict_t *inflictor)
Definition: g_combat.c:30
skill
cvar_t * skill
Definition: g_main.c:36
level_locals_t::time
float time
Definition: g_local.h:299
coop
cvar_t * coop
Definition: g_main.c:34
MOD_BLASTER
#define MOD_BLASTER
Definition: g_local.h:458
FL_IMMUNE_LASER
#define FL_IMMUNE_LASER
Definition: g_local.h:61
up
static vec3_t up
Definition: p_view.c:27
MOD_HELD_GRENADE
#define MOD_HELD_GRENADE
Definition: g_local.h:481
right
static vec3_t right
Definition: p_view.c:27
level
level_locals_t level
Definition: g_main.c:22
MOD_BFG_EFFECT
#define MOD_BFG_EFFECT
Definition: g_local.h:471
MOD_HYPERBLASTER
#define MOD_HYPERBLASTER
Definition: g_local.h:467
fire_lead
static void fire_lead(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int te_impact, int hspread, int vspread, int mod)
Definition: g_weapon.c:126
PlayerNoise
void PlayerNoise(edict_t *who, vec3_t where, int type)
Definition: p_weapon.c:56
flare_think
void flare_think(edict_t *self)
Definition: g_weapon.c:928
MOVETYPE_BOUNCE
@ MOVETYPE_BOUNCE
Definition: g_local.h:196
color
static vec4_t color
Definition: mesh.c:33
range
int range(edict_t *self, edict_t *other)
Definition: g_ai.c:245
MOD_ROCKET
#define MOD_ROCKET
Definition: g_local.h:465
bfg_think
void bfg_think(edict_t *self)
Definition: g_weapon.c:755
VectorNormalize
vec_t VectorNormalize(vec3_t v)
Definition: shared.c:55
blaster_touch
void blaster_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
Definition: g_weapon.c:284
T_RadiusDamage
void T_RadiusDamage(edict_t *inflictor, edict_t *attacker, float damage, edict_t *ignore, float radius, int mod)
Definition: g_combat.c:514