icculus quake2 doxygen  1.0 dev
g_ai.c File Reference
#include "g_local.h"

Go to the source code of this file.

Functions

qboolean FindTarget (edict_t *self)
 
qboolean ai_checkattack (edict_t *self, float dist)
 
void AI_SetSightClient (void)
 
void ai_move (edict_t *self, float dist)
 
void ai_stand (edict_t *self, float dist)
 
void ai_walk (edict_t *self, float dist)
 
void ai_charge (edict_t *self, float dist)
 
void ai_turn (edict_t *self, float dist)
 
int range (edict_t *self, edict_t *other)
 
qboolean visible (edict_t *self, edict_t *other)
 
qboolean infront (edict_t *self, edict_t *other)
 
void HuntTarget (edict_t *self)
 
void FoundTarget (edict_t *self)
 
qboolean FacingIdeal (edict_t *self)
 
qboolean M_CheckAttack (edict_t *self)
 
void ai_run_melee (edict_t *self)
 
void ai_run_missile (edict_t *self)
 
void ai_run_slide (edict_t *self, float distance)
 
void ai_run (edict_t *self, float dist)
 

Variables

cvar_tmaxclients
 
qboolean enemy_vis
 
qboolean enemy_infront
 
int enemy_range
 
float enemy_yaw
 

Function Documentation

◆ ai_charge()

void ai_charge ( edict_t self,
float  dist 
)

Definition at line 194 of file g_ai.c.

195 {
196  vec3_t v;
197 
198  VectorSubtract (self->enemy->s.origin, self->s.origin, v);
199  self->ideal_yaw = vectoyaw(v);
200  M_ChangeYaw (self);
201 
202  if (dist)
203  M_walkmove (self, self->s.angles[YAW], dist);
204 }

◆ ai_checkattack()

qboolean ai_checkattack ( edict_t self,
float  dist 
)

Definition at line 771 of file g_ai.c.

772 {
773  vec3_t temp;
774  qboolean hesDeadJim;
775 
776 // this causes monsters to run blindly to the combat point w/o firing
777  if (self->goalentity)
778  {
779  if (self->monsterinfo.aiflags & AI_COMBAT_POINT)
780  return false;
781 
782  if (self->monsterinfo.aiflags & AI_SOUND_TARGET)
783  {
784  if ((level.time - self->enemy->teleport_time) > 5.0)
785  {
786  if (self->goalentity == self->enemy) {
787  if (self->movetarget)
788  self->goalentity = self->movetarget;
789  else
790  self->goalentity = NULL;
791  }
792  self->monsterinfo.aiflags &= ~AI_SOUND_TARGET;
794  self->monsterinfo.aiflags &= ~(AI_STAND_GROUND | AI_TEMP_STAND_GROUND);
795  }
796  else
797  {
798  self->show_hostile = level.time + 1;
799  return false;
800  }
801  }
802  }
803 
804  enemy_vis = false;
805 
806 // see if the enemy is dead
807  hesDeadJim = false;
808  if ((!self->enemy) || (!self->enemy->inuse))
809  {
810  hesDeadJim = true;
811  }
812  else if (self->monsterinfo.aiflags & AI_MEDIC)
813  {
814  if (self->enemy->health > 0)
815  {
816  hesDeadJim = true;
817  self->monsterinfo.aiflags &= ~AI_MEDIC;
818  }
819  }
820  else
821  {
822  if (self->monsterinfo.aiflags & AI_BRUTAL)
823  {
824  if (self->enemy->health <= -80)
825  hesDeadJim = true;
826  }
827  else
828  {
829  if (self->enemy->health <= 0)
830  hesDeadJim = true;
831  }
832  }
833 
834  if (hesDeadJim)
835  {
836  self->enemy = NULL;
837  // FIXME: look all around for other targets
838  if (self->oldenemy && self->oldenemy->health > 0)
839  {
840  self->enemy = self->oldenemy;
841  self->oldenemy = NULL;
842  HuntTarget (self);
843  }
844  else
845  {
846  if (self->movetarget)
847  {
848  self->goalentity = self->movetarget;
849  self->monsterinfo.walk (self);
850  }
851  else
852  {
853  // we need the pausetime otherwise the stand code
854  // will just revert to walking with no target and
855  // the monsters will wonder around aimlessly trying
856  // to hunt the world entity
857  self->monsterinfo.pausetime = level.time + 100000000;
858  self->monsterinfo.stand (self);
859  }
860  return true;
861  }
862  }
863 
864  self->show_hostile = level.time + 1; // wake up other monsters
865 
866 // check knowledge of enemy
867  enemy_vis = visible(self, self->enemy);
868  if (enemy_vis)
869  {
870  self->monsterinfo.search_time = level.time + 5;
872  }
873 
874 // look for other coop players here
875 // if (coop && self->monsterinfo.search_time < level.time)
876 // {
877 // if (FindTarget (self))
878 // return true;
879 // }
880 
881  enemy_infront = infront(self, self->enemy);
882  enemy_range = range(self, self->enemy);
883  VectorSubtract (self->enemy->s.origin, self->s.origin, temp);
884  enemy_yaw = vectoyaw(temp);
885 
886 
887  // JDC self->ideal_yaw = enemy_yaw;
888 
889  if (self->monsterinfo.attack_state == AS_MISSILE)
890  {
891  ai_run_missile (self);
892  return true;
893  }
894  if (self->monsterinfo.attack_state == AS_MELEE)
895  {
896  ai_run_melee (self);
897  return true;
898  }
899 
900  // if enemy is not currently visible, we will never attack
901  if (!enemy_vis)
902  return false;
903 
904  return self->monsterinfo.checkattack (self);
905 }

