g_newai.c 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001
  1. // Copyright (c) ZeniMax Media Inc.
  2. // Licensed under the GNU General Public License 2.0.
  3. #include "g_local.h"
  4. //===============================
  5. // BLOCKED Logic
  6. //===============================
  7. /*
  8. gi.WriteByte (svc_temp_entity);
  9. gi.WriteByte (TE_DEBUGTRAIL);
  10. gi.WritePosition (pt1);
  11. gi.WritePosition (pt2);
  12. gi.multicast (pt1, MULTICAST_PVS);
  13. self->nextthink = level.time + 10;
  14. */
  15. // plat states, copied from g_func.c
  16. #define STATE_TOP 0
  17. #define STATE_BOTTOM 1
  18. #define STATE_UP 2
  19. #define STATE_DOWN 3
  20. qboolean face_wall (edict_t *self);
  21. void HuntTarget (edict_t *self);
  22. // PMM
  23. qboolean parasite_drain_attack_ok (vec3_t start, vec3_t end);
  24. // blocked_checkshot
  25. // shotchance: 0-1, chance they'll take the shot if it's clear.
  26. qboolean blocked_checkshot (edict_t *self, float shotChance)
  27. {
  28. qboolean playerVisible;
  29. if(!self->enemy)
  30. return false;
  31. // blocked checkshot is only against players. this will
  32. // filter out player sounds and other shit they should
  33. // not be firing at.
  34. if(!(self->enemy->client))
  35. return false;
  36. if (random() < shotChance)
  37. return false;
  38. // PMM - special handling for the parasite
  39. if (!strcmp(self->classname, "monster_parasite"))
  40. {
  41. vec3_t f, r, offset, start, end;
  42. trace_t tr;
  43. AngleVectors (self->s.angles, f, r, NULL);
  44. VectorSet (offset, 24, 0, 6);
  45. G_ProjectSource (self->s.origin, offset, f, r, start);
  46. VectorCopy (self->enemy->s.origin, end);
  47. if (!parasite_drain_attack_ok(start, end))
  48. {
  49. end[2] = self->enemy->s.origin[2] + self->enemy->maxs[2] - 8;
  50. if (!parasite_drain_attack_ok(start, end))
  51. {
  52. end[2] = self->enemy->s.origin[2] + self->enemy->mins[2] + 8;
  53. if (!parasite_drain_attack_ok(start, end))
  54. return false;
  55. }
  56. }
  57. VectorCopy (self->enemy->s.origin, end);
  58. tr = gi.trace (start, NULL, NULL, end, self, MASK_SHOT);
  59. if (tr.ent != self->enemy)
  60. {
  61. self->monsterinfo.aiflags |= AI_BLOCKED;
  62. if(self->monsterinfo.attack)
  63. self->monsterinfo.attack(self);
  64. self->monsterinfo.aiflags &= ~AI_BLOCKED;
  65. return true;
  66. }
  67. }
  68. playerVisible = visible (self, self->enemy);
  69. // always shoot at teslas
  70. if(playerVisible)
  71. {
  72. if (!strcmp(self->enemy->classname, "tesla"))
  73. {
  74. // if(g_showlogic && g_showlogic->value)
  75. // gi.dprintf("blocked: taking a shot\n");
  76. // turn on AI_BLOCKED to let the monster know the attack is being called
  77. // by the blocked functions...
  78. self->monsterinfo.aiflags |= AI_BLOCKED;
  79. if(self->monsterinfo.attack)
  80. self->monsterinfo.attack(self);
  81. self->monsterinfo.aiflags &= ~AI_BLOCKED;
  82. return true;
  83. }
  84. }
  85. return false;
  86. }
  87. // blocked_checkplat
  88. // dist: how far they are trying to walk.
  89. qboolean blocked_checkplat (edict_t *self, float dist)
  90. {
  91. int playerPosition;
  92. trace_t trace;
  93. vec3_t pt1, pt2;
  94. vec3_t forward;
  95. edict_t *plat;
  96. if(!self->enemy)
  97. return false;
  98. // check player's relative altitude
  99. if(self->enemy->absmin[2] >= self->absmax[2])
  100. playerPosition = 1;
  101. else if(self->enemy->absmax[2] <= self->absmin[2])
  102. playerPosition = -1;
  103. else
  104. playerPosition = 0;
  105. // if we're close to the same position, don't bother trying plats.
  106. if(playerPosition == 0)
  107. return false;
  108. plat = NULL;
  109. // see if we're already standing on a plat.
  110. if(self->groundentity && self->groundentity != world)
  111. {
  112. if(!strncmp(self->groundentity->classname, "func_plat", 8))
  113. plat = self->groundentity;
  114. }
  115. // if we're not, check to see if we'll step onto one with this move
  116. if(!plat)
  117. {
  118. AngleVectors (self->s.angles, forward, NULL, NULL);
  119. VectorMA(self->s.origin, dist, forward, pt1);
  120. VectorCopy (pt1, pt2);
  121. pt2[2] -= 384;
  122. trace = gi.trace(pt1, vec3_origin, vec3_origin, pt2, self, MASK_MONSTERSOLID);
  123. if(trace.fraction < 1 && !trace.allsolid && !trace.startsolid)
  124. {
  125. if(!strncmp(trace.ent->classname, "func_plat", 8))
  126. {
  127. plat = trace.ent;
  128. }
  129. }
  130. }
  131. // if we've found a plat, trigger it.
  132. if(plat && plat->use)
  133. {
  134. if (playerPosition == 1)
  135. {
  136. if((self->groundentity == plat && plat->moveinfo.state == STATE_BOTTOM) ||
  137. (self->groundentity != plat && plat->moveinfo.state == STATE_TOP))
  138. {
  139. // if(g_showlogic && g_showlogic->value)
  140. // gi.dprintf("player above, and plat will raise. using!\n");
  141. plat->use (plat, self, self);
  142. return true;
  143. }
  144. }
  145. else if(playerPosition == -1)
  146. {
  147. if((self->groundentity == plat && plat->moveinfo.state == STATE_TOP) ||
  148. (self->groundentity != plat && plat->moveinfo.state == STATE_BOTTOM))
  149. {
  150. // if(g_showlogic && g_showlogic->value)
  151. // gi.dprintf("player below, and plat will lower. using!\n");
  152. plat->use (plat, self, self);
  153. return true;
  154. }
  155. }
  156. // if(g_showlogic && g_showlogic->value)
  157. // gi.dprintf("hit a plat, not using. ppos: %d plat: %d\n", playerPosition, plat->moveinfo.state);
  158. }
  159. return false;
  160. }
  161. // blocked_checkjump
  162. // dist: how far they are trying to walk.
  163. // maxDown/maxUp: how far they'll ok a jump for. set to 0 to disable that direction.
  164. qboolean blocked_checkjump (edict_t *self, float dist, float maxDown, float maxUp)
  165. {
  166. int playerPosition;
  167. trace_t trace;
  168. vec3_t pt1, pt2;
  169. vec3_t forward, up;
  170. if(!self->enemy)
  171. return false;
  172. AngleVectors (self->s.angles, forward, NULL, up);
  173. if(self->enemy->absmin[2] > (self->absmin[2] + 16))
  174. playerPosition = 1;
  175. else if(self->enemy->absmin[2] < (self->absmin[2] - 16))
  176. playerPosition = -1;
  177. else
  178. playerPosition = 0;
  179. if(playerPosition == -1 && maxDown)
  180. {
  181. // check to make sure we can even get to the spot we're going to "fall" from
  182. VectorMA(self->s.origin, 48, forward, pt1);
  183. trace = gi.trace(self->s.origin, self->mins, self->maxs, pt1, self, MASK_MONSTERSOLID);
  184. if(trace.fraction < 1)
  185. {
  186. // gi.dprintf("can't get thar from hear...\n");
  187. return false;
  188. }
  189. VectorCopy (pt1, pt2);
  190. pt2[2] = self->mins[2] - maxDown - 1;
  191. trace = gi.trace(pt1, vec3_origin, vec3_origin, pt2, self, MASK_MONSTERSOLID | MASK_WATER);
  192. if(trace.fraction < 1 && !trace.allsolid && !trace.startsolid)
  193. {
  194. if((self->absmin[2] - trace.endpos[2]) >= 24 && trace.contents & MASK_SOLID)
  195. {
  196. if( (self->enemy->absmin[2] - trace.endpos[2]) > 32)
  197. {
  198. // if(g_showlogic && g_showlogic->value)
  199. // gi.dprintf("That'll take me too far down...%0.1f\n", (self->enemy->absmin[2] - trace.endpos[2]));
  200. return false;
  201. }
  202. if(trace.plane.normal[2] < 0.9)
  203. {
  204. // gi.dprintf("Floor angle too much! %s\n", vtos(trace.plane.normal));
  205. return false;
  206. }
  207. // if(g_showlogic && g_showlogic->value)
  208. // gi.dprintf("Geronimo! %0.1f\n", (self->absmin[2] - trace.endpos[2]));
  209. return true;
  210. }
  211. // else if(g_showlogic && g_showlogic->value)
  212. // {
  213. // if(!(trace.contents & MASK_SOLID))
  214. // gi.dprintf("Ooooh... Bad stuff down there...\n");
  215. // else
  216. // gi.dprintf("Too far to fall\n");
  217. // }
  218. }
  219. // else if(g_showlogic && g_showlogic->value)
  220. // gi.dprintf("Ooooh... Too far to fall...\n");
  221. }
  222. else if(playerPosition == 1 && maxUp)
  223. {
  224. VectorMA(self->s.origin, 48, forward, pt1);
  225. VectorCopy(pt1, pt2);
  226. pt1[2] = self->absmax[2] + maxUp;
  227. trace = gi.trace(pt1, vec3_origin, vec3_origin, pt2, self, MASK_MONSTERSOLID | MASK_WATER);
  228. if(trace.fraction < 1 && !trace.allsolid && !trace.startsolid)
  229. {
  230. if((trace.endpos[2] - self->absmin[2]) <= maxUp && trace.contents & MASK_SOLID)
  231. {
  232. // if(g_showlogic && g_showlogic->value)
  233. // gi.dprintf("Jumping Up! %0.1f\n", (trace.endpos[2] - self->absmin[2]));
  234. face_wall(self);
  235. return true;
  236. }
  237. // else if(g_showlogic && g_showlogic->value)
  238. // gi.dprintf("Too high to jump %0.1f\n", (trace.endpos[2] - self->absmin[2]));
  239. }
  240. // else if(g_showlogic && g_showlogic->value)
  241. // gi.dprintf("Not something I could jump onto\n");
  242. }
  243. // else if(g_showlogic && g_showlogic->value)
  244. // gi.dprintf("Player at similar level. No need to jump up?\n");
  245. return false;
  246. }
  247. // checks to see if another coop player is nearby, and will switch.
  248. qboolean blocked_checknewenemy (edict_t *self)
  249. {
  250. /*
  251. int player;
  252. edict_t *ent;
  253. if (!(coop->value))
  254. return false;
  255. for (player = 1; player <= game.maxclients; player++)
  256. {
  257. ent = &g_edicts[player];
  258. if (!ent->inuse)
  259. continue;
  260. if (!ent->client)
  261. continue;
  262. if (ent == self->enemy)
  263. continue;
  264. if (visible (self, ent))
  265. {
  266. if (g_showlogic && g_showlogic->value)
  267. gi.dprintf ("B_CNE: %s acquired new enemy %s\n", self->classname, ent->client->pers.netname);
  268. self->enemy = ent;
  269. FoundTarget (self);
  270. return true;
  271. }
  272. }
  273. return false;
  274. */
  275. return false;
  276. }
  277. // *************************
  278. // HINT PATHS
  279. // *************************
  280. #define HINT_ENDPOINT 0x0001
  281. #define MAX_HINT_CHAINS 100
  282. int hint_paths_present;
  283. edict_t *hint_path_start[MAX_HINT_CHAINS];
  284. int num_hint_paths;
  285. //
  286. // AI code
  287. //
  288. // =============
  289. // hintpath_findstart - given any hintpath node, finds the start node
  290. // =============
  291. edict_t *hintpath_findstart(edict_t *ent)
  292. {
  293. edict_t *e;
  294. edict_t *last;
  295. int field;
  296. if(ent->target) // starting point
  297. {
  298. last = world;
  299. field = FOFS(targetname);
  300. e = G_Find(NULL, field, ent->target);
  301. while(e)
  302. {
  303. last = e;
  304. if(!e->target)
  305. break;
  306. e = G_Find(NULL, field, e->target);
  307. }
  308. }
  309. else // end point
  310. {
  311. last = world;
  312. field = FOFS(target);
  313. e = G_Find(NULL, field, ent->targetname);
  314. while(e)
  315. {
  316. last = e;
  317. if(!e->targetname)
  318. break;
  319. e = G_Find(NULL, field, e->targetname);
  320. }
  321. }
  322. if(!(last->spawnflags & HINT_ENDPOINT))
  323. {
  324. // gi.dprintf ("end of chain is not HINT_ENDPOINT\n");
  325. return NULL;
  326. }
  327. if(last == world)
  328. last = NULL;
  329. return last;
  330. }
  331. // =============
  332. // hintpath_other_end - given one endpoint of a hintpath, returns the other end.
  333. // =============
  334. edict_t *hintpath_other_end(edict_t *ent)
  335. {
  336. edict_t *e;
  337. edict_t *last;
  338. int field;
  339. if(ent->target) // starting point
  340. {
  341. last = world;
  342. field = FOFS(targetname);
  343. e = G_Find(NULL, field, ent->target);
  344. while(e)
  345. {
  346. last = e;
  347. if(!e->target)
  348. break;
  349. e = G_Find(NULL, field, e->target);
  350. }
  351. }
  352. else // end point
  353. {
  354. last = world;
  355. field = FOFS(target);
  356. e = G_Find(NULL, field, ent->targetname);
  357. while(e)
  358. {
  359. last = e;
  360. if(!e->targetname)
  361. break;
  362. e = G_Find(NULL, field, e->targetname);
  363. }
  364. }
  365. if(!(last->spawnflags & HINT_ENDPOINT))
  366. {
  367. // gi.dprintf ("end of chain is not HINT_ENDPOINT\n");
  368. return NULL;
  369. }
  370. if(last == world)
  371. last = NULL;
  372. return last;
  373. }
  374. // =============
  375. // hintpath_go - starts a monster (self) moving towards the hintpath (point)
  376. // disables all contrary AI flags.
  377. // =============
  378. void hintpath_go (edict_t *self, edict_t *point)
  379. {
  380. vec3_t dir;
  381. vec3_t angles;
  382. VectorSubtract(point->s.origin, self->s.origin, dir);
  383. vectoangles2(dir, angles);
  384. self->ideal_yaw = angles[YAW];
  385. self->goalentity = self->movetarget = point;
  386. self->monsterinfo.pausetime = 0;
  387. self->monsterinfo.aiflags |= AI_HINT_PATH;
  388. self->monsterinfo.aiflags &= ~(AI_SOUND_TARGET | AI_PURSUIT_LAST_SEEN | AI_PURSUE_NEXT | AI_PURSUE_TEMP);
  389. // run for it
  390. self->monsterinfo.search_time = level.time;
  391. self->monsterinfo.run (self);
  392. }
  393. // =============
  394. // hintpath_stop - bails a monster out of following hint paths
  395. // =============
  396. void hintpath_stop (edict_t *self)
  397. {
  398. self->goalentity = NULL;
  399. self->movetarget = NULL;
  400. // self->monsterinfo.last_hint = NULL;
  401. self->monsterinfo.last_hint_time = level.time;
  402. self->monsterinfo.goal_hint = NULL;
  403. self->monsterinfo.aiflags &= ~AI_HINT_PATH;
  404. if (has_valid_enemy(self))
  405. {
  406. // if we can see our target, go nuts
  407. if (visible(self, self->enemy))
  408. {
  409. FoundTarget (self);
  410. return;
  411. }
  412. // otherwise, keep chasing
  413. HuntTarget (self);
  414. return;
  415. }
  416. // if our enemy is no longer valid, forget about our enemy and go into stand
  417. self->enemy = NULL;
  418. // we need the pausetime otherwise the stand code
  419. // will just revert to walking with no target and
  420. // the monsters will wonder around aimlessly trying
  421. // to hunt the world entity
  422. self->monsterinfo.pausetime = level.time + 100000000;
  423. self->monsterinfo.stand (self);
  424. }
  425. // =============
  426. // monsterlost_checkhint - the monster (self) will check around for valid hintpaths.
  427. // a valid hintpath is one where the two endpoints can see both the monster
  428. // and the monster's enemy. if only one person is visible from the endpoints,
  429. // it will not go for it.
  430. // =============
  431. qboolean monsterlost_checkhint2 (edict_t *self);
  432. qboolean monsterlost_checkhint (edict_t *self)
  433. {
  434. edict_t *e, *monster_pathchain, *target_pathchain, *checkpoint;
  435. edict_t *closest;
  436. float closest_range = 1000000;
  437. edict_t *start, *destination;
  438. int field;
  439. int count1=0, count2=0, count3=0, count4=0, count5=0;
  440. float r;
  441. int i;
  442. qboolean hint_path_represented[MAX_HINT_CHAINS];
  443. // if there are no hint paths on this map, exit immediately.
  444. if(!hint_paths_present)
  445. return false;
  446. if(!self->enemy)
  447. return false;
  448. if (self->monsterinfo.aiflags & AI_STAND_GROUND)
  449. return false;
  450. if (!strcmp(self->classname, "monster_turret"))
  451. return false;
  452. monster_pathchain = NULL;
  453. field = FOFS(classname);
  454. // find all the hint_paths.
  455. // FIXME - can we not do this every time?
  456. for (i=0; i < num_hint_paths; i++)
  457. {
  458. e = hint_path_start[i];
  459. while(e)
  460. {
  461. count1++;
  462. if (e->monster_hint_chain)
  463. {
  464. // gi.dprintf ("uh, oh, I didn't clean up after myself\n");
  465. e->monster_hint_chain = NULL;
  466. }
  467. if (monster_pathchain)
  468. {
  469. checkpoint->monster_hint_chain = e;
  470. checkpoint = e;
  471. }
  472. else
  473. {
  474. monster_pathchain = e;
  475. checkpoint = e;
  476. }
  477. e = e->hint_chain;
  478. }
  479. }
  480. // filter them by distance and visibility to the monster
  481. e = monster_pathchain;
  482. checkpoint = NULL;
  483. while (e)
  484. {
  485. r = realrange (self, e);
  486. // if (r > 512)
  487. // count3++;
  488. if (r > 512)
  489. {
  490. count2++;
  491. // if (g_showlogic && g_showlogic->value)
  492. // {
  493. // gi.dprintf ("MONSTER (%s) DISTANCE: ", self->classname);
  494. // if (e->targetname)
  495. // gi.dprintf ("targetname %s\n", e->targetname);
  496. // else
  497. // gi.dprintf ("start -> %s\n", e->target);
  498. // }
  499. if (checkpoint)
  500. {
  501. checkpoint->monster_hint_chain = e->monster_hint_chain;
  502. e->monster_hint_chain = NULL;
  503. e = checkpoint->monster_hint_chain;
  504. continue;
  505. }
  506. else
  507. {
  508. // use checkpoint as temp pointer
  509. checkpoint = e;
  510. e = e->monster_hint_chain;
  511. checkpoint->monster_hint_chain = NULL;
  512. // and clear it again
  513. checkpoint = NULL;
  514. // since we have yet to find a valid one (or else checkpoint would be set) move the
  515. // start of monster_pathchain
  516. monster_pathchain = e;
  517. continue;
  518. }
  519. }
  520. if (!visible(self, e))
  521. {
  522. count4++;
  523. // if (g_showlogic && g_showlogic->value)
  524. // {
  525. // gi.dprintf ("MONSTER (%s) VISIBILITY: ", self->classname);
  526. // if (e->targetname)
  527. // gi.dprintf ("targetname %s\n", e->targetname);
  528. // else
  529. // gi.dprintf ("start -> %s\n", e->target);
  530. // }
  531. if (checkpoint)
  532. {
  533. checkpoint->monster_hint_chain = e->monster_hint_chain;
  534. e->monster_hint_chain = NULL;
  535. e = checkpoint->monster_hint_chain;
  536. continue;
  537. }
  538. else
  539. {
  540. // use checkpoint as temp pointer
  541. checkpoint = e;
  542. e = e->monster_hint_chain;
  543. checkpoint->monster_hint_chain = NULL;
  544. // and clear it again
  545. checkpoint = NULL;
  546. // since we have yet to find a valid one (or else checkpoint would be set) move the
  547. // start of monster_pathchain
  548. monster_pathchain = e;
  549. continue;
  550. }
  551. }
  552. // if it passes all the tests, it's a keeper
  553. // if (g_showlogic && g_showlogic->value)
  554. // {
  555. // gi.dprintf ("MONSTER (%s) ACCEPT: ", self->classname);
  556. // if (e->targetname)
  557. // gi.dprintf ("targetname %s\n", e->targetname);
  558. // else
  559. // gi.dprintf ("start -> %s\n", e->target);
  560. // }
  561. count5++;
  562. checkpoint = e;
  563. e = e->monster_hint_chain;
  564. }
  565. // at this point, we have a list of all of the eligible hint nodes for the monster
  566. // we now take them, figure out what hint chains they're on, and traverse down those chains,
  567. // seeing whether any can see the player
  568. //
  569. // first, we figure out which hint chains we have represented in monster_pathchain
  570. if (count5 == 0)
  571. {
  572. // if ((g_showlogic) && (g_showlogic->value))
  573. // gi.dprintf ("No eligible hint paths found.\n");
  574. return false;
  575. }
  576. for (i=0; i < num_hint_paths; i++)
  577. {
  578. hint_path_represented[i] = false;
  579. }
  580. e = monster_pathchain;
  581. checkpoint = NULL;
  582. while (e)
  583. {
  584. if ((e->hint_chain_id < 0) || (e->hint_chain_id > num_hint_paths))
  585. {
  586. // if (g_showlogic && g_showlogic->value)
  587. // gi.dprintf ("bad hint_chain_id! %d\n", e->hint_chain_id);
  588. return false;
  589. }
  590. hint_path_represented[e->hint_chain_id] = true;
  591. e = e->monster_hint_chain;
  592. }
  593. count1 = 0;
  594. count2 = 0;
  595. count3 = 0;
  596. count4 = 0;
  597. count5 = 0;
  598. // now, build the target_pathchain which contains all of the hint_path nodes we need to check for
  599. // validity (within range, visibility)
  600. target_pathchain = NULL;
  601. checkpoint = NULL;
  602. for (i=0; i < num_hint_paths; i++)
  603. {
  604. // if this hint chain is represented in the monster_hint_chain, add all of it's nodes to the target_pathchain
  605. // for validity checking
  606. if (hint_path_represented[i])
  607. {
  608. e = hint_path_start[i];
  609. while (e)
  610. {
  611. if (target_pathchain)
  612. {
  613. checkpoint->target_hint_chain = e;
  614. checkpoint = e;
  615. }
  616. else
  617. {
  618. target_pathchain = e;
  619. checkpoint = e;
  620. }
  621. e = e->hint_chain;
  622. }
  623. }
  624. }
  625. // target_pathchain is a list of all of the hint_path nodes we need to check for validity relative to the target
  626. e = target_pathchain;
  627. checkpoint = NULL;
  628. while (e)
  629. {
  630. r = realrange (self->enemy, e);
  631. // if (r > 512)
  632. // count3++;
  633. if (r > 512)
  634. {
  635. count2++;
  636. // if (g_showlogic && g_showlogic->value)
  637. // {
  638. // gi.dprintf ("TARGET RANGE: ");
  639. // if (e->targetname)
  640. // gi.dprintf ("targetname %s\n", e->targetname);
  641. // else
  642. // gi.dprintf ("start -> %s\n", e->target);
  643. // }
  644. if (checkpoint)
  645. {
  646. checkpoint->target_hint_chain = e->target_hint_chain;
  647. e->target_hint_chain = NULL;
  648. e = checkpoint->target_hint_chain;
  649. continue;
  650. }
  651. else
  652. {
  653. // use checkpoint as temp pointer
  654. checkpoint = e;
  655. e = e->target_hint_chain;
  656. checkpoint->target_hint_chain = NULL;
  657. // and clear it again
  658. checkpoint = NULL;
  659. target_pathchain = e;
  660. continue;
  661. }
  662. }
  663. if (!visible(self->enemy, e))
  664. {
  665. count4++;
  666. // if (g_showlogic && g_showlogic->value)
  667. // {
  668. // gi.dprintf ("TARGET VISIBILITY: ");
  669. // if (e->targetname)
  670. // gi.dprintf ("targetname %s\n", e->targetname);
  671. // else
  672. // gi.dprintf ("start -> %s\n", e->target);
  673. // }
  674. if (checkpoint)
  675. {
  676. checkpoint->target_hint_chain = e->target_hint_chain;
  677. e->target_hint_chain = NULL;
  678. e = checkpoint->target_hint_chain;
  679. continue;
  680. }
  681. else
  682. {
  683. // use checkpoint as temp pointer
  684. checkpoint = e;
  685. e = e->target_hint_chain;
  686. checkpoint->target_hint_chain = NULL;
  687. // and clear it again
  688. checkpoint = NULL;
  689. target_pathchain = e;
  690. continue;
  691. }
  692. }
  693. // if it passes all the tests, it's a keeper
  694. // if (g_showlogic && g_showlogic->value)
  695. // {
  696. // gi.dprintf ("TARGET ACCEPT: ");
  697. // if (e->targetname)
  698. // gi.dprintf ("targetname %s\n", e->targetname);
  699. // else
  700. // gi.dprintf ("start -> %s\n", e->target);
  701. // }
  702. count5++;
  703. checkpoint = e;
  704. e = e->target_hint_chain;
  705. }
  706. // at this point we should have:
  707. // monster_pathchain - a list of "monster valid" hint_path nodes linked together by monster_hint_chain
  708. // target_pathcain - a list of "target valid" hint_path nodes linked together by target_hint_chain. these
  709. // are filtered such that only nodes which are on the same chain as "monster valid" nodes
  710. //
  711. // Now, we figure out which "monster valid" node we want to use
  712. //
  713. // To do this, we first off make sure we have some target nodes. If we don't, there are no valid hint_path nodes
  714. // for us to take
  715. //
  716. // If we have some, we filter all of our "monster valid" nodes by which ones have "target valid" nodes on them
  717. //
  718. // Once this filter is finished, we select the closest "monster valid" node, and go to it.
  719. if (count5 == 0)
  720. {
  721. // if ((g_showlogic) && (g_showlogic->value))
  722. // gi.dprintf ("No valid target nodes found\n");
  723. return false;
  724. }
  725. // reuse the hint_chain_represented array, this time to see which chains are represented by the target
  726. for (i=0; i < num_hint_paths; i++)
  727. {
  728. hint_path_represented[i] = false;
  729. }
  730. e = target_pathchain;
  731. checkpoint = NULL;
  732. while (e)
  733. {
  734. if ((e->hint_chain_id < 0) || (e->hint_chain_id > num_hint_paths))
  735. {
  736. // gi.dprintf ("bad hint_chain_id! %d\n", e->hint_chain_id);
  737. return false;
  738. }
  739. hint_path_represented[e->hint_chain_id] = true;
  740. e = e->target_hint_chain;
  741. }
  742. // traverse the monster_pathchain - if the hint_node isn't represented in the "target valid" chain list,
  743. // remove it
  744. // if it is on the list, check it for range from the monster. If the range is the closest, keep it
  745. //
  746. closest = NULL;
  747. e = monster_pathchain;
  748. while (e)
  749. {
  750. if (!(hint_path_represented[e->hint_chain_id]))
  751. {
  752. checkpoint = e->monster_hint_chain;
  753. e->monster_hint_chain = NULL;
  754. e = checkpoint;
  755. continue;
  756. }
  757. r = realrange(self, e);
  758. if (r < closest_range)
  759. closest = e;
  760. e = e->monster_hint_chain;
  761. }
  762. if (!closest)
  763. {
  764. // if ((g_showlogic) && (g_showlogic->value))
  765. // gi.dprintf ("Failed to find closest node for monster. Shouldn't happen.\n");
  766. return false;
  767. }
  768. start = closest;
  769. // now we know which one is the closest to the monster .. this is the one the monster will go to
  770. // we need to finally determine what the DESTINATION node is for the monster .. walk down the hint_chain,
  771. // and find the closest one to the player
  772. closest = NULL;
  773. closest_range = 10000000;
  774. e = target_pathchain;
  775. while (e)
  776. {
  777. if (start->hint_chain_id == e->hint_chain_id)
  778. {
  779. r = realrange(self, e);
  780. if (r < closest_range)
  781. closest = e;
  782. }
  783. e = e->target_hint_chain;
  784. }
  785. if (!closest)
  786. {
  787. // if ((g_showlogic) && (g_showlogic->value))
  788. // gi.dprintf ("Failed to find closest node for target. Shouldn't happen.\n");
  789. return false;
  790. }
  791. destination = closest;
  792. self->monsterinfo.goal_hint = destination;
  793. // self->monsterinfo.last_hint = NULL;
  794. hintpath_go(self, start);
  795. // if(g_showlogic && g_showlogic->value)
  796. // {
  797. // gi.dprintf ("found path. proceed to ");
  798. // if (start->targetname)
  799. // gi.dprintf ("%s to get to ", start->targetname);
  800. // else
  801. // gi.dprintf ("start (->%s) to get to ", start->target);
  802. // if (destination->targetname)
  803. // gi.dprintf ("%s.", destination->targetname);
  804. // else
  805. // gi.dprintf ("start (->%s)", destination->target);
  806. // }
  807. // gi.dprintf("found path. proceed to %s to get to %s\n", vtos(start->s.origin), vtos(destination->s.origin));
  808. return true;
  809. }
  810. /*
  811. qboolean monsterlost_checkhint2 (edict_t *self)
  812. {
  813. edict_t *e, *e2, *goPoint;
  814. int field;
  815. int playerVisible, selfVisible;
  816. // if there are no hint paths on this map, exit immediately.
  817. if(!hint_paths_present)
  818. return false;
  819. if(!self->enemy)
  820. return false;
  821. goPoint = NULL;
  822. field = FOFS(classname);
  823. // check all the hint_paths.
  824. e = G_Find(NULL, field, "hint_path");
  825. while(e)
  826. {
  827. // if it's an endpoint, check for "validity"
  828. if(e->spawnflags & HINT_ENDPOINT)
  829. {
  830. // check visibility from this spot
  831. selfVisible = visible(e, self);
  832. playerVisible = visible(e, self->enemy);
  833. // gi.dprintf("checking endpoint at %s %d %d\n", vtos(e->s.origin),selfVisible,playerVisible);
  834. // at least one of us is visible from this endpoint.
  835. // now check the other one if needed.
  836. if(selfVisible || playerVisible)
  837. {
  838. // if endpoint 1 saw me, set my destination to it.
  839. if(selfVisible)
  840. goPoint = e;
  841. // if both aren't visible, try the other endpoint
  842. if(!selfVisible || !playerVisible)
  843. {
  844. e2 = hintpath_other_end(e);
  845. if(!e2) // could not connect to the other endpoint
  846. {
  847. gi.dprintf("Unlinked hint paths!\n");
  848. return false;
  849. }
  850. // if endpoint 1 saw the enemy, see if endpoint 2 sees me
  851. if(!selfVisible)
  852. selfVisible = visible(e2, self);
  853. // if endpoint 1 saw me, see if endpoint 2 sees the enemy
  854. else if(!playerVisible)
  855. playerVisible = visible(e2, self->enemy);
  856. // if endpoint 2 saw me, set my destination to it.
  857. if(!goPoint && selfVisible)
  858. goPoint = e2;
  859. // gi.dprintf("checking other endpoint at %s %d %d\n", vtos(e2->s.origin),selfVisible,playerVisible);
  860. }
  861. // if both are visible from at least one endpoint,
  862. // go for it.
  863. if(selfVisible && playerVisible)
  864. {
  865. // set me to go to goPoint
  866. if(g_showlogic && g_showlogic->value)
  867. gi.dprintf("found path. proceed to %s\n", vtos(goPoint->s.origin));
  868. // since this is a new hint path trip, set last_hint to NULL
  869. self->monsterinfo.last_hint = NULL;
  870. hintpath_go(self, goPoint);
  871. return true;
  872. }
  873. }
  874. }
  875. e = G_Find(e, field, "hint_path");
  876. }
  877. // if we got here, we didn't find a valid path
  878. if(g_showlogic && g_showlogic->value)
  879. gi.dprintf("blocked_checkhint: found no paths\n");
  880. return false;
  881. }
  882. */
  883. //
  884. // Path code
  885. //
  886. // =============
  887. // hint_path_touch - someone's touched the hint_path
  888. // =============
  889. void hint_path_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
  890. {
  891. edict_t *e, *goal, *next;
  892. // int chain; // direction - (-1) = upstream, (1) = downstream, (0) = done
  893. qboolean goalFound = false;
  894. // make sure we're the target of it's obsession
  895. if(other->movetarget == self)
  896. {
  897. goal = other->monsterinfo.goal_hint;
  898. // if the monster is where he wants to be
  899. if (goal == self)
  900. {
  901. // if(g_showlogic && g_showlogic->value)
  902. // gi.dprintf("Got to goal, detatching\n");
  903. hintpath_stop (other);
  904. return;
  905. }
  906. else
  907. {
  908. // if we aren't, figure out which way we want to go
  909. e = hint_path_start[self->hint_chain_id];
  910. while (e)
  911. {
  912. // if we get up to ourselves on the hint chain, we're going down it
  913. if (e == self)
  914. {
  915. next = e->hint_chain;
  916. break;
  917. }
  918. if (e == goal)
  919. goalFound = true;
  920. // if we get to where the next link on the chain is this hint_path and have found the goal on the way
  921. // we're going upstream, so remember who the previous link is
  922. if ((e->hint_chain == self) && goalFound)
  923. {
  924. next = e;
  925. break;
  926. }
  927. e = e->hint_chain;
  928. }
  929. }
  930. // if we couldn't find it, have the monster go back to normal hunting.
  931. if(!next)
  932. {
  933. // if(g_showlogic && g_showlogic->value)
  934. // gi.dprintf("couldn't figure out next node, dropping hint path\n");
  935. hintpath_stop(other);
  936. return;
  937. }
  938. // set the last_hint entry to this hint_path, and
  939. // send him on his way
  940. // other->monsterinfo.last_hint = self;
  941. // if(g_showlogic && g_showlogic->value)
  942. // {
  943. // gi.dprintf("moving to next point, ");
  944. // if (next->targetname)
  945. // gi.dprintf ("targetname %s\n", next->targetname);
  946. // else
  947. // gi.dprintf ("start -> %s\n", next->target);
  948. // }
  949. hintpath_go(other, next);
  950. // have the monster freeze if the hint path we just touched has a wait time
  951. // on it, for example, when riding a plat.
  952. if(self->wait)
  953. {
  954. // if(g_showlogic && g_showlogic->value)
  955. // gi.dprintf("monster waiting %0.1f\n", self->wait);
  956. other->nextthink = level.time + self->wait;
  957. }
  958. }
  959. }
  960. /*
  961. void hint_path_touch2 (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
  962. {
  963. edict_t *next, *last;
  964. int chain;
  965. // make sure we're the target of it's obsession
  966. if(other->movetarget == self)
  967. {
  968. chain = 0; // direction the monster is going in the chain
  969. next = NULL; // next hint_path
  970. // gi.dprintf("hint_path %s\n", vtos(self->s.origin));
  971. // is this the first hintpath targeted? if so, we can do this easily.
  972. if(other->monsterinfo.last_hint == NULL)
  973. {
  974. if(self->target) // forward chaining
  975. chain = 1;
  976. else // backward chaining
  977. chain = -1;
  978. }
  979. else
  980. {
  981. // shortcut to last_hint
  982. last = other->monsterinfo.last_hint;
  983. // make sure it's valid...
  984. if ( (last < g_edicts) || (last >= &g_edicts[globals.num_edicts]))
  985. {
  986. if(g_showlogic && g_showlogic->value)
  987. {
  988. gi.dprintf("bogus last_hint encountered.\n");
  989. gi.dprintf("detaching from hint path %d\n", chain);
  990. }
  991. hintpath_stop (other);
  992. return;
  993. }
  994. // if we're an endpoint, then the monster is done moving.
  995. if(self->spawnflags & HINT_ENDPOINT)
  996. {
  997. chain = 0;
  998. }
  999. // if last hint's target is our targetname, it's forward chaining.
  1000. else if(last->target && self->targetname && !strcmp(last->target, self->targetname))
  1001. {
  1002. chain = 1;
  1003. }
  1004. // if last hint's targetname is our target, it's backward chaining.
  1005. // FIXME - last->targetname was 1, not NULL ???? was a screwed up hintpath
  1006. else if(self->target && last->targetname && !strcmp(last->targetname, self->target))
  1007. {
  1008. chain = -1;
  1009. }
  1010. else // if it gets here, i'm not sure how
  1011. {
  1012. gi.dprintf("hit an uncovered possibility in hint_path_touch\n");
  1013. chain = 0;
  1014. }
  1015. }
  1016. // find the "next" hint_path
  1017. if(chain == 1 && self->target) // forward chaining
  1018. next = G_Find(NULL, FOFS(targetname), self->target);
  1019. else if(chain == -1 && self->targetname) // backward chaining
  1020. next = G_Find(NULL, FOFS(target), self->targetname);
  1021. // if we couldn't find it, have the monster go back to normal hunting.
  1022. if(!next)
  1023. {
  1024. if(g_showlogic && g_showlogic->value)
  1025. gi.dprintf("detaching from hint path %d\n", chain);
  1026. hintpath_stop(other);
  1027. return;
  1028. }
  1029. // set the last_hint entry to this hint_path, and
  1030. // send him on his way
  1031. other->monsterinfo.last_hint = self;
  1032. if(g_showlogic && g_showlogic->value)
  1033. gi.dprintf("moving to next point, %s\n", vtos(next->s.origin));
  1034. hintpath_go(other, next);
  1035. // have the monster freeze if the hint path we just touched has a wait time
  1036. // on it, for example, when riding a plat.
  1037. if(self->wait)
  1038. {
  1039. if(g_showlogic && g_showlogic->value)
  1040. gi.dprintf("monster waiting %0.1f\n", self->wait);
  1041. other->nextthink = level.time + self->wait;
  1042. }
  1043. }
  1044. }
  1045. */
  1046. /*QUAKED hint_path (.5 .3 0) (-8 -8 -8) (8 8 8) END
  1047. Target: next hint path
  1048. END - set this flag on the endpoints of each hintpath.
  1049. "wait" - set this if you want the monster to freeze when they touch this hintpath
  1050. */
  1051. void SP_hint_path (edict_t *self)
  1052. {
  1053. if (deathmatch->value)
  1054. {
  1055. G_FreeEdict(self);
  1056. return;
  1057. }
  1058. if (!self->targetname && !self->target)
  1059. {
  1060. gi.dprintf ("unlinked hint_path at %s\n", vtos(self->s.origin));
  1061. G_FreeEdict (self);
  1062. return;
  1063. }
  1064. self->solid = SOLID_TRIGGER;
  1065. self->touch = hint_path_touch;
  1066. VectorSet (self->mins, -8, -8, -8);
  1067. VectorSet (self->maxs, 8, 8, 8);
  1068. self->svflags |= SVF_NOCLIENT;
  1069. gi.linkentity (self);
  1070. }
  1071. //int hint_paths_present;
  1072. //edict_t *hint_path_start[100];
  1073. //int num_hint_paths;
  1074. // ============
  1075. // InitHintPaths - Called by InitGame (g_save) to enable quick exits if valid
  1076. // ============
  1077. void InitHintPaths (void)
  1078. {
  1079. edict_t *e, *current;
  1080. int field, i, count2;
  1081. qboolean errors = false;
  1082. hint_paths_present = 0;
  1083. // check all the hint_paths.
  1084. field = FOFS(classname);
  1085. e = G_Find(NULL, field, "hint_path");
  1086. if(e)
  1087. {
  1088. // gi.dprintf("hint paths present on map\n");
  1089. hint_paths_present = 1;
  1090. }
  1091. else
  1092. {
  1093. // if ((g_showlogic) && (g_showlogic->value))
  1094. // gi.dprintf ("hint paths not present on map\n");
  1095. return;
  1096. }
  1097. memset (hint_path_start, 0, MAX_HINT_CHAINS*sizeof (edict_t *));
  1098. num_hint_paths = 0;
  1099. while(e)
  1100. {
  1101. if(e->spawnflags & HINT_ENDPOINT)
  1102. {
  1103. if (e->target) // start point
  1104. {
  1105. if (e->targetname) // this is a bad end, ignore it
  1106. {
  1107. gi.dprintf ("Hint path at %s marked as endpoint with both target (%s) and targetname (%s)\n",
  1108. vtos (e->s.origin), e->target, e->targetname);
  1109. errors = true;
  1110. }
  1111. else
  1112. {
  1113. if (num_hint_paths >= MAX_HINT_CHAINS)
  1114. {
  1115. // gi.dprintf ("Only %d hint chains allowed. Connect some together!\n", MAX_HINT_CHAINS);
  1116. break;
  1117. }
  1118. hint_path_start[num_hint_paths++] = e;
  1119. }
  1120. }
  1121. }
  1122. e = G_Find(e, field, "hint_path");
  1123. }
  1124. field = FOFS(targetname);
  1125. for (i=0; i< num_hint_paths; i++)
  1126. {
  1127. count2 = 1;
  1128. current = hint_path_start[i];
  1129. current->hint_chain_id = i;
  1130. // gi.dprintf ("start ");
  1131. e = G_Find(NULL, field, current->target);
  1132. if (G_Find(e, field, current->target))
  1133. {
  1134. gi.dprintf ("\nForked hint path at %s detected for chain %d, target %s\n",
  1135. vtos (current->s.origin), num_hint_paths, current->target);
  1136. hint_path_start[i]->hint_chain = NULL;
  1137. count2 = 0;
  1138. errors = true;
  1139. continue;
  1140. }
  1141. while (e)
  1142. {
  1143. if (e->hint_chain)
  1144. {
  1145. gi.dprintf ("\nCircular hint path at %s detected for chain %d, targetname %s\n",
  1146. vtos (e->s.origin), num_hint_paths, e->targetname);
  1147. hint_path_start[i]->hint_chain = NULL;
  1148. count2 = 0;
  1149. errors = true;
  1150. break;
  1151. }
  1152. count2++;
  1153. current->hint_chain = e;
  1154. current = e;
  1155. current->hint_chain_id = i;
  1156. // gi.dprintf ("-> %s ", current->targetname);
  1157. if (!current->target)
  1158. break;
  1159. e = G_Find(NULL, field, current->target);
  1160. if (G_Find(e, field, current->target))
  1161. {
  1162. gi.dprintf ("\nForked hint path at %s detected for chain %d, target %s\n",
  1163. vtos (current->s.origin), num_hint_paths, current->target);
  1164. hint_path_start[i]->hint_chain = NULL;
  1165. count2 = 0;
  1166. break;
  1167. }
  1168. }
  1169. // if ((g_showlogic) && (g_showlogic->value))
  1170. // if (count2)
  1171. // {
  1172. // goodcount++;
  1173. // gi.dprintf ("\nhint_path #%d, %d elements\n\n", i, count2);
  1174. // }
  1175. // else
  1176. // gi.dprintf ("\nhint_path #%d invalid\n\n", i);
  1177. }
  1178. // if (errors)
  1179. // gi.error ("hint_path processing failed, fix errors\n");
  1180. // if ((g_showlogic) && (g_showlogic->value))
  1181. // gi.dprintf ("hint_path processing done, %d hint paths linked\n", num_hint_paths);
  1182. }
  1183. // *****************************
  1184. // MISCELLANEOUS STUFF
  1185. // *****************************
  1186. // PMM - inback
  1187. // use to see if opponent is behind you (not to side)
  1188. // if it looks a lot like infront, well, there's a reason
  1189. qboolean inback (edict_t *self, edict_t *other)
  1190. {
  1191. vec3_t vec;
  1192. float dot;
  1193. vec3_t forward;
  1194. AngleVectors (self->s.angles, forward, NULL, NULL);
  1195. VectorSubtract (other->s.origin, self->s.origin, vec);
  1196. VectorNormalize (vec);
  1197. dot = DotProduct (vec, forward);
  1198. if (dot < -0.3)
  1199. return true;
  1200. return false;
  1201. }
  1202. float realrange (edict_t *self, edict_t *other)
  1203. {
  1204. vec3_t dir;
  1205. VectorSubtract (self->s.origin, other->s.origin, dir);
  1206. return VectorLength(dir);
  1207. }
  1208. qboolean face_wall (edict_t *self)
  1209. {
  1210. vec3_t pt;
  1211. vec3_t forward;
  1212. vec3_t ang;
  1213. trace_t tr;
  1214. AngleVectors (self->s.angles, forward, NULL, NULL);
  1215. VectorMA(self->s.origin, 64, forward, pt);
  1216. tr = gi.trace(self->s.origin, vec3_origin, vec3_origin, pt, self, MASK_MONSTERSOLID);
  1217. if(tr.fraction < 1 && !tr.allsolid && !tr.startsolid)
  1218. {
  1219. vectoangles2(tr.plane.normal, ang);
  1220. self->ideal_yaw = ang[YAW] + 180;
  1221. if(self->ideal_yaw > 360)
  1222. self->ideal_yaw -= 360;
  1223. // if(g_showlogic && g_showlogic->value)
  1224. // gi.dprintf("facing wall, dir %0.1f/%0.1f\n", ang[YAW], self->ideal_yaw);
  1225. M_ChangeYaw(self);
  1226. return true;
  1227. }
  1228. return false;
  1229. }
  1230. //
  1231. // Monster "Bad" Areas
  1232. //
  1233. void badarea_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
  1234. {
  1235. // drawbbox(ent);
  1236. }
  1237. edict_t *SpawnBadArea(vec3_t mins, vec3_t maxs, float lifespan, edict_t *owner)
  1238. {
  1239. edict_t *badarea;
  1240. vec3_t origin;
  1241. VectorAdd(mins, maxs, origin);
  1242. VectorScale(origin, 0.5, origin);
  1243. VectorSubtract(maxs, origin, maxs);
  1244. VectorSubtract(mins, origin, mins);
  1245. badarea = G_Spawn();
  1246. VectorCopy(origin, badarea->s.origin);
  1247. VectorCopy(maxs, badarea->maxs);
  1248. VectorCopy(mins, badarea->mins);
  1249. badarea->touch = badarea_touch;
  1250. badarea->movetype = MOVETYPE_NONE;
  1251. badarea->solid = SOLID_TRIGGER;
  1252. badarea->classname = "bad_area";
  1253. gi.linkentity (badarea);
  1254. // gi.dprintf("(%s)-(%s)\n", vtos(badarea->absmin), vtos(badarea->absmax));
  1255. if(lifespan)
  1256. {
  1257. badarea->think = G_FreeEdict;
  1258. badarea->nextthink = level.time + lifespan;
  1259. }
  1260. if(owner)
  1261. {
  1262. badarea->owner = owner;
  1263. }
  1264. // drawbbox(badarea);
  1265. return badarea;
  1266. }
  1267. // CheckForBadArea
  1268. // This is a customized version of G_TouchTriggers that will check
  1269. // for bad area triggers and return them if they're touched.
  1270. edict_t *CheckForBadArea(edict_t *ent)
  1271. {
  1272. int i, num;
  1273. edict_t *touch[MAX_EDICTS], *hit;
  1274. vec3_t mins, maxs;
  1275. VectorAdd(ent->s.origin, ent->mins, mins);
  1276. VectorAdd(ent->s.origin, ent->maxs, maxs);
  1277. num = gi.BoxEdicts (mins, maxs, touch, MAX_EDICTS, AREA_TRIGGERS);
  1278. // drawbbox(ent);
  1279. // be careful, it is possible to have an entity in this
  1280. // list removed before we get to it (killtriggered)
  1281. for (i=0 ; i<num ; i++)
  1282. {
  1283. hit = touch[i];
  1284. if (!hit->inuse)
  1285. continue;
  1286. if (hit->touch == badarea_touch)
  1287. {
  1288. return hit;
  1289. }
  1290. }
  1291. return NULL;
  1292. }
  1293. #define TESLA_DAMAGE_RADIUS 128
  1294. qboolean MarkTeslaArea(edict_t *self, edict_t *tesla)
  1295. {
  1296. vec3_t mins, maxs;
  1297. edict_t *e;
  1298. edict_t *tail;
  1299. edict_t *area;
  1300. if(!tesla || !self)
  1301. return false;
  1302. area = NULL;
  1303. // make sure this tesla doesn't have a bad area around it already...
  1304. e = tesla->teamchain;
  1305. tail = tesla;
  1306. while (e)
  1307. {
  1308. tail = tail->teamchain;
  1309. if(!strcmp(e->classname, "bad_area"))
  1310. {
  1311. // gi.dprintf("tesla already has a bad area marked\n");
  1312. return false;
  1313. }
  1314. e = e->teamchain;
  1315. }
  1316. // see if we can grab the trigger directly
  1317. if(tesla->teamchain && tesla->teamchain->inuse)
  1318. {
  1319. edict_t *trigger;
  1320. trigger = tesla->teamchain;
  1321. // VectorAdd (trigger->s.origin, trigger->mins, mins);
  1322. // VectorAdd (trigger->s.origin, trigger->maxs, maxs);
  1323. VectorCopy(trigger->absmin, mins);
  1324. VectorCopy(trigger->absmax, maxs);
  1325. if(tesla->air_finished)
  1326. area = SpawnBadArea (mins, maxs, tesla->air_finished, tesla);
  1327. else
  1328. area = SpawnBadArea (mins, maxs, tesla->nextthink, tesla);
  1329. }
  1330. // otherwise we just guess at how long it'll last.
  1331. else
  1332. {
  1333. VectorSet (mins, -TESLA_DAMAGE_RADIUS, -TESLA_DAMAGE_RADIUS, tesla->mins[2]);
  1334. VectorSet (maxs, TESLA_DAMAGE_RADIUS, TESLA_DAMAGE_RADIUS, TESLA_DAMAGE_RADIUS);
  1335. area = SpawnBadArea(mins, maxs, 30, tesla);
  1336. }
  1337. // if we spawned a bad area, then link it to the tesla
  1338. if(area)
  1339. {
  1340. // gi.dprintf("bad area marker spawned and linked to tesla\n");
  1341. tail->teamchain = area;
  1342. }
  1343. return true;
  1344. }
  1345. // predictive calculator
  1346. // target is who you want to shoot
  1347. // start is where the shot comes from
  1348. // bolt_speed is how fast the shot is
  1349. // eye_height is a boolean to say whether or not to adjust to targets eye_height
  1350. // offset is how much time to miss by
  1351. // aimdir is the resulting aim direction (pass in NULL if you don't want it)
  1352. // aimpoint is the resulting aimpoint (pass in NULL if don't want it)
  1353. void PredictAim (edict_t *target, vec3_t start, float bolt_speed, qboolean eye_height, float offset, vec3_t aimdir, vec3_t aimpoint)
  1354. {
  1355. vec3_t dir, vec;
  1356. float dist, time;
  1357. if (!target || !target->inuse)
  1358. {
  1359. VectorCopy (vec3_origin, aimdir);
  1360. return;
  1361. }
  1362. VectorSubtract(target->s.origin, start, dir);
  1363. if (eye_height)
  1364. dir[2] += target->viewheight;
  1365. dist = VectorLength(dir);
  1366. time = dist / bolt_speed;
  1367. VectorMA(target->s.origin, time - offset, target->velocity, vec);
  1368. if (eye_height)
  1369. vec[2] += target->viewheight;
  1370. if (aimdir)
  1371. {
  1372. VectorSubtract (vec, start, aimdir);
  1373. VectorNormalize (aimdir);
  1374. }
  1375. if (aimpoint)
  1376. {
  1377. VectorCopy (vec, aimpoint);
  1378. }
  1379. }
  1380. qboolean below (edict_t *self, edict_t *other)
  1381. {
  1382. vec3_t vec;
  1383. float dot;
  1384. vec3_t down;
  1385. VectorSubtract (other->s.origin, self->s.origin, vec);
  1386. VectorNormalize (vec);
  1387. VectorSet (down, 0, 0, -1);
  1388. dot = DotProduct (vec, down);
  1389. if (dot > 0.95) // 18 degree arc below
  1390. return true;
  1391. return false;
  1392. }
  1393. void drawbbox (edict_t *self)
  1394. {
  1395. int lines[4][3] = {
  1396. {1, 2, 4},
  1397. {1, 2, 7},
  1398. {1, 4, 5},
  1399. {2, 4, 7}
  1400. };
  1401. int starts[4] = {0, 3, 5, 6};
  1402. vec3_t pt[8];
  1403. int i, j, k;
  1404. vec3_t coords[2];
  1405. vec3_t newbox;
  1406. vec3_t f,r,u, dir;
  1407. VectorCopy (self->absmin, coords[0]);
  1408. VectorCopy (self->absmax, coords[1]);
  1409. for (i=0; i<=1; i++)
  1410. {
  1411. for (j=0; j<=1; j++)
  1412. {
  1413. for (k=0; k<=1; k++)
  1414. {
  1415. pt[4*i+2*j+k][0] = coords[i][0];
  1416. pt[4*i+2*j+k][1] = coords[j][1];
  1417. pt[4*i+2*j+k][2] = coords[k][2];
  1418. }
  1419. }
  1420. }
  1421. for (i=0; i<= 3; i++)
  1422. {
  1423. for (j=0; j<= 2; j++)
  1424. {
  1425. gi.WriteByte (svc_temp_entity);
  1426. gi.WriteByte (TE_DEBUGTRAIL);
  1427. gi.WritePosition (pt[starts[i]]);
  1428. gi.WritePosition (pt[lines[i][j]]);
  1429. gi.multicast (pt[starts[i]], MULTICAST_ALL);
  1430. }
  1431. }
  1432. vectoangles2 (self->s.angles, dir);
  1433. AngleVectors (dir, f, r, u);
  1434. VectorMA (self->s.origin, 50, f, newbox);
  1435. gi.WriteByte (svc_temp_entity);
  1436. gi.WriteByte (TE_DEBUGTRAIL);
  1437. gi.WritePosition (self->s.origin);
  1438. gi.WritePosition (newbox);
  1439. gi.multicast (self->s.origin, MULTICAST_PVS);
  1440. VectorClear (newbox);
  1441. VectorMA (self->s.origin, 50, r, newbox);
  1442. gi.WriteByte (svc_temp_entity);
  1443. gi.WriteByte (TE_DEBUGTRAIL);
  1444. gi.WritePosition (self->s.origin);
  1445. gi.WritePosition (newbox);
  1446. gi.multicast (self->s.origin, MULTICAST_PVS);
  1447. VectorClear (newbox);
  1448. VectorMA (self->s.origin, 50, u, newbox);
  1449. gi.WriteByte (svc_temp_entity);
  1450. gi.WriteByte (TE_DEBUGTRAIL);
  1451. gi.WritePosition (self->s.origin);
  1452. gi.WritePosition (newbox);
  1453. gi.multicast (self->s.origin, MULTICAST_PVS);
  1454. VectorClear (newbox);
  1455. }
  1456. //
  1457. // New dodge code
  1458. //
  1459. void M_MonsterDodge (edict_t *self, edict_t *attacker, float eta, trace_t *tr)
  1460. {
  1461. float r = random();
  1462. float height;
  1463. qboolean ducker = false, dodger = false;
  1464. // this needs to be here since this can be called after the monster has "died"
  1465. if (self->health < 1)
  1466. return;
  1467. if ((self->monsterinfo.duck) && (self->monsterinfo.unduck))
  1468. ducker = true;
  1469. if ((self->monsterinfo.sidestep) && !(self->monsterinfo.aiflags & AI_STAND_GROUND))
  1470. dodger = true;
  1471. if ((!ducker) && (!dodger))
  1472. return;
  1473. // if ((g_showlogic) && (g_showlogic->value))
  1474. // {
  1475. // if (self->monsterinfo.aiflags & AI_DODGING)
  1476. // gi.dprintf ("dodging - ");
  1477. // if (self->monsterinfo.aiflags & AI_DUCKED)
  1478. // gi.dprintf ("ducked - ");
  1479. // }
  1480. if (!self->enemy)
  1481. {
  1482. self->enemy = attacker;
  1483. FoundTarget (self);
  1484. }
  1485. // PMM - don't bother if it's going to hit anyway; fix for weird in-your-face etas (I was
  1486. // seeing numbers like 13 and 14)
  1487. if ((eta < 0.1) || (eta > 5))
  1488. {
  1489. // if ((g_showlogic) && (g_showlogic->value))
  1490. // gi.dprintf ("timeout\n");
  1491. return;
  1492. }
  1493. // skill level determination..
  1494. if (r > (0.25*((skill->value)+1)))
  1495. {
  1496. // if ((g_showlogic) && (g_showlogic->value))
  1497. // gi.dprintf ("skillout\n");
  1498. return;
  1499. }
  1500. // stop charging, since we're going to dodge (somehow) instead
  1501. // soldier_stop_charge (self);
  1502. if (ducker)
  1503. {
  1504. height = self->absmax[2]-32-1; // the -1 is because the absmax is s.origin + maxs + 1
  1505. // FIXME, make smarter
  1506. // if we only duck, and ducking won't help or we're already ducking, do nothing
  1507. //
  1508. // need to add monsterinfo.abort_duck() and monsterinfo.next_duck_time
  1509. if ((!dodger) && ((tr->endpos[2] <= height) || (self->monsterinfo.aiflags & AI_DUCKED)))
  1510. return;
  1511. }
  1512. else
  1513. height = self->absmax[2];
  1514. if (dodger)
  1515. {
  1516. // if we're already dodging, just finish the sequence, i.e. don't do anything else
  1517. if (self->monsterinfo.aiflags & AI_DODGING)
  1518. {
  1519. // if ((g_showlogic) && (g_showlogic->value))
  1520. // gi.dprintf ("already dodging\n");
  1521. return;
  1522. }
  1523. // if we're ducking already, or the shot is at our knees
  1524. if ((tr->endpos[2] <= height) || (self->monsterinfo.aiflags & AI_DUCKED))
  1525. {
  1526. vec3_t right, diff;
  1527. AngleVectors (self->s.angles, NULL, right, NULL);
  1528. VectorSubtract (tr->endpos, self->s.origin, diff);
  1529. if (DotProduct (right, diff) < 0)
  1530. {
  1531. self->monsterinfo.lefty = 0;
  1532. // gi.dprintf ("left\n");
  1533. } else {
  1534. self->monsterinfo.lefty = 1;
  1535. // gi.dprintf ("right\n");
  1536. }
  1537. // if we are currently ducked, unduck
  1538. if ((ducker) && (self->monsterinfo.aiflags & AI_DUCKED))
  1539. {
  1540. // if ((g_showlogic) && (g_showlogic->value))
  1541. // gi.dprintf ("unducking - ");
  1542. self->monsterinfo.unduck(self);
  1543. }
  1544. self->monsterinfo.aiflags |= AI_DODGING;
  1545. self->monsterinfo.attack_state = AS_SLIDING;
  1546. // call the monster specific code here
  1547. self->monsterinfo.sidestep (self);
  1548. return;
  1549. }
  1550. }
  1551. if (ducker)
  1552. {
  1553. if (self->monsterinfo.next_duck_time > level.time)
  1554. {
  1555. // if ((g_showlogic) && (g_showlogic->value))
  1556. // gi.dprintf ("ducked too often, not ducking\n");
  1557. return;
  1558. }
  1559. // if ((g_showlogic) && (g_showlogic->value))
  1560. // gi.dprintf ("ducking!\n");
  1561. monster_done_dodge (self);
  1562. // set this prematurely; it doesn't hurt, and prevents extra iterations
  1563. self->monsterinfo.aiflags |= AI_DUCKED;
  1564. self->monsterinfo.duck (self, eta);
  1565. }
  1566. }
  1567. void monster_duck_down (edict_t *self)
  1568. {
  1569. // if (self->monsterinfo.aiflags & AI_DUCKED)
  1570. // return;
  1571. self->monsterinfo.aiflags |= AI_DUCKED;
  1572. // if ((g_showlogic) && (g_showlogic->value))
  1573. // gi.dprintf ("duck down!\n");
  1574. // self->maxs[2] -= 32;
  1575. self->maxs[2] = self->monsterinfo.base_height - 32;
  1576. self->takedamage = DAMAGE_YES;
  1577. if (self->monsterinfo.duck_wait_time < level.time)
  1578. self->monsterinfo.duck_wait_time = level.time + 1;
  1579. gi.linkentity (self);
  1580. }
  1581. void monster_duck_hold (edict_t *self)
  1582. {
  1583. if (level.time >= self->monsterinfo.duck_wait_time)
  1584. self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
  1585. else
  1586. self->monsterinfo.aiflags |= AI_HOLD_FRAME;
  1587. }
  1588. void monster_duck_up (edict_t *self)
  1589. {
  1590. self->monsterinfo.aiflags &= ~AI_DUCKED;
  1591. // self->maxs[2] += 32;
  1592. self->maxs[2] = self->monsterinfo.base_height;
  1593. self->takedamage = DAMAGE_AIM;
  1594. self->monsterinfo.next_duck_time = level.time + DUCK_INTERVAL;
  1595. gi.linkentity (self);
  1596. }
  1597. //=========================
  1598. //=========================
  1599. qboolean has_valid_enemy (edict_t *self)
  1600. {
  1601. if (!self->enemy)
  1602. return false;
  1603. if (!self->enemy->inuse)
  1604. return false;
  1605. if (self->enemy->health < 1)
  1606. return false;
  1607. return true;
  1608. }
  1609. void TargetTesla (edict_t *self, edict_t *tesla)
  1610. {
  1611. if ((!self) || (!tesla))
  1612. return;
  1613. // PMM - medic bails on healing things
  1614. if (self->monsterinfo.aiflags & AI_MEDIC)
  1615. {
  1616. if (self->enemy)
  1617. cleanupHealTarget(self->enemy);
  1618. self->monsterinfo.aiflags &= ~AI_MEDIC;
  1619. }
  1620. // store the player enemy in case we lose track of him.
  1621. if(self->enemy && self->enemy->client)
  1622. self->monsterinfo.last_player_enemy = self->enemy;
  1623. if(self->enemy != tesla)
  1624. {
  1625. self->oldenemy = self->enemy;
  1626. self->enemy = tesla;
  1627. if(self->monsterinfo.attack)
  1628. {
  1629. if (self->health <= 0)
  1630. {
  1631. // if ((g_showlogic) && (g_showlogic->value))
  1632. // gi.dprintf ("bad tesla attack avoided!\n");
  1633. return;
  1634. }
  1635. self->monsterinfo.attack(self);
  1636. }
  1637. else
  1638. {
  1639. FoundTarget(self);
  1640. }
  1641. }
  1642. }
  1643. // this returns a randomly selected coop player who is visible to self
  1644. // returns NULL if bad
  1645. edict_t * PickCoopTarget (edict_t *self)
  1646. {
  1647. // no more than 4 players in coop, so..
  1648. edict_t *targets[4];
  1649. int num_targets = 0, targetID;
  1650. edict_t *ent;
  1651. int player;
  1652. // if we're not in coop, this is a noop
  1653. if (!coop || !coop->value)
  1654. return NULL;
  1655. memset (targets, 0, 4*sizeof(edict_t *));
  1656. for (player = 1; player <= game.maxclients; player++)
  1657. {
  1658. ent = &g_edicts[player];
  1659. if (!ent->inuse)
  1660. continue;
  1661. if (!ent->client)
  1662. continue;
  1663. if (visible(self, ent))
  1664. {
  1665. // if ((g_showlogic) && (g_showlogic->value))
  1666. // gi.dprintf ("%s: found coop player %s - ", self->classname, ent->client->pers.netname);
  1667. targets[num_targets++] = ent;
  1668. }
  1669. }
  1670. /*
  1671. ent = g_edicts+1; // skip the worldspawn
  1672. // cycle through players
  1673. while (ent)
  1674. {
  1675. if ((ent->client) && (ent->inuse))
  1676. {
  1677. if (visible(self, ent))
  1678. {
  1679. if ((g_showlogic) && (g_showlogic->value))
  1680. gi.dprintf ("%s: found coop player %s - ", self->classname, ent->client->pers.netname);
  1681. targets[num_targets++] = ent;
  1682. }
  1683. ent++;
  1684. }
  1685. else
  1686. ent = NULL;
  1687. }
  1688. */
  1689. if (!num_targets)
  1690. return NULL;
  1691. // get a number from 0 to (num_targets-1)
  1692. targetID = (random() * (float)num_targets);
  1693. // just in case we got a 1.0 from random
  1694. if (targetID == num_targets)
  1695. targetID--;
  1696. // if (g_showlogic && g_showlogic->value)
  1697. // gi.dprintf ("using player %s\n", targets[targetID]->client->pers.netname);
  1698. return targets[targetID];
  1699. }
  1700. // only meant to be used in coop
  1701. int CountPlayers (void)
  1702. {
  1703. edict_t *ent;
  1704. int count = 0;
  1705. int player;
  1706. // if we're not in coop, this is a noop
  1707. if (!coop || !coop->value)
  1708. return 1;
  1709. for (player = 1; player <= game.maxclients; player++)
  1710. {
  1711. ent = &g_edicts[player];
  1712. if (!ent->inuse)
  1713. continue;
  1714. if (!ent->client)
  1715. continue;
  1716. count++;
  1717. }
  1718. /*
  1719. ent = g_edicts+1; // skip the worldspawn
  1720. while (ent)
  1721. {
  1722. if ((ent->client) && (ent->inuse))
  1723. {
  1724. ent++;
  1725. count++;
  1726. }
  1727. else
  1728. ent = NULL;
  1729. }
  1730. */
  1731. return count;
  1732. }
  1733. //*******************
  1734. // JUMPING AIDS
  1735. //*******************
  1736. void monster_jump_start (edict_t *self)
  1737. {
  1738. self->timestamp = level.time;
  1739. }
  1740. qboolean monster_jump_finished (edict_t *self)
  1741. {
  1742. if ((level.time - self->timestamp) > 3)
  1743. {
  1744. // if (g_showlogic && g_showlogic->value)
  1745. // {
  1746. // gi.dprintf("%s jump timed out!\n", self->classname);
  1747. // }
  1748. return true;
  1749. }
  1750. }