* 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
++)
if (move_normal_shot(bp
)) {
if (bp
->b_expl
|| move_normal_shot(bp
)) {
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
++)
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
= Boot
; pp
< &Boot
[NBOOTS
]; pp
++)
for (pp
= Player
; pp
< End_player
; pp
++) {
sendcom(pp
, REFRESH
); /* Flush out the explosions */
for (pp
= Monitor
; pp
< End_monitor
; pp
++)
* Move a normal shot along its trajectory
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
pp
->p_ident
->i_shot
+= bp
->b_charge
;
if (opposite(bp
->b_face
, Maze
[y
][x
])) {
if (rand_num(100) < 10) {
"Your charge was absorbed!");
bp
->b_score
->i_robbed
+= bp
->b_charge
;
pp
->p_ammo
+= bp
->b_charge
;
if (pp
->p_damage
+ bp
->b_size
* MINDAM
message(pp
, "Absorbed charge (good shield!)");
pp
->p_ident
->i_absorbed
+= bp
->b_charge
;
(void) sprintf(Buf
, "%3d", pp
->p_ammo
);
cgoto(pp
, STAT_AMMO_ROW
, STAT_VALUE_COL
);
pp
->p_ident
->i_faced
+= bp
->b_charge
;
* Small chance that the bullet just misses the
* person. If so, the bullet just goes on its
* merry way without exploding.
pp
->p_ident
->i_ducked
+= bp
->b_charge
;
if (pp
->p_damage
+ bp
->b_size
* MINDAM
bp
->b_score
->i_missed
+= bp
->b_charge
;
((bp
->b_score
->i_missed
& 0x7) == 0x7) ?
"My! What a bad shot you are!" :
* The shot hit that sucker! Blow it up.
* Move the drone to the next square
register int mask
, count
;
* See if we can give someone a blast
if (isplayer(Maze
[bp
->b_y
][bp
->b_x
- 1])) {
if (isplayer(Maze
[bp
->b_y
- 1][bp
->b_x
])) {
if (isplayer(Maze
[bp
->b_y
+ 1][bp
->b_x
])) {
if (isplayer(Maze
[bp
->b_y
][bp
->b_x
+ 1])) {
* Find out what directions are clear
if (!iswall(bp
->b_y
, bp
->b_x
- 1))
if (!iswall(bp
->b_y
- 1, bp
->b_x
))
if (!iswall(bp
->b_y
+ 1, bp
->b_x
))
if (!iswall(bp
->b_y
, bp
->b_x
+ 1))
* All blocked up, just you wait
* Get rid of the direction that we came from
* Pick one of the remaining directions
if (n
>= 0 && mask
& NORTH
)
if (n
>= 0 && mask
& SOUTH
)
if (n
>= 0 && mask
& EAST
)
if (n
>= 0 && mask
& WEST
)
* Now that we know the direction of movement,
* just update the position of the drone
switch (Maze
[bp
->b_y
][bp
->b_x
]) {
* give the person a chance to catch a
* drone if s/he is facing it
opposite(bp
->b_face
, Maze
[bp
->b_y
][bp
->b_x
])) {
pp
= play_at(bp
->b_y
, bp
->b_x
);
pp
->p_ammo
+= bp
->b_charge
;
message(pp
, "**** Absorbed drone ****");
(void) sprintf(Buf
, "%3d", pp
->p_ammo
);
cgoto(pp
, STAT_AMMO_ROW
, STAT_VALUE_COL
);
* Put this bullet back onto the bullet list
bp
->b_over
= Maze
[bp
->b_y
][bp
->b_x
];
Maze
[bp
->b_y
][bp
->b_x
] = bp
->b_type
;
* Update the position of a player in flight
fixshots(pp
->p_y
, pp
->p_x
, pp
->p_over
);
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
;
PLUS_DELTA(x
, WIDTH
- 2);
PLUS_DELTA(y
, HEIGHT
- 2);
if (pp
->p_flying
-- == 0) {
if (pp
->p_face
!= BOOT
&& pp
->p_face
!= BOOT_PAIR
) {
checkdam(pp
, (PLAYER
*) NULL
, (IDENT
*) NULL
,
rand_num(pp
->p_damage
/ 5), FALL
);
showexpl(y
, x
, pp
->p_face
);
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
= bp
->b_size
- absdy
;
damage
= bp
->b_size
- dx
;
checkdam(pp
, bp
->b_owner
, bp
->b_score
,
damage
* MINDAM
, bp
->b_type
);
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
));
move_slime(nbp
, nbp
->b_type
== SLIME
? SLIMESPEED
: LAVASPEED
, next
);
move_slime(nbp
, SLIMESPEED
, next
);
* move the given slime shot speed times and add it back if
move_slime(bp
, speed
, next
)
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
);
explshot(next
, bp
->b_y
, bp
->b_x
);
explshot(Bullets
, bp
->b_y
, bp
->b_x
);
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_size
, bp
->b_owner
, bp
->b_score
, TRUE
, SPACE
);
move_slime(nbp
, speed
- 1, next
);
nbp
= create_shot(bp
->b_type
, bp
->b_y
, bp
->b_x
+ 1, RIGHT
,
(count
< j
) ? i
+ 1 : i
, bp
->b_size
, bp
->b_owner
,
bp
->b_score
, TRUE
, SPACE
);
move_slime(nbp
, speed
- 1, next
);
nbp
= create_shot(bp
->b_type
, bp
->b_y
- 1, bp
->b_x
, ABOVE
,
(count
< j
) ? i
+ 1 : i
, bp
->b_size
, bp
->b_owner
,
bp
->b_score
, TRUE
, SPACE
);
move_slime(nbp
, speed
- 1, next
);
nbp
= create_shot(bp
->b_type
, bp
->b_y
+ 1, bp
->b_x
, BELOW
,
(count
< j
) ? i
+ 1 : i
, bp
->b_size
, bp
->b_owner
,
bp
->b_score
, TRUE
, SPACE
);
move_slime(nbp
, speed
- 1, next
);
* 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
) {
* mark a boot as under a shot
for (pp
= Boot
; pp
< &Boot
[NBOOTS
]; pp
++)
if (pp
->p_y
== bp
->b_y
&& pp
->p_x
== bp
->b_x
) {