Referenced by ai_run(), and ai_stand().

◆ ai_move()

void ai_move ( edict_t self,
float  dist 
)

Definition at line 92 of file g_ai.c.

93 {
94  M_walkmove (self, self->s.angles[YAW], dist);
95 }

◆ ai_run()

void ai_run ( edict_t self,
float  dist 
)

Definition at line 915 of file g_ai.c.

916 {
917  vec3_t v;
918  edict_t *tempgoal;
919  edict_t *save;
920  qboolean new;
921  edict_t *marker;
922  float d1, d2;
923  trace_t tr;
924  vec3_t v_forward, v_right;
925  float left, center, right;
926  vec3_t left_target, right_target;
927 
928  // if we're going to a combat point, just proceed
929  if (self->monsterinfo.aiflags & AI_COMBAT_POINT)
930  {
931  M_MoveToGoal (self, dist);
932  return;
933  }
934 
935  if (self->monsterinfo.aiflags & AI_SOUND_TARGET)
936  {
937  VectorSubtract (self->s.origin, self->enemy->s.origin, v);
938  if (VectorLength(v) < 64)
939  {
940  self->monsterinfo.aiflags |= (AI_STAND_GROUND | AI_TEMP_STAND_GROUND);
941  self->monsterinfo.stand (self);
942  return;
943  }
944 
945  M_MoveToGoal (self, dist);
946 
947  if (!FindTarget (self))
948  return;
949  }
950 
951  if (ai_checkattack (self, dist))
952  return;
953 
954  if (self->monsterinfo.attack_state == AS_SLIDING)
955  {
956  ai_run_slide (self, dist);
957  return;
958  }
959 
960  if (enemy_vis)
961  {
962 // if (self.aiflags & AI_LOST_SIGHT)
963 // dprint("regained sight\n");
964  M_MoveToGoal (self, dist);
965  self->monsterinfo.aiflags &= ~AI_LOST_SIGHT;
967  self->monsterinfo.trail_time = level.time;
968  return;
969  }
970 
971  // coop will change to another enemy if visible
972  if (coop->value)
973  { // FIXME: insane guys get mad with this, which causes crashes!
974  if (FindTarget (self))
975  return;
976  }
977 
978  if ((self->monsterinfo.search_time) && (level.time > (self->monsterinfo.search_time + 20)))
979  {
980  M_MoveToGoal (self, dist);
981  self->monsterinfo.search_time = 0;
982 // dprint("search timeout\n");
983  return;
984  }
985 
986  save = self->goalentity;
987  tempgoal = G_Spawn();
988  self->goalentity = tempgoal;
989 
990  new = false;
991 
992  if (!(self->monsterinfo.aiflags & AI_LOST_SIGHT))
993  {
994  // just lost sight of the player, decide where to go first
995 // dprint("lost sight of player, last seen at "); dprint(vtos(self.last_sighting)); dprint("\n");
997  self->monsterinfo.aiflags &= ~(AI_PURSUE_NEXT | AI_PURSUE_TEMP);
998  new = true;
999  }
1000 
1001  if (self->monsterinfo.aiflags & AI_PURSUE_NEXT)
1002  {
1003  self->monsterinfo.aiflags &= ~AI_PURSUE_NEXT;
1004 // dprint("reached current goal: "); dprint(vtos(self.origin)); dprint(" "); dprint(vtos(self.last_sighting)); dprint(" "); dprint(ftos(vlen(self.origin - self.last_sighting))); dprint("\n");
1005 
1006  // give ourself more time since we got this far
1007  self->monsterinfo.search_time = level.time + 5;
1008 
1009  if (self->monsterinfo.aiflags & AI_PURSUE_TEMP)
1010  {
1011 // dprint("was temp goal; retrying original\n");
1012  self->monsterinfo.aiflags &= ~AI_PURSUE_TEMP;
1013  marker = NULL;
1015  new = true;
1016  }
1017  else if (self->monsterinfo.aiflags & AI_PURSUIT_LAST_SEEN)
1018  {
1019  self->monsterinfo.aiflags &= ~AI_PURSUIT_LAST_SEEN;
1020  marker = PlayerTrail_PickFirst (self);
1021  }
1022  else
1023  {
1024  marker = PlayerTrail_PickNext (self);
1025  }
1026 
1027  if (marker)
1028  {
1029  VectorCopy (marker->s.origin, self->monsterinfo.last_sighting);
1030  self->monsterinfo.trail_time = marker->timestamp;
1031  self->s.angles[YAW] = self->ideal_yaw = marker->s.angles[YAW];
1032 // dprint("heading is "); dprint(ftos(self.ideal_yaw)); dprint("\n");
1033 
1034 // debug_drawline(self.origin, self.last_sighting, 52);
1035  new = true;
1036  }
1037  }
1038 
1040  d1 = VectorLength(v);
1041  if (d1 <= dist)
1042  {
1043  self->monsterinfo.aiflags |= AI_PURSUE_NEXT;
1044  dist = d1;
1045  }
1046 
1048 
1049  if (new)
1050  {
1051 // gi.dprintf("checking for course correction\n");
1052 
1053  tr = gi.trace(self->s.origin, self->mins, self->maxs, self->monsterinfo.last_sighting, self, MASK_PLAYERSOLID);
1054  if (tr.fraction < 1)
1055  {
1056  VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
1057  d1 = VectorLength(v);
1058  center = tr.fraction;
1059  d2 = d1 * ((center+1)/2);
1060  self->s.angles[YAW] = self->ideal_yaw = vectoyaw(v);
1061  AngleVectors(self->s.angles, v_forward, v_right, NULL);
1062 
1063  VectorSet(v, d2, -16, 0);
1064  G_ProjectSource (self->s.origin, v, v_forward, v_right, left_target);
1065  tr = gi.trace(self->s.origin, self->mins, self->maxs, left_target, self, MASK_PLAYERSOLID);
1066  left = tr.fraction;
1067 
1068  VectorSet(v, d2, 16, 0);
1069  G_ProjectSource (self->s.origin, v, v_forward, v_right, right_target);
1070  tr = gi.trace(self->s.origin, self->mins, self->maxs, right_target, self, MASK_PLAYERSOLID);
1071  right = tr.fraction;
1072 
1073  center = (d1*center)/d2;
1074  if (left >= center && left > right)
1075  {
1076  if (left < 1)
1077  {
1078  VectorSet(v, d2 * left * 0.5, -16, 0);
1079  G_ProjectSource (self->s.origin, v, v_forward, v_right, left_target);
1080 // gi.dprintf("incomplete path, go part way and adjust again\n");
1081  }
1083  self->monsterinfo.aiflags |= AI_PURSUE_TEMP;
1084  VectorCopy (left_target, self->goalentity->s.origin);
1085  VectorCopy (left_target, self->monsterinfo.last_sighting);
1086  VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
1087  self->s.angles[YAW] = self->ideal_yaw = vectoyaw(v);
1088 // gi.dprintf("adjusted left\n");
1089 // debug_drawline(self.origin, self.last_sighting, 152);
1090  }
1091  else if (right >= center && right > left)
1092  {
1093  if (right < 1)
1094  {
1095  VectorSet(v, d2 * right * 0.5, 16, 0);
1096  G_ProjectSource (self->s.origin, v, v_forward, v_right, right_target);
1097 // gi.dprintf("incomplete path, go part way and adjust again\n");
1098  }
1100  self->monsterinfo.aiflags |= AI_PURSUE_TEMP;
1101  VectorCopy (right_target, self->goalentity->s.origin);
1102  VectorCopy (right_target, self->monsterinfo.last_sighting);
1103  VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
1104  self->s.angles[YAW] = self->ideal_yaw = vectoyaw(v);
1105 // gi.dprintf("adjusted right\n");
1106 // debug_drawline(self.origin, self.last_sighting, 152);
1107  }
1108  }
1109 // else gi.dprintf("course was fine\n");
1110  }
1111 
1112  M_MoveToGoal (self, dist);
1113 
1114  G_FreeEdict(tempgoal);
1115 
1116  if (self)
1117  self->goalentity = save;
1118 }

