shots.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170
  1. /* $NetBSD: shots.c,v 1.5 2004/01/27 20:30:29 jsm Exp $ */
  2. /*
  3. * Copyright (c) 1983-2003, Regents of the University of California.
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions are
  8. * met:
  9. *
  10. * + Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * + Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * + Neither the name of the University of California, San Francisco nor
  16. * the names of its contributors may be used to endorse or promote
  17. * products derived from this software without specific prior written
  18. * permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  21. * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  22. * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  23. * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. */
  32. #include <sys/cdefs.h>
  33. #ifndef lint
  34. __RCSID("$NetBSD: shots.c,v 1.5 2004/01/27 20:30:29 jsm Exp $");
  35. #endif /* not lint */
  36. # include <err.h>
  37. # include <signal.h>
  38. # include <stdlib.h>
  39. # include "hunt.h"
  40. # define PLUS_DELTA(x, max) if (x < max) x++; else x--
  41. # define MINUS_DELTA(x, min) if (x > min) x--; else x++
  42. static void chkshot(BULLET *, BULLET *);
  43. static void chkslime(BULLET *, BULLET *);
  44. static void explshot(BULLET *, int, int);
  45. static void find_under(BULLET *, BULLET *);
  46. static int iswall(int, int);
  47. static void mark_boot(BULLET *);
  48. static void mark_player(BULLET *);
  49. #ifdef DRONE
  50. static void move_drone(BULLET *);
  51. #endif
  52. static void move_flyer(PLAYER *);
  53. static int move_normal_shot(BULLET *);
  54. static void move_slime(BULLET *, int, BULLET *);
  55. static void save_bullet(BULLET *);
  56. static void zapshot(BULLET *, BULLET *);
  57. /*
  58. * moveshots:
  59. * Move the shots already in the air, taking explosions into account
  60. */
  61. void
  62. moveshots()
  63. {
  64. BULLET *bp, *next;
  65. PLAYER *pp;
  66. int x, y;
  67. BULLET *blist;
  68. rollexpl();
  69. if (Bullets == NULL)
  70. goto ret;
  71. /*
  72. * First we move through the bullet list BULSPD times, looking
  73. * for things we may have run into. If we do run into
  74. * something, we set up the explosion and disappear, checking
  75. * for damage to any player who got in the way.
  76. */
  77. blist = Bullets;
  78. Bullets = NULL;
  79. for (bp = blist; bp != NULL; bp = next) {
  80. next = bp->b_next;
  81. x = bp->b_x;
  82. y = bp->b_y;
  83. Maze[y][x] = bp->b_over;
  84. for (pp = Player; pp < End_player; pp++)
  85. check(pp, y, x);
  86. # ifdef MONITOR
  87. for (pp = Monitor; pp < End_monitor; pp++)
  88. check(pp, y, x);
  89. # endif
  90. switch (bp->b_type) {
  91. case SHOT:
  92. case GRENADE:
  93. case SATCHEL:
  94. case BOMB:
  95. if (move_normal_shot(bp)) {
  96. bp->b_next = Bullets;
  97. Bullets = bp;
  98. }
  99. break;
  100. # ifdef OOZE
  101. case SLIME:
  102. if (bp->b_expl || move_normal_shot(bp)) {
  103. bp->b_next = Bullets;
  104. Bullets = bp;
  105. }
  106. break;
  107. # endif
  108. # ifdef DRONE
  109. case DSHOT:
  110. if (move_drone(bp)) {
  111. bp->b_next = Bullets;
  112. Bullets = bp;
  113. }
  114. break;
  115. # endif
  116. default:
  117. bp->b_next = Bullets;
  118. Bullets = bp;
  119. break;
  120. }
  121. }
  122. blist = Bullets;
  123. Bullets = NULL;
  124. for (bp = blist; bp != NULL; bp = next) {
  125. next = bp->b_next;
  126. if (!bp->b_expl) {
  127. save_bullet(bp);
  128. # ifdef MONITOR
  129. for (pp = Monitor; pp < End_monitor; pp++)
  130. check(pp, bp->b_y, bp->b_x);
  131. # endif
  132. # ifdef DRONE
  133. if (bp->b_type == DSHOT)
  134. for (pp = Player; pp < End_player; pp++)
  135. if (pp->p_scan >= 0)
  136. check(pp, bp->b_y, bp->b_x);
  137. # endif
  138. continue;
  139. }
  140. chkshot(bp, next);
  141. free((char *) bp);
  142. }
  143. for (pp = Player; pp < End_player; pp++)
  144. Maze[pp->p_y][pp->p_x] = pp->p_face;
  145. ret:
  146. # ifdef BOOTS
  147. for (pp = Boot; pp < &Boot[NBOOTS]; pp++)
  148. if (pp->p_flying >= 0)
  149. move_flyer(pp);
  150. # endif
  151. for (pp = Player; pp < End_player; pp++) {
  152. # ifdef FLY
  153. if (pp->p_flying >= 0)
  154. move_flyer(pp);
  155. # endif
  156. sendcom(pp, REFRESH); /* Flush out the explosions */
  157. look(pp);
  158. sendcom(pp, REFRESH);
  159. }
  160. # ifdef MONITOR
  161. for (pp = Monitor; pp < End_monitor; pp++)
  162. sendcom(pp, REFRESH);
  163. # endif
  164. return;
  165. }
  166. /*
  167. * move_normal_shot:
  168. * Move a normal shot along its trajectory
  169. */
  170. static int
  171. move_normal_shot(bp)
  172. BULLET *bp;
  173. {
  174. int i, x, y;
  175. PLAYER *pp;
  176. for (i = 0; i < BULSPD; i++) {
  177. if (bp->b_expl)
  178. break;
  179. x = bp->b_x;
  180. y = bp->b_y;
  181. switch (bp->b_face) {
  182. case LEFTS:
  183. x--;
  184. break;
  185. case RIGHT:
  186. x++;
  187. break;
  188. case ABOVE:
  189. y--;
  190. break;
  191. case BELOW:
  192. y++;
  193. break;
  194. }
  195. switch (Maze[y][x]) {
  196. case SHOT:
  197. if (rand_num(100) < 5) {
  198. zapshot(Bullets, bp);
  199. zapshot(bp->b_next, bp);
  200. }
  201. break;
  202. case GRENADE:
  203. if (rand_num(100) < 10) {
  204. zapshot(Bullets, bp);
  205. zapshot(bp->b_next, bp);
  206. }
  207. break;
  208. # ifdef REFLECT
  209. case WALL4: /* reflecting walls */
  210. switch (bp->b_face) {
  211. case LEFTS:
  212. bp->b_face = BELOW;
  213. break;
  214. case RIGHT:
  215. bp->b_face = ABOVE;
  216. break;
  217. case ABOVE:
  218. bp->b_face = RIGHT;
  219. break;
  220. case BELOW:
  221. bp->b_face = LEFTS;
  222. break;
  223. }
  224. Maze[y][x] = WALL5;
  225. # ifdef MONITOR
  226. for (pp = Monitor; pp < End_monitor; pp++)
  227. check(pp, y, x);
  228. # endif
  229. break;
  230. case WALL5:
  231. switch (bp->b_face) {
  232. case LEFTS:
  233. bp->b_face = ABOVE;
  234. break;
  235. case RIGHT:
  236. bp->b_face = BELOW;
  237. break;
  238. case ABOVE:
  239. bp->b_face = LEFTS;
  240. break;
  241. case BELOW:
  242. bp->b_face = RIGHT;
  243. break;
  244. }
  245. Maze[y][x] = WALL4;
  246. # ifdef MONITOR
  247. for (pp = Monitor; pp < End_monitor; pp++)
  248. check(pp, y, x);
  249. # endif
  250. break;
  251. # endif
  252. # ifdef RANDOM
  253. case DOOR:
  254. switch (rand_num(4)) {
  255. case 0:
  256. bp->b_face = ABOVE;
  257. break;
  258. case 1:
  259. bp->b_face = BELOW;
  260. break;
  261. case 2:
  262. bp->b_face = LEFTS;
  263. break;
  264. case 3:
  265. bp->b_face = RIGHT;
  266. break;
  267. }
  268. break;
  269. # endif
  270. # ifdef FLY
  271. case FLYER:
  272. pp = play_at(y, x);
  273. message(pp, "Zing!");
  274. break;
  275. # endif
  276. case LEFTS:
  277. case RIGHT:
  278. case BELOW:
  279. case ABOVE:
  280. /*
  281. * give the person a chance to catch a
  282. * grenade if s/he is facing it
  283. */
  284. pp = play_at(y, x);
  285. pp->p_ident->i_shot += bp->b_charge;
  286. if (opposite(bp->b_face, Maze[y][x])) {
  287. if (rand_num(100) < 10) {
  288. if (bp->b_owner != NULL)
  289. message(bp->b_owner,
  290. "Your charge was absorbed!");
  291. if (bp->b_score != NULL)
  292. bp->b_score->i_robbed += bp->b_charge;
  293. pp->p_ammo += bp->b_charge;
  294. if (pp->p_damage + bp->b_size * MINDAM
  295. > pp->p_damcap)
  296. pp->p_ident->i_saved++;
  297. message(pp, "Absorbed charge (good shield!)");
  298. pp->p_ident->i_absorbed += bp->b_charge;
  299. free((char *) bp);
  300. (void) sprintf(Buf, "%3d", pp->p_ammo);
  301. cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL);
  302. outstr(pp, Buf, 3);
  303. return FALSE;
  304. }
  305. pp->p_ident->i_faced += bp->b_charge;
  306. }
  307. /*
  308. * Small chance that the bullet just misses the
  309. * person. If so, the bullet just goes on its
  310. * merry way without exploding.
  311. */
  312. if (rand_num(100) < 5) {
  313. pp->p_ident->i_ducked += bp->b_charge;
  314. if (pp->p_damage + bp->b_size * MINDAM
  315. > pp->p_damcap)
  316. pp->p_ident->i_saved++;
  317. if (bp->b_score != NULL)
  318. bp->b_score->i_missed += bp->b_charge;
  319. message(pp, "Zing!");
  320. if (bp->b_owner == NULL)
  321. break;
  322. message(bp->b_owner,
  323. ((bp->b_score->i_missed & 0x7) == 0x7) ?
  324. "My! What a bad shot you are!" :
  325. "Missed him");
  326. break;
  327. }
  328. /*
  329. * The shot hit that sucker! Blow it up.
  330. */
  331. /* FALLTHROUGH */
  332. # ifndef RANDOM
  333. case DOOR:
  334. # endif
  335. case WALL1:
  336. case WALL2:
  337. case WALL3:
  338. bp->b_expl = TRUE;
  339. break;
  340. }
  341. bp->b_x = x;
  342. bp->b_y = y;
  343. }
  344. return TRUE;
  345. }
  346. # ifdef DRONE
  347. /*
  348. * move_drone:
  349. * Move the drone to the next square
  350. */
  351. static void
  352. move_drone(bp)
  353. BULLET *bp;
  354. {
  355. int mask, count;
  356. int n, dir;
  357. PLAYER *pp;
  358. /*
  359. * See if we can give someone a blast
  360. */
  361. if (is_player(Maze[bp->b_y][bp->b_x - 1])) {
  362. dir = WEST;
  363. goto drone_move;
  364. }
  365. if (is_player(Maze[bp->b_y - 1][bp->b_x])) {
  366. dir = NORTH;
  367. goto drone_move;
  368. }
  369. if (is_player(Maze[bp->b_y + 1][bp->b_x])) {
  370. dir = SOUTH;
  371. goto drone_move;
  372. }
  373. if (is_player(Maze[bp->b_y][bp->b_x + 1])) {
  374. dir = EAST;
  375. goto drone_move;
  376. }
  377. /*
  378. * Find out what directions are clear
  379. */
  380. mask = count = 0;
  381. if (!iswall(bp->b_y, bp->b_x - 1))
  382. mask |= WEST, count++;
  383. if (!iswall(bp->b_y - 1, bp->b_x))
  384. mask |= NORTH, count++;
  385. if (!iswall(bp->b_y + 1, bp->b_x))
  386. mask |= SOUTH, count++;
  387. if (!iswall(bp->b_y, bp->b_x + 1))
  388. mask |= EAST, count++;
  389. /*
  390. * All blocked up, just you wait
  391. */
  392. if (count == 0)
  393. return TRUE;
  394. /*
  395. * Only one way to go.
  396. */
  397. if (count == 1) {
  398. dir = mask;
  399. goto drone_move;
  400. }
  401. /*
  402. * Get rid of the direction that we came from
  403. */
  404. switch (bp->b_face) {
  405. case LEFTS:
  406. if (mask & EAST)
  407. mask &= ~EAST, count--;
  408. break;
  409. case RIGHT:
  410. if (mask & WEST)
  411. mask &= ~WEST, count--;
  412. break;
  413. case ABOVE:
  414. if (mask & SOUTH)
  415. mask &= ~SOUTH, count--;
  416. break;
  417. case BELOW:
  418. if (mask & NORTH)
  419. mask &= ~NORTH, count--;
  420. break;
  421. }
  422. /*
  423. * Pick one of the remaining directions
  424. */
  425. n = rand_num(count);
  426. if (n >= 0 && mask & NORTH)
  427. dir = NORTH, n--;
  428. if (n >= 0 && mask & SOUTH)
  429. dir = SOUTH, n--;
  430. if (n >= 0 && mask & EAST)
  431. dir = EAST, n--;
  432. if (n >= 0 && mask & WEST)
  433. dir = WEST, n--;
  434. /*
  435. * Now that we know the direction of movement,
  436. * just update the position of the drone
  437. */
  438. drone_move:
  439. switch (dir) {
  440. case WEST:
  441. bp->b_x--;
  442. bp->b_face = LEFTS;
  443. break;
  444. case EAST:
  445. bp->b_x++;
  446. bp->b_face = RIGHT;
  447. break;
  448. case NORTH:
  449. bp->b_y--;
  450. bp->b_face = ABOVE;
  451. break;
  452. case SOUTH:
  453. bp->b_y++;
  454. bp->b_face = BELOW;
  455. break;
  456. }
  457. switch (Maze[bp->b_y][bp->b_x]) {
  458. case LEFTS:
  459. case RIGHT:
  460. case BELOW:
  461. case ABOVE:
  462. /*
  463. * give the person a chance to catch a
  464. * drone if s/he is facing it
  465. */
  466. if (rand_num(100) < 1 &&
  467. opposite(bp->b_face, Maze[bp->b_y][bp->b_x])) {
  468. pp = play_at(bp->b_y, bp->b_x);
  469. pp->p_ammo += bp->b_charge;
  470. message(pp, "**** Absorbed drone ****");
  471. free((char *) bp);
  472. (void) sprintf(Buf, "%3d", pp->p_ammo);
  473. cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL);
  474. outstr(pp, Buf, 3);
  475. return FALSE;
  476. }
  477. bp->b_expl = TRUE;
  478. break;
  479. }
  480. return TRUE;
  481. }
  482. # endif
  483. /*
  484. * save_bullet:
  485. * Put this bullet back onto the bullet list
  486. */
  487. static void
  488. save_bullet(bp)
  489. BULLET *bp;
  490. {
  491. bp->b_over = Maze[bp->b_y][bp->b_x];
  492. switch (bp->b_over) {
  493. case SHOT:
  494. case GRENADE:
  495. case SATCHEL:
  496. case BOMB:
  497. # ifdef OOZE
  498. case SLIME:
  499. # ifdef VOLCANO
  500. case LAVA:
  501. # endif
  502. # endif
  503. # ifdef DRONE
  504. case DSHOT:
  505. # endif
  506. find_under(Bullets, bp);
  507. break;
  508. }
  509. switch (bp->b_over) {
  510. case LEFTS:
  511. case RIGHT:
  512. case ABOVE:
  513. case BELOW:
  514. # ifdef FLY
  515. case FLYER:
  516. # endif
  517. mark_player(bp);
  518. break;
  519. # ifdef BOOTS
  520. case BOOT:
  521. case BOOT_PAIR:
  522. mark_boot(bp);
  523. # endif
  524. default:
  525. Maze[bp->b_y][bp->b_x] = bp->b_type;
  526. break;
  527. }
  528. bp->b_next = Bullets;
  529. Bullets = bp;
  530. }
  531. /*
  532. * move_flyer:
  533. * Update the position of a player in flight
  534. */
  535. static void
  536. move_flyer(pp)
  537. PLAYER *pp;
  538. {
  539. int x, y;
  540. if (pp->p_undershot) {
  541. fixshots(pp->p_y, pp->p_x, pp->p_over);
  542. pp->p_undershot = FALSE;
  543. }
  544. Maze[pp->p_y][pp->p_x] = pp->p_over;
  545. x = pp->p_x + pp->p_flyx;
  546. y = pp->p_y + pp->p_flyy;
  547. if (x < 1) {
  548. x = 1 - x;
  549. pp->p_flyx = -pp->p_flyx;
  550. }
  551. else if (x > WIDTH - 2) {
  552. x = (WIDTH - 2) - (x - (WIDTH - 2));
  553. pp->p_flyx = -pp->p_flyx;
  554. }
  555. if (y < 1) {
  556. y = 1 - y;
  557. pp->p_flyy = -pp->p_flyy;
  558. }
  559. else if (y > HEIGHT - 2) {
  560. y = (HEIGHT - 2) - (y - (HEIGHT - 2));
  561. pp->p_flyy = -pp->p_flyy;
  562. }
  563. again:
  564. switch (Maze[y][x]) {
  565. default:
  566. switch (rand_num(4)) {
  567. case 0:
  568. PLUS_DELTA(x, WIDTH - 2);
  569. break;
  570. case 1:
  571. MINUS_DELTA(x, 1);
  572. break;
  573. case 2:
  574. PLUS_DELTA(y, HEIGHT - 2);
  575. break;
  576. case 3:
  577. MINUS_DELTA(y, 1);
  578. break;
  579. }
  580. goto again;
  581. case WALL1:
  582. case WALL2:
  583. case WALL3:
  584. # ifdef REFLECT
  585. case WALL4:
  586. case WALL5:
  587. # endif
  588. # ifdef RANDOM
  589. case DOOR:
  590. # endif
  591. if (pp->p_flying == 0)
  592. pp->p_flying++;
  593. break;
  594. case SPACE:
  595. break;
  596. }
  597. pp->p_y = y;
  598. pp->p_x = x;
  599. if (pp->p_flying-- == 0) {
  600. # ifdef BOOTS
  601. if (pp->p_face != BOOT && pp->p_face != BOOT_PAIR) {
  602. # endif
  603. checkdam(pp, (PLAYER *) NULL, (IDENT *) NULL,
  604. rand_num(pp->p_damage / 5), FALL);
  605. pp->p_face = rand_dir();
  606. showstat(pp);
  607. # ifdef BOOTS
  608. }
  609. else {
  610. if (Maze[y][x] == BOOT)
  611. pp->p_face = BOOT_PAIR;
  612. Maze[y][x] = SPACE;
  613. }
  614. # endif
  615. }
  616. pp->p_over = Maze[y][x];
  617. Maze[y][x] = pp->p_face;
  618. showexpl(y, x, pp->p_face);
  619. }
  620. /*
  621. * chkshot
  622. * Handle explosions
  623. */
  624. static void
  625. chkshot(bp, next)
  626. BULLET *bp;
  627. BULLET *next;
  628. {
  629. int y, x;
  630. int dy, dx, absdy;
  631. int delta, damage;
  632. char expl;
  633. PLAYER *pp;
  634. delta = 0;
  635. switch (bp->b_type) {
  636. case SHOT:
  637. case MINE:
  638. case GRENADE:
  639. case GMINE:
  640. case SATCHEL:
  641. case BOMB:
  642. delta = bp->b_size - 1;
  643. break;
  644. # ifdef OOZE
  645. case SLIME:
  646. # ifdef VOLCANO
  647. case LAVA:
  648. # endif
  649. chkslime(bp, next);
  650. return;
  651. # endif
  652. # ifdef DRONE
  653. case DSHOT:
  654. bp->b_type = SLIME;
  655. chkslime(bp, next);
  656. return;
  657. # endif
  658. }
  659. for (y = bp->b_y - delta; y <= bp->b_y + delta; y++) {
  660. if (y < 0 || y >= HEIGHT)
  661. continue;
  662. dy = y - bp->b_y;
  663. absdy = (dy < 0) ? -dy : dy;
  664. for (x = bp->b_x - delta; x <= bp->b_x + delta; x++) {
  665. if (x < 0 || x >= WIDTH)
  666. continue;
  667. dx = x - bp->b_x;
  668. if (dx == 0)
  669. expl = (dy == 0) ? '*' : '|';
  670. else if (dy == 0)
  671. expl = '-';
  672. else if (dx == dy)
  673. expl = '\\';
  674. else if (dx == -dy)
  675. expl = '/';
  676. else
  677. expl = '*';
  678. showexpl(y, x, expl);
  679. switch (Maze[y][x]) {
  680. case LEFTS:
  681. case RIGHT:
  682. case ABOVE:
  683. case BELOW:
  684. # ifdef FLY
  685. case FLYER:
  686. # endif
  687. if (dx < 0)
  688. dx = -dx;
  689. if (absdy > dx)
  690. damage = bp->b_size - absdy;
  691. else
  692. damage = bp->b_size - dx;
  693. pp = play_at(y, x);
  694. checkdam(pp, bp->b_owner, bp->b_score,
  695. damage * MINDAM, bp->b_type);
  696. break;
  697. case GMINE:
  698. case MINE:
  699. add_shot((Maze[y][x] == GMINE) ?
  700. GRENADE : SHOT,
  701. y, x, LEFTS,
  702. (Maze[y][x] == GMINE) ?
  703. GRENREQ : BULREQ,
  704. (PLAYER *) NULL, TRUE, SPACE);
  705. Maze[y][x] = SPACE;
  706. break;
  707. }
  708. }
  709. }
  710. }
  711. # ifdef OOZE
  712. /*
  713. * chkslime:
  714. * handle slime shot exploding
  715. */
  716. static void
  717. chkslime(bp, next)
  718. BULLET *bp;
  719. BULLET *next;
  720. {
  721. BULLET *nbp;
  722. switch (Maze[bp->b_y][bp->b_x]) {
  723. case WALL1:
  724. case WALL2:
  725. case WALL3:
  726. # ifdef REFLECT
  727. case WALL4:
  728. case WALL5:
  729. # endif
  730. # ifdef RANDOM
  731. case DOOR:
  732. # endif
  733. switch (bp->b_face) {
  734. case LEFTS:
  735. bp->b_x++;
  736. break;
  737. case RIGHT:
  738. bp->b_x--;
  739. break;
  740. case ABOVE:
  741. bp->b_y++;
  742. break;
  743. case BELOW:
  744. bp->b_y--;
  745. break;
  746. }
  747. break;
  748. }
  749. nbp = (BULLET *) malloc(sizeof (BULLET));
  750. if (nbp == NULL) {
  751. # ifdef LOG
  752. syslog(LOG_ERR, "Out of memory");
  753. # else
  754. warnx("Out of memory");
  755. # endif
  756. cleanup(1);
  757. }
  758. *nbp = *bp;
  759. # ifdef VOLCANO
  760. move_slime(nbp, nbp->b_type == SLIME ? SLIMESPEED : LAVASPEED, next);
  761. # else
  762. move_slime(nbp, SLIMESPEED, next);
  763. # endif
  764. }
  765. /*
  766. * move_slime:
  767. * move the given slime shot speed times and add it back if
  768. * it hasn't fizzled yet
  769. */
  770. void
  771. move_slime(bp, speed, next)
  772. BULLET *bp;
  773. int speed;
  774. BULLET *next;
  775. {
  776. int i, j, dirmask, count;
  777. PLAYER *pp;
  778. BULLET *nbp;
  779. if (speed == 0) {
  780. if (bp->b_charge <= 0)
  781. free((char *) bp);
  782. else
  783. save_bullet(bp);
  784. return;
  785. }
  786. # ifdef VOLCANO
  787. showexpl(bp->b_y, bp->b_x, bp->b_type == LAVA ? LAVA : '*');
  788. # else
  789. showexpl(bp->b_y, bp->b_x, '*');
  790. # endif
  791. switch (Maze[bp->b_y][bp->b_x]) {
  792. case LEFTS:
  793. case RIGHT:
  794. case ABOVE:
  795. case BELOW:
  796. # ifdef FLY
  797. case FLYER:
  798. # endif
  799. pp = play_at(bp->b_y, bp->b_x);
  800. message(pp, "You've been slimed.");
  801. checkdam(pp, bp->b_owner, bp->b_score, MINDAM, bp->b_type);
  802. break;
  803. case SHOT:
  804. case GRENADE:
  805. case SATCHEL:
  806. case BOMB:
  807. # ifdef DRONE
  808. case DSHOT:
  809. # endif
  810. explshot(next, bp->b_y, bp->b_x);
  811. explshot(Bullets, bp->b_y, bp->b_x);
  812. break;
  813. }
  814. if (--bp->b_charge <= 0) {
  815. free((char *) bp);
  816. return;
  817. }
  818. dirmask = 0;
  819. count = 0;
  820. switch (bp->b_face) {
  821. case LEFTS:
  822. if (!iswall(bp->b_y, bp->b_x - 1))
  823. dirmask |= WEST, count++;
  824. if (!iswall(bp->b_y - 1, bp->b_x))
  825. dirmask |= NORTH, count++;
  826. if (!iswall(bp->b_y + 1, bp->b_x))
  827. dirmask |= SOUTH, count++;
  828. if (dirmask == 0)
  829. if (!iswall(bp->b_y, bp->b_x + 1))
  830. dirmask |= EAST, count++;
  831. break;
  832. case RIGHT:
  833. if (!iswall(bp->b_y, bp->b_x + 1))
  834. dirmask |= EAST, count++;
  835. if (!iswall(bp->b_y - 1, bp->b_x))
  836. dirmask |= NORTH, count++;
  837. if (!iswall(bp->b_y + 1, bp->b_x))
  838. dirmask |= SOUTH, count++;
  839. if (dirmask == 0)
  840. if (!iswall(bp->b_y, bp->b_x - 1))
  841. dirmask |= WEST, count++;
  842. break;
  843. case ABOVE:
  844. if (!iswall(bp->b_y - 1, bp->b_x))
  845. dirmask |= NORTH, count++;
  846. if (!iswall(bp->b_y, bp->b_x - 1))
  847. dirmask |= WEST, count++;
  848. if (!iswall(bp->b_y, bp->b_x + 1))
  849. dirmask |= EAST, count++;
  850. if (dirmask == 0)
  851. if (!iswall(bp->b_y + 1, bp->b_x))
  852. dirmask |= SOUTH, count++;
  853. break;
  854. case BELOW:
  855. if (!iswall(bp->b_y + 1, bp->b_x))
  856. dirmask |= SOUTH, count++;
  857. if (!iswall(bp->b_y, bp->b_x - 1))
  858. dirmask |= WEST, count++;
  859. if (!iswall(bp->b_y, bp->b_x + 1))
  860. dirmask |= EAST, count++;
  861. if (dirmask == 0)
  862. if (!iswall(bp->b_y - 1, bp->b_x))
  863. dirmask |= NORTH, count++;
  864. break;
  865. }
  866. if (count == 0) {
  867. /*
  868. * No place to go. Just sit here for a while and wait
  869. * for adjacent squares to clear out.
  870. */
  871. save_bullet(bp);
  872. return;
  873. }
  874. if (bp->b_charge < count) {
  875. /* Only bp->b_charge paths may be taken */
  876. while (count > bp->b_charge) {
  877. if (dirmask & WEST)
  878. dirmask &= ~WEST;
  879. else if (dirmask & EAST)
  880. dirmask &= ~EAST;
  881. else if (dirmask & NORTH)
  882. dirmask &= ~NORTH;
  883. else if (dirmask & SOUTH)
  884. dirmask &= ~SOUTH;
  885. count--;
  886. }
  887. }
  888. i = bp->b_charge / count;
  889. j = bp->b_charge % count;
  890. if (dirmask & WEST) {
  891. count--;
  892. nbp = create_shot(bp->b_type, bp->b_y, bp->b_x - 1, LEFTS,
  893. i, bp->b_size, bp->b_owner, bp->b_score, TRUE, SPACE);
  894. move_slime(nbp, speed - 1, next);
  895. }
  896. if (dirmask & EAST) {
  897. count--;
  898. nbp = create_shot(bp->b_type, bp->b_y, bp->b_x + 1, RIGHT,
  899. (count < j) ? i + 1 : i, bp->b_size, bp->b_owner,
  900. bp->b_score, TRUE, SPACE);
  901. move_slime(nbp, speed - 1, next);
  902. }
  903. if (dirmask & NORTH) {
  904. count--;
  905. nbp = create_shot(bp->b_type, bp->b_y - 1, bp->b_x, ABOVE,
  906. (count < j) ? i + 1 : i, bp->b_size, bp->b_owner,
  907. bp->b_score, TRUE, SPACE);
  908. move_slime(nbp, speed - 1, next);
  909. }
  910. if (dirmask & SOUTH) {
  911. count--;
  912. nbp = create_shot(bp->b_type, bp->b_y + 1, bp->b_x, BELOW,
  913. (count < j) ? i + 1 : i, bp->b_size, bp->b_owner,
  914. bp->b_score, TRUE, SPACE);
  915. move_slime(nbp, speed - 1, next);
  916. }
  917. free((char *) bp);
  918. }
  919. /*
  920. * iswall:
  921. * returns whether the given location is a wall
  922. */
  923. static int
  924. iswall(y, x)
  925. int y, x;
  926. {
  927. if (y < 0 || x < 0 || y >= HEIGHT || x >= WIDTH)
  928. return TRUE;
  929. switch (Maze[y][x]) {
  930. case WALL1:
  931. case WALL2:
  932. case WALL3:
  933. # ifdef REFLECT
  934. case WALL4:
  935. case WALL5:
  936. # endif
  937. # ifdef RANDOM
  938. case DOOR:
  939. # endif
  940. # ifdef OOZE
  941. case SLIME:
  942. # ifdef VOLCANO
  943. case LAVA:
  944. # endif
  945. # endif
  946. return TRUE;
  947. }
  948. return FALSE;
  949. }
  950. # endif
  951. /*
  952. * zapshot:
  953. * Take a shot out of the air.
  954. */
  955. static void
  956. zapshot(blist, obp)
  957. BULLET *blist, *obp;
  958. {
  959. BULLET *bp;
  960. FLAG explode;
  961. explode = FALSE;
  962. for (bp = blist; bp != NULL; bp = bp->b_next) {
  963. if (bp->b_x != obp->b_x || bp->b_y != obp->b_y)
  964. continue;
  965. if (bp->b_face == obp->b_face)
  966. continue;
  967. explode = TRUE;
  968. break;
  969. }
  970. if (!explode)
  971. return;
  972. explshot(blist, obp->b_y, obp->b_x);
  973. }
  974. /*
  975. * explshot -
  976. * Make all shots at this location blow up
  977. */
  978. void
  979. explshot(blist, y, x)
  980. BULLET *blist;
  981. int y, x;
  982. {
  983. BULLET *bp;
  984. for (bp = blist; bp != NULL; bp = bp->b_next)
  985. if (bp->b_x == x && bp->b_y == y) {
  986. bp->b_expl = TRUE;
  987. if (bp->b_owner != NULL)
  988. message(bp->b_owner, "Shot intercepted");
  989. }
  990. }
  991. /*
  992. * play_at:
  993. * Return a pointer to the player at the given location
  994. */
  995. PLAYER *
  996. play_at(y, x)
  997. int y, x;
  998. {
  999. PLAYER *pp;
  1000. for (pp = Player; pp < End_player; pp++)
  1001. if (pp->p_x == x && pp->p_y == y)
  1002. return pp;
  1003. errx(1, "driver: couldn't find player at (%d,%d)", x, y);
  1004. /* NOTREACHED */
  1005. }
  1006. /*
  1007. * opposite:
  1008. * Return TRUE if the bullet direction faces the opposite direction
  1009. * of the player in the maze
  1010. */
  1011. int
  1012. opposite(face, dir)
  1013. int face;
  1014. char dir;
  1015. {
  1016. switch (face) {
  1017. case LEFTS:
  1018. return (dir == RIGHT);
  1019. case RIGHT:
  1020. return (dir == LEFTS);
  1021. case ABOVE:
  1022. return (dir == BELOW);
  1023. case BELOW:
  1024. return (dir == ABOVE);
  1025. default:
  1026. return FALSE;
  1027. }
  1028. }
  1029. /*
  1030. * is_bullet:
  1031. * Is there a bullet at the given coordinates? If so, return
  1032. * a pointer to the bullet, otherwise return NULL
  1033. */
  1034. BULLET *
  1035. is_bullet(y, x)
  1036. int y, x;
  1037. {
  1038. BULLET *bp;
  1039. for (bp = Bullets; bp != NULL; bp = bp->b_next)
  1040. if (bp->b_y == y && bp->b_x == x)
  1041. return bp;
  1042. return NULL;
  1043. }
  1044. /*
  1045. * fixshots:
  1046. * change the underlying character of the shots at a location
  1047. * to the given character.
  1048. */
  1049. void
  1050. fixshots(y, x, over)
  1051. int y, x;
  1052. char over;
  1053. {
  1054. BULLET *bp;
  1055. for (bp = Bullets; bp != NULL; bp = bp->b_next)
  1056. if (bp->b_y == y && bp->b_x == x)
  1057. bp->b_over = over;
  1058. }
  1059. /*
  1060. * find_under:
  1061. * find the underlying character for a bullet when it lands
  1062. * on another bullet.
  1063. */
  1064. static void
  1065. find_under(blist, bp)
  1066. BULLET *blist, *bp;
  1067. {
  1068. BULLET *nbp;
  1069. for (nbp = blist; nbp != NULL; nbp = nbp->b_next)
  1070. if (bp->b_y == nbp->b_y && bp->b_x == nbp->b_x) {
  1071. bp->b_over = nbp->b_over;
  1072. break;
  1073. }
  1074. }
  1075. /*
  1076. * mark_player:
  1077. * mark a player as under a shot
  1078. */
  1079. static void
  1080. mark_player(bp)
  1081. BULLET *bp;
  1082. {
  1083. PLAYER *pp;
  1084. for (pp = Player; pp < End_player; pp++)
  1085. if (pp->p_y == bp->b_y && pp->p_x == bp->b_x) {
  1086. pp->p_undershot = TRUE;
  1087. break;
  1088. }
  1089. }
  1090. # ifdef BOOTS
  1091. /*
  1092. * mark_boot:
  1093. * mark a boot as under a shot
  1094. */
  1095. static void
  1096. mark_boot(bp)
  1097. BULLET *bp;
  1098. {
  1099. PLAYER *pp;
  1100. for (pp = Boot; pp < &Boot[NBOOTS]; pp++)
  1101. if (pp->p_y == bp->b_y && pp->p_x == bp->b_x) {
  1102. pp->p_undershot = TRUE;
  1103. break;
  1104. }
  1105. }
  1106. # endif