home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Games / NetHack 3.1.3 / source / src / invent.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-01  |  49.4 KB  |  1,970 lines  |  [TEXT/R*ch]

  1. /*    SCCS Id: @(#)invent.c    3.1    93/05/17    */
  2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. #include "hack.h"
  6. #include "artifact.h"
  7.  
  8. #define    NOINVSYM    '#'
  9. #define    CONTAINED_SYM    '>'    /* designator for inside a container */
  10.  
  11. #ifdef OVL1
  12. static void NDECL(reorder_invent);
  13. static boolean FDECL(mergable,(struct obj *,struct obj *));
  14. static int FDECL(merged,(struct obj *,struct obj *,int));
  15. #endif /* OVL1 */
  16. STATIC_DCL void FDECL(assigninvlet,(struct obj *));
  17. STATIC_DCL void FDECL(unlinkinv,(struct obj*));
  18. STATIC_DCL void FDECL(compactify,(char *));
  19. STATIC_PTR int FDECL(ckunpaid,(struct obj *));
  20. #ifdef OVLB
  21. static struct obj *FDECL(find_unpaid,(struct obj *,struct obj **));
  22. static boolean NDECL(wearing_armor);
  23. static boolean FDECL(is_worn,(struct obj *));
  24. static boolean FDECL(is_fully_identified,(struct obj *));
  25. #endif /* OVLB */
  26. STATIC_DCL char FDECL(obj_to_let,(struct obj *));
  27.  
  28. #ifdef OVLB
  29.  
  30. static int lastinvnr = 51;    /* 0 ... 51 (never saved&restored) */
  31.  
  32. #ifdef WIZARD
  33. /* wizards can wish for venom, which will become an invisible inventory
  34.  * item without this.  putting it in inv_order would mean venom would
  35.  * suddenly become a choice for all the inventory-class commands, which
  36.  * would probably cause mass confusion.  the test for inventory venom
  37.  * is only WIZARD and not wizard because the wizard can leave venom lying
  38.  * around on a bones level for normal players to find.
  39.  */
  40. static char venom_inv[] = { VENOM_CLASS, 0 };    /* (constant) */
  41. #endif
  42.  
  43. STATIC_OVL void
  44. assigninvlet(otmp)
  45. register struct obj *otmp;
  46. {
  47.     boolean inuse[52];
  48.     register int i;
  49.     register struct obj *obj;
  50.  
  51.     for(i = 0; i < 52; i++) inuse[i] = FALSE;
  52.     for(obj = invent; obj; obj = obj->nobj) if(obj != otmp) {
  53.         i = obj->invlet;
  54.         if('a' <= i && i <= 'z') inuse[i - 'a'] = TRUE; else
  55.         if('A' <= i && i <= 'Z') inuse[i - 'A' + 26] = TRUE;
  56.         if(i == otmp->invlet) otmp->invlet = 0;
  57.     }
  58.     if((i = otmp->invlet) &&
  59.         (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z')))
  60.         return;
  61.     for(i = lastinvnr+1; i != lastinvnr; i++) {
  62.         if(i == 52) { i = -1; continue; }
  63.         if(!inuse[i]) break;
  64.     }
  65.     otmp->invlet = (inuse[i] ? NOINVSYM :
  66.             (i < 26) ? ('a'+i) : ('A'+i-26));
  67.     lastinvnr = i;
  68. }
  69.  
  70. #endif /* OVLB */
  71. #ifdef OVL1
  72.  
  73. /* note: assumes ASCII; toggling a bit puts lowercase in front of uppercase */
  74. #define inv_rank(o) ((o)->invlet ^ 040)
  75.  
  76. /* sort the inventory; used by addinv() and doorganize() */
  77. static void
  78. reorder_invent()
  79. {
  80.     struct obj *otmp, *prev, *next;
  81.     boolean need_more_sorting;
  82.  
  83.     do {
  84.         /*
  85.          * We expect at most one item to be out of order, so this
  86.          * isn't nearly as inefficient as it may first appear.
  87.          */
  88.         need_more_sorting = FALSE;
  89.         for (otmp = invent, prev = 0; otmp; ) {
  90.         next = otmp->nobj;
  91.         if (next && inv_rank(next) < inv_rank(otmp)) {
  92.             need_more_sorting = TRUE;
  93.             if (prev) prev->nobj = next;
  94.             else      invent = next;
  95.             otmp->nobj = next->nobj;
  96.             next->nobj = otmp;
  97.             prev = next;
  98.         } else {
  99.             prev = otmp;
  100.             otmp = next;
  101.         }
  102.         }
  103.     } while (need_more_sorting);
  104. }
  105.  
  106. #undef inv_rank
  107.  
  108. /* merge obj with otmp and delete obj if types agree */
  109. STATIC_OVL int
  110. merged(otmp, obj, lose)
  111. register struct obj *otmp, *obj;
  112. register int lose;
  113. {
  114.     if(mergable(otmp, obj)) {
  115.         /* Approximate age: we do it this way because if we were to
  116.          * do it "accurately" (merge only when ages are identical)
  117.          * we'd wind up never merging any corpses.
  118.          * otmp->age = otmp->age*(1-proportion) + obj->age*proportion;
  119.          */
  120.         otmp->age = ((otmp->age*otmp->quan) + (obj->age*obj->quan))
  121.             / (otmp->quan + obj->quan);
  122.         otmp->quan += obj->quan;
  123.         otmp->owt += obj->owt;
  124.         if(!otmp->onamelth && obj->onamelth)
  125.             otmp = oname(otmp, ONAME(obj), 1);
  126.         if(lose) freeobj(obj);
  127.         obfree(obj,otmp);    /* free(obj), bill->otmp */
  128.         return(1);
  129.     } else    return(0);
  130. }
  131.  
  132. struct obj *
  133. addinv(obj)
  134. register struct obj *obj;
  135. {
  136.     register struct obj *otmp, *prev;
  137.  
  138.     if (obj->otyp == GOLD_PIECE) {
  139.         u.ugold += obj->quan;
  140.         flags.botl = 1;
  141.         return obj;
  142.     } else if (obj->otyp == AMULET_OF_YENDOR) {
  143.         if (u.uhave.amulet) impossible ("already have amulet?");
  144.         u.uhave.amulet = 1;
  145.     } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
  146.         if (u.uhave.menorah) impossible ("already have candelabrum?");
  147.         u.uhave.menorah = 1;
  148.     } else if (obj->otyp == BELL_OF_OPENING) {
  149.         if (u.uhave.bell) impossible ("already have silver bell?");
  150.         u.uhave.bell = 1;
  151.     } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
  152.         if (u.uhave.book) impossible ("already have the book?");
  153.         u.uhave.book = 1;
  154. #ifdef MULDGN
  155.     } else if (is_quest_artifact(obj)) {
  156.         if (u.uhave.questart) impossible ("already have the artifact?");
  157.         u.uhave.questart = 1;
  158.         artitouch();
  159.         set_artifact_intrinsic(obj, 1, W_ART);
  160. #endif
  161.     } else if(obj->oartifact) {
  162.         set_artifact_intrinsic(obj, 1, W_ART);
  163.     }
  164.     /* merge if possible; find end of chain in the process */
  165.     for (prev = 0, otmp = invent; otmp; prev = otmp, otmp = otmp->nobj)
  166.         if (merged(otmp, obj, 0)) {
  167.         obj = otmp;
  168.         goto added;
  169.         }
  170.     /* didn't merge, so insert into chain */
  171.     if (flags.invlet_constant || !prev) {
  172.         if (flags.invlet_constant) assigninvlet(obj);
  173.         obj->nobj = invent;        /* insert at beginning */
  174.         invent = obj;
  175.         if (flags.invlet_constant) reorder_invent();
  176.     } else {
  177.         prev->nobj = obj;        /* insert at end */
  178.         obj->nobj = 0;
  179.     }
  180.  
  181. added:
  182.     if (obj->otyp == LUCKSTONE
  183.         || (obj->oartifact && spec_ability(obj, SPFX_LUCK))) {
  184.         /* new luckstone must be in inventory by this point
  185.          * for correct calculation */
  186.         if (stone_luck(TRUE) >= 0) u.moreluck = LUCKADD;
  187.         else u.moreluck = -LUCKADD;
  188.     } else if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP)
  189.         check_lamps();
  190.     update_inventory();
  191.     return(obj);
  192. }
  193.  
  194. #endif /* OVL1 */
  195. #ifdef OVLB
  196.  
  197. /* Add an item to the inventory unless we're fumbling, and give a message.
  198.  * If there aren't any free inventory slots, we'll drop it instead.
  199.  * If both success and failure messages are NULL, then we're just doing the
  200.  * fumbling/slot-limit checking for a silent grab.
  201.  * Note: will drop the whole bunch if the object merges first.
  202.  */
  203. struct obj *
  204. hold_another_object(obj, drop_fmt, drop_arg, hold_msg)
  205. struct obj *obj;
  206. const char *drop_fmt, *drop_arg, *hold_msg;
  207. {
  208.     long oquan = obj->quan;
  209.     if (!Blind) obj->dknown = 1;    /* maximize mergibility */
  210.     if (Fumbling) {
  211.         if (drop_fmt) pline(drop_fmt, drop_arg);
  212.         dropy(obj);
  213.     } else {
  214.         obj = addinv(obj);
  215.         if (inv_cnt() > 52
  216.             || ((obj->otyp != LOADSTONE || !obj->cursed)
  217.             && near_capacity() >= OVERLOADED)) {
  218.             if (drop_fmt) pline(drop_fmt, drop_arg);
  219.             dropx(obj);
  220.         } else {
  221.             if (hold_msg || drop_fmt) prinv(hold_msg, obj, oquan);
  222.         }
  223.     }
  224.     return obj;
  225. }
  226.  
  227. void
  228. useup(obj)
  229. register struct obj *obj;
  230. {
  231.     /*  Note:  This works correctly for containers because they */
  232.     /*       (containers) don't merge.                */
  233.     if(obj->quan > 1L){
  234. #ifndef NO_SIGNAL
  235.         obj->in_use = FALSE;    /* no longer in use */
  236. #endif
  237.         obj->quan--;
  238.         obj->owt = weight(obj);
  239.     } else {
  240.         setnotworn(obj);
  241.         freeinv(obj);
  242.         obfree(obj, (struct obj *) 0);    /* deletes contents also */
  243.     }
  244. }
  245.  
  246. #endif /* OVLB */
  247. #ifdef OVL3
  248.  
  249. /* used by freeinv and doorganize to do list manipulation */
  250. STATIC_OVL
  251. void
  252. unlinkinv(obj)
  253. register struct obj *obj;
  254. {
  255.     register struct obj *otmp;
  256.  
  257.     if(obj == invent)
  258.         invent = invent->nobj;
  259.     else {
  260.         for(otmp = invent; otmp->nobj != obj; otmp = otmp->nobj)
  261.             if(!otmp->nobj) panic("unlinkinv");
  262.         otmp->nobj = obj->nobj;
  263.     }
  264.     obj->nobj = 0;
  265. }
  266.  
  267. void
  268. freeinv(obj)
  269. register struct obj *obj;
  270. {
  271.     unlinkinv(obj);
  272.  
  273.     if (obj->otyp == GOLD_PIECE) {
  274.         u.ugold -= obj->quan;
  275.         flags.botl = 1;
  276.         return;
  277.     } else if (obj->otyp == AMULET_OF_YENDOR) {
  278.         if (!u.uhave.amulet) impossible ("don't have amulet?");
  279.         u.uhave.amulet = 0;
  280.     } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
  281.         if (!u.uhave.menorah) impossible ("don't have candelabrum?");
  282.         u.uhave.menorah = 0;
  283.     } else if (obj->otyp == BELL_OF_OPENING) {
  284.         if (!u.uhave.bell) impossible ("don't have silver bell?");
  285.         u.uhave.bell = 0;
  286.     } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
  287.         if (!u.uhave.book) impossible ("don't have the book?");
  288.         u.uhave.book = 0;
  289. #ifdef MULDGN
  290.     } else if (is_quest_artifact(obj)) {
  291.         if(!u.uhave.questart) impossible ("don't have the artifact?");
  292.         u.uhave.questart = 0;
  293.         set_artifact_intrinsic(obj, 0, W_ART);
  294. #endif
  295.     } else if (obj->oartifact) {
  296.         set_artifact_intrinsic(obj, 0, W_ART);
  297.     } else if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP
  298.            || obj->otyp == BRASS_LANTERN) {
  299.         if (obj->lamplit) {
  300.             obj->lamplit = 0;
  301.             if (!Blind) pline("%s goes out!", The(xname(obj)));
  302.         }
  303.         check_lamps();
  304.     } else if (obj->otyp == LOADSTONE) {
  305.         curse(obj);
  306.     } else if (obj->otyp == LUCKSTONE
  307.            || (obj->oartifact && spec_ability(obj, SPFX_LUCK))) {
  308.         int luckbon = stone_luck(TRUE);
  309.         if (!luckbon && !carrying(LUCKSTONE)) u.moreluck = 0;
  310.         else if (luckbon >= 0) u.moreluck = LUCKADD;
  311.         else u.moreluck = -LUCKADD;
  312.         flags.botl = 1;
  313.     }
  314.     update_inventory();
  315. }
  316.  
  317. void
  318. delallobj(x, y)
  319. int x, y;
  320. {
  321.     struct obj *otmp, *otmp2;
  322.  
  323.     for (otmp = level.objects[x][y]; otmp; otmp = otmp2) {
  324.         if (otmp == uball)
  325.             unpunish();
  326.         /* after unpunish(), or might get deallocated chain */
  327.         otmp2 = otmp->nexthere;
  328.         if (otmp == uchain)
  329.             continue;
  330.         delobj(otmp);
  331.     }
  332. }
  333.  
  334. /* move objects from fobj/nexthere lists to buriedobjlist, keeping position
  335.  * information */
  336. void
  337. bury_objs(x, y)
  338. int x, y;
  339. {
  340.     struct obj *otmp, *otmp2;
  341.  
  342.     for (otmp = level.objects[x][y]; otmp; otmp = otmp2) {
  343.         if (otmp == uball)
  344.             unpunish();
  345.         /* after unpunish(), or might get deallocated chain */
  346.         otmp2 = otmp->nexthere;
  347.         if (otmp == uchain)
  348.             continue;
  349. #ifdef WALKIES
  350.         if (otmp->otyp == LEASH && otmp->leashmon != 0)
  351.             o_unleash(otmp);
  352. #endif
  353.         if (otmp->lamplit) {
  354.             otmp->lamplit = 0;
  355.             check_lamps();
  356.         }
  357.         freeobj(otmp);
  358.         if (otmp->otyp == ROCK) {
  359.             /* melts into burying material */
  360.             obfree(otmp, (struct obj *)0);
  361.             continue;
  362.         }
  363.         otmp->nexthere = (struct obj *)0;
  364.         otmp->nobj = level.buriedobjlist;
  365.         level.buriedobjlist = otmp;
  366.     }
  367.     /* don't expect any engravings here, but just in case */
  368.     del_engr_at(x, y);
  369.     newsym(x, y);
  370. }
  371.  
  372. /* delete buried object */
  373. void
  374. delburiedobj(obj)
  375. struct obj *obj;
  376. {
  377.     struct obj *otmp;
  378.     if (obj == level.buriedobjlist)
  379.         level.buriedobjlist = obj->nobj;
  380.     else {
  381.         for (otmp = level.buriedobjlist; otmp; otmp = otmp->nobj)
  382.             if (otmp->nobj == obj) {
  383.                 otmp->nobj = obj->nobj;
  384.                 break;
  385.             }
  386.         if (!otmp) panic("error in delburiedobj");
  387.     }
  388.     obfree(obj, (struct obj *) 0);    /* frees contents also */
  389. }
  390.  
  391. /* move objects from buriedobjlist to fobj/nexthere lists */
  392. void
  393. unearth_objs(x, y)
  394. int x, y;
  395. {
  396.     struct obj *otmp, *otmp2, *prevobj;
  397.  
  398.     remove_cadavers(&level.buriedobjlist);
  399.  
  400.     prevobj = (struct obj *) 0;
  401.     for (otmp = level.buriedobjlist; otmp; otmp = otmp2) {
  402.         otmp2 = otmp->nobj;
  403.         if (otmp->ox == x && otmp->oy == y) {
  404.             if (prevobj)
  405.                 prevobj->nobj = otmp2;
  406.             else
  407.                 level.buriedobjlist = otmp2;
  408.             if (is_organic(otmp) && rn2(2)) {
  409.                 /* rotted away */
  410.                 obfree(otmp, (struct obj *) 0);
  411.             } else {
  412.                 otmp->nobj = fobj;
  413.                 fobj = otmp;
  414.                 place_object(otmp, x, y);
  415.                 stackobj(otmp);
  416.             }
  417.         } else
  418.             prevobj = otmp;
  419.     }
  420.     del_engr_at(x, y);
  421.     newsym(x, y);
  422. }
  423.  
  424. #endif /* OVL3 */
  425. #ifdef OVL2
  426.  
  427. /* destroy object in fobj chain (if unpaid, it remains on the bill) */
  428. void
  429. delobj(obj)
  430. register struct obj *obj;
  431. {
  432. #ifdef WALKIES
  433.     if(obj->otyp == LEASH && obj->leashmon != 0) o_unleash(obj);
  434. #endif
  435.     if (obj->otyp == AMULET_OF_YENDOR ||
  436.             obj->otyp == CANDELABRUM_OF_INVOCATION ||
  437.             obj->otyp == BELL_OF_OPENING ||
  438.             obj->otyp == SPE_BOOK_OF_THE_DEAD) {
  439.         /* player might be doing something stupid, but we
  440.          * can't guarantee that.  assume special artifacts
  441.          * are indestructible via drawbridges, and exploding
  442.          * chests, and golem creation, and ...
  443.          */
  444.         return;
  445.     }
  446.     freeobj(obj);
  447.     newsym(obj->ox,obj->oy);
  448.     obfree(obj, (struct obj *) 0);    /* frees contents also */
  449. }
  450.  
  451. /* unlink obj from chain starting with fobj */
  452. void
  453. freeobj(obj)
  454. register struct obj *obj;
  455. {
  456.     register struct obj *otmp;
  457.  
  458.     if (obj == fobj)
  459.         fobj = fobj->nobj;
  460.     else {
  461.         for(otmp = fobj; otmp; otmp = otmp->nobj)
  462.         if (otmp->nobj == obj) {
  463.             otmp->nobj = obj->nobj;
  464.             break;
  465.         }
  466.         if (!otmp) panic("error in freeobj");
  467.     }
  468.     remove_object(obj);
  469. }
  470.  
  471. #endif /* OVL2 */
  472. #ifdef OVL0
  473.  
  474. struct obj *
  475. sobj_at(n,x,y)
  476. register int n, x, y;
  477. {
  478.     register struct obj *otmp;
  479.  
  480.     for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
  481.         if(otmp->otyp == n)
  482.             return(otmp);
  483.     return((struct obj *)0);
  484. }
  485.  
  486. #endif /* OVL0 */
  487. #ifdef OVLB
  488.  
  489. int
  490. carried(obj)
  491. register struct obj *obj;
  492. {
  493.     register struct obj *otmp;
  494.  
  495.     for(otmp = invent; otmp; otmp = otmp->nobj)
  496.         if(otmp == obj) return(1);
  497.     return(0);
  498. }
  499.  
  500. struct obj *
  501. carrying(type)
  502. register int type;
  503. {
  504.     register struct obj *otmp;
  505.  
  506.     for(otmp = invent; otmp; otmp = otmp->nobj)
  507.         if(otmp->otyp == type)
  508.             return(otmp);
  509.     return((struct obj *) 0);
  510. }
  511.  
  512. boolean
  513. have_lizard()
  514. {
  515.     register struct obj *otmp;
  516.  
  517.     for(otmp = invent; otmp; otmp = otmp->nobj)
  518.         if(otmp->otyp == CORPSE && otmp->corpsenm == PM_LIZARD)
  519.             return(TRUE);
  520.     return(FALSE);
  521. }
  522.  
  523. struct obj *
  524. o_on(id, objchn)
  525. unsigned int id;
  526. register struct obj *objchn;
  527. {
  528.     struct obj *temp;
  529.  
  530.     while(objchn) {
  531.         if(objchn->o_id == id) return(objchn);
  532.         if (Has_contents(objchn) && (temp = o_on(id,objchn->cobj)))
  533.             return temp;
  534.         objchn = objchn->nobj;
  535.     }
  536.     return((struct obj *) 0);
  537. }
  538.  
  539. boolean
  540. obj_here(obj, x, y)
  541. register struct obj *obj;
  542. int x, y;
  543. {
  544.     register struct obj *otmp;
  545.  
  546.     for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
  547.         if(obj == otmp) return(TRUE);
  548.     return(FALSE);
  549. }
  550.  
  551. #endif /* OVLB */
  552. #ifdef OVL2
  553.  
  554. struct obj *
  555. g_at(x,y)
  556. register int x, y;
  557. {
  558.     register struct obj *obj = level.objects[x][y];
  559.     while(obj) {
  560.         if (obj->otyp == GOLD_PIECE) return obj;
  561.         obj = obj->nexthere;
  562.     }
  563.     return((struct obj *)0);
  564. }
  565.  
  566. #endif /* OVL2 */
  567. #ifdef OVLB
  568.  
  569. /* Make a gold object from the hero's gold. */
  570. struct obj *
  571. mkgoldobj(q)
  572. register long q;
  573. {
  574.     register struct obj *otmp;
  575.  
  576.     otmp = mksobj(GOLD_PIECE, FALSE, FALSE);
  577.     u.ugold -= q;
  578.     otmp->quan = q;
  579.     otmp->owt = weight(otmp);
  580.     flags.botl = 1;
  581.     return(otmp);
  582. }
  583.  
  584. #endif /* OVLB */
  585. #ifdef OVL1
  586.  
  587. STATIC_OVL void
  588. compactify(buf)
  589. register char *buf;
  590. /* compact a string of inventory letters by dashing runs of letters */
  591. {
  592.     register int i1 = 1, i2 = 1;
  593.     register char ilet, ilet1, ilet2;
  594.  
  595.     ilet2 = buf[0];
  596.     ilet1 = buf[1];
  597.     buf[++i2] = buf[++i1];
  598.     ilet = buf[i1];
  599.     while(ilet) {
  600.         if(ilet == ilet1+1) {
  601.             if(ilet1 == ilet2+1)
  602.                 buf[i2 - 1] = ilet1 = '-';
  603.             else if(ilet2 == '-') {
  604.                 buf[i2 - 1] = ++ilet1;
  605.                 buf[i2] = buf[++i1];
  606.                 ilet = buf[i1];
  607.                 continue;
  608.             }
  609.         }
  610.         ilet2 = ilet1;
  611.         ilet1 = ilet;
  612.         buf[++i2] = buf[++i1];
  613.         ilet = buf[i1];
  614.     }
  615. }
  616.  
  617. /*
  618.  * getobj returns:
  619.  *    struct obj *xxx:    object to do something with.
  620.  *    (struct obj *) 0    error return: no object.
  621.  *    &zeroobj        explicitly no object (as in w-).
  622.  */
  623. struct obj *
  624. getobj(let,word)
  625. register const char *let,*word;
  626. {
  627.     register struct obj *otmp;
  628.     register char ilet;
  629.     char buf[BUFSZ], qbuf[QBUFSZ];
  630.     char lets[BUFSZ];
  631.     register int foo = 0;
  632.     register char *bp = buf;
  633.     xchar allowcnt = 0;    /* 0, 1 or 2 */
  634.     boolean allowgold = FALSE, usegold = FALSE;
  635.         /* Two possibilities: they can't use gold because it's illegal,
  636.          * or they can't use gold because they don't have any.
  637.          */
  638.     boolean allowall = FALSE;
  639.     boolean allownone = FALSE;
  640.     xchar foox = 0;
  641.     long cnt;
  642.     boolean prezero = FALSE;
  643.  
  644.     if(*let == ALLOW_COUNT) let++, allowcnt = 1;
  645.     if(*let == GOLD_CLASS) let++,
  646.         usegold = TRUE, allowgold = (u.ugold ? TRUE : FALSE);
  647. #ifdef POLYSELF
  648.     /* Equivalent of an "ugly check" for gold */
  649.     if (usegold && !strcmp(word, "eat") && !metallivorous(uasmon))
  650.         usegold = allowgold = FALSE;
  651. #endif
  652.     if(*let == ALL_CLASSES) let++, allowall = TRUE;
  653.     if(*let == ALLOW_NONE) let++, allownone = TRUE;
  654.     /* "ugly check" for reading fortune cookies, part 1 */
  655.     if(allowall && !strcmp(word, "read")) allowall = FALSE;
  656.  
  657.     if(allownone) *bp++ = '-';
  658.     if(allowgold) *bp++ = def_oc_syms[GOLD_CLASS];
  659.     if(bp > buf && bp[-1] == '-') *bp++ = ' ';
  660.  
  661.     ilet = 'a';
  662.     for(otmp = invent; otmp; otmp = otmp->nobj){
  663.         if(!*let || index(let, otmp->oclass)) {
  664.         bp[foo++] = flags.invlet_constant ? otmp->invlet : ilet;
  665.  
  666.         /* ugly check: remove inappropriate things */
  667.         if((!strcmp(word, "take off") &&
  668.             (!(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL))
  669.              || (otmp==uarm && uarmc)
  670. #ifdef TOURIST
  671.              || (otmp==uarmu && (uarm || uarmc))
  672. #endif
  673.             ))
  674.         || (!strcmp(word, "wear") &&
  675.              (otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)))
  676.                             /* already worn */
  677.         || (!strcmp(word, "wield") &&
  678.             (otmp->owornmask & W_WEP))
  679.             ) {
  680.             foo--;
  681.             foox++;
  682.         }
  683.  
  684.         /* Second ugly check; unlike the first it won't trigger an
  685.          * "else" in "you don't have anything else to ___".
  686.          */
  687.         else if ((!strcmp(word, "wear") &&
  688.             (otmp->oclass == TOOL_CLASS &&
  689.              otmp->otyp != BLINDFOLD && otmp->otyp != TOWEL))
  690.         || (!strcmp(word, "wield") &&
  691.             (otmp->oclass == TOOL_CLASS &&
  692.              otmp->otyp != PICK_AXE && otmp->otyp != UNICORN_HORN))
  693. #ifdef POLYSELF
  694.         || (!strcmp(word, "eat") && !is_edible(otmp))
  695. #endif
  696.         || (!strcmp(word, "sacrifice") &&
  697.             (otmp->otyp != CORPSE &&
  698.              otmp->otyp != AMULET_OF_YENDOR &&
  699.              otmp->otyp != FAKE_AMULET_OF_YENDOR))
  700.         || (!strcmp(word, "write with") &&
  701.             (otmp->oclass == TOOL_CLASS &&
  702.              otmp->otyp != MAGIC_MARKER && otmp->otyp != TOWEL))
  703.         || (!strcmp(word, "tin") &&
  704.             (otmp->otyp != CORPSE || !tinnable(otmp)))
  705.         || (!strcmp(word, "rub") &&
  706.             (otmp->oclass == TOOL_CLASS &&
  707.              otmp->otyp != OIL_LAMP && otmp->otyp != MAGIC_LAMP &&
  708.              otmp->otyp != BRASS_LANTERN))
  709.             )
  710.             foo--;
  711.         } else {
  712.  
  713.         /* "ugly check" for reading fortune cookies, part 2 */
  714.         if ((!strcmp(word, "read") && otmp->otyp == FORTUNE_COOKIE))
  715.             allowall = TRUE;
  716.         }
  717.  
  718.         if(ilet == 'z') ilet = 'A'; else ilet++;
  719.     }
  720.     bp[foo] = 0;
  721.     if(foo == 0 && bp > buf && bp[-1] == ' ') *--bp = 0;
  722.     Strcpy(lets, bp);    /* necessary since we destroy buf */
  723.     if(foo > 5)            /* compactify string */
  724.         compactify(bp);
  725.  
  726.     if(!foo && !allowall && !allowgold && !allownone) {
  727.         You("don't have anything %sto %s.",
  728.             foox ? "else " : "", word);
  729.         return((struct obj *)0);
  730.     }
  731.     for(;;) {
  732.         cnt = 0;
  733.         if (allowcnt == 2) allowcnt = 1;  /* abort previous count */
  734.         if(!buf[0]) {
  735.             Sprintf(qbuf, "What do you want to %s? [*]", word);
  736.         } else {
  737.             Sprintf(qbuf, "What do you want to %s? [%s or ?*]",
  738.                 word, buf);
  739.         }
  740. #ifdef REDO
  741.         if (in_doagain)
  742.             ilet = readchar();
  743.         else
  744. #endif
  745.             ilet = yn_function(qbuf, NULL, '\0');
  746.         if(ilet == '0') prezero = TRUE;
  747.         while(digit(ilet) && allowcnt) {
  748. #ifdef REDO
  749.             if (ilet != '?' && ilet != '*')    savech(ilet);
  750. #endif
  751.             cnt = 10*cnt + (ilet - '0');
  752.             allowcnt = 2;    /* signal presence of cnt */
  753.             ilet = readchar();
  754.         }
  755.         if(digit(ilet)) {
  756.             pline("No count allowed with this command.");
  757.             continue;
  758.         }
  759.         if(index(quitchars,ilet)) {
  760.             if(flags.verbose)
  761.             pline("Never mind.");
  762.             return((struct obj *)0);
  763.         }
  764.         if(ilet == '-') {
  765.             return(allownone ? &zeroobj : (struct obj *) 0);
  766.         }
  767.         if(ilet == def_oc_syms[GOLD_CLASS]) {
  768.             if(!usegold){
  769.                 You("cannot %s gold.", word);
  770.                 return(struct obj *)0;
  771.             } else if (!allowgold) {
  772.                 You("are not carrying any gold.");
  773.                 return(struct obj *)0;
  774.             }
  775.             if(cnt == 0 && prezero) return((struct obj *)0);
  776.             /* Historic note: early Nethack had a bug which was
  777.              * first reported for Larn, where trying to drop 2^32-n
  778.              * gold pieces was allowed, and did interesting things
  779.              * to your money supply.  The LRS is the tax bureau
  780.              * from Larn.
  781.              */
  782.             if(cnt < 0) {
  783.     pline("The LRS would be very interested to know you have that much.");
  784.                 return(struct obj *)0;
  785.             }
  786.  
  787.             if(!(allowcnt == 2 && cnt < u.ugold))
  788.                 cnt = u.ugold;
  789.             return(mkgoldobj(cnt));
  790.         }
  791.         if(allowcnt == 2 && !strcmp(word,"throw")) {
  792.             /* permit counts for throwing gold, but don't accept
  793.              * counts for other things since the throw code will
  794.              * split off a single item anyway */
  795.             allowcnt = 1;
  796.             if(cnt == 0 && prezero) return((struct obj *)0);
  797.             if(cnt > 1) {
  798.                 You("can only throw one item at a time.");
  799.                 continue;
  800.             }
  801.         }
  802.         if(ilet == '?' || ilet == '*') {
  803.             ilet = display_inventory(ilet == '?' ? lets : NULL, FALSE);
  804.             if(!ilet) continue;
  805.             if(ilet == '\033') {
  806.             if(flags.verbose)
  807.                 pline("Never mind.");
  808.             return((struct obj *)0);
  809.             }
  810.             /* they typed a letter (not a space) at the prompt */
  811.         }
  812. #ifdef REDO
  813.         savech(ilet);
  814. #endif
  815.         if(flags.invlet_constant) {
  816.             for(otmp = invent; otmp; otmp = otmp->nobj)
  817.                 if(otmp->invlet == ilet) break;
  818.         } else {
  819.             if(ilet >= 'A' && ilet <= 'Z') ilet += 'z' - 'A' + 1;
  820.             ilet -= 'a';
  821.             for(otmp = invent; otmp && ilet;
  822.                     ilet--, otmp = otmp->nobj) ;
  823.         }
  824.         if(!otmp) {
  825.             You("don't have that object.");
  826. #ifdef REDO
  827.             if (in_doagain) return((struct obj *) 0);
  828. #endif
  829.             continue;
  830.         } else if (cnt < 0 || otmp->quan < cnt) {
  831.             You("don't have that many!  You have only %ld.",
  832.                 otmp->quan);
  833. #ifdef REDO
  834.             if (in_doagain) return((struct obj *) 0);
  835. #endif
  836.             continue;
  837.         }
  838.         break;
  839.     }
  840.     if(!allowall && let && !index(let,otmp->oclass)) {
  841.         pline(silly_thing_to, word);
  842.         return((struct obj *)0);
  843.     }
  844.     if(allowcnt == 2) {    /* cnt given */
  845.         if(cnt == 0) return (struct obj *)0;
  846.         if(cnt != otmp->quan) {
  847.             register struct obj *obj = splitobj(otmp, cnt);
  848.         /* Very ugly kludge necessary to prevent someone from trying
  849.          * to drop one of several loadstones and having the loadstone
  850.          * now be separate.
  851.          */
  852.             if (!strcmp(word, "drop") &&
  853.                 obj->otyp == LOADSTONE && obj->cursed)
  854.                 otmp->corpsenm = obj->invlet;
  855.             if(otmp == uwep) setuwep(obj);
  856.         }
  857.     }
  858.     return(otmp);
  859. }
  860.  
  861. #endif /* OVL1 */
  862. #ifdef OVLB
  863.  
  864. STATIC_PTR int
  865. ckunpaid(otmp)
  866. register struct obj *otmp;
  867. {
  868.     return((int)(otmp->unpaid));
  869. }
  870.  
  871. static boolean
  872. wearing_armor() {
  873.     return((boolean)(uarm || uarmc || uarmf || uarmg || uarmh || uarms
  874. #ifdef TOURIST
  875.         || uarmu
  876. #endif
  877.         ));
  878. }
  879.  
  880. static boolean
  881. is_worn(otmp)
  882. register struct obj *otmp;
  883. {
  884.     return((boolean)(!!(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL | W_WEP))));
  885. }
  886.  
  887. static boolean
  888. is_fully_identified(otmp)
  889. register struct obj *otmp;
  890. {
  891.     return((boolean)(otmp->known && otmp->dknown && otmp->bknown && otmp->rknown
  892.        && objects[otmp->otyp].oc_name_known));
  893. }
  894.  
  895. static NEARDATA const char removeables[] =
  896.     { ARMOR_CLASS, WEAPON_CLASS, RING_CLASS, AMULET_CLASS, TOOL_CLASS, 0 };
  897.  
  898. /* interactive version of getobj - used for Drop, Identify and */
  899. /* Takeoff (A). Return the number of times fn was called successfully */
  900. int
  901. ggetobj(word, fn, mx)
  902. register const char *word;
  903. register int FDECL((*fn),(OBJ_P)), mx;
  904. {
  905.     char buf[BUFSZ], qbuf[QBUFSZ];
  906.     register char *ip;
  907.     register char sym;
  908.     register int oletct = 0, iletct = 0;
  909.     register boolean allflag = FALSE;
  910.     char olets[20], ilets[20];
  911.     int FDECL((*ckfn),(OBJ_P)) = (int (*)()) 0;
  912.     xchar allowgold = (u.ugold && !strcmp(word, "drop")) ? 1 : 0; /* BAH */
  913.     register boolean takeoff = !strcmp(word, "take off");
  914.     register boolean ident = !strcmp(word, "identify");
  915.     struct obj *obj;
  916.     int unpaid, oc_of_sym;
  917.  
  918.     if(takeoff && !wearing_armor() && !uwep && !uamul &&
  919.             !uleft && !uright && !ublindf) {
  920.         You("are not wearing anything.");
  921.         return(0);
  922.     }
  923.     if(!invent && !allowgold){
  924.         You("have nothing to %s.", word);
  925.         return(0);
  926.     }
  927.  
  928.     if (allowgold) ilets[iletct++] = def_oc_syms[GOLD_CLASS];
  929.     ilets[iletct] = '\0';    /* terminate for index() */
  930.     unpaid = 0;
  931.     for (obj = invent; obj; obj = obj->nobj) {
  932.         sym = (char) def_oc_syms[(int) obj->oclass];
  933.         if (!index(ilets, sym) && (!takeoff || is_worn(obj))
  934.             && (!ident || !is_fully_identified(obj))) {
  935.             ilets[iletct++] = sym;
  936.             /* necessary because of index() being used above */
  937.             ilets[iletct] = '\0';
  938.         }
  939.  
  940.         if (obj->unpaid) unpaid = 1;
  941.     }
  942.  
  943.     if (ident && !iletct) {
  944.         You("have already identified all your possessions.");
  945.         return -1;        /* special case for seffects(read.c) */
  946.     } else if (!takeoff && (unpaid || invent)) {
  947.         ilets[iletct++] = ' ';
  948.         if (unpaid) ilets[iletct++] = 'u';
  949.         if (invent) ilets[iletct++] = 'a';
  950.     } else if (takeoff && invent) {
  951.         ilets[iletct++] = ' ';
  952.     }
  953.     ilets[iletct++] = 'i';
  954.     ilets[iletct] = '\0';
  955.  
  956.     do {
  957.         Sprintf(qbuf,"What kinds of thing do you want to %s? [%s]",
  958.             word, ilets);
  959.         getlin(qbuf, buf);
  960.         if (buf[0] == '\033') return(0);
  961.         if (index(buf, 'i')) {
  962.         (void) display_inventory(NULL, FALSE);
  963.         } else
  964.         break;
  965.     } while (1);
  966.  
  967.     ip = buf;
  968.     olets[0] = 0;
  969.     while ((sym = *ip++) != 0) {
  970.         if(sym == ' ') continue;
  971.         oc_of_sym = def_char_to_objclass(sym);
  972.         if(takeoff && !(uwep && oc_of_sym == uwep->oclass)
  973.            && (oc_of_sym != MAXOCLASSES)) {
  974.             if(!index(removeables,oc_of_sym)) {
  975.             pline("Not applicable.");
  976.             return(0);
  977.             } else if(oc_of_sym == ARMOR_CLASS && !wearing_armor()) {
  978.             You("are not wearing any armor.");
  979.             return(0);
  980.             } else if(oc_of_sym == WEAPON_CLASS && !uwep) {
  981.             You("are not wielding anything.");
  982.             return(0);
  983.             } else if(oc_of_sym == RING_CLASS && !uright && !uleft) {
  984.             You("are not wearing rings.");
  985.             return(0);
  986.             } else if(oc_of_sym == AMULET_CLASS && !uamul) {
  987.             You("are not wearing an amulet.");
  988.             return(0);
  989.             } else if(oc_of_sym == TOOL_CLASS && !ublindf) {
  990.             You("are not wearing a blindfold.");
  991.             return(0);
  992.             }
  993.         }
  994.         if(oc_of_sym == GOLD_CLASS) {
  995.             if(allowgold == 1)
  996.                 (*fn)(mkgoldobj(u.ugold));
  997.             else if(!u.ugold)
  998.                 You("have no gold.");
  999.             allowgold = 2;
  1000.         } else if(sym == 'a' || sym == 'A')
  1001.             allflag = TRUE;
  1002.         else if(sym == 'u' || sym == 'U')
  1003.             ckfn = ckunpaid;
  1004.         else if (oc_of_sym == MAXOCLASSES)
  1005.             You("don't have any %c's.", sym);
  1006.         else if (oc_of_sym != VENOM_CLASS) {/* venom doesn't show up */
  1007.             if (!index(olets, oc_of_sym)) {
  1008.                 olets[oletct++] = oc_of_sym;
  1009.                 olets[oletct] = 0;
  1010.             }
  1011.         }
  1012.     }
  1013.     if(allowgold == 2 && !oletct)
  1014.         return 1;    /* you dropped gold (or at least tried to) */
  1015.     else
  1016.         return askchain((struct obj **)&invent, olets, allflag,
  1017.                 fn, ckfn, mx, word);
  1018. }
  1019.  
  1020. /*
  1021.  * Walk through the chain starting at objchn and ask for all objects
  1022.  * with olet in olets (if nonNULL) and satisfying ckfn (if nonNULL)
  1023.  * whether the action in question (i.e., fn) has to be performed.
  1024.  * If allflag then no questions are asked. Max gives the max nr of
  1025.  * objects to be treated. Return the number of objects treated.
  1026.  */
  1027. int
  1028. askchain(objchn, olets, allflag, fn, ckfn, mx, word)
  1029. struct obj **objchn;
  1030. register int allflag, mx;
  1031. register const char *olets, *word;    /* olets is an Obj Class char array */
  1032. register int FDECL((*fn),(OBJ_P)), FDECL((*ckfn),(OBJ_P));
  1033. {
  1034.     register struct obj *otmp, *otmp2;
  1035.     register char sym, ilet;
  1036.     register int cnt = 0, dud = 0, tmp;
  1037.     boolean takeoff, nodot, ident, ininv;
  1038.     char qbuf[QBUFSZ];
  1039.  
  1040.     takeoff = !strcmp(word, "take off");
  1041.     ident = !strcmp(word, "identify");
  1042.     nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") ||
  1043.          ident || takeoff);
  1044.     ininv = (*objchn == invent);
  1045.     /* Changed so the askchain is interrogated in the order specified.
  1046.      * For example, if a person specifies =/ then first all rings will be
  1047.      * asked about followed by all wands -dgk
  1048.      */
  1049. nextclass:
  1050.     ilet = 'a'-1;
  1051.     if (*objchn && (*objchn)->otyp == GOLD_PIECE) ilet--;    /* extra iteration */
  1052.     for (otmp = *objchn; otmp; otmp = otmp2) {
  1053.         if(ilet == 'z') ilet = 'A'; else ilet++;
  1054.         otmp2 = otmp->nobj;
  1055.         if (olets && *olets && otmp->oclass != *olets) continue;
  1056.         if (takeoff && !is_worn(otmp)) continue;
  1057.         if (ident && is_fully_identified(otmp)) continue;
  1058.         if (ckfn && !(*ckfn)(otmp)) continue;
  1059.         if (!allflag) {
  1060.             Strcpy(qbuf, ininv ?
  1061.                 xprname(otmp, ilet, !nodot, 0L) : doname(otmp));
  1062.             Strcat(qbuf, "?");
  1063.             sym = (takeoff || ident || otmp->quan < 2L) ?
  1064.                 nyaq(qbuf) : nyNaq(qbuf);
  1065.         }
  1066.         else    sym = 'y';
  1067.  
  1068.         if (sym == '#') {
  1069.          /* Number was entered; split the object unless it corresponds
  1070.             to 'none' or 'all'.  2 special cases: cursed loadstones and
  1071.             welded weapons (eg, multiple daggers) will remain as merged
  1072.             unit; done to avoid splitting an object that won't be
  1073.             droppable (even if we're picking up rather than dropping).
  1074.           */
  1075.             if (!yn_number)
  1076.             sym = 'n';
  1077.             else {
  1078.             sym = 'y';
  1079.             if (yn_number < otmp->quan && !welded(otmp) &&
  1080.                 (!otmp->cursed || otmp->otyp != LOADSTONE)) {
  1081.                 struct obj *otmpx = splitobj(otmp, yn_number);
  1082.                 if (!otmpx || otmpx->nobj != otmp2)
  1083.                 impossible("bad object split in askchain");
  1084.             }
  1085.             }
  1086.         }
  1087.         switch(sym){
  1088.         case 'a':
  1089.             allflag = 1;
  1090.         case 'y':
  1091.             tmp = (*fn)(otmp);
  1092.             if(tmp < 0) goto ret;
  1093.             cnt += tmp;
  1094.             if(--mx == 0) goto ret;
  1095.         case 'n':
  1096.             if(nodot) dud++;
  1097.         default:
  1098.             break;
  1099.         case 'q':
  1100.             /* special case for seffects() */
  1101.             if (ident) cnt = -1;
  1102.             goto ret;
  1103.         }
  1104.     }
  1105.     if (olets && *olets && *++olets)
  1106.         goto nextclass;
  1107.     if(!takeoff && (dud || cnt)) pline("That was all.");
  1108.     else if(!dud && !cnt) pline("No applicable objects.");
  1109. ret:
  1110.     return(cnt);
  1111. }
  1112.  
  1113. #endif /* OVLB */
  1114. #ifdef OVL2
  1115.  
  1116. STATIC_OVL char
  1117. obj_to_let(obj)    /* should of course only be called for things in invent */
  1118. register struct obj *obj;
  1119. {
  1120.     register struct obj *otmp;
  1121.     register char ilet;
  1122.  
  1123.     if (obj->otyp == GOLD_PIECE)
  1124.         return GOLD_SYM;
  1125.     else if (flags.invlet_constant)
  1126.         return obj->invlet;
  1127.     ilet = 'a';
  1128.     for(otmp = invent; otmp && otmp != obj; otmp = otmp->nobj)
  1129.         if(++ilet > 'z') ilet = 'A';
  1130.     return((char)(otmp ? ilet : NOINVSYM));
  1131. }
  1132.  
  1133. /*
  1134.  * Print the indicated quantity of the given object.  If quan == 0L then use
  1135.  * the current quantity.
  1136.  */
  1137. void
  1138. prinv(prefix, obj, quan)
  1139. const char *prefix;
  1140. register struct obj *obj;
  1141. long quan;
  1142. {
  1143. #ifdef GCC_WARN
  1144.     long savequan = 0;
  1145. #else
  1146.     long savequan;
  1147. #endif
  1148.     if ( !prefix ) prefix = "";
  1149.     if (quan) {
  1150.         savequan = obj->quan;
  1151.         obj->quan = quan;
  1152.     }
  1153.     pline("%s%s%s",
  1154.           prefix, *prefix ? " " : "",
  1155.           xprname(obj, obj_to_let(obj), TRUE, 0L));
  1156.     if (quan) obj->quan = savequan;
  1157. }
  1158.  
  1159. #endif /* OVL2 */
  1160. #ifdef OVL1
  1161.  
  1162. char *
  1163. xprname(obj,let,dot,cost)
  1164. register struct obj *obj;
  1165. register char let;
  1166. register boolean dot;   /* append period; (dot && cost => Iu) */
  1167. register long cost;     /* cost (for inventory of unpaid or expended items) */
  1168. {
  1169. #ifdef LINT    /* handle static char li[BUFSZ]; */
  1170.     char li[BUFSZ];
  1171. #else
  1172.     static char li[BUFSZ];
  1173. #endif
  1174.     boolean use_invlet = flags.invlet_constant && let != CONTAINED_SYM;
  1175.     /*
  1176.      * If let is:
  1177.      *    *  Then obj == NULL and we are printing a total amount.
  1178.      *    >  Then the object is contained and doesn't have an inventory letter.
  1179.      */
  1180.     if (cost != 0 || let == '*') {
  1181.     /* if dot is true, we're doing Iu, otherwise Ix */
  1182.     Sprintf(li, "%c - %-45s %6ld zorkmid%s",
  1183.         (dot && use_invlet ? obj->invlet : let),
  1184.         (let != '*' ? doname(obj) : "Total:"), cost, plur(cost));
  1185.     } else if (obj->otyp == GOLD_PIECE) {
  1186.     Sprintf(li, "%ld gold piece%s%s", obj->quan, plur(obj->quan),
  1187.         (dot ? "." : ""));
  1188.     } else {
  1189.     /* ordinary inventory display or pickup message */
  1190.     Sprintf(li, "%c - %s",
  1191.         (use_invlet ? obj->invlet : let),
  1192.         doname(obj));
  1193.     if(dot) Strcat(li,".");
  1194.     }
  1195.     return li;
  1196. }
  1197.  
  1198. #endif /* OVL1 */
  1199. #ifdef OVLB
  1200.  
  1201. int
  1202. ddoinv()
  1203. {
  1204.     (void) display_inventory(NULL, FALSE);
  1205.     return 0;
  1206. }
  1207.  
  1208. /*
  1209.  *  find_unpaid()
  1210.  *
  1211.  *  Scan the given list of objects.  If last_found is NULL, return the first
  1212.  *  unpaid object found.  If last_found is not NULL, then skip over unpaid
  1213.  *  objects until last_found is reached, then set last_found to NULL so the
  1214.  *  next unpaid object is returned.  This routine recursively follows
  1215.  *  containers.
  1216.  */
  1217. static struct obj *
  1218. find_unpaid(list, last_found)
  1219.     struct obj *list, **last_found;
  1220. {
  1221.     struct obj *obj;
  1222.  
  1223.     while (list) {
  1224.     if (list->unpaid) {
  1225.         if (*last_found) {
  1226.         /* still looking for previous unpaid object */
  1227.         if (list == *last_found)
  1228.             *last_found = (struct obj *) 0;
  1229.         } else
  1230.         return (*last_found = list);
  1231.     }
  1232.     if (Has_contents(list)) {
  1233.         if ((obj = find_unpaid(list->cobj, last_found)) != 0)
  1234.         return obj;
  1235.     }
  1236.     list = list->nobj;
  1237.     }
  1238.     return (struct obj *) 0;
  1239. }
  1240.  
  1241. /*
  1242.  *  If lets == NULL or "", list all objects in the inventory.  Otherwise,
  1243.  *  list all objects with object classes that match the order in lets.
  1244.  *  The last letter could possibly be a '>' which means list unpaid contained
  1245.  *  objects.
  1246.  *  Returns the letter identifier of a selected item, or 0 (nothing was
  1247.  *  selected), or '\033' (the menu was cancelled).
  1248.  */
  1249. char
  1250. display_inventory(lets,show_cost)
  1251. register const char *lets;
  1252. boolean show_cost;
  1253. {
  1254.     register struct obj *otmp;
  1255.     struct obj *z_obj;
  1256.     register char ilet;
  1257.     char *invlet = flags.inv_order;
  1258.     int classcount;
  1259. #if defined(LINT) || defined(GCC_WARN)
  1260.     int save_unpaid = 0;
  1261. #else
  1262.     int save_unpaid;
  1263. #endif
  1264.     long cost, totcost;
  1265.     boolean do_containers = FALSE;
  1266.  
  1267.     if(!invent){
  1268.         pline("Not carrying anything.");
  1269.         return 0;
  1270.     }
  1271.     if (lets != NULL) {
  1272.         int ct = strlen(lets); /* count number of inventory slots to show */
  1273.         /* If we've got unpaid items in containers, count all unpaid
  1274.            objects.  At least one won't be in any inventory slot. */
  1275.         do_containers = (ct && lets[ct-1] == CONTAINED_SYM);
  1276.         if (do_containers && ct == 1) ct = count_unpaid(invent);
  1277.         /* if only one item of interest, use pline instead of menus */
  1278.         if (ct == 1) {
  1279.         if (do_containers) {    /* single non-inventory object */
  1280.             z_obj = (struct obj *) 0;
  1281.             if ((otmp = find_unpaid(invent, &z_obj)) != 0)
  1282.             pline("%s",
  1283.                   xprname(otmp, CONTAINED_SYM, TRUE,
  1284.                      (show_cost ? unpaid_cost(otmp) : 0L)));
  1285.             else
  1286.             impossible(
  1287.             "display_inventory: no singular unpaid contained objects");
  1288.         } else {
  1289.             for(otmp = invent; otmp; otmp = otmp->nobj) {
  1290.             if (otmp->invlet == lets[0]) {
  1291.                 pline("%s",
  1292.                   xprname(otmp, lets[0], TRUE,
  1293.                      (show_cost ? unpaid_cost(otmp) : 0L)));
  1294.                 break;
  1295.             }
  1296.             }
  1297.         }
  1298.         return 0;
  1299.         }
  1300.     }
  1301.  
  1302.     start_menu(WIN_INVEN);
  1303.     cost = totcost = 0;
  1304. nextclass:
  1305.     classcount = 0;
  1306.     ilet = 'a';
  1307.     for(otmp = invent; otmp; otmp = otmp->nobj) {
  1308.         if(flags.invlet_constant) ilet = otmp->invlet;
  1309.         if(!lets || !*lets || index(lets, ilet)) {
  1310.             if (!flags.sortpack || otmp->oclass == *invlet) {
  1311.                 if (flags.sortpack && !classcount) {
  1312.                 add_menu(WIN_INVEN, 0, ATR_INVERSE,
  1313.                      let_to_name(*invlet, show_cost));
  1314.                 classcount++;
  1315.                 }
  1316.                 if (show_cost) {
  1317.                 totcost += cost = unpaid_cost(otmp);
  1318.                 /* suppress "(unpaid)" suffix */
  1319.                 save_unpaid = otmp->unpaid;
  1320.                 otmp->unpaid = 0;
  1321.                 }
  1322.                 add_menu(WIN_INVEN, ilet, 0,
  1323.                      xprname(otmp, ilet, TRUE, cost));
  1324.                 if (show_cost)  otmp->unpaid = save_unpaid;
  1325.             }
  1326.         }
  1327.         if(!flags.invlet_constant) if(++ilet > 'z') ilet = 'A';
  1328.     }
  1329.     if (flags.sortpack) {
  1330.         if (*++invlet) goto nextclass;
  1331. #ifdef WIZARD
  1332.         if (--invlet != venom_inv) {
  1333.             invlet = venom_inv;
  1334.             goto nextclass;
  1335.         }
  1336. #endif
  1337.     }
  1338.  
  1339.     /* right now, we only do this for unpaid items, so always do cost */
  1340.     if (do_containers) {
  1341.         if (flags.sortpack) add_menu(WIN_INVEN, 0, ATR_INVERSE,
  1342.                      let_to_name(CONTAINED_SYM, 1));
  1343.         /*
  1344.          *  Search through the container objects in the inventory for
  1345.          *  unpaid items.  Note that we check each container, not
  1346.          *  the invent list.  This is because the invent list could
  1347.          *  have unpaid items that have been already listed.
  1348.          */
  1349.         for (otmp = invent; otmp; otmp = otmp->nobj) {
  1350.         if (Has_contents(otmp)) {
  1351.             z_obj = (struct obj *) 0;    /* haven't found any */
  1352.             while (find_unpaid(otmp->cobj, (struct obj **)&z_obj)) {
  1353.             totcost += cost = unpaid_cost(z_obj);
  1354.             save_unpaid = z_obj->unpaid;
  1355.             z_obj->unpaid = 0;    /* suppress "(unpaid)" suffix */
  1356.             add_menu(WIN_INVEN, 0, 0,
  1357.                  xprname(z_obj, CONTAINED_SYM, TRUE, cost));
  1358.             z_obj->unpaid = save_unpaid;
  1359.             }
  1360.         }
  1361.         }
  1362.     }
  1363.  
  1364.     if (show_cost) {
  1365.         /* give 'Totals' line */
  1366.         add_menu(WIN_INVEN, 0, 0, "");
  1367.         add_menu(WIN_INVEN, 0, 0,
  1368.              xprname((struct obj *)0, '*', FALSE, totcost));
  1369.     }
  1370.     end_menu(WIN_INVEN, '\033', "\033 ", NULL);
  1371.     return select_menu(WIN_INVEN);
  1372. }
  1373.  
  1374. /*
  1375.  *  Returns the number of unpaid items within the given list.  This includes
  1376.  *  contained objects.
  1377.  */
  1378. int
  1379. count_unpaid(list)
  1380.     struct obj *list;
  1381. {
  1382.     int count = 0;
  1383.  
  1384.     while (list) {
  1385.     if (list->unpaid) count++;
  1386.     if (Has_contents(list))
  1387.         count += count_unpaid(list->cobj);
  1388.     list = list->nobj;
  1389.     }
  1390.     return count;
  1391. }
  1392.  
  1393. int
  1394. dotypeinv()                /* free after Robert Viduya */
  1395. /* Changed to one type only, so you don't have to type return */
  1396. {
  1397.     char c, ilet;
  1398.     char stuff[BUFSZ];
  1399.     register int stct;
  1400.     register struct obj *otmp;
  1401.     boolean billx = *u.ushops && doinvbill(0);
  1402.     boolean do_unpd = FALSE;
  1403.     int unpd, class;
  1404.  
  1405.     if (!invent && !u.ugold && !billx) {
  1406.         You("aren't carrying anything.");
  1407.         return 0;
  1408.     }
  1409.  
  1410.     Strcpy(stuff, "What type of object do you want an inventory of? [");
  1411.     /* collect a list of classes of objects carried, for use as a prompt */
  1412.     stct = collect_obj_classes(eos(stuff), invent, FALSE, (u.ugold != 0));
  1413.     unpd = count_unpaid(invent);
  1414.     if(unpd) Strcat(stuff, "u");
  1415.     if(billx) Strcat(stuff, "x");
  1416.     Strcat(stuff, "]");
  1417.  
  1418.     if(stct > 1) {
  1419.       c = yn_function(stuff, NULL, '\0');
  1420. #ifdef REDO
  1421.         savech(c);
  1422. #endif
  1423.         if(c == '\0') {
  1424.         clear_nhwindow(WIN_MESSAGE);
  1425.         return 0;
  1426.         }
  1427.     } else
  1428.         c = stuff[0];
  1429.  
  1430.     if(c == 'x' || c == 'X') {
  1431.         if(billx)
  1432.         (void) doinvbill(1);
  1433.         else
  1434.         pline("No used-up objects on the shopping bill.");
  1435.         return(0);
  1436.     }
  1437.  
  1438.     if (c == 'u' || c == 'U') {
  1439.         if (!unpd) {
  1440.         You("are not carrying any unpaid objects.");
  1441.         return(0);
  1442.         }
  1443.         do_unpd = TRUE;
  1444.     }
  1445.  
  1446.     class = def_char_to_objclass(c);    /* change to object class */
  1447.  
  1448.     if(class == GOLD_CLASS)
  1449.         return(doprgold());
  1450.  
  1451.     /* collect all items which match the selected objclass */
  1452.     stct = 0;
  1453.     ilet = 'a';
  1454.     for (otmp = invent; otmp; otmp = otmp->nobj) {
  1455.         if(flags.invlet_constant) ilet = otmp->invlet;
  1456.         if (class == otmp->oclass || (do_unpd && otmp->unpaid)) {
  1457.         stuff[stct++] = ilet;
  1458.         --unpd;    /* decrement unpaid count */
  1459.         }
  1460.         if(!flags.invlet_constant) if(++ilet > 'z') ilet = 'A';
  1461.     }
  1462.     /* unpd is now the number of unpaid contained objects */
  1463.     if (do_unpd && unpd)
  1464.         stuff[stct++] = CONTAINED_SYM;    /* list contained unpaid items */
  1465.  
  1466.     stuff[stct] = '\0';
  1467.     if(stct == 0)
  1468.         You("have no such objects.");
  1469.     else
  1470.         (void) display_inventory(stuff, do_unpd);
  1471.  
  1472.     return(0);
  1473. }
  1474.  
  1475. /* look at what is here */
  1476. int
  1477. dolook()
  1478. {
  1479.     register struct obj *otmp, *otmp0;
  1480.     struct trap *trap;
  1481.     const char *verb = Blind ? "feel" : "see";
  1482.     const char *dfeature = (char*) 0;
  1483.     char fbuf[BUFSZ], fbuf2[BUFSZ];
  1484.     boolean no_article = FALSE;
  1485.     winid tmpwin;
  1486.  
  1487.     if(u.uswallow) {
  1488.         You("%s no objects here.", verb);
  1489.         return(!!Blind);
  1490.     }
  1491.     read_engr_at(u.ux, u.uy); /* Eric Backus */
  1492.     if ((trap = t_at(u.ux,u.uy)) && trap->tseen)
  1493.         pline("There is a%s here.", traps[trap->ttyp]);
  1494.  
  1495.     otmp0 = level.objects[u.ux][u.uy];
  1496.  
  1497.     if(IS_DOOR(levl[u.ux][u.uy].typ))  {
  1498.         switch(levl[u.ux][u.uy].doormask) {
  1499.             case D_NODOOR:
  1500.             dfeature = "doorway"; break;
  1501.             case D_ISOPEN:
  1502.             dfeature = "open door"; break;
  1503.             case D_BROKEN:
  1504.             dfeature = "broken door"; break;
  1505.             default:
  1506.             dfeature = "closed door";
  1507.         }
  1508.     } else if(IS_FOUNTAIN(levl[u.ux][u.uy].typ))
  1509.         /* added by GAN 10/30/86 */
  1510.         dfeature = "fountain";
  1511.     else if(IS_THRONE(levl[u.ux][u.uy].typ))
  1512.         dfeature = "opulent throne";
  1513.     else if(is_lava(u.ux,u.uy))
  1514.         dfeature = "molten lava",  no_article = TRUE;
  1515.     else if(is_ice(u.ux,u.uy))
  1516.         dfeature = "ice",  no_article = TRUE;
  1517.     else if(is_pool(u.ux,u.uy) && !Underwater)
  1518.         dfeature = "pool of water";
  1519. #ifdef SINKS
  1520.     else if(IS_SINK(levl[u.ux][u.uy].typ))
  1521.         dfeature = "kitchen sink";
  1522. #endif
  1523.     else if(IS_ALTAR(levl[u.ux][u.uy].typ))  {
  1524.         Sprintf(fbuf2, "altar to %s (%s)",
  1525.             a_gname(),
  1526.             align_str(Amask2align(levl[u.ux][u.uy].altarmask
  1527.                                 & ~AM_SHRINE)));
  1528.         dfeature = fbuf2;
  1529.     } else if(u.ux == xupstair && u.uy == yupstair)
  1530.         dfeature = "stairway up";
  1531.     else if(u.ux == xdnstair && u.uy == ydnstair)
  1532.         dfeature = "stairway down";
  1533.     else if(u.ux == sstairs.sx && u.uy == sstairs.sy) {
  1534.         if (sstairs.up)
  1535.             dfeature = "stairway up";
  1536.         else
  1537.             dfeature = "stairway down";
  1538.     } else if(u.ux == xupladder && u.uy == yupladder)
  1539.         dfeature = "ladder up";
  1540.     else if(u.ux == xdnladder && u.uy == ydnladder)
  1541.         dfeature = "ladder down";
  1542.     else if (levl[u.ux][u.uy].typ == DRAWBRIDGE_DOWN)
  1543.         dfeature = "lowered drawbridge";
  1544.  
  1545.     if (Blind) {
  1546.         You("try to feel what is %s.",
  1547.             Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) ?
  1548.             "floating here" :
  1549.             "lying here on the floor");
  1550.          if (Levitation &&
  1551.             !Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz)) {
  1552.             pline("But you can't reach it!");
  1553.             return(0);
  1554.          }
  1555.     }
  1556.  
  1557.     if (dfeature)
  1558.         Sprintf(fbuf, "There is %s%s here.",
  1559.             no_article ? "" :
  1560.                 index(vowels,dfeature[0]) ? "an " : "a ",
  1561.             dfeature);
  1562.  
  1563.     if(!otmp0 || (is_pool(u.ux,u.uy) && !Underwater)) {
  1564.             if(dfeature) pline(fbuf);
  1565.         if(Blind || !dfeature)
  1566.             You("%s no objects here.", verb);
  1567.         return(!!Blind);
  1568.     }
  1569.     /* we know there is something here */
  1570.  
  1571.     if (!otmp0->nexthere) {
  1572.         /* only one object */
  1573.         if (dfeature) pline(fbuf);
  1574.         You("%s here %s.", verb, doname(otmp0));
  1575.     } else {
  1576.         display_nhwindow(WIN_MESSAGE, FALSE);
  1577.         tmpwin = create_nhwindow(NHW_MENU);
  1578.         if(dfeature) {
  1579.         putstr(tmpwin, 0, fbuf);
  1580.         putstr(tmpwin, 0, "");
  1581.         }
  1582.         putstr(tmpwin, 0, "Things that are here:");
  1583.         for(otmp = otmp0; otmp; otmp = otmp->nexthere) {
  1584.         putstr(tmpwin, 0, doname(otmp));
  1585.  
  1586.         if(Blind  && !uarmg &&
  1587. #ifdef POLYSELF
  1588.                 !resists_ston(uasmon) &&
  1589. #endif
  1590.                 (otmp->otyp == CORPSE &&
  1591.                     otmp->corpsenm == PM_COCKATRICE)) {
  1592. #if defined(POLYSELF)
  1593.             if(poly_when_stoned(uasmon)) {
  1594.             You("touched the cockatrice corpse with your bare hands.");
  1595.             (void) polymon(PM_STONE_GOLEM);
  1596.             } else
  1597. #endif
  1598.             {
  1599.             pline("Touching the cockatrice corpse is a fatal mistake...");
  1600.             You("turn to stone...");
  1601.             killer_format = KILLED_BY_AN;
  1602.             killer = "cockatrice corpse";
  1603.             done(STONING);
  1604.             }
  1605.         }
  1606.         }
  1607.         display_nhwindow(tmpwin, TRUE);
  1608.         destroy_nhwindow(tmpwin);
  1609.     }
  1610.     return(!!Blind);
  1611. }
  1612.  
  1613. #endif /* OVLB */
  1614. #ifdef OVL1
  1615.  
  1616. void
  1617. stackobj(obj)
  1618. register struct obj *obj;
  1619. {
  1620.     register struct obj *otmp;
  1621.  
  1622.     for(otmp = level.objects[obj->ox][obj->oy]; otmp; otmp = otmp->nexthere)
  1623.         if(otmp != obj && merged(obj,otmp,1))
  1624.             break;
  1625.     return;
  1626. }
  1627.  
  1628. static boolean
  1629. mergable(otmp, obj)    /* returns TRUE if obj  & otmp can be merged */
  1630.     register struct obj *otmp, *obj;
  1631. {
  1632.     if (obj->otyp != otmp->otyp || obj->unpaid != otmp->unpaid ||
  1633.         obj->spe != otmp->spe || obj->dknown != otmp->dknown ||
  1634.         (obj->bknown != otmp->bknown && pl_character[0] != 'P') ||
  1635.         obj->cursed != otmp->cursed || obj->blessed != otmp->blessed ||
  1636.         obj->no_charge != otmp->no_charge ||
  1637.         obj->obroken != otmp->obroken ||
  1638.         obj->otrapped != otmp->otrapped ||
  1639.         obj->lamplit != otmp->lamplit ||
  1640.         obj->oeroded != otmp->oeroded)
  1641.         return(FALSE);
  1642.  
  1643.     if ((obj->oclass==WEAPON_CLASS || obj->oclass==ARMOR_CLASS) &&
  1644.         (obj->oerodeproof!=otmp->oerodeproof || obj->rknown!=otmp->rknown))
  1645.         return FALSE;
  1646.  
  1647.     if (obj->oclass == FOOD_CLASS && (obj->oeaten != otmp->oeaten ||
  1648.                       obj->orotten != otmp->orotten))
  1649.         return(FALSE);
  1650.  
  1651.     if (obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == TIN) {
  1652.         if((obj->corpsenm != otmp->corpsenm) ||
  1653.             (ONAME(obj) && strcmp(ONAME(obj), ONAME(otmp))))
  1654.                 return FALSE;
  1655.     }
  1656.  
  1657.     /* allow candle merging only if their ages are close */
  1658.     /* see burn_lamps() for a reference for the magic "25" */
  1659.     if (Is_candle(obj) && obj->age/25 != otmp->age/25)
  1660.         return(FALSE);
  1661.  
  1662.     /* don't merge surcharged item with base-cost item */
  1663.     if (obj->unpaid && !same_price(obj, otmp))
  1664.         return FALSE;
  1665.  
  1666. /* if they have names, make sure they're the same */
  1667.     if ( (obj->onamelth != otmp->onamelth &&
  1668.         ((obj->onamelth && otmp->onamelth) || obj->otyp == CORPSE)
  1669.          ) ||
  1670.         (obj->onamelth &&
  1671.             strncmp(ONAME(obj), ONAME(otmp), (int)obj->onamelth)))
  1672.         return FALSE;
  1673.  
  1674.     if(obj->oartifact != otmp->oartifact) return FALSE;
  1675.  
  1676.     if(obj->known == otmp->known ||
  1677.         !objects[otmp->otyp].oc_uses_known) {
  1678.         return((boolean)(objects[obj->otyp].oc_merge));
  1679.     } else return(FALSE);
  1680. }
  1681.  
  1682. #endif /* OVL1 */
  1683. #ifdef OVLB
  1684.  
  1685. int
  1686. doprgold(){
  1687.     if(!u.ugold)
  1688.         You("do not carry any gold.");
  1689.     else
  1690.         You("are carrying %ld gold piece%s.", u.ugold, plur(u.ugold));
  1691.     return 0;
  1692. }
  1693.  
  1694. int
  1695. doprwep()
  1696. {
  1697.     if(!uwep) You("are empty %s.", body_part(HANDED));
  1698.     else prinv(NULL, uwep, 0L);
  1699.     return 0;
  1700. }
  1701.  
  1702. int
  1703. doprarm(){
  1704.     if(!wearing_armor())
  1705.         You("are not wearing any armor.");
  1706.     else {
  1707. #ifdef TOURIST
  1708.         char lets[8];
  1709. #else
  1710.         char lets[7];
  1711. #endif
  1712.         register int ct = 0;
  1713.  
  1714. #ifdef TOURIST
  1715.         if(uarmu) lets[ct++] = obj_to_let(uarmu);
  1716. #endif
  1717.         if(uarm) lets[ct++] = obj_to_let(uarm);
  1718.         if(uarmc) lets[ct++] = obj_to_let(uarmc);
  1719.         if(uarmh) lets[ct++] = obj_to_let(uarmh);
  1720.         if(uarms) lets[ct++] = obj_to_let(uarms);
  1721.         if(uarmg) lets[ct++] = obj_to_let(uarmg);
  1722.         if(uarmf) lets[ct++] = obj_to_let(uarmf);
  1723.         lets[ct] = 0;
  1724.         (void) display_inventory(lets, FALSE);
  1725.     }
  1726.     return 0;
  1727. }
  1728.  
  1729. int
  1730. doprring(){
  1731.     if(!uleft && !uright)
  1732.         You("are not wearing any rings.");
  1733.     else {
  1734.         char lets[3];
  1735.         register int ct = 0;
  1736.  
  1737.         if(uleft) lets[ct++] = obj_to_let(uleft);
  1738.         if(uright) lets[ct++] = obj_to_let(uright);
  1739.         lets[ct] = 0;
  1740.         (void) display_inventory(lets, FALSE);
  1741.     }
  1742.     return 0;
  1743. }
  1744.  
  1745. int
  1746. dopramulet(){
  1747.     if (!uamul)
  1748.         You("are not wearing an amulet.");
  1749.     else
  1750.         prinv(NULL, uamul, 0L);
  1751.     return 0;
  1752. }
  1753.  
  1754. int
  1755. doprtool(){
  1756.     register struct obj *otmp;
  1757.     register int ct=0;
  1758.     char lets[3]; /* Maximum: pick-axe, blindfold */
  1759.  
  1760.     for(otmp = invent; otmp; otmp = otmp->nobj) {
  1761.         if (((otmp->owornmask & W_TOOL) && otmp->oclass==TOOL_CLASS)
  1762.            || (otmp==uwep &&
  1763.            (otmp->otyp==PICK_AXE || otmp->otyp==TIN_OPENER)))
  1764.             lets[ct++] = obj_to_let(otmp);
  1765.     }
  1766.     lets[ct] = 0;
  1767.     if (!ct) You("are not using any tools.");
  1768.     else (void) display_inventory(lets, FALSE);
  1769.     return 0;
  1770. }
  1771.  
  1772. /*
  1773.  * uses up an object that's on the floor, charging for it as necessary
  1774.  */
  1775. void
  1776. useupf(obj)
  1777. register struct obj *obj;
  1778. {
  1779.     register struct obj *otmp;
  1780.  
  1781.     /* burn_floor_paper() keeps an object pointer that it tries to
  1782.      * useupf() multiple times, so obj must survive if plural */
  1783.     if(obj->quan > 1L)
  1784.         otmp = splitobj(obj, obj->quan - 1L);
  1785.     else
  1786.         otmp = obj;
  1787.     if(costly_spot(otmp->ox, otmp->oy)) {
  1788.         if(index(u.urooms, *in_rooms(otmp->ox, otmp->oy, 0)))
  1789.             addtobill(otmp, FALSE, FALSE, FALSE);
  1790.         else (void)stolen_value(otmp, otmp->ox, otmp->oy, FALSE, FALSE);
  1791.     }
  1792.     delobj(otmp);
  1793. }
  1794.  
  1795. #endif /* OVLB */
  1796. #ifdef OVL1
  1797.  
  1798. extern const char obj_symbols[];    /* o_init.c */
  1799. /*
  1800.  * Conversion from a symbol to a string for printing object classes.
  1801.  * This must match the array obj_symbols[].
  1802.  */
  1803. static NEARDATA const char *names[] = {
  1804.     "Illegal objects", "Amulets", "Coins", "Comestibles", "Weapons",
  1805.     "Tools", "Iron balls", "Chains", "Boulders/Statues", "Armor",
  1806.     "Potions", "Scrolls", "Wands", "Spellbooks", "Rings", "Gems"
  1807. };
  1808.  
  1809. static NEARDATA const char oth_symbols[] = {
  1810. #ifdef WIZARD
  1811.     VENOM_CLASS,
  1812. #endif
  1813.     CONTAINED_SYM,
  1814.     '\0'
  1815. };
  1816.  
  1817. static NEARDATA const char *oth_names[] = {
  1818. #ifdef WIZARD
  1819.     "Venoms",
  1820. #endif
  1821.     "Bagged/Boxed items"
  1822. };
  1823.  
  1824. char *
  1825. let_to_name(let,unpaid)
  1826. char let;
  1827. boolean unpaid;
  1828. {
  1829.     const char *class_name;
  1830.     const char *pos = index(obj_symbols, let);
  1831.     int len;
  1832.     static NEARDATA char *buf = NULL;
  1833.     static NEARDATA unsigned bufsiz = 0;
  1834.  
  1835.     if (pos)
  1836.         class_name = names[pos - obj_symbols];
  1837.     else if ((pos = index(oth_symbols, let)) != 0)
  1838.         class_name = oth_names[pos - oth_symbols];
  1839.     else
  1840.         class_name = names[0];
  1841.  
  1842.     len = strlen(class_name)
  1843.          + (unpaid ? sizeof("unpaid_") : 1);    /* count terminating NUL */
  1844.     if (len > bufsiz) {
  1845.         if (buf)  free((genericptr_t)buf),  buf = NULL;
  1846.         bufsiz = len + 10; /* add slop to avoid incremental reallocations */
  1847.         buf = (char *) alloc(bufsiz);
  1848.     }
  1849.     if (unpaid)
  1850.         Strcat(strcpy(buf, "Unpaid "), class_name);
  1851.     else
  1852.         Strcpy(buf, class_name);
  1853.     return (buf);
  1854. }
  1855.  
  1856. #endif /* OVL1 */
  1857. #ifdef OVLB 
  1858.  
  1859. void
  1860. reassign()
  1861. {
  1862.     register int i;
  1863.     register struct obj *obj;
  1864.  
  1865.     for(obj = invent, i = 0; obj; obj = obj->nobj, i++)
  1866.         obj->invlet = (i < 26) ? ('a'+i) : ('A'+i-26);
  1867.     lastinvnr = i;
  1868. }
  1869.  
  1870. #endif /* OVLB */
  1871. #ifdef OVL1
  1872. int
  1873. doorganize()    /* inventory organizer by Del Lamb */
  1874. {
  1875.     register struct obj *obj, *otmp;
  1876.     register int ix, cur;
  1877.     register char let;
  1878.     char alphabet[52+1], buf[52+1];
  1879.     char qbuf[QBUFSZ];
  1880.     char allow_all[2];
  1881.     const char *adj_type;
  1882.  
  1883.     /* check to see if the inventory is of the fixed kind */
  1884.     if (!flags.invlet_constant ) {
  1885.         pline("Sorry, only fixed inventories can be adjusted.");
  1886.         return(0);
  1887.     }
  1888. #if 0
  1889.     /* check to see if the inventory has any gaps left in it */
  1890.     if (inv_cnt() >= 52) {
  1891.         pline("Sorry, no available letters for adjustment.");
  1892.         return(0);
  1893.     }
  1894. #endif
  1895.     /* get a pointer to the object the user wants to organize */
  1896.     allow_all[0] = ALL_CLASSES; allow_all[1] = '\0';
  1897.     if (!(obj = getobj(allow_all,"adjust"))) return(0);
  1898.  
  1899.     /* initialize the list with all upper and lower case letters */
  1900.     for (let = 'a', ix = 0;  let <= 'z';) alphabet[ix++] = let++;
  1901.     for (let = 'A', ix = 26; let <= 'Z';) alphabet[ix++] = let++;
  1902.     alphabet[52] = 0;
  1903.  
  1904.     /* blank out all the letters currently in use in the inventory */
  1905.     /* except those that will be merged with the selected object   */
  1906.     for (otmp = invent; otmp; otmp = otmp->nobj)
  1907.         if (otmp != obj && !mergable(otmp,obj))
  1908.             if (otmp->invlet <= 'Z')
  1909.                 alphabet[(otmp->invlet) - 'A' + 26] = ' ';
  1910.             else    alphabet[(otmp->invlet) - 'a']        = ' ';
  1911.  
  1912.     /* compact the list by removing all the blanks */
  1913.     for (ix = cur = 0; ix <= 52; ix++)
  1914.         if (alphabet[ix] != ' ') buf[cur++] = alphabet[ix];
  1915.  
  1916.     /* and by dashing runs of letters */
  1917.     if(cur > 5) compactify(buf);
  1918.  
  1919.     /* get new letter to use as inventory letter */
  1920.     for (;;) {
  1921.         Sprintf(qbuf, "Adjust letter to what [%s]?",buf);
  1922.         let = yn_function(qbuf, NULL, '\0');
  1923.         if(index(quitchars,let)) {
  1924.             pline("Never mind.");
  1925.             return(0);
  1926.         }
  1927.         if (let == '@' || !letter(let))
  1928.             pline("Select an inventory slot letter.");
  1929.         else
  1930.             break;
  1931.     }
  1932.  
  1933.     /* change the inventory and print the resulting item */
  1934.     adj_type = "Moving:";
  1935.  
  1936.     /*
  1937.      * don't use freeinv/addinv to avoid double-touching artifacts,
  1938.      * dousing lamps, losing luck, cursing loadstone, etc.
  1939.      */
  1940.     unlinkinv(obj);
  1941.  
  1942.     for (otmp = invent; otmp;)
  1943.         if (merged(otmp,obj,0)) {
  1944.             adj_type = "Merging:";
  1945.             obj = otmp;
  1946.             otmp = otmp->nobj;
  1947.             unlinkinv(obj);
  1948.         } else {
  1949.             if (otmp->invlet == let) {
  1950.                 adj_type = "Swapping:";
  1951.                 otmp->invlet = obj->invlet;
  1952.             }
  1953.             otmp = otmp->nobj;
  1954.         }
  1955.  
  1956.     /* inline addinv (assuming flags.invlet_constant and !merged) */
  1957.     obj->invlet = let;
  1958.     obj->nobj = invent; /* insert at beginning */
  1959.     invent = obj;
  1960.     reorder_invent();
  1961.  
  1962.     prinv(adj_type, obj, 0L);
  1963.     update_inventory();
  1964.     return(0);
  1965. }
  1966.  
  1967. #endif /* OVL1 */
  1968.  
  1969. /*invent.c*/
  1970.