◆ ai_run_melee()

void ai_run_melee ( edict_t self)

Definition at line 703 of file g_ai.c.

704 {
705  self->ideal_yaw = enemy_yaw;
706  M_ChangeYaw (self);
707 
708  if (FacingIdeal(self))
709  {
710  self->monsterinfo.melee (self);
711  self->monsterinfo.attack_state = AS_STRAIGHT;
712  }
713 }

Referenced by ai_checkattack().

◆ ai_run_missile()

void ai_run_missile ( edict_t self)

Definition at line 723 of file g_ai.c.

724 {
725  self->ideal_yaw = enemy_yaw;
726  M_ChangeYaw (self);
727 
728  if (FacingIdeal(self))
729  {
730  self->monsterinfo.attack (self);
731  self->monsterinfo.attack_state = AS_STRAIGHT;
732  }
733 }

Referenced by ai_checkattack().

◆ ai_run_slide()

void ai_run_slide ( edict_t self,
float  distance 
)

Definition at line 743 of file g_ai.c.

744 {
745  float ofs;
746 
747  self->ideal_yaw = enemy_yaw;
748  M_ChangeYaw (self);
749 
750  if (self->monsterinfo.lefty)
751  ofs = 90;
752  else
753  ofs = -90;
754 
755  if (M_walkmove (self, self->ideal_yaw + ofs, distance))
756  return;
757 
758  self->monsterinfo.lefty = 1 - self->monsterinfo.lefty;
759  M_walkmove (self, self->ideal_yaw - ofs, distance);
760 }

Referenced by ai_run().

◆ AI_SetSightClient()

void AI_SetSightClient ( void  )

Definition at line 50 of file g_ai.c.

51 {
52  edict_t *ent;
53  int start, check;
54 
55  if (level.sight_client == NULL)
56  start = 1;
57  else
58  start = level.sight_client - g_edicts;
59 
60  check = start;
61  while (1)
62  {
63  check++;
64  if (check > game.maxclients)
65  check = 1;
66  ent = &g_edicts[check];
67  if (ent->inuse
68  && ent->health > 0
69  && !(ent->flags & FL_NOTARGET) )
70  {
71  level.sight_client = ent;
72  return; // got one
73  }
74  if (check == start)
75  {
76  level.sight_client = NULL;
77  return; // nobody to see
78  }
79  }
80 }

