m_move2.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738
  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. =============
  114. SV_movestep
  115. Called by monster program code.
  116. The move will be adjusted for slopes and stairs, but if the move isn't
  117. possible, no move is done, false is returned, and
  118. pr_global_struct->trace_normal is set to the normal of the blocking wall
  119. =============
  120. */
  121. //FIXME since we need to test end position contents here, can we avoid doing
  122. //it again later in catagorize position?
  123. qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink)
  124. {
  125. float dz;
  126. vec3_t oldorg, neworg, end;
  127. trace_t trace;
  128. int i;
  129. float stepsize;
  130. vec3_t test;
  131. int contents;
  132. edict_t *current_bad; // PGM
  133. float minheight; // pmm
  134. //======
  135. //PGM
  136. current_bad = CheckForBadArea(ent);
  137. if(current_bad)
  138. {
  139. // gi.dprintf("in bad area\n");
  140. ent->bad_area = current_bad;
  141. if(ent->enemy && !strcmp(ent->enemy->classname, "tesla"))
  142. {
  143. // gi.dprintf("%s -->> ", vtos(move));
  144. VectorScale(move, -1, move);
  145. // gi.dprintf("%s\n", vtos(move));
  146. }
  147. }
  148. else if(ent->bad_area)
  149. {
  150. // if we're no longer in a bad area, get back to business.
  151. ent->bad_area = NULL;
  152. if(ent->oldenemy)// && ent->bad_area->owner == ent->enemy)
  153. {
  154. // gi.dprintf("resuming being pissed at %s\n", ent->oldenemy->classname);
  155. ent->enemy = ent->oldenemy;
  156. ent->goalentity = ent->oldenemy;
  157. FoundTarget(ent);
  158. return true;
  159. }
  160. }
  161. //PGM
  162. //======
  163. // try the move
  164. VectorCopy (ent->s.origin, oldorg);
  165. VectorAdd (ent->s.origin, move, neworg);
  166. // flying monsters don't step up
  167. if ( ent->flags & (FL_SWIM | FL_FLY) )
  168. {
  169. // try one move with vertical motion, then one without
  170. for (i=0 ; i<2 ; i++)
  171. {
  172. VectorAdd (ent->s.origin, move, neworg);
  173. if (i == 0 && ent->enemy)
  174. {
  175. if (!ent->goalentity)
  176. ent->goalentity = ent->enemy;
  177. dz = ent->s.origin[2] - ent->goalentity->s.origin[2];
  178. if (ent->goalentity->client)
  179. {
  180. // we want the carrier to stay a certain distance off the ground, to help prevent him
  181. // from shooting his fliers, who spawn in below him
  182. //
  183. if (!strcmp(ent->classname, "monster_carrier"))
  184. minheight = 104;
  185. else
  186. minheight = 40;
  187. // if (dz > 40)
  188. if (dz > minheight)
  189. // pmm
  190. neworg[2] -= 8;
  191. if (!((ent->flags & FL_SWIM) && (ent->waterlevel < 2)))
  192. if (dz < (minheight - 10))
  193. neworg[2] += 8;
  194. }
  195. else
  196. {
  197. if (dz > 8)
  198. neworg[2] -= 8;
  199. else if (dz > 0)
  200. neworg[2] -= dz;
  201. else if (dz < -8)
  202. neworg[2] += 8;
  203. else
  204. neworg[2] += dz;
  205. }
  206. }
  207. trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, neworg, ent, MASK_MONSTERSOLID);
  208. // fly monsters don't enter water voluntarily
  209. if (ent->flags & FL_FLY)
  210. {
  211. if (!ent->waterlevel)
  212. {
  213. test[0] = trace.endpos[0];
  214. test[1] = trace.endpos[1];
  215. test[2] = trace.endpos[2] + ent->mins[2] + 1;
  216. contents = gi.pointcontents(test);
  217. if (contents & MASK_WATER)
  218. return false;
  219. }
  220. }
  221. // swim monsters don't exit water voluntarily
  222. if (ent->flags & FL_SWIM)
  223. {
  224. if (ent->waterlevel < 2)
  225. {
  226. test[0] = trace.endpos[0];
  227. test[1] = trace.endpos[1];
  228. test[2] = trace.endpos[2] + ent->mins[2] + 1;
  229. contents = gi.pointcontents(test);
  230. if (!(contents & MASK_WATER))
  231. return false;
  232. }
  233. }
  234. // if (trace.fraction == 1)
  235. // PMM - changed above to this
  236. if ((trace.fraction == 1) && (!trace.allsolid) && (!trace.startsolid))
  237. {
  238. VectorCopy (trace.endpos, ent->s.origin);
  239. //=====
  240. //PGM
  241. if(!current_bad && CheckForBadArea(ent))
  242. {
  243. // gi.dprintf("Oooh! Bad Area!\n");
  244. VectorCopy (oldorg, ent->s.origin);
  245. }
  246. else
  247. {
  248. if (relink)
  249. {
  250. gi.linkentity (ent);
  251. G_TouchTriggers (ent);
  252. }
  253. return true;
  254. }
  255. //PGM
  256. //=====
  257. }
  258. if (!ent->enemy)
  259. break;
  260. }
  261. return false;
  262. }
  263. // push down from a step height above the wished position
  264. if (!(ent->monsterinfo.aiflags & AI_NOSTEP))
  265. stepsize = STEPSIZE;
  266. else
  267. stepsize = 1;
  268. //PGM
  269. #ifdef ROGUE_GRAVITY
  270. // trace from 1 stepsize gravityUp to 2 stepsize gravityDown.
  271. VectorMA(neworg, -1 * stepsize, ent->gravityVector, neworg);
  272. VectorMA(neworg, 2 * stepsize, ent->gravityVector, end);
  273. #else
  274. neworg[2] += stepsize;
  275. VectorCopy (neworg, end);
  276. end[2] -= stepsize*2;
  277. #endif
  278. //PGM
  279. trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
  280. if (trace.allsolid)
  281. return false;
  282. if (trace.startsolid)
  283. {
  284. neworg[2] -= stepsize;
  285. trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
  286. if (trace.allsolid || trace.startsolid)
  287. return false;
  288. }
  289. // don't go in to water
  290. if (ent->waterlevel == 0)
  291. {
  292. //PGM
  293. #ifdef ROGUE_GRAVITY
  294. test[0] = trace.endpos[0];
  295. test[1] = trace.endpos[1];
  296. if(ent->gravityVector[2] > 0)
  297. test[2] = trace.endpos[2] + ent->maxs[2] - 1;
  298. else
  299. test[2] = trace.endpos[2] + ent->mins[2] + 1;
  300. #else
  301. test[0] = trace.endpos[0];
  302. test[1] = trace.endpos[1];
  303. test[2] = trace.endpos[2] + ent->mins[2] + 1;
  304. #endif
  305. //PGM
  306. contents = gi.pointcontents(test);
  307. if (contents & MASK_WATER)
  308. return false;
  309. }
  310. if (trace.fraction == 1)
  311. {
  312. // if monster had the ground pulled out, go ahead and fall
  313. if ( ent->flags & FL_PARTIALGROUND )
  314. {
  315. VectorAdd (ent->s.origin, move, ent->s.origin);
  316. if (relink)
  317. {
  318. gi.linkentity (ent);
  319. G_TouchTriggers (ent);
  320. }
  321. ent->groundentity = NULL;
  322. return true;
  323. }
  324. return false; // walked off an edge
  325. }
  326. // check point traces down for dangling corners
  327. VectorCopy (trace.endpos, ent->s.origin);
  328. //PGM
  329. new_bad = CheckForBadArea(ent);
  330. if(!current_bad && new_bad)
  331. {
  332. if (new_bad->owner)
  333. {
  334. if ((g_showlogic) && (g_showlogic->value))
  335. gi.dprintf("Blocked -");
  336. if (!strcmp(new_bad->owner->classname, "tesla"))
  337. {
  338. if ((g_showlogic) && (g_showlogic->value))
  339. gi.dprintf ("it's a tesla -");
  340. if ((!(ent->enemy)) || (!(ent->enemy->inuse)))
  341. {
  342. if ((g_showlogic) && (g_showlogic->value))
  343. gi.dprintf ("I don't have a valid enemy!\n");
  344. }
  345. else if (!strcmp(ent->enemy->classname, "telsa"))
  346. {
  347. if ((g_showlogic) && (g_showlogic->value))
  348. gi.dprintf ("but we're already mad at a tesla\n");
  349. }
  350. else if ((ent->enemy) && (ent->enemy->client))
  351. {
  352. if ((g_showlogic) && (g_showlogic->value))
  353. gi.dprintf ("we have a player enemy -");
  354. if (visible(ent, ent->enemy))
  355. {
  356. if ((g_showlogic) && (g_showlogic->value))
  357. gi.dprintf ("we can see him -");
  358. }
  359. else
  360. {
  361. if ((g_showlogic) && (g_showlogic->value))
  362. gi.dprintf ("can't see him, kill the tesla! -");
  363. }
  364. }
  365. else
  366. {
  367. if ((g_showlogic) && (g_showlogic->value))
  368. gi.dprintf ("the enemy isn't a player -");
  369. }
  370. }
  371. }
  372. gi.dprintf ("\n");
  373. VectorCopy (oldorg, ent->s.origin);
  374. return false;
  375. }
  376. //PGM
  377. if (!M_CheckBottom (ent))
  378. {
  379. if ( ent->flags & FL_PARTIALGROUND )
  380. { // entity had floor mostly pulled out from underneath it
  381. // and is trying to correct
  382. if (relink)
  383. {
  384. gi.linkentity (ent);
  385. G_TouchTriggers (ent);
  386. }
  387. return true;
  388. }
  389. VectorCopy (oldorg, ent->s.origin);
  390. return false;
  391. }
  392. if ( ent->flags & FL_PARTIALGROUND )
  393. {
  394. ent->flags &= ~FL_PARTIALGROUND;
  395. }
  396. ent->groundentity = trace.ent;
  397. ent->groundentity_linkcount = trace.ent->linkcount;
  398. // the move is ok
  399. if (relink)
  400. {
  401. gi.linkentity (ent);
  402. G_TouchTriggers (ent);
  403. }
  404. return true;
  405. }
  406. //============================================================================
  407. /*
  408. ===============
  409. M_ChangeYaw
  410. ===============
  411. */
  412. void M_ChangeYaw (edict_t *ent)
  413. {
  414. float ideal;
  415. float current;
  416. float move;
  417. float speed;
  418. current = anglemod(ent->s.angles[YAW]);
  419. ideal = ent->ideal_yaw;
  420. if (current == ideal)
  421. return;
  422. move = ideal - current;
  423. speed = ent->yaw_speed;
  424. if (ideal > current)
  425. {
  426. if (move >= 180)
  427. move = move - 360;
  428. }
  429. else
  430. {
  431. if (move <= -180)
  432. move = move + 360;
  433. }
  434. if (move > 0)
  435. {
  436. if (move > speed)
  437. move = speed;
  438. }
  439. else
  440. {
  441. if (move < -speed)
  442. move = -speed;
  443. }
  444. ent->s.angles[YAW] = anglemod (current + move);
  445. }
  446. /*
  447. ======================
  448. SV_StepDirection
  449. Turns to the movement direction, and walks the current distance if
  450. facing it.
  451. ======================
  452. */
  453. qboolean SV_StepDirection (edict_t *ent, float yaw, float dist)
  454. {
  455. vec3_t move, oldorigin;
  456. float delta;
  457. if(!ent->inuse) return true; // PGM g_touchtrigger free problem
  458. ent->ideal_yaw = yaw;
  459. M_ChangeYaw (ent);
  460. yaw = yaw*M_PI*2 / 360;
  461. move[0] = cos(yaw)*dist;
  462. move[1] = sin(yaw)*dist;
  463. move[2] = 0;
  464. VectorCopy (ent->s.origin, oldorigin);
  465. if (SV_movestep (ent, move, false))
  466. {
  467. if(!ent->inuse) return true; // PGM g_touchtrigger free problem
  468. delta = ent->s.angles[YAW] - ent->ideal_yaw;
  469. if (strncmp(ent->classname, "monster_widow", 13))
  470. {
  471. if (delta > 45 && delta < 315)
  472. { // not turned far enough, so don't take the step
  473. VectorCopy (oldorigin, ent->s.origin);
  474. }
  475. }
  476. gi.linkentity (ent);
  477. G_TouchTriggers (ent);
  478. return true;
  479. }
  480. gi.linkentity (ent);
  481. G_TouchTriggers (ent);
  482. return false;
  483. }
  484. /*
  485. ======================
  486. SV_FixCheckBottom
  487. ======================
  488. */
  489. void SV_FixCheckBottom (edict_t *ent)
  490. {
  491. ent->flags |= FL_PARTIALGROUND;
  492. }
  493. /*
  494. ================
  495. SV_NewChaseDir
  496. ================
  497. */
  498. #define DI_NODIR -1
  499. void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist)
  500. {
  501. float deltax,deltay;
  502. float d[3];
  503. float tdir, olddir, turnaround;
  504. //FIXME: how did we get here with no enemy
  505. if (!enemy)
  506. return;
  507. olddir = anglemod( (int)(actor->ideal_yaw/45)*45 );
  508. turnaround = anglemod(olddir - 180);
  509. deltax = enemy->s.origin[0] - actor->s.origin[0];
  510. deltay = enemy->s.origin[1] - actor->s.origin[1];
  511. if (deltax>10)
  512. d[1]= 0;
  513. else if (deltax<-10)
  514. d[1]= 180;
  515. else
  516. d[1]= DI_NODIR;
  517. if (deltay<-10)
  518. d[2]= 270;
  519. else if (deltay>10)
  520. d[2]= 90;
  521. else
  522. d[2]= DI_NODIR;
  523. // try direct route
  524. if (d[1] != DI_NODIR && d[2] != DI_NODIR)
  525. {
  526. if (d[1] == 0)
  527. tdir = d[2] == 90 ? 45 : 315;
  528. else
  529. tdir = d[2] == 90 ? 135 : 215;
  530. if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
  531. return;
  532. }
  533. // try other directions
  534. if ( ((rand()&3) & 1) || abs(deltay)>abs(deltax))
  535. {
  536. tdir=d[1];
  537. d[1]=d[2];
  538. d[2]=tdir;
  539. }
  540. if (d[1]!=DI_NODIR && d[1]!=turnaround
  541. && SV_StepDirection(actor, d[1], dist))
  542. return;
  543. if (d[2]!=DI_NODIR && d[2]!=turnaround
  544. && SV_StepDirection(actor, d[2], dist))
  545. return;
  546. //ROGUE
  547. if(actor->monsterinfo.blocked)
  548. {
  549. if((actor->monsterinfo.blocked)(actor, dist))
  550. return;
  551. }
  552. //ROGUE
  553. /* there is no direct path to the player, so pick another direction */
  554. if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist))
  555. return;
  556. if (rand()&1) /*randomly determine direction of search*/
  557. {
  558. for (tdir=0 ; tdir<=315 ; tdir += 45)
  559. if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
  560. return;
  561. }
  562. else
  563. {
  564. for (tdir=315 ; tdir >=0 ; tdir -= 45)
  565. if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
  566. return;
  567. }
  568. if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) )
  569. return;
  570. actor->ideal_yaw = olddir; // can't move
  571. // if a bridge was pulled out from underneath a monster, it may not have
  572. // a valid standing position at all
  573. if (!M_CheckBottom (actor))
  574. SV_FixCheckBottom (actor);
  575. }
  576. /*
  577. ======================
  578. SV_CloseEnough
  579. ======================
  580. */
  581. qboolean SV_CloseEnough (edict_t *ent, edict_t *goal, float dist)
  582. {
  583. int i;
  584. for (i=0 ; i<3 ; i++)
  585. {
  586. if (goal->absmin[i] > ent->absmax[i] + dist)
  587. return false;
  588. if (goal->absmax[i] < ent->absmin[i] - dist)
  589. return false;
  590. }
  591. return true;
  592. }
  593. /*
  594. ======================
  595. M_MoveToGoal
  596. ======================
  597. */
  598. void M_MoveToGoal (edict_t *ent, float dist)
  599. {
  600. edict_t *goal;
  601. goal = ent->goalentity;
  602. if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM)))
  603. return;
  604. // if the next step hits the enemy, return immediately
  605. if (ent->enemy && SV_CloseEnough (ent, ent->enemy, dist) )
  606. return;
  607. // bump around...
  608. // if ( (rand()&3)==1 || !SV_StepDirection (ent, ent->ideal_yaw, dist))
  609. // PMM - charging monsters (AI_CHARGING) don't deflect unless they have to
  610. if ( (((rand()&3)==1) && !(ent->monsterinfo.aiflags & AI_CHARGING)) || !SV_StepDirection (ent, ent->ideal_yaw, dist))
  611. {
  612. if (ent->inuse)
  613. SV_NewChaseDir (ent, goal, dist);
  614. }
  615. }
  616. /*
  617. ===============
  618. M_walkmove
  619. ===============
  620. */
  621. qboolean M_walkmove (edict_t *ent, float yaw, float dist)
  622. {
  623. vec3_t move;
  624. if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM)))
  625. return false;
  626. yaw = yaw*M_PI*2 / 360;
  627. move[0] = cos(yaw)*dist;
  628. move[1] = sin(yaw)*dist;
  629. move[2] = 0;
  630. return SV_movestep(ent, move, true);
  631. }