123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170 |
- /* $NetBSD: shots.c,v 1.5 2004/01/27 20:30:29 jsm Exp $ */
- /*
- * Copyright (c) 1983-2003, Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * + Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * + Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * + Neither the name of the University of California, San Francisco nor
- * the names of its contributors may be used to endorse or promote
- * products derived from this software without specific prior written
- * permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #include <sys/cdefs.h>
- #ifndef lint
- __RCSID("$NetBSD: shots.c,v 1.5 2004/01/27 20:30:29 jsm Exp $");
- #endif /* not lint */
- # include <err.h>
- # include <signal.h>
- # include <stdlib.h>
- # include "hunt.h"
- # define PLUS_DELTA(x, max) if (x < max) x++; else x--
- # define MINUS_DELTA(x, min) if (x > min) x--; else x++
- static void chkshot(BULLET *, BULLET *);
- static void chkslime(BULLET *, BULLET *);
- static void explshot(BULLET *, int, int);
- static void find_under(BULLET *, BULLET *);
- static int iswall(int, int);
- static void mark_boot(BULLET *);
- static void mark_player(BULLET *);
- #ifdef DRONE
- static void move_drone(BULLET *);
- #endif
- static void move_flyer(PLAYER *);
- static int move_normal_shot(BULLET *);
- static void move_slime(BULLET *, int, BULLET *);
- static void save_bullet(BULLET *);
- static void zapshot(BULLET *, BULLET *);
- /*
- * moveshots:
- * Move the shots already in the air, taking explosions into account
- */
- void
- moveshots()
- {
- BULLET *bp, *next;
- PLAYER *pp;
- int x, y;
- BULLET *blist;
- rollexpl();
- if (Bullets == NULL)
- goto ret;
- /*
- * 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.
- */
- blist = Bullets;
- Bullets = NULL;
- for (bp = blist; bp != NULL; bp = next) {
- next = bp->b_next;
- x = bp->b_x;
- y = bp->b_y;
- Maze[y][x] = bp->b_over;
- for (pp = Player; pp < End_player; pp++)
- check(pp, y, x);
- # ifdef MONITOR
- for (pp = Monitor; pp < End_monitor; pp++)
- check(pp, y, x);
- # endif
- switch (bp->b_type) {
- case SHOT:
- case GRENADE:
- case SATCHEL:
- case BOMB:
- if (move_normal_shot(bp)) {
- bp->b_next = Bullets;
- Bullets = bp;
- }
- break;
- # ifdef OOZE
- case SLIME:
- if (bp->b_expl || move_normal_shot(bp)) {
- bp->b_next = Bullets;
- Bullets = bp;
- }
- break;
- # endif
- # ifdef DRONE
- case DSHOT:
- if (move_drone(bp)) {
- bp->b_next = Bullets;
- Bullets = bp;
- }
- break;
- # endif
- default:
- bp->b_next = Bullets;
- Bullets = bp;
- break;
- }
- }
- blist = Bullets;
- Bullets = NULL;
- for (bp = blist; bp != NULL; bp = next) {
- next = bp->b_next;
- if (!bp->b_expl) {
- save_bullet(bp);
- # ifdef MONITOR
- for (pp = Monitor; pp < End_monitor; pp++)
- check(pp, bp->b_y, bp->b_x);
- # endif
- # ifdef DRONE
- if (bp->b_type == DSHOT)
- for (pp = Player; pp < End_player; pp++)
- if (pp->p_scan >= 0)
- check(pp, bp->b_y, bp->b_x);
- # endif
- continue;
- }
- chkshot(bp, next);
- free((char *) bp);
- }
- for (pp = Player; pp < End_player; pp++)
- Maze[pp->p_y][pp->p_x] = pp->p_face;
- ret:
- # ifdef BOOTS
- for (pp = Boot; pp < &Boot[NBOOTS]; pp++)
- if (pp->p_flying >= 0)
- move_flyer(pp);
- # endif
- for (pp = Player; pp < End_player; pp++) {
- # ifdef FLY
- if (pp->p_flying >= 0)
- move_flyer(pp);
- # endif
- sendcom(pp, REFRESH); /* Flush out the explosions */
- look(pp);
- sendcom(pp, REFRESH);
- }
- # ifdef MONITOR
- for (pp = Monitor; pp < End_monitor; pp++)
- sendcom(pp, REFRESH);
- # endif
- return;
- }
- /*
- * move_normal_shot:
- * Move a normal shot along its trajectory
- */
- static int
- move_normal_shot(bp)
- BULLET *bp;
- {
- int i, x, y;
- PLAYER *pp;
- for (i = 0; i < BULSPD; i++) {
- if (bp->b_expl)
- break;
- x = bp->b_x;
- y = bp->b_y;
- switch (bp->b_face) {
- case LEFTS:
- x--;
- break;
- case RIGHT:
- x++;
- break;
- case ABOVE:
- y--;
- break;
- case BELOW:
- y++;
- break;
- }
- switch (Maze[y][x]) {
- case SHOT:
- if (rand_num(100) < 5) {
- zapshot(Bullets, bp);
- zapshot(bp->b_next, bp);
- }
- break;
- case GRENADE:
- if (rand_num(100) < 10) {
- zapshot(Bullets, bp);
- zapshot(bp->b_next, bp);
- }
- break;
- # ifdef REFLECT
- case WALL4: /* reflecting walls */
- switch (bp->b_face) {
- case LEFTS:
- bp->b_face = BELOW;
- break;
- case RIGHT:
- bp->b_face = ABOVE;
- break;
- case ABOVE:
- bp->b_face = RIGHT;
- break;
- case BELOW:
- bp->b_face = LEFTS;
- break;
- }
- Maze[y][x] = WALL5;
- # ifdef MONITOR
- for (pp = Monitor; pp < End_monitor; pp++)
- check(pp, y, x);
- # endif
- break;
- case WALL5:
- switch (bp->b_face) {
- case LEFTS:
- bp->b_face = ABOVE;
- break;
- case RIGHT:
- bp->b_face = BELOW;
- break;
- case ABOVE:
- bp->b_face = LEFTS;
- break;
- case BELOW:
- bp->b_face = RIGHT;
- break;
- }
- Maze[y][x] = WALL4;
- # ifdef MONITOR
- for (pp = Monitor; pp < End_monitor; pp++)
- check(pp, y, x);
- # endif
- break;
- # endif
- # ifdef RANDOM
- case DOOR:
- switch (rand_num(4)) {
- case 0:
- bp->b_face = ABOVE;
- break;
- case 1:
- bp->b_face = BELOW;
- break;
- case 2:
- bp->b_face = LEFTS;
- break;
- case 3:
- bp->b_face = RIGHT;
- break;
- }
- break;
- # endif
- # ifdef FLY
- case FLYER:
- pp = play_at(y, x);
- message(pp, "Zing!");
- break;
- # endif
- case LEFTS:
- case RIGHT:
- case BELOW:
- case ABOVE:
- /*
- * give the person a chance to catch a
- * grenade if s/he is facing it
- */
- pp = play_at(y, x);
- pp->p_ident->i_shot += bp->b_charge;
- if (opposite(bp->b_face, Maze[y][x])) {
- if (rand_num(100) < 10) {
- if (bp->b_owner != NULL)
- message(bp->b_owner,
- "Your charge was absorbed!");
- if (bp->b_score != NULL)
- bp->b_score->i_robbed += bp->b_charge;
- pp->p_ammo += bp->b_charge;
- if (pp->p_damage + bp->b_size * MINDAM
- > pp->p_damcap)
- pp->p_ident->i_saved++;
- message(pp, "Absorbed charge (good shield!)");
- pp->p_ident->i_absorbed += bp->b_charge;
- free((char *) bp);
- (void) sprintf(Buf, "%3d", pp->p_ammo);
- cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL);
- outstr(pp, Buf, 3);
- return FALSE;
- }
- 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.
- */
- if (rand_num(100) < 5) {
- pp->p_ident->i_ducked += bp->b_charge;
- if (pp->p_damage + bp->b_size * MINDAM
- > pp->p_damcap)
- pp->p_ident->i_saved++;
- if (bp->b_score != NULL)
- bp->b_score->i_missed += bp->b_charge;
- message(pp, "Zing!");
- if (bp->b_owner == NULL)
- break;
- message(bp->b_owner,
- ((bp->b_score->i_missed & 0x7) == 0x7) ?
- "My! What a bad shot you are!" :
- "Missed him");
- break;
- }
- /*
- * The shot hit that sucker! Blow it up.
- */
- /* FALLTHROUGH */
- # ifndef RANDOM
- case DOOR:
- # endif
- case WALL1:
- case WALL2:
- case WALL3:
- bp->b_expl = TRUE;
- break;
- }
- bp->b_x = x;
- bp->b_y = y;
- }
- return TRUE;
- }
- # ifdef DRONE
- /*
- * move_drone:
- * Move the drone to the next square
- */
- static void
- move_drone(bp)
- BULLET *bp;
- {
- int mask, count;
- int n, dir;
- PLAYER *pp;
- /*
- * See if we can give someone a blast
- */
- if (is_player(Maze[bp->b_y][bp->b_x - 1])) {
- dir = WEST;
- goto drone_move;
- }
- if (is_player(Maze[bp->b_y - 1][bp->b_x])) {
- dir = NORTH;
- goto drone_move;
- }
- if (is_player(Maze[bp->b_y + 1][bp->b_x])) {
- dir = SOUTH;
- goto drone_move;
- }
- if (is_player(Maze[bp->b_y][bp->b_x + 1])) {
- dir = EAST;
- goto drone_move;
- }
- /*
- * Find out what directions are clear
- */
- mask = count = 0;
- if (!iswall(bp->b_y, bp->b_x - 1))
- mask |= WEST, count++;
- if (!iswall(bp->b_y - 1, bp->b_x))
- mask |= NORTH, count++;
- if (!iswall(bp->b_y + 1, bp->b_x))
- mask |= SOUTH, count++;
- if (!iswall(bp->b_y, bp->b_x + 1))
- mask |= EAST, count++;
- /*
- * All blocked up, just you wait
- */
- if (count == 0)
- return TRUE;
- /*
- * Only one way to go.
- */
- if (count == 1) {
- dir = mask;
- goto drone_move;
- }
- /*
- * Get rid of the direction that we came from
- */
- switch (bp->b_face) {
- case LEFTS:
- if (mask & EAST)
- mask &= ~EAST, count--;
- break;
- case RIGHT:
- if (mask & WEST)
- mask &= ~WEST, count--;
- break;
- case ABOVE:
- if (mask & SOUTH)
- mask &= ~SOUTH, count--;
- break;
- case BELOW:
- if (mask & NORTH)
- mask &= ~NORTH, count--;
- break;
- }
- /*
- * Pick one of the remaining directions
- */
- n = rand_num(count);
- if (n >= 0 && mask & NORTH)
- dir = NORTH, n--;
- if (n >= 0 && mask & SOUTH)
- dir = SOUTH, n--;
- if (n >= 0 && mask & EAST)
- dir = EAST, n--;
- if (n >= 0 && mask & WEST)
- dir = WEST, n--;
- /*
- * Now that we know the direction of movement,
- * just update the position of the drone
- */
- drone_move:
- switch (dir) {
- case WEST:
- bp->b_x--;
- bp->b_face = LEFTS;
- break;
- case EAST:
- bp->b_x++;
- bp->b_face = RIGHT;
- break;
- case NORTH:
- bp->b_y--;
- bp->b_face = ABOVE;
- break;
- case SOUTH:
- bp->b_y++;
- bp->b_face = BELOW;
- break;
- }
- switch (Maze[bp->b_y][bp->b_x]) {
- case LEFTS:
- case RIGHT:
- case BELOW:
- case ABOVE:
- /*
- * give the person a chance to catch a
- * drone if s/he is facing it
- */
- if (rand_num(100) < 1 &&
- 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 ****");
- free((char *) bp);
- (void) sprintf(Buf, "%3d", pp->p_ammo);
- cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL);
- outstr(pp, Buf, 3);
- return FALSE;
- }
- bp->b_expl = TRUE;
- break;
- }
- return TRUE;
- }
- # endif
- /*
- * save_bullet:
- * Put this bullet back onto the bullet list
- */
- static void
- save_bullet(bp)
- BULLET *bp;
- {
- bp->b_over = Maze[bp->b_y][bp->b_x];
- switch (bp->b_over) {
- case SHOT:
- case GRENADE:
- case SATCHEL:
- case BOMB:
- # ifdef OOZE
- case SLIME:
- # ifdef VOLCANO
- case LAVA:
- # endif
- # endif
- # ifdef DRONE
- case DSHOT:
- # endif
- find_under(Bullets, bp);
- break;
- }
- switch (bp->b_over) {
- case LEFTS:
- case RIGHT:
- case ABOVE:
- case BELOW:
- # ifdef FLY
- case FLYER:
- # endif
- mark_player(bp);
- break;
- # ifdef BOOTS
- case BOOT:
- case BOOT_PAIR:
- mark_boot(bp);
- # endif
-
- default:
- Maze[bp->b_y][bp->b_x] = bp->b_type;
- break;
- }
- bp->b_next = Bullets;
- Bullets = bp;
- }
- /*
- * move_flyer:
- * Update the position of a player in flight
- */
- static void
- move_flyer(pp)
- PLAYER *pp;
- {
- int x, y;
- if (pp->p_undershot) {
- fixshots(pp->p_y, pp->p_x, pp->p_over);
- pp->p_undershot = FALSE;
- }
- Maze[pp->p_y][pp->p_x] = pp->p_over;
- x = pp->p_x + pp->p_flyx;
- y = pp->p_y + pp->p_flyy;
- if (x < 1) {
- x = 1 - x;
- pp->p_flyx = -pp->p_flyx;
- }
- else if (x > WIDTH - 2) {
- x = (WIDTH - 2) - (x - (WIDTH - 2));
- pp->p_flyx = -pp->p_flyx;
- }
- if (y < 1) {
- y = 1 - y;
- 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]) {
- default:
- switch (rand_num(4)) {
- case 0:
- PLUS_DELTA(x, WIDTH - 2);
- break;
- case 1:
- MINUS_DELTA(x, 1);
- break;
- case 2:
- PLUS_DELTA(y, HEIGHT - 2);
- break;
- case 3:
- MINUS_DELTA(y, 1);
- break;
- }
- goto again;
- case WALL1:
- case WALL2:
- case WALL3:
- # ifdef REFLECT
- case WALL4:
- case WALL5:
- # endif
- # ifdef RANDOM
- case DOOR:
- # endif
- if (pp->p_flying == 0)
- pp->p_flying++;
- break;
- case SPACE:
- break;
- }
- pp->p_y = y;
- pp->p_x = x;
- if (pp->p_flying-- == 0) {
- # ifdef BOOTS
- if (pp->p_face != BOOT && pp->p_face != BOOT_PAIR) {
- # endif
- checkdam(pp, (PLAYER *) NULL, (IDENT *) NULL,
- rand_num(pp->p_damage / 5), FALL);
- pp->p_face = rand_dir();
- showstat(pp);
- # ifdef BOOTS
- }
- else {
- if (Maze[y][x] == BOOT)
- pp->p_face = BOOT_PAIR;
- Maze[y][x] = SPACE;
- }
- # endif
- }
- pp->p_over = Maze[y][x];
- Maze[y][x] = pp->p_face;
- showexpl(y, x, pp->p_face);
- }
- /*
- * chkshot
- * Handle explosions
- */
- static void
- chkshot(bp, next)
- BULLET *bp;
- BULLET *next;
- {
- int y, x;
- int dy, dx, absdy;
- int delta, damage;
- char expl;
- PLAYER *pp;
- delta = 0;
- switch (bp->b_type) {
- case SHOT:
- case MINE:
- case GRENADE:
- case GMINE:
- case SATCHEL:
- case BOMB:
- delta = bp->b_size - 1;
- break;
- # ifdef OOZE
- case SLIME:
- # ifdef VOLCANO
- case LAVA:
- # endif
- chkslime(bp, next);
- return;
- # endif
- # ifdef DRONE
- case DSHOT:
- bp->b_type = SLIME;
- chkslime(bp, next);
- return;
- # endif
- }
- for (y = bp->b_y - delta; y <= bp->b_y + delta; y++) {
- if (y < 0 || y >= HEIGHT)
- continue;
- dy = y - bp->b_y;
- absdy = (dy < 0) ? -dy : dy;
- for (x = bp->b_x - delta; x <= bp->b_x + delta; x++) {
- if (x < 0 || x >= WIDTH)
- continue;
- dx = x - bp->b_x;
- if (dx == 0)
- expl = (dy == 0) ? '*' : '|';
- else if (dy == 0)
- expl = '-';
- else if (dx == dy)
- expl = '\\';
- else if (dx == -dy)
- expl = '/';
- else
- expl = '*';
- showexpl(y, x, expl);
- switch (Maze[y][x]) {
- case LEFTS:
- case RIGHT:
- case ABOVE:
- case BELOW:
- # ifdef FLY
- case FLYER:
- # endif
- if (dx < 0)
- dx = -dx;
- if (absdy > dx)
- damage = bp->b_size - absdy;
- else
- damage = bp->b_size - dx;
- pp = play_at(y, x);
- checkdam(pp, bp->b_owner, bp->b_score,
- damage * MINDAM, bp->b_type);
- break;
- case GMINE:
- case MINE:
- add_shot((Maze[y][x] == GMINE) ?
- GRENADE : SHOT,
- y, x, LEFTS,
- (Maze[y][x] == GMINE) ?
- GRENREQ : BULREQ,
- (PLAYER *) NULL, TRUE, SPACE);
- Maze[y][x] = SPACE;
- break;
- }
- }
- }
- }
- # ifdef OOZE
- /*
- * chkslime:
- * handle slime shot exploding
- */
- static void
- chkslime(bp, next)
- BULLET *bp;
- BULLET *next;
- {
- BULLET *nbp;
- switch (Maze[bp->b_y][bp->b_x]) {
- case WALL1:
- case WALL2:
- case WALL3:
- # ifdef REFLECT
- case WALL4:
- case WALL5:
- # endif
- # ifdef RANDOM
- case DOOR:
- # endif
- switch (bp->b_face) {
- case LEFTS:
- bp->b_x++;
- break;
- case RIGHT:
- bp->b_x--;
- break;
- case ABOVE:
- bp->b_y++;
- break;
- case BELOW:
- bp->b_y--;
- break;
- }
- break;
- }
- nbp = (BULLET *) malloc(sizeof (BULLET));
- if (nbp == NULL) {
- # ifdef LOG
- syslog(LOG_ERR, "Out of memory");
- # else
- warnx("Out of memory");
- # endif
- cleanup(1);
- }
- *nbp = *bp;
- # ifdef VOLCANO
- move_slime(nbp, nbp->b_type == SLIME ? SLIMESPEED : LAVASPEED, next);
- # else
- move_slime(nbp, SLIMESPEED, next);
- # endif
- }
- /*
- * move_slime:
- * move the given slime shot speed times and add it back if
- * it hasn't fizzled yet
- */
- void
- move_slime(bp, speed, next)
- BULLET *bp;
- int speed;
- BULLET *next;
- {
- int i, j, dirmask, count;
- PLAYER *pp;
- BULLET *nbp;
- if (speed == 0) {
- if (bp->b_charge <= 0)
- free((char *) bp);
- else
- save_bullet(bp);
- return;
- }
- # ifdef VOLCANO
- showexpl(bp->b_y, bp->b_x, bp->b_type == LAVA ? LAVA : '*');
- # else
- showexpl(bp->b_y, bp->b_x, '*');
- # endif
- switch (Maze[bp->b_y][bp->b_x]) {
- case LEFTS:
- case RIGHT:
- case ABOVE:
- case BELOW:
- # ifdef FLY
- case FLYER:
- # endif
- 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);
- break;
- case SHOT:
- case GRENADE:
- case SATCHEL:
- case BOMB:
- # ifdef DRONE
- case DSHOT:
- # endif
- explshot(next, bp->b_y, bp->b_x);
- explshot(Bullets, bp->b_y, bp->b_x);
- break;
- }
- if (--bp->b_charge <= 0) {
- free((char *) bp);
- return;
- }
- dirmask = 0;
- count = 0;
- switch (bp->b_face) {
- case LEFTS:
- 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 (dirmask == 0)
- if (!iswall(bp->b_y, bp->b_x + 1))
- dirmask |= EAST, count++;
- break;
- case RIGHT:
- 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 (dirmask == 0)
- if (!iswall(bp->b_y, bp->b_x - 1))
- dirmask |= WEST, count++;
- break;
- case ABOVE:
- 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 (dirmask == 0)
- if (!iswall(bp->b_y + 1, bp->b_x))
- dirmask |= SOUTH, count++;
- break;
- case BELOW:
- 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 (dirmask == 0)
- if (!iswall(bp->b_y - 1, bp->b_x))
- dirmask |= NORTH, count++;
- break;
- }
- if (count == 0) {
- /*
- * No place to go. Just sit here for a while and wait
- * for adjacent squares to clear out.
- */
- save_bullet(bp);
- return;
- }
- if (bp->b_charge < count) {
- /* Only bp->b_charge paths may be taken */
- while (count > bp->b_charge) {
- if (dirmask & WEST)
- dirmask &= ~WEST;
- else if (dirmask & EAST)
- dirmask &= ~EAST;
- else if (dirmask & NORTH)
- dirmask &= ~NORTH;
- else if (dirmask & SOUTH)
- dirmask &= ~SOUTH;
- count--;
- }
- }
- i = bp->b_charge / count;
- j = bp->b_charge % count;
- if (dirmask & WEST) {
- 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);
- }
- if (dirmask & EAST) {
- count--;
- 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);
- }
- if (dirmask & NORTH) {
- count--;
- 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);
- }
- if (dirmask & SOUTH) {
- count--;
- 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);
- }
- free((char *) bp);
- }
- /*
- * iswall:
- * returns whether the given location is a wall
- */
- static int
- iswall(y, x)
- int y, x;
- {
- if (y < 0 || x < 0 || y >= HEIGHT || x >= WIDTH)
- return TRUE;
- switch (Maze[y][x]) {
- case WALL1:
- case WALL2:
- case WALL3:
- # ifdef REFLECT
- case WALL4:
- case WALL5:
- # endif
- # ifdef RANDOM
- case DOOR:
- # endif
- # ifdef OOZE
- case SLIME:
- # ifdef VOLCANO
- case LAVA:
- # endif
- # endif
- return TRUE;
- }
- return FALSE;
- }
- # endif
- /*
- * zapshot:
- * Take a shot out of the air.
- */
- static void
- zapshot(blist, obp)
- BULLET *blist, *obp;
- {
- BULLET *bp;
- FLAG explode;
- explode = FALSE;
- for (bp = blist; bp != NULL; bp = bp->b_next) {
- if (bp->b_x != obp->b_x || bp->b_y != obp->b_y)
- continue;
- if (bp->b_face == obp->b_face)
- continue;
- explode = TRUE;
- break;
- }
- if (!explode)
- return;
- explshot(blist, obp->b_y, obp->b_x);
- }
- /*
- * explshot -
- * Make all shots at this location blow up
- */
- void
- explshot(blist, y, x)
- BULLET *blist;
- int y, x;
- {
- BULLET *bp;
- for (bp = blist; bp != NULL; bp = bp->b_next)
- if (bp->b_x == x && bp->b_y == y) {
- bp->b_expl = TRUE;
- if (bp->b_owner != NULL)
- message(bp->b_owner, "Shot intercepted");
- }
- }
- /*
- * play_at:
- * Return a pointer to the player at the given location
- */
- PLAYER *
- play_at(y, x)
- int y, x;
- {
- PLAYER *pp;
- for (pp = Player; pp < End_player; pp++)
- if (pp->p_x == x && pp->p_y == y)
- return pp;
- errx(1, "driver: couldn't find player at (%d,%d)", x, y);
- /* NOTREACHED */
- }
- /*
- * opposite:
- * Return TRUE if the bullet direction faces the opposite direction
- * of the player in the maze
- */
- int
- opposite(face, dir)
- int face;
- char dir;
- {
- switch (face) {
- case LEFTS:
- return (dir == RIGHT);
- case RIGHT:
- return (dir == LEFTS);
- case ABOVE:
- return (dir == BELOW);
- case BELOW:
- return (dir == ABOVE);
- default:
- return FALSE;
- }
- }
- /*
- * is_bullet:
- * Is there a bullet at the given coordinates? If so, return
- * a pointer to the bullet, otherwise return NULL
- */
- BULLET *
- is_bullet(y, x)
- int y, x;
- {
- BULLET *bp;
- for (bp = Bullets; bp != NULL; bp = bp->b_next)
- if (bp->b_y == y && bp->b_x == x)
- return bp;
- return NULL;
- }
- /*
- * fixshots:
- * change the underlying character of the shots at a location
- * to the given character.
- */
- void
- fixshots(y, x, over)
- int y, x;
- char over;
- {
- BULLET *bp;
- for (bp = Bullets; bp != NULL; bp = bp->b_next)
- if (bp->b_y == y && bp->b_x == x)
- bp->b_over = over;
- }
- /*
- * find_under:
- * find the underlying character for a bullet when it lands
- * on another bullet.
- */
- static void
- find_under(blist, bp)
- BULLET *blist, *bp;
- {
- BULLET *nbp;
- 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;
- break;
- }
- }
- /*
- * mark_player:
- * mark a player as under a shot
- */
- static void
- mark_player(bp)
- BULLET *bp;
- {
- PLAYER *pp;
- for (pp = Player; pp < End_player; pp++)
- if (pp->p_y == bp->b_y && pp->p_x == bp->b_x) {
- pp->p_undershot = TRUE;
- break;
- }
- }
- # ifdef BOOTS
- /*
- * mark_boot:
- * mark a boot as under a shot
- */
- static void
- mark_boot(bp)
- BULLET *bp;
- {
- PLAYER *pp;
- for (pp = Boot; pp < &Boot[NBOOTS]; pp++)
- if (pp->p_y == bp->b_y && pp->p_x == bp->b_x) {
- pp->p_undershot = TRUE;
- break;
- }
- }
- # endif
|