Referenced by G_RunFrame().

◆ ai_stand()

void ai_stand ( edict_t self,
float  dist 
)

Definition at line 106 of file g_ai.c.

107 {
108  vec3_t v;
109 
110  if (dist)
111  M_walkmove (self, self->s.angles[YAW], dist);
112 
113  if (self->monsterinfo.aiflags & AI_STAND_GROUND)
114  {
115  if (self->enemy)
116  {
117  VectorSubtract (self->enemy->s.origin, self->s.origin, v);
118  self->ideal_yaw = vectoyaw(v);
119  if (self->s.angles[YAW] != self->ideal_yaw && self->monsterinfo.aiflags & AI_TEMP_STAND_GROUND)
120  {
121  self->monsterinfo.aiflags &= ~(AI_STAND_GROUND | AI_TEMP_STAND_GROUND);
122  self->monsterinfo.run (self);
123  }
124  M_ChangeYaw (self);
125  ai_checkattack (self, 0);
126  }
127  else
128  FindTarget (self);
129  return;
130  }
131 
132  if (FindTarget (self))
133  return;
134 
135  if (level.time > self->monsterinfo.pausetime)
136  {
137  self->monsterinfo.walk (self);
138  return;
139  }
140 
141  if (!(self->spawnflags & 1) && (self->monsterinfo.idle) && (level.time > self->monsterinfo.idle_time))
142  {
143  if (self->monsterinfo.idle_time)
144  {
145  self->monsterinfo.idle (self);
146  self->monsterinfo.idle_time = level.time + 15 + random() * 15;
147  }
148  else
149  {
150  self->monsterinfo.idle_time = level.time + random() * 15;
151  }
152  }
153 }

◆ ai_turn()

void ai_turn ( edict_t self,
float  dist 
)

Definition at line 215 of file g_ai.c.

216 {
217  if (dist)
218  M_walkmove (self, self->s.angles[YAW], dist);
219 
220  if (FindTarget (self))
221  return;
222 
223  M_ChangeYaw (self);
224 }

◆ ai_walk()

void ai_walk ( edict_t self,
float  dist 
)

Definition at line 163 of file g_ai.c.

164 {
165  M_MoveToGoal (self, dist);
166 
167  // check for noticing a player
168  if (FindTarget (self))
169  return;
170 
171  if ((self->monsterinfo.search) && (level.time > self->monsterinfo.idle_time))
172  {
173  if (self->monsterinfo.idle_time)
174  {
175  self->monsterinfo.search (self);
176  self->monsterinfo.idle_time = level.time + 15 + random() * 15;
177  }
178  else
179  {
180  self->monsterinfo.idle_time = level.time + random() * 15;
181  }
182  }
183 }

◆ FacingIdeal()

qboolean FacingIdeal ( edict_t self)

Definition at line 594 of file g_ai.c.

595 {
596  float delta;
597 
598  delta = anglemod(self->s.angles[YAW] - self->ideal_yaw);
599  if (delta > 45 && delta < 315)
600  return false;
601  return true;
602 }

Referenced by ai_run_melee(), and ai_run_missile().

◆ FindTarget()

qboolean FindTarget ( edict_t self)

Definition at line 407 of file g_ai.c.

