* Copyright (c) 1985 Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
static char sccsid
[] = "@(#)shots.c 5.2 (Berkeley) 6/27/88";
* Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
* San Francisco, California
# define PLUS_DELTA(x, max) if (x < max) x++; else x--
# define MINUS_DELTA(x, min) if (x > min) x--; else x++
* Move the shots already in the air, taking explosions into account
register BULLET
*bp
, *next
;
* First we move through the bullet list BULSPD times, looking
* for things we may have run into. If we do run into
* something, we set up the explosion and disappear, checking
* for damage to any player who got in the way.
for (bp
= blist
; bp
!= NULL
; bp
= next
) {
for (pp
= Player
; pp
< End_player
; pp
++)
for (pp
= Monitor
; pp
< End_monitor
; pp
++)
for (i
= 0; i
< BULSPD
; i
++) {
if (rand_num(100) < 10) {
case WALL4
: /* reflecting walls */
for (pp
= Monitor
; pp
< End_monitor
; pp
++)
for (pp
= Monitor
; pp
< End_monitor
; pp
++)
* give the person a chance to catch a
* grenade if s/he is facing it
&& opposite(bp
->b_face
, Maze
[y
][x
])) {
"Your charge was absorbed!");
pp
->p_ammo
+= bp
->b_charge
;
"Absorbed charge (good shield!)");
(void) sprintf(Buf
, "%3d", pp
->p_ammo
);
cgoto(pp
, STAT_AMMO_ROW
, STAT_VALUE_COL
);
for (bp
= blist
; bp
!= NULL
; bp
= next
) {
for (pp
= Monitor
; pp
< End_monitor
; pp
++)
check(pp
, bp
->b_y
, bp
->b_x
);
for (pp
= Player
; pp
< End_player
; pp
++)
Maze
[pp
->p_y
][pp
->p_x
] = pp
->p_face
;
for (pp
= Player
; pp
< End_player
; pp
++) {
Maze
[pp
->p_y
][pp
->p_x
] = pp
->p_over
;
x
= pp
->p_x
+ pp
->p_flyx
;
y
= pp
->p_y
+ pp
->p_flyy
;
pp
->p_flyx
= -pp
->p_flyx
;
else if (x
> WIDTH
- 2) {
x
= (WIDTH
- 2) - (x
- (WIDTH
- 2));
pp
->p_flyx
= -pp
->p_flyx
;
pp
->p_flyy
= -pp
->p_flyy
;
else if (y
> HEIGHT
- 2) {
y
= (HEIGHT
- 2) - (y
- (HEIGHT
- 2));
pp
->p_flyy
= -pp
->p_flyy
;
again
: switch (Maze
[y
][x
]) {
PLUS_DELTA(x
, WIDTH
- 2);
PLUS_DELTA(y
, HEIGHT
- 2);
checkdam(pp
, NULL
, NULL
, MINDAM
, MINE
);
checkdam(pp
, NULL
, NULL
, MINDAM
, GMINE
);
checkdam(pp
, NULL
, NULL
, MINDAM
, GMINE
);
if (pp
->p_flying
-- == 0) {
rand_num(pp
->p_damage
/ 5), FALL
);
showexpl(y
, x
, pp
->p_face
);
sendcom(pp
, REFRESH
); /* Flush out the explosions */
for (pp
= Monitor
; pp
< End_monitor
; pp
++)
for (i
= 0; i
< EXPLEN
; i
++)
bp
->b_over
= Maze
[bp
->b_y
][bp
->b_x
];
Maze
[bp
->b_y
][bp
->b_x
] = bp
->b_type
;
register int dy
, dx
, absdy
;
register int delta
, damage
;
for (y
= bp
->b_y
- delta
; y
<= bp
->b_y
+ delta
; y
++) {
if (y
< 0 || y
>= HEIGHT
)
absdy
= (dy
< 0) ? -dy
: dy
;
for (x
= bp
->b_x
- delta
; x
<= bp
->b_x
+ delta
; x
++) {
expl
= (dy
== 0) ? '*' : '|';
damage
= delta
- absdy
+ 1;
checkdam(pp
, bp
->b_owner
, bp
->b_score
,
add_shot((Maze
[y
][x
] == GMINE
) ?
(PLAYER
*) NULL
, TRUE
, SPACE
);
* handle slime shot exploding
switch (Maze
[bp
->b_y
][bp
->b_x
]) {
nbp
= (BULLET
*) malloc(sizeof (BULLET
));
moveslime(nbp
, nbp
->b_type
== SLIME
? SLIMESPEED
: LAVASPEED
);
moveslime(nbp
, SLIMESPEED
);
* move the given slime shot speed times and add it back if
register int i
, j
, dirmask
, count
;
showexpl(bp
->b_y
, bp
->b_x
, bp
->b_type
== LAVA
? LAVA
: '*');
showexpl(bp
->b_y
, bp
->b_x
, '*');
switch (Maze
[bp
->b_y
][bp
->b_x
]) {
pp
= play_at(bp
->b_y
, bp
->b_x
);
message(pp
, "You've been slimed.");
checkdam(pp
, bp
->b_owner
, bp
->b_score
, MINDAM
, bp
->b_type
);
if (--bp
->b_charge
<= 0) {
if (!iswall(bp
->b_y
, bp
->b_x
- 1))
dirmask
|= WEST
, count
++;
if (!iswall(bp
->b_y
- 1, bp
->b_x
))
dirmask
|= NORTH
, count
++;
if (!iswall(bp
->b_y
+ 1, bp
->b_x
))
dirmask
|= SOUTH
, count
++;
if (!iswall(bp
->b_y
, bp
->b_x
+ 1))
dirmask
|= EAST
, count
++;
if (!iswall(bp
->b_y
, bp
->b_x
+ 1))
dirmask
|= EAST
, count
++;
if (!iswall(bp
->b_y
- 1, bp
->b_x
))
dirmask
|= NORTH
, count
++;
if (!iswall(bp
->b_y
+ 1, bp
->b_x
))
dirmask
|= SOUTH
, count
++;
if (!iswall(bp
->b_y
, bp
->b_x
- 1))
dirmask
|= WEST
, count
++;
if (!iswall(bp
->b_y
- 1, bp
->b_x
))
dirmask
|= NORTH
, count
++;
if (!iswall(bp
->b_y
, bp
->b_x
- 1))
dirmask
|= WEST
, count
++;
if (!iswall(bp
->b_y
, bp
->b_x
+ 1))
dirmask
|= EAST
, count
++;
if (!iswall(bp
->b_y
+ 1, bp
->b_x
))
dirmask
|= SOUTH
, count
++;
if (!iswall(bp
->b_y
+ 1, bp
->b_x
))
dirmask
|= SOUTH
, count
++;
if (!iswall(bp
->b_y
, bp
->b_x
- 1))
dirmask
|= WEST
, count
++;
if (!iswall(bp
->b_y
, bp
->b_x
+ 1))
dirmask
|= EAST
, count
++;
if (!iswall(bp
->b_y
- 1, bp
->b_x
))
dirmask
|= NORTH
, count
++;
* No place to go. Just sit here for a while and wait
* for adjacent squares to clear out.
if (bp
->b_charge
< count
) {
/* Only bp->b_charge paths may be taken */
while (count
> bp
->b_charge
) {
else if (dirmask
& NORTH
)
else if (dirmask
& SOUTH
)
i
= bp
->b_charge
/ count
;
j
= bp
->b_charge
% count
;
nbp
= create_shot(bp
->b_type
, bp
->b_y
, bp
->b_x
- 1, LEFTS
,
i
, bp
->b_owner
, bp
->b_score
, TRUE
, SPACE
);
moveslime(nbp
, speed
- 1);
nbp
= create_shot(bp
->b_type
, bp
->b_y
, bp
->b_x
+ 1, RIGHT
,
(count
< j
) ? i
+ 1 : i
, bp
->b_owner
, bp
->b_score
,
moveslime(nbp
, speed
- 1);
nbp
= create_shot(bp
->b_type
, bp
->b_y
- 1, bp
->b_x
, ABOVE
,
(count
< j
) ? i
+ 1 : i
, bp
->b_owner
, bp
->b_score
,
moveslime(nbp
, speed
- 1);
nbp
= create_shot(bp
->b_type
, bp
->b_y
+ 1, bp
->b_x
, BELOW
,
(count
< j
) ? i
+ 1 : i
, bp
->b_owner
, bp
->b_score
,
moveslime(nbp
, speed
- 1);
* returns whether the given location is a wall
if (y
< 0 || x
< 0 || y
>= HEIGHT
|| x
>= WIDTH
)
* Take a shot out of the air.
register BULLET
*blist
, *obp
;
for (bp
= blist
; bp
!= NULL
; bp
= bp
->b_next
) {
if (bp
->b_x
!= obp
->b_x
|| bp
->b_y
!= obp
->b_y
)
if (bp
->b_face
== obp
->b_face
)
explshot(blist
, obp
->b_y
, obp
->b_x
);
* Make all shots at this location blow up
for (bp
= blist
; bp
!= NULL
; bp
= bp
->b_next
)
if (bp
->b_x
== x
&& bp
->b_y
== y
) {
message(bp
->b_owner
, "Shot intercepted");
* Return a pointer to the player at the given location
for (pp
= Player
; pp
< End_player
; pp
++)
if (pp
->p_x
== x
&& pp
->p_y
== y
)
fprintf(stderr
, "driver: couldn't find player at (%d,%d)\n", x
, y
);
* Return TRUE if the bullet direction faces the opposite direction
* of the player in the maze
* Is there a bullet at the given coordinates? If so, return
* a pointer to the bullet, otherwise return NULL
for (bp
= Bullets
; bp
!= NULL
; bp
= bp
->b_next
)
if (bp
->b_y
== y
&& bp
->b_x
== x
)
* change the underlying character of the shots at a location
* to the given character.
for (bp
= Bullets
; bp
!= NULL
; bp
= bp
->b_next
)
if (bp
->b_y
== y
&& bp
->b_x
== x
)
* find the underlying character for a bullet when it lands
register BULLET
*blist
, *bp
;
for (nbp
= blist
; nbp
!= NULL
; nbp
= nbp
->b_next
)
if (bp
->b_y
== nbp
->b_y
&& bp
->b_x
== nbp
->b_x
) {
bp
->b_over
= nbp
->b_over
;
* mark a player as under a shot
for (pp
= Player
; pp
< End_player
; pp
++)
if (pp
->p_y
== bp
->b_y
&& pp
->p_x
== bp
->b_x
) {