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

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 914 of file g_ai.c.

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

◆ 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:1040
game_import_t::dprintf
void(* dprintf)(char *fmt,...)
Definition: game.h:106
edict_s::s
entity_state_t s
Definition: g_local.h:970
RANGE_NEAR
#define RANGE_NEAR
Definition: g_local.h:120
edict_s::timestamp
float timestamp
Definition: g_local.h:1014
CONTENTS_MONSTER
#define CONTENTS_MONSTER
Definition: qfiles.h:359
AI_MEDIC
#define AI_MEDIC
Definition: g_local.h:142
YAW
#define YAW
Definition: q_shared.h:73
AI_COMBAT_POINT
#define AI_COMBAT_POINT
Definition: g_local.h:141
AI_BRUTAL
#define AI_BRUTAL
Definition: g_local.h:138
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:457
MELEE_DISTANCE
#define MELEE_DISTANCE
Definition: g_local.h:82
VectorSubtract
#define VectorSubtract(a, b, c)
Definition: q_shared.h:163
AI_TEMP_STAND_GROUND
#define AI_TEMP_STAND_GROUND
Definition: g_local.h:130
AI_GOOD_GUY
#define AI_GOOD_GUY
Definition: g_local.h:137
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:1038
monsterinfo_t::attack
void(* attack)(edict_t *self)
Definition: g_local.h:431
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:1149
monsterinfo_t::search
void(* search)(edict_t *self)
Definition: g_local.h:427
AI_LOST_SIGHT
#define AI_LOST_SIGHT
Definition: g_local.h:132
monsterinfo_t::last_sighting
vec3_t last_sighting
Definition: g_local.h:442
AI_STAND_GROUND
#define AI_STAND_GROUND
Definition: g_local.h:129
qboolean
qboolean
Definition: q_shared.h:63
edict_s::inuse
qboolean inuse
Definition: g_local.h:976
edict_s::oldenemy
edict_t * oldenemy
Definition: g_local.h:1077
trace_t
Definition: q_shared.h:453
edict_s::client
struct gclient_s * client
Definition: g_local.h:971
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:135
CONTENTS_SOLID
#define CONTENTS_SOLID
Definition: qfiles.h:333
edict_s::mins
vec3_t mins
Definition: g_local.h:990
monsterinfo_t::attack_state
int attack_state
Definition: g_local.h:443
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:985
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:1061
edict_s::svflags
int svflags
Definition: g_local.h:989
monsterinfo_t::sight
void(* sight)(edict_t *self, edict_t *other)
Definition: g_local.h:433
edict_s::classname
char * classname
Definition: g_local.h:1011
edict_s
Definition: g_local.h:968
G_FreeEdict
void G_FreeEdict(edict_t *e)
Definition: g_utils.c:452
monsterinfo_t::pausetime
float pausetime
Definition: g_local.h:436
r
GLdouble GLdouble r
Definition: qgl_win.c:336
monsterinfo_t::search_time
float search_time
Definition: g_local.h:440
ai_run_melee
void ai_run_melee(edict_t *self)
Definition: g_ai.c:703
AS_SLIDING
#define AS_SLIDING
Definition: g_local.h:147
edict_s::viewheight
int viewheight
Definition: g_local.h:1067
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:439
edict_s::spawnflags
int spawnflags
Definition: g_local.h:1012
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:994
AS_MISSILE
#define AS_MISSILE
Definition: g_local.h:149
DotProduct
#define DotProduct(x, y)
Definition: q_shared.h:162
cvar_s::value
float value
Definition: q_shared.h:331
vtos
char * vtos(vec3_t v)
Definition: g_utils.c:293
AI_PURSUIT_LAST_SEEN
#define AI_PURSUIT_LAST_SEEN
Definition: g_local.h:133
game
game_locals_t game
Definition: g_main.c:23
random
#define random()
Definition: g_local.h:515
FL_NOTARGET
#define FL_NOTARGET
Definition: g_local.h:64
VectorNormalize
vec_t VectorNormalize(vec3_t v)
Definition: q_shared.c:681
NULL
#define NULL
Definition: q_shared.h:67
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:421
edict_s::goalentity
edict_t * goalentity
Definition: g_local.h:1037
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:400
CONTENTS_SLIME
#define CONTENTS_SLIME
Definition: qfiles.h:337
monsterinfo_t::lefty
int lefty
Definition: g_local.h:444
edict_s::light_level
int light_level
Definition: g_local.h:1106
PlayerTrail_PickFirst
edict_t * PlayerTrail_PickFirst(edict_t *self)
Definition: p_trail.c:95
VectorCopy
#define VectorCopy(a, b)
Definition: q_shared.h:165
coop
cvar_t * coop
Definition: g_main.c:36
AI_SOUND_TARGET
#define AI_SOUND_TARGET
Definition: g_local.h:131
edict_s::monsterinfo
monsterinfo_t monsterinfo
Definition: g_local.h:1114
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:119
level
GLint level
Definition: qgl_win.c:116
monsterinfo_t::idle_time
float idle_time
Definition: g_local.h:445
edict_s::flags
int flags
Definition: g_local.h:1002
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:1097
CONTENTS_LAVA
#define CONTENTS_LAVA
Definition: qfiles.h:336
edict_s::maxs
vec3_t maxs
Definition: g_local.h:990
RANGE_MID
#define RANGE_MID
Definition: g_local.h:121
monsterinfo_t::idle
void(* idle)(edict_t *self)
Definition: g_local.h:426
trace_t::ent
struct edict_s * ent
Definition: q_shared.h:462
FL_FLY
#define FL_FLY
Definition: g_local.h:59
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:1023
monsterinfo_t::attack_finished
float attack_finished
Definition: g_local.h:437
AI_PURSUE_NEXT
#define AI_PURSUE_NEXT
Definition: g_local.h:134
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:168
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:432
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:1076
MASK_PLAYERSOLID
#define MASK_PLAYERSOLID
Definition: q_shared.h:396
entity_state_s::angles
vec3_t angles
Definition: q_shared.h:1150
AS_MELEE
#define AS_MELEE
Definition: g_local.h:148
RANGE_FAR
#define RANGE_FAR
Definition: g_local.h:122
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:134
AS_STRAIGHT
#define AS_STRAIGHT
Definition: g_local.h:146
edict_s::health
int health
Definition: g_local.h:1057
game_locals_t::maxclients
int maxclients
Definition: g_local.h:286