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