408 {
409  edict_t *client;
410  qboolean heardit;
411  int r;
412 
413  if (self->monsterinfo.aiflags & AI_GOOD_GUY)
414  {
415  if (self->goalentity && self->goalentity->inuse && self->goalentity->classname)
416  {
417  if (strcmp(self->goalentity->classname, "target_actor") == 0)
418  return false;
419  }
420 
421  //FIXME look for monsters?
422  return false;
423  }
424 
425  // if we're going to a combat point, just proceed
426  if (self->monsterinfo.aiflags & AI_COMBAT_POINT)
427  return false;
428 
429 // if the first spawnflag bit is set, the monster will only wake up on
430 // really seeing the player, not another monster getting angry or hearing
431 // something
432 
433 // revised behavior so they will wake up if they "see" a player make a noise
434 // but not weapon impact/explosion noises
435 
436  heardit = false;
437  if ((level.sight_entity_framenum >= (level.framenum - 1)) && !(self->spawnflags & 1) )
438  {
439  client = level.sight_entity;
440  if (client->enemy == self->enemy)
441  {
442  return false;
443  }
444  }
445  else if (level.sound_entity_framenum >= (level.framenum - 1))
446  {
447  client = level.sound_entity;
448  heardit = true;
449  }
450  else if (!(self->enemy) && (level.sound2_entity_framenum >= (level.framenum - 1)) && !(self->spawnflags & 1) )
451  {
452  client = level.sound2_entity;
453  heardit = true;
454  }
455  else
456  {
457  client = level.sight_client;
458  if (!client)
459  return false; // no clients to get mad at
460  }
461 
462  // if the entity went away, forget it
463  if (!client->inuse)
464  return false;
465 
466  if (client == self->enemy)
467  return true; // JDC false;
468 
469  if (client->client)
470  {
471  if (client->flags & FL_NOTARGET)
472  return false;
473  }
474  else if (client->svflags & SVF_MONSTER)
475  {
476  if (!client->enemy)
477  return false;
478  if (client->enemy->flags & FL_NOTARGET)
479  return false;
480  }
481  else if (heardit)
482  {
483  if (client->owner->flags & FL_NOTARGET)
484  return false;
485  }
486  else
487  return false;
488 
489  if (!heardit)
490  {
491  r = range (self, client);
492 
493  if (r == RANGE_FAR)
494  return false;
495 
496 // this is where we would check invisibility
497 
498  // is client in an spot too dark to be seen?
499  if (client->light_level <= 5)
500  return false;
501 
502  if (!visible (self, client))
503  {
504  return false;
505  }
506 
507  if (r == RANGE_NEAR)
508  {
509  if (client->show_hostile < level.time && !infront (self, client))
510  {
511  return false;
512  }
513  }
514  else if (r == RANGE_MID)
515  {
516  if (!infront (self, client))
517  {
518  return false;
519  }
520  }
521 
522  self->enemy = client;
523 
524  if (strcmp(self->enemy->classname, "player_noise") != 0)
525  {
527 
528  if (!self->enemy->client)
529  {
530  self->enemy = self->enemy->enemy;
531  if (!self->enemy->client)
532  {
533  self->enemy = NULL;
534  return false;
535  }
536  }
537  }
538  }
539  else // heardit
540  {
541  vec3_t temp;
542 
543  if (self->spawnflags & 1)
544  {
545  if (!visible (self, client))
546  return false;
547  }
548  else
549  {
550  if (!gi.inPHS(self->s.origin, client->s.origin))
551  return false;
552  }
553 
554  VectorSubtract (client->s.origin, self->s.origin, temp);
555 
556  if (VectorLength(temp) > 1000) // too far to hear
557  {
558  return false;
559  }
560 
561  // check area portals - if they are different and not connected then we can't hear it
562  if (client->areanum != self->areanum)
563  if (!gi.AreasConnected(self->areanum, client->areanum))
564  return false;
565 
566  self->ideal_yaw = vectoyaw(temp);
567  M_ChangeYaw (self);
568 
569  // hunt the sound for a bit; hopefully find the real player
570  self->monsterinfo.aiflags |= AI_SOUND_TARGET;
571  self->enemy = client;
572  }
573 
574 //
575 // got one
576 //
577  FoundTarget (self);
578 
579  if (!(self->monsterinfo.aiflags & AI_SOUND_TARGET) && (self->monsterinfo.sight))
580  self->monsterinfo.sight (self, self->enemy);
581 
582  return true;
583 }

Referenced by ai_run(), ai_stand(), ai_turn(), ai_walk(), and turret_driver_think().

◆ FoundTarget()

void FoundTarget ( edict_t self)

Definition at line 347 of file g_ai.c.

348 {
349  // let other monsters see this monster for a while
350  if (self->enemy->client)
351  {
352  level.sight_entity = self;
353  level.sight_entity_framenum = level.framenum;
354  level.sight_entity->light_level = 128;
355  }
356 
357  self->show_hostile = level.time + 1; // wake up other monsters
358 
360  self->monsterinfo.trail_time = level.time;
361 
362  if (!self->combattarget)
363  {
364  HuntTarget (self);
365  return;
366  }
367 
368  self->goalentity = self->movetarget = G_PickTarget(self->combattarget);
369  if (!self->movetarget)
370  {
371  self->goalentity = self->movetarget = self->enemy;
372  HuntTarget (self);
373  gi.dprintf("%s at %s, combattarget %s not found\n", self->classname, vtos(self->s.origin), self->combattarget);
374  return;
375  }
376 
377  // clear out our combattarget, these are a one shot deal
378  self->combattarget = NULL;
379  self->monsterinfo.aiflags |= AI_COMBAT_POINT;
380 
381  // clear the targetname, that point is ours!
382  self->movetarget->targetname = NULL;
383  self->monsterinfo.pausetime = 0;
384 
385  // run for it
386  self->monsterinfo.run (self);
387 }

Referenced by FindTarget(), M_ReactToDamage(), medic_cable_attack(), medic_idle(), medic_run(), medic_search(), monster_triggered_spawn(), and monster_use().

◆ HuntTarget()

void HuntTarget ( edict_t self)

Definition at line 331 of file g_ai.c.

332 {
333  vec3_t vec;
334 
335  self->goalentity = self->enemy;
336  if (self->monsterinfo.aiflags & AI_STAND_GROUND)
337  self->monsterinfo.stand (self);
338  else
339  self->monsterinfo.run (self);
340  VectorSubtract (self->enemy->s.origin, self->s.origin, vec);
341  self->ideal_yaw = vectoyaw(vec);
342  // wait a while before first attack
343  if (!(self->monsterinfo.aiflags & AI_STAND_GROUND))
344  AttackFinished (self, 1);
345 }

Referenced by ai_checkattack(), and FoundTarget().

◆ infront()

qboolean infront ( edict_t self,
edict_t other 
)

Definition at line 312 of file g_ai.c.

313 {
314  vec3_t vec;
315  float dot;
316  vec3_t forward;
317 
318  AngleVectors (self->s.angles, forward, NULL, NULL);
319  VectorSubtract (other->s.origin, self->s.origin, vec);
320  VectorNormalize (vec);
321  dot = DotProduct (vec, forward);
322 
323  if (dot > 0.3)
324  return true;
325  return false;
326 }

