AI.CPP 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include "engine.h"
  4. #include "ai.h"
  5. #include "db.h"
  6. #include "trig.h"
  7. #include "misc.h"
  8. #include "actor.h"
  9. #include "player.h"
  10. #include "globals.h"
  11. #include "gameutil.h"
  12. #include "multi.h"
  13. #include "dude.h"
  14. #include "debug4g.h"
  15. #include "eventq.h"
  16. #include "aicult.h"
  17. #include "aigarg.h"
  18. #include "aihand.h"
  19. #include "aihound.h"
  20. #include "airat.h"
  21. #include "aispid.h"
  22. #include "aizomba.h"
  23. #include "aizombf.h"
  24. /****************************************************************************
  25. ** LOCAL CONSTANTS
  26. ****************************************************************************/
  27. #define kAIThinkRate 8 // how often high level AI is sampled (in frames)
  28. #define kAIThinkMask (kAIThinkRate - 1)
  29. #define kAIThinkTime (kAIThinkRate * kFrameTicks)
  30. #define kSGargoyleMeleeDist M2X(2.0) //M2X(1.6)
  31. #define kSGargoyleBlastDist1 M2X(20) // used for paralyzing blast
  32. #define kSGargoyleBlastDist2 M2X(14)
  33. #define kTentacleActivateDist M2X(5) // activates and stays on until target reaches deactivate distance?
  34. #define kTentacleDeactivateDist M2X(9)
  35. #define kTentacleMeleeDist M2X(2)
  36. #define kPodActivateDist M2X(8)
  37. #define kPodDeactivateDist M2X(14)
  38. #define kPodFireDist1 M2X(12)
  39. #define kPodFireDist2 M2X(8)
  40. #define kGillBeastMeleeDist M2X(1.6)
  41. #define kGillBeastSummonDist1 M2X(16)
  42. #define kGillBeastSummonDist2 M2X(12)
  43. #define kEelMeleeDist M2X(1)
  44. #define kRatMeleeDist M2X(1)
  45. #define kHandMeleeDist M2X(1)
  46. #define kCerberusMeleeDist M2X(2)
  47. #define kCerberusBlastDist1 M2X(14) // used for fireball
  48. #define kCerberusBlastDist2 M2X(10)
  49. #define kPhantasmMeleeDist M2X(1.6)
  50. #define kPhantasmThrowDist1 M2X(16)
  51. #define kPhantasmThrowDist2 M2X(12)
  52. static int cumulDamage[kMaxXSprites]; // cumulative damage per frame
  53. int gDudeSlope[kMaxXSprites];
  54. static AISTATE genIdle = { kSeqDudeIdle, NULL, 0, NULL, NULL, NULL, NULL };
  55. static AISTATE genRecoil = { kSeqDudeRecoil, NULL, 20, NULL, NULL, NULL, &genIdle };
  56. //struct AISOUND
  57. //{
  58. // short sightID;
  59. // short painID;
  60. // short attackID;
  61. // short altAttackID;
  62. // short deathID;
  63. //};
  64. /*******************************************************************************
  65. AI design idea: p-code kernel which a short program for each dude type.
  66. P-code primitives:
  67. PlaySeq [id] [callback]
  68. PlaySound [id]
  69. *******************************************************************************/
  70. /****************************************************************************
  71. ** GLOBALS
  72. ****************************************************************************/
  73. /****************************************************************************
  74. ** LOCALS
  75. ****************************************************************************/
  76. void aiNewState( SPRITE *pSprite, XSPRITE *pXSprite, AISTATE *pState )
  77. {
  78. DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
  79. pXSprite->stateTimer = pState->ticks;
  80. pXSprite->aiState = pState;
  81. if ( pState->seqId >= 0 )
  82. {
  83. if ( gSysRes.Lookup(pDudeInfo->seqStartID + pState->seqId,".SEQ") == NULL )
  84. {
  85. dprintf("NULL sequence, dudeType = %d, seqId = %d\n", pSprite->type, pState->seqId);
  86. return;
  87. }
  88. seqSpawn(pDudeInfo->seqStartID + pState->seqId, SS_SPRITE, pSprite->extra, pState->seqCallback);
  89. }
  90. // call the enter function if defined
  91. if ( pState->enter )
  92. pState->enter(pSprite, pXSprite);
  93. }
  94. BOOL CanMove( SPRITE *pSprite, int nTarget, int ang, int dist )
  95. {
  96. int zTop, zBot;
  97. GetSpriteExtents(pSprite, &zTop, &zBot);
  98. int dx = mulscale30(dist, Cos(ang));
  99. int dy = mulscale30(dist, Sin(ang));
  100. int x = pSprite->x;
  101. int y = pSprite->y;
  102. int z = pSprite->z;
  103. HITINFO hitInfo;
  104. HitScan(pSprite, z, dx, dy, 0, &hitInfo);
  105. int hitDist = qdist(x - hitInfo.hitx, y - hitInfo.hity);
  106. if ( hitDist - (pSprite->clipdist << 2) < dist )
  107. {
  108. // okay to be blocked by target
  109. if ( hitInfo.hitsprite >= 0 && hitInfo.hitsprite == nTarget )
  110. return TRUE;
  111. return FALSE;
  112. }
  113. x += dx;
  114. y += dy;
  115. short nSector = pSprite->sectnum;
  116. if ( !FindSector(x, y, z, &nSector) )
  117. return FALSE;
  118. long floorZ = getflorzofslope(nSector, x, y);
  119. // this should go into the dude table and be time relative
  120. if ( floorZ - zBot > M2Z(1.0) )
  121. return FALSE;
  122. return TRUE;
  123. }
  124. void aiChooseDirection( SPRITE *pSprite, XSPRITE *pXSprite, int ang )
  125. {
  126. dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
  127. DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
  128. int dang = ((kAngle180 + ang - pSprite->ang) & kAngleMask) - kAngle180;
  129. long sin = Sin(pSprite->ang);
  130. long cos = Cos(pSprite->ang);
  131. // find vel and svel relative to current angle
  132. // long vel = dmulscale30(pSprite->xvel, cos, pSprite->yvel, sin);
  133. // long svel = dmulscale30(pSprite->xvel, sin, -pSprite->yvel, cos);
  134. // look 1.0 second ahead
  135. int avoidDist = pDudeInfo->frontSpeed * kTimerRate >> 4;
  136. int turnTo = kAngle60;
  137. if (dang < 0 )
  138. turnTo = -turnTo;
  139. // clear movement toward target?
  140. if ( CanMove(pSprite, pXSprite->target, pSprite->ang + dang, avoidDist) )
  141. {
  142. pXSprite->goalAng = (pSprite->ang + dang) & kAngleMask;
  143. }
  144. // clear movement partially toward target?
  145. else if ( CanMove(pSprite, pXSprite->target, pSprite->ang + dang / 2, avoidDist) )
  146. {
  147. pXSprite->goalAng = (pSprite->ang + dang / 2) & kAngleMask;
  148. }
  149. // try turning in target direction
  150. else if ( CanMove(pSprite, pXSprite->target, pSprite->ang + turnTo, avoidDist) )
  151. {
  152. pXSprite->goalAng = (pSprite->ang + turnTo) & kAngleMask;
  153. }
  154. // clear movement straight?
  155. else if ( CanMove(pSprite, pXSprite->target, pSprite->ang, avoidDist) )
  156. {
  157. pXSprite->goalAng = pSprite->ang;
  158. }
  159. // try turning away
  160. else if ( CanMove(pSprite, pXSprite->target, pSprite->ang - turnTo, avoidDist) )
  161. {
  162. pXSprite->goalAng = (pSprite->ang - turnTo) & kAngleMask;
  163. }
  164. else
  165. {
  166. // just turn around
  167. pXSprite->goalAng = (pSprite->ang + kAngle180) & kAngleMask;
  168. }
  169. // choose dodge direction
  170. pXSprite->dodgeDir = Chance(0x8000) ? 1 : -1;
  171. if ( !CanMove(pSprite, pXSprite->target, pSprite->ang + kAngle90 * pXSprite->dodgeDir,
  172. pDudeInfo->sideSpeed * 90 >> 4) )
  173. {
  174. pXSprite->dodgeDir = -pXSprite->dodgeDir;
  175. if ( !CanMove(pSprite, pXSprite->target, pSprite->ang + kAngle90 * pXSprite->dodgeDir,
  176. pDudeInfo->sideSpeed * 90 >> 4) )
  177. pXSprite->dodgeDir = 0;
  178. }
  179. // pSprite->zvel = (short)(dz >> 8);
  180. }
  181. void aiMoveForward( SPRITE *pSprite, XSPRITE *pXSprite )
  182. {
  183. dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
  184. DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
  185. pXSprite->moveState = kMoveWalk;
  186. int dang = ((kAngle180 + pXSprite->goalAng - pSprite->ang) & kAngleMask) - kAngle180;
  187. int maxTurn = pDudeInfo->angSpeed * kFrameTicks >> 4;
  188. pSprite->ang = (short)((pSprite->ang + ClipRange(dang, -maxTurn, maxTurn)) & kAngleMask);
  189. int accel = (pDudeInfo->frontAccel + kGroundFriction) * kFrameTicks;
  190. // don't move forward if trying to turn around
  191. if ( qabs(dang) > kAngle60 )
  192. return;
  193. long sin = Sin(pSprite->ang);
  194. long cos = Cos(pSprite->ang);
  195. // find vel and svel relative to current angle
  196. long vel = dmulscale30(pSprite->xvel, cos, pSprite->yvel, sin);
  197. long svel = dmulscale30(pSprite->xvel, sin, -pSprite->yvel, cos);
  198. // acceleration
  199. if ( accel > 0 )
  200. {
  201. if ( vel < pDudeInfo->frontSpeed )
  202. vel = ClipHigh(vel + accel, pDudeInfo->frontSpeed);
  203. }
  204. else
  205. {
  206. if ( vel > -pDudeInfo->backSpeed )
  207. vel = ClipLow(vel + accel, pDudeInfo->backSpeed);
  208. }
  209. // reconstruct x and y velocities
  210. pSprite->xvel = (short)dmulscale30(vel, cos, svel, sin);
  211. pSprite->yvel = (short)dmulscale30(vel, sin, -svel, cos);
  212. }
  213. void aiMoveTurn( SPRITE *pSprite, XSPRITE *pXSprite )
  214. {
  215. dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
  216. DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
  217. pXSprite->moveState = kMoveWalk;
  218. int dang = ((kAngle180 + pXSprite->goalAng - pSprite->ang) & kAngleMask) - kAngle180;
  219. int maxTurn = pDudeInfo->angSpeed * kFrameTicks >> 4;
  220. pSprite->ang = (short)((pSprite->ang + ClipRange(dang, -maxTurn, maxTurn)) & kAngleMask);
  221. }
  222. void aiMoveDodge( SPRITE *pSprite, XSPRITE *pXSprite )
  223. {
  224. dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
  225. DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
  226. pXSprite->moveState = kMoveWalk;
  227. int dang = ((kAngle180 + pXSprite->goalAng - pSprite->ang) & kAngleMask) - kAngle180;
  228. int maxTurn = pDudeInfo->angSpeed * kFrameTicks >> 4;
  229. pSprite->ang = (short)((pSprite->ang + ClipRange(dang, -maxTurn, maxTurn)) & kAngleMask);
  230. if ( pXSprite->dodgeDir == 0 )
  231. return;
  232. int accel = (pDudeInfo->sideAccel + kGroundFriction) * kFrameTicks;
  233. long sin = Sin(pSprite->ang);
  234. long cos = Cos(pSprite->ang);
  235. // find vel and svel relative to current angle
  236. long vel = dmulscale30(pSprite->xvel, cos, pSprite->yvel, sin);
  237. long svel = dmulscale30(pSprite->xvel, sin, -pSprite->yvel, cos);
  238. if ( pXSprite->dodgeDir > 0 )
  239. {
  240. if ( svel < pDudeInfo->sideSpeed )
  241. svel = ClipHigh(svel + accel, pDudeInfo->sideSpeed);
  242. }
  243. else
  244. {
  245. if ( svel > -pDudeInfo->sideSpeed )
  246. svel = ClipLow(svel - accel, -pDudeInfo->sideSpeed);
  247. }
  248. // reconstruct x and y velocities
  249. pSprite->xvel = (short)dmulscale30(vel, cos, svel, sin);
  250. pSprite->yvel = (short)dmulscale30(vel, sin, -svel, cos);
  251. }
  252. void aiActivateDude( SPRITE *pSprite, XSPRITE *pXSprite )
  253. {
  254. dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
  255. DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
  256. if ( pXSprite->state == 0 )
  257. {
  258. // this doesn't take into account sprites triggered w/o a target location....
  259. int nAngle = getangle(pXSprite->targetX - pSprite->x, pXSprite->targetY - pSprite->y);
  260. aiChooseDirection(pSprite, pXSprite, nAngle);
  261. pXSprite->state = 1;
  262. }
  263. switch ( pSprite->type )
  264. {
  265. case kDudeTommyCultist:
  266. case kDudeShotgunCultist:
  267. if (pXSprite->target == -1)
  268. aiNewState(pSprite, pXSprite, &cultistSearch);
  269. else
  270. aiNewState(pSprite, pXSprite, &cultistChase);
  271. break;
  272. case kDudeAxeZombie:
  273. if (pXSprite->target == -1)
  274. aiNewState(pSprite, pXSprite, &zombieASearch);
  275. else
  276. aiNewState(pSprite, pXSprite, &zombieAChase);
  277. break;
  278. case kDudeEarthZombie:
  279. if (pXSprite->aiState == &zombieEIdle)
  280. aiNewState(pSprite, pXSprite, &zombieEUp);
  281. break;
  282. case kDudeFatZombie:
  283. if (pXSprite->target == -1)
  284. aiNewState(pSprite, pXSprite, &zombieFSearch);
  285. else
  286. aiNewState(pSprite, pXSprite, &zombieFChase);
  287. break;
  288. case kDudeFleshStatue:
  289. aiNewState(pSprite, pXSprite, &gargoyleFMorph);
  290. break;
  291. case kDudeStoneStatue:
  292. // seqSpawn(pDudeInfo->seqStartID + kSeqStoneStatueTurn, SS_SPRITE, pSprite->extra);
  293. pSprite->type = kDudeStoneGargoyle;
  294. break;
  295. case kDudeHound:
  296. if (pXSprite->target == -1)
  297. aiNewState(pSprite, pXSprite, &houndSearch);
  298. else
  299. aiNewState(pSprite, pXSprite, &houndChase);
  300. break;
  301. case kDudeHand:
  302. if (pXSprite->target == -1)
  303. aiNewState(pSprite, pXSprite, &handSearch);
  304. else
  305. aiNewState(pSprite, pXSprite, &handChase);
  306. break;
  307. case kDudeRat:
  308. if (pXSprite->target == -1)
  309. aiNewState(pSprite, pXSprite, &ratSearch);
  310. else
  311. aiNewState(pSprite, pXSprite, &ratChase);
  312. break;
  313. case kDudeBrownSpider:
  314. case kDudeRedSpider:
  315. case kDudeBlackSpider:
  316. case kDudeMotherSpider:
  317. pSprite->flags |= kAttrGravity;
  318. pSprite->cstat &= ~kSpriteFlipY;
  319. if (pXSprite->target == -1)
  320. aiNewState(pSprite, pXSprite, &spidSearch);
  321. else
  322. aiNewState(pSprite, pXSprite, &spidChase);
  323. break;
  324. }
  325. }
  326. /*******************************************************************************
  327. FUNCTION: aiSetTarget()
  328. DESCRIPTION: Target a location (as opposed to a sprite)
  329. *******************************************************************************/
  330. void aiSetTarget( XSPRITE *pXSprite, int x, int y, int z )
  331. {
  332. pXSprite->target = -1;
  333. pXSprite->targetX = x;
  334. pXSprite->targetY = y;
  335. pXSprite->targetZ = z;
  336. }
  337. void aiSetTarget( XSPRITE *pXSprite, int nTarget )
  338. {
  339. dassert(nTarget >= 0 && nTarget < kMaxSprites);
  340. SPRITE *pTarget = &sprite[nTarget];
  341. if ( pTarget->type < kDudeBase || pTarget->type >= kDudeMax )
  342. return;
  343. if ( nTarget == sprite[pXSprite->reference].owner )
  344. {
  345. dprintf("aiSetTarget: skipping owner\n");
  346. return;
  347. }
  348. // dassert(pTarget->type >= kDudeBase && pTarget->type < kDudeMax);
  349. DUDEINFO *pTargetInfo = &dudeInfo[pTarget->type - kDudeBase];
  350. pXSprite->target = nTarget;
  351. pXSprite->targetX = pTarget->x;
  352. pXSprite->targetY = pTarget->y;
  353. pXSprite->targetZ = pTarget->z - (pTargetInfo->eyeHeight * pTarget->yrepeat << 2);
  354. }
  355. void aiDamageSprite( SPRITE *pSprite, XSPRITE *pXSprite, int nSource, DAMAGE_TYPE nDamageType, int nDamage )
  356. {
  357. (void)nDamageType;
  358. dassert(nSource < kMaxSprites);
  359. if (pXSprite->health == 0)
  360. return;
  361. cumulDamage[pSprite->extra] += nDamage; // add to cumulative damage
  362. DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
  363. if (nSource >= 0 && nSource != pXSprite->reference)
  364. {
  365. if (pXSprite->target == -1)
  366. {
  367. // give a dude a target
  368. aiSetTarget(pXSprite, nSource);
  369. aiActivateDude(pSprite, pXSprite);
  370. }
  371. else if (nSource != pXSprite->target)
  372. {
  373. // retarget
  374. int nThresh = nDamage;
  375. if ( sprite[nSource].type == pSprite->type )
  376. nThresh *= pDudeInfo->changeTargetKin;
  377. else
  378. nThresh *= pDudeInfo->changeTarget;
  379. if ( Chance(nThresh) )
  380. {
  381. aiSetTarget(pXSprite, nSource);
  382. aiActivateDude(pSprite, pXSprite);
  383. }
  384. }
  385. // you DO need special processing here or somewhere else (your choice) for dodging
  386. switch ( pSprite->type )
  387. {
  388. case kDudeTommyCultist:
  389. case kDudeShotgunCultist:
  390. // if (nDamage >= (pDudeInfo->hinderDamage << 2))
  391. aiNewState(pSprite, pXSprite, &cultistDodge);
  392. break;
  393. case kDudeFleshGargoyle:
  394. aiNewState(pSprite, pXSprite, &gargoyleFChase);
  395. break;
  396. default:
  397. break;
  398. }
  399. }
  400. }
  401. void RecoilDude( SPRITE *pSprite, XSPRITE *pXSprite )
  402. {
  403. dprintf("Recoiling dude\n");
  404. switch ( pSprite->type )
  405. {
  406. case kDudeTommyCultist:
  407. case kDudeShotgunCultist:
  408. aiNewState(pSprite, pXSprite, &cultistRecoil);
  409. break;
  410. case kDudeFatZombie:
  411. aiNewState(pSprite, pXSprite, &zombieFRecoil);
  412. break;
  413. case kDudeAxeZombie:
  414. case kDudeEarthZombie:
  415. aiNewState(pSprite, pXSprite, &zombieARecoil);
  416. break;
  417. case kDudeFleshGargoyle:
  418. aiNewState(pSprite, pXSprite, &gargoyleFRecoil);
  419. break;
  420. case kDudeHound:
  421. aiNewState(pSprite, pXSprite, &houndRecoil);
  422. break;
  423. case kDudeHand:
  424. aiNewState(pSprite, pXSprite, &handRecoil);
  425. break;
  426. case kDudeRat:
  427. aiNewState(pSprite, pXSprite, &handRecoil);
  428. break;
  429. case kDudeBrownSpider:
  430. case kDudeRedSpider:
  431. case kDudeBlackSpider:
  432. case kDudeMotherSpider:
  433. aiNewState(pSprite, pXSprite, &spidDodge);
  434. break;
  435. default:
  436. aiNewState(pSprite, pXSprite, &genRecoil);
  437. break;
  438. }
  439. }
  440. void aiThinkTarget( SPRITE *pSprite, XSPRITE *pXSprite )
  441. {
  442. dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
  443. DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
  444. if ( !Chance(pDudeInfo->alertChance) )
  445. return;
  446. for (int i = 0; i < numplayers; i++)
  447. {
  448. PLAYER *pPlayer = &gPlayer[i];
  449. // skip this player if the he owns the dude or is invisible
  450. if ( pSprite->owner == pPlayer->nSprite
  451. || pPlayer->xsprite->health == 0
  452. || powerupCheck( pPlayer, kItemLtdInvisibility - kItemBase ) > 0 )
  453. continue;
  454. int x = pPlayer->sprite->x;
  455. int y = pPlayer->sprite->y;
  456. int z = pPlayer->sprite->z;
  457. short nSector = pPlayer->sprite->sectnum;
  458. int dx = x - pSprite->x;
  459. int dy = y - pSprite->y;
  460. int dist = qdist(dx, dy);
  461. if ( dist <= pDudeInfo->seeDist || dist <= pDudeInfo->hearDist )
  462. {
  463. int eyeAboveZ = pDudeInfo->eyeHeight * pSprite->yrepeat << 2;
  464. // is there a line of sight to the player?
  465. if ( cansee(x, y, z, nSector, pSprite->x, pSprite->y, pSprite->z - eyeAboveZ,
  466. pSprite->sectnum) )
  467. {
  468. int nAngle = getangle(dx, dy);
  469. int losAngle = ((kAngle180 + nAngle - pSprite->ang) & kAngleMask) - kAngle180;
  470. // is the player visible?
  471. if ( dist < pDudeInfo->seeDist && qabs(losAngle) <= pDudeInfo->periphery )
  472. {
  473. aiSetTarget( pXSprite, pPlayer->nSprite );
  474. aiActivateDude( pSprite, pXSprite );
  475. return;
  476. }
  477. // we may want to make hearing a function of sensitivity, rather than distance
  478. if ( dist < pDudeInfo->hearDist )
  479. {
  480. aiSetTarget(pXSprite, x, y, z);
  481. aiActivateDude( pSprite, pXSprite );
  482. return;
  483. }
  484. }
  485. }
  486. }
  487. }
  488. void aiProcessDudes( void )
  489. {
  490. // process active sprites
  491. for (short nSprite = headspritestat[kStatDude]; nSprite >= 0; nSprite = nextspritestat[nSprite])
  492. {
  493. SPRITE *pSprite = &sprite[nSprite];
  494. int nXSprite = pSprite->extra;
  495. XSPRITE *pXSprite = &xsprite[nXSprite];
  496. DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
  497. // don't manipulate players or dead guys
  498. if (( pSprite->type >= kDudePlayer1 && pSprite->type <= kDudePlayer8 ) || ( pXSprite->health == 0 ))
  499. continue;
  500. pXSprite->stateTimer = ClipLow(pXSprite->stateTimer - kFrameTicks, 0);
  501. if ( pXSprite->aiState->move )
  502. pXSprite->aiState->move(pSprite, pXSprite);
  503. if ( pXSprite->aiState->think && (gFrame & kAIThinkMask) == (nSprite & kAIThinkMask) )
  504. pXSprite->aiState->think(pSprite, pXSprite);
  505. if ( pXSprite->stateTimer == 0 && pXSprite->aiState->next != NULL )
  506. {
  507. if ( pXSprite->aiState->ticks > 0 )
  508. aiNewState(pSprite, pXSprite, pXSprite->aiState->next);
  509. else if ( seqGetStatus(SS_SPRITE, nXSprite) < 0 )
  510. aiNewState(pSprite, pXSprite, pXSprite->aiState->next);
  511. }
  512. // process dudes for recoil
  513. if ( cumulDamage[nXSprite] >= pDudeInfo->hinderDamage << 4 )
  514. RecoilDude(pSprite, pXSprite);
  515. }
  516. // reset the cumulative damages for the next frame
  517. memset(cumulDamage, 0, sizeof(cumulDamage));
  518. /*
  519. // special processing for converting dude types
  520. switch ( pSprite->type )
  521. {
  522. case kDudeCerberus:
  523. if ( pXSprite->health <= 0 && seqGetStatus(SS_SPRITE, nXSprite) < 0 ) // head #1 finished dying?
  524. {
  525. pXSprite->health = dudeInfo[kDudeCerberus2 - kDudeBase].startHealth << 4;
  526. pSprite->type = kDudeCerberus2; // change his type
  527. // aiActivateDude(pSprite, pXSprite); // reactivate him
  528. }
  529. break;
  530. }
  531. */
  532. }
  533. /*******************************************************************************
  534. FUNCTION: aiInit()
  535. DESCRIPTION:
  536. PARAMETERS: void
  537. RETURNS: void
  538. NOTES:
  539. *******************************************************************************/
  540. void aiInit( void )
  541. {
  542. for (short nSprite = headspritestat[kStatDude]; nSprite >= 0; nSprite = nextspritestat[nSprite])
  543. {
  544. SPRITE *pDude = &sprite[nSprite];
  545. XSPRITE *pXDude = &xsprite[pDude->extra];
  546. switch ( pDude->type )
  547. {
  548. case kDudeTommyCultist:
  549. case kDudeShotgunCultist:
  550. aiNewState(pDude, pXDude, &cultistIdle);
  551. break;
  552. case kDudeFatZombie:
  553. aiNewState(pDude, pXDude, &zombieFIdle);
  554. break;
  555. case kDudeAxeZombie:
  556. aiNewState(pDude, pXDude, &zombieAIdle);
  557. break;
  558. case kDudeEarthZombie:
  559. aiNewState(pDude, pXDude, &zombieEIdle);
  560. pDude->flags &= ~kAttrMove;
  561. break;
  562. case kDudeFleshGargoyle:
  563. aiNewState(pDude, pXDude, &gargoyleFIdle);
  564. break;
  565. case kDudeHound:
  566. aiNewState(pDude, pXDude, &houndIdle);
  567. break;
  568. case kDudeHand:
  569. aiNewState(pDude, pXDude, &handIdle);
  570. break;
  571. case kDudeRat:
  572. aiNewState(pDude, pXDude, &ratIdle);
  573. break;
  574. case kDudeBrownSpider:
  575. case kDudeRedSpider:
  576. case kDudeBlackSpider:
  577. case kDudeMotherSpider:
  578. aiNewState(pDude, pXDude, &spidIdle);
  579. break;
  580. default:
  581. aiNewState(pDude, pXDude, &genIdle);
  582. break;
  583. }
  584. aiSetTarget(pXDude, 0, 0, 0);
  585. pXDude->stateTimer = 0;
  586. switch ( pDude->type )
  587. {
  588. case kDudeBrownSpider:
  589. case kDudeRedSpider:
  590. case kDudeBlackSpider:
  591. if ( pDude->cstat & kSpriteFlipY )
  592. pDude->flags &= ~kAttrGravity;
  593. break;
  594. case kDudeBat:
  595. case kDudeFleshGargoyle:
  596. case kDudeStoneGargoyle:
  597. case kDudePhantasm:
  598. pDude->flags &= ~kAttrGravity;
  599. break;
  600. }
  601. }
  602. }