g_ai.c 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118
  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. // g_ai.c
  16. #include "g_local.h"
  17. qboolean FindTarget (edict_t *self);
  18. extern cvar_t *maxclients;
  19. qboolean ai_checkattack (edict_t *self, float dist);
  20. qboolean enemy_vis;
  21. qboolean enemy_infront;
  22. int enemy_range;
  23. float enemy_yaw;
  24. //============================================================================
  25. /*
  26. =================
  27. AI_SetSightClient
  28. Called once each frame to set level.sight_client to the
  29. player to be checked for in findtarget.
  30. If all clients are either dead or in notarget, sight_client
  31. will be null.
  32. In coop games, sight_client will cycle between the clients.
  33. =================
  34. */
  35. void AI_SetSightClient (void)
  36. {
  37. edict_t *ent;
  38. int start, check;
  39. if (level.sight_client == NULL)
  40. start = 1;
  41. else
  42. start = level.sight_client - g_edicts;
  43. check = start;
  44. while (1)
  45. {
  46. check++;
  47. if (check > game.maxclients)
  48. check = 1;
  49. ent = &g_edicts[check];
  50. if (ent->inuse
  51. && ent->health > 0
  52. && !(ent->flags & FL_NOTARGET) )
  53. {
  54. level.sight_client = ent;
  55. return; // got one
  56. }
  57. if (check == start)
  58. {
  59. level.sight_client = NULL;
  60. return; // nobody to see
  61. }
  62. }
  63. }
  64. //============================================================================
  65. /*
  66. =============
  67. ai_move
  68. Move the specified distance at current facing.
  69. This replaces the QC functions: ai_forward, ai_back, ai_pain, and ai_painforward
  70. ==============
  71. */
  72. void ai_move (edict_t *self, float dist)
  73. {
  74. M_walkmove (self, self->s.angles[YAW], dist);
  75. }
  76. /*
  77. =============
  78. ai_stand
  79. Used for standing around and looking for players
  80. Distance is for slight position adjustments needed by the animations
  81. ==============
  82. */
  83. void ai_stand (edict_t *self, float dist)
  84. {
  85. vec3_t v;
  86. if (dist)
  87. M_walkmove (self, self->s.angles[YAW], dist);
  88. if (self->monsterinfo.aiflags & AI_STAND_GROUND)
  89. {
  90. if (self->enemy)
  91. {
  92. VectorSubtract (self->enemy->s.origin, self->s.origin, v);
  93. self->ideal_yaw = vectoyaw(v);
  94. if (self->s.angles[YAW] != self->ideal_yaw && self->monsterinfo.aiflags & AI_TEMP_STAND_GROUND)
  95. {
  96. self->monsterinfo.aiflags &= ~(AI_STAND_GROUND | AI_TEMP_STAND_GROUND);
  97. self->monsterinfo.run (self);
  98. }
  99. M_ChangeYaw (self);
  100. ai_checkattack (self, 0);
  101. }
  102. else
  103. FindTarget (self);
  104. return;
  105. }
  106. if (FindTarget (self))
  107. return;
  108. if (level.time > self->monsterinfo.pausetime)
  109. {
  110. self->monsterinfo.walk (self);
  111. return;
  112. }
  113. if (!(self->spawnflags & 1) && (self->monsterinfo.idle) && (level.time > self->monsterinfo.idle_time))
  114. {
  115. if (self->monsterinfo.idle_time)
  116. {
  117. self->monsterinfo.idle (self);
  118. self->monsterinfo.idle_time = level.time + 15 + random() * 15;
  119. }
  120. else
  121. {
  122. self->monsterinfo.idle_time = level.time + random() * 15;
  123. }
  124. }
  125. }
  126. /*
  127. =============
  128. ai_walk
  129. The monster is walking it's beat
  130. =============
  131. */
  132. void ai_walk (edict_t *self, float dist)
  133. {
  134. M_MoveToGoal (self, dist);
  135. // check for noticing a player
  136. if (FindTarget (self))
  137. return;
  138. if ((self->monsterinfo.search) && (level.time > self->monsterinfo.idle_time))
  139. {
  140. if (self->monsterinfo.idle_time)
  141. {
  142. self->monsterinfo.search (self);
  143. self->monsterinfo.idle_time = level.time + 15 + random() * 15;
  144. }
  145. else
  146. {
  147. self->monsterinfo.idle_time = level.time + random() * 15;
  148. }
  149. }
  150. }
  151. /*
  152. =============
  153. ai_charge
  154. Turns towards target and advances
  155. Use this call with a distnace of 0 to replace ai_face
  156. ==============
  157. */
  158. void ai_charge (edict_t *self, float dist)
  159. {
  160. vec3_t v;
  161. VectorSubtract (self->enemy->s.origin, self->s.origin, v);
  162. self->ideal_yaw = vectoyaw(v);
  163. M_ChangeYaw (self);
  164. if (dist)
  165. M_walkmove (self, self->s.angles[YAW], dist);
  166. }
  167. /*
  168. =============
  169. ai_turn
  170. don't move, but turn towards ideal_yaw
  171. Distance is for slight position adjustments needed by the animations
  172. =============
  173. */
  174. void ai_turn (edict_t *self, float dist)
  175. {
  176. if (dist)
  177. M_walkmove (self, self->s.angles[YAW], dist);
  178. if (FindTarget (self))
  179. return;
  180. M_ChangeYaw (self);
  181. }
  182. /*
  183. .enemy
  184. Will be world if not currently angry at anyone.
  185. .movetarget
  186. The next path spot to walk toward. If .enemy, ignore .movetarget.
  187. When an enemy is killed, the monster will try to return to it's path.
  188. .hunt_time
  189. Set to time + something when the player is in sight, but movement straight for
  190. him is blocked. This causes the monster to use wall following code for
  191. movement direction instead of sighting on the player.
  192. .ideal_yaw
  193. A yaw angle of the intended direction, which will be turned towards at up
  194. to 45 deg / state. If the enemy is in view and hunt_time is not active,
  195. this will be the exact line towards the enemy.
  196. .pausetime
  197. A monster will leave it's stand state and head towards it's .movetarget when
  198. time > .pausetime.
  199. walkmove(angle, speed) primitive is all or nothing
  200. */
  201. /*
  202. =============
  203. range
  204. returns the range catagorization of an entity reletive to self
  205. 0 melee range, will become hostile even if back is turned
  206. 1 visibility and infront, or visibility and show hostile
  207. 2 infront and show hostile
  208. 3 only triggered by damage
  209. =============
  210. */
  211. int range (edict_t *self, edict_t *other)
  212. {
  213. vec3_t v;
  214. float len;
  215. VectorSubtract (self->s.origin, other->s.origin, v);
  216. len = VectorLength (v);
  217. if (len < MELEE_DISTANCE)
  218. return RANGE_MELEE;
  219. if (len < 500)
  220. return RANGE_NEAR;
  221. if (len < 1000)
  222. return RANGE_MID;
  223. return RANGE_FAR;
  224. }
  225. /*
  226. =============
  227. visible
  228. returns 1 if the entity is visible to self, even if not infront ()
  229. =============
  230. */
  231. qboolean visible (edict_t *self, edict_t *other)
  232. {
  233. vec3_t spot1;
  234. vec3_t spot2;
  235. trace_t trace;
  236. VectorCopy (self->s.origin, spot1);
  237. spot1[2] += self->viewheight;
  238. VectorCopy (other->s.origin, spot2);
  239. spot2[2] += other->viewheight;
  240. trace = gi.trace (spot1, vec3_origin, vec3_origin, spot2, self, MASK_OPAQUE);
  241. if (trace.fraction == 1.0)
  242. return true;
  243. return false;
  244. }
  245. /*
  246. =============
  247. infront
  248. returns 1 if the entity is in front (in sight) of self
  249. =============
  250. */
  251. qboolean infront (edict_t *self, edict_t *other)
  252. {
  253. vec3_t vec;
  254. float dot;
  255. vec3_t forward;
  256. AngleVectors (self->s.angles, forward, NULL, NULL);
  257. VectorSubtract (other->s.origin, self->s.origin, vec);
  258. VectorNormalize (vec);
  259. dot = DotProduct (vec, forward);
  260. if (dot > 0.3)
  261. return true;
  262. return false;
  263. }
  264. //============================================================================
  265. void HuntTarget (edict_t *self)
  266. {
  267. vec3_t vec;
  268. self->goalentity = self->enemy;
  269. if (self->monsterinfo.aiflags & AI_STAND_GROUND)
  270. self->monsterinfo.stand (self);
  271. else
  272. self->monsterinfo.run (self);
  273. VectorSubtract (self->enemy->s.origin, self->s.origin, vec);
  274. self->ideal_yaw = vectoyaw(vec);
  275. // wait a while before first attack
  276. if (!(self->monsterinfo.aiflags & AI_STAND_GROUND))
  277. AttackFinished (self, 1);
  278. }
  279. void FoundTarget (edict_t *self)
  280. {
  281. // let other monsters see this monster for a while
  282. if (self->enemy->client)
  283. {
  284. level.sight_entity = self;
  285. level.sight_entity_framenum = level.framenum;
  286. level.sight_entity->light_level = 128;
  287. }
  288. self->show_hostile = level.time + 1; // wake up other monsters
  289. VectorCopy(self->enemy->s.origin, self->monsterinfo.last_sighting);
  290. self->monsterinfo.trail_time = level.time;
  291. if (!self->combattarget)
  292. {
  293. HuntTarget (self);
  294. return;
  295. }
  296. self->goalentity = self->movetarget = G_PickTarget(self->combattarget);
  297. if (!self->movetarget)
  298. {
  299. self->goalentity = self->movetarget = self->enemy;
  300. HuntTarget (self);
  301. gi.dprintf("%s at %s, combattarget %s not found\n", self->classname, vtos(self->s.origin), self->combattarget);
  302. return;
  303. }
  304. // clear out our combattarget, these are a one shot deal
  305. self->combattarget = NULL;
  306. self->monsterinfo.aiflags |= AI_COMBAT_POINT;
  307. // clear the targetname, that point is ours!
  308. self->movetarget->targetname = NULL;
  309. self->monsterinfo.pausetime = 0;
  310. // run for it
  311. self->monsterinfo.run (self);
  312. }
  313. /*
  314. ===========
  315. FindTarget
  316. Self is currently not attacking anything, so try to find a target
  317. Returns TRUE if an enemy was sighted
  318. When a player fires a missile, the point of impact becomes a fakeplayer so
  319. that monsters that see the impact will respond as if they had seen the
  320. player.
  321. To avoid spending too much time, only a single client (or fakeclient) is
  322. checked each frame. This means multi player games will have slightly
  323. slower noticing monsters.
  324. ============
  325. */
  326. qboolean FindTarget (edict_t *self)
  327. {
  328. edict_t *client;
  329. qboolean heardit;
  330. int r;
  331. if (self->monsterinfo.aiflags & AI_GOOD_GUY)
  332. {
  333. if (self->goalentity && self->goalentity->inuse && self->goalentity->classname)
  334. {
  335. if (strcmp(self->goalentity->classname, "target_actor") == 0)
  336. return false;
  337. }
  338. //FIXME look for monsters?
  339. return false;
  340. }
  341. // if we're going to a combat point, just proceed
  342. if (self->monsterinfo.aiflags & AI_COMBAT_POINT)
  343. return false;
  344. // if the first spawnflag bit is set, the monster will only wake up on
  345. // really seeing the player, not another monster getting angry or hearing
  346. // something
  347. // revised behavior so they will wake up if they "see" a player make a noise
  348. // but not weapon impact/explosion noises
  349. heardit = false;
  350. if ((level.sight_entity_framenum >= (level.framenum - 1)) && !(self->spawnflags & 1) )
  351. {
  352. client = level.sight_entity;
  353. if (client->enemy == self->enemy)
  354. {
  355. return false;
  356. }
  357. }
  358. else if (level.sound_entity_framenum >= (level.framenum - 1))
  359. {
  360. client = level.sound_entity;
  361. heardit = true;
  362. }
  363. else if (!(self->enemy) && (level.sound2_entity_framenum >= (level.framenum - 1)) && !(self->spawnflags & 1) )
  364. {
  365. client = level.sound2_entity;
  366. heardit = true;
  367. }
  368. else
  369. {
  370. client = level.sight_client;
  371. if (!client)
  372. return false; // no clients to get mad at
  373. }
  374. // if the entity went away, forget it
  375. if (!client->inuse)
  376. return false;
  377. if (client == self->enemy)
  378. return true; // JDC false;
  379. if (client->client)
  380. {
  381. if (client->flags & FL_NOTARGET)
  382. return false;
  383. }
  384. else if (client->svflags & SVF_MONSTER)
  385. {
  386. if (!client->enemy)
  387. return false;
  388. if (client->enemy->flags & FL_NOTARGET)
  389. return false;
  390. }
  391. else if (heardit)
  392. {
  393. if (client->owner->flags & FL_NOTARGET)
  394. return false;
  395. }
  396. else
  397. return false;
  398. if (!heardit)
  399. {
  400. r = range (self, client);
  401. if (r == RANGE_FAR)
  402. return false;
  403. // this is where we would check invisibility
  404. // is client in an spot too dark to be seen?
  405. if (client->light_level <= 5)
  406. return false;
  407. if (!visible (self, client))
  408. {
  409. return false;
  410. }
  411. if (r == RANGE_NEAR)
  412. {
  413. if (client->show_hostile < level.time && !infront (self, client))
  414. {
  415. return false;
  416. }
  417. }
  418. else if (r == RANGE_MID)
  419. {
  420. if (!infront (self, client))
  421. {
  422. return false;
  423. }
  424. }
  425. self->enemy = client;
  426. if (strcmp(self->enemy->classname, "player_noise") != 0)
  427. {
  428. self->monsterinfo.aiflags &= ~AI_SOUND_TARGET;
  429. if (!self->enemy->client)
  430. {
  431. self->enemy = self->enemy->enemy;
  432. if (!self->enemy->client)
  433. {
  434. self->enemy = NULL;
  435. return false;
  436. }
  437. }
  438. }
  439. }
  440. else // heardit
  441. {
  442. vec3_t temp;
  443. if (self->spawnflags & 1)
  444. {
  445. if (!visible (self, client))
  446. return false;
  447. }
  448. else
  449. {
  450. if (!gi.inPHS(self->s.origin, client->s.origin))
  451. return false;
  452. }
  453. VectorSubtract (client->s.origin, self->s.origin, temp);
  454. if (VectorLength(temp) > 1000) // too far to hear
  455. {
  456. return false;
  457. }
  458. // check area portals - if they are different and not connected then we can't hear it
  459. if (client->areanum != self->areanum)
  460. if (!gi.AreasConnected(self->areanum, client->areanum))
  461. return false;
  462. self->ideal_yaw = vectoyaw(temp);
  463. M_ChangeYaw (self);
  464. // hunt the sound for a bit; hopefully find the real player
  465. self->monsterinfo.aiflags |= AI_SOUND_TARGET;
  466. self->enemy = client;
  467. }
  468. //
  469. // got one
  470. //
  471. FoundTarget (self);
  472. if (!(self->monsterinfo.aiflags & AI_SOUND_TARGET) && (self->monsterinfo.sight))
  473. self->monsterinfo.sight (self, self->enemy);
  474. return true;
  475. }
  476. //=============================================================================
  477. /*
  478. ============
  479. FacingIdeal
  480. ============
  481. */
  482. qboolean FacingIdeal(edict_t *self)
  483. {
  484. float delta;
  485. delta = anglemod(self->s.angles[YAW] - self->ideal_yaw);
  486. if (delta > 45 && delta < 315)
  487. return false;
  488. return true;
  489. }
  490. //=============================================================================
  491. qboolean M_CheckAttack (edict_t *self)
  492. {
  493. vec3_t spot1, spot2;
  494. float chance;
  495. trace_t tr;
  496. if (self->enemy->health > 0)
  497. {
  498. // see if any entities are in the way of the shot
  499. VectorCopy (self->s.origin, spot1);
  500. spot1[2] += self->viewheight;
  501. VectorCopy (self->enemy->s.origin, spot2);
  502. spot2[2] += self->enemy->viewheight;
  503. tr = gi.trace (spot1, NULL, NULL, spot2, self, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_SLIME|CONTENTS_LAVA|CONTENTS_WINDOW);
  504. // do we have a clear shot?
  505. if (tr.ent != self->enemy)
  506. return false;
  507. }
  508. // melee attack
  509. if (enemy_range == RANGE_MELEE)
  510. {
  511. // don't always melee in easy mode
  512. if (skill->value == 0 && (rand()&3) )
  513. return false;
  514. if (self->monsterinfo.melee)
  515. self->monsterinfo.attack_state = AS_MELEE;
  516. else
  517. self->monsterinfo.attack_state = AS_MISSILE;
  518. return true;
  519. }
  520. // missile attack
  521. if (!self->monsterinfo.attack)
  522. return false;
  523. if (level.time < self->monsterinfo.attack_finished)
  524. return false;
  525. if (enemy_range == RANGE_FAR)
  526. return false;
  527. if (self->monsterinfo.aiflags & AI_STAND_GROUND)
  528. {
  529. chance = 0.4;
  530. }
  531. else if (enemy_range == RANGE_MELEE)
  532. {
  533. chance = 0.2;
  534. }
  535. else if (enemy_range == RANGE_NEAR)
  536. {
  537. chance = 0.1;
  538. }
  539. else if (enemy_range == RANGE_MID)
  540. {
  541. chance = 0.02;
  542. }
  543. else
  544. {
  545. return false;
  546. }
  547. if (skill->value == 0)
  548. chance *= 0.5;
  549. else if (skill->value >= 2)
  550. chance *= 2;
  551. if (random () < chance)
  552. {
  553. self->monsterinfo.attack_state = AS_MISSILE;
  554. self->monsterinfo.attack_finished = level.time + 2*random();
  555. return true;
  556. }
  557. if (self->flags & FL_FLY)
  558. {
  559. if (random() < 0.3)
  560. self->monsterinfo.attack_state = AS_SLIDING;
  561. else
  562. self->monsterinfo.attack_state = AS_STRAIGHT;
  563. }
  564. return false;
  565. }
  566. /*
  567. =============
  568. ai_run_melee
  569. Turn and close until within an angle to launch a melee attack
  570. =============
  571. */
  572. void ai_run_melee(edict_t *self)
  573. {
  574. self->ideal_yaw = enemy_yaw;
  575. M_ChangeYaw (self);
  576. if (FacingIdeal(self))
  577. {
  578. self->monsterinfo.melee (self);
  579. self->monsterinfo.attack_state = AS_STRAIGHT;
  580. }
  581. }
  582. /*
  583. =============
  584. ai_run_missile
  585. Turn in place until within an angle to launch a missile attack
  586. =============
  587. */
  588. void ai_run_missile(edict_t *self)
  589. {
  590. self->ideal_yaw = enemy_yaw;
  591. M_ChangeYaw (self);
  592. if (FacingIdeal(self))
  593. {
  594. self->monsterinfo.attack (self);
  595. self->monsterinfo.attack_state = AS_STRAIGHT;
  596. }
  597. };
  598. /*
  599. =============
  600. ai_run_slide
  601. Strafe sideways, but stay at aproximately the same range
  602. =============
  603. */
  604. void ai_run_slide(edict_t *self, float distance)
  605. {
  606. float ofs;
  607. self->ideal_yaw = enemy_yaw;
  608. M_ChangeYaw (self);
  609. if (self->monsterinfo.lefty)
  610. ofs = 90;
  611. else
  612. ofs = -90;
  613. if (M_walkmove (self, self->ideal_yaw + ofs, distance))
  614. return;
  615. self->monsterinfo.lefty = 1 - self->monsterinfo.lefty;
  616. M_walkmove (self, self->ideal_yaw - ofs, distance);
  617. }
  618. /*
  619. =============
  620. ai_checkattack
  621. Decides if we're going to attack or do something else
  622. used by ai_run and ai_stand
  623. =============
  624. */
  625. qboolean ai_checkattack (edict_t *self, float dist)
  626. {
  627. vec3_t temp;
  628. qboolean hesDeadJim;
  629. // this causes monsters to run blindly to the combat point w/o firing
  630. if (self->goalentity)
  631. {
  632. if (self->monsterinfo.aiflags & AI_COMBAT_POINT)
  633. return false;
  634. if (self->monsterinfo.aiflags & AI_SOUND_TARGET)
  635. {
  636. if ((level.time - self->enemy->teleport_time) > 5.0)
  637. {
  638. if (self->goalentity == self->enemy)
  639. if (self->movetarget)
  640. self->goalentity = self->movetarget;
  641. else
  642. self->goalentity = NULL;
  643. self->monsterinfo.aiflags &= ~AI_SOUND_TARGET;
  644. if (self->monsterinfo.aiflags & AI_TEMP_STAND_GROUND)
  645. self->monsterinfo.aiflags &= ~(AI_STAND_GROUND | AI_TEMP_STAND_GROUND);
  646. }
  647. else
  648. {
  649. self->show_hostile = level.time + 1;
  650. return false;
  651. }
  652. }
  653. }
  654. enemy_vis = false;
  655. // see if the enemy is dead
  656. hesDeadJim = false;
  657. if ((!self->enemy) || (!self->enemy->inuse))
  658. {
  659. hesDeadJim = true;
  660. }
  661. else if (self->monsterinfo.aiflags & AI_MEDIC)
  662. {
  663. if (self->enemy->health > 0)
  664. {
  665. hesDeadJim = true;
  666. self->monsterinfo.aiflags &= ~AI_MEDIC;
  667. }
  668. }
  669. else
  670. {
  671. if (self->monsterinfo.aiflags & AI_BRUTAL)
  672. {
  673. if (self->enemy->health <= -80)
  674. hesDeadJim = true;
  675. }
  676. else
  677. {
  678. if (self->enemy->health <= 0)
  679. hesDeadJim = true;
  680. }
  681. }
  682. if (hesDeadJim)
  683. {
  684. self->enemy = NULL;
  685. // FIXME: look all around for other targets
  686. if (self->oldenemy && self->oldenemy->health > 0)
  687. {
  688. self->enemy = self->oldenemy;
  689. self->oldenemy = NULL;
  690. HuntTarget (self);
  691. }
  692. else
  693. {
  694. if (self->movetarget)
  695. {
  696. self->goalentity = self->movetarget;
  697. self->monsterinfo.walk (self);
  698. }
  699. else
  700. {
  701. // we need the pausetime otherwise the stand code
  702. // will just revert to walking with no target and
  703. // the monsters will wonder around aimlessly trying
  704. // to hunt the world entity
  705. self->monsterinfo.pausetime = level.time + 100000000;
  706. self->monsterinfo.stand (self);
  707. }
  708. return true;
  709. }
  710. }
  711. self->show_hostile = level.time + 1; // wake up other monsters
  712. // check knowledge of enemy
  713. enemy_vis = visible(self, self->enemy);
  714. if (enemy_vis)
  715. {
  716. self->monsterinfo.search_time = level.time + 5;
  717. VectorCopy (self->enemy->s.origin, self->monsterinfo.last_sighting);
  718. }
  719. // look for other coop players here
  720. // if (coop && self->monsterinfo.search_time < level.time)
  721. // {
  722. // if (FindTarget (self))
  723. // return true;
  724. // }
  725. enemy_infront = infront(self, self->enemy);
  726. enemy_range = range(self, self->enemy);
  727. VectorSubtract (self->enemy->s.origin, self->s.origin, temp);
  728. enemy_yaw = vectoyaw(temp);
  729. // JDC self->ideal_yaw = enemy_yaw;
  730. if (self->monsterinfo.attack_state == AS_MISSILE)
  731. {
  732. ai_run_missile (self);
  733. return true;
  734. }
  735. if (self->monsterinfo.attack_state == AS_MELEE)
  736. {
  737. ai_run_melee (self);
  738. return true;
  739. }
  740. // if enemy is not currently visible, we will never attack
  741. if (!enemy_vis)
  742. return false;
  743. return self->monsterinfo.checkattack (self);
  744. }
  745. /*
  746. =============
  747. ai_run
  748. The monster has an enemy it is trying to kill
  749. =============
  750. */
  751. void ai_run (edict_t *self, float dist)
  752. {
  753. vec3_t v;
  754. edict_t *tempgoal;
  755. edict_t *save;
  756. qboolean new;
  757. edict_t *marker;
  758. float d1, d2;
  759. trace_t tr;
  760. vec3_t v_forward, v_right;
  761. float left, center, right;
  762. vec3_t left_target, right_target;
  763. // if we're going to a combat point, just proceed
  764. if (self->monsterinfo.aiflags & AI_COMBAT_POINT)
  765. {
  766. M_MoveToGoal (self, dist);
  767. return;
  768. }
  769. if (self->monsterinfo.aiflags & AI_SOUND_TARGET)
  770. {
  771. VectorSubtract (self->s.origin, self->enemy->s.origin, v);
  772. if (VectorLength(v) < 64)
  773. {
  774. self->monsterinfo.aiflags |= (AI_STAND_GROUND | AI_TEMP_STAND_GROUND);
  775. self->monsterinfo.stand (self);
  776. return;
  777. }
  778. M_MoveToGoal (self, dist);
  779. if (!FindTarget (self))
  780. return;
  781. }
  782. if (ai_checkattack (self, dist))
  783. return;
  784. if (self->monsterinfo.attack_state == AS_SLIDING)
  785. {
  786. ai_run_slide (self, dist);
  787. return;
  788. }
  789. if (enemy_vis)
  790. {
  791. // if (self.aiflags & AI_LOST_SIGHT)
  792. // dprint("regained sight\n");
  793. M_MoveToGoal (self, dist);
  794. self->monsterinfo.aiflags &= ~AI_LOST_SIGHT;
  795. VectorCopy (self->enemy->s.origin, self->monsterinfo.last_sighting);
  796. self->monsterinfo.trail_time = level.time;
  797. return;
  798. }
  799. // coop will change to another enemy if visible
  800. if (coop->value)
  801. { // FIXME: insane guys get mad with this, which causes crashes!
  802. if (FindTarget (self))
  803. return;
  804. }
  805. if ((self->monsterinfo.search_time) && (level.time > (self->monsterinfo.search_time + 20)))
  806. {
  807. M_MoveToGoal (self, dist);
  808. self->monsterinfo.search_time = 0;
  809. // dprint("search timeout\n");
  810. return;
  811. }
  812. save = self->goalentity;
  813. tempgoal = G_Spawn();
  814. self->goalentity = tempgoal;
  815. new = false;
  816. if (!(self->monsterinfo.aiflags & AI_LOST_SIGHT))
  817. {
  818. // just lost sight of the player, decide where to go first
  819. // dprint("lost sight of player, last seen at "); dprint(vtos(self.last_sighting)); dprint("\n");
  820. self->monsterinfo.aiflags |= (AI_LOST_SIGHT | AI_PURSUIT_LAST_SEEN);
  821. self->monsterinfo.aiflags &= ~(AI_PURSUE_NEXT | AI_PURSUE_TEMP);
  822. new = true;
  823. }
  824. if (self->monsterinfo.aiflags & AI_PURSUE_NEXT)
  825. {
  826. self->monsterinfo.aiflags &= ~AI_PURSUE_NEXT;
  827. // 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");
  828. // give ourself more time since we got this far
  829. self->monsterinfo.search_time = level.time + 5;
  830. if (self->monsterinfo.aiflags & AI_PURSUE_TEMP)
  831. {
  832. // dprint("was temp goal; retrying original\n");
  833. self->monsterinfo.aiflags &= ~AI_PURSUE_TEMP;
  834. marker = NULL;
  835. VectorCopy (self->monsterinfo.saved_goal, self->monsterinfo.last_sighting);
  836. new = true;
  837. }
  838. else if (self->monsterinfo.aiflags & AI_PURSUIT_LAST_SEEN)
  839. {
  840. self->monsterinfo.aiflags &= ~AI_PURSUIT_LAST_SEEN;
  841. marker = PlayerTrail_PickFirst (self);
  842. }
  843. else
  844. {
  845. marker = PlayerTrail_PickNext (self);
  846. }
  847. if (marker)
  848. {
  849. VectorCopy (marker->s.origin, self->monsterinfo.last_sighting);
  850. self->monsterinfo.trail_time = marker->timestamp;
  851. self->s.angles[YAW] = self->ideal_yaw = marker->s.angles[YAW];
  852. // dprint("heading is "); dprint(ftos(self.ideal_yaw)); dprint("\n");
  853. // debug_drawline(self.origin, self.last_sighting, 52);
  854. new = true;
  855. }
  856. }
  857. VectorSubtract (self->s.origin, self->monsterinfo.last_sighting, v);
  858. d1 = VectorLength(v);
  859. if (d1 <= dist)
  860. {
  861. self->monsterinfo.aiflags |= AI_PURSUE_NEXT;
  862. dist = d1;
  863. }
  864. VectorCopy (self->monsterinfo.last_sighting, self->goalentity->s.origin);
  865. if (new)
  866. {
  867. // gi.dprintf("checking for course correction\n");
  868. tr = gi.trace(self->s.origin, self->mins, self->maxs, self->monsterinfo.last_sighting, self, MASK_PLAYERSOLID);
  869. if (tr.fraction < 1)
  870. {
  871. VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
  872. d1 = VectorLength(v);
  873. center = tr.fraction;
  874. d2 = d1 * ((center+1)/2);
  875. self->s.angles[YAW] = self->ideal_yaw = vectoyaw(v);
  876. AngleVectors(self->s.angles, v_forward, v_right, NULL);
  877. VectorSet(v, d2, -16, 0);
  878. G_ProjectSource (self->s.origin, v, v_forward, v_right, left_target);
  879. tr = gi.trace(self->s.origin, self->mins, self->maxs, left_target, self, MASK_PLAYERSOLID);
  880. left = tr.fraction;
  881. VectorSet(v, d2, 16, 0);
  882. G_ProjectSource (self->s.origin, v, v_forward, v_right, right_target);
  883. tr = gi.trace(self->s.origin, self->mins, self->maxs, right_target, self, MASK_PLAYERSOLID);
  884. right = tr.fraction;
  885. center = (d1*center)/d2;
  886. if (left >= center && left > right)
  887. {
  888. if (left < 1)
  889. {
  890. VectorSet(v, d2 * left * 0.5, -16, 0);
  891. G_ProjectSource (self->s.origin, v, v_forward, v_right, left_target);
  892. // gi.dprintf("incomplete path, go part way and adjust again\n");
  893. }
  894. VectorCopy (self->monsterinfo.last_sighting, self->monsterinfo.saved_goal);
  895. self->monsterinfo.aiflags |= AI_PURSUE_TEMP;
  896. VectorCopy (left_target, self->goalentity->s.origin);
  897. VectorCopy (left_target, self->monsterinfo.last_sighting);
  898. VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
  899. self->s.angles[YAW] = self->ideal_yaw = vectoyaw(v);
  900. // gi.dprintf("adjusted left\n");
  901. // debug_drawline(self.origin, self.last_sighting, 152);
  902. }
  903. else if (right >= center && right > left)
  904. {
  905. if (right < 1)
  906. {
  907. VectorSet(v, d2 * right * 0.5, 16, 0);
  908. G_ProjectSource (self->s.origin, v, v_forward, v_right, right_target);
  909. // gi.dprintf("incomplete path, go part way and adjust again\n");
  910. }
  911. VectorCopy (self->monsterinfo.last_sighting, self->monsterinfo.saved_goal);
  912. self->monsterinfo.aiflags |= AI_PURSUE_TEMP;
  913. VectorCopy (right_target, self->goalentity->s.origin);
  914. VectorCopy (right_target, self->monsterinfo.last_sighting);
  915. VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
  916. self->s.angles[YAW] = self->ideal_yaw = vectoyaw(v);
  917. // gi.dprintf("adjusted right\n");
  918. // debug_drawline(self.origin, self.last_sighting, 152);
  919. }
  920. }
  921. // else gi.dprintf("course was fine\n");
  922. }
  923. M_MoveToGoal (self, dist);
  924. G_FreeEdict(tempgoal);
  925. if (self)
  926. self->goalentity = save;
  927. }