Referenced by ai_checkattack(), Boss2_CheckAttack(), boss2_reattack_mg(), check_dodge(), FindTarget(), Jorg_CheckAttack(), and Makron_CheckAttack().

◆ M_CheckAttack()

qboolean M_CheckAttack ( edict_t self)

Definition at line 607 of file g_ai.c.

608 {
609  vec3_t spot1, spot2;
610  float chance;
611  trace_t tr;
612 
613  if (self->enemy->health > 0)
614  {
615  // see if any entities are in the way of the shot
616  VectorCopy (self->s.origin, spot1);
617  spot1[2] += self->viewheight;
618  VectorCopy (self->enemy->s.origin, spot2);
619  spot2[2] += self->enemy->viewheight;
620 
622 
623  // do we have a clear shot?
624  if (tr.ent != self->enemy)
625  return false;
626  }
627 
628  // melee attack
629  if (enemy_range == RANGE_MELEE)
630  {
631  // don't always melee in easy mode
632  if (skill->value == 0 && (rand()&3) )
633  return false;
634  if (self->monsterinfo.melee)
635  self->monsterinfo.attack_state = AS_MELEE;
636  else
637  self->monsterinfo.attack_state = AS_MISSILE;
638  return true;
639  }
640 
641 // missile attack
642  if (!self->monsterinfo.attack)
643  return false;
644 
645  if (level.time < self->monsterinfo.attack_finished)
646  return false;
647 
648  if (enemy_range == RANGE_FAR)
649  return false;
650 
651  if (self->monsterinfo.aiflags & AI_STAND_GROUND)
652  {
653  chance = 0.4;
654  }
655  else if (enemy_range == RANGE_MELEE)
656  {
657  chance = 0.2;
658  }
659  else if (enemy_range == RANGE_NEAR)
660  {
661  chance = 0.1;
662  }
663  else if (enemy_range == RANGE_MID)
664  {
665  chance = 0.02;
666  }
667  else
668  {
669  return false;
670  }
671 
672  if (skill->value == 0)
673  chance *= 0.5;
674  else if (skill->value >= 2)
675  chance *= 2;
676 
677  if (random () < chance)
678  {
679  self->monsterinfo.attack_state = AS_MISSILE;
680  self->monsterinfo.attack_finished = level.time + 2*random();
681  return true;
682  }
683 
684  if (self->flags & FL_FLY)
685  {
686  if (random() < 0.3)
687  self->monsterinfo.attack_state = AS_SLIDING;
688  else
689  self->monsterinfo.attack_state = AS_STRAIGHT;
690  }
691 
692  return false;
693 }

Referenced by medic_checkattack(), and monster_start().

◆ range()

int range ( edict_t self,
edict_t other 
)

Definition at line 264 of file g_ai.c.

265 {
266  vec3_t v;
267  float len;
268 
269  VectorSubtract (self->s.origin, other->s.origin, v);
270  len = VectorLength (v);
271  if (len < MELEE_DISTANCE)
272  return RANGE_MELEE;
273  if (len < 500)
274  return RANGE_NEAR;
275  if (len < 1000)
276  return RANGE_MID;
277  return RANGE_FAR;
278 }

Referenced by ai_checkattack(), and FindTarget().

◆ visible()

qboolean visible ( edict_t self,
edict_t other 
)

Definition at line 287 of file g_ai.c.

288 {
289  vec3_t spot1;
290  vec3_t spot2;
291  trace_t trace;
292 
293  VectorCopy (self->s.origin, spot1);
294  spot1[2] += self->viewheight;
295  VectorCopy (other->s.origin, spot2);
296  spot2[2] += other->viewheight;
297  trace = gi.trace (spot1, vec3_origin, vec3_origin, spot2, self, MASK_OPAQUE);
298 
299  if (trace.fraction == 1.0)
300  return true;
301  return false;
302 }

Referenced by ai_checkattack(), chick_rerocket(), ClientBeginServerFrame(), FindTarget(), gunner_refire_chain(), hover_reattack(), jorg_reattack1(), M_ReactToDamage(), medic_continue(), medic_FindDeadMonster(), PlayerTrail_PickFirst(), supertank_reattack1(), tank_reattack_blaster(), tank_refire_rocket(), and turret_driver_think().

Variable Documentation

◆ enemy_infront

qboolean enemy_infront

Definition at line 30 of file g_ai.c.

Referenced by ai_checkattack(), Boss2_CheckAttack(), Jorg_CheckAttack(), and Makron_CheckAttack().

◆ enemy_range

int enemy_range

◆ enemy_vis

qboolean enemy_vis

Definition at line 29 of file g_ai.c.

Referenced by ai_checkattack(), and ai_run().

◆ enemy_yaw

◆ maxclients

