xref: /dflybsd-src/games/hunt/huntd/shots.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
186d7f5d3SJohn Marino /*-
286d7f5d3SJohn Marino  * Copyright (c) 1983-2003, Regents of the University of California.
386d7f5d3SJohn Marino  * All rights reserved.
486d7f5d3SJohn Marino  *
586d7f5d3SJohn Marino  * Redistribution and use in source and binary forms, with or without
686d7f5d3SJohn Marino  * modification, are permitted provided that the following conditions are
786d7f5d3SJohn Marino  * met:
886d7f5d3SJohn Marino  *
986d7f5d3SJohn Marino  * 1. Redistributions of source code must retain the above copyright
1086d7f5d3SJohn Marino  *    notice, this list of conditions and the following disclaimer.
1186d7f5d3SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
1286d7f5d3SJohn Marino  *    notice, this list of conditions and the following disclaimer in the
1386d7f5d3SJohn Marino  *    documentation and/or other materials provided with the distribution.
1486d7f5d3SJohn Marino  * 3. Neither the name of the University of California, San Francisco nor
1586d7f5d3SJohn Marino  *    the names of its contributors may be used to endorse or promote
1686d7f5d3SJohn Marino  *    products derived from this software without specific prior written
1786d7f5d3SJohn Marino  *    permission.
1886d7f5d3SJohn Marino  *
1986d7f5d3SJohn Marino  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
2086d7f5d3SJohn Marino  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2186d7f5d3SJohn Marino  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
2286d7f5d3SJohn Marino  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2386d7f5d3SJohn Marino  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2486d7f5d3SJohn Marino  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2586d7f5d3SJohn Marino  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2686d7f5d3SJohn Marino  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2786d7f5d3SJohn Marino  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2886d7f5d3SJohn Marino  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2986d7f5d3SJohn Marino  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3086d7f5d3SJohn Marino  *
3186d7f5d3SJohn Marino  * $OpenBSD: shots.c,v 1.9 2006/03/27 00:10:15 tedu Exp $
3286d7f5d3SJohn Marino  * $NetBSD: shots.c,v 1.3 1997/10/11 08:13:50 lukem Exp $
3386d7f5d3SJohn Marino  * $DragonFly: src/games/hunt/huntd/shots.c,v 1.2 2008/09/04 16:12:51 swildner Exp $
3486d7f5d3SJohn Marino  */
3586d7f5d3SJohn Marino 
3686d7f5d3SJohn Marino #include <err.h>
3786d7f5d3SJohn Marino #include <signal.h>
3886d7f5d3SJohn Marino #include <stdlib.h>
3986d7f5d3SJohn Marino #include <syslog.h>
4086d7f5d3SJohn Marino #include "hunt.h"
4186d7f5d3SJohn Marino #include "conf.h"
4286d7f5d3SJohn Marino #include "server.h"
4386d7f5d3SJohn Marino 
4486d7f5d3SJohn Marino #define	PLUS_DELTA(x, max)	if (x < max) x++; else x--
4586d7f5d3SJohn Marino #define	MINUS_DELTA(x, min)	if (x > min) x--; else x++
4686d7f5d3SJohn Marino 
4786d7f5d3SJohn Marino static	void	chkshot(BULLET *, BULLET *);
4886d7f5d3SJohn Marino static	void	chkslime(BULLET *, BULLET *);
4986d7f5d3SJohn Marino static	void	explshot(BULLET *, int, int);
5086d7f5d3SJohn Marino static	void	find_under(BULLET *, BULLET *);
5186d7f5d3SJohn Marino static	int	iswall(int, int);
5286d7f5d3SJohn Marino static	void	mark_boot(BULLET *);
5386d7f5d3SJohn Marino static	void	mark_player(BULLET *);
5486d7f5d3SJohn Marino static	int	move_drone(BULLET *);
5586d7f5d3SJohn Marino static	void	move_flyer(PLAYER *);
5686d7f5d3SJohn Marino static	int	move_normal_shot(BULLET *);
5786d7f5d3SJohn Marino static	void	move_slime(BULLET *, int, BULLET *);
5886d7f5d3SJohn Marino static	void	save_bullet(BULLET *);
5986d7f5d3SJohn Marino static	void	zapshot(BULLET *, BULLET *);
6086d7f5d3SJohn Marino 
6186d7f5d3SJohn Marino /* Return true if there is pending activity */
6286d7f5d3SJohn Marino int
can_moveshots(void)6386d7f5d3SJohn Marino can_moveshots(void)
6486d7f5d3SJohn Marino {
6586d7f5d3SJohn Marino 	PLAYER *pp;
6686d7f5d3SJohn Marino 
6786d7f5d3SJohn Marino 	/* Bullets are moving? */
6886d7f5d3SJohn Marino 	if (Bullets)
6986d7f5d3SJohn Marino 		return 1;
7086d7f5d3SJohn Marino 
7186d7f5d3SJohn Marino 	/* Explosions are happening? */
7286d7f5d3SJohn Marino 	if (can_rollexpl())
7386d7f5d3SJohn Marino 		return 1;
7486d7f5d3SJohn Marino 
7586d7f5d3SJohn Marino 	/* Things are flying? */
7686d7f5d3SJohn Marino 	for (pp = Boot; pp < &Boot[NBOOTS]; pp++)
7786d7f5d3SJohn Marino 		if (pp->p_flying >= 0)
7886d7f5d3SJohn Marino 			return 1;
7986d7f5d3SJohn Marino 	for (pp = Player; pp < End_player; pp++)
8086d7f5d3SJohn Marino 		if (pp->p_flying >= 0)
8186d7f5d3SJohn Marino 			return 1;
8286d7f5d3SJohn Marino 
8386d7f5d3SJohn Marino 	/* Everything is quiet: */
8486d7f5d3SJohn Marino 	return 0;
8586d7f5d3SJohn Marino }
8686d7f5d3SJohn Marino 
8786d7f5d3SJohn Marino /*
8886d7f5d3SJohn Marino  * moveshots:
8986d7f5d3SJohn Marino  *	Move the shots already in the air, taking explosions into account
9086d7f5d3SJohn Marino  */
9186d7f5d3SJohn Marino void
moveshots(void)9286d7f5d3SJohn Marino moveshots(void)
9386d7f5d3SJohn Marino {
9486d7f5d3SJohn Marino 	BULLET	*bp, *next;
9586d7f5d3SJohn Marino 	PLAYER	*pp;
9686d7f5d3SJohn Marino 	int	x, y;
9786d7f5d3SJohn Marino 	BULLET	*blist;
9886d7f5d3SJohn Marino 
9986d7f5d3SJohn Marino 	rollexpl();
10086d7f5d3SJohn Marino 	if (Bullets == NULL)
10186d7f5d3SJohn Marino 		goto no_bullets;
10286d7f5d3SJohn Marino 
10386d7f5d3SJohn Marino 	/*
10486d7f5d3SJohn Marino 	 * First we move through the bullet list conf_bulspd times, looking
10586d7f5d3SJohn Marino 	 * for things we may have run into.  If we do run into
10686d7f5d3SJohn Marino 	 * something, we set up the explosion and disappear, checking
10786d7f5d3SJohn Marino 	 * for damage to any player who got in the way.
10886d7f5d3SJohn Marino 	 */
10986d7f5d3SJohn Marino 
11086d7f5d3SJohn Marino 	/* Move the list to a working list */
11186d7f5d3SJohn Marino 	blist = Bullets;
11286d7f5d3SJohn Marino 	Bullets = NULL;
11386d7f5d3SJohn Marino 
11486d7f5d3SJohn Marino 	/* Work with bullets on the working list (blist) */
11586d7f5d3SJohn Marino 	for (bp = blist; bp != NULL; bp = next) {
11686d7f5d3SJohn Marino 		next = bp->b_next;
11786d7f5d3SJohn Marino 
11886d7f5d3SJohn Marino 		x = bp->b_x;
11986d7f5d3SJohn Marino 		y = bp->b_y;
12086d7f5d3SJohn Marino 
12186d7f5d3SJohn Marino 		/* Un-draw the bullet on all screens: */
12286d7f5d3SJohn Marino 		Maze[y][x] = bp->b_over;
12386d7f5d3SJohn Marino 		check(ALL_PLAYERS, y, x);
12486d7f5d3SJohn Marino 
12586d7f5d3SJohn Marino 		/* Decide how to move the bullet: */
12686d7f5d3SJohn Marino 		switch (bp->b_type) {
12786d7f5d3SJohn Marino 
12886d7f5d3SJohn Marino 		  /* Normal, atomic bullets: */
12986d7f5d3SJohn Marino 		  case SHOT:
13086d7f5d3SJohn Marino 		  case GRENADE:
13186d7f5d3SJohn Marino 		  case SATCHEL:
13286d7f5d3SJohn Marino 		  case BOMB:
13386d7f5d3SJohn Marino 			if (move_normal_shot(bp)) {
13486d7f5d3SJohn Marino 				/* Still there: put back on the active list */
13586d7f5d3SJohn Marino 				bp->b_next = Bullets;
13686d7f5d3SJohn Marino 				Bullets = bp;
13786d7f5d3SJohn Marino 			}
13886d7f5d3SJohn Marino 			break;
13986d7f5d3SJohn Marino 
14086d7f5d3SJohn Marino 		  /* Slime bullets that explode into slime on impact: */
14186d7f5d3SJohn Marino 		  case SLIME:
14286d7f5d3SJohn Marino 			if (bp->b_expl || move_normal_shot(bp)) {
14386d7f5d3SJohn Marino 				/* Still there: put back on the active list */
14486d7f5d3SJohn Marino 				bp->b_next = Bullets;
14586d7f5d3SJohn Marino 				Bullets = bp;
14686d7f5d3SJohn Marino 			}
14786d7f5d3SJohn Marino 			break;
14886d7f5d3SJohn Marino 
14986d7f5d3SJohn Marino 		  /* Drones that wander about: */
15086d7f5d3SJohn Marino 		  case DSHOT:
15186d7f5d3SJohn Marino 			if (move_drone(bp)) {
15286d7f5d3SJohn Marino 				/* Still there: put back on the active list */
15386d7f5d3SJohn Marino 				bp->b_next = Bullets;
15486d7f5d3SJohn Marino 				Bullets = bp;
15586d7f5d3SJohn Marino 			}
15686d7f5d3SJohn Marino 			break;
15786d7f5d3SJohn Marino 
15886d7f5d3SJohn Marino 		  /* Other/unknown: */
15986d7f5d3SJohn Marino 		  default:
16086d7f5d3SJohn Marino 			/* Place it back on the active list: */
16186d7f5d3SJohn Marino 			bp->b_next = Bullets;
16286d7f5d3SJohn Marino 			Bullets = bp;
16386d7f5d3SJohn Marino 			break;
16486d7f5d3SJohn Marino 		}
16586d7f5d3SJohn Marino 	}
16686d7f5d3SJohn Marino 
16786d7f5d3SJohn Marino 	/* Again, hang the Bullets list off `blist' and work with that: */
16886d7f5d3SJohn Marino 	blist = Bullets;
16986d7f5d3SJohn Marino 	Bullets = NULL;
17086d7f5d3SJohn Marino 	for (bp = blist; bp != NULL; bp = next) {
17186d7f5d3SJohn Marino 		next = bp->b_next;
17286d7f5d3SJohn Marino 		/* Is the bullet exploding? */
17386d7f5d3SJohn Marino 		if (!bp->b_expl) {
17486d7f5d3SJohn Marino 			/*
17586d7f5d3SJohn Marino 			 * Its still flying through the air.
17686d7f5d3SJohn Marino 			 * Put it back on the bullet list.
17786d7f5d3SJohn Marino 			 */
17886d7f5d3SJohn Marino 			save_bullet(bp);
17986d7f5d3SJohn Marino 
18086d7f5d3SJohn Marino 			/* All the monitors can see the bullet: */
18186d7f5d3SJohn Marino 			for (pp = Monitor; pp < End_monitor; pp++)
18286d7f5d3SJohn Marino 				check(pp, bp->b_y, bp->b_x);
18386d7f5d3SJohn Marino 
18486d7f5d3SJohn Marino 			/* All the scanning players can see the drone: */
18586d7f5d3SJohn Marino 			if (bp->b_type == DSHOT)
18686d7f5d3SJohn Marino 				for (pp = Player; pp < End_player; pp++)
18786d7f5d3SJohn Marino 					if (pp->p_scan >= 0)
18886d7f5d3SJohn Marino 						check(pp, bp->b_y, bp->b_x);
18986d7f5d3SJohn Marino 		} else {
19086d7f5d3SJohn Marino 			/* It is exploding. Check what we hit: */
19186d7f5d3SJohn Marino 			chkshot(bp, next);
19286d7f5d3SJohn Marino 			/* Release storage for the destroyed bullet: */
19386d7f5d3SJohn Marino 			free(bp);
19486d7f5d3SJohn Marino 		}
19586d7f5d3SJohn Marino 	}
19686d7f5d3SJohn Marino 
19786d7f5d3SJohn Marino 	/* Re-draw all the players: (in case a bullet wiped them out) */
19886d7f5d3SJohn Marino 	for (pp = Player; pp < End_player; pp++)
19986d7f5d3SJohn Marino 		Maze[pp->p_y][pp->p_x] = pp->p_face;
20086d7f5d3SJohn Marino 
20186d7f5d3SJohn Marino no_bullets:
20286d7f5d3SJohn Marino 
20386d7f5d3SJohn Marino 	/* Move flying boots through the air: */
20486d7f5d3SJohn Marino 	for (pp = Boot; pp < &Boot[NBOOTS]; pp++)
20586d7f5d3SJohn Marino 		if (pp->p_flying >= 0)
20686d7f5d3SJohn Marino 			move_flyer(pp);
20786d7f5d3SJohn Marino 
20886d7f5d3SJohn Marino 	/* Move flying players through the air: */
20986d7f5d3SJohn Marino 	for (pp = Player; pp < End_player; pp++) {
21086d7f5d3SJohn Marino 		if (pp->p_flying >= 0)
21186d7f5d3SJohn Marino 			move_flyer(pp);
21286d7f5d3SJohn Marino 		/* Flush out the explosions: */
21386d7f5d3SJohn Marino 		sendcom(pp, REFRESH);
21486d7f5d3SJohn Marino 		look(pp);
21586d7f5d3SJohn Marino 	}
21686d7f5d3SJohn Marino 
21786d7f5d3SJohn Marino 	/* Flush out and synchronise all the displays: */
21886d7f5d3SJohn Marino 	sendcom(ALL_PLAYERS, REFRESH);
21986d7f5d3SJohn Marino }
22086d7f5d3SJohn Marino 
22186d7f5d3SJohn Marino /*
22286d7f5d3SJohn Marino  * move_normal_shot:
22386d7f5d3SJohn Marino  *	Move a normal shot along its trajectory.
22486d7f5d3SJohn Marino  *	Returns false if the bullet no longer needs tracking.
22586d7f5d3SJohn Marino  */
22686d7f5d3SJohn Marino static int
move_normal_shot(BULLET * bp)22786d7f5d3SJohn Marino move_normal_shot(BULLET *bp)
22886d7f5d3SJohn Marino {
22986d7f5d3SJohn Marino 	int	i, x, y;
23086d7f5d3SJohn Marino 	PLAYER	*pp;
23186d7f5d3SJohn Marino 
23286d7f5d3SJohn Marino 	/*
23386d7f5d3SJohn Marino 	 * Walk an unexploded bullet along conf_bulspd times, moving it
23486d7f5d3SJohn Marino 	 * one unit along each step. We flag it as exploding if it
23586d7f5d3SJohn Marino 	 * meets something.
23686d7f5d3SJohn Marino 	 */
23786d7f5d3SJohn Marino 
23886d7f5d3SJohn Marino 	for (i = 0; i < conf_bulspd; i++) {
23986d7f5d3SJohn Marino 
24086d7f5d3SJohn Marino 		/* Stop if the bullet has already exploded: */
24186d7f5d3SJohn Marino 		if (bp->b_expl)
24286d7f5d3SJohn Marino 			break;
24386d7f5d3SJohn Marino 
24486d7f5d3SJohn Marino 		/* Adjust the bullet's co-ordinates: */
24586d7f5d3SJohn Marino 		x = bp->b_x;
24686d7f5d3SJohn Marino 		y = bp->b_y;
24786d7f5d3SJohn Marino 		switch (bp->b_face) {
24886d7f5d3SJohn Marino 		  case LEFTS:
24986d7f5d3SJohn Marino 			x--;
25086d7f5d3SJohn Marino 			break;
25186d7f5d3SJohn Marino 		  case RIGHT:
25286d7f5d3SJohn Marino 			x++;
25386d7f5d3SJohn Marino 			break;
25486d7f5d3SJohn Marino 		  case ABOVE:
25586d7f5d3SJohn Marino 			y--;
25686d7f5d3SJohn Marino 			break;
25786d7f5d3SJohn Marino 		  case BELOW:
25886d7f5d3SJohn Marino 			y++;
25986d7f5d3SJohn Marino 			break;
26086d7f5d3SJohn Marino 		}
26186d7f5d3SJohn Marino 
26286d7f5d3SJohn Marino 
26386d7f5d3SJohn Marino 		/* Look at what the bullet is colliding with : */
26486d7f5d3SJohn Marino 		switch (Maze[y][x]) {
26586d7f5d3SJohn Marino 		  /* Gun shots have a chance of collision: */
26686d7f5d3SJohn Marino 		  case SHOT:
26786d7f5d3SJohn Marino 			if (rand_num(100) < conf_pshot_coll) {
26886d7f5d3SJohn Marino 				zapshot(Bullets, bp);
26986d7f5d3SJohn Marino 				zapshot(bp->b_next, bp);
27086d7f5d3SJohn Marino 			}
27186d7f5d3SJohn Marino 			break;
27286d7f5d3SJohn Marino 		  /* Grenades only have a chance of collision: */
27386d7f5d3SJohn Marino 		  case GRENADE:
27486d7f5d3SJohn Marino 			if (rand_num(100) < conf_pgren_coll) {
27586d7f5d3SJohn Marino 				zapshot(Bullets, bp);
27686d7f5d3SJohn Marino 				zapshot(bp->b_next, bp);
27786d7f5d3SJohn Marino 			}
27886d7f5d3SJohn Marino 			break;
27986d7f5d3SJohn Marino 		  /* Reflecting walls richochet the bullet: */
28086d7f5d3SJohn Marino 		  case WALL4:
28186d7f5d3SJohn Marino 			switch (bp->b_face) {
28286d7f5d3SJohn Marino 			  case LEFTS:
28386d7f5d3SJohn Marino 				bp->b_face = BELOW;
28486d7f5d3SJohn Marino 				break;
28586d7f5d3SJohn Marino 			  case RIGHT:
28686d7f5d3SJohn Marino 				bp->b_face = ABOVE;
28786d7f5d3SJohn Marino 				break;
28886d7f5d3SJohn Marino 			  case ABOVE:
28986d7f5d3SJohn Marino 				bp->b_face = RIGHT;
29086d7f5d3SJohn Marino 				break;
29186d7f5d3SJohn Marino 			  case BELOW:
29286d7f5d3SJohn Marino 				bp->b_face = LEFTS;
29386d7f5d3SJohn Marino 				break;
29486d7f5d3SJohn Marino 			}
29586d7f5d3SJohn Marino 			Maze[y][x] = WALL5;
29686d7f5d3SJohn Marino 			for (pp = Monitor; pp < End_monitor; pp++)
29786d7f5d3SJohn Marino 				check(pp, y, x);
29886d7f5d3SJohn Marino 			break;
29986d7f5d3SJohn Marino 		  case WALL5:
30086d7f5d3SJohn Marino 			switch (bp->b_face) {
30186d7f5d3SJohn Marino 			  case LEFTS:
30286d7f5d3SJohn Marino 				bp->b_face = ABOVE;
30386d7f5d3SJohn Marino 				break;
30486d7f5d3SJohn Marino 			  case RIGHT:
30586d7f5d3SJohn Marino 				bp->b_face = BELOW;
30686d7f5d3SJohn Marino 				break;
30786d7f5d3SJohn Marino 			  case ABOVE:
30886d7f5d3SJohn Marino 				bp->b_face = LEFTS;
30986d7f5d3SJohn Marino 				break;
31086d7f5d3SJohn Marino 			  case BELOW:
31186d7f5d3SJohn Marino 				bp->b_face = RIGHT;
31286d7f5d3SJohn Marino 				break;
31386d7f5d3SJohn Marino 			}
31486d7f5d3SJohn Marino 			Maze[y][x] = WALL4;
31586d7f5d3SJohn Marino 			for (pp = Monitor; pp < End_monitor; pp++)
31686d7f5d3SJohn Marino 				check(pp, y, x);
31786d7f5d3SJohn Marino 			break;
31886d7f5d3SJohn Marino 		  /* Dispersion doors randomly disperse bullets: */
31986d7f5d3SJohn Marino 		  case DOOR:
32086d7f5d3SJohn Marino 			switch (rand_num(4)) {
32186d7f5d3SJohn Marino 			  case 0:
32286d7f5d3SJohn Marino 				bp->b_face = ABOVE;
32386d7f5d3SJohn Marino 				break;
32486d7f5d3SJohn Marino 			  case 1:
32586d7f5d3SJohn Marino 				bp->b_face = BELOW;
32686d7f5d3SJohn Marino 				break;
32786d7f5d3SJohn Marino 			  case 2:
32886d7f5d3SJohn Marino 				bp->b_face = LEFTS;
32986d7f5d3SJohn Marino 				break;
33086d7f5d3SJohn Marino 			  case 3:
33186d7f5d3SJohn Marino 				bp->b_face = RIGHT;
33286d7f5d3SJohn Marino 				break;
33386d7f5d3SJohn Marino 			}
33486d7f5d3SJohn Marino 			break;
33586d7f5d3SJohn Marino 		  /* Bullets zing past fliers: */
33686d7f5d3SJohn Marino 		  case FLYER:
33786d7f5d3SJohn Marino 			pp = play_at(y, x);
33886d7f5d3SJohn Marino 			message(pp, "Zing!");
33986d7f5d3SJohn Marino 			break;
34086d7f5d3SJohn Marino 		  /* Bullets encountering a player: */
34186d7f5d3SJohn Marino 		  case LEFTS:
34286d7f5d3SJohn Marino 		  case RIGHT:
34386d7f5d3SJohn Marino 		  case BELOW:
34486d7f5d3SJohn Marino 		  case ABOVE:
34586d7f5d3SJohn Marino 			/*
34686d7f5d3SJohn Marino 			 * Give the person a chance to catch a
34786d7f5d3SJohn Marino 			 * grenade if s/he is facing it:
34886d7f5d3SJohn Marino 			 */
34986d7f5d3SJohn Marino 			pp = play_at(y, x);
35086d7f5d3SJohn Marino 			pp->p_ident->i_shot += bp->b_charge;
35186d7f5d3SJohn Marino 			if (opposite(bp->b_face, Maze[y][x])) {
35286d7f5d3SJohn Marino 			    /* Give them a 10% chance: */
35386d7f5d3SJohn Marino 			    if (rand_num(100) < conf_pgren_catch) {
35486d7f5d3SJohn Marino 				/* They caught it! */
35586d7f5d3SJohn Marino 				if (bp->b_owner != NULL)
35686d7f5d3SJohn Marino 					message(bp->b_owner,
35786d7f5d3SJohn Marino 					    "Your charge was absorbed!");
35886d7f5d3SJohn Marino 
35986d7f5d3SJohn Marino 				/*
36086d7f5d3SJohn Marino 				 * The target player stole from the bullet's
36186d7f5d3SJohn Marino 				 * owner. Charge stolen statistics:
36286d7f5d3SJohn Marino 				 */
36386d7f5d3SJohn Marino 				if (bp->b_score != NULL)
36486d7f5d3SJohn Marino 					bp->b_score->i_robbed += bp->b_charge;
36586d7f5d3SJohn Marino 
36686d7f5d3SJohn Marino 				/* They acquire more ammo: */
36786d7f5d3SJohn Marino 				pp->p_ammo += bp->b_charge;
36886d7f5d3SJohn Marino 
36986d7f5d3SJohn Marino 				/* Check if it would have destroyed them: */
37086d7f5d3SJohn Marino 				if (pp->p_damage + bp->b_size * conf_mindam
37186d7f5d3SJohn Marino 				    > pp->p_damcap)
37286d7f5d3SJohn Marino 					/* Lucky escape statistics: */
37386d7f5d3SJohn Marino 					pp->p_ident->i_saved++;
37486d7f5d3SJohn Marino 
37586d7f5d3SJohn Marino 				/* Tell them: */
37686d7f5d3SJohn Marino 				message(pp, "Absorbed charge (good shield!)");
37786d7f5d3SJohn Marino 
37886d7f5d3SJohn Marino 				/* Absorbtion statistics: */
37986d7f5d3SJohn Marino 				pp->p_ident->i_absorbed += bp->b_charge;
38086d7f5d3SJohn Marino 
38186d7f5d3SJohn Marino 				/* Deallocate storage: */
38286d7f5d3SJohn Marino 				free(bp);
38386d7f5d3SJohn Marino 
38486d7f5d3SJohn Marino 				/* Update ammo display: */
38586d7f5d3SJohn Marino 				ammo_update(pp);
38686d7f5d3SJohn Marino 
38786d7f5d3SJohn Marino 				/* No need for caller to keep tracking it: */
38886d7f5d3SJohn Marino 				return FALSE;
38986d7f5d3SJohn Marino 			    }
39086d7f5d3SJohn Marino 
39186d7f5d3SJohn Marino 			    /* Bullets faced head-on (statistics): */
39286d7f5d3SJohn Marino 			    pp->p_ident->i_faced += bp->b_charge;
39386d7f5d3SJohn Marino 			}
39486d7f5d3SJohn Marino 
39586d7f5d3SJohn Marino 			/*
39686d7f5d3SJohn Marino 			 * Small chance that the bullet just misses the
39786d7f5d3SJohn Marino 			 * person.  If so, the bullet just goes on its
39886d7f5d3SJohn Marino 			 * merry way without exploding. (5% chance)
39986d7f5d3SJohn Marino 			 */
40086d7f5d3SJohn Marino 			if (rand_num(100) < conf_pmiss) {
40186d7f5d3SJohn Marino 				/* Ducked statistics: */
40286d7f5d3SJohn Marino 				pp->p_ident->i_ducked += bp->b_charge;
40386d7f5d3SJohn Marino 
40486d7f5d3SJohn Marino 				/* Check if it would have killed them: */
40586d7f5d3SJohn Marino 				if (pp->p_damage + bp->b_size * conf_mindam
40686d7f5d3SJohn Marino 				    > pp->p_damcap)
40786d7f5d3SJohn Marino 					/* Lucky escape statistics: */
40886d7f5d3SJohn Marino 					pp->p_ident->i_saved++;
40986d7f5d3SJohn Marino 
41086d7f5d3SJohn Marino 				/* Shooter missed statistics: */
41186d7f5d3SJohn Marino 				if (bp->b_score != NULL)
41286d7f5d3SJohn Marino 					bp->b_score->i_missed += bp->b_charge;
41386d7f5d3SJohn Marino 
41486d7f5d3SJohn Marino 				/* Tell target that they were missed: */
41586d7f5d3SJohn Marino 				message(pp, "Zing!");
41686d7f5d3SJohn Marino 
41786d7f5d3SJohn Marino 				/* Tell the bullet owner they missed: */
41886d7f5d3SJohn Marino 				if (bp->b_owner != NULL)
41986d7f5d3SJohn Marino 				    message(bp->b_owner,
42086d7f5d3SJohn Marino 					((bp->b_score->i_missed & 0x7) == 0x7) ?
42186d7f5d3SJohn Marino 					"My!  What a bad shot you are!" :
42286d7f5d3SJohn Marino 					"Missed him");
42386d7f5d3SJohn Marino 
42486d7f5d3SJohn Marino 				/* Don't fall through */
42586d7f5d3SJohn Marino 				break;
42686d7f5d3SJohn Marino 			} else {
42786d7f5d3SJohn Marino 				/* The player is to be blown up: */
42886d7f5d3SJohn Marino 				bp->b_expl = TRUE;
42986d7f5d3SJohn Marino 			}
43086d7f5d3SJohn Marino 			break;
43186d7f5d3SJohn Marino 		  /* Bullet hits a wall, and always explodes: */
43286d7f5d3SJohn Marino 		  case WALL1:
43386d7f5d3SJohn Marino 		  case WALL2:
43486d7f5d3SJohn Marino 		  case WALL3:
43586d7f5d3SJohn Marino 			bp->b_expl = TRUE;
43686d7f5d3SJohn Marino 			break;
43786d7f5d3SJohn Marino 		}
43886d7f5d3SJohn Marino 
43986d7f5d3SJohn Marino 		/* Update the bullet's new position: */
44086d7f5d3SJohn Marino 		bp->b_x = x;
44186d7f5d3SJohn Marino 		bp->b_y = y;
44286d7f5d3SJohn Marino 	}
44386d7f5d3SJohn Marino 
44486d7f5d3SJohn Marino 	/* Caller should keep tracking the bullet: */
44586d7f5d3SJohn Marino 	return TRUE;
44686d7f5d3SJohn Marino }
44786d7f5d3SJohn Marino 
44886d7f5d3SJohn Marino /*
44986d7f5d3SJohn Marino  * move_drone:
45086d7f5d3SJohn Marino  *	Move the drone to the next square
45186d7f5d3SJohn Marino  *	Returns FALSE if the drone need no longer be tracked.
45286d7f5d3SJohn Marino  */
45386d7f5d3SJohn Marino static int
move_drone(BULLET * bp)45486d7f5d3SJohn Marino move_drone(BULLET *bp)
45586d7f5d3SJohn Marino {
45686d7f5d3SJohn Marino 	int	mask, count;
45786d7f5d3SJohn Marino 	int	n, dir = -1;
45886d7f5d3SJohn Marino 	PLAYER	*pp;
45986d7f5d3SJohn Marino 
46086d7f5d3SJohn Marino 	/* See if we can give someone a blast: */
46186d7f5d3SJohn Marino 	if (is_player(Maze[bp->b_y][bp->b_x - 1])) {
46286d7f5d3SJohn Marino 		dir = WEST;
46386d7f5d3SJohn Marino 		goto drone_move;
46486d7f5d3SJohn Marino 	}
46586d7f5d3SJohn Marino 	if (is_player(Maze[bp->b_y - 1][bp->b_x])) {
46686d7f5d3SJohn Marino 		dir = NORTH;
46786d7f5d3SJohn Marino 		goto drone_move;
46886d7f5d3SJohn Marino 	}
46986d7f5d3SJohn Marino 	if (is_player(Maze[bp->b_y + 1][bp->b_x])) {
47086d7f5d3SJohn Marino 		dir = SOUTH;
47186d7f5d3SJohn Marino 		goto drone_move;
47286d7f5d3SJohn Marino 	}
47386d7f5d3SJohn Marino 	if (is_player(Maze[bp->b_y][bp->b_x + 1])) {
47486d7f5d3SJohn Marino 		dir = EAST;
47586d7f5d3SJohn Marino 		goto drone_move;
47686d7f5d3SJohn Marino 	}
47786d7f5d3SJohn Marino 
47886d7f5d3SJohn Marino 	/* Find out what directions are clear and move that way: */
47986d7f5d3SJohn Marino 	mask = count = 0;
48086d7f5d3SJohn Marino 	if (!iswall(bp->b_y, bp->b_x - 1))
48186d7f5d3SJohn Marino 		mask |= WEST, count++;
48286d7f5d3SJohn Marino 	if (!iswall(bp->b_y - 1, bp->b_x))
48386d7f5d3SJohn Marino 		mask |= NORTH, count++;
48486d7f5d3SJohn Marino 	if (!iswall(bp->b_y + 1, bp->b_x))
48586d7f5d3SJohn Marino 		mask |= SOUTH, count++;
48686d7f5d3SJohn Marino 	if (!iswall(bp->b_y, bp->b_x + 1))
48786d7f5d3SJohn Marino 		mask |= EAST, count++;
48886d7f5d3SJohn Marino 
48986d7f5d3SJohn Marino 	/* All blocked up, just wait: */
49086d7f5d3SJohn Marino 	if (count == 0)
49186d7f5d3SJohn Marino 		return TRUE;
49286d7f5d3SJohn Marino 
49386d7f5d3SJohn Marino 	/* Only one way to go: */
49486d7f5d3SJohn Marino 	if (count == 1) {
49586d7f5d3SJohn Marino 		dir = mask;
49686d7f5d3SJohn Marino 		goto drone_move;
49786d7f5d3SJohn Marino 	}
49886d7f5d3SJohn Marino 
49986d7f5d3SJohn Marino 	/* Avoid backtracking, and remove the direction we came from: */
50086d7f5d3SJohn Marino 	switch (bp->b_face) {
50186d7f5d3SJohn Marino 	  case LEFTS:
50286d7f5d3SJohn Marino 		if (mask & EAST)
50386d7f5d3SJohn Marino 			mask &= ~EAST, count--;
50486d7f5d3SJohn Marino 		break;
50586d7f5d3SJohn Marino 	  case RIGHT:
50686d7f5d3SJohn Marino 		if (mask & WEST)
50786d7f5d3SJohn Marino 			mask &= ~WEST, count--;
50886d7f5d3SJohn Marino 		break;
50986d7f5d3SJohn Marino 	  case ABOVE:
51086d7f5d3SJohn Marino 		if (mask & SOUTH)
51186d7f5d3SJohn Marino 			mask &= ~SOUTH, count--;
51286d7f5d3SJohn Marino 		break;
51386d7f5d3SJohn Marino 	  case BELOW:
51486d7f5d3SJohn Marino 		if (mask & NORTH)
51586d7f5d3SJohn Marino 			mask &= ~NORTH, count--;
51686d7f5d3SJohn Marino 		break;
51786d7f5d3SJohn Marino 	}
51886d7f5d3SJohn Marino 
51986d7f5d3SJohn Marino 	/* Pick one of the remaining directions: */
52086d7f5d3SJohn Marino 	n = rand_num(count);
52186d7f5d3SJohn Marino 	if (n >= 0 && mask & NORTH)
52286d7f5d3SJohn Marino 		dir = NORTH, n--;
52386d7f5d3SJohn Marino 	if (n >= 0 && mask & SOUTH)
52486d7f5d3SJohn Marino 		dir = SOUTH, n--;
52586d7f5d3SJohn Marino 	if (n >= 0 && mask & EAST)
52686d7f5d3SJohn Marino 		dir = EAST, n--;
52786d7f5d3SJohn Marino 	if (n >= 0 && mask & WEST)
52886d7f5d3SJohn Marino 		dir = WEST, n--;
52986d7f5d3SJohn Marino 
53086d7f5d3SJohn Marino drone_move:
53186d7f5d3SJohn Marino 	/* Move the drone: */
53286d7f5d3SJohn Marino 	switch (dir) {
53386d7f5d3SJohn Marino 	  case -1:
53486d7f5d3SJohn Marino 		/* no move */
53586d7f5d3SJohn Marino 	  case WEST:
53686d7f5d3SJohn Marino 		bp->b_x--;
53786d7f5d3SJohn Marino 		bp->b_face = LEFTS;
53886d7f5d3SJohn Marino 		break;
53986d7f5d3SJohn Marino 	  case EAST:
54086d7f5d3SJohn Marino 		bp->b_x++;
54186d7f5d3SJohn Marino 		bp->b_face = RIGHT;
54286d7f5d3SJohn Marino 		break;
54386d7f5d3SJohn Marino 	  case NORTH:
54486d7f5d3SJohn Marino 		bp->b_y--;
54586d7f5d3SJohn Marino 		bp->b_face = ABOVE;
54686d7f5d3SJohn Marino 		break;
54786d7f5d3SJohn Marino 	  case SOUTH:
54886d7f5d3SJohn Marino 		bp->b_y++;
54986d7f5d3SJohn Marino 		bp->b_face = BELOW;
55086d7f5d3SJohn Marino 		break;
55186d7f5d3SJohn Marino 	}
55286d7f5d3SJohn Marino 
55386d7f5d3SJohn Marino 	/* Look at what the drone moved onto: */
55486d7f5d3SJohn Marino 	switch (Maze[bp->b_y][bp->b_x]) {
55586d7f5d3SJohn Marino 	  case LEFTS:
55686d7f5d3SJohn Marino 	  case RIGHT:
55786d7f5d3SJohn Marino 	  case BELOW:
55886d7f5d3SJohn Marino 	  case ABOVE:
55986d7f5d3SJohn Marino 		/*
56086d7f5d3SJohn Marino 		 * Players have a 1% chance of absorbing a drone,
56186d7f5d3SJohn Marino 		 * if they are facing it.
56286d7f5d3SJohn Marino 		 */
56386d7f5d3SJohn Marino 		if (rand_num(100) < conf_pdroneabsorb && opposite(bp->b_face,
56486d7f5d3SJohn Marino 		    Maze[bp->b_y][bp->b_x])) {
56586d7f5d3SJohn Marino 
56686d7f5d3SJohn Marino 			/* Feel the power: */
56786d7f5d3SJohn Marino 			pp = play_at(bp->b_y, bp->b_x);
56886d7f5d3SJohn Marino 			pp->p_ammo += bp->b_charge;
56986d7f5d3SJohn Marino 			message(pp, "**** Absorbed drone ****");
57086d7f5d3SJohn Marino 
57186d7f5d3SJohn Marino 			/* Release drone storage: */
57286d7f5d3SJohn Marino 			free(bp);
57386d7f5d3SJohn Marino 
57486d7f5d3SJohn Marino 			/* Update ammo: */
57586d7f5d3SJohn Marino 			ammo_update(pp);
57686d7f5d3SJohn Marino 
57786d7f5d3SJohn Marino 			/* No need for caller to keep tracking drone: */
57886d7f5d3SJohn Marino 			return FALSE;
57986d7f5d3SJohn Marino 		}
58086d7f5d3SJohn Marino 		/* Detonate the drone: */
58186d7f5d3SJohn Marino 		bp->b_expl = TRUE;
58286d7f5d3SJohn Marino 		break;
58386d7f5d3SJohn Marino 	}
58486d7f5d3SJohn Marino 
58586d7f5d3SJohn Marino 	/* Keep tracking the drone. */
58686d7f5d3SJohn Marino 	return TRUE;
58786d7f5d3SJohn Marino }
58886d7f5d3SJohn Marino 
58986d7f5d3SJohn Marino /*
59086d7f5d3SJohn Marino  * save_bullet:
59186d7f5d3SJohn Marino  *	Put a bullet back onto the bullet list
59286d7f5d3SJohn Marino  */
59386d7f5d3SJohn Marino static void
save_bullet(BULLET * bp)59486d7f5d3SJohn Marino save_bullet(BULLET *bp)
59586d7f5d3SJohn Marino {
59686d7f5d3SJohn Marino 
59786d7f5d3SJohn Marino 	/* Save what the bullet will be flying over: */
59886d7f5d3SJohn Marino 	bp->b_over = Maze[bp->b_y][bp->b_x];
59986d7f5d3SJohn Marino 
60086d7f5d3SJohn Marino 	switch (bp->b_over) {
60186d7f5d3SJohn Marino 	  /* Bullets that can pass through each other: */
60286d7f5d3SJohn Marino 	  case SHOT:
60386d7f5d3SJohn Marino 	  case GRENADE:
60486d7f5d3SJohn Marino 	  case SATCHEL:
60586d7f5d3SJohn Marino 	  case BOMB:
60686d7f5d3SJohn Marino 	  case SLIME:
60786d7f5d3SJohn Marino 	  case LAVA:
60886d7f5d3SJohn Marino 	  case DSHOT:
60986d7f5d3SJohn Marino 		find_under(Bullets, bp);
61086d7f5d3SJohn Marino 		break;
61186d7f5d3SJohn Marino 	}
61286d7f5d3SJohn Marino 
61386d7f5d3SJohn Marino 	switch (bp->b_over) {
61486d7f5d3SJohn Marino 	  /* A bullet hits a player: */
61586d7f5d3SJohn Marino 	  case LEFTS:
61686d7f5d3SJohn Marino 	  case RIGHT:
61786d7f5d3SJohn Marino 	  case ABOVE:
61886d7f5d3SJohn Marino 	  case BELOW:
61986d7f5d3SJohn Marino 	  case FLYER:
62086d7f5d3SJohn Marino 		mark_player(bp);
62186d7f5d3SJohn Marino 		break;
62286d7f5d3SJohn Marino 
62386d7f5d3SJohn Marino 	  /* A bullet passes a boot: */
62486d7f5d3SJohn Marino 	  case BOOT:
62586d7f5d3SJohn Marino 	  case BOOT_PAIR:
62686d7f5d3SJohn Marino 		mark_boot(bp);
62786d7f5d3SJohn Marino 		/* FALLTHROUGH */
62886d7f5d3SJohn Marino 
62986d7f5d3SJohn Marino 	  /* The bullet flies over everything else: */
63086d7f5d3SJohn Marino 	  default:
63186d7f5d3SJohn Marino 		Maze[bp->b_y][bp->b_x] = bp->b_type;
63286d7f5d3SJohn Marino 		break;
63386d7f5d3SJohn Marino 	}
63486d7f5d3SJohn Marino 
63586d7f5d3SJohn Marino 	/* Insert the bullet into the Bullets list: */
63686d7f5d3SJohn Marino 	bp->b_next = Bullets;
63786d7f5d3SJohn Marino 	Bullets = bp;
63886d7f5d3SJohn Marino }
63986d7f5d3SJohn Marino 
64086d7f5d3SJohn Marino /*
64186d7f5d3SJohn Marino  * move_flyer:
64286d7f5d3SJohn Marino  *	Update the position of a player in flight
64386d7f5d3SJohn Marino  */
64486d7f5d3SJohn Marino static void
move_flyer(PLAYER * pp)64586d7f5d3SJohn Marino move_flyer(PLAYER *pp)
64686d7f5d3SJohn Marino {
64786d7f5d3SJohn Marino 	int	x, y;
64886d7f5d3SJohn Marino 
64986d7f5d3SJohn Marino 	if (pp->p_undershot) {
65086d7f5d3SJohn Marino 		fixshots(pp->p_y, pp->p_x, pp->p_over);
65186d7f5d3SJohn Marino 		pp->p_undershot = FALSE;
65286d7f5d3SJohn Marino 	}
65386d7f5d3SJohn Marino 
65486d7f5d3SJohn Marino 	/* Restore what the flier was flying over */
65586d7f5d3SJohn Marino 	Maze[pp->p_y][pp->p_x] = pp->p_over;
65686d7f5d3SJohn Marino 
65786d7f5d3SJohn Marino 	/* Fly: */
65886d7f5d3SJohn Marino 	x = pp->p_x + pp->p_flyx;
65986d7f5d3SJohn Marino 	y = pp->p_y + pp->p_flyy;
66086d7f5d3SJohn Marino 
66186d7f5d3SJohn Marino 	/* Bouncing off the edges of the maze: */
66286d7f5d3SJohn Marino 	if (x < 1) {
66386d7f5d3SJohn Marino 		x = 1 - x;
66486d7f5d3SJohn Marino 		pp->p_flyx = -pp->p_flyx;
66586d7f5d3SJohn Marino 	}
66686d7f5d3SJohn Marino 	else if (x > WIDTH - 2) {
66786d7f5d3SJohn Marino 		x = (WIDTH - 2) - (x - (WIDTH - 2));
66886d7f5d3SJohn Marino 		pp->p_flyx = -pp->p_flyx;
66986d7f5d3SJohn Marino 	}
67086d7f5d3SJohn Marino 	if (y < 1) {
67186d7f5d3SJohn Marino 		y = 1 - y;
67286d7f5d3SJohn Marino 		pp->p_flyy = -pp->p_flyy;
67386d7f5d3SJohn Marino 	}
67486d7f5d3SJohn Marino 	else if (y > HEIGHT - 2) {
67586d7f5d3SJohn Marino 		y = (HEIGHT - 2) - (y - (HEIGHT - 2));
67686d7f5d3SJohn Marino 		pp->p_flyy = -pp->p_flyy;
67786d7f5d3SJohn Marino 	}
67886d7f5d3SJohn Marino 
67986d7f5d3SJohn Marino 	/* Make sure we don't land on something we can't: */
68086d7f5d3SJohn Marino again:
68186d7f5d3SJohn Marino 	switch (Maze[y][x]) {
68286d7f5d3SJohn Marino 	  default:
68386d7f5d3SJohn Marino 		/*
68486d7f5d3SJohn Marino 		 * Flier is over something other than space, a wall
68586d7f5d3SJohn Marino 		 * or a door. Randomly move (drift) the flier a little bit
68686d7f5d3SJohn Marino 		 * and then try again:
68786d7f5d3SJohn Marino 		 */
68886d7f5d3SJohn Marino 		switch (rand_num(4)) {
68986d7f5d3SJohn Marino 		  case 0:
69086d7f5d3SJohn Marino 			PLUS_DELTA(x, WIDTH - 2);
69186d7f5d3SJohn Marino 			break;
69286d7f5d3SJohn Marino 		  case 1:
69386d7f5d3SJohn Marino 			MINUS_DELTA(x, 1);
69486d7f5d3SJohn Marino 			break;
69586d7f5d3SJohn Marino 		  case 2:
69686d7f5d3SJohn Marino 			PLUS_DELTA(y, HEIGHT - 2);
69786d7f5d3SJohn Marino 			break;
69886d7f5d3SJohn Marino 		  case 3:
69986d7f5d3SJohn Marino 			MINUS_DELTA(y, 1);
70086d7f5d3SJohn Marino 			break;
70186d7f5d3SJohn Marino 		}
70286d7f5d3SJohn Marino 		goto again;
70386d7f5d3SJohn Marino 	  /* Give a little boost when about to land on a wall or door: */
70486d7f5d3SJohn Marino 	  case WALL1:
70586d7f5d3SJohn Marino 	  case WALL2:
70686d7f5d3SJohn Marino 	  case WALL3:
70786d7f5d3SJohn Marino 	  case WALL4:
70886d7f5d3SJohn Marino 	  case WALL5:
70986d7f5d3SJohn Marino 	  case DOOR:
71086d7f5d3SJohn Marino 		if (pp->p_flying == 0)
71186d7f5d3SJohn Marino 			pp->p_flying++;
71286d7f5d3SJohn Marino 		break;
71386d7f5d3SJohn Marino 	  /* Spaces are okay: */
71486d7f5d3SJohn Marino 	  case SPACE:
71586d7f5d3SJohn Marino 		break;
71686d7f5d3SJohn Marino 	}
71786d7f5d3SJohn Marino 
71886d7f5d3SJohn Marino 	/* Update flier's coordinates: */
71986d7f5d3SJohn Marino 	pp->p_y = y;
72086d7f5d3SJohn Marino 	pp->p_x = x;
72186d7f5d3SJohn Marino 
72286d7f5d3SJohn Marino 	/* Consume 'flying' time: */
72386d7f5d3SJohn Marino 	if (pp->p_flying-- == 0) {
72486d7f5d3SJohn Marino 		/* Land: */
72586d7f5d3SJohn Marino 		if (pp->p_face != BOOT && pp->p_face != BOOT_PAIR) {
72686d7f5d3SJohn Marino 			/* Land a player - they stustain a fall: */
72786d7f5d3SJohn Marino 			checkdam(pp, NULL, NULL,
72886d7f5d3SJohn Marino 				rand_num(pp->p_damage / conf_fall_frac), FALL);
72986d7f5d3SJohn Marino 			pp->p_face = rand_dir();
73086d7f5d3SJohn Marino 			showstat(pp);
73186d7f5d3SJohn Marino 		} else {
73286d7f5d3SJohn Marino 			/* Land boots: */
73386d7f5d3SJohn Marino 			if (Maze[y][x] == BOOT)
73486d7f5d3SJohn Marino 				pp->p_face = BOOT_PAIR;
73586d7f5d3SJohn Marino 			Maze[y][x] = SPACE;
73686d7f5d3SJohn Marino 		}
73786d7f5d3SJohn Marino 	}
73886d7f5d3SJohn Marino 
73986d7f5d3SJohn Marino 	/* Save under the flier: */
74086d7f5d3SJohn Marino 	pp->p_over = Maze[y][x];
74186d7f5d3SJohn Marino 	/* Draw in the flier: */
74286d7f5d3SJohn Marino 	Maze[y][x] = pp->p_face;
74386d7f5d3SJohn Marino 	showexpl(y, x, pp->p_face);
74486d7f5d3SJohn Marino }
74586d7f5d3SJohn Marino 
74686d7f5d3SJohn Marino /*
74786d7f5d3SJohn Marino  * chkshot
74886d7f5d3SJohn Marino  *	Handle explosions
74986d7f5d3SJohn Marino  */
75086d7f5d3SJohn Marino static void
chkshot(BULLET * bp,BULLET * next)75186d7f5d3SJohn Marino chkshot(BULLET *bp, BULLET *next)
75286d7f5d3SJohn Marino {
75386d7f5d3SJohn Marino 	int	y, x;
75486d7f5d3SJohn Marino 	int	dy, dx, absdy;
75586d7f5d3SJohn Marino 	int	delta, damage;
75686d7f5d3SJohn Marino 	char	expl;
75786d7f5d3SJohn Marino 	PLAYER	*pp;
75886d7f5d3SJohn Marino 
75986d7f5d3SJohn Marino 	delta = 0;
76086d7f5d3SJohn Marino 	switch (bp->b_type) {
76186d7f5d3SJohn Marino 	  case SHOT:
76286d7f5d3SJohn Marino 	  case MINE:
76386d7f5d3SJohn Marino 	  case GRENADE:
76486d7f5d3SJohn Marino 	  case GMINE:
76586d7f5d3SJohn Marino 	  case SATCHEL:
76686d7f5d3SJohn Marino 	  case BOMB:
76786d7f5d3SJohn Marino 		delta = bp->b_size - 1;
76886d7f5d3SJohn Marino 		break;
76986d7f5d3SJohn Marino 	  case SLIME:
77086d7f5d3SJohn Marino 	  case LAVA:
77186d7f5d3SJohn Marino 		chkslime(bp, next);
77286d7f5d3SJohn Marino 		return;
77386d7f5d3SJohn Marino 	  case DSHOT:
77486d7f5d3SJohn Marino 		bp->b_type = SLIME;
77586d7f5d3SJohn Marino 		chkslime(bp, next);
77686d7f5d3SJohn Marino 		return;
77786d7f5d3SJohn Marino 	}
77886d7f5d3SJohn Marino 
77986d7f5d3SJohn Marino 	/* Draw the explosion square: */
78086d7f5d3SJohn Marino 	for (y = bp->b_y - delta; y <= bp->b_y + delta; y++) {
78186d7f5d3SJohn Marino 		if (y < 0 || y >= HEIGHT)
78286d7f5d3SJohn Marino 			continue;
78386d7f5d3SJohn Marino 		dy = y - bp->b_y;
78486d7f5d3SJohn Marino 		absdy = (dy < 0) ? -dy : dy;
78586d7f5d3SJohn Marino 		for (x = bp->b_x - delta; x <= bp->b_x + delta; x++) {
78686d7f5d3SJohn Marino 			/* Draw a part of the explosion cloud: */
78786d7f5d3SJohn Marino 			if (x < 0 || x >= WIDTH)
78886d7f5d3SJohn Marino 				continue;
78986d7f5d3SJohn Marino 			dx = x - bp->b_x;
79086d7f5d3SJohn Marino 			if (dx == 0)
79186d7f5d3SJohn Marino 				expl = (dy == 0) ? '*' : '|';
79286d7f5d3SJohn Marino 			else if (dy == 0)
79386d7f5d3SJohn Marino 				expl = '-';
79486d7f5d3SJohn Marino 			else if (dx == dy)
79586d7f5d3SJohn Marino 				expl = '\\';
79686d7f5d3SJohn Marino 			else if (dx == -dy)
79786d7f5d3SJohn Marino 				expl = '/';
79886d7f5d3SJohn Marino 			else
79986d7f5d3SJohn Marino 				expl = '*';
80086d7f5d3SJohn Marino 			showexpl(y, x, expl);
80186d7f5d3SJohn Marino 
80286d7f5d3SJohn Marino 			/* Check what poor bastard was in the explosion: */
80386d7f5d3SJohn Marino 			switch (Maze[y][x]) {
80486d7f5d3SJohn Marino 			  case LEFTS:
80586d7f5d3SJohn Marino 			  case RIGHT:
80686d7f5d3SJohn Marino 			  case ABOVE:
80786d7f5d3SJohn Marino 			  case BELOW:
80886d7f5d3SJohn Marino 			  case FLYER:
80986d7f5d3SJohn Marino 				if (dx < 0)
81086d7f5d3SJohn Marino 					dx = -dx;
81186d7f5d3SJohn Marino 				if (absdy > dx)
81286d7f5d3SJohn Marino 					damage = bp->b_size - absdy;
81386d7f5d3SJohn Marino 				else
81486d7f5d3SJohn Marino 					damage = bp->b_size - dx;
81586d7f5d3SJohn Marino 
81686d7f5d3SJohn Marino 				/* Everybody hurts, sometimes. */
81786d7f5d3SJohn Marino 				pp = play_at(y, x);
81886d7f5d3SJohn Marino 				checkdam(pp, bp->b_owner, bp->b_score,
81986d7f5d3SJohn Marino 					damage * conf_mindam, bp->b_type);
82086d7f5d3SJohn Marino 				break;
82186d7f5d3SJohn Marino 			  case GMINE:
82286d7f5d3SJohn Marino 			  case MINE:
82386d7f5d3SJohn Marino 				/* Mines detonate in a chain reaction: */
82486d7f5d3SJohn Marino 				add_shot((Maze[y][x] == GMINE) ?
82586d7f5d3SJohn Marino 					GRENADE : SHOT,
82686d7f5d3SJohn Marino 					y, x, LEFTS,
82786d7f5d3SJohn Marino 					(Maze[y][x] == GMINE) ?
82886d7f5d3SJohn Marino 					GRENREQ : BULREQ,
82986d7f5d3SJohn Marino 					NULL, TRUE, SPACE);
83086d7f5d3SJohn Marino 				Maze[y][x] = SPACE;
83186d7f5d3SJohn Marino 				break;
83286d7f5d3SJohn Marino 			}
83386d7f5d3SJohn Marino 		}
83486d7f5d3SJohn Marino 	}
83586d7f5d3SJohn Marino }
83686d7f5d3SJohn Marino 
83786d7f5d3SJohn Marino /*
83886d7f5d3SJohn Marino  * chkslime:
83986d7f5d3SJohn Marino  *	handle slime shot exploding
84086d7f5d3SJohn Marino  */
84186d7f5d3SJohn Marino static void
chkslime(BULLET * bp,BULLET * next)84286d7f5d3SJohn Marino chkslime(BULLET *bp, BULLET *next)
84386d7f5d3SJohn Marino {
84486d7f5d3SJohn Marino 	BULLET	*nbp;
84586d7f5d3SJohn Marino 
84686d7f5d3SJohn Marino 	switch (Maze[bp->b_y][bp->b_x]) {
84786d7f5d3SJohn Marino 	  /* Slime explodes on walls and doors: */
84886d7f5d3SJohn Marino 	  case WALL1:
84986d7f5d3SJohn Marino 	  case WALL2:
85086d7f5d3SJohn Marino 	  case WALL3:
85186d7f5d3SJohn Marino 	  case WALL4:
85286d7f5d3SJohn Marino 	  case WALL5:
85386d7f5d3SJohn Marino 	  case DOOR:
85486d7f5d3SJohn Marino 		switch (bp->b_face) {
85586d7f5d3SJohn Marino 		  case LEFTS:
85686d7f5d3SJohn Marino 			bp->b_x++;
85786d7f5d3SJohn Marino 			break;
85886d7f5d3SJohn Marino 		  case RIGHT:
85986d7f5d3SJohn Marino 			bp->b_x--;
86086d7f5d3SJohn Marino 			break;
86186d7f5d3SJohn Marino 		  case ABOVE:
86286d7f5d3SJohn Marino 			bp->b_y++;
86386d7f5d3SJohn Marino 			break;
86486d7f5d3SJohn Marino 		  case BELOW:
86586d7f5d3SJohn Marino 			bp->b_y--;
86686d7f5d3SJohn Marino 			break;
86786d7f5d3SJohn Marino 		}
86886d7f5d3SJohn Marino 		break;
86986d7f5d3SJohn Marino 	}
87086d7f5d3SJohn Marino 
87186d7f5d3SJohn Marino 	/* Duplicate the unit of slime: */
87286d7f5d3SJohn Marino 	nbp = (BULLET *) malloc(sizeof (BULLET));
87386d7f5d3SJohn Marino 	if (nbp == NULL) {
87486d7f5d3SJohn Marino 		logit(LOG_ERR, "malloc");
87586d7f5d3SJohn Marino 		return;
87686d7f5d3SJohn Marino 	}
87786d7f5d3SJohn Marino 	*nbp = *bp;
87886d7f5d3SJohn Marino 
87986d7f5d3SJohn Marino 	/* Move it around: */
88086d7f5d3SJohn Marino 	move_slime(nbp, nbp->b_type == SLIME ? conf_slimespeed :
88186d7f5d3SJohn Marino 	    conf_lavaspeed, next);
88286d7f5d3SJohn Marino }
88386d7f5d3SJohn Marino 
88486d7f5d3SJohn Marino /*
88586d7f5d3SJohn Marino  * move_slime:
88686d7f5d3SJohn Marino  *	move the given slime shot speed times and add it back if
88786d7f5d3SJohn Marino  *	it hasn't fizzled yet
88886d7f5d3SJohn Marino  */
88986d7f5d3SJohn Marino static void
move_slime(BULLET * bp,int speed,BULLET * next)89086d7f5d3SJohn Marino move_slime(BULLET *bp, int speed, BULLET *next)
89186d7f5d3SJohn Marino {
89286d7f5d3SJohn Marino 	int	i, j, dirmask, count;
89386d7f5d3SJohn Marino 	PLAYER	*pp;
89486d7f5d3SJohn Marino 	BULLET	*nbp;
89586d7f5d3SJohn Marino 
89686d7f5d3SJohn Marino 	if (speed == 0) {
89786d7f5d3SJohn Marino 		if (bp->b_charge <= 0)
89886d7f5d3SJohn Marino 			free(bp);
89986d7f5d3SJohn Marino 		else
90086d7f5d3SJohn Marino 			save_bullet(bp);
90186d7f5d3SJohn Marino 		return;
90286d7f5d3SJohn Marino 	}
90386d7f5d3SJohn Marino 
90486d7f5d3SJohn Marino 	/* Draw it: */
90586d7f5d3SJohn Marino 	showexpl(bp->b_y, bp->b_x, bp->b_type == LAVA ? LAVA : '*');
90686d7f5d3SJohn Marino 
90786d7f5d3SJohn Marino 	switch (Maze[bp->b_y][bp->b_x]) {
90886d7f5d3SJohn Marino 	  /* Someone got hit by slime or lava: */
90986d7f5d3SJohn Marino 	  case LEFTS:
91086d7f5d3SJohn Marino 	  case RIGHT:
91186d7f5d3SJohn Marino 	  case ABOVE:
91286d7f5d3SJohn Marino 	  case BELOW:
91386d7f5d3SJohn Marino 	  case FLYER:
91486d7f5d3SJohn Marino 		pp = play_at(bp->b_y, bp->b_x);
91586d7f5d3SJohn Marino 		message(pp, "You've been slimed.");
91686d7f5d3SJohn Marino 		checkdam(pp, bp->b_owner, bp->b_score, conf_mindam, bp->b_type);
91786d7f5d3SJohn Marino 		break;
91886d7f5d3SJohn Marino 	  /* Bullets detonate in slime and lava: */
91986d7f5d3SJohn Marino 	  case SHOT:
92086d7f5d3SJohn Marino 	  case GRENADE:
92186d7f5d3SJohn Marino 	  case SATCHEL:
92286d7f5d3SJohn Marino 	  case BOMB:
92386d7f5d3SJohn Marino 	  case DSHOT:
92486d7f5d3SJohn Marino 		explshot(next, bp->b_y, bp->b_x);
92586d7f5d3SJohn Marino 		explshot(Bullets, bp->b_y, bp->b_x);
92686d7f5d3SJohn Marino 		break;
92786d7f5d3SJohn Marino 	}
92886d7f5d3SJohn Marino 
92986d7f5d3SJohn Marino 
93086d7f5d3SJohn Marino 	/* Drain the slime/lava of some energy: */
93186d7f5d3SJohn Marino 	if (--bp->b_charge <= 0) {
93286d7f5d3SJohn Marino 		/* It fizzled: */
93386d7f5d3SJohn Marino 		free(bp);
93486d7f5d3SJohn Marino 		return;
93586d7f5d3SJohn Marino 	}
93686d7f5d3SJohn Marino 
93786d7f5d3SJohn Marino 	/* Figure out which way the slime should flow: */
93886d7f5d3SJohn Marino 	dirmask = 0;
93986d7f5d3SJohn Marino 	count = 0;
94086d7f5d3SJohn Marino 	switch (bp->b_face) {
94186d7f5d3SJohn Marino 	  case LEFTS:
94286d7f5d3SJohn Marino 		if (!iswall(bp->b_y, bp->b_x - 1))
94386d7f5d3SJohn Marino 			dirmask |= WEST, count++;
94486d7f5d3SJohn Marino 		if (!iswall(bp->b_y - 1, bp->b_x))
94586d7f5d3SJohn Marino 			dirmask |= NORTH, count++;
94686d7f5d3SJohn Marino 		if (!iswall(bp->b_y + 1, bp->b_x))
94786d7f5d3SJohn Marino 			dirmask |= SOUTH, count++;
94886d7f5d3SJohn Marino 		if (dirmask == 0)
94986d7f5d3SJohn Marino 			if (!iswall(bp->b_y, bp->b_x + 1))
95086d7f5d3SJohn Marino 				dirmask |= EAST, count++;
95186d7f5d3SJohn Marino 		break;
95286d7f5d3SJohn Marino 	  case RIGHT:
95386d7f5d3SJohn Marino 		if (!iswall(bp->b_y, bp->b_x + 1))
95486d7f5d3SJohn Marino 			dirmask |= EAST, count++;
95586d7f5d3SJohn Marino 		if (!iswall(bp->b_y - 1, bp->b_x))
95686d7f5d3SJohn Marino 			dirmask |= NORTH, count++;
95786d7f5d3SJohn Marino 		if (!iswall(bp->b_y + 1, bp->b_x))
95886d7f5d3SJohn Marino 			dirmask |= SOUTH, count++;
95986d7f5d3SJohn Marino 		if (dirmask == 0)
96086d7f5d3SJohn Marino 			if (!iswall(bp->b_y, bp->b_x - 1))
96186d7f5d3SJohn Marino 				dirmask |= WEST, count++;
96286d7f5d3SJohn Marino 		break;
96386d7f5d3SJohn Marino 	  case ABOVE:
96486d7f5d3SJohn Marino 		if (!iswall(bp->b_y - 1, bp->b_x))
96586d7f5d3SJohn Marino 			dirmask |= NORTH, count++;
96686d7f5d3SJohn Marino 		if (!iswall(bp->b_y, bp->b_x - 1))
96786d7f5d3SJohn Marino 			dirmask |= WEST, count++;
96886d7f5d3SJohn Marino 		if (!iswall(bp->b_y, bp->b_x + 1))
96986d7f5d3SJohn Marino 			dirmask |= EAST, count++;
97086d7f5d3SJohn Marino 		if (dirmask == 0)
97186d7f5d3SJohn Marino 			if (!iswall(bp->b_y + 1, bp->b_x))
97286d7f5d3SJohn Marino 				dirmask |= SOUTH, count++;
97386d7f5d3SJohn Marino 		break;
97486d7f5d3SJohn Marino 	  case BELOW:
97586d7f5d3SJohn Marino 		if (!iswall(bp->b_y + 1, bp->b_x))
97686d7f5d3SJohn Marino 			dirmask |= SOUTH, count++;
97786d7f5d3SJohn Marino 		if (!iswall(bp->b_y, bp->b_x - 1))
97886d7f5d3SJohn Marino 			dirmask |= WEST, count++;
97986d7f5d3SJohn Marino 		if (!iswall(bp->b_y, bp->b_x + 1))
98086d7f5d3SJohn Marino 			dirmask |= EAST, count++;
98186d7f5d3SJohn Marino 		if (dirmask == 0)
98286d7f5d3SJohn Marino 			if (!iswall(bp->b_y - 1, bp->b_x))
98386d7f5d3SJohn Marino 				dirmask |= NORTH, count++;
98486d7f5d3SJohn Marino 		break;
98586d7f5d3SJohn Marino 	}
98686d7f5d3SJohn Marino 	if (count == 0) {
98786d7f5d3SJohn Marino 		/*
98886d7f5d3SJohn Marino 		 * No place to go.  Just sit here for a while and wait
98986d7f5d3SJohn Marino 		 * for adjacent squares to clear out.
99086d7f5d3SJohn Marino 		 */
99186d7f5d3SJohn Marino 		save_bullet(bp);
99286d7f5d3SJohn Marino 		return;
99386d7f5d3SJohn Marino 	}
99486d7f5d3SJohn Marino 	if (bp->b_charge < count) {
99586d7f5d3SJohn Marino 		/* Only bp->b_charge paths may be taken */
99686d7f5d3SJohn Marino 		while (count > bp->b_charge) {
99786d7f5d3SJohn Marino 			if (dirmask & WEST)
99886d7f5d3SJohn Marino 				dirmask &= ~WEST;
99986d7f5d3SJohn Marino 			else if (dirmask & EAST)
100086d7f5d3SJohn Marino 				dirmask &= ~EAST;
100186d7f5d3SJohn Marino 			else if (dirmask & NORTH)
100286d7f5d3SJohn Marino 				dirmask &= ~NORTH;
100386d7f5d3SJohn Marino 			else if (dirmask & SOUTH)
100486d7f5d3SJohn Marino 				dirmask &= ~SOUTH;
100586d7f5d3SJohn Marino 			count--;
100686d7f5d3SJohn Marino 		}
100786d7f5d3SJohn Marino 	}
100886d7f5d3SJohn Marino 
100986d7f5d3SJohn Marino 	/* Spawn little slimes off in every possible direction: */
101086d7f5d3SJohn Marino 	i = bp->b_charge / count;
101186d7f5d3SJohn Marino 	j = bp->b_charge % count;
101286d7f5d3SJohn Marino 	if (dirmask & WEST) {
101386d7f5d3SJohn Marino 		count--;
101486d7f5d3SJohn Marino 		nbp = create_shot(bp->b_type, bp->b_y, bp->b_x - 1, LEFTS,
101586d7f5d3SJohn Marino 			i, bp->b_size, bp->b_owner, bp->b_score, TRUE, SPACE);
101686d7f5d3SJohn Marino 		move_slime(nbp, speed - 1, next);
101786d7f5d3SJohn Marino 	}
101886d7f5d3SJohn Marino 	if (dirmask & EAST) {
101986d7f5d3SJohn Marino 		count--;
102086d7f5d3SJohn Marino 		nbp = create_shot(bp->b_type, bp->b_y, bp->b_x + 1, RIGHT,
102186d7f5d3SJohn Marino 			(count < j) ? i + 1 : i, bp->b_size, bp->b_owner,
102286d7f5d3SJohn Marino 			bp->b_score, TRUE, SPACE);
102386d7f5d3SJohn Marino 		move_slime(nbp, speed - 1, next);
102486d7f5d3SJohn Marino 	}
102586d7f5d3SJohn Marino 	if (dirmask & NORTH) {
102686d7f5d3SJohn Marino 		count--;
102786d7f5d3SJohn Marino 		nbp = create_shot(bp->b_type, bp->b_y - 1, bp->b_x, ABOVE,
102886d7f5d3SJohn Marino 			(count < j) ? i + 1 : i, bp->b_size, bp->b_owner,
102986d7f5d3SJohn Marino 			bp->b_score, TRUE, SPACE);
103086d7f5d3SJohn Marino 		move_slime(nbp, speed - 1, next);
103186d7f5d3SJohn Marino 	}
103286d7f5d3SJohn Marino 	if (dirmask & SOUTH) {
103386d7f5d3SJohn Marino 		count--;
103486d7f5d3SJohn Marino 		nbp = create_shot(bp->b_type, bp->b_y + 1, bp->b_x, BELOW,
103586d7f5d3SJohn Marino 			(count < j) ? i + 1 : i, bp->b_size, bp->b_owner,
103686d7f5d3SJohn Marino 			bp->b_score, TRUE, SPACE);
103786d7f5d3SJohn Marino 		move_slime(nbp, speed - 1, next);
103886d7f5d3SJohn Marino 	}
103986d7f5d3SJohn Marino 
104086d7f5d3SJohn Marino 	free(bp);
104186d7f5d3SJohn Marino }
104286d7f5d3SJohn Marino 
104386d7f5d3SJohn Marino /*
104486d7f5d3SJohn Marino  * iswall:
104586d7f5d3SJohn Marino  *	returns whether the given location is a wall
104686d7f5d3SJohn Marino  */
104786d7f5d3SJohn Marino static int
iswall(int y,int x)104886d7f5d3SJohn Marino iswall(int y, int x)
104986d7f5d3SJohn Marino {
105086d7f5d3SJohn Marino 	if (y < 0 || x < 0 || y >= HEIGHT || x >= WIDTH)
105186d7f5d3SJohn Marino 		return TRUE;
105286d7f5d3SJohn Marino 	switch (Maze[y][x]) {
105386d7f5d3SJohn Marino 	  case WALL1:
105486d7f5d3SJohn Marino 	  case WALL2:
105586d7f5d3SJohn Marino 	  case WALL3:
105686d7f5d3SJohn Marino 	  case WALL4:
105786d7f5d3SJohn Marino 	  case WALL5:
105886d7f5d3SJohn Marino 	  case DOOR:
105986d7f5d3SJohn Marino 	  case SLIME:
106086d7f5d3SJohn Marino 	  case LAVA:
106186d7f5d3SJohn Marino 		return TRUE;
106286d7f5d3SJohn Marino 	}
106386d7f5d3SJohn Marino 	return FALSE;
106486d7f5d3SJohn Marino }
106586d7f5d3SJohn Marino 
106686d7f5d3SJohn Marino /*
106786d7f5d3SJohn Marino  * zapshot:
106886d7f5d3SJohn Marino  *	Take a shot out of the air.
106986d7f5d3SJohn Marino  */
107086d7f5d3SJohn Marino static void
zapshot(BULLET * blist,BULLET * obp)107186d7f5d3SJohn Marino zapshot(BULLET *blist, BULLET *obp)
107286d7f5d3SJohn Marino {
107386d7f5d3SJohn Marino 	BULLET	*bp;
107486d7f5d3SJohn Marino 
107586d7f5d3SJohn Marino 	for (bp = blist; bp != NULL; bp = bp->b_next) {
107686d7f5d3SJohn Marino 		/* Find co-located bullets not facing the same way: */
107786d7f5d3SJohn Marino 		if (bp->b_face != obp->b_face
107886d7f5d3SJohn Marino 		    && bp->b_x == obp->b_x && bp->b_y == obp->b_y)
107986d7f5d3SJohn Marino 		{
108086d7f5d3SJohn Marino 			/* Bullet collision: */
108186d7f5d3SJohn Marino 			explshot(blist, obp->b_y, obp->b_x);
108286d7f5d3SJohn Marino 			return;
108386d7f5d3SJohn Marino 		}
108486d7f5d3SJohn Marino 	}
108586d7f5d3SJohn Marino }
108686d7f5d3SJohn Marino 
108786d7f5d3SJohn Marino /*
108886d7f5d3SJohn Marino  * explshot -
108986d7f5d3SJohn Marino  *	Make all shots at this location blow up
109086d7f5d3SJohn Marino  */
109186d7f5d3SJohn Marino static void
explshot(BULLET * blist,int y,int x)109286d7f5d3SJohn Marino explshot(BULLET *blist, int y, int x)
109386d7f5d3SJohn Marino {
109486d7f5d3SJohn Marino 	BULLET	*bp;
109586d7f5d3SJohn Marino 
109686d7f5d3SJohn Marino 	for (bp = blist; bp != NULL; bp = bp->b_next)
109786d7f5d3SJohn Marino 		if (bp->b_x == x && bp->b_y == y) {
109886d7f5d3SJohn Marino 			bp->b_expl = TRUE;
109986d7f5d3SJohn Marino 			if (bp->b_owner != NULL)
110086d7f5d3SJohn Marino 				message(bp->b_owner, "Shot intercepted.");
110186d7f5d3SJohn Marino 		}
110286d7f5d3SJohn Marino }
110386d7f5d3SJohn Marino 
110486d7f5d3SJohn Marino /*
110586d7f5d3SJohn Marino  * play_at:
110686d7f5d3SJohn Marino  *	Return a pointer to the player at the given location
110786d7f5d3SJohn Marino  */
110886d7f5d3SJohn Marino PLAYER *
play_at(int y,int x)110986d7f5d3SJohn Marino play_at(int y, int x)
111086d7f5d3SJohn Marino {
111186d7f5d3SJohn Marino 	PLAYER	*pp;
111286d7f5d3SJohn Marino 
111386d7f5d3SJohn Marino 	for (pp = Player; pp < End_player; pp++)
111486d7f5d3SJohn Marino 		if (pp->p_x == x && pp->p_y == y)
111586d7f5d3SJohn Marino 			return pp;
111686d7f5d3SJohn Marino 
111786d7f5d3SJohn Marino 	/* Internal fault: */
111886d7f5d3SJohn Marino 	logx(LOG_ERR, "play_at: not a player");
111986d7f5d3SJohn Marino 	abort();
112086d7f5d3SJohn Marino }
112186d7f5d3SJohn Marino 
112286d7f5d3SJohn Marino /*
112386d7f5d3SJohn Marino  * opposite:
112486d7f5d3SJohn Marino  *	Return TRUE if the bullet direction faces the opposite direction
112586d7f5d3SJohn Marino  *	of the player in the maze
112686d7f5d3SJohn Marino  */
112786d7f5d3SJohn Marino int
opposite(int face,char dir)112886d7f5d3SJohn Marino opposite(int face, char dir)
112986d7f5d3SJohn Marino {
113086d7f5d3SJohn Marino 	switch (face) {
113186d7f5d3SJohn Marino 	  case LEFTS:
113286d7f5d3SJohn Marino 		return (dir == RIGHT);
113386d7f5d3SJohn Marino 	  case RIGHT:
113486d7f5d3SJohn Marino 		return (dir == LEFTS);
113586d7f5d3SJohn Marino 	  case ABOVE:
113686d7f5d3SJohn Marino 		return (dir == BELOW);
113786d7f5d3SJohn Marino 	  case BELOW:
113886d7f5d3SJohn Marino 		return (dir == ABOVE);
113986d7f5d3SJohn Marino 	  default:
114086d7f5d3SJohn Marino 		return FALSE;
114186d7f5d3SJohn Marino 	}
114286d7f5d3SJohn Marino }
114386d7f5d3SJohn Marino 
114486d7f5d3SJohn Marino /*
114586d7f5d3SJohn Marino  * is_bullet:
114686d7f5d3SJohn Marino  *	Is there a bullet at the given coordinates?  If so, return
114786d7f5d3SJohn Marino  *	a pointer to the bullet, otherwise return NULL
114886d7f5d3SJohn Marino  */
114986d7f5d3SJohn Marino BULLET *
is_bullet(int y,int x)115086d7f5d3SJohn Marino is_bullet(int y, int x)
115186d7f5d3SJohn Marino {
115286d7f5d3SJohn Marino 	BULLET	*bp;
115386d7f5d3SJohn Marino 
115486d7f5d3SJohn Marino 	for (bp = Bullets; bp != NULL; bp = bp->b_next)
115586d7f5d3SJohn Marino 		if (bp->b_y == y && bp->b_x == x)
115686d7f5d3SJohn Marino 			return bp;
115786d7f5d3SJohn Marino 	return NULL;
115886d7f5d3SJohn Marino }
115986d7f5d3SJohn Marino 
116086d7f5d3SJohn Marino /*
116186d7f5d3SJohn Marino  * fixshots:
116286d7f5d3SJohn Marino  *	change the underlying character of the shots at a location
116386d7f5d3SJohn Marino  *	to the given character.
116486d7f5d3SJohn Marino  */
116586d7f5d3SJohn Marino void
fixshots(int y,int x,char over)116686d7f5d3SJohn Marino fixshots(int y, int x, char over)
116786d7f5d3SJohn Marino {
116886d7f5d3SJohn Marino 	BULLET	*bp;
116986d7f5d3SJohn Marino 
117086d7f5d3SJohn Marino 	for (bp = Bullets; bp != NULL; bp = bp->b_next)
117186d7f5d3SJohn Marino 		if (bp->b_y == y && bp->b_x == x)
117286d7f5d3SJohn Marino 			bp->b_over = over;
117386d7f5d3SJohn Marino }
117486d7f5d3SJohn Marino 
117586d7f5d3SJohn Marino /*
117686d7f5d3SJohn Marino  * find_under:
117786d7f5d3SJohn Marino  *	find the underlying character for a bullet when it lands
117886d7f5d3SJohn Marino  *	on another bullet.
117986d7f5d3SJohn Marino  */
118086d7f5d3SJohn Marino static void
find_under(BULLET * blist,BULLET * bp)118186d7f5d3SJohn Marino find_under(BULLET *blist, BULLET *bp)
118286d7f5d3SJohn Marino {
118386d7f5d3SJohn Marino 	BULLET	*nbp;
118486d7f5d3SJohn Marino 
118586d7f5d3SJohn Marino 	for (nbp = blist; nbp != NULL; nbp = nbp->b_next)
118686d7f5d3SJohn Marino 		if (bp->b_y == nbp->b_y && bp->b_x == nbp->b_x) {
118786d7f5d3SJohn Marino 			bp->b_over = nbp->b_over;
118886d7f5d3SJohn Marino 			break;
118986d7f5d3SJohn Marino 		}
119086d7f5d3SJohn Marino }
119186d7f5d3SJohn Marino 
119286d7f5d3SJohn Marino /*
119386d7f5d3SJohn Marino  * mark_player:
119486d7f5d3SJohn Marino  *	mark a player as under a shot
119586d7f5d3SJohn Marino  */
119686d7f5d3SJohn Marino static void
mark_player(BULLET * bp)119786d7f5d3SJohn Marino mark_player(BULLET *bp)
119886d7f5d3SJohn Marino {
119986d7f5d3SJohn Marino 	PLAYER	*pp;
120086d7f5d3SJohn Marino 
120186d7f5d3SJohn Marino 	for (pp = Player; pp < End_player; pp++)
120286d7f5d3SJohn Marino 		if (pp->p_y == bp->b_y && pp->p_x == bp->b_x) {
120386d7f5d3SJohn Marino 			pp->p_undershot = TRUE;
120486d7f5d3SJohn Marino 			break;
120586d7f5d3SJohn Marino 		}
120686d7f5d3SJohn Marino }
120786d7f5d3SJohn Marino 
120886d7f5d3SJohn Marino /*
120986d7f5d3SJohn Marino  * mark_boot:
121086d7f5d3SJohn Marino  *	mark a boot as under a shot
121186d7f5d3SJohn Marino  */
121286d7f5d3SJohn Marino static void
mark_boot(BULLET * bp)121386d7f5d3SJohn Marino mark_boot(BULLET *bp)
121486d7f5d3SJohn Marino {
121586d7f5d3SJohn Marino 	PLAYER	*pp;
121686d7f5d3SJohn Marino 
121786d7f5d3SJohn Marino 	for (pp = Boot; pp < &Boot[NBOOTS]; pp++)
121886d7f5d3SJohn Marino 		if (pp->p_y == bp->b_y && pp->p_x == bp->b_x) {
121986d7f5d3SJohn Marino 			pp->p_undershot = TRUE;
122086d7f5d3SJohn Marino 			break;
122186d7f5d3SJohn Marino 		}
122286d7f5d3SJohn Marino }
1223