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

bsd-games/2.17/hack/hack.fight.c

    1: /*      $NetBSD: hack.fight.c,v 1.6 2003/04/02 18:36:36 jsm Exp $    */
    2: 
    3: /*
    4:  * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
    5:  * Amsterdam
    6:  * All rights reserved.
    7:  *
    8:  * Redistribution and use in source and binary forms, with or without
    9:  * modification, are permitted provided that the following conditions are
   10:  * met:
   11:  *
   12:  * - Redistributions of source code must retain the above copyright notice,
   13:  * this list of conditions and the following disclaimer.
   14:  *
   15:  * - Redistributions in binary form must reproduce the above copyright
   16:  * notice, this list of conditions and the following disclaimer in the
   17:  * documentation and/or other materials provided with the distribution.
   18:  *
   19:  * - Neither the name of the Stichting Centrum voor Wiskunde en
   20:  * Informatica, nor the names of its contributors may be used to endorse or
   21:  * promote products derived from this software without specific prior
   22:  * written permission.
   23:  *
   24:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
   25:  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   26:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
   27:  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
   28:  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   29:  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   30:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   31:  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   32:  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   33:  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   34:  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   35:  */
   36: 
   37: /*
   38:  * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
   39:  * All rights reserved.
   40:  *
   41:  * Redistribution and use in source and binary forms, with or without
   42:  * modification, are permitted provided that the following conditions
   43:  * are met:
   44:  * 1. Redistributions of source code must retain the above copyright
   45:  *    notice, this list of conditions and the following disclaimer.
   46:  * 2. Redistributions in binary form must reproduce the above copyright
   47:  *    notice, this list of conditions and the following disclaimer in the
   48:  *    documentation and/or other materials provided with the distribution.
   49:  * 3. The name of the author may not be used to endorse or promote products
   50:  *    derived from this software without specific prior written permission.
   51:  *
   52:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
   53:  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
   54:  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
   55:  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   56:  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   57:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   58:  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   59:  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   60:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   61:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   62:  */
   63: 
   64: #include <sys/cdefs.h>
   65: #ifndef lint
   66: __RCSID("$NetBSD: hack.fight.c,v 1.6 2003/04/02 18:36:36 jsm Exp $");
   67: #endif                          /* not lint */
   68: 
   69: #include "hack.h"
   70: #include "extern.h"
   71: 
   72: static boolean  far_noise;
   73: static long     noisetime;
   74: 
   75: /* hitmm returns 0 (miss), 1 (hit), or 2 (kill) */
   76: int
   77: hitmm(magr, mdef)
   78:         struct monst   *magr, *mdef;
   79: {
   80:         const struct permonst *pa = magr->data, *pd = mdef->data;
   81:         int             hit;
   82:         schar           tmp;
   83:         boolean         vis;
   84:         if (strchr("Eauy", pa->mlet))
   85:                 return (0);
   86:         if (magr->mfroz)
   87:                 return (0);   /* riv05!a3 */
   88:         tmp = pd->ac + pa->mlevel;
   89:         if (mdef->mconf || mdef->mfroz || mdef->msleep) {
   90:                 tmp += 4;
   91:                 if (mdef->msleep)
   92:                         mdef->msleep = 0;
   93:         }
   94:         hit = (tmp > rnd(20));
   95:         if (hit)
   96:                 mdef->msleep = 0;
   97:         vis = (cansee(magr->mx, magr->my) && cansee(mdef->mx, mdef->my));
   98:         if (vis) {
   99:                 char            buf[BUFSZ];
  100:                 if (mdef->mimic)
  101:                         seemimic(mdef);
  102:                 if (magr->mimic)
  103:                         seemimic(magr);
  104:                 (void) sprintf(buf, "%s %s", Monnam(magr),
  105:                                hit ? "hits" : "misses");
  106:                 pline("%s %s.", buf, monnam(mdef));
  107:         } else {
  108:                 boolean         far = (dist(magr->mx, magr->my) > 15);
  109:                 if (far != far_noise || moves - noisetime > 10) {
  110:                         far_noise = far;
  111:                         noisetime = moves;
  112:                         pline("You hear some noises%s.",
  113:                               far ? " in the distance" : "");
  114:                 }
  115:         }
  116:         if (hit) {
  117:                 if (magr->data->mlet == 'c' && !magr->cham) {
  118:                         magr->mhpmax += 3;
  119:                         if (vis)
  120:                                 pline("%s is turned to stone!", Monnam(mdef));
  121:                         else if (mdef->mtame)
  122:                                 pline("You have a peculiarly sad feeling for a moment, then it passes.");
  123:                         monstone(mdef);
  124:                         hit = 2;
  125:                 } else if ((mdef->mhp -= d(pa->damn, pa->damd)) < 1) {
  126:                         magr->mhpmax += 1 + rn2(pd->mlevel + 1);
  127:                         if (magr->mtame && magr->mhpmax > 8 * pa->mlevel) {
  128:                                 if (pa == &li_dog)
  129:                                         magr->data = pa = &dog;
  130:                                 else if (pa == &dog)
  131:                                         magr->data = pa = &la_dog;
  132:                         }
  133:                         if (vis)
  134:                                 pline("%s is killed!", Monnam(mdef));
  135:                         else if (mdef->mtame)
  136:                                 pline("You have a sad feeling for a moment, then it passes.");
  137:                         mondied(mdef);
  138:                         hit = 2;
  139:                 }
  140:         }
  141:         return (hit);
  142: }
  143: 
  144: /* drop (perhaps) a cadaver and remove monster */
  145: void
  146: mondied(mdef)
  147:         struct monst   *mdef;
  148: {
  149:         const struct permonst *pd = mdef->data;
  150:         if (letter(pd->mlet) && rn2(3)) {
  151:                 (void) mkobj_at(pd->mlet, mdef->mx, mdef->my);
  152:                 if (cansee(mdef->mx, mdef->my)) {
  153:                         unpmon(mdef);
  154:                         atl(mdef->mx, mdef->my, fobj->olet);
  155:                 }
  156:                 stackobj(fobj);
  157:         }
  158:         mondead(mdef);
  159: }
  160: 
  161: /* drop a rock and remove monster */
  162: void
  163: monstone(mdef)
  164:         struct monst   *mdef;
  165: {
  166:         if (strchr(mlarge, mdef->data->mlet))
  167:                 mksobj_at(ENORMOUS_ROCK, mdef->mx, mdef->my);
  168:         else
  169:                 mksobj_at(ROCK, mdef->mx, mdef->my);
  170:         if (cansee(mdef->mx, mdef->my)) {
  171:                 unpmon(mdef);
  172:                 atl(mdef->mx, mdef->my, fobj->olet);
  173:         }
  174:         mondead(mdef);
  175: }
  176: 
  177: 
  178: int
  179: fightm(mtmp)
  180:         struct monst   *mtmp;
  181: {
  182:         struct monst   *mon;
  183:         for (mon = fmon; mon; mon = mon->nmon)
  184:                 if (mon != mtmp) {
  185:                         if (DIST(mon->mx, mon->my, mtmp->mx, mtmp->my) < 3)
  186:                                 if (rn2(4))
  187:                                         return (hitmm(mtmp, mon));
  188:                 }
  189:         return (-1);
  190: }
  191: 
  192: /* u is hit by sth, but not a monster */
  193: int
  194: thitu(tlev, dam, name)
  195:         int tlev, dam;
  196:         const char           *name;
  197: {
  198:         char            buf[BUFSZ];
  199:         setan(name, buf);
  200:         if (u.uac + tlev <= rnd(20)) {
  201:                 if (Blind)
  202:                         pline("It misses.");
  203:                 else
  204:                         pline("You are almost hit by %s!", buf);
  205:                 return (0);
  206:         } else {
  207:                 if (Blind)
  208:                         pline("You are hit!");
  209:                 else
  210:                         pline("You are hit by %s!", buf);
  211:                 losehp(dam, name);
  212:                 return (1);
  213:         }
  214: }
  215: 
  216: char            mlarge[] = "bCDdegIlmnoPSsTUwY',&";
  217: 
  218: boolean
  219: hmon(mon, obj, thrown)          /* return TRUE if mon still alive */
  220:         struct monst   *mon;
  221:         struct obj     *obj;
  222:         int thrown;
  223: {
  224:         int tmp;
  225:         boolean         hittxt = FALSE;
  226: 
  227:         if (!obj) {
  228:                 tmp = rnd(2); /* attack with bare hands */
  229:                 if (mon->data->mlet == 'c' && !uarmg) {
  230:                         pline("You hit the cockatrice with your bare hands.");
  231:                         pline("You turn to stone ...");
  232:                         done_in_by(mon);
  233:                 }
  234:         } else if (obj->olet == WEAPON_SYM || obj->otyp == PICK_AXE) {
  235:                 if (obj == uwep && (obj->otyp > SPEAR || obj->otyp < BOOMERANG))
  236:                         tmp = rnd(2);
  237:                 else {
  238:                         if (strchr(mlarge, mon->data->mlet)) {
  239:                                 tmp = rnd(objects[obj->otyp].wldam);
  240:                                 if (obj->otyp == TWO_HANDED_SWORD)
  241:                                         tmp += d(2, 6);
  242:                                 else if (obj->otyp == FLAIL)
  243:                                         tmp += rnd(4);
  244:                         } else {
  245:                                 tmp = rnd(objects[obj->otyp].wsdam);
  246:                         }
  247:                         tmp += obj->spe;
  248:                         if (!thrown && obj == uwep && obj->otyp == BOOMERANG
  249:                             && !rn2(3)) {
  250:                                 pline("As you hit %s, the boomerang breaks into splinters.",
  251:                                       monnam(mon));
  252:                                 freeinv(obj);
  253:                                 setworn((struct obj *) 0, obj->owornmask);
  254:                                 obfree(obj, (struct obj *) 0);
  255:                                 tmp++;
  256:                         }
  257:                 }
  258:                 if (mon->data->mlet == 'O' && obj->otyp == TWO_HANDED_SWORD &&
  259:                     !strcmp(ONAME(obj), "Orcrist"))
  260:                         tmp += rnd(10);
  261:         } else
  262:                 switch (obj->otyp) {
  263:                 case HEAVY_IRON_BALL:
  264:                         tmp = rnd(25);
  265:                         break;
  266:                 case EXPENSIVE_CAMERA:
  267:                         pline("You succeed in destroying your camera. Congratulations!");
  268:                         freeinv(obj);
  269:                         if (obj->owornmask)
  270:                                 setworn((struct obj *) 0, obj->owornmask);
  271:                         obfree(obj, (struct obj *) 0);
  272:                         return (TRUE);
  273:                 case DEAD_COCKATRICE:
  274:                         pline("You hit %s with the cockatrice corpse.",
  275:                               monnam(mon));
  276:                         if (mon->data->mlet == 'c') {
  277:                                 tmp = 1;
  278:                                 hittxt = TRUE;
  279:                                 break;
  280:                         }
  281:                         pline("%s is turned to stone!", Monnam(mon));
  282:                         killed(mon);
  283:                         return (FALSE);
  284:                 case CLOVE_OF_GARLIC: /* no effect against demons */
  285:                         if (strchr(UNDEAD, mon->data->mlet))
  286:                                 mon->mflee = 1;
  287:                         tmp = 1;
  288:                         break;
  289:                 default:
  290:                         /* non-weapons can damage because of their weight */
  291:                         /* (but not too much) */
  292:                         tmp = obj->owt / 10;
  293:                         if (tmp < 1)
  294:                                 tmp = 1;
  295:                         else
  296:                                 tmp = rnd(tmp);
  297:                         if (tmp > 6)
  298:                                 tmp = 6;
  299:                 }
  300: 
  301:         /****** NOTE: perhaps obj is undefined!! (if !thrown && BOOMERANG) */
  302: 
  303:         tmp += u.udaminc + dbon();
  304:         if (u.uswallow) {
  305:                 if ((tmp -= u.uswldtim) <= 0) {
  306:                         pline("Your arms are no longer able to hit.");
  307:                         return (TRUE);
  308:                 }
  309:         }
  310:         if (tmp < 1)
  311:                 tmp = 1;
  312:         mon->mhp -= tmp;
  313:         if (mon->mhp < 1) {
  314:                 killed(mon);
  315:                 return (FALSE);
  316:         }
  317:         if (mon->mtame && (!mon->mflee || mon->mfleetim)) {
  318:                 mon->mflee = 1;       /* Rick Richardson */
  319:                 mon->mfleetim += 10 * rnd(tmp);
  320:         }
  321:         if (!hittxt) {
  322:                 if (thrown)
  323:                         /* this assumes that we cannot throw plural things */
  324:                         hit(xname(obj) /* or: objects[obj->otyp].oc_name */ ,
  325:                             mon, exclam(tmp));
  326:                 else if (Blind)
  327:                         pline("You hit it.");
  328:                 else
  329:                         pline("You hit %s%s", monnam(mon), exclam(tmp));
  330:         }
  331:         if (u.umconf && !thrown) {
  332:                 if (!Blind) {
  333:                         pline("Your hands stop glowing blue.");
  334:                         if (!mon->mfroz && !mon->msleep)
  335:                                 pline("%s appears confused.", Monnam(mon));
  336:                 }
  337:                 mon->mconf = 1;
  338:                 u.umconf = 0;
  339:         }
  340:         return (TRUE);         /* mon still alive */
  341: }
  342: 
  343: /* try to attack; return FALSE if monster evaded */
  344: /* u.dx and u.dy must be set */
  345: int
  346: attack(mtmp)
  347:         struct monst   *mtmp;
  348: {
  349:         schar           tmp;
  350:         boolean         malive = TRUE;
  351:         const struct permonst *mdat;
  352:         mdat = mtmp->data;
  353: 
  354:         u_wipe_engr(3);                /* andrew@orca: prevent unlimited pick-axe
  355:                                  * attacks */
  356: 
  357:         if (mdat->mlet == 'L' && !mtmp->mfroz && !mtmp->msleep &&
  358:             !mtmp->mconf && mtmp->mcansee && !rn2(7) &&
  359:             (m_move(mtmp, 0) == 2 /* he died */ ||     /* he moved: */
  360:              mtmp->mx != u.ux + u.dx || mtmp->my != u.uy + u.dy))
  361:                 return (FALSE);
  362: 
  363:         if (mtmp->mimic) {
  364:                 if (!u.ustuck && !mtmp->mflee)
  365:                         u.ustuck = mtmp;
  366:                 switch (levl[u.ux + u.dx][u.uy + u.dy].scrsym) {
  367:                 case '+':
  368:                         pline("The door actually was a Mimic.");
  369:                         break;
  370:                 case '$':
  371:                         pline("The chest was a Mimic!");
  372:                         break;
  373:                 default:
  374:                         pline("Wait! That's a Mimic!");
  375:                 }
  376:                 wakeup(mtmp); /* clears mtmp->mimic */
  377:                 return (TRUE);
  378:         }
  379:         wakeup(mtmp);
  380: 
  381:         if (mtmp->mhide && mtmp->mundetected) {
  382:                 struct obj     *obj;
  383: 
  384:                 mtmp->mundetected = 0;
  385:                 if ((obj = o_at(mtmp->mx, mtmp->my)) && !Blind)
  386:                         pline("Wait! There's a %s hiding under %s!",
  387:                               mdat->mname, doname(obj));
  388:                 return (TRUE);
  389:         }
  390:         tmp = u.uluck + u.ulevel + mdat->ac + abon();
  391:         if (uwep) {
  392:                 if (uwep->olet == WEAPON_SYM || uwep->otyp == PICK_AXE)
  393:                         tmp += uwep->spe;
  394:                 if (uwep->otyp == TWO_HANDED_SWORD)
  395:                         tmp -= 1;
  396:                 else if (uwep->otyp == DAGGER)
  397:                         tmp += 2;
  398:                 else if (uwep->otyp == CRYSKNIFE)
  399:                         tmp += 3;
  400:                 else if (uwep->otyp == SPEAR &&
  401:                          strchr("XDne", mdat->mlet))
  402:                         tmp += 2;
  403:         }
  404:         if (mtmp->msleep) {
  405:                 mtmp->msleep = 0;
  406:                 tmp += 2;
  407:         }
  408:         if (mtmp->mfroz) {
  409:                 tmp += 4;
  410:                 if (!rn2(10))
  411:                         mtmp->mfroz = 0;
  412:         }
  413:         if (mtmp->mflee)
  414:                 tmp += 2;
  415:         if (u.utrap)
  416:                 tmp -= 3;
  417: 
  418:         /* with a lot of luggage, your agility diminishes */
  419:         tmp -= (inv_weight() + 40) / 20;
  420: 
  421:         if (tmp <= rnd(20) && !u.uswallow) {
  422:                 if (Blind)
  423:                         pline("You miss it.");
  424:                 else
  425:                         pline("You miss %s.", monnam(mtmp));
  426:         } else {
  427:                 /* we hit the monster; be careful: it might die! */
  428: 
  429:                 if ((malive = hmon(mtmp, uwep, 0)) == TRUE) {
  430:                         /* monster still alive */
  431:                         if (!rn2(25) && mtmp->mhp < mtmp->mhpmax / 2) {
  432:                                 mtmp->mflee = 1;
  433:                                 if (!rn2(3))
  434:                                         mtmp->mfleetim = rnd(100);
  435:                                 if (u.ustuck == mtmp && !u.uswallow)
  436:                                         u.ustuck = 0;
  437:                         }
  438: #ifndef NOWORM
  439:                         if (mtmp->wormno)
  440:                                 cutworm(mtmp, u.ux + u.dx, u.uy + u.dy,
  441:                                         uwep ? uwep->otyp : 0);
  442: #endif  /* NOWORM */
  443:                 }
  444:                 if (mdat->mlet == 'a') {
  445:                         if (rn2(2)) {
  446:                                 pline("You are splashed by the blob's acid!");
  447:                                 losehp_m(rnd(6), mtmp);
  448:                                 if (!rn2(30))
  449:                                         corrode_armor();
  450:                         }
  451:                         if (!rn2(6))
  452:                                 corrode_weapon();
  453:                 }
  454:         }
  455:         if (malive && mdat->mlet == 'E' && canseemon(mtmp)
  456:             && !mtmp->mcan && rn2(3)) {
  457:                 if (mtmp->mcansee) {
  458:                         pline("You are frozen by the floating eye's gaze!");
  459:                         nomul((u.ulevel > 6 || rn2(4)) ? rn1(20, -21) : -200);
  460:                 } else {
  461:                         pline("The blinded floating eye cannot defend itself.");
  462:                         if (!rn2(500))
  463:                                 if ((int) u.uluck > LUCKMIN)
  464:                                         u.uluck--;
  465:                 }
  466:         }
  467:         return (TRUE);
  468: }
Syntax (Markdown)