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

bsd-games/2.17/hack/hack.c

    1: /*      $NetBSD: hack.c,v 1.6 2003/04/02 18:36:35 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.c,v 1.6 2003/04/02 18:36:35 jsm Exp $");
   67: #endif                          /* not lint */
   68: 
   69: #include "hack.h"
   70: #include "extern.h"
   71: 
   72: /*
   73:  * called on movement: 1. when throwing ball+chain far away 2. when
   74:  * teleporting 3. when walking out of a lit room
   75:  */
   76: void
   77: unsee()
   78: {
   79:         int x, y;
   80:         struct rm *lev;
   81: 
   82:         /*
   83:                 if(u.udispl){
   84:                         u.udispl = 0;
   85:                         newsym(u.udisx, u.udisy);
   86:                 }
   87:         */
   88: #ifndef QUEST
   89:         if (seehx) {
   90:                 seehx = 0;
   91:         } else
   92: #endif  /* QUEST */
   93:                 for (x = u.ux - 1; x < u.ux + 2; x++)
   94:                         for (y = u.uy - 1; y < u.uy + 2; y++) {
   95:                                 if (!isok(x, y))
   96:                                         continue;
   97:                                 lev = &levl[x][y];
   98:                                 if (!lev->lit && lev->scrsym == '.') {
   99:                                         lev->scrsym = ' ';
  100:                                         lev->new = 1;
  101:                                         on_scr(x, y);
  102:                                 }
  103:                         }
  104: }
  105: 
  106: /*
  107:  * called: in hack.eat.c: seeoff(0) - blind after eating rotten food in
  108:  * hack.mon.c: seeoff(0) - blinded by a yellow light in hack.mon.c: seeoff(1)
  109:  * - swallowed in hack.do.c:  seeoff(0) - blind after drinking potion in
  110:  * hack.do.c:  seeoff(1) - go up or down the stairs in hack.trap.c:seeoff(1)
  111:  * - fall through trapdoor
  112:  */
  113: void
  114: seeoff(mode)
  115:         int mode;              /* 1 to redo @, 0 to leave them *//* 1 means
  116:                                  * misc movement, 0 means blindness */
  117: {
  118:         int x, y;
  119:         struct rm *lev;
  120: 
  121:         if (u.udispl && mode) {
  122:                 u.udispl = 0;
  123:                 levl[u.udisx][u.udisy].scrsym = news0(u.udisx, u.udisy);
  124:         }
  125: #ifndef QUEST
  126:         if (seehx) {
  127:                 seehx = 0;
  128:         } else
  129: #endif  /* QUEST */
  130:         if (!mode) {
  131:                 for (x = u.ux - 1; x < u.ux + 2; x++)
  132:                         for (y = u.uy - 1; y < u.uy + 2; y++) {
  133:                                 if (!isok(x, y))
  134:                                         continue;
  135:                                 lev = &levl[x][y];
  136:                                 if (!lev->lit && lev->scrsym == '.')
  137:                                         lev->seen = 0;
  138:                         }
  139:         }
  140: }
  141: 
  142: void
  143: domove()
  144: {
  145:         xchar           oldx, oldy;
  146:         struct monst *mtmp = NULL;
  147:         struct rm *tmpr, *ust;
  148:         struct trap    *trap = NULL;
  149:         struct obj *otmp = NULL;
  150: 
  151:         u_wipe_engr(rnd(5));
  152: 
  153:         if (inv_weight() > 0) {
  154:                 pline("You collapse under your load.");
  155:                 nomul(0);
  156:                 return;
  157:         }
  158:         if (u.uswallow) {
  159:                 u.dx = u.dy = 0;
  160:                 u.ux = u.ustuck->mx;
  161:                 u.uy = u.ustuck->my;
  162:         } else {
  163:                 if (Confusion) {
  164:                         do {
  165:                                 confdir();
  166:                         } while (!isok(u.ux + u.dx, u.uy + u.dy) ||
  167:                                IS_ROCK(levl[u.ux + u.dx][u.uy + u.dy].typ));
  168:                 }
  169:                 if (!isok(u.ux + u.dx, u.uy + u.dy)) {
  170:                         nomul(0);
  171:                         return;
  172:                 }
  173:         }
  174: 
  175:         ust = &levl[u.ux][u.uy];
  176:         oldx = u.ux;
  177:         oldy = u.uy;
  178:         if (!u.uswallow && (trap = t_at(u.ux + u.dx, u.uy + u.dy)) && trap->tseen)
  179:                 nomul(0);
  180:         if (u.ustuck && !u.uswallow && (u.ux + u.dx != u.ustuck->mx ||
  181:                                         u.uy + u.dy != u.ustuck->my)) {
  182:                 if (dist(u.ustuck->mx, u.ustuck->my) > 2) {
  183:                         /* perhaps it fled (or was teleported or ... ) */
  184:                         u.ustuck = 0;
  185:                 } else {
  186:                         if (Blind)
  187:                                 pline("You cannot escape from it!");
  188:                         else
  189:                                 pline("You cannot escape from %s!",
  190:                                       monnam(u.ustuck));
  191:                         nomul(0);
  192:                         return;
  193:                 }
  194:         }
  195:         if (u.uswallow || (mtmp = m_at(u.ux + u.dx, u.uy + u.dy))) {
  196:                 /* attack monster */
  197: 
  198:                 nomul(0);
  199:                 gethungry();
  200:                 if (multi < 0)
  201:                         return;      /* we just fainted */
  202: 
  203:                 /* try to attack; note that it might evade */
  204:                 if (attack(u.uswallow ? u.ustuck : mtmp))
  205:                         return;
  206:         }
  207:         /* not attacking an animal, so we try to move */
  208:         if (u.utrap) {
  209:                 if (u.utraptype == TT_PIT) {
  210:                         pline("You are still in a pit.");
  211:                         u.utrap--;
  212:                 } else {
  213:                         pline("You are caught in a beartrap.");
  214:                         if ((u.dx && u.dy) || !rn2(5))
  215:                                 u.utrap--;
  216:                 }
  217:                 return;
  218:         }
  219:         tmpr = &levl[u.ux + u.dx][u.uy + u.dy];
  220:         if (IS_ROCK(tmpr->typ) ||
  221:             (u.dx && u.dy && (tmpr->typ == DOOR || ust->typ == DOOR))) {
  222:                 flags.move = 0;
  223:                 nomul(0);
  224:                 return;
  225:         }
  226:         while ((otmp = sobj_at(ENORMOUS_ROCK, u.ux + u.dx, u.uy + u.dy)) != NULL){
  227:                 xchar  rx = u.ux + 2 * u.dx, ry = u.uy + 2 * u.dy;
  228:                 struct trap *ttmp;
  229:                 nomul(0);
  230:                 if (isok(rx, ry) && !IS_ROCK(levl[rx][ry].typ) &&
  231:                     (levl[rx][ry].typ != DOOR || !(u.dx && u.dy)) &&
  232:                     !sobj_at(ENORMOUS_ROCK, rx, ry)) {
  233:                         if (m_at(rx, ry)) {
  234:                                 pline("You hear a monster behind the rock.");
  235:                                 pline("Perhaps that's why you cannot move it.");
  236:                                 goto cannot_push;
  237:                         }
  238:                         if ((ttmp = t_at(rx, ry)) != NULL)
  239:                                 switch (ttmp->ttyp) {
  240:                                 case PIT:
  241:                                         pline("You push the rock into a pit!");
  242:                                         deltrap(ttmp);
  243:                                         delobj(otmp);
  244:                                         pline("It completely fills the pit!");
  245:                                         continue;
  246:                                 case TELEP_TRAP:
  247:                                         pline("You push the rock and suddenly it disappears!");
  248:                                         delobj(otmp);
  249:                                         continue;
  250:                                 }
  251:                         if (levl[rx][ry].typ == POOL) {
  252:                                 levl[rx][ry].typ = ROOM;
  253:                                 mnewsym(rx, ry);
  254:                                 prl(rx, ry);
  255:                                 pline("You push the rock into the water.");
  256:                                 pline("Now you can cross the water!");
  257:                                 delobj(otmp);
  258:                                 continue;
  259:                         }
  260:                         otmp->ox = rx;
  261:                         otmp->oy = ry;
  262:                         /* pobj(otmp); */
  263:                         if (cansee(rx, ry))
  264:                                 atl(rx, ry, otmp->olet);
  265:                         if (Invisible)
  266:                                 newsym(u.ux + u.dx, u.uy + u.dy);
  267: 
  268:                         {
  269:                                 static long     lastmovetime;
  270:                                 /*
  271:                                  * note: this var contains garbage initially
  272:                                  * and after a restore
  273:                                  */
  274:                                 if (moves > lastmovetime + 2 || moves < lastmovetime)
  275:                                         pline("With great effort you move the enormous rock.");
  276:                                 lastmovetime = moves;
  277:                         }
  278:                 } else {
  279:                         pline("You try to move the enormous rock, but in vain.");
  280:         cannot_push:
  281:                         if ((!invent || inv_weight() + 90 <= 0) &&
  282:                             (!u.dx || !u.dy || (IS_ROCK(levl[u.ux][u.uy + u.dy].typ)
  283:                                 && IS_ROCK(levl[u.ux + u.dx][u.uy].typ)))) {
  284:                                 pline("However, you can squeeze yourself into a small opening.");
  285:                                 break;
  286:                         } else
  287:                                 return;
  288:                 }
  289:         }
  290:         if (u.dx && u.dy && IS_ROCK(levl[u.ux][u.uy + u.dy].typ) &&
  291:             IS_ROCK(levl[u.ux + u.dx][u.uy].typ) &&
  292:             invent && inv_weight() + 40 > 0) {
  293:                 pline("You are carrying too much to get through.");
  294:                 nomul(0);
  295:                 return;
  296:         }
  297:         if (Punished &&
  298:             DIST(u.ux + u.dx, u.uy + u.dy, uchain->ox, uchain->oy) > 2) {
  299:                 if (carried(uball)) {
  300:                         movobj(uchain, u.ux, u.uy);
  301:                         goto nodrag;
  302:                 }
  303:                 if (DIST(u.ux + u.dx, u.uy + u.dy, uball->ox, uball->oy) < 3) {
  304:                         /* leave ball, move chain under/over ball */
  305:                         movobj(uchain, uball->ox, uball->oy);
  306:                         goto nodrag;
  307:                 }
  308:                 if (inv_weight() + (int) uball->owt / 2 > 0) {
  309:                         pline("You cannot %sdrag the heavy iron ball.",
  310:                               invent ? "carry all that and also " : "");
  311:                         nomul(0);
  312:                         return;
  313:                 }
  314:                 movobj(uball, uchain->ox, uchain->oy);
  315:                 unpobj(uball);        /* BAH %% */
  316:                 uchain->ox = u.ux;
  317:                 uchain->oy = u.uy;
  318:                 nomul(-2);
  319:                 nomovemsg = "";
  320: nodrag: ;
  321:         }
  322:         u.ux += u.dx;
  323:         u.uy += u.dy;
  324:         if (flags.run) {
  325:                 if (tmpr->typ == DOOR ||
  326:                     (xupstair == u.ux && yupstair == u.uy) ||
  327:                     (xdnstair == u.ux && ydnstair == u.uy))
  328:                         nomul(0);
  329:         }
  330:         if (tmpr->typ == POOL && !Levitation)
  331:                 drown();      /* not necessarily fatal */
  332: 
  333:         /*
  334:                 if(u.udispl) {
  335:                         u.udispl = 0;
  336:                         newsym(oldx,oldy);
  337:                 }
  338:         */
  339:         if (!Blind) {
  340: #ifdef QUEST
  341:                 setsee();
  342: #else
  343:                 if (ust->lit) {
  344:                         if (tmpr->lit) {
  345:                                 if (tmpr->typ == DOOR)
  346:                                         prl1(u.ux + u.dx, u.uy + u.dy);
  347:                                 else if (ust->typ == DOOR)
  348:                                         nose1(oldx - u.dx, oldy - u.dy);
  349:                         } else {
  350:                                 unsee();
  351:                                 prl1(u.ux + u.dx, u.uy + u.dy);
  352:                         }
  353:                 } else {
  354:                         if (tmpr->lit)
  355:                                 setsee();
  356:                         else {
  357:                                 prl1(u.ux + u.dx, u.uy + u.dy);
  358:                                 if (tmpr->typ == DOOR) {
  359:                                         if (u.dy) {
  360:                                                 prl(u.ux - 1, u.uy);
  361:                                                 prl(u.ux + 1, u.uy);
  362:                                         } else {
  363:                                                 prl(u.ux, u.uy - 1);
  364:                                                 prl(u.ux, u.uy + 1);
  365:                                         }
  366:                                 }
  367:                         }
  368:                         nose1(oldx - u.dx, oldy - u.dy);
  369:                 }
  370: #endif  /* QUEST */
  371:         } else {
  372:                 pru();
  373:         }
  374:         if (!flags.nopick)
  375:                 pickup(1);
  376:         if (trap)
  377:                 dotrap(trap); /* fall into pit, arrow trap, etc. */
  378:         (void) inshop();
  379:         if (!Blind)
  380:                 read_engr_at(u.ux, u.uy);
  381: }
  382: 
  383: void
  384: movobj(obj, ox, oy)
  385:         struct obj *obj;
  386:         int    ox, oy;
  387: {
  388:         /* Some dirty programming to get display right */
  389:         freeobj(obj);
  390:         unpobj(obj);
  391:         obj->nobj = fobj;
  392:         fobj = obj;
  393:         obj->ox = ox;
  394:         obj->oy = oy;
  395: }
  396: 
  397: int
  398: dopickup()
  399: {
  400:         if (!g_at(u.ux, u.uy) && !o_at(u.ux, u.uy)) {
  401:                 pline("There is nothing here to pick up.");
  402:                 return (0);
  403:         }
  404:         if (Levitation) {
  405:                 pline("You cannot reach the floor.");
  406:                 return (1);
  407:         }
  408:         pickup(0);
  409:         return (1);
  410: }
  411: 
  412: void
  413: pickup(int all)
  414: {
  415:         struct gold *gold;
  416:         struct obj *obj, *obj2;
  417:         int    wt;
  418: 
  419:         if (Levitation)
  420:                 return;
  421:         while ((gold = g_at(u.ux, u.uy)) != NULL) {
  422:                 pline("%ld gold piece%s.", gold->amount, plur(gold->amount));
  423:                 u.ugold += gold->amount;
  424:                 flags.botl = 1;
  425:                 freegold(gold);
  426:                 if (flags.run)
  427:                         nomul(0);
  428:                 if (Invisible)
  429:                         newsym(u.ux, u.uy);
  430:         }
  431: 
  432:         /* check for more than one object */
  433:         if (!all) {
  434:                 int    ct = 0;
  435: 
  436:                 for (obj = fobj; obj; obj = obj->nobj)
  437:                         if (obj->ox == u.ux && obj->oy == u.uy)
  438:                                 if (!Punished || obj != uchain)
  439:                                         ct++;
  440:                 if (ct < 2)
  441:                         all++;
  442:                 else
  443:                         pline("There are several objects here.");
  444:         }
  445:         for (obj = fobj; obj; obj = obj2) {
  446:                 obj2 = obj->nobj;     /* perhaps obj will be picked up */
  447:                 if (obj->ox == u.ux && obj->oy == u.uy) {
  448:                         if (flags.run)
  449:                                 nomul(0);
  450: 
  451:                         /* do not pick up uchain */
  452:                         if (Punished && obj == uchain)
  453:                                 continue;
  454: 
  455:                         if (!all) {
  456:                                 char            c;
  457: 
  458:                                 pline("Pick up %s ? [ynaq]", doname(obj));
  459:                                 while (!strchr("ynaq ", (c = readchar())))
  460:                                         bell();
  461:                                 if (c == 'q')
  462:                                         return;
  463:                                 if (c == 'n')
  464:                                         continue;
  465:                                 if (c == 'a')
  466:                                         all = 1;
  467:                         }
  468:                         if (obj->otyp == DEAD_COCKATRICE && !uarmg) {
  469:                                 pline("Touching the dead cockatrice is a fatal mistake.");
  470:                                 pline("You turn to stone.");
  471:                                 killer = "cockatrice cadaver";
  472:                                 done("died");
  473:                         }
  474:                         if (obj->otyp == SCR_SCARE_MONSTER) {
  475:                                 if (!obj->spe)
  476:                                         obj->spe = 1;
  477:                                 else {
  478:                                         /*
  479:                                          * Note: perhaps the 1st pickup
  480:                                          * failed: you cannot carry anymore,
  481:                                          * and so we never dropped it - let's
  482:                                          * assume that treading on it twice
  483:                                          * also destroys the scroll
  484:                                          */
  485:                                         pline("The scroll turns to dust as you pick it up.");
  486:                                         delobj(obj);
  487:                                         continue;
  488:                                 }
  489:                         }
  490:                         wt = inv_weight() + obj->owt;
  491:                         if (wt > 0) {
  492:                                 if (obj->quan > 1) {
  493:                                         /* see how many we can lift */
  494:                                         int             savequan = obj->quan;
  495:                                         int             iw = inv_weight();
  496:                                         int             qq;
  497:                                         for (qq = 1; qq < savequan; qq++) {
  498:                                                 obj->quan = qq;
  499:                                                 if (iw + weight(obj) > 0)
  500:                                                         break;
  501:                                         }
  502:                                         obj->quan = savequan;
  503:                                         qq--;
  504:                                         /* we can carry qq of them */
  505:                                         if (!qq)
  506:                                                 goto too_heavy;
  507:                                         pline("You can only carry %s of the %s lying here.",
  508:                                               (qq == 1) ? "one" : "some",
  509:                                               doname(obj));
  510:                                         (void) splitobj(obj, qq);
  511:                                         /*
  512:                                          * note: obj2 is set already, so
  513:                                          * we'll never encounter the other
  514:                                          * half; if it should be otherwise
  515:                                          * then write obj2 =
  516:                                          * splitobj(obj,qq);
  517:                                          */
  518:                                         goto lift_some;
  519:                                 }
  520:                 too_heavy:
  521:                                 pline("There %s %s here, but %s.",
  522:                                       (obj->quan == 1) ? "is" : "are",
  523:                                       doname(obj),
  524:                                  !invent ? "it is too heavy for you to lift"
  525:                                       : "you cannot carry anymore");
  526:                                 break;
  527:                         }
  528:         lift_some:
  529:                         if (inv_cnt() >= 52) {
  530:                                 pline("Your knapsack cannot accomodate anymore items.");
  531:                                 break;
  532:                         }
  533:                         if (wt > -5)
  534:                                 pline("You have a little trouble lifting");