home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / HACKSRC.ZIP / INVENT.C < prev    next >
C/C++ Source or Header  |  1985-10-16  |  21KB  |  906 lines

  1. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  2. /* invent.c - version 1.0.3 */
  3.  
  4. #include    <stdio.h>
  5. #include    "hack.h"
  6. extern struct obj *splitobj();
  7. extern struct obj zeroobj;
  8. extern char morc;
  9. extern char quitchars[];
  10. char *xprname();
  11.  
  12. #ifndef NOWORM
  13. #include    "wseg.h"
  14. extern struct wseg *wsegs[32];
  15. #endif NOWORM
  16.  
  17. #define    NOINVSYM    '#'
  18.  
  19. int lastinvnr = 51;    /* 0 ... 51 */
  20. static
  21. assigninvlet(otmp)
  22. register struct obj *otmp;
  23. {
  24.     boolean inuse[52];
  25.     register int i;
  26.     register struct obj *obj;
  27.  
  28.     for(i = 0; i < 52; i++) inuse[i] = FALSE;
  29.     for(obj = invent; obj; obj = obj->nobj) if(obj != otmp) {
  30.         i = obj->invlet;
  31.         if('a' <= i && i <= 'z') inuse[i - 'a'] = TRUE; else
  32.         if('A' <= i && i <= 'Z') inuse[i - 'A' + 26] = TRUE;
  33.         if(i == otmp->invlet) otmp->invlet = 0;
  34.     }
  35.     if((i = otmp->invlet) &&
  36.         (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z')))
  37.         return;
  38.     for(i = lastinvnr+1; i != lastinvnr; i++) {
  39.         if(i == 52) { i = -1; continue; }
  40.         if(!inuse[i]) break;
  41.     }
  42.     otmp->invlet = (inuse[i] ? NOINVSYM :
  43.             (i < 26) ? ('a'+i) : ('A'+i-26));
  44.     lastinvnr = i;
  45. }
  46.  
  47. struct obj *
  48. addinv(obj)
  49. register struct obj *obj;
  50. {
  51.     register struct obj *otmp;
  52.  
  53.     /* merge or attach to end of chain */
  54.     if(!invent) {
  55.         invent = obj;
  56.         otmp = 0;
  57.     } else
  58.     for(otmp = invent; /* otmp */; otmp = otmp->nobj) {
  59.         if(merged(otmp, obj, 0))
  60.             return(otmp);
  61.         if(!otmp->nobj) {
  62.             otmp->nobj = obj;
  63.             break;
  64.         }
  65.     }
  66.     obj->nobj = 0;
  67.  
  68.     if(flags.invlet_constant) {
  69.         assigninvlet(obj);
  70.         /*
  71.          * The ordering of the chain is nowhere significant
  72.          * so in case you prefer some other order than the
  73.          * historical one, change the code below.
  74.          */
  75.         if(otmp) {    /* find proper place in chain */
  76.             otmp->nobj = 0;
  77.             if((invent->invlet ^ 040) > (obj->invlet ^ 040)) {
  78.                 obj->nobj = invent;
  79.                 invent = obj;
  80.             } else
  81.             for(otmp = invent; ; otmp = otmp->nobj) {
  82.                 if(!otmp->nobj ||
  83.                 (otmp->nobj->invlet ^ 040) > (obj->invlet ^ 040)){
  84.                 obj->nobj = otmp->nobj;
  85.                 otmp->nobj = obj;
  86.                 break;
  87.                 }
  88.             }
  89.         }
  90.     }
  91.  
  92.     return(obj);
  93. }
  94.  
  95. useup(obj)
  96. register struct obj *obj;
  97. {
  98.     if(obj->quan > 1){
  99.         obj->quan--;
  100.         obj->owt = weight(obj);
  101.     } else {
  102.         setnotworn(obj);
  103.         freeinv(obj);
  104.         obfree(obj, (struct obj *) 0);
  105.     }
  106. }
  107.  
  108. freeinv(obj)
  109. register struct obj *obj;
  110. {
  111.     register struct obj *otmp;
  112.  
  113.     if(obj == invent)
  114.         invent = invent->nobj;
  115.     else {
  116.         for(otmp = invent; otmp->nobj != obj; otmp = otmp->nobj)
  117.             if(!otmp->nobj) panic("freeinv");
  118.         otmp->nobj = obj->nobj;
  119.     }
  120. }
  121.  
  122. /* destroy object in fobj chain (if unpaid, it remains on the bill) */
  123. delobj(obj) register struct obj *obj; {
  124.     freeobj(obj);
  125.     unpobj(obj);
  126.     obfree(obj, (struct obj *) 0);
  127. }
  128.  
  129. /* unlink obj from chain starting with fobj */
  130. freeobj(obj) register struct obj *obj; {
  131.     register struct obj *otmp;
  132.  
  133.     if(obj == fobj) fobj = fobj->nobj;
  134.     else {
  135.         for(otmp = fobj; otmp->nobj != obj; otmp = otmp->nobj)
  136.             if(!otmp) panic("error in freeobj");
  137.         otmp->nobj = obj->nobj;
  138.     }
  139. }
  140.  
  141. /* Note: freegold throws away its argument! */
  142. freegold(gold) register struct gold *gold; {
  143.     register struct gold *gtmp;
  144.  
  145.     if(gold == fgold) fgold = gold->ngold;
  146.     else {
  147.         for(gtmp = fgold; gtmp->ngold != gold; gtmp = gtmp->ngold)
  148.             if(!gtmp) panic("error in freegold");
  149.         gtmp->ngold = gold->ngold;
  150.     }
  151.     free((char *) gold);
  152. }
  153.  
  154. deltrap(trap)
  155. register struct trap *trap;
  156. {
  157.     register struct trap *ttmp;
  158.  
  159.     if(trap == ftrap)
  160.         ftrap = ftrap->ntrap;
  161.     else {
  162.         for(ttmp = ftrap; ttmp->ntrap != trap; ttmp = ttmp->ntrap) ;
  163.         ttmp->ntrap = trap->ntrap;
  164.     }
  165.     free((char *) trap);
  166. }
  167.  
  168. struct wseg *m_atseg;
  169.  
  170. struct monst *
  171. m_at(x,y)
  172. register x,y;
  173. {
  174.     register struct monst *mtmp;
  175. #ifndef NOWORM
  176.     register struct wseg *wtmp;
  177. #endif NOWORM
  178.  
  179.     m_atseg = 0;
  180.     for(mtmp = fmon; mtmp; mtmp = mtmp->nmon){
  181.         if(mtmp->mx == x && mtmp->my == y)
  182.             return(mtmp);
  183. #ifndef NOWORM
  184.         if(mtmp->wormno){
  185.             for(wtmp = wsegs[mtmp->wormno]; wtmp; wtmp = wtmp->nseg)
  186.             if(wtmp->wx == x && wtmp->wy == y){
  187.             m_atseg = wtmp;
  188.             return(mtmp);
  189.             }
  190.         }
  191. #endif NOWORM
  192.     }
  193.     return(0);
  194. }
  195.  
  196. struct obj *
  197. o_at(x,y)
  198. register x,y;
  199. {
  200.     register struct obj *otmp;
  201.  
  202.     for(otmp = fobj; otmp; otmp = otmp->nobj)
  203.         if(otmp->ox == x && otmp->oy == y) return(otmp);
  204.     return(0);
  205. }
  206.  
  207. struct obj *
  208. sobj_at(n,x,y)
  209. register n,x,y;
  210. {
  211.     register struct obj *otmp;
  212.  
  213.     for(otmp = fobj; otmp; otmp = otmp->nobj)
  214.         if(otmp->ox == x && otmp->oy == y && otmp->otyp == n)
  215.             return(otmp);
  216.     return(0);
  217. }
  218.  
  219. carried(obj) register struct obj *obj; {
  220. register struct obj *otmp;
  221.     for(otmp = invent; otmp; otmp = otmp->nobj)
  222.         if(otmp == obj) return(1);
  223.     return(0);
  224. }
  225.  
  226. carrying(type)
  227. register int type;
  228. {
  229.     register struct obj *otmp;
  230.  
  231.     for(otmp = invent; otmp; otmp = otmp->nobj)
  232.         if(otmp->otyp == type)
  233.             return(TRUE);
  234.     return(FALSE);
  235. }
  236.  
  237. struct obj *
  238. o_on(id, objchn) unsigned int id; register struct obj *objchn; {
  239.     while(objchn) {
  240.         if(objchn->o_id == id) return(objchn);
  241.         objchn = objchn->nobj;
  242.     }
  243.     return((struct obj *) 0);
  244. }
  245.  
  246. struct trap *
  247. t_at(x,y)
  248. register x,y;
  249. {
  250.     register struct trap *trap = ftrap;
  251.     while(trap) {
  252.         if(trap->tx == x && trap->ty == y) return(trap);
  253.         trap = trap->ntrap;
  254.     }
  255.     return(0);
  256. }
  257.  
  258. struct gold *
  259. g_at(x,y)
  260. register x,y;
  261. {
  262.     register struct gold *gold = fgold;
  263.     while(gold) {
  264.         if(gold->gx == x && gold->gy == y) return(gold);
  265.         gold = gold->ngold;
  266.     }
  267.     return(0);
  268. }
  269.  
  270. /* make dummy object structure containing gold - for temporary use only */
  271. struct obj *
  272. mkgoldobj(q)
  273. register long q;
  274. {
  275.     register struct obj *otmp;
  276.  
  277.     otmp = newobj(0);
  278.     /* should set o_id etc. but otmp will be freed soon */
  279.     otmp->olet = '$';
  280.     u.ugold -= q;
  281.     OGOLD(otmp) = q;
  282.     flags.botl = 1;
  283.     return(otmp);
  284. }
  285.  
  286. /*
  287.  * getobj returns:
  288.  *    struct obj *xxx:    object to do something with.
  289.  *    (struct obj *) 0    error return: no object.
  290.  *    &zeroobj        explicitly no object (as in w-).
  291.  */
  292. struct obj *
  293. getobj(let,word)
  294. register char *let,*word;
  295. {
  296.     register struct obj *otmp;
  297.     register char ilet,ilet1,ilet2;
  298.     char buf[BUFSZ];
  299.     char lets[BUFSZ];
  300.     register int foo = 0, foo2;
  301.     register char *bp = buf;
  302.     xchar allowcnt = 0;    /* 0, 1 or 2 */
  303.     boolean allowgold = FALSE;
  304.     boolean allowall = FALSE;
  305.     boolean allownone = FALSE;
  306.     xchar foox = 0;
  307.     long cnt;
  308.  
  309.     if(*let == '0') let++, allowcnt = 1;
  310.     if(*let == '$') let++, allowgold = TRUE;
  311.     if(*let == '#') let++, allowall = TRUE;
  312.     if(*let == '-') let++, allownone = TRUE;
  313.     if(allownone) *bp++ = '-';
  314.     if(allowgold) *bp++ = '$';
  315.     if(bp > buf && bp[-1] == '-') *bp++ = ' ';
  316.  
  317.     ilet = 'a';
  318.     for(otmp = invent; otmp; otmp = otmp->nobj){
  319.         if(!*let || index(let, otmp->olet)) {
  320.         bp[foo++] = flags.invlet_constant ? otmp->invlet : ilet;
  321.  
  322.         /* ugly check: remove inappropriate things */
  323.         if((!strcmp(word, "take off") &&
  324.             !(otmp->owornmask & (W_ARMOR - W_ARM2)))
  325.         || (!strcmp(word, "wear") &&
  326.             (otmp->owornmask & (W_ARMOR | W_RING)))
  327.         || (!strcmp(word, "wield") &&
  328.             (otmp->owornmask & W_WEP))) {
  329.             foo--;
  330.             foox++;
  331.         }
  332.         }
  333.         if(ilet == 'z') ilet = 'A'; else ilet++;
  334.     }
  335.     bp[foo] = 0;
  336.     if(foo == 0 && bp > buf && bp[-1] == ' ') *--bp = 0;
  337.     (void) strcpy(lets, bp);    /* necessary since we destroy buf */
  338.     if(foo > 5) {            /* compactify string */
  339.         foo = foo2 = 1;
  340.         ilet2 = bp[0];
  341.         ilet1 = bp[1];
  342.         while(ilet = bp[++foo2] = bp[++foo]){
  343.             if(ilet == ilet1+1){
  344.                 if(ilet1 == ilet2+1)
  345.                     bp[foo2 - 1] = ilet1 = '-';
  346.                 else if(ilet2 == '-') {
  347.                     bp[--foo2] = ++ilet1;
  348.                     continue;
  349.                 }
  350.             }
  351.             ilet2 = ilet1;
  352.             ilet1 = ilet;
  353.         }
  354.     }
  355.     if(!foo && !allowall && !allowgold && !allownone) {
  356.         pline("You don't have anything %sto %s.",
  357.             foox ? "else " : "", word);
  358.         return(0);
  359.     }
  360.     for(;;) {
  361.         if(!buf[0])
  362.             pline("What do you want to %s [*]? ", word);
  363.         else
  364.             pline("What do you want to %s [%s or ?*]? ",
  365.                 word, buf);
  366.  
  367.         cnt = 0;
  368.         ilet = readchar();
  369.         while(digit(ilet) && allowcnt) {
  370.             cnt = 10*cnt + (ilet - '0');
  371.             allowcnt = 2;    /* signal presence of cnt */
  372.             ilet = readchar();
  373.         }
  374.         if(digit(ilet)) {
  375.             pline("No count allowed with this command.");
  376.             continue;
  377.         }
  378.         if(index(quitchars,ilet))
  379.             return((struct obj *)0);
  380.         if(ilet == '-') {
  381.             return(allownone ? &zeroobj : (struct obj *) 0);
  382.         }
  383.         if(ilet == '$') {
  384.             if(!allowgold){
  385.                 pline("You cannot %s gold.", word);
  386.                 continue;
  387.             }
  388.             if(!(allowcnt == 2 && cnt < u.ugold))
  389.                 cnt = u.ugold;
  390.             return(mkgoldobj(cnt));
  391.         }
  392.         if(ilet == '?') {
  393.             doinv(lets);
  394.             if(!(ilet = morc)) continue;
  395.             /* he typed a letter (not a space) to more() */
  396.         } else if(ilet == '*') {
  397.             doinv((char *) 0);
  398.             if(!(ilet = morc)) continue;
  399.             /* ... */
  400.         }
  401.         if(flags.invlet_constant) {
  402.             for(otmp = invent; otmp; otmp = otmp->nobj)
  403.                 if(otmp->invlet == ilet) break;
  404.         } else {
  405.             if(ilet >= 'A' && ilet <= 'Z') ilet += 'z'-'A'+1;
  406.             ilet -= 'a';
  407.             for(otmp = invent; otmp && ilet;
  408.                     ilet--, otmp = otmp->nobj) ;
  409.         }
  410.         if(!otmp) {
  411.             pline("You don't have that object.");
  412.             continue;
  413.         }
  414.         if(cnt < 0 || otmp->quan < cnt) {
  415.             pline("You don't have that many! [You have %u]"
  416.             , otmp->quan);
  417.             continue;
  418.         }
  419.         break;
  420.     }
  421.     if(!allowall && let && !index(let,otmp->olet)) {
  422.         pline("That is a silly thing to %s.",word);
  423.         return(0);
  424.     }
  425.     if(allowcnt == 2) {    /* cnt given */
  426.         if(cnt == 0) return(0);
  427.         if(cnt != otmp->quan) {
  428.             register struct obj *obj;
  429.             obj = splitobj(otmp, (int) cnt);
  430.             if(otmp == uwep) setuwep(obj);
  431.         }
  432.     }
  433.     return(otmp);
  434. }
  435.  
  436. ckunpaid(otmp) register struct obj *otmp; {
  437.     return( otmp->unpaid );
  438. }
  439.  
  440. /* interactive version of getobj - used for Drop and Identify */
  441. /* return the number of times fn was called successfully */
  442. ggetobj(word, fn, max)
  443. char *word;
  444. int (*fn)(),  max;
  445. {
  446. char buf[BUFSZ];
  447. register char *ip;
  448. register char sym;
  449. register int oletct = 0, iletct = 0;
  450. register boolean allflag = FALSE;
  451. char olets[20], ilets[20];
  452. int (*ckfn)() = (int (*)()) 0;
  453. xchar allowgold = (u.ugold && !strcmp(word, "drop")) ? 1 : 0;    /* BAH */
  454.     if(!invent && !allowgold){
  455.         pline("You have nothing to %s.", word);
  456.         return(0);
  457.     } else {
  458.         register struct obj *otmp = invent;
  459.         register int uflg = 0;
  460.  
  461.         if(allowgold) ilets[iletct++] = '$';
  462.         ilets[iletct] = 0;
  463.         while(otmp) {
  464.             if(!index(ilets, otmp->olet)){
  465.                 ilets[iletct++] = otmp->olet;
  466.                 ilets[iletct] = 0;
  467.             }
  468.             if(otmp->unpaid) uflg = 1;
  469.             otmp = otmp->nobj;
  470.         }
  471.         ilets[iletct++] = ' ';
  472.         if(uflg) ilets[iletct++] = 'u';
  473.         if(invent) ilets[iletct++] = 'a';
  474.         ilets[iletct] = 0;
  475.     }
  476.     pline("What kinds of thing do you want to %s? [%s] ",
  477.         word, ilets);
  478.     getlin(buf);
  479.     if(buf[0] == '\033') {
  480.         clrlin();
  481.         return(0);
  482.     }
  483.     ip = buf;
  484.     olets[0] = 0;
  485.     while(sym = *ip++){
  486.         if(sym == ' ') continue;
  487.         if(sym == '$') {
  488.             if(allowgold == 1)
  489.                 (*fn)(mkgoldobj(u.ugold));
  490.             else if(!u.ugold)
  491.                 pline("You have no gold.");
  492.             allowgold = 2;
  493.         } else
  494.         if(sym == 'a' || sym == 'A') allflag = TRUE; else
  495.         if(sym == 'u' || sym == 'U') ckfn = ckunpaid; else
  496.         if(index("!%?[()=*/\"0", sym)){
  497.             if(!index(olets, sym)){
  498.                 olets[oletct++] = sym;
  499.                 olets[oletct] = 0;
  500.             }
  501.         }
  502.         else pline("You don't have any %c's.", sym);
  503.     }
  504.     if(allowgold == 2 && !oletct)
  505.         return(1);    /* he dropped gold (or at least tried to) */
  506.     else
  507.         return(askchain(invent, olets, allflag, fn, ckfn, max));
  508. }
  509.  
  510. /*
  511.  * Walk through the chain starting at objchn and ask for all objects
  512.  * with olet in olets (if nonNULL) and satisfying ckfn (if nonNULL)
  513.  * whether the action in question (i.e., fn) has to be performed.
  514.  * If allflag then no questions are asked. Max gives the max nr of
  515.  * objects to be treated. Return the number of objects treated.
  516.  */
  517. askchain(objchn, olets, allflag, fn, ckfn, max)
  518. struct obj *objchn;
  519. register char *olets;
  520. int allflag;
  521. int (*fn)(), (*ckfn)();
  522. int max;
  523. {
  524. register struct obj *otmp, *otmp2;
  525. register char sym, ilet;
  526. register int cnt = 0;
  527. #ifdef DGK
  528.     /* changes so the askchain is interrogated in the order specified.
  529.      * For example, if a person specifies =/ then first all rings will be
  530.      * asked about followed by all wands -dgk
  531.      */
  532. nextclass:
  533. #endif DGK
  534.     ilet = 'a'-1;
  535.     for(otmp = objchn; otmp; otmp = otmp2){
  536.         if(ilet == 'z') ilet = 'A'; else ilet++;
  537.         otmp2 = otmp->nobj;
  538. #ifdef DGK
  539.         if (olets && *olets && otmp->olet != *olets) continue;
  540. #else
  541.         if(olets && *olets && !index(olets, otmp->olet)) continue;
  542. #endif DGK
  543.         if(ckfn && !(*ckfn)(otmp)) continue;
  544.         if(!allflag) {
  545.             pline(xprname(otmp, ilet));
  546.             addtopl(" [nyaq]? ");
  547.             sym = readchar();
  548.         }
  549.         else    sym = 'y';
  550.  
  551.         switch(sym){
  552.         case 'a':
  553.             allflag = 1;
  554.         case 'y':
  555.             cnt += (*fn)(otmp);
  556.             if(--max == 0) goto ret;
  557.         case 'n':
  558.         default:
  559.             break;
  560.         case 'q':
  561.             goto ret;
  562.         }
  563.     }
  564. #ifdef DGK
  565.     if (olets && *++olets)
  566.         goto nextclass;
  567. #endif DGK
  568.     pline(cnt ? "That was all." : "No applicable objects.");
  569. ret:
  570.     return(cnt);
  571. }
  572.  
  573. obj_to_let(obj)    /* should of course only be called for things in invent */
  574. register struct obj *obj;
  575. {
  576.     register struct obj *otmp;
  577.     register char ilet;
  578.  
  579.     if(flags.invlet_constant)
  580.         return(obj->invlet);
  581.     ilet = 'a';
  582.     for(otmp = invent; otmp && otmp != obj; otmp = otmp->nobj)
  583.         if(++ilet > 'z') ilet = 'A';
  584.     return(otmp ? ilet : NOINVSYM);
  585. }
  586.  
  587. prinv(obj)
  588. register struct obj *obj;
  589. {
  590.     pline(xprname(obj, obj_to_let(obj)));
  591. }
  592.  
  593. static char *
  594. xprname(obj,let)
  595. register struct obj *obj;
  596. register char let;
  597. {
  598.     static char li[BUFSZ];
  599.  
  600.     (void) sprintf(li, "%c - %s.",
  601.         flags.invlet_constant ? obj->invlet : let,
  602.         doname(obj));
  603.     return(li);
  604. }
  605.  
  606. ddoinv()
  607. {
  608.     doinv((char *) 0);
  609.     return(0);
  610. }
  611.  
  612. #ifdef DGK
  613. char inv_order[] = "\")[%?/=!(*0_`";    /* to be safe, include _ and ` */
  614. extern char *let_to_name();
  615. #endif DGK
  616.  
  617. /* called with 0 or "": all objects in inventory */
  618. /* otherwise: all objects with (serial) letter in lets */
  619. doinv(lets)
  620. register char *lets;
  621. {
  622.     register struct obj *otmp;
  623.     register char ilet;
  624.     int ct = 0;
  625.     char any[BUFSZ];
  626. #ifdef DGK
  627.     char *invlet = inv_order;
  628.     int classcount = 0;
  629. #endif DGK
  630.  
  631.     morc = 0;        /* just to be sure */
  632.  
  633.     if(!invent){
  634.         pline("Not carrying anything.");
  635.         return;
  636.     }
  637.  
  638.     cornline(0, (char *) 0);
  639. #ifdef DGK
  640. nextclass:
  641.     classcount = 0;
  642.     ilet = 'a';
  643.     for(otmp = invent; otmp; otmp = otmp->nobj) {
  644.         if(flags.invlet_constant) ilet = otmp->invlet;
  645.         if(!lets || !*lets || index(lets, ilet)) {
  646.             if (!flags.sortpack || otmp->olet == *invlet) {
  647.                 if (flags.sortpack && !classcount) {
  648.                     cornline(1, let_to_name(*invlet));
  649.                     classcount++;
  650.                 }
  651.                 cornline(1, xprname(otmp, ilet));
  652.                 any[ct++] = ilet;
  653.             }
  654.         }
  655.         if(!flags.invlet_constant) if(++ilet > 'z') ilet = 'A';
  656.     }
  657.     if (flags.sortpack && *++invlet) goto nextclass;
  658. #else
  659.     ilet = 'a';
  660.     for(otmp = invent; otmp; otmp = otmp->nobj) {
  661.         if(flags.invlet_constant) ilet = otmp->invlet;
  662.         if(!lets || !*lets || index(lets, ilet)) {
  663.             cornline(1, xprname(otmp, ilet));
  664.             any[ct++] = ilet;
  665.         }
  666.         if(!flags.invlet_constant) if(++ilet > 'z') ilet = 'A';
  667.     }
  668. #endif DGK
  669.     any[ct] = 0;
  670.     cornline(2, any);
  671. }
  672.  
  673. dotypeinv ()                /* free after Robert Viduya */
  674. /* Changed to one type only, so he doesnt have to type cr */
  675. {
  676.     char c, ilet;
  677.     char stuff[BUFSZ];
  678.     register int stct;
  679.     register struct obj *otmp;
  680.     boolean billx = inshop() && doinvbill(0);
  681.     boolean unpd = FALSE;
  682.  
  683.     if (!invent && !u.ugold && !billx) {
  684.         pline ("You aren't carrying anything.");
  685.         return(0);
  686.     }
  687.  
  688.     stct = 0;
  689.     if(u.ugold) stuff[stct++] = '$';
  690.     stuff[stct] = 0;
  691.     for(otmp = invent; otmp; otmp = otmp->nobj) {
  692.         if (!index (stuff, otmp->olet)) {
  693.         stuff[stct++] = otmp->olet;
  694.         stuff[stct] = 0;
  695.         }
  696.         if(otmp->unpaid)
  697.         unpd = TRUE;
  698.     }
  699.     if(unpd) stuff[stct++] = 'u';
  700.     if(billx) stuff[stct++] = 'x';
  701.     stuff[stct] = 0;
  702.  
  703.     if(stct > 1) {
  704.         pline ("What type of object [%s] do you want an inventory of? ",
  705.         stuff);
  706.         c = readchar();
  707.         if(index(quitchars,c)) return(0);
  708.     } else
  709.         c = stuff[0];
  710.  
  711.     if(c == '$')
  712.         return(doprgold());
  713.  
  714.     if(c == 'x' || c == 'X') {
  715.         if(billx)
  716.         (void) doinvbill(1);
  717.         else
  718.         pline("No used-up objects on the shopping bill.");
  719.         return(0);
  720.     }
  721.  
  722.     if((c == 'u' || c == 'U') && !unpd) {
  723.         pline("You are not carrying any unpaid objects.");
  724.         return(0);
  725.     }
  726.  
  727.     stct = 0;
  728.     ilet = 'a';
  729.     for (otmp = invent; otmp; otmp = otmp -> nobj) {
  730.         if(flags.invlet_constant) ilet = otmp->invlet;
  731.         if (c == otmp -> olet || (c == 'u' && otmp -> unpaid))
  732.         stuff[stct++] = ilet;
  733.         if(!flags.invlet_constant) if(++ilet > 'z') ilet = 'A';
  734.     }
  735.     stuff[stct] = '\0';
  736.     if(stct == 0)
  737.         pline("You have no such objects.");
  738.     else
  739.         doinv (stuff);
  740.  
  741.     return(0);
  742. }
  743.  
  744. /* look at what is here */
  745. dolook() {
  746.     register struct obj *otmp, *otmp0;
  747.     register struct gold *gold;
  748.     char *verb = Blind ? "feel" : "see";
  749.     int    ct = 0;
  750.  
  751.     if(!u.uswallow) {
  752.     if(Blind) {
  753.         pline("You try to feel what is lying here on the floor.");
  754.         if(Levitation) {                /* ab@unido */
  755.         pline("You cannot reach the floor!");
  756.         return(1);
  757.         }
  758.     }
  759.     otmp0 = o_at(u.ux, u.uy);
  760.     gold = g_at(u.ux, u.uy);
  761.     }
  762.  
  763.     if(u.uswallow || (!otmp0 && !gold)) {
  764.     pline("You %s no objects here.", verb);
  765.     return(!!Blind);
  766.     }
  767.  
  768.     cornline(0, "Things that are here:");
  769.     for(otmp = otmp0; otmp; otmp = otmp->nobj) {
  770.     if(otmp->ox == u.ux && otmp->oy == u.uy) {
  771.         ct++;
  772.         cornline(1, doname(otmp));
  773.         if(Blind && otmp->otyp == DEAD_COCKATRICE && !uarmg) {
  774.         pline("Touching the dead cockatrice is a fatal mistake ...");
  775.         pline("You die ...");
  776.         killer = "dead cockatrice";
  777.         done("died");
  778.         }
  779.     }
  780.     }
  781.  
  782.     if(gold) {
  783.     char gbuf[30];
  784.  
  785.     (void) sprintf(gbuf, "%ld gold piece%s",
  786.         gold->amount, plur(gold->amount));
  787.     if(!ct++)
  788.         pline("You %s here %s.", verb, gbuf);
  789.     else
  790.         cornline(1, gbuf);
  791.     }
  792.  
  793.     if(ct == 1 && !gold) {
  794.     pline("You %s here %s.", verb, doname(otmp0));
  795.     cornline(3, (char *) 0);
  796.     }
  797.     if(ct > 1)
  798.     cornline(2, (char *) 0);
  799.     return(!!Blind);
  800. }
  801.  
  802. stackobj(obj) register struct obj *obj; {
  803. register struct obj *otmp = fobj;
  804.     for(otmp = fobj; otmp; otmp = otmp->nobj) if(otmp != obj)
  805.     if(otmp->ox == obj->ox && otmp->oy == obj->oy &&
  806.         merged(obj,otmp,1))
  807.             return;
  808. }
  809.  
  810. /* merge obj with otmp and delete obj if types agree */
  811. merged(otmp,obj,lose) register struct obj *otmp, *obj; {
  812.     if(obj->otyp == otmp->otyp &&
  813.       obj->unpaid == otmp->unpaid &&
  814.       obj->spe == otmp->spe &&
  815.       obj->dknown == otmp->dknown &&
  816.       obj->cursed == otmp->cursed &&
  817.       (index("%*?!", obj->olet) ||
  818.         (obj->known == otmp->known &&
  819.         (obj->olet == WEAPON_SYM && obj->otyp < BOOMERANG)))) {
  820.         otmp->quan += obj->quan;
  821.         otmp->owt += obj->owt;
  822.         if(lose) freeobj(obj);
  823.         obfree(obj,otmp);    /* free(obj), bill->otmp */
  824.         return(1);
  825.     } else    return(0);
  826. }
  827.  
  828. /*
  829.  * Gold is no longer displayed; in fact, when you have a lot of money,
  830.  * it may take a while before you have counted it all.
  831.  * [Bug: d$ and pickup still tell you how much it was.]
  832.  */
  833. extern int (*occupation)();
  834. extern char *occtxt;
  835. static long goldcounted;
  836.  
  837. countgold(){
  838.     if((goldcounted += 100*(u.ulevel + 1)) >= u.ugold) {
  839.         long eps = 0;
  840.         if(!rn2(2)) eps = rnd((int) (u.ugold/100 + 1));
  841.         pline("You probably have about %ld gold pieces.",
  842.             u.ugold + eps);
  843.         return(0);    /* done */
  844.     }
  845.     return(1);        /* continue */
  846. }
  847.  
  848. doprgold(){
  849.     if(!u.ugold)
  850.         pline("You do not carry any gold.");
  851.     else if(u.ugold <= 500)
  852.         pline("You are carrying %ld gold pieces.", u.ugold);
  853.     else {
  854.         pline("You sit down in order to count your gold pieces.");
  855.         goldcounted = 500;
  856.         occupation = countgold;
  857.         occtxt = "counting your gold";
  858.     }
  859.     return(1);
  860. }
  861.  
  862. /* --- end of gold counting section --- */
  863.  
  864. doprwep(){
  865.     if(!uwep) pline("You are empty handed.");
  866.     else prinv(uwep);
  867.     return(0);
  868. }
  869.  
  870. doprarm(){
  871.     if(!uarm && !uarmg && !uarms && !uarmh)
  872.         pline("You are not wearing any armor.");
  873.     else {
  874.         char lets[6];
  875.         register int ct = 0;
  876.  
  877.         if(uarm) lets[ct++] = obj_to_let(uarm);
  878.         if(uarm2) lets[ct++] = obj_to_let(uarm2);
  879.         if(uarmh) lets[ct++] = obj_to_let(uarmh);
  880.         if(uarms) lets[ct++] = obj_to_let(uarms);
  881.         if(uarmg) lets[ct++] = obj_to_let(uarmg);
  882.         lets[ct] = 0;
  883.         doinv(lets);
  884.     }
  885.     return(0);
  886. }
  887.  
  888. doprring(){
  889.     if(!uleft && !uright)
  890.         pline("You are not wearing any rings.");
  891.     else {
  892.         char lets[3];
  893.         register int ct = 0;
  894.  
  895.         if(uleft) lets[ct++] = obj_to_let(uleft);
  896.         if(uright) lets[ct++] = obj_to_let(uright);
  897.         lets[ct] = 0;
  898.         doinv(lets);
  899.     }
  900.     return(0);
  901. }
  902.  
  903. digit(c) char c; {
  904.     return(c >= '0' && c <= '9');
  905. }
  906.