OSDN Git Service

shrink mine
[nethackexpress/trunk.git] / src / invent.c
1 /*      SCCS Id: @(#)invent.c   3.4     2003/12/02      */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 #include "hack.h"
6
7 #define NOINVSYM        '#'
8 #define CONTAINED_SYM   '>'     /* designator for inside a container */
9
10 #ifdef OVL1
11 STATIC_DCL void NDECL(reorder_invent);
12 STATIC_DCL boolean FDECL(mergable,(struct obj *,struct obj *));
13 STATIC_DCL void FDECL(invdisp_nothing, (const char *,const char *));
14 STATIC_DCL boolean FDECL(worn_wield_only, (struct obj *));
15 STATIC_DCL boolean FDECL(only_here, (struct obj *));
16 #endif /* OVL1 */
17 STATIC_DCL void FDECL(compactify,(char *));
18 STATIC_DCL boolean FDECL(taking_off, (const char *));
19 STATIC_DCL boolean FDECL(putting_on, (const char *));
20 STATIC_PTR int FDECL(ckunpaid,(struct obj *));
21 STATIC_PTR int FDECL(ckvalidcat,(struct obj *));
22 static char FDECL(display_pickinv, (const char *,BOOLEAN_P, long *));
23 #ifdef OVLB
24 STATIC_DCL boolean FDECL(this_type_only, (struct obj *));
25 STATIC_DCL void NDECL(dounpaid);
26 STATIC_DCL struct obj *FDECL(find_unpaid,(struct obj *,struct obj **));
27 STATIC_DCL void FDECL(menu_identify, (int));
28 STATIC_DCL boolean FDECL(tool_in_use, (struct obj *));
29 #endif /* OVLB */
30 STATIC_DCL char FDECL(obj_to_let,(struct obj *));
31
32 #ifdef OVLB
33
34 static int lastinvnr = 51;      /* 0 ... 51 (never saved&restored) */
35
36 #ifdef WIZARD
37 /* wizards can wish for venom, which will become an invisible inventory
38  * item without this.  putting it in inv_order would mean venom would
39  * suddenly become a choice for all the inventory-class commands, which
40  * would probably cause mass confusion.  the test for inventory venom
41  * is only WIZARD and not wizard because the wizard can leave venom lying
42  * around on a bones level for normal players to find.
43  */
44 static char venom_inv[] = { VENOM_CLASS, 0 };   /* (constant) */
45 #endif
46
47 void
48 assigninvlet(otmp)
49 register struct obj *otmp;
50 {
51         boolean inuse[52];
52         register int i;
53         register struct obj *obj;
54
55 #ifdef GOLDOBJ
56         /* There is only one of these in inventory... */        
57         if (otmp->oclass == COIN_CLASS) {
58             otmp->invlet = GOLD_SYM;
59             return;
60         }
61 #endif
62
63         for(i = 0; i < 52; i++) inuse[i] = FALSE;
64         for(obj = invent; obj; obj = obj->nobj) if(obj != otmp) {
65                 i = obj->invlet;
66                 if('a' <= i && i <= 'z') inuse[i - 'a'] = TRUE; else
67                 if('A' <= i && i <= 'Z') inuse[i - 'A' + 26] = TRUE;
68                 if(i == otmp->invlet) otmp->invlet = 0;
69         }
70         if((i = otmp->invlet) &&
71             (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z')))
72                 return;
73         for(i = lastinvnr+1; i != lastinvnr; i++) {
74                 if(i == 52) { i = -1; continue; }
75                 if(!inuse[i]) break;
76         }
77         otmp->invlet = (inuse[i] ? NOINVSYM :
78                         (i < 26) ? ('a'+i) : ('A'+i-26));
79         lastinvnr = i;
80 }
81
82 #endif /* OVLB */
83 #ifdef OVL1
84
85 /* note: assumes ASCII; toggling a bit puts lowercase in front of uppercase */
86 #define inv_rank(o) ((o)->invlet ^ 040)
87
88 /* sort the inventory; used by addinv() and doorganize() */
89 STATIC_OVL void
90 reorder_invent()
91 {
92         struct obj *otmp, *prev, *next;
93         boolean need_more_sorting;
94
95         do {
96             /*
97              * We expect at most one item to be out of order, so this
98              * isn't nearly as inefficient as it may first appear.
99              */
100             need_more_sorting = FALSE;
101             for (otmp = invent, prev = 0; otmp; ) {
102                 next = otmp->nobj;
103                 if (next && inv_rank(next) < inv_rank(otmp)) {
104                     need_more_sorting = TRUE;
105                     if (prev) prev->nobj = next;
106                     else      invent = next;
107                     otmp->nobj = next->nobj;
108                     next->nobj = otmp;
109                     prev = next;
110                 } else {
111                     prev = otmp;
112                     otmp = next;
113                 }
114             }
115         } while (need_more_sorting);
116 }
117
118 #undef inv_rank
119
120 /* scan a list of objects to see whether another object will merge with
121    one of them; used in pickup.c when all 52 inventory slots are in use,
122    to figure out whether another object could still be picked up */
123 struct obj *
124 merge_choice(objlist, obj)
125 struct obj *objlist, *obj;
126 {
127         struct monst *shkp;
128         int save_nocharge;
129
130         if (obj->otyp == SCR_SCARE_MONSTER)     /* punt on these */
131             return (struct obj *)0;
132         /* if this is an item on the shop floor, the attributes it will
133            have when carried are different from what they are now; prevent
134            that from eliciting an incorrect result from mergable() */
135         save_nocharge = obj->no_charge;
136         if (objlist == invent && obj->where == OBJ_FLOOR &&
137                 (shkp = shop_keeper(inside_shop(obj->ox, obj->oy))) != 0) {
138             if (obj->no_charge) obj->no_charge = 0;
139             /* A billable object won't have its `unpaid' bit set, so would
140                erroneously seem to be a candidate to merge with a similar
141                ordinary object.  That's no good, because once it's really
142                picked up, it won't merge after all.  It might merge with
143                another unpaid object, but we can't check that here (depends
144                too much upon shk's bill) and if it doesn't merge it would
145                end up in the '#' overflow inventory slot, so reject it now. */
146             else if (inhishop(shkp)) return (struct obj *)0;
147         }
148         while (objlist) {
149             if (mergable(objlist, obj)) break;
150             objlist = objlist->nobj;
151         }
152         obj->no_charge = save_nocharge;
153         return objlist;
154 }
155
156 /* merge obj with otmp and delete obj if types agree */
157 int
158 merged(potmp, pobj)
159 struct obj **potmp, **pobj;
160 {
161         register struct obj *otmp = *potmp, *obj = *pobj;
162
163         if(mergable(otmp, obj)) {
164                 /* Approximate age: we do it this way because if we were to
165                  * do it "accurately" (merge only when ages are identical)
166                  * we'd wind up never merging any corpses.
167                  * otmp->age = otmp->age*(1-proportion) + obj->age*proportion;
168                  *
169                  * Don't do the age manipulation if lit.  We would need
170                  * to stop the burn on both items, then merge the age,
171                  * then restart the burn.
172                  */
173                 if (!obj->lamplit)
174                     otmp->age = ((otmp->age*otmp->quan) + (obj->age*obj->quan))
175                             / (otmp->quan + obj->quan);
176
177                 otmp->quan += obj->quan;
178 #ifdef GOLDOBJ
179                 /* temporary special case for gold objects!!!! */
180 #endif
181                 if (otmp->oclass == COIN_CLASS) otmp->owt = weight(otmp);
182                 else otmp->owt += obj->owt;
183                 if(!otmp->onamelth && obj->onamelth)
184                         otmp = *potmp = oname(otmp, ONAME(obj));
185                 obj_extract_self(obj);
186
187                 /* really should merge the timeouts */
188                 if (obj->lamplit) obj_merge_light_sources(obj, otmp);
189                 if (obj->timed) obj_stop_timers(obj);   /* follows lights */
190
191                 /* fixup for `#adjust' merging wielded darts, daggers, &c */
192                 if (obj->owornmask && carried(otmp)) {
193                     long wmask = otmp->owornmask | obj->owornmask;
194
195                     /* Both the items might be worn in competing slots;
196                        merger preference (regardless of which is which):
197                          primary weapon + alternate weapon -> primary weapon;
198                          primary weapon + quiver -> primary weapon;
199                          alternate weapon + quiver -> alternate weapon.
200                        (Prior to 3.3.0, it was not possible for the two
201                        stacks to be worn in different slots and `obj'
202                        didn't need to be unworn when merging.) */
203                     if (wmask & W_WEP) wmask = W_WEP;
204                     else if (wmask & W_SWAPWEP) wmask = W_SWAPWEP;
205                     else if (wmask & W_QUIVER) wmask = W_QUIVER;
206                     else {
207                         impossible("merging strangely worn items (%lx)", wmask);
208                         wmask = otmp->owornmask;
209                     }
210                     if ((otmp->owornmask & ~wmask) != 0L) setnotworn(otmp);
211                     setworn(otmp, wmask);
212                     setnotworn(obj);
213                 }
214 #if 0
215                 /* (this should not be necessary, since items
216                     already in a monster's inventory don't ever get
217                     merged into other objects [only vice versa]) */
218                 else if (obj->owornmask && mcarried(otmp)) {
219                     if (obj == MON_WEP(otmp->ocarry)) {
220                         MON_WEP(otmp->ocarry) = otmp;
221                         otmp->owornmask = W_WEP;
222                     }
223                 }
224 #endif /*0*/
225
226                 obfree(obj,otmp);       /* free(obj), bill->otmp */
227                 return(1);
228         }
229         return 0;
230 }
231
232 /*
233 Adjust hero intrinsics as if this object was being added to the hero's
234 inventory.  Called _before_ the object has been added to the hero's
235 inventory.
236
237 This is called when adding objects to the hero's inventory normally (via
238 addinv) or when an object in the hero's inventory has been polymorphed
239 in-place.
240
241 It may be valid to merge this code with with addinv_core2().
242 */
243 void
244 addinv_core1(obj)
245 struct obj *obj;
246 {
247         if (obj->oclass == COIN_CLASS) {
248 #ifndef GOLDOBJ
249                 u.ugold += obj->quan;
250 #else
251                 flags.botl = 1;
252 #endif
253         } else if (obj->otyp == AMULET_OF_YENDOR) {
254                 if (u.uhave.amulet) impossible("already have amulet?");
255                 u.uhave.amulet = 1;
256         } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
257                 if (u.uhave.menorah) impossible("already have candelabrum?");
258                 u.uhave.menorah = 1;
259         } else if (obj->otyp == BELL_OF_OPENING) {
260                 if (u.uhave.bell) impossible("already have silver bell?");
261                 u.uhave.bell = 1;
262         } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
263                 if (u.uhave.book) impossible("already have the book?");
264                 u.uhave.book = 1;
265         } else if (obj->oartifact) {
266                 if (is_quest_artifact(obj)) {
267                     if (u.uhave.questart)
268                         impossible("already have quest artifact?");
269                     u.uhave.questart = 1;
270                     artitouch();
271                 }
272                 set_artifact_intrinsic(obj, 1, W_ART);
273         }
274 }
275
276 /*
277 Adjust hero intrinsics as if this object was being added to the hero's
278 inventory.  Called _after_ the object has been added to the hero's
279 inventory.
280
281 This is called when adding objects to the hero's inventory normally (via
282 addinv) or when an object in the hero's inventory has been polymorphed
283 in-place.
284 */
285 void
286 addinv_core2(obj)
287 struct obj *obj;
288 {
289         if (confers_luck(obj)) {
290                 /* new luckstone must be in inventory by this point
291                  * for correct calculation */
292                 set_moreluck();
293         }
294 }
295
296 /*
297 Add obj to the hero's inventory.  Make sure the object is "free".
298 Adjust hero attributes as necessary.
299 */
300 struct obj *
301 addinv(obj)
302 struct obj *obj;
303 {
304         struct obj *otmp, *prev;
305
306         if (obj->where != OBJ_FREE)
307             panic("addinv: obj not free");
308         obj->no_charge = 0;     /* not meaningful for invent */
309
310         addinv_core1(obj);
311 #ifndef GOLDOBJ
312         /* if handed gold, we're done */
313         if (obj->oclass == COIN_CLASS)
314             return obj;
315 #endif
316
317         /* merge if possible; find end of chain in the process */
318         for (prev = 0, otmp = invent; otmp; prev = otmp, otmp = otmp->nobj)
319             if (merged(&otmp, &obj)) {
320                 obj = otmp;
321                 goto added;
322             }
323         /* didn't merge, so insert into chain */
324         if (flags.invlet_constant || !prev) {
325             if (flags.invlet_constant) assigninvlet(obj);
326             obj->nobj = invent;         /* insert at beginning */
327             invent = obj;
328             if (flags.invlet_constant) reorder_invent();
329         } else {
330             prev->nobj = obj;           /* insert at end */
331             obj->nobj = 0;
332         }
333         obj->where = OBJ_INVENT;
334
335 added:
336         addinv_core2(obj);
337         carry_obj_effects(obj);         /* carrying affects the obj */
338         update_inventory();
339         return(obj);
340 }
341
342 /*
343  * Some objects are affected by being carried.
344  * Make those adjustments here. Called _after_ the object
345  * has been added to the hero's or monster's inventory,
346  * and after hero's intrinsics have been updated.
347  */
348 void
349 carry_obj_effects(obj)
350 struct obj *obj;
351 {
352         /* Cursed figurines can spontaneously transform
353            when carried. */
354         if (obj->otyp == FIGURINE) {
355                 if (obj->cursed
356                     && obj->corpsenm != NON_PM
357                     && !dead_species(obj->corpsenm,TRUE)) {
358                         attach_fig_transform_timeout(obj);
359                     }
360         }
361 }
362
363 #endif /* OVL1 */
364 #ifdef OVLB
365
366 /* Add an item to the inventory unless we're fumbling or it refuses to be
367  * held (via touch_artifact), and give a message.
368  * If there aren't any free inventory slots, we'll drop it instead.
369  * If both success and failure messages are NULL, then we're just doing the
370  * fumbling/slot-limit checking for a silent grab.  In any case,
371  * touch_artifact will print its own messages if they are warranted.
372  */
373 struct obj *
374 hold_another_object(obj, drop_fmt, drop_arg, hold_msg)
375 struct obj *obj;
376 const char *drop_fmt, *drop_arg, *hold_msg;
377 {
378         char buf[BUFSZ];
379
380         if (!Blind) obj->dknown = 1;    /* maximize mergibility */
381         if (obj->oartifact) {
382             /* place_object may change these */
383             boolean crysknife = (obj->otyp == CRYSKNIFE);
384             int oerode = obj->oerodeproof;
385             boolean wasUpolyd = Upolyd;
386
387             /* in case touching this object turns out to be fatal */
388             place_object(obj, u.ux, u.uy);
389
390             if (!touch_artifact(obj, &youmonst)) {
391                 obj_extract_self(obj);  /* remove it from the floor */
392                 dropy(obj);             /* now put it back again :-) */
393                 return obj;
394             } else if (wasUpolyd && !Upolyd) {
395                 /* loose your grip if you revert your form */
396                 if (drop_fmt) pline(drop_fmt, drop_arg);
397                 obj_extract_self(obj);
398                 dropy(obj);
399                 return obj;
400             }
401             obj_extract_self(obj);
402             if (crysknife) {
403                 obj->otyp = CRYSKNIFE;
404                 obj->oerodeproof = oerode;
405             }
406         }
407         if (Fumbling) {
408             if (drop_fmt) pline(drop_fmt, drop_arg);
409             dropy(obj);
410         } else {
411             long oquan = obj->quan;
412             int prev_encumbr = near_capacity(); /* before addinv() */
413
414             /* encumbrance only matters if it would now become worse
415                than max( current_value, stressed ) */
416             if (prev_encumbr < MOD_ENCUMBER) prev_encumbr = MOD_ENCUMBER;
417             /* addinv() may redraw the entire inventory, overwriting
418                drop_arg when it comes from something like doname() */
419             if (drop_arg) drop_arg = strcpy(buf, drop_arg);
420
421             obj = addinv(obj);
422             if (inv_cnt() > 52
423                     || ((obj->otyp != LOADSTONE || !obj->cursed)
424                         && near_capacity() > prev_encumbr)) {
425                 if (drop_fmt) pline(drop_fmt, drop_arg);
426                 /* undo any merge which took place */
427                 if (obj->quan > oquan) obj = splitobj(obj, oquan);
428                 dropx(obj);
429             } else {
430                 if (flags.autoquiver && !uquiver && !obj->owornmask &&
431                         (is_missile(obj) ||
432                             ammo_and_launcher(obj, uwep) ||
433                             ammo_and_launcher(obj, uswapwep)))
434                     setuqwep(obj);
435                 if (hold_msg || drop_fmt) prinv(hold_msg, obj, oquan);
436             }
437         }
438         return obj;
439 }
440
441 /* useup() all of an item regardless of its quantity */
442 void
443 useupall(obj)
444 struct obj *obj;
445 {
446         setnotworn(obj);
447         freeinv(obj);
448         obfree(obj, (struct obj *)0);   /* deletes contents also */
449 }
450
451 void
452 useup(obj)
453 register struct obj *obj;
454 {
455         /*  Note:  This works correctly for containers because they */
456         /*         (containers) don't merge.                        */
457         if (obj->quan > 1L) {
458                 obj->in_use = FALSE;    /* no longer in use */
459                 obj->quan--;
460                 obj->owt = weight(obj);
461                 update_inventory();
462         } else {
463                 useupall(obj);
464         }
465 }
466
467 /* use one charge from an item and possibly incur shop debt for it */
468 void
469 consume_obj_charge(obj, maybe_unpaid)
470 struct obj *obj;
471 boolean maybe_unpaid;   /* false if caller handles shop billing */
472 {
473         if (maybe_unpaid) check_unpaid(obj);
474         obj->spe -= 1;
475         if (obj->known) update_inventory();
476 }
477
478 #endif /* OVLB */
479 #ifdef OVL3
480
481 /*
482 Adjust hero's attributes as if this object was being removed from the
483 hero's inventory.  This should only be called from freeinv() and
484 where we are polymorphing an object already in the hero's inventory.
485
486 Should think of a better name...
487 */
488 void
489 freeinv_core(obj)
490 struct obj *obj;
491 {
492         if (obj->oclass == COIN_CLASS) {
493 #ifndef GOLDOBJ
494                 u.ugold -= obj->quan;
495                 obj->in_use = FALSE;
496 #endif
497                 flags.botl = 1;
498                 return;
499         } else if (obj->otyp == AMULET_OF_YENDOR) {
500                 if (!u.uhave.amulet) impossible("don't have amulet?");
501                 u.uhave.amulet = 0;
502         } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
503                 if (!u.uhave.menorah) impossible("don't have candelabrum?");
504                 u.uhave.menorah = 0;
505         } else if (obj->otyp == BELL_OF_OPENING) {
506                 if (!u.uhave.bell) impossible("don't have silver bell?");
507                 u.uhave.bell = 0;
508         } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
509                 if (!u.uhave.book) impossible("don't have the book?");
510                 u.uhave.book = 0;
511         } else if (obj->oartifact) {
512                 if (is_quest_artifact(obj)) {
513                     if (!u.uhave.questart)
514                         impossible("don't have quest artifact?");
515                     u.uhave.questart = 0;
516                 }
517                 set_artifact_intrinsic(obj, 0, W_ART);
518         }
519
520         if (obj->otyp == LOADSTONE) {
521                 curse(obj);
522         } else if (confers_luck(obj)) {
523                 set_moreluck();
524                 flags.botl = 1;
525         } else if (obj->otyp == FIGURINE && obj->timed) {
526                 (void) stop_timer(FIG_TRANSFORM, (genericptr_t) obj);
527         }
528 }
529
530 /* remove an object from the hero's inventory */
531 void
532 freeinv(obj)
533 register struct obj *obj;
534 {
535         extract_nobj(obj, &invent);
536         freeinv_core(obj);
537         update_inventory();
538 }
539
540 void
541 delallobj(x, y)
542 int x, y;
543 {
544         struct obj *otmp, *otmp2;
545
546         for (otmp = level.objects[x][y]; otmp; otmp = otmp2) {
547                 if (otmp == uball)
548                         unpunish();
549                 /* after unpunish(), or might get deallocated chain */
550                 otmp2 = otmp->nexthere;
551                 if (otmp == uchain)
552                         continue;
553                 delobj(otmp);
554         }
555 }
556
557 #endif /* OVL3 */
558 #ifdef OVL2
559
560 /* destroy object in fobj chain (if unpaid, it remains on the bill) */
561 void
562 delobj(obj)
563 register struct obj *obj;
564 {
565         boolean update_map;
566
567         if (obj->otyp == AMULET_OF_YENDOR ||
568                         obj->otyp == CANDELABRUM_OF_INVOCATION ||
569                         obj->otyp == BELL_OF_OPENING ||
570                         obj->otyp == SPE_BOOK_OF_THE_DEAD) {
571                 /* player might be doing something stupid, but we
572                  * can't guarantee that.  assume special artifacts
573                  * are indestructible via drawbridges, and exploding
574                  * chests, and golem creation, and ...
575                  */
576                 return;
577         }
578         update_map = (obj->where == OBJ_FLOOR);
579         obj_extract_self(obj);
580         if (update_map) newsym(obj->ox, obj->oy);
581         obfree(obj, (struct obj *) 0);  /* frees contents also */
582 }
583
584 #endif /* OVL2 */
585 #ifdef OVL0
586
587 struct obj *
588 sobj_at(n,x,y)
589 register int n, x, y;
590 {
591         register struct obj *otmp;
592
593         for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
594                 if(otmp->otyp == n)
595                     return(otmp);
596         return((struct obj *)0);
597 }
598
599 #endif /* OVL0 */
600 #ifdef OVLB
601
602 struct obj *
603 carrying(type)
604 register int type;
605 {
606         register struct obj *otmp;
607
608         for(otmp = invent; otmp; otmp = otmp->nobj)
609                 if(otmp->otyp == type)
610                         return(otmp);
611         return((struct obj *) 0);
612 }
613
614 const char *
615 currency(amount)
616 long amount;
617 {
618         if (amount == 1L) return "zorkmid";
619         else return "zorkmids";
620 }
621
622 boolean
623 have_lizard()
624 {
625         register struct obj *otmp;
626
627         for(otmp = invent; otmp; otmp = otmp->nobj)
628                 if(otmp->otyp == CORPSE && otmp->corpsenm == PM_LIZARD)
629                         return(TRUE);
630         return(FALSE);
631 }
632
633 struct obj *
634 o_on(id, objchn)
635 unsigned int id;
636 register struct obj *objchn;
637 {
638         struct obj *temp;
639
640         while(objchn) {
641                 if(objchn->o_id == id) return(objchn);
642                 if (Has_contents(objchn) && (temp = o_on(id,objchn->cobj)))
643                         return temp;
644                 objchn = objchn->nobj;
645         }
646         return((struct obj *) 0);
647 }
648
649 boolean
650 obj_here(obj, x, y)
651 register struct obj *obj;
652 int x, y;
653 {
654         register struct obj *otmp;
655
656         for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
657                 if(obj == otmp) return(TRUE);
658         return(FALSE);
659 }
660
661 #endif /* OVLB */
662 #ifdef OVL2
663
664 struct obj *
665 g_at(x,y)
666 register int x, y;
667 {
668         register struct obj *obj = level.objects[x][y];
669         while(obj) {
670             if (obj->oclass == COIN_CLASS) return obj;
671             obj = obj->nexthere;
672         }
673         return((struct obj *)0);
674 }
675
676 #endif /* OVL2 */
677 #ifdef OVLB
678 #ifndef GOLDOBJ
679 /* Make a gold object from the hero's gold. */
680 struct obj *
681 mkgoldobj(q)
682 register long q;
683 {
684         register struct obj *otmp;
685
686         otmp = mksobj(GOLD_PIECE, FALSE, FALSE);
687         u.ugold -= q;
688         otmp->quan = q;
689         otmp->owt = weight(otmp);
690         flags.botl = 1;
691         return(otmp);
692 }
693 #endif
694 #endif /* OVLB */
695 #ifdef OVL1
696
697 STATIC_OVL void
698 compactify(buf)
699 register char *buf;
700 /* compact a string of inventory letters by dashing runs of letters */
701 {
702         register int i1 = 1, i2 = 1;
703         register char ilet, ilet1, ilet2;
704
705         ilet2 = buf[0];
706         ilet1 = buf[1];
707         buf[++i2] = buf[++i1];
708         ilet = buf[i1];
709         while(ilet) {
710                 if(ilet == ilet1+1) {
711                         if(ilet1 == ilet2+1)
712                                 buf[i2 - 1] = ilet1 = '-';
713                         else if(ilet2 == '-') {
714                                 buf[i2 - 1] = ++ilet1;
715                                 buf[i2] = buf[++i1];
716                                 ilet = buf[i1];
717                                 continue;
718                         }
719                 }
720                 ilet2 = ilet1;
721                 ilet1 = ilet;
722                 buf[++i2] = buf[++i1];
723                 ilet = buf[i1];
724         }
725 }
726
727 /* match the prompt for either 'T' or 'R' command */
728 STATIC_OVL boolean
729 taking_off(action)
730 const char *action;
731 {
732     return !strcmp(action, "take off") || !strcmp(action, "remove");
733 }
734
735 /* match the prompt for either 'W' or 'P' command */
736 STATIC_OVL boolean
737 putting_on(action)
738 const char *action;
739 {
740     return !strcmp(action, "wear") || !strcmp(action, "put on");
741 }
742
743 /*
744  * getobj returns:
745  *      struct obj *xxx:        object to do something with.
746  *      (struct obj *) 0        error return: no object.
747  *      &zeroobj                explicitly no object (as in w-).
748 #ifdef GOLDOBJ
749 !!!! test if gold can be used in unusual ways (eaten etc.)
750 !!!! may be able to remove "usegold"
751 #endif
752  */
753 struct obj *
754 getobj(let,word)
755 register const char *let,*word;
756 {
757         register struct obj *otmp;
758         register char ilet;
759         char buf[BUFSZ], qbuf[QBUFSZ];
760         char lets[BUFSZ], altlets[BUFSZ], *ap;
761         register int foo = 0;
762         register char *bp = buf;
763         xchar allowcnt = 0;     /* 0, 1 or 2 */
764 #ifndef GOLDOBJ
765         boolean allowgold = FALSE;      /* can't use gold because they don't have any */
766 #endif
767         boolean usegold = FALSE;        /* can't use gold because its illegal */
768         boolean allowall = FALSE;
769         boolean allownone = FALSE;
770         boolean useboulder = FALSE;
771         xchar foox = 0;
772         long cnt;
773         boolean prezero = FALSE;
774         long dummymask;
775
776         if(*let == ALLOW_COUNT) let++, allowcnt = 1;
777 #ifndef GOLDOBJ
778         if(*let == COIN_CLASS) let++,
779                 usegold = TRUE, allowgold = (u.ugold ? TRUE : FALSE);
780 #else
781         if(*let == COIN_CLASS) let++, usegold = TRUE;
782 #endif
783
784         /* Equivalent of an "ugly check" for gold */
785         if (usegold && !strcmp(word, "eat") &&
786             (!metallivorous(youmonst.data)
787              || youmonst.data == &mons[PM_RUST_MONSTER]))
788 #ifndef GOLDOBJ
789                 usegold = allowgold = FALSE;
790 #else
791                 usegold = FALSE;
792 #endif
793
794         if(*let == ALL_CLASSES) let++, allowall = TRUE;
795         if(*let == ALLOW_NONE) let++, allownone = TRUE;
796         /* "ugly check" for reading fortune cookies, part 1 */
797         /* The normal 'ugly check' keeps the object on the inventory list.
798          * We don't want to do that for shirts/cookies, so the check for
799          * them is handled a bit differently (and also requires that we set
800          * allowall in the caller)
801          */
802         if(allowall && !strcmp(word, "read")) allowall = FALSE;
803
804         /* another ugly check: show boulders (not statues) */
805         if(*let == WEAPON_CLASS &&
806            !strcmp(word, "throw") && throws_rocks(youmonst.data))
807             useboulder = TRUE;
808
809         if(allownone) *bp++ = '-';
810 #ifndef GOLDOBJ
811         if(allowgold) *bp++ = def_oc_syms[COIN_CLASS];
812 #endif
813         if(bp > buf && bp[-1] == '-') *bp++ = ' ';
814         ap = altlets;
815
816         ilet = 'a';
817         for (otmp = invent; otmp; otmp = otmp->nobj) {
818             if (!flags.invlet_constant)
819 #ifdef GOLDOBJ
820                 if (otmp->invlet != GOLD_SYM) /* don't reassign this */
821 #endif
822                 otmp->invlet = ilet;    /* reassign() */
823             if (!*let || index(let, otmp->oclass)
824 #ifdef GOLDOBJ
825                 || (usegold && otmp->invlet == GOLD_SYM)
826 #endif
827                 || (useboulder && otmp->otyp == BOULDER)
828                 ) {
829                 register int otyp = otmp->otyp;
830                 bp[foo++] = otmp->invlet;
831
832                 /* ugly check: remove inappropriate things */
833                 if ((taking_off(word) &&
834                     (!(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL))
835                      || (otmp==uarm && uarmc)
836 #ifdef TOURIST
837                      || (otmp==uarmu && (uarm || uarmc))
838 #endif
839                     ))
840                 || (putting_on(word) &&
841                      (otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)))
842                                                         /* already worn */
843 #if 0   /* 3.4.1 -- include currently wielded weapon among the choices */
844                 || (!strcmp(word, "wield") &&
845                     (otmp->owornmask & W_WEP))
846 #endif
847                 || (!strcmp(word, "ready") &&
848                     (otmp == uwep || (otmp == uswapwep && u.twoweap)))
849                     ) {
850                         foo--;
851                         foox++;
852                 }
853
854                 /* Second ugly check; unlike the first it won't trigger an
855                  * "else" in "you don't have anything else to ___".
856                  */
857                 else if ((putting_on(word) &&
858                     ((otmp->oclass == FOOD_CLASS && otmp->otyp != MEAT_RING) ||
859                     (otmp->oclass == TOOL_CLASS &&
860                      otyp != BLINDFOLD && otyp != TOWEL && otyp != LENSES)))
861                 || (!strcmp(word, "wield") &&
862                     (otmp->oclass == TOOL_CLASS && !is_weptool(otmp)))
863                 || (!strcmp(word, "eat") && !is_edible(otmp))
864                 || (!strcmp(word, "sacrifice") &&
865                     (otyp != CORPSE &&
866                      otyp != AMULET_OF_YENDOR && otyp != FAKE_AMULET_OF_YENDOR))
867                 || (!strcmp(word, "write with") &&
868                     (otmp->oclass == TOOL_CLASS &&
869                      otyp != MAGIC_MARKER && otyp != TOWEL))
870                 || (!strcmp(word, "tin") &&
871                     (otyp != CORPSE || !tinnable(otmp)))
872                 || (!strcmp(word, "rub") &&
873                     ((otmp->oclass == TOOL_CLASS &&
874                       otyp != OIL_LAMP && otyp != MAGIC_LAMP &&
875                       otyp != BRASS_LANTERN) ||
876                      (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
877                 || (!strncmp(word, "rub on the stone", 16) &&
878                     *let == GEM_CLASS &&        /* using known touchstone */
879                     otmp->dknown && objects[otyp].oc_name_known)
880                 || ((!strcmp(word, "use or apply") ||
881                         !strcmp(word, "untrap with")) &&
882                      /* Picks, axes, pole-weapons, bullwhips */
883                     ((otmp->oclass == WEAPON_CLASS && !is_pick(otmp) &&
884                       !is_axe(otmp) && !is_pole(otmp) && otyp != BULLWHIP) ||
885                      (otmp->oclass == POTION_CLASS &&
886                      /* only applicable potion is oil, and it will only
887                         be offered as a choice when already discovered */
888                      (otyp != POT_OIL || !otmp->dknown ||
889                       !objects[POT_OIL].oc_name_known)) ||
890                      (otmp->oclass == FOOD_CLASS &&
891                       otyp != CREAM_PIE && otyp != EUCALYPTUS_LEAF) ||
892                      (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
893                 || (!strcmp(word, "invoke") &&
894                     (!otmp->oartifact && !objects[otyp].oc_unique &&
895                      (otyp != FAKE_AMULET_OF_YENDOR || otmp->known) &&
896                      otyp != CRYSTAL_BALL &&    /* #invoke synonym for apply */
897                    /* note: presenting the possibility of invoking non-artifact
898                       mirrors and/or lamps is a simply a cruel deception... */
899                      otyp != MIRROR && otyp != MAGIC_LAMP &&
900                      (otyp != OIL_LAMP ||       /* don't list known oil lamp */
901                       (otmp->dknown && objects[OIL_LAMP].oc_name_known))))
902                 || (!strcmp(word, "untrap with") &&
903                     (otmp->oclass == TOOL_CLASS && otyp != CAN_OF_GREASE))
904                 || (!strcmp(word, "charge") && !is_chargeable(otmp))
905                     )
906                         foo--;
907                 /* ugly check for unworn armor that can't be worn */
908                 else if (putting_on(word) && *let == ARMOR_CLASS &&
909                          !canwearobj(otmp, &dummymask, FALSE)) {
910                         foo--;
911                         allowall = TRUE;
912                         *ap++ = otmp->invlet;
913                 }
914             } else {
915
916                 /* "ugly check" for reading fortune cookies, part 2 */
917                 if ((!strcmp(word, "read") &&
918                     (otmp->otyp == FORTUNE_COOKIE
919 #ifdef TOURIST
920                         || otmp->otyp == T_SHIRT
921 #endif
922                     )))
923                         allowall = TRUE;
924             }
925
926             if(ilet == 'z') ilet = 'A'; else ilet++;
927         }
928         bp[foo] = 0;
929         if(foo == 0 && bp > buf && bp[-1] == ' ') *--bp = 0;
930         Strcpy(lets, bp);       /* necessary since we destroy buf */
931         if(foo > 5)                     /* compactify string */
932                 compactify(bp);
933         *ap = '\0';
934
935 #ifndef GOLDOBJ
936         if(!foo && !allowall && !allowgold && !allownone) {
937 #else
938         if(!foo && !allowall && !allownone) {
939 #endif
940                 You("don't have anything %sto %s.",
941                         foox ? "else " : "", word);
942                 return((struct obj *)0);
943         }
944         for(;;) {
945                 cnt = 0;
946                 if (allowcnt == 2) allowcnt = 1;  /* abort previous count */
947                 if(!buf[0]) {
948                         Sprintf(qbuf, "What do you want to %s? [*]", word);
949                 } else {
950                         Sprintf(qbuf, "What do you want to %s? [%s or ?*]",
951                                 word, buf);
952                 }
953 #ifdef REDO
954                 if (in_doagain)
955                     ilet = readchar();
956                 else
957 #endif
958                     ilet = yn_function(qbuf, (char *)0, '\0');
959                 if(ilet == '0') prezero = TRUE;
960                 while(digit(ilet) && allowcnt) {
961 #ifdef REDO
962                         if (ilet != '?' && ilet != '*') savech(ilet);
963 #endif
964                         cnt = 10*cnt + (ilet - '0');
965                         allowcnt = 2;   /* signal presence of cnt */
966                         ilet = readchar();
967                 }
968                 if(digit(ilet)) {
969                         pline("No count allowed with this command.");
970                         continue;
971                 }
972                 if(index(quitchars,ilet)) {
973                     if(flags.verbose)
974                         pline(Never_mind);
975                     return((struct obj *)0);
976                 }
977                 if(ilet == '-') {
978                         return(allownone ? &zeroobj : (struct obj *) 0);
979                 }
980                 if(ilet == def_oc_syms[COIN_CLASS]) {
981                         if (!usegold) {
982                             if (!strncmp(word, "rub on ", 7)) {
983                                 /* the dangers of building sentences... */
984                                 You("cannot rub gold%s.", word + 3);
985                             } else {
986                                 You("cannot %s gold.", word);
987                             }
988                             return(struct obj *)0;
989 #ifndef GOLDOBJ
990                         } else if (!allowgold) {
991                                 You("are not carrying any gold.");
992                                 return(struct obj *)0;
993 #endif
994                         } 
995                         if(cnt == 0 && prezero) return((struct obj *)0);
996                         /* Historic note: early Nethack had a bug which was
997                          * first reported for Larn, where trying to drop 2^32-n
998                          * gold pieces was allowed, and did interesting things
999                          * to your money supply.  The LRS is the tax bureau
1000                          * from Larn.
1001                          */
1002                         if(cnt < 0) {
1003         pline_The("LRS would be very interested to know you have that much.");
1004                                 return(struct obj *)0;
1005                         }
1006
1007 #ifndef GOLDOBJ
1008                         if(!(allowcnt == 2 && cnt < u.ugold))
1009                                 cnt = u.ugold;
1010                         return(mkgoldobj(cnt));
1011 #endif
1012                 }
1013                 if(ilet == '?' || ilet == '*') {
1014                     char *allowed_choices = (ilet == '?') ? lets : (char *)0;
1015                     long ctmp = 0;
1016
1017                     if (ilet == '?' && !*lets && *altlets)
1018                         allowed_choices = altlets;
1019                     ilet = display_pickinv(allowed_choices, TRUE,
1020                                            allowcnt ? &ctmp : (long *)0);
1021                     if(!ilet) continue;
1022                     if (allowcnt && ctmp >= 0) {
1023                         cnt = ctmp;
1024                         if (!cnt) prezero = TRUE;
1025                         allowcnt = 2;
1026                     }
1027                     if(ilet == '\033') {
1028                         if(flags.verbose)
1029                             pline(Never_mind);
1030                         return((struct obj *)0);
1031                     }
1032                     /* they typed a letter (not a space) at the prompt */
1033                 }
1034                 if(allowcnt == 2 && !strcmp(word,"throw")) {
1035                     /* permit counts for throwing gold, but don't accept
1036                      * counts for other things since the throw code will
1037                      * split off a single item anyway */
1038 #ifdef GOLDOBJ
1039                     if (ilet != def_oc_syms[COIN_CLASS])
1040 #endif
1041                         allowcnt = 1;
1042                     if(cnt == 0 && prezero) return((struct obj *)0);
1043                     if(cnt > 1) {
1044                         You("can only throw one item at a time.");
1045                         continue;
1046                     }
1047                 }
1048 #ifdef GOLDOBJ
1049                 flags.botl = 1; /* May have changed the amount of money */
1050 #endif
1051 #ifdef REDO
1052                 savech(ilet);
1053 #endif
1054                 for (otmp = invent; otmp; otmp = otmp->nobj)
1055                         if (otmp->invlet == ilet) break;
1056                 if(!otmp) {
1057                         You("don't have that object.");
1058 #ifdef REDO
1059                         if (in_doagain) return((struct obj *) 0);
1060 #endif
1061                         continue;
1062                 } else if (cnt < 0 || otmp->quan < cnt) {
1063                         You("don't have that many!  You have only %ld.",
1064                             otmp->quan);
1065 #ifdef REDO
1066                         if (in_doagain) return((struct obj *) 0);
1067 #endif
1068                         continue;
1069                 }
1070                 break;
1071         }
1072         if(!allowall && let && !index(let,otmp->oclass)
1073 #ifdef GOLDOBJ
1074            && !(usegold && otmp->oclass == COIN_CLASS)
1075 #endif
1076            ) {
1077                 silly_thing(word, otmp);
1078                 return((struct obj *)0);
1079         }
1080         if(allowcnt == 2) {     /* cnt given */
1081             if(cnt == 0) return (struct obj *)0;
1082             if(cnt != otmp->quan) {
1083                 /* don't split a stack of cursed loadstones */
1084                 if (otmp->otyp == LOADSTONE && otmp->cursed)
1085                     /* kludge for canletgo()'s can't-drop-this message */
1086                     otmp->corpsenm = (int) cnt;
1087                 else
1088                     otmp = splitobj(otmp, cnt);
1089             }
1090         }
1091         return(otmp);
1092 }
1093
1094 void
1095 silly_thing(word, otmp)
1096 const char *word;
1097 struct obj *otmp;
1098 {
1099         const char *s1, *s2, *s3, *what;
1100         int ocls = otmp->oclass, otyp = otmp->otyp;
1101
1102         s1 = s2 = s3 = 0;
1103         /* check for attempted use of accessory commands ('P','R') on armor
1104            and for corresponding armor commands ('W','T') on accessories */
1105         if (ocls == ARMOR_CLASS) {
1106             if (!strcmp(word, "put on"))
1107                 s1 = "W", s2 = "wear", s3 = "";
1108             else if (!strcmp(word, "remove"))
1109                 s1 = "T", s2 = "take", s3 = " off";
1110         } else if ((ocls == RING_CLASS || otyp == MEAT_RING) ||
1111                 ocls == AMULET_CLASS ||
1112                 (otyp == BLINDFOLD || otyp == TOWEL || otyp == LENSES)) {
1113             if (!strcmp(word, "wear"))
1114                 s1 = "P", s2 = "put", s3 = " on";
1115             else if (!strcmp(word, "take off"))
1116                 s1 = "R", s2 = "remove", s3 = "";
1117         }
1118         if (s1) {
1119             what = "that";
1120             /* quantity for armor and accessory objects is always 1,
1121                but some things should be referred to as plural */
1122             if (otyp == LENSES || is_gloves(otmp) || is_boots(otmp))
1123                 what = "those";
1124             pline("Use the '%s' command to %s %s%s.", s1, s2, what, s3);
1125         } else {
1126             pline(silly_thing_to, word);
1127         }
1128 }
1129
1130 #endif /* OVL1 */
1131 #ifdef OVLB
1132
1133 STATIC_PTR int
1134 ckvalidcat(otmp)
1135 register struct obj *otmp;
1136 {
1137         /* use allow_category() from pickup.c */
1138         return((int)allow_category(otmp));
1139 }
1140
1141 STATIC_PTR int
1142 ckunpaid(otmp)
1143 register struct obj *otmp;
1144 {
1145         return((int)(otmp->unpaid));
1146 }
1147
1148 boolean
1149 wearing_armor()
1150 {
1151         return((boolean)(uarm || uarmc || uarmf || uarmg || uarmh || uarms
1152 #ifdef TOURIST
1153                 || uarmu
1154 #endif
1155                 ));
1156 }
1157
1158 boolean
1159 is_worn(otmp)
1160 register struct obj *otmp;
1161 {
1162     return((boolean)(!!(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL |
1163 #ifdef STEED
1164                         W_SADDLE |
1165 #endif
1166                         W_WEP | W_SWAPWEP | W_QUIVER))));
1167 }
1168
1169 static NEARDATA const char removeables[] =
1170         { ARMOR_CLASS, WEAPON_CLASS, RING_CLASS, AMULET_CLASS, TOOL_CLASS, 0 };
1171
1172 /* interactive version of getobj - used for Drop, Identify and */
1173 /* Takeoff (A). Return the number of times fn was called successfully */
1174 /* If combo is TRUE, we just use this to get a category list */
1175 int
1176 ggetobj(word, fn, mx, combo, resultflags)
1177 const char *word;
1178 int FDECL((*fn),(OBJ_P)), mx;
1179 boolean combo;          /* combination menu flag */
1180 unsigned *resultflags;
1181 {
1182         int FDECL((*ckfn),(OBJ_P)) = (int FDECL((*),(OBJ_P))) 0;
1183         boolean FDECL((*filter),(OBJ_P)) = (boolean FDECL((*),(OBJ_P))) 0;
1184         boolean takeoff, ident, allflag, m_seen;
1185         int itemcount;
1186 #ifndef GOLDOBJ
1187         int oletct, iletct, allowgold, unpaid, oc_of_sym;
1188 #else
1189         int oletct, iletct, unpaid, oc_of_sym;
1190 #endif
1191         char sym, *ip, olets[MAXOCLASSES+5], ilets[MAXOCLASSES+5];
1192         char extra_removeables[3+1];    /* uwep,uswapwep,uquiver */
1193         char buf[BUFSZ], qbuf[QBUFSZ];
1194
1195         if (resultflags) *resultflags = 0;
1196 #ifndef GOLDOBJ
1197         allowgold = (u.ugold && !strcmp(word, "drop")) ? 1 : 0;
1198 #endif
1199         takeoff = ident = allflag = m_seen = FALSE;
1200 #ifndef GOLDOBJ
1201         if(!invent && !allowgold){
1202 #else
1203         if(!invent){
1204 #endif
1205                 You("have nothing to %s.", word);
1206                 return(0);
1207         }
1208         add_valid_menu_class(0);        /* reset */
1209         if (taking_off(word)) {
1210             takeoff = TRUE;
1211             filter = is_worn;
1212         } else if (!strcmp(word, "identify")) {
1213             ident = TRUE;
1214             filter = not_fully_identified;
1215         }
1216
1217         iletct = collect_obj_classes(ilets, invent,
1218                                         FALSE,
1219 #ifndef GOLDOBJ
1220                                         (allowgold != 0),
1221 #endif
1222                                         filter, &itemcount);
1223         unpaid = count_unpaid(invent);
1224
1225         if (ident && !iletct) {
1226             return -1;          /* no further identifications */
1227         } else if (!takeoff && (unpaid || invent)) {
1228             ilets[iletct++] = ' ';
1229             if (unpaid) ilets[iletct++] = 'u';
1230             if (count_buc(invent, BUC_BLESSED))  ilets[iletct++] = 'B';
1231             if (count_buc(invent, BUC_UNCURSED)) ilets[iletct++] = 'U';
1232             if (count_buc(invent, BUC_CURSED))   ilets[iletct++] = 'C';
1233             if (count_buc(invent, BUC_UNKNOWN))  ilets[iletct++] = 'X';
1234             if (invent) ilets[iletct++] = 'a';
1235         } else if (takeoff && invent) {
1236             ilets[iletct++] = ' ';
1237         }
1238         ilets[iletct++] = 'i';
1239         if (!combo)
1240             ilets[iletct++] = 'm';      /* allow menu presentation on request */
1241         ilets[iletct] = '\0';
1242
1243         for (;;) {
1244             Sprintf(qbuf,"What kinds of thing do you want to %s? [%s]",
1245                     word, ilets);
1246             getlin(qbuf, buf);
1247             if (buf[0] == '\033') return(0);
1248             if (index(buf, 'i')) {
1249                 if (display_inventory((char *)0, TRUE) == '\033') return 0;
1250             } else
1251                 break;
1252         }
1253
1254         extra_removeables[0] = '\0';
1255         if (takeoff) {
1256             /* arbitrary types of items can be placed in the weapon slots
1257                [any duplicate entries in extra_removeables[] won't matter] */
1258             if (uwep) (void)strkitten(extra_removeables, uwep->oclass);
1259             if (uswapwep) (void)strkitten(extra_removeables, uswapwep->oclass);
1260             if (uquiver) (void)strkitten(extra_removeables, uquiver->oclass);
1261         }
1262
1263         ip = buf;
1264         olets[oletct = 0] = '\0';
1265         while ((sym = *ip++) != '\0') {
1266             if (sym == ' ') continue;
1267             oc_of_sym = def_char_to_objclass(sym);
1268             if (takeoff && oc_of_sym != MAXOCLASSES) {
1269                 if (index(extra_removeables, oc_of_sym)) {
1270                     ;   /* skip rest of takeoff checks */
1271                 } else if (!index(removeables, oc_of_sym)) {
1272                     pline("Not applicable.");
1273                     return 0;
1274                 } else if (oc_of_sym == ARMOR_CLASS && !wearing_armor()) {
1275                     You("are not wearing any armor.");
1276                     return 0;
1277                 } else if (oc_of_sym == WEAPON_CLASS &&
1278                         !uwep && !uswapwep && !uquiver) {
1279                     You("are not wielding anything.");
1280                     return 0;
1281                 } else if (oc_of_sym == RING_CLASS && !uright && !uleft) {
1282                     You("are not wearing rings.");
1283                     return 0;
1284                 } else if (oc_of_sym == AMULET_CLASS && !uamul) {
1285                     You("are not wearing an amulet.");
1286                     return 0;
1287                 } else if (oc_of_sym == TOOL_CLASS && !ublindf) {
1288                     You("are not wearing a blindfold.");
1289                     return 0;
1290                 }
1291             }
1292
1293             if (oc_of_sym == COIN_CLASS && !combo) {
1294 #ifndef GOLDOBJ
1295                 if (allowgold == 1)
1296                     (*fn)(mkgoldobj(u.ugold));
1297                 else if (!u.ugold)
1298                     You("have no gold.");
1299                 allowgold = 2;
1300 #else
1301                 flags.botl = 1;
1302 #endif
1303             } else if (sym == 'a') {
1304                 allflag = TRUE;
1305             } else if (sym == 'A') {
1306                 /* same as the default */ ;
1307             } else if (sym == 'u') {
1308                 add_valid_menu_class('u');
1309                 ckfn = ckunpaid;
1310             } else if (sym == 'B') {
1311                 add_valid_menu_class('B');
1312                 ckfn = ckvalidcat;
1313             } else if (sym == 'U') {
1314                 add_valid_menu_class('U');
1315                 ckfn = ckvalidcat;
1316             } else if (sym == 'C') {
1317                 add_valid_menu_class('C');
1318                 ckfn = ckvalidcat;
1319             } else if (sym == 'X') {
1320                 add_valid_menu_class('X');
1321                 ckfn = ckvalidcat;
1322             } else if (sym == 'm') {
1323                 m_seen = TRUE;
1324             } else if (oc_of_sym == MAXOCLASSES) {
1325                 You("don't have any %c's.", sym);
1326             } else if (oc_of_sym != VENOM_CLASS) {      /* suppress venom */
1327                 if (!index(olets, oc_of_sym)) {
1328                     add_valid_menu_class(oc_of_sym);
1329                     olets[oletct++] = oc_of_sym;
1330                     olets[oletct] = 0;
1331                 }
1332             }
1333         }
1334
1335         if (m_seen)
1336             return (allflag || (!oletct && ckfn != ckunpaid)) ? -2 : -3;
1337         else if (flags.menu_style != MENU_TRADITIONAL && combo && !allflag)
1338             return 0;
1339 #ifndef GOLDOBJ
1340         else if (allowgold == 2 && !oletct)
1341             return 1;   /* you dropped gold (or at least tried to) */
1342         else {
1343 #else
1344         else /*!!!! if (allowgold == 2 && !oletct)
1345             !!!! return 1;       you dropped gold (or at least tried to) 
1346             !!!! test gold dropping
1347         else*/ {
1348 #endif
1349             int cnt = askchain(&invent, olets, allflag, fn, ckfn, mx, word); 
1350             /*
1351              * askchain() has already finished the job in this case
1352              * so set a special flag to convey that back to the caller
1353              * so that it won't continue processing.
1354              * Fix for bug C331-1 reported by Irina Rempt-Drijfhout. 
1355              */
1356             if (combo && allflag && resultflags)
1357                 *resultflags |= ALL_FINISHED; 
1358             return cnt;
1359         }
1360 }
1361
1362 /*
1363  * Walk through the chain starting at objchn and ask for all objects
1364  * with olet in olets (if nonNULL) and satisfying ckfn (if nonnull)
1365  * whether the action in question (i.e., fn) has to be performed.
1366  * If allflag then no questions are asked. Max gives the max nr of
1367  * objects to be treated. Return the number of objects treated.
1368  */
1369 int
1370 askchain(objchn, olets, allflag, fn, ckfn, mx, word)
1371 struct obj **objchn;
1372 register int allflag, mx;
1373 register const char *olets, *word;      /* olets is an Obj Class char array */
1374 register int FDECL((*fn),(OBJ_P)), FDECL((*ckfn),(OBJ_P));
1375 {
1376         struct obj *otmp, *otmp2, *otmpo;
1377         register char sym, ilet;
1378         register int cnt = 0, dud = 0, tmp;
1379         boolean takeoff, nodot, ident, ininv;
1380         char qbuf[QBUFSZ];
1381
1382         takeoff = taking_off(word);
1383         ident = !strcmp(word, "identify");
1384         nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") ||
1385                  ident || takeoff);
1386         ininv = (*objchn == invent);
1387         /* Changed so the askchain is interrogated in the order specified.
1388          * For example, if a person specifies =/ then first all rings will be
1389          * asked about followed by all wands -dgk
1390          */
1391 nextclass:
1392         ilet = 'a'-1;
1393         if (*objchn && (*objchn)->oclass == COIN_CLASS)
1394                 ilet--;         /* extra iteration */
1395         for (otmp = *objchn; otmp; otmp = otmp2) {
1396                 if(ilet == 'z') ilet = 'A'; else ilet++;
1397                 otmp2 = otmp->nobj;
1398                 if (olets && *olets && otmp->oclass != *olets) continue;
1399                 if (takeoff && !is_worn(otmp)) continue;
1400                 if (ident && !not_fully_identified(otmp)) continue;
1401                 if (ckfn && !(*ckfn)(otmp)) continue;
1402                 if (!allflag) {
1403                         Strcpy(qbuf, !ininv ? doname(otmp) :
1404                                 xprname(otmp, (char *)0, ilet, !nodot, 0L, 0L));
1405                         Strcat(qbuf, "?");
1406                         sym = (takeoff || ident || otmp->quan < 2L) ?
1407                                 nyaq(qbuf) : nyNaq(qbuf);
1408                 }
1409                 else    sym = 'y';
1410
1411                 otmpo = otmp;
1412                 if (sym == '#') {
1413                  /* Number was entered; split the object unless it corresponds
1414                     to 'none' or 'all'.  2 special cases: cursed loadstones and
1415                     welded weapons (eg, multiple daggers) will remain as merged
1416                     unit; done to avoid splitting an object that won't be
1417                     droppable (even if we're picking up rather than dropping).
1418                   */
1419                     if (!yn_number)
1420                         sym = 'n';
1421                     else {
1422                         sym = 'y';
1423                         if (yn_number < otmp->quan && !welded(otmp) &&
1424                             (!otmp->cursed || otmp->otyp != LOADSTONE)) {
1425                             otmp = splitobj(otmp, yn_number);
1426                         }
1427                     }
1428                 }
1429                 switch(sym){
1430                 case 'a':
1431                         allflag = 1;
1432                 case 'y':
1433                         tmp = (*fn)(otmp);
1434                         if(tmp < 0) {
1435                             if (otmp != otmpo) {
1436                                 /* split occurred, merge again */
1437                                 (void) merged(&otmpo, &otmp);
1438                             }
1439                             goto ret;
1440                         }
1441                         cnt += tmp;
1442                         if(--mx == 0) goto ret;
1443                 case 'n':
1444                         if(nodot) dud++;
1445                 default:
1446                         break;
1447                 case 'q':
1448                         /* special case for seffects() */
1449                         if (ident) cnt = -1;
1450                         goto ret;
1451                 }
1452         }
1453         if (olets && *olets && *++olets)
1454                 goto nextclass;
1455         if(!takeoff && (dud || cnt)) pline("That was all.");
1456         else if(!dud && !cnt) pline("No applicable objects.");
1457 ret:
1458         return(cnt);
1459 }
1460
1461
1462 /*
1463  *      Object identification routines:
1464  */
1465
1466 /* make an object actually be identified; no display updating */
1467 void
1468 fully_identify_obj(otmp)
1469 struct obj *otmp;
1470 {
1471     makeknown(otmp->otyp);
1472     if (otmp->oartifact) discover_artifact((xchar)otmp->oartifact);
1473     otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1;
1474     if (otmp->otyp == EGG && otmp->corpsenm != NON_PM)
1475         learn_egg_type(otmp->corpsenm);
1476 }
1477
1478 /* ggetobj callback routine; identify an object and give immediate feedback */
1479 int
1480 identify(otmp)
1481 struct obj *otmp;
1482 {
1483     fully_identify_obj(otmp);
1484     prinv((char *)0, otmp, 0L);
1485     return 1;
1486 }
1487
1488 /* menu of unidentified objects; select and identify up to id_limit of them */
1489 STATIC_OVL void
1490 menu_identify(id_limit)
1491 int id_limit;
1492 {
1493     menu_item *pick_list;
1494     int n, i, first = 1;
1495     char buf[BUFSZ];
1496     /* assumptions:  id_limit > 0 and at least one unID'd item is present */
1497
1498     while (id_limit) {
1499         Sprintf(buf, "What would you like to identify %s?",
1500                 first ? "first" : "next");
1501         n = query_objlist(buf, invent, SIGNAL_NOMENU|USE_INVLET|INVORDER_SORT,
1502                 &pick_list, PICK_ANY, not_fully_identified);
1503
1504         if (n > 0) {
1505             if (n > id_limit) n = id_limit;
1506             for (i = 0; i < n; i++, id_limit--)
1507                 (void) identify(pick_list[i].item.a_obj);
1508             free((genericptr_t) pick_list);
1509             mark_synch(); /* Before we loop to pop open another menu */
1510         } else {
1511             if (n < 0) pline("That was all.");
1512             id_limit = 0; /* Stop now */
1513         }
1514         first = 0;
1515     }
1516 }
1517
1518 /* dialog with user to identify a given number of items; 0 means all */
1519 void
1520 identify_pack(id_limit)
1521 int id_limit;
1522 {
1523     struct obj *obj, *the_obj;
1524     int n, unid_cnt;
1525
1526     unid_cnt = 0;
1527     the_obj = 0;                /* if unid_cnt ends up 1, this will be it */
1528     for (obj = invent; obj; obj = obj->nobj)
1529         if (not_fully_identified(obj)) ++unid_cnt, the_obj = obj;
1530
1531     if (!unid_cnt) {
1532         You("have already identified all of your possessions.");
1533     } else if (!id_limit) {
1534         /* identify everything */
1535         if (unid_cnt == 1) {
1536             (void) identify(the_obj);
1537         } else {
1538
1539             /* TODO:  use fully_identify_obj and cornline/menu/whatever here */
1540             for (obj = invent; obj; obj = obj->nobj)
1541                 if (not_fully_identified(obj)) (void) identify(obj);
1542
1543         }
1544     } else {
1545         /* identify up to `id_limit' items */
1546         n = 0;
1547         if (flags.menu_style == MENU_TRADITIONAL)
1548             do {
1549                 n = ggetobj("identify", identify, id_limit, FALSE, (unsigned *)0);
1550                 if (n < 0) break; /* quit or no eligible items */
1551             } while ((id_limit -= n) > 0);
1552         if (n == 0 || n < -1)
1553             menu_identify(id_limit);
1554     }
1555     update_inventory();
1556 }
1557
1558 #endif /* OVLB */
1559 #ifdef OVL2
1560
1561 STATIC_OVL char
1562 obj_to_let(obj) /* should of course only be called for things in invent */
1563 register struct obj *obj;
1564 {
1565 #ifndef GOLDOBJ
1566         if (obj->oclass == COIN_CLASS)
1567                 return GOLD_SYM;
1568 #endif
1569         if (!flags.invlet_constant) {
1570                 obj->invlet = NOINVSYM;
1571                 reassign();
1572         }
1573         return obj->invlet;
1574 }
1575
1576 /*
1577  * Print the indicated quantity of the given object.  If quan == 0L then use
1578  * the current quantity.
1579  */
1580 void
1581 prinv(prefix, obj, quan)
1582 const char *prefix;
1583 register struct obj *obj;
1584 long quan;
1585 {
1586         if (!prefix) prefix = "";
1587         pline("%s%s%s",
1588               prefix, *prefix ? " " : "",
1589               xprname(obj, (char *)0, obj_to_let(obj), TRUE, 0L, quan));
1590 }
1591
1592 #endif /* OVL2 */
1593 #ifdef OVL1
1594
1595 char *
1596 xprname(obj, txt, let, dot, cost, quan)
1597 struct obj *obj;
1598 const char *txt;        /* text to print instead of obj */
1599 char let;               /* inventory letter */
1600 boolean dot;            /* append period; (dot && cost => Iu) */
1601 long cost;              /* cost (for inventory of unpaid or expended items) */
1602 long quan;              /* if non-0, print this quantity, not obj->quan */
1603 {
1604 #ifdef LINT     /* handle static char li[BUFSZ]; */
1605     char li[BUFSZ];
1606 #else
1607     static char li[BUFSZ];
1608 #endif
1609     boolean use_invlet = flags.invlet_constant && let != CONTAINED_SYM;
1610     long savequan = 0;
1611
1612     if (quan && obj) {
1613         savequan = obj->quan;
1614         obj->quan = quan;
1615     }
1616
1617     /*
1618      * If let is:
1619      *  *  Then obj == null and we are printing a total amount.
1620      *  >  Then the object is contained and doesn't have an inventory letter.
1621      */
1622     if (cost != 0 || let == '*') {
1623         /* if dot is true, we're doing Iu, otherwise Ix */
1624         Sprintf(li, "%c - %-45s %6ld %s",
1625                 (dot && use_invlet ? obj->invlet : let),
1626                 (txt ? txt : doname(obj)), cost, currency(cost));
1627 #ifndef GOLDOBJ
1628     } else if (obj && obj->oclass == COIN_CLASS) {
1629         Sprintf(li, "%ld gold piece%s%s", obj->quan, plur(obj->quan),
1630                 (dot ? "." : ""));
1631 #endif
1632     } else {
1633         /* ordinary inventory display or pickup message */
1634         Sprintf(li, "%c - %s%s",
1635                 (use_invlet ? obj->invlet : let),
1636                 (txt ? txt : doname(obj)), (dot ? "." : ""));
1637     }
1638     if (savequan) obj->quan = savequan;
1639
1640     return li;
1641 }
1642
1643 #endif /* OVL1 */
1644 #ifdef OVLB
1645
1646 /* the 'i' command */
1647 int
1648 ddoinv()
1649 {
1650         (void) display_inventory((char *)0, FALSE);
1651         return 0;
1652 }
1653
1654 /*
1655  * find_unpaid()
1656  *
1657  * Scan the given list of objects.  If last_found is NULL, return the first
1658  * unpaid object found.  If last_found is not NULL, then skip over unpaid
1659  * objects until last_found is reached, then set last_found to NULL so the
1660  * next unpaid object is returned.  This routine recursively follows
1661  * containers.
1662  */
1663 STATIC_OVL struct obj *
1664 find_unpaid(list, last_found)
1665     struct obj *list, **last_found;
1666 {
1667     struct obj *obj;
1668
1669     while (list) {
1670         if (list->unpaid) {
1671             if (*last_found) {
1672                 /* still looking for previous unpaid object */
1673                 if (list == *last_found)
1674                     *last_found = (struct obj *) 0;
1675             } else
1676                 return (*last_found = list);
1677         }
1678         if (Has_contents(list)) {
1679             if ((obj = find_unpaid(list->cobj, last_found)) != 0)
1680                 return obj;
1681         }
1682         list = list->nobj;
1683     }
1684     return (struct obj *) 0;
1685 }
1686
1687 /*
1688  * Internal function used by display_inventory and getobj that can display
1689  * inventory and return a count as well as a letter. If out_cnt is not null,
1690  * any count returned from the menu selection is placed here.
1691  */
1692 static char
1693 display_pickinv(lets, want_reply, out_cnt)
1694 register const char *lets;
1695 boolean want_reply;
1696 long* out_cnt;
1697 {
1698         struct obj *otmp;
1699         char ilet, ret;
1700         char *invlet = flags.inv_order;
1701         int n, classcount;
1702         winid win;                              /* windows being used */
1703         static winid local_win = WIN_ERR;       /* window for partial menus */
1704         anything any;
1705         menu_item *selected;
1706
1707         /* overriden by global flag */
1708         if (flags.perm_invent) {
1709             win = (lets && *lets) ? local_win : WIN_INVEN;
1710             /* create the first time used */
1711             if (win == WIN_ERR)
1712                 win = local_win = create_nhwindow(NHW_MENU);
1713         } else
1714             win = WIN_INVEN;
1715
1716         /*
1717         Exit early if no inventory -- but keep going if we are doing
1718         a permanent inventory update.  We need to keep going so the
1719         permanent inventory window updates itself to remove the last
1720         item(s) dropped.  One down side:  the addition of the exception
1721         for permanent inventory window updates _can_ pop the window
1722         up when it's not displayed -- even if it's empty -- because we
1723         don't know at this level if its up or not.  This may not be
1724         an issue if empty checks are done before hand and the call
1725         to here is short circuited away.
1726         */
1727         if (!invent && !(flags.perm_invent && !lets && !want_reply)) {
1728 #ifndef GOLDOBJ
1729             pline("Not carrying anything%s.", u.ugold ? " except gold" : "");
1730 #else
1731             pline("Not carrying anything.");
1732 #endif
1733             return 0;
1734         }
1735
1736         /* oxymoron? temporarily assign permanent inventory letters */
1737         if (!flags.invlet_constant) reassign();
1738
1739         if (lets && strlen(lets) == 1) {
1740             /* when only one item of interest, use pline instead of menus;
1741                we actually use a fake message-line menu in order to allow
1742                the user to perform selection at the --More-- prompt for tty */
1743             ret = '\0';
1744             for (otmp = invent; otmp; otmp = otmp->nobj) {
1745                 if (otmp->invlet == lets[0]) {
1746                     ret = message_menu(lets[0],
1747                           want_reply ? PICK_ONE : PICK_NONE,
1748                           xprname(otmp, (char *)0, lets[0], TRUE, 0L, 0L));
1749                     if (out_cnt) *out_cnt = -1L;        /* select all */
1750                     break;
1751                 }
1752             }
1753             return ret;
1754         }
1755
1756         start_menu(win);
1757 nextclass:
1758         classcount = 0;
1759         any.a_void = 0;         /* set all bits to zero */
1760         for(otmp = invent; otmp; otmp = otmp->nobj) {
1761                 ilet = otmp->invlet;
1762                 if(!lets || !*lets || index(lets, ilet)) {
1763                         if (!flags.sortpack || otmp->oclass == *invlet) {
1764                             if (flags.sortpack && !classcount) {
1765                                 any.a_void = 0;         /* zero */
1766                                 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
1767                                     let_to_name(*invlet, FALSE), MENU_UNSELECTED);
1768                                 classcount++;
1769                             }
1770                             any.a_char = ilet;
1771                             add_menu(win, obj_to_glyph(otmp),
1772                                         &any, ilet, 0, ATR_NONE, doname(otmp),
1773                                         MENU_UNSELECTED);
1774                         }
1775                 }
1776         }
1777         if (flags.sortpack) {
1778                 if (*++invlet) goto nextclass;
1779 #ifdef WIZARD
1780                 if (--invlet != venom_inv) {
1781                         invlet = venom_inv;
1782                         goto nextclass;
1783                 }
1784 #endif
1785         }
1786         end_menu(win, (char *) 0);
1787
1788         n = select_menu(win, want_reply ? PICK_ONE : PICK_NONE, &selected);
1789         if (n > 0) {
1790             ret = selected[0].item.a_char;
1791             if (out_cnt) *out_cnt = selected[0].count;
1792             free((genericptr_t)selected);
1793         } else
1794             ret = !n ? '\0' : '\033';   /* cancelled */
1795
1796         return ret;
1797 }
1798
1799 /*
1800  * If lets == NULL or "", list all objects in the inventory.  Otherwise,
1801  * list all objects with object classes that match the order in lets.
1802  *
1803  * Returns the letter identifier of a selected item, or 0 if nothing
1804  * was selected.
1805  */
1806 char
1807 display_inventory(lets, want_reply)
1808 register const char *lets;
1809 boolean want_reply;
1810 {
1811         return display_pickinv(lets, want_reply, (long *)0);
1812 }
1813
1814 /*
1815  * Returns the number of unpaid items within the given list.  This includes
1816  * contained objects.
1817  */
1818 int
1819 count_unpaid(list)
1820     struct obj *list;
1821 {
1822     int count = 0;
1823
1824     while (list) {
1825         if (list->unpaid) count++;
1826         if (Has_contents(list))
1827             count += count_unpaid(list->cobj);
1828         list = list->nobj;
1829     }
1830     return count;
1831 }
1832
1833 /*
1834  * Returns the number of items with b/u/c/unknown within the given list.  
1835  * This does NOT include contained objects.
1836  */
1837 int
1838 count_buc(list, type)
1839     struct obj *list;
1840     int type;
1841 {
1842     int count = 0;
1843
1844     while (list) {
1845         if (Role_if(PM_PRIEST)) list->bknown = TRUE;
1846         switch(type) {
1847             case BUC_BLESSED:
1848                 if (list->oclass != COIN_CLASS && list->bknown && list->blessed)
1849                     count++;
1850                 break;
1851             case BUC_CURSED:
1852                 if (list->oclass != COIN_CLASS && list->bknown && list->cursed)
1853                     count++;
1854                 break;
1855             case BUC_UNCURSED:
1856                 if (list->oclass != COIN_CLASS &&
1857                         list->bknown && !list->blessed && !list->cursed)
1858                     count++;
1859                 break;
1860             case BUC_UNKNOWN:
1861                 if (list->oclass != COIN_CLASS && !list->bknown)
1862                     count++;
1863                 break;
1864             default:
1865                 impossible("need count of curse status %d?", type);
1866                 return 0;
1867         }
1868         list = list->nobj;
1869     }
1870     return count;
1871 }
1872
1873 STATIC_OVL void
1874 dounpaid()
1875 {
1876     winid win;
1877     struct obj *otmp, *marker;
1878     register char ilet;
1879     char *invlet = flags.inv_order;
1880     int classcount, count, num_so_far;
1881     int save_unpaid = 0;        /* lint init */
1882     long cost, totcost;
1883
1884     count = count_unpaid(invent);
1885
1886     if (count == 1) {
1887         marker = (struct obj *) 0;
1888         otmp = find_unpaid(invent, &marker);
1889
1890         /* see if the unpaid item is in the top level inventory */
1891         for (marker = invent; marker; marker = marker->nobj)
1892             if (marker == otmp) break;
1893
1894         pline("%s", xprname(otmp, distant_name(otmp, doname),
1895                             marker ? otmp->invlet : CONTAINED_SYM,
1896                             TRUE, unpaid_cost(otmp), 0L));
1897         return;
1898     }
1899
1900     win = create_nhwindow(NHW_MENU);
1901     cost = totcost = 0;
1902     num_so_far = 0;     /* count of # printed so far */
1903     if (!flags.invlet_constant) reassign();
1904
1905     do {
1906         classcount = 0;
1907         for (otmp = invent; otmp; otmp = otmp->nobj) {
1908             ilet = otmp->invlet;
1909             if (otmp->unpaid) {
1910                 if (!flags.sortpack || otmp->oclass == *invlet) {
1911                     if (flags.sortpack && !classcount) {
1912                         putstr(win, 0, let_to_name(*invlet, TRUE));
1913                         classcount++;
1914                     }
1915
1916                     totcost += cost = unpaid_cost(otmp);
1917                     /* suppress "(unpaid)" suffix */
1918                     save_unpaid = otmp->unpaid;
1919                     otmp->unpaid = 0;
1920                     putstr(win, 0, xprname(otmp, distant_name(otmp, doname),
1921                                            ilet, TRUE, cost, 0L));
1922                     otmp->unpaid = save_unpaid;
1923                     num_so_far++;
1924                 }
1925             }
1926         }
1927     } while (flags.sortpack && (*++invlet));
1928
1929     if (count > num_so_far) {
1930         /* something unpaid is contained */
1931         if (flags.sortpack)
1932             putstr(win, 0, let_to_name(CONTAINED_SYM, TRUE));
1933         /*
1934          * Search through the container objects in the inventory for
1935          * unpaid items.  The top level inventory items have already
1936          * been listed.
1937          */
1938         for (otmp = invent; otmp; otmp = otmp->nobj) {
1939             if (Has_contents(otmp)) {
1940                 marker = (struct obj *) 0;      /* haven't found any */
1941                 while (find_unpaid(otmp->cobj, &marker)) {
1942                     totcost += cost = unpaid_cost(marker);
1943                     save_unpaid = marker->unpaid;
1944                     marker->unpaid = 0;    /* suppress "(unpaid)" suffix */
1945                     putstr(win, 0,
1946                            xprname(marker, distant_name(marker, doname),
1947                                    CONTAINED_SYM, TRUE, cost, 0L));
1948                     marker->unpaid = save_unpaid;
1949                 }
1950             }
1951         }
1952     }
1953
1954     putstr(win, 0, "");
1955     putstr(win, 0, xprname((struct obj *)0, "Total:", '*', FALSE, totcost, 0L));
1956     display_nhwindow(win, FALSE);
1957     destroy_nhwindow(win);
1958 }
1959
1960
1961 /* query objlist callback: return TRUE if obj type matches "this_type" */
1962 static int this_type;
1963
1964 STATIC_OVL boolean
1965 this_type_only(obj)
1966     struct obj *obj;
1967 {
1968     return (obj->oclass == this_type);
1969 }
1970
1971 /* the 'I' command */
1972 int
1973 dotypeinv()
1974 {
1975         char c = '\0';
1976         int n, i = 0;
1977         char *extra_types, types[BUFSZ];
1978         int class_count, oclass, unpaid_count, itemcount;
1979         boolean billx = *u.ushops && doinvbill(0);
1980         menu_item *pick_list;
1981         boolean traditional = TRUE;
1982         const char *prompt = "What type of object do you want an inventory of?";
1983
1984 #ifndef GOLDOBJ
1985         if (!invent && !u.ugold && !billx) {
1986 #else
1987         if (!invent && !billx) {
1988 #endif
1989             You("aren't carrying anything.");
1990             return 0;
1991         }
1992         unpaid_count = count_unpaid(invent);
1993         if (flags.menu_style != MENU_TRADITIONAL) {
1994             if (flags.menu_style == MENU_FULL ||
1995                                 flags.menu_style == MENU_PARTIAL) {
1996                 traditional = FALSE;
1997                 i = UNPAID_TYPES;
1998                 if (billx) i |= BILLED_TYPES;
1999                 n = query_category(prompt, invent, i, &pick_list, PICK_ONE);
2000                 if (!n) return 0;
2001                 this_type = c = pick_list[0].item.a_int;
2002                 free((genericptr_t) pick_list);
2003             }
2004         }
2005         if (traditional) {
2006             /* collect a list of classes of objects carried, for use as a prompt */
2007             types[0] = 0;
2008             class_count = collect_obj_classes(types, invent,
2009                                               FALSE,
2010 #ifndef GOLDOBJ
2011                                               (u.ugold != 0),
2012 #endif
2013                                               (boolean FDECL((*),(OBJ_P))) 0, &itemcount);
2014             if (unpaid_count) {
2015                 Strcat(types, "u");
2016                 class_count++;
2017             }
2018             if (billx) {
2019                 Strcat(types, "x");
2020                 class_count++;
2021             }
2022             /* add everything not already included; user won't see these */
2023             extra_types = eos(types);
2024             *extra_types++ = '\033';
2025             if (!unpaid_count) *extra_types++ = 'u';
2026             if (!billx) *extra_types++ = 'x';
2027             *extra_types = '\0';        /* for index() */
2028             for (i = 0; i < MAXOCLASSES; i++)
2029                 if (!index(types, def_oc_syms[i])) {
2030                     *extra_types++ = def_oc_syms[i];
2031                     *extra_types = '\0';
2032                 }
2033
2034             if(class_count > 1) {
2035                 c = yn_function(prompt, types, '\0');
2036 #ifdef REDO
2037                 savech(c);
2038 #endif
2039                 if(c == '\0') {
2040                         clear_nhwindow(WIN_MESSAGE);
2041                         return 0;
2042                 }
2043             } else {
2044                 /* only one thing to itemize */
2045                 if (unpaid_count)
2046                     c = 'u';
2047                 else if (billx)
2048                     c = 'x';
2049                 else
2050                     c = types[0];
2051             }
2052         }
2053         if (c == 'x') {
2054             if (billx)
2055                 (void) doinvbill(1);
2056             else
2057                 pline("No used-up objects on your shopping bill.");
2058             return 0;
2059         }
2060         if (c == 'u') {
2061             if (unpaid_count)
2062                 dounpaid();
2063             else
2064                 You("are not carrying any unpaid objects.");
2065             return 0;
2066         }
2067         if (traditional) {
2068             oclass = def_char_to_objclass(c); /* change to object class */
2069             if (oclass == COIN_CLASS) {
2070                 return doprgold();
2071             } else if (index(types, c) > index(types, '\033')) {
2072                 You("have no such objects.");
2073                 return 0;
2074             }
2075             this_type = oclass;
2076         }
2077         if (query_objlist((char *) 0, invent,
2078                     (flags.invlet_constant ? USE_INVLET : 0)|INVORDER_SORT,
2079                     &pick_list, PICK_NONE, this_type_only) > 0)
2080             free((genericptr_t)pick_list);
2081         return 0;
2082 }
2083
2084 /* return a string describing the dungeon feature at <x,y> if there
2085    is one worth mentioning at that location; otherwise null */
2086 const char *
2087 dfeature_at(x, y, buf)
2088 int x, y;
2089 char *buf;
2090 {
2091         struct rm *lev = &levl[x][y];
2092         int ltyp = lev->typ, cmap = -1;
2093         const char *dfeature = 0;
2094         static char altbuf[BUFSZ];
2095
2096         if (IS_DOOR(ltyp)) {
2097             switch (lev->doormask) {
2098             case D_NODOOR:      cmap = S_ndoor; break;  /* "doorway" */
2099             case D_ISOPEN:      cmap = S_vodoor; break; /* "open door" */
2100             case D_BROKEN:      dfeature = "broken door"; break;
2101             default:    cmap = S_vcdoor; break; /* "closed door" */
2102             }
2103             /* override door description for open drawbridge */
2104             if (is_drawbridge_wall(x, y) >= 0)
2105                 dfeature = "open drawbridge portcullis",  cmap = -1;
2106         } else if (IS_FOUNTAIN(ltyp))
2107             cmap = S_fountain;                          /* "fountain" */
2108         else if (IS_THRONE(ltyp))
2109             cmap = S_throne;                            /* "opulent throne" */
2110         else if (is_lava(x,y))
2111             cmap = S_lava;                              /* "molten lava" */
2112         else if (is_ice(x,y))
2113             cmap = S_ice;                               /* "ice" */
2114         else if (is_pool(x,y))
2115             dfeature = "pool of water";
2116 #ifdef SINKS
2117         else if (IS_SINK(ltyp))
2118             cmap = S_sink;                              /* "sink" */
2119 #endif
2120         else if (IS_ALTAR(ltyp)) {
2121             Sprintf(altbuf, "altar to %s (%s)", a_gname(),
2122                     align_str(Amask2align(lev->altarmask & ~AM_SHRINE)));
2123             dfeature = altbuf;
2124         } else if ((x == xupstair && y == yupstair) ||
2125                  (x == sstairs.sx && y == sstairs.sy && sstairs.up))
2126             cmap = S_upstair;                           /* "staircase up" */
2127         else if ((x == xdnstair && y == ydnstair) ||
2128                  (x == sstairs.sx && y == sstairs.sy && !sstairs.up))
2129             cmap = S_dnstair;                           /* "staircase down" */
2130         else if (x == xupladder && y == yupladder)
2131             cmap = S_upladder;                          /* "ladder up" */
2132         else if (x == xdnladder && y == ydnladder)
2133             cmap = S_dnladder;                          /* "ladder down" */
2134         else if (ltyp == DRAWBRIDGE_DOWN)
2135             cmap = S_vodbridge;                 /* "lowered drawbridge" */
2136         else if (ltyp == DBWALL)
2137             cmap = S_vcdbridge;                 /* "raised drawbridge" */
2138         else if (IS_GRAVE(ltyp))
2139             cmap = S_grave;                             /* "grave" */
2140         else if (ltyp == TREE)
2141             cmap = S_tree;                              /* "tree" */
2142         else if (ltyp == IRONBARS)
2143             dfeature = "set of iron bars";
2144
2145         if (cmap >= 0) dfeature = defsyms[cmap].explanation;
2146         if (dfeature) Strcpy(buf, dfeature);
2147         return dfeature;
2148 }
2149
2150 /* look at what is here; if there are many objects (5 or more),
2151    don't show them unless obj_cnt is 0 */
2152 int
2153 look_here(obj_cnt, picked_some)
2154 int obj_cnt;    /* obj_cnt > 0 implies that autopickup is in progess */
2155 boolean picked_some;
2156 {
2157         struct obj *otmp;
2158         struct trap *trap;
2159         const char *verb = Blind ? "feel" : "see";
2160         const char *dfeature = (char *)0;
2161         char fbuf[BUFSZ], fbuf2[BUFSZ];
2162         winid tmpwin;
2163         boolean skip_objects = (obj_cnt >= 5), felt_cockatrice = FALSE;
2164
2165         if (u.uswallow && u.ustuck) {
2166             struct monst *mtmp = u.ustuck;
2167             Sprintf(fbuf, "Contents of %s %s",
2168                 s_suffix(mon_nam(mtmp)), mbodypart(mtmp, STOMACH));
2169             /* Skip "Contents of " by using fbuf index 12 */
2170             You("%s to %s what is lying in %s.",
2171                 Blind ? "try" : "look around", verb, &fbuf[12]);
2172             otmp = mtmp->minvent;
2173             if (otmp) {
2174                 for ( ; otmp; otmp = otmp->nobj) {
2175                         /* If swallower is an animal, it should have become stone but... */
2176                         if (otmp->otyp == CORPSE) feel_cockatrice(otmp, FALSE);
2177                 }
2178                 if (Blind) Strcpy(fbuf, "You feel");
2179                 Strcat(fbuf,":");
2180                 (void) display_minventory(mtmp, MINV_ALL, fbuf);
2181             } else {
2182                 You("%s no objects here.", verb);
2183             }
2184             return(!!Blind);
2185         }
2186         if (!skip_objects && (trap = t_at(u.ux,u.uy)) && trap->tseen)
2187                 There("is %s here.",
2188                         an(defsyms[trap_to_defsym(trap->ttyp)].explanation));
2189
2190         otmp = level.objects[u.ux][u.uy];
2191         dfeature = dfeature_at(u.ux, u.uy, fbuf2);
2192         if (dfeature && !strcmp(dfeature, "pool of water") && Underwater)
2193                 dfeature = 0;
2194
2195         if (Blind) {
2196                 boolean drift = Is_airlevel(&u.uz) || Is_waterlevel(&u.uz);
2197                 if (dfeature && !strncmp(dfeature, "altar ", 6)) {
2198                     /* don't say "altar" twice, dfeature has more info */
2199                     You("try to feel what is here.");
2200                 } else {
2201                     You("try to feel what is %s%s.",
2202                         drift ? "floating here" : "lying here on the ",
2203                         drift ? ""              : surface(u.ux, u.uy));
2204                 }
2205                 if (dfeature && !drift && !strcmp(dfeature, surface(u.ux,u.uy)))
2206                         dfeature = 0;           /* ice already identifed */
2207                 if (!can_reach_floor()) {
2208                         pline("But you can't reach it!");
2209                         return(0);
2210                 }
2211         }
2212
2213         if (dfeature)
2214                 Sprintf(fbuf, "There is %s here.", an(dfeature));
2215
2216         if (!otmp || is_lava(u.ux,u.uy) || (is_pool(u.ux,u.uy) && !Underwater)) {
2217                 if (dfeature) pline(fbuf);
2218                 read_engr_at(u.ux, u.uy); /* Eric Backus */
2219                 if (!skip_objects && (Blind || !dfeature))
2220                     You("%s no objects here.", verb);
2221                 return(!!Blind);
2222         }
2223         /* we know there is something here */
2224
2225         if (skip_objects) {
2226             if (dfeature) pline(fbuf);
2227             read_engr_at(u.ux, u.uy); /* Eric Backus */
2228             There("are %s%s objects here.",
2229                   (obj_cnt <= 10) ? "several" : "many",
2230                   picked_some ? " more" : "");
2231         } else if (!otmp->nexthere) {
2232             /* only one object */
2233             if (dfeature) pline(fbuf);
2234             read_engr_at(u.ux, u.uy); /* Eric Backus */
2235 #ifdef INVISIBLE_OBJECTS
2236             if (otmp->oinvis && !See_invisible) verb = "feel";
2237 #endif
2238             You("%s here %s.", verb, doname(otmp));
2239             if (otmp->otyp == CORPSE) feel_cockatrice(otmp, FALSE);
2240         } else {
2241             display_nhwindow(WIN_MESSAGE, FALSE);
2242             tmpwin = create_nhwindow(NHW_MENU);
2243             if(dfeature) {
2244                 putstr(tmpwin, 0, fbuf);
2245                 putstr(tmpwin, 0, "");
2246             }
2247             putstr(tmpwin, 0, Blind ? "Things that you feel here:" :
2248                                       "Things that are here:");
2249             for ( ; otmp; otmp = otmp->nexthere) {
2250                 if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) {
2251                         char buf[BUFSZ];
2252                         felt_cockatrice = TRUE;
2253                         Strcpy(buf, doname(otmp));
2254                         Strcat(buf, "...");
2255                         putstr(tmpwin, 0, buf);
2256                         break;
2257                 }
2258                 putstr(tmpwin, 0, doname(otmp));
2259             }
2260             display_nhwindow(tmpwin, TRUE);
2261             destroy_nhwindow(tmpwin);
2262             if (felt_cockatrice) feel_cockatrice(otmp, FALSE);
2263             read_engr_at(u.ux, u.uy); /* Eric Backus */
2264         }
2265         return(!!Blind);
2266 }
2267
2268 /* explicilty look at what is here, including all objects */
2269 int
2270 dolook()
2271 {
2272         return look_here(0, FALSE);
2273 }
2274
2275 boolean
2276 will_feel_cockatrice(otmp, force_touch)
2277 struct obj *otmp;
2278 boolean force_touch;
2279 {
2280         if ((Blind || force_touch) && !uarmg && !Stone_resistance &&
2281                 (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm])))
2282                         return TRUE;
2283         return FALSE;
2284 }
2285
2286 void
2287 feel_cockatrice(otmp, force_touch)
2288 struct obj *otmp;
2289 boolean force_touch;
2290 {
2291         char kbuf[BUFSZ];
2292
2293         if (will_feel_cockatrice(otmp, force_touch)) {
2294             if(poly_when_stoned(youmonst.data))
2295                         You("touched the %s corpse with your bare %s.",
2296                                 mons[otmp->corpsenm].mname, makeplural(body_part(HAND)));
2297             else
2298                         pline("Touching the %s corpse is a fatal mistake...",
2299                                 mons[otmp->corpsenm].mname);
2300                 Sprintf(kbuf, "%s corpse", an(mons[otmp->corpsenm].mname));
2301                 instapetrify(kbuf);
2302         }
2303 }
2304
2305 #endif /* OVLB */
2306 #ifdef OVL1
2307
2308 void
2309 stackobj(obj)
2310 struct obj *obj;
2311 {
2312         struct obj *otmp;
2313
2314         for(otmp = level.objects[obj->ox][obj->oy]; otmp; otmp = otmp->nexthere)
2315                 if(otmp != obj && merged(&obj,&otmp))
2316                         break;
2317         return;
2318 }
2319
2320 STATIC_OVL boolean
2321 mergable(otmp, obj)     /* returns TRUE if obj  & otmp can be merged */
2322         register struct obj *otmp, *obj;
2323 {
2324         if (obj->otyp != otmp->otyp) return FALSE;
2325 #ifdef GOLDOBJ
2326         /* coins of the same kind will always merge */
2327         if (obj->oclass == COIN_CLASS) return TRUE;
2328 #endif
2329         if (obj->unpaid != otmp->unpaid ||
2330             obj->spe != otmp->spe || obj->dknown != otmp->dknown ||
2331             (obj->bknown != otmp->bknown && !Role_if(PM_PRIEST)) ||
2332             obj->cursed != otmp->cursed || obj->blessed != otmp->blessed ||
2333             obj->no_charge != otmp->no_charge ||
2334             obj->obroken != otmp->obroken ||
2335             obj->otrapped != otmp->otrapped ||
2336             obj->lamplit != otmp->lamplit ||
2337 #ifdef INVISIBLE_OBJECTS
2338                 obj->oinvis != otmp->oinvis ||
2339 #endif
2340             obj->greased != otmp->greased ||
2341             obj->oeroded != otmp->oeroded ||
2342             obj->oeroded2 != otmp->oeroded2 ||
2343             obj->bypass != otmp->bypass)
2344             return(FALSE);
2345
2346         if ((obj->oclass==WEAPON_CLASS || obj->oclass==ARMOR_CLASS) &&
2347             (obj->oerodeproof!=otmp->oerodeproof || obj->rknown!=otmp->rknown))
2348             return FALSE;
2349
2350         if (obj->oclass == FOOD_CLASS && (obj->oeaten != otmp->oeaten ||
2351                                           obj->orotten != otmp->orotten))
2352             return(FALSE);
2353
2354         if (obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == TIN) {
2355                 if (obj->corpsenm != otmp->corpsenm)
2356                                 return FALSE;
2357         }
2358
2359         /* hatching eggs don't merge; ditto for revivable corpses */
2360         if ((obj->otyp == EGG && (obj->timed || otmp->timed)) ||
2361             (obj->otyp == CORPSE && otmp->corpsenm >= LOW_PM &&
2362                 is_reviver(&mons[otmp->corpsenm])))
2363             return FALSE;
2364
2365         /* allow candle merging only if their ages are close */
2366         /* see begin_burn() for a reference for the magic "25" */
2367         if (Is_candle(obj) && obj->age/25 != otmp->age/25)
2368             return(FALSE);
2369
2370         /* burning potions of oil never merge */
2371         if (obj->otyp == POT_OIL && obj->lamplit)
2372             return FALSE;
2373
2374         /* don't merge surcharged item with base-cost item */
2375         if (obj->unpaid && !same_price(obj, otmp))
2376             return FALSE;
2377
2378         /* if they have names, make sure they're the same */
2379         if ( (obj->onamelth != otmp->onamelth &&
2380                 ((obj->onamelth && otmp->onamelth) || obj->otyp == CORPSE)
2381              ) ||
2382             (obj->onamelth && otmp->onamelth &&
2383                     strncmp(ONAME(obj), ONAME(otmp), (int)obj->onamelth)))
2384                 return FALSE;
2385
2386         /* for the moment, any additional information is incompatible */
2387         if (obj->oxlth || otmp->oxlth) return FALSE;
2388
2389         if(obj->oartifact != otmp->oartifact) return FALSE;
2390
2391         if(obj->known == otmp->known ||
2392                 !objects[otmp->otyp].oc_uses_known) {
2393                 return((boolean)(objects[obj->otyp].oc_merge));
2394         } else return(FALSE);
2395 }
2396
2397 int
2398 doprgold()
2399 {
2400         /* the messages used to refer to "carrying gold", but that didn't
2401            take containers into account */
2402 #ifndef GOLDOBJ
2403         if(!u.ugold)
2404             Your("wallet is empty.");
2405         else
2406             Your("wallet contains %ld gold piece%s.", u.ugold, plur(u.ugold));
2407 #else
2408         long umoney = money_cnt(invent);
2409         if(!umoney)
2410             Your("wallet is empty.");
2411         else
2412             Your("wallet contains %ld %s.", umoney, currency(umoney));
2413 #endif
2414         shopper_financial_report();
2415         return 0;
2416 }
2417
2418 #endif /* OVL1 */
2419 #ifdef OVLB
2420
2421 int
2422 doprwep()
2423 {
2424     if (!uwep) {
2425         You("are empty %s.", body_part(HANDED));
2426     } else {
2427         prinv((char *)0, uwep, 0L);
2428         if (u.twoweap) prinv((char *)0, uswapwep, 0L);
2429     }
2430     return 0;
2431 }
2432
2433 int
2434 doprarm()
2435 {
2436         if(!wearing_armor())
2437                 You("are not wearing any armor.");
2438         else {
2439 #ifdef TOURIST
2440                 char lets[8];
2441 #else
2442                 char lets[7];
2443 #endif
2444                 register int ct = 0;
2445
2446 #ifdef TOURIST
2447                 if(uarmu) lets[ct++] = obj_to_let(uarmu);
2448 #endif
2449                 if(uarm) lets[ct++] = obj_to_let(uarm);
2450                 if(uarmc) lets[ct++] = obj_to_let(uarmc);
2451                 if(uarmh) lets[ct++] = obj_to_let(uarmh);
2452                 if(uarms) lets[ct++] = obj_to_let(uarms);
2453                 if(uarmg) lets[ct++] = obj_to_let(uarmg);
2454                 if(uarmf) lets[ct++] = obj_to_let(uarmf);
2455                 lets[ct] = 0;
2456                 (void) display_inventory(lets, FALSE);
2457         }
2458         return 0;
2459 }
2460
2461 int
2462 doprring()
2463 {
2464         if(!uleft && !uright)
2465                 You("are not wearing any rings.");
2466         else {
2467                 char lets[3];
2468                 register int ct = 0;
2469
2470                 if(uleft) lets[ct++] = obj_to_let(uleft);
2471                 if(uright) lets[ct++] = obj_to_let(uright);
2472                 lets[ct] = 0;
2473                 (void) display_inventory(lets, FALSE);
2474         }
2475         return 0;
2476 }
2477
2478 int
2479 dopramulet()
2480 {
2481         if (!uamul)
2482                 You("are not wearing an amulet.");
2483         else
2484                 prinv((char *)0, uamul, 0L);
2485         return 0;
2486 }
2487
2488 STATIC_OVL boolean
2489 tool_in_use(obj)
2490 struct obj *obj;
2491 {
2492         if ((obj->owornmask & (W_TOOL
2493 #ifdef STEED
2494                         | W_SADDLE
2495 #endif
2496                         )) != 0L) return TRUE;
2497         if (obj->oclass != TOOL_CLASS) return FALSE;
2498         return (boolean)(obj == uwep || obj->lamplit ||
2499                                 (obj->otyp == LEASH && obj->leashmon));
2500 }
2501
2502 int
2503 doprtool()
2504 {
2505         struct obj *otmp;
2506         int ct = 0;
2507         char lets[52+1];
2508
2509         for (otmp = invent; otmp; otmp = otmp->nobj)
2510             if (tool_in_use(otmp))
2511                 lets[ct++] = obj_to_let(otmp);
2512         lets[ct] = '\0';
2513         if (!ct) You("are not using any tools.");
2514         else (void) display_inventory(lets, FALSE);
2515         return 0;
2516 }
2517
2518 /* '*' command; combines the ')' + '[' + '=' + '"' + '(' commands;
2519    show inventory of all currently wielded, worn, or used objects */
2520 int
2521 doprinuse()
2522 {
2523         struct obj *otmp;
2524         int ct = 0;
2525         char lets[52+1];
2526
2527         for (otmp = invent; otmp; otmp = otmp->nobj)
2528             if (is_worn(otmp) || tool_in_use(otmp))
2529                 lets[ct++] = obj_to_let(otmp);
2530         lets[ct] = '\0';
2531         if (!ct) You("are not wearing or wielding anything.");
2532         else (void) display_inventory(lets, FALSE);
2533         return 0;
2534 }
2535
2536 /*
2537  * uses up an object that's on the floor, charging for it as necessary
2538  */
2539 void
2540 useupf(obj, numused)
2541 register struct obj *obj;
2542 long numused;
2543 {
2544         register struct obj *otmp;
2545         boolean at_u = (obj->ox == u.ux && obj->oy == u.uy);
2546
2547         /* burn_floor_paper() keeps an object pointer that it tries to
2548          * useupf() multiple times, so obj must survive if plural */
2549         if (obj->quan > numused)
2550                 otmp = splitobj(obj, numused);
2551         else
2552                 otmp = obj;
2553         if(costly_spot(otmp->ox, otmp->oy)) {
2554             if(index(u.urooms, *in_rooms(otmp->ox, otmp->oy, 0)))
2555                 addtobill(otmp, FALSE, FALSE, FALSE);
2556             else (void)stolen_value(otmp, otmp->ox, otmp->oy, FALSE, FALSE);
2557         }
2558         delobj(otmp);
2559         if (at_u && u.uundetected && hides_under(youmonst.data))
2560             u.uundetected = OBJ_AT(u.ux, u.uy);
2561 }
2562
2563 #endif /* OVLB */
2564
2565
2566 #ifdef OVL1
2567
2568 /*
2569  * Conversion from a class to a string for printing.
2570  * This must match the object class order.
2571  */
2572 STATIC_VAR NEARDATA const char *names[] = { 0,
2573         "Illegal objects", "Weapons", "Armor", "Rings", "Amulets",
2574         "Tools", "Comestibles", "Potions", "Scrolls", "Spellbooks",
2575         "Wands", "Coins", "Gems", "Boulders/Statues", "Iron balls",
2576         "Chains", "Venoms"
2577 };
2578
2579 static NEARDATA const char oth_symbols[] = {
2580         CONTAINED_SYM,
2581         '\0'
2582 };
2583
2584 static NEARDATA const char *oth_names[] = {
2585         "Bagged/Boxed items"
2586 };
2587
2588 static NEARDATA char *invbuf = (char *)0;
2589 static NEARDATA unsigned invbufsiz = 0;
2590
2591 char *
2592 let_to_name(let,unpaid)
2593 char let;
2594 boolean unpaid;
2595 {
2596         const char *class_name;
2597         const char *pos;
2598         int oclass = (let >= 1 && let < MAXOCLASSES) ? let : 0;
2599         unsigned len;
2600
2601         if (oclass)
2602             class_name = names[oclass];
2603         else if ((pos = index(oth_symbols, let)) != 0)
2604             class_name = oth_names[pos - oth_symbols];
2605         else
2606             class_name = names[0];
2607
2608         len = strlen(class_name) + (unpaid ? sizeof "unpaid_" : sizeof "");
2609         if (len > invbufsiz) {
2610             if (invbuf) free((genericptr_t)invbuf);
2611             invbufsiz = len + 10; /* add slop to reduce incremental realloc */
2612             invbuf = (char *) alloc(invbufsiz);
2613         }
2614         if (unpaid)
2615             Strcat(strcpy(invbuf, "Unpaid "), class_name);
2616         else
2617             Strcpy(invbuf, class_name);
2618         return invbuf;
2619 }
2620
2621 void
2622 free_invbuf()
2623 {
2624         if (invbuf) free((genericptr_t)invbuf),  invbuf = (char *)0;
2625         invbufsiz = 0;
2626 }
2627
2628 #endif /* OVL1 */
2629 #ifdef OVLB
2630
2631 void
2632 reassign()
2633 {
2634         register int i;
2635         register struct obj *obj;
2636
2637         for(obj = invent, i = 0; obj; obj = obj->nobj, i++)
2638                 obj->invlet = (i < 26) ? ('a'+i) : ('A'+i-26);
2639         lastinvnr = i;
2640 }
2641
2642 #endif /* OVLB */
2643 #ifdef OVL1
2644
2645 int
2646 doorganize()    /* inventory organizer by Del Lamb */
2647 {
2648         struct obj *obj, *otmp;
2649         register int ix, cur;
2650         register char let;
2651         char alphabet[52+1], buf[52+1];
2652         char qbuf[QBUFSZ];
2653         char allowall[2];
2654         const char *adj_type;
2655
2656         if (!flags.invlet_constant) reassign();
2657         /* get a pointer to the object the user wants to organize */
2658         allowall[0] = ALL_CLASSES; allowall[1] = '\0';
2659         if (!(obj = getobj(allowall,"adjust"))) return(0);
2660
2661         /* initialize the list with all upper and lower case letters */
2662         for (let = 'a', ix = 0;  let <= 'z';) alphabet[ix++] = let++;
2663         for (let = 'A', ix = 26; let <= 'Z';) alphabet[ix++] = let++;
2664         alphabet[52] = 0;
2665
2666         /* blank out all the letters currently in use in the inventory */
2667         /* except those that will be merged with the selected object   */
2668         for (otmp = invent; otmp; otmp = otmp->nobj)
2669                 if (otmp != obj && !mergable(otmp,obj)) {
2670                         if (otmp->invlet <= 'Z')
2671                                 alphabet[(otmp->invlet) - 'A' + 26] = ' ';
2672                         else    alphabet[(otmp->invlet) - 'a']      = ' ';
2673                 }
2674
2675         /* compact the list by removing all the blanks */
2676         for (ix = cur = 0; ix <= 52; ix++)
2677                 if (alphabet[ix] != ' ') buf[cur++] = alphabet[ix];
2678
2679         /* and by dashing runs of letters */
2680         if(cur > 5) compactify(buf);
2681
2682         /* get new letter to use as inventory letter */
2683         for (;;) {
2684                 Sprintf(qbuf, "Adjust letter to what [%s]?",buf);
2685                 let = yn_function(qbuf, (char *)0, '\0');
2686                 if(index(quitchars,let)) {
2687                         pline(Never_mind);
2688                         return(0);
2689                 }
2690                 if (let == '@' || !letter(let))
2691                         pline("Select an inventory slot letter.");
2692                 else
2693                         break;
2694         }
2695
2696         /* change the inventory and print the resulting item */
2697         adj_type = "Moving:";
2698
2699         /*
2700          * don't use freeinv/addinv to avoid double-touching artifacts,
2701          * dousing lamps, losing luck, cursing loadstone, etc.
2702          */
2703         extract_nobj(obj, &invent);
2704
2705         for (otmp = invent; otmp;)
2706                 if (merged(&otmp,&obj)) {
2707                         adj_type = "Merging:";
2708                         obj = otmp;
2709                         otmp = otmp->nobj;
2710                         extract_nobj(obj, &invent);
2711                 } else {
2712                         if (otmp->invlet == let) {
2713                                 adj_type = "Swapping:";
2714                                 otmp->invlet = obj->invlet;
2715                         }
2716                         otmp = otmp->nobj;
2717                 }
2718
2719         /* inline addinv (assuming flags.invlet_constant and !merged) */
2720         obj->invlet = let;
2721         obj->nobj = invent; /* insert at beginning */
2722         obj->where = OBJ_INVENT;
2723         invent = obj;
2724         reorder_invent();
2725
2726         prinv(adj_type, obj, 0L);
2727         update_inventory();
2728         return(0);
2729 }
2730
2731 /* common to display_minventory and display_cinventory */
2732 STATIC_OVL void
2733 invdisp_nothing(hdr, txt)
2734 const char *hdr, *txt;
2735 {
2736         winid win;
2737         anything any;
2738         menu_item *selected;
2739
2740         any.a_void = 0;
2741         win = create_nhwindow(NHW_MENU);
2742         start_menu(win);
2743         add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, hdr, MENU_UNSELECTED);
2744         add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
2745         add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, txt, MENU_UNSELECTED);
2746         end_menu(win, (char *)0);
2747         if (select_menu(win, PICK_NONE, &selected) > 0)
2748             free((genericptr_t)selected);
2749         destroy_nhwindow(win);
2750         return;
2751 }
2752
2753 /* query_objlist callback: return things that could possibly be worn/wielded */
2754 STATIC_OVL boolean
2755 worn_wield_only(obj)
2756 struct obj *obj;
2757 {
2758     return (obj->oclass == WEAPON_CLASS
2759                 || obj->oclass == ARMOR_CLASS
2760                 || obj->oclass == AMULET_CLASS
2761                 || obj->oclass == RING_CLASS
2762                 || obj->oclass == TOOL_CLASS);
2763 }
2764
2765 /*
2766  * Display a monster's inventory.
2767  * Returns a pointer to the object from the monster's inventory selected
2768  * or NULL if nothing was selected.
2769  *
2770  * By default, only worn and wielded items are displayed.  The caller
2771  * can pick one.  Modifier flags are:
2772  *
2773  *      MINV_NOLET      - nothing selectable
2774  *      MINV_ALL        - display all inventory
2775  */
2776 struct obj *
2777 display_minventory(mon, dflags, title)
2778 register struct monst *mon;
2779 int dflags;
2780 char *title;
2781 {
2782         struct obj *ret;
2783 #ifndef GOLDOBJ
2784         struct obj m_gold;
2785 #endif
2786         char tmp[QBUFSZ];
2787         int n;
2788         menu_item *selected = 0;
2789 #ifndef GOLDOBJ
2790         int do_all = (dflags & MINV_ALL) != 0,
2791             do_gold = (do_all && mon->mgold);
2792 #else
2793         int do_all = (dflags & MINV_ALL) != 0;
2794 #endif
2795
2796         Sprintf(tmp,"%s %s:", s_suffix(noit_Monnam(mon)),
2797                 do_all ? "possessions" : "armament");
2798
2799 #ifndef GOLDOBJ
2800         if (do_all ? (mon->minvent || mon->mgold)
2801 #else
2802         if (do_all ? (mon->minvent != 0)
2803 #endif
2804                    : (mon->misc_worn_check || MON_WEP(mon))) {
2805             /* Fool the 'weapon in hand' routine into
2806              * displaying 'weapon in claw', etc. properly.
2807              */
2808             youmonst.data = mon->data;
2809
2810 #ifndef GOLDOBJ
2811             if (do_gold) {
2812                 /*
2813                  * Make temporary gold object and insert at the head of
2814                  * the mon's inventory.  We can get away with using a
2815                  * stack variable object because monsters don't carry
2816                  * gold in their inventory, so it won't merge.
2817                  */
2818                 m_gold = zeroobj;
2819                 m_gold.otyp = GOLD_PIECE;  m_gold.oclass = COIN_CLASS;
2820                 m_gold.quan = mon->mgold;  m_gold.dknown = 1;
2821                 m_gold.where = OBJ_FREE;
2822                 /* we had better not merge and free this object... */
2823                 if (add_to_minv(mon, &m_gold))
2824                     panic("display_minventory: static object freed.");
2825             }
2826
2827 #endif
2828             n = query_objlist(title ? title : tmp, mon->minvent, INVORDER_SORT, &selected,
2829                         (dflags & MINV_NOLET) ? PICK_NONE : PICK_ONE,
2830                         do_all ? allow_all : worn_wield_only);
2831
2832 #ifndef GOLDOBJ
2833             if (do_gold) obj_extract_self(&m_gold);
2834 #endif
2835
2836             set_uasmon();
2837         } else {
2838             invdisp_nothing(title ? title : tmp, "(none)");
2839             n = 0;
2840         }
2841
2842         if (n > 0) {
2843             ret = selected[0].item.a_obj;
2844             free((genericptr_t)selected);
2845 #ifndef GOLDOBJ
2846             /*
2847              * Unfortunately, we can't return a pointer to our temporary
2848              * gold object.  We'll have to work out a scheme where this
2849              * can happen.  Maybe even put gold in the inventory list...
2850              */
2851             if (ret == &m_gold) ret = (struct obj *) 0;
2852 #endif
2853         } else
2854             ret = (struct obj *) 0;
2855         return ret;
2856 }
2857
2858 /*
2859  * Display the contents of a container in inventory style.
2860  * Currently, this is only used for statues, via wand of probing.
2861  */
2862 struct obj *
2863 display_cinventory(obj)
2864 register struct obj *obj;
2865 {
2866         struct obj *ret;
2867         char tmp[QBUFSZ];
2868         int n;
2869         menu_item *selected = 0;
2870
2871         Sprintf(tmp,"Contents of %s:", doname(obj));
2872
2873         if (obj->cobj) {
2874             n = query_objlist(tmp, obj->cobj, INVORDER_SORT, &selected,
2875                             PICK_NONE, allow_all);
2876         } else {
2877             invdisp_nothing(tmp, "(empty)");
2878             n = 0;
2879         }
2880         if (n > 0) {
2881             ret = selected[0].item.a_obj;
2882             free((genericptr_t)selected);
2883         } else
2884             ret = (struct obj *) 0;
2885         return ret;
2886 }
2887
2888 /* query objlist callback: return TRUE if obj is at given location */
2889 static coord only;
2890
2891 STATIC_OVL boolean
2892 only_here(obj)
2893     struct obj *obj;
2894 {
2895     return (obj->ox == only.x && obj->oy == only.y);
2896 }
2897
2898 /*
2899  * Display a list of buried items in inventory style.  Return a non-zero
2900  * value if there were items at that spot.
2901  *
2902  * Currently, this is only used with a wand of probing zapped downwards.
2903  */
2904 int
2905 display_binventory(x, y, as_if_seen)
2906 int x, y;
2907 boolean as_if_seen;
2908 {
2909         struct obj *obj;
2910         menu_item *selected = 0;
2911         int n;
2912
2913         /* count # of objects here */
2914         for (n = 0, obj = level.buriedobjlist; obj; obj = obj->nobj)
2915             if (obj->ox == x && obj->oy == y) {
2916                 if (as_if_seen) obj->dknown = 1;
2917                 n++;
2918             }
2919
2920         if (n) {
2921             only.x = x;
2922             only.y = y;
2923             if (query_objlist("Things that are buried here:",
2924                               level.buriedobjlist, INVORDER_SORT,
2925                               &selected, PICK_NONE, only_here) > 0)
2926                 free((genericptr_t)selected);
2927             only.x = only.y = 0;
2928         }
2929         return n;
2930 }
2931
2932 #endif /* OVL1 */
2933
2934 /*invent.c*/