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