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