C5_STATE.C 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. /* Catacomb Armageddon Source Code
  2. * Copyright (C) 1993-2014 Flat Rock Software
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along
  15. * with this program; if not, write to the Free Software Foundation, Inc.,
  16. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  17. */
  18. // C3_STATE.C
  19. #include "DEF.H"
  20. #pragma hdrstop
  21. /*
  22. =============================================================================
  23. LOCAL CONSTANTS
  24. =============================================================================
  25. */
  26. /*
  27. =============================================================================
  28. GLOBAL VARIABLES
  29. =============================================================================
  30. */
  31. /*
  32. =============================================================================
  33. LOCAL VARIABLES
  34. =============================================================================
  35. */
  36. dirtype opposite[9] =
  37. {south,west,north,east,southwest,northwest,northeast,southeast,nodir};
  38. //===========================================================================
  39. /*
  40. ===================
  41. =
  42. = Internal_SpawnNewObj
  43. =
  44. ===================
  45. */
  46. void Internal_SpawnNewObj (unsigned x, unsigned y, statetype *state, unsigned size, boolean UseDummy, boolean PutInActorat)
  47. {
  48. extern objtype dummyobj;
  49. GetNewObj(UseDummy);
  50. new->size = size;
  51. new->state = state;
  52. new->ticcount = random (state->tictime)+1;
  53. new->tilex = x;
  54. new->tiley = y;
  55. new->x = ((long)x<<TILESHIFT)+TILEGLOBAL/2;
  56. new->y = ((long)y<<TILESHIFT)+TILEGLOBAL/2;
  57. CalcBounds(new);
  58. new->dir = nodir;
  59. new->active = noalways;
  60. if (new != &dummyobj && PutInActorat)
  61. actorat[new->tilex][new->tiley] = new;
  62. }
  63. void Internal_SpawnNewObjFrac (long x, long y, statetype *state, unsigned size,boolean UseDummy)
  64. {
  65. GetNewObj(UseDummy);
  66. new->size = size;
  67. new->state = state;
  68. new->ticcount = random (state->tictime)+1;
  69. new->active = noalways;
  70. new->x = x;
  71. new->y = y;
  72. new->tilex = x>>TILESHIFT;
  73. new->tiley = y>>TILESHIFT;
  74. CalcBounds(new);
  75. new->distance = 100;
  76. new->dir = nodir;
  77. }
  78. /*
  79. ===================
  80. =
  81. = CheckHandAttack
  82. =
  83. = If the object can move next to the player, it will return true
  84. =
  85. ===================
  86. */
  87. boolean CheckHandAttack (objtype *ob)
  88. {
  89. long deltax,deltay,size;
  90. size = (long)ob->size + player->size + ob->speed*tics + SIZE_TEST;
  91. deltax = ob->x - player->x;
  92. deltay = ob->y - player->y;
  93. if (deltax > size || deltax < -size || deltay > size || deltay < -size)
  94. return false;
  95. return true;
  96. }
  97. /*
  98. ===================
  99. =
  100. = T_DoDamage
  101. =
  102. = Attacks the player if still nearby, then immediately changes to next state
  103. =
  104. ===================
  105. */
  106. void T_DoDamage (objtype *ob)
  107. {
  108. int points;
  109. if (CheckHandAttack(ob) && (!(ob->flags & of_damagedone)))
  110. {
  111. points = 0;
  112. switch (ob->obclass)
  113. {
  114. case zombieobj:
  115. case fatdemonobj:
  116. points = 8;
  117. break;
  118. case reddemonobj:
  119. case godessobj:
  120. points = 15;
  121. break;
  122. case antobj:
  123. points = 2;
  124. break;
  125. case skeletonobj:
  126. points = 6;
  127. break;
  128. case wetobj:
  129. points = 7;
  130. break;
  131. case treeobj:
  132. points = 7;
  133. break;
  134. case bunnyobj:
  135. points = 4;
  136. break;
  137. }
  138. TakeDamage (points);
  139. ob->flags |= of_damagedone;
  140. }
  141. }
  142. //==========================================================================
  143. /*
  144. ==================================
  145. =
  146. = Walk
  147. =
  148. ==================================
  149. */
  150. boolean Walk (objtype *ob)
  151. {
  152. switch (ob->dir)
  153. {
  154. case north:
  155. if (actorat[ob->tilex][ob->tiley-1])
  156. return false;
  157. ob->tiley--;
  158. ob->distance = TILEGLOBAL;
  159. return true;
  160. case northeast:
  161. if (actorat[ob->tilex+1][ob->tiley-1])
  162. return false;
  163. ob->tilex++;
  164. ob->tiley--;
  165. ob->distance = TILEGLOBAL;
  166. return true;
  167. case east:
  168. if (actorat[ob->tilex+1][ob->tiley])
  169. return false;
  170. ob->tilex++;
  171. ob->distance = TILEGLOBAL;
  172. return true;
  173. case southeast:
  174. if (actorat[ob->tilex+1][ob->tiley+1])
  175. return false;
  176. ob->tilex++;
  177. ob->tiley++;
  178. ob->distance = TILEGLOBAL;
  179. return true;
  180. case south:
  181. if (actorat[ob->tilex][ob->tiley+1])
  182. return false;
  183. ob->tiley++;
  184. ob->distance = TILEGLOBAL;
  185. return true;
  186. case southwest:
  187. if (actorat[ob->tilex-1][ob->tiley+1])
  188. return false;
  189. ob->tilex--;
  190. ob->tiley++;
  191. ob->distance = TILEGLOBAL;
  192. return true;
  193. case west:
  194. if (actorat[ob->tilex-1][ob->tiley])
  195. return false;
  196. ob->tilex--;
  197. ob->distance = TILEGLOBAL;
  198. return true;
  199. case northwest:
  200. if (actorat[ob->tilex-1][ob->tiley-1])
  201. return false;
  202. ob->tilex--;
  203. ob->tiley--;
  204. ob->distance = TILEGLOBAL;
  205. return true;
  206. case nodir:
  207. return false;
  208. }
  209. Quit ("Walk: Bad dir");
  210. return false;
  211. }
  212. /*
  213. ==================================
  214. =
  215. = ChaseThink
  216. = have the current monster go after the player,
  217. = either diagonally or straight on
  218. =
  219. ==================================
  220. */
  221. void ChaseThink (objtype *obj, boolean diagonal)
  222. {
  223. int deltax,deltay,i;
  224. dirtype d[3];
  225. dirtype tdir, olddir, turnaround;
  226. olddir=obj->dir;
  227. turnaround=opposite[olddir];
  228. deltax=player->tilex - obj->tilex;
  229. deltay=player->tiley - obj->tiley;
  230. d[1]=nodir;
  231. d[2]=nodir;
  232. if (deltax>0)
  233. d[1]= east;
  234. if (deltax<0)
  235. d[1]= west;
  236. if (deltay>0)
  237. d[2]=south;
  238. if (deltay<0)
  239. d[2]=north;
  240. if (abs(deltay)>abs(deltax))
  241. {
  242. tdir=d[1];
  243. d[1]=d[2];
  244. d[2]=tdir;
  245. }
  246. if (d[1]==turnaround)
  247. d[1]=nodir;
  248. if (d[2]==turnaround)
  249. d[2]=nodir;
  250. if (diagonal)
  251. { /*ramdiagonals try the best dir first*/
  252. if (d[1]!=nodir)
  253. {
  254. obj->dir=d[1];
  255. if (Walk(obj))
  256. return; /*either moved forward or attacked*/
  257. }
  258. if (d[2]!=nodir)
  259. {
  260. obj->dir=d[2];
  261. if (Walk(obj))
  262. return;
  263. }
  264. }
  265. else
  266. { /*ramstraights try the second best dir first*/
  267. if (d[2]!=nodir)
  268. {
  269. obj->dir=d[2];
  270. if (Walk(obj))
  271. return;
  272. }
  273. if (d[1]!=nodir)
  274. {
  275. obj->dir=d[1];
  276. if (Walk(obj))
  277. return;
  278. }
  279. }
  280. /* there is no direct path to the player, so pick another direction */
  281. obj->dir=olddir;
  282. if (Walk(obj))
  283. return;
  284. if (US_RndT()>128) /*randomly determine direction of search*/
  285. {
  286. for (tdir=north;tdir<=west;tdir++)
  287. {
  288. if (tdir!=turnaround)
  289. {
  290. obj->dir=tdir;
  291. if (Walk(obj))
  292. return;
  293. }
  294. }
  295. }
  296. else
  297. {
  298. for (tdir=west;tdir>=north;tdir--)
  299. {
  300. if (tdir!=turnaround)
  301. {
  302. obj->dir=tdir;
  303. if (Walk(obj))
  304. return;
  305. }
  306. }
  307. }
  308. obj->dir=turnaround;
  309. Walk(obj); /*last chance, don't worry about returned value*/
  310. }
  311. /*
  312. =================
  313. =
  314. = MoveObj
  315. =
  316. =================
  317. */
  318. void MoveObj (objtype *ob, long move)
  319. {
  320. ob->distance -=move;
  321. switch (ob->dir)
  322. {
  323. case north:
  324. ob->y -= move;
  325. return;
  326. case northeast:
  327. ob->x += move;
  328. ob->y -= move;
  329. return;
  330. case east:
  331. ob->x += move;
  332. return;
  333. case southeast:
  334. ob->x += move;
  335. ob->y += move;
  336. return;
  337. case south:
  338. ob->y += move;
  339. return;
  340. case southwest:
  341. ob->x -= move;
  342. ob->y += move;
  343. return;
  344. case west:
  345. ob->x -= move;
  346. return;
  347. case northwest:
  348. ob->x -= move;
  349. ob->y -= move;
  350. return;
  351. case nodir:
  352. return;
  353. }
  354. }
  355. /*
  356. =================
  357. =
  358. = Chase
  359. =
  360. = returns true if hand attack range
  361. =
  362. =================
  363. */
  364. boolean Chase (objtype *ob, boolean diagonal)
  365. {
  366. long move;
  367. long deltax,deltay,size;
  368. ob->flags &= ~of_damagedone;
  369. move = ob->speed*tics;
  370. size = (long)ob->size + player->size + move + SIZE_TEST;
  371. while (move)
  372. {
  373. deltax = ob->x - player->x;
  374. deltay = ob->y - player->y;
  375. if (deltax <= size && deltax >= -size
  376. && deltay <= size && deltay >= -size)
  377. {
  378. CalcBounds (ob);
  379. return true;
  380. }
  381. if (move < ob->distance)
  382. {
  383. MoveObj (ob,move);
  384. break;
  385. }
  386. actorat[ob->tilex][ob->tiley] = 0; // pick up marker from goal
  387. if (ob->dir == nodir)
  388. ob->dir = north;
  389. ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;
  390. ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;
  391. move -= ob->distance;
  392. ChaseThink (ob,diagonal);
  393. if (!ob->distance)
  394. break; // no possible move
  395. actorat[ob->tilex][ob->tiley] = ob; // set down a new goal marker
  396. }
  397. CalcBounds (ob);
  398. return false;
  399. }
  400. //===========================================================================
  401. /*
  402. ===================
  403. =
  404. = ShootActor
  405. =
  406. ===================
  407. */
  408. void ShootActor (objtype *ob, unsigned damage)
  409. {
  410. ob->hitpoints -= damage;
  411. if (ob->hitpoints<=0)
  412. {
  413. switch (ob->obclass)
  414. {
  415. case reddemonobj:
  416. ob->state = &s_red_demondie1;
  417. break;
  418. case succubusobj:
  419. ob->state = &s_succubus_death1;
  420. break;
  421. case fatdemonobj:
  422. ob->state = &s_fatdemon_blowup1;
  423. break;
  424. case godessobj:
  425. ob->state = &s_godessdie1;
  426. break;
  427. case mageobj:
  428. ob->state = &s_magedie1;
  429. break;
  430. case batobj:
  431. ob->state = &s_batdie1;
  432. #if USE_INERT_LIST
  433. ob->obclass = solidobj; // don't add this obj to inert list
  434. #endif
  435. break;
  436. case grelmobj:
  437. ob->state = &s_greldie1;
  438. break;
  439. case zombieobj:
  440. ob->state = &s_zombie_death1;
  441. break;
  442. case skeletonobj:
  443. ob->state = &s_skel_die1;
  444. break;
  445. case antobj:
  446. ob->state = &s_ant_die1;
  447. break;
  448. case wetobj:
  449. ob->state = &s_wet_die1;
  450. #if USE_INERT_LIST
  451. ob->obclass = solidobj; // don't add this obj to inert list
  452. #endif
  453. break;
  454. case eyeobj:
  455. ob->state = &s_eye_die1;
  456. break;
  457. case sshotobj:
  458. case eshotobj:
  459. case mshotobj:
  460. ob->state = &s_bonus_die;
  461. #if USE_INERT_LIST
  462. ob->obclass = solidobj; // don't add these objs to inert list
  463. #endif
  464. break;
  465. case treeobj:
  466. ob->state = &s_tree_death1;
  467. ob->obclass = solidobj;
  468. ob->temp1 = 3;
  469. ob->flags &= ~of_damagedone;
  470. CalcBounds(ob);
  471. break;
  472. case bunnyobj:
  473. ob->state = &s_bunny_death1;
  474. break;
  475. case bonusobj:
  476. case freezeobj:
  477. switch (ob->temp1)
  478. {
  479. case B_POTION:
  480. case B_CHEST:
  481. case B_NUKE:
  482. case B_BOLT:
  483. ob->state = &s_pshot_exp1;
  484. ob->obclass = expobj;
  485. ob->ticcount = ob->state->tictime;
  486. SpawnBigExplosion(ob->x,ob->y,12,(16l<<16L));
  487. bordertime = FLASHTICS<<2;
  488. bcolor = 14;
  489. VW_ColorBorder(14 | 56);
  490. DisplaySMsg("Item destroyed", NULL);
  491. status_flag = S_NONE;
  492. status_delay = 80;
  493. break;
  494. }
  495. #if USE_INERT_LIST
  496. ob->obclass = solidobj; // don't add this obj to inert list
  497. #endif
  498. break;
  499. }
  500. if (ob->obclass != solidobj && ob->obclass != realsolidobj)
  501. {
  502. ob->obclass = inertobj;
  503. ob->flags &= ~of_shootable;
  504. actorat[ob->tilex][ob->tiley] = NULL;
  505. #if USE_INERT_LIST
  506. MoveObjToInert(ob);
  507. #endif
  508. }
  509. else
  510. {
  511. if (ob->flags & of_forcefield)
  512. {
  513. ob->state = &s_force_field_die;
  514. ob->flags &= ~of_shootable;
  515. }
  516. }
  517. }
  518. else
  519. {
  520. switch (ob->obclass)
  521. {
  522. case reddemonobj:
  523. if (!(random(8)))
  524. ob->state = &s_red_demonouch;
  525. else
  526. return;
  527. break;
  528. case succubusobj:
  529. ob->state = &s_succubus_ouch;
  530. break;
  531. case fatdemonobj:
  532. ob->state = &s_fatdemon_ouch;
  533. break;
  534. case godessobj:
  535. ob->state = &s_godessouch;
  536. break;
  537. case mageobj:
  538. ob->state = &s_mageouch;
  539. break;
  540. case grelmobj:
  541. ob->state = &s_grelouch;
  542. break;
  543. case zombieobj:
  544. ob->state = &s_zombie_ouch;
  545. break;
  546. case antobj:
  547. ob->state = &s_ant_ouch;
  548. break;
  549. case skeletonobj:
  550. ob->state = &s_skel_ouch;
  551. break;
  552. case wetobj:
  553. ob->state = &s_wet_ouch;
  554. break;
  555. case eyeobj:
  556. ob->state = &s_eye_ouch;
  557. break;
  558. case treeobj:
  559. ob->state = &s_tree_ouch;
  560. break;
  561. case bunnyobj:
  562. ob->state = &s_bunny_ouch;
  563. break;
  564. }
  565. }
  566. ob->ticcount = ob->state->tictime;
  567. }