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

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

    1: /*      $NetBSD: hack.invent.c,v 1.9 2004/01/27 20:30:29 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.invent.c,v 1.9 2004/01/27 20:30:29 jsm Exp $");
   67: #endif                          /* not lint */
   68: 
   69: #include <stdlib.h>
   70: #include "hack.h"
   71: #include "extern.h"
   72: 
   73: #ifndef NOWORM
   74: #include        "def.wseg.h"
   75: #endif  /* NOWORM */
   76: 
   77: #define NOINVSYM        '#'
   78: 
   79: static int      lastinvnr = 51; /* 0 ... 51 */
   80: 
   81: static void assigninvlet(struct obj *);
   82: static char *xprname(struct obj *, char);
   83: 
   84: static void
   85: assigninvlet(otmp)
   86:         struct obj     *otmp;
   87: {
   88:         boolean         inuse[52];
   89:         int             i;
   90:         struct obj     *obj;
   91: 
   92:         for (i = 0; i < 52; i++)
   93:                 inuse[i] = FALSE;
   94:         for (obj = invent; obj; obj = obj->nobj)
   95:                 if (obj != otmp) {
   96:                         i = obj->invlet;
   97:                         if ('a' <= i && i <= 'z')
   98:                                 inuse[i - 'a'] = TRUE;
   99:                         else if ('A' <= i && i <= 'Z')
  100:                                 inuse[i - 'A' + 26] = TRUE;
  101:                         if (i == otmp->invlet)
  102:                                 otmp->invlet = 0;
  103:                 }
  104:         if ((i = otmp->invlet) &&
  105:             (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z')))
  106:                 return;
  107:         for (i = lastinvnr + 1; i != lastinvnr; i++) {
  108:                 if (i == 52) {
  109:                         i = -1;
  110:                         continue;
  111:                 }
  112:                 if (!inuse[i])
  113:                         break;
  114:         }
  115:         otmp->invlet = (inuse[i] ? NOINVSYM :
  116:                         (i < 26) ? ('a' + i) : ('A' + i - 26));
  117:         lastinvnr = i;
  118: }
  119: 
  120: struct obj     *
  121: addinv(obj)
  122:         struct obj     *obj;
  123: {
  124:         struct obj     *otmp;
  125: 
  126:         /* merge or attach to end of chain */
  127:         if (!invent) {
  128:                 invent = obj;
  129:                 otmp = 0;
  130:         } else
  131:                 for (otmp = invent; /* otmp */ ; otmp = otmp->nobj) {
  132:                         if (merged(otmp, obj, 0))
  133:                                 return (otmp);
  134:                         if (!otmp->nobj) {
  135:                                 otmp->nobj = obj;
  136:                                 break;
  137:                         }
  138:                 }
  139:         obj->nobj = 0;
  140: 
  141:         if (flags.invlet_constant) {
  142:                 assigninvlet(obj);
  143:                 /*
  144:                  * The ordering of the chain is nowhere significant
  145:                  * so in case you prefer some other order than the
  146:                  * historical one, change the code below.
  147:                  */
  148:                 if (otmp) {   /* find proper place in chain */
  149:                         otmp->nobj = 0;
  150:                         if ((invent->invlet ^ 040) > (obj->invlet ^ 040)) {
  151:                                 obj->nobj = invent;
  152:                                 invent = obj;
  153:                         } else
  154:                                 for (otmp = invent;; otmp = otmp->nobj) {
  155:                                         if (!otmp->nobj ||
  156:                                             (otmp->nobj->invlet ^ 040) > (obj->invlet ^ 040)) {
  157:                                                 obj->nobj = otmp->nobj;
  158:                                                 otmp->nobj = obj;
  159:                                                 break;
  160:                                         }
  161:                                 }
  162:                 }
  163:         }
  164:         return (obj);
  165: }
  166: 
  167: void
  168: useup(obj)
  169:         struct obj     *obj;
  170: {
  171:         if (obj->quan > 1) {
  172:                 obj->quan--;
  173:                 obj->owt = weight(obj);
  174:         } else {
  175:                 setnotworn(obj);
  176:                 freeinv(obj);
  177:                 obfree(obj, (struct obj *) 0);
  178:         }
  179: }
  180: 
  181: void
  182: freeinv(obj)
  183:         struct obj     *obj;
  184: {
  185:         struct obj     *otmp;
  186: 
  187:         if (obj == invent)
  188:                 invent = invent->nobj;
  189:         else {
  190:                 for (otmp = invent; otmp->nobj != obj; otmp = otmp->nobj)
  191:                         if (!otmp->nobj)
  192:                                 panic("freeinv");
  193:                 otmp->nobj = obj->nobj;
  194:         }
  195: }
  196: 
  197: /* destroy object in fobj chain (if unpaid, it remains on the bill) */
  198: void
  199: delobj(obj)
  200:         struct obj     *obj;
  201: {
  202:         freeobj(obj);
  203:         unpobj(obj);
  204:         obfree(obj, (struct obj *) 0);
  205: }
  206: 
  207: /* unlink obj from chain starting with fobj */
  208: void
  209: freeobj(obj)
  210:         struct obj     *obj;
  211: {
  212:         struct obj     *otmp;
  213: 
  214:         if (obj == fobj)
  215:                 fobj = fobj->nobj;
  216:         else {
  217:                 for (otmp = fobj; otmp->nobj != obj; otmp = otmp->nobj)
  218:                         if (!otmp)
  219:                                 panic("error in freeobj");
  220:                 otmp->nobj = obj->nobj;
  221:         }
  222: }
  223: 
  224: /* Note: freegold throws away its argument! */
  225: void
  226: freegold(gold)
  227:         struct gold    *gold;
  228: {
  229:         struct gold    *gtmp;
  230: 
  231:         if (gold == fgold)
  232:                 fgold = gold->ngold;
  233:         else {
  234:                 for (gtmp = fgold; gtmp->ngold != gold; gtmp = gtmp->ngold)
  235:                         if (!gtmp)
  236:                                 panic("error in freegold");
  237:                 gtmp->ngold = gold->ngold;
  238:         }
  239:         free((char *) gold);
  240: }
  241: 
  242: void
  243: deltrap(trap)
  244:         struct trap    *trap;
  245: {
  246:         struct trap    *ttmp;
  247: 
  248:         if (trap == ftrap)
  249:                 ftrap = ftrap->ntrap;
  250:         else {
  251:                 for (ttmp = ftrap; ttmp->ntrap != trap; ttmp = ttmp->ntrap);
  252:                 ttmp->ntrap = trap->ntrap;
  253:         }
  254:         free((char *) trap);
  255: }
  256: 
  257: struct wseg    *m_atseg;
  258: 
  259: struct monst   *
  260: m_at(x, y)
  261:         int x, y;
  262: {
  263:         struct monst   *mtmp;
  264: #ifndef NOWORM
  265:         struct wseg    *wtmp;
  266: #endif  /* NOWORM */
  267: 
  268:         m_atseg = 0;
  269:         for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
  270:                 if (mtmp->mx == x && mtmp->my == y)
  271:                         return (mtmp);
  272: #ifndef NOWORM
  273:                 if (mtmp->wormno) {
  274:                         for (wtmp = wsegs[mtmp->wormno]; wtmp; wtmp = wtmp->nseg)
  275:                                 if (wtmp->wx == x && wtmp->wy == y) {
  276:                                         m_atseg = wtmp;
  277:                                         return (mtmp);
  278:                                 }
  279:                 }
  280: #endif  /* NOWORM */
  281:         }
  282:         return (0);
  283: }
  284: 
  285: struct obj     *
  286: o_at(x, y)
  287:         int x, y;
  288: {
  289:         struct obj     *otmp;
  290: 
  291:         for (otmp = fobj; otmp; otmp = otmp->nobj)
  292:                 if (otmp->ox == x && otmp->oy == y)
  293:                         return (otmp);
  294:         return (0);
  295: }
  296: 
  297: struct obj     *
  298: sobj_at(n, x, y)
  299:         int n, x, y;
  300: {
  301:         struct obj     *otmp;
  302: 
  303:         for (otmp = fobj; otmp; otmp = otmp->nobj)
  304:                 if (otmp->ox == x && otmp->oy == y && otmp->otyp == n)
  305:                         return (otmp);
  306:         return (0);
  307: }
  308: 
  309: int
  310: carried(obj)
  311:         struct obj     *obj;
  312: {
  313:         struct obj     *otmp;
  314:         for (otmp = invent; otmp; otmp = otmp->nobj)
  315:                 if (otmp == obj)
  316:                         return (1);
  317:         return (0);
  318: }
  319: 
  320: int
  321: carrying(type)
  322:         int             type;
  323: {
  324:         struct obj     *otmp;
  325: 
  326:         for (otmp = invent; otmp; otmp = otmp->nobj)
  327:                 if (otmp->otyp == type)
  328:                         return (TRUE);
  329:         return (FALSE);
  330: }
  331: 
  332: struct obj     *
  333: o_on(id, objchn)
  334:         unsigned int    id;
  335:         struct obj     *objchn;
  336: {
  337:         while (objchn) {
  338:                 if (objchn->o_id == id)
  339:                         return (objchn);
  340:                 objchn = objchn->nobj;
  341:         }
  342:         return ((struct obj *) 0);
  343: }
  344: 
  345: struct trap    *
  346: t_at(x, y)
  347:         int x, y;
  348: {
  349:         struct trap    *trap = ftrap;
  350:         while (trap) {
  351:                 if (trap->tx == x && trap->ty == y)
  352:                         return (trap);
  353:                 trap = trap->ntrap;
  354:         }
  355:         return (0);
  356: }
  357: 
  358: struct gold    *
  359: g_at(x, y)
  360:         int x, y;
  361: {
  362:         struct gold    *gold = fgold;
  363:         while (gold) {
  364:                 if (gold->gx == x && gold->gy == y)
  365:                         return (gold);
  366:                 gold = gold->ngold;
  367:         }
  368:         return (0);
  369: }
  370: 
  371: /* make dummy object structure containing gold - for temporary use only */
  372: struct obj     *
  373: mkgoldobj(q)
  374:         long            q;
  375: {
  376:         struct obj     *otmp;
  377: 
  378:         otmp = newobj(0);
  379:         /* should set o_id etc. but otmp will be freed soon */
  380:         otmp->olet = '$';
  381:         u.ugold -= q;
  382:         OGOLD(otmp) = q;
  383:         flags.botl = 1;
  384:         return (otmp);
  385: }
  386: 
  387: /*
  388:  * getobj returns:
  389:  *      struct obj *xxx:     object to do something with.
  390:  *      (struct obj *) 0     error return: no object.
  391:  *      &zeroobj             explicitly no object (as in w-).
  392:  */
  393: struct obj     *
  394: getobj(let, word)
  395:         const char           *let, *word;
  396: {
  397:         struct obj     *otmp;
  398:         char            ilet, ilet1, ilet2;
  399:         char            buf[BUFSZ];
  400:         char            lets[BUFSZ];
  401:         int             foo = 0, foo2;
  402:         char           *bp = buf;
  403:         xchar           allowcnt = 0;  /* 0, 1 or 2 */
  404:         boolean         allowgold = FALSE;
  405:         boolean         allowall = FALSE;
  406:         boolean         allownone = FALSE;
  407:         xchar           foox = 0;
  408:         long            cnt;
  409: 
  410:         if (*let == '0')
  411:                 let++, allowcnt = 1;
  412:         if (*let == '$')
  413:                 let++, allowgold = TRUE;
  414:         if (*let == '#')
  415:                 let++, allowall = TRUE;
  416:         if (*let == '-')
  417:                 let++, allownone = TRUE;
  418:         if (allownone)
  419:                 *bp++ = '-';
  420:         if (allowgold)
  421:                 *bp++ = '$';
  422:         if (bp > buf && bp[-1] == '-')
  423:                 *bp++ = ' ';
  424: 
  425:         ilet = 'a';
  426:         for (otmp = invent; otmp; otmp = otmp->nobj) {
  427:                 if (!*let || strchr(let, otmp->olet)) {
  428:                         bp[foo++] = flags.invlet_constant ? otmp->invlet : ilet;
  429: 
  430:                         /* ugly check: remove inappropriate things */
  431:                         if ((!strcmp(word, "take off") &&
  432:                              !(otmp->owornmask & (W_ARMOR - W_ARM2)))
  433:                             || (!strcmp(word, "wear") &&
  434:                                 (otmp->owornmask & (W_ARMOR | W_RING)))
  435:                             || (!strcmp(word, "wield") &&
  436:                                 (otmp->owornmask & W_WEP))) {
  437:                                 foo--;
  438:                                 foox++;
  439:                         }
  440:                 }
  441:                 if (ilet == 'z')
  442:                         ilet = 'A';
  443:                 else
  444:                         ilet++;
  445:         }
  446:         bp[foo] = 0;
  447:         if (foo == 0 && bp > buf && bp[-1] == ' ')
  448:                 *--bp = 0;
  449:         (void) strcpy(lets, bp);/* necessary since we destroy buf */
  450:         if (foo > 5) {         /* compactify string */
  451:                 foo = foo2 = 1;
  452:                 ilet2 = bp[0];
  453:                 ilet1 = bp[1];
  454:                 while ((ilet = bp[++foo2] = bp[++foo]) != '\0') {
  455:                         if (ilet == ilet1 + 1) {
  456:                                 if (ilet1 == ilet2 + 1)
  457:                                         bp[foo2 - 1] = ilet1 = '-';
  458:                                 else if (ilet2 == '-') {
  459:                                         bp[--foo2] = ++ilet1;
  460:                                         continue;
  461:                                 }
  462:                         }
  463:                         ilet2 = ilet1;
  464:                         ilet1 = ilet;
  465:                 }
  466:         }
  467:         if (!foo && !allowall && !allowgold && !allownone) {
  468:                 pline("You don't have anything %sto %s.",
  469:                       foox ? "else " : "", word);
  470:                 return (0);
  471:         }
  472:         for (;;) {
  473:                 if (!buf[0])
  474:                         pline("What do you want to %s [*]? ", word);
  475:                 else
  476:                         pline("What do you want to %s [%s or ?*]? ",
  477:                               word, buf);
  478: 
  479:                 cnt = 0;
  480:                 ilet = readchar();
  481:                 while (digit(ilet) && allowcnt) {
  482:                         if (cnt < 100000000)
  483:                                 cnt = 10 * cnt + (ilet - '0');
  484:                         else
  485:                                 cnt = 999999999;
  486:                         allowcnt = 2;        /* signal presence of cnt */
  487:                         ilet = readchar();
  488:                 }
  489:                 if (digit(ilet)) {
  490:                         pline("No count allowed with this command.");
  491:                         continue;
  492:                 }
  493:                 if (strchr(quitchars, ilet))
  494:                         return ((struct obj *) 0);
  495:                 if (ilet == '-') {
  496:                         return (allownone ? &zeroobj : (struct obj *) 0);
  497:                 }
  498:                 if (ilet == '$') {
  499:                         if (!allowgold) {
  500:                                 pline("You cannot %s gold.", word);
  501:                                 continue;
  502:                         }
  503:                         if (!(allowcnt == 2 && cnt < u.ugold))
  504:                                 cnt = u.ugold;
  505:                         return (mkgoldobj(cnt));
  506:                 }
  507:                 if (ilet == '?') {
  508:                         doinv(lets);
  509:                         if (!(ilet = morc))
  510:                                 continue;
  511:                         /* he typed a letter (not a space) to more() */
  512:                 } else if (ilet == '*') {
  513:                         doinv((char *) 0);
  514:                         if (!(ilet = morc))
  515:                                 continue;
  516:                         /* ... */
  517:                 }
  518:                 if (flags.invlet_constant) {
  519:                         for (otmp = invent; otmp; otmp = otmp->nobj)
  520:                                 if (otmp->invlet == ilet)
  521:                                         break;
  522:                 } else {
  523:                         if (ilet >= 'A' && ilet <= 'Z')
  524:                                 ilet += 'z' - 'A' + 1;
  525:                         ilet -= 'a';
  526:                         for (otmp = invent; otmp && ilet;
  527:                              ilet--, otmp = otmp->nobj);
  528:                 }
  529:                 if (!otmp) {
  530:                         pline("You don't have that object.");
  531:                         continue;
  532:                 }
  533:                 if (cnt < 0 || otmp->quan < cnt) {
  534:                         pline("You don't have that many! [You have %u]"
  535:                               ,otmp->quan);
  536:                         continue;
  537:                 }
  538:                 break;
  539:         }
  540:         if (!allowall && let && !strchr(let, otmp->olet)) {
  541:                 pline("That is a silly thing to %s.", word);
  542:                 return (0);
  543:         }
  544:         if (allowcnt == 2) {   /* cnt given */
  545:                 if (cnt == 0)
  546:                         return (0);
  547:                 if (cnt != otmp->quan) {
  548:                         struct obj     *obj;
  549:                         obj = splitobj(otmp, (int) cnt);
  550:                         if (otmp == uwep)
  551:                                 setuwep(obj);
  552: