Home | History | Annotate | Line # | Download | only in huntd
shots.c revision 1.1
      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
   1097