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