gi
game_import_t gi
Definition: g_main.c:25
G_ProjectSource
void G_ProjectSource(vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
Definition: g_utils.c:25
edict_s::ideal_yaw
float ideal_yaw
Definition: g_local.h:1034
game_import_t::dprintf
void(* dprintf)(char *fmt,...)
Definition: game.h:106
edict_s::s
entity_state_t s
Definition: g_local.h:964
RANGE_NEAR
#define RANGE_NEAR
Definition: g_local.h:118
edict_s::timestamp
float timestamp
Definition: g_local.h:1008
CONTENTS_MONSTER
#define CONTENTS_MONSTER
Definition: qfiles.h:359
AI_MEDIC
#define AI_MEDIC
Definition: g_local.h:140
YAW
#define YAW
Definition: q_shared.h:66
AI_COMBAT_POINT
#define AI_COMBAT_POINT
Definition: g_local.h:139
AI_BRUTAL
#define AI_BRUTAL
Definition: g_local.h:136
game_import_t::trace
trace_t(* trace)(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passent, int contentmask)
Definition: game.h:128
G_Spawn
edict_t * G_Spawn(void)
Definition: g_utils.c:420
trace_t::fraction
float fraction
Definition: q_shared.h:453
MELEE_DISTANCE
#define MELEE_DISTANCE
Definition: g_local.h:80
VectorSubtract
#define VectorSubtract(a, b, c)
Definition: q_shared.h:156
AI_TEMP_STAND_GROUND
#define AI_TEMP_STAND_GROUND
Definition: g_local.h:128
AI_GOOD_GUY
#define AI_GOOD_GUY
Definition: g_local.h:135
PlayerTrail_PickNext
edict_t * PlayerTrail_PickNext(edict_t *self)
Definition: p_trail.c:124
AttackFinished
void AttackFinished(edict_t *self, float time)
Definition: g_monster.c:135
edict_s::movetarget
edict_t * movetarget
Definition: g_local.h:1032
monsterinfo_t::attack
void(* attack)(edict_t *self)
Definition: g_local.h:429
v
GLdouble v
Definition: qgl_win.c:143
M_walkmove
qboolean M_walkmove(edict_t *ent, float yaw, float dist)
Definition: m_move.c:542
ai_checkattack
qboolean ai_checkattack(edict_t *self, float dist)
Definition: g_ai.c:771
entity_state_s::origin
vec3_t origin
Definition: q_shared.h:1173
monsterinfo_t::search
void(* search)(edict_t *self)
Definition: g_local.h:425
AI_LOST_SIGHT
#define AI_LOST_SIGHT
Definition: g_local.h:130
monsterinfo_t::last_sighting
vec3_t last_sighting
Definition: g_local.h:440
AI_STAND_GROUND
#define AI_STAND_GROUND
Definition: g_local.h:127
qboolean
qboolean
Definition: q_shared.h:56
edict_s::inuse
qboolean inuse
Definition: g_local.h:970
edict_s::oldenemy
edict_t * oldenemy
Definition: g_local.h:1071
trace_t
Definition: q_shared.h:449
edict_s::client
struct gclient_s * client
Definition: g_local.h:965
ai_run_missile
void ai_run_missile(edict_t *self)
Definition: g_ai.c:723
vectoyaw
float vectoyaw(vec3_t vec)
Definition: g_utils.c:333
AI_PURSUE_TEMP
#define AI_PURSUE_TEMP
Definition: g_local.h:133
CONTENTS_SOLID
#define CONTENTS_SOLID
Definition: qfiles.h:333
edict_s::mins
vec3_t mins
Definition: g_local.h:984
monsterinfo_t::attack_state
int attack_state
Definition: g_local.h:441
g_edicts
edict_t * g_edicts
Definition: g_main.c:33
anglemod
float anglemod(float a)
Definition: q_shared.c:293
edict_s::areanum
int areanum
Definition: g_local.h:979
infront
qboolean infront(edict_t *self, edict_t *other)
Definition: g_ai.c:312
HuntTarget
void HuntTarget(edict_t *self)
Definition: g_ai.c:331
AngleVectors
void AngleVectors(vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
Definition: q_shared.c:93
edict_s::show_hostile
qboolean show_hostile
Definition: g_local.h:1055
edict_s::svflags
int svflags
Definition: g_local.h:983
monsterinfo_t::sight
void(* sight)(edict_t *self, edict_t *other)
Definition: g_local.h:431
edict_s::classname
char * classname
Definition: g_local.h:1005
edict_s
Definition: g_local.h:962
G_FreeEdict
void G_FreeEdict(edict_t *e)
Definition: g_utils.c:452
monsterinfo_t::pausetime
float pausetime
Definition: g_local.h:434
r
GLdouble GLdouble r
Definition: qgl_win.c:336
monsterinfo_t::search_time
float search_time
Definition: g_local.h:438
ai_run_melee
void ai_run_melee(edict_t *self)
Definition: g_ai.c:703
AS_SLIDING
#define AS_SLIDING
Definition: g_local.h:145
edict_s::viewheight
int viewheight
Definition: g_local.h:1061
M_MoveToGoal
void M_MoveToGoal(edict_t *ent, float dist)
Definition: m_move.c:515
forward
static vec3_t forward
Definition: p_view.c:29
monsterinfo_t::saved_goal
vec3_t saved_goal
Definition: g_local.h:437
edict_s::spawnflags
int spawnflags
Definition: g_local.h:1006
VectorLength
vec_t VectorLength(vec3_t v)
Definition: q_shared.c:762
FindTarget
qboolean FindTarget(edict_t *self)
Definition: g_ai.c:407
edict_s::owner
edict_t * owner
Definition: g_local.h:988
AS_MISSILE
#define AS_MISSILE
Definition: g_local.h:147
DotProduct
#define DotProduct(x, y)
Definition: q_shared.h:155
cvar_s::value
float value
Definition: q_shared.h:324
vtos
char * vtos(vec3_t v)
Definition: g_utils.c:293
AI_PURSUIT_LAST_SEEN
#define AI_PURSUIT_LAST_SEEN
Definition: g_local.h:131
game
game_locals_t game
Definition: g_main.c:23
random
#define random()
Definition: g_local.h:509
FL_NOTARGET
#define FL_NOTARGET
Definition: g_local.h:62
VectorNormalize
vec_t VectorNormalize(vec3_t v)
Definition: q_shared.c:681
NULL
#define NULL
Definition: q_shared.h:60
FoundTarget
void FoundTarget(edict_t *self)
Definition: g_ai.c:347
game_import_t::AreasConnected
qboolean(* AreasConnected)(int area1, int area2)
Definition: game.h:133
monsterinfo_t::aiflags
int aiflags
Definition: g_local.h:419
edict_s::goalentity
edict_t * goalentity
Definition: g_local.h:1031
enemy_infront
qboolean enemy_infront
Definition: g_ai.c:30
skill
cvar_t * skill
Definition: g_main.c:38
MASK_OPAQUE
#define MASK_OPAQUE
Definition: q_shared.h:396
CONTENTS_SLIME
#define CONTENTS_SLIME
Definition: qfiles.h:337
monsterinfo_t::lefty
int lefty
Definition: g_local.h:442
edict_s::light_level
int light_level
Definition: g_local.h:1100
PlayerTrail_PickFirst
edict_t * PlayerTrail_PickFirst(edict_t *self)
Definition: p_trail.c:95
VectorCopy
#define VectorCopy(a, b)
Definition: q_shared.h:158
coop
cvar_t * coop
Definition: g_main.c:36
AI_SOUND_TARGET
#define AI_SOUND_TARGET
Definition: g_local.h:129
edict_s::monsterinfo
monsterinfo_t monsterinfo
Definition: g_local.h:1108
visible
qboolean visible(edict_t *self, edict_t *other)
Definition: g_ai.c:287
vec3_origin
vec3_t vec3_origin
Definition: q_shared.c:24
RANGE_MELEE
#define RANGE_MELEE
Definition: g_local.h:117
level
GLint level
Definition: qgl_win.c:116
monsterinfo_t::idle_time
float idle_time
Definition: g_local.h:443
edict_s::flags
int flags
Definition: g_local.h:996
enemy_range
int enemy_range
Definition: g_ai.c:31
enemy_vis
qboolean enemy_vis
Definition: g_ai.c:29
edict_s::teleport_time
float teleport_time
Definition: g_local.h:1091
CONTENTS_LAVA
#define CONTENTS_LAVA
Definition: qfiles.h:336
edict_s::maxs
vec3_t maxs
Definition: g_local.h:984
RANGE_MID
#define RANGE_MID
Definition: g_local.h:119
monsterinfo_t::idle
void(* idle)(edict_t *self)
Definition: g_local.h:424
trace_t::ent
struct edict_s * ent
Definition: q_shared.h:458
FL_FLY
#define FL_FLY
Definition: g_local.h:57
SVF_MONSTER
#define SVF_MONSTER
Definition: game.h:29
ai_run_slide
void ai_run_slide(edict_t *self, float distance)
Definition: g_ai.c:743
edict_s::combattarget
char * combattarget
Definition: g_local.h:1017
monsterinfo_t::attack_finished
float attack_finished
Definition: g_local.h:435
AI_PURSUE_NEXT
#define AI_PURSUE_NEXT
Definition: g_local.h:132
range
int range(edict_t *self, edict_t *other)
Definition: g_ai.c:264
VectorSet
#define VectorSet(v, x, y, z)
Definition: q_shared.h:161
right
GLdouble right
Definition: qgl_win.c:159
CONTENTS_WINDOW
#define CONTENTS_WINDOW
Definition: qfiles.h:334
monsterinfo_t::melee
void(* melee)(edict_t *self)
Definition: g_local.h:430
M_ChangeYaw
void M_ChangeYaw(edict_t *ent)
Definition: m_move.c:304
FacingIdeal
qboolean FacingIdeal(edict_t *self)
Definition: g_ai.c:594
G_PickTarget
edict_t * G_PickTarget(char *targetname)
Definition: g_utils.c:118
edict_s::enemy
edict_t * enemy
Definition: g_local.h:1070
MASK_PLAYERSOLID
#define MASK_PLAYERSOLID
Definition: q_shared.h:392
entity_state_s::angles
vec3_t angles
Definition: q_shared.h:1174
AS_MELEE
#define AS_MELEE
Definition: g_local.h:146
RANGE_FAR
#define RANGE_FAR
Definition: g_local.h:120
game_import_t::inPHS
qboolean(* inPHS)(vec3_t p1, vec3_t p2)
Definition: game.h:131
enemy_yaw
float enemy_yaw
Definition: g_ai.c:32
vec3_t
vec_t vec3_t[3]
Definition: q_shared.h:127
AS_STRAIGHT
#define AS_STRAIGHT
Definition: g_local.h:144
edict_s::health
int health
Definition: g_local.h:1051
game_locals_t::maxclients
int maxclients
Definition: g_local.h:284