(linenum→info "unix/slp.c:2238")

bsd-games/2.17/hunt/huntd/shots.c

    1: /*      $NetBSD: shots.c,v 1.5 2004/01/27 20:30:29 jsm Exp $ */
    2: /*
    3:  * Copyright (c) 1983-2003, Regents of the University of California.
    4:  * All rights reserved.
    5:  * 
    6:  * Redistribution and use in source and binary forms, with or without 
    7:  * modification, are permitted provided that the following conditions are 
    8:  * met:
    9:  * 
   10:  * + Redistributions of source code must retain the above copyright 
   11:  *   notice, this list of conditions and the following disclaimer.
   12:  * + Redistributions in binary form must reproduce the above copyright 
   13:  *   notice, this list of conditions and the following disclaimer in the 
   14:  *   documentation and/or other materials provided with the distribution.
   15:  * + Neither the name of the University of California, San Francisco nor 
   16:  *   the names of its contributors may be used to endorse or promote 
   17:  *   products derived from this software without specific prior written 
   18:  *   permission.
   19:  * 
   20:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 
   21:  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
   22:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
   23:  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
   24:  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
   25:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
   26:  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
   27:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
   28:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
   29:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
   30:  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   31:  */
   32: 
   33: #include <sys/cdefs.h>
   34: #ifndef lint
   35: __RCSID("$NetBSD: shots.c,v 1.5 2004/01/27 20:30:29 jsm Exp $");
   36: #endif /* not lint */
   37: 
   38: # include       <err.h>
   39: # include       <signal.h>
   40: # include       <stdlib.h>
   41: # include       "hunt.h"
   42: 
   43: # define        PLUS_DELTA(x, max)     if (x < max) x++; else x--
   44: # define        MINUS_DELTA(x, min)    if (x > min) x--; else x++
   45: 
   46: static  void     chkshot(BULLET *, BULLET *);
   47: static  void     chkslime(BULLET *, BULLET *);
   48: static  void     explshot(BULLET *, int, int);
   49: static  void     find_under(BULLET *, BULLET *);
   50: static  int      iswall(int, int);
   51: static  void     mark_boot(BULLET *);
   52: static  void     mark_player(BULLET *);
   53: #ifdef DRONE
   54: static  void     move_drone(BULLET *);
   55: #endif
   56: static  void     move_flyer(PLAYER *);
   57: static  int      move_normal_shot(BULLET *);
   58: static  void     move_slime(BULLET *, int, BULLET *);
   59: static  void     save_bullet(BULLET *);
   60: static  void     zapshot(BULLET *, BULLET *);
   61: 
   62: /*
   63:  * moveshots:
   64:  *      Move the shots already in the air, taking explosions into account
   65:  */
   66: void
   67: moveshots()
   68: {
   69:         BULLET *bp, *next;
   70:         PLAYER *pp;
   71:         int    x, y;
   72:         BULLET *blist;
   73: 
   74:         rollexpl();
   75:         if (Bullets == NULL)
   76:                 goto ret;
   77: 
   78:         /*
   79:          * First we move through the bullet list BULSPD times, looking
   80:          * for things we may have run into.  If we do run into
   81:          * something, we set up the explosion and disappear, checking
   82:          * for damage to any player who got in the way.
   83:          */
   84: 
   85:         blist = Bullets;
   86:         Bullets = NULL;
   87:         for (bp = blist; bp != NULL; bp = next) {
   88:                 next = bp->b_next;
   89:                 x = bp->b_x;
   90:                 y = bp->b_y;
   91:                 Maze[y][x] = bp->b_over;
   92:                 for (pp = Player; pp < End_player; pp++)
   93:                         check(pp, y, x);
   94: # ifdef MONITOR
   95:                 for (pp = Monitor; pp < End_monitor; pp++)
   96:                         check(pp, y, x);
   97: # endif
   98: 
   99:                 switch (bp->b_type) {
  100:                   case SHOT:
  101:                   case GRENADE:
  102:                   case SATCHEL:
  103:                   case BOMB:
  104:                         if (move_normal_shot(bp)) {
  105:                                 bp->b_next = Bullets;
  106:                                 Bullets = bp;
  107:                         }
  108:                         break;
  109: # ifdef OOZE
  110:                   case SLIME:
  111:                         if (bp->b_expl || move_normal_shot(bp)) {
  112:                                 bp->b_next = Bullets;
  113:                                 Bullets = bp;
  114:                         }
  115:                         break;
  116: # endif
  117: # ifdef DRONE
  118:                   case DSHOT:
  119:                         if (move_drone(bp)) {
  120:                                 bp->b_next = Bullets;
  121:                                 Bullets = bp;
  122:                         }
  123:                         break;
  124: # endif
  125:                   default:
  126:                         bp->b_next = Bullets;
  127:                         Bullets = bp;
  128:                         break;
  129:                 }
  130:         }
  131: 
  132:         blist = Bullets;
  133:         Bullets = NULL;
  134:         for (bp = blist; bp != NULL; bp = next) {
  135:                 next = bp->b_next;
  136:                 if (!bp->b_expl) {
  137:                         save_bullet(bp);
  138: # ifdef MONITOR
  139:                         for (pp = Monitor; pp < End_monitor; pp++)
  140:                                 check(pp, bp->b_y, bp->b_x);
  141: # endif
  142: # ifdef DRONE
  143:                         if (bp->b_type == DSHOT)
  144:                                 for (pp = Player; pp < End_player; pp++)
  145:                                         if (pp->p_scan >= 0)
  146:                                                 check(pp, bp->b_y, bp->b_x);
  147: # endif
  148:                         continue;
  149:                 }
  150: 
  151:                 chkshot(bp, next);
  152:                 free((char *) bp);
  153:         }
  154: 
  155:         for (pp = Player; pp < End_player; pp++)
  156:                 Maze[pp->p_y][pp->p_x] = pp->p_face;
  157: 
  158: ret:
  159: # ifdef BOOTS
  160:         for (pp = Boot; pp < &Boot[NBOOTS]; pp++)
  161:                 if (pp->p_flying >= 0)
  162:                         move_flyer(pp);
  163: # endif
  164:         for (pp = Player; pp < End_player; pp++) {
  165: # ifdef FLY
  166:                 if (pp->p_flying >= 0)
  167:                         move_flyer(pp);
  168: # endif
  169:                 sendcom(pp, REFRESH); /* Flush out the explosions */
  170:                 look(pp);
  171:                 sendcom(pp, REFRESH);
  172:         }
  173: # ifdef MONITOR
  174:         for (pp = Monitor; pp < End_monitor; pp++)
  175:                 sendcom(pp, REFRESH);
  176: # endif
  177: 
  178:         return;
  179: }
  180: 
  181: /*
  182:  * move_normal_shot:
  183:  *      Move a normal shot along its trajectory
  184:  */
  185: static int
  186: move_normal_shot(bp)
  187:         BULLET *bp;
  188: {
  189:         int    i, x, y;
  190:         PLAYER *pp;
  191: 
  192:         for (i = 0; i < BULSPD; i++) {
  193:                 if (bp->b_expl)
  194:                         break;
  195: 
  196:                 x = bp->b_x;
  197:                 y = bp->b_y;
  198: 
  199:                 switch (bp->b_face) {
  200:                   case LEFTS:
  201:                         x--;
  202:                         break;
  203:                   case RIGHT:
  204:                         x++;
  205:                         break;
  206:                   case ABOVE:
  207:                         y--;
  208:                         break;
  209:                   case BELOW:
  210:                         y++;
  211:                         break;
  212:                 }
  213: 
  214:                 switch (Maze[y][x]) {
  215:                   case SHOT:
  216:                         if (rand_num(100) < 5) {
  217:                                 zapshot(Bullets, bp);
  218:                                 zapshot(bp->b_next, bp);
  219:                         }
  220:                         break;
  221:                   case GRENADE:
  222:                         if (rand_num(100) < 10) {
  223:                                 zapshot(Bullets, bp);
  224:                                 zapshot(bp->b_next, bp);
  225:                         }
  226:                         break;
  227: # ifdef REFLECT
  228:                   case WALL4: /* reflecting walls */
  229:                         switch (bp->b_face) {
  230:                           case LEFTS:
  231:                                 bp->b_face = BELOW;
  232:                                 break;
  233:                           case RIGHT:
  234:                                 bp->b_face = ABOVE;
  235:                                 break;
  236:                           case ABOVE:
  237:                                 bp->b_face = RIGHT;
  238:                                 break;
  239:                           case BELOW:
  240:                                 bp->b_face = LEFTS;
  241:                                 break;
  242:                         }
  243:                         Maze[y][x] = WALL5;
  244: # ifdef MONITOR
  245:                         for (pp = Monitor; pp < End_monitor; pp++)
  246:                                 check(pp, y, x);
  247: # endif
  248:                         break;
  249:                   case WALL5:
  250:                         switch (bp->b_face) {
  251:                           case LEFTS:
  252:                                 bp->b_face = ABOVE;
  253:                                 break;
  254:                           case RIGHT:
  255:                                 bp->b_face = BELOW;
  256:                                 break;
  257:                           case ABOVE:
  258:                                 bp->b_face = LEFTS;
  259:                                 break;
  260:                           case BELOW:
  261:                                 bp->b_face = RIGHT;
  262:                                 break;
  263:                         }
  264:                         Maze[y][x] = WALL4;
  265: # ifdef MONITOR
  266:                         for (pp = Monitor; pp < End_monitor; pp++)
  267:                                 check(pp, y, x);
  268: # endif
  269:                         break;
  270: # endif
  271: # ifdef RANDOM
  272:                   case DOOR:
  273:                         switch (rand_num(4)) {
  274:                           case 0:
  275:                                 bp->b_face = ABOVE;
  276:                                 break;
  277:                           case 1:
  278:                                 bp->b_face = BELOW;
  279:                                 break;
  280:                           case 2:
  281:                                 bp->b_face = LEFTS;
  282:                                 break;
  283:                           case 3:
  284:                                 bp->b_face = RIGHT;
  285:                                 break;
  286:                         }
  287:                         break;
  288: # endif
  289: # ifdef FLY
  290:                   case FLYER:
  291:                         pp = play_at(y, x);
  292:                         message(pp, "Zing!");
  293:                         break;
  294: # endif
  295:                   case LEFTS:
  296:                   case RIGHT:
  297:                   case BELOW:
  298:                   case ABOVE:
  299:                         /*
  300:                          * give the person a chance to catch a
  301:                          * grenade if s/he is facing it
  302:                          */
  303:                         pp = play_at(y, x);
  304:                         pp->p_ident->i_shot += bp->b_charge;
  305:                         if (opposite(bp->b_face, Maze[y][x])) {
  306:                             if (rand_num(100) < 10) {
  307:                                 if (bp->b_owner != NULL)
  308:                                         message(bp->b_owner,
  309:                                             "Your charge was absorbed!");
  310:                                 if (bp->b_score != NULL)
  311:                                         bp->b_score->i_robbed += bp->b_charge;
  312:                                 pp->p_ammo += bp->b_charge;
  313:                                 if (pp->p_damage + bp->b_size * MINDAM
  314:                                     > pp->p_damcap)
  315:                                         pp->p_ident->i_saved++;
  316:                                 message(pp, "Absorbed charge (good shield!)");
  317:                                 pp->p_ident->i_absorbed += bp->b_charge;
  318:                                 free((char *) bp);
  319:                                 (void) sprintf(Buf, "%3d", pp->p_ammo);
  320:                                 cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL);
  321:                                 outstr(pp, Buf, 3);
  322:                                 return FALSE;
  323:                             }
  324:                             pp->p_ident->i_faced += bp->b_charge;
  325:                         }
  326:                         /*
  327:                          * Small chance that the bullet just misses the
  328:                          * person.  If so, the bullet just goes on its
  329:                          * merry way without exploding.
  330:                          */
  331:                         if (rand_num(100) < 5) {
  332:                                 pp->p_ident->i_ducked += bp->b_charge;
  333:                                 if (pp->p_damage + bp->b_size * MINDAM
  334:                                     > pp->p_damcap)
  335:                                         pp->p_ident->i_saved++;
  336:                                 if (bp->b_score != NULL)
  337:                                         bp->b_score->i_missed += bp->b_charge;
  338:                                 message(pp, "Zing!");
  339:                                 if (bp->b_owner == NULL)
  340:                                         break;
  341:                                 message(bp->b_owner,
  342:                                         ((bp->b_score->i_missed & 0x7) == 0x7) ?
  343:                                         "My!  What a bad shot you are!" :
  344:                                         "Missed him");
  345:                                 break;
  346:                         }
  347:                         /*
  348:                          * The shot hit that sucker!  Blow it up.
  349:                          */
  350:                         /* FALLTHROUGH */
  351: # ifndef RANDOM
  352:                   case DOOR:
  353: # endif
  354:                   case WALL1:
  355:                   case WALL2:
  356:                   case WALL3:
  357:                         bp->b_expl = TRUE;
  358:                         break;
  359:                 }
  360: 
  361:                 bp->b_x = x;
  362:                 bp->b_y = y;
  363:         }
  364:         return TRUE;
  365: }
  366: 
  367: # ifdef DRONE
  368: /*
  369:  * move_drone:
  370:  *      Move the drone to the next square
  371:  */
  372: static void
  373: move_drone(bp)
  374:         BULLET *bp;
  375: {
  376:         int    mask, count;
  377:         int    n, dir;
  378:         PLAYER *pp;
  379: 
  380:         /*
  381:          * See if we can give someone a blast
  382:          */
  383:         if (is_player(Maze[bp->b_y][bp->b_x - 1])) {
  384:                 dir = WEST;
  385:                 goto drone_move;
  386:         }
  387:         if (is_player(Maze[bp->b_y - 1][bp->b_x])) {
  388:                 dir = NORTH;
  389:                 goto drone_move;
  390:         }
  391:         if (is_player(Maze[bp->b_y + 1][bp->b_x])) {
  392:                 dir = SOUTH;
  393:                 goto drone_move;
  394:         }
  395:         if (is_player(Maze[bp->b_y][bp->b_x + 1])) {
  396:                 dir = EAST;
  397:                 goto drone_move;
  398:         }
  399: 
  400:         /*
  401:          * Find out what directions are clear
  402:          */
  403:         mask = count = 0;
  404:         if (!iswall(bp->b_y, bp->b_x - 1))
  405:                 mask |= WEST, count++;
  406:         if (!iswall(bp->b_y - 1, bp->b_x))
  407:                 mask |= NORTH, count++;
  408:         if (!iswall(bp->b_y + 1, bp->b_x))
  409:                 mask |= SOUTH, count++;
  410:         if (!iswall(bp->b_y, bp->b_x + 1))
  411:                 mask |= EAST, count++;
  412: 
  413:         /*
  414:          * All blocked up, just you wait
  415:          */
  416:         if (count == 0)
  417:                 return TRUE;
  418: 
  419:         /*
  420:          * Only one way to go.
  421:          */
  422:         if (count == 1) {
  423:                 dir = mask;
  424:                 goto drone_move;
  425:         }
  426: 
  427:         /*
  428:          * Get rid of the direction that we came from
  429:          */
  430:         switch (bp->b_face) {
  431:           case LEFTS:
  432:                 if (mask & EAST)
  433:                         mask &= ~EAST, count--;
  434:                 break;
  435:           case RIGHT:
  436:                 if (mask & WEST)
  437:                         mask &= ~WEST, count--;
  438:                 break;
  439:           case ABOVE:
  440:                 if (mask & SOUTH)
  441:                         mask &= ~SOUTH, count--;
  442:                 break;
  443:           case BELOW:
  444:                 if (mask & NORTH)
  445:                         mask &= ~NORTH, count--;
  446:                 break;
  447:         }
  448: 
  449:         /*
  450:          * Pick one of the remaining directions
  451:          */
  452:         n = rand_num(count);
  453:         if (n >= 0 && mask & NORTH)
  454:                 dir = NORTH, n--;
  455:         if (n >= 0 && mask & SOUTH)
  456:                 dir = SOUTH, n--;
  457:         if (n >= 0 && mask & EAST)
  458:                 dir = EAST, n--;
  459:         if (n >= 0 && mask & WEST)
  460:                 dir = WEST, n--;
  461: 
  462:         /*
  463:          * Now that we know the direction of movement,
  464:          * just update the position of the drone
  465:          */
  466: drone_move:
  467:         switch (dir) {
  468:           case WEST:
  469:                 bp->b_x--;
  470:                 bp->b_face = LEFTS;
  471:                 break;
  472:           case EAST:
  473:                 bp->b_x++;
  474:                 bp->b_face = RIGHT;
  475:                 break;
  476:           case NORTH:
  477:                 bp->b_y--;
  478:                 bp->b_face = ABOVE;
  479:                 break;
  480:           case SOUTH:
  481:                 bp->b_y++;
  482:                 bp->b_face = BELOW;
  483:                 break;
  484:         }
  485:         switch (Maze[bp->b_y][bp->b_x]) {
  486:           case LEFTS:
  487:           case RIGHT:
  488:           case BELOW:
  489:           case ABOVE:
  490:                 /*
  491:                  * give the person a chance to catch a
  492:                  * drone if s/he is facing it
  493:                  */
  494:                 if (rand_num(100) < 1 &&
  495:                 opposite(bp->b_face, Maze[bp->b_y][bp->b_x])) {
  496:                         pp = play_at(bp->b_y, bp->b_x);
  497:                         pp->p_ammo += bp->b_charge;
  498:                         message(pp, "**** Absorbed drone ****");
  499:                         free((char *) bp);
  500:                         (void) sprintf(Buf, "%3d", pp->p_ammo);
  501:                         cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL);
  502:                         outstr(pp, Buf, 3);
  503:                         return FALSE;
  504:                 }
  505:                 bp->b_expl = TRUE;
  506:                 break;
  507:         }
  508:         return TRUE;
  509: }
  510: # endif
  511: 
  512: /*
  513:  * save_bullet:
  514:  *      Put this bullet back onto the bullet list
  515:  */
  516: static void
  517: save_bullet(bp)
  518:         BULLET *bp;
  519: {
  520:         bp->b_over = Maze[bp->b_y][bp->b_x];
  521:         switch (bp->b_over) {
  522:           case SHOT:
  523:           case GRENADE:
  524:           case SATCHEL:
  525:           case BOMB:
  526: # ifdef OOZE
  527:           case SLIME:
  528: # ifdef VOLCANO
  529:           case LAVA:
  530: # endif
  531: # endif
  532: # ifdef DRONE
  533:           case DSHOT:
  534: # endif
  535:                 find_under(Bullets, bp);
  536:                 break;
  537:         }
  538: 
  539:         switch (bp->b_over) {
  540:           case LEFTS:
  541:           case RIGHT:
  542:           case ABOVE: