m_move.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848
  1. // Copyright (c) ZeniMax Media Inc.
  2. // Licensed under the GNU General Public License 2.0.
  3. // m_move.c -- monster movement
  4. #include "g_local.h"
  5. #define STEPSIZE 18
  6. // this is used for communications out of sv_movestep to say what entity
  7. // is blocking us
  8. edict_t *new_bad; //pmm
  9. /*
  10. =============
  11. M_CheckBottom
  12. Returns false if any part of the bottom of the entity is off an edge that
  13. is not a staircase.
  14. =============
  15. */
  16. int c_yes, c_no;
  17. qboolean M_CheckBottom (edict_t *ent)
  18. {
  19. vec3_t mins, maxs, start, stop;
  20. trace_t trace;
  21. int x, y;
  22. float mid, bottom;
  23. VectorAdd (ent->s.origin, ent->mins, mins);
  24. VectorAdd (ent->s.origin, ent->maxs, maxs);
  25. // if all of the points under the corners are solid world, don't bother
  26. // with the tougher checks
  27. // the corners must be within 16 of the midpoint
  28. //PGM
  29. #ifdef ROGUE_GRAVITY
  30. // FIXME - this will only handle 0,0,1 and 0,0,-1 gravity vectors
  31. start[2] = mins[2] - 1;
  32. if(ent->gravityVector[2] > 0)
  33. start[2] = maxs[2] + 1;
  34. #else
  35. start[2] = mins[2] - 1;
  36. #endif
  37. //PGM
  38. for (x=0 ; x<=1 ; x++)
  39. for (y=0 ; y<=1 ; y++)
  40. {
  41. start[0] = x ? maxs[0] : mins[0];
  42. start[1] = y ? maxs[1] : mins[1];
  43. if (gi.pointcontents (start) != CONTENTS_SOLID)
  44. goto realcheck;
  45. }
  46. c_yes++;
  47. return true; // we got out easy
  48. realcheck:
  49. c_no++;
  50. //
  51. // check it for real...
  52. //
  53. start[2] = mins[2];
  54. // the midpoint must be within 16 of the bottom
  55. start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
  56. start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
  57. //PGM
  58. #ifdef ROGUE_GRAVITY
  59. if(ent->gravityVector[2] < 0)
  60. {
  61. start[2] = mins[2];
  62. stop[2] = start[2] - STEPSIZE - STEPSIZE;
  63. }
  64. else
  65. {
  66. start[2] = maxs[2];
  67. stop[2] = start[2] + STEPSIZE + STEPSIZE;
  68. }
  69. #else
  70. stop[2] = start[2] - 2*STEPSIZE;
  71. #endif
  72. //PGM
  73. trace = gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID);
  74. if (trace.fraction == 1.0)
  75. return false;
  76. mid = bottom = trace.endpos[2];
  77. // the corners must be within 16 of the midpoint
  78. for (x=0 ; x<=1 ; x++)
  79. for (y=0 ; y<=1 ; y++)
  80. {
  81. start[0] = stop[0] = x ? maxs[0] : mins[0];
  82. start[1] = stop[1] = y ? maxs[1] : mins[1];
  83. trace = gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID);
  84. //PGM
  85. #ifdef ROGUE_GRAVITY
  86. // FIXME - this will only handle 0,0,1 and 0,0,-1 gravity vectors
  87. if(ent->gravityVector[2] > 0)
  88. {
  89. if (trace.fraction != 1.0 && trace.endpos[2] < bottom)
  90. bottom = trace.endpos[2];
  91. if (trace.fraction == 1.0 || trace.endpos[2] - mid > STEPSIZE)
  92. return false;
  93. }
  94. else
  95. {
  96. if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
  97. bottom = trace.endpos[2];
  98. if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE)
  99. return false;
  100. }
  101. #else
  102. if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
  103. bottom = trace.endpos[2];
  104. if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE)
  105. return false;
  106. #endif
  107. //PGM
  108. }
  109. c_yes++;
  110. return true;
  111. }
  112. //============
  113. // ROGUE
  114. qboolean IsBadAhead (edict_t *self, edict_t *bad, vec3_t move)
  115. {
  116. vec3_t dir;
  117. vec3_t forward;
  118. float dp_bad, dp_move;
  119. vec3_t move_copy;
  120. VectorCopy (move, move_copy);
  121. VectorSubtract (bad->s.origin, self->s.origin, dir);
  122. VectorNormalize (dir);
  123. AngleVectors (self->s.angles, forward, NULL, NULL);
  124. dp_bad = DotProduct (forward, dir);
  125. VectorNormalize (move_copy);
  126. AngleVectors (self->s.angles, forward, NULL, NULL);
  127. dp_move = DotProduct (forward, move_copy);
  128. if ((dp_bad < 0) && (dp_move < 0))
  129. return true;
  130. if ((dp_bad > 0) && (dp_move > 0))
  131. return true;
  132. return false;
  133. /*
  134. if(DotProduct(forward, dir) > 0)
  135. {
  136. // gi.dprintf ("bad ahead...\n");
  137. return true;
  138. }
  139. // gi.dprintf ("bad behind...\n");
  140. return false;
  141. */
  142. }
  143. // ROGUE
  144. //============
  145. /*
  146. =============
  147. SV_movestep
  148. Called by monster program code.
  149. The move will be adjusted for slopes and stairs, but if the move isn't
  150. possible, no move is done, false is returned, and
  151. pr_global_struct->trace_normal is set to the normal of the blocking wall
  152. =============
  153. */
  154. //FIXME since we need to test end position contents here, can we avoid doing
  155. //it again later in catagorize position?
  156. qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink)
  157. {
  158. float dz;
  159. vec3_t oldorg, neworg, end;
  160. trace_t trace;
  161. int i;
  162. float stepsize;
  163. vec3_t test;
  164. int contents;
  165. edict_t *current_bad; // PGM
  166. float minheight; // pmm
  167. //======
  168. //PGM
  169. // PMM - who cares about bad areas if you're dead?
  170. if (ent->health > 0)
  171. {
  172. current_bad = CheckForBadArea(ent);
  173. if(current_bad)
  174. {
  175. ent->bad_area = current_bad;
  176. if(ent->enemy && !strcmp(ent->enemy->classname, "tesla"))
  177. {
  178. // if the tesla is in front of us, back up...
  179. if (IsBadAhead (ent, current_bad, move))
  180. VectorScale(move, -1, move);
  181. }
  182. }
  183. else if(ent->bad_area)
  184. {
  185. // if we're no longer in a bad area, get back to business.
  186. ent->bad_area = NULL;
  187. if(ent->oldenemy)// && ent->bad_area->owner == ent->enemy)
  188. {
  189. // gi.dprintf("resuming being pissed at %s\n", ent->oldenemy->classname);
  190. ent->enemy = ent->oldenemy;
  191. ent->goalentity = ent->oldenemy;
  192. FoundTarget(ent);
  193. // FIXME - remove this when ready!!!
  194. // if (ent->lastMoveTime == level.time)
  195. // if ((g_showlogic) && (g_showlogic->value))
  196. // gi.dprintf ("Duplicate move detected for %s, please tell programmers!\n", ent->classname);
  197. // ent->lastMoveTime = level.time;
  198. // FIXME
  199. return true;
  200. }
  201. }
  202. }
  203. //PGM
  204. //======
  205. // try the move
  206. VectorCopy (ent->s.origin, oldorg);
  207. VectorAdd (ent->s.origin, move, neworg);
  208. // flying monsters don't step up
  209. if ( ent->flags & (FL_SWIM | FL_FLY) )
  210. {
  211. // try one move with vertical motion, then one without
  212. for (i=0 ; i<2 ; i++)
  213. {
  214. VectorAdd (ent->s.origin, move, neworg);
  215. if (i == 0 && ent->enemy)
  216. {
  217. if (!ent->goalentity)
  218. ent->goalentity = ent->enemy;
  219. dz = ent->s.origin[2] - ent->goalentity->s.origin[2];
  220. if (ent->goalentity->client)
  221. {
  222. // we want the carrier to stay a certain distance off the ground, to help prevent him
  223. // from shooting his fliers, who spawn in below him
  224. //
  225. if (!strcmp(ent->classname, "monster_carrier"))
  226. minheight = 104;
  227. else
  228. minheight = 40;
  229. // if (dz > 40)
  230. if (dz > minheight)
  231. // pmm
  232. neworg[2] -= 8;
  233. if (!((ent->flags & FL_SWIM) && (ent->waterlevel < 2)))
  234. if (dz < (minheight - 10))
  235. neworg[2] += 8;
  236. }
  237. else
  238. {
  239. if (dz > 8)
  240. neworg[2] -= 8;
  241. else if (dz > 0)
  242. neworg[2] -= dz;
  243. else if (dz < -8)
  244. neworg[2] += 8;
  245. else
  246. neworg[2] += dz;
  247. }
  248. }
  249. trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, neworg, ent, MASK_MONSTERSOLID);
  250. // fly monsters don't enter water voluntarily
  251. if (ent->flags & FL_FLY)
  252. {
  253. if (!ent->waterlevel)
  254. {
  255. test[0] = trace.endpos[0];
  256. test[1] = trace.endpos[1];
  257. test[2] = trace.endpos[2] + ent->mins[2] + 1;
  258. contents = gi.pointcontents(test);
  259. if (contents & MASK_WATER)
  260. return false;
  261. }
  262. }
  263. // swim monsters don't exit water voluntarily
  264. if (ent->flags & FL_SWIM)
  265. {
  266. if (ent->waterlevel < 2)
  267. {
  268. test[0] = trace.endpos[0];
  269. test[1] = trace.endpos[1];
  270. test[2] = trace.endpos[2] + ent->mins[2] + 1;
  271. contents = gi.pointcontents(test);
  272. if (!(contents & MASK_WATER))
  273. return false;
  274. }
  275. }
  276. // if (trace.fraction == 1)
  277. // PMM - changed above to this
  278. if ((trace.fraction == 1) && (!trace.allsolid) && (!trace.startsolid))
  279. {
  280. VectorCopy (trace.endpos, ent->s.origin);
  281. //=====
  282. //PGM
  283. if(!current_bad && CheckForBadArea(ent))
  284. {
  285. // gi.dprintf("Oooh! Bad Area!\n");
  286. VectorCopy (oldorg, ent->s.origin);
  287. }
  288. else
  289. {
  290. if (relink)
  291. {
  292. gi.linkentity (ent);
  293. G_TouchTriggers (ent);
  294. }
  295. // FIXME - remove this when ready!!!
  296. // if (ent->lastMoveTime == level.time)
  297. // if ((g_showlogic) && (g_showlogic->value))
  298. // gi.dprintf ("Duplicate move detected for %s, please tell programmers!\n", ent->classname);
  299. // ent->lastMoveTime = level.time;
  300. // FIXME
  301. return true;
  302. }
  303. //PGM
  304. //=====
  305. }
  306. if (!ent->enemy)
  307. break;
  308. }
  309. return false;
  310. }
  311. // push down from a step height above the wished position
  312. if (!(ent->monsterinfo.aiflags & AI_NOSTEP))
  313. stepsize = STEPSIZE;
  314. else
  315. stepsize = 1;
  316. //PGM
  317. #ifdef ROGUE_GRAVITY
  318. // trace from 1 stepsize gravityUp to 2 stepsize gravityDown.
  319. VectorMA(neworg, -1 * stepsize, ent->gravityVector, neworg);
  320. VectorMA(neworg, 2 * stepsize, ent->gravityVector, end);
  321. #else
  322. neworg[2] += stepsize;
  323. VectorCopy (neworg, end);
  324. end[2] -= stepsize*2;
  325. #endif
  326. //PGM
  327. trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
  328. if (trace.allsolid)
  329. return false;
  330. if (trace.startsolid)
  331. {
  332. neworg[2] -= stepsize;
  333. trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
  334. if (trace.allsolid || trace.startsolid)
  335. return false;
  336. }
  337. // don't go in to water
  338. if (ent->waterlevel == 0)
  339. {
  340. //PGM
  341. #ifdef ROGUE_GRAVITY
  342. test[0] = trace.endpos[0];
  343. test[1] = trace.endpos[1];
  344. if(ent->gravityVector[2] > 0)
  345. test[2] = trace.endpos[2] + ent->maxs[2] - 1;
  346. else
  347. test[2] = trace.endpos[2] + ent->mins[2] + 1;
  348. #else
  349. test[0] = trace.endpos[0];
  350. test[1] = trace.endpos[1];
  351. test[2] = trace.endpos[2] + ent->mins[2] + 1;
  352. #endif
  353. //PGM
  354. contents = gi.pointcontents(test);
  355. if (contents & MASK_WATER)
  356. return false;
  357. }
  358. if (trace.fraction == 1)
  359. {
  360. // if monster had the ground pulled out, go ahead and fall
  361. if ( ent->flags & FL_PARTIALGROUND )
  362. {
  363. VectorAdd (ent->s.origin, move, ent->s.origin);
  364. if (relink)
  365. {
  366. gi.linkentity (ent);
  367. G_TouchTriggers (ent);
  368. }
  369. ent->groundentity = NULL;
  370. // FIXME - remove this when ready!!!
  371. // if (ent->lastMoveTime == level.time)
  372. // if ((g_showlogic) && (g_showlogic->value))
  373. // gi.dprintf ("Duplicate move detected for %s, please tell programmers!\n", ent->classname);
  374. // ent->lastMoveTime = level.time;
  375. // FIXME
  376. return true;
  377. }
  378. return false; // walked off an edge
  379. }
  380. // check point traces down for dangling corners
  381. VectorCopy (trace.endpos, ent->s.origin);
  382. //PGM
  383. // PMM - don't bother with bad areas if we're dead
  384. if (ent->health > 0)
  385. {
  386. // use AI_BLOCKED to tell the calling layer that we're now mad at a tesla
  387. new_bad = CheckForBadArea(ent);
  388. if(!current_bad && new_bad)
  389. {
  390. if (new_bad->owner)
  391. {
  392. // if ((g_showlogic) && (g_showlogic->value))
  393. // gi.dprintf("Blocked -");
  394. if (!strcmp(new_bad->owner->classname, "tesla"))
  395. {
  396. // if ((g_showlogic) && (g_showlogic->value))
  397. // gi.dprintf ("it's a tesla -");
  398. if ((!(ent->enemy)) || (!(ent->enemy->inuse)))
  399. {
  400. // if ((g_showlogic) && (g_showlogic->value))
  401. // gi.dprintf ("I don't have a valid enemy, attacking tesla!\n");
  402. TargetTesla (ent, new_bad->owner);
  403. ent->monsterinfo.aiflags |= AI_BLOCKED;
  404. }
  405. else if (!strcmp(ent->enemy->classname, "telsa"))
  406. {
  407. // if ((g_showlogic) && (g_showlogic->value))
  408. // gi.dprintf ("but we're already mad at a tesla\n");
  409. }
  410. else if ((ent->enemy) && (ent->enemy->client))
  411. {
  412. // if ((g_showlogic) && (g_showlogic->value))
  413. // gi.dprintf ("we have a player enemy -");
  414. if (visible(ent, ent->enemy))
  415. {
  416. // if ((g_showlogic) && (g_showlogic->value))
  417. // gi.dprintf ("we can see him -");
  418. }
  419. else
  420. {
  421. // if ((g_showlogic) && (g_showlogic->value))
  422. // gi.dprintf ("can't see him, kill the tesla! -");
  423. TargetTesla (ent, new_bad->owner);
  424. ent->monsterinfo.aiflags |= AI_BLOCKED;
  425. }
  426. }
  427. else
  428. {
  429. // if ((g_showlogic) && (g_showlogic->value))
  430. // gi.dprintf ("the enemy isn't a player, killing tesla -");
  431. TargetTesla (ent, new_bad->owner);
  432. ent->monsterinfo.aiflags |= AI_BLOCKED;
  433. }
  434. }
  435. // else if ((g_showlogic) && (g_showlogic->value))
  436. // {
  437. // gi.dprintf(" by non-tesla bad area!");
  438. // }
  439. }
  440. // gi.dprintf ("\n");
  441. VectorCopy (oldorg, ent->s.origin);
  442. return false;
  443. }
  444. }
  445. //PGM
  446. if (!M_CheckBottom (ent))
  447. {
  448. if ( ent->flags & FL_PARTIALGROUND )
  449. { // entity had floor mostly pulled out from underneath it
  450. // and is trying to correct
  451. if (relink)
  452. {
  453. gi.linkentity (ent);
  454. G_TouchTriggers (ent);
  455. }
  456. // FIXME - remove this when ready!!!
  457. // if (ent->lastMoveTime == level.time)
  458. // if ((g_showlogic) && (g_showlogic->value))
  459. // gi.dprintf ("Duplicate move detected for %s, please tell programmers!\n", ent->classname);
  460. // ent->lastMoveTime = level.time;
  461. // FIXME
  462. return true;
  463. }
  464. VectorCopy (oldorg, ent->s.origin);
  465. return false;
  466. }
  467. if ( ent->flags & FL_PARTIALGROUND )
  468. {
  469. ent->flags &= ~FL_PARTIALGROUND;
  470. }
  471. ent->groundentity = trace.ent;
  472. ent->groundentity_linkcount = trace.ent->linkcount;
  473. // the move is ok
  474. if (relink)
  475. {
  476. gi.linkentity (ent);
  477. G_TouchTriggers (ent);
  478. }
  479. // FIXME - remove this when ready!!!
  480. // if (ent->lastMoveTime == level.time)
  481. // if ((g_showlogic) && (g_showlogic->value))
  482. // gi.dprintf ("Duplicate move detected for %s, please tell programmers!\n", ent->classname);
  483. // ent->lastMoveTime = level.time;
  484. // FIXME
  485. return true;
  486. }
  487. //============================================================================
  488. /*
  489. ===============
  490. M_ChangeYaw
  491. ===============
  492. */
  493. void M_ChangeYaw (edict_t *ent)
  494. {
  495. float ideal;
  496. float current;
  497. float move;
  498. float speed;
  499. current = anglemod(ent->s.angles[YAW]);
  500. ideal = ent->ideal_yaw;
  501. if (current == ideal)
  502. return;
  503. move = ideal - current;
  504. speed = ent->yaw_speed;
  505. if (ideal > current)
  506. {
  507. if (move >= 180)
  508. move = move - 360;
  509. }
  510. else
  511. {
  512. if (move <= -180)
  513. move = move + 360;
  514. }
  515. if (move > 0)
  516. {
  517. if (move > speed)
  518. move = speed;
  519. }
  520. else
  521. {
  522. if (move < -speed)
  523. move = -speed;
  524. }
  525. ent->s.angles[YAW] = anglemod (current + move);
  526. }
  527. /*
  528. ======================
  529. SV_StepDirection
  530. Turns to the movement direction, and walks the current distance if
  531. facing it.
  532. ======================
  533. */
  534. qboolean SV_StepDirection (edict_t *ent, float yaw, float dist)
  535. {
  536. vec3_t move, oldorigin;
  537. float delta;
  538. if(!ent->inuse) return true; // PGM g_touchtrigger free problem
  539. ent->ideal_yaw = yaw;
  540. M_ChangeYaw (ent);
  541. yaw = yaw*M_PI*2 / 360;
  542. move[0] = cos(yaw)*dist;
  543. move[1] = sin(yaw)*dist;
  544. move[2] = 0;
  545. VectorCopy (ent->s.origin, oldorigin);
  546. if (SV_movestep (ent, move, false))
  547. {
  548. ent->monsterinfo.aiflags &= ~AI_BLOCKED;
  549. if(!ent->inuse) return true; // PGM g_touchtrigger free problem
  550. delta = ent->s.angles[YAW] - ent->ideal_yaw;
  551. if (strncmp(ent->classname, "monster_widow", 13))
  552. {
  553. if (delta > 45 && delta < 315)
  554. { // not turned far enough, so don't take the step
  555. VectorCopy (oldorigin, ent->s.origin);
  556. }
  557. }
  558. gi.linkentity (ent);
  559. G_TouchTriggers (ent);
  560. return true;
  561. }
  562. gi.linkentity (ent);
  563. G_TouchTriggers (ent);
  564. return false;
  565. }
  566. /*
  567. ======================
  568. SV_FixCheckBottom
  569. ======================
  570. */
  571. void SV_FixCheckBottom (edict_t *ent)
  572. {
  573. ent->flags |= FL_PARTIALGROUND;
  574. }
  575. /*
  576. ================
  577. SV_NewChaseDir
  578. ================
  579. */
  580. #define DI_NODIR -1
  581. void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist)
  582. {
  583. float deltax,deltay;
  584. float d[3];
  585. float tdir, olddir, turnaround;
  586. //FIXME: how did we get here with no enemy
  587. if (!enemy)
  588. return;
  589. olddir = anglemod( (int)(actor->ideal_yaw/45)*45 );
  590. turnaround = anglemod(olddir - 180);
  591. deltax = enemy->s.origin[0] - actor->s.origin[0];
  592. deltay = enemy->s.origin[1] - actor->s.origin[1];
  593. if (deltax>10)
  594. d[1]= 0;
  595. else if (deltax<-10)
  596. d[1]= 180;
  597. else
  598. d[1]= DI_NODIR;
  599. if (deltay<-10)
  600. d[2]= 270;
  601. else if (deltay>10)
  602. d[2]= 90;
  603. else
  604. d[2]= DI_NODIR;
  605. // try direct route
  606. if (d[1] != DI_NODIR && d[2] != DI_NODIR)
  607. {
  608. if (d[1] == 0)
  609. tdir = d[2] == 90 ? 45 : 315;
  610. else
  611. tdir = d[2] == 90 ? 135 : 215;
  612. if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
  613. return;
  614. }
  615. // try other directions
  616. if ( ((rand()&3) & 1) || abs(deltay)>abs(deltax))
  617. {
  618. tdir=d[1];
  619. d[1]=d[2];
  620. d[2]=tdir;
  621. }
  622. if (d[1]!=DI_NODIR && d[1]!=turnaround
  623. && SV_StepDirection(actor, d[1], dist))
  624. return;
  625. if (d[2]!=DI_NODIR && d[2]!=turnaround
  626. && SV_StepDirection(actor, d[2], dist))
  627. return;
  628. //ROGUE
  629. if(actor->monsterinfo.blocked)
  630. {
  631. if ((actor->inuse) && (actor->health > 0))
  632. {
  633. if((actor->monsterinfo.blocked)(actor, dist))
  634. return;
  635. }
  636. }
  637. //ROGUE
  638. /* there is no direct path to the player, so pick another direction */
  639. if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist))
  640. return;
  641. if (rand()&1) /*randomly determine direction of search*/
  642. {
  643. for (tdir=0 ; tdir<=315 ; tdir += 45)
  644. if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
  645. return;
  646. }
  647. else
  648. {
  649. for (tdir=315 ; tdir >=0 ; tdir -= 45)
  650. if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
  651. return;
  652. }
  653. if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) )
  654. return;
  655. actor->ideal_yaw = olddir; // can't move
  656. // if a bridge was pulled out from underneath a monster, it may not have
  657. // a valid standing position at all
  658. if (!M_CheckBottom (actor))
  659. SV_FixCheckBottom (actor);
  660. }
  661. /*
  662. ======================
  663. SV_CloseEnough
  664. ======================
  665. */
  666. qboolean SV_CloseEnough (edict_t *ent, edict_t *goal, float dist)
  667. {
  668. int i;
  669. for (i=0 ; i<3 ; i++)
  670. {
  671. if (goal->absmin[i] > ent->absmax[i] + dist)
  672. return false;
  673. if (goal->absmax[i] < ent->absmin[i] - dist)
  674. return false;
  675. }
  676. return true;
  677. }
  678. /*
  679. ======================
  680. M_MoveToGoal
  681. ======================
  682. */
  683. void M_MoveToGoal (edict_t *ent, float dist)
  684. {
  685. edict_t *goal;
  686. goal = ent->goalentity;
  687. if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM)))
  688. return;
  689. // if the next step hits the enemy, return immediately
  690. if (ent->enemy && SV_CloseEnough (ent, ent->enemy, dist) )
  691. return;
  692. // bump around...
  693. // if ( (rand()&3)==1 || !SV_StepDirection (ent, ent->ideal_yaw, dist))
  694. // PMM - charging monsters (AI_CHARGING) don't deflect unless they have to
  695. if ( (((rand()&3)==1) && !(ent->monsterinfo.aiflags & AI_CHARGING)) || !SV_StepDirection (ent, ent->ideal_yaw, dist))
  696. {
  697. if (ent->monsterinfo.aiflags & AI_BLOCKED)
  698. {
  699. // if ((g_showlogic) && (g_showlogic->value))
  700. // gi.dprintf ("tesla attack detected, not changing direction!\n");
  701. ent->monsterinfo.aiflags &= ~AI_BLOCKED;
  702. return;
  703. }
  704. if (ent->inuse)
  705. SV_NewChaseDir (ent, goal, dist);
  706. }
  707. }
  708. /*
  709. ===============
  710. M_walkmove
  711. ===============
  712. */
  713. qboolean M_walkmove (edict_t *ent, float yaw, float dist)
  714. {
  715. vec3_t move;
  716. // PMM
  717. qboolean retval;
  718. if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM)))
  719. return false;
  720. yaw = yaw*M_PI*2 / 360;
  721. move[0] = cos(yaw)*dist;
  722. move[1] = sin(yaw)*dist;
  723. move[2] = 0;
  724. // PMM
  725. retval = SV_movestep(ent, move, true);
  726. ent->monsterinfo.aiflags &= ~AI_BLOCKED;
  727. return retval;
  728. // pmm
  729. //return SV_movestep(ent, move, true);
  730. }